diff --git a/.rubocop.yml b/.rubocop.yml new file mode 100644 index 00000000000..f1deca38196 --- /dev/null +++ b/.rubocop.yml @@ -0,0 +1,34 @@ +inherit_from: .rubocop_todo.yml + +# Please keep AllCops, Bundler, Layout, Style, Metrics groups and then order cops +# alphabetically +# +# References: +# * https://github.com/bbatsov/ruby-style-guide +# * https://rubocop.readthedocs.io/ +AllCops: + DisplayCopNames: true + DisplayStyleGuide: true + Exclude: + - "generators/**/*" + - "lib/active_merchant/billing/gateways/paypal/**/*" + - "lib/active_merchant/billing/gateways/paypal_express.rb" + - "vendor/**/*" + ExtraDetails: false + TargetRubyVersion: 2.3 + +# Active Merchant gateways are not amenable to length restrictions +Metrics/ClassLength: + Enabled: false + +Metrics/ModuleLength: + Enabled: false + +Layout/AlignParameters: + EnforcedStyle: with_fixed_indentation + +Layout/DotPosition: + EnforcedStyle: trailing + +Layout/CaseIndentation: + EnforcedStyle: end diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml new file mode 100644 index 00000000000..b8025e1f862 --- /dev/null +++ b/.rubocop_todo.yml @@ -0,0 +1,1095 @@ +# This configuration was generated by +# `rubocop --auto-gen-config` +# on 2018-11-20 16:45:49 -0500 using RuboCop version 0.60.0. +# The point is for the user to remove these configuration records +# one by one as the offenses are removed from the code base. +# Note that changes in the inspected code, or installation of new +# versions of RuboCop, may require this file to be generated again. + +# Offense count: 2 +# Cop supports --auto-correct. +# Configuration parameters: Include, TreatCommentsAsGroupSeparators. +# Include: **/*.gemspec +Gemspec/OrderedDependencies: + Exclude: + - 'activemerchant.gemspec' + +# Offense count: 1828 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedHashRocketStyle, EnforcedColonStyle, EnforcedLastArgumentHashStyle. +# SupportedHashRocketStyles: key, separator, table +# SupportedColonStyles: key, separator, table +# SupportedLastArgumentHashStyles: always_inspect, always_ignore, ignore_implicit, ignore_explicit +Layout/AlignHash: + Enabled: false + +# Offense count: 57 +# Cop supports --auto-correct. +Layout/ClosingHeredocIndentation: + Enabled: false + +# Offense count: 167 +# Cop supports --auto-correct. +Layout/EmptyLineAfterGuardClause: + Enabled: false + +# Offense count: 173 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle. +# SupportedStyles: empty_lines, empty_lines_except_namespace, empty_lines_special, no_empty_lines, beginning_only, ending_only +Layout/EmptyLinesAroundClassBody: + Enabled: false + +# Offense count: 39 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyleAlignWith, AutoCorrect, Severity. +# SupportedStylesAlignWith: keyword, variable, start_of_line +Layout/EndAlignment: + Enabled: false + +# Offense count: 174 +# Cop supports --auto-correct. +# Configuration parameters: AllowForAlignment, ForceEqualSignAlignment. +Layout/ExtraSpacing: + Enabled: false + +# Offense count: 105 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle, IndentationWidth. +# SupportedStyles: consistent, consistent_relative_to_receiver, special_for_inner_method_call, special_for_inner_method_call_in_parentheses +Layout/FirstParameterIndentation: + Enabled: false + +# Offense count: 255 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle, IndentationWidth. +# SupportedStyles: special_inside_parentheses, consistent, align_braces +Layout/IndentHash: + Enabled: false + +# Offense count: 392 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle. +# SupportedStyles: auto_detection, squiggly, active_support, powerpack, unindent +Layout/IndentHeredoc: + Enabled: false + +# Offense count: 1 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle. +# SupportedStyles: symmetrical, new_line, same_line +Layout/MultilineArrayBraceLayout: + Exclude: + - 'lib/active_merchant/billing/gateways/optimal_payment.rb' + +# Offense count: 36 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle. +# SupportedStyles: symmetrical, new_line, same_line +Layout/MultilineHashBraceLayout: + Enabled: false + +# Offense count: 232 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle. +# SupportedStyles: symmetrical, new_line, same_line +Layout/MultilineMethodCallBraceLayout: + Enabled: false + +# Offense count: 24 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle, IndentationWidth. +# SupportedStyles: aligned, indented +Layout/MultilineOperationIndentation: + Exclude: + - 'lib/active_merchant/billing/credit_card_methods.rb' + - 'lib/active_merchant/billing/gateways/iridium.rb' + - 'lib/active_merchant/billing/gateways/moneris.rb' + - 'lib/active_merchant/billing/gateways/moneris_us.rb' + - 'lib/active_merchant/billing/gateways/orbital.rb' + - 'lib/active_merchant/billing/gateways/redsys.rb' + - 'test/unit/gateways/braintree_blue_test.rb' + - 'test/unit/gateways/skip_jack_test.rb' + +# Offense count: 15 +# Cop supports --auto-correct. +Layout/RescueEnsureAlignment: + Exclude: + - 'lib/active_merchant/billing/gateways/balanced.rb' + - 'lib/active_merchant/billing/gateways/clearhaus.rb' + - 'lib/active_merchant/billing/gateways/culqi.rb' + - 'lib/active_merchant/billing/gateways/eway_managed.rb' + - 'lib/active_merchant/billing/gateways/fat_zebra.rb' + - 'lib/active_merchant/billing/gateways/hps.rb' + - 'lib/active_merchant/billing/gateways/iveri.rb' + - 'lib/active_merchant/billing/gateways/kushki.rb' + - 'lib/active_merchant/billing/gateways/merchant_e_solutions.rb' + - 'lib/active_merchant/billing/gateways/netbanx.rb' + - 'lib/active_merchant/billing/gateways/opp.rb' + - 'lib/active_merchant/billing/gateways/orbital.rb' + - 'lib/active_merchant/billing/gateways/pay_junction_v2.rb' + - 'lib/active_merchant/billing/gateways/quickbooks.rb' + - 'lib/active_merchant/billing/gateways/trans_first_transaction_express.rb' + +# Offense count: 649 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle. +# SupportedStyles: space, no_space +Layout/SpaceAroundEqualsInParameterDefault: + Enabled: false + +# Offense count: 104 +# Cop supports --auto-correct. +Layout/SpaceAroundKeyword: + Enabled: false + +# Offense count: 782 +# Cop supports --auto-correct. +# Configuration parameters: AllowForAlignment. +Layout/SpaceAroundOperators: + Enabled: false + +# Offense count: 118 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle, EnforcedStyleForEmptyBrackets. +# SupportedStyles: space, no_space, compact +# SupportedStylesForEmptyBrackets: space, no_space +Layout/SpaceInsideArrayLiteralBrackets: + Enabled: false + +# Offense count: 12 +# Cop supports --auto-correct. +Layout/SpaceInsideArrayPercentLiteral: + Exclude: + - 'lib/active_merchant/billing/gateways/migs/migs_codes.rb' + +# Offense count: 1186 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle, EnforcedStyleForEmptyBraces. +# SupportedStyles: space, no_space, compact +# SupportedStylesForEmptyBraces: space, no_space +Layout/SpaceInsideHashLiteralBraces: + Enabled: false + +# Offense count: 115 +# Cop supports --auto-correct. +Layout/SpaceInsidePercentLiteralDelimiters: + Enabled: false + +# Offense count: 150 +# Configuration parameters: AllowSafeAssignment. +Lint/AssignmentInCondition: + Enabled: false + +# Offense count: 3 +Lint/FormatParameterMismatch: + Exclude: + - 'test/unit/credit_card_formatting_test.rb' + +# Offense count: 2 +Lint/HandleExceptions: + Exclude: + - 'lib/active_merchant/billing/gateways/mastercard.rb' + - 'lib/active_merchant/billing/gateways/trust_commerce.rb' + +# Offense count: 1 +Lint/RescueException: + Exclude: + - 'lib/active_merchant/billing/gateways/quantum.rb' + +# Offense count: 1502 +# Cop supports --auto-correct. +# Configuration parameters: IgnoreEmptyBlocks, AllowUnusedKeywordArguments. +Lint/UnusedBlockArgument: + Enabled: false + +# Offense count: 284 +# Cop supports --auto-correct. +# Configuration parameters: AllowUnusedKeywordArguments, IgnoreEmptyMethods. +Lint/UnusedMethodArgument: + Enabled: false + +# Offense count: 1418 +Metrics/AbcSize: + Max: 192 + +# Offense count: 26 +# Configuration parameters: CountComments, ExcludedMethods. +# ExcludedMethods: refine +Metrics/BlockLength: + Max: 54 + +# Offense count: 9 +# Configuration parameters: CountBlocks. +Metrics/BlockNesting: + Max: 6 + +# Offense count: 175 +Metrics/CyclomaticComplexity: + Max: 36 + +# Offense count: 1793 +# Configuration parameters: CountComments, ExcludedMethods. +Metrics/MethodLength: + Max: 163 + +# Offense count: 2 +# Configuration parameters: CountKeywordArgs. +Metrics/ParameterLists: + Max: 6 + +# Offense count: 129 +Metrics/PerceivedComplexity: + Max: 33 + +# Offense count: 6 +Naming/AccessorMethodName: + Exclude: + - 'lib/active_merchant/billing/gateways/usa_epay_advanced.rb' + - 'test/remote/gateways/remote_authorize_net_cim_test.rb' + - 'test/unit/gateways/authorize_net_cim_test.rb' + +# Offense count: 1 +Naming/ConstantName: + Exclude: + - 'test/test_helper.rb' + +# Offense count: 46 +# Configuration parameters: EnforcedStyle. +# SupportedStyles: lowercase, uppercase +Naming/HeredocDelimiterCase: + Exclude: + - 'test/unit/gateways/authorize_net_test.rb' + - 'test/unit/gateways/card_stream_test.rb' + - 'test/unit/gateways/hps_test.rb' + - 'test/unit/gateways/litle_test.rb' + - 'test/unit/gateways/moneris_test.rb' + +# Offense count: 85 +# Configuration parameters: Blacklist. +# Blacklist: (?-mix:(^|\s)(EO[A-Z]{1}|END)(\s|$)) +Naming/HeredocDelimiterNaming: + Enabled: false + +# Offense count: 1 +# Configuration parameters: EnforcedStyleForLeadingUnderscores. +# SupportedStylesForLeadingUnderscores: disallowed, required, optional +Naming/MemoizedInstanceVariableName: + Exclude: + - 'lib/active_merchant/billing/compatibility.rb' + +# Offense count: 15 +# Configuration parameters: EnforcedStyle. +# SupportedStyles: snake_case, camelCase +Naming/MethodName: + Exclude: + - 'lib/active_merchant/billing/gateways/card_connect.rb' + - 'lib/active_merchant/billing/gateways/latitude19.rb' + - 'lib/active_merchant/billing/gateways/qbms.rb' + - 'test/remote/gateways/remote_card_connect_test.rb' + - 'test/remote/gateways/remote_card_stream_test.rb' + - 'test/remote/gateways/remote_fat_zebra_test.rb' + - 'test/remote/gateways/remote_sage_pay_test.rb' + - 'test/unit/gateways/sage_pay_test.rb' + +# Offense count: 5 +# Configuration parameters: NamePrefix, NamePrefixBlacklist, NameWhitelist, MethodDefinitionMacros. +# NamePrefix: is_, has_, have_ +# NamePrefixBlacklist: is_, has_, have_ +# NameWhitelist: is_a? +# MethodDefinitionMacros: define_method, define_singleton_method +Naming/PredicateName: + Exclude: + - 'spec/**/*' + - 'lib/active_merchant/billing/gateways/authorize_net.rb' + - 'lib/active_merchant/billing/gateways/payeezy.rb' + - 'lib/active_merchant/billing/gateways/paymill.rb' + - 'lib/active_merchant/billing/gateways/redsys.rb' + - 'lib/active_merchant/billing/gateways/sage_pay.rb' + +# Offense count: 14 +# Configuration parameters: MinNameLength, AllowNamesEndingInNumbers, AllowedNames, ForbiddenNames. +# AllowedNames: io, id, to, by, on, in, at, ip, db +Naming/UncommunicativeMethodParamName: + Exclude: + - 'lib/active_merchant/billing/gateways/blue_snap.rb' + - 'lib/active_merchant/billing/gateways/cyber_source.rb' + - 'lib/active_merchant/billing/gateways/iridium.rb' + - 'lib/active_merchant/billing/gateways/latitude19.rb' + - 'lib/active_merchant/billing/gateways/merchant_ware.rb' + - 'lib/active_merchant/billing/gateways/quantum.rb' + - 'lib/active_merchant/billing/gateways/worldpay_online_payments.rb' + - 'test/unit/gateways/paypal/paypal_common_api_test.rb' + - 'test/unit/gateways/realex_test.rb' + +# Offense count: 49 +# Configuration parameters: EnforcedStyle. +# SupportedStyles: snake_case, camelCase +Naming/VariableName: + Exclude: + - 'lib/active_merchant/billing/gateways/cyber_source.rb' + - 'lib/active_merchant/billing/gateways/iridium.rb' + - 'lib/active_merchant/billing/gateways/latitude19.rb' + - 'lib/active_merchant/billing/gateways/optimal_payment.rb' + - 'lib/active_merchant/billing/gateways/quantum.rb' + - 'lib/active_merchant/billing/gateways/worldpay_online_payments.rb' + - 'test/remote/gateways/remote_authorize_net_test.rb' + - 'test/remote/gateways/remote_card_stream_test.rb' + - 'test/remote/gateways/remote_worldpay_test.rb' + - 'test/unit/gateways/card_stream_test.rb' + - 'test/unit/gateways/worldpay_online_payments_test.rb' + +# Offense count: 11 +# Configuration parameters: EnforcedStyle. +# SupportedStyles: snake_case, normalcase, non_integer +Naming/VariableNumber: + Exclude: + - 'lib/active_merchant/billing/gateways/merchant_partners.rb' + - 'lib/active_merchant/billing/gateways/mercury.rb' + - 'lib/active_merchant/billing/gateways/orbital.rb' + - 'test/remote/gateways/remote_paypal_test.rb' + - 'test/unit/gateways/merchant_ware_test.rb' + - 'test/unit/gateways/merchant_ware_version_four_test.rb' + - 'test/unit/gateways/orbital_test.rb' + - 'test/unit/gateways/paypal/paypal_common_api_test.rb' + +# Offense count: 4 +# Cop supports --auto-correct. +Performance/RedundantMatch: + Exclude: + - 'lib/active_merchant/billing/gateways/opp.rb' + - 'test/unit/gateways/payu_latam_test.rb' + +# Offense count: 11 +# Cop supports --auto-correct. +Performance/StringReplacement: + Exclude: + - 'lib/active_merchant/billing/compatibility.rb' + - 'lib/active_merchant/billing/gateways/card_connect.rb' + - 'lib/active_merchant/billing/gateways/firstdata_e4.rb' + - 'lib/active_merchant/billing/gateways/merchant_ware.rb' + - 'lib/active_merchant/billing/gateways/merchant_ware_version_four.rb' + - 'lib/active_merchant/billing/gateways/orbital.rb' + - 'lib/active_merchant/billing/gateways/quickbooks.rb' + - 'lib/active_merchant/billing/gateways/quickpay/quickpay_v10.rb' + - 'lib/active_merchant/billing/gateways/realex.rb' + - 'test/unit/gateways/nab_transact_test.rb' + +# Offense count: 2 +# Configuration parameters: EnforcedStyle. +# SupportedStyles: inline, group +Style/AccessModifierDeclarations: + Exclude: + - 'test/unit/gateways/metrics_global_test.rb' + - 'test/unit/gateways/optimal_payment_test.rb' + +# Offense count: 11 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle. +# SupportedStyles: prefer_alias, prefer_alias_method +Style/Alias: + Exclude: + - 'lib/active_merchant/billing/gateways/beanstream.rb' + - 'lib/active_merchant/billing/gateways/braintree_blue.rb' + - 'lib/active_merchant/billing/gateways/inspire.rb' + - 'lib/active_merchant/billing/gateways/migs.rb' + - 'lib/active_merchant/billing/gateways/smart_ps.rb' + - 'lib/active_merchant/billing/gateways/spreedly_core.rb' + - 'lib/active_merchant/post_data.rb' + - 'test/unit/gateways/bpoint_test.rb' + - 'test/unit/gateways/paymentez_test.rb' + +# Offense count: 12 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle. +# SupportedStyles: always, conditionals +Style/AndOr: + Exclude: + - 'lib/active_merchant/billing/gateways/beanstream/beanstream_core.rb' + - 'lib/active_merchant/billing/gateways/eway.rb' + - 'lib/active_merchant/billing/gateways/iridium.rb' + - 'lib/active_merchant/billing/gateways/pac_net_raven.rb' + - 'lib/active_merchant/billing/gateways/smart_ps.rb' + - 'lib/active_merchant/billing/gateways/stripe.rb' + - 'lib/active_merchant/billing/gateways/webpay.rb' + +# Offense count: 47 +# Configuration parameters: AllowedChars. +Style/AsciiComments: + Exclude: + - 'lib/active_merchant/billing/gateways/authorize_net_arb.rb' + - 'lib/active_merchant/billing/gateways/authorize_net_cim.rb' + - 'lib/active_merchant/billing/gateways/beanstream/beanstream_core.rb' + - 'lib/active_merchant/billing/gateways/eway_rapid.rb' + - 'lib/active_merchant/billing/gateways/netbanx.rb' + - 'lib/active_merchant/billing/gateways/ogone.rb' + - 'lib/active_merchant/billing/gateways/orbital.rb' + - 'lib/active_merchant/billing/gateways/payflow_express.rb' + - 'lib/active_merchant/billing/gateways/paystation.rb' + - 'lib/active_merchant/billing/gateways/psl_card.rb' + - 'lib/active_merchant/billing/gateways/sage.rb' + - 'test/remote/gateways/remote_data_cash_test.rb' + - 'test/remote/gateways/remote_nab_transact_test.rb' + +# Offense count: 1 +# Cop supports --auto-correct. +Style/Attr: + Exclude: + - 'test/unit/gateways/forte_test.rb' + +# Offense count: 2 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle. +# SupportedStyles: percent_q, bare_percent +Style/BarePercentLiterals: + Exclude: + - 'test/unit/gateways/eway_rapid_test.rb' + - 'test/unit/gateways/orbital_test.rb' + +# Offense count: 3 +# Cop supports --auto-correct. +Style/BlockComments: + Exclude: + - 'test/remote/gateways/remote_barclays_epdq_extra_plus_test.rb' + - 'test/remote/gateways/remote_netpay_test.rb' + - 'test/remote/gateways/remote_payu_in_test.rb' + +# Offense count: 77 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle, ProceduralMethods, FunctionalMethods, IgnoredMethods. +# SupportedStyles: line_count_based, semantic, braces_for_chaining +# ProceduralMethods: benchmark, bm, bmbm, create, each_with_object, measure, new, realtime, tap, with_object +# FunctionalMethods: let, let!, subject, watch +# IgnoredMethods: lambda, proc, it +Style/BlockDelimiters: + Enabled: false + +# Offense count: 440 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle. +# SupportedStyles: braces, no_braces, context_dependent +Style/BracesAroundHashParameters: + Enabled: false + +# Offense count: 2 +Style/CaseEquality: + Exclude: + - 'lib/active_merchant/billing/gateways/braintree_blue.rb' + - 'test/test_helper.rb' + +# Offense count: 2 +# Cop supports --auto-correct. +# Configuration parameters: AutoCorrect, EnforcedStyle. +# SupportedStyles: nested, compact +Style/ClassAndModuleChildren: + Exclude: + - 'test/unit/gateways/optimal_payment_test.rb' + - 'test/unit/gateways/realex_test.rb' + +# Offense count: 30 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle. +# SupportedStyles: is_a?, kind_of? +Style/ClassCheck: + Enabled: false + +# Offense count: 8 +Style/ClassVars: + Exclude: + - 'lib/active_merchant/billing/base.rb' + - 'lib/active_merchant/billing/gateway.rb' + - 'lib/active_merchant/billing/gateways/balanced.rb' + - 'lib/active_merchant/billing/gateways/cyber_source.rb' + - 'test/remote/gateways/remote_cams_test.rb' + - 'test/test_helper.rb' + +# Offense count: 10 +# Cop supports --auto-correct. +Style/ColonMethodCall: + Exclude: + - 'lib/active_merchant/billing/gateways/blue_pay.rb' + - 'lib/active_merchant/billing/gateways/cashnet.rb' + - 'lib/active_merchant/billing/gateways/credorax.rb' + - 'lib/active_merchant/billing/gateways/epay.rb' + - 'lib/active_merchant/billing/gateways/evo_ca.rb' + - 'lib/active_merchant/billing/gateways/ezic.rb' + - 'lib/active_merchant/billing/gateways/migs.rb' + - 'lib/active_merchant/billing/gateways/nmi.rb' + - 'test/unit/gateways/quickpay_v4to7_test.rb' + +# Offense count: 5 +# Cop supports --auto-correct. +# Configuration parameters: Keywords. +# Keywords: TODO, FIXME, OPTIMIZE, HACK, REVIEW +Style/CommentAnnotation: + Exclude: + - 'test/remote/gateways/remote_usa_epay_advanced_test.rb' + - 'test/unit/gateways/authorize_net_cim_test.rb' + - 'test/unit/gateways/usa_epay_advanced_test.rb' + +# Offense count: 8 +Style/CommentedKeyword: + Exclude: + - 'lib/active_merchant/billing/gateways/blue_pay.rb' + - 'lib/active_merchant/billing/gateways/usa_epay_advanced.rb' + - 'lib/active_merchant/errors.rb' + - 'test/remote/gateways/remote_cardknox_test.rb' + - 'test/unit/gateways/cardknox_test.rb' + +# Offense count: 22 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle, SingleLineConditionsOnly, IncludeTernaryExpressions. +# SupportedStyles: assign_to_condition, assign_inside_condition +Style/ConditionalAssignment: + Enabled: false + +# Offense count: 7 +# Configuration parameters: AllowCoercion. +Style/DateTime: + Exclude: + - 'test/remote/gateways/remote_first_pay_test.rb' + - 'test/remote/gateways/remote_pin_test.rb' + - 'test/remote/gateways/remote_trexle_test.rb' + - 'test/unit/gateways/orbital_test.rb' + - 'test/unit/gateways/paypal/paypal_common_api_test.rb' + +# Offense count: 211 +Style/Documentation: + Enabled: false + +# Offense count: 3 +Style/DoubleNegation: + Exclude: + - 'lib/active_merchant/billing/gateways/balanced.rb' + - 'lib/active_merchant/billing/gateways/netbilling.rb' + - 'lib/active_merchant/billing/gateways/pay_secure.rb' + +# Offense count: 18 +# Cop supports --auto-correct. +Style/EachWithObject: + Exclude: + - 'lib/active_merchant/billing/avs_result.rb' + - 'lib/active_merchant/billing/gateways/beanstream/beanstream_core.rb' + - 'lib/active_merchant/billing/gateways/cams.rb' + - 'lib/active_merchant/billing/gateways/ezic.rb' + - 'lib/active_merchant/billing/gateways/federated_canada.rb' + - 'lib/active_merchant/billing/gateways/merchant_one.rb' + - 'lib/active_merchant/billing/gateways/micropayment.rb' + - 'lib/active_merchant/billing/gateways/money_movers.rb' + - 'lib/active_merchant/billing/gateways/orbital.rb' + - 'lib/active_merchant/billing/gateways/payu_in.rb' + - 'lib/active_merchant/billing/gateways/usa_epay_advanced.rb' + - 'lib/active_merchant/billing/model.rb' + - 'test/test_helper.rb' + - 'test/unit/gateways/authorize_net_test.rb' + +# Offense count: 6 +# Cop supports --auto-correct. +Style/EmptyCaseCondition: + Exclude: + - 'lib/active_merchant/billing/gateways/inspire.rb' + - 'lib/active_merchant/billing/gateways/payflow/payflow_common_api.rb' + - 'lib/active_merchant/billing/gateways/smart_ps.rb' + - 'lib/active_merchant/billing/gateways/usa_epay_advanced.rb' + +# Offense count: 4 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle. +# SupportedStyles: empty, nil, both +Style/EmptyElse: + Exclude: + - 'lib/active_merchant/billing/gateways/fat_zebra.rb' + - 'lib/active_merchant/billing/gateways/mercado_pago.rb' + - 'lib/active_merchant/billing/gateways/payeezy.rb' + - 'lib/active_merchant/billing/gateways/payment_express.rb' + +# Offense count: 5 +# Cop supports --auto-correct. +Style/EmptyLiteral: + Exclude: + - 'lib/active_merchant/billing/gateways/element.rb' + - 'lib/active_merchant/billing/gateways/itransact.rb' + - 'lib/active_merchant/billing/gateways/kushki.rb' + - 'lib/active_merchant/billing/gateways/transact_pro.rb' + - 'test/unit/gateways/paypal_digital_goods_test.rb' + +# Offense count: 14 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle. +# SupportedStyles: compact, expanded +Style/EmptyMethod: + Exclude: + - 'lib/active_merchant/billing/gateways/qbms.rb' + - 'lib/active_merchant/billing/gateways/usa_epay_advanced.rb' + - 'test/remote/gateways/remote_ncr_secure_pay_test.rb' + - 'test/unit/gateways/card_connect_test.rb' + - 'test/unit/gateways/cardknox_test.rb' + - 'test/unit/gateways/latitude19_test.rb' + - 'test/unit/gateways/world_net_test.rb' + - 'test/unit/gateways/worldpay_online_payments_test.rb' + +# Offense count: 23 +# Cop supports --auto-correct. +Style/Encoding: + Enabled: false + +# Offense count: 2 +Style/EvalWithLocation: + Exclude: + - 'lib/active_merchant/billing/credit_card.rb' + - 'lib/active_merchant/billing/response.rb' + +# Offense count: 5 +# Cop supports --auto-correct. +Style/ExpandPathArguments: + Exclude: + - 'Rakefile' + - 'activemerchant.gemspec' + - 'script/generate' + - 'test/test_helper.rb' + +# Offense count: 11 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle. +# SupportedStyles: each, for +Style/For: + Exclude: + - 'lib/active_merchant/billing/gateways/cardknox.rb' + - 'lib/active_merchant/billing/gateways/linkpoint.rb' + - 'lib/active_merchant/billing/gateways/merchant_one.rb' + - 'lib/active_merchant/billing/gateways/psl_card.rb' + - 'lib/active_merchant/billing/gateways/usa_epay_transaction.rb' + - 'test/remote/gateways/remote_orbital_test.rb' + +# Offense count: 97 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle. +# SupportedStyles: format, sprintf, percent +Style/FormatString: + Enabled: false + +# Offense count: 22 +# Configuration parameters: EnforcedStyle. +# SupportedStyles: annotated, template, unannotated +Style/FormatStringToken: + Exclude: + - 'lib/active_merchant/billing/gateways/redsys.rb' + - 'lib/active_merchant/connection.rb' + - 'lib/active_merchant/network_connection_retries.rb' + - 'test/remote/gateways/remote_balanced_test.rb' + - 'test/remote/gateways/remote_openpay_test.rb' + - 'test/unit/gateways/balanced_test.rb' + - 'test/unit/gateways/elavon_test.rb' + - 'test/unit/gateways/exact_test.rb' + - 'test/unit/gateways/firstdata_e4_test.rb' + - 'test/unit/gateways/safe_charge_test.rb' + +# Offense count: 679 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle. +# SupportedStyles: when_needed, always, never +Style/FrozenStringLiteralComment: + Enabled: false + +# Offense count: 5 +# Configuration parameters: AllowedVariables. +Style/GlobalVars: + Exclude: + - 'test/remote/gateways/remote_finansbank_test.rb' + - 'test/remote/gateways/remote_garanti_test.rb' + - 'test/remote/gateways/remote_secure_pay_tech_test.rb' + - 'test/unit/gateways/finansbank_test.rb' + - 'test/unit/gateways/garanti_test.rb' + +# Offense count: 196 +# Configuration parameters: MinBodyLength. +Style/GuardClause: + Enabled: false + +# Offense count: 7482 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle, UseHashRocketsWithSymbolValues, PreferHashRocketsForNonAlnumEndingSymbols. +# SupportedStyles: ruby19, hash_rockets, no_mixed_keys, ruby19_no_mixed_keys +Style/HashSyntax: + Enabled: false + +# Offense count: 6 +Style/IdenticalConditionalBranches: + Exclude: + - 'lib/active_merchant/billing/gateways/elavon.rb' + - 'lib/active_merchant/billing/gateways/litle.rb' + - 'lib/active_merchant/billing/gateways/payu_latam.rb' + +# Offense count: 14 +Style/IfInsideElse: + Exclude: + - 'lib/active_merchant/billing/credit_card.rb' + - 'lib/active_merchant/billing/gateways/authorize_net.rb' + - 'lib/active_merchant/billing/gateways/cecabank.rb' + - 'lib/active_merchant/billing/gateways/element.rb' + - 'lib/active_merchant/billing/gateways/eway_managed.rb' + - 'lib/active_merchant/billing/gateways/global_collect.rb' + - 'lib/active_merchant/billing/gateways/iridium.rb' + - 'lib/active_merchant/billing/gateways/quantum.rb' + - 'lib/active_merchant/billing/gateways/skip_jack.rb' + - 'lib/active_merchant/billing/gateways/worldpay_online_payments.rb' + +# Offense count: 128 +# Cop supports --auto-correct. +Style/IfUnlessModifier: + Enabled: false + +# Offense count: 1 +Style/IfUnlessModifierOfIfUnless: + Exclude: + - 'lib/active_merchant/billing/gateways/merchant_e_solutions.rb' + +# Offense count: 2 +# Cop supports --auto-correct. +# Configuration parameters: InverseMethods, InverseBlocks. +Style/InverseMethods: + Exclude: + - 'lib/active_merchant/billing/gateways/ogone.rb' + - 'lib/active_merchant/billing/gateways/worldpay.rb' + +# Offense count: 32 +# Cop supports --auto-correct. +# Configuration parameters: IgnoredMethods. +Style/MethodCallWithoutArgsParentheses: + Enabled: false + +# Offense count: 656 +Style/MultilineBlockChain: + Enabled: false + +# Offense count: 15 +# Cop supports --auto-correct. +Style/MultilineIfModifier: + Exclude: + - 'lib/active_merchant/billing/compatibility.rb' + - 'lib/active_merchant/billing/gateways/authorize_net_cim.rb' + - 'lib/active_merchant/billing/gateways/bank_frick.rb' + - 'lib/active_merchant/billing/gateways/cenpos.rb' + - 'lib/active_merchant/billing/gateways/efsnet.rb' + - 'lib/active_merchant/billing/gateways/eway.rb' + - 'lib/active_merchant/billing/gateways/flo2cash.rb' + - 'lib/active_merchant/billing/gateways/itransact.rb' + - 'lib/active_merchant/billing/gateways/monei.rb' + - 'lib/active_merchant/billing/gateways/optimal_payment.rb' + - 'lib/active_merchant/billing/gateways/payflow/payflow_common_api.rb' + - 'lib/active_merchant/billing/gateways/psigate.rb' + - 'lib/active_merchant/billing/gateways/realex.rb' + +# Offense count: 6 +# Cop supports --auto-correct. +Style/MultilineIfThen: + Exclude: + - 'lib/active_merchant/billing/gateways/eway_managed.rb' + +# Offense count: 4 +Style/MultilineTernaryOperator: + Exclude: + - 'lib/active_merchant/billing/gateways/merchant_partners.rb' + - 'lib/active_merchant/billing/gateways/ogone.rb' + - 'lib/active_merchant/billing/gateways/swipe_checkout.rb' + - 'lib/active_merchant/billing/gateways/transact_pro.rb' + +# Offense count: 1 +Style/MultipleComparison: + Exclude: + - 'lib/active_merchant/billing/gateways/worldpay_online_payments.rb' + +# Offense count: 530 +# Cop supports --auto-correct. +Style/MutableConstant: + Enabled: false + +# Offense count: 17 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle. +# SupportedStyles: both, prefix, postfix +Style/NegatedIf: + Exclude: + - 'lib/active_merchant/billing/credit_card.rb' + - 'lib/active_merchant/billing/gateways/adyen.rb' + - 'lib/active_merchant/billing/gateways/itransact.rb' + - 'lib/active_merchant/billing/gateways/iveri.rb' + - 'lib/active_merchant/billing/gateways/ogone.rb' + - 'lib/active_merchant/billing/gateways/orbital.rb' + - 'lib/active_merchant/billing/gateways/qbms.rb' + - 'lib/active_merchant/billing/gateways/worldpay.rb' + - 'lib/support/ssl_verify.rb' + - 'test/remote/gateways/remote_paypal_test.rb' + +# Offense count: 1 +# Cop supports --auto-correct. +Style/NestedModifier: + Exclude: + - 'lib/active_merchant/billing/gateways/merchant_e_solutions.rb' + +# Offense count: 2 +# Cop supports --auto-correct. +# Configuration parameters: Whitelist. +# Whitelist: be, be_a, be_an, be_between, be_falsey, be_kind_of, be_instance_of, be_truthy, be_within, eq, eql, end_with, include, match, raise_error, respond_to, start_with +Style/NestedParenthesizedCalls: + Exclude: + - 'lib/active_merchant/billing/gateways/quickpay/quickpay_v10.rb' + +# Offense count: 2 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle, MinBodyLength. +# SupportedStyles: skip_modifier_ifs, always +Style/Next: + Exclude: + - 'lib/active_merchant/billing/gateways/authorize_net.rb' + - 'lib/support/outbound_hosts.rb' + +# Offense count: 5 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle. +# SupportedStyles: predicate, comparison +Style/NilComparison: + Exclude: + - 'lib/active_merchant/billing/gateways/card_stream.rb' + - 'lib/active_merchant/billing/gateways/litle.rb' + - 'lib/active_merchant/billing/gateways/telr.rb' + - 'test/unit/gateways/braintree_blue_test.rb' + - 'test/unit/gateways/stripe_test.rb' + +# Offense count: 1 +# Cop supports --auto-correct. +# Configuration parameters: IncludeSemanticChanges. +Style/NonNilCheck: + Exclude: + - 'lib/active_merchant/billing/gateways/usa_epay_advanced.rb' + +# Offense count: 4 +# Cop supports --auto-correct. +Style/Not: + Exclude: + - 'test/remote/gateways/remote_paypal_test.rb' + - 'test/test_helper.rb' + - 'test/unit/gateways/braintree_blue_test.rb' + +# Offense count: 19 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedOctalStyle. +# SupportedOctalStyles: zero_with_o, zero_only +Style/NumericLiteralPrefix: + Exclude: + - 'lib/active_merchant/billing/gateways/psl_card.rb' + - 'test/remote/gateways/remote_axcessms_test.rb' + - 'test/remote/gateways/remote_cecabank_test.rb' + - 'test/remote/gateways/remote_cenpos_test.rb' + - 'test/remote/gateways/remote_culqi_test.rb' + - 'test/remote/gateways/remote_litle_certification_test.rb' + - 'test/remote/gateways/remote_opp_test.rb' + - 'test/remote/gateways/remote_pay_junction_v2_test.rb' + - 'test/remote/gateways/remote_tns_test.rb' + - 'test/unit/credit_card_formatting_test.rb' + - 'test/unit/gateways/axcessms_test.rb' + - 'test/unit/gateways/opp_test.rb' + - 'test/unit/gateways/pay_junction_v2_test.rb' + +# Offense count: 466 +# Cop supports --auto-correct. +# Configuration parameters: Strict. +Style/NumericLiterals: + MinDigits: 17 + +# Offense count: 41 +# Cop supports --auto-correct. +# Configuration parameters: AutoCorrect, EnforcedStyle, IgnoredMethods. +# SupportedStyles: predicate, comparison +Style/NumericPredicate: + Enabled: false + +# Offense count: 1 +# Cop supports --auto-correct. +Style/OrAssignment: + Exclude: + - 'lib/active_merchant/billing/gateways/net_registry.rb' + +# Offense count: 24 +# Cop supports --auto-correct. +Style/ParallelAssignment: + Enabled: false + +# Offense count: 879 +# Cop supports --auto-correct. +# Configuration parameters: PreferredDelimiters. +Style/PercentLiteralDelimiters: + Enabled: false + +# Offense count: 6 +# Cop supports --auto-correct. +Style/PerlBackrefs: + Exclude: + - 'lib/active_merchant/billing/gateways/qvalent.rb' + - 'lib/active_merchant/billing/gateways/sage_pay.rb' + - 'lib/support/outbound_hosts.rb' + - 'test/unit/gateways/payu_in_test.rb' + +# Offense count: 96 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle. +# SupportedStyles: short, verbose +Style/PreferredHashMethods: + Enabled: false + +# Offense count: 2 +# Cop supports --auto-correct. +Style/Proc: + Exclude: + - 'test/unit/credit_card_methods_test.rb' + - 'test/unit/gateways/nab_transact_test.rb' + +# Offense count: 31 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle. +# SupportedStyles: compact, exploded +Style/RaiseArgs: + Enabled: false + +# Offense count: 86 +# Cop supports --auto-correct. +# Configuration parameters: AllowMultipleReturnValues. +Style/RedundantReturn: + Enabled: false + +# Offense count: 179 +# Cop supports --auto-correct. +Style/RedundantSelf: + Enabled: false + +# Offense count: 1209 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle, AllowInnerSlashes. +# SupportedStyles: slashes, percent_r, mixed +Style/RegexpLiteral: + Enabled: false + +# Offense count: 15 +# Cop supports --auto-correct. +Style/RescueModifier: + Exclude: + - 'lib/active_merchant/billing/gateways/clearhaus.rb' + - 'lib/active_merchant/billing/gateways/cyber_source.rb' + - 'lib/active_merchant/billing/gateways/jetpay.rb' + - 'lib/active_merchant/billing/gateways/jetpay_v2.rb' + - 'lib/active_merchant/billing/gateways/optimal_payment.rb' + - 'lib/active_merchant/billing/gateways/payflow/payflow_response.rb' + - 'lib/active_merchant/billing/gateways/sage.rb' + - 'lib/active_merchant/billing/gateways/secure_pay.rb' + - 'lib/active_merchant/billing/gateways/telr.rb' + - 'test/remote/gateways/remote_secure_pay_au_test.rb' + +# Offense count: 1 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle. +# SupportedStyles: implicit, explicit +Style/RescueStandardError: + Exclude: + - 'lib/active_merchant/billing/base.rb' + +# Offense count: 2 +# Cop supports --auto-correct. +Style/SelfAssignment: + Exclude: + - 'lib/active_merchant/billing/credit_card.rb' + - 'lib/active_merchant/billing/gateways/barclaycard_smartpay.rb' + +# Offense count: 7 +# Cop supports --auto-correct. +# Configuration parameters: AllowAsExpressionSeparator. +Style/Semicolon: + Exclude: + - 'lib/active_merchant/billing/gateways/ezic.rb' + - 'lib/active_merchant/billing/gateways/merchant_one.rb' + - 'lib/active_merchant/billing/gateways/usa_epay_advanced.rb' + - 'test/remote/gateways/remote_orbital_test.rb' + - 'test/unit/gateways/cardknox_test.rb' + - 'test/unit/gateways/omise_test.rb' + +# Offense count: 2 +# Cop supports --auto-correct. +# Configuration parameters: AllowIfMethodIsEmpty. +Style/SingleLineMethods: + Exclude: + - 'test/unit/gateways/paypal/paypal_common_api_test.rb' + +# Offense count: 3 +# Cop supports --auto-correct. +# Configuration parameters: . +# SupportedStyles: use_perl_names, use_english_names +Style/SpecialGlobalVars: + EnforcedStyle: use_perl_names + +# Offense count: 27 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle. +# SupportedStyles: single_quotes, double_quotes +Style/StringLiteralsInInterpolation: + Exclude: + - 'lib/active_merchant/billing/gateways/banwire.rb' + - 'lib/active_merchant/billing/gateways/cams.rb' + - 'lib/active_merchant/billing/gateways/checkout_v2.rb' + - 'lib/active_merchant/billing/gateways/credorax.rb' + - 'lib/active_merchant/billing/gateways/digitzs.rb' + - 'lib/active_merchant/billing/gateways/ebanx.rb' + - 'lib/active_merchant/billing/gateways/merchant_one.rb' + - 'lib/active_merchant/billing/gateways/micropayment.rb' + - 'lib/active_merchant/billing/gateways/pagarme.rb' + - 'lib/active_merchant/billing/gateways/quickpay/quickpay_v10.rb' + - 'lib/active_merchant/billing/gateways/stripe.rb' + - 'lib/active_merchant/billing/gateways/usa_epay_advanced.rb' + - 'lib/active_merchant/billing/gateways/worldpay.rb' + - 'test/unit/gateways/eway_managed_test.rb' + +# Offense count: 309 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle, MinSize. +# SupportedStyles: percent, brackets +Style/SymbolArray: + Enabled: false + +# Offense count: 7 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyleForMultiline. +# SupportedStylesForMultiline: comma, consistent_comma, no_comma +Style/TrailingCommaInArrayLiteral: + Exclude: + - 'lib/active_merchant/billing/credit_card_methods.rb' + - 'test/unit/gateways/netaxept_test.rb' + - 'test/unit/gateways/usa_epay_transaction_test.rb' + +# Offense count: 160 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyleForMultiline. +# SupportedStylesForMultiline: comma, consistent_comma, no_comma +Style/TrailingCommaInHashLiteral: + Enabled: false + +# Offense count: 38 +# Cop supports --auto-correct. +# Configuration parameters: AllowNamedUnderscoreVariables. +Style/TrailingUnderscoreVariable: + Enabled: false + +# Offense count: 119 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle, MinSize, WordRegex. +# SupportedStyles: percent, brackets +Style/WordArray: + Enabled: false + +# Offense count: 34 +# Cop supports --auto-correct. +Style/ZeroLengthPredicate: + Enabled: false + +# Offense count: 9321 +# Configuration parameters: AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, IgnoredPatterns. +# URISchemes: http, https +Metrics/LineLength: + Max: 2602 diff --git a/.travis.yml b/.travis.yml index d0e49bc6109..e2207604777 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,24 +1,29 @@ language: ruby -script: "bundle exec rake test:units" sudo: false cache: bundler rvm: -- 2.1 -- 2.2.3 -- 2.3.3 +- 2.5 +- 2.4 +- 2.3 gemfile: -- Gemfile.rails32 -- Gemfile.rails40 -- Gemfile.rails41 -- Gemfile.rails42 -- Gemfile.rails5 +- gemfiles/Gemfile.rails52 +- gemfiles/Gemfile.rails51 +- gemfiles/Gemfile.rails50 +- gemfiles/Gemfile.rails42 +- gemfiles/Gemfile.rails_master + +jobs: + include: + rvm: 2.5 + gemfile: Gemfile + script: bundle exec rubocop --parallel matrix: exclude: - - rvm: 2.1 - gemfile: Gemfile.rails5 + - rvm: 2.3 + gemfile: 'gemfiles/Gemfile.rails_master' notifications: email: diff --git a/CHANGELOG b/CHANGELOG index 24ab9f1f460..1e421bcda0c 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,19 +1,543 @@ = ActiveMerchant CHANGELOG == HEAD +* Worldpay: handle Visa and MasterCard payouts differently [bpollack] #3068 +* QuickPay: update supported countries [ta] #3049 +* WorldPay: set cardholder name to "3D" for 3DS transactions [bpollack] #3071 +* Authorize.Net: Support refunds for bank accounts [nfarve] #3063 +* Stripe: support specifying a reason for refunds [yosukehasumi] #3056 +* TrustCommerce: Add ACH Ability [nfarve] #3073 +* Payeezy: Support $0 for verify transactions [molbrown] #3074 +* USA ePay: add support for recurring transactions, custom fields, and line items [lancecarlson] #3069 + +== Version 1.88.0 (November 30, 2018) +* Added ActiveSupport/Rails master support [Edouard-chin] #3065 + +== Version 1.87.0 (November 29, 2018) +* Barclaycard Smartpay: Improves Error Handling [deedeelavinder] #3026 +* Braintree: Fix passing phone-only billing address [curiousepic] #3025 +* Litle: Capitalize check account type [curiousepic] #3028 +* Braintree: Account for nil billing address fields [curiousepic] #3029 +* Realex: Add verify [kheang] #3030 +* Braintree: Actually account for nil address fields [curiousepic] #3032 +* Mercado Pago: do not infer card type [bpollack] #3038 +* Credorax: allow sending submerchant ID (h3 parameter) [bpollack] #3040 +* Worldpay: Pass stored credential option fields [curiousepic] #3041 +* Make behavior of nil CC numbers more consistent [guaguasi] #3010 +* Moneris: Adds Credential on File logic [deedeelavinder] #3042 +* Adyen: Return AVS and CVC Result [nfarve] #3044 +* Paymentez: Supports phone field, does not send if empty [molbrown] #3043 +* Braintree: Account for nil address with existing customer [curiousepic] #3047 +* Optimal Payment: Add verify capabilities #3052 +* Moneris: Allows cof_enabled gateway to process non-cof transactions [deedeelavinder] #3051 +* Cenpos: update supported countries [bpollack] #3055 +* CyberSource: update supported countries [bpollack] #3055 +* MiGS: update supported countries [bpollack] #3055 +* Clearhaus: update submission data format [bpollack] #3053 +* Forte: Allow void on capture [nfarve] #3059 + +== Version 1.86.0 (October 26, 2018) +* UsaEpayTransaction: Support UMcheckformat option for echecks [dtykocki] #3002 +* Global Collect: handle internal server errors [molbrown] #3005 +* Barclaycard Smartpay: allow third-party payouts for credits [bpollack] #3009 +* RuboCop: AlignHash [nfarve] #3004 +* Beanstream: Switch `recurringPayment` flag from boolean to integer [dtykocki] #3011 +* Update Swipe HQ endpoint [bdewater] #3013 +* Braintree: Adds device_data [deedeelavinder] #3012 +* Payflow Express: Add phone to returned Response [filipebarcos] #3003 +* Authorize.Net: Pass some level 3 fields [curiousepic] #3022 +* Add state to the netbanx payload [Girardvjonathan] #3024 + +== Version 1.85.0 (September 28, 2018) +* Authorize.Net: Support custom delimiter for cim [curiousepic] #3001 + +== Version 1.84.0 (September 27, 2018) +* PayU Latam: support partial captures [bpollack] #2974 +* Braintree: Reflect correct test mode in Braintree responses [elfassy] #2980 +* FirstPay: Expose error code [curiousepic] #2979 +* Barclaycard Smartpay: Pass device_fingerprint when specified [dtykocki] #2981 +* Komoju: remove no-longer-relevant sandbox URL [miyazawadegica] #2987 +* [POSSIBLE BREAKAGE] Determine credit cards via functions [bpollack] #2983 +* Drop support for Laser cards [bpollack] #2983 +* Improve Maestro card detection [bpollack] #2983 +* Add ROU alpha3 code for Romania [dtykocki] #2989 +* [POSSIBLE BREAKAGE] Drop support for Solo and Switch cards [bpollack] #2991 +* Add support for Carnet cards [bpollack] #2992 +* Stripe: support a reason for voiding a transaction [whitby3001] #2378 +* Payeezy: Add reversal_id in support of timeout reversals [dtykocki] #2997 +* Stripe: support Level 3 transaction fields [bpollack] #2996 +* Conekta: support Carnet cards [bpollack] #2999 +* Openpay: support Carnet cards [bpollack] #2999 +* Adyen: Add support for GooglePay [dtykocki] #2971 + +== Version 1.83.0 (August 30, 2018) +* CT Payment: Update How Address is Passed [nfarve] #2960 +* Adyen: Add RecurringProcessingModel [nfarve] #2951 +* Optimal Payments: update country list [bpollack] #2961 +* Ebanx: update sandbox and production URLs [vnbrs] #2949 +* Ebanx: support additional countries [vnbrs] #2950 +* Gateway generator: fix a typo that would cause the script to crash [bpollack] #2962 +* Clearhaus: use $0 for verify transactions [bpollack] #2964 +* Global Collect: properly handle partial captures [bpollack] #2967 +* Braintree: Add support for GooglePay [dtykocki] #2966 +* Adyen: allow overriding card brands [bpollack] #2968 +* Adyen: allow custom routing [bpollack] #2969 +* First Pay: Adds scrubbing [deedeelavinder] #2972 + +== Version 1.82.0 (August 13, 2018) +* FirstData: add support for WalletProviderID in v27 gateway [bpollack] #2946 +* BlueSnap: Handle 403 responses [curiousepic] #2948 +* BlueSnap: Add StoreCard Field [nfarve] #2953 +* Worldpay: support installments [bpollack] #2957 +* Paymentez: support partial refunds [bpollack] #2959 +* Payflow: allow support for partial captures [pi3r] #2952 + +== Version 1.81.0 (July 30, 2018) +* GlobalCollect: Don't overwrite contactDetails [curiousepic] #2915 +* Pin Payments: Pass reference for statement desc [curiousepic] #2919 +* FirstData: introduce v27 gateway [shasum] #2912 +* Stripe: Fix contactless magstripe support [abhiin1947] #2917 +* ANET: Expose full response code [curiousepic] #2924 +* Global Collect: Fix customer data field structure [curiousepic] #2929 +* Adyen: Set Default Name for Apple Pay Transactions [nfarve] #2930 +* Beanstream: Update to use api key with login credentials [nfarve] #2934 +* CT Payments: Fix a typo in the live URL scheme [bpollack] #2936 +* CyberSource: Don't throw exceptions on HTML responses [bpollack] #2937 +* CyberSource: Remove extraneous parameter blocking echecks [chriscz] #2861 +* FirstPay: Update Fields For Recurring Payments [nfarve] #2940 +* Remove unused handle_response method [bl] #2309 +* Barclaycard Smartpay: bump API version to v30 [bpollack] #2941 +* Safecharge: Remove duplicate supported country [curiousepic] +* Payflow Express: Use SHIPTONAME instead of `full_name` for shipping address [filipebarcos] #2945 + +== Version 1.80.0 (July 4, 2018) +* Default SSL min_version to TLS 1.1 to comply with June 30 PCI DSS deadline [bdewater] #2909 +* Paymentez: return a Result object even when the upstream server 500s [bpollack] #2871 +* Drop support for Ruby versions older than 2.3 [bpollack] #2863 +* Bridge Pay: don't throw an exception when bank account type is omitted [bpollack] #2873 +* Avoid making actual connections in Blue Snap and Mundipagg unit tests [bpollack] #2875 +* Avoid making actual connections in the connection unit tests [bpollack] #2876 +* Openpay: support payment installments [bpollack] #2865 +* First Pay: support recurring charges [bpollack] #2877 +* Bridge Pay: pass full name of account type for echeck transactions [bpollack] #2878 +* Kushki: do not send 0 for tax values if tax values are not provided [bpollack] #2886 +* Payflow: Update ACH tests [curiousepic] #2887 +* Credorax: support passing billing description [bpollack] #2889 +* MiGS: scrub 3DS fields [abarrak] #2771 +* Forte: avoid crashing when location_id or account_id have spaces [bpollack] #2890 +* Adyen: Support Network Tokenization Cards via mpiData fields [curiousepic] #2891 +* Moneris US: Add ACH [nfarve] #2888 +* Realex: Pass amount for captures [curiousepic] #2895 +* Card Connect: support storing cards [bpollack] #2896 +* Avoid mutating headers passed in for Active Merchant connections [grantbdev] #2892 +* Forte: add support for refunds [bpollack] #2898 +* Forte: fix a bug in logic for selecting billing names [whitby3001] #2381 +* Paymentez: allow capture amount to exceed authorization amount [bpollack] #2900 +* JetPay: fix typo in error messages [reynhout] #2749 +* Braintree: add support for Maestro cards [matthewheath] #2571 +* Visanet Peru: Refund on unsettled transactions [nfarve] #2772 +* Remove iDeal offsite gateway references [bdewater] #2807 +* Conekta: Allow customer application in headers [curiousepic] #2908 +* Payment Express: use testing URLs when testing [oklas] #2231 +* Redsys: Fix payments with cc token [Leonardo Diez] #2586 +* Redsys: Missing cardnumber params in xml_signed_fields [nerburish] #2628 +* Bogus: allow authorizing with a tokenized card [Azdaroth] #2703 +* CT Payment: Add new gateway [nfarve] #2911 + +== Version 1.79.2 (June 2, 2018) +* Fix Gateway#max_version= overwriting min_version [bdewater] + +== Version 1.79.1 (May 31, 2018) +* Fix Net::HTTP connections defaulting to connection: keep-alive instead of close since #2862 [bpollack] #2868 +* Mundipagg: allow passing holder_document for credit card purchases [bpollack] #2864 +* Conekta: support monthly_installments [bpollack] #2866 +* Authorize.net: allow sending email_customer set to false [bpollack] #2867 + +== Version 1.79.0 (May 30, 2018) +* Allow setting min/max SSL version for a connection on Ruby 2.5 [bdewater] #2775 +* Add `gateways:ssl:min_version` rake task to test upcoming TLS 1.0 deprecation deadline [bdewater] #2775 +* Log negotiated SSL version and cipher [bdewater + methodmissing] #2862 +* Remove support for Rails < 4.2, add support for Rails 5.2 and Ruby 2.5 [bdewater] +* Spreedly: Support verify and find transactions [abarrak] #2798 +* Adyen: Support merchant-specific subdomains [curiousepic] #2799 +* Fix ENV based configuration of Net::Http for proxies [bbergstrom] #2800 +* ANET: Withhold cryptogram for credit [curiousepic] #2804 +* Borgun: Remove batch from request parameters [deedeelavinder] #2805 +* WorldPay: Remove Inquiry requests in verify transactions [nfarve] #2802 +* Credorax: Update tests [curiousepic] #2809 +* Braintree: Remove decimal for non-fractional currencies [nfarve] #2806 +* Realex: Add documented country support for US and CA [a-salty-strudel] #2810 +* Paymentez: Add `tax_percentage` optional parameter [deedeelavinder] #2814 +* Braintree: Add `skip_advanced_fraud_checking` optional parameter [deedeelavinder] #2811 +* SafeCharge: Additional gateway options [dtykocki] #2816 +* FirstPay: Handle missing billing addresses [dtykocki] #2822 +* Realex: Add ApplePay Support [nfarve] #2820 +* Checkout V2: Additional gateway options [dtykocki] #2821 +* CyberSource: Support 3ds validate request [curiousepic] #2823 +* Paymentez: Remove card tokenization step from authorize [dtykocki] #2825 +* WorldPay: Add 3DS [nfarve] #2819 +* EBANX: Interpolate authorization string [curiousepic] #2830 +* CyberSource: Support 3DS validation for authorize [curiousepic] #2832 +* Redsys: Fix ISO code for PLN [chopenhauer] #2831 +* Merchant E Solutions: Support transcript scrubbing [curiousepic] #2836 +* Paystation: Support transcript scrubbing [curiousepic] #2837 +* Psigate: Support transcript scrubbing [curiousepic] #2835 +* Braintree: Adding 3D Secure pass thru capabilities [filipebarcos] #2843 +* Authorize.net: Add flexibility for 3D Secure Parameters [filipebarcos] #2844 +* Elavon: Update Country List [nfarve] #2840 +* WorldPay: Update Country List [nfarve] #2841 +* Merchant Warrior: Support transcript scrubbing [curiousepic] #2845 +* NAB Transact: Pass nonfractional amounts correctly [curiousepic] #2843 +* Realex: Update Country List [nfarve] #2842 +* QBMS: Support transcript scrubbing [curiousepic] #2849 +* Adyen: Add support for installments [nfarve] #2839 +* Paymentez: Read messages on Failure with no error [nfarve] #2850 +* Paymentez: Fix response message conditional [curiousepic] #2851 +* Add ability to send email receipt [nfarve] #2852 +* Barclaycard Smartpay: Pass shopper_interaction [curiousepic] #2853 +* Stripe: Treat UGX as a zero-decimal currency [bpollack] #2857 +* Mundipagg: Remove Billing Address if no Address Sent [nfarve] #2855 +* Paypal: Support more robust scrubbing [curiousepic] #2858 +* Stripe: Report internal Stripe errors as failures [bpollack] #2859 +* Authorize.net: Add ability to pass `customer_payment_profile_id` [nfarve] #2854 + +== Version 1.78.0 (March 29, 2018) +* Litle: Add store for echecks [nfarve] #2779 +* Litle: Add Support for Echeck [nfarve] #2776 +* Orbital: Correct level 2 tax handling [deedeelavinder] #2729 +* Payeezy: Change determination method of endpoint for store request [deedeelavinder] #2731 +* Adyen: Return refusal_reason_raw when present [curiousepic] #2728 +* Payeezy: Update Store method [nfarve] #2733 +* CenPOS: Remove gzip encoding header [curiousepic] #2735 +* Mercado Pago: Allow binary_mode to be changed [nfarve] #2736 +* Stripe: Accept strings for refund_fee_amount [curiousepic] #2738 +* Orbital: Complete scrub test coverage [curiousepic] #2739 +* MIGS: Scrub sensitive data [curiousepic] #2740 +* Worldpay US: Scrub sensitive data [curiousepic] #2742 +* WorldPay: Remove Israel from supported country list [dtykocki] #2746 +* Optimal Payments: Scrub sensitive data [curiousepic] #2743 +* USA Epay Transaction: Scrub sensitive data [curiousepic] #2745 +* MIGS: Add unit test for scrub [curiousepic] #2747 +* Worldpay US: Fix bank account scrub [curiousepic] #2748 +* Litle: Add support for merchantData elements [dtykocki] #2751 +* Paymentez: Add support for purchasing and authorizatin with tokens [bpollack] #2753 +* Ingenico: Remove Trinidad and Tobego from supported country list [bpollack] #2754 +* Barclaycard Smartpay: Remove Georgia from supported country list [bpollack] #2755 +* Merchant Warrior: Remove requirement for state field [joshnuss] #2638 +* Wirecard: Adding missing DigiCert Global Root G2 Cert [filipebarcos] #2759 +* Redsys: Add support for CNY, IDR, INR, KRW and TWD [chopenhauer] #2761 +* Optimal Payments: Fix scrub for double escaping [curiousepic] #2763 +* Orbital: Scrub profile transactions [curiousepic] #2762 +* BlueSnap: Fix currency passing [curiousepic] #2765 +* Stripe: Support pickup_card decline code [dtykocki] #2764 +* Improve scrub testing for five gateways [curiousepic] #2767 +* Payflow: Support scrub [curiousepic] #2768 +* SecureNet: Support scrub [curiousepic] #2769 +* Payeezy: Update transaction method when using stored cards [dtykocki] #2770 +* Citrus Pay, DIBS, 1stPayGateway, Global Transport, NETbilling, Ogone, TNS: remove TLS 1.0 requirement [bdewater] #2774 +* CardStream: Default IP and customer country [dtykocki] #2773 +* Stripe: Support destination amount [dtykocki] #2777 +* GlobalCollect: Update supported country list [dtykocki] #2783 +* Adyen: Support store action [curiousepic] #2784 +* Psigate: Update Test URL and Card [nfarve] #2785 +* USA ePay Transaction: Support ACH/eChecks [curiousepic] #2786 +* PayU Latam: Support language parameter [dtykocki] #2787 +* Payflow: Pass OrderDesc field [curiousepic] #2789 +* Global Collect: Add arbitrary fraudField params [curiousepic] #2790 +* Paystation: Support verify action [curiousepic] #2793 +* Checkout V2: Return error codes in response [curiousepic] #2791 +* CardStream: Change refund to use REFUND_SALE [dtykocki] #2795 +* Spreedly: Scrub sensitive transaction data [abarrak] #2781 +* Stripe: Add `exchange_rate` parameter [WilsonChiang] #2796 +* Mundipagg: New Gateway Implementation [nfarve] #2791 + +== Version 1.77.0 (January 31, 2018) +* Authorize.net: Allow Transaction Id to be passed for refuds [nfarve] #2698 +* Forte: ensure unit tests are local-only [bpollack] #2696 +* Moneris US: ensure unit tests are local-only [bpollack] #2696 +* Payflow: Change Verify Method for Amex Cards [nfarve] #2693 +* Safe Charge: fix an issue with variable shadowing in the adapter [bpollack] #2697 +* Crashnet: add scrubbing support [bpollack] #2695 +* Barclays EPDQ: add scrubbing support [bpollack] #2695 +* Fat Zebra: add remote scrubbing test [bpollack] #2695 +* Clearhaus: add remote scrubbing test [bpollack] #2695 +* Borgun: add remote scrubbing test [bpollack] #2695 +* Stripe: Added support for the quickchip entry mode option [rbalsdon] +* Ogone: Add tests for scrubbing [bpollack] #2700 +* Global Transport: Add scrubbing support [bpollack] #2700 +* HPS: Add scrubbing support [bpollack] #2700 +* FirstData E4: Improve scrubbing and add remote scrubbing test [bpollack] #2700 +* Elavon: Add scrubbing support [bpollack] #2700 +* Data Cash: Add scrubbing support [bpollack] #2700 +* Litle: Fix testing URL [wsmoak] #2673 +* Barclays ePDQ Extra Plus: Add missing Entrust root certificates [pacso] #2614 +* Moneris US: Add scrubbing support [bpollack] #2702 +* Mercury: Add scrubbing support [bpollack] #2702 +* Fat Zebra: Tweak remote scrubbing test [bpollack] #2704 +* Card Connect: Add new gateway [nfarve] #2706 +* Payeezy: Ensure store calls are properly scrubbed [dtykocki] #2709 +* Payeezy: Add unit test for scrubbing store call [dtykocki] #2710 +* Element: Correct URL used by store transactions [dtykocki] #2711 +* Borgun: Add support for specifying TerminalID [bpollack] #2712 +* Barclaycard Smartpay: 3DS Implementation [nfarve] #2714 +* Payeezy: Surface gateway_message on failure [curiousepic] #2717 +* Payment Express: Scrub merchant password [curiousepic] #2723 +* Stripe: Fix Partial Application Fee Refunds [curiousepic] #2713 +* GooglePay: Support network tokenized cards [joshnuss] #2725 + +== Version 1.76.0 (January 3, 2018) +* PayU Latam: Change default text for description [nfarve] #2669 +* Checkout V2: Allows AVS and CVV result details to come through on authorizations [deedeelavinder] #2650 +* Global Collect: Adds boolean option for pre_authorization [deeedeelavinder] #2651 +* Credorax: Pass Transaction Type field [curiousepic] #2653 +* Add CardProcess Gateway [bpollack] #2659 +* Safe Charge: Provision 3DS option for approved merchants [deedeelavinder] #2661 +* PayU Latam: Require payment_country on initialize [curiousepic] #2663 +* Adyen: Remove CVV as Required Field and Determines shopperInteraction [nfarve] #2665 +* SafeCharge: add support for VendorID, WebsiteID, and IP logging [bpollack] #2667 +* Safe Charge: Adds 3DS flag [deedeelavinder] #2668 +* CardProcess: Fix success? to always return true or false [bpollack] #2674 +* SagePay: Correct CVV, AVS codes for Sagepay [singhai0] #2670 +* PayU Latam: Count pending Voids as successful [curiousepic] #2677 +* Mercado Pago: Ensure acess tokens are URL escaped [bpollack] #2675 +* MiGS: Update hash format to SHA256 and restore remote tests [bpollack] #2676 +* MiGS: Support verify calls [bpollack] #2664 +* iATS: Fix Messages with Failure on iATS Server [nfarve] #2680 +* Barclaycard Smartpay: Correct repsonse for fraud rejects #2683 +* Adyen: Allow incomplete addresses in some situations [bpollack] #2684 +* Paymentez: Add new gateway [bpollack] #2685 +* PayU Latam: Provide a mechanism to override the amount in verify [dtykocki] #2688 +* Mercado Pago: Support X-Device-Session-ID Header [bpollack] #2689 +* Mercado Pago: Support arbitrary additional_info JSON [bpollack] #2691 +* FirstData E4: Override ECI value for Apple Pay transactions with Discover [jasonwebster] #2671 +* Quickbooks: Add payment context to Quickbooks charges and refunds [bdewater] #2694 + +== Version 1.75.0 (November 9, 2017) +* Barclaycard Smartpay: Clean up test options hashes [bpollack] #2632 +* Barclaycard Smartpay: Extra data fields for credits [bpollack] #2631 +* Cyber Source: Correctly passes subscriptionID for store [deedeelavinder] #2633 +* Ebanx: Pass fields for business person responsible [curiousepic] #2635 +* Ebanx: Support Colombian transactions [bpollack] #2636 +* FirstData E4 (Payeezy): Ensure numeric ECI values are zero padded [jasonwebster] #2630 +* Netbanx: Only send currency and billing_details for auths and sales [anotherjosmith] #2643 +* Netbanx: Revert "Fixes basic auth for netbanx by sending the account_number and api_key" [anotherjosmith] #2644 +* PayU Latam: Adds `partnerID`, adjusts phone preferences, allows empty `ip_address`, and adjusts for no `cvv` [deedeelavinder] #2634 +* Sage Payment Solutions: Scrub check info [curiousepic] #2639 +* Worldbank US: Allow using the backup URL [bpollack] #2641 +* Worldbank US: Allow using the backup URL per-request [bpollack] #2645 + +== Version 1.74.0 (October 24, 2017) +* Adyen: Update list of supported countries [dtykocki] #2600 +* Authorize.net CIM: Handle multiple error messages [amandapuff] #2537 +* Barclaycard Smartpay: Pass street and house_number fields, in addition to standard address [deedeelavinder] #2603 +* Barclaycard Smartpay: Use authorization pspReference for refunds [davidsantoso] #2599 +* Beanstream: Pass email fields without address [curiousepic] #2615 +* Beanstream: Support recurringPayment for auth, capture, and purchase transactions [dtykocki] #2617 +* Borgun: Add support for USD transactions [dtykocki] #2602 +* Borgun: Include currency code from split authorization for voids [dtykocki] #2605 +* Checkout V2: Expose AVS and CVV results for purchases [dtykocki] #2619 +* Credorax: Update response codes [curiousepic] #2595 +* CyberSource: Support 3DSecure requests [curiousepic] #2624 +* Ebanx: Pass person_type and name for stored cards [curiousepic] #2621 +* Ebanx: Support Store and person_type option [curiousepic] #2604 +* Elavon: Update endpoint URLs [curiousepic] #2608 +* Netbanx: Fix basic auth by sending the account_number and api_key [anotherjosmith] #2616 +* Payeezy: Adds support for store [deedeelavinder] #2591 +* PayU Latam: Set payment_country gateway attribute [curiousepic] #2611 +* Redsys: Support the DKK currency type [bpollack] #2618 +* WePay: Only send ip and device for non-recurring transactions [dtykocki] #2597 + +== Version 1.73.0 (September 28, 2017) +* Adyen: Use original authorization pspReference on Refunds [lyverovski] #2589 +* Braintree Blue: Explicitly require braintree-ruby version 2.78 [anotherjosmith] +* FirstData E4: Scrub 3DS cryptogram [jasonwebster] #2596 +* PayHub: Replace single quotes with double quotes in error message [matthewheath] #2572 +* Wirecard: Format non-fractional currency amounts correctly [bdewater] #2594 + +== Version 1.72.0 (September 20, 2017) +* Adyen: Fix failing remote tests [dtykocki] #2584 +* Authorize.net: Remove numeric restriction on customer ID [dtykocki] #2579 +* Authorize.net: Restore default state value for non-US addresses [jasonwebster] #2563 +* Beanstream: Do not default state and zip with empty country [dtykocki] #2582 +* Braintree Blue: Add eci_indicator field for Apple Pay [davidsantoso] #2565 +* Conekta: Add guard clause for details fallbacks [curiousepic] #2573 +* Conekta: Pull required details from billing address [nfarve] #2568 +* DataCash: Enable refunding recurring transactions [davidsantoso] #2560 +* Ebanx: Adds Brazil Specific Parameters [nfarve] #2559 +* Kushki: Add support for refunds [dtykocki] #2575 +* MercadoPago: Additional tweaks for transaction requests [davidsantoso] +* MercadoPago: Default to alphanumeric order_id [davidsantoso] +* MercadoPago: Send diners_club cards as diners [davidsantoso] #2585 +* PayU Latam: Correctly condition buyer element fields [curiousepic] #2578 +* PayU Latam: Pass unique buyer fields and country requirements [curiousepic] #2570 +* Qvalent: Support general credit [curiousepic] #2558 +* SafeCharge: Update to Version 4.1.0 [nfarve] #2556 +* WePay: Don't default API version header [curiousepic] #2567 +* WePay: Don't require email for Store [curiousepic] #2588 + +== Version 1.71.0 (August 22, 2017) +* Bambora formerly Beanstream: Change casing on customerIp variable [aengusbates] #2551 +* Checkout V2: Add localized_amount support to add_invoice function [nicolas-maalouf-cko] #2452 +* Checkout V2: Add UAE to country list [shasum] #2548 +* Checkout V2: Fix success response code validation [nicolas-maalouf-cko] #2452 +* CreditCall: Only allow AVS when specified [curiousepic] #2549 +* CreditCall: Parse additional params from responses [nfarve] #2552 +* CreditCall: Parse more response params [nfavre] #2543 +* MercadoPago: Small tweaks to building requests [davidsantoso] #2555 +* Orbital: Support Network Tokenization Credit Cards [curiousepic] #2553 +* Orbital: Updgrade schema version to 7.1 [curiousepic] #2546 +* Remove HUF from default non-fractional currencies [curiousepic] #2538 +* Stripe: Add support for statement_address parameters for EMV transactions [malcolm-mergulhao] #2524 +* TransFirst Express: Don't send address2 without value [nfarve] #2545 +* TransFirst Express: Fix Optional Fields Being Passed Blank [nfarve] #2550 +* TransFirst: Fix partial refund [nfarve] #2541 +* Vantiv (Litle): Pass 3DS fields [curiousepic] #2536 +* Braintree Blue: Add phone to options [deedeelavinder] #2564 + +== Version 1.70.0 (August 4, 2017) +* Barclaycard Smartpay: Provider a default billing address house number [nfarve] #2520 +* FirstData E4: Fix duplicate XID and CAVV values in tokenized transactions [jasonwebster] #2529 +* FirstData E4: Loose XSD validation for Payeezy (FirstData E4) [jasonwebster] #2529 +* GlobalTransport: Support partial authorizations [dtykocki] #2511 +* Litle: Update schema and certification tests to v9.12 [curiousepic] #2522 +* Litle: Update urls and name to Vantiv [curiousepic] #2531 +* Mercado Pago: Add gateway support [davidsantoso] #2518 +* Orbital: Add support for level 2 data [dtykocki] #2515 +* PayU Latam: Pass DNI Number [curiousepic] #2517 +* Qvalent: Pass 3dSecure fields [curiousepic] #2508 +* SafeCharge: Correct UserID field name [curiousepic] +* SafeCharge: Pass UserID field [curiousepic] #2507 +* AuthorizeNet: Allow Response Code 4 to be returned as successful [nfarve] #2530 +* Forte: Remove order number from captures in Forte Gateway [nfarve] #2532 +* PayU Latam: Add additional mandatory fields [deedeelavinder] #2528 + +== Version 1.69.0 (July 12, 2017) +* WePay: Add payer_rbits and transaction_rbits optional fields [davidsantoso] +* Adyen: Use Active Merchant standard order_id option for reference [jasonwebster] #2483 +* Correct calculation for three-exponent currencies [curiousepic] #2486 +* SagePay: Use VPSTxId from authorization for refunds [dtykocki] #2489 +* Payflow: Move PAYPAL-NVP header option to a class attribute on the payment gateway [deuxpi] #2492 +* Optimal Payments: Pass CVD indicator accurately [curiousepic] #2491 +* SagePay: Make Repeat purchase if payment is a past authorization [curiousepic] #2495 +* Netbanx: map response errorCodes onto standard error code [iirving] #2456 +* Netbanx: Update supported countries and cardtypes [iirving] #2456 +* Barclaycard Smartpay: Support 0- and 3-exponent currencies [curiousepic] #2498 +* CyberSource: Fix XSD schema validation issues [jasonwebster] #2497 +* WorldPay: Support three-decimal currencies [curiousepic] #2501 +* NMI: Add first and lastname to echeck transactions [dtykocki] #2499 +* PayFlow: Add optional email field [davidsantoso] #2505 +* Worldpay: Support Credit on CFT-enabled merchant IDs [curiousepic] #2503 +* FirstPay: Add processor_id field [davidsantoso] #2506 +* Authorize.Net: Use two character default for billing state [dtykocki] #2496 + +== Version 1.68.0 (June 27, 2017) +* Authorize.Net: Return failed response if forced refund settlement fails [bizla] #2476 +* Authorize.net: Concatenate address1 and address2 [dtykocki] #2479 +* Braintree Blue: Braintree Blue: Add ECI indicator to Android Pay transactions [davidsantoso] #2474 +* Credorax: Support 0- and 3-exponent currencies [curiousepic] +* Cybersource: update supported card types [bdewater] #2477 +* FirstData: Add a default network tokenization strategy for FirstData E4 [krystosterone] #2473 +* FirstPay: FirstPay: Update hostname and force TLSv1 minimum [davidsantoso] #2478 +* JetPay V2: Support store transactions and token based payments [shasum] #2475 +* Moneris: Add 3DS fields for decrypted Apple and Android Pay data [davidsantoso] #2457 +* Openpay: Send customer name and email in authorize and purchase [dtykocki] #2468 +* Payflow: Moved to name value pair (NVP) with payflow [jusleg] #2462 +* Payflow: Set PAYPAL_NVP header as optional [davidsantoso] #2480 +* QuickPay V10: Return last response for purchase and authorize [curiousepic] #2461 +* SafeCharge: Map billing address fields [davidsantoso] #2464 +* SafeCharge: Track currency from original transaction [davidsantoso] #2470 +* Support three-decimal currencies [curiousepic] #2466 +* Trexle: Add gateway support [hossamhossny] #2351 + +== Version 1.67.0 (June 8, 2017) +* Acapture: Pass 3D Secure fields [davidsantoso] #2451 +* Authorize.net: Pass Level 2 Data Fields [curiousepic] #2444 +* Credorax: Add 3D Secure authentication fields [davidsantoso] #2446 +* Ebanx: Add gateway support [davidsantoso] #2447 +* Ebanx: Reduce supported countries to Brazil and Mexico [davidsantoso] +* FirstData Payeezy: Set default ECI value for auth/purchase transactions [jasonwebster] #2448 +* JetPay V2: Add new gateway [shasum] #2442 +* JetPay V2: Add optional tax data to capture calls [shasum] #2445 +* NMI: Add Network Tokenization support [shasum] #2431 +* Orbital: Pass soft descriptors from options hash [curiousepic] +* Orbital: Update test and production urls [jcowhigjr] #2436 +* Payeezy: Add client_email field for telecheck [davidsantoso] #2455 +* Payeezy: Add customer_id_type and customer_id_number fields [davidsantoso] #2454 +* Quickpay V10: Fix store and token use for recurring payments [wsmoak] #2180 +* Elavon: Support custom fields [curiousepic] #2416 +* WePay: Support risk headers [shasum] #2419 +* WePay: Add Canada as supported country [shasum] #2419 +* Fat Zebra: Fix xid 3D Secure field [curiousepic] +* SafeCharge: Mark support for European countries [curiousepic] +* Checkout V2: Pass customer ip option [curiousepic] +* Realex: Map AVS and CVV response codes [davidsantoso] #2424 +* Opp: Send disable3DSecure custom parameter if present [davidsantoso] #2432 +* SafeCharge: Map standard Active Merchant order_id field [davidsantoso] #2434 +* Payeezy: Default check number to 001 if not present [davidsantoso] #2439 +* Opp: Fix incorrect customParameter key to disable 3DS [davidsantoso] + +== Version 1.66.0 (May 4, 2017) +* Support Rails 5.1 [jhawthorn] #2407 +* ProPay: Add Canada as supported country [davidsantoso] +* ProPay: Add gateway support [davidsantoso] #2405 +* SafeCharge: Support credit transactions [shasum] #2404 +* WePay: Add scrub method [shasum] #2406 +* iVeri: Add gateway support [curiousepic] #2400 +* iVeri: Support 3DSecure data fields [davidsantoso] #2412 +* Opp: Fix transaction success criteria and clean up options [shasum] #2414 + +== Version 1.65.0 (April 26, 2017) +* Adyen: Add Adyen v18 gateway [adyenpayments] #2272 +* Authorize.Net: Force refund of unsettled payments via void [bizla] #2399 +* Barclays ePDQ: removed because it has been replaced by a new API [bdewater] #2331 +* Beanstream: Map ISO province codes for US and CA [shasum] #2396 +* Braintree Blue: Change :full_refund option to :force_full_refund_if_unsettled [bizla] #2403 +* Braintree Blue: Force refund of unsettled payments via void [bizla] #2398 +* Checkout V2: Fix sandbox URL [nicolas-maalouf-cko] #2391 +* Checkout V2: Fix success_from not properly checking two possible success codes [davidsantoso] +* Cybersource: Rescue XML parse exception [shasum] #2380 +* GlobalCollect: Make message and error reporting more robust [curiousepic] #2370 +* GlobalCollect: Set REJECTED refunds as unsuccessful transactions [davidsantoso] #2365 +* GlobalCollect: Truncate firstName field to 15 characters [davidsantoso] +* JetPay: Pass down authorization payment method token to refund a capture [davidsantoso] +* Openpay: Support card points [shasum] #2401 +* Orbital: Don't send CVV indicator if CVV is not present [curiousepic] #2368 +* PayU LATAM: Fix incorrect capture method definition [davidsantoso] +* Payeezy: Support dynamic soft descriptors [shasum] #2384 +* Pin: Add metadata optional field [shasum] #2363 +* Qvalent: Add soft descriptor fields. Add authorize, capture, and void [davidsantoso] +* SafeCharge: Add gateway [davidsantoso] +* SagePay: Support Repeat transactions [curiousepic] #2395 +* Stripe: Support custom application in X-Stripe-Client-User-Agent header [davidsantoso] +* TransFirst Transaction Express: Support ACH [curiousepic] #2389 +* WePay: Support unique_id for idempotent transactions [shasum] #2367 +* Worldpay: Force refund of unsettled payments via void [bizla] #2402 + +== Version 1.64.0 (March 6, 2017) * Authorize.net: Allow settings to be passed for CIM purchases [fwilkins] #2300 -* Omise: Enable Japan, JPY and JCB support [zdk] #2284 +* Authorize.net: Use new `unsupported_feature` standard error code [jasonwebster] #2322 +* Base Gateway: Add new `unsupported_feature` standard error code [jasonwebster] #2322 * Braintree Blue: Pass cardholder_name with card [curiousepic] #2324 -* Paymill: Send new required fields on tokenization requests [tschelabaumann] #2279 +* Braintree: Add Android Pay meta data fields [jknipp] #2347 +* CardStream: Add additional of currencies [shasum] #2337 +* Credorax: Return failure response reason [shasum] #2341 +* Digitzs: Add gateway [davidsantoso] +* Digitzs: Remove merchant_id from gateway credentials [davidsantoso] * GlobalCollect: Pass options to Refund [curiousepic] #2330 -* PayU LATAM: Let Refund take amount value [curiousepic] #2334 -* Linkpoint: Raise ArgumentError when trying to instantiate without `:pem` [jasonwebster] #2329 -* Base Gateway: Add new `unsupported_feature` standard error code [jasonwebster] #2322 -* Authorize.net: Use new `unsupported_feature` standard error code [jasonwebster] #2322 * Kushki: Add new gateway [shasum] #2326 +* Kushki: Remove body from void call [shasum] #2348 +* Linkpoint: Raise ArgumentError when trying to instantiate without `:pem` [jasonwebster] #2329 +* Omise: Enable Japan, JPY and JCB support [zdk] #2284 * PayU LATAM: Count pending refunds as succeeded [curiousepic] #2336 +* PayU LATAM: Let Refund take amount value [curiousepic] #2334 +* Paymill: Send new required fields on tokenization requests [tschelabaumann] #2279 +* Revert "Authorize.net: Allow settings to be passed for CIM purchases" [curiousepic] #2339 +* Sage: Default billing state when outside US [shasum] #2340 * Stripe: Remove idempotency key from verify [shasum] #2335 -* CardStream: Add additional of currencies [shasum] #2337 +* TransFirst Transaction Express: Don't send order_id with refunds [curiousepic] #2350 +* TransFirst Transaction Express: Fix improper AVS and CVV response code mapping [shasum] #2342 +* WePay: Update API version [shasum] #2349 +* USA ePay Advanced: Add quick_update_customer action [joshreeves] #2229 == Version 1.63.0 (February 2, 2017) * Authorize.net: Add #unstore support [jimryan] #2293 @@ -1598,7 +2122,7 @@ value [jduff] * Support default Return class for all Integrations that don't use returns [Soleone] * Add support for passing additional options when creating a Notification to all Integrations [Soleone] * Update BraintreeBlue#refund to have consistent method signature [Jonathan Rudenberg] -* Add rails/init.rb for gem campatability in Rails [Rūdolfs Ošiņš] +* Add rails/init.rb for gem campatability in Rails [R?dolfs O?i??] * Fix Paypal Express response parser [Jonathan Rudenberg] * Braintree/Transax: Add tax field [wisq] @@ -1914,7 +2438,7 @@ value [jduff] * Update Secure Pay Au to meet specs for MessageInfo elements [cody] * Add support for the Australian Secure Pay payment gateway [cody] * Allow LinkPoint cancellations for recurring billing. [yanagimoto.shin] -* Add support for Åland Islands to the country list [cody] +* Add support for ?land Islands to the country list [cody] == Version 1.3.1 (January 28, 2008) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 7d7989b171d..c9ce8e449ea 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,10 +1,16 @@ # Contributing guidelines -We gladly accept bugfixes and new gateways. Please follow the guidelines here to ensure your work is accepted. +We gladly accept bugfixes, but are not actively looking to add new gateways. Please follow the guidelines here to ensure your work is accepted. ## New Gateways -Please see the [ActiveMerchant Guide to Contributing a new Gateway](https://github.com/activemerchant/active_merchant/wiki/contributing) for information on adding a new gateway to ActiveMerchant. +We're not taking on many new gateways at the moment. The team maintaining ActiveMerchant is small and with the limited resources available, we generally prefer not to support a gateway than to support a gateway poorly. + +Please see the [ActiveMerchant Guide to Contributing a new Gateway](https://github.com/activemerchant/active_merchant/wiki/contributing) for information on creating a new gateway. You can place your gateway code in your application's `lib/active_merchant/billing` folder to use it. + +We would like to work with the community to figure out how gateways can release and maintain their integrations outside of the the ActiveMerchant repository. Please join [the discussion](https://github.com/activemerchant/active_merchant/issues/2923) if you're interested or have ideas. + +Gateway placement within Shopify is available by invitation only at this time. ## Issues & Bugfixes @@ -25,10 +31,6 @@ When submitting a pull request to resolve an issue: 4. Push your changes to your fork (`git push origin my_awesome_feature`) 5. Open a [Pull Request](https://github.com/activemerchant/active_merchant/pulls) -## Gateway Placement within Shopify - -Placement within Shopify is available by invitation only at this time. - ## Version/Release Management Contributors don't need to worry about versions, this is something Committers do at important milestones: diff --git a/Gemfile b/Gemfile index 7c62a122f4e..8ce730332ad 100644 --- a/Gemfile +++ b/Gemfile @@ -2,8 +2,9 @@ source 'https://rubygems.org' gemspec gem 'jruby-openssl', :platforms => :jruby +gem 'rubocop', '~> 0.60.0', require: false group :test, :remote_test do # gateway-specific dependencies, keeping these gems out of the gemspec - gem 'braintree', '>= 2.50.0' + gem 'braintree', '>= 2.78.0' end diff --git a/Gemfile.rails32 b/Gemfile.rails32 deleted file mode 100644 index cc1430f5681..00000000000 --- a/Gemfile.rails32 +++ /dev/null @@ -1,11 +0,0 @@ -source 'https://rubygems.org' -gemspec - -gem 'jruby-openssl', :platforms => :jruby - -group :test, :remote_test do - # gateway-specific dependencies, keeping these gems out of the gemspec - gem 'braintree', '>= 2.50.0' -end - -gem 'rails', '~> 3.2.0' diff --git a/Gemfile.rails40 b/Gemfile.rails40 deleted file mode 100644 index 26f25a01cee..00000000000 --- a/Gemfile.rails40 +++ /dev/null @@ -1,11 +0,0 @@ -source 'https://rubygems.org' -gemspec - -gem 'jruby-openssl', :platforms => :jruby - -group :test, :remote_test do - # gateway-specific dependencies, keeping these gems out of the gemspec - gem 'braintree', '>= 2.50.0' -end - -gem 'rails', '~> 4.0.0' diff --git a/Gemfile.rails41 b/Gemfile.rails41 deleted file mode 100644 index 6a44812d025..00000000000 --- a/Gemfile.rails41 +++ /dev/null @@ -1,11 +0,0 @@ -source 'https://rubygems.org' -gemspec - -gem 'jruby-openssl', :platforms => :jruby - -group :test, :remote_test do - # gateway-specific dependencies, keeping these gems out of the gemspec - gem 'braintree', '>= 2.50.0' -end - -gem 'rails', '~> 4.1.0' diff --git a/Gemfile.rails42 b/Gemfile.rails42 deleted file mode 100644 index 7cf96452cdf..00000000000 --- a/Gemfile.rails42 +++ /dev/null @@ -1,11 +0,0 @@ -source 'https://rubygems.org' -gemspec - -gem 'jruby-openssl', :platforms => :jruby - -group :test, :remote_test do - # gateway-specific dependencies, keeping these gems out of the gemspec - gem 'braintree', '>= 2.50.0' -end - -gem 'rails', '~> 4.2.0' diff --git a/Gemfile.rails5 b/Gemfile.rails5 deleted file mode 100644 index a7bec76b4bc..00000000000 --- a/Gemfile.rails5 +++ /dev/null @@ -1,13 +0,0 @@ -source 'https://rubygems.org' -gemspec - -gem 'jruby-openssl', :platforms => :jruby - -group :test, :remote_test do - # gateway-specific dependencies, keeping these gems out of the gemspec - gem 'braintree', '>= 2.50.0' -end - -gem 'rails', github: 'rails/rails' -gem 'arel', github: 'rails/arel' -gem 'rack', github: 'rack/rack' diff --git a/GettingStarted.md b/GettingStarted.md index f8fac95f593..d78458d7d40 100644 --- a/GettingStarted.md +++ b/GettingStarted.md @@ -43,12 +43,13 @@ Instantiating such an object is simple: ```ruby credit_card = ActiveMerchant::Billing::CreditCard.new( - :first_name => 'Steve', - :last_name => 'Smith', - :month => '9', - :year => '2014', - :type => 'visa', - :number => '4242424242424242') + :first_name => 'Steve', + :last_name => 'Smith', + :month => '9', + :year => '2022', + :brand => 'visa', + :number => '4242424242424242', + :verification_value => '424') ``` Most often, though, you'll be using user-supplied data. In a typical Rails controller: diff --git a/README.md b/README.md index be48a8c8fa5..fb9dfdc3705 100644 --- a/README.md +++ b/README.md @@ -31,11 +31,15 @@ You can check out the latest source from git: Installation from RubyGems: - gem install activemerchant +```console +gem install activemerchant +``` Or, if you're using Bundler, just add the following to your Gemfile: - gem 'activemerchant' +```ruby +gem 'activemerchant' +``` ## Usage @@ -91,7 +95,6 @@ The [ActiveMerchant Wiki](http://github.com/activemerchant/active_merchant/wikis * [Bank Frick](http://www.bankfrickacquiring.com/) - LI, US * [Banwire](http://www.banwire.com/) - MX * [Barclays ePDQ Extra Plus](http://www.barclaycard.co.uk/business/accepting-payments/epdq-ecomm/) - GB -* [Barclays ePDQ MPI](http://www.barclaycard.co.uk/business/accepting-payments/epdq-mpi/) - GB * [Be2Bill](http://www.be2bill.com/) - FR * [Beanstream.com](http://www.beanstream.com/) - CA, US * [BluePay](http://www.bluepay.com/) - US @@ -196,7 +199,7 @@ The [ActiveMerchant Wiki](http://github.com/activemerchant/active_merchant/wikis * [QuickBooks Merchant Services](http://payments.intuit.com/) - US * [QuickBooks Payments](http://payments.intuit.com/) - US * [Quantum Gateway](http://www.quantumgateway.com) - US -* [QuickPay](http://quickpay.net/) - DE, DK, ES, FI, FR, FO, GB, IS, NO, SE +* [QuickPay](http://quickpay.net/) - AT, BE, BG, CY, CZ, DE, DK, EE, ES, FI, FR, GB, GR, HR, HU, IE, IS, IT, LI, LT, LU, LV, MT, NL, NO, PL, PT, RO, SE SI, SK * [Qvalent](https://www.qvalent.com/) - AU * [Raven](http://www.deepcovelabs.com/raven) - AI, AN, AT, AU, BE, BG, BS, BZ, CA, CH, CR, CY, CZ, DE, DK, DM, DO, EE, EL, ES, FI, FR, GB, GG, GI, HK, HR, HU, IE, IL, IM, IN, IT, JE, KN, LI, LT, LU, LV, MH, MT, MY, NL, NO, NZ, PA, PE, PH, PL, PT, RO, RS, SC, SE, SG, SI, SK, UK, US, VG, ZA * [Realex](http://www.realexpayments.com/) - IE, GB, FR, BE, NL, LU, IT @@ -233,3 +236,7 @@ The [ActiveMerchant Wiki](http://github.com/activemerchant/active_merchant/wikis ## API stability policy Functionality or APIs that are deprecated will be marked as such. Deprecated functionality is removed on major version changes - for example, deprecations from 2.x are removed in 3.x. + +## Ruby and Rails compatibility policies + +Because Active Merchant is a payment library, it needs to take security seriously. For this reason, Active Merchant guarantees compatibility only with actively supported versions of Ruby and Rails. At the time of this writing, that means that Ruby 2.3+ and Rails 4.2+ are supported. diff --git a/Rakefile b/Rakefile index 4852f416101..5e92782a541 100644 --- a/Rakefile +++ b/Rakefile @@ -11,31 +11,36 @@ end require 'rake' require 'rake/testtask' +require 'rubocop/rake_task' require 'support/gateway_support' require 'support/ssl_verify' +require 'support/ssl_version' require 'support/outbound_hosts' require 'bundler/gem_tasks' task :tag_release do system "git tag 'v#{ActiveMerchant::VERSION}'" - system "git push --tags" + system 'git push --tags' end -desc "Run the unit test suite" +desc 'Run the unit test suite' task :default => 'test:units' task :test => 'test:units' +RuboCop::RakeTask.new + namespace :test do Rake::TestTask.new(:units) do |t| t.pattern = 'test/unit/**/*_test.rb' - t.ruby_opts << '-rubygems -w' t.libs << 'test' t.verbose = true end + desc 'Run all tests that do not require network access' + task :local => ['test:units', 'rubocop'] + Rake::TestTask.new(:remote) do |t| t.pattern = 'test/remote/**/*_test.rb' - t.ruby_opts << '-rubygems -w' t.libs << 'test' t.verbose = true end @@ -84,15 +89,22 @@ namespace :gateways do unless invalid_lines.empty? puts - puts "Unable to parse:" + puts 'Unable to parse:' invalid_lines.each do |line| puts line end end end - desc 'Test that gateways allow SSL verify_peer' - task :ssl_verify do - SSLVerify.new.test_gateways + namespace :ssl do + desc 'Test that gateways allow SSL verify_peer' + task :verify do + SSLVerify.new.test_gateways + end + + desc 'Test gateways minimal SSL version connection' + task :min_version do + SSLVersion.new.test_gateways + end end end diff --git a/activemerchant.gemspec b/activemerchant.gemspec index 3ed9f110385..bb9ea4e14f8 100644 --- a/activemerchant.gemspec +++ b/activemerchant.gemspec @@ -1,4 +1,4 @@ -$:.push File.expand_path("../lib", __FILE__) +$:.push File.expand_path('../lib', __FILE__) require 'active_merchant/version' Gem::Specification.new do |s| @@ -7,24 +7,24 @@ Gem::Specification.new do |s| s.version = ActiveMerchant::VERSION s.summary = 'Framework and tools for dealing with credit card transactions.' s.description = 'Active Merchant is a simple payment abstraction library used in and sponsored by Shopify. It is written by Tobias Luetke, Cody Fauser, and contributors. The aim of the project is to feel natural to Ruby users and to abstract as many parts as possible away from the user to offer a consistent interface across all supported gateways.' - s.license = "MIT" + s.license = 'MIT' s.author = 'Tobias Luetke' s.email = 'tobi@leetsoft.com' s.homepage = 'http://activemerchant.org/' s.rubyforge_project = 'activemerchant' - s.required_ruby_version = '>= 2.1' + s.required_ruby_version = '>= 2.3' s.files = Dir['CHANGELOG', 'README.md', 'MIT-LICENSE', 'CONTRIBUTORS', 'lib/**/*', 'vendor/**/*'] s.require_path = 'lib' s.has_rdoc = true if Gem::VERSION < '1.7.0' - s.add_dependency('activesupport', '>= 3.2.14', '< 5.1') + s.add_dependency('activesupport', '>= 4.2') s.add_dependency('i18n', '>= 0.6.9') s.add_dependency('builder', '>= 2.1.2', '< 4.0.0') - s.add_dependency('nokogiri', "~> 1.4") + s.add_dependency('nokogiri', '~> 1.4') s.add_development_dependency('rake') s.add_development_dependency('test-unit', '~> 3') diff --git a/circle.yml b/circle.yml index b6aab8e1717..5d2a53e5abb 100644 --- a/circle.yml +++ b/circle.yml @@ -1,6 +1,6 @@ machine: ruby: - version: '2.1.0' + version: '2.3.0' dependencies: cache_directories: diff --git a/gemfiles/Gemfile.rails42 b/gemfiles/Gemfile.rails42 new file mode 100644 index 00000000000..8d11bec617c --- /dev/null +++ b/gemfiles/Gemfile.rails42 @@ -0,0 +1,3 @@ +eval_gemfile '../Gemfile' + +gem 'activesupport', '~> 4.2.0' diff --git a/gemfiles/Gemfile.rails50 b/gemfiles/Gemfile.rails50 new file mode 100644 index 00000000000..ce57bebccbe --- /dev/null +++ b/gemfiles/Gemfile.rails50 @@ -0,0 +1,3 @@ +eval_gemfile '../Gemfile' + +gem 'activesupport', '~> 5.0.0' diff --git a/gemfiles/Gemfile.rails51 b/gemfiles/Gemfile.rails51 new file mode 100644 index 00000000000..a352b24eaa8 --- /dev/null +++ b/gemfiles/Gemfile.rails51 @@ -0,0 +1,3 @@ +eval_gemfile '../Gemfile' + +gem 'activesupport', '~> 5.1.0' diff --git a/gemfiles/Gemfile.rails52 b/gemfiles/Gemfile.rails52 new file mode 100644 index 00000000000..c6c439fce53 --- /dev/null +++ b/gemfiles/Gemfile.rails52 @@ -0,0 +1,3 @@ +eval_gemfile '../Gemfile' + +gem 'activesupport', '~> 5.2.0.rc1' diff --git a/gemfiles/Gemfile.rails_master b/gemfiles/Gemfile.rails_master new file mode 100644 index 00000000000..04b88ec1b00 --- /dev/null +++ b/gemfiles/Gemfile.rails_master @@ -0,0 +1,3 @@ +eval_gemfile '../Gemfile' + +gem 'activesupport', github: 'rails/rails' diff --git a/generators/gateway/gateway_generator.rb b/generators/gateway/gateway_generator.rb index d20ad21343c..27dda8aa510 100644 --- a/generators/gateway/gateway_generator.rb +++ b/generators/gateway/gateway_generator.rb @@ -38,7 +38,7 @@ def fixtures_file end def next_identifier - fixtures = (YAML.load(File.read(fixtures_file)).keys + [identifier]).uniq.sort + fixtures = (YAML.safe_load(File.read(fixtures_file), [], [], true).keys + [identifier]).uniq.sort fixtures[fixtures.sort.index(identifier)+1] end end diff --git a/generators/gateway/templates/remote_gateway_test.rb b/generators/gateway/templates/remote_gateway_test.rb index f397794e4e6..08262a97c93 100644 --- a/generators/gateway/templates/remote_gateway_test.rb +++ b/generators/gateway/templates/remote_gateway_test.rb @@ -43,7 +43,7 @@ def test_successful_authorize_and_capture assert capture = @gateway.capture(@amount, auth.authorization) assert_success capture - assert_equal 'REPLACE WITH SUCCESS MESSAGE', response.message + assert_equal 'REPLACE WITH SUCCESS MESSAGE', capture.message end def test_failed_authorize diff --git a/lib/active_merchant.rb b/lib/active_merchant.rb index b53c4bbbed4..06ab2f0d19d 100644 --- a/lib/active_merchant.rb +++ b/lib/active_merchant.rb @@ -28,11 +28,6 @@ require 'active_support/core_ext/object/conversions' require 'active_support/core_ext/class/attribute' require 'active_support/core_ext/enumerable' - -if(!defined?(ActiveSupport::VERSION) || (ActiveSupport::VERSION::STRING < "4.1")) - require 'active_support/core_ext/class/attribute_accessors' -end - require 'active_support/core_ext/module/attribute_accessors' require 'base64' @@ -42,9 +37,10 @@ require 'rexml/document' require 'timeout' require 'socket' +require 'openssl' require 'active_merchant/network_connection_retries' -require 'active_merchant/delete_with_body' +require 'active_merchant/net_http_ssl_connection' require 'active_merchant/connection' require 'active_merchant/post_data' require 'active_merchant/posts_data' @@ -55,7 +51,7 @@ module ActiveMerchant def self.deprecated(message, caller=Kernel.caller[1]) - warning = caller + ": " + message + warning = caller + ': ' + message if(respond_to?(:logger) && logger.present?) logger.warn(warning) else diff --git a/lib/active_merchant/billing/avs_result.rb b/lib/active_merchant/billing/avs_result.rb index 527c3efa119..b21017eaa2f 100644 --- a/lib/active_merchant/billing/avs_result.rb +++ b/lib/active_merchant/billing/avs_result.rb @@ -1,8 +1,7 @@ -#!ruby19 # encoding: utf-8 module ActiveMerchant - module Billing + module Billing # Implements the Address Verification System # https://www.wellsfargo.com/downloads/pdf/biz/merchant/visa_avs.pdf # http://en.wikipedia.org/wiki/Address_Verification_System @@ -38,7 +37,7 @@ class AVSResult 'Y' => 'Street address and 5-digit postal code match.', 'Z' => 'Street address does not match, but 5-digit postal code matches.' } - + # Map vendor's AVS result code to a postal match code POSTAL_MATCH_CODE = { 'Y' => %w( D H F H J L M P Q V W X Y Z ), @@ -49,7 +48,7 @@ class AVSResult codes.each { |code| map[code] = type } map end - + # Map vendor's AVS result code to a street match code STREET_MATCH_CODE = { 'Y' => %w( A B D H J M O Q T V X Y ), @@ -60,32 +59,32 @@ class AVSResult codes.each { |code| map[code] = type } map end - + attr_reader :code, :message, :street_match, :postal_match - + def self.messages MESSAGES end - + def initialize(attrs) attrs ||= {} - + @code = attrs[:code].upcase unless attrs[:code].blank? @message = self.class.messages[code] - + if attrs[:street_match].blank? @street_match = STREET_MATCH_CODE[code] - else + else @street_match = attrs[:street_match].upcase end - + if attrs[:postal_match].blank? @postal_match = POSTAL_MATCH_CODE[code] - else + else @postal_match = attrs[:postal_match].upcase end end - + def to_hash { 'code' => code, 'message' => message, diff --git a/lib/active_merchant/billing/base.rb b/lib/active_merchant/billing/base.rb index 2248e6f9c39..5392189e46b 100644 --- a/lib/active_merchant/billing/base.rb +++ b/lib/active_merchant/billing/base.rb @@ -49,7 +49,7 @@ def self.gateway(name) # notification = chronopay.notification(raw_post) # def self.integration(name) - Billing::Integrations.const_get("#{name.to_s.downcase}".camelize) + Billing::Integrations.const_get(name.to_s.downcase.camelize) end # A check to see if we're in test mode diff --git a/lib/active_merchant/billing/check.rb b/lib/active_merchant/billing/check.rb index b630f73ffce..3c26abb8a0c 100644 --- a/lib/active_merchant/billing/check.rb +++ b/lib/active_merchant/billing/check.rb @@ -7,8 +7,9 @@ module Billing #:nodoc: # You may use Check in place of CreditCard with any gateway that supports it. class Check < Model attr_accessor :first_name, :last_name, - :bank_name, :routing_number, :account_number, - :account_holder_type, :account_type, :number + :bank_name, :routing_number, :account_number, + :account_holder_type, :account_type, :number, + :remote_account_id # Used for Canadian bank accounts attr_accessor :institution_number, :transit_number @@ -30,17 +31,17 @@ def validate errors = [] [:name, :routing_number, :account_number].each do |attr| - errors << [attr, "cannot be empty"] if empty?(self.send(attr)) + errors << [attr, 'cannot be empty'] if empty?(self.send(attr)) end - errors << [:routing_number, "is invalid"] unless valid_routing_number? + errors << [:routing_number, 'is invalid'] unless valid_routing_number? if(!empty?(account_holder_type) && !%w[business personal].include?(account_holder_type.to_s)) - errors << [:account_holder_type, "must be personal or business"] + errors << [:account_holder_type, 'must be personal or business'] end if(!empty?(account_type) && !%w[checking savings].include?(account_type.to_s)) - errors << [:account_type, "must be checking or savings"] + errors << [:account_type, 'must be checking or savings'] end errors_hash(errors) @@ -53,12 +54,13 @@ def type def credit_card? false end + # Routing numbers may be validated by calculating a checksum and dividing it by 10. The # formula is: # (3(d1 + d4 + d7) + 7(d2 + d5 + d8) + 1(d3 + d6 + d9))mod 10 = 0 # See http://en.wikipedia.org/wiki/Routing_transit_number#Internal_checksums def valid_routing_number? - digits = routing_number.to_s.split('').map(&:to_i).select{|d| (0..9).include?(d)} + digits = routing_number.to_s.split('').map(&:to_i).select { |d| (0..9).cover?(d) } case digits.size when 9 checksum = ((3 * (digits[0] + digits[3] + digits[6])) + diff --git a/lib/active_merchant/billing/compatibility.rb b/lib/active_merchant/billing/compatibility.rb index 09dcfbf569d..11103dcee68 100644 --- a/lib/active_merchant/billing/compatibility.rb +++ b/lib/active_merchant/billing/compatibility.rb @@ -27,11 +27,9 @@ def self.deprecated def self.humanize(lower_case_and_underscored_word) result = lower_case_and_underscored_word.to_s.dup - result.gsub!(/_id$/, "") + result.gsub!(/_id$/, '') result.gsub!(/_/, ' ') - result.gsub(/([a-z\d]*)/i) { |match| - match.downcase - }.gsub(/^\w/) { $&.upcase } + result.gsub(/([a-z\d]*)/i, &:downcase).gsub(/^\w/) { $&.upcase } end end end @@ -63,7 +61,7 @@ def internal_errors class Errors < Hash def initialize - super(){|h, k| h[k] = []} + super() { |h, k| h[k] = [] } end alias count size @@ -77,7 +75,7 @@ def []=(key, value) end def empty? - all?{|k, v| v && v.empty?} + all? { |k, v| v&.empty? } end def on(field) @@ -93,7 +91,7 @@ def add_to_base(error) end def each_full - full_messages.each{|msg| yield msg} + full_messages.each { |msg| yield msg } end def full_messages @@ -102,7 +100,7 @@ def full_messages self.each do |key, messages| next unless(messages && !messages.empty?) if key == 'base' - result << "#{messages.first}" + result << messages.first.to_s else result << "#{Compatibility.humanize(key)} #{messages.first}" end @@ -117,4 +115,3 @@ def full_messages Compatibility::Model.send(:include, Rails::Model) end end - diff --git a/lib/active_merchant/billing/credit_card.rb b/lib/active_merchant/billing/credit_card.rb index 3e7a344ee11..d48f1d2b769 100644 --- a/lib/active_merchant/billing/credit_card.rb +++ b/lib/active_merchant/billing/credit_card.rb @@ -1,6 +1,6 @@ require 'time' require 'date' -require "active_merchant/billing/model" +require 'active_merchant/billing/model' module ActiveMerchant #:nodoc: module Billing #:nodoc: @@ -15,12 +15,9 @@ module Billing #:nodoc: # * American Express # * Diner's Club # * JCB - # * Switch - # * Solo # * Dankort # * Maestro # * Forbrugsforeningen - # * Laser # # For testing purposes, use the 'bogus' credit card brand. This skips the vast majority of # validations, allowing you to focus on your core concerns until you're ready to be more concerned @@ -65,7 +62,7 @@ class << self attr_reader :number def number=(value) - @number = (empty?(value) ? value : value.to_s.gsub(/[^\d]/, "")) + @number = (empty?(value) ? value : value.to_s.gsub(/[^\d]/, '')) end # Returns or sets the expiry month for the card. @@ -88,12 +85,9 @@ def number=(value) # * +'american_express'+ # * +'diners_club'+ # * +'jcb'+ - # * +'switch'+ - # * +'solo'+ # * +'dankort'+ # * +'maestro'+ # * +'forbrugsforeningen'+ - # * +'laser'+ # # Or, if you wish to test your implementation, +'bogus'+. # @@ -121,10 +115,6 @@ def brand=(value) # @return [String] attr_accessor :last_name - # Required for Switch / Solo cards - attr_reader :start_month, :start_year - attr_accessor :issue_number - # Returns or sets the card verification value. # # This attribute is optional but recommended. The verification value is @@ -176,21 +166,20 @@ def requires_verification_value? # @return [String] attr_accessor :icc_data - # Returns or sets a fallback reason for a EMV transaction whereby the customer's card entered a fallback scenario. - # This can be an arbitrary string. + # Returns or sets information about the source of the card data. # # @return [String] - attr_accessor :fallback_reason - - # Returns or sets whether card-present EMV data has been read contactlessly. - # - # @return [true, false] - attr_accessor :contactless_emv - - # Returns or sets whether card-present magstripe data has been read contactlessly. - # - # @return [true, false] - attr_accessor :contactless_magstripe + attr_accessor :read_method + + READ_METHOD_DESCRIPTIONS = { + nil => 'A card reader was not used.', + 'fallback_no_chip' => 'Magstripe was read because the card has no chip.', + 'fallback_chip_error' => "Magstripe was read because the card's chip failed.", + 'contactless' => 'Data was read by a Contactless EMV kernel. Issuer script results are not available.', + 'contactless_magstripe' => 'Contactless data was read with a non-EMV protocol.', + 'contact' => 'Data was read using the EMV protocol. Issuer script results may follow.', + 'contact_quickchip' => 'Data was read by the Quickchip EMV kernel. Issuer script results are not available.', + } # Returns the ciphertext of the card's encrypted PIN. # @@ -203,12 +192,12 @@ def requires_verification_value? attr_accessor :encrypted_pin_ksn def type - ActiveMerchant.deprecated "CreditCard#type is deprecated and will be removed from a future release of ActiveMerchant. Please use CreditCard#brand instead." + ActiveMerchant.deprecated 'CreditCard#type is deprecated and will be removed from a future release of ActiveMerchant. Please use CreditCard#brand instead.' brand end def type=(value) - ActiveMerchant.deprecated "CreditCard#type is deprecated and will be removed from a future release of ActiveMerchant. Please use CreditCard#brand instead." + ActiveMerchant.deprecated 'CreditCard#type is deprecated and will be removed from a future release of ActiveMerchant. Please use CreditCard#brand instead.' self.brand = value end @@ -251,7 +240,7 @@ def name def name=(full_name) names = full_name.split self.last_name = names.pop - self.first_name = names.join(" ") + self.first_name = names.join(' ') end %w(month year start_month start_year).each do |m| @@ -304,8 +293,7 @@ def validate errors_hash( errors + - validate_card_brand_and_number + - validate_switch_or_solo_attributes + validate_card_brand_and_number ) end @@ -327,20 +315,20 @@ def validate_essential_attributes #:nodoc: errors = [] if self.class.requires_name? - errors << [:first_name, "cannot be empty"] if first_name.blank? - errors << [:last_name, "cannot be empty"] if last_name.blank? + errors << [:first_name, 'cannot be empty'] if first_name.blank? + errors << [:last_name, 'cannot be empty'] if last_name.blank? end if(empty?(month) || empty?(year)) - errors << [:month, "is required"] if empty?(month) - errors << [:year, "is required"] if empty?(year) + errors << [:month, 'is required'] if empty?(month) + errors << [:year, 'is required'] if empty?(year) else - errors << [:month, "is not a valid month"] if !valid_month?(month) + errors << [:month, 'is not a valid month'] if !valid_month?(month) if expired? - errors << [:year, "expired"] + errors << [:year, 'expired'] else - errors << [:year, "is not a valid year"] if !valid_expiry_year?(year) + errors << [:year, 'is not a valid year'] if !valid_expiry_year?(year) end end @@ -351,17 +339,17 @@ def validate_card_brand_and_number #:nodoc: errors = [] if !empty?(brand) - errors << [:brand, "is invalid"] if !CreditCard.card_companies.keys.include?(brand) + errors << [:brand, 'is invalid'] if !CreditCard.card_companies.include?(brand) end if empty?(number) - errors << [:number, "is required"] + errors << [:number, 'is required'] elsif !CreditCard.valid_number?(number) - errors << [:number, "is not a valid credit card number"] + errors << [:number, 'is not a valid credit card number'] end if errors.empty? - errors << [:brand, "does not match the card number"] if !CreditCard.matching_brand?(number, brand) + errors << [:brand, 'does not match the card number'] if !CreditCard.matching_brand?(number, brand) end errors @@ -375,29 +363,8 @@ def validate_verification_value #:nodoc: errors << [:verification_value, "should be #{card_verification_value_length(brand)} digits"] end elsif requires_verification_value? - errors << [:verification_value, "is required"] - end - errors - end - - def validate_switch_or_solo_attributes #:nodoc: - errors = [] - - if %w[switch solo].include?(brand) - valid_start_month = valid_month?(start_month) - valid_start_year = valid_start_year?(start_year) - - if((!valid_start_month || !valid_start_year) && !valid_issue_number?(issue_number)) - if empty?(issue_number) - errors << [:issue_number, "cannot be empty"] - errors << [:start_month, "is invalid"] if !valid_start_month - errors << [:start_year, "is invalid"] if !valid_start_year - else - errors << [:issue_number, "is invalid"] if !valid_issue_number?(issue_number) - end - end + errors << [:verification_value, 'is required'] end - errors end @@ -413,16 +380,15 @@ def expired? #:nodoc: end def expiration #:nodoc: - begin - Time.utc(year, month, month_days, 23, 59, 59) - rescue ArgumentError - Time.at(0).utc - end + Time.utc(year, month, month_days, 23, 59, 59) + rescue ArgumentError + Time.at(0).utc end private + def month_days - mdays = [nil,31,28,31,30,31,30,31,31,30,31,30,31] + mdays = [nil, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] mdays[2] = 29 if Date.leap?(year) mdays[month] end diff --git a/lib/active_merchant/billing/credit_card_formatting.rb b/lib/active_merchant/billing/credit_card_formatting.rb index 63ce2a93b2e..2a55bae60ad 100644 --- a/lib/active_merchant/billing/credit_card_formatting.rb +++ b/lib/active_merchant/billing/credit_card_formatting.rb @@ -1,7 +1,6 @@ module ActiveMerchant #:nodoc: module Billing #:nodoc: module CreditCardFormatting - def expdate(credit_card) "#{format(credit_card.month, :two_digits)}#{format(credit_card.year, :two_digits)}" end @@ -14,9 +13,9 @@ def format(number, option) return '' if number.blank? case option - when :two_digits ; sprintf("%.2i", number.to_i)[-2..-1] - when :four_digits ; sprintf("%.4i", number.to_i)[-4..-1] - else number + when :two_digits then sprintf('%.2i', number.to_i)[-2..-1] + when :four_digits then sprintf('%.4i', number.to_i)[-4..-1] + else number end end end diff --git a/lib/active_merchant/billing/credit_card_methods.rb b/lib/active_merchant/billing/credit_card_methods.rb index a76a148fadd..05f07e46667 100644 --- a/lib/active_merchant/billing/credit_card_methods.rb +++ b/lib/active_merchant/billing/credit_card_methods.rb @@ -2,19 +2,24 @@ module ActiveMerchant #:nodoc: module Billing #:nodoc: # Convenience methods that can be included into a custom Credit Card object, such as an ActiveRecord based Credit Card object. module CreditCardMethods - CARD_COMPANIES = { - 'visa' => /^4\d{12}(\d{3})?(\d{3})?$/, - 'master' => /^(5[1-5]\d{4}|677189|222[1-9]\d{2}|22[3-9]\d{3}|2[3-6]\d{4}|27[01]\d{3}|2720\d{2})\d{10}$/, - 'discover' => /^(6011|65\d{2}|64[4-9]\d)\d{12}|(62\d{14})$/, - 'american_express' => /^3[47]\d{13}$/, - 'diners_club' => /^3(0[0-5]|[68]\d)\d{11}$/, - 'jcb' => /^35(28|29|[3-8]\d)\d{12}$/, - 'switch' => /^6759\d{12}(\d{2,3})?$/, - 'solo' => /^6767\d{12}(\d{2,3})?$/, - 'dankort' => /^5019\d{12}$/, - 'maestro' => /^(5[06-8]|6\d)\d{10,17}$/, - 'forbrugsforeningen' => /^600722\d{10}$/, - 'laser' => /^(6304|6706|6709|6771(?!89))\d{8}(\d{4}|\d{6,7})?$/ + CARD_COMPANY_DETECTORS = { + 'visa' => ->(num) { num =~ /^4\d{12}(\d{3})?(\d{3})?$/ }, + 'master' => ->(num) { num&.size == 16 && in_bin_range?(num.slice(0, 6), MASTERCARD_RANGES) }, + 'discover' => ->(num) { num =~ /^(6011|65\d{2}|64[4-9]\d)\d{12}|(62\d{14})$/ }, + 'american_express' => ->(num) { num =~ /^3[47]\d{13}$/ }, + 'diners_club' => ->(num) { num =~ /^3(0[0-5]|[68]\d)\d{11}$/ }, + 'jcb' => ->(num) { num =~ /^35(28|29|[3-8]\d)\d{12}$/ }, + 'dankort' => ->(num) { num =~ /^5019\d{12}$/ }, + 'maestro' => ->(num) { (12..19).cover?(num&.size) && in_bin_range?(num.slice(0, 6), MAESTRO_RANGES) }, + 'forbrugsforeningen' => ->(num) { num =~ /^600722\d{10}$/ }, + 'sodexo' => ->(num) { num =~ /^(606071|603389|606070|606069|606068|600818)\d{8}$/ }, + 'vr' => ->(num) { num =~ /^(627416|637036)\d{8}$/ }, + 'carnet' => lambda { |num| + num&.size == 16 && ( + in_bin_range?(num.slice(0, 6), CARNET_RANGES) || + CARNET_BINS.any? { |bin| num.slice(0, bin.size) == bin } + ) + } } # http://www.barclaycard.co.uk/business/files/bin_rules.pdf @@ -37,12 +42,43 @@ module CreditCardMethods (491730..491759), ] + CARNET_RANGES = [ + (506199..506499), + ] + + CARNET_BINS = Set.new( + [ + '286900', '502275', '606333', '627535', '636318', '636379', '639388', + '639484', '639559', '50633601', '50633606', '58877274', '62753500', + '60462203', '60462204', '588772' + ] + ) + + # https://www.mastercard.us/content/dam/mccom/global/documents/mastercard-rules.pdf, page 73 + MASTERCARD_RANGES = [ + (222100..272099), + (510000..559999), + ] + + # https://www.mastercard.us/content/dam/mccom/global/documents/mastercard-rules.pdf, page 73 + MAESTRO_RANGES = [ + (639000..639099), + (670000..679999), + ] + def self.included(base) base.extend(ClassMethods) end + def self.in_bin_range?(number, ranges) + bin = number.to_i + ranges.any? do |range| + range.cover?(bin) + end + end + def valid_month?(month) - (1..12).include?(month.to_i) + (1..12).cover?(month.to_i) end def credit_card? @@ -50,7 +86,7 @@ def credit_card? end def valid_expiry_year?(year) - (Time.now.year..Time.now.year + 20).include?(year.to_i) + (Time.now.year..Time.now.year + 20).cover?(year.to_i) end def valid_start_year?(year) @@ -75,7 +111,14 @@ def valid_card_verification_value?(cvv, brand) end def card_verification_value_length(brand) - brand == 'american_express' ? 4 : 3 + case brand + when 'american_express' + 4 + when 'maestro' + 0 + else + 3 + end end def valid_issue_number?(number) @@ -101,42 +144,23 @@ def valid_number?(number) valid_checksum?(number) end - # Regular expressions for the known card companies. - # - # References: - # - http://en.wikipedia.org/wiki/Credit_card_number - # - http://www.barclaycardbusiness.co.uk/information_zone/processing/bin_rules.html def card_companies - CARD_COMPANIES + CARD_COMPANY_DETECTORS.keys end # Returns a string containing the brand of card from the list of known information below. - # Need to check the cards in a particular order, as there is some overlap of the allowable ranges - #-- - # TODO Refactor this method. We basically need to tighten up the Maestro Regexp. - # - # Right now the Maestro regexp overlaps with the MasterCard regexp (IIRC). If we can tighten - # things up, we can boil this whole thing down to something like... - # - # def brand?(number) - # return 'visa' if valid_test_mode_card_number?(number) - # card_companies.find([nil]) { |brand, regexp| number =~ regexp }.first.dup - # end - # def brand?(number) return 'bogus' if valid_test_mode_card_number?(number) - card_companies.reject { |c,p| c == 'maestro' }.each do |company, pattern| - return company.dup if number =~ pattern + CARD_COMPANY_DETECTORS.each do |company, func| + return company.dup if func.call(number) end - return 'maestro' if number =~ card_companies['maestro'] - return nil end def electron?(number) - return false unless [16, 19].include?(number.length) + return false unless [16, 19].include?(number&.length) # don't recalculate for each range bank_identification_number = first_digits(number).to_i @@ -147,16 +171,17 @@ def electron?(number) end def type?(number) - ActiveMerchant.deprecated "CreditCard#type? is deprecated and will be removed from a future release of ActiveMerchant. Please use CreditCard#brand? instead." + ActiveMerchant.deprecated 'CreditCard#type? is deprecated and will be removed from a future release of ActiveMerchant. Please use CreditCard#brand? instead.' brand?(number) end def first_digits(number) - number.to_s.slice(0,6) + number&.slice(0, 6) || '' end def last_digits(number) - number.to_s.length <= 4 ? number : number.to_s.slice(-4..-1) + return '' if number.nil? + number.length <= 4 ? number : number.slice(-4..-1) end def mask(number) @@ -169,23 +194,25 @@ def matching_brand?(number, brand) end def matching_type?(number, brand) - ActiveMerchant.deprecated "CreditCard#matching_type? is deprecated and will be removed from a future release of ActiveMerchant. Please use CreditCard#matching_brand? instead." + ActiveMerchant.deprecated 'CreditCard#matching_type? is deprecated and will be removed from a future release of ActiveMerchant. Please use CreditCard#matching_brand? instead.' matching_brand?(number, brand) end private def valid_card_number_length?(number) #:nodoc: - number.to_s.length >= 12 + return false if number.nil? + number.length >= 12 end def valid_card_number_characters?(number) #:nodoc: - !number.to_s.match(/\D/) + return false if number.nil? + !number.match(/\D/) end def valid_test_mode_card_number?(number) #:nodoc: ActiveMerchant::Billing::Base.test? && - %w[1 2 3 success failure error].include?(number.to_s) + %w[1 2 3 success failure error].include?(number) end ODD_LUHN_VALUE = { diff --git a/lib/active_merchant/billing/gateway.rb b/lib/active_merchant/billing/gateway.rb index 52c945c0774..29fcc6bbaf8 100644 --- a/lib/active_merchant/billing/gateway.rb +++ b/lib/active_merchant/billing/gateway.rb @@ -56,10 +56,8 @@ class Gateway include PostsData include CreditCardFormatting - DEBIT_CARDS = [ :switch, :solo ] - - CREDIT_DEPRECATION_MESSAGE = "Support for using credit to refund existing transactions is deprecated and will be removed from a future release of ActiveMerchant. Please use the refund method instead." - RECURRING_DEPRECATION_MESSAGE = "Recurring functionality in ActiveMerchant is deprecated and will be removed in a future version. Please contact the ActiveMerchant maintainers if you have an interest in taking ownership of a separate gem that continues support for it." + CREDIT_DEPRECATION_MESSAGE = 'Support for using credit to refund existing transactions is deprecated and will be removed from a future release of ActiveMerchant. Please use the refund method instead.' + RECURRING_DEPRECATION_MESSAGE = 'Recurring functionality in ActiveMerchant is deprecated and will be removed in a future version. Please contact the ActiveMerchant maintainers if you have an interest in taking ownership of a separate gem that continues support for it.' # == Standardized Error Codes # @@ -125,8 +123,9 @@ def generate_unique_id class_attribute :supported_cardtypes self.supported_cardtypes = [] - class_attribute :currencies_without_fractions - self.currencies_without_fractions = %w(BIF BYR CLP CVE DJF GNF HUF ISK JPY KMF KRW PYG RWF UGX VND VUV XAF XOF XPF) + class_attribute :currencies_without_fractions, :currencies_with_three_decimal_places + self.currencies_without_fractions = %w(BIF BYR CLP CVE DJF GNF ISK JPY KMF KRW PYG RWF UGX VND VUV XAF XOF XPF) + self.currencies_with_three_decimal_places = %w() class_attribute :homepage_url class_attribute :display_name @@ -194,7 +193,7 @@ def supports_scrubbing? end def scrub(transcript) - raise RuntimeError.new("This gateway does not support scrubbing.") + raise 'This gateway does not support scrubbing.' end def supports_network_tokenization? @@ -205,11 +204,11 @@ def supports_network_tokenization? def normalize(field) case field - when "true" then true - when "false" then false - when "" then nil - when "null" then nil - else field + when 'true' then true + when 'false' then false + when '' then nil + when 'null' then nil + else field end end @@ -242,10 +241,10 @@ def name def amount(money) return nil if money.nil? cents = if money.respond_to?(:cents) - ActiveMerchant.deprecated "Support for Money objects is deprecated and will be removed from a future release of ActiveMerchant. Please use an Integer value in cents" - money.cents - else - money + ActiveMerchant.deprecated 'Support for Money objects is deprecated and will be removed from a future release of ActiveMerchant. Please use an Integer value in cents' + money.cents + else + money end if money.is_a?(String) @@ -255,7 +254,7 @@ def amount(money) if self.money_format == :cents cents.to_s else - sprintf("%.2f", cents.to_f / 100) + sprintf('%.2f', cents.to_f / 100) end end @@ -263,15 +262,26 @@ def non_fractional_currency?(currency) self.currencies_without_fractions.include?(currency.to_s) end + def three_decimal_currency?(currency) + self.currencies_with_three_decimal_places.include?(currency.to_s) + end + def localized_amount(money, currency) amount = amount(money) - return amount unless non_fractional_currency?(currency) - - if self.money_format == :cents - sprintf("%.0f", amount.to_f / 100) - else - amount.split('.').first + return amount unless non_fractional_currency?(currency) || three_decimal_currency?(currency) + if non_fractional_currency?(currency) + if self.money_format == :cents + sprintf('%.0f', amount.to_f / 100) + else + amount.split('.').first + end + elsif three_decimal_currency?(currency) + if self.money_format == :cents + amount.to_s + else + sprintf('%.3f', (amount.to_f / 10)) + end end end @@ -285,19 +295,14 @@ def truncate(value, max_size) end def split_names(full_name) - names = (full_name || "").split + names = (full_name || '').split return [nil, nil] if names.size == 0 last_name = names.pop - first_name = names.join(" ") + first_name = names.join(' ') [first_name, last_name] end - def requires_start_date_or_issue_number?(credit_card) - return false if card_brand(credit_card).blank? - DEBIT_CARDS.include?(card_brand(credit_card).to_sym) - end - def requires!(hash, *params) params.each do |param| if param.is_a?(Array) diff --git a/lib/active_merchant/billing/gateways/adyen.rb b/lib/active_merchant/billing/gateways/adyen.rb new file mode 100644 index 00000000000..2e7b5ba1eb9 --- /dev/null +++ b/lib/active_merchant/billing/gateways/adyen.rb @@ -0,0 +1,362 @@ +module ActiveMerchant #:nodoc: + module Billing #:nodoc: + class AdyenGateway < Gateway + + # we recommend setting up merchant-specific endpoints. + # https://docs.adyen.com/developers/api-manual#apiendpoints + self.test_url = 'https://pal-test.adyen.com/pal/servlet/Payment/v18' + self.live_url = 'https://pal-live.adyen.com/pal/servlet/Payment/v18' + + self.supported_countries = ['AT', 'AU', 'BE', 'BG', 'BR', 'CH', 'CY', 'CZ', 'DE', 'DK', 'EE', 'ES', 'FI', 'FR', 'GB', 'GI', 'GR', 'HK', 'HU', 'IE', 'IS', 'IT', 'LI', 'LT', 'LU', 'LV', 'MC', 'MT', 'MX', 'NL', 'NO', 'PL', 'PT', 'RO', 'SE', 'SG', 'SK', 'SI', 'US'] + self.default_currency = 'USD' + self.supported_cardtypes = [:visa, :master, :american_express, :diners_club, :jcb, :dankort, :maestro, :discover] + + self.money_format = :cents + + self.homepage_url = 'https://www.adyen.com/' + self.display_name = 'Adyen' + + STANDARD_ERROR_CODE_MAPPING = { + '101' => STANDARD_ERROR_CODE[:incorrect_number], + '103' => STANDARD_ERROR_CODE[:invalid_cvc], + '131' => STANDARD_ERROR_CODE[:incorrect_address], + '132' => STANDARD_ERROR_CODE[:incorrect_address], + '133' => STANDARD_ERROR_CODE[:incorrect_address], + '134' => STANDARD_ERROR_CODE[:incorrect_address], + '135' => STANDARD_ERROR_CODE[:incorrect_address], + } + + def initialize(options={}) + requires!(options, :username, :password, :merchant_account) + @username, @password, @merchant_account = options.values_at(:username, :password, :merchant_account) + super + end + + def purchase(money, payment, options={}) + MultiResponse.run do |r| + r.process { authorize(money, payment, options) } + r.process { capture(money, r.authorization, options) } + end + end + + def authorize(money, payment, options={}) + requires!(options, :order_id) + post = init_post(options) + add_invoice(post, money, options) + add_payment(post, payment) + add_extra_data(post, payment, options) + add_shopper_interaction(post, payment, options) + add_address(post, options) + add_installments(post, options) if options[:installments] + commit('authorise', post) + end + + def capture(money, authorization, options={}) + post = init_post(options) + add_invoice_for_modification(post, money, options) + add_reference(post, authorization, options) + commit('capture', post) + end + + def refund(money, authorization, options={}) + post = init_post(options) + add_invoice_for_modification(post, money, options) + add_original_reference(post, authorization, options) + commit('refund', post) + end + + def void(authorization, options={}) + post = init_post(options) + add_reference(post, authorization, options) + commit('cancel', post) + end + + def store(credit_card, options={}) + requires!(options, :order_id) + post = init_post(options) + add_invoice(post, 0, options) + add_payment(post, credit_card) + add_extra_data(post, credit_card, options) + add_recurring_contract(post, options) + add_address(post, options) + commit('authorise', post) + end + + def verify(credit_card, options={}) + MultiResponse.run(:use_first_response) do |r| + r.process { authorize(0, credit_card, options) } + r.process(:ignore_result) { void(r.authorization, options) } + end + end + + def supports_scrubbing? + true + end + + def scrub(transcript) + transcript. + gsub(%r((Authorization: Basic )\w+), '\1[FILTERED]'). + gsub(%r(("number\\?":\\?")[^"]*)i, '\1[FILTERED]'). + gsub(%r(("cvc\\?":\\?")[^"]*)i, '\1[FILTERED]'). + gsub(%r(("cavv\\?":\\?")[^"]*)i, '\1[FILTERED]') + end + + private + + AVS_MAPPING = { + '0' => 'R', # Unknown + '1' => 'A', # Address matches, postal code doesn't + '2' => 'N', # Neither postal code nor address match + '3' => 'R', # AVS unavailable + '4' => 'E', # AVS not supported for this card type + '5' => 'U', # No AVS data provided + '6' => 'Z', # Postal code matches, address doesn't match + '7' => 'D', # Both postal code and address match + '8' => 'U', # Address not checked, postal code unknown + '9' => 'B', # Address matches, postal code unknown + '10' => 'N', # Address doesn't match, postal code unknown + '11' => 'U', # Postal code not checked, address unknown + '12' => 'B', # Address matches, postal code not checked + '13' => 'U', # Address doesn't match, postal code not checked + '14' => 'P', # Postal code matches, address unknown + '15' => 'P', # Postal code matches, address not checked + '16' => 'N', # Postal code doesn't match, address unknown + '17' => 'U', # Postal code doesn't match, address not checked + '18' => 'I' # Neither postal code nor address were checked + } + + CVC_MAPPING = { + '0' => 'P', # Unknown + '1' => 'M', # Matches + '2' => 'N', # Does not match + '3' => 'P', # Not checked + '4' => 'S', # No CVC/CVV provided, but was required + '5' => 'U', # Issuer not certifed by CVC/CVV + '6' => 'P' # No CVC/CVV provided + } + + NETWORK_TOKENIZATION_CARD_SOURCE = { + 'apple_pay' => 'applepay', + 'android_pay' => 'androidpay', + 'google_pay' => 'paywithgoogle' + } + + def add_extra_data(post, payment, options) + post[:shopperEmail] = options[:shopper_email] if options[:shopper_email] + post[:shopperIP] = options[:shopper_ip] if options[:shopper_ip] + post[:shopperReference] = options[:shopper_reference] if options[:shopper_reference] + post[:fraudOffset] = options[:fraud_offset] if options[:fraud_offset] + post[:selectedBrand] = options[:selected_brand] if options[:selected_brand] + post[:selectedBrand] ||= NETWORK_TOKENIZATION_CARD_SOURCE[payment.source.to_s] if payment.is_a?(NetworkTokenizationCreditCard) + post[:deliveryDate] = options[:delivery_date] if options[:delivery_date] + post[:merchantOrderReference] = options[:merchant_order_reference] if options[:merchant_order_reference] + post[:additionalData] ||= {} + post[:additionalData][:overwriteBrand] = normalize(options[:overwrite_brand]) if options[:overwrite_brand] + post[:additionalData][:customRoutingFlag] = options[:custom_routing_flag] if options[:custom_routing_flag] + post[:additionalData]['paymentdatasource.type'] = NETWORK_TOKENIZATION_CARD_SOURCE[payment.source.to_s] if payment.is_a?(NetworkTokenizationCreditCard) + end + + def add_shopper_interaction(post, payment, options={}) + if (payment.respond_to?(:verification_value) && payment.verification_value) || payment.is_a?(NetworkTokenizationCreditCard) + shopper_interaction = 'Ecommerce' + else + shopper_interaction = 'ContAuth' + end + + post[:shopperInteraction] = options[:shopper_interaction] || shopper_interaction + end + + def add_address(post, options) + return unless post[:card]&.kind_of?(Hash) + if (address = options[:billing_address] || options[:address]) && address[:country] + post[:card][:billingAddress] = {} + post[:card][:billingAddress][:street] = address[:address1] || 'N/A' + post[:card][:billingAddress][:houseNumberOrName] = address[:address2] || 'N/A' + post[:card][:billingAddress][:postalCode] = address[:zip] if address[:zip] + post[:card][:billingAddress][:city] = address[:city] || 'N/A' + post[:card][:billingAddress][:stateOrProvince] = address[:state] if address[:state] + post[:card][:billingAddress][:country] = address[:country] if address[:country] + end + end + + def add_invoice(post, money, options) + amount = { + value: amount(money), + currency: options[:currency] || currency(money) + } + post[:amount] = amount + post[:recurringProcessingModel] = options[:recurring_processing_model] if options[:recurring_processing_model] + end + + def add_invoice_for_modification(post, money, options) + amount = { + value: amount(money), + currency: options[:currency] || currency(money) + } + post[:modificationAmount] = amount + end + + def add_payment(post, payment) + if payment.is_a?(String) + _, _, recurring_detail_reference = payment.split('#') + post[:selectedRecurringDetailReference] = recurring_detail_reference + add_recurring_contract(post, options) + else + add_mpi_data_for_network_tokenization_card(post, payment) if payment.is_a?(NetworkTokenizationCreditCard) + add_card(post, payment) + end + end + + def add_card(post, credit_card) + card = { + expiryMonth: credit_card.month, + expiryYear: credit_card.year, + holderName: credit_card.name, + number: credit_card.number, + cvc: credit_card.verification_value + } + + card.delete_if { |k, v| v.blank? } + card[:holderName] ||= 'Not Provided' if credit_card.is_a?(NetworkTokenizationCreditCard) + requires!(card, :expiryMonth, :expiryYear, :holderName, :number) + post[:card] = card + end + + def add_reference(post, authorization, options = {}) + _, psp_reference, _ = authorization.split('#') + post[:originalReference] = single_reference(authorization) || psp_reference + end + + def add_original_reference(post, authorization, options = {}) + original_psp_reference, _, _ = authorization.split('#') + post[:originalReference] = single_reference(authorization) || original_psp_reference + end + + def add_mpi_data_for_network_tokenization_card(post, payment) + post[:mpiData] = {} + post[:mpiData][:authenticationResponse] = 'Y' + post[:mpiData][:cavv] = payment.payment_cryptogram + post[:mpiData][:directoryResponse] = 'Y' + post[:mpiData][:eci] = payment.eci || '07' + end + + def single_reference(authorization) + authorization if !authorization.include?('#') + end + + def add_recurring_contract(post, options = {}) + recurring = { + contract: 'RECURRING' + } + + post[:recurring] = recurring + end + + def add_installments(post, options) + post[:installments] = { + value: options[:installments] + } + end + + def parse(body) + return {} if body.blank? + JSON.parse(body) + end + + def commit(action, parameters) + begin + raw_response = ssl_post("#{url}/#{action}", post_data(action, parameters), request_headers) + response = parse(raw_response) + rescue ResponseError => e + raw_response = e.response.body + response = parse(raw_response) + end + success = success_from(action, response) + Response.new( + success, + message_from(action, response), + response, + authorization: authorization_from(action, parameters, response), + test: test?, + error_code: success ? nil : error_code_from(response), + avs_result: AVSResult.new(:code => avs_code_from(response)), + cvv_result: CVVResult.new(cvv_result_from(response)) + ) + end + + def avs_code_from(response) + AVS_MAPPING[response['additionalData']['avsResult'][0..1].strip] if response.dig('additionalData', 'avsResult') + end + + def cvv_result_from(response) + CVC_MAPPING[response['additionalData']['cvcResult'][0]] if response.dig('additionalData', 'cvcResult') + end + + def url + if test? + test_url + elsif @options[:subdomain] + "https://#{@options[:subdomain]}-pal-live.adyenpayments.com/pal/servlet/Payment/v18" + else + live_url + end + end + + def basic_auth + Base64.strict_encode64("#{@username}:#{@password}") + end + + def request_headers + { + 'Content-Type' => 'application/json', + 'Authorization' => "Basic #{basic_auth}" + } + end + + def success_from(action, response) + case action.to_s + when 'authorise' + ['Authorised', 'Received', 'RedirectShopper'].include?(response['resultCode']) + when 'capture', 'refund', 'cancel' + response['response'] == "[#{action}-received]" + else + false + end + end + + def message_from(action, response) + return authorize_message_from(response) if action.to_s == 'authorise' + response['response'] || response['message'] + end + + def authorize_message_from(response) + if response['refusalReason'] && response['additionalData'] && response['additionalData']['refusalReasonRaw'] + "#{response['refusalReason']} | #{response['additionalData']['refusalReasonRaw']}" + else + response['refusalReason'] || response['resultCode'] || response['message'] + end + end + + def authorization_from(action, parameters, response) + return nil if response['pspReference'].nil? + recurring = response['additionalData']['recurring.recurringDetailReference'] if response['additionalData'] + "#{parameters[:originalReference]}##{response['pspReference']}##{recurring}" + end + + def init_post(options = {}) + post = {} + post[:merchantAccount] = options[:merchant_account] || @merchant_account + post[:reference] = options[:order_id] if options[:order_id] + post + end + + def post_data(action, parameters = {}) + JSON.generate(parameters) + end + + def error_code_from(response) + STANDARD_ERROR_CODE_MAPPING[response['errorCode']] + end + end + end +end diff --git a/lib/active_merchant/billing/gateways/allied_wallet.rb b/lib/active_merchant/billing/gateways/allied_wallet.rb index fb4ecd7f12a..8cdbd6f4eaa 100644 --- a/lib/active_merchant/billing/gateways/allied_wallet.rb +++ b/lib/active_merchant/billing/gateways/allied_wallet.rb @@ -1,13 +1,13 @@ module ActiveMerchant #:nodoc: module Billing #:nodoc: class AlliedWalletGateway < Gateway - self.display_name = "Allied Wallet" - self.homepage_url = "https://www.alliedwallet.com" + self.display_name = 'Allied Wallet' + self.homepage_url = 'https://www.alliedwallet.com' - self.live_url = "https://api.alliedwallet.com/merchants/" + self.live_url = 'https://api.alliedwallet.com/merchants/' - self.supported_countries = ["US"] - self.default_currency = "USD" + self.supported_countries = ['US'] + self.default_currency = 'USD' self.money_format = :dollars self.supported_cardtypes = [:visa, :master, :american_express, :discover, :diners_club, :jcb, :maestro] @@ -104,7 +104,7 @@ def add_payment_method(post, payment_method) end def add_customer_data(post, options) - post[:email] = options[:email] || "unspecified@example.com" + post[:email] = options[:email] || 'unspecified@example.com' post[:iPAddress] = options[:ip] if (billing_address = options[:billing_address]) post[:firstName], post[:lastName] = split_names(billing_address[:name]) @@ -128,13 +128,12 @@ def add_reference(post, authorization, action) post[transactions[action]] = authorization end - ACTIONS = { - purchase: "SALE", - authorize: "AUTHORIZE", - capture: "CAPTURE", - void: "VOID", - refund: "REFUND" + purchase: 'SALE', + authorize: 'AUTHORIZE', + capture: 'CAPTURE', + void: 'VOID', + refund: 'REFUND' } def commit(action, post) @@ -146,14 +145,14 @@ def commit(action, post) response = parse(e.response.body) end - succeeded = success_from(response["status"]) + succeeded = success_from(response['status']) Response.new( succeeded, message_from(succeeded, response), response, - authorization: response["id"], - :avs_result => AVSResult.new(code: response["avs_response"]), - :cvv_result => CVVResult.new(response["cvv2_response"]), + authorization: response['id'], + :avs_result => AVSResult.new(code: response['avs_response']), + :cvv_result => CVVResult.new(response['cvv2_response']), test: test? ) rescue JSON::ParserError @@ -161,20 +160,20 @@ def commit(action, post) end def unparsable_response(raw_response) - message = "Unparsable response received from Allied Wallet. Please contact Allied Wallet if you continue to receive this message." + message = 'Unparsable response received from Allied Wallet. Please contact Allied Wallet if you continue to receive this message.' message += " (The raw response returned by the API was #{raw_response.inspect})" return Response.new(false, message) end def headers { - "Content-type" => "application/json", - "Authorization" => "Bearer " + @options[:token] + 'Content-type' => 'application/json', + 'Authorization' => 'Bearer ' + @options[:token] } end def url(action) - live_url + CGI.escape(@options[:merchant_id]) + "/" + ACTIONS[action] + "transactions" + live_url + CGI.escape(@options[:merchant_id]) + '/' + ACTIONS[action] + 'transactions' end def parse(body) @@ -183,21 +182,21 @@ def parse(body) def parse_element(response, node) if node.has_elements? - node.elements.each{|element| parse_element(response, element) } + node.elements.each { |element| parse_element(response, element) } else response[node.name.underscore.to_sym] = node.text end end def success_from(response) - response == "Successful" + response == 'Successful' end def message_from(succeeded, response) if succeeded - "Succeeded" + 'Succeeded' else - response["message"] || "Unable to read error message" + response['message'] || 'Unable to read error message' end end diff --git a/lib/active_merchant/billing/gateways/authorize_net.rb b/lib/active_merchant/billing/gateways/authorize_net.rb index 0c3884f8a69..587537d61c5 100644 --- a/lib/active_merchant/billing/gateways/authorize_net.rb +++ b/lib/active_merchant/billing/gateways/authorize_net.rb @@ -89,9 +89,10 @@ class AuthorizeNetGateway < Gateway 2 => /\A;(?[\d]{1,19}+)=(?[\d]{0,4}|=)(?[\d]{0,3}|=)(?.*)\?\Z/ }.freeze - APPLE_PAY_DATA_DESCRIPTOR = "COMMON.APPLE.INAPP.PAYMENT" + APPLE_PAY_DATA_DESCRIPTOR = 'COMMON.APPLE.INAPP.PAYMENT' - PAYMENT_METHOD_NOT_SUPPORTED_ERROR = "155" + PAYMENT_METHOD_NOT_SUPPORTED_ERROR = '155' + INELIGIBLE_FOR_ISSUING_CREDIT_ERROR = '54' def initialize(options={}) requires!(options, :login, :password) @@ -100,24 +101,24 @@ def initialize(options={}) def purchase(amount, payment, options = {}) if payment.is_a?(String) - commit(:cim_purchase) do |xml| - add_cim_auth_purchase(xml, "profileTransAuthCapture", amount, payment, options) + commit(:cim_purchase, options) do |xml| + add_cim_auth_purchase(xml, 'profileTransAuthCapture', amount, payment, options) end else commit(:purchase) do |xml| - add_auth_purchase(xml, "authCaptureTransaction", amount, payment, options) + add_auth_purchase(xml, 'authCaptureTransaction', amount, payment, options) end end end def authorize(amount, payment, options={}) if payment.is_a?(String) - commit(:cim_authorize) do |xml| - add_cim_auth_purchase(xml, "profileTransAuthOnly", amount, payment, options) + commit(:cim_authorize, options) do |xml| + add_cim_auth_purchase(xml, 'profileTransAuthOnly', amount, payment, options) end else commit(:authorize) do |xml| - add_auth_purchase(xml, "authOnlyTransaction", amount, payment, options) + add_auth_purchase(xml, 'authOnlyTransaction', amount, payment, options) end end end @@ -131,10 +132,19 @@ def capture(amount, authorization, options={}) end def refund(amount, authorization, options={}) - if auth_was_for_cim?(authorization) - cim_refund(amount, authorization, options) + response = if auth_was_for_cim?(authorization) + cim_refund(amount, authorization, options) + else + normal_refund(amount, authorization, options) + end + + return response if response.success? + return response unless options[:force_full_refund_if_unsettled] + + if response.params['response_reason_code'] == INELIGIBLE_FOR_ISSUING_CREDIT_ERROR + void(authorization, options) else - normal_refund(amount, authorization, options) + response end end @@ -148,7 +158,7 @@ def void(authorization, options={}) def credit(amount, payment, options={}) if payment.is_a?(String) - raise ArgumentError, "Reference credits are not supported. Please supply the original credit card or use the #refund method." + raise ArgumentError, 'Reference credits are not supported. Please supply the original credit card or use the #refund method.' end commit(:credit) do |xml| @@ -157,8 +167,9 @@ def credit(amount, payment, options={}) xml.transactionType('refundTransaction') xml.amount(amount(amount)) - add_payment_source(xml, payment) - add_invoice(xml, options) + add_payment_source(xml, payment, options, :credit) + xml.refTransId(transaction_id_from(options[:transaction_id])) if options[:transaction_id] + add_invoice(xml, 'refundTransaction', options) add_customer_data(xml, payment, options) add_settings(xml, payment, options) add_user_fields(xml, amount, options) @@ -188,7 +199,7 @@ def unstore(authorization) end def verify_credentials - response = commit(:verify_credentials) { } + response = commit(:verify_credentials) {} response.success? end @@ -211,7 +222,7 @@ def scrub(transcript) def supports_network_tokenization? card = Billing::NetworkTokenizationCreditCard.new({ - :number => "4111111111111111", + :number => '4111111111111111', :month => 12, :year => 20, :first_name => 'John', @@ -221,7 +232,7 @@ def supports_network_tokenization? }) request = post_data(:authorize) do |xml| - add_auth_purchase(xml, "authOnlyTransaction", 1, card, {}) + add_auth_purchase(xml, 'authOnlyTransaction', 1, card, {}) end raw_response = ssl_post(url, request, headers) response = parse(:authorize, raw_response) @@ -235,12 +246,18 @@ def add_auth_purchase(xml, transaction_type, amount, payment, options) xml.transactionRequest do xml.transactionType(transaction_type) xml.amount(amount(amount)) - add_payment_source(xml, payment) - add_invoice(xml, options) + add_payment_source(xml, payment, options) + add_invoice(xml, transaction_type, options) + add_tax_fields(xml, options) + add_duty_fields(xml, options) + add_shipping_fields(xml, options) + add_tax_exempt_status(xml, options) + add_po_number(xml, options) add_customer_data(xml, payment, options) add_market_type_device_type(xml, payment, options) add_settings(xml, payment, options) add_user_fields(xml, amount, options) + add_ship_from_address(xml, options) end end @@ -249,22 +266,30 @@ def add_cim_auth_purchase(xml, transaction_type, amount, payment, options) xml.transaction do xml.send(transaction_type) do xml.amount(amount(amount)) - add_payment_source(xml, payment) - add_settings(xml, payment, options) - add_invoice(xml, options) + add_tax_fields(xml, options) + add_shipping_fields(xml, options) + add_duty_fields(xml, options) + add_payment_source(xml, payment, options) + add_invoice(xml, transaction_type, options) + add_tax_exempt_status(xml, options) end end + add_extra_options_for_cim(xml, options) end def cim_capture(amount, authorization, options) - commit(:cim_capture) do |xml| + commit(:cim_capture, options) do |xml| add_order_id(xml, options) xml.transaction do xml.profileTransPriorAuthCapture do xml.amount(amount(amount)) + add_tax_fields(xml, options) + add_shipping_fields(xml, options) + add_duty_fields(xml, options) xml.transId(transaction_id_from(authorization)) end end + add_extra_options_for_cim(xml, options) end end @@ -274,8 +299,13 @@ def normal_capture(amount, authorization, options) xml.transactionRequest do xml.transactionType('priorAuthCaptureTransaction') xml.amount(amount(amount)) + add_tax_fields(xml, options) + add_duty_fields(xml, options) + add_shipping_fields(xml, options) + add_tax_exempt_status(xml, options) + add_po_number(xml, options) xml.refTransId(transaction_id_from(authorization)) - add_invoice(xml, options) + add_invoice(xml, 'capture', options) add_user_fields(xml, amount, options) end end @@ -284,16 +314,20 @@ def normal_capture(amount, authorization, options) def cim_refund(amount, authorization, options) transaction_id, card_number, _ = split_authorization(authorization) - commit(:cim_refund) do |xml| + commit(:cim_refund, options) do |xml| add_order_id(xml, options) xml.transaction do xml.profileTransRefund do xml.amount(amount(amount)) + add_tax_fields(xml, options) + add_shipping_fields(xml, options) + add_duty_fields(xml, options) xml.creditCardNumberMasked(card_number) - add_invoice(xml, options) + add_invoice(xml, 'profileTransRefund', options) xml.transId(transaction_id) end end + add_extra_options_for_cim(xml, options) end end @@ -305,14 +339,28 @@ def normal_refund(amount, authorization, options) xml.transactionType('refundTransaction') xml.amount(amount.nil? ? 0 : amount(amount)) xml.payment do - xml.creditCard do - xml.cardNumber(card_number || options[:card_number]) - xml.expirationDate('XXXX') + if options[:routing_number] + xml.bankAccount do + xml.accountType(options[:account_type]) + xml.routingNumber(options[:routing_number]) + xml.accountNumber(options[:account_number]) + xml.nameOnAccount("#{options[:first_name]} #{options[:last_name]}") + end + else + xml.creditCard do + xml.cardNumber(card_number || options[:card_number]) + xml.expirationDate('XXXX') + end end end xml.refTransId(transaction_id) - add_invoice(xml, options) + add_invoice(xml, 'refundTransaction', options) + add_tax_fields(xml, options) + add_duty_fields(xml, options) + add_shipping_fields(xml, options) + add_tax_exempt_status(xml, options) + add_po_number(xml, options) add_customer_data(xml, nil, options) add_user_fields(xml, amount, options) end @@ -320,13 +368,14 @@ def normal_refund(amount, authorization, options) end def cim_void(authorization, options) - commit(:cim_void) do |xml| + commit(:cim_void, options) do |xml| add_order_id(xml, options) xml.transaction do xml.profileTransVoid do xml.transId(transaction_id_from(authorization)) end end + add_extra_options_for_cim(xml, options) end end @@ -340,10 +389,10 @@ def normal_void(authorization, options) end end - def add_payment_source(xml, source) + def add_payment_source(xml, source, options, action = nil) return unless source if source.is_a?(String) - add_token_payment_method(xml, source) + add_token_payment_method(xml, source, options) elsif card_brand(source) == 'check' add_check(xml, source) elsif card_brand(source) == 'apple_pay' @@ -351,52 +400,58 @@ def add_payment_source(xml, source) elsif card_brand(source) == 'tokenized' add_tokenized_credit_card(xml, source) else - add_credit_card(xml, source) + add_credit_card(xml, source, action) end end def camel_case_lower(key) - String(key).split('_').inject([]){ |buffer,e| buffer.push(buffer.empty? ? e : e.capitalize) }.join + String(key).split('_').inject([]) { |buffer, e| buffer.push(buffer.empty? ? e : e.capitalize) }.join end def add_settings(xml, source, options) xml.transactionSettings do if options[:recurring] xml.setting do - xml.settingName("recurringBilling") - xml.settingValue("true") + xml.settingName('recurringBilling') + xml.settingValue('true') end end if options[:disable_partial_auth] xml.setting do - xml.settingName("allowPartialAuth") - xml.settingValue("false") + xml.settingName('allowPartialAuth') + xml.settingValue('false') end end if options[:duplicate_window] set_duplicate_window(xml, options[:duplicate_window]) elsif self.class.duplicate_window - ActiveMerchant.deprecated "Using the duplicate_window class_attribute is deprecated. Use the transaction options hash instead." + ActiveMerchant.deprecated 'Using the duplicate_window class_attribute is deprecated. Use the transaction options hash instead.' set_duplicate_window(xml, self.class.duplicate_window) end - if options[:email_customer] + if options.key?(:email_customer) xml.setting do - xml.settingName("emailCustomer") - xml.settingValue("true") + xml.settingName('emailCustomer') + xml.settingValue(options[:email_customer] ? 'true' : 'false') end end if options[:header_email_receipt] xml.setting do - xml.settingName("headerEmailReceipt") + xml.settingName('headerEmailReceipt') xml.settingValue(options[:header_email_receipt]) end end + if options[:test_request] + xml.setting do + xml.settingName('testRequest') + xml.settingValue('1') + end + end end end def set_duplicate_window(xml, value) xml.setting do - xml.settingName("duplicateWindow") + xml.settingName('duplicateWindow') xml.settingValue(value) end end @@ -405,20 +460,20 @@ def add_user_fields(xml, amount, options) xml.userFields do if currency = (options[:currency] || currency(amount)) xml.userField do - xml.name("x_currency_code") + xml.name('x_currency_code') xml.value(currency) end end if application_id.present? xml.userField do - xml.name("x_solution_id") + xml.name('x_solution_id') xml.value(application_id) end end end end - def add_credit_card(xml, credit_card) + def add_credit_card(xml, credit_card, action) if credit_card.track_data add_swipe_data(xml, credit_card) else @@ -429,7 +484,7 @@ def add_credit_card(xml, credit_card) if credit_card.valid_card_verification_value?(credit_card.verification_value, credit_card.brand) xml.cardCode(credit_card.verification_value) end - if credit_card.is_a?(NetworkTokenizationCreditCard) + if credit_card.is_a?(NetworkTokenizationCreditCard) && action != :credit xml.cryptogram(credit_card.payment_cryptogram) end end @@ -463,8 +518,10 @@ def add_swipe_data(xml, credit_card) end end - def add_token_payment_method(xml, token) + def add_token_payment_method(xml, token, options) customer_profile_id, customer_payment_profile_id, _ = split_authorization(token) + customer_profile_id = options[:customer_profile_id] if options[:customer_profile_id] + customer_payment_profile_id = options[:customer_payment_profile_id] if options[:customer_payment_profile_id] xml.customerProfileId(customer_profile_id) xml.customerPaymentProfileId(customer_payment_profile_id) end @@ -516,7 +573,7 @@ def add_check(xml, check) def add_customer_data(xml, payment_source, options) xml.customer do - xml.id(options[:customer]) unless empty?(options[:customer]) || options[:customer] !~ /^\d+$/ + xml.id(options[:customer]) unless empty?(options[:customer]) || options[:customer] !~ /^\w+$/ xml.email(options[:email]) unless empty?(options[:email]) end @@ -526,8 +583,11 @@ def add_customer_data(xml, payment_source, options) xml.customerIP(options[:ip]) unless empty?(options[:ip]) xml.cardholderAuthentication do - xml.authenticationIndicator(options[:authentication_indicator]) - xml.cardholderAuthenticationValue(options[:cardholder_authentication_value]) + three_d_secure = options.fetch(:three_d_secure, {}) + xml.authenticationIndicator( + options[:authentication_indicator] || three_d_secure[:eci]) + xml.cardholderAuthenticationValue( + options[:cardholder_authentication_value] || three_d_secure[:cavv]) end end @@ -536,13 +596,15 @@ def add_billing_address(xml, payment_source, options) xml.billTo do first_name, last_name = names_from(payment_source, address, options) + state = state_from(address, options) + full_address = "#{address[:address1]} #{address[:address2]}".strip + xml.firstName(truncate(first_name, 50)) unless empty?(first_name) xml.lastName(truncate(last_name, 50)) unless empty?(last_name) - xml.company(truncate(address[:company], 50)) unless empty?(address[:company]) - xml.address(truncate(address[:address1], 60)) + xml.address(truncate(full_address, 60)) xml.city(truncate(address[:city], 40)) - xml.state(empty?(address[:state]) ? 'n/a' : truncate(address[:state], 40)) + xml.state(truncate(state, 40)) xml.zip(truncate((address[:zip] || options[:zip]), 20)) xml.country(truncate(address[:country], 60)) xml.phoneNumber(truncate(address[:phone], 25)) unless empty?(address[:phone]) @@ -550,38 +612,49 @@ def add_billing_address(xml, payment_source, options) end end - def add_shipping_address(xml, options, root_node="shipTo") + def add_shipping_address(xml, options, root_node='shipTo') address = options[:shipping_address] || options[:address] return unless address xml.send(root_node) do first_name, last_name = if address[:name] - split_names(address[:name]) - else - [address[:first_name], address[:last_name]] + split_names(address[:name]) + else + [address[:first_name], address[:last_name]] end + full_address = "#{address[:address1]} #{address[:address2]}".strip xml.firstName(truncate(first_name, 50)) unless empty?(first_name) xml.lastName(truncate(last_name, 50)) unless empty?(last_name) - xml.company(truncate(address[:company], 50)) unless empty?(address[:company]) - xml.address(truncate(address[:address1], 60)) + xml.address(truncate(full_address, 60)) xml.city(truncate(address[:city], 40)) xml.state(truncate(address[:state], 40)) xml.zip(truncate(address[:zip], 20)) xml.country(truncate(address[:country], 60)) end + end + def add_ship_from_address(xml, options, root_node='shipFrom') + address = options[:ship_from_address] + return unless address + + xml.send(root_node) do + xml.zip(truncate(address[:zip], 20)) unless empty?(address[:zip]) + xml.country(truncate(address[:country], 60)) unless empty?(address[:country]) + end end def add_order_id(xml, options) xml.refId(truncate(options[:order_id], 20)) end - def add_invoice(xml, options) + def add_invoice(xml, transaction_type, options) xml.order do xml.invoiceNumber(truncate(options[:order_id], 20)) xml.description(truncate(options[:description], 255)) + xml.purchaseOrderNumber(options[:po_number]) if options[:po_number] && transaction_type.start_with?('profileTrans') + xml.summaryCommodityCode(truncate(options[:summary_commodity_code], 4)) if options[:summary_commodity_code] && !transaction_type.start_with?('profileTrans') end # Authorize.net API requires lineItems to be placed directly after order tag @@ -598,8 +671,53 @@ def add_invoice(xml, options) end end + def add_tax_fields(xml, options) + tax = options[:tax] + if tax.is_a?(Hash) + xml.tax do + xml.amount(amount(tax[:amount].to_i)) + xml.name(tax[:name]) + xml.description(tax[:description]) + end + end + end + + def add_duty_fields(xml, options) + duty = options[:duty] + if duty.is_a?(Hash) + xml.duty do + xml.amount(amount(duty[:amount].to_i)) + xml.name(duty[:name]) + xml.description(duty[:description]) + end + end + end + + def add_shipping_fields(xml, options) + shipping = options[:shipping] + if shipping.is_a?(Hash) + xml.shipping do + xml.amount(amount(shipping[:amount].to_i)) + xml.name(shipping[:name]) + xml.description(shipping[:description]) + end + end + end + + def add_tax_exempt_status(xml, options) + xml.taxExempt(options[:tax_exempt]) if options[:tax_exempt] + end + + def add_po_number(xml, options) + xml.poNumber(options[:po_number]) if options[:po_number] + end + + def add_extra_options_for_cim(xml, options) + xml.extraOptions("x_delim_char=#{options[:delimiter]}") if options[:delimiter] + end + def create_customer_payment_profile(credit_card, options) - commit(:cim_store_update) do |xml| + commit(:cim_store_update, options) do |xml| xml.customerProfileId options[:customer_profile_id] xml.paymentProfile do add_billing_address(xml, credit_card, options) @@ -615,16 +733,16 @@ def create_customer_payment_profile(credit_card, options) end def create_customer_profile(credit_card, options) - commit(:cim_store) do |xml| + commit(:cim_store, options) do |xml| xml.profile do xml.merchantCustomerId(truncate(options[:merchant_customer_id], 20) || SecureRandom.hex(10)) xml.description(truncate(options[:description], 255)) unless empty?(options[:description]) xml.email(options[:email]) unless empty?(options[:email]) xml.paymentProfiles do - xml.customerType("individual") + xml.customerType('individual') add_billing_address(xml, credit_card, options) - add_shipping_address(xml, options, "shipToList") + add_shipping_address(xml, options, 'shipToList') xml.payment do xml.creditCard do xml.cardNumber(truncate(credit_card.number, 16)) @@ -638,7 +756,7 @@ def create_customer_profile(credit_card, options) end def delete_customer_profile(customer_profile_id) - commit(:cim_store_delete_customer) do |xml| + commit(:cim_store_delete_customer, options) do |xml| xml.customerProfileId(customer_profile_id) end end @@ -652,6 +770,14 @@ def names_from(payment_source, address, options) end end + def state_from(address, options) + if ['US', 'CA'].include?(address[:country]) + address[:state] || 'NC' + else + address[:state] || 'n/a' + end + end + def headers { 'Content-Type' => 'text/xml' } end @@ -660,23 +786,23 @@ def url test? ? test_url : live_url end - def parse(action, raw_response) + def parse(action, raw_response, options = {}) if is_cim_action?(action) || action == :verify_credentials - parse_cim(raw_response) + parse_cim(raw_response, options) else parse_normal(action, raw_response) end end - def commit(action, &payload) + def commit(action, options = {}, &payload) raw_response = ssl_post(url, post_data(action, &payload), headers) - response = parse(action, raw_response) + response = parse(action, raw_response, options) avs_result_code = response[:avs_result_code].upcase if response[:avs_result_code] avs_result = AVSResult.new(code: STANDARD_AVS_CODE_MAPPING[avs_result_code]) cvv_result = CVVResult.new(response[:card_code]) if using_live_gateway_in_test_mode?(response) - Response.new(false, "Using a live Authorize.net account in Test Mode is not permitted.") + Response.new(false, 'Using a live Authorize.net account in Test Mode is not permitted.') else Response.new( success_from(action, response), @@ -693,7 +819,7 @@ def commit(action, &payload) end def is_cim_action?(action) - action.to_s.start_with?("cim") + action.to_s.start_with?('cim') end def post_data(action) @@ -707,17 +833,17 @@ def post_data(action) def root_for(action) if action == :cim_store - "createCustomerProfileRequest" + 'createCustomerProfileRequest' elsif action == :cim_store_update - "createCustomerPaymentProfileRequest" + 'createCustomerPaymentProfileRequest' elsif action == :cim_store_delete_customer - "deleteCustomerProfileRequest" + 'deleteCustomerProfileRequest' elsif action == :verify_credentials - "authenticateTestRequest" + 'authenticateTestRequest' elsif is_cim_action?(action) - "createCustomerProfileTransactionRequest" + 'createCustomerProfileTransactionRequest' else - "createTransactionRequest" + 'createTransactionRequest' end end @@ -734,100 +860,104 @@ def parse_normal(action, body) response = {action: action} - response[:response_code] = if(element = doc.at_xpath("//transactionResponse/responseCode")) - (empty?(element.content) ? nil : element.content.to_i) + response[:response_code] = if(element = doc.at_xpath('//transactionResponse/responseCode')) + (empty?(element.content) ? nil : element.content.to_i) end - if(element = doc.at_xpath("//errors/error")) - response[:response_reason_code] = element.at_xpath("errorCode").content[/0*(\d+)$/, 1] - response[:response_reason_text] = element.at_xpath("errorText").content.chomp('.') - elsif(element = doc.at_xpath("//transactionResponse/messages/message")) - response[:response_reason_code] = element.at_xpath("code").content[/0*(\d+)$/, 1] - response[:response_reason_text] = element.at_xpath("description").content.chomp('.') - elsif(element = doc.at_xpath("//messages/message")) - response[:response_reason_code] = element.at_xpath("code").content[/0*(\d+)$/, 1] - response[:response_reason_text] = element.at_xpath("text").content.chomp('.') + if(element = doc.at_xpath('//errors/error')) + response[:response_reason_code] = element.at_xpath('errorCode').content[/0*(\d+)$/, 1] + response[:response_reason_text] = element.at_xpath('errorText').content.chomp('.') + elsif(element = doc.at_xpath('//transactionResponse/messages/message')) + response[:response_reason_code] = element.at_xpath('code').content[/0*(\d+)$/, 1] + response[:response_reason_text] = element.at_xpath('description').content.chomp('.') + elsif(element = doc.at_xpath('//messages/message')) + response[:response_reason_code] = element.at_xpath('code').content[/0*(\d+)$/, 1] + response[:response_reason_text] = element.at_xpath('text').content.chomp('.') else response[:response_reason_code] = nil - response[:response_reason_text] = "" + response[:response_reason_text] = '' + end + + response[:avs_result_code] = if(element = doc.at_xpath('//avsResultCode')) + (empty?(element.content) ? nil : element.content) end - response[:avs_result_code] = if(element = doc.at_xpath("//avsResultCode")) - (empty?(element.content) ? nil : element.content) + response[:transaction_id] = if(element = doc.at_xpath('//transId')) + (empty?(element.content) ? nil : element.content) end - response[:transaction_id] = if(element = doc.at_xpath("//transId")) - (empty?(element.content) ? nil : element.content) + response[:card_code] = if(element = doc.at_xpath('//cvvResultCode')) + (empty?(element.content) ? nil : element.content) end - response[:card_code] = if(element = doc.at_xpath("//cvvResultCode")) - (empty?(element.content) ? nil : element.content) + response[:authorization_code] = if(element = doc.at_xpath('//authCode')) + (empty?(element.content) ? nil : element.content) end - response[:authorization_code] = if(element = doc.at_xpath("//authCode")) - (empty?(element.content) ? nil : element.content) + response[:cardholder_authentication_code] = if(element = doc.at_xpath('//cavvResultCode')) + (empty?(element.content) ? nil : element.content) end - response[:cardholder_authentication_code] = if(element = doc.at_xpath("//cavvResultCode")) - (empty?(element.content) ? nil : element.content) + response[:account_number] = if(element = doc.at_xpath('//accountNumber')) + (empty?(element.content) ? nil : element.content[-4..-1]) end - response[:account_number] = if(element = doc.at_xpath("//accountNumber")) - (empty?(element.content) ? nil : element.content[-4..-1]) + response[:test_request] = if(element = doc.at_xpath('//testRequest')) + (empty?(element.content) ? nil : element.content) end - response[:test_request] = if(element = doc.at_xpath("//testRequest")) - (empty?(element.content) ? nil : element.content) + response[:full_response_code] = if(element = doc.at_xpath('//messages/message/code')) + (empty?(element.content) ? nil : element.content) end response end - def parse_cim(body) + def parse_cim(body, options) response = {} doc = Nokogiri::XML(body).remove_namespaces! - if (element = doc.at_xpath("//messages/message")) - response[:message_code] = element.at_xpath("code").content[/0*(\d+)$/, 1] - response[:message_text] = element.at_xpath("text").content.chomp('.') + if (element = doc.at_xpath('//messages/message')) + response[:message_code] = element.at_xpath('code').content[/0*(\d+)$/, 1] + response[:message_text] = element.at_xpath('text').content.chomp('.') end - response[:result_code] = if(element = doc.at_xpath("//messages/resultCode")) - (empty?(element.content) ? nil : element.content) + response[:result_code] = if(element = doc.at_xpath('//messages/resultCode')) + (empty?(element.content) ? nil : element.content) end - response[:test_request] = if(element = doc.at_xpath("//testRequest")) - (empty?(element.content) ? nil : element.content) + response[:test_request] = if(element = doc.at_xpath('//testRequest')) + (empty?(element.content) ? nil : element.content) end - response[:customer_profile_id] = if(element = doc.at_xpath("//customerProfileId")) - (empty?(element.content) ? nil : element.content) + response[:customer_profile_id] = if(element = doc.at_xpath('//customerProfileId')) + (empty?(element.content) ? nil : element.content) end - response[:customer_payment_profile_id] = if(element = doc.at_xpath("//customerPaymentProfileIdList/numericString")) - (empty?(element.content) ? nil : element.content) + response[:customer_payment_profile_id] = if(element = doc.at_xpath('//customerPaymentProfileIdList/numericString')) + (empty?(element.content) ? nil : element.content) end - response[:customer_payment_profile_id] = if(element = doc.at_xpath("//customerPaymentProfileIdList/numericString") || - doc.at_xpath("//customerPaymentProfileId")) - (empty?(element.content) ? nil : element.content) + response[:customer_payment_profile_id] = if(element = doc.at_xpath('//customerPaymentProfileIdList/numericString') || + doc.at_xpath('//customerPaymentProfileId')) + (empty?(element.content) ? nil : element.content) end - response[:direct_response] = if(element = doc.at_xpath("//directResponse")) - (empty?(element.content) ? nil : element.content) + response[:direct_response] = if(element = doc.at_xpath('//directResponse')) + (empty?(element.content) ? nil : element.content) end - response.merge!(parse_direct_response_elements(response)) + response.merge!(parse_direct_response_elements(response, options)) response end def success_from(action, response) if cim?(action) || (action == :verify_credentials) - response[:result_code] == "Ok" + response[:result_code] == 'Ok' else - response[:response_code] == APPROVED && TRANSACTION_ALREADY_ACTIONED.exclude?(response[:response_reason_code]) + [APPROVED, FRAUD_REVIEW].include?(response[:response_code]) && TRANSACTION_ALREADY_ACTIONED.exclude?(response[:response_reason_code]) end end @@ -845,14 +975,14 @@ def message_from(action, response, avs_result, cvv_result) def authorization_from(action, response) if cim?(action) - [response[:customer_profile_id], response[:customer_payment_profile_id], action].join("#") + [response[:customer_profile_id], response[:customer_payment_profile_id], action].join('#') else - [response[:transaction_id], response[:account_number], action].join("#") + [response[:transaction_id], response[:account_number], action].join('#') end end def split_authorization(authorization) - authorization.split("#") + authorization.split('#') end def cim?(action) @@ -869,7 +999,7 @@ def fraud_review?(response) end def using_live_gateway_in_test_mode?(response) - !test? && response[:test_request] == "1" + !test? && response[:test_request] == '1' end def map_error_code(response_code, response_reason_code) @@ -881,11 +1011,11 @@ def auth_was_for_cim?(authorization) action && is_cim_action?(action) end - def parse_direct_response_elements(response) + def parse_direct_response_elements(response, options) params = response[:direct_response] return {} unless params - parts = params.split(',') + parts = params.split(options[:delimiter] || ',') { response_code: parts[0].to_i, response_subcode: parts[1], diff --git a/lib/active_merchant/billing/gateways/authorize_net_arb.rb b/lib/active_merchant/billing/gateways/authorize_net_arb.rb index ee19b1e1e3a..406cc55e50e 100644 --- a/lib/active_merchant/billing/gateways/authorize_net_arb.rb +++ b/lib/active_merchant/billing/gateways/authorize_net_arb.rb @@ -57,7 +57,7 @@ class AuthorizeNetArbGateway < Gateway # * :test -- +true+ or +false+. If true, perform transactions against the test server. # Otherwise, perform transactions against the production server. def initialize(options = {}) - ActiveMerchant.deprecated "ARB functionality in ActiveMerchant is deprecated and will be removed in a future version. Please contact the ActiveMerchant maintainers if you have an interest in taking ownership of a separate gem that continues support for it." + ActiveMerchant.deprecated 'ARB functionality in ActiveMerchant is deprecated and will be removed in a future version. Please contact the ActiveMerchant maintainers if you have an interest in taking ownership of a separate gem that continues support for it.' requires!(options, :login, :password) super end @@ -377,7 +377,7 @@ def expdate(credit_card) def recurring_commit(action, request) url = test? ? test_url : live_url - xml = ssl_post(url, request, "Content-Type" => "text/xml") + xml = ssl_post(url, request, 'Content-Type' => 'text/xml') response = recurring_parse(action, xml) @@ -395,7 +395,7 @@ def recurring_parse(action, xml) response = {} xml = REXML::Document.new(xml) root = REXML::XPath.first(xml, "//#{RECURRING_ACTIONS[action]}Response") || - REXML::XPath.first(xml, "//ErrorResponse") + REXML::XPath.first(xml, '//ErrorResponse') if root root.elements.to_a.each do |node| recurring_parse_element(response, node) @@ -407,7 +407,7 @@ def recurring_parse(action, xml) def recurring_parse_element(response, node) if node.has_elements? - node.elements.each{|e| recurring_parse_element(response, e) } + node.elements.each { |e| recurring_parse_element(response, e) } else response[node.name.underscore.to_sym] = node.text end diff --git a/lib/active_merchant/billing/gateways/authorize_net_cim.rb b/lib/active_merchant/billing/gateways/authorize_net_cim.rb index d4c59ad12a7..fac2913ff37 100644 --- a/lib/active_merchant/billing/gateways/authorize_net_cim.rb +++ b/lib/active_merchant/billing/gateways/authorize_net_cim.rb @@ -379,19 +379,19 @@ def create_customer_profile_transaction(options) requires!(options, :transaction) requires!(options[:transaction], :type) case options[:transaction][:type] - when :void - requires!(options[:transaction], :trans_id) - when :refund - requires!(options[:transaction], :trans_id) && - ( - (options[:transaction][:customer_profile_id] && options[:transaction][:customer_payment_profile_id]) || - options[:transaction][:credit_card_number_masked] || - (options[:transaction][:bank_routing_number_masked] && options[:transaction][:bank_account_number_masked]) - ) - when :prior_auth_capture - requires!(options[:transaction], :amount, :trans_id) - else - requires!(options[:transaction], :amount, :customer_profile_id, :customer_payment_profile_id) + when :void + requires!(options[:transaction], :trans_id) + when :refund + requires!(options[:transaction], :trans_id) && + ( + (options[:transaction][:customer_profile_id] && options[:transaction][:customer_payment_profile_id]) || + options[:transaction][:credit_card_number_masked] || + (options[:transaction][:bank_routing_number_masked] && options[:transaction][:bank_account_number_masked]) + ) + when :prior_auth_capture + requires!(options[:transaction], :amount, :trans_id) + else + requires!(options[:transaction], :amount, :customer_profile_id, :customer_payment_profile_id) end request = build_request(:create_customer_profile_transaction, options) commit(:create_customer_profile_transaction, request) @@ -614,7 +614,7 @@ def build_update_customer_shipping_address_request(xml, options) def build_create_customer_profile_transaction_request(xml, options) options[:extra_options] ||= {} - options[:extra_options].merge!('x_delim_char' => @options[:delimiter]) if @options[:delimiter] + options[:extra_options]['x_delim_char'] = @options[:delimiter] if @options[:delimiter] add_transaction(xml, options[:transaction]) xml.tag!('extraOptions') do @@ -665,41 +665,40 @@ def add_transaction(xml, transaction) xml.tag!(CIM_TRANSACTION_TYPES[transaction[:type]]) do # The amount to be billed to the customer case transaction[:type] - when :void - tag_unless_blank(xml,'customerProfileId', transaction[:customer_profile_id]) - tag_unless_blank(xml,'customerPaymentProfileId', transaction[:customer_payment_profile_id]) - tag_unless_blank(xml,'customerShippingAddressId', transaction[:customer_shipping_address_id]) - xml.tag!('transId', transaction[:trans_id]) - when :refund - #TODO - add lineItems field - xml.tag!('amount', transaction[:amount]) - tag_unless_blank(xml, 'customerProfileId', transaction[:customer_profile_id]) - tag_unless_blank(xml, 'customerPaymentProfileId', transaction[:customer_payment_profile_id]) - tag_unless_blank(xml, 'customerShippingAddressId', transaction[:customer_shipping_address_id]) - tag_unless_blank(xml, 'creditCardNumberMasked', transaction[:credit_card_number_masked]) - tag_unless_blank(xml, 'bankRoutingNumberMasked', transaction[:bank_routing_number_masked]) - tag_unless_blank(xml, 'bankAccountNumberMasked', transaction[:bank_account_number_masked]) - add_order(xml, transaction[:order]) if transaction[:order].present? - xml.tag!('transId', transaction[:trans_id]) - add_tax(xml, transaction[:tax]) if transaction[:tax] - add_duty(xml, transaction[:duty]) if transaction[:duty] - add_shipping(xml, transaction[:shipping]) if transaction[:shipping] - when :prior_auth_capture - xml.tag!('amount', transaction[:amount]) - add_order(xml, transaction[:order]) if transaction[:order].present? - xml.tag!('transId', transaction[:trans_id]) - else - xml.tag!('amount', transaction[:amount]) - xml.tag!('customerProfileId', transaction[:customer_profile_id]) - xml.tag!('customerPaymentProfileId', transaction[:customer_payment_profile_id]) - xml.tag!('approvalCode', transaction[:approval_code]) if transaction[:type] == :capture_only - add_order(xml, transaction[:order]) if transaction[:order].present? + when :void + tag_unless_blank(xml, 'customerProfileId', transaction[:customer_profile_id]) + tag_unless_blank(xml, 'customerPaymentProfileId', transaction[:customer_payment_profile_id]) + tag_unless_blank(xml, 'customerShippingAddressId', transaction[:customer_shipping_address_id]) + xml.tag!('transId', transaction[:trans_id]) + when :refund + xml.tag!('amount', transaction[:amount]) + tag_unless_blank(xml, 'customerProfileId', transaction[:customer_profile_id]) + tag_unless_blank(xml, 'customerPaymentProfileId', transaction[:customer_payment_profile_id]) + tag_unless_blank(xml, 'customerShippingAddressId', transaction[:customer_shipping_address_id]) + tag_unless_blank(xml, 'creditCardNumberMasked', transaction[:credit_card_number_masked]) + tag_unless_blank(xml, 'bankRoutingNumberMasked', transaction[:bank_routing_number_masked]) + tag_unless_blank(xml, 'bankAccountNumberMasked', transaction[:bank_account_number_masked]) + add_order(xml, transaction[:order]) if transaction[:order].present? + xml.tag!('transId', transaction[:trans_id]) + add_tax(xml, transaction[:tax]) if transaction[:tax] + add_duty(xml, transaction[:duty]) if transaction[:duty] + add_shipping(xml, transaction[:shipping]) if transaction[:shipping] + when :prior_auth_capture + xml.tag!('amount', transaction[:amount]) + add_order(xml, transaction[:order]) if transaction[:order].present? + xml.tag!('transId', transaction[:trans_id]) + else + xml.tag!('amount', transaction[:amount]) + xml.tag!('customerProfileId', transaction[:customer_profile_id]) + xml.tag!('customerPaymentProfileId', transaction[:customer_payment_profile_id]) + xml.tag!('approvalCode', transaction[:approval_code]) if transaction[:type] == :capture_only + add_order(xml, transaction[:order]) if transaction[:order].present? end if [:auth_capture, :auth_only, :capture_only].include?(transaction[:type]) xml.tag!('recurringBilling', transaction[:recurring_billing]) if transaction.has_key?(:recurring_billing) end - unless [:void,:refund,:prior_auth_capture].include?(transaction[:type]) + unless [:void, :refund, :prior_auth_capture].include?(transaction[:type]) tag_unless_blank(xml, 'cardCode', transaction[:card_code]) end end @@ -854,11 +853,13 @@ def add_drivers_license(xml, drivers_license) def commit(action, request) url = test? ? test_url : live_url - xml = ssl_post(url, request, "Content-Type" => "text/xml") + xml = ssl_post(url, request, 'Content-Type' => 'text/xml') response_params = parse(action, xml) - message = response_params['messages']['message']['text'] + message_element= response_params['messages']['message'] + first_error = message_element.is_a?(Array) ? message_element.first : message_element + message = first_error['text'] test_mode = @options[:test_requests] || message =~ /Test Mode/ success = response_params['messages']['result_code'] == 'Ok' response_params['direct_response'] = parse_direct_response(response_params['direct_response']) if response_params['direct_response'] @@ -867,7 +868,7 @@ def commit(action, request) response_options = {} response_options[:test] = test_mode response_options[:authorization] = transaction_id || response_params['customer_profile_id'] || (response_params['profile'] ? response_params['profile']['customer_profile_id'] : nil) - response_options[:error_code] = response_params['messages']['message']['code'] unless success + response_options[:error_code] = first_error['code'] unless success Response.new(success, message, response_params, response_options) end @@ -877,7 +878,7 @@ def tag_unless_blank(xml, tag_name, data) end def format_extra_options(options) - options.map{ |k, v| "#{k}=#{v}" }.join('&') unless options.nil? + options&.map { |k, v| "#{k}=#{v}" }&.join('&') end def parse_direct_response(params) @@ -940,7 +941,7 @@ def parse_direct_response(params) def parse(action, xml) xml = REXML::Document.new(xml) root = REXML::XPath.first(xml, "//#{CIM_ACTIONS[action]}Response") || - REXML::XPath.first(xml, "//ErrorResponse") + REXML::XPath.first(xml, '//ErrorResponse') if root response = parse_element(root) end @@ -951,7 +952,7 @@ def parse(action, xml) def parse_element(node) if node.has_elements? response = {} - node.elements.each{ |e| + node.elements.each { |e| key = e.name.underscore value = parse_element(e) if response.has_key?(key) diff --git a/lib/active_merchant/billing/gateways/axcessms.rb b/lib/active_merchant/billing/gateways/axcessms.rb index 30203788ad4..7f9207ff6a2 100644 --- a/lib/active_merchant/billing/gateways/axcessms.rb +++ b/lib/active_merchant/billing/gateways/axcessms.rb @@ -1,27 +1,27 @@ module ActiveMerchant #:nodoc: module Billing #:nodoc: class AxcessmsGateway < Gateway - self.test_url = "https://test.ctpe.io/payment/ctpe" - self.live_url = "https://ctpe.io/payment/ctpe" + self.test_url = 'https://test.ctpe.io/payment/ctpe' + self.live_url = 'https://ctpe.io/payment/ctpe' self.supported_countries = %w(AD AT BE BG BR CA CH CY CZ DE DK EE ES FI FO FR GB GI GR HR HU IE IL IM IS IT LI LT LU LV MC MT MX NL NO PL PT RO RU SE SI SK TR US VA) - self.supported_cardtypes = [:visa, :master, :american_express, :discover, :jcb, :maestro, :solo] + self.supported_cardtypes = [:visa, :master, :american_express, :discover, :jcb, :maestro] - self.homepage_url = "http://www.axcessms.com/" - self.display_name = "Axcess MS" + self.homepage_url = 'http://www.axcessms.com/' + self.display_name = 'Axcess MS' self.money_format = :dollars - self.default_currency = "GBP" + self.default_currency = 'GBP' - API_VERSION = "1.0" - PAYMENT_CODE_PREAUTHORIZATION = "CC.PA" - PAYMENT_CODE_DEBIT = "CC.DB" - PAYMENT_CODE_CAPTURE = "CC.CP" - PAYMENT_CODE_REVERSAL = "CC.RV" - PAYMENT_CODE_REFUND = "CC.RF" - PAYMENT_CODE_REBILL = "CC.RB" + API_VERSION = '1.0' + PAYMENT_CODE_PREAUTHORIZATION = 'CC.PA' + PAYMENT_CODE_DEBIT = 'CC.DB' + PAYMENT_CODE_CAPTURE = 'CC.CP' + PAYMENT_CODE_REVERSAL = 'CC.RV' + PAYMENT_CODE_REFUND = 'CC.RF' + PAYMENT_CODE_REBILL = 'CC.RB' def initialize(options={}) requires!(options, :sender, :login, :password, :channel) @@ -59,21 +59,21 @@ def verify(credit_card, options={}) private def commit(paymentcode, money, payment, options) - options[:mode] ||= (test? ? "INTEGRATOR_TEST" : "LIVE") + options[:mode] ||= (test? ? 'INTEGRATOR_TEST' : 'LIVE') request = build_request(paymentcode, money, payment, options) headers = { - "Content-Type" => "application/x-www-form-urlencoded;charset=UTF-8" + 'Content-Type' => 'application/x-www-form-urlencoded;charset=UTF-8' } response = parse(ssl_post((test? ? test_url : live_url), "load=#{CGI.escape(request)}", headers)) - success = (response[:result] == "ACK") + success = (response[:result] == 'ACK') message = "#{response[:reason]} - #{response[:return]}" authorization = response[:unique_id] Response.new(success, message, response, :authorization => authorization, - :test => (response[:mode] != "LIVE") + :test => (response[:mode] != 'LIVE') ) end @@ -87,18 +87,18 @@ def parse(body) parse_element(response, node) end - response[:mode] = REXML::XPath.first(xml, "//Transaction").attributes["mode"] + response[:mode] = REXML::XPath.first(xml, '//Transaction').attributes['mode'] response end def parse_element(response, node) if node.has_attributes? - node.attributes.each{|name, value| response["#{node.name}_#{name}".underscore.to_sym] = value } + node.attributes.each { |name, value| response["#{node.name}_#{name}".underscore.to_sym] = value } end if node.has_elements? - node.elements.each{|element| parse_element(response, element) } + node.elements.each { |element| parse_element(response, element) } else response[node.name.underscore.to_sym] = node.text end @@ -107,30 +107,30 @@ def parse_element(response, node) def build_request(payment_code, money, payment, options) xml = Builder::XmlMarkup.new :indent => 2 xml.instruct! - xml.tag! "Request", "version" => API_VERSION do - xml.tag! "Header" do - xml.tag! "Security", "sender" => @options[:sender] + xml.tag! 'Request', 'version' => API_VERSION do + xml.tag! 'Header' do + xml.tag! 'Security', 'sender' => @options[:sender] end - xml.tag! "Transaction", "mode" => options[:mode], "channel" => @options[:channel], "response" => "SYNC" do - xml.tag! "User", "login" => @options[:login], "pwd" => @options[:password] - xml.tag! "Identification" do - xml.tag! "TransactionID", options[:order_id] || generate_unique_id - xml.tag! "ReferenceID", payment unless payment.respond_to?(:number) + xml.tag! 'Transaction', 'mode' => options[:mode], 'channel' => @options[:channel], 'response' => 'SYNC' do + xml.tag! 'User', 'login' => @options[:login], 'pwd' => @options[:password] + xml.tag! 'Identification' do + xml.tag! 'TransactionID', options[:order_id] || generate_unique_id + xml.tag! 'ReferenceID', payment unless payment.respond_to?(:number) end - xml.tag! "Payment", "code" => payment_code do - xml.tag! "Memo", options[:memo] unless options[:memo].blank? - xml.tag! "Presentation" do - xml.tag! "Amount", amount(money) - xml.tag! "Currency", (options[:currency] || currency(money)) - xml.tag! "Usage", options[:description] + xml.tag! 'Payment', 'code' => payment_code do + xml.tag! 'Memo', options[:memo] unless options[:memo].blank? + xml.tag! 'Presentation' do + xml.tag! 'Amount', amount(money) + xml.tag! 'Currency', (options[:currency] || currency(money)) + xml.tag! 'Usage', options[:description] end end if payment.respond_to?(:number) add_payment(xml, payment) - xml.tag! "Customer" do + xml.tag! 'Customer' do add_customer_name(xml, payment) add_address(xml, options[:billing_address] || options[:address]) add_contact(xml, options) @@ -143,37 +143,37 @@ def build_request(payment_code, money, payment, options) end def add_contact(xml, options) - xml.tag! "Contact" do - xml.tag! "Email", (options[:email] || "unknown@example.com") - xml.tag! "Ip", (options[:ip] || "127.0.0.1") + xml.tag! 'Contact' do + xml.tag! 'Email', (options[:email] || 'unknown@example.com') + xml.tag! 'Ip', (options[:ip] || '127.0.0.1') end end def add_customer_name(xml, payment) - xml.tag! "Name" do - xml.tag! "Given", payment.first_name - xml.tag! "Family", payment.last_name + xml.tag! 'Name' do + xml.tag! 'Given', payment.first_name + xml.tag! 'Family', payment.last_name end end def add_payment(xml, payment) - xml.tag! "Account" do - xml.tag! "Number", payment.number - xml.tag! "Holder", payment.name - xml.tag! "Brand", payment.brand - xml.tag! "Expiry", "month" => payment.month, "year" => payment.year - xml.tag! "Verification", payment.verification_value + xml.tag! 'Account' do + xml.tag! 'Number', payment.number + xml.tag! 'Holder', payment.name + xml.tag! 'Brand', payment.brand + xml.tag! 'Expiry', 'month' => payment.month, 'year' => payment.year + xml.tag! 'Verification', payment.verification_value end end def add_address(xml, address) - raise ArgumentError.new("Address is required") unless address - xml.tag! "Address" do - xml.tag! "Street", "#{address[:address1]} #{address[:address2]}".strip - xml.tag! "City", address[:city] - xml.tag! "State", address[:state] - xml.tag! "Zip", address[:zip] - xml.tag! "Country", address[:country] + raise ArgumentError.new('Address is required') unless address + xml.tag! 'Address' do + xml.tag! 'Street', "#{address[:address1]} #{address[:address2]}".strip + xml.tag! 'City', address[:city] + xml.tag! 'State', address[:state] + xml.tag! 'Zip', address[:zip] + xml.tag! 'Country', address[:country] end end end diff --git a/lib/active_merchant/billing/gateways/balanced.rb b/lib/active_merchant/billing/gateways/balanced.rb index 153c1a1369c..f9b7accff02 100644 --- a/lib/active_merchant/billing/gateways/balanced.rb +++ b/lib/active_merchant/billing/gateways/balanced.rb @@ -17,7 +17,7 @@ module Billing #:nodoc: # live" button on the Balanced dashboard and fill in your marketplace # details. class BalancedGateway < Gateway - VERSION = "2.0.0" + VERSION = '2.0.0' self.live_url = 'https://api.balancedpayments.com' @@ -45,12 +45,12 @@ def purchase(money, payment_method, options = {}) MultiResponse.run do |r| identifier = if(payment_method.respond_to?(:number)) - r.process{store(payment_method, options)} - r.authorization - else - payment_method + r.process { store(payment_method, options) } + r.authorization + else + payment_method end - r.process{commit("debits", "cards/#{card_identifier_from(identifier)}/debits", post)} + r.process { commit('debits', "cards/#{card_identifier_from(identifier)}/debits", post) } end end @@ -62,12 +62,12 @@ def authorize(money, payment_method, options = {}) MultiResponse.run do |r| identifier = if(payment_method.respond_to?(:number)) - r.process{store(payment_method, options)} - r.authorization - else - payment_method + r.process { store(payment_method, options) } + r.authorization + else + payment_method end - r.process{commit("card_holds", "cards/#{card_identifier_from(identifier)}/card_holds", post)} + r.process { commit('card_holds', "cards/#{card_identifier_from(identifier)}/card_holds", post) } end end @@ -77,7 +77,7 @@ def capture(money, identifier, options = {}) post[:description] = options[:description] if options[:description] add_common_params(post, options) - commit("debits", "card_holds/#{reference_identifier_from(identifier)}/debits", post) + commit('debits', "card_holds/#{reference_identifier_from(identifier)}/debits", post) end def void(identifier, options = {}) @@ -85,7 +85,7 @@ def void(identifier, options = {}) post[:is_void] = true add_common_params(post, options) - commit("card_holds", "card_holds/#{reference_identifier_from(identifier)}", post, :put) + commit('card_holds', "card_holds/#{reference_identifier_from(identifier)}", post, :put) end def refund(money, identifier, options = {}) @@ -94,7 +94,7 @@ def refund(money, identifier, options = {}) post[:description] = options[:description] add_common_params(post, options) - commit("refunds", "debits/#{reference_identifier_from(identifier)}/refunds", post) + commit('refunds', "debits/#{reference_identifier_from(identifier)}/refunds", post) end def store(credit_card, options={}) @@ -108,7 +108,7 @@ def store(credit_card, options={}) add_address(post, options) - commit("cards", "cards", post) + commit('cards', 'cards', post) end private @@ -117,18 +117,18 @@ def reference_identifier_from(identifier) case identifier when %r{\|} uri = identifier. - split("|"). - detect{|part| part.size > 0} - uri.split("/")[2] + split('|'). + detect { |part| part.size > 0 } + uri.split('/')[2] when %r{\/} - identifier.split("/")[5] + identifier.split('/')[5] else identifier end end def card_identifier_from(identifier) - identifier.split("/").last + identifier.split('/').last end def add_amount(post, money) @@ -172,7 +172,7 @@ def commit(entity_name, path, post, method=:post) message_from(raw_response), raw_response, authorization: authorization_from(entity_name, raw_response), - test: test?, + test: test? ) end @@ -180,29 +180,29 @@ def success_from(entity_name, raw_response) entity = (raw_response[entity_name] || []).first if(!entity) false - elsif((entity_name == "refunds") && entity.include?("status")) - %w(succeeded pending).include?(entity["status"]) - elsif(entity.include?("status")) - (entity["status"] == "succeeded") - elsif(entity_name == "cards") - !!entity["id"] + elsif((entity_name == 'refunds') && entity.include?('status')) + %w(succeeded pending).include?(entity['status']) + elsif(entity.include?('status')) + (entity['status'] == 'succeeded') + elsif(entity_name == 'cards') + !!entity['id'] else false end end def message_from(raw_response) - if(raw_response["errors"]) - error = raw_response["errors"].first - (error["additional"] || error["message"] || error["description"]) + if(raw_response['errors']) + error = raw_response['errors'].first + (error['additional'] || error['message'] || error['description']) else - "Success" + 'Success' end end def authorization_from(entity_name, raw_response) entity = (raw_response[entity_name] || []).first - (entity && entity["id"]) + (entity && entity['id']) end def parse(body) @@ -211,8 +211,8 @@ def parse(body) message = 'Invalid response received from the Balanced API. Please contact support@balancedpayments.com if you continue to receive this message.' message += " (The raw response returned by the API was #{raw_response.inspect})" { - "errors" => [{ - "message" => message + 'errors' => [{ + 'message' => message }] } end @@ -231,24 +231,24 @@ def post_data(params) else "#{key}=#{CGI.escape(value.to_s)}" end - end.compact.join("&") + end.compact.join('&') end def headers @@ua ||= JSON.dump( - bindings_version: ActiveMerchant::VERSION, - lang: 'ruby', - lang_version: "#{RUBY_VERSION} p#{RUBY_PATCHLEVEL} (#{RUBY_RELEASE_DATE})", - lib_version: BalancedGateway::VERSION, - platform: RUBY_PLATFORM, - publisher: 'active_merchant' + bindings_version: ActiveMerchant::VERSION, + lang: 'ruby', + lang_version: "#{RUBY_VERSION} p#{RUBY_PATCHLEVEL} (#{RUBY_RELEASE_DATE})", + lib_version: BalancedGateway::VERSION, + platform: RUBY_PLATFORM, + publisher: 'active_merchant' ) { - "Authorization" => "Basic " + Base64.encode64(@options[:login].to_s + ":").strip, - "User-Agent" => "Balanced/v1.1 ActiveMerchantBindings/#{ActiveMerchant::VERSION}", - "Accept" => "application/vnd.api+json;revision=1.1", - "X-Balanced-User-Agent" => @@ua, + 'Authorization' => 'Basic ' + Base64.encode64(@options[:login].to_s + ':').strip, + 'User-Agent' => "Balanced/v1.1 ActiveMerchantBindings/#{ActiveMerchant::VERSION}", + 'Accept' => 'application/vnd.api+json;revision=1.1', + 'X-Balanced-User-Agent' => @@ua, } end end diff --git a/lib/active_merchant/billing/gateways/bank_frick.rb b/lib/active_merchant/billing/gateways/bank_frick.rb index 2f5185d395d..8a35089978c 100644 --- a/lib/active_merchant/billing/gateways/bank_frick.rb +++ b/lib/active_merchant/billing/gateways/bank_frick.rb @@ -9,7 +9,7 @@ class BankFrickGateway < Gateway self.test_url = 'https://test.ctpe.io/payment/ctpe' self.live_url = 'https://ctpe.io/payment/ctpe' - self.supported_countries = ['LI','US'] + self.supported_countries = ['LI', 'US'] self.default_currency = 'EUR' self.supported_cardtypes = [:visa, :master, :american_express, :discover] @@ -93,7 +93,7 @@ def add_address(post, creditcard, options) if address = options[:billing_address] || options[:address] post[:address] = address[:address1].to_s post[:company] = address[:company].to_s - post[:phone] = address[:phone].to_s.gsub(/[^0-9]/, '') || "0000000" + post[:phone] = address[:phone].to_s.gsub(/[^0-9]/, '') || '0000000' post[:zip] = address[:zip].to_s post[:city] = address[:city].to_s post[:country] = address[:country].to_s @@ -121,11 +121,11 @@ def add_payment(post, payment) def parse(body) results = {} xml = Nokogiri::XML(body) - resp = xml.xpath("//Response/Transaction/Identification") + resp = xml.xpath('//Response/Transaction/Identification') resp.children.each do |element| results[element.name.downcase.to_sym] = element.text end - resp = xml.xpath("//Response/Transaction/Processing") + resp = xml.xpath('//Response/Transaction/Processing') resp.children.each do |element| results[element.name.downcase.to_sym] = element.text end diff --git a/lib/active_merchant/billing/gateways/banwire.rb b/lib/active_merchant/billing/gateways/banwire.rb index 09082f50318..99d3e683e34 100644 --- a/lib/active_merchant/billing/gateways/banwire.rb +++ b/lib/active_merchant/billing/gateways/banwire.rb @@ -40,13 +40,13 @@ def scrub(transcript) private def add_response_type(post) - post[:response_format] = "JSON" + post[:response_format] = 'JSON' end def add_customer_data(post, options) post[:user] = @options[:login] post[:phone] = options[:billing_address][:phone] - post[:mail] = options[:email] || "unspecified@email.com" + post[:mail] = options[:email] || 'unspecified@email.com' end def add_order_data(post, options) @@ -63,7 +63,7 @@ def add_creditcard(post, creditcard) post[:card_num] = creditcard.number post[:card_name] = creditcard.name post[:card_type] = card_brand(creditcard) - post[:card_exp] = "#{sprintf("%02d", creditcard.month)}/#{"#{creditcard.year}"[-2, 2]}" + post[:card_exp] = "#{sprintf("%02d", creditcard.month)}/#{creditcard.year.to_s[-2, 2]}" post[:card_ccv2] = creditcard.verification_value end @@ -74,7 +74,7 @@ def add_amount(post, money, options) def card_brand(card) brand = super - ({"master" => "mastercard", "american_express" => "amex"}[brand] || brand) + ({'master' => 'mastercard', 'american_express' => 'amex'}[brand] || brand) end def parse(body) @@ -90,25 +90,25 @@ def commit(money, parameters) end Response.new(success?(response), - response["message"], - response, - :test => test?, - :authorization => response["code_auth"]) + response['message'], + response, + :test => test?, + :authorization => response['code_auth']) end def success?(response) - (response["response"] == "ok") + (response['response'] == 'ok') end def post_data(parameters = {}) - parameters.collect { |key, value| "#{key}=#{CGI.escape(value.to_s)}" }.join("&") + parameters.collect { |key, value| "#{key}=#{CGI.escape(value.to_s)}" }.join('&') end def json_error(raw_response) msg = 'Invalid response received from the Banwire API. Please contact Banwire support if you continue to receive this message.' msg += " (The raw response returned by the API was #{raw_response.inspect})" { - "message" => msg + 'message' => msg } end end diff --git a/lib/active_merchant/billing/gateways/barclaycard_smartpay.rb b/lib/active_merchant/billing/gateways/barclaycard_smartpay.rb index d62014232a5..84a59f82081 100644 --- a/lib/active_merchant/billing/gateways/barclaycard_smartpay.rb +++ b/lib/active_merchant/billing/gateways/barclaycard_smartpay.rb @@ -4,14 +4,17 @@ class BarclaycardSmartpayGateway < Gateway self.test_url = 'https://pal-test.barclaycardsmartpay.com/pal/servlet' self.live_url = 'https://pal-live.barclaycardsmartpay.com/pal/servlet' - self.supported_countries = ['AL', 'AD', 'AM', 'AT', 'AZ', 'BY', 'BE', 'BA', 'BG', 'HR', 'CY', 'CZ', 'DK', 'EE', 'FI', 'FR', 'GE', 'DE', 'GR', 'HU', 'IS', 'IE', 'IT', 'KZ', 'LV', 'LI', 'LT', 'LU', 'MK', 'MT', 'MD', 'MC', 'ME', 'NL', 'NO', 'PL', 'PT', 'RO', 'RU', 'SM', 'RS', 'SK', 'SI', 'ES', 'SE', 'CH', 'TR', 'UA', 'GB', 'VA'] + self.supported_countries = ['AL', 'AD', 'AM', 'AT', 'AZ', 'BY', 'BE', 'BA', 'BG', 'HR', 'CY', 'CZ', 'DK', 'EE', 'FI', 'FR', 'DE', 'GR', 'HU', 'IS', 'IE', 'IT', 'KZ', 'LV', 'LI', 'LT', 'LU', 'MK', 'MT', 'MD', 'MC', 'ME', 'NL', 'NO', 'PL', 'PT', 'RO', 'RU', 'SM', 'RS', 'SK', 'SI', 'ES', 'SE', 'CH', 'TR', 'UA', 'GB', 'VA'] self.default_currency = 'EUR' + self.currencies_with_three_decimal_places = %w(BHD KWD OMR RSD TND) self.money_format = :cents self.supported_cardtypes = [:visa, :master, :american_express, :discover, :diners_club, :jcb, :dankort, :maestro] self.homepage_url = 'https://www.barclaycardsmartpay.com/' self.display_name = 'Barclaycard Smartpay' + API_VERSION = 'v30' + def initialize(options = {}) requires!(options, :company, :merchant, :password) super @@ -32,15 +35,9 @@ def authorize(money, creditcard, options = {}) post = payment_request(money, options) post[:amount] = amount_hash(money, options[:currency]) post[:card] = credit_card_hash(creditcard) - - if address = (options[:billing_address] || options[:address]) - post[:billingAddress] = address_hash(address) - end - - if options[:shipping_address] - post[:deliveryAddress] = address_hash(options[:shipping_address]) - end - + post[:billingAddress] = billing_address_hash(options) if options[:billing_address] + post[:deliveryAddress] = shipping_address_hash(options) if options[:shipping_address] + add_3ds(post, options) if options[:execute_threed] commit('authorise', post) end @@ -66,8 +63,32 @@ def credit(money, creditcard, options = {}) post = payment_request(money, options) post[:amount] = amount_hash(money, options[:currency]) post[:card] = credit_card_hash(creditcard) - - commit('refundWithData', post) + post[:dateOfBirth] = options[:date_of_birth] if options[:date_of_birth] + post[:entityType] = options[:entity_type] if options[:entity_type] + post[:nationality] = options[:nationality] if options[:nationality] + post[:shopperName] = options[:shopper_name] if options[:shopper_name] + + if options[:third_party_payout] + post[:recurring] = options[:recurring_contract] || {contract: 'PAYOUT'} + MultiResponse.run do |r| + r.process { + commit( + 'storeDetailAndSubmitThirdParty', + post, + @options[:store_payout_account], + @options[:store_payout_password]) + } + r.process { + commit( + 'confirmThirdParty', + modification_request(r.authorization, @options), + @options[:review_payout_account], + @options[:review_payout_password]) + } + end + else + commit('refundWithData', post) + end end def void(identification, options = {}) @@ -127,9 +148,10 @@ def scrub(transcript) '18' => 'I' # Neither postal code nor address were checked } - def commit(action, post) + def commit(action, post, account = 'ws', password = @options[:password]) request = post_data(flatten_hash(post)) - raw_response = ssl_post(build_url(action), request, headers) + request_headers = headers(account, password) + raw_response = ssl_post(build_url(action), request, request_headers) response = parse(raw_response) Response.new( @@ -138,27 +160,33 @@ def commit(action, post) response, test: test?, avs_result: AVSResult.new(:code => parse_avs_code(response)), - authorization: response['recurringDetailReference'] || response['pspReference'] + authorization: response['recurringDetailReference'] || authorization_from(post, response) ) - rescue ResponseError => e case e.response.code when '401' return Response.new(false, 'Invalid credentials', {}, :test => test?) when '403' return Response.new(false, 'Not allowed', {}, :test => test?) - when '422' - return Response.new(false, 'Unprocessable Entity', {}, :test => test?) - when '500' - if e.response.body.split(' ')[0] == 'validation' - return Response.new(false, e.response.body.split(' ', 3)[2], {}, :test => test?) + when '422', '500' + if e.response.body.split(/\W+/).any? { |word| %w(validation configuration security).include?(word) } + error_message = e.response.body[/#{Regexp.escape('message=')}(.*?)#{Regexp.escape('&')}/m, 1].tr('+', ' ') + error_code = e.response.body[/#{Regexp.escape('errorCode=')}(.*?)#{Regexp.escape('&')}/m, 1] + return Response.new(false, error_code + ': ' + error_message, {}, :test => test?) end end raise end + def authorization_from(parameters, response) + authorization = [parameters[:originalReference], response['pspReference']].compact + + return nil if authorization.empty? + return authorization.join('#') + end + def parse_avs_code(response) - AVS_MAPPING[response["avsResult"][0..1].strip] if response["avsResult"] + AVS_MAPPING[response['avsResult'][0..1].strip] if response['avsResult'] end def flatten_hash(hash, prefix = nil) @@ -174,10 +202,10 @@ def flatten_hash(hash, prefix = nil) flat_hash end - def headers + def headers(account, password) { 'Content-Type' => 'application/x-www-form-urlencoded; charset=utf-8', - 'Authorization' => 'Basic ' + Base64.strict_encode64("ws@Company.#{@options[:company]}:#{@options[:password]}").strip + 'Authorization' => 'Basic ' + Base64.strict_encode64("#{account}@Company.#{@options[:company]}:#{password}").strip } end @@ -206,41 +234,70 @@ def message_from(response) end def success_from(response) - return true if response.has_key?('authCode') return true if response['result'] == 'Success' - return true if response['resultCode'] == 'Received' - successful_responses = %w([capture-received] [cancel-received] [refund-received]) - successful_responses.include?(response['response']) + + successful_results = %w(Authorised Received [payout-submit-received]) + successful_responses = %w([capture-received] [cancel-received] [refund-received] [payout-confirm-received]) + successful_results.include?(response['resultCode']) || successful_responses.include?(response['response']) end def build_url(action) case action when 'store' - "#{test? ? self.test_url : self.live_url}/Recurring/v12/storeToken" + "#{test? ? self.test_url : self.live_url}/Recurring/#{API_VERSION}/storeToken" + when 'finalize3ds' + "#{test? ? self.test_url : self.live_url}/Payment/#{API_VERSION}/authorise3d" + when 'storeDetailAndSubmitThirdParty', 'confirmThirdParty' + "#{test? ? self.test_url : self.live_url}/Payout/#{API_VERSION}/#{action}" else - "#{test? ? self.test_url : self.live_url}/Payment/v12/#{action}" + "#{test? ? self.test_url : self.live_url}/Payment/#{API_VERSION}/#{action}" end end - def address_hash(address) - full_address = "#{address[:address1]} #{address[:address2]}" if address - street = address[:street] if address[:street] - house = address[:houseNumberOrName] if address[:houseNumberOrName] + def billing_address_hash(options) + address = options[:address] || options[:billing_address] if options[:address] || options[:billing_address] + street = options[:street] || parse_street(address) + house = options[:house_number] || parse_house_number(address) + + create_address_hash(address, house, street) + end + def shipping_address_hash(options) + address = options[:shipping_address] + street = options[:shipping_street] || parse_street(address) + house = options[:shipping_house_number] || parse_house_number(address) + + create_address_hash(address, house, street) + end + + def parse_street(address) + address_to_parse = "#{address[:address1]} #{address[:address2]}" + street = address[:street] || address_to_parse.split(/\s+/).keep_if { |x| x !~ /\d/ }.join(' ') + street.empty? ? 'Not Provided' : street + end + + def parse_house_number(address) + address_to_parse = "#{address[:address1]} #{address[:address2]}" + house = address[:houseNumberOrName] || address_to_parse.split(/\s+/).keep_if { |x| x =~ /\d/ }.join(' ') + house.empty? ? 'Not Provided' : house + end + + def create_address_hash(address, house, street) hash = {} - hash[:city] = address[:city] if address[:city] - hash[:street] = street || full_address.split(/\s+/).keep_if { |x| x !~ /\d/ }.join(' ') - hash[:houseNumberOrName] = house || full_address.split(/\s+/).keep_if { |x| x =~ /\d/ }.join(' ') - hash[:postalCode] = address[:zip] if address[:zip] - hash[:stateOrProvince] = address[:state] if address[:state] - hash[:country] = address[:country] if address[:country] - hash + hash[:houseNumberOrName] = house + hash[:street] = street + hash[:city] = address[:city] + hash[:stateOrProvince] = address[:state] + hash[:postalCode] = address[:zip] + hash[:country] = address[:country] + hash.keep_if { |_, v| v } end def amount_hash(money, currency) + currency = currency || currency(money) hash = {} - hash[:currency] = currency || currency(money) - hash[:value] = amount(money) if money + hash[:currency] = currency + hash[:value] = localized_amount(money, currency) if money hash end @@ -257,27 +314,38 @@ def credit_card_hash(creditcard) def modification_request(reference, options) hash = {} hash[:merchantAccount] = @options[:merchant] - hash[:originalReference] = reference if reference + hash[:originalReference] = psp_reference_from(reference) hash.keep_if { |_, v| v } end + def psp_reference_from(authorization) + authorization.nil? ? nil : authorization.split('#').first + end + def payment_request(money, options) hash = {} - hash[:merchantAccount] = @options[:merchant] - hash[:reference] = options[:order_id] if options[:order_id] - hash[:shopperEmail] = options[:email] if options[:email] - hash[:shopperIP] = options[:ip] if options[:ip] - hash[:shopperReference] = options[:customer] if options[:customer] + hash[:merchantAccount] = @options[:merchant] + hash[:reference] = options[:order_id] + hash[:shopperEmail] = options[:email] + hash[:shopperIP] = options[:ip] + hash[:shopperReference] = options[:customer] + hash[:shopperInteraction] = options[:shopper_interaction] + hash[:deviceFingerprint] = options[:device_fingerprint] hash.keep_if { |_, v| v } end def store_request(options) hash = {} hash[:merchantAccount] = @options[:merchant] - hash[:shopperEmail] = options[:email] if options[:email] + hash[:shopperEmail] = options[:email] hash[:shopperReference] = options[:customer] if options[:customer] hash.keep_if { |_, v| v } end + + def add_3ds(post, options) + post[:additionalData] = { executeThreeD: 'true' } + post[:browserInfo] = { userAgent: options[:user_agent], acceptHeader: options[:accept_header] } + end end end end diff --git a/lib/active_merchant/billing/gateways/barclays_epdq.rb b/lib/active_merchant/billing/gateways/barclays_epdq.rb deleted file mode 100644 index 4349f0726a7..00000000000 --- a/lib/active_merchant/billing/gateways/barclays_epdq.rb +++ /dev/null @@ -1,314 +0,0 @@ -module ActiveMerchant #:nodoc: - module Billing #:nodoc: - class BarclaysEpdqGateway < Gateway - self.test_url = 'https://secure2.mde.epdq.co.uk:11500' - self.live_url = 'https://secure2.epdq.co.uk:11500' - - self.supported_countries = ['GB'] - self.default_currency = 'GBP' - self.supported_cardtypes = [:visa, :master, :american_express, :maestro, :switch ] - self.money_format = :cents - self.homepage_url = 'http://www.barclaycard.co.uk/business/accepting-payments/epdq-mpi/' - self.display_name = 'Barclays ePDQ MPI' - - def initialize(options = {}) - requires!(options, :login, :password, :client_id) - super - end - - def authorize(money, creditcard, options = {}) - document = Document.new(self, @options) do - add_order_form(options[:order_id]) do - add_consumer(options) do - add_creditcard(creditcard) - end - add_transaction(:PreAuth, money) - end - end - - commit(document) - end - - def purchase(money, creditcard, options = {}) - # disable fraud checks if this is a repeat order: - if options[:payment_number] && (options[:payment_number] > 1) - no_fraud = true - else - no_fraud = options[:no_fraud] - end - document = Document.new(self, @options, :no_fraud => no_fraud) do - add_order_form(options[:order_id], options[:group_id]) do - add_consumer(options) do - add_creditcard(creditcard) - end - add_transaction(:Auth, money, options) - end - end - commit(document) - end - - # authorization is your unique order ID, not the authorization - # code returned by ePDQ - def capture(money, authorization, options = {}) - document = Document.new(self, @options) do - add_order_form(authorization) do - add_transaction(:PostAuth, money) - end - end - - commit(document) - end - - # authorization is your unique order ID, not the authorization - # code returned by ePDQ - def credit(money, creditcard_or_authorization, options = {}) - if creditcard_or_authorization.is_a?(String) - ActiveMerchant.deprecated CREDIT_DEPRECATION_MESSAGE - refund(money, creditcard_or_authorization, options) - else - credit_new_order(money, creditcard_or_authorization, options) - end - end - - def refund(money, authorization, options = {}) - credit_existing_order(money, authorization, options) - end - - def void(authorization, options = {}) - document = Document.new(self, @options) do - add_order_form(authorization) do - add_transaction(:Void) - end - end - - commit(document) - end - - private - def credit_new_order(money, creditcard, options) - document = Document.new(self, @options) do - add_order_form do - add_consumer(options) do - add_creditcard(creditcard) - end - add_transaction(:Credit, money) - end - end - - commit(document) - end - - def credit_existing_order(money, authorization, options) - order_id, _ = authorization.split(":") - document = Document.new(self, @options) do - add_order_form(order_id) do - add_transaction(:Credit, money) - end - end - - commit(document) - end - - def parse(body) - parser = Parser.new(body) - response = parser.parse - Response.new(response[:success], response[:message], response, - :test => test?, - :authorization => response[:authorization], - :avs_result => response[:avsresponse], - :cvv_result => response[:cvv_result], - :order_id => response[:order_id], - :raw_response => response[:raw_response] - ) - end - - def commit(document) - url = (test? ? self.test_url : self.live_url) - data = ssl_post(url, document.to_xml) - parse(data) - end - - class Parser - def initialize(response) - @response = response - end - - def parse - require 'iconv' unless String.method_defined?(:encode) - if String.method_defined?(:encode) - doc = REXML::Document.new(@response.encode("UTF-8", "ISO-8859-1")) - else - ic = Iconv.new('UTF-8', 'ISO-8859-1') - doc = REXML::Document.new(ic.iconv(@response)) - end - - auth_type = find(doc, "//Transaction/Type").to_s - - message = find(doc, "//Message/Text") - if message.blank? - message = find(doc, "//Transaction/CardProcResp/CcReturnMsg") - end - - case auth_type - when 'Credit', 'Void' - success = find(doc, "//CcReturnMsg") == "Approved." - else - success = find(doc, "//Transaction/AuthCode").present? - end - - { - :success => success, - :message => message, - :transaction_id => find(doc, "//Transaction/Id"), - :avs_result => find(doc, "//Transaction/AvsRespCode"), - :cvv_result => find(doc, "//Transaction/Cvv2Resp"), - :authorization => find(doc, "//OrderFormDoc/Id"), - :raw_response => @response - } - end - - def find(doc, xpath) - REXML::XPath.first(doc, xpath).try(:text) - end - end - - class Document - attr_reader :type, :xml - - PAYMENT_INTERVALS = { - :days => 'D', - :months => 'M' - } - - EPDQ_CARD_TYPES = { - :visa => 1, - :master => 2, - :switch => 9, - :maestro => 10, - } - - def initialize(gateway, options = {}, document_options = {}, &block) - @gateway = gateway - @options = options - @document_options = document_options - @xml = Builder::XmlMarkup.new(:indent => 2) - build(&block) - end - - def to_xml - @xml.target! - end - - def build(&block) - xml.instruct!(:xml, :version => '1.0') - xml.EngineDocList do - xml.DocVersion "1.0" - xml.EngineDoc do - xml.ContentType "OrderFormDoc" - xml.User do - xml.Name(@options[:login]) - xml.Password(@options[:password]) - xml.ClientId({ :DataType => "S32" }, @options[:client_id]) - end - xml.Instructions do - if @document_options[:no_fraud] - xml.Pipeline "PaymentNoFraud" - else - xml.Pipeline "Payment" - end - end - instance_eval(&block) - end - end - end - - def add_order_form(order_id=nil, group_id=nil, &block) - xml.OrderFormDoc do - xml.Mode 'P' - xml.Id(order_id) if order_id - xml.GroupId(group_id) if group_id - instance_eval(&block) - end - end - - def add_consumer(options=nil, &block) - xml.Consumer do - if options - xml.Email(options[:email]) if options[:email] - billing_address = options[:billing_address] || options[:address] - if billing_address - xml.BillTo do - xml.Location do - xml.Address do - xml.Street1 billing_address[:address1] - xml.Street2 billing_address[:address2] - xml.City billing_address[:city] - xml.StateProv billing_address[:state] - xml.PostalCode billing_address[:zip] - xml.Country billing_address[:country_code] - end - end - end - end - end - instance_eval(&block) - end - end - - def add_creditcard(creditcard) - xml.PaymentMech do - xml.CreditCard do - xml.Type({ :DataType => 'S32' }, EPDQ_CARD_TYPES[creditcard.brand.to_sym]) - xml.Number creditcard.number - xml.Expires({ :DataType => 'ExpirationDate', :Locale => 826 }, format_expiry_date(creditcard)) - if creditcard.verification_value.present? - xml.Cvv2Indicator 1 - xml.Cvv2Val creditcard.verification_value - else - xml.Cvv2Indicator 5 - end - xml.IssueNum(creditcard.issue_number) if creditcard.issue_number.present? - end - end - end - - def add_transaction(auth_type, amount = nil, options = {}) - @auth_type = auth_type - xml.Transaction do - xml.Type @auth_type.to_s - if options[:payment_number] && options[:payment_number] > 1 - xml.CardholderPresentCode({ :DataType => 'S32' }, 8) - else - xml.CardholderPresentCode({ :DataType => 'S32' }, 7) - end - if options[:payment_number] - xml.PaymentNumber({ :DataType => 'S32' }, options[:payment_number]) - end - if options[:total_payments] - xml.TotalNumberPayments({ :DataType => 'S32' }, options[:total_payments]) - end - if amount - xml.CurrentTotals do - xml.Totals do - xml.Total({ :DataType => 'Money', :Currency => 826 }, amount) - end - end - end - end - end - - # date must be formatted MM/YY - def format_expiry_date(creditcard) - month_str = "%02d" % creditcard.month - if match = creditcard.year.to_s.match(/^\d{2}(\d{2})$/) - year_str = "%02d" % match[1].to_i - else - year_str = "%02d" % creditcard.year - end - "#{month_str}/#{year_str}" - end - end - end - end -end - diff --git a/lib/active_merchant/billing/gateways/barclays_epdq_extra_plus.rb b/lib/active_merchant/billing/gateways/barclays_epdq_extra_plus.rb index 933d27f7f63..6f020860b2a 100644 --- a/lib/active_merchant/billing/gateways/barclays_epdq_extra_plus.rb +++ b/lib/active_merchant/billing/gateways/barclays_epdq_extra_plus.rb @@ -1,15 +1,15 @@ module ActiveMerchant #:nodoc: module Billing #:nodoc: class BarclaysEpdqExtraPlusGateway < OgoneGateway - self.test_url = "https://mdepayments.epdq.co.uk/ncol/test/" - self.live_url = "https://payments.epdq.co.uk/ncol/prod/" + self.test_url = 'https://mdepayments.epdq.co.uk/ncol/test/' + self.live_url = 'https://payments.epdq.co.uk/ncol/prod/' - self.display_name = "Barclays ePDQ Extra Plus" - self.homepage_url = "http://www.barclaycard.co.uk/business/accepting-payments/epdq-ecomm/" + self.display_name = 'Barclays ePDQ Extra Plus' + self.homepage_url = 'http://www.barclaycard.co.uk/business/accepting-payments/epdq-ecomm/' - self.supported_countries = ["GB"] + self.supported_countries = ['GB'] self.supported_cardtypes = [:visa, :master, :american_express, :diners_club, :discover, :jcb, :maestro] - self.default_currency = "GBP" + self.default_currency = 'GBP' end end end diff --git a/lib/active_merchant/billing/gateways/be2bill.rb b/lib/active_merchant/billing/gateways/be2bill.rb index 8c46902e9cc..f309272466f 100644 --- a/lib/active_merchant/billing/gateways/be2bill.rb +++ b/lib/active_merchant/billing/gateways/be2bill.rb @@ -1,4 +1,4 @@ -require "digest/sha2" +require 'digest/sha2' module ActiveMerchant #:nodoc: module Billing #:nodoc: @@ -72,7 +72,7 @@ def add_invoice(post, options) def add_creditcard(post, creditcard) post[:CARDFULLNAME] = creditcard ? creditcard.name : '' post[:CARDCODE] = creditcard ? creditcard.number : '' - post[:CARDVALIDITYDATE] = creditcard ? "%02d-%02s" % [creditcard.month, creditcard.year.to_s[-2..-1]] : '' + post[:CARDVALIDITYDATE] = creditcard ? '%02d-%02s' % [creditcard.month, creditcard.year.to_s[-2..-1]] : '' post[:CARDCVV] = creditcard ? creditcard.verification_value : '' end diff --git a/lib/active_merchant/billing/gateways/beanstream.rb b/lib/active_merchant/billing/gateways/beanstream.rb index f396a7d7d0f..aedcac80462 100644 --- a/lib/active_merchant/billing/gateways/beanstream.rb +++ b/lib/active_merchant/billing/gateways/beanstream.rb @@ -75,6 +75,7 @@ def authorize(money, source, options = {}) add_address(post, options) add_transaction_type(post, :authorization) add_customer_ip(post, options) + add_recurring_payment(post, options) commit(post) end @@ -86,6 +87,7 @@ def purchase(money, source, options = {}) add_address(post, options) add_transaction_type(post, purchase_action(source)) add_customer_ip(post, options) + add_recurring_payment(post, options) commit(post) end @@ -165,10 +167,10 @@ def store(payment_method, options = {}) commit(post, true) end - #can't actually delete a secure profile with the supplicated API. This function sets the status of the profile to closed (C). - #Closed profiles will have to removed manually. + # can't actually delete a secure profile with the supplicated API. This function sets the status of the profile to closed (C). + # Closed profiles will have to removed manually. def delete(vault_id) - update(vault_id, false, {:status => "C"}) + update(vault_id, false, {:status => 'C'}) end alias_method :unstore, :delete @@ -184,8 +186,9 @@ def update(vault_id, payment_method, options = {}) else post[:singleUseToken] = payment_method end - options.merge!({:vault_id => vault_id, :operation => secure_profile_action(:modify)}) - add_secure_profile_variables(post,options) + options[:vault_id] = vault_id + options[:operation] = secure_profile_action(:modify) + add_secure_profile_variables(post, options) commit(post, true) end @@ -197,11 +200,13 @@ def scrub(transcript) transcript. gsub(%r((Authorization: Basic )\w+), '\1[FILTERED]'). gsub(/(&?password=)[^&\s]*(&?)/, '\1[FILTERED]\2'). + gsub(/(&?passcode=)[^&\s]*(&?)/, '\1[FILTERED]\2'). gsub(/(&?trnCardCvd=)\d*(&?)/, '\1[FILTERED]\2'). gsub(/(&?trnCardNumber=)\d*(&?)/, '\1[FILTERED]\2') end private + def build_response(*args) Response.new(*args) end diff --git a/lib/active_merchant/billing/gateways/beanstream/beanstream_core.rb b/lib/active_merchant/billing/gateways/beanstream/beanstream_core.rb index cd7262a4afd..5d0640262fe 100644 --- a/lib/active_merchant/billing/gateways/beanstream/beanstream_core.rb +++ b/lib/active_merchant/billing/gateways/beanstream/beanstream_core.rb @@ -1,6 +1,8 @@ module ActiveMerchant #:nodoc: module Billing #:nodoc: module BeanstreamCore + include Empty + RECURRING_URL = 'https://www.beanstream.com/scripts/recurring_billing.asp' SECURE_PROFILE_URL = 'https://www.beanstream.com/scripts/payment_profile.asp' @@ -59,6 +61,72 @@ module BeanstreamCore :cancel => 'C' } + STATES = { + 'ALBERTA' => 'AB', + 'BRITISH COLUMBIA' => 'BC', + 'MANITOBA' => 'MB', + 'NEW BRUNSWICK' => 'NB', + 'NEWFOUNDLAND AND LABRADOR' => 'NL', + 'NOVA SCOTIA' => 'NS', + 'ONTARIO' => 'ON', + 'PRINCE EDWARD ISLAND' => 'PE', + 'QUEBEC' => 'QC', + 'SASKATCHEWAN' => 'SK', + 'NORTHWEST TERRITORIES' => 'NT', + 'NUNAVUT' => 'NU', + 'YUKON' => 'YT', + 'ALABAMA' => 'AL', + 'ALASKA' => 'AK', + 'ARIZONA' => 'AZ', + 'ARKANSAS' => 'AR', + 'CALIFORNIA' => 'CA', + 'COLORADO' => 'CO', + 'CONNECTICUT' => 'CT', + 'DELAWARE' => 'DE', + 'FLORIDA' => 'FL', + 'GEORGIA' => 'GA', + 'HAWAII' => 'HI', + 'IDAHO' => 'ID', + 'ILLINOIS' => 'IL', + 'INDIANA' => 'IN', + 'IOWA' => 'IA', + 'KANSAS' => 'KS', + 'KENTUCKY' => 'KY', + 'LOUISIANA' => 'LA', + 'MAINE' => 'ME', + 'MARYLAND' => 'MD', + 'MASSACHUSETTS' => 'MA', + 'MICHIGAN' => 'MI', + 'MINNESOTA' => 'MN', + 'MISSISSIPPI' => 'MS', + 'MISSOURI' => 'MO', + 'MONTANA' => 'MT', + 'NEBRASKA' => 'NE', + 'NEVADA' => 'NV', + 'NEW HAMPSHIRE' => 'NH', + 'NEW JERSEY' => 'NJ', + 'NEW MEXICO' => 'NM', + 'NEW YORK' => 'NY', + 'NORTH CAROLINA' => 'NC', + 'NORTH DAKOTA' => 'ND', + 'OHIO' => 'OH', + 'OKLAHOMA' => 'OK', + 'OREGON' => 'OR', + 'PENNSYLVANIA' => 'PA', + 'RHODE ISLAND' => 'RI', + 'SOUTH CAROLINA' => 'SC', + 'SOUTH DAKOTA' => 'SD', + 'TENNESSEE' => 'TN', + 'TEXAS' => 'TX', + 'UTAH' => 'UT', + 'VERMONT' => 'VT', + 'VIRGINIA' => 'VA', + 'WASHINGTON' => 'WA', + 'WEST VIRGINIA' => 'WV', + 'WISCONSIN' => 'WI', + 'WYOMING' => 'WY' + } + def self.included(base) base.default_currency = 'CAD' @@ -70,7 +138,7 @@ def self.included(base) # The homepage URL of the gateway base.homepage_url = 'http://www.beanstream.com/' - base.live_url = 'https://www.beanstream.com/scripts/process_transaction.asp' + base.live_url = 'https://api.na.bambora.com/scripts/process_transaction.asp' # The name of the gateway base.display_name = 'Beanstream.com' @@ -88,11 +156,11 @@ def initialize(options = {}) def capture(money, authorization, options = {}) reference, _, _ = split_auth(authorization) - post = {} add_amount(post, money) add_reference(post, reference) add_transaction_type(post, :capture) + add_recurring_payment(post, options) commit(post) end @@ -111,6 +179,7 @@ def credit(money, source, options = {}) end private + def purchase_action(source) if source.is_a?(Check) :check_purchase @@ -120,15 +189,15 @@ def purchase_action(source) end def add_customer_ip(post, options) - post[:customerIP] = options[:ip] if options[:ip] + post[:customerIp] = options[:ip] if options[:ip] end def void_action(original_transaction_type) - (original_transaction_type == TRANSACTIONS[:refund]) ? :void_refund : :void_purchase + original_transaction_type == TRANSACTIONS[:refund] ? :void_refund : :void_purchase end def refund_action(type) - (type == TRANSACTIONS[:check_purchase]) ? :check_refund : :refund + type == TRANSACTIONS[:check_purchase] ? :check_refund : :refund end def secure_profile_action(type) @@ -136,7 +205,7 @@ def secure_profile_action(type) end def split_auth(string) - string.split(";") + string.split(';') end def add_amount(post, money) @@ -152,27 +221,29 @@ def add_reference(post, reference) end def add_address(post, options) + post[:ordEmailAddress] = options[:email] if options[:email] + post[:shipEmailAddress] = options[:shipping_email] || options[:email] if options[:email] + prepare_address_for_non_american_countries(options) if billing_address = options[:billing_address] || options[:address] post[:ordName] = billing_address[:name] - post[:ordEmailAddress] = options[:email] post[:ordPhoneNumber] = billing_address[:phone] post[:ordAddress1] = billing_address[:address1] post[:ordAddress2] = billing_address[:address2] post[:ordCity] = billing_address[:city] - post[:ordProvince] = billing_address[:state] + post[:ordProvince] = state_for(billing_address) post[:ordPostalCode] = billing_address[:zip] post[:ordCountry] = billing_address[:country] end + if shipping_address = options[:shipping_address] post[:shipName] = shipping_address[:name] - post[:shipEmailAddress] = options[:email] post[:shipPhoneNumber] = shipping_address[:phone] post[:shipAddress1] = shipping_address[:address1] post[:shipAddress2] = shipping_address[:address2] post[:shipCity] = shipping_address[:city] - post[:shipProvince] = shipping_address[:state] + post[:shipProvince] = state_for(shipping_address) post[:shipPostalCode] = shipping_address[:zip] post[:shipCountry] = shipping_address[:country] post[:shippingMethod] = shipping_address[:shipping_method] @@ -180,8 +251,13 @@ def add_address(post, options) end end + def state_for(address) + STATES[address[:state].upcase] || address[:state] if address[:state] + end + def prepare_address_for_non_american_countries(options) [ options[:billing_address], options[:shipping_address] ].compact.each do |address| + next if empty?(address[:country]) unless ['US', 'CA'].include?(address[:country]) address[:state] = '--' address[:zip] = '000000' unless address[:zip] @@ -189,6 +265,10 @@ def prepare_address_for_non_american_countries(options) end end + def add_recurring_payment(post, options) + post[:recurringPayment] = 1 if options[:recurring].to_s == 'true' + end + def add_invoice(post, options) post[:trnOrderNumber] = options[:order_id] post[:trnComments] = options[:description] @@ -232,7 +312,6 @@ def add_secure_profile_variables(post, options = {}) post[:serviceVersion] = SP_SERVICE_VERSION post[:responseFormat] = 'QS' post[:cardValidation] = (options[:cardValidation].to_i == 1) || '0' - post[:operationType] = options[:operationType] || options[:operation] || secure_profile_action(:new) post[:customerCode] = options[:billing_id] || options[:vault_id] || false post[:status] = options[:status] @@ -296,17 +375,15 @@ def interval(options) def parse(body) results = {} - if !body.nil? - body.split(/&/).each do |pair| - key, val = pair.split(/\=/) - results[key.to_sym] = val.nil? ? nil : CGI.unescape(val) - end + body&.split(/&/)&.each do |pair| + key, val = pair.split(/\=/) + results[key.to_sym] = val.nil? ? nil : CGI.unescape(val) end # Clean up the message text if there is any if results[:messageText] - results[:messageText].gsub!(/
  • /, "") - results[:messageText].gsub!(/(\.)?
    /, ". ") + results[:messageText].gsub!(/
  • /, '') + results[:messageText].gsub!(/(\.)?
    /, '. ') results[:messageText].strip! end @@ -321,7 +398,7 @@ def recurring_parse(data) end def commit(params, use_profile_api = false) - post(post_data(params,use_profile_api),use_profile_api) + post(post_data(params, use_profile_api), use_profile_api) end def recurring_commit(params) @@ -332,10 +409,10 @@ def post(data, use_profile_api=nil) response = parse(ssl_post((use_profile_api ? SECURE_PROFILE_URL : self.live_url), data)) response[:customer_vault_id] = response[:customerCode] if response[:customerCode] build_response(success?(response), message_from(response), response, - :test => test? || response[:authCode] == "TEST", + :test => test? || response[:authCode] == 'TEST', :authorization => authorization_from(response), :cvv_result => CVD_CODES[response[:cvdId]], - :avs_result => { :code => (AVS_CODES.include? response[:avsId]) ? AVS_CODES[response[:avsId]] : response[:avsId] } + :avs_result => { :code => AVS_CODES.include?(response[:avsId]) ? AVS_CODES[response[:avsId]] : response[:avsId] } ) end @@ -364,7 +441,7 @@ def add_source(post, source) if source.is_a?(String) or source.is_a?(Integer) post[:customerCode] = source else - card_brand(source) == "check" ? add_check(post, source) : add_credit_card(post, source) + card_brand(source) == 'check' ? add_check(post, source) : add_credit_card(post, source) end end @@ -381,14 +458,13 @@ def post_data(params, use_profile_api) params[:username] = @options[:user] if @options[:user] params[:password] = @options[:password] if @options[:password] params[:merchant_id] = @options[:login] + params[:passcode] = @options[:api_key] end params[:vbvEnabled] = '0' params[:scEnabled] = '0' - params.reject{|k, v| v.blank?}.collect { |key, value| "#{key}=#{CGI.escape(value.to_s)}" }.join("&") + params.reject { |k, v| v.blank? }.collect { |key, value| "#{key}=#{CGI.escape(value.to_s)}" }.join('&') end - end end end - diff --git a/lib/active_merchant/billing/gateways/beanstream_interac.rb b/lib/active_merchant/billing/gateways/beanstream_interac.rb index 836f686607d..37ca7595a31 100644 --- a/lib/active_merchant/billing/gateways/beanstream_interac.rb +++ b/lib/active_merchant/billing/gateways/beanstream_interac.rb @@ -55,4 +55,3 @@ def build_response(*args) end end end - diff --git a/lib/active_merchant/billing/gateways/blue_pay.rb b/lib/active_merchant/billing/gateways/blue_pay.rb index 25966133876..b80ffcc2575 100644 --- a/lib/active_merchant/billing/gateways/blue_pay.rb +++ b/lib/active_merchant/billing/gateways/blue_pay.rb @@ -155,7 +155,7 @@ def void(identification, options = {}) # * options -- A hash of parameters. def refund(money, identification, options = {}) if(identification && !identification.kind_of?(String)) - ActiveMerchant.deprecated "refund should only be used to refund a referenced transaction" + ActiveMerchant.deprecated 'refund should only be used to refund a referenced transaction' return credit(money, identification, options) end @@ -163,7 +163,7 @@ def refund(money, identification, options = {}) post[:PAYMENT_ACCOUNT] = '' post[:MASTER_ID] = identification post[:TRANS_TYPE] = 'REFUND' - post[:NAME1] = (options[:first_name] ? options[:first_name] : "") + post[:NAME1] = options[:first_name] || '' post[:NAME2] = options[:last_name] if options[:last_name] post[:ZIP] = options[:zip] if options[:zip] add_invoice(post, options) @@ -173,8 +173,8 @@ def refund(money, identification, options = {}) end def credit(money, payment_object, options = {}) - if(payment_object && payment_object.kind_of?(String)) - ActiveMerchant.deprecated "credit should only be used to credit a payment method" + if payment_object&.kind_of?(String) + ActiveMerchant.deprecated 'credit should only be used to credit a payment method' return refund(money, payment_object, options) end @@ -183,7 +183,7 @@ def credit(money, payment_object, options = {}) add_payment_method(post, payment_object) post[:TRANS_TYPE] = 'CREDIT' - post[:NAME1] = (options[:first_name] ? options[:first_name] : "") + post[:NAME1] = options[:first_name] || '' post[:NAME2] = options[:last_name] if options[:last_name] post[:ZIP] = options[:zip] if options[:zip] add_invoice(post, options) @@ -330,7 +330,7 @@ def commit(action, money, fields) def parse_recurring(response_fields, opts={}) # expected status? parsed = {} - response_fields.each do |k,v| + response_fields.each do |k, v| mapped_key = REBILL_FIELD_MAP.include?(k) ? REBILL_FIELD_MAP[k] : k parsed[mapped_key] = v end @@ -345,14 +345,14 @@ def parse_recurring(response_fields, opts={}) # expected status? def parse(body) # The bp20api has max one value per form field. - response_fields = Hash[CGI::parse(body).map{|k,v| [k.upcase,v.first]}] + response_fields = Hash[CGI::parse(body).map { |k, v| [k.upcase, v.first] }] - if response_fields.include? "REBILL_ID" + if response_fields.include? 'REBILL_ID' return parse_recurring(response_fields) end parsed = {} - response_fields.each do |k,v| + response_fields.each do |k, v| mapped_key = FIELD_MAP.include?(k) ? FIELD_MAP[k] : k parsed[mapped_key] = v end @@ -374,16 +374,16 @@ def message_from(parsed) if CARD_CODE_ERRORS.include?(parsed[:card_code]) message = CVVResult.messages[parsed[:card_code]] elsif AVS_ERRORS.include?(parsed[:avs_result_code]) - message = AVSResult.messages[ parsed[:avs_result_code] ] + message = AVSResult.messages[parsed[:avs_result_code]] else message = message.chomp('.') end - elsif message == "Missing ACCOUNT_ID" - message = "The merchant login ID or password is invalid" + elsif message == 'Missing ACCOUNT_ID' + message = 'The merchant login ID or password is invalid' elsif message =~ /Approved/ - message = "This transaction has been approved" + message = 'This transaction has been approved' elsif message =~ /Expired/ - message = "The credit card has expired" + message = 'The credit card has expired' end message end @@ -418,13 +418,13 @@ def add_creditcard(post, creditcard) end CHECK_ACCOUNT_TYPES = { - "checking" => "C", - "savings" => "S" + 'checking' => 'C', + 'savings' => 'S' } def add_check(post, check) post[:PAYMENT_TYPE] = 'ACH' - post[:PAYMENT_ACCOUNT] = [CHECK_ACCOUNT_TYPES[check.account_type], check.routing_number, check.account_number].join(":") + post[:PAYMENT_ACCOUNT] = [CHECK_ACCOUNT_TYPES[check.account_type], check.routing_number, check.account_number].join(':') post[:NAME1] = check.first_name post[:NAME2] = check.last_name end @@ -465,15 +465,15 @@ def post_data(action, parameters = {}) post[:version] = '1' post[:login] = '' post[:tran_key] = '' - post[:relay_response] = "FALSE" + post[:relay_response] = 'FALSE' post[:type] = action - post[:delim_data] = "TRUE" - post[:delim_char] = "," - post[:encap_char] = "$" + post[:delim_data] = 'TRUE' + post[:delim_char] = ',' + post[:encap_char] = '$' post[:card_num] = '4111111111111111' post[:exp_date] = '1212' post[:solution_ID] = application_id if application_id - post.merge(parameters).collect { |key, value| "#{key}=#{CGI.escape(value.to_s)}" }.join("&") + post.merge(parameters).collect { |key, value| "#{key}=#{CGI.escape(value.to_s)}" }.join('&') end def expdate(creditcard) @@ -494,7 +494,7 @@ def calc_tps(amount, post) post[:MASTER_ID], post[:NAME1], post[:PAYMENT_ACCOUNT] - ].join("") + ].join('') ) end @@ -505,12 +505,12 @@ def calc_rebill_tps(post) @options[:login], post[:TRANS_TYPE], post[:REBILL_ID] - ].join("") + ].join('') ) end def handle_response(response) - if ignore_http_status || (200...300).include?(response.code.to_i) + if ignore_http_status || (200...300).cover?(response.code.to_i) return response.body end raise ResponseError.new(response) diff --git a/lib/active_merchant/billing/gateways/blue_snap.rb b/lib/active_merchant/billing/gateways/blue_snap.rb index 624b95ce96f..a9098385466 100644 --- a/lib/active_merchant/billing/gateways/blue_snap.rb +++ b/lib/active_merchant/billing/gateways/blue_snap.rb @@ -2,8 +2,8 @@ module ActiveMerchant module Billing class BlueSnapGateway < Gateway - self.test_url = "https://sandbox.bluesnap.com/services/2" - self.live_url = "https://ws.bluesnap.com/services/2" + self.test_url = 'https://sandbox.bluesnap.com/services/2' + self.live_url = 'https://ws.bluesnap.com/services/2' self.supported_countries = %w(US CA GB AT BE BG HR CY CZ DK EE FI FR DE GR HU IE IT LV LT LU MT NL PL PT RO SK SI ES SE) self.default_currency = 'USD' @@ -93,7 +93,7 @@ def capture(money, authorization, options = {}) def refund(money, authorization, options = {}) commit(:refund, :put, nil, authorization) do |doc| add_authorization(doc, authorization) - add_amount(doc, money) + add_amount(doc, money, options) add_order(doc, options) end end @@ -113,8 +113,8 @@ def verify(payment_method, options = {}) def store(credit_card, options = {}) commit(:store) do |doc| add_personal_info(doc, credit_card, options) - doc.send("payment-sources") do - doc.send("credit-card-info") do + doc.send('payment-sources') do + doc.send('credit-card-info') do add_credit_card(doc, credit_card) end end @@ -124,7 +124,7 @@ def store(credit_card, options = {}) def verify_credentials begin - ssl_get("#{url}/nonexistent", headers) + ssl_get(url.to_s, headers) rescue ResponseError => e return false if e.response.code.to_i == 401 end @@ -150,9 +150,9 @@ def scrub(transcript) private def add_auth_purchase(doc, money, payment_method, options) - doc.send("recurring-transaction", options[:recurring] ? "RECURRING" : "ECOMMERCE") + doc.send('recurring-transaction', options[:recurring] ? 'RECURRING' : 'ECOMMERCE') add_order(doc, options) - add_amount(doc, money) + add_amount(doc, money, options) add_fraud_info(doc, options) doc.send("vaulted-shopper-id", payment_method) if payment_method.is_a? String @@ -167,6 +167,17 @@ def add_payer_info(doc, payment_method, options) add_ach_info(doc, payment_method) end + def add_payer_info(doc, payment_method, options) + if payment_method.remote_account_id + add_vaulted_ach_info(doc, payment_method) + else + doc.send("payer-info") do + add_personal_info(doc, payment_method, options) + end + add_ach_info(doc, payment_method) + end + end + def add_card_holder_info(doc, payment_method, options) doc.send("card-holder-info") do add_personal_info(doc, payment_method, options) @@ -180,7 +191,7 @@ def add_fraud_info(doc, options) end end - def add_amount(doc, money) + def add_amount(doc, money, options) doc.amount(amount(money)) doc.currency(options[:currency] || currency(money)) end @@ -213,7 +224,12 @@ def add_ach_info(doc, check) doc.send("routing-number", check.routing_number) add_account_type(doc, check) end - # TODO: Be sure to add form field for this and pull the value from it. + doc.send("authorized-by-shopper", "true") + end + + def add_vaulted_ach_info(doc, check) + doc.send("ecp-transaction") + doc.send("vaulted-shopper-id", check.remote_account_id) doc.send("authorized-by-shopper", "true") end @@ -236,18 +252,18 @@ def add_encrypted_fields(doc, card, options) end def add_description(doc, description) - doc.send("transaction-meta-data") do - doc.send("meta-data") do - doc.send("meta-key", "description") - doc.send("meta-value", truncate(description, 50)) - doc.send("meta-description", "Description") + doc.send('transaction-meta-data') do + doc.send('meta-data') do + doc.send('meta-key', 'description') + doc.send('meta-value', truncate(description, 500)) + doc.send('meta-description', 'Description') end end end def add_order(doc, options) - doc.send("merchant-transaction-id", truncate(options[:order_id], 50)) if options[:order_id] - doc.send("soft-descriptor", options[:soft_descriptor]) if options[:soft_descriptor] + doc.send('merchant-transaction-id', truncate(options[:order_id], 50)) if options[:order_id] + doc.send('soft-descriptor', options[:soft_descriptor]) if options[:soft_descriptor] add_description(doc, options[:description]) if options[:description] end @@ -262,13 +278,8 @@ def add_address(doc, options) doc.zip(address[:zip]) if address[:zip] end - def add_invoice(post, money, options) - post[:amount] = amount(money) - post[:currency] = (options[:currency] || currency(money)) - end - def add_authorization(doc, authorization) - doc.send("transaction-id", authorization) + doc.send('transaction-id', authorization) end def add_transaction_type(doc, authorization) @@ -277,6 +288,7 @@ def add_transaction_type(doc, authorization) def parse(response) return bad_authentication_response if response.code.to_i == 401 + return forbidden_response(response.body) if response.code.to_i == 403 # Upon success a refund response comes back with code 204 and no content. return {code: response.code} if response.code.to_i == 204 @@ -284,7 +296,7 @@ def parse(response) parsed = {} doc = Nokogiri::XML(response.body) doc.root.xpath('*').each do |node| - if (node.elements.empty?) + if node.elements.empty? parsed[node.name.downcase] = node.text else node.elements.each do |childnode| @@ -293,7 +305,7 @@ def parse(response) end end - parsed["content-location-header"] = response['content-location'] + parsed['content-location-header'] = response['content-location'] parsed end @@ -347,7 +359,7 @@ def url(action = nil, payment_type = nil, authorization = nil) end def cvv_result(parsed) - CVVResult.new(CVC_CODE_TRANSLATOR[parsed["cvv-response-code"]]) + CVVResult.new(CVC_CODE_TRANSLATOR[parsed['cvv-response-code']]) end def avs_result(parsed) @@ -359,30 +371,30 @@ def avs_lookup_key(p) end def success_from(action, response) - (200...300).include?(response.code.to_i) + (200...300).cover?(response.code.to_i) end def message_from(succeeded, parsed_response) - return "Success" if succeeded - parsed_response["description"] + return 'Success' if succeeded + parsed_response['description'] end def authorization_from(action, parsed_response) - (action == :store) ? vaulted_shopper_id(parsed_response) : parsed_response["transaction-id"] + action == :store ? vaulted_shopper_id(parsed_response) : parsed_response['transaction-id'] end def vaulted_shopper_id(parsed_response) - return nil unless parsed_response["content-location-header"] - parsed_response["content-location-header"].split("/").last + return nil unless parsed_response['content-location-header'] + parsed_response['content-location-header'].split('/').last end def error_code_from(parsed_response) - parsed_response["code"] + parsed_response['code'] end def root_attributes { - xmlns: "http://ws.plimus.com" + xmlns: 'http://ws.plimus.com' } end @@ -424,7 +436,11 @@ def handle_response(response) end def bad_authentication_response - {"description" => "Unable to authenticate. Please check your credentials."} + { 'description' => 'Unable to authenticate. Please check your credentials.' } + end + + def forbidden_response(body) + { 'description' => body } end end end diff --git a/lib/active_merchant/billing/gateways/bogus.rb b/lib/active_merchant/billing/gateways/bogus.rb index 2f5407c069d..8cafd0eeba5 100644 --- a/lib/active_merchant/billing/gateways/bogus.rb +++ b/lib/active_merchant/billing/gateways/bogus.rb @@ -7,15 +7,15 @@ class BogusGateway < Gateway AUTHORIZATION_EMV_SUCCESS = '8A023030' AUTHORIZATION_EMV_DECLINE = '8A023035' - SUCCESS_MESSAGE = "Bogus Gateway: Forced success" - FAILURE_MESSAGE = "Bogus Gateway: Forced failure" - NUMBER_ERROR_MESSAGE = "Bogus Gateway: Use CreditCard number ending in 1 for success, 2 for exception and anything else for error" - AMOUNT_ERROR_MESSAGE = "Bogus Gateway: Use amount ending in 00 for success, 05 for failure and anything else for exception" - UNSTORE_ERROR_MESSAGE = "Bogus Gateway: Use trans_id ending in 1 for success, 2 for exception and anything else for error" - CAPTURE_ERROR_MESSAGE = "Bogus Gateway: Use authorization number ending in 1 for exception, 2 for error and anything else for success" - VOID_ERROR_MESSAGE = "Bogus Gateway: Use authorization number ending in 1 for exception, 2 for error and anything else for success" - REFUND_ERROR_MESSAGE = "Bogus Gateway: Use trans_id number ending in 1 for exception, 2 for error and anything else for success" - CHECK_ERROR_MESSAGE = "Bogus Gateway: Use bank account number ending in 1 for success, 2 for exception and anything else for error" + SUCCESS_MESSAGE = 'Bogus Gateway: Forced success' + FAILURE_MESSAGE = 'Bogus Gateway: Forced failure' + NUMBER_ERROR_MESSAGE = 'Bogus Gateway: Use CreditCard number ending in 1 for success, 2 for exception and anything else for error' + AMOUNT_ERROR_MESSAGE = 'Bogus Gateway: Use amount ending in 00 for success, 05 for failure and anything else for exception' + UNSTORE_ERROR_MESSAGE = 'Bogus Gateway: Use trans_id ending in 1 for success, 2 for exception and anything else for error' + CAPTURE_ERROR_MESSAGE = 'Bogus Gateway: Use authorization number ending in 1 for exception, 2 for error and anything else for success' + VOID_ERROR_MESSAGE = 'Bogus Gateway: Use authorization number ending in 1 for exception, 2 for error and anything else for success' + REFUND_ERROR_MESSAGE = 'Bogus Gateway: Use trans_id number ending in 1 for exception, 2 for error and anything else for success' + CHECK_ERROR_MESSAGE = 'Bogus Gateway: Use bank account number ending in 1 for success, 2 for exception and anything else for error' self.supported_countries = [] self.supported_cardtypes = [:bogus] @@ -47,7 +47,7 @@ def credit(money, paysource, options = {}) money = amount(money) case normalize(paysource) when /1$/ - Response.new(true, SUCCESS_MESSAGE, {:paid_amount => money}, :test => true ) + Response.new(true, SUCCESS_MESSAGE, {:paid_amount => money}, :test => true) when /2$/ Response.new(false, FAILURE_MESSAGE, {:paid_amount => money, :error => FAILURE_MESSAGE }, :test => true, :error_code => STANDARD_ERROR_CODE[:processing_error]) else @@ -106,7 +106,7 @@ def unstore(reference, options = {}) when /1$/ Response.new(true, SUCCESS_MESSAGE, {}, :test => true) when /2$/ - Response.new(false, FAILURE_MESSAGE, {:error => FAILURE_MESSAGE },:test => true, :error_code => STANDARD_ERROR_CODE[:processing_error]) + Response.new(false, FAILURE_MESSAGE, {:error => FAILURE_MESSAGE }, :test => true, :error_code => STANDARD_ERROR_CODE[:processing_error]) else raise Error, UNSTORE_ERROR_MESSAGE end @@ -129,8 +129,8 @@ def authorize_emv(money, paysource, options = {}) def authorize_swipe(money, paysource, options = {}) money = amount(money) case normalize(paysource) - when /1$/ - Response.new(true, SUCCESS_MESSAGE, {:authorized_amount => money}, :test => true, :authorization => AUTHORIZATION ) + when /1$/, AUTHORIZATION + Response.new(true, SUCCESS_MESSAGE, {:authorized_amount => money}, :test => true, :authorization => AUTHORIZATION) when /2$/ Response.new(false, FAILURE_MESSAGE, {:authorized_amount => money, :error => FAILURE_MESSAGE }, :test => true, :error_code => STANDARD_ERROR_CODE[:processing_error]) else diff --git a/lib/active_merchant/billing/gateways/borgun.rb b/lib/active_merchant/billing/gateways/borgun.rb index ff329fb4b2c..b949144fcfb 100644 --- a/lib/active_merchant/billing/gateways/borgun.rb +++ b/lib/active_merchant/billing/gateways/borgun.rb @@ -1,9 +1,9 @@ -require "nokogiri" +require 'nokogiri' module ActiveMerchant #:nodoc: module Billing #:nodoc: class BorgunGateway < Gateway - self.display_name = "Borgun" + self.display_name = 'Borgun' self.homepage_url = 'http://www.borgun.com' self.test_url = 'https://gatewaytest.borgun.is/ws/Heimir.pub.ws:Authorization' @@ -26,7 +26,6 @@ def purchase(money, payment, options={}) post[:TransType] = '1' add_invoice(post, money, options) add_payment_method(post, payment) - commit('sale', post) end @@ -35,7 +34,6 @@ def authorize(money, payment, options={}) post[:TransType] = '5' add_invoice(post, money, options) add_payment_method(post, payment) - commit('authonly', post) end @@ -57,9 +55,10 @@ def refund(money, authorization, options={}) def void(authorization, options={}) post = {} - # TransType and TrAmount must match original values from auth or purchase. - _, _, _, _, _, transtype, tramount = split_authorization(authorization) + # TransType, TrAmount, and currency must match original values from auth or purchase. + _, _, _, _, _, transtype, tramount, currency = split_authorization(authorization) post[:TransType] = transtype + options[:currency] = options[:currency] || CURRENCY_CODES.key(currency) add_invoice(post, tramount.to_i, options) add_reference(post, authorization) commit('void', post) @@ -77,27 +76,28 @@ def scrub(transcript) private - CURRENCY_CODES = Hash.new{|h,k| raise ArgumentError.new("Unsupported currency for HDFC: #{k}")} - CURRENCY_CODES["ISK"] = "352" - CURRENCY_CODES["EUR"] = "978" + CURRENCY_CODES = Hash.new { |h, k| raise ArgumentError.new("Unsupported currency for HDFC: #{k}") } + CURRENCY_CODES['ISK'] = '352' + CURRENCY_CODES['EUR'] = '978' + CURRENCY_CODES['USD'] = '840' def add_invoice(post, money, options) post[:TrAmount] = amount(money) post[:TrCurrency] = CURRENCY_CODES[options[:currency] || currency(money)] + post[:TerminalID] = options[:terminal_id] || '1' end def add_payment_method(post, payment_method) post[:PAN] = payment_method.number post[:ExpDate] = format(payment_method.year, :two_digits) + format(payment_method.month, :two_digits) post[:CVC2] = payment_method.verification_value - post[:DateAndTime] = Time.now.strftime("%y%m%d%H%M%S") + post[:DateAndTime] = Time.now.strftime('%y%m%d%H%M%S') post[:RRN] = 'AMRCNT' + six_random_digits end def add_reference(post, authorization) - dateandtime, batch, transaction, rrn, authcode, _, _ = split_authorization(authorization) + dateandtime, _batch, transaction, rrn, authcode, _, _, _ = split_authorization(authorization) post[:DateAndTime] = dateandtime - post[:Batch] = batch post[:Transaction] = transaction post[:RRN] = rrn post[:AuthCode] = authcode @@ -112,7 +112,7 @@ def parse(xml) body.children.each do |node| if node.text? next - elsif (node.elements.size == 0) + elsif node.elements.size == 0 response[node.name.downcase.to_sym] = node.text else node.elements.each do |childnode| @@ -129,9 +129,7 @@ def commit(action, post) post[:Version] = '1000' post[:Processor] = @options[:processor] post[:MerchantID] = @options[:merchant_id] - post[:TerminalID] = 1 - url = (test? ? test_url : live_url) request = build_request(action, post) raw = ssl_post(url(action), request, headers) pairs = parse(raw) @@ -152,7 +150,7 @@ def success_from(response) def message_from(succeeded, response) if succeeded - "Succeeded" + 'Succeeded' else response[:message] || "Error with ActionCode=#{response[:actioncode]}" end @@ -166,13 +164,14 @@ def authorization_from(response) response[:rrn], response[:authcode], response[:transtype], - response[:tramount] - ].join("|") + response[:tramount], + response[:trcurrency] + ].join('|') end def split_authorization(authorization) - dateandtime, batch, transaction, rrn, authcode, transtype, tramount = authorization.split("|") - [dateandtime, batch, transaction, rrn, authcode, transtype, tramount] + dateandtime, batch, transaction, rrn, authcode, transtype, tramount, currency = authorization.split('|') + [dateandtime, batch, transaction, rrn, authcode, transtype, tramount, currency] end def headers @@ -182,7 +181,7 @@ def headers end def build_request(action, post) - mode = (action == 'void') ? 'cancel' : 'get' + mode = action == 'void' ? 'cancel' : 'get' xml = Builder::XmlMarkup.new :indent => 18 xml.instruct!(:xml, :version => '1.0', :encoding => 'utf-8') xml.tag!("#{mode}Authorization") do @@ -191,7 +190,7 @@ def build_request(action, post) end end inner = CGI.escapeHTML(xml.target!) - envelope(mode).sub(/{{ :body }}/,inner) + envelope(mode).sub(/{{ :body }}/, inner) end def envelope(mode) @@ -214,7 +213,7 @@ def url(action) end def six_random_digits - (0...6).map { (48 + rand(10)).chr }.join + (0...6).map { rand(48..57).chr }.join end end end diff --git a/lib/active_merchant/billing/gateways/bpoint.rb b/lib/active_merchant/billing/gateways/bpoint.rb index 41ed27d6266..dc48ffa47a1 100644 --- a/lib/active_merchant/billing/gateways/bpoint.rb +++ b/lib/active_merchant/billing/gateways/bpoint.rb @@ -185,7 +185,7 @@ def commit(request_body) end def request_headers - { "Content-Type" => "application/soap+xml; charset=utf-8" } + { 'Content-Type' => 'application/soap+xml; charset=utf-8' } end def parse(body) diff --git a/lib/active_merchant/billing/gateways/braintree/braintree_common.rb b/lib/active_merchant/billing/gateways/braintree/braintree_common.rb index af47eae5a36..7343584f7aa 100644 --- a/lib/active_merchant/billing/gateways/braintree/braintree_common.rb +++ b/lib/active_merchant/billing/gateways/braintree/braintree_common.rb @@ -1,10 +1,11 @@ module BraintreeCommon def self.included(base) base.supported_countries = %w(US CA AD AT BE BG HR CY CZ DK EE FI FR GI DE GR GG HU IS IM IE IT JE LV LI LT LU MT MC NL NO PL PT RO SM SK SI ES SE CH TR GB SG HK MY AU NZ) - base.supported_cardtypes = [:visa, :master, :american_express, :discover, :jcb, :diners_club] + base.supported_cardtypes = [:visa, :master, :american_express, :discover, :jcb, :diners_club, :maestro] base.homepage_url = 'http://www.braintreepaymentsolutions.com' base.display_name = 'Braintree' base.default_currency = 'USD' + base.currencies_without_fractions = %w(BIF CLP DJF GNF JPY KMF KRW LAK PYG RWF UGX VND VUV XAF XOF XPF) end def supports_scrubbing @@ -12,7 +13,7 @@ def supports_scrubbing end def scrub(transcript) - return "" if transcript.blank? + return '' if transcript.blank? transcript. gsub(%r((Authorization: Basic )\w+), '\1[FILTERED]'). gsub(%r((&?ccnumber=)\d*(&?)), '\1[FILTERED]\2'). diff --git a/lib/active_merchant/billing/gateways/braintree_blue.rb b/lib/active_merchant/billing/gateways/braintree_blue.rb index 9ca8ef42ece..4cbecdfb4f4 100644 --- a/lib/active_merchant/billing/gateways/braintree_blue.rb +++ b/lib/active_merchant/billing/gateways/braintree_blue.rb @@ -1,13 +1,13 @@ require 'active_merchant/billing/gateways/braintree/braintree_common' begin - require "braintree" + require 'braintree' rescue LoadError - raise "Could not load the braintree gem. Use `gem install braintree` to install it." + raise 'Could not load the braintree gem. Use `gem install braintree` to install it.' end -unless Braintree::Version::Major == 2 && Braintree::Version::Minor >= 4 - raise "Need braintree gem >= 2.4.0. Run `gem install braintree --version '~>2.4'` to get the correct version." +unless Braintree::Version::Major == 2 && Braintree::Version::Minor >= 78 + raise "Need braintree gem >= 2.78.0. Run `gem install braintree --version '~>2.78'` to get the correct version." end module ActiveMerchant #:nodoc: @@ -39,9 +39,14 @@ module Billing #:nodoc: # class BraintreeBlueGateway < Gateway include BraintreeCommon + include Empty self.display_name = 'Braintree (Blue Platform)' + ERROR_CODES = { + cannot_refund_if_unsettled: 91506 + } + def initialize(options = {}) requires!(options, :merchant_id, :public_key, :private_key) @merchant_account_id = options[:merchant_account_id] @@ -49,7 +54,7 @@ def initialize(options = {}) super if wiredump_device.present? - logger = ((Logger === wiredump_device) ? wiredump_device : Logger.new(wiredump_device)) + logger = (Logger === wiredump_device ? wiredump_device : Logger.new(wiredump_device)) logger.level = Logger::DEBUG else logger = Braintree::Configuration.logger.clone @@ -62,10 +67,10 @@ def initialize(options = {}) :private_key => options[:private_key], :environment => (options[:environment] || (test? ? :sandbox : :production)).to_sym, :custom_user_agent => "ActiveMerchant #{ActiveMerchant::VERSION}", - :logger => options[:logger] || logger, + :logger => options[:logger] || logger ) - @braintree_gateway = Braintree::Gateway.new( @configuration ) + @braintree_gateway = Braintree::Gateway.new(@configuration) end def authorize(money, credit_card_or_vault_id, options = {}) @@ -74,7 +79,7 @@ def authorize(money, credit_card_or_vault_id, options = {}) def capture(money, authorization, options = {}) commit do - result = @braintree_gateway.transaction.submit_for_settlement(authorization, amount(money).to_s) + result = @braintree_gateway.transaction.submit_for_settlement(authorization, localized_amount(money, options[:currency] || default_currency).to_s) response_from_result(result) end end @@ -90,11 +95,15 @@ def credit(money, credit_card_or_vault_id, options = {}) def refund(*args) # legacy signature: #refund(transaction_id, options = {}) # new signature: #refund(money, transaction_id, options = {}) - money, transaction_id, _ = extract_refund_args(args) - money = amount(money).to_s if money + money, transaction_id, options = extract_refund_args(args) + money = localized_amount(money, options[:currency] || default_currency).to_s if money commit do - response_from_result(@braintree_gateway.transaction.refund(transaction_id, money)) + response = response_from_result(@braintree_gateway.transaction.refund(transaction_id, money)) + return response if response.success? + return response unless options[:force_full_refund_if_unsettled] + + void(transaction_id) if response.message =~ /#{ERROR_CODES[:cannot_refund_if_unsettled]}/ end end @@ -115,9 +124,9 @@ def store(creditcard, options = {}) if options[:customer].present? MultiResponse.new.tap do |r| customer_exists_response = nil - r.process{customer_exists_response = check_customer_exists(options[:customer])} + r.process { customer_exists_response = check_customer_exists(options[:customer]) } r.process do - if customer_exists_response.params["exists"] + if customer_exists_response.params['exists'] add_credit_card_to_customer(creditcard, options) else add_customer_with_credit_card(creditcard, options) @@ -132,16 +141,16 @@ def store(creditcard, options = {}) def update(vault_id, creditcard, options = {}) braintree_credit_card = nil commit do - braintree_credit_card = @braintree_gateway.customer.find(vault_id).credit_cards.detect { |cc| cc.default? } + braintree_credit_card = @braintree_gateway.customer.find(vault_id).credit_cards.detect(&:default?) return Response.new(false, 'Braintree::NotFoundError') if braintree_credit_card.nil? - options.merge!(:update_existing_token => braintree_credit_card.token) + options[:update_existing_token] = braintree_credit_card.token credit_card_params = merge_credit_card_options({ :credit_card => { :cardholder_name => creditcard.name, :number => creditcard.number, :cvv => creditcard.verification_value, - :expiration_month => creditcard.month.to_s.rjust(2, "0"), + :expiration_month => creditcard.month.to_s.rjust(2, '0'), :expiration_year => creditcard.year.to_s } }, options)[:credit_card] @@ -150,6 +159,8 @@ def update(vault_id, creditcard, options = {}) :first_name => creditcard.first_name, :last_name => creditcard.last_name, :email => scrub_email(options[:email]), + :phone => options[:phone] || (options[:billing_address][:phone] if options[:billing_address] && + options[:billing_address][:phone]), :credit_card => credit_card_params ) Response.new(result.success?, message_from_result(result), @@ -166,7 +177,7 @@ def unstore(customer_vault_id, options = {}) else @braintree_gateway.customer.delete(customer_vault_id) end - Response.new(true, "OK") + Response.new(true, 'OK') end end alias_method :delete, :unstore @@ -177,7 +188,7 @@ def supports_network_tokenization? def verify_credentials begin - @braintree_gateway.transaction.find("non_existent_token") + @braintree_gateway.transaction.find('non_existent_token') rescue Braintree::AuthenticationError return false rescue Braintree::NotFoundError @@ -193,9 +204,9 @@ def check_customer_exists(customer_vault_id) commit do begin @braintree_gateway.customer.find(customer_vault_id) - ActiveMerchant::Billing::Response.new(true, "Customer found", {exists: true}, authorization: customer_vault_id) + ActiveMerchant::Billing::Response.new(true, 'Customer found', {exists: true}, authorization: customer_vault_id) rescue Braintree::NotFoundError - ActiveMerchant::Billing::Response.new(true, "Customer not found", {exists: false}) + ActiveMerchant::Billing::Response.new(true, 'Customer not found', {exists: false}) end end end @@ -210,7 +221,7 @@ def add_customer_with_credit_card(creditcard, options) :cardholder_name => creditcard.name, :number => creditcard.number, :cvv => creditcard.verification_value, - :expiration_month => creditcard.month.to_s.rjust(2, "0"), + :expiration_month => creditcard.month.to_s.rjust(2, '0'), :expiration_year => creditcard.year.to_s, :token => options[:credit_card_token] } @@ -220,7 +231,10 @@ def add_customer_with_credit_card(creditcard, options) :first_name => creditcard.first_name, :last_name => creditcard.last_name, :email => scrub_email(options[:email]), + :phone => options[:phone] || (options[:billing_address][:phone] if options[:billing_address] && + options[:billing_address][:phone]), :id => options[:customer], + :device_data => options[:device_data], }.merge credit_card_params result = @braintree_gateway.customer.create(merge_credit_card_options(parameters, options)) Response.new(result.success?, message_from_result(result), @@ -242,10 +256,14 @@ def add_credit_card_to_customer(credit_card, options) cardholder_name: credit_card.name, number: credit_card.number, cvv: credit_card.verification_value, - expiration_month: credit_card.month.to_s.rjust(2, "0"), + expiration_month: credit_card.month.to_s.rjust(2, '0'), expiration_year: credit_card.year.to_s, + device_data: options[:device_data], } - parameters[:billing_address] = map_address(options[:billing_address]) if options[:billing_address] + if options[:billing_address] + address = map_address(options[:billing_address]) + parameters[:credit_card][:billing_address] = address unless address.all? { |_k, v| empty?(v) } + end result = @braintree_gateway.credit_card.create(parameters) ActiveMerchant::Billing::Response.new( @@ -262,10 +280,10 @@ def add_credit_card_to_customer(credit_card, options) def scrub_email(email) return nil unless email.present? - return nil if ( + return nil if email !~ /^.+@[^\.]+(\.[^\.]+)+[a-z]$/i || email =~ /\.(con|met)$/i - ) + email end @@ -289,13 +307,15 @@ def merge_credit_card_options(parameters, options) end parameters[:credit_card] ||= {} - parameters[:credit_card].merge!(:options => valid_options) - parameters[:credit_card][:billing_address] = map_address(options[:billing_address]) if options[:billing_address] + parameters[:credit_card][:options] = valid_options + if options[:billing_address] + address = map_address(options[:billing_address]) + parameters[:credit_card][:billing_address] = address unless address.all? { |_k, v| empty?(v) } + end parameters end def map_address(address) - return {} if address.nil? mapped = { :street_address => address[:address1], :extended_address => address[:address2], @@ -304,7 +324,7 @@ def map_address(address) :region => address[:state], :postal_code => scrub_zip(address[:zip]), } - if(address[:country] || address[:country_code_alpha2]) + if address[:country] || address[:country_code_alpha2] mapped[:country_code_alpha2] = (address[:country] || address[:country_code_alpha2]) elsif address[:country_name] mapped[:country_name] = address[:country_name] @@ -324,9 +344,9 @@ def commit(&block) def message_from_result(result) if result.success? - "OK" + 'OK' elsif result.errors.any? - result.errors.map { |e| "#{e.message} (#{e.code})" }.join(" ") + result.errors.map { |e| "#{e.message} (#{e.code})" }.join(' ') elsif result.credit_card_verification "Processor declined: #{result.credit_card_verification.processor_response_text} (#{result.credit_card_verification.processor_response_code})" else @@ -335,10 +355,15 @@ def message_from_result(result) end def response_from_result(result) - Response.new(result.success?, message_from_result(result), - { braintree_transaction: transaction_hash(result) }, - { authorization: (result.transaction.id if result.transaction) } - ) + response_hash = { braintree_transaction: transaction_hash(result) } + + Response.new( + result.success?, + message_from_result(result), + response_hash, + authorization: result.transaction&.id, + test: test? + ) end def response_params(result) @@ -356,6 +381,7 @@ def response_options(result) options[:avs_result] = { code: avs_code_from(result.transaction) } options[:cvv_result] = result.transaction.cvv_response_code end + options[:test] = test? options end @@ -366,41 +392,41 @@ def avs_code_from(transaction) def avs_mapping { - "street: M, zip: M" => "M", - "street: M, zip: N" => "A", - "street: M, zip: U" => "B", - "street: M, zip: I" => "B", - "street: M, zip: A" => "B", - - "street: N, zip: M" => "Z", - "street: N, zip: N" => "C", - "street: N, zip: U" => "C", - "street: N, zip: I" => "C", - "street: N, zip: A" => "C", - - "street: U, zip: M" => "P", - "street: U, zip: N" => "N", - "street: U, zip: U" => "I", - "street: U, zip: I" => "I", - "street: U, zip: A" => "I", - - "street: I, zip: M" => "P", - "street: I, zip: N" => "C", - "street: I, zip: U" => "I", - "street: I, zip: I" => "I", - "street: I, zip: A" => "I", - - "street: A, zip: M" => "P", - "street: A, zip: N" => "C", - "street: A, zip: U" => "I", - "street: A, zip: I" => "I", - "street: A, zip: A" => "I" + 'street: M, zip: M' => 'M', + 'street: M, zip: N' => 'A', + 'street: M, zip: U' => 'B', + 'street: M, zip: I' => 'B', + 'street: M, zip: A' => 'B', + + 'street: N, zip: M' => 'Z', + 'street: N, zip: N' => 'C', + 'street: N, zip: U' => 'C', + 'street: N, zip: I' => 'C', + 'street: N, zip: A' => 'C', + + 'street: U, zip: M' => 'P', + 'street: U, zip: N' => 'N', + 'street: U, zip: U' => 'I', + 'street: U, zip: I' => 'I', + 'street: U, zip: A' => 'I', + + 'street: I, zip: M' => 'P', + 'street: I, zip: N' => 'C', + 'street: I, zip: U' => 'I', + 'street: I, zip: I' => 'I', + 'street: I, zip: A' => 'I', + + 'street: A, zip: M' => 'P', + 'street: A, zip: N' => 'C', + 'street: A, zip: U' => 'I', + 'street: A, zip: I' => 'I', + 'street: A, zip: A' => 'I' } end def message_from_transaction_result(result) - if result.transaction && result.transaction.status == "gateway_rejected" - "Transaction declined - gateway rejected" + if result.transaction && result.transaction.status == 'gateway_rejected' + 'Transaction declined - gateway rejected' elsif result.transaction "#{result.transaction.processor_response_code} #{result.transaction.processor_response_text}" else @@ -443,21 +469,22 @@ def extract_refund_args(args) def customer_hash(customer, include_credit_cards=false) hash = { - "email" => customer.email, - "first_name" => customer.first_name, - "last_name" => customer.last_name, - "id" => customer.id + 'email' => customer.email, + 'phone' => customer.phone, + 'first_name' => customer.first_name, + 'last_name' => customer.last_name, + 'id' => customer.id } if include_credit_cards - hash["credit_cards"] = customer.credit_cards.map do |cc| + hash['credit_cards'] = customer.credit_cards.map do |cc| { - "bin" => cc.bin, - "expiration_date" => cc.expiration_date, - "token" => cc.token, - "last_4" => cc.last_4, - "card_type" => cc.card_type, - "masked_number" => cc.masked_number + 'bin' => cc.bin, + 'expiration_date' => cc.expiration_date, + 'token' => cc.token, + 'last_4' => cc.last_4, + 'card_type' => cc.card_type, + 'masked_number' => cc.masked_number } end end @@ -467,16 +494,16 @@ def customer_hash(customer, include_credit_cards=false) def transaction_hash(result) unless result.success? - return { "processor_response_code" => response_code_from_result(result) } + return { 'processor_response_code' => response_code_from_result(result) } end transaction = result.transaction if transaction.vault_customer vault_customer = { } - vault_customer["credit_cards"] = transaction.vault_customer.credit_cards.map do |cc| + vault_customer['credit_cards'] = transaction.vault_customer.credit_cards.map do |cc| { - "bin" => cc.bin + 'bin' => cc.bin } end else @@ -484,53 +511,55 @@ def transaction_hash(result) end customer_details = { - "id" => transaction.customer_details.id, - "email" => transaction.customer_details.email + 'id' => transaction.customer_details.id, + 'email' => transaction.customer_details.email, + 'phone' => transaction.customer_details.phone, } billing_details = { - "street_address" => transaction.billing_details.street_address, - "extended_address" => transaction.billing_details.extended_address, - "company" => transaction.billing_details.company, - "locality" => transaction.billing_details.locality, - "region" => transaction.billing_details.region, - "postal_code" => transaction.billing_details.postal_code, - "country_name" => transaction.billing_details.country_name, + 'street_address' => transaction.billing_details.street_address, + 'extended_address' => transaction.billing_details.extended_address, + 'company' => transaction.billing_details.company, + 'locality' => transaction.billing_details.locality, + 'region' => transaction.billing_details.region, + 'postal_code' => transaction.billing_details.postal_code, + 'country_name' => transaction.billing_details.country_name, } shipping_details = { - "street_address" => transaction.shipping_details.street_address, - "extended_address" => transaction.shipping_details.extended_address, - "company" => transaction.shipping_details.company, - "locality" => transaction.shipping_details.locality, - "region" => transaction.shipping_details.region, - "postal_code" => transaction.shipping_details.postal_code, - "country_name" => transaction.shipping_details.country_name, + 'street_address' => transaction.shipping_details.street_address, + 'extended_address' => transaction.shipping_details.extended_address, + 'company' => transaction.shipping_details.company, + 'locality' => transaction.shipping_details.locality, + 'region' => transaction.shipping_details.region, + 'postal_code' => transaction.shipping_details.postal_code, + 'country_name' => transaction.shipping_details.country_name, } credit_card_details = { - "masked_number" => transaction.credit_card_details.masked_number, - "bin" => transaction.credit_card_details.bin, - "last_4" => transaction.credit_card_details.last_4, - "card_type" => transaction.credit_card_details.card_type, - "token" => transaction.credit_card_details.token + 'masked_number' => transaction.credit_card_details.masked_number, + 'bin' => transaction.credit_card_details.bin, + 'last_4' => transaction.credit_card_details.last_4, + 'card_type' => transaction.credit_card_details.card_type, + 'token' => transaction.credit_card_details.token } { - "order_id" => transaction.order_id, - "status" => transaction.status, - "credit_card_details" => credit_card_details, - "customer_details" => customer_details, - "billing_details" => billing_details, - "shipping_details" => shipping_details, - "vault_customer" => vault_customer, - "merchant_account_id" => transaction.merchant_account_id, - "processor_response_code" => response_code_from_result(result) + 'order_id' => transaction.order_id, + 'amount' => transaction.amount.to_s, + 'status' => transaction.status, + 'credit_card_details' => credit_card_details, + 'customer_details' => customer_details, + 'billing_details' => billing_details, + 'shipping_details' => shipping_details, + 'vault_customer' => vault_customer, + 'merchant_account_id' => transaction.merchant_account_id, + 'processor_response_code' => response_code_from_result(result) } end def create_transaction_parameters(money, credit_card_or_vault_id, options) parameters = { - :amount => amount(money).to_s, + :amount => localized_amount(money, options[:currency] || default_currency).to_s, :order_id => options[:order_id], :customer => { :id => options[:store] == true ? "" : options[:store], @@ -542,10 +571,14 @@ def create_transaction_parameters(money, credit_card_or_vault_id, options) :options => { :store_in_vault => options[:store] ? true : false, :submit_for_settlement => options[:submit_for_settlement], - :hold_in_escrow => options[:hold_in_escrow] + :hold_in_escrow => options[:hold_in_escrow], } } + if options[:skip_advanced_fraud_checking] + parameters[:options][:skip_advanced_fraud_checking] = options[:skip_advanced_fraud_checking] + end + parameters[:custom_fields] = options[:custom_fields] parameters[:device_data] = options[:device_data] if options[:device_data] parameters[:service_fee_amount] = options[:service_fee_amount] if options[:service_fee_amount] @@ -575,25 +608,29 @@ def create_transaction_parameters(money, credit_card_or_vault_id, options) if credit_card_or_vault_id.source == :apple_pay parameters[:apple_pay_card] = { :number => credit_card_or_vault_id.number, - :expiration_month => credit_card_or_vault_id.month.to_s.rjust(2, "0"), + :expiration_month => credit_card_or_vault_id.month.to_s.rjust(2, '0'), :expiration_year => credit_card_or_vault_id.year.to_s, :cardholder_name => credit_card_or_vault_id.name, - :cryptogram => credit_card_or_vault_id.payment_cryptogram + :cryptogram => credit_card_or_vault_id.payment_cryptogram, + :eci_indicator => credit_card_or_vault_id.eci } - elsif credit_card_or_vault_id.source == :android_pay + elsif credit_card_or_vault_id.source == :android_pay || credit_card_or_vault_id.source == :google_pay parameters[:android_pay_card] = { :number => credit_card_or_vault_id.number, :cryptogram => credit_card_or_vault_id.payment_cryptogram, - :expiration_month => credit_card_or_vault_id.month.to_s.rjust(2, "0"), + :expiration_month => credit_card_or_vault_id.month.to_s.rjust(2, '0'), :expiration_year => credit_card_or_vault_id.year.to_s, - :google_transaction_id => credit_card_or_vault_id.transaction_id + :google_transaction_id => credit_card_or_vault_id.transaction_id, + :source_card_type => credit_card_or_vault_id.brand, + :source_card_last_four => credit_card_or_vault_id.last_digits, + :eci_indicator => credit_card_or_vault_id.eci } end else parameters[:credit_card] = { :number => credit_card_or_vault_id.number, :cvv => credit_card_or_vault_id.verification_value, - :expiration_month => credit_card_or_vault_id.month.to_s.rjust(2, "0"), + :expiration_month => credit_card_or_vault_id.month.to_s.rjust(2, '0'), :expiration_year => credit_card_or_vault_id.year.to_s, :cardholder_name => credit_card_or_vault_id.name } @@ -613,6 +650,14 @@ def create_transaction_parameters(money, credit_card_or_vault_id, options) } end + if options[:three_d_secure] + parameters[:three_d_secure_pass_thru] = { + cavv: options[:three_d_secure][:cavv], + eci_flag: options[:three_d_secure][:eci], + xid: options[:three_d_secure][:xid], + } + end + parameters end end diff --git a/lib/active_merchant/billing/gateways/braintree_orange.rb b/lib/active_merchant/billing/gateways/braintree_orange.rb index a8b76b3d8b2..f56502eb7a0 100644 --- a/lib/active_merchant/billing/gateways/braintree_orange.rb +++ b/lib/active_merchant/billing/gateways/braintree_orange.rb @@ -7,7 +7,7 @@ class BraintreeOrangeGateway < SmartPs include BraintreeCommon self.display_name = 'Braintree (Orange Platform)' - self.supported_countries = ["US"] + self.supported_countries = ['US'] self.live_url = self.test_url = 'https://secure.braintreepaymentgateway.com/api/transact.php' diff --git a/lib/active_merchant/billing/gateways/bridge_pay.rb b/lib/active_merchant/billing/gateways/bridge_pay.rb index 2754a20428b..d8cf6218265 100644 --- a/lib/active_merchant/billing/gateways/bridge_pay.rb +++ b/lib/active_merchant/billing/gateways/bridge_pay.rb @@ -1,29 +1,28 @@ -require "nokogiri" +require 'nokogiri' module ActiveMerchant #:nodoc: module Billing #:nodoc: class BridgePayGateway < Gateway - self.display_name = "BridgePay" - self.homepage_url = "http://www.bridgepaynetwork.com/" + self.display_name = 'BridgePay' + self.homepage_url = 'http://www.bridgepaynetwork.com/' - self.test_url = "https://gatewaystage.itstgate.com/SmartPayments/transact3.asmx" - self.live_url = "https://gateway.itstgate.com/SmartPayments/transact3.asmx" + self.test_url = 'https://gatewaystage.itstgate.com/SmartPayments/transact3.asmx' + self.live_url = 'https://gateway.itstgate.com/SmartPayments/transact3.asmx' - self.supported_countries = ["CA", "US"] - self.default_currency = "USD" + self.supported_countries = ['CA', 'US'] + self.default_currency = 'USD' self.supported_cardtypes = [:visa, :master, :american_express, :discover, :diners_club, :jcb] - def initialize(options={}) requires!(options, :user_name, :password) super end def purchase(amount, payment_method, options={}) - post = initialize_required_fields("Sale") + post = initialize_required_fields('Sale') # Allow the same amount in multiple transactions. - post[:ExtData] = "T" + post[:ExtData] = 'T' add_invoice(post, amount, options) add_payment_method(post, payment_method) add_customer_data(post, options) @@ -32,7 +31,7 @@ def purchase(amount, payment_method, options={}) end def authorize(amount, payment_method, options={}) - post = initialize_required_fields("Auth") + post = initialize_required_fields('Auth') add_invoice(post, amount, options) add_payment_method(post, payment_method) @@ -42,7 +41,7 @@ def authorize(amount, payment_method, options={}) end def capture(amount, authorization, options={}) - post = initialize_required_fields("Force") + post = initialize_required_fields('Force') add_invoice(post, amount, options) add_reference(post, authorization) @@ -52,7 +51,7 @@ def capture(amount, authorization, options={}) end def refund(amount, authorization, options={}) - post = initialize_required_fields("Return") + post = initialize_required_fields('Return') add_invoice(post, amount, options) add_reference(post, authorization) @@ -61,7 +60,7 @@ def refund(amount, authorization, options={}) end def void(authorization, options={}) - post = initialize_required_fields("Void") + post = initialize_required_fields('Void') add_reference(post, authorization) @@ -114,36 +113,36 @@ def add_payment_method(post, payment_method) post[:TransitNum] = payment_method.routing_number post[:AccountNum] = payment_method.account_number post[:NameOnCheck] = payment_method.name - post[:ExtData] = "#{payment_method.account_type.capitalize}" + post[:ExtData] = "#{payment_method.account_type.capitalize}" if payment_method.account_type end end def add_token(post, payment_method) - payment_method = payment_method.split("|") + payment_method = payment_method.split('|') post[:ExtData] = "TRead#{payment_method[1]}#{payment_method[0]}#{payment_method[2]}" end def initialize_required_fields(transaction_type) post = {} post[:TransType] = transaction_type - post[:Amount] = "" - post[:PNRef] = "" - post[:InvNum] = "" - post[:CardNum] = "" - post[:ExpDate] = "" - post[:MagData] = "" - post[:NameOnCard] = "" - post[:Zip] = "" - post[:Street] = "" - post[:CVNum] = "" - post[:MagData] = "" - post[:ExtData] = "" - post[:MICR] = "" - post[:DL] = "" - post[:SS] = "" - post[:DOB] = "" - post[:StateCode] = "" - post[:CheckType] = "" + post[:Amount] = '' + post[:PNRef] = '' + post[:InvNum] = '' + post[:CardNum] = '' + post[:ExpDate] = '' + post[:MagData] = '' + post[:NameOnCard] = '' + post[:Zip] = '' + post[:Street] = '' + post[:CVNum] = '' + post[:MagData] = '' + post[:ExtData] = '' + post[:MICR] = '' + post[:DL] = '' + post[:SS] = '' + post[:DOB] = '' + post[:StateCode] = '' + post[:CheckType] = '' post end @@ -167,8 +166,8 @@ def parse(xml) response = {} doc = Nokogiri::XML(xml) - doc.root.xpath("*").each do |node| - if (node.elements.size == 0) + doc.root&.xpath('*')&.each do |node| + if node.elements.size == 0 response[node.name.downcase.to_sym] = node.text else node.elements.each do |childnode| @@ -176,7 +175,7 @@ def parse(xml) response[name.to_sym] = childnode.text end end - end unless doc.root.nil? + end response end @@ -208,7 +207,7 @@ def base_url end def success_from(response) - response[:result] == "0" + response[:result] == '0' end def message_from(response) @@ -217,14 +216,14 @@ def message_from(response) def authorization_from(response) if response[:token] - [response[:token], response[:customerpaymentinfokey], response[:expdate]].join("|") + [response[:token], response[:customerpaymentinfokey], response[:expdate]].join('|') else - [response[:authcode], response[:pnref]].join("|") + [response[:authcode], response[:pnref]].join('|') end end def split_authorization(authorization) - authcode, pnref = authorization.split("|") + authcode, pnref = authorization.split('|') [authcode, pnref] end @@ -238,7 +237,7 @@ def post_data(post) { :UserName => @options[:user_name], :Password => @options[:password] - }.merge(post).collect{|k,v| "#{k}=#{CGI.escape(v.to_s)}"}.join("&") + }.merge(post).collect { |k, v| "#{k}=#{CGI.escape(v.to_s)}" }.join('&') end end end diff --git a/lib/active_merchant/billing/gateways/cams.rb b/lib/active_merchant/billing/gateways/cams.rb index 93d9297dc47..4fd30dd0489 100644 --- a/lib/active_merchant/billing/gateways/cams.rb +++ b/lib/active_merchant/billing/gateways/cams.rb @@ -1,7 +1,7 @@ module ActiveMerchant #:nodoc: module Billing #:nodoc: class CamsGateway < Gateway - self.live_url = "https://secure.centralams.com/gw/api/transact.php" + self.live_url = 'https://secure.centralams.com/gw/api/transact.php' self.supported_countries = ['US'] self.default_currency = 'USD' @@ -83,7 +83,7 @@ def purchase(money, payment, options={}) post[:transactionid] = split_authorization(payment)[0] end - commit("sale", post) + commit('sale', post) end def authorize(money, payment, options={}) @@ -140,24 +140,24 @@ def scrub(transcript) def add_address(post, creditcard, options={}) post[:firstname] = creditcard.first_name - post[:lastname ] = creditcard.last_name + post[:lastname] = creditcard.last_name return unless options[:billing_address] address = options[:billing_address] - post[:address1 ] = address[:address1] - post[:address2 ] = address[:address2] - post[:city ] = address[:city] - post[:state ] = address[:state] - post[:zip ] = address[:zip] - post[:country ] = address[:country] - post[:phone ] = address[:phone] + post[:address1] = address[:address1] + post[:address2] = address[:address2] + post[:city] = address[:city] + post[:state] = address[:state] + post[:zip] = address[:zip] + post[:country] = address[:country] + post[:phone] = address[:phone] end def add_reference(post, authorization) transaction_id, authcode = split_authorization(authorization) - post["transactionid"] = transaction_id - post["authcode"] = authcode + post['transactionid'] = transaction_id + post['authcode'] = authcode end def add_invoice(post, money, options) @@ -167,15 +167,15 @@ def add_invoice(post, money, options) def add_payment(post, payment) post[:ccnumber] = payment.number - post[:ccexp ] = "#{payment.month.to_s.rjust(2,"0")}#{payment.year.to_s[-2..-1]}" - post[:cvv ] = payment.verification_value + post[:ccexp] = "#{payment.month.to_s.rjust(2, "0")}#{payment.year.to_s[-2..-1]}" + post[:cvv] = payment.verification_value end def parse(body) - kvs = body.split("&") + kvs = body.split('&') kvs.inject({}) { |h, kv| - k,v = kv.split("=") + k, v = kv.split('=') h[k] = v h } @@ -199,19 +199,19 @@ def commit(action, parameters) end def success_from(response) - response["response_code"] == "100" + response['response_code'] == '100' end def message_from(response) - response["responsetext"] + response['responsetext'] end def authorization_from(response) - [response["transactionid"], response["authcode"]].join("#") + [response['transactionid'], response['authcode']].join('#') end def split_authorization(authorization) - transaction_id, authcode = authorization.split("#") + transaction_id, authcode = authorization.split('#') [transaction_id, authcode] end @@ -219,11 +219,11 @@ def post_data(parameters = {}) parameters[:password] = @options[:password] parameters[:username] = @options[:username] - parameters.collect{|k,v| "#{k}=#{v}" }.join("&") + parameters.collect { |k, v| "#{k}=#{v}" }.join('&') end def error_code_from(response) - STANDARD_ERROR_CODE_MAPPING[response["response_code"]] + STANDARD_ERROR_CODE_MAPPING[response['response_code']] end end end diff --git a/lib/active_merchant/billing/gateways/card_connect.rb b/lib/active_merchant/billing/gateways/card_connect.rb new file mode 100644 index 00000000000..c4630cf0697 --- /dev/null +++ b/lib/active_merchant/billing/gateways/card_connect.rb @@ -0,0 +1,311 @@ +module ActiveMerchant #:nodoc: + module Billing #:nodoc: + class CardConnectGateway < Gateway + self.test_url = 'https://fts.cardconnect.com:6443/cardconnect/rest/' + self.live_url = 'https://fts.cardconnect.com:8443/cardconnect/rest/' + + self.supported_countries = ['US'] + self.default_currency = 'USD' + self.supported_cardtypes = [:visa, :master, :american_express, :discover] + + self.homepage_url = 'https://cardconnect.com/' + self.display_name = 'Card Connect' + + STANDARD_ERROR_CODE_MAPPING = { + '11' => STANDARD_ERROR_CODE[:card_declined], + '12' => STANDARD_ERROR_CODE[:incorrect_number], + '13' => STANDARD_ERROR_CODE[:incorrect_cvc], + '14' => STANDARD_ERROR_CODE[:incorrect_cvc], + '15' => STANDARD_ERROR_CODE[:invalid_expiry_date], + '16' => STANDARD_ERROR_CODE[:expired_card], + '17' => STANDARD_ERROR_CODE[:incorrect_zip], + '21' => STANDARD_ERROR_CODE[:config_error], + '22' => STANDARD_ERROR_CODE[:config_error], + '23' => STANDARD_ERROR_CODE[:config_error], + '24' => STANDARD_ERROR_CODE[:processing_error], + '25' => STANDARD_ERROR_CODE[:processing_error], + '27' => STANDARD_ERROR_CODE[:processing_error], + '28' => STANDARD_ERROR_CODE[:processing_error], + '29' => STANDARD_ERROR_CODE[:processing_error], + '31' => STANDARD_ERROR_CODE[:processing_error], + '32' => STANDARD_ERROR_CODE[:processing_error], + '33' => STANDARD_ERROR_CODE[:card_declined], + '34' => STANDARD_ERROR_CODE[:card_declined], + '35' => STANDARD_ERROR_CODE[:incorrect_zip], + '36' => STANDARD_ERROR_CODE[:processing_error], + '37' => STANDARD_ERROR_CODE[:incorrect_cvc], + '41' => STANDARD_ERROR_CODE[:processing_error], + '42' => STANDARD_ERROR_CODE[:processing_error], + '43' => STANDARD_ERROR_CODE[:processing_error], + '44' => STANDARD_ERROR_CODE[:config_error], + '61' => STANDARD_ERROR_CODE[:processing_error], + '62' => STANDARD_ERROR_CODE[:processing_error], + '63' => STANDARD_ERROR_CODE[:processing_error], + '64' => STANDARD_ERROR_CODE[:config_error], + '65' => STANDARD_ERROR_CODE[:processing_error], + '66' => STANDARD_ERROR_CODE[:processing_error], + '91' => STANDARD_ERROR_CODE[:processing_error], + '92' => STANDARD_ERROR_CODE[:processing_error], + '93' => STANDARD_ERROR_CODE[:processing_error], + '94' => STANDARD_ERROR_CODE[:processing_error], + '95' => STANDARD_ERROR_CODE[:config_error], + '96' => STANDARD_ERROR_CODE[:processing_error], + 'NU' => STANDARD_ERROR_CODE[:card_declined], + 'N3' => STANDARD_ERROR_CODE[:card_declined], + 'NJ' => STANDARD_ERROR_CODE[:card_declined], + '51' => STANDARD_ERROR_CODE[:card_declined], + 'C2' => STANDARD_ERROR_CODE[:incorrect_cvc], + '54' => STANDARD_ERROR_CODE[:expired_card], + '05' => STANDARD_ERROR_CODE[:card_declined], + '03' => STANDARD_ERROR_CODE[:config_error], + '60' => STANDARD_ERROR_CODE[:pickup_card] + } + + def initialize(options = {}) + requires!(options, :merchant_id, :username, :password) + require_valid_domain!(options, :domain) + super + end + + def require_valid_domain!(options, param) + if options.key?(param) + raise ArgumentError.new('not a valid cardconnect domain') unless /\Dcardconnect.com:\d{1,}\D/ =~ options[param] + end + end + + def purchase(money, payment, options = {}) + if options[:po_number] + MultiResponse.run do |r| + r.process { authorize(money, payment, options) } + r.process { capture(money, r.authorization, options) } + end + else + post = {} + add_invoice(post, options) + add_money(post, money) + add_payment(post, payment) + add_currency(post, money, options) + add_address(post, options) + add_customer_data(post, options) + add_3DS(post, options) + post[:capture] = 'Y' + commit('auth', post) + end + end + + def authorize(money, payment, options = {}) + post = {} + add_money(post, money) + add_currency(post, money, options) + add_invoice(post, options) + add_payment(post, payment) + add_address(post, options) + add_customer_data(post, options) + add_3DS(post, options) + commit('auth', post) + end + + def capture(money, authorization, options = {}) + post = {} + add_money(post, money) + add_reference(post, authorization) + add_additional_data(post, options) + commit('capture', post) + end + + def refund(money, authorization, options = {}) + post = {} + add_money(post, money) + add_reference(post, authorization) + commit('refund', post) + end + + def void(authorization, options = {}) + post = {} + add_reference(post, authorization) + commit('void', post) + end + + def verify(credit_card, options = {}) + authorize(0, credit_card, options) + end + + def store(payment, options = {}) + post = {} + add_payment(post, payment) + add_address(post, options) + add_customer_data(post, options) + commit('profile', post) + end + + def unstore(authorization, options = {}) + account_id, profile_id = authorization.split('|') + commit('profile', {}, + verb: :delete, + path: "/#{profile_id}/#{account_id}/#{@options[:merchant_id]}") + end + + def supports_scrubbing? + true + end + + def scrub(transcript) + transcript. + gsub(%r((Authorization: Basic )\w+), '\1[FILTERED]'). + gsub(%r(("cvv2\\":\\")\d*), '\1[FILTERED]'). + gsub(%r(("merchid\\":\\")\d*), '\1[FILTERED]'). + gsub(%r((&?"account\\":\\")\d*), '\1[FILTERED]'). + gsub(%r((&?"token\\":\\")\d*), '\1[FILTERED]') + end + + private + + def add_customer_data(post, options) + post[:email] = options[:email] if options[:email] + end + + def add_address(post, options) + if address = options[:billing_address] || options[:address] + post[:address] = address[:address1] if address[:address1] + post[:address].concat(" #{address[:address2]}") if address[:address2] + post[:city] = address[:city] if address[:city] + post[:region] = address[:state] if address[:state] + post[:country] = address[:country] if address[:country] + post[:postal] = address[:zip] if address[:zip] + post[:phone] = address[:phone] if address[:phone] + end + end + + def add_money(post, money) + post[:amount] = amount(money) + end + + def add_currency(post, money, options) + post[:currency] = (options[:currency] || currency(money)) + end + + def add_invoice(post, options) + post[:orderid] = options[:order_id] + post[:ecomind] = (options[:recurring] ? 'R' : 'E') + end + + def add_payment(post, payment) + if payment.is_a?(String) + account_id, profile_id = payment.split('|') + post[:profile] = profile_id + post[:acctid] = account_id + else + post[:name] = payment.name + if card_brand(payment) == 'check' + add_echeck(post, payment) + else + post[:account] = payment.number + post[:expiry] = expdate(payment) + post[:cvv2] = payment.verification_value + end + end + end + + def add_echeck(post, payment) + post[:accttype] = 'ECHK' + post[:account] = payment.account_number + post[:bankaba] = payment.routing_number + end + + def add_reference(post, authorization) + post[:retref] = authorization + end + + def add_additional_data(post, options) + post[:ponumber] = options[:po_number] + post[:taxamnt] = options[:tax_amount] if options[:tax_amount] + post[:frtamnt] = options[:freight_amount] if options[:freight_amount] + post[:dutyamnt] = options[:duty_amount] if options[:duty_amount] + post[:orderdate] = options[:order_date] if options[:order_date] + post[:shipfromzip] = options[:ship_from_zip] if options[:ship_from_zip] + if (shipping_address = options[:shipping_address]) + post[:shiptozip] = shipping_address[:zip] + post[:shiptocountry] = shipping_address[:country] + end + if options[:items] + post[:items] = options[:items].map do |item| + updated = {} + item.each_pair do |k, v| + updated.merge!(k.to_s.gsub(/_/, '') => v) + end + end + end + end + + def add_3DS(post, options) + post[:secureflag] = options[:secure_flag] if options[:secure_flag] + post[:securevalue] = options[:secure_value] if options[:secure_value] + post[:securexid] = options[:secure_xid] if options[:secure_xid] + end + + def headers + { + 'Authorization' => 'Basic ' + Base64.strict_encode64("#{@options[:username]}:#{@options[:password]}"), + 'Content-Type' => 'application/json' + } + end + + def expdate(credit_card) + "#{format(credit_card.month, :two_digits)}#{format(credit_card.year, :two_digits)}" + end + + def parse(body) + JSON.parse(body) + end + + def url(action, path) + if test? + test_url + action + path + else + (@options[:domain] || live_url) + action + path + end + end + + def commit(action, parameters, verb: :put, path: '') + parameters[:merchid] = @options[:merchant_id] + url = url(action, path) + response = parse(ssl_request(verb, url, post_data(parameters), headers)) + + Response.new( + success_from(response), + message_from(response), + response, + authorization: authorization_from(response), + avs_result: AVSResult.new(code: response['avsresp']), + cvv_result: CVVResult.new(response['cvvresp']), + test: test?, + error_code: error_code_from(response) + ) + end + + def success_from(response) + response['respstat'] == 'A' + end + + def message_from(response) + response['setlstat'] ? "#{response['resptext']} #{response['setlstat']}" : response['resptext'] + end + + def authorization_from(response) + if response['profileid'] + "#{response['acctid']}|#{response['profileid']}" + else + response['retref'] + end + end + + def post_data(parameters = {}) + parameters.to_json + end + + def error_code_from(response) + STANDARD_ERROR_CODE_MAPPING[response['respcode']] unless success_from(response) + end + end + end +end diff --git a/lib/active_merchant/billing/gateways/card_save.rb b/lib/active_merchant/billing/gateways/card_save.rb index 7bd9ee8e4d2..7d5920be05b 100644 --- a/lib/active_merchant/billing/gateways/card_save.rb +++ b/lib/active_merchant/billing/gateways/card_save.rb @@ -1,23 +1,22 @@ module ActiveMerchant #:nodoc: module Billing #:nodoc: class CardSaveGateway < IridiumGateway - #CardSave lets you handle failovers on payments by providing 3 gateways in case one happens to be down - #URLS = ['https://gw1.cardsaveonlinepayments.com:4430/','https://gw2.cardsaveonlinepayments.com:4430/','https://gw3.cardsaveonlinepayments.com:4430/'] - + # CardSave lets you handle failovers on payments by providing 3 gateways in case one happens to be down + # URLS = ['https://gw1.cardsaveonlinepayments.com:4430/','https://gw2.cardsaveonlinepayments.com:4430/','https://gw3.cardsaveonlinepayments.com:4430/'] + self.money_format = :cents self.default_currency = 'GBP' - self.supported_cardtypes = [ :visa, :switch, :maestro, :master, :solo, :american_express, :jcb ] + self.supported_cardtypes = [ :visa, :maestro, :master, :american_express, :jcb ] self.supported_countries = [ 'GB' ] self.homepage_url = 'http://www.cardsave.net/' self.display_name = 'CardSave' - + def initialize(options={}) super @test_url = 'https://gw1.cardsaveonlinepayments.com:4430/' @live_url = 'https://gw1.cardsaveonlinepayments.com:4430/' end - + end end end - diff --git a/lib/active_merchant/billing/gateways/card_stream.rb b/lib/active_merchant/billing/gateways/card_stream.rb index fc33a4db0ca..f5ac54fdb83 100644 --- a/lib/active_merchant/billing/gateways/card_stream.rb +++ b/lib/active_merchant/billing/gateways/card_stream.rb @@ -2,107 +2,107 @@ module ActiveMerchant #:nodoc: module Billing #:nodoc: class CardStreamGateway < Gateway - THREEDSECURE_REQUIRED_DEPRECATION_MESSAGE = "Specifying the :threeDSRequired initialization option is deprecated. Please use the `:threeds_required => true` *transaction* option instead." + THREEDSECURE_REQUIRED_DEPRECATION_MESSAGE = 'Specifying the :threeDSRequired initialization option is deprecated. Please use the `:threeds_required => true` *transaction* option instead.' self.test_url = self.live_url = 'https://gateway.cardstream.com/direct/' self.money_format = :cents self.default_currency = 'GBP' self.supported_countries = ['GB', 'US', 'CH', 'SE', 'SG', 'NO', 'JP', 'IS', 'HK', 'NL', 'CZ', 'CA', 'AU'] - self.supported_cardtypes = [:visa, :master, :american_express, :diners_club, :discover, :jcb, :maestro, :solo, :switch] + self.supported_cardtypes = [:visa, :master, :american_express, :diners_club, :discover, :jcb, :maestro] self.homepage_url = 'http://www.cardstream.com/' self.display_name = 'CardStream' CURRENCY_CODES = { - "AED" => "784", - "ALL" => "008", - "AMD" => "051", - "ANG" => "532", - "ARS" => "032", - "AUD" => "036", - "AWG" => "533", - "BAM" => "977", - "BBD" => "052", - "BGN" => "975", - "BMD" => "060", - "BOB" => "068", - "BRL" => "986", - "BSD" => "044", - "BWP" => "072", - "BZD" => "084", - "CAD" => "124", - "CHF" => "756", - "CLP" => "152", - "CNY" => "156", - "COP" => "170", - "CRC" => "188", - "CZK" => "203", - "DKK" => "208", - "DOP" => "214", - "EGP" => "818", - "EUR" => "978", - "GBP" => "826", - "GEL" => "981", - "GIP" => "292", - "GTQ" => "320", - "GYD" => "328", - "HKD" => "344", - "HNL" => "340", - "HRK" => "191", - "HUF" => "348", - "ISK" => "352", - "IDR" => "360", - "ILS" => "376", - "INR" => "356", - "JPY" => "392", - "JMD" => "388", - "KES" => "404", - "KRW" => "410", - "KYD" => "136", - "LBP" => "422", - "LKR" => "144", - "MAD" => "504", - "MVR" => "462", - "MWK" => "454", - "MXN" => "484", - "MYR" => "458", - "NAD" => "516", - "NGN" => "566", - "NIO" => "558", - "NOK" => "578", - "NPR" => "524", - "NZD" => "554", - "PAB" => "590", - "PEN" => "604", - "PGK" => "598", - "PHP" => "608", - "PKR" => "586", - "PLN" => "985", - "PYG" => "600", - "QAR" => "634", - "RON" => "946", - "RSD" => "941", - "RUB" => "643", - "RWF" => "646", - "SAR" => "682", - "SEK" => "752", - "SGD" => "702", - "SRD" => "968", - "THB" => "764", - "TND" => "788", - "TRY" => "949", - "TTD" => "780", - "TWD" => "901", - "TZS" => "834", - "UAH" => "980", - "UGX" => "800", - "USD" => "840", - "UYU" => "858", - "VND" => "704", - "WST" => "882", - "XAF" => "950", - "XCD" => "951", - "XOF" => "952", - "ZAR" => "710" + 'AED' => '784', + 'ALL' => '008', + 'AMD' => '051', + 'ANG' => '532', + 'ARS' => '032', + 'AUD' => '036', + 'AWG' => '533', + 'BAM' => '977', + 'BBD' => '052', + 'BGN' => '975', + 'BMD' => '060', + 'BOB' => '068', + 'BRL' => '986', + 'BSD' => '044', + 'BWP' => '072', + 'BZD' => '084', + 'CAD' => '124', + 'CHF' => '756', + 'CLP' => '152', + 'CNY' => '156', + 'COP' => '170', + 'CRC' => '188', + 'CZK' => '203', + 'DKK' => '208', + 'DOP' => '214', + 'EGP' => '818', + 'EUR' => '978', + 'GBP' => '826', + 'GEL' => '981', + 'GIP' => '292', + 'GTQ' => '320', + 'GYD' => '328', + 'HKD' => '344', + 'HNL' => '340', + 'HRK' => '191', + 'HUF' => '348', + 'ISK' => '352', + 'IDR' => '360', + 'ILS' => '376', + 'INR' => '356', + 'JPY' => '392', + 'JMD' => '388', + 'KES' => '404', + 'KRW' => '410', + 'KYD' => '136', + 'LBP' => '422', + 'LKR' => '144', + 'MAD' => '504', + 'MVR' => '462', + 'MWK' => '454', + 'MXN' => '484', + 'MYR' => '458', + 'NAD' => '516', + 'NGN' => '566', + 'NIO' => '558', + 'NOK' => '578', + 'NPR' => '524', + 'NZD' => '554', + 'PAB' => '590', + 'PEN' => '604', + 'PGK' => '598', + 'PHP' => '608', + 'PKR' => '586', + 'PLN' => '985', + 'PYG' => '600', + 'QAR' => '634', + 'RON' => '946', + 'RSD' => '941', + 'RUB' => '643', + 'RWF' => '646', + 'SAR' => '682', + 'SEK' => '752', + 'SGD' => '702', + 'SRD' => '968', + 'THB' => '764', + 'TND' => '788', + 'TRY' => '949', + 'TTD' => '780', + 'TWD' => '901', + 'TZS' => '834', + 'UAH' => '980', + 'UGX' => '800', + 'USD' => '840', + 'UYU' => '858', + 'VND' => '704', + 'WST' => '882', + 'XAF' => '950', + 'XCD' => '951', + 'XOF' => '952', + 'ZAR' => '710' } CVV_CODE = { @@ -118,11 +118,11 @@ class CardStreamGateway < Gateway # 4 - Postcode not matched. # 8 - Postcode partially matched. AVS_POSTAL_MATCH = { - "0" => nil, - "1" => nil, - "2" => "Y", - "4" => "N", - "8" => "N" + '0' => nil, + '1' => nil, + '2' => 'Y', + '4' => 'N', + '8' => 'N' } # 0 - No additional information available. @@ -131,17 +131,17 @@ class CardStreamGateway < Gateway # 4 - Address numeric not matched. # 8 - Address numeric partially matched. AVS_STREET_MATCH = { - "0" => nil, - "1" => nil, - "2" => "Y", - "4" => "N", - "8" => "N" + '0' => nil, + '1' => nil, + '2' => 'Y', + '4' => 'N', + '8' => 'N' } def initialize(options = {}) requires!(options, :login, :shared_secret) @threeds_required = false - if (options[:threeDSRequired]) + if options[:threeDSRequired] ActiveMerchant.deprecated(THREEDSECURE_REQUIRED_DEPRECATION_MESSAGE) @threeds_required = options[:threeDSRequired] end @@ -155,6 +155,7 @@ def authorize(money, credit_card_or_reference, options = {}) add_invoice(post, credit_card_or_reference, money, options) add_credit_card_or_reference(post, credit_card_or_reference) add_customer_data(post, options) + add_remote_address(post, options) commit('SALE', post) end @@ -165,6 +166,7 @@ def purchase(money, credit_card_or_reference, options = {}) add_invoice(post, credit_card_or_reference, money, options) add_credit_card_or_reference(post, credit_card_or_reference) add_customer_data(post, options) + add_remote_address(post, options) commit('SALE', post) end @@ -172,6 +174,7 @@ def capture(money, authorization, options = {}) post = {} add_pair(post, :xref, authorization) add_pair(post, :amount, amount(money), :required => true) + add_remote_address(post, options) commit('CAPTURE', post) end @@ -180,12 +183,23 @@ def refund(money, authorization, options = {}) post = {} add_pair(post, :xref, authorization) add_amount(post, money, options) - commit('REFUND', post) + add_remote_address(post, options) + response = commit('REFUND_SALE', post) + + return response if response.success? + return response unless options[:force_full_refund_if_unsettled] + + if response.params['responseCode'] == '65541' + void(authorization, options) + else + response + end end def void(authorization, options = {}) post = {} add_pair(post, :xref, authorization) + add_remote_address(post, options) commit('CANCEL', post) end @@ -220,6 +234,9 @@ def add_customer_data(post, options) add_pair(post, :customerAddress, "#{address[:address1]} #{address[:address2]}".strip) add_pair(post, :customerPostCode, address[:zip]) add_pair(post, :customerPhone, options[:phone]) + add_pair(post, :customerCountryCode, address[:country] || 'GB') + else + add_pair(post, :customerCountryCode, 'GB') end end @@ -255,30 +272,25 @@ def add_reference(post, reference) def add_credit_card(post, credit_card) add_pair(post, :customerName, credit_card.name, :required => true) add_pair(post, :cardNumber, credit_card.number, :required => true) - add_pair(post, :cardExpiryMonth, format(credit_card.month, :two_digits), :required => true) add_pair(post, :cardExpiryYear, format(credit_card.year, :two_digits), :required => true) - - if requires_start_date_or_issue_number?(credit_card) - add_pair(post, :cardStartMonth, format(credit_card.start_month, :two_digits)) - add_pair(post, :cardStartYear, format(credit_card.start_year, :two_digits)) - - add_pair(post, :cardIssueNumber, credit_card.issue_number) - end - add_pair(post, :cardCVV, credit_card.verification_value) end def add_threeds_required(post, options) - add_pair(post, :threeDSRequired, (options[:threeds_required] || @threeds_required) ? 'Y' : 'N') + add_pair(post, :threeDSRequired, options[:threeds_required] || @threeds_required ? 'Y' : 'N') + end + + def add_remote_address(post, options={}) + add_pair(post, :remoteAddress, options[:ip] || '1.1.1.1') end def normalize_line_endings(str) - str.gsub(/%0D%0A|%0A%0D|%0D/, "%0A") + str.gsub(/%0D%0A|%0A%0D|%0D/, '%0A') end def add_hmac(post) - result = post.sort.collect { |key, value| "#{key}=#{normalize_line_endings(CGI.escape(value.to_s))}" }.join("&") + result = post.sort.collect { |key, value| "#{key}=#{normalize_line_endings(CGI.escape(value.to_s))}" }.join('&') result = Digest::SHA512.hexdigest("#{result}#{@options[:shared_secret]}") add_pair(post, :signature, result) @@ -286,9 +298,9 @@ def add_hmac(post) def parse(body) result = {} - pairs = body.split("&") + pairs = body.split('&') pairs.each do |pair| - a = pair.split("=") + a = pair.split('=') # because some value pairs don't have a value result[a[0].to_sym] = a[1] == nil ? '' : CGI.unescape(a[1]) end @@ -306,13 +318,14 @@ def commit(action, parameters) response = parse(ssl_post(self.live_url, post_data(action, parameters))) - Response.new(response[:responseCode] == "0", - response[:responseCode] == "0" ? "APPROVED" : response[:responseMessage], - response, - :test => test?, - :authorization => response[:xref], - :cvv_result => CVV_CODE[response[:avscv2ResponseCode].to_s[0, 1]], - :avs_result => avs_from(response) + Response.new( + response[:responseCode] == '0', + response[:responseCode] == '0' ? 'APPROVED' : response[:responseMessage], + response, + :test => test?, + :authorization => response[:xref], + :cvv_result => CVV_CODE[response[:avscv2ResponseCode].to_s[0, 1]], + :avs_result => avs_from(response) ) end @@ -320,14 +333,14 @@ def avs_from(response) postal_match = AVS_POSTAL_MATCH[response[:avscv2ResponseCode].to_s[1, 1]] street_match = AVS_STREET_MATCH[response[:avscv2ResponseCode].to_s[2, 1]] - code = if postal_match == "Y" && street_match == "Y" - "M" - elsif postal_match == "Y" - "P" - elsif street_match == "Y" - "A" - else - "I" + code = if postal_match == 'Y' && street_match == 'Y' + 'M' + elsif postal_match == 'Y' + 'P' + elsif street_match == 'Y' + 'A' + else + 'I' end AVSResult.new({ @@ -337,13 +350,12 @@ def avs_from(response) }) end - def currency_code(currency) CURRENCY_CODES[currency] end def post_data(action, parameters = {}) - parameters.collect { |key, value| "#{key}=#{CGI.escape(value.to_s)}" }.join("&") + parameters.collect { |key, value| "#{key}=#{CGI.escape(value.to_s)}" }.join('&') end def add_pair(post, key, value, options = {}) diff --git a/lib/active_merchant/billing/gateways/cardknox.rb b/lib/active_merchant/billing/gateways/cardknox.rb index 664626ab8fa..938e6ade478 100644 --- a/lib/active_merchant/billing/gateways/cardknox.rb +++ b/lib/active_merchant/billing/gateways/cardknox.rb @@ -3,7 +3,7 @@ module Billing #:nodoc: class CardknoxGateway < Gateway self.live_url = 'https://x1.cardknox.com/gateway' - self.supported_countries = ['US','CA','GB'] + self.supported_countries = ['US', 'CA', 'GB'] self.default_currency = 'USD' self.supported_cardtypes = [:visa, :master, :american_express, :discover, :diners_club, :jcb] @@ -81,8 +81,8 @@ def void(authorization, options = {}) def verify(credit_card, options={}) MultiResponse.run(:use_first_response) do |r| - r.process { authorize(100, credit_card, options) } - r.process(:ignore_result) { void(r.authorization, options) } + r.process { authorize(100, credit_card, options) } + r.process(:ignore_result) { void(r.authorization, options) } end end @@ -112,7 +112,7 @@ def scrub(transcript) private def split_authorization(authorization) - authorization.split(";") + authorization.split(';') end def add_reference(post, reference) @@ -134,7 +134,7 @@ def source_type(source) def source_type_from(authorization) _, _, source_type = split_authorization(authorization) - (source_type || "credit_card").to_sym + (source_type || 'credit_card').to_sym end def add_source(post, source) @@ -255,7 +255,7 @@ def add_cardknox_token(post, authorization) def parse(body) fields = {} for line in body.split('&') - key, value = *line.scan( %r{^(\w+)\=(.*)$} ).flatten + key, value = *line.scan(%r{^(\w+)\=(.*)$}).flatten fields[key] = CGI.unescape(value.to_s) end @@ -276,14 +276,13 @@ def parse(body) amount: fields['xAuthAmount'], masked_card_num: fields['xMaskedCardNumber'], masked_account_number: fields['MaskedAccountNumber'] - }.delete_if{|k, v| v.nil?} + }.delete_if { |k, v| v.nil? } end - def commit(action, source_type, parameters) response = parse(ssl_post(live_url, post_data(COMMANDS[source_type][action], parameters))) - Response.new( + Response.new( (response[:status] == 'Approved'), message_from(response), response, @@ -294,10 +293,10 @@ def commit(action, source_type, parameters) end def message_from(response) - if response[:status] == "Approved" - "Success" + if response[:status] == 'Approved' + 'Success' elsif response[:error].blank? - "Unspecified error" + 'Unspecified error' else response[:error] end @@ -310,9 +309,9 @@ def authorization_from(response, source_type) def post_data(command, parameters = {}) initial_parameters = { Key: @options[:api_key], - Version: "4.5.4", + Version: '4.5.4', SoftwareName: 'Active Merchant', - SoftwareVersion: "#{ActiveMerchant::VERSION}", + SoftwareVersion: ActiveMerchant::VERSION.to_s, Command: command, } @@ -321,7 +320,7 @@ def post_data(command, parameters = {}) initial_parameters[:Hash] = "s/#{seed}/#{hash}/n" unless @options[:pin].blank? parameters = initial_parameters.merge(parameters) - parameters.reject{|k, v| v.blank?}.collect{ |key, value| "x#{key}=#{CGI.escape(value.to_s)}" }.join("&") + parameters.reject { |k, v| v.blank? }.collect { |key, value| "x#{key}=#{CGI.escape(value.to_s)}" }.join('&') end end end diff --git a/lib/active_merchant/billing/gateways/cardprocess.rb b/lib/active_merchant/billing/gateways/cardprocess.rb new file mode 100644 index 00000000000..c91121c0641 --- /dev/null +++ b/lib/active_merchant/billing/gateways/cardprocess.rb @@ -0,0 +1,254 @@ +module ActiveMerchant #:nodoc: + module Billing #:nodoc: + class CardprocessGateway < Gateway + self.test_url = 'https://test.vr-pay-ecommerce.de/v1/payments' + self.live_url = 'https://vr-pay-ecommerce.de/v1/payments' + + self.supported_countries = %w[ BE BG CZ DK DE EE IE ES FR HR IT CY LV LT LU + MT HU NL AT PL PT RO SI SK FI SE GB IS LI NO + CH ME MK AL RS TR BA ] + self.default_currency = 'EUR' + self.supported_cardtypes = [:visa, :master, :american_express, :diners_club, :jcb] + + self.homepage_url = 'https://vr-pay-ecommerce.docs.oppwa.com/' + self.display_name = 'CardProcess VR-Pay' + self.money_format = :dollars + + STANDARD_ERROR_CODE_MAPPING = {} + + # Creates a new CardProcess Gateway + # + # The gateway requires a valid login, password, and entity ID + # to be passed in the +options+ hash. + # + # === Options + # + # * :user_id -- The CardProcess user ID + # * :password -- The CardProcess password + # * :entity_id -- The CardProcess channel or entity ID for any transactions + def initialize(options={}) + requires!(options, :user_id, :password, :entity_id) + super + # This variable exists purely to allow remote tests to force error codes; + # the lack of a setter despite its usage is intentional. + @test_options = {} + end + + def purchase(money, payment, options = {}) + post = {} + add_invoice(post, money, options) + add_payment(post, payment) + add_address(post, payment, options) + add_customer_data(post, options) + + commit('DB', post) + end + + def authorize(money, payment, options = {}) + post = {} + add_invoice(post, money, options) + add_payment(post, payment) + add_address(post, payment, options) + add_customer_data(post, options) + + commit('PA', post) + end + + def capture(money, authorization, options = {}) + post = { + id: authorization + } + add_invoice(post, money, options) + commit('CP', post) + end + + def refund(money, authorization, options = {}) + post = { + id: authorization + } + add_invoice(post, money, options) + commit('RF', post) + end + + def credit(money, payment, options = {}) + post = {} + add_invoice(post, money, options) + add_payment(post, payment) + add_address(post, payment, options) + add_customer_data(post, options) + + commit('CD', post) + end + + def void(authorization, _options = {}) + post = { + id: authorization + } + commit('RV', post) + end + + def verify(credit_card, options = {}) + MultiResponse.run do |r| + r.process { authorize(100, credit_card, options) } + r.process { void(r.authorization, options) } + end + end + + def supports_scrubbing? + true + end + + def scrub(transcript) + transcript. + gsub(%r{(authentication\.[^=]+=)[^&]+}, '\1[FILTERED]'). + gsub(%r{(card\.number=)\d+}, '\1[FILTERED]'). + gsub(%r{(cvv=)\d{3,4}}, '\1[FILTERED]\2') + end + + private + + def add_customer_data(post, options) + post['customer.ip'] = options[:ip] if options[:ip] + end + + def add_address(post, _card, options) + if (address = options[:billing_address] || options[:address]) + post[:billing] = hashify_address(address) + end + + if (shipping = options[:shipping_address]) + post[:shipping] = hashify_address(shipping) + end + end + + def add_invoice(post, money, options) + return if money.nil? + post[:amount] = amount(money) + post[:currency] = (options[:currency] || currency(money)) + post[:merchantInvoiceId] = options[:merchant_invoice_id] if options[:merchant_invoice_id] + post[:merchantTransactionId] = options[:merchant_transaction_id] if options[:merchant_transaction_id] + post[:transactionCategory] = options[:transaction_category] if options[:transaction_category] + end + + def add_payment(post, payment) + return if payment.is_a?(String) + post[:paymentBrand] = payment.brand.upcase if payment.brand + post[:card] ||= {} + post[:card][:number] = payment.number + post[:card][:holder] = payment.name + post[:card][:expiryMonth] = sprintf('%02d', payment.month) + post[:card][:expiryYear] = sprintf('%02d', payment.year) + post[:card][:cvv] = payment.verification_value + end + + def parse(body) + JSON.parse(body) + end + + def commit(action, parameters) + url = (test? ? test_url : live_url) + if (id = parameters.delete(:id)) + url += "/#{id}" + end + + begin + raw_response = ssl_post(url, post_data(action, parameters.merge(@test_options))) + rescue ResponseError => e + raw_response = e.response.body + end + response = parse(raw_response) + + Response.new( + success_from(response), + message_from(response), + response, + authorization: authorization_from(response), + avs_result: AVSResult.new(code: response['result']['avsResponse']), + cvv_result: CVVResult.new(response['result']['cvvResponse']), + test: test?, + error_code: error_code_from(response) + ) + end + + def success_from(response) + !(response['result']['code'] =~ /^(000\.000\.|000\.100\.1|000\.[36])/).nil? + end + + def message_from(response) + response['result']['description'] + end + + def authorization_from(response) + response['id'] + end + + def post_data(action, parameters = {}) + post = parameters.clone + post[:authentication] ||= {} + post[:authentication][:userId] = @options[:user_id] + post[:authentication][:password] = @options[:password] + post[:authentication][:entityId] = @options[:entity_id] + post[:paymentType] = action + dot_flatten_hash(post).map { |key, value| "#{key}=#{CGI.escape(value.to_s)}" }.join('&') + end + + def error_code_from(response) + unless success_from(response) + case response['result']['code'] + when '100.100.101' + STANDARD_ERROR_CODE[:incorrect_number] + when '100.100.303' + STANDARD_ERROR_CODE[:expired_card] + when /100\.100\.(201|301|305)/ + STANDARD_ERROR_CODE[:invalid_expiry_date] + when /100.100.60[01]/ + STANDARD_ERROR_CODE[:invalid_cvc] + when '800.100.151' + STANDARD_ERROR_CODE[:invalid_number] + when '800.100.153' + STANDARD_ERROR_CODE[:incorrect_cvc] + when /800.800.(102|302)/ + STANDARD_ERROR_CODE[:incorrect_address] + when '800.800.202' + STANDARD_ERROR_CODE[:invalid_zip] + when '800.100.166' + STANDARD_ERROR_CODE[:incorrect_pin] + when '800.100.171' + STANDARD_ERROR_CODE[:pickup_card] + when /^(200|700)\./ + STANDARD_ERROR_CODE[:config_error] + when /^(800\.[17]00|800\.800\.[123])/ + STANDARD_ERROR_CODE[:card_declined] + when /^(900\.[1234]00)/ + STANDARD_ERROR_CODE[:processing_error] + else + STANDARD_ERROR_CODE[:processing_error] + end + end + end + + def hashify_address(address) + hash = {} + hash[:street1] = address[:address1] if address[:address1] + hash[:street2] = address[:address2] if address[:address2] + hash[:city] = address[:city] if address[:city] + hash[:state] = address[:state] if address[:state] + hash[:postcode] = address[:zip] if address[:zip] + hash[:country] = address[:country] if address[:country] + hash + end + + def dot_flatten_hash(hash, prefix = '') + h = {} + hash.each_pair do |k, v| + if v.is_a?(Hash) + h.merge!(dot_flatten_hash(v, prefix + k.to_s + '.')) + else + h[prefix + k.to_s] = v + end + end + h + end + end + end +end diff --git a/lib/active_merchant/billing/gateways/cashnet.rb b/lib/active_merchant/billing/gateways/cashnet.rb index df790f198ba..48a7d1308c5 100644 --- a/lib/active_merchant/billing/gateways/cashnet.rb +++ b/lib/active_merchant/billing/gateways/cashnet.rb @@ -3,12 +3,13 @@ module Billing #:nodoc: class CashnetGateway < Gateway include Empty - self.live_url = "https://commerce.cashnet.com/" + self.live_url = 'https://commerce.cashnet.com/' + self.test_url = 'https://train.cashnet.com/' - self.supported_countries = ["US"] + self.supported_countries = ['US'] self.supported_cardtypes = [:visa, :master, :american_express, :discover, :diners_club, :jcb] - self.homepage_url = "http://www.higherone.com/" - self.display_name = "Cashnet" + self.homepage_url = 'http://www.higherone.com/' + self.display_name = 'Cashnet' self.money_format = :dollars self.max_retries = 0 @@ -33,7 +34,7 @@ def initialize(options = {}) :password, :merchant_gateway_name ) - options[:default_item_code] ||= "FEE" + options[:default_item_code] ||= 'FEE' super end @@ -54,11 +55,22 @@ def refund(money, identification, options = {}) commit('REFUND', money, post) end + def supports_scrubbing? + true + end + + def scrub(transcript) + transcript. + gsub(%r{(password=)[^&]+}, '\1[FILTERED]'). + gsub(%r{(cardno=)[^&]+}, '\1[FILTERED]'). + gsub(%r{(cid=)[^&]+}, '\1[FILTERED]') + end + private def commit(action, money, fields) fields[:amount] = amount(money) - url = live_url + CGI.escape(@options[:merchant_gateway_name]) + url = (test? ? test_url : live_url) + CGI.escape(@options[:merchant_gateway_name]) raw_response = ssl_post(url, post_data(action, fields)) parsed_response = parse(raw_response) @@ -80,9 +92,9 @@ def post_data(action, parameters = {}) post[:merchant] = @options[:merchant] post[:operator] = @options[:operator] post[:password] = @options[:password] - post[:station] = (@options[:station] || "WEB") + post[:station] = (@options[:station] || 'WEB') post[:custcode] = (@options[:custcode] || "ActiveMerchant/#{ActiveMerchant::VERSION}") - post.merge(parameters).collect { |key, value| "#{key}=#{CGI.escape(value.to_s)}" }.join("&") + post.merge(parameters).collect { |key, value| "#{key}=#{CGI.escape(value.to_s)}" }.join('&') end def add_creditcard(post, creditcard) @@ -124,20 +136,20 @@ def parse(body) match = body.match(/(.*)<\/cngateway>/) return nil unless match - Hash[CGI::parse(match[1]).map{|k,v| [k.to_sym,v.first]}] + Hash[CGI::parse(match[1]).map { |k, v| [k.to_sym, v.first] }] end def handle_response(response) - if (200...300).include?(response.code.to_i) + if (200...300).cover?(response.code.to_i) return response.body - elsif 302 == response.code.to_i + elsif response.code.to_i == 302 return ssl_get(URI.parse(response['location'])) end raise ResponseError.new(response) end def unparsable_response(raw_response) - message = "Unparsable response received from Cashnet. Please contact Cashnet if you continue to receive this message." + message = 'Unparsable response received from Cashnet. Please contact Cashnet if you continue to receive this message.' message += " (The raw response returned by the API was #{raw_response.inspect})" return Response.new(false, message) end diff --git a/lib/active_merchant/billing/gateways/cc5.rb b/lib/active_merchant/billing/gateways/cc5.rb index 6efc099db15..3d25ec7d3f1 100644 --- a/lib/active_merchant/billing/gateways/cc5.rb +++ b/lib/active_merchant/billing/gateways/cc5.rb @@ -70,7 +70,6 @@ def build_sale_request(type, money, creditcard, options = {}) add_address(xml, address) end end - end xml.target! @@ -148,7 +147,7 @@ def currency_code(currency) end def commit(request) - raw_response = ssl_post((test? ? self.test_url : self.live_url), "DATA=" + request) + raw_response = ssl_post((test? ? self.test_url : self.live_url), 'DATA=' + request) response = parse(raw_response) @@ -175,25 +174,23 @@ def parse(body) def parse_element(response, node) if node.has_elements? - node.elements.each{|element| parse_element(response, element) } + node.elements.each { |element| parse_element(response, element) } else response[node.name.underscore.to_sym] = node.text end end def success?(response) - (response[:response] == "Approved") + (response[:response] == 'Approved') end def normalize(text) return unless text if ActiveSupport::Inflector.method(:transliterate).arity == -2 - ActiveSupport::Inflector.transliterate(text,'') - elsif RUBY_VERSION >= '1.9' - text.gsub(/[^\x00-\x7F]+/, '') + ActiveSupport::Inflector.transliterate(text, '') else - ActiveSupport::Inflector.transliterate(text).to_s + text.gsub(/[^\x00-\x7F]+/, '') end end end diff --git a/lib/active_merchant/billing/gateways/cecabank.rb b/lib/active_merchant/billing/gateways/cecabank.rb index 3eb62be1526..0b7cf8bc86d 100644 --- a/lib/active_merchant/billing/gateways/cecabank.rb +++ b/lib/active_merchant/billing/gateways/cecabank.rb @@ -19,7 +19,7 @@ class CecabankGateway < Gateway CECA_UI_LESS_LANGUAGE = 'XML' CECA_UI_LESS_LANGUAGE_REFUND = '1' CECA_UI_LESS_REFUND_PAGE = 'anulacion_xml' - CECA_ACTION_REFUND = 'tpvanularparcialmente' #use partial refund's URL to avoid time frame limitations and decision logic on client side + CECA_ACTION_REFUND = 'tpvanularparcialmente' # use partial refund's URL to avoid time frame limitations and decision logic on client side CECA_ACTION_PURCHASE = 'tpv' CECA_CURRENCIES_DICTIONARY = {'EUR' => 978, 'USD' => 840, 'GBP' => 826} @@ -123,7 +123,7 @@ def parse(body) root = REXML::Document.new(body).root - response[:success] = (root.attributes['valor'] == "OK") + response[:success] = (root.attributes['valor'] == 'OK') response[:date] = root.attributes['fecha'] response[:operation_number] = root.attributes['numeroOperacion'] response[:message] = root.attributes['valor'] @@ -142,7 +142,7 @@ def parse(body) response[:error_code] = root.elements['ERROR/codigo'].text response[:error_message] = root.elements['ERROR/descripcion'].text else - if("000" == root.elements['OPERACION'].attributes['numeroOperacion']) + if root.elements['OPERACION'].attributes['numeroOperacion'] == '000' if(root.elements['OPERACION/numeroAutorizacion']) response[:authorization] = root.elements['OPERACION/numeroAutorizacion'].text end @@ -152,10 +152,9 @@ def parse(body) end return response - rescue REXML::ParseException => e response[:success] = false - response[:message] = "Unable to parse the response." + response[:message] = 'Unable to parse the response.' response[:error_message] = e.message response end @@ -195,15 +194,15 @@ def post_data(params) else "#{key}=#{CGI.escape(value.to_s)}" end - end.compact.join("&") + end.compact.join('&') end def build_authorization(response) - [response[:reference], response[:authorization]].join("|") + [response[:reference], response[:authorization]].join('|') end def split_authorization(authorization) - authorization.split("|") + authorization.split('|') end def generate_signature(action, parameters) diff --git a/lib/active_merchant/billing/gateways/cenpos.rb b/lib/active_merchant/billing/gateways/cenpos.rb index cc208e39661..9ba37a7c00b 100644 --- a/lib/active_merchant/billing/gateways/cenpos.rb +++ b/lib/active_merchant/billing/gateways/cenpos.rb @@ -1,15 +1,15 @@ -require "nokogiri" +require 'nokogiri' module ActiveMerchant #:nodoc: module Billing #:nodoc: class CenposGateway < Gateway - self.display_name = "CenPOS" - self.homepage_url = "https://www.cenpos.com/" + self.display_name = 'CenPOS' + self.homepage_url = 'https://www.cenpos.com/' - self.live_url = "https://ww3.cenpos.net/6/transact.asmx" + self.live_url = 'https://ww3.cenpos.net/6/transact.asmx' - self.supported_countries = %w(AD AI AG AR AU AT BS BB BE BZ BM BR BN BG CA HR CY CZ DK DM EE FI FR DE GR GD GY HK HU IS IN IL IT JP LV LI LT LU MY MT MX MC MS NL PA PL PT KN LC MF VC SM SG SK SI ZA ES SR SE CH TR GB US UY) - self.default_currency = "USD" + self.supported_countries = %w(AD AI AG AR AU AT BS BB BE BZ BM BR BN BG CA HR CY CZ DK DM EE FI FR DE GR GD GY HK HU IS IL IT JP LV LI LT LU MY MT MX MC MS NL PA PL PT KN LC MF VC SM SG SK SI ZA ES SR SE CH TR GB US UY) + self.default_currency = 'USD' self.money_format = :dollars self.supported_cardtypes = [:visa, :master, :american_express, :discover] @@ -24,7 +24,7 @@ def purchase(amount, payment_method, options={}) add_payment_method(post, payment_method) add_customer_data(post, options) - commit("Sale", post) + commit('Sale', post) end def authorize(amount, payment_method, options={}) @@ -33,7 +33,7 @@ def authorize(amount, payment_method, options={}) add_payment_method(post, payment_method) add_customer_data(post, options) - commit("Auth", post) + commit('Auth', post) end def capture(amount, authorization, options={}) @@ -42,7 +42,7 @@ def capture(amount, authorization, options={}) add_reference(post, authorization) add_customer_data(post, options) - commit("SpecialForce", post) + commit('SpecialForce', post) end def void(authorization, options={}) @@ -53,7 +53,7 @@ def void(authorization, options={}) add_tax(post, options) add_order_id(post, options) - commit("Void", post) + commit('Void', post) end def refund(amount, authorization, options={}) @@ -62,7 +62,7 @@ def refund(amount, authorization, options={}) add_reference(post, authorization) add_customer_data(post, options) - commit("SpecialReturn", post) + commit('SpecialReturn', post) end def credit(amount, payment_method, options={}) @@ -70,7 +70,7 @@ def credit(amount, payment_method, options={}) add_invoice(post, amount, options) add_payment_method(post, payment_method) - commit("Credit", post) + commit('Credit', post) end def verify(credit_card, options={}) @@ -156,9 +156,9 @@ def commit(action, post) xml = ssl_post(self.live_url, data, headers) raw = parse(xml) rescue ActiveMerchant::ResponseError => e - if(e.response.code == "500" && e.response.body.start_with?(" "gzip,deflate", - "Content-Type" => "text/xml;charset=UTF-8", - "SOAPAction" => "http://tempuri.org/Transactional/ProcessCreditCard" + 'Accept-Encoding' => 'identity', + 'Content-Type' => 'text/xml;charset=UTF-8', + 'SOAPAction' => 'http://tempuri.org/Transactional/ProcessCreditCard' } end def build_request(post) xml = Builder::XmlMarkup.new :indent => 8 - xml.tag!("acr:MerchantId", post.delete(:MerchantId)) - xml.tag!("acr:Password", post.delete(:Password)) - xml.tag!("acr:UserId", post.delete(:UserId)) + xml.tag!('acr:MerchantId', post.delete(:MerchantId)) + xml.tag!('acr:Password', post.delete(:Password)) + xml.tag!('acr:UserId', post.delete(:UserId)) post.sort.each do |field, value| xml.tag!("acr1:#{field}", value) end @@ -217,9 +217,9 @@ def parse(xml) doc = Nokogiri::XML(xml) doc.remove_namespaces! - body = doc.xpath("//ProcessCreditCardResult") + body = doc.xpath('//ProcessCreditCardResult') body.children.each do |node| - if (node.elements.size == 0) + if node.elements.size == 0 response[node.name.underscore.to_sym] = node.text else node.elements.each do |childnode| @@ -233,32 +233,32 @@ def parse(xml) end def success_from(response) - response == "0" + response == '0' end def message_from(succeeded, response) if succeeded - "Succeeded" + 'Succeeded' else - response[:message] || "Unable to read error message" + response[:message] || 'Unable to read error message' end end STANDARD_ERROR_CODE_MAPPING = { - "211" => STANDARD_ERROR_CODE[:invalid_number], - "252" => STANDARD_ERROR_CODE[:invalid_expiry_date], - "257" => STANDARD_ERROR_CODE[:invalid_cvc], - "333" => STANDARD_ERROR_CODE[:expired_card], - "1" => STANDARD_ERROR_CODE[:card_declined], - "99" => STANDARD_ERROR_CODE[:processing_error], + '211' => STANDARD_ERROR_CODE[:invalid_number], + '252' => STANDARD_ERROR_CODE[:invalid_expiry_date], + '257' => STANDARD_ERROR_CODE[:invalid_cvc], + '333' => STANDARD_ERROR_CODE[:expired_card], + '1' => STANDARD_ERROR_CODE[:card_declined], + '99' => STANDARD_ERROR_CODE[:processing_error], } def authorization_from(request, response) - [ response[:reference_number], request[:CardLastFourDigits], request[:Amount] ].join("|") + [ response[:reference_number], request[:CardLastFourDigits], request[:Amount] ].join('|') end def split_authorization(authorization) - reference_number, last_four_digits, original_amount = authorization.split("|") + reference_number, last_four_digits, original_amount = authorization.split('|') [reference_number, last_four_digits, original_amount] end @@ -275,14 +275,14 @@ def avs_result_from_xml(xml) end def cvv_result_code(xml) - cvv = validation_result_element(xml, "CVV") + cvv = validation_result_element(xml, 'CVV') return nil unless cvv validation_result_matches?(*validation_result_element_text(cvv.parent)) ? 'M' : 'N' end def avs_result_code(xml) - billing_address_elem = validation_result_element(xml, "Billing Address") - zip_code_elem = validation_result_element(xml, "Zip Code") + billing_address_elem = validation_result_element(xml, 'Billing Address') + zip_code_elem = validation_result_element(xml, 'Zip Code') return nil unless billing_address_elem && zip_code_elem @@ -312,10 +312,10 @@ def validation_result_element(xml, name) def validation_result_element_text(element) result_text = element.elements.detect { |elem| - elem.name == "Result" - }.children.detect { |elem| elem.text }.text + elem.name == 'Result' + }.children.detect(&:text).text - result_text.split(";").collect(&:strip) + result_text.split(';').collect(&:strip) end def validation_result_matches?(present, match) diff --git a/lib/active_merchant/billing/gateways/checkout.rb b/lib/active_merchant/billing/gateways/checkout.rb index d52d4656fd4..bd6149b246d 100644 --- a/lib/active_merchant/billing/gateways/checkout.rb +++ b/lib/active_merchant/billing/gateways/checkout.rb @@ -5,7 +5,7 @@ module ActiveMerchant #:nodoc: module Billing #:nodoc: class CheckoutGateway < Gateway self.default_currency = 'USD' - self.money_format = :decimals + self.money_format = :cents self.supported_countries = ['AD', 'AT', 'BE', 'BG', 'CH', 'CY', 'CZ', 'DE', 'DK', 'EE', 'ES', 'FO', 'FI', 'FR', 'GB', 'GI', 'GL', 'GR', 'HR', 'HU', 'IE', 'IS', 'IL', 'IT', 'LI', 'LT', 'LU', 'LV', 'MC', 'MT', 'NL', 'NO', 'PL', 'PT', 'RO', 'SE', 'SI', 'SM', 'SK', 'SJ', 'TR', 'VA'] self.supported_cardtypes = [:visa, :master, :american_express, :diners_club] @@ -125,13 +125,13 @@ def add_billing_info(xml, options) def add_shipping_info(xml, options) if options[:shipping_address] - xml.ship_address_ options[:shipping_address][:address1] - xml.ship_address2_ options[:shipping_address][:address2] - xml.ship_city_ options[:shipping_address][:city] - xml.ship_state_ options[:shipping_address][:state] - xml.ship_postal_ options[:shipping_address][:zip] - xml.ship_country_ options[:shipping_address][:country] - xml.ship_phone_ options[:shipping_address][:phone] + xml.ship_address_ options[:shipping_address][:address1] + xml.ship_address2_ options[:shipping_address][:address2] + xml.ship_city_ options[:shipping_address][:city] + xml.ship_state_ options[:shipping_address][:state] + xml.ship_postal_ options[:shipping_address][:zip] + xml.ship_country_ options[:shipping_address][:country] + xml.ship_phone_ options[:shipping_address][:phone] end end @@ -144,7 +144,7 @@ def add_user_defined_fields(xml, options) end def add_other_fields(xml, options) - xml.bill_email_ options[:email] + xml.bill_email_ options[:email] xml.bill_customerip_ options[:ip] xml.merchantcustomerid_ options[:customer] xml.descriptor_name options[:descriptor_name] @@ -164,8 +164,8 @@ def add_track_id(xml, trackid) def commit(action, amount=nil, options={}, &builder) response = parse_xml(ssl_post(live_url, build_xml(action, &builder))) Response.new( - (response[:responsecode] == "0"), - (response[:result] || response[:error_text] || "Unknown Response"), + (response[:responsecode] == '0'), + (response[:result] || response[:error_text] || 'Unknown Response'), response, authorization: authorization_from(response, action, amount, options), test: test? @@ -184,10 +184,10 @@ def build_xml(action) def parse_xml(xml) response = {} - Nokogiri::XML(CGI.unescapeHTML(xml)).xpath("//response").children.each do |node| + Nokogiri::XML(CGI.unescapeHTML(xml)).xpath('//response').children.each do |node| if node.text? next - elsif (node.elements.size == 0) + elsif node.elements.size == 0 response[node.name.downcase.to_sym] = node.text else node.elements.each do |childnode| @@ -202,11 +202,11 @@ def parse_xml(xml) def authorization_from(response, action, amount, options) currency = options[:currency] || currency(amount) - [response[:tranid], response[:trackid], action, amount, currency].join("|") + [response[:tranid], response[:trackid], action, amount, currency].join('|') end def split_authorization(authorization) - transid, trackid, action, amount, currency = authorization.split("|") + transid, trackid, action, amount, currency = authorization.split('|') [transid, trackid, action, amount, currency] end end diff --git a/lib/active_merchant/billing/gateways/checkout_v2.rb b/lib/active_merchant/billing/gateways/checkout_v2.rb index 571d96a49ee..6289c2a0811 100644 --- a/lib/active_merchant/billing/gateways/checkout_v2.rb +++ b/lib/active_merchant/billing/gateways/checkout_v2.rb @@ -1,13 +1,13 @@ module ActiveMerchant #:nodoc: module Billing #:nodoc: class CheckoutV2Gateway < Gateway - self.display_name = "Checkout.com V2 Gateway" - self.homepage_url = "https://www.checkout.com/" - self.live_url = "https://api2.checkout.com/v2" - self.test_url = "http://sandbox.checkout.com/api2/v2" + self.display_name = 'Checkout.com V2 Gateway' + self.homepage_url = 'https://www.checkout.com/' + self.live_url = 'https://api2.checkout.com/v2' + self.test_url = 'https://sandbox.checkout.com/api2/v2' - self.supported_countries = ['AD', 'AT', 'BE', 'BG', 'CH', 'CY', 'CZ', 'DE', 'DK', 'EE', 'ES', 'FO', 'FI', 'FR', 'GB', 'GI', 'GL', 'GR', 'HR', 'HU', 'IE', 'IS', 'IL', 'IT', 'LI', 'LT', 'LU', 'LV', 'MC', 'MT', 'NL', 'NO', 'PL', 'PT', 'RO', 'SE', 'SI', 'SM', 'SK', 'SJ', 'TR', 'VA'] - self.default_currency = "USD" + self.supported_countries = ['AD', 'AE', 'AT', 'BE', 'BG', 'CH', 'CY', 'CZ', 'DE', 'DK', 'EE', 'ES', 'FO', 'FI', 'FR', 'GB', 'GI', 'GL', 'GR', 'HR', 'HU', 'IE', 'IS', 'IL', 'IT', 'LI', 'LT', 'LU', 'LV', 'MC', 'MT', 'NL', 'NO', 'PL', 'PT', 'RO', 'SE', 'SI', 'SM', 'SK', 'SJ', 'TR', 'VA'] + self.default_currency = 'USD' self.money_format = :cents self.supported_cardtypes = [:visa, :master, :american_express, :diners_club] @@ -17,18 +17,24 @@ def initialize(options={}) end def purchase(amount, payment_method, options={}) - MultiResponse.run do |r| + multi = MultiResponse.run do |r| r.process { authorize(amount, payment_method, options) } r.process { capture(amount, r.authorization, options) } end + + merged_params = multi.responses.map(&:params).reduce({}, :merge) + succeeded = success_from(merged_params) + + response(:purchase, succeeded, merged_params) end def authorize(amount, payment_method, options={}) post = {} - post[:autoCapture] = "n" + post[:autoCapture] = 'n' add_invoice(post, amount, options) add_payment_method(post, payment_method) add_customer_data(post, options) + add_transaction_data(post, options) commit(:authorize, post) end @@ -75,7 +81,7 @@ def scrub(transcript) private def add_invoice(post, money, options) - post[:value] = amount(money) + post[:value] = localized_amount(money, options[:currency]) post[:trackId] = options[:order_id] post[:currency] = options[:currency] || currency(money) post[:descriptor] = {} @@ -93,12 +99,13 @@ def add_payment_method(post, payment_method) end def add_customer_data(post, options) - post[:email] = options[:email] || "unspecified@example.com" + post[:email] = options[:email] || 'unspecified@example.com' + post[:customerIp] = options[:ip] if options[:ip] address = options[:billing_address] if(address && post[:card]) post[:card][:billingDetails] = {} - post[:card][:billingDetails][:address1] = address[:address1] - post[:card][:billingDetails][:address2] = address[:address2] + post[:card][:billingDetails][:addressLine1] = address[:address1] + post[:card][:billingDetails][:addressLine2] = address[:address2] post[:card][:billingDetails][:city] = address[:city] post[:card][:billingDetails][:state] = address[:state] post[:card][:billingDetails][:country] = address[:country] @@ -107,6 +114,12 @@ def add_customer_data(post, options) end end + def add_transaction_data(post, options={}) + post[:cardOnFile] = true if options[:card_on_file] == true + post[:transactionIndicator] = options[:transaction_indicator] || 1 + post[:previousChargeId] = options[:previous_charge_id] if options[:previous_charge_id] + end + def commit(action, post, authorization = nil) begin raw_response = ssl_post(url(post, action, authorization), post.to_json, headers) @@ -117,6 +130,15 @@ def commit(action, post, authorization = nil) end succeeded = success_from(response) + + response(action, succeeded, response) + end + + def response(action, succeeded, response) + successful_response = succeeded && action == :purchase || action == :authorize + avs_result = successful_response ? avs_result(response) : nil + cvv_result = successful_response ? cvv_result(response) : nil + Response.new( succeeded, message_from(succeeded, response), @@ -124,14 +146,15 @@ def commit(action, post, authorization = nil) authorization: authorization_from(response), error_code: error_code_from(succeeded, response), test: test?, - avs_result: avs_result(action, response), - cvv_result: cvv_result(action, response)) + avs_result: avs_result, + cvv_result: cvv_result + ) end def headers { - "Authorization" => @options[:secret_key], - "Content-Type" => "application/json;charset=UTF-8" + 'Authorization' => @options[:secret_key], + 'Content-Type' => 'application/json;charset=UTF-8' } end @@ -147,56 +170,63 @@ def base_url test? ? test_url : live_url end - def avs_result(action, response) - action == :purchase ? AVSResult.new(code: response["card"]["avsCheck"]) : nil + def avs_result(response) + response['card'] && response['card']['avsCheck'] ? AVSResult.new(code: response['card']['avsCheck']) : nil end - def cvv_result(action, response) - action == :purchase ? CVVResult.new(response["card"]["cvvCheck"]) : nil + def cvv_result(response) + response['card'] && response['card']['cvvCheck'] ? CVVResult.new(response['card']['cvvCheck']) : nil end def parse(body) JSON.parse(body) - rescue JSON::ParserError - { - "message" => "Invalid JSON response received from CheckoutV2Gateway. Please contact CheckoutV2Gateway if you continue to receive this message.", - "raw_response" => scrub(body) - } + rescue JSON::ParserError + { + 'message' => 'Invalid JSON response received from CheckoutV2Gateway. Please contact CheckoutV2Gateway if you continue to receive this message.', + 'raw_response' => scrub(body) + } end def success_from(response) - response["responseCode"] == ("10000" || "10100") + (response['responseCode'] == '10000' && !response['responseMessage'].start_with?('40')) || response['responseCode'] == '10100' end def message_from(succeeded, response) if succeeded - "Succeeded" - elsif response["errors"] - response["message"] + ": " + response["errors"].first + 'Succeeded' + elsif response['errors'] + response['message'] + ': ' + response['errors'].first else - response["responseMessage"] || response["message"] || "Unable to read error message" + response['responseMessage'] || response['message'] || 'Unable to read error message' end end STANDARD_ERROR_CODE_MAPPING = { - "20014" => STANDARD_ERROR_CODE[:invalid_number], - "20100" => STANDARD_ERROR_CODE[:invalid_expiry_date], - "20054" => STANDARD_ERROR_CODE[:expired_card], - "40104" => STANDARD_ERROR_CODE[:incorrect_cvc], - "40108" => STANDARD_ERROR_CODE[:incorrect_zip], - "40111" => STANDARD_ERROR_CODE[:incorrect_address], - "20005" => STANDARD_ERROR_CODE[:card_declined], - "20088" => STANDARD_ERROR_CODE[:processing_error], - "20001" => STANDARD_ERROR_CODE[:call_issuer], - "30004" => STANDARD_ERROR_CODE[:pickup_card] + '20014' => STANDARD_ERROR_CODE[:invalid_number], + '20100' => STANDARD_ERROR_CODE[:invalid_expiry_date], + '20054' => STANDARD_ERROR_CODE[:expired_card], + '40104' => STANDARD_ERROR_CODE[:incorrect_cvc], + '40108' => STANDARD_ERROR_CODE[:incorrect_zip], + '40111' => STANDARD_ERROR_CODE[:incorrect_address], + '20005' => STANDARD_ERROR_CODE[:card_declined], + '20088' => STANDARD_ERROR_CODE[:processing_error], + '20001' => STANDARD_ERROR_CODE[:call_issuer], + '30004' => STANDARD_ERROR_CODE[:pickup_card] } def authorization_from(raw) - raw["id"] + raw['id'] end def error_code_from(succeeded, response) - succeeded ? nil : STANDARD_ERROR_CODE_MAPPING[response["responseCode"]] + return if succeeded + if response['errorCode'] && response['errorMessageCodes'] + "#{response["errorCode"]}: #{response["errorMessageCodes"].join(", ")}" + elsif response['errorCode'] + response['errorCode'] + else + STANDARD_ERROR_CODE_MAPPING[response['responseCode']] + end end end end diff --git a/lib/active_merchant/billing/gateways/citrus_pay.rb b/lib/active_merchant/billing/gateways/citrus_pay.rb index ae6d068818f..00ab762d196 100644 --- a/lib/active_merchant/billing/gateways/citrus_pay.rb +++ b/lib/active_merchant/billing/gateways/citrus_pay.rb @@ -15,10 +15,8 @@ class CitrusPayGateway < Gateway self.homepage_url = 'http://www.citruspay.com/' self.supported_countries = %w(AR AU BR FR DE HK MX NZ SG GB US) self.default_currency = 'USD' - self.supported_cardtypes = [:visa, :master, :american_express, :discover, :diners_club, :jcb, :maestro, :laser] - self.ssl_version = :TLSv1 + self.supported_cardtypes = [:visa, :master, :american_express, :discover, :diners_club, :jcb, :maestro] end end end - diff --git a/lib/active_merchant/billing/gateways/clearhaus.rb b/lib/active_merchant/billing/gateways/clearhaus.rb index ae11cbbdc6b..b53d792a4f4 100644 --- a/lib/active_merchant/billing/gateways/clearhaus.rb +++ b/lib/active_merchant/billing/gateways/clearhaus.rb @@ -1,5 +1,3 @@ -require 'openssl' - module ActiveMerchant #:nodoc: module Billing #:nodoc: class ClearhausGateway < Gateway @@ -56,16 +54,16 @@ def authorize(amount, payment, options={}) add_invoice(post, amount, options) action = if payment.respond_to?(:number) - add_payment(post, payment) - "/authorizations" - elsif payment.kind_of?(String) - "/cards/#{payment}/authorizations" - else - raise ArgumentError.new("Unknown payment type #{payment.inspect}") + add_payment(post, payment) + '/authorizations' + elsif payment.kind_of?(String) + "/cards/#{payment}/authorizations" + else + raise ArgumentError.new("Unknown payment type #{payment.inspect}") end post[:recurring] = options[:recurring] if options[:recurring] - post[:threed_secure] = {pares: options[:pares]} if options[:pares] + post[:card][:pares] = options[:pares] if options[:pares] commit(action, post) end @@ -90,7 +88,7 @@ def void(authorization, options = {}) def verify(credit_card, options={}) MultiResponse.run(:use_first_response) do |r| - r.process { authorize(100, credit_card, options) } + r.process { authorize(0, credit_card, options) } r.process(:ignore_result) { void(r.authorization, options) } end end @@ -99,7 +97,7 @@ def store(credit_card, options={}) post = {} add_payment(post, credit_card) - commit("/cards", post) + commit('/cards', post) end def supports_scrubbing? @@ -110,7 +108,7 @@ def scrub(transcript) transcript. gsub(%r((Authorization: Basic )[\w=]+), '\1[FILTERED]'). gsub(%r((&?card(?:\[|%5B)csc(?:\]|%5D)=)[^&]*)i, '\1[FILTERED]'). - gsub(%r((&?card(?:\[|%5B)number(?:\]|%5D)=)[^&]*)i, '\1[FILTERED]') + gsub(%r((&?card(?:\[|%5B)pan(?:\]|%5D)=)[^&]*)i, '\1[FILTERED]') end private @@ -128,12 +126,12 @@ def add_amount(post, amount, options) def add_payment(post, payment) card = {} - card[:number] = payment.number + card[:pan] = payment.number card[:expire_month] = '%02d'% payment.month card[:expire_year] = payment.year if payment.verification_value? - card[:csc] = payment.verification_value + card[:csc] = payment.verification_value end post[:card] = card if card.any? @@ -141,8 +139,8 @@ def add_payment(post, payment) def headers(api_key) { - "Authorization" => "Basic " + Base64.strict_encode64("#{api_key}:"), - "User-Agent" => "Clearhaus ActiveMerchantBindings/#{ActiveMerchant::VERSION}" + 'Authorization' => 'Basic ' + Base64.strict_encode64("#{api_key}:"), + 'User-Agent' => "Clearhaus ActiveMerchantBindings/#{ActiveMerchant::VERSION}" } end @@ -157,7 +155,7 @@ def commit(action, parameters) if @options[:signing_key] && @options[:private_key] begin - headers["Signature"] = generate_signature(body) + headers['Signature'] = generate_signature(body) rescue OpenSSL::PKey::RSAError => e return Response.new(false, e.message) end diff --git a/lib/active_merchant/billing/gateways/commercegate.rb b/lib/active_merchant/billing/gateways/commercegate.rb index d70a11aa153..c1d6d5bc1f4 100644 --- a/lib/active_merchant/billing/gateways/commercegate.rb +++ b/lib/active_merchant/billing/gateways/commercegate.rb @@ -65,18 +65,17 @@ def add_address(post, address) post[:state] = address[:state] post[:postalCode] = address[:zip] end - post[:countryCode] = ((address && address[:country]) || "US") + post[:countryCode] = ((address && address[:country]) || 'US') end def add_auth_purchase_options(post, money, options) add_address(post, options[:address]) - post[:customerIP] = options[:ip] || "127.0.0.1" + post[:customerIP] = options[:ip] || '127.0.0.1' post[:amount] = amount(money) - post[:email] = options[:email] || "unknown@example.com" + post[:email] = options[:email] || 'unknown@example.com' post[:currencyCode]= options[:currency] || currency(money) post[:merchAcct] = options[:merchant] - end def add_creditcard(params, creditcard) @@ -112,7 +111,7 @@ def parse(body) results = {} body.split(/\&/).each do |pair| - key,val = pair.split(%r{=}) + key, val = pair.split(%r{=}) results[key] = CGI.unescape(val) end @@ -127,8 +126,8 @@ def message_from(response) if response['returnText'].present? response['returnText'] else - "Invalid response received from the CommerceGate API. " + - "Please contact CommerceGate support if you continue to receive this message. " + + 'Invalid response received from the CommerceGate API. ' \ + 'Please contact CommerceGate support if you continue to receive this message. ' \ "(The raw response returned by the API was #{response.inspect})" end end @@ -136,7 +135,7 @@ def message_from(response) def post_data(parameters) parameters.collect do |key, value| "#{key}=#{CGI.escape(value.to_s)}" - end.join("&") + end.join('&') end end end diff --git a/lib/active_merchant/billing/gateways/conekta.rb b/lib/active_merchant/billing/gateways/conekta.rb index ce073519eda..06aad777b09 100644 --- a/lib/active_merchant/billing/gateways/conekta.rb +++ b/lib/active_merchant/billing/gateways/conekta.rb @@ -4,7 +4,7 @@ class ConektaGateway < Gateway self.live_url = 'https://api.conekta.io/' self.supported_countries = ['MX'] - self.supported_cardtypes = [:visa, :master, :american_express] + self.supported_cardtypes = [:visa, :master, :american_express, :carnet] self.homepage_url = 'https://conekta.io/' self.display_name = 'Conekta Gateway' self.money_format = :cents @@ -23,7 +23,7 @@ def purchase(money, payment_source, options = {}) add_payment_source(post, payment_source, options) add_details_data(post, options) - commit(:post, 'charges', post) + commit(:post, 'charges', post, options) end def authorize(money, payment_source, options = {}) @@ -34,7 +34,7 @@ def authorize(money, payment_source, options = {}) add_details_data(post, options) post[:capture] = false - commit(:post, "charges", post) + commit(:post, 'charges', post, options) end def capture(money, identifier, options = {}) @@ -43,7 +43,7 @@ def capture(money, identifier, options = {}) post[:order_id] = identifier add_order(post, money, options) - commit(:post, "charges/#{identifier}/capture", post) + commit(:post, "charges/#{identifier}/capture", post, options) end def refund(money, identifier, options) @@ -52,12 +52,12 @@ def refund(money, identifier, options) post[:order_id] = identifier add_order(post, money, options) - commit(:post, "charges/#{identifier}/refund", post) + commit(:post, "charges/#{identifier}/refund", post, options) end def void(identifier, options = {}) post = {} - commit(:post, "charges/#{identifier}/void", post) + commit(:post, "charges/#{identifier}/void", post, options) end def supports_scrubbing @@ -74,24 +74,24 @@ def scrub(transcript) private def add_order(post, money, options) - post[:description] = options[:description] || "Active Merchant Purchase" + post[:description] = options[:description] || 'Active Merchant Purchase' post[:reference_id] = options[:order_id] if options[:order_id] post[:currency] = (options[:currency] || currency(money)).downcase + post[:monthly_installments] = options[:monthly_installments] if options[:monthly_installments] post[:amount] = amount(money) end def add_details_data(post, options) details = {} - details[:name] = options[:customer] if options[:customer] + details[:name] = options[:customer] || (options[:billing_address][:name] if options[:billing_address]) + details[:phone] = options[:phone] || (options[:billing_address][:phone] if options[:billing_address]) details[:email] = options[:email] if options[:email] - details[:phone] = options[:phone] if options[:phone] - post[:device_fingerprint] = options[:device_fingerprint] if options[:device_fingerprint] details[:ip] = options[:ip] if options[:ip] add_billing_address(details, options) add_line_items(details, options) add_shipment(details, options) - post[:details] = details + post[:device_fingerprint] = options[:device_fingerprint] if options[:device_fingerprint] end def add_shipment(post, options) @@ -162,8 +162,8 @@ def add_payment_source(post, payment_source, options) post[:card][:name] = payment_source.name post[:card][:cvc] = payment_source.verification_value post[:card][:number] = payment_source.number - post[:card][:exp_month] = "#{sprintf("%02d", payment_source.month)}" - post[:card][:exp_year] = "#{"#{payment_source.year}"[-2, 2]}" + post[:card][:exp_month] = sprintf('%02d', payment_source.month) + post[:card][:exp_year] = payment_source.year.to_s[-2, 2] add_address(post[:card], options) end end @@ -173,23 +173,28 @@ def parse(body) JSON.parse(body) end - def headers(meta) + def headers(options) { - "Accept" => "application/vnd.conekta-v#{options[:version]}+json", - "Accept-Language" => "es", - "Authorization" => "Basic " + Base64.encode64("#{options[:key]}:"), - "RaiseHtmlError" => "false", - "Conekta-Client-User-Agent" => {"agent"=>"Conekta ActiveMerchantBindings/#{ActiveMerchant::VERSION}"}.to_json, - "X-Conekta-Client-User-Agent" => user_agent, - "X-Conekta-Client-User-Metadata" => meta.to_json + 'Accept' => "application/vnd.conekta-v#{@options[:version]}+json", + 'Accept-Language' => 'es', + 'Authorization' => 'Basic ' + Base64.encode64("#{@options[:key]}:"), + 'RaiseHtmlError' => 'false', + 'Conekta-Client-User-Agent' => {'agent'=>"Conekta ActiveMerchantBindings/#{ActiveMerchant::VERSION}"}.to_json, + 'X-Conekta-Client-User-Agent' => conekta_client_user_agent(options), + 'X-Conekta-Client-User-Metadata' => options[:meta].to_json } end + def conekta_client_user_agent(options) + return user_agent unless options[:application] + JSON.dump(JSON.parse(user_agent).merge!({application: options[:application]})) + end + def commit(method, url, parameters, options = {}) success = false begin - raw_response = parse(ssl_request(method, live_url + url, (parameters ? parameters.to_query : nil), headers(options[:meta]))) - success = (raw_response.key?("object") && (raw_response["object"] != "error")) + raw_response = parse(ssl_request(method, live_url + url, (parameters ? parameters.to_query : nil), headers(options))) + success = (raw_response.key?('object') && (raw_response['object'] != 'error')) rescue ResponseError => e raw_response = response_error(e.response.body) rescue JSON::ParserError @@ -198,26 +203,24 @@ def commit(method, url, parameters, options = {}) Response.new( success, - raw_response["message_to_purchaser"], + raw_response['message_to_purchaser'], raw_response, test: test?, - authorization: raw_response["id"] + authorization: raw_response['id'] ) end def response_error(raw_response) - begin - parse(raw_response) - rescue JSON::ParserError - json_error(raw_response) - end + parse(raw_response) + rescue JSON::ParserError + json_error(raw_response) end def json_error(raw_response) msg = 'Invalid response received from the Conekta API.' msg += " (The raw response returned by the API was #{raw_response.inspect})" { - "message" => msg + 'message' => msg } end end diff --git a/lib/active_merchant/billing/gateways/creditcall.rb b/lib/active_merchant/billing/gateways/creditcall.rb index c9ae198bfe4..45f84569f5d 100644 --- a/lib/active_merchant/billing/gateways/creditcall.rb +++ b/lib/active_merchant/billing/gateways/creditcall.rb @@ -15,6 +15,32 @@ class CreditcallGateway < Gateway self.homepage_url = 'https://www.creditcall.com' self.display_name = 'Creditcall' + CVV_CODE = { + 'matched' => 'M', + 'notmatched' => 'N', + 'notchecked' => 'P', + 'partialmatch' => 'N' + } + + AVS_CODE = { + 'matched;matched' => 'D', + 'matched;notchecked' =>'B', + 'matched;notmatched' => 'A', + 'matched;partialmatch' => 'A', + 'notchecked;matched' => 'P', + 'notchecked;notchecked' =>'I', + 'notchecked;notmatched' => 'I', + 'notchecked;partialmatch' => 'I', + 'notmatched;matched' => 'W', + 'notmatched;notchecked' =>'C', + 'notmatched;notmatched' => 'C', + 'notmatched;partialmatch' => 'C', + 'partialmatched;matched' => 'W', + 'partialmatched;notchecked' =>'C', + 'partialmatched;notmatched' => 'C', + 'partialmatched;partialmatch' => 'C' + } + def initialize(options={}) requires!(options, :terminal_id, :transaction_key) super @@ -26,18 +52,23 @@ def purchase(money, payment_method, options={}) r.process { capture(money, r.authorization, options) } end + merged_params = multi_response.responses.map(&:params).reduce({}, :merge) + Response.new( multi_response.primary_response.success?, multi_response.primary_response.message, - multi_response.primary_response.params, + merged_params, authorization: multi_response.responses.first.authorization, + avs_result: AVSResult.new(code: avs_result_code_from(merged_params)), + cvv_result: CVVResult.new(cvv_result_code_from(merged_params)), + error_code: error_result_code_from(merged_params), test: test? ) end def authorize(money, payment_method, options={}) request = build_xml_request do |xml| - add_transaction_details(xml, money, nil, "Auth", options) + add_transaction_details(xml, money, nil, 'Auth', options) add_terminal_details(xml, options) add_card_details(xml, payment_method, options) end @@ -47,7 +78,7 @@ def authorize(money, payment_method, options={}) def capture(money, authorization, options={}) request = build_xml_request do |xml| - add_transaction_details(xml, money, authorization, "Conf", options) + add_transaction_details(xml, money, authorization, 'Conf', options) add_terminal_details(xml, options) end @@ -56,7 +87,7 @@ def capture(money, authorization, options={}) def refund(money, authorization, options={}) request = build_xml_request do |xml| - add_transaction_details(xml, money, authorization, "Refund", options) + add_transaction_details(xml, money, authorization, 'Refund', options) add_terminal_details(xml, options) end @@ -65,7 +96,7 @@ def refund(money, authorization, options={}) def void(authorization, options={}) request = build_xml_request do |xml| - add_transaction_details(xml, nil, authorization, "Void", options) + add_transaction_details(xml, nil, authorization, 'Void', options) add_terminal_details(xml, options) end @@ -92,9 +123,21 @@ def scrub(transcript) private + def avs_result_code_from(params) + AVS_CODE["#{params['Address']};#{params['Zip']}"] + end + + def cvv_result_code_from(params) + CVV_CODE[params['CSC']] + end + + def error_result_code_from(params) + params['ErrorCode'] + end + def build_xml_request builder = Nokogiri::XML::Builder.new do |xml| - xml.Request(type: "CardEaseXML", version: "1.0.0") do + xml.Request(type: 'CardEaseXML', version: '1.0.0') do yield(xml) end end @@ -104,9 +147,9 @@ def build_xml_request def add_transaction_details(xml, amount, authorization, type, options={}) xml.TransactionDetails do xml.MessageType type - xml.Amount(unit: "Minor"){ xml.text(amount) } if amount + xml.Amount(unit: 'Minor') { xml.text(amount) } if amount xml.CardEaseReference authorization if authorization - xml.VoidReason "01" if type == "Void" + xml.VoidReason '01' if type == 'Void' end end @@ -114,23 +157,28 @@ def add_terminal_details(xml, options={}) xml.TerminalDetails do xml.TerminalID @options[:terminal_id] xml.TransactionKey @options[:transaction_key] - xml.Software(version: "SoftwareVersion"){ xml.text("SoftwareName") } + xml.Software(version: 'SoftwareVersion') { xml.text('SoftwareName') } end end def add_card_details(xml, payment_method, options={}) xml.CardDetails do - xml.Manual(type: "ecommerce") do + xml.Manual(type: manual_type(options)) do xml.PAN payment_method.number xml.ExpiryDate exp_date(payment_method) xml.CSC payment_method.verification_value unless empty?(payment_method.verification_value) end - if address = options[:billing_address] - xml.AdditionalVerification do - xml.Address address[:address1] - xml.Zip address[:zip] - end + add_additional_verification(xml, options) + end + end + + def add_additional_verification(xml, options) + return unless (options[:verify_zip].to_s == 'true') || (options[:verify_address].to_s == 'true') + if address = options[:billing_address] + xml.AdditionalVerification do + xml.Zip address[:zip] if options[:verify_zip].to_s == 'true' + xml.Address address[:address1] if options[:verify_address].to_s == 'true' end end end @@ -143,12 +191,21 @@ def parse(body) response = {} xml = Nokogiri::XML(body) - node = xml.xpath("//Response/TransactionDetails") + node = xml.xpath('//Response/TransactionDetails') node.children.each do |childnode| response[childnode.name] = childnode.text end - node = xml.xpath("//Response/Result") + node = xml.xpath('//Response/Result') + node.children.each do |childnode| + if childnode.elements.empty? + response[childnode.name] = childnode.text + else + childnode_to_response(response, childnode) + end + end + + node = xml.xpath('//Response/CardDetails') node.children.each do |childnode| if childnode.elements.empty? response[childnode.name] = childnode.text @@ -162,9 +219,9 @@ def parse(body) def childnode_to_response(response, childnode) childnode.elements.each do |element| - if element.name == "Error" - response["ErrorCode"] = element.attr("code") - response["ErrorMessage"] = element.text + if element.name == 'Error' + response['ErrorCode'] = element.attr('code') + response['ErrorMessage'] = element.text else response[element.name] = element.text end @@ -179,8 +236,9 @@ def commit(parameters) message_from(response), response, authorization: authorization_from(response), - avs_result: AVSResult.new(code: response["some_avs_response_key"]), - cvv_result: CVVResult.new(response["some_cvv_response_key"]), + avs_result: AVSResult.new(code: avs_result_code_from(response)), + cvv_result: CVVResult.new(cvv_result_code_from(response)), + error_code: error_result_code_from(response), test: test? ) end @@ -190,21 +248,24 @@ def url end def success_from(response) - response["LocalResult"] == "0" || response["LocalResult"] == "00" + response['LocalResult'] == '0' || response['LocalResult'] == '00' end def message_from(response) if success_from(response) - "Succeeded" + 'Succeeded' else - response["ErrorMessage"] + response['ErrorMessage'] end end def authorization_from(response) - response["CardEaseReference"] + response['CardEaseReference'] end + def manual_type(options) + options[:manual_type] || 'ecommerce' + end end end end diff --git a/lib/active_merchant/billing/gateways/credorax.rb b/lib/active_merchant/billing/gateways/credorax.rb index c36e04c88c4..ccc42a508ed 100644 --- a/lib/active_merchant/billing/gateways/credorax.rb +++ b/lib/active_merchant/billing/gateways/credorax.rb @@ -3,10 +3,10 @@ module Billing #:nodoc: class CredoraxGateway < Gateway class_attribute :test_url, :live_na_url, :live_eu_url - self.display_name = "Credorax Gateway" - self.homepage_url = "https://www.credorax.com/" + self.display_name = 'Credorax Gateway' + self.homepage_url = 'https://www.credorax.com/' - self.test_url = "https://intconsole.credorax.com/intenv/service/gateway" + self.test_url = 'https://intconsole.credorax.com/intenv/service/gateway' # The live URL is assigned on a per merchant basis once certification has passed # See the Credorax remote tests for the full certification test suite @@ -16,10 +16,106 @@ class CredoraxGateway < Gateway self.live_url = 'https://assigned-subdomain.credorax.net/crax_gate/service/gateway' self.supported_countries = %w(DE GB FR IT ES PL NL BE GR CZ PT SE HU RS AT CH BG DK FI SK NO IE HR BA AL LT MK SI LV EE ME LU MT IS AD MC LI SM) - self.default_currency = "EUR" + self.default_currency = 'EUR' + self.currencies_without_fractions = %w(CLP JPY KRW PYG VND) + self.currencies_with_three_decimal_places = %w(BHD JOD KWD OMR RSD TND) + self.money_format = :cents self.supported_cardtypes = [:visa, :master, :maestro] + RESPONSE_MESSAGES = { + '00' => 'Approved or completed successfully', + '01' => 'Refer to card issuer', + '02' => 'Refer to card issuer special condition', + '03' => 'Invalid merchant', + '04' => 'Pick up card', + '05' => 'Do not Honour', + '06' => 'Error', + '07' => 'Pick up card special condition', + '08' => 'Honour with identification', + '09' => 'Request in progress', + '10' => 'Approved for partial amount', + '11' => 'Approved (VIP)', + '12' => 'Invalid transaction', + '13' => 'Invalid amount', + '14' => 'Invalid card number', + '15' => 'No such issuer', + '16' => 'Approved, update track 3', + '17' => 'Customer cancellation', + '18' => 'Customer dispute', + '19' => 'Re-enter transaction', + '20' => 'Invalid response', + '21' => 'No action taken', + '22' => 'Suspected malfunction', + '23' => 'Unacceptable transaction fee', + '24' => 'File update not supported by receiver', + '25' => 'No such record', + '26' => 'Duplicate record update, old record replaced', + '27' => 'File update field edit error', + '28' => 'File locked out while update', + '29' => 'File update error, contact acquirer', + '30' => 'Format error', + '31' => 'Issuer signed-off', + '32' => 'Completed partially', + '33' => 'Pick-up, expired card', + '34' => 'Suspect Fraud', + '35' => 'Pick-up, card acceptor contact acquirer', + '36' => 'Pick up, card restricted', + '37' => 'Pick up, call acquirer security', + '38' => 'Pick up, Allowable PIN tries exceeded', + '39' => 'Transaction Not Allowed', + '40' => 'Requested function not supported', + '41' => 'Lost Card, Pickup', + '42' => 'No universal account', + '43' => 'Pick up, stolen card', + '44' => 'No investment account', + '50' => 'Do not renew', + '51' => 'Not sufficient funds', + '52' => 'No checking Account', + '53' => 'No savings account', + '54' => 'Expired card', + '55' => 'Pin incorrect', + '56' => 'No card record', + '57' => 'Transaction not allowed for cardholder', + '58' => 'Transaction not allowed for merchant', + '59' => 'Suspected Fraud', + '60' => 'Card acceptor contact acquirer', + '61' => 'Exceeds withdrawal amount limit', + '62' => 'Restricted card', + '63' => 'Security violation', + '64' => 'Wrong original amount', + '65' => 'Activity count limit exceeded', + '66' => 'Call acquirers security department', + '67' => 'Card to be picked up at ATM', + '68' => 'Response received too late.', + '70' => 'Invalid transaction; contact card issuer', + '71' => 'Decline PIN not changed', + '75' => 'Pin tries exceeded', + '76' => 'Wrong PIN, number of PIN tries exceeded', + '77' => 'Wrong Reference No.', + '78' => 'Record Not Found', + '79' => 'Already reversed', + '80' => 'Network error', + '81' => 'Foreign network error / PIN cryptographic error', + '82' => 'Time out at issuer system', + '83' => 'Transaction failed', + '84' => 'Pre-authorization timed out', + '85' => 'No reason to decline', + '86' => 'Cannot verify pin', + '87' => 'Purchase amount only, no cashback allowed', + '88' => 'MAC sync Error', + '89' => 'Authentication failure', + '91' => 'Issuer not available', + '92' => 'Unable to route at acquirer Module', + '93' => 'Cannot be completed, violation of law', + '94' => 'Duplicate Transmission', + '95' => 'Reconcile error / Auth Not found', + '96' => 'System malfunction', + 'R0' => 'Stop Payment Order', + 'R1' => 'Revocation of Authorisation Order', + 'R3' => 'Revocation of all Authorisations Order' + } + def initialize(options={}) requires!(options, :merchant_id, :cipher_key) super @@ -31,7 +127,10 @@ def purchase(amount, payment_method, options={}) add_payment_method(post, payment_method) add_customer_data(post, options) add_email(post, options) + add_3d_secure(post, options) add_echo(post, options) + add_submerchant_id(post, options) + add_transaction_type(post, options) commit(:purchase, post) end @@ -42,7 +141,10 @@ def authorize(amount, payment_method, options={}) add_payment_method(post, payment_method) add_customer_data(post, options) add_email(post, options) + add_3d_secure(post, options) add_echo(post, options) + add_submerchant_id(post, options) + add_transaction_type(post, options) commit(:authorize, post) end @@ -53,6 +155,7 @@ def capture(amount, authorization, options={}) add_reference(post, authorization) add_customer_data(post, options) add_echo(post, options) + add_submerchant_id(post, options) commit(:capture, post) end @@ -62,6 +165,7 @@ def void(authorization, options={}) add_customer_data(post, options) reference_action = add_reference(post, authorization) add_echo(post, options) + add_submerchant_id(post, options) post[:a1] = generate_unique_id commit(:void, post, reference_action) @@ -73,6 +177,7 @@ def refund(amount, authorization, options={}) add_reference(post, authorization) add_customer_data(post, options) add_echo(post, options) + add_submerchant_id(post, options) commit(:refund, post) end @@ -84,6 +189,8 @@ def credit(amount, payment_method, options={}) add_customer_data(post, options) add_email(post, options) add_echo(post, options) + add_submerchant_id(post, options) + add_transaction_type(post, options) commit(:credit, post) end @@ -108,16 +215,19 @@ def scrub(transcript) private def add_invoice(post, money, options) - post[:a4] = amount(money) + currency = options[:currency] || currency(money) + + post[:a4] = localized_amount(money, currency) post[:a1] = generate_unique_id - post[:a5] = options[:currency] || currency(money) + post[:a5] = currency post[:h9] = options[:order_id] + post[:i2] = options[:billing_descriptor] if options[:billing_descriptor] end CARD_TYPES = { - "visa" => '1', - "mastercard" => '2', - "maestro" => '9' + 'visa' => '1', + 'mastercard' => '2', + 'maestro' => '9' } def add_payment_method(post, payment_method) @@ -142,7 +252,7 @@ def add_customer_data(post, options) end def add_reference(post, authorization) - response_id, authorization_code, request_id, action = authorization.split(";") + response_id, authorization_code, request_id, action = authorization.split(';') post[:g2] = response_id post[:g3] = authorization_code post[:g4] = request_id @@ -153,17 +263,30 @@ def add_email(post, options) post[:c3] = options[:email] || 'unspecified@example.com' end + def add_3d_secure(post, options) + return unless options[:eci] && options[:xid] + post[:i8] = "#{options[:eci]}:#{(options[:cavv] || "none")}:#{options[:xid]}" + end + def add_echo(post, options) # The d2 parameter is used during the certification process # See remote tests for full certification test suite post[:d2] = options[:echo] unless options[:echo].blank? end + def add_submerchant_id(post, options) + post[:h3] = options[:submerchant_id] if options[:submerchant_id] + end + + def add_transaction_type(post, options) + post[:a9] = options[:transaction_type] if options[:transaction_type] + end + ACTIONS = { purchase: '1', authorize: '2', capture: '3', - authorize_void:'4', + authorize_void: '4', refund: '5', credit: '6', purchase_void: '7', @@ -180,8 +303,8 @@ def commit(action, params, reference_action = nil) message_from(response), response, authorization: "#{response["Z1"]};#{response["Z4"]};#{response["A1"]};#{action}", - avs_result: AVSResult.new(code: response["Z9"]), - cvv_result: CVVResult.new(response["Z14"]), + avs_result: AVSResult.new(code: response['Z9']), + cvv_result: CVVResult.new(response['Z14']), test: test? ) end @@ -194,11 +317,11 @@ def sign_request(params) end def post_data(action, params, reference_action) - params.keys.each { |key| params[key] = params[key].to_s} + params.keys.each { |key| params[key] = params[key].to_s } params[:M] = @options[:merchant_id] params[:O] = request_action(action, reference_action) params[:K] = sign_request(params) - params.map {|k, v| "#{k}=#{CGI.escape(v.to_s)}"}.join('&') + params.map { |k, v| "#{k}=#{CGI.escape(v.to_s)}" }.join('&') end def request_action(action, reference_action) @@ -214,18 +337,18 @@ def url end def parse(body) - Hash[CGI::parse(body).map{|k,v| [k.upcase,v.first]}] + Hash[CGI::parse(body).map { |k, v| [k.upcase, v.first] }] end def success_from(response) - response["Z2"] == "0" + response['Z2'] == '0' end def message_from(response) if success_from(response) - "Succeeded" + 'Succeeded' else - response["Z3"] || "Unable to read error message" + RESPONSE_MESSAGES[response['Z6']] || response['Z3'] || 'Unable to read error message' end end end diff --git a/lib/active_merchant/billing/gateways/ct_payment.rb b/lib/active_merchant/billing/gateways/ct_payment.rb new file mode 100644 index 00000000000..315f16375d8 --- /dev/null +++ b/lib/active_merchant/billing/gateways/ct_payment.rb @@ -0,0 +1,268 @@ +module ActiveMerchant #:nodoc: + module Billing #:nodoc: + class CtPaymentGateway < Gateway + self.test_url = 'https://test.ctpaiement.ca/v1/' + self.live_url = 'https://www.ctpaiement.com/v1/' + + self.supported_countries = ['US', 'CA'] + self.default_currency = 'CAD' + self.supported_cardtypes = [:visa, :master, :american_express, :discover, :diners_club] + + self.homepage_url = 'http://www.ct-payment.com/' + self.display_name = 'CT Payment' + + STANDARD_ERROR_CODE_MAPPING = { + '14' => STANDARD_ERROR_CODE[:invalid_number], + '05' => STANDARD_ERROR_CODE[:card_declined], + 'M6' => STANDARD_ERROR_CODE[:card_declined], + '9068' => STANDARD_ERROR_CODE[:incorrect_number], + '9067' => STANDARD_ERROR_CODE[:incorrect_number] + } + CARD_BRAND = { + 'american_express' => 'A', + 'master' => 'M', + 'diners_club' => 'I', + 'visa' => 'V', + 'discover' => 'O' + } + + def initialize(options={}) + requires!(options, :api_key, :company_number, :merchant_number) + super + end + + def purchase(money, payment, options={}) + requires!(options, :order_id) + post = {} + add_terminal_number(post, options) + add_money(post, money) + add_operator_id(post, options) + add_invoice(post, money, options) + add_payment(post, payment) + add_address(post, payment, options) + add_customer_data(post, options) + + payment.is_a?(String) ? commit('purchaseWithToken', post) : commit('purchase', post) + end + + def authorize(money, payment, options={}) + requires!(options, :order_id) + post = {} + add_money(post, money) + add_terminal_number(post, options) + add_operator_id(post, options) + add_invoice(post, money, options) + add_payment(post, payment) + add_address(post, payment, options) + add_customer_data(post, options) + + payment.is_a?(String) ? commit('preAuthorizationWithToken', post) : commit('preAuthorization', post) + end + + def capture(money, authorization, options={}) + requires!(options, :order_id) + post = {} + add_invoice(post, money, options) + add_money(post, money) + add_customer_data(post, options) + transaction_number, authorization_number, invoice_number = split_authorization(authorization) + post[:OriginalTransactionNumber] = transaction_number + post[:OriginalAuthorizationNumber] = authorization_number + post[:OriginalInvoiceNumber] = invoice_number + + commit('completion', post) + end + + def refund(money, authorization, options={}) + requires!(options, :order_id) + post = {} + add_invoice(post, money, options) + add_money(post, money) + add_customer_data(post, options) + transaction_number, _, invoice_number = split_authorization(authorization) + post[:OriginalTransactionNumber] = transaction_number + post[:OriginalInvoiceNumber] = invoice_number + + commit('refundWithoutCard', post) + end + + def credit(money, payment, options={}) + requires!(options, :order_id) + post = {} + add_terminal_number(post, options) + add_money(post, money) + add_operator_id(post, options) + add_invoice(post, money, options) + add_payment(post, payment) + add_address(post, payment, options) + add_customer_data(post, options) + + payment.is_a?(String) ? commit('refundWithToken', post) : commit('refund', post) + end + + def void(authorization, options={}) + post = {} + post[:InputType] = 'I' + post[:LanguageCode] = 'E' + transaction_number, _, invoice_number = split_authorization(authorization) + post[:OriginalTransactionNumber] = transaction_number + post[:OriginalInvoiceNumber] = invoice_number + add_operator_id(post, options) + add_customer_data(post, options) + + commit('void', post) + end + + def verify(credit_card, options={}) + requires!(options, :order_id) + post = {} + add_terminal_number(post, options) + add_operator_id(post, options) + add_invoice(post, 0, options) + add_payment(post, credit_card) + add_address(post, credit_card, options) + add_customer_data(post, options) + + commit('verifyAccount', post) + end + + def store(credit_card, options={}) + requires!(options, :email) + post = { + LanguageCode: 'E', + Name: credit_card.name.rjust(50, ' '), + Email: options[:email].rjust(240, ' ') + } + add_operator_id(post, options) + add_payment(post, credit_card) + add_customer_data(post, options) + + commit('recur/AddUser', post) + end + + def supports_scrubbing? + true + end + + def scrub(transcript) + transcript. + gsub(%r((&?auth-api-key=)[^&]*)i, '\1[FILTERED]'). + gsub(%r((&?payload=)[a-zA-Z%0-9=]+)i, '\1[FILTERED]'). + gsub(%r((&?token:)[^&]*)i, '\1[FILTERED]'). + gsub(%r((&?cardNumber:)[^&]*)i, '\1[FILTERED]') + end + + private + + def add_terminal_number(post, options) + post[:MerchantTerminalNumber] = options[:merchant_terminal_number] || ' ' * 5 + end + + def add_money(post, money) + post[:Amount] = money.to_s.rjust(11, '0') + end + + def add_operator_id(post, options) + post[:OperatorID] = options[:operator_id] || '0' * 8 + end + + def add_customer_data(post, options) + post[:CustomerNumber] = options[:customer_number] || '0' * 8 + end + + def add_address(post, creditcard, options) + if address = options[:billing_address] || options[:address] + post[:CardHolderAddress] = "#{address[:address1]} #{address[:address2]} #{address[:city]} #{address[:state]}".rjust(20, ' ') + post[:CardHolderPostalCode] = address[:zip].gsub(/\s+/, '').rjust(9, ' ') + end + end + + def add_invoice(post, money, options) + post[:CurrencyCode] = options[:currency] || (currency(money) if money) + post[:InvoiceNumber] = options[:order_id].rjust(12, '0') + post[:InputType] = 'I' + post[:LanguageCode] = 'E' + end + + def add_payment(post, payment) + if payment.is_a?(String) + post[:Token] = split_authorization(payment)[3].strip + else + post[:CardType] = CARD_BRAND[payment.brand] || ' ' + post[:CardNumber] = payment.number.rjust(40, ' ') + post[:ExpirationDate] = expdate(payment) + post[:Cvv2Cvc2Number] = payment.verification_value + end + end + + def parse(body) + JSON.parse(body) + end + + def split_authorization(authorization) + authorization.split(';') + end + + def commit_raw(action, parameters) + url = (test? ? test_url : live_url) + action + response = parse(ssl_post(url, post_data(action, parameters))) + + Response.new( + success_from(response), + message_from(response), + response, + authorization: authorization_from(response), + avs_result: AVSResult.new(code: response['avsStatus']), + cvv_result: CVVResult.new(response['cvv2Cvc2Status']), + test: test?, + error_code: error_code_from(response) + ) + end + + def commit(action, parameters) + if action == 'void' + commit_raw(action, parameters) + else + MultiResponse.run(true) do |r| + r.process { commit_raw(action, parameters) } + r.process { + split_auth = split_authorization(r.authorization) + auth = (action.include?('recur')? split_auth[4] : split_auth[0]) + action.include?('recur') ? commit_raw('recur/ack', {ID: auth}) : commit_raw('ack', {TransactionNumber: auth}) + } + end + end + end + + def success_from(response) + return true if response['returnCode'] == ' 00' + return true if response['returnCode'] == 'true' + return true if response['recurReturnCode'] == ' 00' + return false + end + + def message_from(response) + response['errorDescription'] || response['terminalDisp']&.strip + end + + def authorization_from(response) + "#{response['transactionNumber']};#{response['authorizationNumber']};"\ + "#{response['invoiceNumber']};#{response['token']};#{response['id']}" + end + + def post_data(action, parameters = {}) + parameters[:CompanyNumber] = @options[:company_number] + parameters[:MerchantNumber] = @options[:merchant_number] + parameters = parameters.collect do |key, value| + "#{key}=#{value}" unless value.nil? || value.empty? + end.join('&') + payload = Base64.strict_encode64(parameters) + "auth-api-key=#{@options[:api_key]}&payload=#{payload}".strip + end + + def error_code_from(response) + STANDARD_ERROR_CODE_MAPPING[response['returnCode'].strip || response['recurReturnCode'.strip]] unless success_from(response) + end + end + end +end diff --git a/lib/active_merchant/billing/gateways/culqi.rb b/lib/active_merchant/billing/gateways/culqi.rb index 1b3f0e8f3a2..80b4d030198 100644 --- a/lib/active_merchant/billing/gateways/culqi.rb +++ b/lib/active_merchant/billing/gateways/culqi.rb @@ -9,14 +9,14 @@ module Billing #:nodoc: # largely depends on the transaction acquiring bank. Be sure to understand how # your account was configured prior to using this gateway. class CulqiGateway < Gateway - self.display_name = "Culqi" - self.homepage_url = "https://www.culqi.com" + self.display_name = 'Culqi' + self.homepage_url = 'https://www.culqi.com' - self.test_url = "https://staging.paymentz.com/transaction/" - self.live_url = "https://secure.culqi.com/transaction/" + self.test_url = 'https://staging.paymentz.com/transaction/' + self.live_url = 'https://secure.culqi.com/transaction/' - self.supported_countries = ["PE"] - self.default_currency = "PEN" + self.supported_countries = ['PE'] + self.default_currency = 'PEN' self.money_format = :dollars self.supported_cardtypes = [:visa, :master, :diners_club, :american_express] @@ -86,8 +86,8 @@ def verify(credit_card, options={}) end def verify_credentials - response = void("0", order_id: "0") - response.message.include? "Transaction not found" + response = void('0', order_id: '0') + response.message.include? 'Transaction not found' end def store(credit_card, options={}) @@ -181,11 +181,11 @@ def add_customer_data(post, options) def add_checksum(action, post) checksum_elements = case action - when :capture; [post[:toid], post[:trackingid], post[:captureamount], @options[:secret_key]] - when :void; [post[:toid], post[:description], post[:trackingid], @options[:secret_key]] - when :refund; [post[:toid], post[:trackingid], post[:refundamount], @options[:secret_key]] - when :tokenize; [post[:partnerid], post[:cardnumber], post[:cvv], @options[:secret_key]] - when :invalidate; [post[:partnerid], post[:token], @options[:secret_key]] + when :capture then [post[:toid], post[:trackingid], post[:captureamount], @options[:secret_key]] + when :void then [post[:toid], post[:description], post[:trackingid], @options[:secret_key]] + when :refund then [post[:toid], post[:trackingid], post[:refundamount], @options[:secret_key]] + when :tokenize then [post[:partnerid], post[:cardnumber], post[:cvv], @options[:secret_key]] + when :invalidate then [post[:partnerid], post[:token], @options[:secret_key]] else [post[:toid], post[:totype], post[:amount], post[:description], post[:redirecturl], post[:cardnumber] || post[:token], @options[:secret_key]] end @@ -198,13 +198,13 @@ def add_reference(post, authorization) end ACTIONS = { - authorize: "SingleCallGenericServlet", - capture: "SingleCallGenericCaptureServlet", - void: "SingleCallGenericVoid", - refund: "SingleCallGenericReverse", - tokenize: "SingleCallTokenServlet", - invalidate: "SingleCallInvalidateToken", - tokenpay: "SingleCallTokenTransaction", + authorize: 'SingleCallGenericServlet', + capture: 'SingleCallGenericCaptureServlet', + void: 'SingleCallGenericVoid', + refund: 'SingleCallGenericReverse', + tokenize: 'SingleCallTokenServlet', + invalidate: 'SingleCallInvalidateToken', + tokenpay: 'SingleCallTokenTransaction', } def commit(action, params) @@ -229,13 +229,13 @@ def commit(action, params) def headers { - "Accept" => "application/json", - "Content-Type" => "application/x-www-form-urlencoded;charset=UTF-8" + 'Accept' => 'application/json', + 'Content-Type' => 'application/x-www-form-urlencoded;charset=UTF-8' } end def post_data(action, params) - params.map {|k, v| "#{k}=#{CGI.escape(v.to_s)}"}.join('&') + params.map { |k, v| "#{k}=#{CGI.escape(v.to_s)}" }.join('&') end def url @@ -243,16 +243,14 @@ def url end def parse(body) - begin - JSON.parse(body) - rescue JSON::ParserError - message = "Invalid JSON response received from CulqiGateway. Please contact CulqiGateway if you continue to receive this message." - message += "(The raw response returned by the API was #{body.inspect})" - { - "status" => "N", - "statusdescription" => message - } - end + JSON.parse(body) + rescue JSON::ParserError + message = 'Invalid JSON response received from CulqiGateway. Please contact CulqiGateway if you continue to receive this message.' + message += "(The raw response returned by the API was #{body.inspect})" + { + 'status' => 'N', + 'statusdescription' => message + } end def success_from(response) diff --git a/lib/active_merchant/billing/gateways/cyber_source.rb b/lib/active_merchant/billing/gateways/cyber_source.rb index 87435db29f6..9bc89b747ce 100644 --- a/lib/active_merchant/billing/gateways/cyber_source.rb +++ b/lib/active_merchant/billing/gateways/cyber_source.rb @@ -24,10 +24,10 @@ class CyberSourceGateway < Gateway self.test_url = 'https://ics2wstesta.ic3.com/commerce/1.x/transactionProcessor' self.live_url = 'https://ics2wsa.ic3.com/commerce/1.x/transactionProcessor' - XSD_VERSION = "1.121" + XSD_VERSION = '1.121' - self.supported_cardtypes = [:visa, :master, :american_express, :discover] - self.supported_countries = %w(US BR CA CN DK FI FR DE JP MX NO SE GB SG LB) + self.supported_cardtypes = [:visa, :master, :american_express, :discover, :diners_club, :jcb, :dankort, :maestro] + self.supported_countries = %w(US BR CA CN DK FI FR DE IN JP MX NO SE GB SG LB) self.default_currency = 'USD' self.currencies_without_fractions = %w(JPY) @@ -39,48 +39,52 @@ class CyberSourceGateway < Gateway :visa => '001', :master => '002', :american_express => '003', - :discover => '004' + :discover => '004', + :diners_club => '005', + :jcb => '007', + :dankort => '034', + :maestro => '042' } @@response_codes = { - :r100 => "Successful transaction", - :r101 => "Request is missing one or more required fields" , - :r102 => "One or more fields contains invalid data", - :r150 => "General failure", - :r151 => "The request was received but a server time-out occurred", - :r152 => "The request was received, but a service timed out", - :r200 => "The authorization request was approved by the issuing bank but declined by CyberSource because it did not pass the AVS check", - :r201 => "The issuing bank has questions about the request", - :r202 => "Expired card", - :r203 => "General decline of the card", - :r204 => "Insufficient funds in the account", - :r205 => "Stolen or lost card", - :r207 => "Issuing bank unavailable", - :r208 => "Inactive card or card not authorized for card-not-present transactions", - :r209 => "American Express Card Identifiction Digits (CID) did not match", - :r210 => "The card has reached the credit limit", - :r211 => "Invalid card verification number", + :r100 => 'Successful transaction', + :r101 => 'Request is missing one or more required fields', + :r102 => 'One or more fields contains invalid data', + :r150 => 'General failure', + :r151 => 'The request was received but a server time-out occurred', + :r152 => 'The request was received, but a service timed out', + :r200 => 'The authorization request was approved by the issuing bank but declined by CyberSource because it did not pass the AVS check', + :r201 => 'The issuing bank has questions about the request', + :r202 => 'Expired card', + :r203 => 'General decline of the card', + :r204 => 'Insufficient funds in the account', + :r205 => 'Stolen or lost card', + :r207 => 'Issuing bank unavailable', + :r208 => 'Inactive card or card not authorized for card-not-present transactions', + :r209 => 'American Express Card Identifiction Digits (CID) did not match', + :r210 => 'The card has reached the credit limit', + :r211 => 'Invalid card verification number', :r221 => "The customer matched an entry on the processor's negative file", - :r230 => "The authorization request was approved by the issuing bank but declined by CyberSource because it did not pass the card verification check", - :r231 => "Invalid account number", - :r232 => "The card type is not accepted by the payment processor", - :r233 => "General decline by the processor", - :r234 => "A problem exists with your CyberSource merchant configuration", - :r235 => "The requested amount exceeds the originally authorized amount", - :r236 => "Processor failure", - :r237 => "The authorization has already been reversed", - :r238 => "The authorization has already been captured", - :r239 => "The requested transaction amount must match the previous transaction amount", - :r240 => "The card type sent is invalid or does not correlate with the credit card number", - :r241 => "The request ID is invalid", - :r242 => "You requested a capture, but there is no corresponding, unused authorization record.", - :r243 => "The transaction has already been settled or reversed", - :r244 => "The bank account number failed the validation check", - :r246 => "The capture or credit is not voidable because the capture or credit information has already been submitted to your processor", - :r247 => "You requested a credit for a capture that was previously voided", - :r250 => "The request was received, but a time-out occurred with the payment processor", - :r254 => "Your CyberSource account is prohibited from processing stand-alone refunds", - :r255 => "Your CyberSource account is not configured to process the service in the country you specified" + :r230 => 'The authorization request was approved by the issuing bank but declined by CyberSource because it did not pass the card verification check', + :r231 => 'Invalid account number', + :r232 => 'The card type is not accepted by the payment processor', + :r233 => 'General decline by the processor', + :r234 => 'A problem exists with your CyberSource merchant configuration', + :r235 => 'The requested amount exceeds the originally authorized amount', + :r236 => 'Processor failure', + :r237 => 'The authorization has already been reversed', + :r238 => 'The authorization has already been captured', + :r239 => 'The requested transaction amount must match the previous transaction amount', + :r240 => 'The card type sent is invalid or does not correlate with the credit card number', + :r241 => 'The request ID is invalid', + :r242 => 'You requested a capture, but there is no corresponding, unused authorization record.', + :r243 => 'The transaction has already been settled or reversed', + :r244 => 'The bank account number failed the validation check', + :r246 => 'The capture or credit is not voidable because the capture or credit information has already been submitted to your processor', + :r247 => 'You requested a credit for a capture that was previously voided', + :r250 => 'The request was received, but a time-out occurred with the payment processor', + :r254 => 'Your CyberSource account is prohibited from processing stand-alone refunds', + :r255 => 'Your CyberSource account is not configured to process the service in the country you specified' } # These are the options that can be used when creating a new CyberSource @@ -109,7 +113,7 @@ def initialize(options = {}) def authorize(money, creditcard_or_reference, options = {}) setup_address_hash(options) - commit(build_auth_request(money, creditcard_or_reference, options), :authorize, money, options ) + commit(build_auth_request(money, creditcard_or_reference, options), :authorize, money, options) end def capture(money, authorization, options = {}) @@ -205,7 +209,7 @@ def calculate_tax(creditcard, options) # Determines if a card can be used for Pinless Debit Card transactions def validate_pinless_debit_card(creditcard, options = {}) requires!(options, :order_id) - commit(build_validate_pinless_debit_request(creditcard,options), :validate_pinless_debit_card, nil, options) + commit(build_validate_pinless_debit_request(creditcard, options), :validate_pinless_debit_card, nil, options) end def supports_scrubbing? @@ -227,8 +231,8 @@ def supports_network_tokenization? end def verify_credentials - response = void("0") - response.params["reasonCode"] == "102" + response = void('0') + response.params['reasonCode'] == '102' end private @@ -253,6 +257,8 @@ def build_auth_request(money, creditcard_or_reference, options) add_decision_manager_fields(xml, options) add_mdd_fields(xml, options) add_auth_service(xml, creditcard_or_reference, options) + add_threeds_services(xml, options) + add_payment_network_token(xml) if network_tokenization?(creditcard_or_reference) add_business_rules_data(xml, creditcard_or_reference, options) xml.target! end @@ -269,7 +275,7 @@ def build_tax_calculation_request(creditcard, options) end def build_capture_request(money, authorization, options) - order_id, request_id, request_token = authorization.split(";") + order_id, request_id, request_token = authorization.split(';') options[:order_id] = order_id xml = Builder::XmlMarkup.new :indent => 2 @@ -288,17 +294,19 @@ def build_purchase_request(money, payment_method_or_reference, options) add_check_service(xml) else add_purchase_service(xml, payment_method_or_reference, options) + add_threeds_services(xml, options) + add_payment_network_token(xml) if network_tokenization?(payment_method_or_reference) add_business_rules_data(xml, payment_method_or_reference, options) unless options[:pinless_debit_card] end xml.target! end def build_void_request(identification, options) - order_id, request_id, request_token, action, money, currency = identification.split(";") + order_id, request_id, request_token, action, money, currency = identification.split(';') options[:order_id] = order_id xml = Builder::XmlMarkup.new :indent => 2 - if action == "capture" + if action == 'capture' add_void_service(xml, request_id, request_token) else add_purchase_data(xml, money, true, options.merge(:currency => currency || default_currency)) @@ -308,7 +316,7 @@ def build_void_request(identification, options) end def build_refund_request(money, identification, options) - order_id, request_id, request_token = identification.split(";") + order_id, request_id, request_token = identification.split(';') options[:order_id] = order_id xml = Builder::XmlMarkup.new :indent => 2 @@ -329,7 +337,7 @@ def build_credit_request(money, reference, options) end def build_create_subscription_request(payment_method, options) - default_subscription_params = {:frequency => "on-demand", :amount => 0, :automatic_renew => false} + default_subscription_params = {:frequency => 'on-demand', :amount => 0, :automatic_renew => false} options[:subscription] = default_subscription_params.update( options[:subscription] || {} ) @@ -347,9 +355,10 @@ def build_create_subscription_request(payment_method, options) add_subscription(xml, options) if options[:setup_fee] if card_brand(payment_method) == 'check' - add_check_service(xml, options) + add_check_service(xml) else add_purchase_service(xml, payment_method, options) + add_payment_network_token(xml) if network_tokenization?(payment_method) end end add_subscription_create_service(xml, options) @@ -383,7 +392,7 @@ def build_retrieve_subscription_request(reference, options) xml.target! end - def build_validate_pinless_debit_request(creditcard,options) + def build_validate_pinless_debit_request(creditcard, options) xml = Builder::XmlMarkup.new :indent => 2 add_creditcard(xml, creditcard) add_validate_pinless_debit_service(xml) @@ -401,7 +410,7 @@ def add_business_rules_data(xml, payment_method, options) end end - def extract_option prioritized_options, option_name + def extract_option(prioritized_options, option_name) options_matching_key = prioritized_options.detect do |options| options.has_key? option_name end @@ -423,9 +432,9 @@ def add_line_item_data(xml, options) def add_merchant_data(xml, options) xml.tag! 'merchantID', @options[:login] xml.tag! 'merchantReferenceCode', options[:order_id] || generate_unique_id - xml.tag! 'clientLibrary' ,'Ruby Active Merchant' + xml.tag! 'clientLibrary', 'Ruby Active Merchant' xml.tag! 'clientLibraryVersion', VERSION - xml.tag! 'clientEnvironment' , RUBY_PLATFORM + xml.tag! 'clientEnvironment', RUBY_PLATFORM end def add_purchase_data(xml, money = 0, include_grand_total = false, options={}) @@ -460,12 +469,14 @@ def add_creditcard(xml, creditcard) xml.tag! 'accountNumber', creditcard.number xml.tag! 'expirationMonth', format(creditcard.month, :two_digits) xml.tag! 'expirationYear', format(creditcard.year, :four_digits) - xml.tag!('cvNumber', creditcard.verification_value) unless (@options[:ignore_cvv] || creditcard.verification_value.blank? ) + xml.tag!('cvNumber', creditcard.verification_value) unless @options[:ignore_cvv] || creditcard.verification_value.blank? xml.tag! 'cardType', @@credit_card_codes[card_brand(creditcard).to_sym] end end def add_decision_manager_fields(xml, options) + return unless options[:decision_manager_enabled] + xml.tag! 'decisionManager' do xml.tag! 'enabled', options[:decision_manager_enabled] if options[:decision_manager_enabled] xml.tag! 'profile', options[:decision_manager_profile] if options[:decision_manager_profile] @@ -473,6 +484,8 @@ def add_decision_manager_fields(xml, options) end def add_mdd_fields(xml, options) + return unless options.keys.any? { |key| key.to_s.start_with?('mdd_field') } + xml.tag! 'merchantDefinedData' do (1..100).each do |each| key = "mdd_field_#{each}".to_sym @@ -498,7 +511,7 @@ def add_tax_service(xml) def add_auth_service(xml, payment_method, options) if network_tokenization?(payment_method) - add_network_tokenization(xml, payment_method, options) + add_auth_network_tokenization(xml, payment_method, options) else xml.tag! 'ccAuthService', {'run' => 'true'} end @@ -508,35 +521,37 @@ def network_tokenization?(payment_method) payment_method.is_a?(NetworkTokenizationCreditCard) end - def add_network_tokenization(xml, payment_method, options) + def add_auth_network_tokenization(xml, payment_method, options) return unless network_tokenization?(payment_method) case card_brand(payment_method).to_sym when :visa xml.tag! 'ccAuthService', {'run' => 'true'} do - xml.tag!("cavv", payment_method.payment_cryptogram) - xml.tag!("commerceIndicator", "vbv") - xml.tag!("xid", payment_method.payment_cryptogram) + xml.tag!('cavv', payment_method.payment_cryptogram) + xml.tag!('commerceIndicator', 'vbv') + xml.tag!('xid', payment_method.payment_cryptogram) end when :mastercard xml.tag! 'ucaf' do - xml.tag!("authenticationData", payment_method.payment_cryptogram) - xml.tag!("collectionIndicator", "2") + xml.tag!('authenticationData', payment_method.payment_cryptogram) + xml.tag!('collectionIndicator', '2') end xml.tag! 'ccAuthService', {'run' => 'true'} do - xml.tag!("commerceIndicator", "spa") + xml.tag!('commerceIndicator', 'spa') end when :american_express cryptogram = Base64.decode64(payment_method.payment_cryptogram) xml.tag! 'ccAuthService', {'run' => 'true'} do - xml.tag!("cavv", Base64.encode64(cryptogram[0...20])) - xml.tag!("commerceIndicator", "aesk") - xml.tag!("xid", Base64.encode64(cryptogram[20...40])) + xml.tag!('cavv', Base64.encode64(cryptogram[0...20])) + xml.tag!('commerceIndicator', 'aesk') + xml.tag!('xid', Base64.encode64(cryptogram[20...40])) end end + end + def add_payment_network_token(xml) xml.tag! 'paymentNetworkToken' do - xml.tag!('transactionType', "1") + xml.tag!('transactionType', '1') end end @@ -602,7 +617,7 @@ def add_subscription(xml, options, reference = nil) xml.tag! 'recurringSubscriptionInfo' do if reference - _, subscription_id, _ = reference.split(";") + subscription_id = reference.split(';')[6] xml.tag! 'subscriptionID', subscription_id end @@ -611,8 +626,8 @@ def add_subscription(xml, options, reference = nil) xml.tag! 'numberOfPayments', options[:subscription][:occurrences] if options[:subscription][:occurrences] xml.tag! 'automaticRenew', options[:subscription][:automatic_renew] if options[:subscription][:automatic_renew] xml.tag! 'frequency', options[:subscription][:frequency] if options[:subscription][:frequency] - xml.tag! 'startDate', options[:subscription][:start_date].strftime("%Y%m%d") if options[:subscription][:start_date] - xml.tag! 'endDate', options[:subscription][:end_date].strftime("%Y%m%d") if options[:subscription][:end_date] + xml.tag! 'startDate', options[:subscription][:start_date].strftime('%Y%m%d') if options[:subscription][:start_date] + xml.tag! 'endDate', options[:subscription][:end_date].strftime('%Y%m%d') if options[:subscription][:end_date] xml.tag! 'approvalRequired', options[:subscription][:approval_required] || false xml.tag! 'event', options[:subscription][:event] if options[:subscription][:event] xml.tag! 'billPayment', options[:subscription][:bill_payment] if options[:subscription][:bill_payment] @@ -621,13 +636,13 @@ def add_subscription(xml, options, reference = nil) def add_creditcard_payment_method(xml) xml.tag! 'subscription' do - xml.tag! 'paymentMethod', "credit card" + xml.tag! 'paymentMethod', 'credit card' end end def add_check_payment_method(xml) xml.tag! 'subscription' do - xml.tag! 'paymentMethod', "check" + xml.tag! 'paymentMethod', 'check' end end @@ -648,34 +663,43 @@ def add_payment_method_or_subscription(xml, money, payment_method_or_reference, end def add_validate_pinless_debit_service(xml) - xml.tag!'pinlessDebitValidateService', {'run' => 'true'} + xml.tag! 'pinlessDebitValidateService', {'run' => 'true'} + end + + def add_threeds_services(xml, options) + xml.tag! 'payerAuthEnrollService', {'run' => 'true'} if options[:payer_auth_enroll_service] + if options[:payer_auth_validate_service] + xml.tag! 'payerAuthValidateService', {'run' => 'true'} do + xml.tag! 'signedPARes', options[:pares] + end + end end def lookup_country_code(country_field) country_code = Country.find(country_field) rescue nil - country_code.code(:alpha2) if country_code + country_code&.code(:alpha2) end # Where we actually build the full SOAP request using builder def build_request(body, options) xml = Builder::XmlMarkup.new :indent => 2 - xml.instruct! - xml.tag! 's:Envelope', {'xmlns:s' => 'http://schemas.xmlsoap.org/soap/envelope/'} do - xml.tag! 's:Header' do - xml.tag! 'wsse:Security', {'s:mustUnderstand' => '1', 'xmlns:wsse' => 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd'} do - xml.tag! 'wsse:UsernameToken' do - xml.tag! 'wsse:Username', @options[:login] - xml.tag! 'wsse:Password', @options[:password], 'Type' => 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText' - end + xml.instruct! + xml.tag! 's:Envelope', {'xmlns:s' => 'http://schemas.xmlsoap.org/soap/envelope/'} do + xml.tag! 's:Header' do + xml.tag! 'wsse:Security', {'s:mustUnderstand' => '1', 'xmlns:wsse' => 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd'} do + xml.tag! 'wsse:UsernameToken' do + xml.tag! 'wsse:Username', @options[:login] + xml.tag! 'wsse:Password', @options[:password], 'Type' => 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText' end end - xml.tag! 's:Body', {'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance', 'xmlns:xsd' => 'http://www.w3.org/2001/XMLSchema'} do - xml.tag! 'requestMessage', {'xmlns' => "urn:schemas-cybersource-com:transaction-data-#{XSD_VERSION}"} do - add_merchant_data(xml, options) - xml << body - end + end + xml.tag! 's:Body', {'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance', 'xmlns:xsd' => 'http://www.w3.org/2001/XMLSchema'} do + xml.tag! 'requestMessage', {'xmlns' => "urn:schemas-cybersource-com:transaction-data-#{XSD_VERSION}"} do + add_merchant_data(xml, options) + xml << body end end + end xml.target! end @@ -683,14 +707,21 @@ def build_request(body, options) # Response object def commit(request, action, amount, options) begin - response = parse(ssl_post(test? ? self.test_url : self.live_url, build_request(request, options))) + raw_response = ssl_post(test? ? self.test_url : self.live_url, build_request(request, options)) rescue ResponseError => e - response = parse(e.response.body) + raw_response = e.response.body end - success = response[:decision] == "ACCEPT" - message = @@response_codes[('r' + response[:reasonCode]).to_sym] rescue response[:message] - authorization = success ? [ options[:order_id], response[:requestID], response[:requestToken], action, amount, options[:currency]].compact.join(";") : nil + begin + response = parse(raw_response) + rescue REXML::ParseException => e + response = { message: e.to_s } + end + + success = response[:decision] == 'ACCEPT' + message = response[:message] + + authorization = success ? authorization_from(response, action, amount, options) : nil Response.new(success, message, response, :test => test?, @@ -705,16 +736,17 @@ def commit(request, action, amount, options) def parse(xml) reply = {} xml = REXML::Document.new(xml) - if root = REXML::XPath.first(xml, "//c:replyMessage") + if root = REXML::XPath.first(xml, '//c:replyMessage') root.elements.to_a.each do |node| - case node.name + case node.expanded_name when 'c:reasonCode' - reply[:message] = reply(node.text) + reply[:reasonCode] = node.text + reply[:message] = reason_message(node.text) else parse_element(reply, node) end end - elsif root = REXML::XPath.first(xml, "//soap:Fault") + elsif root = REXML::XPath.first(xml, '//soap:Fault') parse_element(reply, root) reply[:message] = "#{reply[:faultcode]}: #{reply[:faultstring]}" end @@ -723,17 +755,27 @@ def parse(xml) def parse_element(reply, node) if node.has_elements? - node.elements.each{|e| parse_element(reply, e) } + node.elements.each { |e| parse_element(reply, e) } else if node.parent.name =~ /item/ - parent = node.parent.name + (node.parent.attributes["id"] ? "_" + node.parent.attributes["id"] : '') - reply[(parent + '_' + node.name).to_sym] = node.text - else - reply[node.name.to_sym] = node.text + parent = node.parent.name + parent += '_' + node.parent.attributes['id'] if node.parent.attributes['id'] + parent += '_' end + reply["#{parent}#{node.name}".to_sym] ||= node.text end return reply end + + def reason_message(reason_code) + return if reason_code.blank? + @@response_codes[:"r#{reason_code}"] + end + + def authorization_from(response, action, amount, options) + [options[:order_id], response[:requestID], response[:requestToken], action, amount, + options[:currency], response[:subscriptionID]].join(';') + end end end end diff --git a/lib/active_merchant/billing/gateways/data_cash.rb b/lib/active_merchant/billing/gateways/data_cash.rb index bfc05f71959..def3288babf 100644 --- a/lib/active_merchant/billing/gateways/data_cash.rb +++ b/lib/active_merchant/billing/gateways/data_cash.rb @@ -1,4 +1,4 @@ -require "active_support/core_ext/string/access" +require 'active_support/core_ext/string/access' module ActiveMerchant module Billing @@ -6,7 +6,7 @@ class DataCashGateway < Gateway self.default_currency = 'GBP' self.supported_countries = ['GB'] - self.supported_cardtypes = [ :visa, :master, :american_express, :discover, :diners_club, :jcb, :maestro, :switch, :solo, :laser ] + self.supported_cardtypes = [ :visa, :master, :american_express, :discover, :diners_club, :jcb, :maestro ] self.homepage_url = 'http://www.datacash.com/' self.display_name = 'DataCash' @@ -77,6 +77,16 @@ def refund(money, reference, options = {}) commit(build_transaction_refund_request(money, reference)) end + def supports_scrubbing? + true + end + + def scrub(transcript) + transcript. + gsub(/()\d+(<\/pan>)/i, '\1[FILTERED]\2'). + gsub(/()\d+(<\/cv2>)/i, '\1[FILTERED]\2'). + gsub(/().+(<\/password>)/i, '\1[FILTERED]\2') + end private @@ -132,7 +142,7 @@ def build_purchase_or_authorization_request_with_credit_card_request(type, money def build_purchase_or_authorization_request_with_continuous_authority_reference_request(type, money, authorization, options) parsed_authorization = parse_authorization_string(authorization) - raise ArgumentError, "The continuous authority reference is required for continuous authority transactions" if parsed_authorization[:ca_reference].blank? + raise ArgumentError, 'The continuous authority reference is required for continuous authority transactions' if parsed_authorization[:ca_reference].blank? xml = Builder::XmlMarkup.new :indent => 2 xml.instruct! @@ -168,6 +178,7 @@ def build_transaction_refund_request(money, authorization) unless money.nil? xml.tag! :TxnDetails do xml.tag! :amount, amount(money) + xml.tag! :capturemethod, 'ecomm' end end end @@ -188,6 +199,7 @@ def build_credit_request(money, credit_card, options) xml.tag! :TxnDetails do xml.tag! :merchantreference, format_reference_number(options[:order_id]) xml.tag! :amount, amount(money) + xml.tag! :capturemethod, 'ecomm' end end end @@ -202,23 +214,11 @@ def add_authentication(xml) end def add_credit_card(xml, credit_card, address) - xml.tag! :Card do - # DataCash calls the CC number 'pan' xml.tag! :pan, credit_card.number xml.tag! :expirydate, format_date(credit_card.month, credit_card.year) - # optional values - for Solo etc - if [ 'switch', 'solo' ].include?(card_brand(credit_card).to_s) - - xml.tag! :issuenumber, credit_card.issue_number unless credit_card.issue_number.blank? - - if !credit_card.start_month.blank? && !credit_card.start_year.blank? - xml.tag! :startdate, format_date(credit_card.start_month, credit_card.start_year) - end - end - xml.tag! :Cv2Avs do xml.tag! :cv2, credit_card.verification_value if credit_card.verification_value? if address @@ -237,23 +237,23 @@ def add_credit_card(xml, credit_card, address) # a predefined one xml.tag! :ExtendedPolicy do xml.tag! :cv2_policy, - :notprovided => POLICY_REJECT, - :notchecked => POLICY_REJECT, - :matched => POLICY_ACCEPT, - :notmatched => POLICY_REJECT, - :partialmatch => POLICY_REJECT + :notprovided => POLICY_REJECT, + :notchecked => POLICY_REJECT, + :matched => POLICY_ACCEPT, + :notmatched => POLICY_REJECT, + :partialmatch => POLICY_REJECT xml.tag! :postcode_policy, - :notprovided => POLICY_ACCEPT, - :notchecked => POLICY_ACCEPT, - :matched => POLICY_ACCEPT, - :notmatched => POLICY_REJECT, - :partialmatch => POLICY_ACCEPT + :notprovided => POLICY_ACCEPT, + :notchecked => POLICY_ACCEPT, + :matched => POLICY_ACCEPT, + :notmatched => POLICY_REJECT, + :partialmatch => POLICY_ACCEPT xml.tag! :address_policy, - :notprovided => POLICY_ACCEPT, - :notchecked => POLICY_ACCEPT, - :matched => POLICY_ACCEPT, - :notmatched => POLICY_REJECT, - :partialmatch => POLICY_ACCEPT + :notprovided => POLICY_ACCEPT, + :notchecked => POLICY_ACCEPT, + :matched => POLICY_ACCEPT, + :notmatched => POLICY_REJECT, + :partialmatch => POLICY_ACCEPT end end end @@ -269,14 +269,13 @@ def commit(request) end def format_date(month, year) - "#{format(month,:two_digits)}/#{format(year, :two_digits)}" + "#{format(month, :two_digits)}/#{format(year, :two_digits)}" end def parse(body) - response = {} xml = REXML::Document.new(body) - root = REXML::XPath.first(xml, "//Response") + root = REXML::XPath.first(xml, '//Response') root.elements.to_a.each do |node| parse_element(response, node) @@ -287,14 +286,14 @@ def parse(body) def parse_element(response, node) if node.has_elements? - node.elements.each{|e| parse_element(response, e) } + node.elements.each { |e| parse_element(response, e) } else response[node.name.underscore.to_sym] = node.text end end def format_reference_number(number) - number.to_s.gsub(/[^A-Za-z0-9]/, '').rjust(6, "0").first(30) + number.to_s.gsub(/[^A-Za-z0-9]/, '').rjust(6, '0').first(30) end def parse_authorization_string(authorization) diff --git a/lib/active_merchant/billing/gateways/dibs.rb b/lib/active_merchant/billing/gateways/dibs.rb index da5be718a3e..e3936bc383f 100644 --- a/lib/active_merchant/billing/gateways/dibs.rb +++ b/lib/active_merchant/billing/gateways/dibs.rb @@ -1,15 +1,14 @@ module ActiveMerchant #:nodoc: module Billing #:nodoc: class DibsGateway < Gateway - self.display_name = "DIBS" - self.homepage_url = "http://www.dibspayment.com/" + self.display_name = 'DIBS' + self.homepage_url = 'http://www.dibspayment.com/' - self.live_url = "https://api.dibspayment.com/merchant/v1/JSON/Transaction/" + self.live_url = 'https://api.dibspayment.com/merchant/v1/JSON/Transaction/' - self.supported_countries = ["US", "FI", "NO", "SE", "GB"] - self.default_currency = "USD" + self.supported_countries = ['US', 'FI', 'NO', 'SE', 'GB'] + self.default_currency = 'USD' self.money_format = :cents - self.ssl_version = :TLSv1 self.supported_cardtypes = [:visa, :master, :american_express, :discover] def initialize(options={}) @@ -28,14 +27,13 @@ def authorize(amount, payment_method, options={}) post = {} add_amount(post, amount) add_invoice(post, amount, options) - if (payment_method.respond_to?(:number)) + if payment_method.respond_to?(:number) add_payment_method(post, payment_method, options) commit(:authorize, post) else add_ticket_id(post, payment_method) commit(:authorize_ticket, post) end - end def capture(amount, authorization, options={}) @@ -89,13 +87,13 @@ def scrub(transcript) private - CURRENCY_CODES = Hash.new{|h,k| raise ArgumentError.new("Unsupported currency: #{k}")} - CURRENCY_CODES["USD"] = "840" - CURRENCY_CODES["DKK"] = "208" - CURRENCY_CODES["NOK"] = "578" - CURRENCY_CODES["SEK"] = "752" - CURRENCY_CODES["GBP"] = "826" - CURRENCY_CODES["EUR"] = "978" + CURRENCY_CODES = Hash.new { |h, k| raise ArgumentError.new("Unsupported currency: #{k}") } + CURRENCY_CODES['USD'] = '840' + CURRENCY_CODES['DKK'] = '208' + CURRENCY_CODES['NOK'] = '578' + CURRENCY_CODES['SEK'] = '752' + CURRENCY_CODES['GBP'] = '826' + CURRENCY_CODES['EUR'] = '978' def add_invoice(post, money, options) post[:orderId] = options[:order_id] || generate_unique_id @@ -111,15 +109,10 @@ def add_payment_method(post, payment_method, options) post[:cvc] = payment_method.verification_value if payment_method.verification_value post[:expYear] = format(payment_method.year, :two_digits) post[:expMonth] = payment_method.month - - post[:startMonth] = payment_method.start_month if payment_method.start_month - post[:startYear] = payment_method.start_year if payment_method.start_year - post[:issueNumber] = payment_method.issue_number if payment_method.issue_number - post[:clientIp] = options[:ip] || "127.0.0.1" + post[:clientIp] = options[:ip] || '127.0.0.1' post[:test] = true if test? end - def add_reference(post, authorization) post[:transactionId] = authorization end @@ -129,12 +122,12 @@ def add_amount(post, amount) end ACTIONS = { - authorize: "AuthorizeCard", - authorize_ticket: "AuthorizeTicket", - capture: "CaptureTransaction", - void: "CancelTransaction", - refund: "RefundTransaction", - store: "CreateTicket" + authorize: 'AuthorizeCard', + authorize_ticket: 'AuthorizeTicket', + capture: 'CaptureTransaction', + void: 'CancelTransaction', + refund: 'RefundTransaction', + store: 'CreateTicket' } def commit(action, post) @@ -156,7 +149,7 @@ def commit(action, post) def headers { - "Content-Type" => "application/x-www-form-urlencoded" + 'Content-Type' => 'application/x-www-form-urlencoded' } end @@ -166,7 +159,7 @@ def build_request(post) end def add_hmac(post) - data = post.sort.collect { |key, value| "#{key}=#{value.to_s}" }.join("&") + data = post.sort.collect { |key, value| "#{key}=#{value}" }.join('&') digest = OpenSSL::Digest.new('sha256') key = [@options[:secret_key]].pack('H*') post[:MAC] = OpenSSL::HMAC.hexdigest(digest, key, data) @@ -181,14 +174,14 @@ def parse(body) end def success_from(raw_response) - raw_response["status"] == "ACCEPT" + raw_response['status'] == 'ACCEPT' end def message_from(succeeded, response) if succeeded - "Succeeded" + 'Succeeded' else - response["status"] + ": " + response["declineReason"] || "Unable to read error message" + response['status'] + ': ' + response['declineReason'] || 'Unable to read error message' end end @@ -197,7 +190,7 @@ def authorization_from(request, response) end def unparsable_response(raw_response) - message = "Invalid JSON response received from Dibs. Please contact Dibs if you continue to receive this message." + message = 'Invalid JSON response received from Dibs. Please contact Dibs if you continue to receive this message.' message += " (The raw response returned by the API was #{raw_response.inspect})" return Response.new(false, message) end diff --git a/lib/active_merchant/billing/gateways/digitzs.rb b/lib/active_merchant/billing/gateways/digitzs.rb new file mode 100644 index 00000000000..bbc82d4a2b8 --- /dev/null +++ b/lib/active_merchant/billing/gateways/digitzs.rb @@ -0,0 +1,292 @@ +module ActiveMerchant #:nodoc: + module Billing #:nodoc: + class DigitzsGateway < Gateway + include Empty + + self.test_url = 'https://beta.digitzsapi.com/sandbox' + self.live_url = 'https://beta.digitzsapi.com/v3' + + self.supported_countries = ['US'] + self.default_currency = 'USD' + self.supported_cardtypes = [:visa, :master, :american_express, :discover] + self.money_format = :cents + + self.homepage_url = 'https://digitzs.com' + self.display_name = 'Digitzs' + + def initialize(options={}) + requires!(options, :app_key, :api_key) + super + end + + def purchase(money, payment, options={}) + MultiResponse.run do |r| + r.process { commit('auth/token', app_token_request(options)) } + r.process { commit('payments', purchase_request(money, payment, options), options.merge({ app_token: app_token_from(r) })) } + end + end + + def refund(money, authorization, options={}) + MultiResponse.run do |r| + r.process { commit('auth/token', app_token_request(options)) } + r.process { commit('payments', refund_request(money, authorization, options), options.merge({ app_token: app_token_from(r) })) } + end + end + + def store(payment, options = {}) + MultiResponse.run do |r| + r.process { commit('auth/token', app_token_request(options)) } + options[:app_token] = app_token_from(r) + + if options[:customer_id].present? + customer_id = check_customer_exists(options) + + if customer_id + r.process { add_credit_card_to_customer(payment, options) } + else + r.process { add_customer_with_credit_card(payment, options) } + end + else + r.process { add_customer_with_credit_card(payment, options) } + end + end + end + + def supports_scrubbing? + true + end + + def scrub(transcript) + transcript. + gsub(%r((Authorization: Bearer ).+), '\1[FILTERED]'). + gsub(%r((X-Api-Key: )\w+), '\1[FILTERED]'). + gsub(%r((\"id\\\":\\\").+), '\1[FILTERED]'). + gsub(%r((\"appKey\\\":\\\").+), '\1[FILTERED]'). + gsub(%r((\"appToken\\\":\\\").+), '\1[FILTERED]'). + gsub(%r((\"code\\\":\\\")\d+), '\1[FILTERED]'). + gsub(%r((\"number\\\":\\\")\d+), '\1[FILTERED]') + end + + private + + def new_post + { + data: { + attributes: {} + } + } + end + + def add_split(post, options) + return unless options[:payment_type] == 'card_split' || options[:payment_type] == 'token_split' + + post[:data][:attributes][:split] = { + merchantId: options[:split_merchant_id], + amount: amount(options[:split_amount]) + } + end + + def add_payment(post, payment, options) + if payment.is_a? String + customer_id, token = split_authorization(payment) + post[:data][:attributes][:token] = { + customerId: customer_id, + tokenId: token + } + else + post[:data][:attributes][:card] = { + type: payment.brand, + holder: payment.name, + number: payment.number, + expiry: expdate(payment), + code: payment.verification_value + } + end + end + + def add_transaction(post, money, options) + post[:data][:attributes][:transaction] = { + amount: amount(money), + currency: (options[:currency] || currency(money)), + invoice: options[:order_id] || generate_unique_id + } + end + + def add_address(post, options) + if address = options[:billing_address] || options[:address] + post[:data][:attributes][:billingAddress] = { + line1: address[:address1] || '', + line2: address[:address2] || '', + city: address[:city] || '', + state: address[:state] || '', + zip: address[:zip] || '', + country: address['country'] || 'USA' + } + end + end + + def app_token_request(options) + post = new_post + post[:data][:type] = 'auth' + post[:data][:attributes] = { appKey: @options[:app_key] } + + post + end + + def purchase_request(money, payment, options) + post = new_post + post[:data][:type] = 'payments' + post[:data][:attributes][:merchantId] = options[:merchant_id] + post[:data][:attributes][:paymentType] = determine_payment_type(payment, options) + add_split(post, options) + add_payment(post, payment, options) + add_transaction(post, money, options) + add_address(post, options) + + post + end + + def refund_request(money, authorization, options) + post = new_post + post[:data][:type] = 'payments' + post[:data][:attributes][:merchantId] = options[:merchant_id] + post[:data][:attributes][:paymentType] = 'cardRefund' + post[:data][:attributes][:originalTransaction] = {id: authorization} + add_transaction(post, money, options) + + post + end + + def create_customer_request(payment, options) + post = new_post + post[:data][:type] = 'customers' + post[:data][:attributes] = { + merchantId: options[:merchant_id], + name: payment.name, + externalId: SecureRandom.hex(16) + } + + post + end + + def create_token_request(payment, options) + post = new_post + post[:data][:type] = 'tokens' + post[:data][:attributes] = { + tokenType: 'card', + customerId: options[:customer_id], + label: 'Credit Card', + } + add_payment(post, payment, options) + add_address(post, options) + + post + end + + def check_customer_exists(options = {}) + url = (test? ? test_url : live_url) + response = parse(ssl_get(url + "/customers/#{options[:customer_id]}", headers(options))) + + return response.try(:[], 'data').try(:[], 'customerId') if success_from(response) + return nil + end + + def add_credit_card_to_customer(payment, options = {}) + commit('tokens', create_token_request(payment, options), options) + end + + def add_customer_with_credit_card(payment, options = {}) + customer_response = commit('customers', create_customer_request(payment, options), options) + options[:customer_id] = customer_response.authorization + commit('tokens', create_token_request(payment, options), options) + end + + def parse(body) + JSON.parse(body) + end + + def commit(action, parameters, options={}) + url = (test? ? test_url : live_url) + response = parse(ssl_post(url + "/#{action}", parameters.to_json, headers(options))) + + Response.new( + success_from(response), + message_from(response), + response, + authorization: authorization_from(response), + avs_result: AVSResult.new(code: avs_result_from(response)), + cvv_result: CVVResult.new(cvv_result_from(response)), + test: test?, + error_code: error_code_from(response) + ) + end + + def success_from(response) + response['errors'].nil? && response['message'].nil? + end + + def message_from(response) + return response['message'] if response['message'] + return 'Success' if success_from(response) + response['errors'].map { |error_hash| error_hash['detail'] }.join(', ') + end + + def authorization_from(response) + if customer_id = response.try(:[], 'data').try(:[], 'attributes').try(:[], 'customerId') + "#{customer_id}|#{response.try(:[], "data").try(:[], "id")}" + else + response.try(:[], 'data').try(:[], 'id') + end + end + + def avs_result_from(response) + response.try(:[], 'data').try(:[], 'attributes').try(:[], 'transaction').try(:[], 'avsResult') + end + + def cvv_result_from(response) + response.try(:[], 'data').try(:[], 'attributes').try(:[], 'transaction').try(:[], 'codeResult') + end + + def app_token_from(response) + response.params.try(:[], 'data').try(:[], 'attributes').try(:[], 'appToken') + end + + def headers(options) + headers = { + 'Content-Type' => 'application/json', + 'x-api-key' => @options[:api_key] + } + + headers['Authorization'] = "Bearer #{options[:app_token]}" if options[:app_token] + headers + end + + def error_code_from(response) + unless success_from(response) + response['errors'].nil? ? response['message'] : response['errors'].map { |error_hash| error_hash['code'] }.join(', ') + end + end + + def split_authorization(authorization) + customer_id, token = authorization.split('|') + [customer_id, token] + end + + def determine_payment_type(payment, options) + return 'cardSplit' if options[:payment_type] == 'card_split' + return 'tokenSplit' if options[:payment_type] == 'token_split' + return 'token' if payment.is_a? String + 'card' + end + + def handle_response(response) + case response.code.to_i + when 200..499 + response.body + else + raise ResponseError.new(response) + end + end + end + end +end diff --git a/lib/active_merchant/billing/gateways/ebanx.rb b/lib/active_merchant/billing/gateways/ebanx.rb new file mode 100644 index 00000000000..b7d1dc15171 --- /dev/null +++ b/lib/active_merchant/billing/gateways/ebanx.rb @@ -0,0 +1,296 @@ +module ActiveMerchant #:nodoc: + module Billing #:nodoc: + class EbanxGateway < Gateway + self.test_url = 'https://sandbox.ebanxpay.com/ws/' + self.live_url = 'https://api.ebanxpay.com/ws/' + + self.supported_countries = ['BR', 'MX', 'CO', 'CL', 'AR'] + self.default_currency = 'USD' + self.supported_cardtypes = [:visa, :master, :american_express, :discover, :diners_club] + + self.homepage_url = 'http://www.ebanx.com/' + self.display_name = 'EBANX' + + CARD_BRAND = { + visa: 'visa', + master: 'master_card', + american_express: 'amex', + discover: 'discover', + diners_club: 'diners' + } + + URL_MAP = { + purchase: 'direct', + authorize: 'direct', + capture: 'capture', + refund: 'refund', + void: 'cancel', + store: 'token' + } + + HTTP_METHOD = { + purchase: :post, + authorize: :post, + capture: :get, + refund: :post, + void: :get, + store: :post + } + + def initialize(options={}) + requires!(options, :integration_key) + super + end + + def purchase(money, payment, options={}) + post = { payment: {} } + add_integration_key(post) + add_operation(post) + add_invoice(post, money, options) + add_customer_data(post, payment, options) + add_card_or_token(post, payment) + add_address(post, options) + add_customer_responsible_person(post, payment, options) + + commit(:purchase, post) + end + + def authorize(money, payment, options={}) + post = { payment: {} } + add_integration_key(post) + add_operation(post) + add_invoice(post, money, options) + add_customer_data(post, payment, options) + add_card_or_token(post, payment) + add_address(post, options) + add_customer_responsible_person(post, payment, options) + post[:payment][:creditcard][:auto_capture] = false + + commit(:authorize, post) + end + + def capture(money, authorization, options={}) + post = {} + add_integration_key(post) + post[:hash] = authorization + post[:amount] = amount(money) + + commit(:capture, post) + end + + def refund(money, authorization, options={}) + post = {} + add_integration_key(post) + add_operation(post) + add_authorization(post, authorization) + post[:amount] = amount(money) + post[:description] = options[:description] + + commit(:refund, post) + end + + def void(authorization, options={}) + post = {} + add_integration_key(post) + add_authorization(post, authorization) + + commit(:void, post) + end + + def store(credit_card, options={}) + post = {} + add_integration_key(post) + add_payment_details(post, credit_card) + post[:country] = customer_country(options) + + commit(:store, post) + end + + def verify(credit_card, options={}) + MultiResponse.run(:use_first_response) do |r| + r.process { authorize(100, credit_card, options) } + r.process(:ignore_result) { void(r.authorization, options) } + end + end + + def supports_scrubbing? + true + end + + def scrub(transcript) + transcript. + gsub(/(integration_key\\?":\\?")(\d*)/, '\1[FILTERED]'). + gsub(/(card_number\\?":\\?")(\d*)/, '\1[FILTERED]'). + gsub(/(card_cvv\\?":\\?")(\d*)/, '\1[FILTERED]') + end + + private + + def add_integration_key(post) + post[:integration_key] = @options[:integration_key].to_s + end + + def add_operation(post) + post[:operation] = 'request' + end + + def add_authorization(post, authorization) + post[:hash] = authorization + end + + def add_customer_data(post, payment, options) + post[:payment][:name] = customer_name(payment, options) + post[:payment][:email] = options[:email] || 'unspecified@example.com' + post[:payment][:document] = options[:document] + post[:payment][:birth_date] = options[:birth_date] if options[:birth_date] + end + + def add_customer_responsible_person(post, payment, options) + post[:payment][:person_type] = options[:person_type] if options[:person_type] + if options[:person_type]&.casecmp('business')&.zero? + post[:payment][:responsible] = {} + post[:payment][:responsible][:name] = options[:responsible_name] if options[:responsible_name] + post[:payment][:responsible][:document] = options[:responsible_document] if options[:responsible_document] + post[:payment][:responsible][:birth_date] = options[:responsible_birth_date] if options[:responsible_birth_date] + end + end + + def add_address(post, options) + if address = options[:billing_address] || options[:address] + post[:payment][:address] = address[:address1].split[1..-1].join(' ') if address[:address1] + post[:payment][:street_number] = address[:address1].split.first if address[:address1] + post[:payment][:city] = address[:city] + post[:payment][:state] = address[:state] + post[:payment][:zipcode] = address[:zip] + post[:payment][:country] = address[:country].downcase + post[:payment][:phone_number] = address[:phone] + end + end + + def add_invoice(post, money, options) + post[:payment][:amount_total] = amount(money) + post[:payment][:currency_code] = (options[:currency] || currency(money)) + post[:payment][:merchant_payment_code] = options[:order_id] + post[:payment][:instalments] = options[:instalments] || 1 + end + + def add_card_or_token(post, payment) + if payment.is_a?(String) + payment, brand = payment.split('|') + end + post[:payment][:payment_type_code] = payment.is_a?(String) ? brand : CARD_BRAND[payment.brand.to_sym] + post[:payment][:creditcard] = payment_details(payment) + end + + def add_payment_details(post, payment) + post[:payment_type_code] = CARD_BRAND[payment.brand.to_sym] + post[:creditcard] = payment_details(payment) + end + + def payment_details(payment) + if payment.is_a?(String) + { token: payment } + else + { + card_number: payment.number, + card_name: payment.name, + card_due_date: "#{payment.month}/#{payment.year}", + card_cvv: payment.verification_value + } + end + end + + def parse(body) + JSON.parse(body) + end + + def commit(action, parameters) + url = url_for((test? ? test_url : live_url), action, parameters) + response = parse(ssl_request(HTTP_METHOD[action], url, post_data(action, parameters), {})) + + success = success_from(action, response) + + Response.new( + success, + message_from(response), + response, + authorization: authorization_from(action, parameters, response), + test: test?, + error_code: error_code_from(response, success) + ) + end + + def success_from(action, response) + if [:purchase, :capture, :refund].include?(action) + response.try(:[], 'payment').try(:[], 'status') == 'CO' + elsif action == :authorize + response.try(:[], 'payment').try(:[], 'status') == 'PE' + elsif action == :void + response.try(:[], 'payment').try(:[], 'status') == 'CA' + elsif action == :store + response.try(:[], 'status') == 'SUCCESS' + else + false + end + end + + def message_from(response) + return response['status_message'] if response['status'] == 'ERROR' + response.try(:[], 'payment').try(:[], 'transaction_status').try(:[], 'description') + end + + def authorization_from(action, parameters, response) + if action == :store + "#{response.try(:[], "token")}|#{CARD_BRAND[parameters[:payment_type_code].to_sym]}" + else + response.try(:[], 'payment').try(:[], 'hash') + end + end + + def post_data(action, parameters = {}) + return nil if requires_http_get(action) + return convert_to_url_form_encoded(parameters) if action == :refund + "request_body=#{parameters.to_json}" + end + + def url_for(hostname, action, parameters) + return "#{hostname}#{URL_MAP[action]}?#{convert_to_url_form_encoded(parameters)}" if requires_http_get(action) + "#{hostname}#{URL_MAP[action]}" + end + + def requires_http_get(action) + return true if [:capture, :void].include?(action) + false + end + + def convert_to_url_form_encoded(parameters) + parameters.map do |key, value| + next if value != false && value.blank? + "#{key}=#{value}" + end.compact.join('&') + end + + def error_code_from(response, success) + unless success + return response['status_code'] if response['status'] == 'ERROR' + response.try(:[], 'payment').try(:[], 'transaction_status').try(:[], 'code') + end + end + + def customer_country(options) + if country = options[:country] || (options[:billing_address][:country] if options[:billing_address]) + country.downcase + end + end + + def customer_name(payment, options) + address_name = options[:billing_address][:name] if options[:billing_address] && options[:billing_address][:name] + if payment.is_a?(String) + address_name || 'Not Provided' + else + payment.name + end + end + end + end +end diff --git a/lib/active_merchant/billing/gateways/efsnet.rb b/lib/active_merchant/billing/gateways/efsnet.rb index 6051db0efb2..ad16cfbf349 100644 --- a/lib/active_merchant/billing/gateways/efsnet.rb +++ b/lib/active_merchant/billing/gateways/efsnet.rb @@ -2,7 +2,6 @@ module ActiveMerchant #:nodoc: module Billing #:nodoc: - class EfsnetGateway < Gateway self.supported_countries = ['US'] self.supported_cardtypes = [:visa, :master, :american_express, :discover] @@ -54,7 +53,7 @@ def refund(money, reference, options = {}) def void(identification, options = {}) requires!(options, :order_id) - original_transaction_id, _ = identification.split(";") + original_transaction_id, _ = identification.split(';') commit(:void_transaction, {:reference_number => format_reference_number(options[:order_id]), :transaction_id => original_transaction_id}) end @@ -77,7 +76,7 @@ def system_check private def build_refund_or_settle_request(money, identification, options = {}) - original_transaction_id, original_transaction_amount = identification.split(";") + original_transaction_id, original_transaction_amount = identification.split(';') requires!(options, :order_id) @@ -100,16 +99,16 @@ def build_credit_card_request(money, creditcard, options = {}) :client_ip_address => options[:ip] } - add_creditcard(post,creditcard) - add_address(post,options) + add_creditcard(post, creditcard) + add_address(post, options) post end def format_reference_number(number) - number.to_s.slice(0,12) + number.to_s.slice(0, 12) end - def add_address(post,options) + def add_address(post, options) if address = options[:billing_address] || options[:address] if address[:address2] post[:billing_address] = address[:address1].to_s << ' ' << address[:address2].to_s @@ -139,11 +138,10 @@ def add_creditcard(post, creditcard) post[:billing_name] = creditcard.name if creditcard.name post[:account_number] = creditcard.number post[:card_verification_value] = creditcard.verification_value if creditcard.verification_value? - post[:expiration_month] = sprintf("%.2i", creditcard.month) - post[:expiration_year] = sprintf("%.4i", creditcard.year)[-2..-1] + post[:expiration_month] = sprintf('%.2i', creditcard.month) + post[:expiration_year] = sprintf('%.4i', creditcard.year)[-2..-1] end - def commit(action, parameters) response = parse(ssl_post(test? ? self.test_url : self.live_url, post_data(action, parameters), 'Content-Type' => 'text/xml')) @@ -169,9 +167,7 @@ def parse(xml) xml = REXML::Document.new(xml) xml.elements.each('//Reply//TransactionReply/*') do |node| - response[node.name.underscore.to_sym] = normalize(node.text) - end unless xml.root.nil? response @@ -179,10 +175,10 @@ def parse(xml) def post_data(action, parameters = {}) xml = REXML::Document.new("") - root = xml.add_element("Request") - root.attributes["StoreID"] = options[:login] - root.attributes["StoreKey"] = options[:password] - root.attributes["ApplicationID"] = 'ot 1.0' + root = xml.add_element('Request') + root.attributes['StoreID'] = options[:login] + root.attributes['StoreKey'] = options[:password] + root.attributes['ApplicationID'] = 'ot 1.0' transaction = root.add_element(action.to_s.camelize) actions[action].each do |key| @@ -194,7 +190,7 @@ def post_data(action, parameters = {}) def message_from(message) return 'Unspecified error' if message.blank? - message.gsub(/[^\w]/, ' ').split.join(" ").capitalize + message.gsub(/[^\w]/, ' ').split.join(' ').capitalize end def actions @@ -204,15 +200,15 @@ def actions CREDIT_CARD_FIELDS = %w(AuthorizationNumber ClientIpAddress BillingAddress BillingCity BillingState BillingPostalCode BillingCountry BillingName CardVerificationValue ExpirationMonth ExpirationYear ReferenceNumber TransactionAmount AccountNumber ) ACTIONS = { - :credit_card_authorize => CREDIT_CARD_FIELDS, - :credit_card_charge => CREDIT_CARD_FIELDS, - :credit_card_voice_authorize => CREDIT_CARD_FIELDS, - :credit_card_capture => CREDIT_CARD_FIELDS, - :credit_card_credit => CREDIT_CARD_FIELDS + ["OriginalTransactionAmount"], - :credit_card_refund => %w(ReferenceNumber TransactionAmount OriginalTransactionAmount OriginalTransactionID ClientIpAddress), - :void_transaction => %w(ReferenceNumber TransactionID), - :credit_card_settle => %w(ReferenceNumber TransactionAmount OriginalTransactionAmount OriginalTransactionID ClientIpAddress), - :system_check => %w(SystemCheck), + :credit_card_authorize => CREDIT_CARD_FIELDS, + :credit_card_charge => CREDIT_CARD_FIELDS, + :credit_card_voice_authorize => CREDIT_CARD_FIELDS, + :credit_card_capture => CREDIT_CARD_FIELDS, + :credit_card_credit => CREDIT_CARD_FIELDS + ['OriginalTransactionAmount'], + :credit_card_refund => %w(ReferenceNumber TransactionAmount OriginalTransactionAmount OriginalTransactionID ClientIpAddress), + :void_transaction => %w(ReferenceNumber TransactionID), + :credit_card_settle => %w(ReferenceNumber TransactionAmount OriginalTransactionAmount OriginalTransactionID ClientIpAddress), + :system_check => %w(SystemCheck), } end end diff --git a/lib/active_merchant/billing/gateways/elavon.rb b/lib/active_merchant/billing/gateways/elavon.rb index 655e8b58de6..ab234228e87 100644 --- a/lib/active_merchant/billing/gateways/elavon.rb +++ b/lib/active_merchant/billing/gateways/elavon.rb @@ -2,43 +2,16 @@ module ActiveMerchant #:nodoc: module Billing #:nodoc: - # = Elavon Virtual Merchant Gateway - # - # == Example use: - # - # gateway = ActiveMerchant::Billing::ElavonGateway.new( - # :login => "my_virtual_merchant_id", - # :password => "my_virtual_merchant_pin", - # :user => "my_virtual_merchant_user_id" # optional - # ) - # - # # set up credit card obj as in main ActiveMerchant example - # creditcard = ActiveMerchant::Billing::CreditCard.new( - # :type => 'visa', - # :number => '41111111111111111', - # :month => 10, - # :year => 2011, - # :first_name => 'Bob', - # :last_name => 'Bobsen' - # ) - # - # # run request - # response = gateway.purchase(1000, creditcard) # authorize and capture 10 USD - # - # puts response.success? # Check whether the transaction was successful - # puts response.message # Retrieve the message returned by Elavon - # puts response.authorization # Retrieve the unique transaction ID returned by Elavon - # class ElavonGateway < Gateway include Empty class_attribute :test_url, :live_url, :delimiter, :actions - self.test_url = 'https://demo.myvirtualmerchant.com/VirtualMerchantDemo/process.do' - self.live_url = 'https://www.myvirtualmerchant.com/VirtualMerchant/process.do' + self.test_url = 'https://api.demo.convergepay.com/VirtualMerchantDemo/process.do' + self.live_url = 'https://api.convergepay.com/VirtualMerchant/process.do' self.display_name = 'Elavon MyVirtualMerchant' - self.supported_countries = %w(US CA PR DE IE NO PL LU BE NL) + self.supported_countries = %w(US CA PR DE IE NO PL LU BE NL MX) self.supported_cardtypes = [:visa, :master, :american_express, :discover] self.homepage_url = 'http://www.elavon.com/' @@ -55,23 +28,11 @@ class ElavonGateway < Gateway :update => 'CCUPDATETOKEN', } - # Initialize the Gateway - # - # The gateway requires that a valid login and password be passed - # in the +options+ hash. - # - # ==== Options - # - # * :login -- Merchant ID - # * :password -- PIN - # * :user -- Specify a subuser of the account (optional) - # * :test => +true+ or +false+ -- Force test transactions def initialize(options = {}) requires!(options, :login, :password) super end - # Make a purchase def purchase(money, payment_method, options = {}) form = {} add_salestax(form, options) @@ -85,16 +46,9 @@ def purchase(money, payment_method, options = {}) add_customer_data(form, options) add_test_mode(form, options) add_ip(form, options) - commit(:purchase, money, form) + commit(:purchase, money, form, options) end - # Authorize a credit card for a given amount. - # - # ==== Parameters - # * money - The amount to be authorized as an Integer value in cents. - # * credit_card - The CreditCard details for the transaction. - # * options - # * :billing_address - The billing address for the cardholder. def authorize(money, creditcard, options = {}) form = {} add_salestax(form, options) @@ -104,16 +58,9 @@ def authorize(money, creditcard, options = {}) add_customer_data(form, options) add_test_mode(form, options) add_ip(form, options) - commit(:authorize, money, form) + commit(:authorize, money, form, options) end - # Capture authorized funds from a credit card. - # - # ==== Parameters - # * money - The amount to be captured as an Integer value in cents. - # * authorization - The approval code returned from the initial authorization. - # * options - # * :credit_card - The CreditCard details from the initial transaction (required). def capture(money, authorization, options = {}) form = {} if options[:credit_card] @@ -130,48 +77,26 @@ def capture(money, authorization, options = {}) add_partial_shipment_flag(form, options) add_test_mode(form, options) end - commit(action, money, form) - end - - # Refund a transaction. - # - # This transaction indicates to the gateway that - # money should flow from the merchant to the customer. - # - # ==== Parameters - # - # * money -- The amount to be credited to the customer as an Integer value in cents. - # * identification -- The ID of the original transaction against which the refund is being issued. - # * options -- A hash of parameters. + commit(action, money, form, options) + end + def refund(money, identification, options = {}) form = {} add_txn_id(form, identification) add_test_mode(form, options) - commit(:refund, money, form) + commit(:refund, money, form, options) end - # Void a previous transaction - # - # ==== Parameters - # - # * authorization - The authorization returned from the previous request. def void(identification, options = {}) form = {} add_txn_id(form, identification) add_test_mode(form, options) - commit(:void, nil, form) + commit(:void, nil, form, options) end - # Make a credit to a card. Use the refund method if you'd like to credit using - # previous transaction - # - # ==== Parameters - # * money - The amount to be credited as an Integer value in cents. - # * creditcard - The credit card to be credited. - # * options def credit(money, creditcard, options = {}) if creditcard.is_a?(String) - raise ArgumentError, "Reference credits are not supported. Please supply the original credit card or use the #refund method." + raise ArgumentError, 'Reference credits are not supported. Please supply the original credit card or use the #refund method.' end form = {} @@ -180,7 +105,7 @@ def credit(money, creditcard, options = {}) add_address(form, options) add_customer_data(form, options) add_test_mode(form, options) - commit(:credit, money, form) + commit(:credit, money, form, options) end def verify(credit_card, options = {}) @@ -198,7 +123,7 @@ def store(creditcard, options = {}) add_test_mode(form, options) add_verification(form, options) form[:add_token] = 'Y' - commit(:store, nil, form) + commit(:store, nil, form, options) end def update(token, creditcard, options = {}) @@ -208,12 +133,23 @@ def update(token, creditcard, options = {}) add_address(form, options) add_customer_data(form, options) add_test_mode(form, options) - commit(:update, nil, form) + commit(:update, nil, form, options) + end + + def supports_scrubbing? + true + end + + def scrub(transcript) + transcript. + gsub(%r((&?ssl_pin=)[^&]*)i, '\1[FILTERED]'). + gsub(%r((&?ssl_card_number=)[^&\\n\r\n]*)i, '\1[FILTERED]'). + gsub(%r((&?ssl_cvv2cvc2=)[^&]*)i, '\1[FILTERED]') end private - def add_invoice(form,options) + def add_invoice(form, options) form[:invoice_number] = truncate((options[:order_id] || options[:invoice]), 10) form[:description] = truncate(options[:description], 255) end @@ -255,6 +191,9 @@ def add_customer_data(form, options) form[:email] = truncate(options[:email], 100) unless empty?(options[:email]) form[:customer_code] = truncate(options[:customer], 10) unless empty?(options[:customer]) form[:customer_number] = options[:customer_number] unless empty?(options[:customer_number]) + options[:custom_fields]&.each do |key, value| + form[key.to_s] = value + end end def add_salestax(form, options) @@ -313,11 +252,11 @@ def success?(response) !response.has_key?('errorMessage') end - def commit(action, money, parameters) + def commit(action, money, parameters, options) parameters[:amount] = amount(money) parameters[:transaction_type] = self.actions[action] - response = parse( ssl_post(test? ? self.test_url : self.live_url, post_data(parameters)) ) + response = parse(ssl_post(test? ? self.test_url : self.live_url, post_data(parameters, options))) Response.new(response['result'] == '0', message_from(response), response, :test => @options[:test] || test?, @@ -327,21 +266,22 @@ def commit(action, money, parameters) ) end - def post_data(parameters) + def post_data(parameters, options) result = preamble result.merge!(parameters) - result.collect { |key, value| post_data_string(key, value) }.join("&") + result.collect { |key, value| post_data_string(key, value, options) }.join('&') end - def post_data_string(key, value) - if custom_field?(key) + def post_data_string(key, value, options) + if custom_field?(key, options) "#{key}=#{CGI.escape(value.to_s)}" else "ssl_#{key}=#{CGI.escape(value.to_s)}" end end - def custom_field?(field_name) + def custom_field?(field_name, options) + return true if options[:custom_fields]&.include?(field_name.to_sym) field_name == :customer_number end @@ -359,10 +299,10 @@ def preamble def parse(msg) resp = {} - msg.split(self.delimiter).collect{|li| - key, value = li.split("=") - resp[key.to_s.strip.gsub(/^ssl_/, '')] = value.to_s.strip - } + msg.split(self.delimiter).collect { |li| + key, value = li.split('=') + resp[key.to_s.strip.gsub(/^ssl_/, '')] = value.to_s.strip + } resp end diff --git a/lib/active_merchant/billing/gateways/element.rb b/lib/active_merchant/billing/gateways/element.rb index 9543fec46bd..a82803884ba 100644 --- a/lib/active_merchant/billing/gateways/element.rb +++ b/lib/active_merchant/billing/gateways/element.rb @@ -15,7 +15,7 @@ class ElementGateway < Gateway self.display_name = 'Element' SERVICE_TEST_URL = 'https://certservices.elementexpress.com/express.asmx' - SERVICE_LIVE_URL = 'https://service.elementexpress.com/express.asmx' + SERVICE_LIVE_URL = 'https://services.elementexpress.com/express.asmx' def initialize(options={}) requires!(options, :account_id, :account_token, :application_id, :acceptor_id, :application_name, :application_version) @@ -23,10 +23,10 @@ def initialize(options={}) end def purchase(money, payment, options={}) - action = payment.is_a?(Check) ? "CheckSale" : "CreditCardSale" + action = payment.is_a?(Check) ? 'CheckSale' : 'CreditCardSale' request = build_soap_request do |xml| - xml.send(action, xmlns: "https://transaction.elementexpress.com") do + xml.send(action, xmlns: 'https://transaction.elementexpress.com') do add_credentials(xml) add_payment_method(xml, payment) add_transaction(xml, money, options) @@ -40,7 +40,7 @@ def purchase(money, payment, options={}) def authorize(money, payment, options={}) request = build_soap_request do |xml| - xml.CreditCardAuthorization(xmlns: "https://transaction.elementexpress.com") do + xml.CreditCardAuthorization(xmlns: 'https://transaction.elementexpress.com') do add_credentials(xml) add_payment_method(xml, payment) add_transaction(xml, money, options) @@ -54,10 +54,10 @@ def authorize(money, payment, options={}) def capture(money, authorization, options={}) trans_id, _ = split_authorization(authorization) - options.merge!({trans_id: trans_id}) + options[:trans_id] = trans_id request = build_soap_request do |xml| - xml.CreditCardAuthorizationCompletion(xmlns: "https://transaction.elementexpress.com") do + xml.CreditCardAuthorizationCompletion(xmlns: 'https://transaction.elementexpress.com') do add_credentials(xml) add_transaction(xml, money, options) add_terminal(xml, options) @@ -69,10 +69,10 @@ def capture(money, authorization, options={}) def refund(money, authorization, options={}) trans_id, _ = split_authorization(authorization) - options.merge!({trans_id: trans_id}) + options[:trans_id] = trans_id request = build_soap_request do |xml| - xml.CreditCardReturn(xmlns: "https://transaction.elementexpress.com") do + xml.CreditCardReturn(xmlns: 'https://transaction.elementexpress.com') do add_credentials(xml) add_transaction(xml, money, options) add_terminal(xml, options) @@ -84,10 +84,10 @@ def refund(money, authorization, options={}) def void(authorization, options={}) trans_id, trans_amount = split_authorization(authorization) - options.merge!({trans_id: trans_id, trans_amount: trans_amount, reversal_type: "Full"}) + options.merge!({trans_id: trans_id, trans_amount: trans_amount, reversal_type: 'Full'}) request = build_soap_request do |xml| - xml.CreditCardReversal(xmlns: "https://transaction.elementexpress.com") do + xml.CreditCardReversal(xmlns: 'https://transaction.elementexpress.com') do add_credentials(xml) add_transaction(xml, trans_amount, options) add_terminal(xml, options) @@ -99,7 +99,7 @@ def void(authorization, options={}) def store(payment, options = {}) request = build_soap_request do |xml| - xml.PaymentAccountCreate(xmlns: "https://services.elementexpress.com") do + xml.PaymentAccountCreate(xmlns: 'https://services.elementexpress.com') do add_credentials(xml) add_payment_method(xml, payment) add_payment_account(xml, payment, options[:payment_account_reference_number] || SecureRandom.hex(20)) @@ -165,8 +165,8 @@ def add_payment_account(xml, payment, payment_account_reference_number) def add_payment_account_id(xml, payment) xml.extendedParameters do xml.ExtendedParameters do - xml.Key "PaymentAccount" - xml.Value("xsi:type" => "PaymentAccount") do + xml.Key 'PaymentAccount' + xml.Value('xsi:type' => 'PaymentAccount') do xml.PaymentAccountID payment end end @@ -178,21 +178,21 @@ def add_transaction(xml, money, options = {}) xml.ReversalType options[:reversal_type] if options[:reversal_type] xml.TransactionID options[:trans_id] if options[:trans_id] xml.TransactionAmount amount(money.to_i) if money - xml.MarketCode "Default" if money + xml.MarketCode 'Default' if money xml.ReferenceNumber options[:order_id] || SecureRandom.hex(20) end end def add_terminal(xml, options) xml.terminal do - xml.TerminalID "01" - xml.CardPresentCode "UseDefault" - xml.CardholderPresentCode "UseDefault" - xml.CardInputCode "UseDefault" - xml.CVVPresenceCode "UseDefault" - xml.TerminalCapabilityCode "UseDefault" - xml.TerminalEnvironmentCode "UseDefault" - xml.MotoECICode "NonAuthenticatedSecureECommerceTransaction" + xml.TerminalID '01' + xml.CardPresentCode 'UseDefault' + xml.CardholderPresentCode 'UseDefault' + xml.CardInputCode 'UseDefault' + xml.CVVPresenceCode 'UseDefault' + xml.TerminalCapabilityCode 'UseDefault' + xml.TerminalEnvironmentCode 'UseDefault' + xml.MotoECICode 'NonAuthenticatedSecureECommerceTransaction' end end @@ -201,7 +201,7 @@ def add_credit_card(xml, payment) xml.CardNumber payment.number xml.ExpirationMonth format(payment.month, :two_digits) xml.ExpirationYear format(payment.year, :two_digits) - xml.CardholderName payment.first_name + " " + payment.last_name + xml.CardholderName payment.first_name + ' ' + payment.last_name xml.CVV payment.verification_value end end @@ -244,14 +244,14 @@ def parse(xml) doc = Nokogiri::XML(xml) doc.remove_namespaces! - root = doc.root.xpath("//response/*") + root = doc.root.xpath('//response/*') if root.empty? - root = doc.root.xpath("//Response/*") + root = doc.root.xpath('//Response/*') end root.each do |node| - if (node.elements.empty?) + if node.elements.empty? response[node.name.downcase] = node.text else node_name = node.name.downcase @@ -281,31 +281,31 @@ def commit(action, xml, amount) end def authorization_from(action, response, amount) - if action == "PaymentAccountCreate" - response["paymentaccount"]["paymentaccountid"] + if action == 'PaymentAccountCreate' + response['paymentaccount']['paymentaccountid'] else "#{response['transaction']['transactionid']}|#{amount}" if response['transaction'] end end def success_from(response) - response["expressresponsecode"] == "0" + response['expressresponsecode'] == '0' end def message_from(response) - response["expressresponsemessage"] + response['expressresponsemessage'] end def avs_from(response) - AVSResult.new(code: response["card"]["avsresponsecode"]) if response["card"] + AVSResult.new(code: response['card']['avsresponsecode']) if response['card'] end def cvv_from(response) - CVVResult.new(response["card"]["cvvresponsecode"]) if response["card"] + CVVResult.new(response['card']['cvvresponsecode']) if response['card'] end def split_authorization(authorization) - authorization.split("|") + authorization.split('|') end def build_soap_request @@ -327,28 +327,28 @@ def payment_account_type(payment) if payment.is_a?(Check) payment_account_type = payment.account_type else - payment_account_type = "CreditCard" + payment_account_type = 'CreditCard' end payment_account_type end def url(action) - if action == "PaymentAccountCreate" - url = (test? ? SERVICE_TEST_URL : SERVICE_LIVE_URL) + if action == 'PaymentAccountCreate' + test? ? SERVICE_TEST_URL : SERVICE_LIVE_URL else - url = (test? ? test_url : live_url) + test? ? test_url : live_url end end def interface(action) - return "transaction" if action != "PaymentAccountCreate" - return "services" if action == "PaymentAccountCreate" + return 'transaction' if action != 'PaymentAccountCreate' + return 'services' if action == 'PaymentAccountCreate' end def headers(action) { - "Content-Type" => "text/xml; charset=utf-8", - "SOAPAction" => "https://#{interface(action)}.elementexpress.com/#{action}" + 'Content-Type' => 'text/xml; charset=utf-8', + 'SOAPAction' => "https://#{interface(action)}.elementexpress.com/#{action}" } end end diff --git a/lib/active_merchant/billing/gateways/epay.rb b/lib/active_merchant/billing/gateways/epay.rb index aab61a11d3c..4f33ae1afe8 100644 --- a/lib/active_merchant/billing/gateways/epay.rb +++ b/lib/active_merchant/billing/gateways/epay.rb @@ -120,7 +120,6 @@ def scrub(transcript) gsub(%r((&?cvc=)\d*(&?)), '\1[FILTERED]\2') end - private def add_amount(post, money, options) @@ -164,16 +163,16 @@ def commit(action, params) if action == :authorize Response.new response['accept'].to_i == 1, - response['errortext'], - response, - :test => test?, - :authorization => response['tid'] + response['errortext'], + response, + :test => test?, + :authorization => response['tid'] else Response.new response['result'] == 'true', - messages(response['epay'], response['pbs']), - response, - :test => test?, - :authorization => params[:transaction] + messages(response['epay'], response['pbs']), + response, + :test => test?, + :authorization => params[:transaction] end end @@ -191,7 +190,7 @@ def soap_post(method, params) def do_authorize(params) headers = {} - headers['Referer'] = (options[:password] || "activemerchant.org") + headers['Referer'] = (options[:password] || 'activemerchant.org') response = raw_ssl_request(:post, live_url + 'auth/default.aspx', authorize_post_data(params), headers) @@ -209,7 +208,7 @@ def do_authorize(params) end result = {} - query.each_pair do |k,v| + query.each_pair do |k, v| result[k] = v.is_a?(Array) && v.size == 1 ? v[0] : v # make values like ['v'] into 'v' end result @@ -244,7 +243,7 @@ def do_void(params) def make_headers(data, soap_call) { 'Content-Type' => 'text/xml; charset=utf-8', - 'Host' => "ssl.ditonlinebetalingssystem.dk", + 'Host' => 'ssl.ditonlinebetalingssystem.dk', 'Content-Length' => data.size.to_s, 'SOAPAction' => self.live_url + 'remote/payment/' + soap_call } @@ -253,17 +252,17 @@ def make_headers(data, soap_call) def xml_builder(params, soap_call) xml = Builder::XmlMarkup.new(:indent => 2) xml.instruct! - xml.tag! 'soap:Envelope', { 'xmlns:xsi' => 'http://schemas.xmlsoap.org/soap/envelope/', - 'xmlns:xsd' => 'http://www.w3.org/2001/XMLSchema', - 'xmlns:soap' => 'http://schemas.xmlsoap.org/soap/envelope/' } do - xml.tag! 'soap:Body' do - xml.tag! soap_call, { 'xmlns' => "#{self.live_url}remote/payment" } do - xml.tag! 'merchantnumber', @options[:login] - xml.tag! 'transactionid', params[:transaction] - xml.tag! 'amount', params[:amount].to_s if soap_call != 'delete' - end + xml.tag! 'soap:Envelope', { 'xmlns:xsi' => 'http://schemas.xmlsoap.org/soap/envelope/', + 'xmlns:xsd' => 'http://www.w3.org/2001/XMLSchema', + 'xmlns:soap' => 'http://schemas.xmlsoap.org/soap/envelope/' } do + xml.tag! 'soap:Body' do + xml.tag! soap_call, { 'xmlns' => "#{self.live_url}remote/payment" } do + xml.tag! 'merchantnumber', @options[:login] + xml.tag! 'transactionid', params[:transaction] + xml.tag! 'amount', params[:amount].to_s if soap_call != 'delete' end end + end xml.target! end @@ -274,12 +273,12 @@ def authorize_post_data(params = {}) params[:declineurl] = live_url + 'auth/default.aspx?decline=1' params[:merchantnumber] = @options[:login] - params.collect { |key, value| "#{key}=#{CGI.escape(value.to_s)}" }.join("&") + params.collect { |key, value| "#{key}=#{CGI.escape(value.to_s)}" }.join('&') end # Limited to 20 digits max def format_order_number(number) - number.to_s.gsub(/[^\w]/, '').rjust(4, "0")[0...20] + number.to_s.gsub(/[^\w]/, '').rjust(4, '0')[0...20] end end end diff --git a/lib/active_merchant/billing/gateways/evo_ca.rb b/lib/active_merchant/billing/gateways/evo_ca.rb index c2f76883ebf..b5f976b7cee 100644 --- a/lib/active_merchant/billing/gateways/evo_ca.rb +++ b/lib/active_merchant/billing/gateways/evo_ca.rb @@ -301,7 +301,7 @@ def post_data(action, parameters = {}) post[:username] = options[:username] post[:password] = options[:password] end - post.merge(parameters).collect { |key, value| "#{key}=#{CGI.escape(value.to_s)}" unless value.nil? }.compact.join("&") + post.merge(parameters).collect { |key, value| "#{key}=#{CGI.escape(value.to_s)}" unless value.nil? }.compact.join('&') end end end diff --git a/lib/active_merchant/billing/gateways/eway.rb b/lib/active_merchant/billing/gateways/eway.rb index 6e31e39b337..04874aac7ba 100644 --- a/lib/active_merchant/billing/gateways/eway.rb +++ b/lib/active_merchant/billing/gateways/eway.rb @@ -64,14 +64,15 @@ def scrub(transcript) end private + def requires_address!(options) - raise ArgumentError.new("Missing eWay required parameters: address or billing_address") unless (options.has_key?(:address) or options.has_key?(:billing_address)) + raise ArgumentError.new('Missing eWay required parameters: address or billing_address') unless options.has_key?(:address) or options.has_key?(:billing_address) end def add_creditcard(post, creditcard) post[:CardNumber] = creditcard.number - post[:CardExpiryMonth] = sprintf("%.2i", creditcard.month) - post[:CardExpiryYear] = sprintf("%.4i", creditcard.year)[-2..-1] + post[:CardExpiryMonth] = sprintf('%.2i', creditcard.month) + post[:CardExpiryYear] = sprintf('%.4i', creditcard.year)[-2..-1] post[:CustomerFirstName] = creditcard.first_name post[:CustomerLastName] = creditcard.last_name post[:CardHoldersName] = creditcard.name @@ -119,7 +120,7 @@ def commit(url, money, parameters) end def success?(response) - response[:ewaytrxnstatus] == "True" + response[:ewaytrxnstatus] == 'True' end def parse(xml) @@ -134,7 +135,7 @@ def parse(xml) def post_data(parameters = {}) xml = REXML::Document.new - root = xml.add_element("ewaygateway") + root = xml.add_element('ewaygateway') parameters.each do |key, value| root.add_element("eway#{key}").text = value @@ -144,7 +145,7 @@ def post_data(parameters = {}) def message_from(message) return '' if message.blank? - MESSAGES[message[0,2]] || message + MESSAGES[message[0, 2]] || message end def purchase_url(cvn) @@ -159,66 +160,66 @@ def refund_url end MESSAGES = { - "00" => "Transaction Approved", - "01" => "Refer to Issuer", - "02" => "Refer to Issuer, special", - "03" => "No Merchant", - "04" => "Pick Up Card", - "05" => "Do Not Honour", - "06" => "Error", - "07" => "Pick Up Card, Special", - "08" => "Honour With Identification", - "09" => "Request In Progress", - "10" => "Approved For Partial Amount", - "11" => "Approved, VIP", - "12" => "Invalid Transaction", - "13" => "Invalid Amount", - "14" => "Invalid Card Number", - "15" => "No Issuer", - "16" => "Approved, Update Track 3", - "19" => "Re-enter Last Transaction", - "21" => "No Action Taken", - "22" => "Suspected Malfunction", - "23" => "Unacceptable Transaction Fee", - "25" => "Unable to Locate Record On File", - "30" => "Format Error", - "31" => "Bank Not Supported By Switch", - "33" => "Expired Card, Capture", - "34" => "Suspected Fraud, Retain Card", - "35" => "Card Acceptor, Contact Acquirer, Retain Card", - "36" => "Restricted Card, Retain Card", - "37" => "Contact Acquirer Security Department, Retain Card", - "38" => "PIN Tries Exceeded, Capture", - "39" => "No Credit Account", - "40" => "Function Not Supported", - "41" => "Lost Card", - "42" => "No Universal Account", - "43" => "Stolen Card", - "44" => "No Investment Account", - "51" => "Insufficient Funds", - "52" => "No Cheque Account", - "53" => "No Savings Account", - "54" => "Expired Card", - "55" => "Incorrect PIN", - "56" => "No Card Record", - "57" => "Function Not Permitted to Cardholder", - "58" => "Function Not Permitted to Terminal", - "59" => "Suspected Fraud", - "60" => "Acceptor Contact Acquirer", - "61" => "Exceeds Withdrawal Limit", - "62" => "Restricted Card", - "63" => "Security Violation", - "64" => "Original Amount Incorrect", - "66" => "Acceptor Contact Acquirer, Security", - "67" => "Capture Card", - "75" => "PIN Tries Exceeded", - "82" => "CVV Validation Error", - "90" => "Cutoff In Progress", - "91" => "Card Issuer Unavailable", - "92" => "Unable To Route Transaction", - "93" => "Cannot Complete, Violation Of The Law", - "94" => "Duplicate Transaction", - "96" => "System Error" + '00' => 'Transaction Approved', + '01' => 'Refer to Issuer', + '02' => 'Refer to Issuer, special', + '03' => 'No Merchant', + '04' => 'Pick Up Card', + '05' => 'Do Not Honour', + '06' => 'Error', + '07' => 'Pick Up Card, Special', + '08' => 'Honour With Identification', + '09' => 'Request In Progress', + '10' => 'Approved For Partial Amount', + '11' => 'Approved, VIP', + '12' => 'Invalid Transaction', + '13' => 'Invalid Amount', + '14' => 'Invalid Card Number', + '15' => 'No Issuer', + '16' => 'Approved, Update Track 3', + '19' => 'Re-enter Last Transaction', + '21' => 'No Action Taken', + '22' => 'Suspected Malfunction', + '23' => 'Unacceptable Transaction Fee', + '25' => 'Unable to Locate Record On File', + '30' => 'Format Error', + '31' => 'Bank Not Supported By Switch', + '33' => 'Expired Card, Capture', + '34' => 'Suspected Fraud, Retain Card', + '35' => 'Card Acceptor, Contact Acquirer, Retain Card', + '36' => 'Restricted Card, Retain Card', + '37' => 'Contact Acquirer Security Department, Retain Card', + '38' => 'PIN Tries Exceeded, Capture', + '39' => 'No Credit Account', + '40' => 'Function Not Supported', + '41' => 'Lost Card', + '42' => 'No Universal Account', + '43' => 'Stolen Card', + '44' => 'No Investment Account', + '51' => 'Insufficient Funds', + '52' => 'No Cheque Account', + '53' => 'No Savings Account', + '54' => 'Expired Card', + '55' => 'Incorrect PIN', + '56' => 'No Card Record', + '57' => 'Function Not Permitted to Cardholder', + '58' => 'Function Not Permitted to Terminal', + '59' => 'Suspected Fraud', + '60' => 'Acceptor Contact Acquirer', + '61' => 'Exceeds Withdrawal Limit', + '62' => 'Restricted Card', + '63' => 'Security Violation', + '64' => 'Original Amount Incorrect', + '66' => 'Acceptor Contact Acquirer, Security', + '67' => 'Capture Card', + '75' => 'PIN Tries Exceeded', + '82' => 'CVV Validation Error', + '90' => 'Cutoff In Progress', + '91' => 'Card Issuer Unavailable', + '92' => 'Unable To Route Transaction', + '93' => 'Cannot Complete, Violation Of The Law', + '94' => 'Duplicate Transaction', + '96' => 'System Error' } end end diff --git a/lib/active_merchant/billing/gateways/eway_managed.rb b/lib/active_merchant/billing/gateways/eway_managed.rb index b89d5555d0a..fcdd34afbd4 100644 --- a/lib/active_merchant/billing/gateways/eway_managed.rb +++ b/lib/active_merchant/billing/gateways/eway_managed.rb @@ -12,7 +12,7 @@ class EwayManagedGateway < Gateway self.default_currency = 'AUD' - #accepted money format + # accepted money format self.money_format = :cents # The homepage URL of the gateway @@ -46,7 +46,7 @@ def store(creditcard, options = {}) add_address(post, billing_address) add_misc_fields(post, options) - commit("CreateCustomer", post) + commit('CreateCustomer', post) end def update(billing_id, creditcard, options={}) @@ -64,7 +64,7 @@ def update(billing_id, creditcard, options={}) add_address(post, billing_address) add_misc_fields(post, options) - commit("UpdateCustomer", post) + commit('UpdateCustomer', post) end # Process a payment in the given amount against the stored credit card given by billing_id @@ -86,7 +86,7 @@ def purchase(money, billing_id, options={}) post[:amount]=money add_invoice(post, options) - commit("ProcessPayment", post) + commit('ProcessPayment', post) end # Get customer's stored credit card details given by billing_id @@ -98,7 +98,7 @@ def retrieve(billing_id) post = {} post[:managedCustomerID] = billing_id.to_s - commit("QueryCustomer", post) + commit('QueryCustomer', post) end # TODO: eWay API also provides QueryPayment @@ -106,8 +106,8 @@ def retrieve(billing_id) private def eway_requires!(hash) - raise ArgumentError.new("Missing eWay required parameter in `billing_address`: title") unless hash.has_key?(:title) - raise ArgumentError.new("Missing eWay required parameter in `billing_address`: country") unless hash.has_key?(:country) + raise ArgumentError.new('Missing eWay required parameter in `billing_address`: title') unless hash.has_key?(:title) + raise ArgumentError.new('Missing eWay required parameter in `billing_address`: country') unless hash.has_key?(:country) end def add_address(post, address) @@ -136,12 +136,11 @@ def add_invoice(post, options) post[:invoiceDescription] = options[:description] end - # add credit card details to be stored by eway. NOTE eway requires "title" field def add_creditcard(post, creditcard) post[:CCNumber] = creditcard.number - post[:CCExpiryMonth] = sprintf("%.2i", creditcard.month) - post[:CCExpiryYear] = sprintf("%.4i", creditcard.year)[-2..-1] + post[:CCExpiryMonth] = sprintf('%.2i', creditcard.month) + post[:CCExpiryYear] = sprintf('%.4i', creditcard.year)[-2..-1] post[:CCNameOnCard] = creditcard.name post[:FirstName] = creditcard.first_name post[:LastName] = creditcard.last_name @@ -150,8 +149,8 @@ def add_creditcard(post, creditcard) def parse(body) reply = {} xml = REXML::Document.new(body) - if root = REXML::XPath.first(xml, "//soap:Fault") then - reply=parse_fault(root) + if root = REXML::XPath.first(xml, '//soap:Fault') then + reply=parse_fault(root) else if root = REXML::XPath.first(xml, '//ProcessPaymentResponse/ewayResponse') then # Successful payment @@ -166,19 +165,19 @@ def parse(body) reply[:success]=true else if root = REXML::XPath.first(xml, '//UpdateCustomerResult') then - if root.text.downcase == 'true' then + if root.text.casecmp('true').zero? then reply[:message]='OK' reply[:success]=true else # ERROR: This state should never occur. If there is a problem, # a soap:Fault will be returned. The presence of this # element always means a success. - raise StandardError, "Unexpected \"false\" in UpdateCustomerResult" + raise StandardError, 'Unexpected "false" in UpdateCustomerResult' end else # ERROR: This state should never occur currently. We have handled # responses for all the methods which we support. - raise StandardError, "Unexpected response" + raise StandardError, 'Unexpected response' end end end @@ -232,34 +231,34 @@ def commit(action, post) def soap_request(arguments, action) # eWay demands all fields be sent, but contain an empty string if blank post = case action - when 'QueryCustomer' - arguments - when 'ProcessPayment' - default_payment_fields.merge(arguments) - when 'CreateCustomer' - default_customer_fields.merge(arguments) - when 'UpdateCustomer' - default_customer_fields.merge(arguments) + when 'QueryCustomer' + arguments + when 'ProcessPayment' + default_payment_fields.merge(arguments) + when 'CreateCustomer' + default_customer_fields.merge(arguments) + when 'UpdateCustomer' + default_customer_fields.merge(arguments) end xml = Builder::XmlMarkup.new :indent => 2 - xml.instruct! - xml.tag! 'soap12:Envelope', {'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance', 'xmlns:xsd' => 'http://www.w3.org/2001/XMLSchema', 'xmlns:soap12' => 'http://www.w3.org/2003/05/soap-envelope'} do - xml.tag! 'soap12:Header' do - xml.tag! 'eWAYHeader', {'xmlns' => 'https://www.eway.com.au/gateway/managedpayment'} do - xml.tag! 'eWAYCustomerID', @options[:login] - xml.tag! 'Username', @options[:username] - xml.tag! 'Password', @options[:password] - end + xml.instruct! + xml.tag! 'soap12:Envelope', {'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance', 'xmlns:xsd' => 'http://www.w3.org/2001/XMLSchema', 'xmlns:soap12' => 'http://www.w3.org/2003/05/soap-envelope'} do + xml.tag! 'soap12:Header' do + xml.tag! 'eWAYHeader', {'xmlns' => 'https://www.eway.com.au/gateway/managedpayment'} do + xml.tag! 'eWAYCustomerID', @options[:login] + xml.tag! 'Username', @options[:username] + xml.tag! 'Password', @options[:password] end - xml.tag! 'soap12:Body' do |x| - x.tag! "#{action}", {'xmlns' => 'https://www.eway.com.au/gateway/managedpayment'} do |y| - post.each do |key, value| - y.tag! "#{key}", "#{value}" - end + end + xml.tag! 'soap12:Body' do |x| + x.tag! action, {'xmlns' => 'https://www.eway.com.au/gateway/managedpayment'} do |y| + post.each do |key, value| + y.tag! key, value end end end + end xml.target! end diff --git a/lib/active_merchant/billing/gateways/eway_rapid.rb b/lib/active_merchant/billing/gateways/eway_rapid.rb index 130254682db..29d06a837b4 100644 --- a/lib/active_merchant/billing/gateways/eway_rapid.rb +++ b/lib/active_merchant/billing/gateways/eway_rapid.rb @@ -3,15 +3,15 @@ module ActiveMerchant #:nodoc: module Billing #:nodoc: class EwayRapidGateway < Gateway - self.test_url = "https://api.sandbox.ewaypayments.com/" - self.live_url = "https://api.ewaypayments.com/" + self.test_url = 'https://api.sandbox.ewaypayments.com/' + self.live_url = 'https://api.ewaypayments.com/' self.money_format = :cents self.supported_countries = ['AU', 'NZ', 'GB', 'SG', 'MY', 'HK'] self.supported_cardtypes = [:visa, :master, :american_express, :diners_club, :jcb] - self.homepage_url = "http://www.eway.com.au/" - self.display_name = "eWAY Rapid 3.1" - self.default_currency = "AUD" + self.homepage_url = 'http://www.eway.com.au/' + self.display_name = 'eWAY Rapid 3.1' + self.default_currency = 'AUD' class_attribute :partner_id @@ -72,13 +72,13 @@ def capture(amount, identification, options = {}) add_metadata(params, options) add_invoice(params, amount, options) add_reference(params, identification) - commit(url_for("CapturePayment"), params) + commit(url_for('CapturePayment'), params) end def void(identification, options = {}) params = {} add_reference(params, identification) - commit(url_for("CancelAuthorisation"), params) + commit(url_for('CancelAuthorisation'), params) end # Public: Refund a transaction. @@ -109,8 +109,8 @@ def void(identification, options = {}) def refund(amount, identification, options = {}) params = {} add_metadata(params, options) - add_invoice(params, amount, options, "Refund") - add_reference(params["Refund"], identification) + add_invoice(params, amount, options, 'Refund') + add_reference(params['Refund'], identification) add_customer_data(params, options) commit(url_for("Transaction/#{identification}/Refund"), params) end @@ -140,7 +140,7 @@ def store(payment_method, options = {}) add_customer_data(params, options) add_credit_card(params, payment_method, options) params['Method'] = 'CreateTokenCustomer' - commit(url_for("Transaction"), params) + commit(url_for('Transaction'), params) end # Public: Update a customer's data @@ -170,7 +170,7 @@ def update(customer_token, payment_method, options = {}) add_credit_card(params, payment_method, options) add_customer_token(params, customer_token) params['Method'] = 'UpdateTokenCustomer' - commit(url_for("Transaction"), params) + commit(url_for('Transaction'), params) end def supports_scrubbing @@ -197,7 +197,7 @@ def add_metadata(params, options) params end - def add_invoice(params, money, options, key = "Payment") + def add_invoice(params, money, options, key = 'Payment') currency_code = options[:currency] || currency(money) params[key] = { 'TotalAmount' => localized_amount(money, currency_code), @@ -243,8 +243,8 @@ def add_credit_card(params, credit_card, options) card_details = params['Customer']['CardDetails'] = {} card_details['Name'] = truncate(credit_card.name, 50) card_details['Number'] = credit_card.number - card_details['ExpiryMonth'] = "%02d" % (credit_card.month || 0) - card_details['ExpiryYear'] = "%02d" % (credit_card.year || 0) + card_details['ExpiryMonth'] = '%02d' % (credit_card.month || 0) + card_details['ExpiryYear'] = '%02d' % (credit_card.year || 0) card_details['CVN'] = credit_card.verification_value else add_customer_token(params, credit_card) @@ -262,8 +262,8 @@ def url_for(action) def commit(url, params) headers = { - "Authorization" => ("Basic " + Base64.strict_encode64(@options[:login].to_s + ":" + @options[:password].to_s).chomp), - "Content-Type" => "application/json" + 'Authorization' => ('Basic ' + Base64.strict_encode64(@options[:login].to_s + ':' + @options[:password].to_s).chomp), + 'Content-Type' => 'application/json' } request = params.to_json raw = parse(ssl_post(url, request, headers)) @@ -287,19 +287,19 @@ def parse(data) end def success?(response) - if response['ResponseCode'] == "00" + if response['ResponseCode'] == '00' true elsif response['TransactionStatus'] (response['TransactionStatus'] == true) - elsif response["Succeeded"] - (response["Succeeded"] == true) + elsif response['Succeeded'] + (response['Succeeded'] == true) else false end end def parse_errors(message) - errors = message.split(',').collect{|code| MESSAGES[code.strip]}.flatten.join(',') + errors = message.split(',').collect { |code| MESSAGES[code.strip] }.flatten.join(',') errors.presence || message end @@ -311,9 +311,9 @@ def message_from(succeeded, response) elsif response['ResponseCode'] ActiveMerchant::Billing::EwayGateway::MESSAGES[response['ResponseCode']] elsif succeeded - "Succeeded" + 'Succeeded' else - "Failed" + 'Failed' end end @@ -326,12 +326,12 @@ def authorization_from(response) def avs_result_from(response) verification = response['Verification'] || {} code = case verification['Address'] - when "Valid" - "M" - when "Invalid" - "N" + when 'Valid' + 'M' + when 'Invalid' + 'N' else - "I" + 'I' end {:code => code} end @@ -339,12 +339,12 @@ def avs_result_from(response) def cvv_result_from(response) verification = response['Verification'] || {} case verification['CVN'] - when "Valid" - "M" - when "Invalid" - "N" + when 'Valid' + 'M' + when 'Invalid' + 'N' else - "P" + 'P' end end diff --git a/lib/active_merchant/billing/gateways/exact.rb b/lib/active_merchant/billing/gateways/exact.rb index 1341f184c10..d9649b84e21 100644 --- a/lib/active_merchant/billing/gateways/exact.rb +++ b/lib/active_merchant/billing/gateways/exact.rb @@ -3,23 +3,22 @@ module Billing #:nodoc: class ExactGateway < Gateway self.live_url = self.test_url = 'https://secure2.e-xact.com/vplug-in/transaction/rpc-enc/service.asmx' - API_VERSION = "8.5" + API_VERSION = '8.5' - TEST_LOGINS = [ {:login => "A00049-01", :password => "test1"}, - {:login => "A00427-01", :password => "testus"} ] - - TRANSACTIONS = { :sale => "00", - :authorization => "01", - :capture => "32", - :credit => "34" } + TEST_LOGINS = [ {:login => 'A00049-01', :password => 'test1'}, + {:login => 'A00427-01', :password => 'testus'} ] + TRANSACTIONS = { :sale => '00', + :authorization => '01', + :capture => '32', + :credit => '34' } ENVELOPE_NAMESPACES = { 'xmlns:xsd' => 'http://www.w3.org/2001/XMLSchema', 'xmlns:env' => 'http://schemas.xmlsoap.org/soap/envelope/', 'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance' } - SEND_AND_COMMIT_ATTRIBUTES = { 'xmlns:n1' => "http://secure2.e-xact.com/vplug-in/transaction/rpc-enc/Request", + SEND_AND_COMMIT_ATTRIBUTES = { 'xmlns:n1' => 'http://secure2.e-xact.com/vplug-in/transaction/rpc-enc/Request', 'env:encodingStyle' => 'http://schemas.xmlsoap.org/soap/encoding/' } @@ -27,11 +26,11 @@ class ExactGateway < Gateway 'xsi:type' => 'n2:Transaction' } - POST_HEADERS = { 'soapAction' => "http://secure2.e-xact.com/vplug-in/transaction/rpc-enc/SendAndCommit", + POST_HEADERS = { 'soapAction' => 'http://secure2.e-xact.com/vplug-in/transaction/rpc-enc/SendAndCommit', 'Content-Type' => 'text/xml' } - SUCCESS = "true" + SUCCESS = 'true' SENSITIVE_FIELDS = [ :verification_str2, :expiry_date, :card_number ] @@ -161,15 +160,14 @@ def expdate(credit_card) end def commit(action, request) - response = parse(ssl_post(self.live_url, build_request(action, request), POST_HEADERS)) - - Response.new(successful?(response), message_from(response), response, - :test => test?, - :authorization => authorization_from(response), - :avs_result => { :code => response[:avs] }, - :cvv_result => response[:cvv2] - ) - + response = parse(ssl_post(self.live_url, build_request(action, request), POST_HEADERS)) + + Response.new(successful?(response), message_from(response), response, + :test => test?, + :authorization => authorization_from(response), + :avs_result => { :code => response[:avs] }, + :cvv_result => response[:cvv2] + ) rescue ResponseError => e case e.response.code when '401' @@ -185,9 +183,9 @@ def successful?(response) def authorization_from(response) if response[:authorization_num] && response[:transaction_tag] - "#{response[:authorization_num]};#{response[:transaction_tag]}" + "#{response[:authorization_num]};#{response[:transaction_tag]}" else - '' + '' end end @@ -207,13 +205,13 @@ def parse(xml) response = {} xml = REXML::Document.new(xml) - if root = REXML::XPath.first(xml, "//types:TransactionResult") + if root = REXML::XPath.first(xml, '//types:TransactionResult') parse_elements(response, root) - elsif root = REXML::XPath.first(xml, "//soap:Fault") + elsif root = REXML::XPath.first(xml, '//soap:Fault') parse_elements(response, root) end - response.delete_if{ |k,v| SENSITIVE_FIELDS.include?(k) } + response.delete_if { |k, v| SENSITIVE_FIELDS.include?(k) } end def parse_elements(response, root) @@ -224,4 +222,3 @@ def parse_elements(response, root) end end end - diff --git a/lib/active_merchant/billing/gateways/ezic.rb b/lib/active_merchant/billing/gateways/ezic.rb index 7c1367cb650..3bfe469c857 100644 --- a/lib/active_merchant/billing/gateways/ezic.rb +++ b/lib/active_merchant/billing/gateways/ezic.rb @@ -23,7 +23,7 @@ def purchase(money, payment, options={}) add_payment(post, payment) add_customer_data(post, options) - commit("S", post) + commit('S', post) end def authorize(money, payment, options={}) @@ -34,7 +34,7 @@ def authorize(money, payment, options={}) add_payment(post, payment) add_customer_data(post, options) - commit("A", post) + commit('A', post) end def capture(money, authorization, options={}) @@ -45,7 +45,7 @@ def capture(money, authorization, options={}) add_authorization(post, authorization) add_pay_type(post) - commit("D", post) + commit('D', post) end def refund(money, authorization, options={}) @@ -56,7 +56,7 @@ def refund(money, authorization, options={}) add_authorization(post, authorization) add_pay_type(post) - commit("R", post) + commit('R', post) end def void(authorization, options={}) @@ -66,7 +66,7 @@ def void(authorization, options={}) add_authorization(post, authorization) add_pay_type(post) - commit("U", post) + commit('U', post) end def verify(credit_card, options={}) @@ -143,7 +143,7 @@ def add_authorization(post, authorization) end def add_pay_type(post) - post[:pay_type] = "C" + post[:pay_type] = 'C' end def parse(body) @@ -160,8 +160,8 @@ def commit(transaction_type, parameters) message_from(response), response, authorization: authorization_from(response), - avs_result: AVSResult.new(code: response["avs_code"]), - cvv_result: CVVResult.new(response["cvv2_code"]), + avs_result: AVSResult.new(code: response['avs_code']), + cvv_result: CVVResult.new(response['cvv2_code']), test: test? ) rescue ResponseError => e @@ -170,27 +170,26 @@ def commit(transaction_type, parameters) end def success_from(response) - response["status_code"] == "1" || response["status_code"] == "T" + response['status_code'] == '1' || response['status_code'] == 'T' end def message_from(response) - response["auth_msg"] + response['auth_msg'] end def authorization_from(response) - response["trans_id"] + response['trans_id'] end def post_data(parameters = {}) - parameters.collect { |key, value| "#{key}=#{CGI.escape(value.to_s)}" }.join("&") + parameters.collect { |key, value| "#{key}=#{CGI.escape(value.to_s)}" }.join('&') end def headers { - "User-Agent" => "ActiveMerchantBindings/#{ActiveMerchant::VERSION}", + 'User-Agent' => "ActiveMerchantBindings/#{ActiveMerchant::VERSION}", } end end - end end diff --git a/lib/active_merchant/billing/gateways/fat_zebra.rb b/lib/active_merchant/billing/gateways/fat_zebra.rb index a06fe59fe6a..93d25df692a 100644 --- a/lib/active_merchant/billing/gateways/fat_zebra.rb +++ b/lib/active_merchant/billing/gateways/fat_zebra.rb @@ -3,8 +3,8 @@ module ActiveMerchant #:nodoc: module Billing #:nodoc: class FatZebraGateway < Gateway - self.live_url = "https://gateway.fatzebra.com.au/v1.0" - self.test_url = "https://gateway.sandbox.fatzebra.com.au/v1.0" + self.live_url = 'https://gateway.fatzebra.com.au/v1.0' + self.test_url = 'https://gateway.sandbox.fatzebra.com.au/v1.0' self.supported_countries = ['AU'] self.default_currency = 'AUD' @@ -14,23 +14,11 @@ class FatZebraGateway < Gateway self.homepage_url = 'https://www.fatzebra.com.au/' self.display_name = 'Fat Zebra' - # Setup a new instance of the gateway. - # - # The options hash should include :username and :token - # You can find your username and token at https://dashboard.fatzebra.com.au - # Under the Your Account section def initialize(options = {}) requires!(options, :username, :token) super end - # To create a purchase on a credit card use: - # - # purchase(money, creditcard) - # - # To charge a tokenized card - # - # purchase(money, "abzy87u", :cvv => "123") def purchase(money, creditcard, options = {}) post = {} @@ -65,11 +53,6 @@ def capture(money, authorization, options = {}) commit(:post, "purchases/#{CGI.escape(authorization)}/capture", post) end - # Refund a transaction - # - # amount - Integer - the amount to refund - # txn_id - String - the original transaction to be refunded - # reference - String - your transaction reference def refund(money, txn_id, options={}) post = {} @@ -78,17 +61,14 @@ def refund(money, txn_id, options={}) post[:transaction_id] = txn_id add_order_id(post, options) - commit(:post, "refunds", post) + commit(:post, 'refunds', post) end - # Tokenize a credit card - # - # The token is returned in the Response#authorization def store(creditcard, options={}) post = {} add_creditcard(post, creditcard) - commit(:post, "credit_cards", post) + commit(:post, 'credit_cards', post) end def supports_scrubbing? @@ -98,20 +78,18 @@ def supports_scrubbing? def scrub(transcript) transcript. gsub(%r((Authorization: Basic )\w+), '\1[FILTERED]'). - gsub(%r(("card_number\\":\\")[^"\\]*)i, '\1[FILTERED]'). - gsub(%r(("cvv\\":\\")\d+), '\1[FILTERED]') + gsub(%r(("card_number\\?":\\?")[^"\\]*)i, '\1[FILTERED]'). + gsub(%r(("cvv\\?":\\?")\d+), '\1[FILTERED]') end private - # Add the money details to the request def add_amount(post, money, options) post[:currency] = (options[:currency] || currency(money)) post[:currency] = post[:currency].upcase if post[:currency] post[:amount] = money end - # Add the credit card details to the request def add_creditcard(post, creditcard, options = {}) if creditcard.respond_to?(:number) post[:card_number] = creditcard.number @@ -122,7 +100,7 @@ def add_creditcard(post, creditcard, options = {}) post[:card_token] = creditcard post[:cvv] = options[:cvv] elsif creditcard.is_a?(Hash) - ActiveMerchant.deprecated "Passing the credit card as a Hash is deprecated. Use a String and put the (optional) CVV in the options hash instead." + ActiveMerchant.deprecated 'Passing the credit card as a Hash is deprecated. Use a String and put the (optional) CVV in the options hash instead.' post[:card_token] = creditcard[:token] post[:cvv] = creditcard[:cvv] else @@ -132,9 +110,9 @@ def add_creditcard(post, creditcard, options = {}) def add_extra_options(post, options) extra = {} - extra[:ecm] = "32" if options[:recurring] + extra[:ecm] = '32' if options[:recurring] extra[:cavv] = options[:cavv] if options[:cavv] - extra[:xid] = options[:cavv] if options[:xid] + extra[:xid] = options[:xid] if options[:xid] extra[:sli] = options[:sli] if options[:sli] extra[:name] = options[:merchant] if options[:merchant] extra[:location] = options[:merchant_location] if options[:merchant_location] @@ -146,15 +124,14 @@ def add_order_id(post, options) end def add_ip(post, options) - post[:customer_ip] = options[:ip] || "127.0.0.1" + post[:customer_ip] = options[:ip] || '127.0.0.1' end - # Post the data to the gateway def commit(method, uri, parameters=nil) response = begin parse(ssl_request(method, get_url(uri), parameters.to_json, headers)) rescue ResponseError => e - return Response.new(false, "Invalid Login") if(e.response.code == "401") + return Response.new(false, 'Invalid Login') if(e.response.code == '401') parse(e.response.body) end @@ -163,63 +140,58 @@ def commit(method, uri, parameters=nil) success, message_from(response), response, - :test => response["test"], + :test => response['test'], :authorization => authorization_from(response, success) ) end def success_from(response) ( - response["successful"] && - response["response"] && - (response["response"]["successful"] || response["response"]["token"]) + response['successful'] && + response['response'] && + (response['response']['successful'] || response['response']['token']) ) end def authorization_from(response, success) if success - (response["response"]["id"] || response["response"]["token"]) + (response['response']['id'] || response['response']['token']) else nil end end def message_from(response) - if !response["errors"].empty? - response["errors"].join(", ") - elsif response["response"]["message"] - response["response"]["message"] + if !response['errors'].empty? + response['errors'].join(', ') + elsif response['response']['message'] + response['response']['message'] else - "Unknown Error" + 'Unknown Error' end end - # Parse the returned JSON, if parse errors are raised then return a detailed error. def parse(response) - begin - JSON.parse(response) - rescue JSON::ParserError - msg = 'Invalid JSON response received from Fat Zebra. Please contact support@fatzebra.com.au if you continue to receive this message.' - msg += " (The raw response returned by the API was #{response.inspect})" - { - "successful" => false, - "response" => {}, - "errors" => [msg] - } - end + JSON.parse(response) + rescue JSON::ParserError + msg = 'Invalid JSON response received from Fat Zebra. Please contact support@fatzebra.com.au if you continue to receive this message.' + msg += " (The raw response returned by the API was #{response.inspect})" + { + 'successful' => false, + 'response' => {}, + 'errors' => [msg] + } end - # Build the URL based on the AM mode and the URI def get_url(uri) base = test? ? self.test_url : self.live_url - base + "/" + uri + base + '/' + uri end - # Builds the auth and U-A headers for the request def headers { - "Authorization" => "Basic " + Base64.strict_encode64(@options[:username].to_s + ":" + @options[:token].to_s).strip, - "User-Agent" => "Fat Zebra v1.0/ActiveMerchant #{ActiveMerchant::VERSION}" + 'Authorization' => 'Basic ' + Base64.strict_encode64(@options[:username].to_s + ':' + @options[:token].to_s).strip, + 'User-Agent' => "Fat Zebra v1.0/ActiveMerchant #{ActiveMerchant::VERSION}" } end end diff --git a/lib/active_merchant/billing/gateways/federated_canada.rb b/lib/active_merchant/billing/gateways/federated_canada.rb index c6694712ad9..b6666a9fa44 100644 --- a/lib/active_merchant/billing/gateways/federated_canada.rb +++ b/lib/active_merchant/billing/gateways/federated_canada.rb @@ -134,17 +134,17 @@ def success?(response) end def test? - (@options[:login].eql?('demo')) && (@options[:password].eql?('password')) + @options[:login].eql?('demo') && @options[:password].eql?('password') end def message_from(response) case response['response'].to_i when APPROVED - "Transaction Approved" + 'Transaction Approved' when DECLINED - "Transaction Declined" + 'Transaction Declined' else - "Error in transaction data or system error" + 'Error in transaction data or system error' end end @@ -152,9 +152,8 @@ def post_data(action, parameters = {}) parameters[:type] = action parameters[:username] = @options[:login] parameters[:password] = @options[:password] - parameters.map{|k, v| "#{k}=#{CGI.escape(v.to_s)}"}.join('&') + parameters.map { |k, v| "#{k}=#{CGI.escape(v.to_s)}" }.join('&') end end end end - diff --git a/lib/active_merchant/billing/gateways/finansbank.rb b/lib/active_merchant/billing/gateways/finansbank.rb index 144f798abfe..5f496570853 100644 --- a/lib/active_merchant/billing/gateways/finansbank.rb +++ b/lib/active_merchant/billing/gateways/finansbank.rb @@ -20,4 +20,3 @@ class FinansbankGateway < CC5Gateway end end end - diff --git a/lib/active_merchant/billing/gateways/first_giving.rb b/lib/active_merchant/billing/gateways/first_giving.rb index 715b585e782..09dea7f8e5a 100644 --- a/lib/active_merchant/billing/gateways/first_giving.rb +++ b/lib/active_merchant/billing/gateways/first_giving.rb @@ -31,7 +31,7 @@ def refund(money, identifier, options = {}) get = {} get[:transactionId] = identifier get[:tranType] = 'REFUNDREQUEST' - commit("/transaction/refundrequest?" + encode(get)) + commit('/transaction/refundrequest?' + encode(get)) end private @@ -39,13 +39,13 @@ def refund(money, identifier, options = {}) def add_donation_data(post, money, options) post[:amount] = amount(money) post[:charityId] = @options[:charity_id] - post[:description] = (options[:description] || "Purchase") + post[:description] = (options[:description] || 'Purchase') post[:currencyCode] = (options[:currency] || currency(money)) end def add_customer_data(post, options) - post[:billToEmail] = (options[:email] || "activemerchant@example.com") - post[:remoteAddr] = (options[:ip] || "127.0.0.1") + post[:billToEmail] = (options[:email] || 'activemerchant@example.com') + post[:remoteAddr] = (options[:ip] || '127.0.0.1') end def add_address(post, options) @@ -76,7 +76,7 @@ def parse(body) response = {} xml = Nokogiri::XML(body) - element = xml.xpath("//firstGivingDonationApi/firstGivingResponse").first + element = xml.xpath('//firstGivingDonationApi/firstGivingResponse').first element.attributes.each do |name, attribute| response[name] = attribute.content @@ -103,28 +103,28 @@ def commit(action, post=nil) end Response.new( - (response["acknowledgement"] == "Success"), - (response["friendlyErrorMessage"] || response["verboseErrorMessage"] || response["acknowledgement"]), + (response['acknowledgement'] == 'Success'), + (response['friendlyErrorMessage'] || response['verboseErrorMessage'] || response['acknowledgement']), response, - authorization: response["transactionId"], - test: test?, + authorization: response['transactionId'], + test: test? ) end def post_data(post) - post.collect { |key, value| "#{key}=#{CGI.escape(value.to_s)}" }.join("&") + post.collect { |key, value| "#{key}=#{CGI.escape(value.to_s)}" }.join('&') end def encode(hash) - hash.collect{|(k,v)| "#{CGI.escape(k.to_s)}=#{CGI.escape(v.to_s)}"}.join('&') + hash.collect { |(k, v)| "#{CGI.escape(k.to_s)}=#{CGI.escape(v.to_s)}" }.join('&') end def creditcard_brand(brand) case brand - when "visa" then "VI" - when "master" then "MC" - when "discover" then "DI" - when "american_express" then "AX" + when 'visa' then 'VI' + when 'master' then 'MC' + when 'discover' then 'DI' + when 'american_express' then 'AX' else raise "Unhandled credit card brand #{brand}" end @@ -132,12 +132,11 @@ def creditcard_brand(brand) def headers { - "User-Agent" => "ActiveMerchantBindings/#{ActiveMerchant::VERSION}", - "JG_APPLICATIONKEY" => "#{@options[:application_key]}", - "JG_SECURITYTOKEN" => "#{@options[:security_token]}" + 'User-Agent' => "ActiveMerchantBindings/#{ActiveMerchant::VERSION}", + 'JG_APPLICATIONKEY' => @options[:application_key].to_s, + 'JG_SECURITYTOKEN' => @options[:security_token].to_s } end end end end - diff --git a/lib/active_merchant/billing/gateways/first_pay.rb b/lib/active_merchant/billing/gateways/first_pay.rb index fdf83cb0167..3c197f0d79e 100644 --- a/lib/active_merchant/billing/gateways/first_pay.rb +++ b/lib/active_merchant/billing/gateways/first_pay.rb @@ -3,7 +3,7 @@ module ActiveMerchant #:nodoc: module Billing #:nodoc: class FirstPayGateway < Gateway - self.live_url = 'https://secure.1stpaygateway.net/secure/gateway/xmlgateway.aspx' + self.live_url = 'https://secure.goemerchant.com/secure/gateway/xmlgateway.aspx' self.supported_countries = ['US'] self.default_currency = 'USD' @@ -21,7 +21,7 @@ def initialize(options={}) def purchase(money, payment, options={}) post = {} add_invoice(post, money, options) - add_payment(post, payment) + add_payment(post, payment, options) add_address(post, payment, options) add_customer_data(post, options) @@ -31,7 +31,7 @@ def purchase(money, payment, options={}) def authorize(money, payment, options={}) post = {} add_invoice(post, money, options) - add_payment(post, payment) + add_payment(post, payment, options) add_address(post, payment, options) add_customer_data(post, options) @@ -56,6 +56,17 @@ def void(authorization, options={}) commit('void', post) end + def supports_scrubbing? + true + end + + def scrub(transcript) + transcript. + gsub(%r((gateway_id)[^<]*())i, '\1[FILTERED]\2'). + gsub(%r((card_number)[^<]*())i, '\1[FILTERED]\2'). + gsub(%r((cvv2)[^<]*())i, '\1[FILTERED]\2') + end + private def add_authentication(post, options) @@ -66,18 +77,20 @@ def add_authentication(post, options) def add_customer_data(post, options) post[:owner_email] = options[:email] if options[:email] post[:remote_ip_address] = options[:ip] if options[:ip] + post[:processor_id] = options[:processor_id] if options[:processor_id] end def add_address(post, creditcard, options) - address = options[:billing_address] || options[:address] - post[:owner_name] = address[:name] - post[:owner_street] = address[:address1] - post[:owner_street2] = address[:address2] if address[:address2] - post[:owner_city] = address[:city] - post[:owner_state] = address[:state] - post[:owner_zip] = address[:zip] - post[:owner_country] = address[:country] - post[:owner_phone] = address[:phone] if address[:phone] + if address = options[:billing_address] || options[:address] + post[:owner_name] = address[:name] + post[:owner_street] = address[:address1] + post[:owner_street2] = address[:address2] if address[:address2] + post[:owner_city] = address[:city] + post[:owner_state] = address[:state] + post[:owner_zip] = address[:zip] + post[:owner_country] = address[:country] + post[:owner_phone] = address[:phone] if address[:phone] + end end def add_invoice(post, money, options) @@ -85,11 +98,15 @@ def add_invoice(post, money, options) post[:total] = amount(money) end - def add_payment(post, payment) + def add_payment(post, payment, options) post[:card_name] = payment.brand # Unclear if need to map to known names or open text field?? post[:card_number] = payment.number post[:card_exp] = expdate(payment) post[:cvv2] = payment.verification_value + post[:recurring] = options[:recurring] if options[:recurring] + post[:recurring_start_date] = options[:recurring_start_date] if options[:recurring_start_date] + post[:recurring_end_date] = options[:recurring_end_date] if options[:recurring_end_date] + post[:recurring_type] = options[:recurring_type] if options[:recurring_type] end def add_reference(post, action, money, authorization) @@ -102,9 +119,9 @@ def parse(xml) response = {} doc = Nokogiri::XML(xml) - doc.root.xpath("//RESPONSE/FIELDS/FIELD").each do |field| + doc.root&.xpath('//RESPONSE/FIELDS/FIELD')&.each do |field| response[field['KEY']] = field.text - end unless doc.root.nil? + end response end @@ -117,6 +134,7 @@ def commit(action, parameters) message_from(response), response, authorization: authorization_from(response), + error_code: error_code_from(response), test: test? ) end @@ -131,7 +149,11 @@ def success_from(response) def message_from(response) # Silly inconsistent gateway. Always make capitalized (but not all caps) msg = (response['auth_response'] || response['response1']) - msg.downcase.capitalize if msg + msg&.downcase&.capitalize + end + + def error_code_from(response) + response['error'] end def authorization_from(response) diff --git a/lib/active_merchant/billing/gateways/firstdata_e4.rb b/lib/active_merchant/billing/gateways/firstdata_e4.rb index 27e5c94cfec..12290ad51c6 100755 --- a/lib/active_merchant/billing/gateways/firstdata_e4.rb +++ b/lib/active_merchant/billing/gateways/firstdata_e4.rb @@ -2,46 +2,48 @@ module ActiveMerchant #:nodoc: module Billing #:nodoc: class FirstdataE4Gateway < Gateway # TransArmor support requires v11 or lower - self.test_url = "https://api.demo.globalgatewaye4.firstdata.com/transaction/v11" - self.live_url = "https://api.globalgatewaye4.firstdata.com/transaction/v11" + self.test_url = 'https://api.demo.globalgatewaye4.firstdata.com/transaction/v11' + self.live_url = 'https://api.globalgatewaye4.firstdata.com/transaction/v11' TRANSACTIONS = { - sale: "00", - authorization: "01", - verify: "05", - capture: "32", - void: "33", - credit: "34", - store: "05" + sale: '00', + authorization: '01', + verify: '05', + capture: '32', + void: '33', + credit: '34', + store: '05' } POST_HEADERS = { - "Accepts" => "application/xml", - "Content-Type" => "application/xml" + 'Accepts' => 'application/xml', + 'Content-Type' => 'application/xml' } - SUCCESS = "true" + SUCCESS = 'true' SENSITIVE_FIELDS = [:verification_str2, :expiry_date, :card_number] BRANDS = { :visa => 'Visa', - :master => "Mastercard", - :american_express => "American Express", - :jcb => "JCB", - :discover => "Discover" + :master => 'Mastercard', + :american_express => 'American Express', + :jcb => 'JCB', + :discover => 'Discover' } - E4_BRANDS = BRANDS.merge({:mastercard => "Mastercard"}) + E4_BRANDS = BRANDS.merge({:mastercard => 'Mastercard'}) + + DEFAULT_ECI = '07' self.supported_cardtypes = BRANDS.keys - self.supported_countries = ["CA", "US"] - self.default_currency = "USD" - self.homepage_url = "http://www.firstdata.com" - self.display_name = "FirstData Global Gateway e4" + self.supported_countries = ['CA', 'US'] + self.default_currency = 'USD' + self.homepage_url = 'http://www.firstdata.com' + self.display_name = 'FirstData Global Gateway e4' STANDARD_ERROR_CODE_MAPPING = { - # Bank error codes: https://firstdata.zendesk.com/entries/471297-First-Data-Global-Gateway-e4-Bank-Response-Codes + # Bank error codes: https://firstdata.zendesk.com/entries/471297-First-Data-Global-Gateway-e4-Bank-Response-Codes '201' => STANDARD_ERROR_CODE[:incorrect_number], '531' => STANDARD_ERROR_CODE[:invalid_cvc], '503' => STANDARD_ERROR_CODE[:invalid_cvc], @@ -53,7 +55,7 @@ class FirstdataE4Gateway < Gateway '401' => STANDARD_ERROR_CODE[:call_issuer], '402' => STANDARD_ERROR_CODE[:call_issuer], '501' => STANDARD_ERROR_CODE[:pickup_card], - # Ecommerce error codes -- https://firstdata.zendesk.com/entries/451980-ecommerce-response-codes-etg-codes + # Ecommerce error codes -- https://firstdata.zendesk.com/entries/451980-ecommerce-response-codes-etg-codes '22' => STANDARD_ERROR_CODE[:invalid_number], '25' => STANDARD_ERROR_CODE[:invalid_expiry_date], '31' => STANDARD_ERROR_CODE[:incorrect_cvc], @@ -130,8 +132,8 @@ def store(credit_card, options = {}) end def verify_credentials - response = void("0") - response.message != "Unauthorized Request. Bad or missing credentials." + response = void('0') + response.message != 'Unauthorized Request. Bad or missing credentials.' end def supports_scrubbing? @@ -141,7 +143,10 @@ def supports_scrubbing? def scrub(transcript) transcript. gsub(%r(().+()), '\1[FILTERED]\2'). - gsub(%r(().+()), '\1[FILTERED]\2') + gsub(%r(().+()), '\1[FILTERED]\2'). + gsub(%r(().+())i, '\1[FILTERED]\2'). + gsub(%r(().+()), '\1[FILTERED]\2'). + gsub(%r((Card Number : ).*\d)i, '\1[FILTERED]') end def supports_network_tokenization? @@ -154,7 +159,7 @@ def build_request(action, body) xml = Builder::XmlMarkup.new xml.instruct! - xml.tag! "Transaction" do + xml.tag! 'Transaction', xmlns: 'http://secure2.e-xact.com/vplug-in/transaction/rpc-enc/encodedTypes' do add_credentials(xml) add_transaction_type(xml, action) xml << body @@ -169,14 +174,13 @@ def build_sale_or_authorization_request(money, credit_card_or_store_authorizatio add_amount(xml, money, options) if credit_card_or_store_authorization.is_a? String - add_credit_card_token(xml, credit_card_or_store_authorization) + add_credit_card_token(xml, credit_card_or_store_authorization, options) else add_credit_card(xml, credit_card_or_store_authorization, options) end add_customer_data(xml, options) add_invoice(xml, options) - add_card_authentication_data(xml, options) add_tax_fields(xml, options) add_level_3(xml, options) @@ -204,19 +208,19 @@ def build_store_request(credit_card, options) end def add_credentials(xml) - xml.tag! "ExactID", @options[:login] - xml.tag! "Password", @options[:password] + xml.tag! 'ExactID', @options[:login] + xml.tag! 'Password', @options[:password] end def add_transaction_type(xml, action) - xml.tag! "Transaction_Type", TRANSACTIONS[action] + xml.tag! 'Transaction_Type', TRANSACTIONS[action] end def add_identification(xml, identification) - authorization_num, transaction_tag, _ = identification.split(";") + authorization_num, transaction_tag, _ = identification.split(';') - xml.tag! "Authorization_Num", authorization_num - xml.tag! "Transaction_Tag", transaction_tag + xml.tag! 'Authorization_Num', authorization_num + xml.tag! 'Transaction_Tag', transaction_tag end def add_amount(xml, money, options) @@ -227,59 +231,71 @@ def add_amount(xml, money, options) def add_credit_card(xml, credit_card, options) if credit_card.respond_to?(:track_data) && credit_card.track_data.present? - xml.tag! "Track1", credit_card.track_data - xml.tag! "Ecommerce_Flag", "R" + xml.tag! 'Track1', credit_card.track_data + xml.tag! 'Ecommerce_Flag', 'R' else - xml.tag! "Card_Number", credit_card.number - xml.tag! "Expiry_Date", expdate(credit_card) - xml.tag! "CardHoldersName", credit_card.name - xml.tag! "CardType", card_type(credit_card.brand) + xml.tag! 'Card_Number', credit_card.number + xml.tag! 'Expiry_Date', expdate(credit_card) + xml.tag! 'CardHoldersName', credit_card.name + xml.tag! 'CardType', card_type(credit_card.brand) + add_credit_card_eci(xml, credit_card, options) add_credit_card_verification_strings(xml, credit_card, options) end end + def add_credit_card_eci(xml, credit_card, options) + eci = if credit_card.is_a?(NetworkTokenizationCreditCard) && credit_card.source == :apple_pay && card_brand(credit_card) == 'discover' + # Discover requires any Apple Pay transaction, regardless of in-app + # or web, and regardless of the ECI contained in the PKPaymentToken, + # to have an ECI value explicitly of 04. + '04' + else + (credit_card.respond_to?(:eci) ? credit_card.eci : nil) || options[:eci] || DEFAULT_ECI + end + + xml.tag! 'Ecommerce_Flag', eci.to_s =~ /^[0-9]+$/ ? eci.to_s.rjust(2, '0') : eci + end + def add_credit_card_verification_strings(xml, credit_card, options) address = options[:billing_address] || options[:address] if address address_values = [] [:address1, :zip, :city, :state, :country].each { |part| address_values << address[part].to_s } - xml.tag! "VerificationStr1", address_values.join("|") + xml.tag! 'VerificationStr1', address_values.join('|') end if credit_card.is_a?(NetworkTokenizationCreditCard) add_network_tokenization_credit_card(xml, credit_card) - elsif credit_card.verification_value? - xml.tag! "CVD_Presence_Ind", "1" - xml.tag! "VerificationStr2", credit_card.verification_value + else + if credit_card.verification_value? + xml.tag! 'CVD_Presence_Ind', '1' + xml.tag! 'VerificationStr2', credit_card.verification_value + end + + add_card_authentication_data(xml, options) end end def add_network_tokenization_credit_card(xml, credit_card) - xml.tag!("Ecommerce_Flag", credit_card.eci) - case card_brand(credit_card).to_sym - when :visa - xml.tag!("XID", credit_card.transaction_id) if credit_card.transaction_id - xml.tag!("CAVV", credit_card.payment_cryptogram) - when :mastercard - xml.tag!("XID", credit_card.transaction_id) if credit_card.transaction_id - xml.tag!("CAVV", credit_card.payment_cryptogram) when :american_express cryptogram = Base64.decode64(credit_card.payment_cryptogram) - xml.tag!("XID", Base64.encode64(cryptogram[20...40])) - xml.tag!("CAVV", Base64.encode64(cryptogram[0...20])) + xml.tag!('XID', Base64.encode64(cryptogram[20...40])) + xml.tag!('CAVV', Base64.encode64(cryptogram[0...20])) + else + xml.tag!('XID', credit_card.transaction_id) if credit_card.transaction_id + xml.tag!('CAVV', credit_card.payment_cryptogram) end end def add_card_authentication_data(xml, options) - xml.tag! "CAVV", options[:cavv] - xml.tag! "XID", options[:xid] - xml.tag! "Ecommerce_Flag", options[:eci] + xml.tag! 'CAVV', options[:cavv] + xml.tag! 'XID', options[:xid] end - def add_credit_card_token(xml, store_authorization) - params = store_authorization.split(";") + def add_credit_card_token(xml, store_authorization, options) + params = store_authorization.split(';') credit_card = CreditCard.new( :brand => params[1], :first_name => params[2], @@ -287,36 +303,37 @@ def add_credit_card_token(xml, store_authorization) :month => params[4], :year => params[5]) - xml.tag! "TransarmorToken", params[0] - xml.tag! "Expiry_Date", expdate(credit_card) - xml.tag! "CardHoldersName", credit_card.name - xml.tag! "CardType", card_type(credit_card.brand) + xml.tag! 'TransarmorToken', params[0] + xml.tag! 'Expiry_Date', expdate(credit_card) + xml.tag! 'CardHoldersName', credit_card.name + xml.tag! 'CardType', card_type(credit_card.brand) + add_card_authentication_data(xml, options) end def add_customer_data(xml, options) - xml.tag! "Customer_Ref", options[:customer] if options[:customer] - xml.tag! "Client_IP", options[:ip] if options[:ip] - xml.tag! "Client_Email", options[:email] if options[:email] + xml.tag! 'Customer_Ref', options[:customer] if options[:customer] + xml.tag! 'Client_IP', options[:ip] if options[:ip] + xml.tag! 'Client_Email', options[:email] if options[:email] end def add_address(xml, options) if address = (options[:billing_address] || options[:address]) - xml.tag! "ZipCode", address[:zip] + xml.tag! 'ZipCode', address[:zip] end end def add_invoice(xml, options) - xml.tag! "Reference_No", options[:order_id] - xml.tag! "Reference_3", options[:description] if options[:description] + xml.tag! 'Reference_No', options[:order_id] + xml.tag! 'Reference_3', options[:description] if options[:description] end def add_tax_fields(xml, options) - xml.tag! "Tax1Amount", options[:tax1_amount] if options[:tax1_amount] - xml.tag! "Tax1Number", options[:tax1_number] if options[:tax1_number] + xml.tag! 'Tax1Amount', options[:tax1_amount] if options[:tax1_amount] + xml.tag! 'Tax1Number', options[:tax1_number] if options[:tax1_number] end def add_level_3(xml, options) - xml.tag!("Level3") { |x| x << options[:level_3] } if options[:level_3] + xml.tag!('Level3') { |x| x << options[:level_3] } if options[:level_3] end def expdate(credit_card) @@ -362,9 +379,9 @@ def authorization_from(response) response[:authorization_num], response[:transaction_tag], (response[:dollar_amount].to_f * 100).round - ].join(";") + ].join(';') else - "" + '' end end @@ -377,7 +394,7 @@ def store_authorization_from(response, credit_card) credit_card.last_name, credit_card.month, credit_card.year - ].map { |value| value.to_s.gsub(/;/, "") }.join(";") + ].map { |value| value.to_s.gsub(/;/, '') }.join(';') else raise StandardError, "TransArmor support is not enabled on your #{display_name} account" end @@ -391,10 +408,10 @@ def money_from_authorization(auth) def message_from(response) if(response[:faultcode] && response[:faultstring]) response[:faultstring] - elsif(response[:error_number] && response[:error_number] != "0") + elsif(response[:error_number] && response[:error_number] != '0') response[:error_description] else - result = (response[:exact_message] || "") + result = (response[:exact_message] || '') result << " - #{response[:bank_message]}" if response[:bank_message].present? result end @@ -402,7 +419,7 @@ def message_from(response) def parse_error(error) { - :transaction_approved => "false", + :transaction_approved => 'false', :error_number => error.code, :error_description => error.body, :ecommerce_error_code => error.body.gsub(/[^\d]/, '') @@ -417,16 +434,16 @@ def parse(xml) response = {} xml = REXML::Document.new(xml) - if root = REXML::XPath.first(xml, "//TransactionResult") + if root = REXML::XPath.first(xml, '//TransactionResult') parse_elements(response, root) end - response.delete_if{ |k,v| SENSITIVE_FIELDS.include?(k) } + response.delete_if { |k, v| SENSITIVE_FIELDS.include?(k) } end def parse_elements(response, root) root.elements.to_a.each do |node| - response[node.name.gsub(/EXact/, "Exact").underscore.to_sym] = (node.text || "").strip + response[node.name.gsub(/EXact/, 'Exact').underscore.to_sym] = (node.text || '').strip end end end diff --git a/lib/active_merchant/billing/gateways/firstdata_e4_v27.rb b/lib/active_merchant/billing/gateways/firstdata_e4_v27.rb new file mode 100644 index 00000000000..31c16f7d1e5 --- /dev/null +++ b/lib/active_merchant/billing/gateways/firstdata_e4_v27.rb @@ -0,0 +1,446 @@ +module ActiveMerchant #:nodoc: + module Billing #:nodoc: + class FirstdataE4V27Gateway < Gateway + self.test_url = 'https://api.demo.globalgatewaye4.firstdata.com/transaction/v27' + self.live_url = 'https://api.globalgatewaye4.firstdata.com/transaction/v27' + + TRANSACTIONS = { + sale: '00', + authorization: '01', + verify: '05', + capture: '32', + void: '33', + credit: '34', + store: '05' + } + + SUCCESS = 'true' + + SENSITIVE_FIELDS = [:cvdcode, :expiry_date, :card_number] + + BRANDS = { + :visa => 'Visa', + :master => 'Mastercard', + :american_express => 'American Express', + :jcb => 'JCB', + :discover => 'Discover' + } + + DEFAULT_ECI = '07' + + self.supported_cardtypes = BRANDS.keys + self.supported_countries = ['CA', 'US'] + self.default_currency = 'USD' + self.homepage_url = 'http://www.firstdata.com' + self.display_name = 'FirstData Global Gateway e4 v27' + + STANDARD_ERROR_CODE_MAPPING = { + # Bank error codes: https://support.payeezy.com/hc/en-us/articles/203730509-First-Data-Global-Gateway-e4-Bank-Response-Codes + '201' => STANDARD_ERROR_CODE[:incorrect_number], + '531' => STANDARD_ERROR_CODE[:invalid_cvc], + '503' => STANDARD_ERROR_CODE[:invalid_cvc], + '811' => STANDARD_ERROR_CODE[:invalid_cvc], + '605' => STANDARD_ERROR_CODE[:invalid_expiry_date], + '522' => STANDARD_ERROR_CODE[:expired_card], + '303' => STANDARD_ERROR_CODE[:card_declined], + '530' => STANDARD_ERROR_CODE[:card_declined], + '401' => STANDARD_ERROR_CODE[:call_issuer], + '402' => STANDARD_ERROR_CODE[:call_issuer], + '501' => STANDARD_ERROR_CODE[:pickup_card], + # Ecommerce error codes: https://support.payeezy.com/hc/en-us/articles/203730499-eCommerce-Response-Codes-ETG-e4-Transaction-Gateway-Codes + '22' => STANDARD_ERROR_CODE[:invalid_number], + '25' => STANDARD_ERROR_CODE[:invalid_expiry_date], + '31' => STANDARD_ERROR_CODE[:incorrect_cvc], + '44' => STANDARD_ERROR_CODE[:incorrect_zip], + '42' => STANDARD_ERROR_CODE[:processing_error] + } + + def initialize(options = {}) + requires!(options, :login, :password, :key_id, :hmac_key) + @options = options + + super + end + + def authorize(money, credit_card_or_store_authorization, options = {}) + commit(:authorization, build_sale_or_authorization_request(money, credit_card_or_store_authorization, options)) + end + + def purchase(money, credit_card_or_store_authorization, options = {}) + commit(:sale, build_sale_or_authorization_request(money, credit_card_or_store_authorization, options)) + end + + def capture(money, authorization, options = {}) + commit(:capture, build_capture_or_credit_request(money, authorization, options)) + end + + def void(authorization, options = {}) + commit(:void, build_capture_or_credit_request(money_from_authorization(authorization), authorization, options)) + end + + def refund(money, authorization, options = {}) + commit(:credit, build_capture_or_credit_request(money, authorization, options)) + end + + def verify(credit_card, options = {}) + commit(:verify, build_sale_or_authorization_request(0, credit_card, options)) + end + + # Tokenize a credit card with TransArmor + # + # The TransArmor token and other card data necessary for subsequent + # transactions is stored in the response's +authorization+ attribute. + # The authorization string may be passed to +authorize+ and +purchase+ + # instead of a +ActiveMerchant::Billing::CreditCard+ instance. + # + # TransArmor support must be explicitly activated on your gateway + # account by FirstData. If your authorization string is empty, contact + # FirstData support for account setup assistance. + # + # https://support.payeezy.com/hc/en-us/articles/203731189-TransArmor-Tokenization + def store(credit_card, options = {}) + commit(:store, build_store_request(credit_card, options), credit_card) + end + + def verify_credentials + response = void('0') + response.message != 'Unauthorized Request. Bad or missing credentials.' + end + + def supports_scrubbing? + true + end + + def scrub(transcript) + transcript. + gsub(%r(().+()), '\1[FILTERED]\2'). + gsub(%r(().+()), '\1[FILTERED]\2'). + gsub(%r(().+())i, '\1[FILTERED]\2'). + gsub(%r(().+()), '\1[FILTERED]\2'). + gsub(%r((CARD NUMBER\s+: )#+\d+), '\1[FILTERED]') + end + + def supports_network_tokenization? + true + end + + private + + def build_request(action, body) + xml = Builder::XmlMarkup.new + + xml.instruct! + xml.tag! 'Transaction', xmlns: 'http://secure2.e-xact.com/vplug-in/transaction/rpc-enc/encodedTypes' do + add_credentials(xml) + add_transaction_type(xml, action) + xml << body + end + + xml.target! + end + + def build_sale_or_authorization_request(money, credit_card_or_store_authorization, options) + xml = Builder::XmlMarkup.new + + add_amount(xml, money, options) + + if credit_card_or_store_authorization.is_a? String + add_credit_card_token(xml, credit_card_or_store_authorization, options) + else + add_credit_card(xml, credit_card_or_store_authorization, options) + end + + add_address(xml, options) + add_customer_data(xml, options) + add_invoice(xml, options) + add_tax_fields(xml, options) + add_level_3(xml, options) + + xml.target! + end + + def build_capture_or_credit_request(money, identification, options) + xml = Builder::XmlMarkup.new + + add_identification(xml, identification) + add_amount(xml, money, options) + add_customer_data(xml, options) + add_card_authentication_data(xml, options) + + xml.target! + end + + def build_store_request(credit_card, options) + xml = Builder::XmlMarkup.new + + add_credit_card(xml, credit_card, options) + add_address(xml, options) + add_customer_data(xml, options) + + xml.target! + end + + def add_credentials(xml) + xml.tag! 'ExactID', @options[:login] + xml.tag! 'Password', @options[:password] + end + + def add_transaction_type(xml, action) + xml.tag! 'Transaction_Type', TRANSACTIONS[action] + end + + def add_identification(xml, identification) + authorization_num, transaction_tag, _ = identification.split(';') + + xml.tag! 'Authorization_Num', authorization_num + xml.tag! 'Transaction_Tag', transaction_tag + end + + def add_amount(xml, money, options) + currency_code = options[:currency] || default_currency + xml.tag! 'DollarAmount', localized_amount(money, currency_code) + xml.tag! 'Currency', currency_code + end + + def add_credit_card(xml, credit_card, options) + if credit_card.respond_to?(:track_data) && credit_card.track_data.present? + xml.tag! 'Track1', credit_card.track_data + xml.tag! 'Ecommerce_Flag', 'R' + else + xml.tag! 'Card_Number', credit_card.number + xml.tag! 'Expiry_Date', expdate(credit_card) + xml.tag! 'CardHoldersName', credit_card.name + xml.tag! 'CardType', card_type(credit_card.brand) + xml.tag! 'WalletProviderID', options[:wallet_provider_id] if options[:wallet_provider_id] + + add_credit_card_eci(xml, credit_card, options) + add_credit_card_verification_strings(xml, credit_card, options) + end + end + + def add_credit_card_eci(xml, credit_card, options) + eci = if credit_card.is_a?(NetworkTokenizationCreditCard) && credit_card.source == :apple_pay && card_brand(credit_card) == 'discover' + # Discover requires any Apple Pay transaction, regardless of in-app + # or web, and regardless of the ECI contained in the PKPaymentToken, + # to have an ECI value explicitly of 04. + '04' + else + (credit_card.respond_to?(:eci) ? credit_card.eci : nil) || options[:eci] || DEFAULT_ECI + end + + xml.tag! 'Ecommerce_Flag', eci.to_s =~ /^[0-9]+$/ ? eci.to_s.rjust(2, '0') : eci + end + + def add_credit_card_verification_strings(xml, credit_card, options) + if credit_card.is_a?(NetworkTokenizationCreditCard) + add_network_tokenization_credit_card(xml, credit_card) + else + if credit_card.verification_value? + xml.tag! 'CVD_Presence_Ind', '1' + xml.tag! 'CVDCode', credit_card.verification_value + end + + add_card_authentication_data(xml, options) + end + end + + def add_network_tokenization_credit_card(xml, credit_card) + case card_brand(credit_card).to_sym + when :american_express + cryptogram = Base64.decode64(credit_card.payment_cryptogram) + xml.tag!('XID', Base64.encode64(cryptogram[20...40])) + xml.tag!('CAVV', Base64.encode64(cryptogram[0...20])) + else + xml.tag!('XID', credit_card.transaction_id) if credit_card.transaction_id + xml.tag!('CAVV', credit_card.payment_cryptogram) + end + end + + def add_card_authentication_data(xml, options) + xml.tag! 'CAVV', options[:cavv] + xml.tag! 'XID', options[:xid] + end + + def add_credit_card_token(xml, store_authorization, options) + params = store_authorization.split(';') + credit_card = CreditCard.new( + :brand => params[1], + :first_name => params[2], + :last_name => params[3], + :month => params[4], + :year => params[5]) + + xml.tag! 'TransarmorToken', params[0] + xml.tag! 'Expiry_Date', expdate(credit_card) + xml.tag! 'CardHoldersName', credit_card.name + xml.tag! 'CardType', card_type(credit_card.brand) + xml.tag! 'WalletProviderID', options[:wallet_provider_id] if options[:wallet_provider_id] + add_card_authentication_data(xml, options) + end + + def add_customer_data(xml, options) + xml.tag! 'Customer_Ref', options[:customer] if options[:customer] + xml.tag! 'Client_IP', options[:ip] if options[:ip] + xml.tag! 'Client_Email', options[:email] if options[:email] + end + + def add_address(xml, options) + if (address = options[:billing_address] || options[:address]) + xml.tag! 'Address' do + xml.tag! 'Address1', address[:address1] + xml.tag! 'Address2', address[:address2] if address[:address2] + xml.tag! 'City', address[:city] + xml.tag! 'State', address[:state] + xml.tag! 'Zip', address[:zip] + xml.tag! 'CountryCode', address[:country] + end + xml.tag! 'ZipCode', address[:zip] + end + end + + def add_invoice(xml, options) + xml.tag! 'Reference_No', options[:order_id] + xml.tag! 'Reference_3', options[:description] if options[:description] + end + + def add_tax_fields(xml, options) + xml.tag! 'Tax1Amount', options[:tax1_amount] if options[:tax1_amount] + xml.tag! 'Tax1Number', options[:tax1_number] if options[:tax1_number] + end + + def add_level_3(xml, options) + xml.tag!('Level3') { |x| x << options[:level_3] } if options[:level_3] + end + + def expdate(credit_card) + "#{format(credit_card.month, :two_digits)}#{format(credit_card.year, :two_digits)}" + end + + def card_type(credit_card_brand) + BRANDS[credit_card_brand.to_sym] if credit_card_brand + end + + def commit(action, data, credit_card = nil) + url = (test? ? self.test_url : self.live_url) + request = build_request(action, data) + begin + response = parse(ssl_post(url, request, headers('POST', url, request))) + rescue ResponseError => e + response = parse_error(e.response) + end + + Response.new(successful?(response), message_from(response), response, + :test => test?, + :authorization => successful?(response) ? response_authorization(action, response, credit_card) : '', + :avs_result => {:code => response[:avs]}, + :cvv_result => response[:cvv2], + :error_code => standard_error_code(response) + ) + end + + def headers(method, url, request) + content_type = 'application/xml' + content_digest = Digest::SHA1.hexdigest(request) + sending_time = Time.now.utc.iso8601 + payload = [method, content_type, content_digest, sending_time, url.split('.com')[1]].join("\n") + hmac = OpenSSL::HMAC.digest('sha1', @options[:hmac_key], payload) + encoded = Base64.strict_encode64(hmac) + + { + 'x-gge4-date' => sending_time, + 'x-gge4-content-sha1' => content_digest, + 'Authorization' => 'GGE4_API ' + @options[:key_id].to_s + ':' + encoded, + 'Accepts' => content_type, + 'Content-Type' => content_type + } + end + + def successful?(response) + response[:transaction_approved] == SUCCESS + end + + def response_authorization(action, response, credit_card) + if action == :store + store_authorization_from(response, credit_card) + else + authorization_from(response) + end + end + + def authorization_from(response) + if response[:authorization_num] && response[:transaction_tag] + [ + response[:authorization_num], + response[:transaction_tag], + (response[:dollar_amount].to_f * 100).round + ].join(';') + else + '' + end + end + + def store_authorization_from(response, credit_card) + if response[:transarmor_token].present? + [ + response[:transarmor_token], + credit_card.brand, + credit_card.first_name, + credit_card.last_name, + credit_card.month, + credit_card.year + ].map { |value| value.to_s.tr(';', '') }.join(';') + else + raise StandardError, "TransArmor support is not enabled on your #{display_name} account" + end + end + + def money_from_authorization(auth) + _, _, amount = auth.split(/;/, 3) + amount.to_i + end + + def message_from(response) + if response[:faultcode] && response[:faultstring] + response[:faultstring] + elsif response[:error_number] && response[:error_number] != '0' + response[:error_description] + else + result = (response[:exact_message] || '') + result << " - #{response[:bank_message]}" if response[:bank_message].present? + result + end + end + + def parse_error(error) + { + :transaction_approved => 'false', + :error_number => error.code, + :error_description => error.body, + :ecommerce_error_code => error.body.gsub(/[^\d]/, '') + } + end + + def standard_error_code(response) + STANDARD_ERROR_CODE_MAPPING[response[:bank_resp_code] || response[:ecommerce_error_code]] + end + + def parse(xml) + response = {} + xml = REXML::Document.new(xml) + + if (root = REXML::XPath.first(xml, '//TransactionResult')) + parse_elements(response, root) + end + + SENSITIVE_FIELDS.each { |key| response.delete(key) } + response + end + + def parse_elements(response, root) + root.elements.to_a.each do |node| + response[node.name.gsub(/EXact/, 'Exact').underscore.to_sym] = (node.text || '').strip + end + end + end + end +end diff --git a/lib/active_merchant/billing/gateways/flo2cash.rb b/lib/active_merchant/billing/gateways/flo2cash.rb index 9db34880391..1f5c9d8076b 100644 --- a/lib/active_merchant/billing/gateways/flo2cash.rb +++ b/lib/active_merchant/billing/gateways/flo2cash.rb @@ -13,10 +13,10 @@ class Flo2cashGateway < Gateway self.supported_cardtypes = [:visa, :master, :american_express, :diners_club] BRAND_MAP = { - "visa" => "VISA", - "master" => "MC", - "american_express" => "AMEX", - "diners_club" => "DINERS" + 'visa' => 'VISA', + 'master' => 'MC', + 'american_express' => 'AMEX', + 'diners_club' => 'DINERS' } def initialize(options={}) @@ -37,7 +37,7 @@ def authorize(amount, payment_method, options={}) add_payment_method(post, payment_method) add_customer_data(post, options) - commit("ProcessAuthorise", post) + commit('ProcessAuthorise', post) end def capture(amount, authorization, options={}) @@ -46,7 +46,7 @@ def capture(amount, authorization, options={}) add_reference(post, authorization) add_customer_data(post, options) - commit("ProcessCapture", post) + commit('ProcessCapture', post) end def refund(amount, authorization, options={}) @@ -55,7 +55,7 @@ def refund(amount, authorization, options={}) add_reference(post, authorization) add_customer_data(post, options) - commit("ProcessRefund", post) + commit('ProcessRefund', post) end def supports_scrubbing? @@ -71,8 +71,8 @@ def scrub(transcript) private - CURRENCY_CODES = Hash.new{|h,k| raise ArgumentError.new("Unsupported currency: #{k}")} - CURRENCY_CODES["NZD"] = "554" + CURRENCY_CODES = Hash.new { |h, k| raise ArgumentError.new("Unsupported currency: #{k}") } + CURRENCY_CODES['NZD'] = '554' def add_invoice(post, money, options) post[:Amount] = amount(money) @@ -107,7 +107,7 @@ def commit(action, post) begin raw = parse(ssl_post(url, data, headers(action)), action) rescue ActiveMerchant::ResponseError => e - if(e.response.code == "500" && e.response.body.start_with?(" ("Basic " + Base64.strict_encode64("#{@options[:api_key]}:#{@options[:secret]}")), + 'Authorization' => ('Basic ' + Base64.strict_encode64("#{@options[:api_key]}:#{@options[:secret]}")), 'X-Forte-Auth-Account-Id' => "act_#{@options[:account_id]}", 'Content-Type' => 'application/json' } @@ -240,17 +253,17 @@ def format_card_brand(card_brand) end def split_authorization(authorization) - authorization.split("#") + authorization.split('#') end def authorization_code_from(authorization) - _, authorization_code = split_authorization(authorization) - authorization_code + _, authorization_code, _, original_auth_authorization_code = split_authorization(authorization) + original_auth_authorization_code.present? ? original_auth_authorization_code : authorization_code end def transaction_id_from(authorization) - transaction_id, _ = split_authorization(authorization) - transaction_id + transaction_id, _, original_auth_transaction_id, _= split_authorization(authorization) + original_auth_transaction_id.present? ? original_auth_transaction_id : transaction_id end end end diff --git a/lib/active_merchant/billing/gateways/garanti.rb b/lib/active_merchant/billing/gateways/garanti.rb index 34533bca4bb..3c7f19efc5d 100644 --- a/lib/active_merchant/billing/gateways/garanti.rb +++ b/lib/active_merchant/billing/gateways/garanti.rb @@ -5,7 +5,7 @@ class GarantiGateway < Gateway self.test_url = 'https://sanalposprovtest.garanti.com.tr/VPServlet' # The countries the gateway supports merchants from as 2 digit ISO country codes - self.supported_countries = ['US','TR'] + self.supported_countries = ['US', 'TR'] # The card types supported by the payment gateway self.supported_cardtypes = [:visa, :master, :american_express, :discover] @@ -30,31 +30,30 @@ class GarantiGateway < Gateway 'JPY' => 392 } - def initialize(options = {}) requires!(options, :login, :password, :terminal_id, :merchant_id) super end def purchase(money, credit_card, options = {}) - options = options.merge(:gvp_order_type => "sales") + options = options.merge(:gvp_order_type => 'sales') commit(money, build_sale_request(money, credit_card, options)) end def authorize(money, credit_card, options = {}) - options = options.merge(:gvp_order_type => "preauth") + options = options.merge(:gvp_order_type => 'preauth') commit(money, build_authorize_request(money, credit_card, options)) end def capture(money, ref_id, options = {}) - options = options.merge(:gvp_order_type => "postauth") + options = options.merge(:gvp_order_type => 'postauth') commit(money, build_capture_request(money, ref_id, options)) end private def security_data - rjusted_terminal_id = @options[:terminal_id].to_s.rjust(9, "0") + rjusted_terminal_id = @options[:terminal_id].to_s.rjust(9, '0') Digest::SHA1.hexdigest(@options[:password].to_s + rjusted_terminal_id).upcase end @@ -68,7 +67,7 @@ def build_xml_request(money, credit_card, options, &block) hash_data = generate_hash_data(format_order_id(options[:order_id]), @options[:terminal_id], card_number, amount(money), security_data) xml = Builder::XmlMarkup.new(:indent => 2) - xml.instruct! :xml, :version => "1.0", :encoding => "UTF-8" + xml.instruct! :xml, :version => '1.0', :encoding => 'UTF-8' xml.tag! 'GVPSRequest' do xml.tag! 'Mode', test? ? 'TEST' : 'PROD' @@ -103,7 +102,7 @@ def build_sale_request(money, credit_card, options) end def build_authorize_request(money, credit_card, options) - build_xml_request(money, credit_card, options) do |xml| + build_xml_request(money, credit_card, options) do |xml| add_customer_data(xml, options) add_order_data(xml, options) do add_addresses(xml, options) @@ -117,7 +116,7 @@ def build_authorize_request(money, credit_card, options) def build_capture_request(money, ref_id, options) options = options.merge(:order_id => ref_id) - build_xml_request(money, ref_id, options) do |xml| + build_xml_request(money, ref_id, options) do |xml| add_customer_data(xml, options) add_order_data(xml, options) add_transaction_data(xml, money, options) @@ -182,7 +181,7 @@ def add_addresses(xml, options) def add_address(xml, address) xml.tag! 'Name', normalize(address[:name]) address_text = address[:address1] - address_text << " #{ address[:address2]}" if address[:address2] + address_text << " #{address[:address2]}" if address[:address2] xml.tag! 'Text', normalize(address_text) xml.tag! 'City', normalize(address[:city]) xml.tag! 'District', normalize(address[:state]) @@ -196,11 +195,9 @@ def normalize(text) return unless text if ActiveSupport::Inflector.method(:transliterate).arity == -2 - ActiveSupport::Inflector.transliterate(text,'') - elsif RUBY_VERSION >= '1.9' - text.gsub(/[^\x00-\x7F]+/, '') + ActiveSupport::Inflector.transliterate(text, '') else - ActiveSupport::Inflector.transliterate(text).to_s + text.gsub(/[^\x00-\x7F]+/, '') end end @@ -217,18 +214,18 @@ def currency_code(currency) CURRENCY_CODES[currency] || CURRENCY_CODES[default_currency] end - def commit(money,request) + def commit(money, request) url = test? ? self.test_url : self.live_url - raw_response = ssl_post(url, "data=" + request) + raw_response = ssl_post(url, 'data=' + request) response = parse(raw_response) success = success?(response) Response.new(success, - success ? 'Approved' : "Declined (Reason: #{response[:reason_code]} - #{response[:error_msg]} - #{response[:sys_err_msg]})", - response, - :test => test?, - :authorization => response[:order_id]) + success ? 'Approved' : "Declined (Reason: #{response[:reason_code]} - #{response[:error_msg]} - #{response[:sys_err_msg]})", + response, + :test => test?, + :authorization => response[:order_id]) end def parse(body) @@ -243,14 +240,14 @@ def parse(body) def parse_element(response, node) if node.has_elements? - node.elements.each{|element| parse_element(response, element) } + node.elements.each { |element| parse_element(response, element) } else response[node.name.underscore.to_sym] = node.text end end def success?(response) - response[:message] == "Approved" + response[:message] == 'Approved' end def strip_invalid_xml_chars(xml) @@ -260,4 +257,3 @@ def strip_invalid_xml_chars(xml) end end end - diff --git a/lib/active_merchant/billing/gateways/global_collect.rb b/lib/active_merchant/billing/gateways/global_collect.rb index 8c1245cc8e6..370780d14f1 100644 --- a/lib/active_merchant/billing/gateways/global_collect.rb +++ b/lib/active_merchant/billing/gateways/global_collect.rb @@ -1,17 +1,14 @@ module ActiveMerchant #:nodoc: module Billing #:nodoc: class GlobalCollectGateway < Gateway - self.display_name = "GlobalCollect" - self.homepage_url = "http://www.globalcollect.com/" + self.display_name = 'GlobalCollect' + self.homepage_url = 'http://www.globalcollect.com/' - self.test_url = "https://api-sandbox.globalcollect.com/" - self.live_url = "https://api.globalcollect.com/" + self.test_url = 'https://eu.sandbox.api-ingenico.com' + self.live_url = 'https://api.globalcollect.com' - self.supported_countries = %w(AD AE AT AU BD BE BG BN CA CH CY CZ DE DK - EE EG ES FI FR GB GI GR HK HU ID IE IL IM IN IS IT JO KW LB LI LK LT LU - LV MC MT MU MV MX MY NL NO NZ OM PH PL PT QA RO SA SE SG SI SK SM TR TT - UM US VA VN ZA) - self.default_currency = "USD" + self.supported_countries = ['AD', 'AE', 'AG', 'AI', 'AL', 'AM', 'AO', 'AR', 'AS', 'AT', 'AU', 'AW', 'AX', 'AZ', 'BA', 'BB', 'BD', 'BE', 'BF', 'BG', 'BH', 'BI', 'BJ', 'BL', 'BM', 'BN', 'BO', 'BQ', 'BR', 'BS', 'BT', 'BW', 'BY', 'BZ', 'CA', 'CC', 'CD', 'CF', 'CH', 'CI', 'CK', 'CL', 'CM', 'CN', 'CO', 'CR', 'CU', 'CV', 'CW', 'CX', 'CY', 'CZ', 'DE', 'DJ', 'DK', 'DM', 'DO', 'DZ', 'EC', 'EE', 'EG', 'ER', 'ES', 'ET', 'FI', 'FJ', 'FK', 'FM', 'FO', 'FR', 'GA', 'GB', 'GD', 'GE', 'GF', 'GH', 'GI', 'GL', 'GM', 'GN', 'GP', 'GQ', 'GR', 'GS', 'GT', 'GU', 'GW', 'GY', 'HK', 'HN', 'HR', 'HT', 'HU', 'ID', 'IE', 'IL', 'IM', 'IN', 'IS', 'IT', 'JM', 'JO', 'JP', 'KE', 'KG', 'KH', 'KI', 'KM', 'KN', 'KR', 'KW', 'KY', 'KZ', 'LA', 'LB', 'LC', 'LI', 'LK', 'LR', 'LS', 'LT', 'LU', 'LV', 'MA', 'MC', 'MD', 'ME', 'MF', 'MG', 'MH', 'MK', 'MM', 'MN', 'MO', 'MP', 'MQ', 'MR', 'MS', 'MT', 'MU', 'MV', 'MW', 'MX', 'MY', 'MZ', 'NA', 'NC', 'NE', 'NG', 'NI', 'NL', 'NO', 'NP', 'NR', 'NU', 'NZ', 'OM', 'PA', 'PE', 'PF', 'PG', 'PH', 'PL', 'PN', 'PS', 'PT', 'PW', 'QA', 'RE', 'RO', 'RS', 'RU', 'RW', 'SA', 'SB', 'SC', 'SE', 'SG', 'SH', 'SI', 'SJ', 'SK', 'SL', 'SM', 'SN', 'SR', 'ST', 'SV', 'SZ', 'TC', 'TD', 'TG', 'TH', 'TJ', 'TL', 'TM', 'TN', 'TO', 'TR', 'TT', 'TV', 'TW', 'TZ', 'UA', 'UG', 'US', 'UY', 'UZ', 'VC', 'VE', 'VG', 'VI', 'VN', 'WF', 'WS', 'ZA', 'ZM', 'ZW'] + self.default_currency = 'USD' self.money_format = :cents self.supported_cardtypes = [:visa, :master, :american_express, :discover] @@ -30,17 +27,20 @@ def purchase(money, payment, options={}) def authorize(money, payment, options={}) post = nestable_hash add_order(post, money, options) - add_payment(post, payment) + add_payment(post, payment, options) add_customer_data(post, options, payment) add_address(post, payment, options) + add_creator_info(post, options) + add_fraud_fields(post, options) commit(:authorize, post) end def capture(money, authorization, options={}) post = nestable_hash - add_order(post, money, options) + add_order(post, money, options, capture: true) add_customer_data(post, options) + add_creator_info(post, options) commit(:capture, post, authorization) end @@ -48,11 +48,13 @@ def refund(money, authorization, options={}) post = nestable_hash add_amount(post, money, options) add_refund_customer_data(post, options) + add_creator_info(post, options) commit(:refund, post, authorization) end def void(authorization, options={}) post = nestable_hash + add_creator_info(post, options) commit(:void, post, authorization) end @@ -70,126 +72,139 @@ def supports_scrubbing? def scrub(transcript) transcript. gsub(%r((Authorization: )[^\\]*)i, '\1[FILTERED]'). - gsub(%r(("cardNumber\\":\\")\d+), '\1[FILTERED]'). - gsub(%r(("cvv\\":\\")\d+), '\1[FILTERED]') + gsub(%r(("cardNumber\\+":\\+")\d+), '\1[FILTERED]'). + gsub(%r(("cvv\\+":\\+")\d+), '\1[FILTERED]') end private BRAND_MAP = { - "visa" => "1", - "american_express" => "2", - "master" => "3", - "discover" => "128", - "jcb" => "125", - "diners_club" => "132" + 'visa' => '1', + 'american_express' => '2', + 'master' => '3', + 'discover' => '128', + 'jcb' => '125', + 'diners_club' => '132' } - def add_order(post, money, options) - post["order"]["amountOfMoney"] = { - "amount" => amount(money), - "currencyCode" => options[:currency] || currency(money) - } - post["order"]["references"] = { - "merchantReference" => options[:order_id], - "descriptor" => options[:description] # Max 256 chars + def add_order(post, money, options, capture: false) + if capture + post['amount'] = amount(money) + else + add_amount(post['order'], money, options) + end + post['order']['references'] = { + 'merchantReference' => options[:order_id], + 'descriptor' => options[:description] # Max 256 chars } - post["order"]["references"]["invoiceData"] = { - "invoiceNumber" => options[:invoice] + post['order']['references']['invoiceData'] = { + 'invoiceNumber' => options[:invoice] } end + def add_creator_info(post, options) + post['sdkIdentifier'] = options[:sdk_identifier] if options[:sdk_identifier] + post['sdkCreator'] = options[:sdk_creator] if options[:sdk_creator] + post['integrator'] = options[:integrator] if options[:integrator] + post['shoppingCartExtension'] = {} + post['shoppingCartExtension']['creator'] = options[:creator] if options[:creator] + post['shoppingCartExtension']['name'] = options[:name] if options[:name] + post['shoppingCartExtension']['version'] = options[:version] if options[:version] + post['shoppingCartExtension']['extensionID'] = options[:extension_ID] if options[:extension_ID] + end + def add_amount(post, money, options={}) - post["amountOfMoney"] = { - "amount" => amount(money), - "currencyCode" => options[:currency] || currency(money) + post['amountOfMoney'] = { + 'amount' => amount(money), + 'currencyCode' => options[:currency] || currency(money) } end - def add_payment(post, payment) + def add_payment(post, payment, options) year = format(payment.year, :two_digits) month = format(payment.month, :two_digits) expirydate = "#{month}#{year}" + pre_authorization = options[:pre_authorization] ? 'PRE_AUTHORIZATION' : 'FINAL_AUTHORIZATION' - post["cardPaymentMethodSpecificInput"] = { - "paymentProductId" => BRAND_MAP[payment.brand], - "skipAuthentication" => "true", # refers to 3DSecure - "skipFraudService" => "true" + post['cardPaymentMethodSpecificInput'] = { + 'paymentProductId' => BRAND_MAP[payment.brand], + 'skipAuthentication' => 'true', # refers to 3DSecure + 'skipFraudService' => 'true', + 'authorizationMode' => pre_authorization } - post["cardPaymentMethodSpecificInput"]["card"] = { - "cvv" => payment.verification_value, - "cardNumber" => payment.number, - "expiryDate" => expirydate, - "cardholderName" => payment.name + post['cardPaymentMethodSpecificInput']['card'] = { + 'cvv' => payment.verification_value, + 'cardNumber' => payment.number, + 'expiryDate' => expirydate, + 'cardholderName' => payment.name } end def add_customer_data(post, options, payment = nil) - post["order"]["customer"] = { - "merchantCustomerId" => options[:customer] - } if payment - post["order"]["customer"]["personalInformation"] = { - "name" => { - "firstName" => payment.first_name, - "surname" => payment.last_name + post['order']['customer']['personalInformation'] = { + 'name' => { + 'firstName' => payment.first_name[0..14], + 'surname' => payment.last_name[0..69] } } end - post["order"]["companyInformation"] = { - "name" => options[:company] - } - post["order"]["contactDetails"] = { - "emailAddress" => options[:email] - } + post['order']['customer']['merchantCustomerId'] = options[:customer] if options[:customer] + post['order']['customer']['companyInformation']['name'] = options[:company] if options[:company] + post['order']['customer']['contactDetails']['emailAddress'] = options[:email] if options[:email] if address = options[:billing_address] || options[:address] - post["order"]["contactDetails"] = { - "phoneNumber" => address[:phone] - } + post['order']['customer']['contactDetails']['phoneNumber'] = address[:phone] if address[:phone] end end def add_refund_customer_data(post, options) if address = options[:billing_address] || options[:address] - post["customer"]["address"] = { - "countryCode" => address[:country] - } - post["customer"]["contactDetails"] = { - "emailAddress" => options[:email], - "phoneNumber" => address[:phone] + post['customer']['address'] = { + 'countryCode' => address[:country] } + post['customer']['contactDetails']['emailAddress'] = options[:email] if options[:email] + if address = options[:billing_address] || options[:address] + post['customer']['contactDetails']['phoneNumber'] = address[:phone] if address[:phone] + end end end def add_address(post, creditcard, options) - billing_address = options[:billing_address] || options[:address] shipping_address = options[:shipping_address] if billing_address = options[:billing_address] || options[:address] - post["order"]["customer"]["billingAddress"] = { - "street" => billing_address[:address1], - "additionalInfo" => billing_address[:address2], - "zip" => billing_address[:zip], - "city" => billing_address[:city], - "state" => billing_address[:state], - "countryCode" => billing_address[:country] + post['order']['customer']['billingAddress'] = { + 'street' => billing_address[:address1], + 'additionalInfo' => billing_address[:address2], + 'zip' => billing_address[:zip], + 'city' => billing_address[:city], + 'state' => billing_address[:state], + 'countryCode' => billing_address[:country] } end if shipping_address - post["order"]["customer"]["shippingAddress"] = { - "street" => shipping_address[:address1], - "additionalInfo" => shipping_address[:address2], - "zip" => shipping_address[:zip], - "city" => shipping_address[:city], - "state" => shipping_address[:state], - "countryCode" => shipping_address[:country] + post['order']['customer']['shippingAddress'] = { + 'street' => shipping_address[:address1], + 'additionalInfo' => shipping_address[:address2], + 'zip' => shipping_address[:zip], + 'city' => shipping_address[:city], + 'state' => shipping_address[:state], + 'countryCode' => shipping_address[:country] } - post["order"]["customer"]["shippingAddress"]["name"] = { - "firstName" => shipping_address[:firstname], - "surname" => shipping_address[:lastname] + post['order']['customer']['shippingAddress']['name'] = { + 'firstName' => shipping_address[:firstname], + 'surname' => shipping_address[:lastname] } end end + def add_fraud_fields(post, options) + fraud_fields = {} + fraud_fields.merge!(options[:fraud_fields]) if options[:fraud_fields] + fraud_fields[:customerIpAddress] = options[:ip] if options[:ip] + + post['fraudFields'] = fraud_fields unless fraud_fields.empty? + end + def parse(body) JSON.parse(body) end @@ -202,7 +217,7 @@ def uri(action, authorization) uri = "/v1/#{@options[:merchant_id]}/" case action when :authorize - uri + "payments" + uri + 'payments' when :capture uri + "payments/#{authorization}/approve" when :refund @@ -214,30 +229,40 @@ def uri(action, authorization) def commit(action, post, authorization = nil) begin - response = parse(ssl_post(url(action, authorization), post.to_json, headers(action, post, authorization))) + raw_response = ssl_post(url(action, authorization), post.to_json, headers(action, post, authorization)) + response = parse(raw_response) rescue ResponseError => e if e.response.code.to_i >= 400 response = parse(e.response.body) end + rescue JSON::ParserError + response = json_error(raw_response) end succeeded = success_from(response) Response.new( - succeeded, - message_from(succeeded, response), - response, - authorization: authorization_from(succeeded, response), - error_code: error_code_from(succeeded, response), - test: test? + succeeded, + message_from(succeeded, response), + response, + authorization: authorization_from(succeeded, response), + error_code: error_code_from(succeeded, response), + test: test? ) + end + def json_error(raw_response) + { + 'error_message' => 'Invalid response received from the Ingenico ePayments (formerly GlobalCollect) API. Please contact Ingenico ePayments if you continue to receive this message.' \ + " (The raw response returned by the API was #{raw_response.inspect})", + 'status' => 'REJECTED' + } end def headers(action, post, authorization = nil) { - "Content-type" => content_type, - "Authorization" => auth_digest(action, post, authorization), - "Date" => date + 'Content-Type' => content_type, + 'Authorization' => auth_digest(action, post, authorization), + 'Date' => date } end @@ -254,45 +279,61 @@ def auth_digest(action, post, authorization = nil) end def date - @date ||= Time.now.strftime("%a, %d %b %Y %H:%M:%S %Z") # Must be same in digest and HTTP header + @date ||= Time.now.strftime('%a, %d %b %Y %H:%M:%S %Z') # Must be same in digest and HTTP header end def content_type - "application/json" + 'application/json' end def success_from(response) - !response["errorId"] + !response['errorId'] && response['status'] != 'REJECTED' end def message_from(succeeded, response) if succeeded - "Succeeded" + 'Succeeded' else - response["errors"][0]["message"] || "Unable to read error message" + if errors = response['errors'] + errors.first.try(:[], 'message') + elsif response['error_message'] + response['error_message'] + elsif response['status'] + 'Status: ' + response['status'] + else + 'No message available' + end end end def authorization_from(succeeded, response) if succeeded - response["id"] || response["payment"]["id"] || response["paymentResult"]["payment"]["id"] + response['id'] || response['payment']['id'] || response['paymentResult']['payment']['id'] + elsif response['errorId'] + response['errorId'] else - response["errorId"] + 'GATEWAY ERROR' end end def error_code_from(succeeded, response) unless succeeded - response["errors"][0]["code"] || "Unable to read error code" + if errors = response['errors'] + errors.first.try(:[], 'code') + elsif status = response.try(:[], 'statusOutput').try(:[], 'statusCode') + status.to_s + else + 'No error code available' + end end end def nestable_hash - Hash.new {|h,k| h[k] = Hash.new(&h.default_proc) } + Hash.new { |h, k| h[k] = Hash.new(&h.default_proc) } end def capture_requested?(response) - response.params.try(:[], "payment").try(:[], "status") == "CAPTURE_REQUESTED" + response.params.try(:[], 'payment').try(:[], 'status') == 'CAPTURE_REQUESTED' end end end diff --git a/lib/active_merchant/billing/gateways/global_transport.rb b/lib/active_merchant/billing/gateways/global_transport.rb index d88f2feaee5..94087b23e17 100644 --- a/lib/active_merchant/billing/gateways/global_transport.rb +++ b/lib/active_merchant/billing/gateways/global_transport.rb @@ -9,7 +9,6 @@ class GlobalTransportGateway < Gateway self.supported_countries = %w(CA PR US) self.default_currency = 'USD' self.supported_cardtypes = [:visa, :master, :american_express, :discover, :diners_club, :jcb] - self.ssl_version = :TLSv1 self.homepage_url = 'https://www.globalpaymentsinc.com' self.display_name = 'Global Transport' @@ -75,6 +74,17 @@ def verify(payment_method, options={}) commit('CardVerify', post, options) end + def supports_scrubbing? + true + end + + def scrub(transcript) + transcript. + gsub(%r((&?CardNum=)[^&]*)i, '\1[FILTERED]'). + gsub(%r((&?CVNum=)[^&]*)i, '\1[FILTERED]'). + gsub(%r((&?GlobalPassword=)[^&]*)i, '\1[FILTERED]') + end + private def add_address(post, options) @@ -109,6 +119,10 @@ def parse(body) response[node.name.downcase.to_sym] = node.text end + ext_data = Nokogiri::HTML.parse(response[:extdata]) + response[:approved_amount] = ext_data.xpath('//approvedamount').text + response[:balance_due] = ext_data.xpath('//balancedue').text + response end @@ -132,7 +146,7 @@ def post_data(action, params, options) post[:TransType] = action post[:ExtData] = "#{@options[:term_type]}" - post.merge(params).map { |key, value| "#{key}=#{CGI.escape(value.to_s)}" }.join("&") + post.merge(params).map { |key, value| "#{key}=#{CGI.escape(value.to_s)}" }.join('&') end def url @@ -140,7 +154,7 @@ def url end def success_from(response) - (response[:result] == "0") + response[:result] == '0' || response[:result] == '200' end def message_from(response) diff --git a/lib/active_merchant/billing/gateways/hdfc.rb b/lib/active_merchant/billing/gateways/hdfc.rb index be973857764..142d7c83b82 100644 --- a/lib/active_merchant/billing/gateways/hdfc.rb +++ b/lib/active_merchant/billing/gateways/hdfc.rb @@ -1,16 +1,16 @@ -require "nokogiri" +require 'nokogiri' module ActiveMerchant #:nodoc: module Billing #:nodoc: class HdfcGateway < Gateway - self.display_name = "HDFC" - self.homepage_url = "http://www.hdfcbank.com/sme/sme-details/merchant-services/guzh6m0i" + self.display_name = 'HDFC' + self.homepage_url = 'http://www.hdfcbank.com/sme/sme-details/merchant-services/guzh6m0i' - self.test_url = "https://securepgtest.fssnet.co.in/pgway/servlet/" - self.live_url = "https://securepg.fssnet.co.in/pgway/servlet/" + self.test_url = 'https://securepgtest.fssnet.co.in/pgway/servlet/' + self.live_url = 'https://securepg.fssnet.co.in/pgway/servlet/' - self.supported_countries = ["IN"] - self.default_currency = "INR" + self.supported_countries = ['IN'] + self.default_currency = 'INR' self.money_format = :dollars self.supported_cardtypes = [:visa, :master, :discover, :diners_club] @@ -25,7 +25,7 @@ def purchase(amount, payment_method, options={}) add_payment_method(post, payment_method) add_customer_data(post, options) - commit("purchase", post) + commit('purchase', post) end def authorize(amount, payment_method, options={}) @@ -34,7 +34,7 @@ def authorize(amount, payment_method, options={}) add_payment_method(post, payment_method) add_customer_data(post, options) - commit("authorize", post) + commit('authorize', post) end def capture(amount, authorization, options={}) @@ -43,7 +43,7 @@ def capture(amount, authorization, options={}) add_reference(post, authorization) add_customer_data(post, options) - commit("capture", post) + commit('capture', post) end def refund(amount, authorization, options={}) @@ -52,22 +52,22 @@ def refund(amount, authorization, options={}) add_reference(post, authorization) add_customer_data(post, options) - commit("refund", post) + commit('refund', post) end private - CURRENCY_CODES = Hash.new{|h,k| raise ArgumentError.new("Unsupported currency for HDFC: #{k}")} - CURRENCY_CODES["AED"] = "784" - CURRENCY_CODES["AUD"] = "036" - CURRENCY_CODES["CAD"] = "124" - CURRENCY_CODES["EUR"] = "978" - CURRENCY_CODES["GBP"] = "826" - CURRENCY_CODES["INR"] = "356" - CURRENCY_CODES["OMR"] = "512" - CURRENCY_CODES["QAR"] = "634" - CURRENCY_CODES["SGD"] = "702" - CURRENCY_CODES["USD"] = "840" + CURRENCY_CODES = Hash.new { |h, k| raise ArgumentError.new("Unsupported currency for HDFC: #{k}") } + CURRENCY_CODES['AED'] = '784' + CURRENCY_CODES['AUD'] = '036' + CURRENCY_CODES['CAD'] = '124' + CURRENCY_CODES['EUR'] = '978' + CURRENCY_CODES['GBP'] = '826' + CURRENCY_CODES['INR'] = '356' + CURRENCY_CODES['OMR'] = '512' + CURRENCY_CODES['QAR'] = '634' + CURRENCY_CODES['SGD'] = '702' + CURRENCY_CODES['USD'] = '840' def add_invoice(post, amount, options) post[:amt] = amount(amount) @@ -113,7 +113,7 @@ def parse(xml) doc.children.each do |node| if node.text? next - elsif (node.elements.size == 0) + elsif node.elements.size == 0 response[node.name.downcase.to_sym] = node.text else node.elements.each do |childnode| @@ -127,14 +127,14 @@ def parse(xml) end def fix_xml(xml) - xml.gsub(/&(?!(?:amp|quot|apos|lt|gt);)/, "&") + xml.gsub(/&(?!(?:amp|quot|apos|lt|gt);)/, '&') end ACTIONS = { - "purchase" => "1", - "refund" => "2", - "authorize" => "4", - "capture" => "5", + 'purchase' => '1', + 'refund' => '2', + 'authorize' => '4', + 'capture' => '5', } def commit(action, post) @@ -164,13 +164,13 @@ def build_request(post) end def url(action) - endpoint = "TranPortalXMLServlet" + endpoint = 'TranPortalXMLServlet' (test? ? test_url : live_url) + endpoint end def success_from(result) case result - when "CAPTURED", "APPROVED", "NOT ENROLLED", "ENROLLED" + when 'CAPTURED', 'APPROVED', 'NOT ENROLLED', 'ENROLLED' true else false @@ -179,23 +179,23 @@ def success_from(result) def message_from(succeeded, response) if succeeded - "Succeeded" + 'Succeeded' else - (response[:error_text] || response[:result] || "Unable to read error message").split("-").last + (response[:error_text] || response[:result] || 'Unable to read error message').split('-').last end end def authorization_from(request, response) - [response[:tranid], request[:member]].join("|") + [response[:tranid], request[:member]].join('|') end def split_authorization(authorization) - tranid, member = authorization.split("|") + tranid, member = authorization.split('|') [tranid, member] end def escape(string, max_length=250) - return "" unless string + return '' unless string if max_length string = string[0...max_length] end @@ -204,4 +204,3 @@ def escape(string, max_length=250) end end end - diff --git a/lib/active_merchant/billing/gateways/hps.rb b/lib/active_merchant/billing/gateways/hps.rb index a6e79e8534f..dbc7997370b 100644 --- a/lib/active_merchant/billing/gateways/hps.rb +++ b/lib/active_merchant/billing/gateways/hps.rb @@ -1,4 +1,4 @@ -require "nokogiri" +require 'nokogiri' module ActiveMerchant #:nodoc: module Billing #:nodoc: @@ -42,7 +42,7 @@ def purchase(money, card_or_token, options={}) commit('CreditSale') do |xml| add_amount(xml, money) add_allow_dup(xml) - add_customer_data(xml, card_or_token,options) + add_customer_data(xml, card_or_token, options) add_details(xml, options) add_descriptor_name(xml, options) add_payment(xml, card_or_token, options) @@ -54,7 +54,7 @@ def refund(money, transaction_id, options={}) add_amount(xml, money) add_allow_dup(xml) add_reference(xml, transaction_id) - add_customer_data(xml, transaction_id,options) + add_customer_data(xml, transaction_id, options) add_details(xml, options) end end @@ -73,6 +73,17 @@ def void(transaction_id, options={}) end end + def supports_scrubbing? + true + end + + def scrub(transcript) + transcript. + gsub(%r(()[^<]*(<\/hps:CardNbr>))i, '\1[FILTERED]\2'). + gsub(%r(()[^<]*(<\/hps:CVV2>))i, '\1[FILTERED]\2'). + gsub(%r(()[^<]*(<\/hps:SecretAPIKey>))i, '\1[FILTERED]\2') + end + private def add_reference(xml, transaction_id) @@ -106,7 +117,7 @@ def add_payment(xml, card_or_token, options) xml.hps :CardData do if card_or_token.respond_to?(:number) if card_or_token.track_data - xml.tag!("hps:TrackData", 'method'=>'swipe') do + xml.tag!('hps:TrackData', 'method'=>'swipe') do xml.text! card_or_token.track_data end if options[:encryption_type] @@ -191,9 +202,9 @@ def parse(raw) doc = Nokogiri::XML(raw) doc.remove_namespaces! - if(header = doc.xpath("//Header").first) + if(header = doc.xpath('//Header').first) header.elements.each do |node| - if (node.elements.size == 0) + if node.elements.size == 0 response[node.name] = node.text else node.elements.each do |childnode| @@ -202,13 +213,13 @@ def parse(raw) end end end - if(transaction = doc.xpath("//Transaction/*[1]").first) + if(transaction = doc.xpath('//Transaction/*[1]').first) transaction.elements.each do |node| response[node.name] = node.text end end - if(fault = doc.xpath("//Fault/Reason/Text").first) - response["Fault"] = fault.text + if(fault = doc.xpath('//Fault/Reason/Text').first) + response['Fault'] = fault.text end response @@ -218,7 +229,7 @@ def commit(action, &request) data = build_request(action, &request) response = begin - parse(ssl_post((test? ? test_url : live_url), data, 'Content-type' => 'text/xml')) + parse(ssl_post((test? ? test_url : live_url), data, 'Content-Type' => 'text/xml')) rescue ResponseError => e parse(e.response.body) end @@ -239,22 +250,22 @@ def commit(action, &request) def successful?(response) ( - (response["GatewayRspCode"] == "0") && - ((response["RspCode"] || "00") == "00" || response["RspCode"] == "85") + (response['GatewayRspCode'] == '0') && + ((response['RspCode'] || '00') == '00' || response['RspCode'] == '85') ) end def message_from(response) - if(response["Fault"]) - response["Fault"] - elsif(response["GatewayRspCode"] == "0") - if(response["RspCode"] != "00" && response["RspCode"] != "85") - issuer_message(response["RspCode"]) + if(response['Fault']) + response['Fault'] + elsif(response['GatewayRspCode'] == '0') + if(response['RspCode'] != '00' && response['RspCode'] != '85') + issuer_message(response['RspCode']) else response['GatewayRspMsg'] end else - (GATEWAY_MESSAGES[response["GatewayRspCode"]] || response["GatewayRspMsg"]) + (GATEWAY_MESSAGES[response['GatewayRspCode']] || response['GatewayRspMsg']) end end @@ -263,31 +274,31 @@ def authorization_from(response) end def test? - (@options[:secret_api_key] && @options[:secret_api_key].include?('_cert_')) + @options[:secret_api_key]&.include?('_cert_') end ISSUER_MESSAGES = { - "13" => "Must be greater than or equal 0.", - "14" => "The card number is incorrect.", - "54" => "The card has expired.", - "55" => "The 4-digit pin is invalid.", - "75" => "Maximum number of pin retries exceeded.", - "80" => "Card expiration date is invalid.", - "86" => "Can't verify card pin number." + '13' => 'Must be greater than or equal 0.', + '14' => 'The card number is incorrect.', + '54' => 'The card has expired.', + '55' => 'The 4-digit pin is invalid.', + '75' => 'Maximum number of pin retries exceeded.', + '80' => 'Card expiration date is invalid.', + '86' => "Can't verify card pin number." } def issuer_message(code) - return "The card was declined." if %w(02 03 04 05 41 43 44 51 56 61 62 63 65 78).include?(code) - return "An error occurred while processing the card." if %w(06 07 12 15 19 12 52 53 57 58 76 77 91 96 EC).include?(code) + return 'The card was declined.' if %w(02 03 04 05 41 43 44 51 56 61 62 63 65 78).include?(code) + return 'An error occurred while processing the card.' if %w(06 07 12 15 19 12 52 53 57 58 76 77 91 96 EC).include?(code) return "The card's security code is incorrect." if %w(EB N7).include?(code) ISSUER_MESSAGES[code] end GATEWAY_MESSAGES = { - "-2" => "Authentication error. Please double check your service configuration.", - "12" => "Invalid CPC data.", - "13" => "Invalid card data.", - "14" => "The card number is not a valid credit card number.", - "30" => "Gateway timed out." + '-2' => 'Authentication error. Please double check your service configuration.', + '12' => 'Invalid CPC data.', + '13' => 'Invalid card data.', + '14' => 'The card number is not a valid credit card number.', + '30' => 'Gateway timed out.' } end end diff --git a/lib/active_merchant/billing/gateways/iats_payments.rb b/lib/active_merchant/billing/gateways/iats_payments.rb index 56acbcb530f..c2d4505dfb9 100644 --- a/lib/active_merchant/billing/gateways/iats_payments.rb +++ b/lib/active_merchant/billing/gateways/iats_payments.rb @@ -14,12 +14,12 @@ class IatsPaymentsGateway < Gateway self.display_name = 'iATS Payments' ACTIONS = { - purchase: "ProcessCreditCardV1", - purchase_check: "ProcessACHEFTV1", - refund: "ProcessCreditCardRefundWithTransactionIdV1", - refund_check: "ProcessACHEFTRefundWithTransactionIdV1", - store: "CreateCreditCardCustomerCodeV1", - unstore: "DeleteCustomerCodeV1" + purchase: 'ProcessCreditCardV1', + purchase_check: 'ProcessACHEFTV1', + refund: 'ProcessCreditCardRefundWithTransactionIdV1', + refund_check: 'ProcessACHEFTRefundWithTransactionIdV1', + store: 'CreateCreditCardCustomerCodeV1', + unstore: 'DeleteCustomerCodeV1' } def initialize(options={}) @@ -145,19 +145,19 @@ def add_store_defaults(post) end def expdate(creditcard) - year = sprintf("%.4i", creditcard.year) - month = sprintf("%.2i", creditcard.month) + year = sprintf('%.4i', creditcard.year) + month = sprintf('%.2i', creditcard.month) "#{month}/#{year[-2..-1]}" end def creditcard_brand(brand) case brand - when "visa" then "VISA" - when "master" then "MC" - when "discover" then "DSC" - when "american_express" then "AMX" - when "maestro" then "MAESTR" + when 'visa' then 'VISA' + when 'master' then 'MC' + when 'discover' then 'DSC' + when 'american_express' then 'AMX' + when 'maestro' then 'MAESTR' else raise "Unhandled credit card brand #{brand}" end @@ -165,7 +165,7 @@ def creditcard_brand(brand) def commit(action, parameters) response = parse(ssl_post(url(action), post_data(action, parameters), - { 'Content-Type' => 'application/soap+xml; charset=utf-8'})) + { 'Content-Type' => 'application/soap+xml; charset=utf-8'})) Response.new( success_from(response), @@ -178,12 +178,12 @@ def commit(action, parameters) def endpoints { - purchase: "ProcessLink.asmx", - purchase_check: "ProcessLink.asmx", - refund: "ProcessLink.asmx", - refund_check: "ProcessLink.asmx", - store: "CustomerLink.asmx", - unstore: "CustomerLink.asmx" + purchase: 'ProcessLink.asmx', + purchase_check: 'ProcessLink.asmx', + refund: 'ProcessLink.asmx', + refund_check: 'ProcessLink.asmx', + store: 'CustomerLink.asmx', + unstore: 'CustomerLink.asmx' } end @@ -211,7 +211,7 @@ def dexmlize_param_name(name) def hashify_xml!(xml, response) xml = REXML::Document.new(xml) - xml.elements.each("//IATSRESPONSE/*") do |node| + xml.elements.each('//IATSRESPONSE/*') do |node| recursively_parse_element(node, response) end end @@ -225,15 +225,15 @@ def recursively_parse_element(node, response) end def successful_result_message?(response) - response[:authorization_result].start_with?('OK') + response[:authorization_result] ? response[:authorization_result].start_with?('OK') : false end def success_from(response) - response[:status] == "Success" && successful_result_message?(response) + response[:status] == 'Success' && successful_result_message?(response) end def message_from(response) - if(!successful_result_message?(response)) + if !successful_result_message?(response) && response[:authorization_result] return response[:authorization_result].strip elsif(response[:status] == 'Failure') return response[:errors] @@ -253,14 +253,14 @@ def authorization_from(action, response) end def split_authorization(authorization) - authorization.split("|") + authorization.split('|') end def envelope_namespaces { - "xmlns:xsi" => "http://www.w3.org/2001/XMLSchema-instance", - "xmlns:xsd" => "http://www.w3.org/2001/XMLSchema", - "xmlns:soap12" => "http://www.w3.org/2003/05/soap-envelope" + 'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance', + 'xmlns:xsd' => 'http://www.w3.org/2001/XMLSchema', + 'xmlns:soap12' => 'http://www.w3.org/2003/05/soap-envelope' } end @@ -269,7 +269,7 @@ def post_data(action, parameters = {}) xml.instruct!(:xml, :version => '1.0', :encoding => 'utf-8') xml.tag! 'soap12:Envelope', envelope_namespaces do xml.tag! 'soap12:Body' do - xml.tag! ACTIONS[action], { "xmlns" => "https://www.iatspayments.com/NetGate/" } do + xml.tag! ACTIONS[action], { 'xmlns' => 'https://www.iatspayments.com/NetGate/' } do xml.tag!('agentCode', @options[:agent_code]) xml.tag!('password', @options[:password]) parameters.each do |name, value| diff --git a/lib/active_merchant/billing/gateways/ideal/ideal_base.rb b/lib/active_merchant/billing/gateways/ideal/ideal_base.rb deleted file mode 100644 index 2ee6d04eb01..00000000000 --- a/lib/active_merchant/billing/gateways/ideal/ideal_base.rb +++ /dev/null @@ -1,246 +0,0 @@ -require 'active_merchant/billing/gateways/ideal/ideal_response' - -module ActiveMerchant #:nodoc: - module Billing #:nodoc: - # Implementation contains some simplifications - # - does not support multiple subID per merchant - # - language is fixed to 'nl' - class IdealBaseGateway < Gateway - class_attribute :server_pem, :pem_password, :default_expiration_period - self.default_expiration_period = 'PT10M' - self.default_currency = 'EUR' - self.pem_password = true - - self.abstract_class = true - - # These constants will never change for most users - AUTHENTICATION_TYPE = 'SHA1_RSA' - LANGUAGE = 'nl' - SUB_ID = '0' - API_VERSION = '1.1.0' - - def initialize(options = {}) - requires!(options, :login, :password, :pem) - - options[:pem_password] = options[:password] - super - end - - # Setup transaction. Get redirect_url from response.service_url - def setup_purchase(money, options = {}) - requires!(options, :issuer_id, :return_url, :order_id, :currency, :description, :entrance_code) - - commit(build_transaction_request(money, options)) - end - - # Check status of transaction and confirm payment - # transaction_id must be a valid transaction_id from a prior setup. - def capture(transaction, options = {}) - options[:transaction_id] = transaction - commit(build_status_request(options)) - end - - # Get list of issuers from response.issuer_list - def issuers - commit(build_directory_request) - end - - private - - def url - (test? ? test_url : live_url) - end - - def token - @token ||= create_fingerprint(@options[:pem]) - end - - # - # - # 2001-12-17T09:30:47.0Z - # - # 1003 - # - # - # 000123456 - # 0 - # passkey - # 1 - # 3823ad872eff23 - # https://www.mijnwinkel.nl/betaalafhandeling - # - # - # - # iDEAL-aankoop 21 - # 5999 - # EUR - # PT3M30S - # nl - # Documentensuite - # D67tyx6rw9IhY71 - # - # - def build_transaction_request(money, options) - date_time_stamp = create_time_stamp - message = date_time_stamp + - options[:issuer_id] + - @options[:login] + - SUB_ID + - options[:return_url] + - options[:order_id] + - money.to_s + - (options[:currency] || currency(money)) + - LANGUAGE + - options[:description] + - options[:entrance_code] - token_code = sign_message(@options[:pem], @options[:password], message) - - xml = Builder::XmlMarkup.new(:indent => 2) - xml.instruct! - xml.tag! 'AcquirerTrxReq', 'xmlns' => 'http://www.idealdesk.com/Message', 'version' => API_VERSION do - xml.tag! 'createDateTimeStamp', date_time_stamp - xml.tag! 'Issuer' do - xml.tag! 'issuerID', options[:issuer_id] - end - xml.tag! 'Merchant' do - xml.tag! 'merchantID', @options[:login] - xml.tag! 'subID', SUB_ID - xml.tag! 'authentication', AUTHENTICATION_TYPE - xml.tag! 'token', token - xml.tag! 'tokenCode', token_code - xml.tag! 'merchantReturnURL', options[:return_url] - end - xml.tag! 'Transaction' do - xml.tag! 'purchaseID', options[:order_id] - xml.tag! 'amount', money - xml.tag! 'currency', options[:currency] - xml.tag! 'expirationPeriod', options[:expiration_period] || default_expiration_period - xml.tag! 'language', LANGUAGE - xml.tag! 'description', options[:description] - xml.tag! 'entranceCode', options[:entrance_code] - end - xml.target! - end - end - - # - # - # 2001-12-17T09:30:47.0Z - # - # 000123456 - # 0 - # keyed hash - # 1 - # 3823ad872eff23 - # - # - # 0001023456789112 - # - # - def build_status_request(options) - datetimestamp = create_time_stamp - message = datetimestamp + @options[:login] + SUB_ID + options[:transaction_id] - tokenCode = sign_message(@options[:pem], @options[:password], message) - - xml = Builder::XmlMarkup.new(:indent => 2) - xml.instruct! - xml.tag! 'AcquirerStatusReq', 'xmlns' => 'http://www.idealdesk.com/Message', 'version' => API_VERSION do - xml.tag! 'createDateTimeStamp', datetimestamp - xml.tag! 'Merchant' do - xml.tag! 'merchantID', @options[:login] - xml.tag! 'subID', SUB_ID - xml.tag! 'authentication' , AUTHENTICATION_TYPE - xml.tag! 'token', token - xml.tag! 'tokenCode', tokenCode - end - xml.tag! 'Transaction' do - xml.tag! 'transactionID', options[:transaction_id] - end - end - xml.target! - end - - # - # - # 2001-12-17T09:30:47.0Z - # - # 000000001 - # 0 - # 1 - # hashkey - # WajqV1a3nDen0be2r196g9FGFF= - # - # - def build_directory_request - datetimestamp = create_time_stamp - message = datetimestamp + @options[:login] + SUB_ID - tokenCode = sign_message(@options[:pem], @options[:password], message) - - xml = Builder::XmlMarkup.new(:indent => 2) - xml.instruct! - xml.tag! 'DirectoryReq', 'xmlns' => 'http://www.idealdesk.com/Message', 'version' => API_VERSION do - xml.tag! 'createDateTimeStamp', datetimestamp - xml.tag! 'Merchant' do - xml.tag! 'merchantID', @options[:login] - xml.tag! 'subID', SUB_ID - xml.tag! 'authentication', AUTHENTICATION_TYPE - xml.tag! 'token', token - xml.tag! 'tokenCode', tokenCode - end - end - xml.target! - end - - def commit(request) - raw_response = ssl_post(url, request) - response = Hash.from_xml(raw_response.to_s) - response_type = response.keys[0] - - case response_type - when 'AcquirerTrxRes', 'DirectoryRes' - success = true - when 'ErrorRes' - success = false - when 'AcquirerStatusRes' - raise SecurityError, "Message verification failed.", caller unless status_response_verified?(response) - success = (response['AcquirerStatusRes']['Transaction']['status'] == 'Success') - else - raise ArgumentError, "Unknown response type.", caller - end - - return IdealResponse.new(success, response.keys[0], response, :test => test?) - end - - def create_fingerprint(cert_file) - cert_data = OpenSSL::X509::Certificate.new(cert_file).to_s - cert_data = cert_data.sub(/-----BEGIN CERTIFICATE-----/, '') - cert_data = cert_data.sub(/-----END CERTIFICATE-----/, '') - fingerprint = Base64.decode64(cert_data) - fingerprint = Digest::SHA1.hexdigest(fingerprint) - return fingerprint.upcase - end - - def sign_message(private_key_data, password, data) - private_key = OpenSSL::PKey::RSA.new(private_key_data, password) - signature = private_key.sign(OpenSSL::Digest::SHA1.new, data.gsub('\s', '')) - return Base64.encode64(signature).gsub(/\n/, '') - end - - def verify_message(cert_file, data, signature) - public_key = OpenSSL::X509::Certificate.new(cert_file).public_key - return public_key.verify(OpenSSL::Digest::SHA1.new, Base64.decode64(signature), data) - end - - def status_response_verified?(response) - transaction = response['AcquirerStatusRes']['Transaction'] - message = response['AcquirerStatusRes']['createDateTimeStamp'] + transaction['transactionID' ] + transaction['status'] - message << transaction['consumerAccountNumber'].to_s - verify_message(server_pem, message, response['AcquirerStatusRes']['Signature']['signatureValue']) - end - - def create_time_stamp - Time.now.gmtime.strftime('%Y-%m-%dT%H:%M:%S.000Z') - end - end - end -end diff --git a/lib/active_merchant/billing/gateways/ideal/ideal_rabobank.pem b/lib/active_merchant/billing/gateways/ideal/ideal_rabobank.pem deleted file mode 100644 index 3259cfa330a..00000000000 --- a/lib/active_merchant/billing/gateways/ideal/ideal_rabobank.pem +++ /dev/null @@ -1,13 +0,0 @@ ------BEGIN CERTIFICATE----- -MIICQDCCAakCBELvbPYwDQYJKoZIhvcNAQEEBQAwZzELMAkGA1UEBhMCREUxDzANBgNVBAgTBkhl -c3NlbjESMBAGA1UEBxMJRnJhbmtmdXJ0MQ4wDAYDVQQKEwVpREVBTDEOMAwGA1UECxMFaURFQUwx -EzARBgNVBAMTCmlERUFMIFJhYm8wHhcNMDUwODAyMTI1NDE0WhcNMTUwNzMxMTI1NDE0WjBnMQsw -CQYDVQQGEwJERTEPMA0GA1UECBMGSGVzc2VuMRIwEAYDVQQHEwlGcmFua2Z1cnQxDjAMBgNVBAoT -BWlERUFMMQ4wDAYDVQQLEwVpREVBTDETMBEGA1UEAxMKaURFQUwgUmFibzCBnzANBgkqhkiG9w0B -AQEFAAOBjQAwgYkCgYEA486iIKVhr8RNjxH+PZ3yTWx/8k2fqDFm8XU8I1Z5esRmPFnXmlgA8cG7 -e9AaBPaLoP7Dc8dRQoUO66KMakzGI/WAVdHIJiiKrz8xOcioIgrzPSqec7aqse3J28UraEHkGESJ -7dAW7Pw/shrmpmkzKsunLt6AkXss4W3JUndZUN0CAwEAATANBgkqhkiG9w0BAQQFAAOBgQCGy/FK -Lotp2ZOTtuLMgvDy74eicq/Znv4bLfpglzAPHycRHcHsXuer/lNHyvpKf2gdYe+IFalUW3OJZWIM -jpm4UniJ16RPdgwWVRJEdPr/P7JXMIqD2IEOgujuuTQ7x0VgCf9XrsPsP9ZR5DIPcDDhbrpSE0yF -Do77nwG61xMaGA== ------END CERTIFICATE----- diff --git a/lib/active_merchant/billing/gateways/ideal/ideal_response.rb b/lib/active_merchant/billing/gateways/ideal/ideal_response.rb deleted file mode 100644 index e050964ae40..00000000000 --- a/lib/active_merchant/billing/gateways/ideal/ideal_response.rb +++ /dev/null @@ -1,29 +0,0 @@ -module ActiveMerchant #:nodoc: - module Billing #:nodoc: - class IdealResponse < Response - - def issuer_list - list = @params.values[0]['Directory']['Issuer'] - case list - when Hash - return [list] - when Array - return list - end - end - - def service_url - @params.values[0]['Issuer']['issuerAuthenticationURL'] - end - - def transaction - @params.values[0]['Transaction'] - end - - def error - @params.values[0]['Error'] - end - - end - end -end \ No newline at end of file diff --git a/lib/active_merchant/billing/gateways/ideal_rabobank.rb b/lib/active_merchant/billing/gateways/ideal_rabobank.rb deleted file mode 100644 index bc2707adb04..00000000000 --- a/lib/active_merchant/billing/gateways/ideal_rabobank.rb +++ /dev/null @@ -1,66 +0,0 @@ -require 'active_merchant/billing/gateways/ideal/ideal_base' - -module ActiveMerchant #:nodoc: - module Billing #:nodoc: - # First, make sure you have everything setup correctly and all of your dependencies in place with: - # - # require 'rubygems' - # require 'active_merchant' - # - # ActiveMerchant expects the amounts to be given as an Integer in cents. In this case, 10 EUR becomes 1000. - # - # Create certificates for authentication: - # - # The PEM file expected should contain both the certificate and the generated PEM file. - # Some sample shell commands to generate the certificates: - # - # openssl genrsa -aes128 -out priv.pem -passout pass:[YOUR PASSWORD] 1024 - # openssl req -x509 -new -key priv.pem -passin pass:[YOUR PASSWORD] -days 3000 -out cert.cer - # cat cert.cer priv.pem > ideal.pem - # - # Following the steps above, upload cert.cer to the ideal web interface and pass the path of ideal.pem to the :pem option. - # - # Configure the gateway using your iDEAL bank account info and security settings: - # - # Create gateway: - # gateway = ActiveMerchant::Billing::IdealRabobankGateway.new( - # :login => '123456789', # 9 digit merchant number - # :pem => File.read(Rails.root + 'config/ideal.pem'), - # :password => 'password' # password for the PEM key - # ) - # - # Get list of issuers to fill selection list on your payment form: - # response = gateway.issuers - # list = response.issuer_list - # - # Request transaction: - # - # options = { - # :issuer_id => '0001', - # :expiration_period => 'PT10M', - # :return_url => 'http://www.return.url', - # :order_id => '1234567890123456', - # :currency => 'EUR', - # :description => 'Een omschrijving', - # :entrance_code => '1234' - # } - # - # response = gateway.setup_purchase(amount, options) - # transaction_id = response.transaction['transactionID'] - # redirect_url = response.service_url - # - # Mandatory status request will confirm transaction: - # response = gateway.capture(transaction_id) - # - # Implementation contains some simplifications - # - does not support multiple subID per merchant - # - language is fixed to 'nl' - class IdealRabobankGateway < IdealBaseGateway - class_attribute :test_url, :live_url - - self.test_url = 'https://idealtest.rabobank.nl/ideal/iDeal' - self.live_url = 'https://ideal.rabobank.nl/ideal/iDeal' - self.server_pem = File.read(File.dirname(__FILE__) + '/ideal/ideal_rabobank.pem') - end - end -end diff --git a/lib/active_merchant/billing/gateways/inspire.rb b/lib/active_merchant/billing/gateways/inspire.rb index 0c08f18b98b..e7771e9ec81 100644 --- a/lib/active_merchant/billing/gateways/inspire.rb +++ b/lib/active_merchant/billing/gateways/inspire.rb @@ -33,7 +33,7 @@ def initialize(options = {}) def authorize(money, creditcard, options = {}) post = {} add_invoice(post, options) - add_payment_source(post, creditcard,options) + add_payment_source(post, creditcard, options) add_address(post, creditcard, options) add_customer_data(post, options) @@ -73,7 +73,7 @@ def refund(money, authorization, options = {}) # CreditCard object. def update(vault_id, creditcard, options = {}) post = {} - post[:customer_vault] = "update_customer" + post[:customer_vault] = 'update_customer' add_customer_vault_id(post, vault_id) add_creditcard(post, creditcard, options) add_address(post, creditcard, options) @@ -84,7 +84,7 @@ def update(vault_id, creditcard, options = {}) def delete(vault_id) post = {} - post[:customer_vault] = "delete_customer" + post[:customer_vault] = 'delete_customer' add_customer_vault_id(post, vault_id) commit(nil, nil, post) end @@ -99,6 +99,7 @@ def store(creditcard, options = {}) alias_method :unstore, :delete private + def add_customer_data(post, options) if options.has_key? :email post[:email] = options[:email] @@ -135,13 +136,13 @@ def add_payment_source(params, source, options={}) end end - def add_customer_vault_id(params,vault_id) + def add_customer_vault_id(params, vault_id) params[:customer_vault_id] = vault_id end - def add_creditcard(post, creditcard,options) + def add_creditcard(post, creditcard, options) if options[:store] - post[:customer_vault] = "add_customer" + post[:customer_vault] = 'add_customer' post[:customer_vault_id] = options[:store] unless options[:store] == true end post[:ccnumber] = creditcard.number @@ -163,7 +164,7 @@ def add_check(post, check) def parse(body) results = {} body.split(/&/).each do |pair| - key,val = pair.split(%r{=}) + key, val = pair.split(%r{=}) results[key] = val end @@ -173,25 +174,24 @@ def parse(body) def commit(action, money, parameters) parameters[:amount] = amount(money) if money - response = parse( ssl_post(self.live_url, post_data(action,parameters)) ) + response = parse(ssl_post(self.live_url, post_data(action, parameters))) - Response.new(response["response"] == "1", message_from(response), response, - :authorization => response["transactionid"], + Response.new(response['response'] == '1', message_from(response), response, + :authorization => response['transactionid'], :test => test?, - :cvv_result => response["cvvresponse"], - :avs_result => { :code => response["avsresponse"] } + :cvv_result => response['cvvresponse'], + :avs_result => { :code => response['avsresponse'] } ) - end def message_from(response) - case response["responsetext"] - when "SUCCESS","Approved" - "This transaction has been approved" - when "DECLINE" - "This transaction has been declined" + case response['responsetext'] + when 'SUCCESS', 'Approved' + 'This transaction has been approved' + when 'DECLINE' + 'This transaction has been declined' else - response["responsetext"] + response['responsetext'] end end @@ -201,19 +201,18 @@ def post_data(action, parameters = {}) post[:password] = @options[:password] post[:type] = action if action - request = post.merge(parameters).map {|key,value| "#{key}=#{CGI.escape(value.to_s)}"}.join("&") + request = post.merge(parameters).map { |key, value| "#{key}=#{CGI.escape(value.to_s)}" }.join('&') request end def determine_funding_source(source) case when source.is_a?(String) then :vault - when CreditCard.card_companies.keys.include?(card_brand(source)) then :credit_card + when CreditCard.card_companies.include?(card_brand(source)) then :credit_card when card_brand(source) == 'check' then :check - else raise ArgumentError, "Unsupported funding source provided" + else raise ArgumentError, 'Unsupported funding source provided' end end end end end - diff --git a/lib/active_merchant/billing/gateways/instapay.rb b/lib/active_merchant/billing/gateways/instapay.rb index ee4ddc55007..7d18c8da05b 100644 --- a/lib/active_merchant/billing/gateways/instapay.rb +++ b/lib/active_merchant/billing/gateways/instapay.rb @@ -16,8 +16,8 @@ class InstapayGateway < Gateway # The name of the gateway self.display_name = 'InstaPay' - SUCCESS = "Accepted" - SUCCESS_MESSAGE = "The transaction has been approved" + SUCCESS = 'Accepted' + SUCCESS_MESSAGE = 'The transaction has been approved' def initialize(options = {}) requires!(options, :login) @@ -66,7 +66,7 @@ def add_reference(post, reference) def add_customer_data(post, options) post[:ci_email] = options[:email] - post["ci_IP Address"] = options[:ip] + post['ci_IP Address'] = options[:ip] end def add_address(post, options) @@ -140,7 +140,7 @@ def commit(action, parameters) data = ssl_post self.live_url, post_data(action, parameters) response = parse(data) - Response.new(response[:success] , response[:message], response, + Response.new(response[:success], response[:message], response, :authorization => response[:transaction_id], :avs_result => { :code => response[:avs_result] }, :cvv_result => response[:cvv_result] @@ -154,10 +154,9 @@ def post_data(action, parameters = {}) post[:merchantpin] = @options[:password] end post[:action] = action - request = post.merge(parameters).collect { |key, value| "#{key}=#{CGI.escape(value.to_s)}" }.join("&") + request = post.merge(parameters).collect { |key, value| "#{key}=#{CGI.escape(value.to_s)}" }.join('&') request end end end end - diff --git a/lib/active_merchant/billing/gateways/ipp.rb b/lib/active_merchant/billing/gateways/ipp.rb index dd475462a39..7813de28e1c 100644 --- a/lib/active_merchant/billing/gateways/ipp.rb +++ b/lib/active_merchant/billing/gateways/ipp.rb @@ -1,4 +1,4 @@ -require "nokogiri" +require 'nokogiri' module ActiveMerchant #:nodoc: module Billing #:nodoc: @@ -15,10 +15,10 @@ class IppGateway < Gateway self.money_format = :cents STANDARD_ERROR_CODE_MAPPING = { - "05" => STANDARD_ERROR_CODE[:card_declined], - "06" => STANDARD_ERROR_CODE[:processing_error], - "14" => STANDARD_ERROR_CODE[:invalid_number], - "54" => STANDARD_ERROR_CODE[:expired_card], + '05' => STANDARD_ERROR_CODE[:card_declined], + '06' => STANDARD_ERROR_CODE[:processing_error], + '14' => STANDARD_ERROR_CODE[:invalid_number], + '54' => STANDARD_ERROR_CODE[:expired_card], } def initialize(options={}) @@ -27,11 +27,11 @@ def initialize(options={}) end def purchase(money, payment, options={}) - commit("SubmitSinglePayment") do |xml| + commit('SubmitSinglePayment') do |xml| xml.Transaction do xml.CustRef options[:order_id] add_amount(xml, money) - xml.TrnType "1" + xml.TrnType '1' add_credit_card(xml, payment) add_credentials(xml) xml.TrnSource options[:ip] @@ -40,11 +40,11 @@ def purchase(money, payment, options={}) end def authorize(money, payment, options={}) - commit("SubmitSinglePayment") do |xml| + commit('SubmitSinglePayment') do |xml| xml.Transaction do xml.CustRef options[:order_id] add_amount(xml, money) - xml.TrnType "2" + xml.TrnType '2' add_credit_card(xml, payment) add_credentials(xml) xml.TrnSource options[:ip] @@ -53,7 +53,7 @@ def authorize(money, payment, options={}) end def capture(money, authorization, options={}) - commit("SubmitSingleCapture") do |xml| + commit('SubmitSingleCapture') do |xml| xml.Capture do xml.Receipt authorization add_amount(xml, money) @@ -63,7 +63,7 @@ def capture(money, authorization, options={}) end def refund(money, authorization, options={}) - commit("SubmitSingleRefund") do |xml| + commit('SubmitSingleRefund') do |xml| xml.Refund do xml.Receipt authorization add_amount(xml, money) @@ -97,7 +97,7 @@ def add_amount(xml, money) end def add_credit_card(xml, payment) - xml.CreditCard :Registered => "False" do + xml.CreditCard :Registered => 'False' do xml.CardNumber payment.number xml.ExpM format(payment.month, :two_digits) xml.ExpY format(payment.year, :four_digits) @@ -119,8 +119,8 @@ def parse(body) def commit(action, &block) headers = { - "Content-Type" => "text/xml; charset=utf-8", - "SOAPAction" => "http://www.ippayments.com.au/interface/api/dts/#{action}", + 'Content-Type' => 'text/xml; charset=utf-8', + 'SOAPAction' => "http://www.ippayments.com.au/interface/api/dts/#{action}", } response = parse(ssl_post(commit_url, new_submit_xml(action, &block), headers)) @@ -130,16 +130,16 @@ def commit(action, &block) response, authorization: authorization_from(response), error_code: error_code_from(response), - test: test?, + test: test? ) end def new_submit_xml(action) xml = Builder::XmlMarkup.new(indent: 2) xml.instruct! - xml.soap :Envelope, "xmlns:xsi" => "http://www.w3.org/2001/XMLSchema-instance", "xmlns:xsd" => "http://www.w3.org/2001/XMLSchema", "xmlns:soap" => "http://schemas.xmlsoap.org/soap/envelope/" do + xml.soap :Envelope, 'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance', 'xmlns:xsd' => 'http://www.w3.org/2001/XMLSchema', 'xmlns:soap' => 'http://schemas.xmlsoap.org/soap/envelope/' do xml.soap :Body do - xml.__send__(action, "xmlns" => "http://www.ippayments.com.au/interface/api/dts") do + xml.__send__(action, 'xmlns' => 'http://www.ippayments.com.au/interface/api/dts') do xml.trnXML do inner_xml = Builder::XmlMarkup.new(indent: 2) yield(inner_xml) @@ -156,7 +156,7 @@ def commit_url end def success_from(response) - (response[:response_code] == "0") + (response[:response_code] == '0') end def error_code_from(response) diff --git a/lib/active_merchant/billing/gateways/iridium.rb b/lib/active_merchant/billing/gateways/iridium.rb index 615dae08661..6b6eda3805b 100644 --- a/lib/active_merchant/billing/gateways/iridium.rb +++ b/lib/active_merchant/billing/gateways/iridium.rb @@ -15,7 +15,7 @@ class IridiumGateway < Gateway self.money_format = :cents # The card types supported by the payment gateway - self.supported_cardtypes = [:visa, :master, :american_express, :discover, :maestro, :jcb, :solo, :diners_club] + self.supported_cardtypes = [:visa, :master, :american_express, :discover, :maestro, :jcb, :diners_club] # The homepage URL of the gateway self.homepage_url = 'http://www.iridiumcorp.co.uk/' @@ -24,202 +24,202 @@ class IridiumGateway < Gateway self.display_name = 'Iridium' CURRENCY_CODES = { - "AED" => '784', - "AFN" => '971', - "ALL" => '008', - "AMD" => '051', - "ANG" => '532', - "AOA" => '973', - "ARS" => '032', - "AUD" => '036', - "AWG" => '533', - "AZN" => '944', - "BAM" => '977', - "BBD" => '052', - "BDT" => '050', - "BGN" => '975', - "BHD" => '048', - "BIF" => '108', - "BMD" => '060', - "BND" => '096', - "BOB" => '068', - "BOV" => '984', - "BRL" => '986', - "BSD" => '044', - "BTN" => '064', - "BWP" => '072', - "BYR" => '974', - "BZD" => '084', - "CAD" => '124', - "CDF" => '976', - "CHE" => '947', - "CHF" => '756', - "CHW" => '948', - "CLF" => '990', - "CLP" => '152', - "CNY" => '156', - "COP" => '170', - "COU" => '970', - "CRC" => '188', - "CUP" => '192', - "CVE" => '132', - "CYP" => '196', - "CZK" => '203', - "DJF" => '262', - "DKK" => '208', - "DOP" => '214', - "DZD" => '012', - "EEK" => '233', - "EGP" => '818', - "ERN" => '232', - "ETB" => '230', - "EUR" => '978', - "FJD" => '242', - "FKP" => '238', - "GBP" => '826', - "GEL" => '981', - "GHS" => '288', - "GIP" => '292', - "GMD" => '270', - "GNF" => '324', - "GTQ" => '320', - "GYD" => '328', - "HKD" => '344', - "HNL" => '340', - "HRK" => '191', - "HTG" => '332', - "HUF" => '348', - "IDR" => '360', - "ILS" => '376', - "INR" => '356', - "IQD" => '368', - "IRR" => '364', - "ISK" => '352', - "JMD" => '388', - "JOD" => '400', - "JPY" => '392', - "KES" => '404', - "KGS" => '417', - "KHR" => '116', - "KMF" => '174', - "KPW" => '408', - "KRW" => '410', - "KWD" => '414', - "KYD" => '136', - "KZT" => '398', - "LAK" => '418', - "LBP" => '422', - "LKR" => '144', - "LRD" => '430', - "LSL" => '426', - "LTL" => '440', - "LVL" => '428', - "LYD" => '434', - "MAD" => '504', - "MDL" => '498', - "MGA" => '969', - "MKD" => '807', - "MMK" => '104', - "MNT" => '496', - "MOP" => '446', - "MRO" => '478', - "MTL" => '470', - "MUR" => '480', - "MVR" => '462', - "MWK" => '454', - "MXN" => '484', - "MXV" => '979', - "MYR" => '458', - "MZN" => '943', - "NAD" => '516', - "NGN" => '566', - "NIO" => '558', - "NOK" => '578', - "NPR" => '524', - "NZD" => '554', - "OMR" => '512', - "PAB" => '590', - "PEN" => '604', - "PGK" => '598', - "PHP" => '608', - "PKR" => '586', - "PLN" => '985', - "PYG" => '600', - "QAR" => '634', - "ROL" => '642', - "RON" => '946', - "RSD" => '941', - "RUB" => '643', - "RWF" => '646', - "SAR" => '682', - "SBD" => '090', - "SCR" => '690', - "SDG" => '938', - "SEK" => '752', - "SGD" => '702', - "SHP" => '654', - "SKK" => '703', - "SLL" => '694', - "SOS" => '706', - "SRD" => '968', - "STD" => '678', - "SYP" => '760', - "SZL" => '748', - "THB" => '764', - "TJS" => '972', - "TMM" => '795', - "TND" => '788', - "TOP" => '776', - "TRY" => '949', - "TTD" => '780', - "TWD" => '901', - "TZS" => '834', - "UAH" => '980', - "UGX" => '800', - "USD" => '840', - "USN" => '997', - "USS" => '998', - "UYU" => '858', - "UZS" => '860', - "VEB" => '862', - "VND" => '704', - "VUV" => '548', - "WST" => '882', - "XAF" => '950', - "XAG" => '961', - "XAU" => '959', - "XBA" => '955', - "XBB" => '956', - "XBC" => '957', - "XBD" => '958', - "XCD" => '951', - "XDR" => '960', - "XOF" => '952', - "XPD" => '964', - "XPF" => '953', - "XPT" => '962', - "XTS" => '963', - "XXX" => '999', - "YER" => '886', - "ZAR" => '710', - "ZMK" => '894', - "ZWD" => '716', + 'AED' => '784', + 'AFN' => '971', + 'ALL' => '008', + 'AMD' => '051', + 'ANG' => '532', + 'AOA' => '973', + 'ARS' => '032', + 'AUD' => '036', + 'AWG' => '533', + 'AZN' => '944', + 'BAM' => '977', + 'BBD' => '052', + 'BDT' => '050', + 'BGN' => '975', + 'BHD' => '048', + 'BIF' => '108', + 'BMD' => '060', + 'BND' => '096', + 'BOB' => '068', + 'BOV' => '984', + 'BRL' => '986', + 'BSD' => '044', + 'BTN' => '064', + 'BWP' => '072', + 'BYR' => '974', + 'BZD' => '084', + 'CAD' => '124', + 'CDF' => '976', + 'CHE' => '947', + 'CHF' => '756', + 'CHW' => '948', + 'CLF' => '990', + 'CLP' => '152', + 'CNY' => '156', + 'COP' => '170', + 'COU' => '970', + 'CRC' => '188', + 'CUP' => '192', + 'CVE' => '132', + 'CYP' => '196', + 'CZK' => '203', + 'DJF' => '262', + 'DKK' => '208', + 'DOP' => '214', + 'DZD' => '012', + 'EEK' => '233', + 'EGP' => '818', + 'ERN' => '232', + 'ETB' => '230', + 'EUR' => '978', + 'FJD' => '242', + 'FKP' => '238', + 'GBP' => '826', + 'GEL' => '981', + 'GHS' => '288', + 'GIP' => '292', + 'GMD' => '270', + 'GNF' => '324', + 'GTQ' => '320', + 'GYD' => '328', + 'HKD' => '344', + 'HNL' => '340', + 'HRK' => '191', + 'HTG' => '332', + 'HUF' => '348', + 'IDR' => '360', + 'ILS' => '376', + 'INR' => '356', + 'IQD' => '368', + 'IRR' => '364', + 'ISK' => '352', + 'JMD' => '388', + 'JOD' => '400', + 'JPY' => '392', + 'KES' => '404', + 'KGS' => '417', + 'KHR' => '116', + 'KMF' => '174', + 'KPW' => '408', + 'KRW' => '410', + 'KWD' => '414', + 'KYD' => '136', + 'KZT' => '398', + 'LAK' => '418', + 'LBP' => '422', + 'LKR' => '144', + 'LRD' => '430', + 'LSL' => '426', + 'LTL' => '440', + 'LVL' => '428', + 'LYD' => '434', + 'MAD' => '504', + 'MDL' => '498', + 'MGA' => '969', + 'MKD' => '807', + 'MMK' => '104', + 'MNT' => '496', + 'MOP' => '446', + 'MRO' => '478', + 'MTL' => '470', + 'MUR' => '480', + 'MVR' => '462', + 'MWK' => '454', + 'MXN' => '484', + 'MXV' => '979', + 'MYR' => '458', + 'MZN' => '943', + 'NAD' => '516', + 'NGN' => '566', + 'NIO' => '558', + 'NOK' => '578', + 'NPR' => '524', + 'NZD' => '554', + 'OMR' => '512', + 'PAB' => '590', + 'PEN' => '604', + 'PGK' => '598', + 'PHP' => '608', + 'PKR' => '586', + 'PLN' => '985', + 'PYG' => '600', + 'QAR' => '634', + 'ROL' => '642', + 'RON' => '946', + 'RSD' => '941', + 'RUB' => '643', + 'RWF' => '646', + 'SAR' => '682', + 'SBD' => '090', + 'SCR' => '690', + 'SDG' => '938', + 'SEK' => '752', + 'SGD' => '702', + 'SHP' => '654', + 'SKK' => '703', + 'SLL' => '694', + 'SOS' => '706', + 'SRD' => '968', + 'STD' => '678', + 'SYP' => '760', + 'SZL' => '748', + 'THB' => '764', + 'TJS' => '972', + 'TMM' => '795', + 'TND' => '788', + 'TOP' => '776', + 'TRY' => '949', + 'TTD' => '780', + 'TWD' => '901', + 'TZS' => '834', + 'UAH' => '980', + 'UGX' => '800', + 'USD' => '840', + 'USN' => '997', + 'USS' => '998', + 'UYU' => '858', + 'UZS' => '860', + 'VEB' => '862', + 'VND' => '704', + 'VUV' => '548', + 'WST' => '882', + 'XAF' => '950', + 'XAG' => '961', + 'XAU' => '959', + 'XBA' => '955', + 'XBB' => '956', + 'XBC' => '957', + 'XBD' => '958', + 'XCD' => '951', + 'XDR' => '960', + 'XOF' => '952', + 'XPD' => '964', + 'XPF' => '953', + 'XPT' => '962', + 'XTS' => '963', + 'XXX' => '999', + 'YER' => '886', + 'ZAR' => '710', + 'ZMK' => '894', + 'ZWD' => '716', } AVS_CODE = { - "PASSED" => "Y", - "FAILED" => "N", - "PARTIAL" => "X", - "NOT_CHECKED" => "X", - "UNKNOWN" => "X" + 'PASSED' => 'Y', + 'FAILED' => 'N', + 'PARTIAL' => 'X', + 'NOT_CHECKED' => 'X', + 'UNKNOWN' => 'X' } CVV_CODE = { - "PASSED" => "M", - "FAILED" => "N", - "PARTIAL" => "I", - "NOT_CHECKED" => "P", - "UNKNOWN" => "U" + 'PASSED' => 'M', + 'FAILED' => 'N', + 'PARTIAL' => 'I', + 'NOT_CHECKED' => 'P', + 'UNKNOWN' => 'U' } def initialize(options = {}) @@ -278,7 +278,7 @@ def scrub(transcript) private def build_purchase_request(type, money, creditcard, options) - options.merge!(:action => 'CardDetailsTransaction') + options[:action] = 'CardDetailsTransaction' build_request(options) do |xml| add_purchase_data(xml, type, money, options) add_creditcard(xml, creditcard) @@ -287,8 +287,8 @@ def build_purchase_request(type, money, creditcard, options) end def build_reference_request(type, money, authorization, options) - options.merge!(:action => 'CrossReferenceTransaction') - order_id, cross_reference, _ = authorization.split(";") + options[:action] = 'CrossReferenceTransaction' + order_id, cross_reference, _ = authorization.split(';') build_request(options) do |xml| if money details = {'CurrencyCode' => currency_code(options[:currency] || default_currency), 'Amount' => amount(money)} @@ -310,7 +310,7 @@ def build_request(options) 'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance', 'xmlns:xsd' => 'http://www.w3.org/2001/XMLSchema'} do xml.tag! 'soap:Body' do - xml.tag! options[:action], {'xmlns' => "https://www.thepaymentgateway.net/"} do + xml.tag! options[:action], {'xmlns' => 'https://www.thepaymentgateway.net/'} do xml.tag! 'PaymentMessage' do add_merchant_data(xml, options) yield(xml) @@ -357,7 +357,7 @@ def add_customerdetails(xml, creditcard, address, options, shipTo = false) end xml.tag! 'EmailAddress', options[:email] - xml.tag! 'CustomerIPAddress', options[:ip] || "127.0.0.1" + xml.tag! 'CustomerIPAddress', options[:ip] || '127.0.0.1' end end @@ -366,23 +366,23 @@ def add_creditcard(xml, creditcard) xml.tag! 'CardName', creditcard.name xml.tag! 'CV2', creditcard.verification_value if creditcard.verification_value xml.tag! 'CardNumber', creditcard.number - xml.tag! 'ExpiryDate', { 'Month' => creditcard.month.to_s.rjust(2, "0"), 'Year' => creditcard.year.to_s[/\d\d$/] } + xml.tag! 'ExpiryDate', { 'Month' => creditcard.month.to_s.rjust(2, '0'), 'Year' => creditcard.year.to_s[/\d\d$/] } end end def add_merchant_data(xml, options) - xml.tag! 'MerchantAuthentication', {"MerchantID" => @options[:login], "Password" => @options[:password]} + xml.tag! 'MerchantAuthentication', {'MerchantID' => @options[:login], 'Password' => @options[:password]} end def commit(request, options) requires!(options, :action) response = parse(ssl_post(test? ? self.test_url : self.live_url, request, - {"SOAPAction" => "https://www.thepaymentgateway.net/" + options[:action], - "Content-Type" => "text/xml; charset=utf-8" })) + {'SOAPAction' => 'https://www.thepaymentgateway.net/' + options[:action], + 'Content-Type' => 'text/xml; charset=utf-8' })) - success = response[:transaction_result][:status_code] == "0" + success = response[:transaction_result][:status_code] == '0' message = response[:transaction_result][:message] - authorization = success ? [ options[:order_id], response[:transaction_output_data][:cross_reference], response[:transaction_output_data][:auth_code] ].compact.join(";") : nil + authorization = success ? [ options[:order_id], response[:transaction_output_data][:cross_reference], response[:transaction_output_data][:auth_code] ].compact.join(';') : nil Response.new(success, message, response, :test => test?, @@ -398,8 +398,8 @@ def commit(request, options) def parse(xml) reply = {} xml = REXML::Document.new(xml) - if (root = REXML::XPath.first(xml, "//CardDetailsTransactionResponse")) or - (root = REXML::XPath.first(xml, "//CrossReferenceTransactionResponse")) + if (root = REXML::XPath.first(xml, '//CardDetailsTransactionResponse')) or + (root = REXML::XPath.first(xml, '//CrossReferenceTransactionResponse')) root.elements.to_a.each do |node| case node.name when 'Message' @@ -408,7 +408,7 @@ def parse(xml) parse_element(reply, node) end end - elsif root = REXML::XPath.first(xml, "//soap:Fault") + elsif root = REXML::XPath.first(xml, '//soap:Fault') parse_element(reply, root) reply[:message] = "#{reply[:faultcode]}: #{reply[:faultstring]}" end @@ -417,41 +417,41 @@ def parse(xml) def parse_element(reply, node) case node.name - when "CrossReferenceTransactionResult" + when 'CrossReferenceTransactionResult' reply[:transaction_result] = {} - node.attributes.each do |a,b| + node.attributes.each do |a, b| reply[:transaction_result][a.underscore.to_sym] = b end - node.elements.each{|e| parse_element(reply[:transaction_result], e) } if node.has_elements? + node.elements.each { |e| parse_element(reply[:transaction_result], e) } if node.has_elements? - when "CardDetailsTransactionResult" + when 'CardDetailsTransactionResult' reply[:transaction_result] = {} - node.attributes.each do |a,b| + node.attributes.each do |a, b| reply[:transaction_result][a.underscore.to_sym] = b end - node.elements.each{|e| parse_element(reply[:transaction_result], e) } if node.has_elements? + node.elements.each { |e| parse_element(reply[:transaction_result], e) } if node.has_elements? - when "TransactionOutputData" + when 'TransactionOutputData' reply[:transaction_output_data] = {} - node.attributes.each{|a,b| reply[:transaction_output_data][a.underscore.to_sym] = b } - node.elements.each{|e| parse_element(reply[:transaction_output_data], e) } if node.has_elements? - when "CustomVariables" + node.attributes.each { |a, b| reply[:transaction_output_data][a.underscore.to_sym] = b } + node.elements.each { |e| parse_element(reply[:transaction_output_data], e) } if node.has_elements? + when 'CustomVariables' reply[:custom_variables] = {} - node.attributes.each{|a,b| reply[:custom_variables][a.underscore.to_sym] = b } - node.elements.each{|e| parse_element(reply[:custom_variables], e) } if node.has_elements? - when "GatewayEntryPoints" + node.attributes.each { |a, b| reply[:custom_variables][a.underscore.to_sym] = b } + node.elements.each { |e| parse_element(reply[:custom_variables], e) } if node.has_elements? + when 'GatewayEntryPoints' reply[:gateway_entry_points] = {} - node.attributes.each{|a,b| reply[:gateway_entry_points][a.underscore.to_sym] = b } - node.elements.each{|e| parse_element(reply[:gateway_entry_points], e) } if node.has_elements? + node.attributes.each { |a, b| reply[:gateway_entry_points][a.underscore.to_sym] = b } + node.elements.each { |e| parse_element(reply[:gateway_entry_points], e) } if node.has_elements? else k = node.name.underscore.to_sym if node.has_elements? reply[k] = {} - node.elements.each{|e| parse_element(reply[k], e) } + node.elements.each { |e| parse_element(reply[k], e) } else if node.has_attributes? reply[k] = {} - node.attributes.each{|a,b| reply[k][a.underscore.to_sym] = b } + node.attributes.each { |a, b| reply[k][a.underscore.to_sym] = b } else reply[k] = node.text end diff --git a/lib/active_merchant/billing/gateways/itransact.rb b/lib/active_merchant/billing/gateways/itransact.rb index 0d96f7556e6..8bac0734e0a 100644 --- a/lib/active_merchant/billing/gateways/itransact.rb +++ b/lib/active_merchant/billing/gateways/itransact.rb @@ -302,7 +302,7 @@ def add_invoice(xml, money, options) xml.AuthCode options[:force] if options[:force] if options[:order_items].blank? xml.Total(amount(money)) unless(money.nil? || money < 0.01) - xml.Description(options[:description]) unless( options[:description].blank?) + xml.Description(options[:description]) unless(options[:description].blank?) else xml.OrderItems { options[:order_items].each do |item| @@ -336,7 +336,7 @@ def add_creditcard(xml, creditcard) xml.AccountInfo { xml.CardAccount { xml.AccountNumber(creditcard.number.to_s) - xml.ExpirationMonth(creditcard.month.to_s.rjust(2,'0')) + xml.ExpirationMonth(creditcard.month.to_s.rjust(2, '0')) xml.ExpirationYear(creditcard.year.to_s) xml.CVVNumber(creditcard.verification_value.to_s) unless creditcard.verification_value.blank? } @@ -372,7 +372,7 @@ def add_transaction_control(xml, options) def add_vendor_data(xml, options) return if options[:vendor_data].blank? xml.VendorData { - options[:vendor_data].each do |k,v| + options[:vendor_data].each do |k, v| xml.Element { xml.Name(k) xml.Key(v) @@ -424,7 +424,7 @@ def parse(raw_xml) def successful?(response) # Turns out the PaymentClearing gateway is not consistent... - response[:status].downcase =='ok' + response[:status].casecmp('ok').zero? end def test_mode?(response) @@ -445,4 +445,3 @@ def sign_payload(payload) end end end - diff --git a/lib/active_merchant/billing/gateways/iveri.rb b/lib/active_merchant/billing/gateways/iveri.rb new file mode 100644 index 00000000000..4a8d96e4752 --- /dev/null +++ b/lib/active_merchant/billing/gateways/iveri.rb @@ -0,0 +1,251 @@ +require 'nokogiri' + +module ActiveMerchant #:nodoc: + module Billing #:nodoc: + class IveriGateway < Gateway + self.live_url = self.test_url = 'https://portal.nedsecure.co.za/iVeriWebService/Service.asmx' + + self.supported_countries = ['US', 'ZA', 'GB'] + self.default_currency = 'ZAR' + self.money_format = :cents + self.supported_cardtypes = [:visa, :master, :american_express] + + self.homepage_url = 'http://www.iveri.com' + self.display_name = 'iVeri' + + def initialize(options={}) + requires!(options, :app_id, :cert_id) + super + end + + def purchase(money, payment_method, options={}) + post = build_vxml_request('Debit', options) do |xml| + add_auth_purchase_params(xml, money, payment_method, options) + end + + commit(post) + end + + def authorize(money, payment_method, options={}) + post = build_vxml_request('Authorisation', options) do |xml| + add_auth_purchase_params(xml, money, payment_method, options) + end + + commit(post) + end + + def capture(money, authorization, options={}) + post = build_vxml_request('Debit', options) do |xml| + add_authorization(xml, authorization, options) + end + + commit(post) + end + + def refund(money, authorization, options={}) + post = build_vxml_request('Credit', options) do |xml| + add_amount(xml, money, options) + add_authorization(xml, authorization, options) + end + + commit(post) + end + + def void(authorization, options={}) + post = build_vxml_request('Void', options) do |xml| + add_authorization(xml, authorization, options) + end + + commit(post) + end + + def verify(credit_card, options={}) + authorize(0, credit_card, options) + end + + def verify_credentials + void = void('', options) + return true if void.message == 'Missing OriginalMerchantTrace' + false + end + + def supports_scrubbing? + true + end + + def scrub(transcript) + transcript. + gsub(%r((CertificateID=\\\")[^\\]*), '\1[FILTERED]'). + gsub(%r((<PAN>)[^&]*), '\1[FILTERED]'). + gsub(%r((<CardSecurityCode>)[^&]*), '\1[FILTERED]') + end + + private + + def build_xml_envelope(vxml) + builder = Nokogiri::XML::Builder.new(:encoding => 'UTF-8') do |xml| + xml[:soap].Envelope 'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance', 'xmlns:xsd' => 'http://www.w3.org/2001/XMLSchema', 'xmlns:soap' => 'http://schemas.xmlsoap.org/soap/envelope/' do + xml[:soap].Body do + xml.Execute 'xmlns' => 'http://iveri.com/' do + xml.validateRequest 'true' + xml.protocol 'V_XML' + xml.protocolVersion '2.0' + xml.request vxml + end + end + end + end + + builder.to_xml + end + + def build_vxml_request(action, options) + builder = Nokogiri::XML::Builder.new do |xml| + xml.V_XML('Version' => '2.0', 'CertificateID' => @options[:cert_id], 'Direction' => 'Request') do + xml.Transaction('ApplicationID' => @options[:app_id], 'Command' => action, 'Mode' => mode) do + yield(xml) + end + end + end + + builder.doc.root.to_xml + end + + def add_auth_purchase_params(post, money, payment_method, options) + add_card_holder_authentication(post, options) + add_amount(post, money, options) + add_electronic_commerce_indicator(post, options) + add_payment_method(post, payment_method, options) + end + + def add_amount(post, money, options) + post.Amount(amount(money)) + post.Currency(options[:currency] || default_currency) + end + + def add_electronic_commerce_indicator(post, options) + post.ElectronicCommerceIndicator(options[:eci]) if options[:eci] + end + + def add_authorization(post, authorization, options) + post.MerchantReference(split_auth(authorization)[2]) + post.TransactionIndex(split_auth(authorization)[1]) + post.OriginalRequestID(split_auth(authorization)[0]) + end + + def add_payment_method(post, payment_method, options) + post.ExpiryDate("#{format(payment_method.month, :two_digits)}#{payment_method.year}") + add_new_reference(post, options) + post.CardSecurityCode(payment_method.verification_value) + post.PAN(payment_method.number) + end + + def add_new_reference(post, options) + post.MerchantReference(options[:order_id] || generate_unique_id) + end + + def add_card_holder_authentication(post, options) + post.CardHolderAuthenticationID(options[:xid]) if options[:xid] + post.CardHolderAuthenticationData(options[:cavv]) if options[:cavv] + end + + def commit(post) + raw_response = begin + ssl_post(live_url, build_xml_envelope(post), headers(post)) + rescue ActiveMerchant::ResponseError => e + e.response.body + end + + parsed = parse(raw_response) + succeeded = success_from(parsed) + + Response.new( + succeeded, + message_from(parsed, succeeded), + parsed, + authorization: authorization_from(parsed), + error_code: error_code_from(parsed, succeeded), + test: test? + ) + end + + def mode + test? ? 'Test' : 'Live' + end + + def headers(post) + { + 'Content-Type' => 'text/xml; charset=utf-8', + 'Content-Length' => post.size.to_s, + 'SOAPAction' => 'http://iveri.com/Execute' + } + end + + def parse(body) + parsed = {} + + vxml = Nokogiri::XML(body).remove_namespaces!.xpath('//Envelope/Body/ExecuteResponse/ExecuteResult').inner_text + doc = Nokogiri::XML(vxml) + doc.xpath('*').each do |node| + if node.elements.empty? + parsed[underscore(node.name)] = node.text + else + node.elements.each do |childnode| + parse_element(parsed, childnode) + end + end + end + parsed + end + + def parse_element(parsed, node) + if !node.attributes.empty? + node.attributes.each do |a| + parsed[underscore(node.name)+ '_' + underscore(a[1].name)] = a[1].value + end + end + + if !node.elements.empty? + node.elements.each { |e| parse_element(parsed, e) } + else + parsed[underscore(node.name)] = node.text + end + end + + def success_from(response) + response['result_status'] == '0' + end + + def message_from(response, succeeded) + if succeeded + 'Succeeded' + else + response['result_description'] || response['result_acquirer_description'] + end + end + + def authorization_from(response) + "#{response['transaction_request_id']}|#{response['transaction_index']}|#{response['merchant_reference']}" + end + + def split_auth(authorization) + request_id, transaction_index, merchant_reference = authorization.to_s.split('|') + [request_id, transaction_index, merchant_reference] + end + + def error_code_from(response, succeeded) + unless succeeded + response['result_code'] + end + end + + def underscore(camel_cased_word) + camel_cased_word.to_s.gsub(/::/, '/'). + gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2'). + gsub(/([a-z\d])([A-Z])/, '\1_\2'). + tr('-', '_'). + downcase + end + end + end +end diff --git a/lib/active_merchant/billing/gateways/jetpay.rb b/lib/active_merchant/billing/gateways/jetpay.rb index 03fe5f2b828..aaa955dd24a 100644 --- a/lib/active_merchant/billing/gateways/jetpay.rb +++ b/lib/active_merchant/billing/gateways/jetpay.rb @@ -23,132 +23,132 @@ class JetpayGateway < Gateway self.money_format = :cents ACTION_CODE_MESSAGES = { - "000" => "Approved.", - "001" => "Refer to card issuer.", - "002" => "Refer to card issuer, special condition.", - "003" => "Invalid merchant or service provider.", - "004" => "Pick up card.", - "005" => "Do not honor.", - "006" => "Error.", - "007" => "Pick up card, special condition.", - "008" => "Honor with ID (Show ID).", - "010" => "Partial approval.", - "011" => "VIP approval.", - "012" => "Invalid transaction.", - "013" => "Invalid amount or exceeds maximum for card program.", - "014" => "Invalid account number (no such number).", - "015" => "No such issuer.", - "019" => "Re-enter Transaction.", - "021" => "No action taken (unable to back out prior transaction).", - "025" => "Transaction Not Found.", - "027" => "File update field edit error.", - "028" => "File is temporarily unavailable.", - "030" => "Format error.", - "039" => "No credit account.", - "041" => "Pick up card (lost card).", - "043" => "Pick up card (stolen card).", - "051" => "Insufficient funds.", - "052" => "No checking account.", - "053" => "Mp savomgs accpimt.", - "054" => "Expired Card.", - "055" => "Incorrect PIN.", - "057" => "Transaction not permitted to cardholder.", - "058" => "Transaction not allowed at terminal.", - "061" => "Exceeds withdrawal limit.", - "062" => "Restricted card (eg, Country Exclusion).", - "063" => "Security violation.", - "065" => "Activity count limit exceeded.", - "068" => "Response late.", - "070" => "Contact card issuer.", - "071" => "PIN not changed.", - "075" => "Allowable number of PIN-entry tries exceeded.", - "076" => "Unable to locate previous message (no matching retrieval reference number).", - "077" => "Repeat or reversal data are inconsistent with original message.", - "078" => "Blocked (first use), or non-existent account.", - "079" => "Key exchange validation failed.", - "080" => "Credit issuer unavailable or invalid date.", - "081" => "PIN cryptographic error found.", - "082" => "Negative online CVV results.", - "084" => "Invalid auth life cycle.", - "085" => "No reason to decline - CVV or AVS approved.", - "086" => "Cannot verify PIN.", - "087" => "Cashback not allowed.", - "089" => "Issuer Down.", - "091" => "Issuer Down.", - "092" => "Unable to route transaction.", - "093" => "Transaction cannot be completed - violation of law.", - "094" => "Duplicate transmission.", - "096" => "System error.", - "100" => "Deny.", - "101" => "Expired Card.", - "103" => "Deny - Invalid manual Entry 4DBC.", - "104" => "Deny - New card issued.", - "105" => "Deny - Account Cancelled.", - "106" => "Exceeded PIN Attempts.", - "107" => "Please Call Issuer.", - "109" => "Invalid merchant.", - "110" => "Invalid amount.", - "111" => "Invalid account.", - "115" => "Service not permitted.", - "122" => "Invalid card (CID) security code.", - "125" => "Invalid effective date.", - "181" => "Format error.", - "182" => "Please wait.", - "183" => "Invalid currency code.", - "187" => "Deny - new card issued.", - "188" => "Deny - Expiration date required.", - "189" => "Deny - Cancelled or Closed Merchant/SE.", - "200" => "Deny - Pick up card.", - "400" => "Reversal accepted.", - "601" => "Reject - EMV Chip Declined Transaction.", - "602" => "Reject - Suspected Fraud.", - "603" => "Reject - Communications Error.", - "604" => "Reject - Insufficient Approval.", - "750" => "Velocity Check Fail.", - "899" => "Misc Decline.", - "900" => "Invalid Message Type.", - "901" => "Invalid Merchant ID.", - "903" => "Debit not supported.", - "904" => "Private label not supported.", - "905" => "Invalid card type.", - "906" => "Unit not active.", - "908" => "Manual card entry invalid.", - "909" => "Invalid track information.", - "911" => "Master merchant not found.", - "912" => "Invalid card format.", - "913" => "Invalid card type.", - "914" => "Invalid card length.", - "917" => "Expired card.", - "919" => "Invalid entry type.", - "920" => "Invalid amount.", - "921" => "Invalid messge format.", - "923" => "Invalid ABA.", - "924" => "Invalid DDA.", - "925" => "Invalid TID.", - "926" => "Invalid Password.", - "930" => "Invalid zipcode.", - "931" => "Invalid Address.", - "932" => "Invalid ZIP and Address.", - "933" => "Invalid CVV2.", - "934" => "Program Not Allowed.", - "940" => "Record Not Found.", - "941" => "Merchant ID error.", - "942" => "Refund Not Allowed.", - "943" => "Refund denied.", - "955" => "Invalid PIN block.", - "956" => "Invalid KSN.", - "958" => "Bad Status.", - "959" => "Seek Record limit exceeded.", - "962" => "Invalid PIN key (Unknown KSN).", - "981" => "Invalid AVS.", - "987" => "Issuer Unavailable.", - "988" => "System error SD.", - "989" => "Database Error.", - "992" => "Transaction Timeout.", - "996" => "Bad Terminal ID.", - "997" => "Message rejected by association.", - "999" => "Communication failure", - nil => "No response returned (missing credentials?)." + '000' => 'Approved.', + '001' => 'Refer to card issuer.', + '002' => 'Refer to card issuer, special condition.', + '003' => 'Invalid merchant or service provider.', + '004' => 'Pick up card.', + '005' => 'Do not honor.', + '006' => 'Error.', + '007' => 'Pick up card, special condition.', + '008' => 'Honor with ID (Show ID).', + '010' => 'Partial approval.', + '011' => 'VIP approval.', + '012' => 'Invalid transaction.', + '013' => 'Invalid amount or exceeds maximum for card program.', + '014' => 'Invalid account number (no such number).', + '015' => 'No such issuer.', + '019' => 'Re-enter Transaction.', + '021' => 'No action taken (unable to back out prior transaction).', + '025' => 'Transaction Not Found.', + '027' => 'File update field edit error.', + '028' => 'File is temporarily unavailable.', + '030' => 'Format error.', + '039' => 'No credit account.', + '041' => 'Pick up card (lost card).', + '043' => 'Pick up card (stolen card).', + '051' => 'Insufficient funds.', + '052' => 'No checking account.', + '053' => 'No savings account.', + '054' => 'Expired Card.', + '055' => 'Incorrect PIN.', + '057' => 'Transaction not permitted to cardholder.', + '058' => 'Transaction not allowed at terminal.', + '061' => 'Exceeds withdrawal limit.', + '062' => 'Restricted card (eg, Country Exclusion).', + '063' => 'Security violation.', + '065' => 'Activity count limit exceeded.', + '068' => 'Response late.', + '070' => 'Contact card issuer.', + '071' => 'PIN not changed.', + '075' => 'Allowable number of PIN-entry tries exceeded.', + '076' => 'Unable to locate previous message (no matching retrieval reference number).', + '077' => 'Repeat or reversal data are inconsistent with original message.', + '078' => 'Blocked (first use), or non-existent account.', + '079' => 'Key exchange validation failed.', + '080' => 'Credit issuer unavailable or invalid date.', + '081' => 'PIN cryptographic error found.', + '082' => 'Negative online CVV results.', + '084' => 'Invalid auth life cycle.', + '085' => 'No reason to decline - CVV or AVS approved.', + '086' => 'Cannot verify PIN.', + '087' => 'Cashback not allowed.', + '089' => 'Issuer Down.', + '091' => 'Issuer Down.', + '092' => 'Unable to route transaction.', + '093' => 'Transaction cannot be completed - violation of law.', + '094' => 'Duplicate transmission.', + '096' => 'System error.', + '100' => 'Deny.', + '101' => 'Expired Card.', + '103' => 'Deny - Invalid manual Entry 4DBC.', + '104' => 'Deny - New card issued.', + '105' => 'Deny - Account Cancelled.', + '106' => 'Exceeded PIN Attempts.', + '107' => 'Please Call Issuer.', + '109' => 'Invalid merchant.', + '110' => 'Invalid amount.', + '111' => 'Invalid account.', + '115' => 'Service not permitted.', + '122' => 'Invalid card (CID) security code.', + '125' => 'Invalid effective date.', + '181' => 'Format error.', + '182' => 'Please wait.', + '183' => 'Invalid currency code.', + '187' => 'Deny - new card issued.', + '188' => 'Deny - Expiration date required.', + '189' => 'Deny - Cancelled or Closed Merchant/SE.', + '200' => 'Deny - Pick up card.', + '400' => 'Reversal accepted.', + '601' => 'Reject - EMV Chip Declined Transaction.', + '602' => 'Reject - Suspected Fraud.', + '603' => 'Reject - Communications Error.', + '604' => 'Reject - Insufficient Approval.', + '750' => 'Velocity Check Fail.', + '899' => 'Misc Decline.', + '900' => 'Invalid Message Type.', + '901' => 'Invalid Merchant ID.', + '903' => 'Debit not supported.', + '904' => 'Private label not supported.', + '905' => 'Invalid card type.', + '906' => 'Unit not active.', + '908' => 'Manual card entry invalid.', + '909' => 'Invalid track information.', + '911' => 'Master merchant not found.', + '912' => 'Invalid card format.', + '913' => 'Invalid card type.', + '914' => 'Invalid card length.', + '917' => 'Expired card.', + '919' => 'Invalid entry type.', + '920' => 'Invalid amount.', + '921' => 'Invalid messge format.', + '923' => 'Invalid ABA.', + '924' => 'Invalid DDA.', + '925' => 'Invalid TID.', + '926' => 'Invalid Password.', + '930' => 'Invalid zipcode.', + '931' => 'Invalid Address.', + '932' => 'Invalid ZIP and Address.', + '933' => 'Invalid CVV2.', + '934' => 'Program Not Allowed.', + '940' => 'Record Not Found.', + '941' => 'Merchant ID error.', + '942' => 'Refund Not Allowed.', + '943' => 'Refund denied.', + '955' => 'Invalid PIN block.', + '956' => 'Invalid KSN.', + '958' => 'Bad Status.', + '959' => 'Seek Record limit exceeded.', + '962' => 'Invalid PIN key (Unknown KSN).', + '981' => 'Invalid AVS.', + '987' => 'Issuer Unavailable.', + '988' => 'System error SD.', + '989' => 'Database Error.', + '992' => 'Transaction Timeout.', + '996' => 'Bad Terminal ID.', + '997' => 'Message rejected by association.', + '999' => 'Communication failure', + nil => 'No response returned (missing credentials?).' } def initialize(options = {}) @@ -165,12 +165,15 @@ def authorize(money, credit_card, options = {}) end def capture(money, reference, options = {}) - commit(money, build_capture_request(reference.split(";").first, money, options)) + split_authorization = reference.split(';') + transaction_id = split_authorization[0] + token = split_authorization[3] + commit(money, build_capture_request(transaction_id, money, options), token) end def void(reference, options = {}) - transaction_id, approval, amount, token = reference.split(";") - commit(amount.to_i, build_void_request(amount.to_i, transaction_id, approval, token, options)) + transaction_id, approval, amount, token = reference.split(';') + commit(amount.to_i, build_void_request(amount.to_i, transaction_id, approval, token, options), token) end def credit(money, transaction_id_or_card, options = {}) @@ -183,9 +186,9 @@ def credit(money, transaction_id_or_card, options = {}) end def refund(money, reference, options = {}) - params = reference.split(";") - transaction_id = params[0] - token = params[3] + split_authorization = reference.split(';') + transaction_id = split_authorization[0] + token = split_authorization[3] credit_card = options[:credit_card] commit(money, build_credit_request('CREDIT', money, transaction_id, credit_card, token, options)) end @@ -279,7 +282,7 @@ def build_credit_request(transaction_type, money, transaction_id, card, token, o end end - def commit(money, request) + def commit(money, request, token = nil) response = parse(ssl_post(url, request)) success = success?(response) @@ -287,7 +290,7 @@ def commit(money, request) success ? 'APPROVED' : message_from(response), response, :test => test?, - :authorization => authorization_from(response, money), + :authorization => authorization_from(response, money, token), :avs_result => { :code => response[:avs] }, :cvv_result => response[:cvv2] ) @@ -312,7 +315,7 @@ def parse(body) def parse_element(response, node) if node.has_elements? - node.elements.each{|element| parse_element(response, element) } + node.elements.each { |element| parse_element(response, element) } else response[node.name.underscore.to_sym] = node.text end @@ -323,25 +326,25 @@ def format_exp(value) end def success?(response) - response[:action_code] == "000" + response[:action_code] == '000' end def message_from(response) ACTION_CODE_MESSAGES[response[:action_code]] end - def authorization_from(response, money) + def authorization_from(response, money, previous_token) original_amount = amount(money) if money - [ response[:transaction_id], response[:approval], original_amount, response[:token]].join(";") + [ response[:transaction_id], response[:approval], original_amount, (response[:token] || previous_token)].join(';') end def add_credit_card(xml, credit_card) - xml.tag! 'CardNum', credit_card.number, "Tokenize" => true + xml.tag! 'CardNum', credit_card.number, 'Tokenize' => true xml.tag! 'CardExpMonth', format_exp(credit_card.month) xml.tag! 'CardExpYear', format_exp(credit_card.year) if credit_card.first_name || credit_card.last_name - xml.tag! 'CardName', [credit_card.first_name,credit_card.last_name].compact.join(' ') + xml.tag! 'CardName', [credit_card.first_name, credit_card.last_name].compact.join(' ') end unless credit_card.verification_value.nil? || (credit_card.verification_value.length == 0) @@ -351,7 +354,7 @@ def add_credit_card(xml, credit_card) def add_addresses(xml, options) if billing_address = options[:billing_address] || options[:address] - xml.tag! 'BillingAddress', [billing_address[:address1], billing_address[:address2]].compact.join(" ") + xml.tag! 'BillingAddress', [billing_address[:address1], billing_address[:address2]].compact.join(' ') xml.tag! 'BillingCity', billing_address[:city] xml.tag! 'BillingStateProv', billing_address[:state] xml.tag! 'BillingPostalCode', billing_address[:zip] @@ -364,7 +367,7 @@ def add_addresses(xml, options) xml.tag! 'ShippingName', shipping_address[:name] xml.tag! 'ShippingAddr' do - xml.tag! 'Address', [shipping_address[:address1], shipping_address[:address2]].compact.join(" ") + xml.tag! 'Address', [shipping_address[:address1], shipping_address[:address2]].compact.join(' ') xml.tag! 'City', shipping_address[:city] xml.tag! 'StateProv', shipping_address[:state] xml.tag! 'PostalCode', shipping_address[:zip] @@ -392,7 +395,7 @@ def add_user_defined_fields(xml, options) def lookup_country_code(code) country = Country.find(code) rescue nil - country && country.code(:alpha3) + country&.code(:alpha3) end end end diff --git a/lib/active_merchant/billing/gateways/jetpay_v2.rb b/lib/active_merchant/billing/gateways/jetpay_v2.rb new file mode 100644 index 00000000000..515bba8fc84 --- /dev/null +++ b/lib/active_merchant/billing/gateways/jetpay_v2.rb @@ -0,0 +1,437 @@ +module ActiveMerchant #:nodoc: + module Billing #:nodoc: + class JetpayV2Gateway < Gateway + self.test_url = 'https://test1.jetpay.com/jetpay' + self.live_url = 'https://gateway20.jetpay.com/jetpay' + + self.money_format = :cents + self.default_currency = 'USD' + self.supported_countries = ['US', 'CA'] + self.supported_cardtypes = [:visa, :master, :american_express, :discover] + + self.homepage_url = 'http://www.jetpay.com' + self.display_name = 'JetPay' + + API_VERSION = '2.2' + + ACTION_CODE_MESSAGES = { + '000' => 'Approved.', + '001' => 'Refer to card issuer.', + '002' => 'Refer to card issuer, special condition.', + '003' => 'Invalid merchant or service provider.', + '004' => 'Pick up card.', + '005' => 'Do not honor.', + '006' => 'Error.', + '007' => 'Pick up card, special condition.', + '008' => 'Honor with ID (Show ID).', + '010' => 'Partial approval.', + '011' => 'VIP approval.', + '012' => 'Invalid transaction.', + '013' => 'Invalid amount or exceeds maximum for card program.', + '014' => 'Invalid account number (no such number).', + '015' => 'No such issuer.', + '019' => 'Re-enter Transaction.', + '021' => 'No action taken (unable to back out prior transaction).', + '025' => 'Transaction Not Found.', + '027' => 'File update field edit error.', + '028' => 'File is temporarily unavailable.', + '030' => 'Format error.', + '039' => 'No credit account.', + '041' => 'Pick up card (lost card).', + '043' => 'Pick up card (stolen card).', + '051' => 'Insufficient funds.', + '052' => 'No checking account.', + '053' => 'No savings account.', + '054' => 'Expired Card.', + '055' => 'Incorrect PIN.', + '057' => 'Transaction not permitted to cardholder.', + '058' => 'Transaction not allowed at terminal.', + '061' => 'Exceeds withdrawal limit.', + '062' => 'Restricted card (eg, Country Exclusion).', + '063' => 'Security violation.', + '065' => 'Activity count limit exceeded.', + '068' => 'Response late.', + '070' => 'Contact card issuer.', + '071' => 'PIN not changed.', + '075' => 'Allowable number of PIN-entry tries exceeded.', + '076' => 'Unable to locate previous message (no matching retrieval reference number).', + '077' => 'Repeat or reversal data are inconsistent with original message.', + '078' => 'Blocked (first use), or non-existent account.', + '079' => 'Key exchange validation failed.', + '080' => 'Credit issuer unavailable or invalid date.', + '081' => 'PIN cryptographic error found.', + '082' => 'Negative online CVV results.', + '084' => 'Invalid auth life cycle.', + '085' => 'No reason to decline - CVV or AVS approved.', + '086' => 'Cannot verify PIN.', + '087' => 'Cashback not allowed.', + '089' => 'Issuer Down.', + '091' => 'Issuer Down.', + '092' => 'Unable to route transaction.', + '093' => 'Transaction cannot be completed - violation of law.', + '094' => 'Duplicate transmission.', + '096' => 'System error.', + '100' => 'Deny.', + '101' => 'Expired Card.', + '103' => 'Deny - Invalid manual Entry 4DBC.', + '104' => 'Deny - New card issued.', + '105' => 'Deny - Account Cancelled.', + '106' => 'Exceeded PIN Attempts.', + '107' => 'Please Call Issuer.', + '109' => 'Invalid merchant.', + '110' => 'Invalid amount.', + '111' => 'Invalid account.', + '115' => 'Service not permitted.', + '117' => 'Invalid PIN.', + '119' => 'Card member not enrolled.', + '122' => 'Invalid card (CID) security code.', + '125' => 'Invalid effective date.', + '181' => 'Format error.', + '182' => 'Please wait.', + '183' => 'Invalid currency code.', + '187' => 'Deny - new card issued.', + '188' => 'Deny - Expiration date required.', + '189' => 'Deny - Cancelled or Closed Merchant/SE.', + '200' => 'Deny - Pick up card.', + '400' => 'Reversal accepted.', + '601' => 'Reject - EMV Chip Declined Transaction.', + '602' => 'Reject - Suspected Fraud.', + '603' => 'Reject - Communications Error.', + '604' => 'Reject - Insufficient Approval.', + '750' => 'Velocity Check Fail.', + '899' => 'Misc Decline.', + '900' => 'Invalid Message Type.', + '901' => 'Invalid Merchant ID.', + '903' => 'Debit not supported.', + '904' => 'Private label not supported.', + '905' => 'Invalid card type.', + '906' => 'Unit not active.', + '908' => 'Manual card entry invalid.', + '909' => 'Invalid track information.', + '911' => 'Master merchant not found.', + '912' => 'Invalid card format.', + '913' => 'Invalid card type.', + '914' => 'Invalid card length.', + '917' => 'Expired card.', + '919' => 'Invalid entry type.', + '920' => 'Invalid amount.', + '921' => 'Invalid messge format.', + '923' => 'Invalid ABA.', + '924' => 'Invalid DDA.', + '925' => 'Invalid TID.', + '926' => 'Invalid Password.', + '930' => 'Invalid zipcode.', + '931' => 'Invalid Address.', + '932' => 'Invalid ZIP and Address.', + '933' => 'Invalid CVV2.', + '934' => 'Program Not Allowed.', + '935' => 'Invalid Device/App.', + '940' => 'Record Not Found.', + '941' => 'Merchant ID error.', + '942' => 'Refund Not Allowed.', + '943' => 'Refund denied.', + '955' => 'Invalid PIN block.', + '956' => 'Invalid KSN.', + '958' => 'Bad Status.', + '959' => 'Seek Record limit exceeded.', + '960' => 'Internal Key Database Error.', + '961' => 'TRANS not Supported. Cash Disbursement required a specific MCC.', + '962' => 'Invalid PIN key (Unknown KSN).', + '981' => 'Invalid AVS.', + '987' => 'Issuer Unavailable.', + '988' => 'System error SD.', + '989' => 'Database Error.', + '992' => 'Transaction Timeout.', + '996' => 'Bad Terminal ID.', + '997' => 'Message rejected by association.', + '999' => 'Communication failure', + nil => 'No response returned (missing credentials?).' + } + + def initialize(options = {}) + requires!(options, :login) + super + end + + def purchase(money, payment, options = {}) + commit(money, build_sale_request(money, payment, options)) + end + + def authorize(money, payment, options = {}) + commit(money, build_authonly_request(money, payment, options)) + end + + def capture(money, reference, options = {}) + transaction_id, _, _, token = reference.split(';') + commit(money, build_capture_request(money, transaction_id, options), token) + end + + def void(reference, options = {}) + transaction_id, _, amount, token = reference.split(';') + commit(amount.to_i, build_void_request(amount.to_i, transaction_id, options), token) + end + + def credit(money, payment, options = {}) + commit(money, build_credit_request(money, nil, payment, options)) + end + + def refund(money, reference, options = {}) + transaction_id, _, _, token = reference.split(';') + commit(money, build_credit_request(money, transaction_id, token, options), token) + end + + def verify(credit_card, options = {}) + authorize(0, credit_card, options) + end + + def store(credit_card, options = {}) + commit(nil, build_store_request(credit_card, options)) + end + + def supports_scrubbing + true + end + + def scrub(transcript) + transcript. + gsub(%r((Authorization: Basic )\w+), '\1[FILTERED]'). + gsub(%r((>)\d+()), '\1[FILTERED]\2'). + gsub(%r(()\d+()), '\1[FILTERED]\2') + end + + private + + def build_xml_request(transaction_type, options = {}, transaction_id = nil, &block) + xml = Builder::XmlMarkup.new + xml.tag! 'JetPay', 'Version' => API_VERSION do + # Basic values needed for any request + xml.tag! 'TerminalID', @options[:login] + xml.tag! 'TransactionType', transaction_type + xml.tag! 'TransactionID', transaction_id.nil? ? generate_unique_id.slice(0, 18) : transaction_id + xml.tag! 'Origin', options[:origin] || 'INTERNET' + xml.tag! 'IndustryInfo', 'Type' => options[:industry_info] || 'ECOMMERCE' + xml.tag! 'Application', (options[:application] || 'n/a'), {'Version' => options[:application_version] || '1.0'} + xml.tag! 'Device', (options[:device] || 'n/a'), {'Version' => options[:device_version] || '1.0'} + xml.tag! 'Library', 'VirtPOS SDK', 'Version' => '1.5' + xml.tag! 'Gateway', 'JetPay' + xml.tag! 'DeveloperID', options[:developer_id] || 'n/a' + + if block_given? + yield xml + else + xml.target! + end + end + end + + def build_sale_request(money, payment, options) + build_xml_request('SALE', options) do |xml| + add_payment(xml, payment) + add_addresses(xml, options) + add_customer_data(xml, options) + add_invoice_data(xml, options) + add_user_defined_fields(xml, options) + xml.tag! 'TotalAmount', amount(money) + + xml.target! + end + end + + def build_authonly_request(money, payment, options) + build_xml_request('AUTHONLY', options) do |xml| + add_payment(xml, payment) + add_addresses(xml, options) + add_customer_data(xml, options) + add_invoice_data(xml, options) + add_user_defined_fields(xml, options) + xml.tag! 'TotalAmount', amount(money) + + xml.target! + end + end + + def build_capture_request(money, transaction_id, options) + build_xml_request('CAPT', options, transaction_id) do |xml| + add_invoice_data(xml, options) + add_purchase_order(xml, options) + add_user_defined_fields(xml, options) + xml.tag! 'TotalAmount', amount(money) + + xml.target! + end + end + + def build_void_request(money, transaction_id, options) + build_xml_request('VOID', options, transaction_id) do |xml| + xml.tag! 'TotalAmount', amount(money) + xml.target! + end + end + + def build_credit_request(money, transaction_id, payment, options) + build_xml_request('CREDIT', options, transaction_id) do |xml| + add_payment(xml, payment) + add_invoice_data(xml, options) + add_addresses(xml, options) + add_customer_data(xml, options) + add_user_defined_fields(xml, options) + xml.tag! 'TotalAmount', amount(money) + + xml.target! + end + end + + def build_store_request(credit_card, options) + build_xml_request('TOKENIZE', options) do |xml| + add_payment(xml, credit_card) + add_addresses(xml, options) + add_customer_data(xml, options) + + xml.target! + end + end + + def commit(money, request, token = nil) + response = parse(ssl_post(url, request)) + + success = success?(response) + Response.new(success, + success ? 'APPROVED' : message_from(response), + response, + :test => test?, + :authorization => authorization_from(response, money, token), + :avs_result => AVSResult.new(:code => response[:avs]), + :cvv_result => CVVResult.new(response[:cvv2]), + :error_code => success ? nil : error_code_from(response) + ) + end + + def url + test? ? test_url : live_url + end + + def parse(body) + return {} if body.blank? + + xml = REXML::Document.new(body) + + response = {} + xml.root.elements.to_a.each do |node| + parse_element(response, node) + end + response + end + + def parse_element(response, node) + if node.has_elements? + node.elements.each { |element| parse_element(response, element) } + else + response[node.name.underscore.to_sym] = node.text + end + end + + def format_exp(value) + format(value, :two_digits) + end + + def success?(response) + response[:action_code] == '000' + end + + def message_from(response) + ACTION_CODE_MESSAGES[response[:action_code]] + end + + def authorization_from(response, money, previous_token) + original_amount = amount(money) if money + [ response[:transaction_id], response[:approval], original_amount, (response[:token] || previous_token)].join(';') + end + + def error_code_from(response) + response[:action_code] + end + + def add_payment(xml, payment) + return unless payment + + if payment.is_a? String + token = payment + _, _, _, token = payment.split(';') if payment.include? ';' + xml.tag! 'Token', token if token + else + add_credit_card(xml, payment) + end + end + + def add_credit_card(xml, credit_card) + xml.tag! 'CardNum', credit_card.number, 'CardPresent' => false, 'Tokenize' => true + xml.tag! 'CardExpMonth', format_exp(credit_card.month) + xml.tag! 'CardExpYear', format_exp(credit_card.year) + + if credit_card.first_name || credit_card.last_name + xml.tag! 'CardName', [credit_card.first_name, credit_card.last_name].compact.join(' ') + end + + unless credit_card.verification_value.nil? || (credit_card.verification_value.length == 0) + xml.tag! 'CVV2', credit_card.verification_value + end + end + + def add_addresses(xml, options) + if billing_address = options[:billing_address] || options[:address] + xml.tag! 'Billing' do + xml.tag! 'Address', [billing_address[:address1], billing_address[:address2]].compact.join(' ') + xml.tag! 'City', billing_address[:city] + xml.tag! 'StateProv', billing_address[:state] + xml.tag! 'PostalCode', billing_address[:zip] + xml.tag! 'Country', lookup_country_code(billing_address[:country]) + xml.tag! 'Phone', billing_address[:phone] + xml.tag! 'Email', options[:email] if options[:email] + end + end + + if shipping_address = options[:shipping_address] + xml.tag! 'Shipping' do + xml.tag! 'Name', shipping_address[:name] + xml.tag! 'Address', [shipping_address[:address1], shipping_address[:address2]].compact.join(' ') + xml.tag! 'City', shipping_address[:city] + xml.tag! 'StateProv', shipping_address[:state] + xml.tag! 'PostalCode', shipping_address[:zip] + xml.tag! 'Country', lookup_country_code(shipping_address[:country]) + xml.tag! 'Phone', shipping_address[:phone] + end + end + end + + def add_customer_data(xml, options) + xml.tag! 'UserIPAddress', options[:ip] if options[:ip] + end + + def add_invoice_data(xml, options) + xml.tag! 'OrderNumber', options[:order_id] if options[:order_id] + if tax_amount = options[:tax_amount] + xml.tag! 'TaxAmount', tax_amount, {'ExemptInd' => options[:tax_exempt] || 'false'} + end + end + + def add_purchase_order(xml, options) + if purchase_order = options[:purchase_order] + xml.tag! 'Billing' do + xml.tag! 'CustomerPO', purchase_order + end + end + end + + def add_user_defined_fields(xml, options) + xml.tag! 'UDField1', options[:ud_field_1] if options[:ud_field_1] + xml.tag! 'UDField2', options[:ud_field_2] if options[:ud_field_2] + xml.tag! 'UDField3', options[:ud_field_3] if options[:ud_field_3] + end + + def lookup_country_code(code) + country = Country.find(code) rescue nil + country&.code(:alpha3) + end + end + end +end diff --git a/lib/active_merchant/billing/gateways/komoju.rb b/lib/active_merchant/billing/gateways/komoju.rb index f2e5f172411..d53ab5f5165 100644 --- a/lib/active_merchant/billing/gateways/komoju.rb +++ b/lib/active_merchant/billing/gateways/komoju.rb @@ -3,8 +3,8 @@ module ActiveMerchant #:nodoc: module Billing #:nodoc: class KomojuGateway < Gateway - self.test_url = "https://sandbox.komoju.com/api/v1" - self.live_url = "https://komoju.com/api/v1" + self.test_url = 'https://komoju.com/api/v1' + self.live_url = 'https://komoju.com/api/v1' self.supported_countries = ['JP'] self.default_currency = 'JPY' self.money_format = :cents @@ -13,10 +13,10 @@ class KomojuGateway < Gateway self.supported_cardtypes = [:visa, :master, :american_express, :jcb] STANDARD_ERROR_CODE_MAPPING = { - "bad_verification_value" => "incorrect_cvc", - "card_expired" => "expired_card", - "card_declined" => "card_declined", - "invalid_number" => "invalid_number" + 'bad_verification_value' => 'incorrect_cvc', + 'card_expired' => 'expired_card', + 'card_declined' => 'card_declined', + 'invalid_number' => 'invalid_number' } def initialize(options = {}) @@ -34,7 +34,7 @@ def purchase(money, payment, options = {}) post[:tax] = options[:tax] if options[:tax] add_fraud_details(post, options) - commit("/payments", post) + commit('/payments', post) end def refund(money, identification, options = {}) @@ -82,15 +82,15 @@ def api_request(path, data) def commit(path, params) response = api_request(path, params.to_json) - success = !response.key?("error") - message = (success ? "Transaction succeeded" : response["error"]["message"]) + success = !response.key?('error') + message = (success ? 'Transaction succeeded' : response['error']['message']) Response.new( success, message, response, test: test?, - error_code: (success ? nil : error_code(response["error"]["code"])), - authorization: (success ? response["id"] : nil) + error_code: (success ? nil : error_code(response['error']['code'])), + authorization: (success ? response['id'] : nil) ) end @@ -104,10 +104,10 @@ def url def headers { - "Authorization" => "Basic " + Base64.encode64(@options[:login].to_s + ":").strip, - "Accept" => "application/json", - "Content-Type" => "application/json", - "User-Agent" => "Komoju/v1 ActiveMerchantBindings/#{ActiveMerchant::VERSION}" + 'Authorization' => 'Basic ' + Base64.encode64(@options[:login].to_s + ':').strip, + 'Accept' => 'application/json', + 'Content-Type' => 'application/json', + 'User-Agent' => "Komoju/v1 ActiveMerchantBindings/#{ActiveMerchant::VERSION}" } end end diff --git a/lib/active_merchant/billing/gateways/kushki.rb b/lib/active_merchant/billing/gateways/kushki.rb index 3ef46158d0d..c97bd2e6f38 100644 --- a/lib/active_merchant/billing/gateways/kushki.rb +++ b/lib/active_merchant/billing/gateways/kushki.rb @@ -1,14 +1,14 @@ module ActiveMerchant #:nodoc: module Billing #:nodoc: class KushkiGateway < Gateway - self.display_name = "Kushki" - self.homepage_url = "https://www.kushkipagos.com" + self.display_name = 'Kushki' + self.homepage_url = 'https://www.kushkipagos.com' - self.test_url = "https://api-uat.kushkipagos.com/v1/" - self.live_url = "https://api.kushkipagos.com/v1/" + self.test_url = 'https://api-uat.kushkipagos.com/v1/' + self.live_url = 'https://api.kushkipagos.com/v1/' - self.supported_countries = ["CO", "EC"] - self.default_currency = "USD" + self.supported_countries = ['CO', 'EC'] + self.default_currency = 'USD' self.money_format = :dollars self.supported_cardtypes = [:visa, :master, :american_express, :discover, :diners_club] @@ -24,13 +24,22 @@ def purchase(amount, payment_method, options={}) end end + def refund(amount, authorization, options={}) + action = 'refund' + + post = {} + post[:ticketNumber] = authorization + + commit(action, post) + end + def void(authorization, options={}) - action = "void" + action = 'void' post = {} - add_invoice(action, post, nil, options) + post[:ticketNumber] = authorization - commit(action, post, authorization) + commit(action, post) end def supports_scrubbing? @@ -47,7 +56,7 @@ def scrub(transcript) private def tokenize(amount, payment_method, options) - action = "tokenize" + action = 'tokenize' post = {} add_invoice(action, post, amount, options) @@ -57,7 +66,7 @@ def tokenize(amount, payment_method, options) end def charge(amount, authorization, options) - action = "charge" + action = 'charge' post = {} add_reference(post, authorization, options) @@ -67,7 +76,7 @@ def charge(amount, authorization, options) end def add_invoice(action, post, money, options) - if action == "tokenize" + if action == 'tokenize' post[:totalAmount] = amount(money).to_f post[:currency] = options[:currency] || currency(money) post[:isDeferred] = false @@ -85,14 +94,7 @@ def add_amount_defaults(sum, money, options) sum[:iva] = 0 sum[:subtotalIva0] = 0 - if sum[:currency] == "COP" - extra_taxes = {} - extra_taxes[:propina] = 0 - extra_taxes[:tasaAeroportuaria] = 0 - extra_taxes[:agenciaDeViaje] = 0 - extra_taxes[:iac] = 0 - sum[:extraTaxes] = extra_taxes - else + if sum[:currency] != 'COP' sum[:ice] = 0 end end @@ -103,7 +105,8 @@ def add_amount_by_country(sum, options) sum[:iva] = amount[:iva].to_f if amount[:iva] sum[:subtotalIva0] = amount[:subtotal_iva_0].to_f if amount[:subtotal_iva_0] sum[:ice] = amount[:ice].to_f if amount[:ice] - if extra_taxes = amount[:extra_taxes] && sum[:currency] == "COP" + if (extra_taxes = amount[:extra_taxes]) && sum[:currency] == 'COP' + sum[:extraTaxes] ||= Hash.new sum[:extraTaxes][:propina] = extra_taxes[:propina].to_f if extra_taxes[:propina] sum[:extraTaxes][:tasaAeroportuaria] = extra_taxes[:tasa_aeroportuaria].to_f if extra_taxes[:tasa_aeroportuaria] sum[:extraTaxes][:agenciaDeViaje] = extra_taxes[:agencia_de_viaje].to_f if extra_taxes[:agencia_de_viaje] @@ -127,14 +130,15 @@ def add_reference(post, authorization, options) end ENDPOINT = { - "tokenize" => "tokens", - "charge" => "charges", - "void" => "charges" + 'tokenize' => 'tokens', + 'charge' => 'charges', + 'void' => 'charges', + 'refund' => 'refund' } - def commit(action, params, authorization=nil) + def commit(action, params) response = begin - parse(ssl_invoke(action, params, authorization)) + parse(ssl_invoke(action, params)) rescue ResponseError => e parse(e.response.body) end @@ -151,19 +155,19 @@ def commit(action, params, authorization=nil) ) end - def ssl_invoke(action, params, authorization) - if action == "void" - ssl_request(:delete_with_body, url(action, authorization), post_data(params), headers(action)) + def ssl_invoke(action, params) + if ['void', 'refund'].include?(action) + ssl_request(:delete, url(action, params), nil, headers(action)) else - ssl_post(url(action, authorization), post_data(params), headers(action)) + ssl_post(url(action, params), post_data(params), headers(action)) end end def headers(action) hfields = {} - hfields["Public-Merchant-Id"] = @options[:public_merchant_id] if action == "tokenize" - hfields["Private-Merchant-Id"] = @options[:private_merchant_id] unless action == "tokenize" - hfields["Content-Type"] = "application/json" + hfields['Public-Merchant-Id'] = @options[:public_merchant_id] if action == 'tokenize' + hfields['Private-Merchant-Id'] = @options[:private_merchant_id] unless action == 'tokenize' + hfields['Content-Type'] = 'application/json' hfields end @@ -171,46 +175,44 @@ def post_data(params) params.to_json end - def url(action, authorization) + def url(action, params) base_url = test? ? test_url : live_url - if action == "void" - base_url + ENDPOINT[action] + "/" + authorization + if ['void', 'refund'].include?(action) + base_url + ENDPOINT[action] + '/' + params[:ticketNumber].to_s else base_url + ENDPOINT[action] end end def parse(body) - begin - JSON.parse(body) - rescue JSON::ParserError - message = "Invalid JSON response received from KushkiGateway. Please contact KushkiGateway if you continue to receive this message." - message += " (The raw response returned by the API was #{body.inspect})" - { - "message" => message - } - end + JSON.parse(body) + rescue JSON::ParserError + message = 'Invalid JSON response received from KushkiGateway. Please contact KushkiGateway if you continue to receive this message.' + message += " (The raw response returned by the API was #{body.inspect})" + { + 'message' => message + } end def success_from(response) - return true if response["token"] || response["ticketNumber"] + return true if response['token'] || response['ticketNumber'] || response['code'] == 'K000' end def message_from(succeeded, response) if succeeded - "Succeeded" + 'Succeeded' else - response["message"] + response['message'] end end def authorization_from(response) - response["token"] || response["ticketNumber"] + response['token'] || response['ticketNumber'] end def error_from(response) - response["code"] + response['code'] end end end diff --git a/lib/active_merchant/billing/gateways/latitude19.rb b/lib/active_merchant/billing/gateways/latitude19.rb index b7daf2a2f7d..d30b5e14a22 100644 --- a/lib/active_merchant/billing/gateways/latitude19.rb +++ b/lib/active_merchant/billing/gateways/latitude19.rb @@ -1,14 +1,14 @@ module ActiveMerchant #:nodoc: module Billing #:nodoc: class Latitude19Gateway < Gateway - self.display_name = "Latitude19 Gateway" - self.homepage_url = "http://www.l19tech.com" + self.display_name = 'Latitude19 Gateway' + self.homepage_url = 'http://www.l19tech.com' - self.live_url = "https://gateway.l19tech.com/payments/" - self.test_url = "https://gateway-sb.l19tech.com/payments/" + self.live_url = 'https://gateway.l19tech.com/payments/' + self.test_url = 'https://gateway-sb.l19tech.com/payments/' - self.supported_countries = ["US", "CA"] - self.default_currency = "USD" + self.supported_countries = ['US', 'CA'] + self.default_currency = 'USD' self.money_format = :cents self.supported_cardtypes = [:visa, :master, :american_express, :discover, :diners_club, :jcb] @@ -43,12 +43,12 @@ class Latitude19Gateway < Gateway } BRAND_MAP = { - "master" => "MC", - "visa" => "VI", - "american_express" => "AX", - "discover" => "DS", - "diners_club" => "DC", - "jcb" => "JC" + 'master' => 'MC', + 'visa' => 'VI', + 'american_express' => 'AX', + 'discover' => 'DS', + 'diners_club' => 'DC', + 'jcb' => 'JC' } def initialize(options={}) @@ -58,31 +58,31 @@ def initialize(options={}) def purchase(amount, payment_method, options={}) if payment_method.is_a?(String) - auth_or_sale("sale", payment_method, amount, nil, options) + auth_or_sale('sale', payment_method, amount, nil, options) else MultiResponse.run() do |r| r.process { get_session(options) } r.process { get_token(r.authorization, payment_method, options) } - r.process { auth_or_sale("sale", r.authorization, amount, payment_method, options) } + r.process { auth_or_sale('sale', r.authorization, amount, payment_method, options) } end end end def authorize(amount, payment_method, options={}) if payment_method.is_a?(String) - auth_or_sale("auth", payment_method, amount, nil, options) + auth_or_sale('auth', payment_method, amount, nil, options) else MultiResponse.run() do |r| r.process { get_session(options) } r.process { get_token(r.authorization, payment_method, options) } - r.process { auth_or_sale("auth", r.authorization, amount, payment_method, options) } + r.process { auth_or_sale('auth', r.authorization, amount, payment_method, options) } end end end def capture(amount, authorization, options={}) post = {} - post[:method] = "deposit" + post[:method] = 'deposit' add_request_id(post) params = {} @@ -93,18 +93,18 @@ def capture(amount, authorization, options={}) add_credentials(params, post[:method]) post[:params] = [params] - commit("v1/", post) + commit('v1/', post) end def void(authorization, options={}) method, pgwTID = split_authorization(authorization) case method - when "auth" - reverse_or_void("reversal", pgwTID, options) - when "deposit", "sale" - reverse_or_void("void", pgwTID, options) + when 'auth' + reverse_or_void('reversal', pgwTID, options) + when 'deposit', 'sale' + reverse_or_void('void', pgwTID, options) else - message = "Unsupported operation: successful Purchase, Authorize and unsettled Capture transactions can only be voided." + message = 'Unsupported operation: successful Purchase, Authorize and unsettled Capture transactions can only be voided.' return Response.new(false, message) end end @@ -134,7 +134,7 @@ def verify(payment_method, options={}, action=nil) end def store(payment_method, options={}) - verify(payment_method, options, "store") + verify(payment_method, options, 'store') end def supports_scrubbing? @@ -147,22 +147,21 @@ def scrub(transcript) gsub(%r((\"cvv\\\":\\\")\d+), '\1[FILTERED]') end - private def add_request_id(post) post[:id] = SecureRandom.hex(16) end - def add_timestamp() - Time.now.getutc.strftime("%Y%m%d%H%M%S") + def add_timestamp + Time.now.getutc.strftime('%Y%m%d%H%M%S') end def add_hmac(params, method) - if method == "getSession" - hmac_message = params[:pgwAccountNumber] + "|" + params[:pgwConfigurationId] + "|" + params[:requestTimeStamp] + "|" + method + if method == 'getSession' + hmac_message = params[:pgwAccountNumber] + '|' + params[:pgwConfigurationId] + '|' + params[:requestTimeStamp] + '|' + method else - hmac_message = params[:pgwAccountNumber] + "|" + params[:pgwConfigurationId] + "|" + (params[:orderNumber] || "") + "|" + method + "|" + (params[:amount] || "") + "|" + (params[:sessionToken] || "") + "|" + (params[:accountToken] || "") + hmac_message = params[:pgwAccountNumber] + '|' + params[:pgwConfigurationId] + '|' + (params[:orderNumber] || '') + '|' + method + '|' + (params[:amount] || '') + '|' + (params[:sessionToken] || '') + '|' + (params[:accountToken] || '') end OpenSSL::HMAC.hexdigest('sha512', @options[:secret], hmac_message) @@ -172,7 +171,7 @@ def add_credentials(params, method) params[:pgwAccountNumber] = @options[:account_number] params[:pgwConfigurationId] = @options[:configuration_id] - params[:requestTimeStamp] = add_timestamp() if method == "getSession" + params[:requestTimeStamp] = add_timestamp() if method == 'getSession' params[:pgwHMAC] = add_hmac(params, method) end @@ -180,11 +179,11 @@ def add_credentials(params, method) def add_invoice(params, money, options) params[:amount] = amount(money) params[:orderNumber] = options[:order_id] - params[:transactionClass] = options[:transaction_class] || "eCommerce" + params[:transactionClass] = options[:transaction_class] || 'eCommerce' end def add_payment_method(params, credit_card) - params[:cardExp] = format(credit_card.month, :two_digits).to_s + "/" + format(credit_card.year, :two_digits).to_s + params[:cardExp] = format(credit_card.month, :two_digits).to_s + '/' + format(credit_card.year, :two_digits).to_s params[:cardType] = BRAND_MAP[credit_card.brand.to_s] params[:cvv] = credit_card.verification_value params[:firstName] = credit_card.first_name @@ -204,19 +203,19 @@ def add_customer_data(params, options) def get_session(options={}) post = {} - post[:method] = "getSession" + post[:method] = 'getSession' add_request_id(post) params = {} add_credentials(params, post[:method]) post[:params] = [params] - commit("session", post) + commit('session', post) end def get_token(authorization, payment_method, options={}) post = {} - post[:method] = "tokenize" + post[:method] = 'tokenize' add_request_id(post) params = {} @@ -224,7 +223,7 @@ def get_token(authorization, payment_method, options={}) params[:cardNumber] = payment_method.number post[:params] = [params] - commit("token", post) + commit('token', post) end def auth_or_sale(method, authorization, amount, credit_card, options={}) @@ -244,12 +243,12 @@ def auth_or_sale(method, authorization, amount, credit_card, options={}) add_credentials(params, post[:method]) post[:params] = [params] - commit("v1/", post) + commit('v1/', post) end def verifyOnly(action, authorization, credit_card, options={}) post = {} - post[:method] = "verifyOnly" + post[:method] = 'verifyOnly' add_request_id(post) params = {} @@ -260,17 +259,17 @@ def verifyOnly(action, authorization, credit_card, options={}) else _, params[:accountToken] = split_authorization(authorization) end - params[:requestAccountToken] = "1" if action == "store" + params[:requestAccountToken] = '1' if action == 'store' add_invoice(params, 0, options) add_credentials(params, post[:method]) post[:params] = [params] - commit("v1/", post) + commit('v1/', post) end def refundWithCard(authorization, amount, credit_card, options={}) post = {} - post[:method] = "refundWithCard" + post[:method] = 'refundWithCard' add_request_id(post) params = {} @@ -284,7 +283,7 @@ def refundWithCard(authorization, amount, credit_card, options={}) add_credentials(params, post[:method]) post[:params] = [params] - commit("v1/", post) + commit('v1/', post) end def reverse_or_void(method, pgwTID, options={}) @@ -298,36 +297,34 @@ def reverse_or_void(method, pgwTID, options={}) add_credentials(params, post[:method]) post[:params] = [params] - commit("v1/", post) + commit('v1/', post) end def commit(endpoint, post) - begin - raw_response = ssl_post(url() + endpoint, post_data(post), headers) - response = parse(raw_response) - rescue ResponseError => e - raw_response = e.response.body - response_error(raw_response) - rescue JSON::ParserError - unparsable_response(raw_response) - else - success = success_from(response) - Response.new( - success, - message_from(response), - response, - authorization: success ? authorization_from(response, post[:method]) : nil, - avs_result: success ? avs_from(response) : nil, - cvv_result: success ? cvv_from(response) : nil, - error_code: success ? nil : error_from(response), - test: test? - ) - end + raw_response = ssl_post(url() + endpoint, post_data(post), headers) + response = parse(raw_response) + rescue ResponseError => e + raw_response = e.response.body + response_error(raw_response) + rescue JSON::ParserError + unparsable_response(raw_response) + else + success = success_from(response) + Response.new( + success, + message_from(response), + response, + authorization: success ? authorization_from(response, post[:method]) : nil, + avs_result: success ? avs_from(response) : nil, + cvv_result: success ? cvv_from(response) : nil, + error_code: success ? nil : error_from(response), + test: test? + ) end def headers { - "Content-Type" => "application/json" + 'Content-Type' => 'application/json' } end @@ -344,70 +341,68 @@ def parse(body) end def success_from(response) - return false if response["result"].nil? || response["error"] + return false if response['result'].nil? || response['error'] - if response["result"].key?("pgwResponseCode") - response["error"].nil? && response["result"]["lastActionSucceeded"] == 1 && response["result"]["pgwResponseCode"] == "100" + if response['result'].key?('pgwResponseCode') + response['error'].nil? && response['result']['lastActionSucceeded'] == 1 && response['result']['pgwResponseCode'] == '100' else - response["error"].nil? && response["result"]["lastActionSucceeded"] == 1 + response['error'].nil? && response['result']['lastActionSucceeded'] == 1 end end def message_from(response) - return response["error"] if response["error"] - return "Failed" unless response.key?("result") + return response['error'] if response['error'] + return 'Failed' unless response.key?('result') - if response["result"].key?("pgwResponseCode") - RESPONSE_CODE_MAPPING[response["result"]["pgwResponseCode"]] || response["result"]["responseText"] + if response['result'].key?('pgwResponseCode') + RESPONSE_CODE_MAPPING[response['result']['pgwResponseCode']] || response['result']['responseText'] else - response["result"]["lastActionSucceeded"] == 1 ? "Succeeded" : "Failed" + response['result']['lastActionSucceeded'] == 1 ? 'Succeeded' : 'Failed' end end def error_from(response) - return response["error"] if response["error"] - return "Failed" unless response.key?("result") - return response["result"]["pgwResponseCode"] || response["result"]["processor"]["responseCode"] || "Failed" + return response['error'] if response['error'] + return 'Failed' unless response.key?('result') + return response['result']['pgwResponseCode'] || response['result']['processor']['responseCode'] || 'Failed' end def authorization_from(response, method) - method + "|" + ( - response["result"]["sessionId"] || - response["result"]["sessionToken"] || - response["result"]["pgwTID"] || - response["result"]["accountToken"] + method + '|' + ( + response['result']['sessionId'] || + response['result']['sessionToken'] || + response['result']['pgwTID'] || + response['result']['accountToken'] ) end def split_authorization(authorization) - authorization.split("|") + authorization.split('|') end def avs_from(response) - response["result"].key?("avsResponse") ? AVSResult.new(code: response["result"]["avsResponse"]) : nil + response['result'].key?('avsResponse') ? AVSResult.new(code: response['result']['avsResponse']) : nil end def cvv_from(response) - response["result"].key?("cvvResponse") ? CVVResult.new(response["result"]["cvvResponse"]) : nil + response['result'].key?('cvvResponse') ? CVVResult.new(response['result']['cvvResponse']) : nil end def response_error(raw_response) - begin - response = parse(raw_response) - rescue JSON::ParserError - unparsable_response(raw_response) - else - return Response.new( - false, - message_from(response), - response, - :test => test? - ) - end + response = parse(raw_response) + rescue JSON::ParserError + unparsable_response(raw_response) + else + return Response.new( + false, + message_from(response), + response, + :test => test? + ) end def unparsable_response(raw_response) - message = "Invalid JSON response received from Latitude19Gateway. Please contact Latitude19Gateway if you continue to receive this message." + message = 'Invalid JSON response received from Latitude19Gateway. Please contact Latitude19Gateway if you continue to receive this message.' message += " (The raw response returned by the API was #{raw_response.inspect})" return Response.new(false, message) end diff --git a/lib/active_merchant/billing/gateways/linkpoint.rb b/lib/active_merchant/billing/gateways/linkpoint.rb index 653cd8e3946..4dd09c89800 100644 --- a/lib/active_merchant/billing/gateways/linkpoint.rb +++ b/lib/active_merchant/billing/gateways/linkpoint.rb @@ -2,7 +2,6 @@ module ActiveMerchant #:nodoc: module Billing #:nodoc: - # Initialization Options # :login Your store number # :pem The text of your linkpoint PEM file. Note @@ -170,14 +169,14 @@ def initialize(options = {}) def recurring(money, creditcard, options={}) ActiveMerchant.deprecated RECURRING_DEPRECATION_MESSAGE - requires!(options, [:periodicity, :bimonthly, :monthly, :biweekly, :weekly, :yearly, :daily], :installments, :order_id ) + requires!(options, [:periodicity, :bimonthly, :monthly, :biweekly, :weekly, :yearly, :daily], :installments, :order_id) options.update( - :ordertype => "SALE", - :action => options[:action] || "SUBMIT", + :ordertype => 'SALE', + :action => options[:action] || 'SUBMIT', :installments => options[:installments] || 12, - :startdate => options[:startdate] || "immediate", - :periodicity => options[:periodicity].to_s || "monthly", + :startdate => options[:startdate] || 'immediate', + :periodicity => options[:periodicity].to_s || 'monthly', :comments => options[:comments] || nil, :threshold => options[:threshold] || 3 ) @@ -188,7 +187,7 @@ def recurring(money, creditcard, options={}) def purchase(money, creditcard, options={}) requires!(options, :order_id) options.update( - :ordertype => "SALE" + :ordertype => 'SALE' ) commit(money, creditcard, options) end @@ -201,7 +200,7 @@ def purchase(money, creditcard, options={}) def authorize(money, creditcard, options = {}) requires!(options, :order_id) options.update( - :ordertype => "PREAUTH" + :ordertype => 'PREAUTH' ) commit(money, creditcard, options) end @@ -215,7 +214,7 @@ def authorize(money, creditcard, options = {}) def capture(money, authorization, options = {}) options.update( :order_id => authorization, - :ordertype => "POSTAUTH" + :ordertype => 'POSTAUTH' ) commit(money, nil, options) end @@ -224,7 +223,7 @@ def capture(money, authorization, options = {}) def void(identification, options = {}) options.update( :order_id => identification, - :ordertype => "VOID" + :ordertype => 'VOID' ) commit(nil, nil, options) end @@ -236,7 +235,7 @@ def void(identification, options = {}) # def refund(money, identification, options = {}) options.update( - :ordertype => "CREDIT", + :ordertype => 'CREDIT', :order_id => identification ) commit(money, nil, options) @@ -259,6 +258,7 @@ def scrub(transcript) end private + # Commit the transaction by posting the XML file to the LinkPoint server def commit(money, creditcard, options = {}) response = parse(ssl_post(test? ? self.test_url : self.live_url, post_data(money, creditcard, options))) @@ -266,13 +266,13 @@ def commit(money, creditcard, options = {}) Response.new(successful?(response), response[:message], response, :test => test?, :authorization => response[:ordernum], - :avs_result => { :code => response[:avs].to_s[2,1] }, - :cvv_result => response[:avs].to_s[3,1] + :avs_result => { :code => response[:avs].to_s[2, 1] }, + :cvv_result => response[:avs].to_s[3, 1] ) end def successful?(response) - response[:approved] == "APPROVED" + response[:approved] == 'APPROVED' end # Build the XML file @@ -280,11 +280,11 @@ def post_data(money, creditcard, options) params = parameters(money, creditcard, options) xml = REXML::Document.new - order = xml.add_element("order") + order = xml.add_element('order') # Merchant Info - merchantinfo = order.add_element("merchantinfo") - merchantinfo.add_element("configfile").text = @options[:login] + merchantinfo = order.add_element('merchantinfo') + merchantinfo.add_element('configfile').text = @options[:login] # Loop over the params hash to construct the XML string for key, value in params @@ -305,14 +305,14 @@ def post_data(money, creditcard, options) # adds LinkPoint's Items entity to the XML. Called from post_data def build_items(element, items) for item in items - item_element = element.add_element("item") + item_element = element.add_element('item') for key, value in item if key == :options - options_element = item_element.add_element("options") + options_element = item_element.add_element('options') for option in value - opt_element = options_element.add_element("option") - opt_element.add_element("name").text = option[:name] unless option[:name].blank? - opt_element.add_element("value").text = option[:value] unless option[:value].blank? + opt_element = options_element.add_element('option') + opt_element.add_element('name').text = option[:name] unless option[:name].blank? + opt_element.add_element('value').text = option[:value] unless option[:value].blank? end else item_element.add_element(key.to_s).text = item[key].to_s unless item[key].blank? @@ -324,7 +324,6 @@ def build_items(element, items) # Set up the parameters hash just once so we don't have to do it # for every action. def parameters(money, creditcard, options = {}) - params = { :payment => { :subtotal => amount(options[:subtotal]), @@ -334,14 +333,14 @@ def parameters(money, creditcard, options = {}) :chargetotal => amount(money) }, :transactiondetails => { - :transactionorigin => options[:transactionorigin] || "ECI", + :transactionorigin => options[:transactionorigin] || 'ECI', :oid => options[:order_id], :ponumber => options[:ponumber], :taxexempt => options[:taxexempt], :terminaltype => options[:terminaltype], :ip => options[:ip], :reference_number => options[:reference_number], - :recurring => options[:recurring] || "NO", #DO NOT USE if you are using the periodic billing option. + :recurring => options[:recurring] || 'NO', # DO NOT USE if you are using the periodic billing option. :tdate => options[:tdate] }, :orderoptions => { @@ -418,7 +417,6 @@ def parameters(money, creditcard, options = {}) end def parse(xml) - # For reference, a typical response... # # @@ -433,18 +431,18 @@ def parse(xml) # APPROVED # - response = {:message => "Global Error Receipt", :complete => false} + response = {:message => 'Global Error Receipt', :complete => false} xml = REXML::Document.new("#{xml}") - xml.root.elements.each do |node| + xml.root&.elements&.each do |node| response[node.name.downcase.sub(/^r_/, '').to_sym] = normalize(node.text) - end unless xml.root.nil? + end response end def format_creditcard_expiry_year(year) - sprintf("%.4i", year)[-2..-1] + sprintf('%.4i', year)[-2..-1] end end end diff --git a/lib/active_merchant/billing/gateways/litle.rb b/lib/active_merchant/billing/gateways/litle.rb index e46ab85a06b..82b35cc7af6 100644 --- a/lib/active_merchant/billing/gateways/litle.rb +++ b/lib/active_merchant/billing/gateways/litle.rb @@ -3,24 +3,18 @@ module ActiveMerchant #:nodoc: module Billing #:nodoc: class LitleGateway < Gateway - SCHEMA_VERSION = '9.4' + SCHEMA_VERSION = '9.12' - self.test_url = 'https://www.testlitle.com/sandbox/communicator/online' - self.live_url = 'https://payments.litle.com/vap/communicator/online' + self.test_url = 'https://www.testvantivcnp.com/sandbox/communicator/online' + self.live_url = 'https://payments.vantivcnp.com/vap/communicator/online' self.supported_countries = ['US'] self.default_currency = 'USD' self.supported_cardtypes = [:visa, :master, :american_express, :discover, :diners_club, :jcb] - self.homepage_url = 'http://www.litle.com/' - self.display_name = 'Litle & Co.' + self.homepage_url = 'http://www.vantiv.com/' + self.display_name = 'Vantiv eCommerce' - # Public: Create a new Litle gateway. - # - # options - A hash of options: - # :login - The user. - # :password - The password. - # :merchant_id - The merchant id. def initialize(options={}) requires!(options, :login, :password, :merchant_id) super @@ -29,23 +23,33 @@ def initialize(options={}) def purchase(money, payment_method, options={}) request = build_xml_request do |doc| add_authentication(doc) - doc.sale(transaction_attributes(options)) do - add_auth_purchase_params(doc, money, payment_method, options) + if check?(payment_method) + doc.echeckSale(transaction_attributes(options)) do + add_echeck_purchase_params(doc, money, payment_method, options) + end + else + doc.sale(transaction_attributes(options)) do + add_auth_purchase_params(doc, money, payment_method, options) + end end end - - commit(:sale, request, money) + check?(payment_method) ? commit(:echeckSales, request, money) : commit(:sale, request, money) end def authorize(money, payment_method, options={}) request = build_xml_request do |doc| add_authentication(doc) - doc.authorization(transaction_attributes(options)) do - add_auth_purchase_params(doc, money, payment_method, options) + if check?(payment_method) + doc.echeckVerification(transaction_attributes(options)) do + add_echeck_purchase_params(doc, money, payment_method, options) + end + else + doc.authorization(transaction_attributes(options)) do + add_auth_purchase_params(doc, money, payment_method, options) + end end end - - commit(:authorization, request, money) + check?(payment_method) ? commit(:echeckVerification, request, money) : commit(:authorization, request, money) end def capture(money, authorization, options={}) @@ -68,19 +72,24 @@ def credit(money, authorization, options = {}) refund(money, authorization, options) end - def refund(money, authorization, options={}) - transaction_id, _, _ = split_authorization(authorization) - + def refund(money, payment, options={}) request = build_xml_request do |doc| add_authentication(doc) add_descriptor(doc, options) - doc.credit(transaction_attributes(options)) do - doc.litleTxnId(transaction_id) - doc.amount(money) if money + doc.send(refund_type(payment), transaction_attributes(options)) do + if payment.is_a?(String) + transaction_id, _, _ = split_authorization(payment) + doc.litleTxnId(transaction_id) + doc.amount(money) if money + elsif check?(payment) + add_echeck_purchase_params(doc, money, payment, options) + else + add_auth_purchase_params(doc, money, payment, options) + end end end - commit(:credit, request) + commit(refund_type(payment), request) end def verify(creditcard, options = {}) @@ -111,6 +120,11 @@ def store(payment_method, options = {}) doc.orderId(truncate(options[:order_id], 24)) if payment_method.is_a?(String) doc.paypageRegistrationId(payment_method) + elsif check?(payment_method) + doc.echeckForToken do + doc.accNum(payment_method.account_number) + doc.routingNum(payment_method.routing_number) + end else doc.accountNumber(payment_method.number) doc.cardValidationNum(payment_method.verification_value) if payment_method.verification_value @@ -130,6 +144,8 @@ def scrub(transcript) gsub(%r(().+()), '\1[FILTERED]\2'). gsub(%r(().+()), '\1[FILTERED]\2'). gsub(%r(().+()), '\1[FILTERED]\2'). + gsub(%r(().+()), '\1[FILTERED]\2'). + gsub(%r(().+()), '\1[FILTERED]\2'). gsub(%r(().+()), '\1[FILTERED]\2'). gsub(%r(().+()), '\1[FILTERED]\2'). gsub(%r(().+()), '\1[FILTERED]\2'). @@ -137,6 +153,7 @@ def scrub(transcript) end private + CARD_TYPE = { 'visa' => 'VI', 'master' => 'MC', @@ -165,7 +182,27 @@ def scrub(transcript) } def void_type(kind) - (kind == 'authorization') ? :authReversal : :void + if kind == 'authorization' + :authReversal + elsif kind == 'echeckSales' + :echeckVoid + else + :void + end + end + + def refund_type(payment) + _, kind, _ = split_authorization(payment) + if check?(payment) || kind == 'echeckSales' + :echeckCredit + else + :credit + end + end + + def check?(payment_method) + return false if payment_method.is_a?(String) + card_brand(payment_method) == 'check' end def add_authentication(doc) @@ -181,12 +218,32 @@ def add_auth_purchase_params(doc, money, payment_method, options) add_order_source(doc, payment_method, options) add_billing_address(doc, payment_method, options) add_shipping_address(doc, payment_method, options) - add_payment_method(doc, payment_method) + add_payment_method(doc, payment_method, options) add_pos(doc, payment_method) add_descriptor(doc, options) + add_merchant_data(doc, options) add_debt_repayment(doc, options) end + def add_merchant_data(doc, options={}) + if options[:affiliate] || options[:campaign] || options[:merchant_grouping_id] + doc.merchantData do + doc.affiliate(options[:affiliate]) if options[:affiliate] + doc.campaign(options[:campaign]) if options[:campaign] + doc.merchantGroupingId(options[:merchant_grouping_id]) if options[:merchant_grouping_id] + end + end + end + + def add_echeck_purchase_params(doc, money, payment_method, options) + doc.orderId(truncate(options[:order_id], 24)) + doc.amount(money) + add_order_source(doc, payment_method, options) + add_billing_address(doc, payment_method, options) + add_payment_method(doc, payment_method, options) + add_descriptor(doc, options) + end + def add_descriptor(doc, options) if options[:descriptor_name] || options[:descriptor_phone] doc.customBilling do @@ -200,7 +257,7 @@ def add_debt_repayment(doc, options) doc.debtRepayment(true) if options[:debt_repayment] == true end - def add_payment_method(doc, payment_method) + def add_payment_method(doc, payment_method, options) if payment_method.is_a?(String) doc.token do doc.litleToken(payment_method) @@ -209,6 +266,13 @@ def add_payment_method(doc, payment_method) doc.card do doc.track(payment_method.track_data) end + elsif check?(payment_method) + doc.echeck do + doc.accType(payment_method.account_type.capitalize) + doc.accNum(payment_method.account_number) + doc.routingNum(payment_method.routing_number) + doc.checkNum(payment_method.number) + end else doc.card do doc.type_(CARD_TYPE[payment_method.brand]) @@ -220,6 +284,11 @@ def add_payment_method(doc, payment_method) doc.cardholderAuthentication do doc.authenticationValue(payment_method.payment_cryptogram) end + elsif options[:order_source]&.start_with?('3ds') + doc.cardholderAuthentication do + doc.authenticationValue(options[:cavv]) if options[:cavv] + doc.authenticationTransactionId(options[:xid]) if options[:xid] + end end end end @@ -228,7 +297,13 @@ def add_billing_address(doc, payment_method, options) return if payment_method.is_a?(String) doc.billToAddress do - doc.name(payment_method.name) + if check?(payment_method) + doc.name(payment_method.name) + doc.firstName(payment_method.first_name) + doc.lastName(payment_method.last_name) + else + doc.name(payment_method.name) + end doc.email(options[:email]) if options[:email] add_address(doc, options[:billing_address]) @@ -261,6 +336,8 @@ def add_order_source(doc, payment_method, options) doc.orderSource(options[:order_source]) elsif payment_method.is_a?(NetworkTokenizationCreditCard) && payment_method.source == :apple_pay doc.orderSource('applepay') + elsif payment_method.is_a?(NetworkTokenizationCreditCard) && payment_method.source == :android_pay + doc.orderSource('androidpay') elsif payment_method.respond_to?(:track_data) && payment_method.track_data.present? doc.orderSource('retail') else @@ -287,7 +364,7 @@ def parse(kind, xml) doc = Nokogiri::XML(xml).remove_namespaces! doc.xpath("//litleOnlineResponse/#{kind}Response/*").each do |node| - if (node.elements.empty?) + if node.elements.empty? parsed[node.name.to_sym] = node.text else node.elements.each do |childnode| @@ -299,7 +376,7 @@ def parse(kind, xml) if parsed.empty? %w(response message).each do |attribute| - parsed[attribute.to_sym] = doc.xpath("//litleOnlineResponse").attribute(attribute).value + parsed[attribute.to_sym] = doc.xpath('//litleOnlineResponse').attribute(attribute).value end end @@ -325,7 +402,7 @@ def success_from(kind, parsed) end def authorization_from(kind, parsed, money) - (kind == :registerToken) ? parsed[:litleToken] : "#{parsed[:litleTxnId]};#{kind};#{money}" + kind == :registerToken ? parsed[:litleToken] : "#{parsed[:litleTxnId]};#{kind};#{money}" end def split_authorization(authorization) @@ -346,7 +423,7 @@ def root_attributes { merchantId: @options[:merchant_id], version: SCHEMA_VERSION, - xmlns: "http://www.litle.com/schema" + xmlns: 'http://www.litle.com/schema' } end diff --git a/lib/active_merchant/billing/gateways/mastercard.rb b/lib/active_merchant/billing/gateways/mastercard.rb index ecec06dcff8..609039cb9e3 100644 --- a/lib/active_merchant/billing/gateways/mastercard.rb +++ b/lib/active_merchant/billing/gateways/mastercard.rb @@ -1,7 +1,6 @@ module ActiveMerchant module Billing module MastercardGateway - def initialize(options={}) requires!(options, :userid, :password) super @@ -59,7 +58,7 @@ def verify(credit_card, options={}) end def verify_credentials - url = build_url(SecureRandom.uuid, "nonexistent") + url = build_url(SecureRandom.uuid, 'nonexistent') begin ssl_get(url, headers) rescue ResponseError => e @@ -81,6 +80,7 @@ def scrub(transcript) end private + def new_post { order: {}, @@ -164,7 +164,7 @@ def add_customer_data(post, payment_method, options) def add_3dsecure_id(post, options) return unless options[:threed_secure_id] - post.merge!({"3DSecureId" => options[:threed_secure_id]}) + post.merge!({'3DSecureId' => options[:threed_secure_id]}) end def country_code(country) @@ -221,7 +221,7 @@ def parse(body) end def success_from(response) - response['result'] == "SUCCESS" + response['result'] == 'SUCCESS' end def message_from(succeeded, response) @@ -262,7 +262,6 @@ def next_authorization(authorization) next_transactionid = SecureRandom.uuid [orderid, next_transactionid, prev_transactionid] end - end end end diff --git a/lib/active_merchant/billing/gateways/maxipago.rb b/lib/active_merchant/billing/gateways/maxipago.rb index 69ae9a8bd9f..b4ca346327b 100644 --- a/lib/active_merchant/billing/gateways/maxipago.rb +++ b/lib/active_merchant/billing/gateways/maxipago.rb @@ -98,7 +98,7 @@ def url def build_xml_request(action) builder = Nokogiri::XML::Builder.new(encoding: 'UTF-8') - builder.send("transaction-request") do |xml| + builder.send('transaction-request') do |xml| xml.version '3.1.1.15' xml.verification do xml.merchantId @options[:login] @@ -127,7 +127,7 @@ def authorization_from(response) end def split_authorization(authorization) - authorization.split("|") + authorization.split('|') end def parse(body) @@ -142,7 +142,7 @@ def parse(body) def parse_element(response, node) if node.has_elements? - node.elements.each{|element| parse_element(response, element) } + node.elements.each { |element| parse_element(response, element) } else response[node.name.underscore.to_sym] = node.text end diff --git a/lib/active_merchant/billing/gateways/mercado_pago.rb b/lib/active_merchant/billing/gateways/mercado_pago.rb new file mode 100644 index 00000000000..95a9f372930 --- /dev/null +++ b/lib/active_merchant/billing/gateways/mercado_pago.rb @@ -0,0 +1,261 @@ +module ActiveMerchant #:nodoc: + module Billing #:nodoc: + class MercadoPagoGateway < Gateway + self.live_url = self.test_url = 'https://api.mercadopago.com/v1' + + self.supported_countries = ['AR', 'BR', 'CL', 'CO', 'MX', 'PE', 'UY'] + self.supported_cardtypes = [:visa, :master, :american_express] + + self.homepage_url = 'https://www.mercadopago.com/' + self.display_name = 'Mercado Pago' + self.money_format = :dollars + + def initialize(options={}) + requires!(options, :access_token) + super + end + + def purchase(money, payment, options={}) + MultiResponse.run do |r| + r.process { commit('tokenize', 'card_tokens', card_token_request(money, payment, options)) } + options[:card_token] = r.authorization.split('|').first + r.process { commit('purchase', 'payments', purchase_request(money, payment, options)) } + end + end + + def authorize(money, payment, options={}) + MultiResponse.run do |r| + r.process { commit('tokenize', 'card_tokens', card_token_request(money, payment, options)) } + options[:card_token] = r.authorization.split('|').first + r.process { commit('authorize', 'payments', authorize_request(money, payment, options)) } + end + end + + def capture(money, authorization, options={}) + post = {} + authorization, _ = authorization.split('|') + post[:capture] = true + post[:transaction_amount] = amount(money).to_f + commit('capture', "payments/#{authorization}", post) + end + + def refund(money, authorization, options={}) + post = {} + authorization, original_amount = authorization.split('|') + post[:amount] = amount(money).to_f if original_amount && original_amount.to_f > amount(money).to_f + commit('refund', "payments/#{authorization}/refunds", post) + end + + def void(authorization, options={}) + authorization, _ = authorization.split('|') + post = { status: 'cancelled' } + commit('void', "payments/#{authorization}", post) + end + + def verify(credit_card, options={}) + MultiResponse.run(:use_first_response) do |r| + r.process { authorize(100, credit_card, options) } + r.process(:ignore_result) { void(r.authorization, options) } + end + end + + def supports_scrubbing? + true + end + + def scrub(transcript) + transcript. + gsub(%r((access_token=).*?([^\s]+)), '\1[FILTERED]'). + gsub(%r((\"card_number\\\":\\\")\d+), '\1[FILTERED]'). + gsub(%r((\"security_code\\\":\\\")\d+), '\1[FILTERED]') + end + + private + + def card_token_request(money, payment, options = {}) + post = {} + post[:card_number] = payment.number + post[:security_code] = payment.verification_value + post[:expiration_month] = payment.month + post[:expiration_year] = payment.year + post[:cardholder] = { + name: payment.name, + identification: { + type: options[:cardholder_identification_type], + number: options[:cardholder_identification_number] + } + } + post + end + + def purchase_request(money, payment, options = {}) + post = {} + add_invoice(post, money, options) + add_payment(post, options) + add_additional_data(post, options) + add_customer_data(post, payment, options) + add_address(post, options) + post[:binary_mode] = (options[:binary_mode].nil? ? true : options[:binary_mode]) + post + end + + def authorize_request(money, payment, options = {}) + post = purchase_request(money, payment, options) + post[:capture] = false + post + end + + def add_additional_data(post, options) + post[:sponsor_id] = options[:sponsor_id] + post[:device_id] = options[:device_id] if options[:device_id] + post[:additional_info] = { + ip_address: options[:ip_address] + }.merge(options[:additional_info] || {}) + + add_address(post, options) + add_shipping_address(post, options) + end + + def add_customer_data(post, payment, options) + post[:payer] = { + email: options[:email], + first_name: payment.first_name, + last_name: payment.last_name + } + end + + def add_address(post, options) + if address = (options[:billing_address] || options[:address]) + + post[:additional_info].merge!({ + payer: { + address: { + zip_code: address[:zip], + street_name: "#{address[:address1]} #{address[:address2]}" + } + } + }) + end + end + + def add_shipping_address(post, options) + if address = options[:shipping_address] + + post[:additional_info].merge!({ + shipments: { + receiver_address: { + zip_code: address[:zip], + street_name: "#{address[:address1]} #{address[:address2]}" + } + } + }) + end + end + + def split_street_address(address1) + street_number = address1.split(' ').first + + if street_name = address1.split(' ')[1..-1] + street_name = street_name.join(' ') + else + nil + end + + [street_number, street_name] + end + + def add_invoice(post, money, options) + post[:transaction_amount] = amount(money).to_f + post[:description] = options[:description] + post[:installments] = options[:installments] ? options[:installments].to_i : 1 + post[:statement_descriptor] = options[:statement_descriptor] if options[:statement_descriptor] + post[:external_reference] = options[:order_id] || SecureRandom.hex(16) + end + + def add_payment(post, options) + post[:token] = options[:card_token] + post[:issuer_id] = options[:issuer_id] if options[:issuer_id] + post[:payment_method_id] = options[:payment_method_id] if options[:payment_method_id] + end + + def parse(body) + JSON.parse(body) + rescue JSON::ParserError + { + 'status' => 'error', + 'status_detail' => 'json_parse_error', + 'message' => "A non-JSON response was received from Mercado Pago where one was expected. The raw response was:\n\n#{body}" + } + end + + def commit(action, path, parameters) + if ['capture', 'void'].include?(action) + response = parse(ssl_request(:put, url(path), post_data(parameters), headers)) + else + response = parse(ssl_post(url(path), post_data(parameters), headers(parameters))) + end + + Response.new( + success_from(action, response), + message_from(response), + response, + authorization: authorization_from(response, parameters), + test: test?, + error_code: error_code_from(action, response) + ) + end + + def success_from(action, response) + if action == 'refund' + response['status'] != 404 && response['error'].nil? + else + ['active', 'approved', 'authorized', 'cancelled', 'in_process'].include?(response['status']) + end + end + + def message_from(response) + (response['status_detail']) || (response['message']) + end + + def authorization_from(response, params) + [response['id'], params[:transaction_amount]].join('|') + end + + def post_data(parameters = {}) + parameters.clone.tap { |p| p.delete(:device_id) }.to_json + end + + def error_code_from(action, response) + unless success_from(action, response) + if cause = response['cause'] + cause.empty? ? nil : cause.first['code'] + else + response['status'] + end + end + end + + def url(action) + full_url = (test? ? test_url : live_url) + full_url + "/#{action}?access_token=#{CGI.escape(@options[:access_token])}" + end + + def headers(options = {}) + headers = { + 'Content-Type' => 'application/json' + } + headers['X-Device-Session-ID'] = options[:device_id] if options[:device_id] + headers + end + + def handle_response(response) + case response.code.to_i + when 200..499 + response.body + else + raise ResponseError.new(response) + end + end + end + end +end diff --git a/lib/active_merchant/billing/gateways/merchant_e_solutions.rb b/lib/active_merchant/billing/gateways/merchant_e_solutions.rb index f27adf3e306..bad8070e2d1 100644 --- a/lib/active_merchant/billing/gateways/merchant_e_solutions.rb +++ b/lib/active_merchant/billing/gateways/merchant_e_solutions.rb @@ -94,6 +94,17 @@ def void(transaction_id, options = {}) commit('V', nil, options.merge(post)) end + def supports_scrubbing? + true + end + + def scrub(transcript) + transcript. + gsub(%r((&?profile_key=)\w*(&?)), '\1[FILTERED]\2'). + gsub(%r((&?card_number=)\d*(&?)), '\1[FILTERED]\2'). + gsub(%r((&?cvv2=)\d*(&?)), '\1[FILTERED]\2') + end + private def add_address(post, options) @@ -137,7 +148,7 @@ def add_3dsecure_params(post, options) def parse(body) results = {} body.split(/&/).each do |pair| - key,val = pair.split(/=/) + key, val = pair.split(/=/) results[key] = val end results @@ -147,26 +158,25 @@ def commit(action, money, parameters) url = test? ? self.test_url : self.live_url parameters[:transaction_amount] = amount(money) if money unless action == 'V' - response = begin - parse( ssl_post(url, post_data(action,parameters)) ) + parse(ssl_post(url, post_data(action, parameters))) rescue ActiveMerchant::ResponseError => e - { "error_code" => "404", "auth_response_text" => e.to_s } + { 'error_code' => '404', 'auth_response_text' => e.to_s } end - Response.new(response["error_code"] == "000", message_from(response), response, - :authorization => response["transaction_id"], + Response.new(response['error_code'] == '000', message_from(response), response, + :authorization => response['transaction_id'], :test => test?, - :cvv_result => response["cvv2_result"], - :avs_result => { :code => response["avs_result"] } + :cvv_result => response['cvv2_result'], + :avs_result => { :code => response['avs_result'] } ) end def message_from(response) - if response["error_code"] == "000" - "This transaction has been approved" + if response['error_code'] == '000' + 'This transaction has been approved' else - response["auth_response_text"] + response['auth_response_text'] end end @@ -176,7 +186,7 @@ def post_data(action, parameters = {}) post[:profile_key] = @options[:password] post[:transaction_type] = action if action - request = post.merge(parameters).map {|key,value| "#{key}=#{CGI.escape(value.to_s)}"}.join("&") + request = post.merge(parameters).map { |key, value| "#{key}=#{CGI.escape(value.to_s)}" }.join('&') request end end diff --git a/lib/active_merchant/billing/gateways/merchant_one.rb b/lib/active_merchant/billing/gateways/merchant_one.rb index 3d5cb0558e0..20f60dd0cd2 100644 --- a/lib/active_merchant/billing/gateways/merchant_one.rb +++ b/lib/active_merchant/billing/gateways/merchant_one.rb @@ -1,4 +1,4 @@ -require "cgi" +require 'cgi' module ActiveMerchant #:nodoc: module Billing #:nodoc: @@ -46,7 +46,7 @@ def purchase(money, creditcard, options = {}) def capture(money, authorization, options = {}) post = {} - post.merge!(:transactionid => authorization) + post[:transactionid] = authorization add_amount(post, money, options) commit('capture', money, post) end @@ -75,40 +75,39 @@ def add_address(post, creditcard, options) end def add_creditcard(post, creditcard) - post['cvv'] = creditcard.verification_value - post['ccnumber'] = creditcard.number - post['ccexp'] = "#{sprintf("%02d", creditcard.month)}#{"#{creditcard.year}"[-2, 2]}" + post['cvv'] = creditcard.verification_value + post['ccnumber'] = creditcard.number + post['ccexp'] = "#{sprintf("%02d", creditcard.month)}#{creditcard.year.to_s[-2, 2]}" end def commit(action, money, parameters={}) parameters['username'] = @options[:username] parameters['password'] = @options[:password] - parse(ssl_post(BASE_URL,post_data(action, parameters))) + parse(ssl_post(BASE_URL, post_data(action, parameters))) end def post_data(action, parameters = {}) - parameters.merge!({:type => action}) - ret = "" + parameters[:type] = action + ret = '' for key in parameters.keys ret += "#{key}=#{CGI.escape(parameters[key].to_s)}" if key != parameters.keys.last - ret += "&" + ret += '&' end end ret.to_s end def parse(data) - responses = CGI.parse(data).inject({}){|h,(k, v)| h[k] = v.first; h} + responses = CGI.parse(data).inject({}) { |h, (k, v)| h[k] = v.first; h } Response.new( - (responses["response"].to_i == 1), - responses["responsetext"], + (responses['response'].to_i == 1), + responses['responsetext'], responses, :test => test?, - :authorization => responses["transactionid"] + :authorization => responses['transactionid'] ) end end end end - diff --git a/lib/active_merchant/billing/gateways/merchant_partners.rb b/lib/active_merchant/billing/gateways/merchant_partners.rb index 9c5c407d3b1..e4630211a5d 100644 --- a/lib/active_merchant/billing/gateways/merchant_partners.rb +++ b/lib/active_merchant/billing/gateways/merchant_partners.rb @@ -3,13 +3,13 @@ module ActiveMerchant #:nodoc: module Billing #:nodoc: class MerchantPartnersGateway < Gateway - self.display_name = "Merchant Partners" - self.homepage_url = "http://www.merchantpartners.com/" + self.display_name = 'Merchant Partners' + self.homepage_url = 'http://www.merchantpartners.com/' - self.live_url = "https://trans.merchantpartners.com/cgi-bin/ProcessXML.cgi" + self.live_url = 'https://trans.merchantpartners.com/cgi-bin/ProcessXML.cgi' - self.supported_countries = ["US"] - self.default_currency = "USD" + self.supported_countries = ['US'] + self.default_currency = 'USD' self.money_format = :dollars self.supported_cardtypes = [:visa, :master, :american_express, :discover, :diners_club, :jcb] @@ -143,19 +143,19 @@ def add_reference(post, authorization) end ACTIONS = { - purchase: "2", - authorize: "1", - capture: "3", - void: "5", - refund: "4", - credit: "6", - store: "7", - stored_purchase: "8", - stored_credit: "13" + purchase: '2', + authorize: '1', + capture: '3', + void: '5', + refund: '4', + credit: '6', + store: '7', + stored_purchase: '8', + stored_credit: '13' } STORE_TX_TYPES = { - store_only: "3" + store_only: '3' } def commit(action, post) @@ -172,15 +172,15 @@ def commit(action, post) message_from(succeeded, response_data), response_data, authorization: authorization_from(post, response_data), - :avs_result => AVSResult.new(code: response_data["avs_response"]), - :cvv_result => CVVResult.new(response_data["cvv2_response"]), + :avs_result => AVSResult.new(code: response_data['avs_response']), + :cvv_result => CVVResult.new(response_data['cvv2_response']), test: test? ) end def headers { - "Content-Type" => "application/xml" + 'Content-Type' => 'application/xml' } end @@ -188,7 +188,7 @@ def build_request(post) Nokogiri::XML::Builder.new(:encoding => 'utf-8') do |xml| xml.interface_driver { xml.trans_catalog { - xml.transaction(name: "creditcard") { + xml.transaction(name: 'creditcard') { xml.inputs { post.each do |field, value| xml.send(field, value) @@ -202,7 +202,7 @@ def build_request(post) def parse(body) response = {} - Nokogiri::XML(CGI.unescapeHTML(body)).xpath("//trans_catalog/transaction/outputs").children.each do |node| + Nokogiri::XML(CGI.unescapeHTML(body)).xpath('//trans_catalog/transaction/outputs').children.each do |node| parse_element(response, node) end response @@ -212,16 +212,16 @@ def parse_element(response, node) if node.elements.size == 0 response[node.name.downcase.underscore.to_sym] = node.text else - node.elements.each{|element| parse_element(response, element) } + node.elements.each { |element| parse_element(response, element) } end end def success_from(response) - response[:status] == "Approved" + response[:status] == 'Approved' end def message_from(succeeded, response) - succeeded ? "Succeeded" : error_message_from(response) + succeeded ? 'Succeeded' : error_message_from(response) end def authorization_from(request, response) @@ -231,11 +231,11 @@ def authorization_from(request, response) end def split_authorization(authorization) - authorization.split("|") + authorization.split('|') end def error_message_from(response) - if(response[:status] == "Declined") + if(response[:status] == 'Declined') match = response[:result].match(/DECLINED:\d{10}:(.+):/) match[1] if match end diff --git a/lib/active_merchant/billing/gateways/merchant_ware.rb b/lib/active_merchant/billing/gateways/merchant_ware.rb index 47d596b3343..d028024ccb0 100644 --- a/lib/active_merchant/billing/gateways/merchant_ware.rb +++ b/lib/active_merchant/billing/gateways/merchant_ware.rb @@ -11,25 +11,25 @@ class MerchantWareGateway < Gateway self.homepage_url = 'http://merchantwarehouse.com/merchantware' self.display_name = 'MerchantWARE' - ENV_NAMESPACES = { "xmlns:xsi" => "http://www.w3.org/2001/XMLSchema-instance", - "xmlns:xsd" => "http://www.w3.org/2001/XMLSchema", - "xmlns:env" => "http://schemas.xmlsoap.org/soap/envelope/" + ENV_NAMESPACES = { 'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance', + 'xmlns:xsd' => 'http://www.w3.org/2001/XMLSchema', + 'xmlns:env' => 'http://schemas.xmlsoap.org/soap/envelope/' } - ENV_NAMESPACES_V4 = { "xmlns:xsi" => "http://www.w3.org/2001/XMLSchema-instance", - "xmlns:xsd" => "http://www.w3.org/2001/XMLSchema", - "xmlns:soap" => "http://schemas.xmlsoap.org/soap/envelope/" + ENV_NAMESPACES_V4 = { 'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance', + 'xmlns:xsd' => 'http://www.w3.org/2001/XMLSchema', + 'xmlns:soap' => 'http://schemas.xmlsoap.org/soap/envelope/' } - TX_NAMESPACE = "http://merchantwarehouse.com/MerchantWARE/Client/TransactionRetail" - TX_NAMESPACE_V4 = "http://schemas.merchantwarehouse.com/merchantware/40/Credit/" + TX_NAMESPACE = 'http://merchantwarehouse.com/MerchantWARE/Client/TransactionRetail' + TX_NAMESPACE_V4 = 'http://schemas.merchantwarehouse.com/merchantware/40/Credit/' ACTIONS = { - :purchase => "IssueKeyedSale", - :authorize => "IssueKeyedPreAuth", - :capture => "IssuePostAuth", - :void => "VoidPreAuthorization", - :credit => "IssueKeyedRefund", - :reference_credit => "IssueRefundByReference" + :purchase => 'IssueKeyedSale', + :authorize => 'IssueKeyedPreAuth', + :capture => 'IssuePostAuth', + :void => 'VoidPreAuthorization', + :credit => 'IssueKeyedRefund', + :reference_credit => 'IssueRefundByReference' } # Creates a new MerchantWareGateway @@ -121,9 +121,9 @@ def refund(money, reference, options = {}) def soap_request(action) xml = Builder::XmlMarkup.new :indent => 2 xml.instruct! - xml.tag! "env:Envelope", ENV_NAMESPACES do - xml.tag! "env:Body" do - xml.tag! ACTIONS[action], "xmlns" => TX_NAMESPACE do + xml.tag! 'env:Envelope', ENV_NAMESPACES do + xml.tag! 'env:Body' do + xml.tag! ACTIONS[action], 'xmlns' => TX_NAMESPACE do add_credentials(xml) yield xml end @@ -135,12 +135,12 @@ def soap_request(action) def v4_soap_request(action) xml = Builder::XmlMarkup.new :indent => 2 xml.instruct! - xml.tag! "soap:Envelope", ENV_NAMESPACES_V4 do - xml.tag! "soap:Body" do - xml.tag! ACTIONS[:void], "xmlns" => TX_NAMESPACE_V4 do - xml.tag! "merchantName", @options[:name] - xml.tag! "merchantSiteId", @options[:login] - xml.tag! "merchantKey", @options[:password] + xml.tag! 'soap:Envelope', ENV_NAMESPACES_V4 do + xml.tag! 'soap:Body' do + xml.tag! ACTIONS[:void], 'xmlns' => TX_NAMESPACE_V4 do + xml.tag! 'merchantName', @options[:name] + xml.tag! 'merchantSiteId', @options[:login] + xml.tag! 'merchantKey', @options[:password] yield xml end end @@ -175,7 +175,7 @@ def perform_reference_credit(money, identification, options) request = soap_request(:reference_credit) do |xml| add_reference(xml, reference) add_invoice(xml, options) - add_amount(xml, money, "strOverrideAmount") + add_amount(xml, money, 'strOverrideAmount') end commit(:reference_credit, request) @@ -194,47 +194,47 @@ def perform_credit(money, credit_card, options) end def add_credentials(xml) - xml.tag! "strSiteId", @options[:login] - xml.tag! "strKey", @options[:password] - xml.tag! "strName", @options[:name] + xml.tag! 'strSiteId', @options[:login] + xml.tag! 'strKey', @options[:password] + xml.tag! 'strName', @options[:name] end def add_invoice(xml, options) - xml.tag! "strOrderNumber", options[:order_id].to_s.gsub(/[^\w]/, '').slice(0, 25) + xml.tag! 'strOrderNumber', options[:order_id].to_s.gsub(/[^\w]/, '').slice(0, 25) end - def add_amount(xml, money, tag = "strAmount") + def add_amount(xml, money, tag = 'strAmount') xml.tag! tag, amount(money) end def add_reference(xml, reference) - xml.tag! "strReferenceCode", reference + xml.tag! 'strReferenceCode', reference end def add_reference_token(xml, reference) - xml.tag! "token", reference + xml.tag! 'token', reference end def add_address(xml, options) if address = options[:billing_address] || options[:address] - xml.tag! "strAVSStreetAddress", address[:address1] - xml.tag! "strAVSZipCode", address[:zip] + xml.tag! 'strAVSStreetAddress', address[:address1] + xml.tag! 'strAVSZipCode', address[:zip] end end def add_credit_card(xml, credit_card) if credit_card.respond_to?(:track_data) && credit_card.track_data.present? - xml.tag! "trackData", credit_card.track_data + xml.tag! 'trackData', credit_card.track_data else - xml.tag! "strPAN", credit_card.number - xml.tag! "strExpDate", expdate(credit_card) - xml.tag! "strCardHolder", credit_card.name - xml.tag! "strCVCode", credit_card.verification_value if credit_card.verification_value? + xml.tag! 'strPAN', credit_card.number + xml.tag! 'strExpDate', expdate(credit_card) + xml.tag! 'strCardHolder', credit_card.name + xml.tag! 'strCVCode', credit_card.verification_value if credit_card.verification_value? end end def split_reference(reference) - reference.to_s.split(";") + reference.to_s.split(';') end def parse(action, data) @@ -247,10 +247,10 @@ def parse(action, data) response[element.name] = element.text end - status, code, message = response["ApprovalStatus"].split(";") + status, code, message = response['ApprovalStatus'].split(';') response[:status] = status - if response[:success] = status == "APPROVED" + if response[:success] = status == 'APPROVED' response[:message] = status else response[:message] = message @@ -268,17 +268,17 @@ def parse_error(http_response) document = REXML::Document.new(http_response.body) - node = REXML::XPath.first(document, "//soap:Fault") + node = REXML::XPath.first(document, '//soap:Fault') node.elements.each do |element| response[element.name] = element.text end - response[:message] = response["faultstring"].to_s.gsub("\n", " ") + response[:message] = response['faultstring'].to_s.gsub("\n", ' ') response rescue REXML::ParseException response[:http_body] = http_response.body - response[:message] = "Failed to parse the failed response" + response[:message] = 'Failed to parse the failed response' response end @@ -293,9 +293,9 @@ def url(v4 = false) def commit(action, request, v4 = false) begin data = ssl_post(url(v4), request, - "Content-Type" => 'text/xml; charset=utf-8', - "SOAPAction" => soap_action(action, v4) - ) + 'Content-Type' => 'text/xml; charset=utf-8', + 'SOAPAction' => soap_action(action, v4) + ) response = parse(action, data) rescue ActiveMerchant::ResponseError => e response = parse_error(e.response) @@ -304,14 +304,14 @@ def commit(action, request, v4 = false) Response.new(response[:success], response[:message], response, :test => test?, :authorization => authorization_from(response), - :avs_result => { :code => response["AVSResponse"] }, - :cvv_result => response["CVResponse"] + :avs_result => { :code => response['AVSResponse'] }, + :cvv_result => response['CVResponse'] ) end def authorization_from(response) if response[:success] - [ response["ReferenceID"], response["OrderNumber"] ].join(";") + [ response['ReferenceID'], response['OrderNumber'] ].join(';') end end end diff --git a/lib/active_merchant/billing/gateways/merchant_ware_version_four.rb b/lib/active_merchant/billing/gateways/merchant_ware_version_four.rb index 5107e7cd48e..4b1667334a4 100644 --- a/lib/active_merchant/billing/gateways/merchant_ware_version_four.rb +++ b/lib/active_merchant/billing/gateways/merchant_ware_version_four.rb @@ -9,19 +9,19 @@ class MerchantWareVersionFourGateway < Gateway self.homepage_url = 'http://merchantwarehouse.com/merchantware' self.display_name = 'MerchantWARE' - ENV_NAMESPACES = { "xmlns:xsi" => "http://www.w3.org/2001/XMLSchema-instance", - "xmlns:xsd" => "http://www.w3.org/2001/XMLSchema", - "xmlns:soap" => "http://schemas.xmlsoap.org/soap/envelope/" } + ENV_NAMESPACES = { 'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance', + 'xmlns:xsd' => 'http://www.w3.org/2001/XMLSchema', + 'xmlns:soap' => 'http://schemas.xmlsoap.org/soap/envelope/' } - TX_NAMESPACE = "http://schemas.merchantwarehouse.com/merchantware/40/Credit/" + TX_NAMESPACE = 'http://schemas.merchantwarehouse.com/merchantware/40/Credit/' ACTIONS = { - :purchase => "SaleKeyed", + :purchase => 'SaleKeyed', :reference_purchase => 'RepeatSale', - :authorize => "PreAuthorizationKeyed", - :capture => "PostAuthorization", - :void => "Void", - :refund => "Refund" + :authorize => 'PreAuthorizationKeyed', + :capture => 'PostAuthorization', + :void => 'Void', + :refund => 'Refund' } # Creates a new MerchantWareVersionFourGateway @@ -102,7 +102,7 @@ def refund(money, identification, options = {}) request = soap_request(:refund) do |xml| add_reference_token(xml, reference) add_invoice(xml, options) - add_amount(xml, money, "overrideAmount") + add_amount(xml, money, 'overrideAmount') end commit(:refund, request) @@ -131,12 +131,12 @@ def scrub(transcript) def soap_request(action) xml = Builder::XmlMarkup.new :indent => 2 xml.instruct! - xml.tag! "soap:Envelope", ENV_NAMESPACES do - xml.tag! "soap:Body" do - xml.tag! ACTIONS[action], "xmlns" => TX_NAMESPACE do - xml.tag! "merchantName", @options[:name] - xml.tag! "merchantSiteId", @options[:login] - xml.tag! "merchantKey", @options[:password] + xml.tag! 'soap:Envelope', ENV_NAMESPACES do + xml.tag! 'soap:Body' do + xml.tag! ACTIONS[action], 'xmlns' => TX_NAMESPACE do + xml.tag! 'merchantName', @options[:name] + xml.tag! 'merchantSiteId', @options[:login] + xml.tag! 'merchantKey', @options[:password] yield xml end end @@ -166,21 +166,21 @@ def build_capture_request(action, money, identification, options) end def add_invoice(xml, options) - xml.tag! "invoiceNumber", truncate(options[:order_id].to_s.gsub(/[^\w]/, ''), 8) + xml.tag! 'invoiceNumber', truncate(options[:order_id].to_s.gsub(/[^\w]/, ''), 8) end - def add_amount(xml, money, tag = "amount") + def add_amount(xml, money, tag = 'amount') xml.tag! tag, amount(money) end def add_reference_token(xml, reference) - xml.tag! "token", reference + xml.tag! 'token', reference end def add_address(xml, options) address = options[:billing_address] || options[:address] || {} - xml.tag! "avsStreetAddress", address[:address1] - xml.tag! "avsStreetZipCode", address[:zip] + xml.tag! 'avsStreetAddress', address[:address1] + xml.tag! 'avsStreetZipCode', address[:zip] end def add_payment_source(xml, source) @@ -192,14 +192,14 @@ def add_payment_source(xml, source) end def add_credit_card(xml, credit_card) - xml.tag! "cardNumber", credit_card.number - xml.tag! "expirationDate", expdate(credit_card) - xml.tag! "cardholder", credit_card.name - xml.tag! "cardSecurityCode", credit_card.verification_value if credit_card.verification_value? + xml.tag! 'cardNumber', credit_card.number + xml.tag! 'expirationDate', expdate(credit_card) + xml.tag! 'cardholder', credit_card.name + xml.tag! 'cardSecurityCode', credit_card.verification_value if credit_card.verification_value? end def split_reference(reference) - reference.to_s.split(";") + reference.to_s.split(';') end def parse(action, data) @@ -212,14 +212,14 @@ def parse(action, data) response[element.name] = element.text end - if response["ErrorMessage"].present? - response[:message] = response["ErrorMessage"] + if response['ErrorMessage'].present? + response[:message] = response['ErrorMessage'] response[:success] = false else - status, code, message = response["ApprovalStatus"].split(";") + status, code, message = response['ApprovalStatus'].split(';') response[:status] = status - if response[:success] = status == "APPROVED" + if response[:success] = status == 'APPROVED' response[:message] = status else response[:message] = message @@ -243,11 +243,11 @@ def parse_error(http_response, action) response[element.name] = element.text end - response[:message] = response["ErrorMessage"].to_s.gsub("\n", " ") + response[:message] = response['ErrorMessage'].to_s.gsub("\n", ' ') response rescue REXML::ParseException response[:http_body] = http_response.body - response[:message] = "Failed to parse the failed response" + response[:message] = 'Failed to parse the failed response' response end @@ -262,9 +262,9 @@ def url def commit(action, request) begin data = ssl_post(url, request, - "Content-Type" => 'text/xml; charset=utf-8', - "SOAPAction" => soap_action(action) - ) + 'Content-Type' => 'text/xml; charset=utf-8', + 'SOAPAction' => soap_action(action) + ) response = parse(action, data) rescue ActiveMerchant::ResponseError => e response = parse_error(e.response, action) @@ -273,8 +273,8 @@ def commit(action, request) Response.new(response[:success], response[:message], response, :test => test?, :authorization => authorization_from(response), - :avs_result => { :code => response["AvsResponse"] }, - :cvv_result => response["CvResponse"] + :avs_result => { :code => response['AvsResponse'] }, + :cvv_result => response['CvResponse'] ) end diff --git a/lib/active_merchant/billing/gateways/merchant_warrior.rb b/lib/active_merchant/billing/gateways/merchant_warrior.rb index 90dff734d9b..8e92e21811e 100644 --- a/lib/active_merchant/billing/gateways/merchant_warrior.rb +++ b/lib/active_merchant/billing/gateways/merchant_warrior.rb @@ -46,7 +46,7 @@ def capture(money, identification, options = {}) post = {} add_amount(post, money, options) add_transaction(post, identification) - post.merge!('captureAmount' => amount(money)) + post['captureAmount'] = amount(money) commit('processCapture', post) end @@ -68,6 +68,18 @@ def store(creditcard, options = {}) commit('addCard', post) end + def supports_scrubbing? + true + end + + def scrub(transcript) + transcript. + gsub(%r((&?paymentCardNumber=)[^&]*)i, '\1[FILTERED]'). + gsub(%r((CardNumber=)[^&]*)i, '\1[FILTERED]'). + gsub(%r((&?paymentCardCSC=)[^&]*)i, '\1[FILTERED]'). + gsub(%r((&?apiKey=)[^&]*)i, '\1[FILTERED]') + end + private def add_transaction(post, identification) @@ -79,13 +91,13 @@ def add_address(post, options) post['customerName'] = scrub_name(address[:name]) post['customerCountry'] = address[:country] - post['customerState'] = address[:state] + post['customerState'] = address[:state] || 'N/A' post['customerCity'] = address[:city] post['customerAddress'] = address[:address1] post['customerPostCode'] = address[:zip] - post['customerIP'] = address[:ip] - post['customerPhone'] = address[:phone] - post['customerEmail'] = address[:email] + post['customerIP'] = address[:ip] + post['customerPhone'] = address[:phone] + post['customerEmail'] = address[:email] end def add_order_id(post, options) @@ -107,7 +119,7 @@ def add_token(post, token) def add_creditcard(post, creditcard) post['paymentCardNumber'] = creditcard.number post['paymentCardName'] = scrub_name(creditcard.name) - post['paymentCardExpiry'] = creditcard.expiry_date.expiration.strftime("%m%y") + post['paymentCardExpiry'] = creditcard.expiry_date.expiration.strftime('%m%y') post['paymentCardCSC'] = creditcard.verification_value if creditcard.verification_value? end @@ -146,7 +158,7 @@ def parse(body) def parse_element(response, node) if node.has_elements? - node.elements.each{|element| parse_element(response, element)} + node.elements.each { |element| parse_element(response, element) } else response[node.name.underscore.to_sym] = node.text end @@ -176,14 +188,14 @@ def add_auth(action, post) def url_for(action, post) if token?(post) - [(test? ? TOKEN_TEST_URL : TOKEN_LIVE_URL), action].join("/") + [(test? ? TOKEN_TEST_URL : TOKEN_LIVE_URL), action].join('/') else (test? ? POST_TEST_URL : POST_LIVE_URL) end end def token?(post) - (post["cardID"] || post["cardName"]) + (post['cardID'] || post['cardName']) end def success?(response) @@ -191,7 +203,7 @@ def success?(response) end def post_data(post) - post.collect{|k,v| "#{k}=#{CGI.escape(v.to_s)}" }.join("&") + post.collect { |k, v| "#{k}=#{CGI.escape(v.to_s)}" }.join('&') end end end diff --git a/lib/active_merchant/billing/gateways/mercury.rb b/lib/active_merchant/billing/gateways/mercury.rb index 7af43962755..6fea6dd9197 100644 --- a/lib/active_merchant/billing/gateways/mercury.rb +++ b/lib/active_merchant/billing/gateways/mercury.rb @@ -18,7 +18,7 @@ class MercuryGateway < Gateway self.homepage_url = 'http://www.mercurypay.com' self.display_name = 'Mercury' - self.supported_countries = ['US','CA'] + self.supported_countries = ['US', 'CA'] self.supported_cardtypes = [:visa, :master, :american_express, :discover, :diners_club, :jcb] self.default_currency = 'USD' @@ -81,20 +81,33 @@ def store(credit_card, options={}) commit('CardLookup', request) end + def supports_scrubbing? + true + end + + def scrub(transcript) + transcript. + gsub(%r(<), '<'). + gsub(%r(>), '>'). + gsub(%r(().*())i, '\1[FILTERED]\2'). + gsub(%r(()(\d|x)*())i, '\1[FILTERED]\3'). + gsub(%r(()\d*())i, '\1[FILTERED]\2') + end + private def build_non_authorized_request(action, money, credit_card, options) xml = Builder::XmlMarkup.new - xml.tag! "TStream" do - xml.tag! "Transaction" do + xml.tag! 'TStream' do + xml.tag! 'Transaction' do xml.tag! 'TranType', 'Credit' xml.tag! 'TranCode', action - if options[:allow_partial_auth] && (action == 'PreAuth' || action == 'Sale') - xml.tag! "PartialAuth", "Allow" + if options[:allow_partial_auth] && ['PreAuth', 'Sale'].include?(action) + xml.tag! 'PartialAuth', 'Allow' end add_invoice(xml, options[:order_id], nil, options) - add_reference(xml, "RecordNumberRequested") + add_reference(xml, 'RecordNumberRequested') add_customer_data(xml, options) add_amount(xml, money, options) add_credit_card(xml, credit_card, action) @@ -108,15 +121,15 @@ def build_authorized_request(action, money, authorization, credit_card, options) xml = Builder::XmlMarkup.new invoice_no, ref_no, auth_code, acq_ref_data, process_data, record_no, amount = split_authorization(authorization) - ref_no = "1" if ref_no.blank? + ref_no = '1' if ref_no.blank? - xml.tag! "TStream" do - xml.tag! "Transaction" do + xml.tag! 'TStream' do + xml.tag! 'Transaction' do xml.tag! 'TranType', 'Credit' if options[:allow_partial_auth] && (action == 'PreAuthCapture') - xml.tag! "PartialAuth", "Allow" + xml.tag! 'PartialAuth', 'Allow' end - xml.tag! 'TranCode', (@use_tokenization ? (action + "ByRecordNo") : action) + xml.tag! 'TranCode', (@use_tokenization ? (action + 'ByRecordNo') : action) add_invoice(xml, invoice_no, ref_no, options) add_reference(xml, record_no) add_customer_data(xml, options) @@ -124,9 +137,9 @@ def build_authorized_request(action, money, authorization, credit_card, options) add_credit_card(xml, credit_card, action) if credit_card add_address(xml, options) xml.tag! 'TranInfo' do - xml.tag! "AuthCode", auth_code - xml.tag! "AcqRefData", acq_ref_data - xml.tag! "ProcessData", process_data + xml.tag! 'AuthCode', auth_code + xml.tag! 'AcqRefData', acq_ref_data + xml.tag! 'ProcessData', process_data end end end @@ -136,8 +149,8 @@ def build_authorized_request(action, money, authorization, credit_card, options) def build_card_lookup_request(credit_card, options) xml = Builder::XmlMarkup.new - xml.tag! "TStream" do - xml.tag! "Transaction" do + xml.tag! 'TStream' do + xml.tag! 'Transaction' do xml.tag! 'TranType', 'CardLookup' xml.tag! 'RecordNo', 'RecordNumberRequested' xml.tag! 'Frequency', 'OneTime' @@ -159,15 +172,15 @@ def add_invoice(xml, invoice_no, ref_no, options) def add_reference(xml, record_no) if @use_tokenization - xml.tag! "Frequency", "OneTime" - xml.tag! "RecordNo", record_no + xml.tag! 'Frequency', 'OneTime' + xml.tag! 'RecordNo', record_no end end def add_customer_data(xml, options) xml.tag! 'IpAddress', options[:ip] if options[:ip] if options[:customer] - xml.tag! "TranInfo" do + xml.tag! 'TranInfo' do xml.tag! 'CustomerCode', options[:customer] end end @@ -199,7 +212,7 @@ def add_credit_card(xml, credit_card, action) # Track 1 and 2 have identical end sentinels (ETX) of '?' # Tracks may or may not have checksum (LRC) after the ETX # If the track has no STX or is corrupt, we send it as track 1, to let Mercury - #handle with the validation error as it sees fit. + # handle with the validation error as it sees fit. # Track 2 requires having the STX and ETX stripped. Track 1 does not. # Max-length track 1s require having the STX and ETX stripped. Max is 79 bytes including LRC. is_track_2 = credit_card.track_data[0] == ';' @@ -242,12 +255,12 @@ def parse(action, body) def hashify_xml!(xml, response) xml = REXML::Document.new(xml) - xml.elements.each("//CmdResponse/*") do |node| + xml.elements.each('//CmdResponse/*') do |node| response[node.name.underscore.to_sym] = node.text end - xml.elements.each("//TranResponse/*") do |node| - if node.name.to_s == "Amount" + xml.elements.each('//TranResponse/*') do |node| + if node.name.to_s == 'Amount' node.elements.each do |amt| response[amt.name.underscore.to_sym] = amt.text end @@ -280,8 +293,8 @@ def build_soap_request(body) def build_header { - "SOAPAction" => "http://www.mercurypay.com/CreditTransaction", - "Content-Type" => "text/xml; charset=utf-8" + 'SOAPAction' => 'http://www.mercurypay.com/CreditTransaction', + 'Content-Type' => 'text/xml; charset=utf-8' } end @@ -306,7 +319,7 @@ def message_from(response) end def authorization_from(response) - dollars, cents = (response[:purchase] || "").split(".").collect{|e| e.to_i} + dollars, cents = (response[:purchase] || '').split('.').collect(&:to_i) dollars ||= 0 cents ||= 0 [ @@ -317,17 +330,17 @@ def authorization_from(response) response[:process_data], response[:record_no], ((dollars * 100) + cents).to_s - ].join(";") + ].join(';') end def split_authorization(authorization) - invoice_no, ref_no, auth_code, acq_ref_data, process_data, record_no, amount = authorization.split(";") + invoice_no, ref_no, auth_code, acq_ref_data, process_data, record_no, amount = authorization.split(';') [invoice_no, ref_no, auth_code, acq_ref_data, process_data, record_no, amount] end ENVELOPE_NAMESPACES = { 'xmlns:xsd' => 'http://www.w3.org/2001/XMLSchema', - 'xmlns:soap' => "http://schemas.xmlsoap.org/soap/envelope/", + 'xmlns:soap' => 'http://schemas.xmlsoap.org/soap/envelope/', 'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance' } @@ -336,7 +349,7 @@ def escape_xml(xml) end def unescape_xml(escaped_xml) - escaped_xml.gsub(/\>/,'>').gsub(/\</,'<') + escaped_xml.gsub(/\>/, '>').gsub(/\</, '<') end end end diff --git a/lib/active_merchant/billing/gateways/metrics_global.rb b/lib/active_merchant/billing/gateways/metrics_global.rb index 58ddab8753b..314f403c83c 100644 --- a/lib/active_merchant/billing/gateways/metrics_global.rb +++ b/lib/active_merchant/billing/gateways/metrics_global.rb @@ -20,8 +20,8 @@ class MetricsGlobalGateway < Gateway class_attribute :test_url, :live_url - self.test_url = "https://secure.metricsglobalgateway.com/gateway/transact.dll?testing=true" - self.live_url = "https://secure.metricsglobalgateway.com/gateway/transact.dll" + self.test_url = 'https://secure.metricsglobalgateway.com/gateway/transact.dll?testing=true' + self.live_url = 'https://secure.metricsglobalgateway.com/gateway/transact.dll' class_attribute :duplicate_window @@ -213,14 +213,14 @@ def post_data(action, parameters = {}) post[:version] = API_VERSION post[:login] = @options[:login] post[:tran_key] = @options[:password] - post[:relay_response] = "FALSE" + post[:relay_response] = 'FALSE' post[:type] = action - post[:delim_data] = "TRUE" - post[:delim_char] = "," - post[:encap_char] = "$" + post[:delim_data] = 'TRUE' + post[:delim_char] = ',' + post[:encap_char] = '$' post[:solution_ID] = application_id if application_id - request = post.merge(parameters).collect { |key, value| "x_#{key}=#{CGI.escape(value.to_s)}" }.join("&") + request = post.merge(parameters).collect { |key, value| "x_#{key}=#{CGI.escape(value.to_s)}" }.join('&') request end @@ -286,9 +286,9 @@ def add_address(post, options) def message_from(results) if results[:response_code] == DECLINED - return CVVResult.messages[ results[:card_code] ] if CARD_CODE_ERRORS.include?(results[:card_code]) + return CVVResult.messages[results[:card_code]] if CARD_CODE_ERRORS.include?(results[:card_code]) if AVS_REASON_CODES.include?(results[:response_reason_code]) && AVS_ERRORS.include?(results[:avs_result_code]) - return AVSResult.messages[ results[:avs_result_code] ] + return AVSResult.messages[results[:avs_result_code]] end end diff --git a/lib/active_merchant/billing/gateways/micropayment.rb b/lib/active_merchant/billing/gateways/micropayment.rb index b1f7f07d36f..fc416311865 100644 --- a/lib/active_merchant/billing/gateways/micropayment.rb +++ b/lib/active_merchant/billing/gateways/micropayment.rb @@ -2,17 +2,16 @@ module ActiveMerchant #:nodoc: module Billing #:nodoc: class MicropaymentGateway < Gateway - self.display_name = "micropayment" - self.homepage_url = "https://www.micropayment.de/" + self.display_name = 'micropayment' + self.homepage_url = 'https://www.micropayment.de/' - self.test_url = self.live_url = "https://sipg.micropayment.de/public/creditcardpsp/v1/nvp/" + self.test_url = self.live_url = 'https://sipg.micropayment.de/public/creditcardpsp/v1/nvp/' self.supported_countries = %w(DE) - self.default_currency = "EUR" + self.default_currency = 'EUR' self.money_format = :cents self.supported_cardtypes = [:visa, :master, :american_express] - def initialize(options={}) requires!(options, :access_key) super @@ -24,7 +23,7 @@ def purchase(amount, payment_method, options={}) add_payment_method(post, payment_method, options) add_customer_data(post, options) add_address(post, options) - commit("purchase", post) + commit('purchase', post) end def authorize(amount, payment_method, options={}) @@ -33,31 +32,30 @@ def authorize(amount, payment_method, options={}) add_payment_method(post, payment_method, options) add_customer_data(post, options) add_address(post, options) - commit("authorize", post) + commit('authorize', post) end def capture(amount, authorization, options={}) post = {} add_reference(post, authorization) add_invoice(post, amount, options) - commit("capture", post) + commit('capture', post) end def void(authorization, options={}) post = {} add_reference(post, authorization) - commit("void", post) + commit('void', post) end def refund(amount, authorization, options={}) post = {} add_reference(post, authorization) add_invoice(post, amount, options) - commit("refund", post) + commit('refund', post) end def verify(credit_card, options={}) - MultiResponse.run(:use_first_response) do |r| r.process { authorize(250, credit_card, options) } r.process(:ignore_result) { void(r.authorization, options) } @@ -83,7 +81,7 @@ def add_invoice(post, money, options) post[:currency] = options[:currency] || currency(money) end post[:project] = options[:project] if options[:project] - post["params[title]"] = options[:description] if options[:description] + post['params[title]'] = options[:description] if options[:description] end def add_payment_method(post, payment_method, options={}) @@ -93,24 +91,24 @@ def add_payment_method(post, payment_method, options={}) post[:expiryYear] = format(payment_method.year, :four_digits) post[:expiryMonth] = format(payment_method.month, :two_digits) - post["params[firstname]"] = payment_method.first_name - post["params[surname]"] = payment_method.last_name + post['params[firstname]'] = payment_method.first_name + post['params[surname]'] = payment_method.last_name end def add_customer_data(post, options) - post["params[email]"] = options[:email] if options[:email] - post["params[ip]"] = options[:ip] || "1.1.1.1" - post["params[sendMail]"] = options[:send_mail] || 'false' + post['params[email]'] = options[:email] if options[:email] + post['params[ip]'] = options[:ip] || '1.1.1.1' + post['params[sendMail]'] = options[:send_mail] || 'false' end def add_address(post, options) address = options[:billing_address] return unless address - post["params[address]"] = address[:address1] if address[:address1] - post["params[zipcode]"] = address[:zip] if address[:zip] - post["params[town]"] = address[:city] if address[:city] - post["params[country]"] = address[:country] if address[:country] + post['params[address]'] = address[:address1] if address[:address1] + post['params[zipcode]'] = address[:zip] if address[:zip] + post['params[town]'] = address[:city] if address[:city] + post['params[country]'] = address[:country] if address[:country] end def add_reference(post, authorization) @@ -122,7 +120,7 @@ def add_reference(post, authorization) def commit(action, params) params[:testMode] = 1 if test? params[:accessKey] = @options[:access_key] - params[:apiKey] = @options[:api_key] || "af1fd841af792f4c50131414ff76e004" + params[:apiKey] = @options[:api_key] || 'af1fd841af792f4c50131414ff76e004' response = parse(ssl_post(url(action), post_data(action, params), headers)) @@ -131,18 +129,18 @@ def commit(action, params) message_from(succeeded, response), response, authorization: authorization_from(response, params), - avs_result: AVSResult.new(code: response["some_avs_result_key"]), - cvv_result: CVVResult.new(response["some_cvv_result_key"]), + avs_result: AVSResult.new(code: response['some_avs_result_key']), + cvv_result: CVVResult.new(response['some_cvv_result_key']), test: test? ) end def headers - { "Content-Type" => "application/x-www-form-urlencoded;charset=UTF-8" } + { 'Content-Type' => 'application/x-www-form-urlencoded;charset=UTF-8' } end def post_data(action, params) - params.map {|k, v| "#{CGI.escape(k.to_s)}=#{CGI.escape(v.to_s)}"}.join('&') + params.map { |k, v| "#{CGI.escape(k.to_s)}=#{CGI.escape(v.to_s)}" }.join('&') end def url(action) @@ -152,32 +150,32 @@ def url(action) def parse(body) body.split(/\r?\n/).inject({}) do |acc, pair| - key, value = pair.split("=") + key, value = pair.split('=') acc[key] = CGI.unescape(value) acc end end def success_from(response) - response["error"] == "0" && - response["transactionResultCode"] == "00" && - response["transactionStatus"] == "SUCCESS" + response['error'] == '0' && + response['transactionResultCode'] == '00' && + response['transactionStatus'] == 'SUCCESS' end def message_from(succeeded, response) if succeeded - "Succeeded" + 'Succeeded' else - response["errorMessage"] || response["transactionResultMessage"] + response['errorMessage'] || response['transactionResultMessage'] end end def split_authorization(authorization) - authorization.split("|") + authorization.split('|') end def authorization_from(response, request_params) - session_id = response["sessionId"] ? response["sessionId"] : request_params[:sessionId] + session_id = response['sessionId'] || request_params[:sessionId] "#{session_id}|#{response["transactionId"]}" end end diff --git a/lib/active_merchant/billing/gateways/migs.rb b/lib/active_merchant/billing/gateways/migs.rb index 11feb96f512..98261a9d58f 100644 --- a/lib/active_merchant/billing/gateways/migs.rb +++ b/lib/active_merchant/billing/gateways/migs.rb @@ -20,7 +20,7 @@ class MigsGateway < Gateway # MiGS is supported throughout Asia Pacific, Middle East and Africa # MiGS is used in Australia (AU) by ANZ (eGate), CBA (CommWeb) and more # Source of Country List: http://www.scribd.com/doc/17811923 - self.supported_countries = %w(AU AE BD BN EG HK ID IN JO KW LB LK MU MV MY NZ OM PH QA SA SG TT VN) + self.supported_countries = %w(AU AE BD BN EG HK ID JO KW LB LK MU MV MY NZ OM PH QA SA SG TT VN) # The card types supported by the payment gateway self.supported_cardtypes = [:visa, :master, :american_express, :diners_club, :jcb] @@ -122,6 +122,13 @@ def credit(money, authorization, options = {}) refund(money, authorization, options) end + def verify(credit_card, options={}) + MultiResponse.run do |r| + r.process { authorize(100, credit_card, options) } + r.process(:ignore_result) { void(r.authorization, options) } + end + end + # Checks the status of a previous transaction # This can be useful when a response is not received due to network issues # @@ -165,10 +172,8 @@ def purchase_offsite_url(money, options = {}) add_invoice(post, options) add_creditcard_type(post, options[:card_type]) if options[:card_type] - post.merge!( - :Locale => options[:locale] || 'en', - :ReturnURL => options[:return_url] - ) + post[:Locale] = options[:locale] || 'en' + post[:ReturnURL] = options[:return_url] add_standard_parameters('pay', post, options[:unique_id]) @@ -190,7 +195,7 @@ def purchase_offsite_response(data) expected_secure_hash = calculate_secure_hash(response_hash, @options[:secure_hash]) unless response_hash[:SecureHash] == expected_secure_hash - raise SecurityError, "Secure Hash mismatch, response may be tampered with" + raise SecurityError, 'Secure Hash mismatch, response may be tampered with' end response_object(response_hash) @@ -200,6 +205,20 @@ def test? @options[:login].start_with?('TEST') end + def supports_scrubbing? + true + end + + def scrub(transcript) + transcript. + gsub(%r((&?CardNum=)\d*(&?)), '\1[FILTERED]\2'). + gsub(%r((&?CardSecurityCode=)\d*(&?)), '\1[FILTERED]\2'). + gsub(%r((&?AccessCode=)[^&]*(&?)), '\1[FILTERED]\2'). + gsub(%r((&?Password=)[^&]*(&?)), '\1[FILTERED]\2'). + gsub(%r((&?3DSXID=)[^&]*(&?)), '\1[FILTERED]\2'). + gsub(%r((&?VerToken=)[^&]*(&?)), '\1[FILTERED]\2') + end + private def add_amount(post, money, options) @@ -219,10 +238,10 @@ def add_invoice(post, options) def add_3ds(post, options) post[:VerType] = options[:ver_type] if options[:ver_type] post[:VerToken] = options[:ver_token] if options[:ver_token] - post["3DSXID"] = options[:three_ds_xid] if options[:three_ds_xid] - post["3DSECI"] = options[:three_ds_eci] if options[:three_ds_eci] - post["3DSenrolled"] = options[:three_ds_enrolled] if options[:three_ds_enrolled] - post["3DSstatus"] = options[:three_ds_status] if options[:three_ds_status] + post['3DSXID'] = options[:three_ds_xid] if options[:three_ds_xid] + post['3DSECI'] = options[:three_ds_eci] if options[:three_ds_eci] + post['3DSenrolled'] = options[:three_ds_enrolled] if options[:three_ds_enrolled] + post['3DSstatus'] = options[:three_ds_status] if options[:three_ds_status] end def add_creditcard(post, creditcard) @@ -233,7 +252,7 @@ def add_creditcard(post, creditcard) def add_creditcard_type(post, card_type) post[:Gateway] = 'ssl' - post[:card] = CARD_TYPES.detect{|ct| ct.am_code == card_type}.migs_long_code + post[:card] = CARD_TYPES.detect { |ct| ct.am_code == card_type }.migs_long_code end def parse(body) @@ -246,6 +265,7 @@ def parse(body) end def commit(post) + add_secure_hash(post) if @options[:secure_hash] data = ssl_post self.merchant_hosted_url, post_data(post) response_hash = parse(data) response_object(response_hash) @@ -253,10 +273,10 @@ def commit(post) def response_object(response) avs_response_code = response[:AVSResultCode] - avs_response_code = 'S' if avs_response_code == "Unsupported" + avs_response_code = 'S' if avs_response_code == 'Unsupported' cvv_result_code = response[:CSCResultCode] - cvv_result_code = 'P' if cvv_result_code == "Unsupported" + cvv_result_code = 'P' if cvv_result_code == 'Unsupported' Response.new(success?(response), response[:Message], response, :test => test?, @@ -286,7 +306,7 @@ def add_standard_parameters(action, post, unique_id = nil) end def post_data(post) - post.collect { |key, value| "vpc_#{key}=#{CGI.escape(value.to_s)}" }.join("&") + post.collect { |key, value| "vpc_#{key}=#{CGI.escape(value.to_s)}" }.join('&') end def add_secure_hash(post) diff --git a/lib/active_merchant/billing/gateways/modern_payments.rb b/lib/active_merchant/billing/gateways/modern_payments.rb index ca1bce5a639..c5846f7a079 100644 --- a/lib/active_merchant/billing/gateways/modern_payments.rb +++ b/lib/active_merchant/billing/gateways/modern_payments.rb @@ -19,7 +19,7 @@ def purchase(money, credit_card, options = {}) customer_response = cim.create_customer(options) return customer_response unless customer_response.success? - customer_id = customer_response.params["create_customer_result"] + customer_id = customer_response.params['create_customer_result'] card_response = cim.modify_customer_credit_card(customer_id, credit_card) return card_response unless card_response.success? @@ -28,10 +28,10 @@ def purchase(money, credit_card, options = {}) end private + def cim @cim ||= ModernPaymentsCimGateway.new(@options) end end end end - diff --git a/lib/active_merchant/billing/gateways/modern_payments_cim.rb b/lib/active_merchant/billing/gateways/modern_payments_cim.rb index 4145d70e296..b1626434d38 100644 --- a/lib/active_merchant/billing/gateways/modern_payments_cim.rb +++ b/lib/active_merchant/billing/gateways/modern_payments_cim.rb @@ -1,20 +1,20 @@ module ActiveMerchant #:nodoc: module Billing #:nodoc: class ModernPaymentsCimGateway < Gateway #:nodoc: - self.test_url = "https://secure.modpay.com/netservices/test/ModpayTest.asmx" + self.test_url = 'https://secure.modpay.com/netservices/test/ModpayTest.asmx' self.live_url = 'https://secure.modpay.com/ws/modpay.asmx' - LIVE_XMLNS = "https://secure.modpay.com/ws/" - TEST_XMLNS = "https://secure.modpay.com/netservices/test/" + LIVE_XMLNS = 'https://secure.modpay.com/ws/' + TEST_XMLNS = 'https://secure.modpay.com/netservices/test/' self.supported_countries = ['US'] self.supported_cardtypes = [:visa, :master, :american_express, :discover] self.homepage_url = 'http://www.modpay.com' self.display_name = 'Modern Payments' - SUCCESS_MESSAGE = "Transaction accepted" - FAILURE_MESSAGE = "Transaction failed" - ERROR_MESSAGE = "Transaction error" + SUCCESS_MESSAGE = 'Transaction accepted' + FAILURE_MESSAGE = 'Transaction failed' + ERROR_MESSAGE = 'Transaction error' PAYMENT_METHOD = { :check => 1, @@ -35,7 +35,7 @@ def create_customer(options = {}) end def modify_customer_credit_card(customer_id, credit_card) - raise ArgumentError, "The customer_id cannot be blank" if customer_id.blank? + raise ArgumentError, 'The customer_id cannot be blank' if customer_id.blank? post = {} add_customer_id(post, customer_id) @@ -45,7 +45,7 @@ def modify_customer_credit_card(customer_id, credit_card) end def authorize_credit_card_payment(customer_id, amount) - raise ArgumentError, "The customer_id cannot be blank" if customer_id.blank? + raise ArgumentError, 'The customer_id cannot be blank' if customer_id.blank? post = {} add_customer_id(post, customer_id) @@ -55,7 +55,7 @@ def authorize_credit_card_payment(customer_id, amount) end def create_payment(customer_id, amount, options = {}) - raise ArgumentError, "The customer_id cannot be blank" if customer_id.blank? + raise ArgumentError, 'The customer_id cannot be blank' if customer_id.blank? post = {} add_customer_id(post, customer_id) @@ -66,8 +66,9 @@ def create_payment(customer_id, amount, options = {}) end private + def add_payment_details(post, options) - post[:pmtDate] = (options[:payment_date] || Time.now.utc).strftime("%Y-%m-%dT%H:%M:%SZ") + post[:pmtDate] = (options[:payment_date] || Time.now.utc).strftime('%Y-%m-%dT%H:%M:%SZ') post[:pmtType] = PAYMENT_METHOD[options[:payment_method] || :credit_card] end @@ -118,10 +119,10 @@ def build_request(action, params) 'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance' } do xml.tag! 'env:Body' do - xml.tag! action, { "xmlns" => xmlns(action) } do - xml.tag! "clientId", @options[:login] - xml.tag! "clientCode", @options[:password] - params.each {|key, value| xml.tag! key, value } + xml.tag! action, { 'xmlns' => xmlns(action) } do + xml.tag! 'clientId', @options[:login] + xml.tag! 'clientCode', @options[:password] + params.each { |key, value| xml.tag! key, value } end end end @@ -146,9 +147,9 @@ def url(action) def commit(action, params) data = ssl_post(url(action), build_request(action, params), - { 'Content-Type' =>'text/xml; charset=utf-8', - 'SOAPAction' => "#{xmlns(action)}#{action}" } - ) + { 'Content-Type' =>'text/xml; charset=utf-8', + 'SOAPAction' => "#{xmlns(action)}#{action}" } + ) response = parse(action, data) Response.new(successful?(action, response), message_from(action, response), response, @@ -163,14 +164,14 @@ def authorization_from(action, response) end def authorization_key(action) - action == "AuthorizeCreditCardPayment" ? :trans_id : "#{action.underscore}_result".to_sym + action == 'AuthorizeCreditCardPayment' ? :trans_id : "#{action.underscore}_result".to_sym end def successful?(action, response) key = authorization_key(action) if key == :trans_id - response[:approved] == "true" + response[:approved] == 'true' else response[key].to_i > 0 end @@ -195,7 +196,7 @@ def parse(action, xml) root.elements.to_a.each do |node| parse_element(response, node) end - elsif root = REXML::XPath.first(xml, "//soap:Fault") + elsif root = REXML::XPath.first(xml, '//soap:Fault') root.elements.to_a.each do |node| response[node.name.underscore.to_sym] = node.text end @@ -206,7 +207,7 @@ def parse(action, xml) def parse_element(response, node) if node.has_elements? - node.elements.each{|e| parse_element(response, e) } + node.elements.each { |e| parse_element(response, e) } else response[node.name.underscore.to_sym] = node.text.to_s.strip end @@ -214,4 +215,3 @@ def parse_element(response, node) end end end - diff --git a/lib/active_merchant/billing/gateways/monei.rb b/lib/active_merchant/billing/gateways/monei.rb index 1b0cd6ba848..a5fce7eb0f0 100755 --- a/lib/active_merchant/billing/gateways/monei.rb +++ b/lib/active_merchant/billing/gateways/monei.rb @@ -151,7 +151,7 @@ def execute_dependant(action, money, authorization, options) # Private: Build XML wrapping code yielding to code to fill the transaction information def build_request builder = Nokogiri::XML::Builder.new(:encoding => 'UTF-8') do |xml| - xml.Request(:version => "1.0") do + xml.Request(:version => '1.0') do xml.Header { xml.Security(:sender => @options[:sender_id]) } xml.Transaction(:mode => test? ? 'CONNECTOR_TEST' : 'LIVE', :response => 'SYNC', :channel => @options[:channel_id]) do xml.User(:login => @options[:login], :pwd => @options[:pwd]) @@ -229,10 +229,10 @@ def add_customer(xml, credit_card, options) def parse(body) xml = Nokogiri::XML(body) { - :unique_id => xml.xpath("//Response/Transaction/Identification/UniqueID").text, - :status => translate_status_code(xml.xpath("//Response/Transaction/Processing/Status/@code").text), - :reason => translate_status_code(xml.xpath("//Response/Transaction/Processing/Reason/@code").text), - :message => xml.xpath("//Response/Transaction/Processing/Return").text + :unique_id => xml.xpath('//Response/Transaction/Identification/UniqueID').text, + :status => translate_status_code(xml.xpath('//Response/Transaction/Processing/Status/@code').text), + :reason => translate_status_code(xml.xpath('//Response/Transaction/Processing/Reason/@code').text), + :message => xml.xpath('//Response/Transaction/Processing/Return').text } end diff --git a/lib/active_merchant/billing/gateways/moneris.rb b/lib/active_merchant/billing/gateways/moneris.rb index 5449d553fb8..9410a306b0a 100644 --- a/lib/active_merchant/billing/gateways/moneris.rb +++ b/lib/active_merchant/billing/gateways/moneris.rb @@ -2,7 +2,6 @@ module ActiveMerchant #:nodoc: module Billing #:nodoc: - # To learn more about the Moneris gateway, please contact # eselectplus@moneris.com for a copy of their integration guide. For # information on remote testing, please see "Test Environment Penny Value @@ -34,7 +33,8 @@ def initialize(options = {}) requires!(options, :login, :password) @cvv_enabled = options[:cvv_enabled] @avs_enabled = options[:avs_enabled] - options = { :crypt_type => 7 }.merge(options) + @cof_enabled = options[:cof_enabled] + options[:crypt_type] = 7 unless options.has_key?(:crypt_type) super end @@ -47,17 +47,18 @@ def authorize(money, creditcard_or_datakey, options = {}) requires!(options, :order_id) post = {} add_payment_source(post, creditcard_or_datakey, options) - post[:amount] = amount(money) - post[:order_id] = options[:order_id] - post[:address] = options[:billing_address] || options[:address] + post[:amount] = amount(money) + post[:order_id] = options[:order_id] + post[:address] = options[:billing_address] || options[:address] post[:crypt_type] = options[:crypt_type] || @options[:crypt_type] + add_cof(post, options) if @cof_enabled action = if post[:cavv] - 'cavv_preauth' - elsif post[:data_key].blank? - 'preauth' - else - 'res_preauth_cc' - end + 'cavv_preauth' + elsif post[:data_key].blank? + 'preauth' + else + 'res_preauth_cc' + end commit(action, post) end @@ -69,17 +70,18 @@ def purchase(money, creditcard_or_datakey, options = {}) requires!(options, :order_id) post = {} add_payment_source(post, creditcard_or_datakey, options) - post[:amount] = amount(money) - post[:order_id] = options[:order_id] - post[:address] = options[:billing_address] || options[:address] + post[:amount] = amount(money) + post[:order_id] = options[:order_id] + post[:address] = options[:billing_address] || options[:address] post[:crypt_type] = options[:crypt_type] || @options[:crypt_type] + add_cof(post, options) if @cof_enabled action = if post[:cavv] - 'cavv_purchase' - elsif post[:data_key].blank? - 'purchase' - else - 'res_purchase_cc' - end + 'cavv_purchase' + elsif post[:data_key].blank? + 'purchase' + else + 'res_purchase_cc' + end commit(action, post) end @@ -178,27 +180,35 @@ def scrub(transcript) private # :nodoc: all def expdate(creditcard) - sprintf("%.4i", creditcard.year)[-2..-1] + sprintf("%.2i", creditcard.month) + sprintf('%.4i', creditcard.year)[-2..-1] + sprintf('%.2i', creditcard.month) end - def add_payment_source(post, source, options) - if source.is_a?(String) - post[:data_key] = source - post[:cust_id] = options[:customer] + def add_payment_source(post, payment_method, options) + if payment_method.is_a?(String) + post[:data_key] = payment_method + post[:cust_id] = options[:customer] else - if source.respond_to?(:track_data) && source.track_data.present? - post[:pos_code] = '00' - post[:track2] = source.track_data + if payment_method.respond_to?(:track_data) && payment_method.track_data.present? + post[:pos_code] = '00' + post[:track2] = payment_method.track_data else - post[:pan] = source.number - post[:expdate] = expdate(source) - post[:cvd_value] = source.verification_value if source.verification_value? - post[:cavv] = source.payment_cryptogram if source.is_a?(NetworkTokenizationCreditCard) + post[:pan] = payment_method.number + post[:expdate] = expdate(payment_method) + post[:cvd_value] = payment_method.verification_value if payment_method.verification_value? + post[:cavv] = payment_method.payment_cryptogram if payment_method.is_a?(NetworkTokenizationCreditCard) + post[:wallet_indicator] = wallet_indicator(payment_method.source.to_s) if payment_method.is_a?(NetworkTokenizationCreditCard) + post[:crypt_type] = (payment_method.eci || 7) if payment_method.is_a?(NetworkTokenizationCreditCard) end - post[:cust_id] = options[:customer] || source.name + post[:cust_id] = options[:customer] || payment_method.name end end + def add_cof(post, options) + post[:issuer_id] = options[:issuer_id] if options[:issuer_id] + post[:payment_indicator] = options[:payment_indicator] if options[:payment_indicator] + post[:payment_information] = options[:payment_information] if options[:payment_information] + end + # Common params used amongst the +credit+, +void+ and +capture+ methods def crediting_params(authorization, options = {}) { @@ -224,12 +234,14 @@ def commit(action, parameters = {}) raw = ssl_post(url, data) response = parse(raw) - Response.new(successful?(response), message_from(response[:message]), response, - :test => test?, - :avs_result => { :code => response[:avs_result_code] }, - :cvv_result => response[:cvd_result_code] && response[:cvd_result_code][-1,1], - :authorization => authorization_from(response) - ) + Response.new( + successful?(response), + message_from(response[:message]), + response, + :test => test?, + :avs_result => {:code => response[:avs_result_code]}, + :cvv_result => response[:cvd_result_code] && response[:cvd_result_code][-1, 1], + :authorization => authorization_from(response)) end # Generates a Moneris authorization string of the form 'trans_id;receipt_id'. @@ -243,11 +255,11 @@ def authorization_from(response = {}) def successful?(response) response[:response_code] && response[:complete] && - (0..49).include?(response[:response_code].to_i) + (0..49).cover?(response[:response_code].to_i) end def parse(xml) - response = { :message => "Global Error Receipt", :complete => false } + response = { :message => 'Global Error Receipt', :complete => false } hashify_xml!(xml, response) response end @@ -261,10 +273,10 @@ def hashify_xml!(xml, response) end def post_data(action, parameters = {}) - xml = REXML::Document.new - root = xml.add_element("request") - root.add_element("store_id").text = options[:login] - root.add_element("api_token").text = options[:password] + xml = REXML::Document.new + root = xml.add_element('request') + root.add_element('store_id').text = options[:login] + root.add_element('api_token').text = options[:password] root.add_element(transaction_element(action, parameters)) xml.to_s @@ -280,6 +292,8 @@ def transaction_element(action, parameters) transaction.add_element(avs_element(parameters[:address])) if @avs_enabled && parameters[:address] when :cvd_info transaction.add_element(cvd_element(parameters[:cvd_value])) if @cvv_enabled + when :cof_info + transaction.add_element(credential_on_file(parameters)) if @cof_enabled && cof_details_present?(parameters) else transaction.add_element(key.to_s).text = parameters[key] unless parameters[key].blank? end @@ -293,8 +307,8 @@ def avs_element(address) tokens = full_address.split(/\s+/) element = REXML::Element.new('avs_info') - element.add_element('avs_street_number').text = tokens.select{|x| x =~ /\d/}.join(' ') - element.add_element('avs_street_name').text = tokens.reject{|x| x =~ /\d/}.join(' ') + element.add_element('avs_street_number').text = tokens.select { |x| x =~ /\d/ }.join(' ') + element.add_element('avs_street_name').text = tokens.reject { |x| x =~ /\d/ }.join(' ') element.add_element('avs_zipcode').text = address[:zip] element end @@ -302,39 +316,61 @@ def avs_element(address) def cvd_element(cvd_value) element = REXML::Element.new('cvd_info') if cvd_value - element.add_element('cvd_indicator').text = "1" + element.add_element('cvd_indicator').text = '1' element.add_element('cvd_value').text = cvd_value else - element.add_element('cvd_indicator').text = "0" + element.add_element('cvd_indicator').text = '0' end element end + def cof_details_present?(parameters) + parameters[:issuer_id] && parameters[:payment_indicator] && parameters[:payment_information] + end + + def credential_on_file(parameters) + issuer_id = parameters[:issuer_id] + payment_indicator = parameters[:payment_indicator] + payment_information = parameters[:payment_information] + + cof_info = REXML::Element.new('cof_info') + cof_info.add_element('issuer_id').text = issuer_id + cof_info.add_element('payment_indicator').text = payment_indicator + cof_info.add_element('payment_information').text = payment_information + cof_info + end + + def wallet_indicator(token_source) + return 'APP' if token_source == 'apple_pay' + return 'ANP' if token_source == 'android_pay' + nil + end + def message_from(message) return 'Unspecified error' if message.blank? - message.gsub(/[^\w]/, ' ').split.join(" ").capitalize + message.gsub(/[^\w]/, ' ').split.join(' ').capitalize end def actions { - "purchase" => [:order_id, :cust_id, :amount, :pan, :expdate, :crypt_type, :avs_info, :cvd_info, :track2, :pos_code], - "preauth" => [:order_id, :cust_id, :amount, :pan, :expdate, :crypt_type, :avs_info, :cvd_info, :track2, :pos_code], - "command" => [:order_id], - "refund" => [:order_id, :amount, :txn_number, :crypt_type], - "indrefund" => [:order_id, :cust_id, :amount, :pan, :expdate, :crypt_type], - "completion" => [:order_id, :comp_amount, :txn_number, :crypt_type], - "purchasecorrection" => [:order_id, :txn_number, :crypt_type], - "cavv_preauth" => [:order_id, :cust_id, :amount, :pan, :expdate, :cavv], - "cavv_purchase" => [:order_id, :cust_id, :amount, :pan, :expdate, :cavv], - "transact" => [:order_id, :cust_id, :amount, :pan, :expdate, :crypt_type], - "Batchcloseall" => [], - "opentotals" => [:ecr_number], - "batchclose" => [:ecr_number], - "res_add_cc" => [:pan, :expdate, :crypt_type], - "res_delete" => [:data_key], - "res_update_cc" => [:data_key, :pan, :expdate, :crypt_type], - "res_purchase_cc" => [:data_key, :order_id, :cust_id, :amount, :crypt_type], - "res_preauth_cc" => [:data_key, :order_id, :cust_id, :amount, :crypt_type] + 'purchase' => [:order_id, :cust_id, :amount, :pan, :expdate, :crypt_type, :avs_info, :cvd_info, :track2, :pos_code, :cof_info], + 'preauth' => [:order_id, :cust_id, :amount, :pan, :expdate, :crypt_type, :avs_info, :cvd_info, :track2, :pos_code, :cof_info], + 'command' => [:order_id], + 'refund' => [:order_id, :amount, :txn_number, :crypt_type], + 'indrefund' => [:order_id, :cust_id, :amount, :pan, :expdate, :crypt_type], + 'completion' => [:order_id, :comp_amount, :txn_number, :crypt_type], + 'purchasecorrection' => [:order_id, :txn_number, :crypt_type], + 'cavv_preauth' => [:order_id, :cust_id, :amount, :pan, :expdate, :cavv, :crypt_type, :wallet_indicator], + 'cavv_purchase' => [:order_id, :cust_id, :amount, :pan, :expdate, :cavv, :crypt_type, :wallet_indicator], + 'transact' => [:order_id, :cust_id, :amount, :pan, :expdate, :crypt_type], + 'Batchcloseall' => [], + 'opentotals' => [:ecr_number], + 'batchclose' => [:ecr_number], + 'res_add_cc' => [:pan, :expdate, :crypt_type, :cof_info], + 'res_delete' => [:data_key], + 'res_update_cc' => [:data_key, :pan, :expdate, :crypt_type], + 'res_purchase_cc' => [:data_key, :order_id, :cust_id, :amount, :crypt_type, :cof_info], + 'res_preauth_cc' => [:data_key, :order_id, :cust_id, :amount, :crypt_type, :cof_info] } end end diff --git a/lib/active_merchant/billing/gateways/moneris_us.rb b/lib/active_merchant/billing/gateways/moneris_us.rb index 6f1ac826bc7..28c06ea91d0 100644 --- a/lib/active_merchant/billing/gateways/moneris_us.rb +++ b/lib/active_merchant/billing/gateways/moneris_us.rb @@ -2,7 +2,6 @@ module ActiveMerchant #:nodoc: module Billing #:nodoc: - # To learn more about the Moneris (US) gateway, please contact # ussales@moneris.com for a copy of their integration guide. For # information on remote testing, please see "Test Environment Penny Value @@ -58,7 +57,7 @@ def authorize(money, creditcard_or_datakey, options = {}) post[:order_id] = options[:order_id] post[:address] = options[:billing_address] || options[:address] post[:crypt_type] = options[:crypt_type] || @options[:crypt_type] - action = (post[:data_key].blank?) ? 'us_preauth' : 'us_res_preauth_cc' + action = post[:data_key].blank? ? 'us_preauth' : 'us_res_preauth_cc' commit(action, post) end @@ -72,9 +71,15 @@ def purchase(money, creditcard_or_datakey, options = {}) add_payment_source(post, creditcard_or_datakey, options) post[:amount] = amount(money) post[:order_id] = options[:order_id] - post[:address] = options[:billing_address] || options[:address] + add_address(post, creditcard_or_datakey, options) post[:crypt_type] = options[:crypt_type] || @options[:crypt_type] - action = (post[:data_key].blank?) ? 'us_purchase' : 'us_res_purchase_cc' + action = if creditcard_or_datakey.is_a?(String) + 'us_res_purchase_cc' + elsif card_brand(creditcard_or_datakey) == 'check' + 'us_ach_debit' + elsif post[:data_key].blank? + 'us_purchase' + end commit(action, post) end @@ -114,12 +119,11 @@ def refund(money, authorization, options = {}) commit 'us_refund', crediting_params(authorization, :amount => amount(money)) end - def store(credit_card, options = {}) + def store(payment_source, options = {}) post = {} - post[:pan] = credit_card.number - post[:expdate] = expdate(credit_card) + add_payment_source(post, payment_source, options) post[:crypt_type] = options[:crypt_type] || @options[:crypt_type] - commit('us_res_add_cc', post) + card_brand(payment_source) == 'check' ? commit('us_res_add_ach', post) : commit('us_res_add_cc', post) end def unstore(data_key, options = {}) @@ -128,29 +132,65 @@ def unstore(data_key, options = {}) commit('us_res_delete', post) end - def update(data_key, credit_card, options = {}) + def update(data_key, payment_source, options = {}) post = {} - post[:pan] = credit_card.number - post[:expdate] = expdate(credit_card) + add_payment_source(post, payment_source, options) post[:data_key] = data_key - post[:crypt_type] = options[:crypt_type] || @options[:crypt_type] - commit('us_res_update_cc', post) + card_brand(payment_source) == 'check' ? commit('us_res_update_ach', post) : commit('us_res_update_cc', post) + end + + def supports_scrubbing? + true + end + + def scrub(transcript) + transcript. + gsub(%r(()[^<]*())i, '\1[FILTERED]\2'). + gsub(%r(()[^<]*())i, '\1[FILTERED]\2'). + gsub(%r(()[^<]*())i, '\1[FILTERED]\2') end private # :nodoc: all def expdate(creditcard) - sprintf("%.4i", creditcard.year)[-2..-1] + sprintf("%.2i", creditcard.month) + sprintf('%.4i', creditcard.year)[-2..-1] + sprintf('%.2i', creditcard.month) + end + + def add_address(post, payment_method, options) + if !payment_method.is_a?(String) && card_brand(payment_method) == 'check' + post[:ach_info][:cust_first_name] = payment_method.first_name if payment_method.first_name + post[:ach_info][:cust_last_name] = payment_method.last_name if payment_method.last_name + if address = options[:billing_address] || options[:address] + post[:ach_info][:cust_address1] = address[:address1] if address[:address1] + post[:ach_info][:cust_address2] = address[:address2] if address[:address2] + post[:ach_info][:city] = address[:city] if address[:city] + post[:ach_info][:state] = address[:state] if address[:state] + post[:ach_info][:zip] = address[:zip] if address[:zip] + end + else + post[:address] = options[:billing_address] || options[:address] + end end def add_payment_source(post, source, options) if source.is_a?(String) post[:data_key] = source post[:cust_id] = options[:customer] + elsif card_brand(source) == 'check' + ach_info = {} + ach_info[:sec] = 'web' + ach_info[:routing_num] = source.routing_number + ach_info[:account_num] = source.account_number + ach_info[:account_type] = source.account_type + ach_info[:check_num] = source.number if source.number + post[:ach_info] = ach_info else post[:pan] = source.number post[:expdate] = expdate(source) post[:cvd_value] = source.verification_value if source.verification_value? + if crypt_type = options[:crypt_type] || @options[:crypt_type] + post[:crypt_type] = crypt_type + end post[:cust_id] = options[:customer] || source.name end end @@ -183,7 +223,7 @@ def commit(action, parameters = {}) Response.new(successful?(response), message_from(response[:message]), response, :test => test?, :avs_result => { :code => response[:avs_result_code] }, - :cvv_result => response[:cvd_result_code] && response[:cvd_result_code][-1,1], + :cvv_result => response[:cvd_result_code] && response[:cvd_result_code][-1, 1], :authorization => authorization_from(response) ) end @@ -199,11 +239,11 @@ def authorization_from(response = {}) def successful?(response) response[:response_code] && response[:complete] && - (0..49).include?(response[:response_code].to_i) + (0..49).cover?(response[:response_code].to_i) end def parse(xml) - response = { :message => "Global Error Receipt", :complete => false } + response = { :message => 'Global Error Receipt', :complete => false } hashify_xml!(xml, response) response end @@ -218,9 +258,9 @@ def hashify_xml!(xml, response) def post_data(action, parameters = {}) xml = REXML::Document.new - root = xml.add_element("request") - root.add_element("store_id").text = options[:login] - root.add_element("api_token").text = options[:password] + root = xml.add_element('request') + root.add_element('store_id').text = options[:login] + root.add_element('api_token').text = options[:password] root.add_element(transaction_element(action, parameters)) xml.to_s @@ -236,6 +276,8 @@ def transaction_element(action, parameters) transaction.add_element(avs_element(parameters[:address])) if @avs_enabled && parameters[:address] when :cvd_info transaction.add_element(cvd_element(parameters[:cvd_value])) if @cvv_enabled + when :ach_info + transaction.add_element(ach_element(parameters[:ach_info])) else transaction.add_element(key.to_s).text = parameters[key] unless parameters[key].blank? end @@ -249,8 +291,8 @@ def avs_element(address) tokens = full_address.split(/\s+/) element = REXML::Element.new('avs_info') - element.add_element('avs_street_number').text = tokens.select{|x| x =~ /\d/}.join(' ') - element.add_element('avs_street_name').text = tokens.reject{|x| x =~ /\d/}.join(' ') + element.add_element('avs_street_number').text = tokens.select { |x| x =~ /\d/ }.join(' ') + element.add_element('avs_street_name').text = tokens.reject { |x| x =~ /\d/ }.join(' ') element.add_element('avs_zipcode').text = address[:zip] element end @@ -258,39 +300,51 @@ def avs_element(address) def cvd_element(cvd_value) element = REXML::Element.new('cvd_info') if cvd_value - element.add_element('cvd_indicator').text = "1" + element.add_element('cvd_indicator').text = '1' element.add_element('cvd_value').text = cvd_value else - element.add_element('cvd_indicator').text = "0" + element.add_element('cvd_indicator').text = '0' + end + element + end + + def ach_element(ach_info) + element = REXML::Element.new('ach_info') + actions['ach_info'].each do |key| + element.add_element(key.to_s).text = ach_info[key] unless ach_info[key].blank? end element end def message_from(message) return 'Unspecified error' if message.blank? - message.gsub(/[^\w]/, ' ').split.join(" ").capitalize + message.gsub(/[^\w]/, ' ').split.join(' ').capitalize end def actions { - "us_purchase" => [:order_id, :cust_id, :amount, :pan, :expdate, :crypt_type, :avs_info, :cvd_info], - "us_preauth" => [:order_id, :cust_id, :amount, :pan, :expdate, :crypt_type, :avs_info, :cvd_info], - "us_command" => [:order_id], - "us_refund" => [:order_id, :amount, :txn_number, :crypt_type], - "us_indrefund" => [:order_id, :cust_id, :amount, :pan, :expdate, :crypt_type], - "us_completion" => [:order_id, :comp_amount, :txn_number, :crypt_type], - "us_purchasecorrection" => [:order_id, :txn_number, :crypt_type], - "us_cavvpurcha" => [:order_id, :cust_id, :amount, :pan, :expdate, :cav], - "us_cavvpreaut" => [:order_id, :cust_id, :amount, :pan, :expdate, :cavv], - "us_transact" => [:order_id, :cust_id, :amount, :pan, :expdate, :crypt_type], - "us_Batchcloseall" => [], - "us_opentotals" => [:ecr_number], - "us_batchclose" => [:ecr_number], - "us_res_add_cc" => [:pan, :expdate, :crypt_type], - "us_res_delete" => [:data_key], - "us_res_update_cc" => [:data_key, :pan, :expdate, :crypt_type], - "us_res_purchase_cc" => [:data_key, :order_id, :cust_id, :amount, :crypt_type], - "us_res_preauth_cc" => [:data_key, :order_id, :cust_id, :amount, :crypt_type] + 'us_purchase' => [:order_id, :cust_id, :amount, :pan, :expdate, :crypt_type, :avs_info, :cvd_info], + 'us_preauth' => [:order_id, :cust_id, :amount, :pan, :expdate, :crypt_type, :avs_info, :cvd_info], + 'us_command' => [:order_id], + 'us_refund' => [:order_id, :amount, :txn_number, :crypt_type], + 'us_indrefund' => [:order_id, :cust_id, :amount, :pan, :expdate, :crypt_type], + 'us_completion' => [:order_id, :comp_amount, :txn_number, :crypt_type], + 'us_purchasecorrection' => [:order_id, :txn_number, :crypt_type], + 'us_cavvpurcha' => [:order_id, :cust_id, :amount, :pan, :expdate, :cav], + 'us_cavvpreaut' => [:order_id, :cust_id, :amount, :pan, :expdate, :cavv], + 'us_transact' => [:order_id, :cust_id, :amount, :pan, :expdate, :crypt_type], + 'us_Batchcloseall' => [], + 'us_opentotals' => [:ecr_number], + 'us_batchclose' => [:ecr_number], + 'us_res_add_cc' => [:pan, :expdate, :crypt_type], + 'us_res_delete' => [:data_key], + 'us_res_update_cc' => [:data_key, :pan, :expdate, :crypt_type], + 'us_res_purchase_cc' => [:data_key, :order_id, :cust_id, :amount, :crypt_type], + 'us_res_preauth_cc' => [:data_key, :order_id, :cust_id, :amount, :crypt_type], + 'us_ach_debit' => [:order_id, :cust_id, :amount, :ach_info], + 'us_res_add_ach' => [:order_id, :cust_id, :amount, :ach_info], + 'us_res_update_ach' => [:order_id, :data_key, :cust_id, :amount, :ach_info], + 'ach_info' => [:sec, :cust_first_name, :cust_last_name, :cust_address1, :cust_address2, :cust_city, :cust_state, :cust_zip, :routing_num, :account_num, :check_num, :account_type] } end end diff --git a/lib/active_merchant/billing/gateways/money_movers.rb b/lib/active_merchant/billing/gateways/money_movers.rb index cc01dae258a..8a7a1e9e9a4 100644 --- a/lib/active_merchant/billing/gateways/money_movers.rb +++ b/lib/active_merchant/billing/gateways/money_movers.rb @@ -126,17 +126,17 @@ def success?(response) end def test? - (@options[:login].eql?('demo')) && (@options[:password].eql?('password')) + @options[:login].eql?('demo') && @options[:password].eql?('password') end def message_from(response) case response['response'].to_i when APPROVED - "Transaction Approved" + 'Transaction Approved' when DECLINED - "Transaction Declined" + 'Transaction Declined' else - "Error in transaction data or system error" + 'Error in transaction data or system error' end end @@ -144,9 +144,8 @@ def post_data(action, parameters = {}) parameters[:type] = action parameters[:username] = @options[:login] parameters[:password] = @options[:password] - parameters.map{|k, v| "#{k}=#{CGI.escape(v.to_s)}"}.join('&') + parameters.map { |k, v| "#{k}=#{CGI.escape(v.to_s)}" }.join('&') end end end end - diff --git a/lib/active_merchant/billing/gateways/mundipagg.rb b/lib/active_merchant/billing/gateways/mundipagg.rb new file mode 100644 index 00000000000..aeac34ebe11 --- /dev/null +++ b/lib/active_merchant/billing/gateways/mundipagg.rb @@ -0,0 +1,292 @@ +module ActiveMerchant #:nodoc: + module Billing #:nodoc: + class MundipaggGateway < Gateway + self.live_url = 'https://api.mundipagg.com/core/v1' + + self.supported_countries = ['US'] + self.default_currency = 'USD' + self.supported_cardtypes = [:visa, :master, :american_express, :discover] + + self.homepage_url = 'https://www.mundipagg.com/' + self.display_name = 'Mundipagg' + + STANDARD_ERROR_CODE_MAPPING = { + '400' => STANDARD_ERROR_CODE[:processing_error], + '401' => STANDARD_ERROR_CODE[:config_error], + '404' => STANDARD_ERROR_CODE[:processing_error], + '412' => STANDARD_ERROR_CODE[:processing_error], + '422' => STANDARD_ERROR_CODE[:processing_error], + '500' => STANDARD_ERROR_CODE[:processing_error] + } + + STANDARD_ERROR_MESSAGE_MAPPING = { + '400' => 'Invalid request;', + '401' => 'Invalid API key;', + '404' => 'The requested resource does not exist;', + '412' => 'Valid parameters but request failed;', + '422' => 'Invalid parameters;', + '500' => 'An internal error occurred;' + } + + def initialize(options={}) + requires!(options, :api_key) + super + end + + def purchase(money, payment, options={}) + post = {} + add_invoice(post, money, options) + add_customer_data(post, options) unless payment.is_a?(String) + add_shipping_address(post, options) + add_payment(post, payment, options) + + commit('sale', post) + end + + def authorize(money, payment, options={}) + post = {} + add_invoice(post, money, options) + add_customer_data(post, options) unless payment.is_a?(String) + add_shipping_address(post, options) + add_payment(post, payment, options) + add_capture_flag(post, payment) + commit('authonly', post) + end + + def capture(money, authorization, options={}) + post = {} + post[:code] = authorization + add_invoice(post, money, options) + commit('capture', post, authorization) + end + + def refund(money, authorization, options={}) + add_invoice(post={}, money, options) + commit('refund', post, authorization) + end + + def void(authorization, options={}) + commit('void', nil, authorization) + end + + def store(payment, options={}) + post = {} + options.update(name: payment.name) + options = add_customer(options) unless options[:customer_id] + add_payment(post, payment, options) + commit('store', post, options[:customer_id]) + end + + def verify(credit_card, options={}) + MultiResponse.run(:use_first_response) do |r| + r.process { authorize(100, credit_card, options) } + r.process(:ignore_result) { void(r.authorization, options) } + end + end + + def supports_scrubbing? + true + end + + def scrub(transcript) + transcript. + gsub(%r((Authorization: Basic )\w+), '\1[FILTERED]'). + gsub(%r(("cvv\\":\\")\d*), '\1[FILTERED]'). + gsub(%r((card\\":{\\"number\\":\\")\d*), '\1[FILTERED]') + end + + private + + def add_customer(options) + post = {} + post[:name] = options[:name] + customer = commit('customer', post) + options.update(customer_id: customer.authorization) + end + + def add_customer_data(post, options) + post[:customer] = {} + post[:customer][:email] = options[:email] + end + + def add_billing_address(post, type, options) + if address = (options[:billing_address] || options[:address]) + billing = {} + address = options[:billing_address] || options[:address] + billing[:street] = address[:address1].match(/\D+/)[0].strip if address[:address1] + billing[:number] = address[:address1].match(/\d+/)[0] if address[:address1] + billing[:compliment] = address[:address2] if address[:address2] + billing[:city] = address[:city] if address[:city] + billing[:state] = address[:state] if address[:state] + billing[:country] = address[:country] if address[:country] + billing[:zip_code] = address[:zip] if address[:zip] + billing[:neighborhood] = address[:neighborhood] + post[:payment][type.to_sym][:card][:billing_address] = billing + end + end + + def add_shipping_address(post, options) + if address = options[:shipping_address] + post[:address] = {} + post[:address][:street] = address[:address1].match(/\D+/)[0].strip if address[:address1] + post[:address][:number] = address[:address1].match(/\d+/)[0] if address[:address1] + post[:address][:compliment] = address[:address2] if address[:address2] + post[:address][:city] = address[:city] if address[:city] + post[:address][:state] = address[:state] if address[:state] + post[:address][:country] = address[:country] if address[:country] + post[:address][:zip_code] = address[:zip] if address[:zip] + end + end + + def add_invoice(post, money, options) + post[:amount] = money + post[:currency] = (options[:currency] || currency(money)) + end + + def add_capture_flag(post, payment) + if voucher?(payment) + post[:payment][:voucher][:capture] = false + else + post[:payment][:credit_card][:capture] = false + end + end + + def add_payment(post, payment, options) + post[:customer][:name] = payment.name if post[:customer] + post[:customer_id] = parse_auth(payment)[0] if payment.is_a?(String) + post[:payment] = {} + post[:payment][:gateway_affiliation_id] = @options[:gateway_id] if @options[:gateway_id] + post[:payment][:metadata] = { mundipagg_payment_method_code: '1' } if test? + if voucher?(payment) + add_voucher(post, payment, options) + else + add_credit_card(post, payment, options) + end + end + + def add_credit_card(post, payment, options) + post[:payment][:payment_method] = 'credit_card' + post[:payment][:credit_card] = {} + if payment.is_a?(String) + post[:payment][:credit_card][:card_id] = parse_auth(payment)[1] + else + post[:payment][:credit_card][:card] = {} + post[:payment][:credit_card][:card][:number] = payment.number + post[:payment][:credit_card][:card][:holder_name] = payment.name + post[:payment][:credit_card][:card][:exp_month] = payment.month + post[:payment][:credit_card][:card][:exp_year] = payment.year + post[:payment][:credit_card][:card][:cvv] = payment.verification_value + post[:payment][:credit_card][:card][:holder_document] = options[:holder_document] if options[:holder_document] + add_billing_address(post, 'credit_card', options) + end + end + + def add_voucher(post, payment, options) + post[:currency] = 'BRL' + post[:payment][:payment_method] = 'voucher' + post[:payment][:voucher] = {} + post[:payment][:voucher][:card] = {} + post[:payment][:voucher][:card][:number] = payment.number + post[:payment][:voucher][:card][:holder_name] = payment.name + post[:payment][:voucher][:card][:holder_document] = options[:holder_document] + post[:payment][:voucher][:card][:exp_month] = payment.month + post[:payment][:voucher][:card][:exp_year] = payment.year + post[:payment][:voucher][:card][:cvv] = payment.verification_value + add_billing_address(post, 'voucher', options) + end + + def voucher?(payment) + return false if payment.is_a?(String) + %w[sodexo vr].include? card_brand(payment) + end + + def headers + { + 'Authorization' => 'Basic ' + Base64.strict_encode64("#{@options[:api_key]}:"), + 'Content-Type' => 'application/json', + 'Accept' => 'application/json' + } + end + + def parse(body) + JSON.parse(body) + end + + def url_for(action, auth = nil) + url = live_url + case action + when 'store' + "#{url}/customers/#{auth}/cards/" + when 'customer' + "#{url}/customers/" + when 'refund', 'void' + "#{url}/charges/#{auth}/" + when 'capture' + "#{url}/charges/#{auth}/capture/" + else + "#{url}/charges/" + end + end + + def commit(action, parameters, auth = nil) + url = url_for(action, auth) + parameters.merge!(parameters[:payment][:credit_card].delete(:card)).delete(:payment) if action == 'store' + response = if %w[refund void].include? action + parse(ssl_request(:delete, url, post_data(parameters), headers)) + else + parse(ssl_post(url, post_data(parameters), headers)) + end + + Response.new( + success_from(response), + message_from(response), + response, + authorization: authorization_from(response, action), + avs_result: AVSResult.new(code: response['some_avs_response_key']), + cvv_result: CVVResult.new(response['some_cvv_response_key']), + test: test?, + error_code: error_code_from(response) + ) + rescue ResponseError => e + message = get_error_message(e) + return Response.new( + false, + "#{STANDARD_ERROR_MESSAGE_MAPPING[e.response.code]} #{message}", + parse(e.response.body), + test: test?, + error_code: STANDARD_ERROR_CODE_MAPPING[e.response.code] + ) + end + + def success_from(response) + %w[pending paid processing canceled active].include? response['status'] + end + + def get_error_message(error) + JSON.parse(error.response.body)['message'] + end + + def message_from(response) + return response['message'] if response['message'] + return response['last_transaction']['acquirer_message'] if response['last_transaction'] + end + + def authorization_from(response, action) + return "#{response['customer']['id']}|#{response['id']}" if action == 'store' + response['id'] + end + + def parse_auth(auth) + auth.split('|') + end + + def post_data(parameters = {}) + parameters.to_json + end + + def error_code_from(response) + STANDARD_ERROR_CODE[:processing_error] unless success_from(response) + end + end + end +end diff --git a/lib/active_merchant/billing/gateways/nab_transact.rb b/lib/active_merchant/billing/gateways/nab_transact.rb index 4c5f5102ca7..f7df53da09b 100644 --- a/lib/active_merchant/billing/gateways/nab_transact.rb +++ b/lib/active_merchant/billing/gateways/nab_transact.rb @@ -6,11 +6,11 @@ module Billing #:nodoc: # be a rebadged Securepay Australia service, though some differences exist. class NabTransactGateway < Gateway API_VERSION = 'xml-4.2' - PERIODIC_API_VERSION = "spxml-4.2" + PERIODIC_API_VERSION = 'spxml-4.2' class_attribute :test_periodic_url, :live_periodic_url - self.test_url = 'https://transact.nab.com.au/test/xmlapi/payment' + self.test_url = 'https://demo.transact.nab.com.au/xmlapi/payment' self.live_url = 'https://transact.nab.com.au/live/xmlapi/payment' self.test_periodic_url = 'https://transact.nab.com.au/xmlapidemo/periodic' self.live_periodic_url = 'https://transact.nab.com.au/xmlapi/periodic' @@ -23,14 +23,14 @@ class NabTransactGateway < Gateway self.money_format = :cents self.default_currency = 'AUD' - #Transactions currently accepted by NAB Transact XML API + # Transactions currently accepted by NAB Transact XML API TRANSACTIONS = { - :purchase => 0, #Standard Payment - :refund => 4, #Refund - :void => 6, #Client Reversal (Void) - :unmatched_refund => 666, #Unmatched Refund - :authorization => 10, #Preauthorise - :capture => 11 #Preauthorise Complete (Advice) + :purchase => 0, # Standard Payment + :refund => 4, # Refund + :void => 6, # Client Reversal (Void) + :unmatched_refund => 666, # Unmatched Refund + :authorization => 10, # Preauthorise + :capture => 11 # Preauthorise Complete (Advice) } PERIODIC_TYPES = { @@ -41,7 +41,6 @@ class NabTransactGateway < Gateway SUCCESS_CODES = [ '00', '08', '11', '16', '77' ] - def initialize(options = {}) requires!(options, :login, :password) super @@ -84,7 +83,7 @@ def supports_scrubbing? end def scrub(transcript) - return "" if transcript.blank? + return '' if transcript.blank? transcript. gsub(%r(()[^<]+(<))i, '\1[FILTERED]\2'). gsub(%r(()[^<]+(<))i, '\1[FILTERED]\2'). @@ -104,7 +103,7 @@ def add_metadata(xml, options) def build_purchase_request(money, credit_card, options) xml = Builder::XmlMarkup.new - xml.tag! 'amount', amount(money) + xml.tag! 'amount', localized_amount(money, options[:currency] || currency(money)) xml.tag! 'currency', options[:currency] || currency(money) xml.tag! 'purchaseOrderNo', options[:order_id].to_s.gsub(/[ ']/, '') @@ -124,7 +123,7 @@ def build_reference_request(money, reference, options) transaction_id, order_id, preauth_id, original_amount = reference.split('*') - xml.tag! 'amount', (money ? amount(money) : original_amount) + xml.tag! 'amount', (money ? localized_amount(money, options[:currency] || currency(money)) : original_amount) xml.tag! 'currency', options[:currency] || currency(money) xml.tag! 'txnID', transaction_id xml.tag! 'purchaseOrderNo', order_id @@ -135,7 +134,7 @@ def build_reference_request(money, reference, options) xml.target! end - #Generate payment request XML + # Generate payment request XML # - API is set to allow multiple Txn's but currently only allows one # - txnSource = 23 - (XML) def build_request(action, body) @@ -156,8 +155,8 @@ def build_request(action, body) xml.tag! 'RequestType', 'Payment' xml.tag! 'Payment' do - xml.tag! 'TxnList', "count" => 1 do - xml.tag! 'Txn', "ID" => 1 do + xml.tag! 'TxnList', 'count' => 1 do + xml.tag! 'Txn', 'ID' => 1 do xml.tag! 'txnType', TRANSACTIONS[action] xml.tag! 'txnSource', 23 xml << body @@ -187,8 +186,8 @@ def build_periodic_request(action, body) xml.tag! 'RequestType', 'Periodic' xml.tag! 'Periodic' do - xml.tag! 'PeriodicList', "count" => 1 do - xml.tag! 'PeriodicItem', "ID" => 1 do + xml.tag! 'PeriodicList', 'count' => 1 do + xml.tag! 'PeriodicItem', 'ID' => 1 do xml.tag! 'actionType', action.to_s xml.tag! 'periodicType', PERIODIC_TYPES[action] if PERIODIC_TYPES[action] xml << body @@ -205,7 +204,7 @@ def build_purchase_using_stored_card_request(money, identification, options) xml.tag! 'crn', identification xml.tag! 'currency', options[:currency] || currency(money) - xml.tag! 'amount', amount(money) + xml.tag! 'amount', localized_amount(money, options[:currency] || currency(money)) xml.target! end @@ -281,7 +280,7 @@ def parse(body) def parse_element(response, node) if node.has_elements? - node.elements.each{|element| parse_element(response, element) } + node.elements.each { |element| parse_element(response, element) } else response[node.name.underscore.to_sym] = node.text end diff --git a/lib/active_merchant/billing/gateways/ncr_secure_pay.rb b/lib/active_merchant/billing/gateways/ncr_secure_pay.rb index 3fcc6587dc0..1a595dd196d 100644 --- a/lib/active_merchant/billing/gateways/ncr_secure_pay.rb +++ b/lib/active_merchant/billing/gateways/ncr_secure_pay.rb @@ -105,7 +105,7 @@ def add_payment(post, payment) def parse(body) doc = Nokogiri::XML(body) doc.remove_namespaces! - response = doc.xpath("/MonetraResp/Resp")[0] + response = doc.xpath('/MonetraResp/Resp')[0] resp_params = {} response.elements.each do |node| @@ -129,7 +129,7 @@ def commit(action, parameters) end def success_from(response) - response[:code] == "AUTH" + response[:code] == 'AUTH' end def message_from(response) @@ -143,7 +143,7 @@ def authorization_from(response) def request_body(action, parameters = {}) Nokogiri::XML::Builder.new(:encoding => 'utf-8') do |xml| xml.MonetraTrans do - xml.Trans(identifier: parameters.delete(:identifier) || "1") do + xml.Trans(identifier: parameters.delete(:identifier) || '1') do xml.username(options[:username]) xml.password(options[:password]) xml.action(action) diff --git a/lib/active_merchant/billing/gateways/net_registry.rb b/lib/active_merchant/billing/gateways/net_registry.rb index f3767e1be66..8f199a88ca8 100644 --- a/lib/active_merchant/billing/gateways/net_registry.rb +++ b/lib/active_merchant/billing/gateways/net_registry.rb @@ -122,6 +122,7 @@ def status(identification) end private + def add_request_details(params, options) params['COMMENT'] = options[:description] unless options[:description].blank? end @@ -130,7 +131,7 @@ def add_request_details(params, options) # format for a command. def expiry(credit_card) month = format(credit_card.month, :two_digits) - year = format(credit_card.year , :two_digits) + year = format(credit_card.year, :two_digits) "#{month}/#{year}" end @@ -141,7 +142,7 @@ def expiry(credit_card) # omitted if nil. def commit(action, params) # get gateway response - response = parse( ssl_post(self.live_url, post_data(action, params)) ) + response = parse(ssl_post(self.live_url, post_data(action, params))) Response.new(response['status'] == 'approved', message_from(response), response, :authorization => authorization_from(response, action) @@ -151,7 +152,7 @@ def commit(action, params) def post_data(action, params) params['COMMAND'] = TRANSACTIONS[action] params['LOGIN'] = "#{@options[:login]}/#{@options[:password]}" - escape_uri(params.map{|k,v| "#{k}=#{v}"}.join('&')) + escape_uri(params.map { |k, v| "#{k}=#{v}" }.join('&')) end # The upstream is picky and so we can't use CGI.escape like we want to diff --git a/lib/active_merchant/billing/gateways/netaxept.rb b/lib/active_merchant/billing/gateways/netaxept.rb index 3ee6443f5a9..6681259e657 100644 --- a/lib/active_merchant/billing/gateways/netaxept.rb +++ b/lib/active_merchant/billing/gateways/netaxept.rb @@ -31,8 +31,8 @@ def purchase(money, creditcard, options = {}) requires!(options, :order_id) MultiResponse.run do |r| - r.process{authorize(money, creditcard, options)} - r.process{capture(money, r.authorization, options)} + r.process { authorize(money, creditcard, options) } + r.process { capture(money, r.authorization, options) } end end @@ -40,9 +40,9 @@ def authorize(money, creditcard, options = {}) requires!(options, :order_id) MultiResponse.run do |r| - r.process{setup_transaction(money, options)} - r.process{add_and_auth_credit_card(r.authorization, creditcard, options)} - r.process{query_transaction(r.authorization, options)} + r.process { setup_transaction(money, options) } + r.process { add_and_auth_credit_card(r.authorization, creditcard, options) } + r.process { query_transaction(r.authorization, options) } end end @@ -50,24 +50,24 @@ def capture(money, authorization, options = {}) post = {} add_credentials(post, options) add_authorization(post, authorization, money) - post[:operation] = "Capture" - commit("Netaxept/process.aspx", post) + post[:operation] = 'Capture' + commit('Netaxept/process.aspx', post) end def refund(money, authorization, options = {}) post = {} add_credentials(post, options) add_authorization(post, authorization, money) - post[:operation] = "Credit" - commit("Netaxept/process.aspx", post) + post[:operation] = 'Credit' + commit('Netaxept/process.aspx', post) end def void(authorization, options = {}) post = {} add_credentials(post, options) add_authorization(post, authorization) - post[:operation] = "Annul" - commit("Netaxept/process.aspx", post) + post[:operation] = 'Annul' + commit('Netaxept/process.aspx', post) end private @@ -76,7 +76,7 @@ def setup_transaction(money, options) post = {} add_credentials(post, options) add_order(post, money, options) - commit("Netaxept/Register.aspx", post) + commit('Netaxept/Register.aspx', post) end def add_and_auth_credit_card(authorization, creditcard, options) @@ -84,14 +84,14 @@ def add_and_auth_credit_card(authorization, creditcard, options) add_credentials(post, options, false) add_authorization(post, authorization) add_creditcard(post, creditcard) - commit("terminal/default.aspx", post, false) + commit('terminal/default.aspx', post, false) end def query_transaction(authorization, options) post = {} add_credentials(post, options) add_authorization(post, authorization) - commit("Netaxept/query.aspx", post) + commit('Netaxept/query.aspx', post) end def add_credentials(post, options, secure=true) @@ -109,7 +109,7 @@ def add_order(post, money, options) post[:orderNumber] = options[:order_id] post[:amount] = amount(money) post[:currencyCode] = (options[:currency] || currency(money)) - post[:autoAuth] = "true" + post[:autoAuth] = 'true' end def add_creditcard(post, options) @@ -122,13 +122,13 @@ def commit(path, parameters, xml=true) raw = parse(ssl_get(build_url(path, parameters)), xml) success = false - authorization = (raw["TransactionId"] || parameters[:transactionId]) + authorization = (raw['TransactionId'] || parameters[:transactionId]) if raw[:container] =~ /Exception|Error/ - message = (raw["Message"] || raw["Error"]["Message"]) - elsif raw["Error"] && !raw["Error"].empty? - message = (raw["Error"]["ResponseText"] || raw["Error"]["ResponseCode"]) + message = (raw['Message'] || raw['Error']['Message']) + elsif raw['Error'] && !raw['Error'].empty? + message = (raw['Error']['ResponseText'] || raw['Error']['ResponseCode']) else - message = (raw["ResponseText"] || raw["ResponseCode"] || "OK") + message = (raw['ResponseText'] || raw['ResponseCode'] || 'OK') success = true end @@ -173,9 +173,8 @@ def build_url(base, parameters=nil) end def encode(hash) - hash.collect{|(k,v)| "#{CGI.escape(k.to_s)}=#{CGI.escape(v.to_s)}"}.join('&') + hash.collect { |(k, v)| "#{CGI.escape(k.to_s)}=#{CGI.escape(v.to_s)}" }.join('&') end end end end - diff --git a/lib/active_merchant/billing/gateways/netbanx.rb b/lib/active_merchant/billing/gateways/netbanx.rb index 7c7ee9e2db1..901efd4ddfb 100644 --- a/lib/active_merchant/billing/gateways/netbanx.rb +++ b/lib/active_merchant/billing/gateways/netbanx.rb @@ -5,16 +5,23 @@ class NetbanxGateway < Gateway self.test_url = 'https://api.test.netbanx.com/' self.live_url = 'https://api.netbanx.com/' - self.supported_countries = ['CA', 'US', 'GB'] + self.supported_countries = %w(AF AX AL DZ AS AD AO AI AQ AG AR AM AW AU AT AZ BS BH BD BB BY BE BZ BJ BM BT BO BQ BA BW BV BR IO BN BG BF BI KH CM CA CV KY CF TD CL CN CX CC CO KM CG CD CK CR CI HR CU CW CY CZ DK DJ DM DO EC EG SV GQ ER EE ET FK FO FJ FI FR GF PF TF GA GM GE DE GH GI GR GL GD GP GU GT GG GN GW GY HT HM HN HK HU IS IN ID IR IQ IE IM IL IT JM JP JE JO KZ KE KI KP KR KW KG LA LV LB LS LR LY LI LT LU MO MK MG MW MY MV ML MT MH MQ MR MU YT MX FM MD MC MN ME MS MA MZ MM NA NR NP NC NZ NI NE NG NU NF MP NO OM PK PW PS PA PG PY PE PH PN PL PT PR QA RE RO RU RW BL SH KN LC MF VC WS SM ST SA SN RS SC SL SG SX SK SI SB SO ZA GS SS ES LK PM SD SR SJ SZ SE CH SY TW TJ TZ TH NL TL TG TK TO TT TN TR TM TC TV UG UA AE GB US UM UY UZ VU VA VE VN VG VI WF EH YE ZM ZW) self.default_currency = 'CAD' - self.supported_cardtypes = [:visa, :master, :american_express, :discover] + self.supported_cardtypes = [ + :american_express, + :diners_club, + :discover, + :jcb, + :master, + :maestro, + :visa + ] + self.money_format = :cents self.homepage_url = 'https://processing.paysafe.com/' self.display_name = 'Netbanx by PaySafe' - STANDARD_ERROR_CODE_MAPPING = {} - def initialize(options={}) requires!(options, :account_number, :api_key) super @@ -24,7 +31,7 @@ def purchase(money, payment, options={}) post = {} add_invoice(post, money, options) add_settle_with_auth(post) - add_payment(post, payment) + add_payment(post, payment, options) commit(:post, 'auths', post) end @@ -32,7 +39,7 @@ def purchase(money, payment, options={}) def authorize(money, payment, options={}) post = {} add_invoice(post, money, options) - add_payment(post, payment) + add_payment(post, payment, options) commit(:post, 'auths', post) end @@ -110,9 +117,6 @@ def add_settle_with_auth(post) def add_customer_data(post, options) post[:merchantCustomerId] = (options[:merchant_customer_id] || SecureRandom.uuid) post[:locale] = options[:locale] - # if options[:billing_address] - # post[:address] = map_address(options[:billing_address]) - # end end def add_credit_card(post, credit_card, options = {}) @@ -128,13 +132,7 @@ def add_credit_card(post, credit_card, options = {}) def add_invoice(post, money, options) post[:amount] = amount(money) - post[:currencyCode] = options[:currency] if options[:currency] add_order_id(post, options) - - if options[:billing_address] - post[:billingDetails] = map_address(options[:billing_address]) - end - end def add_payment(post, credit_card_or_reference, options = {}) @@ -146,6 +144,9 @@ def add_payment(post, credit_card_or_reference, options = {}) post[:card][:cvv] = credit_card_or_reference.verification_value post[:card][:cardExpiry] = expdate(credit_card_or_reference) end + + post[:currencyCode] = options[:currency] if options[:currency] + post[:billingDetails] = map_address(options[:billing_address]) if options[:billing_address] end def expdate(credit_card) @@ -164,11 +165,12 @@ def map_address(address) return {} if address.nil? country = Country.find(address[:country]) if address[:country] mapped = { - :street => address[:address1], - :city => address[:city], - :zip => address[:zip], + :street => address[:address1], + :city => address[:city], + :zip => address[:zip], + :state => address[:state], } - mapped.merge!({:country => country.code(:alpha2).value}) unless country.blank? + mapped[:country] = country.code(:alpha2).value unless country.blank? mapped end @@ -192,6 +194,7 @@ def commit(method, uri, parameters) message_from(success, response), response, :test => test?, + :error_code => error_code_from(response), :authorization => authorization_from(success, get_url(uri), method, response) ) end @@ -210,7 +213,7 @@ def success_from(response) end def message_from(success, response) - success ? 'OK' : (response['error']['message'] || "Unknown error - please contact Netbanx-Paysafe") + success ? 'OK' : (response['error']['message'] || 'Unknown error - please contact Netbanx-Paysafe') end def authorization_from(success, url, method, response) @@ -227,7 +230,7 @@ def authorization_from(success, url, method, response) # # both id's are used to unstore, the payment token is only used for # purchase transactions - [response['id'], response['cards'].first['id'], response['cards'].first['paymentToken']].join("|") + [response['id'], response['cards'].first['id'], response['cards'].first['paymentToken']].join('|') end end @@ -236,10 +239,52 @@ def headers { 'Accept' => 'application/json', 'Content-type' => 'application/json', - 'Authorization' => "Basic #{Base64.strict_encode64(@options[:api_key].to_s).strip}", + 'Authorization' => "Basic #{Base64.strict_encode64(@options[:api_key].to_s)}", 'User-Agent' => "Netbanx-Paysafe v1.0/ActiveMerchant #{ActiveMerchant::VERSION}" } end + + def error_code_from(response) + unless success_from(response) + case response['errorCode'] + when '3002' then STANDARD_ERROR_CODE[:invalid_number] # You submitted an invalid card number or brand or combination of card number and brand with your request. + when '3004' then STANDARD_ERROR_CODE[:incorrect_zip] # The zip/postal code must be provided for an AVS check request. + when '3005' then STANDARD_ERROR_CODE[:incorrect_cvc] # You submitted an incorrect CVC value with your request. + when '3006' then STANDARD_ERROR_CODE[:expired_card] # You submitted an expired credit card number with your request. + when '3009' then STANDARD_ERROR_CODE[:card_declined] # Your request has been declined by the issuing bank. + when '3011' then STANDARD_ERROR_CODE[:card_declined] # Your request has been declined by the issuing bank because the card used is a restricted card. Contact the cardholder's credit card company for further investigation. + when '3012' then STANDARD_ERROR_CODE[:card_declined] # Your request has been declined by the issuing bank because the credit card expiry date submitted is invalid. + when '3013' then STANDARD_ERROR_CODE[:card_declined] # Your request has been declined by the issuing bank due to problems with the credit card account. + when '3014' then STANDARD_ERROR_CODE[:card_declined] # Your request has been declined - the issuing bank has returned an unknown response. Contact the card holder's credit card company for further investigation. + when '3015' then STANDARD_ERROR_CODE[:card_declined] # The bank has requested that you process the transaction manually by calling the cardholder's credit card company. + when '3016' then STANDARD_ERROR_CODE[:card_declined] # The bank has requested that you retrieve the card from the cardholder – it may be a lost or stolen card. + when '3017' then STANDARD_ERROR_CODE[:invalid_number] # You submitted an invalid credit card number with your request. + when '3022' then STANDARD_ERROR_CODE[:card_declined] # The card has been declined due to insufficient funds. + when '3023' then STANDARD_ERROR_CODE[:card_declined] # Your request has been declined by the issuing bank due to its proprietary card activity regulations. + when '3024' then STANDARD_ERROR_CODE[:card_declined] # Your request has been declined because the issuing bank does not permit the transaction for this card. + when '3032' then STANDARD_ERROR_CODE[:card_declined] # Your request has been declined by the issuing bank or external gateway because the card is probably in one of their negative databases. + when '3035' then STANDARD_ERROR_CODE[:card_declined] # Your request has been declined due to exceeded PIN attempts. + when '3036' then STANDARD_ERROR_CODE[:card_declined] # Your request has been declined due to an invalid issuer. + when '3037' then STANDARD_ERROR_CODE[:card_declined] # Your request has been declined because it is invalid. + when '3038' then STANDARD_ERROR_CODE[:card_declined] # Your request has been declined due to customer cancellation. + when '3039' then STANDARD_ERROR_CODE[:card_declined] # Your request has been declined due to an invalid authentication value. + when '3040' then STANDARD_ERROR_CODE[:card_declined] # Your request has been declined because the request type is not permitted on the card. + when '3041' then STANDARD_ERROR_CODE[:card_declined] # Your request has been declined due to a timeout. + when '3042' then STANDARD_ERROR_CODE[:card_declined] # Your request has been declined due to a cryptographic error. + when '3045' then STANDARD_ERROR_CODE[:invalid_expiry_date] # You submitted an invalid date format for this request. + when '3046' then STANDARD_ERROR_CODE[:card_declined] # The transaction was declined because the amount was set to zero. + when '3047' then STANDARD_ERROR_CODE[:card_declined] # The transaction was declined because the amount exceeds the floor limit. + when '3048' then STANDARD_ERROR_CODE[:card_declined] # The transaction was declined because the amount is less than the floor limit. + when '3049' then STANDARD_ERROR_CODE[:card_declined] # The bank has requested that you retrieve the card from the cardholder – the credit card has expired. + when '3050' then STANDARD_ERROR_CODE[:card_declined] # The bank has requested that you retrieve the card from the cardholder – fraudulent activity is suspected. + when '3051' then STANDARD_ERROR_CODE[:card_declined] # The bank has requested that you retrieve the card from the cardholder – contact the acquirer for more information. + when '3052' then STANDARD_ERROR_CODE[:card_declined] # The bank has requested that you retrieve the card from the cardholder – the credit card is restricted. + when '3053' then STANDARD_ERROR_CODE[:card_declined] # The bank has requested that you retrieve the card from the cardholder – please call the acquirer. + when '3054' then STANDARD_ERROR_CODE[:card_declined] # The transaction was declined due to suspected fraud. + else STANDARD_ERROR_CODE[:processing_error] + end + end + end end end end diff --git a/lib/active_merchant/billing/gateways/netbilling.rb b/lib/active_merchant/billing/gateways/netbilling.rb index d0c1fee0167..296d9e198ad 100644 --- a/lib/active_merchant/billing/gateways/netbilling.rb +++ b/lib/active_merchant/billing/gateways/netbilling.rb @@ -31,7 +31,6 @@ class NetbillingGateway < Gateway self.display_name = 'NETbilling' self.homepage_url = 'http://www.netbilling.com' self.supported_countries = ['US'] - self.ssl_version = :TLSv1 self.supported_cardtypes = [:visa, :master, :american_express, :discover, :jcb, :diners_club] def initialize(options = {}) @@ -144,14 +143,14 @@ def add_address(post, credit_card, options) post[:bill_state] = billing_address[:state] end - if shipping_address = options[:shipping_address] - post[:ship_name1], post[:ship_name2] = split_names(shipping_address[:name]) - post[:ship_street] = shipping_address[:address1] - post[:ship_zip] = shipping_address[:zip] - post[:ship_city] = shipping_address[:city] - post[:ship_country] = shipping_address[:country] - post[:ship_state] = shipping_address[:state] - end + if shipping_address = options[:shipping_address] + post[:ship_name1], post[:ship_name2] = split_names(shipping_address[:name]) + post[:ship_street] = shipping_address[:address1] + post[:ship_zip] = shipping_address[:zip] + post[:ship_city] = shipping_address[:city] + post[:ship_country] = shipping_address[:country] + post[:ship_state] = shipping_address[:state] + end end def add_invoice(post, options) @@ -187,7 +186,7 @@ def add_credit_card(post, credit_card) def parse(body) results = {} body.split(/&/).each do |pair| - key,val = pair.split(/\=/) + key, val = pair.split(/\=/) results[key.to_sym] = CGI.unescape(val) end results @@ -225,7 +224,7 @@ def post_data(action, parameters = {}) parameters[:pay_type] = 'C' parameters[:tran_type] = TRANSACTIONS[action] - parameters.reject{|k,v| v.blank?}.collect { |key, value| "#{key}=#{CGI.escape(value.to_s)}" }.join("&") + parameters.reject { |k, v| v.blank? }.collect { |key, value| "#{key}=#{CGI.escape(value.to_s)}" }.join('&') end end diff --git a/lib/active_merchant/billing/gateways/netpay.rb b/lib/active_merchant/billing/gateways/netpay.rb index b950d33073b..48e2a0a14d5 100644 --- a/lib/active_merchant/billing/gateways/netpay.rb +++ b/lib/active_merchant/billing/gateways/netpay.rb @@ -51,7 +51,7 @@ class NetpayGateway < Gateway self.display_name = 'NETPAY Gateway' CURRENCY_CODES = { - "MXN" => '484' + 'MXN' => '484' } # The header keys that we will provide in the response params hash @@ -110,7 +110,6 @@ def refund(money, authorization, options = {}) add_order_id(post, order_id_from(authorization)) add_amount(post, money, options) - #commit('Refund', post, options) commit('Credit', post, options) end @@ -157,7 +156,7 @@ def build_authorization(request_params, response_params) end def split_authorization(authorization) - order_id, amount, currency = authorization.split("|") + order_id, amount, currency = authorization.split('|') [order_id, amount, currency] end @@ -166,8 +165,8 @@ def order_id_from(authorization) end def expdate(credit_card) - year = sprintf("%.4i", credit_card.year) - month = sprintf("%.2i", credit_card.month) + year = sprintf('%.4i', credit_card.year) + month = sprintf('%.2i', credit_card.month) "#{month}/#{year[-2..-1]}" end @@ -191,7 +190,7 @@ def commit(action, parameters, options) add_login_data(parameters) add_action(parameters, action, options) - post = parameters.collect{|key, value| "#{key}=#{CGI.escape(value.to_s)}" }.join("&") + post = parameters.collect { |key, value| "#{key}=#{CGI.escape(value.to_s)}" }.join('&') parse(ssl_post(url, post), parameters) end diff --git a/lib/active_merchant/billing/gateways/network_merchants.rb b/lib/active_merchant/billing/gateways/network_merchants.rb index b684e92c5a8..aadc09d425f 100644 --- a/lib/active_merchant/billing/gateways/network_merchants.rb +++ b/lib/active_merchant/billing/gateways/network_merchants.rb @@ -239,4 +239,3 @@ def parse(raw_response) end end end - diff --git a/lib/active_merchant/billing/gateways/nmi.rb b/lib/active_merchant/billing/gateways/nmi.rb index b2e0f38862c..8591a802945 100644 --- a/lib/active_merchant/billing/gateways/nmi.rb +++ b/lib/active_merchant/billing/gateways/nmi.rb @@ -3,7 +3,7 @@ module Billing #:nodoc: class NmiGateway < Gateway include Empty - DUP_WINDOW_DEPRECATION_MESSAGE = "The class-level duplicate_window variable is deprecated. Please use the :dup_seconds transaction option instead." + DUP_WINDOW_DEPRECATION_MESSAGE = 'The class-level duplicate_window variable is deprecated. Please use the :dup_seconds transaction option instead.' self.test_url = self.live_url = 'https://secure.nmi.com/api/transact.php' self.default_currency = 'USD' @@ -34,7 +34,7 @@ def purchase(amount, payment_method, options={}) add_customer_data(post, options) add_merchant_defined_fields(post, options) - commit("sale", post) + commit('sale', post) end def authorize(amount, payment_method, options={}) @@ -44,7 +44,7 @@ def authorize(amount, payment_method, options={}) add_customer_data(post, options) add_merchant_defined_fields(post, options) - commit("auth", post) + commit('auth', post) end def capture(amount, authorization, options={}) @@ -53,7 +53,7 @@ def capture(amount, authorization, options={}) add_reference(post, authorization) add_merchant_defined_fields(post, options) - commit("capture", post) + commit('capture', post) end def void(authorization, options={}) @@ -61,7 +61,7 @@ def void(authorization, options={}) add_reference(post, authorization) add_payment_type(post, authorization) - commit("void", post) + commit('void', post) end def refund(amount, authorization, options={}) @@ -70,7 +70,7 @@ def refund(amount, authorization, options={}) add_reference(post, authorization) add_payment_type(post, authorization) - commit("refund", post) + commit('refund', post) end def credit(amount, payment_method, options={}) @@ -79,7 +79,7 @@ def credit(amount, payment_method, options={}) add_payment_method(post, payment_method, options) add_customer_data(post, options) - commit("credit", post) + commit('credit', post) end def verify(payment_method, options={}) @@ -88,7 +88,7 @@ def verify(payment_method, options={}) add_customer_data(post, options) add_merchant_defined_fields(post, options) - commit("validate", post) + commit('validate', post) end def store(payment_method, options = {}) @@ -98,12 +98,12 @@ def store(payment_method, options = {}) add_customer_data(post, options) add_merchant_defined_fields(post, options) - commit("add_customer", post) + commit('add_customer', post) end def verify_credentials - response = void("0") - response.message != "Authentication Failed" + response = void('0') + response.message != 'Authentication Failed' end def supports_scrubbing? @@ -116,7 +116,12 @@ def scrub(transcript) gsub(%r((ccnumber=)\d+), '\1[FILTERED]'). gsub(%r((cvv=)\d+), '\1[FILTERED]'). gsub(%r((checkaba=)\d+), '\1[FILTERED]'). - gsub(%r((checkaccount=)\d+), '\1[FILTERED]') + gsub(%r((checkaccount=)\d+), '\1[FILTERED]'). + gsub(%r((cryptogram=)[^&]+(&?)), '\1[FILTERED]\2') + end + + def supports_network_tokenization? + true end private @@ -126,7 +131,7 @@ def add_invoice(post, money, options) post[:orderid] = options[:order_id] post[:orderdescription] = options[:description] post[:currency] = options[:currency] || currency(money) - post[:billing_method] = "recurring" if options[:recurring] + post[:billing_method] = 'recurring' if options[:recurring] if (dup_seconds = (options[:dup_seconds] || self.class.duplicate_window)) post[:dup_seconds] = dup_seconds end @@ -135,8 +140,14 @@ def add_invoice(post, money, options) def add_payment_method(post, payment_method, options) if(payment_method.is_a?(String)) post[:customer_vault_id] = payment_method + elsif payment_method.is_a?(NetworkTokenizationCreditCard) + post[:ccnumber] = payment_method.number + post[:ccexp] = exp_date(payment_method) + post[:token_cryptogram] = payment_method.payment_cryptogram elsif(card_brand(payment_method) == 'check') post[:payment] = 'check' + post[:firstname] = payment_method.first_name + post[:lastname] = payment_method.last_name post[:checkname] = payment_method.name post[:checkaba] = payment_method.routing_number post[:checkaccount] = payment_method.account_number @@ -203,8 +214,7 @@ def exp_date(payment_method) end def commit(action, params) - - params[action == "add_customer" ? :customer_vault : :type] = action + params[action == 'add_customer' ? :customer_vault : :type] = action params[:username] = @options[:login] params[:password] = @options[:password] @@ -224,19 +234,19 @@ def commit(action, params) end def authorization_from(response, payment_type) - [ response[:transactionid], payment_type ].join("#") + [ response[:transactionid], payment_type ].join('#') end def split_authorization(authorization) - authorization.split("#") + authorization.split('#') end def headers - { "Content-Type" => "application/x-www-form-urlencoded;charset=UTF-8" } + { 'Content-Type' => 'application/x-www-form-urlencoded;charset=UTF-8' } end def post_data(action, params) - params.map {|k, v| "#{k}=#{CGI.escape(v.to_s)}"}.join('&') + params.map { |k, v| "#{k}=#{CGI.escape(v.to_s)}" }.join('&') end def url @@ -244,16 +254,16 @@ def url end def parse(body) - Hash[CGI::parse(body).map { |k,v| [k.intern, v.first] }] + Hash[CGI::parse(body).map { |k, v| [k.intern, v.first] }] end def success_from(response) - response[:response] == "1" + response[:response] == '1' end def message_from(succeeded, response) if succeeded - "Succeeded" + 'Succeeded' else response[:responsetext] end diff --git a/lib/active_merchant/billing/gateways/ogone.rb b/lib/active_merchant/billing/gateways/ogone.rb index 3700b334782..883ac94a05a 100644 --- a/lib/active_merchant/billing/gateways/ogone.rb +++ b/lib/active_merchant/billing/gateways/ogone.rb @@ -1,4 +1,5 @@ # coding: utf-8 + require 'rexml/document' module ActiveMerchant #:nodoc: @@ -119,20 +120,18 @@ class OgoneGateway < Gateway 'KO' => 'N', 'NO' => 'R' } - SUCCESS_MESSAGE = "The transaction was successful" + SUCCESS_MESSAGE = 'The transaction was successful' + + THREE_D_SECURE_DISPLAY_WAYS = { :main_window => 'MAINW', # display the identification page in the main window (default value). - THREE_D_SECURE_DISPLAY_WAYS = { :main_window => 'MAINW', # display the identification page in the main window - # (default value). - :pop_up => 'POPUP', # display the identification page in a pop-up window - # and return to the main window at the end. - :pop_ix => 'POPIX' } # display the identification page in a pop-up window - # and remain in the pop-up window. + :pop_up => 'POPUP', # display the identification page in a pop-up window and return to the main window at the end. + :pop_ix => 'POPIX' } # display the identification page in a pop-up window and remain in the pop-up window. - OGONE_NO_SIGNATURE_DEPRECATION_MESSAGE = "Signature usage will be the default for a future release of ActiveMerchant. You should either begin using it, or update your configuration to explicitly disable it (signature_encryptor: none)" + OGONE_NO_SIGNATURE_DEPRECATION_MESSAGE = 'Signature usage will be the default for a future release of ActiveMerchant. You should either begin using it, or update your configuration to explicitly disable it (signature_encryptor: none)' OGONE_STORE_OPTION_DEPRECATION_MESSAGE = "The 'store' option has been renamed to 'billing_id', and its usage is deprecated." - self.test_url = "https://secure.ogone.com/ncol/test/" - self.live_url = "https://secure.ogone.com/ncol/prod/" + self.test_url = 'https://secure.ogone.com/ncol/test/' + self.live_url = 'https://secure.ogone.com/ncol/prod/' self.supported_countries = ['BE', 'DE', 'FR', 'NL', 'AT', 'CH'] # also supports Airplus and UATP @@ -141,7 +140,6 @@ class OgoneGateway < Gateway self.display_name = 'Ogone' self.default_currency = 'EUR' self.money_format = :cents - self.ssl_version = :TLSv1 def initialize(options = {}) requires!(options, :login, :user, :password) @@ -151,7 +149,7 @@ def initialize(options = {}) # Verify and reserve the specified amount on the account, without actually doing the transaction. def authorize(money, payment_source, options = {}) post = {} - action = (payment_source.brand == "mastercard") ? "PAU" : "RES" + action = payment_source.brand == 'mastercard' ? 'PAU' : 'RES' add_invoice(post, options) add_payment_source(post, payment_source, options) add_address(post, payment_source, options) @@ -215,7 +213,7 @@ def verify(credit_card, options={}) # Store a credit card by creating an Ogone Alias def store(payment_source, options = {}) - options.merge!(:alias_operation => 'BYPSP') unless(options.has_key?(:billing_id) || options.has_key?(:store)) + options[:alias_operation] = 'BYPSP' unless(options.has_key?(:billing_id) || options.has_key?(:store)) response = authorize(@options[:store_amount] || 1, payment_source, options) void(response.authorization) if response.success? response @@ -227,21 +225,21 @@ def supports_scrubbing? def scrub(transcript) transcript. - gsub(%r((Authorization: Basic )\w+), '\1[FILTERED]'). - gsub(%r((&?cardno=)[^&]*)i, '\1[FILTERED]'). - gsub(%r((&?cvc=)[^&]*)i, '\1[FILTERED]'). - gsub(%r((&?pswd=)[^&]*)i, '\1[FILTERED]') + gsub(%r((Authorization: Basic )\w+), '\1[FILTERED]'). + gsub(%r((&?cardno=)[^&]*)i, '\1[FILTERED]'). + gsub(%r((&?cvc=)[^&]*)i, '\1[FILTERED]'). + gsub(%r((&?pswd=)[^&]*)i, '\1[FILTERED]') end private def reference_from(authorization) - authorization.split(";").first + authorization.split(';').first end def reference_transaction?(identifier) return false unless identifier.is_a?(String) - _, action = identifier.split(";") + _, action = identifier.split(';') !action.nil? end @@ -287,7 +285,7 @@ def add_d3d(post, options) THREE_D_SECURE_DISPLAY_WAYS[:main_window] add_pair post, 'WIN3DS', win_3ds - add_pair post, 'HTTP_ACCEPT', options[:http_accept] || "*/*" + add_pair post, 'HTTP_ACCEPT', options[:http_accept] || '*/*' add_pair post, 'HTTP_USER_AGENT', options[:http_user_agent] if options[:http_user_agent] add_pair post, 'ACCEPTURL', options[:accept_url] if options[:accept_url] add_pair post, 'DECLINEURL', options[:decline_url] if options[:decline_url] @@ -303,8 +301,8 @@ def add_eci(post, eci) add_pair post, 'ECI', eci.to_s end - def add_alias(post, _alias, alias_operation = nil) - add_pair post, 'ALIAS', _alias + def add_alias(post, alias_name, alias_operation = nil) + add_pair post, 'ALIAS', alias_name add_pair post, 'ALIASOPERATION', alias_operation unless alias_operation.nil? end @@ -334,12 +332,13 @@ def add_address(post, creditcard, options) def add_invoice(post, options) add_pair post, 'orderID', options[:order_id] || generate_unique_id[0...30] add_pair post, 'COM', options[:description] + add_pair post, 'ORIG', options[:origin] if options[:origin] end def add_creditcard(post, creditcard) add_pair post, 'CN', creditcard.name add_pair post, 'CARDNO', creditcard.number - add_pair post, 'ED', "%02d%02s" % [creditcard.month, creditcard.year.to_s[-2..-1]] + add_pair post, 'ED', '%02d%02s' % [creditcard.month, creditcard.year.to_s[-2..-1]] add_pair post, 'CVC', creditcard.verification_value end @@ -349,8 +348,8 @@ def parse(body) # Add HTML_ANSWER element (3-D Secure specific to the response's params) # Note: HTML_ANSWER is not an attribute so we add it "by hand" to the response - if html_answer = REXML::XPath.first(xml_root, "//HTML_ANSWER") - response["HTML_ANSWER"] = html_answer.text + if html_answer = REXML::XPath.first(xml_root, '//HTML_ANSWER') + response['HTML_ANSWER'] = html_answer.text end response @@ -365,27 +364,27 @@ def commit(action, parameters) response = parse(ssl_post(url(parameters['PAYID']), post_data(action, parameters))) options = { - :authorization => [response["PAYID"], action].join(";"), + :authorization => [response['PAYID'], action].join(';'), :test => test?, - :avs_result => { :code => AVS_MAPPING[response["AAVCheck"]] }, - :cvv_result => CVV_MAPPING[response["CVCCheck"]] + :avs_result => { :code => AVS_MAPPING[response['AAVCheck']] }, + :cvv_result => CVV_MAPPING[response['CVCCheck']] } OgoneResponse.new(successful?(response), message_from(response), response, options) end def url(payid) - (test? ? test_url : live_url) + (payid ? "maintenancedirect.asp" : "orderdirect.asp") + (test? ? test_url : live_url) + (payid ? 'maintenancedirect.asp' : 'orderdirect.asp') end def successful?(response) - response["NCERROR"] == "0" + response['NCERROR'] == '0' end def message_from(response) if successful?(response) SUCCESS_MESSAGE else - format_error_message(response["NCERRORPLUS"]) + format_error_message(response['NCERRORPLUS']) end end @@ -393,9 +392,9 @@ def format_error_message(message) raw_message = message.to_s.strip case raw_message when /\|/ - raw_message.split("|").join(", ").capitalize + raw_message.split('|').join(', ').capitalize when /\// - raw_message.split("/").first.to_s.capitalize + raw_message.split('/').first.to_s.capitalize else raw_message.to_s.capitalize end @@ -409,8 +408,8 @@ def post_data(action, parameters = {}) def add_signature(parameters) if @options[:signature].blank? - ActiveMerchant.deprecated(OGONE_NO_SIGNATURE_DEPRECATION_MESSAGE) unless(@options[:signature_encryptor] == "none") - return + ActiveMerchant.deprecated(OGONE_NO_SIGNATURE_DEPRECATION_MESSAGE) unless(@options[:signature_encryptor] == 'none') + return end add_pair parameters, 'SHASign', calculate_signature(parameters, @options[:signature_encryptor], @options[:signature]) @@ -430,9 +429,9 @@ def calculate_signature(signed_parameters, algorithm, secret) raise "Unknown signature algorithm #{algorithm}" end - filtered_params = signed_parameters.select{|k,v| !v.blank?} + filtered_params = signed_parameters.select { |k, v| !v.blank? } sha_encryptor.hexdigest( - filtered_params.sort_by{|k,v| k.upcase}.map{|k, v| "#{k.upcase}=#{v}#{secret}"}.join("") + filtered_params.sort_by { |k, v| k.upcase }.map { |k, v| "#{k.upcase}=#{v}#{secret}" }.join('') ).upcase end @@ -447,9 +446,9 @@ def legacy_calculate_signature(parameters, secret) PSPID Operation ALIAS - ).map{|key| parameters[key]} + + ).map { |key| parameters[key] } + [secret] - ).join("") + ).join('') ).upcase end diff --git a/lib/active_merchant/billing/gateways/omise.rb b/lib/active_merchant/billing/gateways/omise.rb index a3c21bf2c10..218b099590f 100644 --- a/lib/active_merchant/billing/gateways/omise.rb +++ b/lib/active_merchant/billing/gateways/omise.rb @@ -19,7 +19,7 @@ class OmiseGateway < Gateway self.default_currency = 'THB' self.money_format = :cents - #Country supported by Omise + # Country supported by Omise # * Thailand self.supported_countries = %w( TH JP ) @@ -164,7 +164,7 @@ def scrub(transcript) transcript. gsub(/(Authorization: Basic )\w+/i, '\1[FILTERED]'). gsub(/(\\"number\\":)\\"\d+\\"/, '\1[FILTERED]'). - gsub(/(\\"security_code\\":)\\"\d+\\"/,'\1[FILTERED]') + gsub(/(\\"security_code\\":)\\"\d+\\"/, '\1[FILTERED]') end private @@ -182,7 +182,7 @@ def headers(options={}) key = options[:key] || @secret_key { 'Content-Type' => 'application/json;utf-8', - 'Omise-Version' => @api_version || "2014-07-27", + 'Omise-Version' => @api_version || '2014-07-27', 'User-Agent' => "ActiveMerchantBindings/#{ActiveMerchant::VERSION} Ruby/#{RUBY_VERSION}", 'Authorization' => 'Basic ' + Base64.encode64(key.to_s + ':').strip, 'Accept-Encoding' => 'utf-8' @@ -216,7 +216,7 @@ def parse(body) end def json_error(raw_response) - msg = "Invalid response received from Omise API. Please contact support@omise.co if you continue to receive this message." + msg = 'Invalid response received from Omise API. Please contact support@omise.co if you continue to receive this message.' msg += "The raw response returned by the API was #{raw_response.inspect})" { message: msg } end @@ -246,16 +246,16 @@ def error_code_from(response) def message_to_standard_error_code_from(response) message = response['message'] if response['code'] == 'invalid_card' case message - when /brand not supported/ - STANDARD_ERROR_CODE[:invalid_number] - when /number is invalid/ - STANDARD_ERROR_CODE[:incorrect_number] - when /expiration date cannot be in the past/ - STANDARD_ERROR_CODE[:expired_card] - when /expiration \w+ is invalid/ - STANDARD_ERROR_CODE[:invalid_expiry_date] - else - STANDARD_ERROR_CODE[:processing_error] + when /brand not supported/ + STANDARD_ERROR_CODE[:invalid_number] + when /number is invalid/ + STANDARD_ERROR_CODE[:incorrect_number] + when /expiration date cannot be in the past/ + STANDARD_ERROR_CODE[:expired_card] + when /expiration \w+ is invalid/ + STANDARD_ERROR_CODE[:invalid_expiry_date] + else + STANDARD_ERROR_CODE[:processing_error] end end @@ -263,7 +263,7 @@ def message_from(response) if successful?(response) 'Success' else - (response['message'] ? response['message'] : response['failure_message']) + response['message'] || response['failure_message'] end end diff --git a/lib/active_merchant/billing/gateways/openpay.rb b/lib/active_merchant/billing/gateways/openpay.rb index aea2c4ff98f..778729f4cbd 100644 --- a/lib/active_merchant/billing/gateways/openpay.rb +++ b/lib/active_merchant/billing/gateways/openpay.rb @@ -5,7 +5,7 @@ class OpenpayGateway < Gateway self.test_url = 'https://sandbox-api.openpay.mx/v1/' self.supported_countries = ['MX'] - self.supported_cardtypes = [:visa, :master, :american_express] + self.supported_cardtypes = [:visa, :master, :american_express, :carnet] self.homepage_url = 'http://www.openpay.mx/' self.display_name = 'Openpay' self.default_currency = 'MXN' @@ -38,6 +38,7 @@ def authorize(money, creditcard, options = {}) def capture(money, authorization, options = {}) post = {} post[:amount] = amount(money) if money + post[:payments] = options[:payments] if options[:payments] commit(:post, "charges/#{CGI.escape(authorization)}/capture", post, options) end @@ -103,6 +104,7 @@ def scrub(transcript) gsub(%r((cvv2\\?":\\?")\\?"), '\1[BLANK]"'). gsub(%r((cvv2\\?":\\?")\s+), '\1[BLANK]') end + private def create_post_for_auth_or_purchase(money, creditcard, options) @@ -113,6 +115,8 @@ def create_post_for_auth_or_purchase(money, creditcard, options) post[:order_id] = options[:order_id] post[:device_session_id] = options[:device_session_id] post[:currency] = (options[:currency] || currency(money)).upcase + post[:use_card_points] = options[:use_card_points] if options[:use_card_points] + post[:payment_plan] = {payments: options[:payments]} if options[:payments] add_creditcard(post, creditcard, options) post end @@ -123,16 +127,28 @@ def add_creditcard(post, creditcard, options) elsif creditcard.respond_to?(:number) card = { card_number: creditcard.number, - expiration_month: "#{sprintf("%02d", creditcard.month)}", - expiration_year: "#{"#{creditcard.year}"[-2, 2]}", + expiration_month: sprintf('%02d', creditcard.month), + expiration_year: creditcard.year.to_s[-2, 2], cvv2: creditcard.verification_value, holder_name: creditcard.name } add_address(card, options) + add_customer_data(post, creditcard, options) post[:card] = card end end + def add_customer_data(post, creditcard, options) + if options[:email] + customer = { + name: creditcard.name || options[:name], + email: options[:email] + } + post[:customer] = customer + end + post + end + def add_address(card, options) return unless card.kind_of?(Hash) if address = (options[:billing_address] || options[:address]) @@ -150,10 +166,10 @@ def add_address(card, options) def headers(options = {}) { - "Content-Type" => "application/json", - "Authorization" => "Basic " + Base64.strict_encode64(@api_key.to_s + ":").strip, - "User-Agent" => "Openpay/v1 ActiveMerchantBindings/#{ActiveMerchant::VERSION}", - "X-Openpay-Client-User-Agent" => user_agent + 'Content-Type' => 'application/json', + 'Authorization' => 'Basic ' + Base64.strict_encode64(@api_key.to_s + ':').strip, + 'User-Agent' => "Openpay/v1 ActiveMerchantBindings/#{ActiveMerchant::VERSION}", + 'X-Openpay-Client-User-Agent' => user_agent } end @@ -193,11 +209,9 @@ def error?(response) end def response_error(raw_response) - begin - parse(raw_response) - rescue JSON::ParserError - json_error(raw_response) - end + parse(raw_response) + rescue JSON::ParserError + json_error(raw_response) end def json_error(raw_response) diff --git a/lib/active_merchant/billing/gateways/opp.rb b/lib/active_merchant/billing/gateways/opp.rb index 6c36a8963b2..8c82574a670 100644 --- a/lib/active_merchant/billing/gateways/opp.rb +++ b/lib/active_merchant/billing/gateways/opp.rb @@ -1,119 +1,119 @@ module ActiveMerchant #:nodoc: module Billing #:nodoc: class OppGateway < Gateway -# = Open Payment Platform - # - # The Open Payment Platform includes a powerful omni-channel transaction processing API, - # enabling you to quickly and flexibly build new applications and services on the platform. - # - # This plugin enables connectivity to the Open Payment Platform for activemerchant. - # - # For any questions or comments please contact support@payon.com - # - # == Usage - # - # gateway = ActiveMerchant::Billing::OppGateway.new( - # user_id: 'merchant user id', - # password: 'password', - # entity_id: 'entity id', - # ) - # - # # set up credit card object as in main ActiveMerchant example - # creditcard = ActiveMerchant::Billing::CreditCard.new( - # :type => 'visa', - # :number => '4242424242424242', - # :month => 8, - # :year => 2009, - # :first_name => 'Bob', - # :last_name => 'Bobsen' - # :verification_value: '123') - # - # # Request: complete example, including address, billing address, shipping address - # complete_request_options = { - # order_id: "your merchant/shop order id", # alternative is to set merchantInvoiceId - # merchant_transaction_id: "your merchant/shop transaction id", - # address: address, - # description: 'Store Purchase - Books', - # risk_workflow: false, - # test_mode: 'EXTERNAL' # or 'INTERNAL', valid only for test system - # create_registration: false, # payment details will be stored on the server an latter can be referenced - # - # billing_address: { - # address1: '123 Test Street', - # city: 'Test', - # state: 'TE', - # zip: 'AB12CD', - # country: 'GB', - # }, - # shipping_address: { - # name: 'Muton DeMicelis', - # address1: 'My Street On Upiter, Apt 3.14/2.78', - # city: 'Munich', - # state: 'Bov', - # zip: '81675', - # country: 'DE', - # }, - # customer: { - # merchant_customer_id: "your merchant/customer id", - # givenname: 'Jane', - # surname: 'Jones', - # birth_date: '1965-05-01', - # phone: '(?!?)555-5555', - # mobile: '(?!?)234-23423', - # email: 'jane@jones.com', - # company_name: 'JJ Ltd.', - # identification_doctype: 'PASSPORT', - # identification_docid: 'FakeID2342431234123', - # ip: 101.102.103.104, - # }, - # } - # - # # Request: minimal example - # minimal_request_options = { - # order_id: "your merchant/shop order id", # alternative is to set merchantInvoiceId - # description: 'Store Purchase - Books', - # } - # - # options = - # # run request - # response = gateway.purchase(754, creditcard, options) # charge 7,54 EUR - # - # response.success? # Check whether the transaction was successful - # response.error_code # Retrieve the error message - it's mapped to Gateway::STANDARD_ERROR_CODE - # response.message # Retrieve the message returned by opp - # response.authorization # Retrieve the unique transaction ID returned by opp - # response.params['result']['code'] # Retrieve original return code returned by opp server - # - # == Errors - # If transaction is not successful, response.error_code contains mapped to Gateway::STANDARD_ERROR_CODE error message. - # Complete list of opp error codes can be viewed on https://docs.oppwa.com/ - # Because this list is much bigger than Gateway::STANDARD_ERROR_CODE, only fraction is mapped to Gateway::STANDARD_ERROR_CODE. - # All other codes are mapped as Gateway::STANDARD_ERROR_CODE[:processing_error], so if this is the case, - # you may check the original result code from OPP that can be found in response.params['result']['code'] - # - # == Special features - # For purchase method risk check can be forced when options[:risk_workflow] = true - # This will split (on OPP server side) the transaction into two separate transactions: authorize and capture, - # but capture will be executed only if risk checks are successful. - # - # For testing you may use the test account details listed fixtures.yml under opp. It is important to note that there are two test modes available: - # options[:test_mode]='EXTERNAL' causes test transactions to be forwarded to the processor's test system for 'end-to-end' testing - # options[:test_mode]='INTERNAL' causes transactions to be sent to opp simulators, which is useful when switching to the live endpoint for connectivity testing. - # If no test_mode parameter is sent, test_mode=INTERNAL is the default behaviour. - # - # Billing Address, Shipping Address, Custom Parameters are supported as described under https://docs.oppwa.com/parameters - # See complete example above for details. - # - # == Tokenization - # When create_registration is set to true, the payment details will be stored and a token will be returned in registrationId response field, - # which can subsequently be used to reference the stored payment. + # = Open Payment Platform + # + # The Open Payment Platform includes a powerful omni-channel transaction processing API, + # enabling you to quickly and flexibly build new applications and services on the platform. + # + # This plugin enables connectivity to the Open Payment Platform for activemerchant. + # + # For any questions or comments please contact support@payon.com + # + # == Usage + # + # gateway = ActiveMerchant::Billing::OppGateway.new( + # user_id: 'merchant user id', + # password: 'password', + # entity_id: 'entity id', + # ) + # + # # set up credit card object as in main ActiveMerchant example + # creditcard = ActiveMerchant::Billing::CreditCard.new( + # :type => 'visa', + # :number => '4242424242424242', + # :month => 8, + # :year => 2009, + # :first_name => 'Bob', + # :last_name => 'Bobsen' + # :verification_value: '123') + # + # # Request: complete example, including address, billing address, shipping address + # complete_request_options = { + # order_id: "your merchant/shop order id", # alternative is to set merchantInvoiceId + # merchant_transaction_id: "your merchant/shop transaction id", + # address: address, + # description: 'Store Purchase - Books', + # risk_workflow: false, + # test_mode: 'EXTERNAL' # or 'INTERNAL', valid only for test system + # create_registration: false, # payment details will be stored on the server an latter can be referenced + # + # billing_address: { + # address1: '123 Test Street', + # city: 'Test', + # state: 'TE', + # zip: 'AB12CD', + # country: 'GB', + # }, + # shipping_address: { + # name: 'Muton DeMicelis', + # address1: 'My Street On Upiter, Apt 3.14/2.78', + # city: 'Munich', + # state: 'Bov', + # zip: '81675', + # country: 'DE', + # }, + # customer: { + # merchant_customer_id: "your merchant/customer id", + # givenname: 'Jane', + # surname: 'Jones', + # birth_date: '1965-05-01', + # phone: '(?!?)555-5555', + # mobile: '(?!?)234-23423', + # email: 'jane@jones.com', + # company_name: 'JJ Ltd.', + # identification_doctype: 'PASSPORT', + # identification_docid: 'FakeID2342431234123', + # ip: 101.102.103.104, + # }, + # } + # + # # Request: minimal example + # minimal_request_options = { + # order_id: "your merchant/shop order id", # alternative is to set merchantInvoiceId + # description: 'Store Purchase - Books', + # } + # + # options = + # # run request + # response = gateway.purchase(754, creditcard, options) # charge 7,54 EUR + # + # response.success? # Check whether the transaction was successful + # response.error_code # Retrieve the error message - it's mapped to Gateway::STANDARD_ERROR_CODE + # response.message # Retrieve the message returned by opp + # response.authorization # Retrieve the unique transaction ID returned by opp + # response.params['result']['code'] # Retrieve original return code returned by opp server + # + # == Errors + # If transaction is not successful, response.error_code contains mapped to Gateway::STANDARD_ERROR_CODE error message. + # Complete list of opp error codes can be viewed on https://docs.oppwa.com/ + # Because this list is much bigger than Gateway::STANDARD_ERROR_CODE, only fraction is mapped to Gateway::STANDARD_ERROR_CODE. + # All other codes are mapped as Gateway::STANDARD_ERROR_CODE[:processing_error], so if this is the case, + # you may check the original result code from OPP that can be found in response.params['result']['code'] + # + # == Special features + # For purchase method risk check can be forced when options[:risk_workflow] = true + # This will split (on OPP server side) the transaction into two separate transactions: authorize and capture, + # but capture will be executed only if risk checks are successful. + # + # For testing you may use the test account details listed fixtures.yml under opp. It is important to note that there are two test modes available: + # options[:test_mode]='EXTERNAL' causes test transactions to be forwarded to the processor's test system for 'end-to-end' testing + # options[:test_mode]='INTERNAL' causes transactions to be sent to opp simulators, which is useful when switching to the live endpoint for connectivity testing. + # If no test_mode parameter is sent, test_mode=INTERNAL is the default behaviour. + # + # Billing Address, Shipping Address, Custom Parameters are supported as described under https://docs.oppwa.com/parameters + # See complete example above for details. + # + # == Tokenization + # When create_registration is set to true, the payment details will be stored and a token will be returned in registrationId response field, + # which can subsequently be used to reference the stored payment. self.test_url = 'https://test.oppwa.com/v1/payments' self.live_url = 'https://oppwa.com/v1/payments' self.supported_countries = %w(AD AI AG AR AU AT BS BB BE BZ BM BR BN BG CA HR CY CZ DK DM EE FI FR DE GR GD GY HK HU IS IN IL IT JP LV LI LT LU MY MT MX MC MS NL PA PL PT KN LC MF VC SM SG SK SI ZA ES SR SE CH TR GB US UY) self.default_currency = 'EUR' - self.supported_cardtypes = [:visa, :master, :american_express, :diners_club, :discover, :jcb, :maestro, :dankort] + self.supported_cardtypes = [:visa, :master, :american_express, :diners_club, :discover, :jcb, :maestro, :dankort] self.homepage_url = 'https://docs.oppwa.com' self.display_name = 'Open Payment Platform' @@ -125,7 +125,7 @@ def initialize(options={}) def purchase(money, payment, options={}) # debit - execute_dbpa(options[:risk_workflow] ? 'PA.CP': 'DB', + execute_dbpa(options[:risk_workflow] ? 'PA.CP': 'DB', money, payment, options) end @@ -133,7 +133,7 @@ def authorize(money, payment, options={}) # preauthorization PA execute_dbpa('PA', money, payment, options) end - + def capture(money, authorization, options={}) # capture CP execute_referencing('CP', money, authorization, options) @@ -163,8 +163,6 @@ def supports_scrubbing? def scrub(transcript) transcript. gsub(%r((authentication\.password=)\w+), '\1[FILTERED]'). - gsub(%r((authentication\.userId=)\w+), '\1[FILTERED]'). - gsub(%r((authentication\.entityId=)\w+), '\1[FILTERED]'). gsub(%r((card\.number=)\d+), '\1[FILTERED]'). gsub(%r((card\.cvv=)\d+), '\1[FILTERED]') end @@ -173,12 +171,13 @@ def scrub(transcript) def execute_dbpa(txtype, money, payment, options) post = {} - post[:paymentType] = txtype + post[:paymentType] = txtype add_invoice(post, money, options) add_payment_method(post, payment, options) add_address(post, options) - add_customer_data(post, options) + add_customer_data(post, payment, options) add_options(post, options) + add_3d_secure(post, options) commit(post, nil, options) end @@ -189,128 +188,160 @@ def execute_referencing(txtype, money, authorization, options) commit(post, authorization, options) end - def add_authentication(post) - post[:authentication] = { entityId: @options[:entity_id], password: @options[:password], userId: @options[:user_id]} + def add_authentication(post) + post[:authentication] = { entityId: @options[:entity_id], password: @options[:password], userId: @options[:user_id]} end - def add_customer_data(post, options) + def add_customer_data(post, payment, options) if options[:customer] post[:customer] = { merchantCustomerId: options[:customer][:merchant_customer_id], - givenName: options[:customer][:givenname], - surname: options[:customer][:surname], + givenName: options[:customer][:givenname] || payment.first_name, + surname: options[:customer][:surname] || payment.last_name, birthDate: options[:customer][:birth_date], phone: options[:customer][:phone], mobile: options[:customer][:mobile], - email: options[:customer][:email], + email: options[:customer][:email] || options[:email], companyName: options[:customer][:company_name], identificationDocType: options[:customer][:identification_doctype], identificationDocId: options[:customer][:identification_docid], - ip: options[:customer][:ip], + ip: options[:customer][:ip] || options[:ip] } end end def add_address(post, options) - if billing_address = options[:billing_address] + if billing_address = options[:billing_address] || options[:address] address(post, billing_address, 'billing') end if shipping_address = options[:shipping_address] - address(post, billing_address, 'shipping') + address(post, shipping_address, 'shipping') if shipping_address[:name] - firstname, lastname = shipping_address[:name].split(' ') - post[:shipping] = { givenName: firstname, surname: lastname } - end + firstname, lastname = shipping_address[:name].split(' ') + post[:shipping] = { givenName: firstname, surname: lastname } + end end end def address(post, address, prefix) - post[prefix] = { - street1: address[:address1], - street2: address[:address2], - city: address[:city], - state: address[:state], - postcode: address[:zip], - country: address[:country], - } + post[prefix] = { + street1: address[:address1], + street2: address[:address2], + city: address[:city], + state: address[:state], + postcode: address[:zip], + country: address[:country], + } end def add_invoice(post, money, options) - post[:amount] = amount(money) - post[:currency] = (currency(money) || @options[:currency]) if 'RV'!=(post[:paymentType]) - post[:descriptor] = options[:description] || options[:descriptor] - post[:merchantInvoiceId] = options[:merchantInvoiceId] || options[:order_id] - post[:merchantTransactionId] = options[:merchant_transaction_id] + post[:amount] = amount(money) + post[:currency] = options[:currency] || currency(money) unless post[:paymentType] == 'RV' + post[:descriptor] = options[:description] || options[:descriptor] + post[:merchantInvoiceId] = options[:merchantInvoiceId] || options[:order_id] + post[:merchantTransactionId] = options[:merchant_transaction_id] || generate_unique_id end def add_payment_method(post, payment, options) - if options[:registrationId] - #post[:recurringType] = 'REPEATED' - post[:card] = { - cvv: payment.verification_value, - } - else - post[:paymentBrand] = payment.brand.upcase - post[:card] = { - holder: payment.name, - number: payment.number, - expiryMonth: "%02d" % payment.month, - expiryYear: payment.year, - cvv: payment.verification_value, - } - end + if options[:registrationId] + post[:card] = { + cvv: payment.verification_value, + } + else + post[:paymentBrand] = payment.brand.upcase + post[:card] = { + holder: payment.name, + number: payment.number, + expiryMonth: '%02d' % payment.month, + expiryYear: payment.year, + cvv: payment.verification_value, + } + end + end + + def add_3d_secure(post, options) + return unless options[:eci] && options[:cavv] && options[:xid] + + post[:threeDSecure] = { + eci: options[:eci], + verificationId: options[:cavv], + xid: options[:xid] + } end def add_options(post, options) post[:createRegistration] = options[:create_registration] if options[:create_registration] && !options[:registrationId] post[:testMode] = options[:test_mode] if test? && options[:test_mode] - options.each {|key, value| post[key] = value if key.to_s.match('customParameters\[[a-zA-Z0-9\._]{3,64}\]') } + options.each { |key, value| post[key] = value if key.to_s.match('customParameters\[[a-zA-Z0-9\._]{3,64}\]') } post['customParameters[SHOPPER_pluginId]'] = 'activemerchant' + post['customParameters[custom_disable3DSecure]'] = options[:disable_3d_secure] if options[:disable_3d_secure] end def build_url(url, authorization, options) if options[:registrationId] "#{url.gsub(/payments/, 'registrations')}/#{options[:registrationId]}/payments" - elsif authorization + elsif authorization "#{url}/#{authorization}" else url end end - + def commit(post, authorization, options) - url = (test? ? test_url : live_url) + url = build_url(test? ? test_url : live_url, authorization, options) add_authentication(post) post = flatten_hash(post) - url = build_url(url, authorization, options) - raw_response = raw_ssl_request(:post, url, - post.collect { |key, value| "#{key}=#{CGI.escape(value.to_s)}" }.join("&"), - "Content-Type" => "application/x-www-form-urlencoded;charset=UTF-8") - - success = success_from(raw_response) - response = raw_response.body - begin - response = JSON.parse(response) - rescue JSON::ParserError - response = json_error(response) + response = begin + parse( + ssl_post( + url, + post.collect { |key, value| "#{key}=#{CGI.escape(value.to_s)}" }.join('&'), + 'Content-Type' => 'application/x-www-form-urlencoded;charset=UTF-8' + ) + ) + rescue ResponseError => e + parse(e.response.body) end + success = success_from(response) + Response.new( success, message_from(response), response, authorization: authorization_from(response), test: test?, - error_code: success ? nil : error_code_from(response), + error_code: success ? nil : error_code_from(response) ) end - def success_from(raw_response) - raw_response.code.to_i.between?(200,299) + def parse(body) + JSON.parse(body) + rescue JSON::ParserError + json_error(body) + end + + def json_error(body) + message = "Invalid response received #{body.inspect}" + { 'result' => {'description' => message, 'code' => 'unknown' } } + end + + def success_from(response) + return false unless response['result'] + + success_regex = /^(000\.000\.|000\.100\.1|000\.[36])/ + + if success_regex =~ response['result']['code'] + true + else + false + end end def message_from(response) + return 'Failed' unless response['result'] + response['result']['description'] end @@ -319,44 +350,20 @@ def authorization_from(response) end def error_code_from(response) - case response['result']['code'] - when '100.100.101' - Gateway::STANDARD_ERROR_CODE[:incorrect_number] - when '100.400.317' - Gateway::STANDARD_ERROR_CODE[:invalid_number] - when '100.100.600', '100.100.601', '800.100.153', '800.100.192' - Gateway::STANDARD_ERROR_CODE[:invalid_cvc] - when '100.100.303' - Gateway::STANDARD_ERROR_CODE[:expired_card] - when '100.800.200', '100.800.201', '100.800.202', '800.800.202' - Gateway::STANDARD_ERROR_CODE[:incorrect_zip] - when '100.400.000', '100.400.086', '100.400.305', '800.400.150' - Gateway::STANDARD_ERROR_CODE[:incorrect_address] - when '800.100.159' - Gateway::STANDARD_ERROR_CODE[:pickup_card] - when '800.100.151', '800.100.158', '800.100.160' - Gateway::STANDARD_ERROR_CODE[:card_declined] - else - Gateway::STANDARD_ERROR_CODE[:processing_error] - end - end - - def json_error(raw_response) - message = "Invalid response received #{raw_response.inspect}" - { 'result' => {'description' => message, 'code' => 'unknown' } } + response['result']['code'] end - + def flatten_hash(hash) hash.each_with_object({}) do |(k, v), h| if v.is_a? Hash flatten_hash(v).map do |h_k, h_v| h["#{k}.#{h_k}".to_sym] = h_v end - else + else h[k] = v end - end - end + end + end end end end diff --git a/lib/active_merchant/billing/gateways/optimal_payment.rb b/lib/active_merchant/billing/gateways/optimal_payment.rb index 9604335381d..30f7bf57e02 100644 --- a/lib/active_merchant/billing/gateways/optimal_payment.rb +++ b/lib/active_merchant/billing/gateways/optimal_payment.rb @@ -5,10 +5,12 @@ class OptimalPaymentGateway < Gateway self.live_url = 'https://webservices.optimalpayments.com/creditcardWS/CreditCardServlet/v1' # The countries the gateway supports merchants from as 2 digit ISO country codes - self.supported_countries = ['CA', 'US', 'GB'] + self.supported_countries = ['CA', 'US', 'GB', 'AU', 'AT', 'BE', 'BG', 'HR', 'CY', 'CZ', 'DK', + 'EE', 'FI', 'DE', 'GR', 'HU', 'IE', 'IT', 'LV', 'LT', 'LU', 'MT', + 'NL', 'NO', 'PL', 'PT', 'RO', 'SK', 'SI', 'ES', 'SE', 'CH'] # The card types supported by the payment gateway - self.supported_cardtypes = [:visa, :master, :american_express, :discover, :diners_club, :solo] # :switch? + self.supported_cardtypes = [:visa, :master, :american_express, :discover, :diners_club] # The homepage URL of the gateway self.homepage_url = 'http://www.optimalpayments.com/' @@ -17,7 +19,6 @@ class OptimalPaymentGateway < Gateway self.display_name = 'Optimal Payments' def initialize(options = {}) - if(options[:login]) ActiveMerchant.deprecated("The 'login' option is deprecated in favor of 'store_id' and will be removed in a future version.") options[:store_id] = options[:login] @@ -59,15 +60,31 @@ def capture(money, authorization, options = {}) commit('ccSettlement', money, options) end + def verify(credit_card, options = {}) + parse_card_or_auth(credit_card, options) + commit('ccVerification', 0, options) + end + + def supports_scrubbing? + true + end + + def scrub(transcript) + transcript. + gsub(%r((%3CstorePwd%3E).*(%3C(%2F|/)storePwd%3E))i, '\1[FILTERED]\2'). + gsub(%r((%3CcardNum%3E)\d*(%3C(%2F|/)cardNum%3E))i, '\1[FILTERED]\2'). + gsub(%r((%3Ccvd%3E)\d*(%3C(%2F|/)cvd%3E))i, '\1[FILTERED]\2') + end + private def parse_card_or_auth(card_or_auth, options) if card_or_auth.respond_to?(:number) @credit_card = card_or_auth - @stored_data = "" + @stored_data = '' else options[:confirmationNumber] = card_or_auth - @stored_data = "StoredData" + @stored_data = 'StoredData' end end @@ -87,11 +104,11 @@ def commit(action, money, post) cc_stored_data_request(money, post) when 'ccAuthorizeReversal' cc_auth_reversal_request(post) - #when 'ccCancelSettle', 'ccCancelCredit', 'ccCancelPayment' + # when 'ccCancelSettle', 'ccCancelCredit', 'ccCancelPayment' # cc_cancel_request(money, post) - #when 'ccPayment' + # when 'ccPayment' # cc_payment_request(money, post) - #when 'ccAuthenticate' + # when 'ccAuthenticate' # cc_authenticate_request(money, post) else raise 'Unknown Action' @@ -166,7 +183,7 @@ def xml_document(root_tag) def get_text_from_document(document, node) node = REXML::XPath.first(document, node) - node && node.text + node&.text end def cc_auth_request(money, opts) @@ -243,25 +260,27 @@ def schema def build_merchant_account(xml) xml.tag! 'merchantAccount' do - xml.tag! 'accountNum' , @options[:account_number] - xml.tag! 'storeID' , @options[:store_id] - xml.tag! 'storePwd' , @options[:password] + xml.tag! 'accountNum', @options[:account_number] + xml.tag! 'storeID', @options[:store_id] + xml.tag! 'storePwd', @options[:password] end end def build_card(xml, opts) xml.tag! 'card' do - xml.tag! 'cardNum' , @credit_card.number + xml.tag! 'cardNum', @credit_card.number xml.tag! 'cardExpiry' do - xml.tag! 'month' , @credit_card.month - xml.tag! 'year' , @credit_card.year + xml.tag! 'month', @credit_card.month + xml.tag! 'year', @credit_card.year end if brand = card_type(@credit_card.brand) - xml.tag! 'cardType' , brand + xml.tag! 'cardType', brand end - if @credit_card.verification_value - xml.tag! 'cvdIndicator' , '1' # Value Provided - xml.tag! 'cvd' , @credit_card.verification_value + if @credit_card.verification_value? + xml.tag! 'cvdIndicator', '1' # Value Provided + xml.tag! 'cvd', @credit_card.verification_value + else + xml.tag! 'cvdIndicator', '0' end end end @@ -285,18 +304,18 @@ def build_address(xml, addr) if addr[:name] first_name, last_name = split_names(addr[:name]) xml.tag! 'firstName', first_name - xml.tag! 'lastName' , last_name + xml.tag! 'lastName', last_name end - xml.tag! 'street' , addr[:address1] if addr[:address1].present? + xml.tag! 'street', addr[:address1] if addr[:address1].present? xml.tag! 'street2', addr[:address2] if addr[:address2].present? - xml.tag! 'city' , addr[:city] if addr[:city].present? + xml.tag! 'city', addr[:city] if addr[:city].present? if addr[:state].present? state_tag = %w(US CA).include?(addr[:country]) ? 'state' : 'region' xml.tag! state_tag, addr[:state] end - xml.tag! 'country', addr[:country] if addr[:country].present? - xml.tag! 'zip' , addr[:zip] if addr[:zip].present? - xml.tag! 'phone' , addr[:phone] if addr[:phone].present? + xml.tag! 'country', addr[:country] if addr[:country].present? + xml.tag! 'zip', addr[:zip] if addr[:zip].present? + xml.tag! 'phone', addr[:phone] if addr[:phone].present? end def card_type(key) @@ -305,8 +324,6 @@ def card_type(key) 'american_express'=> 'AM', 'discover' => 'DI', 'diners_club' => 'DC', - #'switch' => '', - 'solo' => 'SO' }[key] end diff --git a/lib/active_merchant/billing/gateways/orbital.rb b/lib/active_merchant/billing/gateways/orbital.rb index 8b67ca493f5..2514617b6da 100644 --- a/lib/active_merchant/billing/gateways/orbital.rb +++ b/lib/active_merchant/billing/gateways/orbital.rb @@ -1,5 +1,5 @@ require 'active_merchant/billing/gateways/orbital/orbital_soft_descriptors' -require "rexml/document" +require 'rexml/document' module ActiveMerchant #:nodoc: module Billing #:nodoc: @@ -30,15 +30,15 @@ module Billing #:nodoc: class OrbitalGateway < Gateway include Empty - API_VERSION = "5.6" + API_VERSION = '7.1' POST_HEADERS = { - "MIME-Version" => "1.1", - "Content-Type" => "application/PTI56", - "Content-transfer-encoding" => "text", - "Request-number" => '1', - "Document-type" => "Request", - "Interface-Version" => "Ruby|ActiveMerchant|Proprietary Gateway" + 'MIME-Version' => '1.1', + 'Content-Type' => "application/PTI#{API_VERSION.gsub(/\./, '')}", + 'Content-transfer-encoding' => 'text', + 'Request-number' => '1', + 'Document-type' => 'Request', + 'Interface-Version' => 'Ruby|ActiveMerchant|Proprietary Gateway' } SUCCESS = '0' @@ -65,14 +65,14 @@ class OrbitalGateway < Gateway class_attribute :secondary_test_url, :secondary_live_url - self.test_url = "https://orbitalvar1.paymentech.net/authorize" - self.secondary_test_url = "https://orbitalvar2.paymentech.net/authorize" + self.test_url = 'https://orbitalvar1.chasepaymentech.com/authorize' + self.secondary_test_url = 'https://orbitalvar2.chasepaymentech.com/authorize' - self.live_url = "https://orbital1.paymentech.net/authorize" - self.secondary_live_url = "https://orbital2.paymentech.net/authorize" + self.live_url = 'https://orbital1.chasepaymentech.com/authorize' + self.secondary_live_url = 'https://orbital2.chasepaymentech.com/authorize' - self.supported_countries = ["US", "CA"] - self.default_currency = "CAD" + self.supported_countries = ['US', 'CA'] + self.default_currency = 'CAD' self.supported_cardtypes = [:visa, :master, :american_express, :discover, :diners_club, :jcb] self.display_name = 'Orbital Paymentech' @@ -83,45 +83,45 @@ class OrbitalGateway < Gateway AVS_SUPPORTED_COUNTRIES = ['US', 'CA', 'UK', 'GB'] CURRENCY_CODES = { - "AUD" => '036', - "BRL" => '986', - "CAD" => '124', - "CLP" => '152', - "CZK" => '203', - "DKK" => '208', - "HKD" => '344', - "ICK" => '352', - "JPY" => '392', - "MXN" => '484', - "NZD" => '554', - "NOK" => '578', - "SGD" => '702', - "SEK" => '752', - "CHF" => '756', - "GBP" => '826', - "USD" => '840', - "EUR" => '978' + 'AUD' => '036', + 'BRL' => '986', + 'CAD' => '124', + 'CLP' => '152', + 'CZK' => '203', + 'DKK' => '208', + 'HKD' => '344', + 'ICK' => '352', + 'JPY' => '392', + 'MXN' => '484', + 'NZD' => '554', + 'NOK' => '578', + 'SGD' => '702', + 'SEK' => '752', + 'CHF' => '756', + 'GBP' => '826', + 'USD' => '840', + 'EUR' => '978' } CURRENCY_EXPONENTS = { - "AUD" => '2', - "BRL" => '2', - "CAD" => '2', - "CLP" => '2', - "CZK" => '2', - "DKK" => '2', - "HKD" => '2', - "ICK" => '2', - "JPY" => '0', - "MXN" => '2', - "NZD" => '2', - "NOK" => '2', - "SGD" => '2', - "SEK" => '2', - "CHF" => '2', - "GBP" => '2', - "USD" => '2', - "EUR" => '2' + 'AUD' => '2', + 'BRL' => '2', + 'CAD' => '2', + 'CLP' => '2', + 'CZK' => '2', + 'DKK' => '2', + 'HKD' => '2', + 'ICK' => '2', + 'JPY' => '0', + 'MXN' => '2', + 'NZD' => '2', + 'NOK' => '2', + 'SGD' => '2', + 'SEK' => '2', + 'CHF' => '2', + 'GBP' => '2', + 'USD' => '2', + 'EUR' => '2' } # INDUSTRY TYPES @@ -187,11 +187,12 @@ def initialize(options = {}) requires!(options, :merchant_id) requires!(options, :login, :password) unless options[:ip_authentication] super + @options[:merchant_id] = @options[:merchant_id].to_s end # A – Authorization request def authorize(money, creditcard, options = {}) - order = build_new_order_xml(AUTH_ONLY, money, options) do |xml| + order = build_new_order_xml(AUTH_ONLY, money, creditcard, options) do |xml| add_creditcard(xml, creditcard, options[:currency]) add_address(xml, creditcard, options) if @options[:customer_profiles] @@ -211,7 +212,7 @@ def verify(creditcard, options = {}) # AC – Authorization and Capture def purchase(money, creditcard, options = {}) - order = build_new_order_xml(AUTH_AND_CAPTURE, money, options) do |xml| + order = build_new_order_xml(AUTH_AND_CAPTURE, money, creditcard, options) do |xml| add_creditcard(xml, creditcard, options[:currency]) add_address(xml, creditcard, options) if @options[:customer_profiles] @@ -229,7 +230,7 @@ def capture(money, authorization, options = {}) # R – Refund request def refund(money, authorization, options = {}) - order = build_new_order_xml(REFUND, money, options.merge(:authorization => authorization)) do |xml| + order = build_new_order_xml(REFUND, money, nil, options.merge(:authorization => authorization)) do |xml| add_refund(xml, options[:currency]) xml.tag! :CustomerRefNum, options[:customer_ref_num] if @options[:customer_profiles] && options[:profile_txn] end @@ -243,7 +244,7 @@ def credit(money, authorization, options= {}) def void(authorization, options = {}, deprecated = {}) if(!options.kind_of?(Hash)) - ActiveMerchant.deprecated("Calling the void method with an amount parameter is deprecated and will be removed in a future version.") + ActiveMerchant.deprecated('Calling the void method with an amount parameter is deprecated and will be removed in a future version.') return void(options, deprecated.merge(:amount => authorization)) end @@ -251,7 +252,6 @@ def void(authorization, options = {}, deprecated = {}) commit(order, :void, options[:trace_number]) end - # ==== Customer Profiles # :customer_ref_num should be set unless you're happy with Orbital providing one # @@ -274,13 +274,13 @@ def void(authorization, options = {}, deprecated = {}) # 'MS' - Manual Suspend def add_customer_profile(creditcard, options = {}) - options.merge!(:customer_profile_action => CREATE) + options[:customer_profile_action] = CREATE order = build_customer_request_xml(creditcard, options) commit(order, :add_customer_profile) end def update_customer_profile(creditcard, options = {}) - options.merge!(:customer_profile_action => UPDATE) + options[:customer_profile_action] = UPDATE order = build_customer_request_xml(creditcard, options) commit(order, :update_customer_profile) end @@ -306,14 +306,16 @@ def scrub(transcript) gsub(%r(().+()), '\1[FILTERED]\2'). gsub(%r(().+()), '\1[FILTERED]\2'). gsub(%r(().+()), '\1[FILTERED]\2'). + gsub(%r(().+()), '\1[FILTERED]\2'). gsub(%r(().+()), '\1[FILTERED]\2'). - gsub(%r(().+()), '\1[FILTERED]\2') + gsub(%r(().+()), '\1[FILTERED]\2'). + gsub(%r(().+()), '\1[FILTERED]\2') end private def authorization_string(*args) - args.compact.join(";") + args.compact.join(';') end def split_authorization(authorization) @@ -345,6 +347,43 @@ def add_soft_descriptors(xml, soft_desc) xml.tag! :SDMerchantEmail, soft_desc.merchant_email if soft_desc.merchant_email end + def add_soft_descriptors_from_hash(xml, soft_desc) + xml.tag! :SDMerchantName, soft_desc[:merchant_name] || nil + xml.tag! :SDProductDescription, soft_desc[:product_description] || nil + xml.tag! :SDMerchantCity, soft_desc[:merchant_city] || nil + xml.tag! :SDMerchantPhone, soft_desc[:merchant_phone] || nil + xml.tag! :SDMerchantURL, soft_desc[:merchant_url] || nil + xml.tag! :SDMerchantEmail, soft_desc[:merchant_email] || nil + end + + def add_level_2_tax(xml, options={}) + if (level_2 = options[:level_2_data]) + xml.tag! :TaxInd, level_2[:tax_indicator] if [TAX_NOT_PROVIDED, TAX_INCLUDED, NON_TAXABLE_TRANSACTION].include?(level_2[:tax_indicator].to_i) + xml.tag! :Tax, level_2[:tax].to_i if level_2[:tax] + end + end + + def add_level_2_advice_addendum(xml, options={}) + if (level_2 = options[:level_2_data]) + xml.tag! :AMEXTranAdvAddn1, byte_limit(level_2[:advice_addendum_1], 40) if level_2[:advice_addendum_1] + xml.tag! :AMEXTranAdvAddn2, byte_limit(level_2[:advice_addendum_2], 40) if level_2[:advice_addendum_2] + xml.tag! :AMEXTranAdvAddn3, byte_limit(level_2[:advice_addendum_3], 40) if level_2[:advice_addendum_3] + xml.tag! :AMEXTranAdvAddn4, byte_limit(level_2[:advice_addendum_4], 40) if level_2[:advice_addendum_4] + end + end + + def add_level_2_purchase(xml, options={}) + if (level_2 = options[:level_2_data]) + xml.tag! :PCOrderNum, byte_limit(level_2[:purchase_order], 17) if level_2[:purchase_order] + xml.tag! :PCDestZip, byte_limit(format_address_field(level_2[:zip]), 10) if level_2[:zip] + xml.tag! :PCDestName, byte_limit(format_address_field(level_2[:name]), 30) if level_2[:name] + xml.tag! :PCDestAddress1, byte_limit(format_address_field(level_2[:address1]), 30) if level_2[:address1] + xml.tag! :PCDestAddress2, byte_limit(format_address_field(level_2[:address2]), 30) if level_2[:address2] + xml.tag! :PCDestCity, byte_limit(format_address_field(level_2[:city]), 20) if level_2[:city] + xml.tag! :PCDestState, byte_limit(format_address_field(level_2[:state]), 2) if level_2[:state] + end + end + def add_address(xml, creditcard, options) if(address = (options[:billing_address] || options[:address])) avs_supported = AVS_SUPPORTED_COUNTRIES.include?(address[:country].to_s) || empty?(address[:country]) @@ -358,8 +397,8 @@ def add_address(xml, creditcard, options) xml.tag! :AVSphoneNum, (address[:phone] ? address[:phone].scan(/\d/).join.to_s[0..13] : nil) end - xml.tag! :AVSname, ((creditcard && creditcard.name) ? creditcard.name[0..29] : nil) - xml.tag! :AVScountryCode, (avs_supported ? (byte_limit(format_address_field(address[:country]), 2)) : '') + xml.tag! :AVSname, (creditcard&.name ? creditcard.name[0..29] : nil) + xml.tag! :AVScountryCode, (avs_supported ? byte_limit(format_address_field(address[:country]), 2) : '') # Needs to come after AVScountryCode add_destination_address(xml, address) if avs_supported @@ -417,13 +456,25 @@ def add_creditcard(xml, creditcard, currency=nil) # Do not submit the attribute at all. # - http://download.chasepaymentech.com/docs/orbital/orbital_gateway_xml_specification.pdf unless creditcard.nil? - if %w( visa discover ).include?(creditcard.brand) - xml.tag! :CardSecValInd, (creditcard.verification_value? ? '1' : '9') + if creditcard.verification_value? + if %w( visa discover ).include?(creditcard.brand) + xml.tag! :CardSecValInd, '1' + end + xml.tag! :CardSecVal, creditcard.verification_value end - xml.tag! :CardSecVal, creditcard.verification_value if creditcard.verification_value? end end + def add_cdpt_eci_and_xid(xml, creditcard) + xml.tag! :AuthenticationECIInd, creditcard.eci + xml.tag! :XID, creditcard.transaction_id if creditcard.transaction_id + end + + def add_cdpt_payment_cryptogram(xml, creditcard) + xml.tag! :DPANInd, 'Y' + xml.tag! :DigitalTokenCryptogram, creditcard.payment_cryptogram + end + def add_refund(xml, currency=nil) xml.tag! :AccountNum, nil @@ -458,30 +509,32 @@ def add_managed_billing(xml, options) def parse(body) response = {} xml = REXML::Document.new(body) - root = REXML::XPath.first(xml, "//Response") || - REXML::XPath.first(xml, "//ErrorResponse") + root = REXML::XPath.first(xml, '//Response') || + REXML::XPath.first(xml, '//ErrorResponse') if root root.elements.to_a.each do |node| recurring_parse_element(response, node) end end - response.delete_if { |k,_| SENSITIVE_FIELDS.include?(k) } + response.delete_if { |k, _| SENSITIVE_FIELDS.include?(k) } end def recurring_parse_element(response, node) if node.has_elements? - node.elements.each{|e| recurring_parse_element(response, e) } + node.elements.each { |e| recurring_parse_element(response, e) } else response[node.name.underscore.to_sym] = node.text end end def commit(order, message_type, trace_number=nil) - headers = POST_HEADERS.merge("Content-length" => order.size.to_s) - headers.merge!( "Trace-number" => trace_number.to_s, - "Merchant-Id" => @options[:merchant_id] ) if @options[:retry_logic] && trace_number - request = lambda{|url| parse(ssl_post(url, order, headers))} + headers = POST_HEADERS.merge('Content-length' => order.size.to_s) + if @options[:retry_logic] && trace_number + headers['Trace-number'] = trace_number.to_s + headers['Merchant-Id'] = @options[:merchant_id] + end + request = ->(url) { parse(ssl_post(url, order, headers)) } # Failover URL will be attempted in the event of a connection error response = begin @@ -527,7 +580,7 @@ def ip_authentication? @options[:ip_authentication] == true end - def build_new_order_xml(action, money, parameters = {}) + def build_new_order_xml(action, money, creditcard, parameters = {}) requires!(parameters, :order_id) xml = xml_envelope xml.tag! :Request do @@ -550,14 +603,27 @@ def build_new_order_xml(action, money, parameters = {}) yield xml if block_given? + if creditcard.is_a?(NetworkTokenizationCreditCard) + add_cdpt_eci_and_xid(xml, creditcard) + end + xml.tag! :OrderID, format_order_id(parameters[:order_id]) xml.tag! :Amount, amount(money) xml.tag! :Comments, parameters[:comments] if parameters[:comments] + add_level_2_tax(xml, parameters) + add_level_2_advice_addendum(xml, parameters) + # CustomerAni, AVSPhoneType and AVSDestPhoneType could be added here. + if creditcard.is_a?(NetworkTokenizationCreditCard) + add_cdpt_payment_cryptogram(xml, creditcard) + end + if parameters[:soft_descriptors].is_a?(OrbitalSoftDescriptors) add_soft_descriptors(xml, parameters[:soft_descriptors]) + elsif parameters[:soft_descriptors].is_a?(Hash) + add_soft_descriptors_from_hash(xml, parameters[:soft_descriptors]) end set_recurring_ind(xml, parameters) @@ -567,6 +633,8 @@ def build_new_order_xml(action, money, parameters = {}) tx_ref_num, _ = split_authorization(parameters[:authorization]) xml.tag! :TxRefNum, tx_ref_num end + + add_level_2_purchase(xml, parameters) end end xml.target! @@ -577,7 +645,7 @@ def build_new_order_xml(action, money, parameters = {}) # RS - Subsequent Recurring Transactions def set_recurring_ind(xml, parameters) if parameters[:recurring_ind] - raise "RecurringInd must be set to either \"RF\" or \"RS\"" unless %w(RF RS).include?(parameters[:recurring_ind]) + raise 'RecurringInd must be set to either "RF" or "RS"' unless %w(RF RS).include?(parameters[:recurring_ind]) xml.tag! :RecurringInd, parameters[:recurring_ind] end end @@ -590,8 +658,11 @@ def build_mark_for_capture_xml(money, authorization, parameters = {}) add_xml_credentials(xml) xml.tag! :OrderID, format_order_id(order_id) xml.tag! :Amount, amount(money) + add_level_2_tax(xml, parameters) add_bin_merchant_and_terminal(xml, parameters) xml.tag! :TxRefNum, tx_ref_num + add_level_2_purchase(xml, parameters) + add_level_2_advice_addendum(xml, parameters) end end xml.target! @@ -676,7 +747,7 @@ def format_address_field(value) # Field lengths should be limited by byte count instead of character count # Returns the truncated value or nil def byte_limit(value, byte_length) - limited_value = "" + limited_value = '' value.to_s.each_char do |c| break if((limited_value.bytesize + c.bytesize) > byte_length) @@ -687,7 +758,7 @@ def byte_limit(value, byte_length) end def build_customer_request_xml(creditcard, options = {}) - ActiveMerchant.deprecated "Customer Profile support in Orbital is non-conformant to the ActiveMerchant API and will be removed in its current form in a future version. Please contact the ActiveMerchant maintainers if you have an interest in modifying it to conform to the store/unstore/update API." + ActiveMerchant.deprecated 'Customer Profile support in Orbital is non-conformant to the ActiveMerchant API and will be removed in its current form in a future version. Please contact the ActiveMerchant maintainers if you have an interest in modifying it to conform to the store/unstore/update API.' xml = xml_envelope xml.tag! :Request do xml.tag! :Profile do @@ -724,7 +795,7 @@ def build_customer_request_xml(creditcard, options = {}) end xml.tag! :CCAccountNum, creditcard.number if creditcard - xml.tag! :CCExpireDate, creditcard.expiry_date.expiration.strftime("%m%y") if creditcard + xml.tag! :CCExpireDate, creditcard.expiry_date.expiration.strftime('%m%y') if creditcard # This has to come after CCExpireDate. add_managed_billing(xml, options) diff --git a/lib/active_merchant/billing/gateways/orbital/orbital_soft_descriptors.rb b/lib/active_merchant/billing/gateways/orbital/orbital_soft_descriptors.rb index 44eceace7e2..da1d82d0ca0 100644 --- a/lib/active_merchant/billing/gateways/orbital/orbital_soft_descriptors.rb +++ b/lib/active_merchant/billing/gateways/orbital/orbital_soft_descriptors.rb @@ -27,16 +27,16 @@ def initialize(options = {}) def validate errors = [] - errors << [:merchant_name, "is required"] if self.merchant_name.blank? - errors << [:merchant_name, "is required to be 25 bytes or less"] if self.merchant_name.bytesize > 25 + errors << [:merchant_name, 'is required'] if self.merchant_name.blank? + errors << [:merchant_name, 'is required to be 25 bytes or less'] if self.merchant_name.bytesize > 25 if(!empty?(self.merchant_phone) && !self.merchant_phone.match(PHONE_FORMAT_1) && !self.merchant_phone.match(PHONE_FORMAT_2)) - errors << [:merchant_phone, "is required to follow \"NNN-NNN-NNNN\" or \"NNN-AAAAAAA\" format"] + errors << [:merchant_phone, 'is required to follow "NNN-NNN-NNNN" or "NNN-AAAAAAA" format'] end [:merchant_email, :merchant_url].each do |attr| unless self.send(attr).blank? - errors << [attr, "is required to be 13 bytes or less"] if(self.send(attr).bytesize > 13) + errors << [attr, 'is required to be 13 bytes or less'] if(self.send(attr).bytesize > 13) end end diff --git a/lib/active_merchant/billing/gateways/pac_net_raven.rb b/lib/active_merchant/billing/gateways/pac_net_raven.rb index ad400d48c25..952684b1943 100644 --- a/lib/active_merchant/billing/gateways/pac_net_raven.rb +++ b/lib/active_merchant/billing/gateways/pac_net_raven.rb @@ -107,7 +107,7 @@ def add_address(post, options) end def parse(body) - Hash[body.split('&').map{|x| x.split('=').map{|y| CGI.unescape(y)}}] + Hash[body.split('&').map { |x| x.split('=').map { |y| CGI.unescape(y) } }] end def commit(action, money, parameters) @@ -159,11 +159,11 @@ def message_from(response) return response['Message'] if response['Message'] if response['Status'] == 'Approved' - "This transaction has been approved" + 'This transaction has been approved' elsif response['Status'] == 'Declined' - "This transaction has been declined" + 'This transaction has been declined' elsif response['Status'] == 'Voided' - "This transaction has been voided" + 'This transaction has been voided' else response['Status'] end @@ -179,12 +179,12 @@ def post_data(action, parameters = {}) post['RequestID'] = request_id post['Signature'] = signature(action, post, parameters) - request = post.merge(parameters).collect { |key, value| "#{key}=#{CGI.escape(value.to_s)}" }.join("&") + request = post.merge(parameters).collect { |key, value| "#{key}=#{CGI.escape(value.to_s)}" }.join('&') request end def timestamp - Time.now.strftime("%Y-%m-%dT%H:%M:%S.Z") + Time.now.strftime('%Y-%m-%dT%H:%M:%S.Z') end def request_id @@ -193,15 +193,14 @@ def request_id def signature(action, post, parameters = {}) string = if %w(cc_settle cc_debit cc_preauth cc_refund).include?(action) - post['UserName'] + post['Timestamp'] + post['RequestID'] + post['PymtType'] + parameters['Amount'].to_s + parameters['Currency'] - elsif action == 'void' - post['UserName'] + post['Timestamp'] + post['RequestID'] + parameters['TrackingNumber'] - else - post['UserName'] + post['UserName'] + post['Timestamp'] + post['RequestID'] + post['PymtType'] + parameters['Amount'].to_s + parameters['Currency'] + elsif action == 'void' + post['UserName'] + post['Timestamp'] + post['RequestID'] + parameters['TrackingNumber'] + else + post['UserName'] end OpenSSL::HMAC.hexdigest(OpenSSL::Digest::SHA1.new(@options[:secret]), @options[:secret], string) end end end end - diff --git a/lib/active_merchant/billing/gateways/pagarme.rb b/lib/active_merchant/billing/gateways/pagarme.rb index 449a440990d..26545c7c2d3 100644 --- a/lib/active_merchant/billing/gateways/pagarme.rb +++ b/lib/active_merchant/billing/gateways/pagarme.rb @@ -132,18 +132,18 @@ def post_data(params) end post_data(h) elsif value.is_a?(Array) - value.map { |v| "#{key}[]=#{CGI.escape(v.to_s)}" }.join("&") + value.map { |v| "#{key}[]=#{CGI.escape(v.to_s)}" }.join('&') else "#{key}=#{CGI.escape(value.to_s)}" end - end.compact.join("&") + end.compact.join('&') end def headers(options = {}) { - "Authorization" => "Basic " + Base64.encode64(@api_key.to_s + ":x").strip, - "User-Agent" => "Pagar.me/1 ActiveMerchant/#{ActiveMerchant::VERSION}", - "Accept-Encoding" => "deflate" + 'Authorization' => 'Basic ' + Base64.encode64(@api_key.to_s + ':x').strip, + 'User-Agent' => "Pagar.me/1 ActiveMerchant/#{ActiveMerchant::VERSION}", + 'Accept-Encoding' => 'deflate' } end @@ -175,72 +175,70 @@ def commit(method, url, parameters, options = {}) end def response_error(raw_response) - begin - parse(raw_response) - rescue JSON::ParserError - json_error(raw_response) - end + parse(raw_response) + rescue JSON::ParserError + json_error(raw_response) end def json_error(raw_response) - msg = 'Resposta inválida retornada pela API do Pagar.me. Por favor entre em contato com suporte@pagar.me se você continuar recebendo essa mensagem.' + msg = 'Resposta inválida retornada pela API do Pagar.me. Por favor entre em contato com suporte@pagar.me se você continuar recebendo essa mensagem.' msg += " (A resposta retornada pela API foi #{raw_response.inspect})" { - "errors" => [{ - "message" => msg + 'errors' => [{ + 'message' => msg }] } end def success_from(response) - success_purchase = response.key?("status") && response["status"] == "paid" - success_authorize = response.key?("status") && response["status"] == "authorized" - success_refund = response.key?("status") && response["status"] == "refunded" + success_purchase = response.key?('status') && response['status'] == 'paid' + success_authorize = response.key?('status') && response['status'] == 'authorized' + success_refund = response.key?('status') && response['status'] == 'refunded' success_purchase || success_authorize || success_refund end def failure_from(response) - response.key?("status") && response["status"] == "refused" + response.key?('status') && response['status'] == 'refused' end def message_from(response) if success_from(response) - case response["status"] - when "paid" - "Transação aprovada" - when "authorized" - "Transação autorizada" - when "refunded" - "Transação estornada" + case response['status'] + when 'paid' + 'Transação aprovada' + when 'authorized' + 'Transação autorizada' + when 'refunded' + 'Transação estornada' else "Transação com status '#{response["status"]}'" end elsif failure_from(response) - "Transação recusada" - elsif response.key?("errors") - response["errors"][0]["message"] + 'Transação recusada' + elsif response.key?('errors') + response['errors'][0]['message'] else msg = json_error(response) - msg["errors"][0]["message"] + msg['errors'][0]['message'] end end def authorization_from(response) if success_from(response) - response["id"] + response['id'] end end - def test?() - @api_key.start_with?("ak_test") + def test? + @api_key.start_with?('ak_test') end def error_code_from(response) if failure_from(response) - STANDARD_ERROR_CODE_MAPPING["refused"] - elsif response.key?("errors") - STANDARD_ERROR_CODE_MAPPING["processing_error"] + STANDARD_ERROR_CODE_MAPPING['refused'] + elsif response.key?('errors') + STANDARD_ERROR_CODE_MAPPING['processing_error'] end end end diff --git a/lib/active_merchant/billing/gateways/pago_facil.rb b/lib/active_merchant/billing/gateways/pago_facil.rb index 49d2bf72c12..85793fbb369 100644 --- a/lib/active_merchant/billing/gateways/pago_facil.rb +++ b/lib/active_merchant/billing/gateways/pago_facil.rb @@ -63,7 +63,7 @@ def add_payment(post, credit_card) post[:apellidos] = credit_card.last_name post[:numeroTarjeta] = credit_card.number post[:cvt] = credit_card.verification_value - post[:mesExpiracion] = sprintf("%02d", credit_card.month) + post[:mesExpiracion] = sprintf('%02d', credit_card.month) post[:anyoExpiracion] = credit_card.year.to_s.slice(-2, 2) end @@ -74,7 +74,7 @@ def add_merchant_data(post) end def parse(body) - JSON.parse(body)["WebServices_Transacciones"]["transaccion"] + JSON.parse(body)['WebServices_Transacciones']['transaccion'] rescue JSON::ParserError json_error(body) end @@ -92,16 +92,16 @@ def commit(parameters) end def success_from(response) - response["autorizado"] == "1" || - response["autorizado"] == true + response['autorizado'] == '1' || + response['autorizado'] == true end def message_from(response) - response["texto"] + response['texto'] end def authorization_from(response) - response["autorizacion"] + response['autorizacion'] end def post_data(parameters = {}) @@ -113,8 +113,8 @@ def post_data(parameters = {}) def json_error(response) { - "texto" => 'Invalid response received from the PagoFacil API.', - "raw_response" => response + 'texto' => 'Invalid response received from the PagoFacil API.', + 'raw_response' => response } end end diff --git a/lib/active_merchant/billing/gateways/pay_conex.rb b/lib/active_merchant/billing/gateways/pay_conex.rb index 0161ca0ac3f..d0ae08146e8 100644 --- a/lib/active_merchant/billing/gateways/pay_conex.rb +++ b/lib/active_merchant/billing/gateways/pay_conex.rb @@ -3,15 +3,15 @@ module Billing #:nodoc: class PayConexGateway < Gateway include Empty - self.test_url = "https://cert.payconex.net/api/qsapi/3.8/" - self.live_url = "https://secure.payconex.net/api/qsapi/3.8/" + self.test_url = 'https://cert.payconex.net/api/qsapi/3.8/' + self.live_url = 'https://secure.payconex.net/api/qsapi/3.8/' self.supported_countries = %w(US CA) - self.default_currency = "USD" + self.default_currency = 'USD' self.supported_cardtypes = [:visa, :master, :american_express, :discover, :jcb, :diners_club] - self.homepage_url = "http://www.bluefincommerce.com/" - self.display_name = "PayConex" + self.homepage_url = 'http://www.bluefincommerce.com/' + self.display_name = 'PayConex' def initialize(options={}) requires!(options, :account_id, :api_accesskey) @@ -21,43 +21,43 @@ def initialize(options={}) def purchase(money, payment_method, options={}) post = {} add_auth_purchase_params(post, money, payment_method, options) - commit("SALE", post) + commit('SALE', post) end def authorize(money, payment_method, options={}) post = {} add_auth_purchase_params(post, money, payment_method, options) - commit("AUTHORIZATION", post) + commit('AUTHORIZATION', post) end def capture(money, authorization, options={}) post = {} add_reference_params(post, authorization, options) add_amount(post, money, options) - commit("CAPTURE", post) + commit('CAPTURE', post) end def refund(money, authorization, options={}) post = {} add_reference_params(post, authorization, options) add_amount(post, money, options) - commit("REFUND", post) + commit('REFUND', post) end def void(authorization, options = {}) post = {} add_reference_params(post, authorization, options) - commit("REVERSAL", post) + commit('REVERSAL', post) end def credit(money, payment_method, options={}) if payment_method.is_a?(String) - raise ArgumentError, "Reference credits are not supported. Please supply the original credit card or use the #refund method." + raise ArgumentError, 'Reference credits are not supported. Please supply the original credit card or use the #refund method.' end post = {} add_auth_purchase_params(post, money, payment_method, options) - commit("CREDIT", post) + commit('CREDIT', post) end def verify(payment_method, options={}) @@ -70,7 +70,7 @@ def store(payment_method, options={}) add_payment_method(post, payment_method) add_address(post, options) add_common_options(post, options) - commit("STORE", post) + commit('STORE', post) end def supports_scrubbing? @@ -88,8 +88,8 @@ def scrub(transcript) def force_utf8(string) return nil unless string - binary = string.encode("BINARY", invalid: :replace, undef: :replace, replace: "?") # Needed for Ruby 2.0 since #encode is a no-op if the string is already UTF-8. It's not needed for Ruby 2.1 and up since it's not a no-op there. - binary.encode("UTF-8", invalid: :replace, undef: :replace, replace: "?") + binary = string.encode('BINARY', invalid: :replace, undef: :replace, replace: '?') # Needed for Ruby 2.0 since #encode is a no-op if the string is already UTF-8. It's not needed for Ruby 2.1 and up since it's not a no-op there. + binary.encode('UTF-8', invalid: :replace, undef: :replace, replace: '?') end def add_credentials(post) @@ -134,7 +134,7 @@ def add_payment_method(post, payment_method) end def add_credit_card(post, payment_method) - post[:tender_type] = "CARD" + post[:tender_type] = 'CARD' post[:card_number] = payment_method.number post[:card_expiration] = expdate(payment_method) post[:card_verification] = payment_method.verification_value @@ -143,18 +143,18 @@ def add_credit_card(post, payment_method) end def add_token_payment_method(post, payment_method) - post[:tender_type] = "CARD" + post[:tender_type] = 'CARD' post[:token_id] = payment_method post[:reissue] = true end def add_card_present_payment_method(post, payment_method) - post[:tender_type] = "CARD" + post[:tender_type] = 'CARD' post[:card_tracks] = payment_method.track_data end def add_check(post, payment_method) - post[:tender_type] = "ACH" + post[:tender_type] = 'ACH' post[:first_name] = payment_method.first_name post[:last_name] = payment_method.last_name post[:bank_account_number] = payment_method.account_number @@ -208,12 +208,11 @@ def commit(action, params) success_from(response), message_from(response), response, - authorization: response["transaction_id"], - :avs_result => AVSResult.new(code: response["avs_response"]), - :cvv_result => CVVResult.new(response["cvv2_response"]), + authorization: response['transaction_id'], + :avs_result => AVSResult.new(code: response['avs_response']), + :cvv_result => CVVResult.new(response['cvv2_response']), test: test? ) - rescue JSON::ParserError unparsable_response(raw_response) end @@ -223,20 +222,20 @@ def url end def success_from(response) - response["transaction_approved"] || !response["error"] + response['transaction_approved'] || !response['error'] end def message_from(response) - success_from(response) ? response["authorization_message"] : response["error_message"] + success_from(response) ? response['authorization_message'] : response['error_message'] end def post_data(action, params) params[:transaction_type] = action - params.map {|k, v| "#{k}=#{CGI.escape(v.to_s)}"}.join('&') + params.map { |k, v| "#{k}=#{CGI.escape(v.to_s)}" }.join('&') end def unparsable_response(raw_response) - message = "Invalid JSON response received from PayConex. Please contact PayConex if you continue to receive this message." + message = 'Invalid JSON response received from PayConex. Please contact PayConex if you continue to receive this message.' message += " (The raw response returned by the API was #{raw_response.inspect})" return Response.new(false, message) end diff --git a/lib/active_merchant/billing/gateways/pay_gate_xml.rb b/lib/active_merchant/billing/gateways/pay_gate_xml.rb index 86947816811..35261aaf564 100644 --- a/lib/active_merchant/billing/gateways/pay_gate_xml.rb +++ b/lib/active_merchant/billing/gateways/pay_gate_xml.rb @@ -102,45 +102,45 @@ class PayGateXmlGateway < Gateway DECLINE_CODES = { # Credit Card Errors - These RESULT_CODEs are returned if the transaction cannot be authorized due to a problem with the card. The TRANSACTION_STATUS will be 2 - 900001 => "Call for Approval", - 900002 => "Card Expired", - 900003 => "Insufficient Funds", - 900004 => "Invalid Card Number", - 900005 => "Bank Interface Timeout", # indicates a communications failure between the banks systems - 900006 => "Invalid Card", - 900007 => "Declined", - 900009 => "Lost Card", - 900010 => "Invalid Card Length", - 900011 => "Suspected Fraud", - 900012 => "Card Reported As Stolen", - 900013 => "Restricted Card", - 900014 => "Excessive Card Usage", - 900015 => "Card Blacklisted", - - 900207 => "Declined; authentication failed", # indicates the cardholder did not enter their MasterCard SecureCode / Verified by Visa password correctly - - 990020 => "Auth Declined", - - 991001 => "Invalid expiry date", - 991002 => "Invalid amount", + 900001 => 'Call for Approval', + 900002 => 'Card Expired', + 900003 => 'Insufficient Funds', + 900004 => 'Invalid Card Number', + 900005 => 'Bank Interface Timeout', # indicates a communications failure between the banks systems + 900006 => 'Invalid Card', + 900007 => 'Declined', + 900009 => 'Lost Card', + 900010 => 'Invalid Card Length', + 900011 => 'Suspected Fraud', + 900012 => 'Card Reported As Stolen', + 900013 => 'Restricted Card', + 900014 => 'Excessive Card Usage', + 900015 => 'Card Blacklisted', + + 900207 => 'Declined; authentication failed', # indicates the cardholder did not enter their MasterCard SecureCode / Verified by Visa password correctly + + 990020 => 'Auth Declined', + + 991001 => 'Invalid expiry date', + 991002 => 'Invalid amount', # Communication Errors - These RESULT_CODEs are returned if the transaction cannot be completed due to an unexpected error. TRANSACTION_STATUS will be 0. - 900205 => "Unexpected authentication result (phase 1)", - 900206 => "Unexpected authentication result (phase 1)", + 900205 => 'Unexpected authentication result (phase 1)', + 900206 => 'Unexpected authentication result (phase 1)', - 990001 => "Could not insert into Database", + 990001 => 'Could not insert into Database', - 990022 => "Bank not available", + 990022 => 'Bank not available', - 990053 => "Error processing transaction", + 990053 => 'Error processing transaction', # Miscellaneous - Unless otherwise noted, the TRANSACTION_STATUS will be 0. - 900209 => "Transaction verification failed (phase 2)", # Indicates the verification data returned from MasterCard SecureCode / Verified by Visa has been altered - 900210 => "Authentication complete; transaction must be restarted", # Indicates that the MasterCard SecuerCode / Verified by Visa transaction has already been completed. Most likely caused by the customer clicking the refresh button + 900209 => 'Transaction verification failed (phase 2)', # Indicates the verification data returned from MasterCard SecureCode / Verified by Visa has been altered + 900210 => 'Authentication complete; transaction must be restarted', # Indicates that the MasterCard SecuerCode / Verified by Visa transaction has already been completed. Most likely caused by the customer clicking the refresh button - 990024 => "Duplicate Transaction Detected. Please check before submitting", + 990024 => 'Duplicate Transaction Detected. Please check before submitting', - 990028 => "Transaction cancelled" # Customer clicks the 'Cancel' button on the payment page + 990028 => 'Transaction cancelled' # Customer clicks the 'Cancel' button on the payment page } SUCCESS_CODES = %w( 990004 990005 990017 990012 990018 990031 ) @@ -162,29 +162,32 @@ def initialize(options = {}) def purchase(money, creditcard, options = {}) MultiResponse.run do |r| - r.process{authorize(money, creditcard, options)} - r.process{capture(money, r.authorization, options)} + r.process { authorize(money, creditcard, options) } + r.process { capture(money, r.authorization, options) } end end def authorize(money, creditcard, options = {}) action = 'authtx' - options.merge!(:money => money, :creditcard => creditcard) + options[:money] = money + options[:creditcard] = creditcard commit(action, build_request(action, options)) end def capture(money, authorization, options = {}) action = 'settletx' - options.merge!(:money => money, :authorization => authorization) + options[:money] = money + options[:authorization] = authorization commit(action, build_request(action, options), authorization) end def refund(money, authorization, options={}) action = 'refundtx' - options.merge!(:money => money, :authorization => authorization) + options[:money] = money + options[:authorization] = authorization commit(action, build_request(action, options)) end @@ -210,7 +213,7 @@ def build_request(action, options={}) when 'refundtx' build_refund(protocol, money, authorization, options) else - raise "no action specified for build_request" + raise 'no action specified for build_request' end end @@ -265,7 +268,7 @@ def commit(action, request, authorization = nil) response = parse(action, ssl_post(self.live_url, request)) Response.new(successful?(response), message_from(response), response, :test => test?, - :authorization => authorization ? authorization : response[:tid] + :authorization => authorization || response[:tid] ) end @@ -274,4 +277,4 @@ def message_from(response) end end end -end \ No newline at end of file +end diff --git a/lib/active_merchant/billing/gateways/pay_hub.rb b/lib/active_merchant/billing/gateways/pay_hub.rb index fede5ca5c92..fdcc6c5d600 100644 --- a/lib/active_merchant/billing/gateways/pay_hub.rb +++ b/lib/active_merchant/billing/gateways/pay_hub.rb @@ -19,32 +19,32 @@ class PayHubGateway < Gateway } AVS_CODE_TRANSLATOR = { - '0' => "Approved, Address verification was not requested.", - 'A' => "Approved, Address matches only.", - 'B' => "Address Match. Street Address math for international transaction Postal Code not verified because of incompatible formats (Acquirer sent both street address and Postal Code)", - 'C' => "Serv Unavailable. Street address and Postal Code not verified for international transaction because of incompatible formats (Acquirer sent both street and Postal Code).", - 'D' => "Exact Match, Street Address and Postal Code match for international transaction.", - 'F' => "Exact Match, Street Address and Postal Code match. Applies to UK only.", - 'G' => "Ver Unavailable, Non-U.S. Issuer does not participate.", - 'I' => "Ver Unavailable, Address information not verified for international transaction", - 'M' => "Exact Match, Street Address and Postal Code match for international transaction", - 'N' => "No - Address and ZIP Code does not match", - 'P' => "Zip Match, Postal Codes match for international transaction Street address not verified because of incompatible formats (Acquirer sent both street address and Postal Code).", - 'R' => "Retry - Issuer system unavailable", - 'S' => "Serv Unavailable, Service not supported", - 'U' => "Ver Unavailable, Address unavailable.", - 'W' => "ZIP match - Nine character numeric ZIP match only.", - 'X' => "Exact match, Address and nine-character ZIP match.", - 'Y' => "Exact Match, Address and five character ZIP match.", - 'Z' => "Zip Match, Five character numeric ZIP match only.", - '1' => "Cardholder name and ZIP match AMEX only.", - '2' => "Cardholder name, address, and ZIP match AMEX only.", - '3' => "Cardholder name and address match AMEX only.", - '4' => "Cardholder name match AMEX only.", - '5' => "Cardholder name incorrect, ZIP match AMEX only.", - '6' => "Cardholder name incorrect, address and ZIP match AMEX only.", - '7' => "Cardholder name incorrect, address match AMEX only.", - '8' => "Cardholder, all do not match AMEX only." + '0' => 'Approved, Address verification was not requested.', + 'A' => 'Approved, Address matches only.', + 'B' => 'Address Match. Street Address math for international transaction Postal Code not verified because of incompatible formats (Acquirer sent both street address and Postal Code)', + 'C' => 'Serv Unavailable. Street address and Postal Code not verified for international transaction because of incompatible formats (Acquirer sent both street and Postal Code).', + 'D' => 'Exact Match, Street Address and Postal Code match for international transaction.', + 'F' => 'Exact Match, Street Address and Postal Code match. Applies to UK only.', + 'G' => 'Ver Unavailable, Non-U.S. Issuer does not participate.', + 'I' => 'Ver Unavailable, Address information not verified for international transaction', + 'M' => 'Exact Match, Street Address and Postal Code match for international transaction', + 'N' => 'No - Address and ZIP Code does not match', + 'P' => 'Zip Match, Postal Codes match for international transaction Street address not verified because of incompatible formats (Acquirer sent both street address and Postal Code).', + 'R' => 'Retry - Issuer system unavailable', + 'S' => 'Serv Unavailable, Service not supported', + 'U' => 'Ver Unavailable, Address unavailable.', + 'W' => 'ZIP match - Nine character numeric ZIP match only.', + 'X' => 'Exact match, Address and nine-character ZIP match.', + 'Y' => 'Exact Match, Address and five character ZIP match.', + 'Z' => 'Zip Match, Five character numeric ZIP match only.', + '1' => 'Cardholder name and ZIP match AMEX only.', + '2' => 'Cardholder name, address, and ZIP match AMEX only.', + '3' => 'Cardholder name and address match AMEX only.', + '4' => 'Cardholder name match AMEX only.', + '5' => 'Cardholder name incorrect, ZIP match AMEX only.', + '6' => 'Cardholder name incorrect, address and ZIP match AMEX only.', + '7' => 'Cardholder name incorrect, address match AMEX only.', + '8' => 'Cardholder, all do not match AMEX only.' } STANDARD_ERROR_CODE_MAPPING = { @@ -171,9 +171,9 @@ def commit(post) success = false begin - raw_response = ssl_post(live_url, post.to_json, {'Content-Type' => 'application/json'} ) + raw_response = ssl_post(live_url, post.to_json, {'Content-Type' => 'application/json'}) response = parse(raw_response) - success = (response['RESPONSE_CODE'] == "00") + success = (response['RESPONSE_CODE'] == '00') rescue ResponseError => e raw_response = e.response.body response = response_error(raw_response) @@ -200,13 +200,13 @@ def response_error(raw_response) def json_error(raw_response) { - error_message: 'Invalid response received from the Payhub API. Please contact wecare@payhub.com if you continue to receive this message.' + - ' (The raw response returned by the API was #{raw_response.inspect})' + error_message: 'Invalid response received from the Payhub API. Please contact wecare@payhub.com if you continue to receive this message.' \ + " (The raw response returned by the API was #{raw_response.inspect})" } end def response_message(response) - (response['RESPONSE_TEXT'] || response["RESPONSE_CODE"] || response[:error_message]) + (response['RESPONSE_TEXT'] || response['RESPONSE_CODE'] || response[:error_message]) end end end diff --git a/lib/active_merchant/billing/gateways/pay_junction.rb b/lib/active_merchant/billing/gateways/pay_junction.rb index 57a3f7356bd..68a24d6f8fc 100644 --- a/lib/active_merchant/billing/gateways/pay_junction.rb +++ b/lib/active_merchant/billing/gateways/pay_junction.rb @@ -101,19 +101,19 @@ class PayJunctionGateway < Gateway class_attribute :test_url, :live_url - self.test_url = "https://www.payjunctionlabs.com/quick_link" - self.live_url = "https://payjunction.com/quick_link" + self.test_url = 'https://www.payjunctionlabs.com/quick_link' + self.live_url = 'https://payjunction.com/quick_link' TEST_LOGIN = 'pj-ql-01' TEST_PASSWORD = 'pj-ql-01p' - SUCCESS_CODES = ["00", "85"] + SUCCESS_CODES = ['00', '85'] SUCCESS_MESSAGE = 'The transaction was approved.' FAILURE_MESSAGE = 'The transaction was declined.' DECLINE_CODES = { - "AE" => 'Address verification failed because address did not match.', + 'AE' => 'Address verification failed because address did not match.', 'ZE' => 'Address verification failed because zip did not match.', 'XE' => 'Address verification failed because zip and address did not match.', 'YE' => 'Address verification failed because zip and address did not match.', @@ -144,8 +144,8 @@ class PayJunctionGateway < Gateway '96' => 'Declined because of a system error.', 'N7' => 'Declined because of a CVV2/CVC2 mismatch.', 'M4' => 'Declined.', - "FE" => "There was a format error with your Trinity Gateway Service (API) request.", - "LE" => "Could not log you in (problem with dc_logon and/or dc_password).", + 'FE' => 'There was a format error with your Trinity Gateway Service (API) request.', + 'LE' => 'Could not log you in (problem with dc_logon and/or dc_password).', 'NL' => 'Aborted because of a system error, please try again later. ', 'AB' => 'Aborted because of an upstream system error, please try again later.' } @@ -334,7 +334,7 @@ def add_optional_fields(params, options) def commit(action, parameters) url = test? ? self.test_url : self.live_url - response = parse( ssl_post(url, post_data(action, parameters)) ) + response = parse(ssl_post(url, post_data(action, parameters))) Response.new(successful?(response), message_from(response), response, :test => test?, @@ -366,7 +366,7 @@ def post_data(action, params) params[:version] = API_VERSION params[:transaction_type] = action - params.reject{|k,v| v.blank?}.collect{ |k, v| "dc_#{k.to_s}=#{CGI.escape(v.to_s)}" }.join("&") + params.reject { |k, v| v.blank? }.collect { |k, v| "dc_#{k}=#{CGI.escape(v.to_s)}" }.join('&') end def parse(body) diff --git a/lib/active_merchant/billing/gateways/pay_junction_v2.rb b/lib/active_merchant/billing/gateways/pay_junction_v2.rb index f93aea23655..aed266facd6 100644 --- a/lib/active_merchant/billing/gateways/pay_junction_v2.rb +++ b/lib/active_merchant/billing/gateways/pay_junction_v2.rb @@ -1,14 +1,14 @@ module ActiveMerchant #:nodoc: module Billing #:nodoc: class PayJunctionV2Gateway < Gateway - self.display_name = "PayJunction" - self.homepage_url = "https://www.payjunction.com/" + self.display_name = 'PayJunction' + self.homepage_url = 'https://www.payjunction.com/' - self.test_url = "https://api.payjunctionlabs.com/transactions" - self.live_url = "https://api.payjunction.com/transactions" + self.test_url = 'https://api.payjunctionlabs.com/transactions' + self.live_url = 'https://api.payjunction.com/transactions' - self.supported_countries = ["US"] - self.default_currency = "USD" + self.supported_countries = ['US'] + self.default_currency = 'USD' self.money_format = :dollars self.supported_cardtypes = [:visa, :master, :american_express, :discover] @@ -22,51 +22,51 @@ def purchase(amount, payment_method, options={}) add_invoice(post, amount, options) add_payment_method(post, payment_method) - commit("purchase", post) + commit('purchase', post) end def authorize(amount, payment_method, options={}) post = {} - post[:status] = "HOLD" + post[:status] = 'HOLD' add_invoice(post, amount, options) add_payment_method(post, payment_method) - commit("authorize", post) + commit('authorize', post) end def capture(amount, authorization, options={}) post = {} - post[:status] = "CAPTURE" + post[:status] = 'CAPTURE' post[:transactionId] = authorization add_invoice(post, amount, options) - commit("capture", post) + commit('capture', post) end def void(authorization, options={}) post = {} - post[:status] = "VOID" + post[:status] = 'VOID' post[:transactionId] = authorization - commit("void", post) + commit('void', post) end def refund(amount, authorization, options={}) post = {} - post[:action] = "REFUND" + post[:action] = 'REFUND' post[:transactionId] = authorization add_invoice(post, amount, options) - commit("refund", post) + commit('refund', post) end def credit(amount, payment_method, options={}) post = {} - post[:action] = "REFUND" + post[:action] = 'REFUND' add_invoice(post, amount, options) add_payment_method(post, payment_method) - commit("credit", post) + commit('credit', post) end def verify(credit_card, options={}) @@ -129,7 +129,7 @@ def commit(action, params) end def ssl_invoke(action, params) - if ["purchase", "authorize", "refund", "credit"].include?(action) + if ['purchase', 'authorize', 'refund', 'credit'].include?(action) ssl_post(url(), post_data(params), headers) else ssl_request(:put, url(params), post_data(params), headers) @@ -138,15 +138,15 @@ def ssl_invoke(action, params) def headers { - "Authorization" => "Basic " + Base64.encode64("#{@options[:api_login]}:#{@options[:api_password]}").strip, - "Content-Type" => "application/x-www-form-urlencoded;charset=UTF-8", - "Accept" => "application/json", - "X-PJ-Application-Key" => "#{@options[:api_key]}" + 'Authorization' => 'Basic ' + Base64.encode64("#{@options[:api_login]}:#{@options[:api_password]}").strip, + 'Content-Type' => 'application/x-www-form-urlencoded;charset=UTF-8', + 'Accept' => 'application/json', + 'X-PJ-Application-Key' => @options[:api_key].to_s } end def post_data(params) - params.map {|k, v| "#{k}=#{CGI.escape(v.to_s)}"}.join('&') + params.map { |k, v| "#{k}=#{CGI.escape(v.to_s)}" }.join('&') end def url(params={}) @@ -154,36 +154,34 @@ def url(params={}) end def parse(body) - begin - JSON.parse(body) - rescue JSON::ParserError - message = "Invalid JSON response received from PayJunctionV2Gateway. Please contact PayJunctionV2Gateway if you continue to receive this message." - message += " (The raw response returned by the API was #{body.inspect})" - { - "errors" => [{ - "message" => message - }] - } - end + JSON.parse(body) + rescue JSON::ParserError + message = 'Invalid JSON response received from PayJunctionV2Gateway. Please contact PayJunctionV2Gateway if you continue to receive this message.' + message += " (The raw response returned by the API was #{body.inspect})" + { + 'errors' => [{ + 'message' => message + }] + } end def success_from(response) - return response["response"]["approved"] if response["response"] + return response['response']['approved'] if response['response'] false end def message_from(response) - return response["response"]["message"] if response["response"] + return response['response']['message'] if response['response'] - response["errors"].inject(""){ |message,error| error["message"] + "|" + message } if response["errors"] + response['errors']&.inject('') { |message, error| error['message'] + '|' + message } end def authorization_from(response) - response["transactionId"] + response['transactionId'] end def error_from(response) - response["response"]["code"] if response["response"] + response['response']['code'] if response['response'] end end end diff --git a/lib/active_merchant/billing/gateways/pay_secure.rb b/lib/active_merchant/billing/gateways/pay_secure.rb index 0faeaef2cf5..76c13578379 100644 --- a/lib/active_merchant/billing/gateways/pay_secure.rb +++ b/lib/active_merchant/billing/gateways/pay_secure.rb @@ -39,9 +39,10 @@ def purchase(money, credit_card, options = {}) end private + # Used for capturing, which is currently not supported. def add_reference(post, identification) - auth, trans_id = identification.split(";") + auth, trans_id = identification.split(';') post[:authnum] = auth post[:transid] = trans_id end @@ -51,7 +52,7 @@ def add_amount(post, money) end def add_invoice(post, options) - post[:merchant_transid] = options[:order_id].to_s.slice(0,21) + post[:merchant_transid] = options[:order_id].to_s.slice(0, 21) post[:memnum] = options[:invoice] post[:custnum] = options[:customer] post[:clientdata] = options[:description] @@ -65,13 +66,12 @@ def add_credit_card(post, credit_card) end def commit(action, money, parameters) - response = parse( ssl_post(self.live_url, post_data(action, parameters)) ) + response = parse(ssl_post(self.live_url, post_data(action, parameters))) Response.new(successful?(response), message_from(response), response, :test => test_response?(response), :authorization => authorization_from(response) ) - end def successful?(response) @@ -79,7 +79,7 @@ def successful?(response) end def authorization_from(response) - [ response[:authnum], response[:transid] ].compact.join(";") + [ response[:authnum], response[:transid] ].compact.join(';') end def test_response?(response) @@ -93,7 +93,7 @@ def message_from(response) def parse(body) response = {} body.to_s.each_line do |l| - key, value = l.split(":", 2) + key, value = l.split(':', 2) response[key.to_s.downcase.to_sym] = value.strip end response @@ -104,9 +104,8 @@ def post_data(action, parameters = {}) parameters[:merchant_id] = @options[:login] parameters[:password] = @options[:password] - parameters.reject{|k,v| v.blank?}.collect { |key, value| "#{key.to_s.upcase}=#{CGI.escape(value.to_s)}" }.join("&") + parameters.reject { |k, v| v.blank? }.collect { |key, value| "#{key.to_s.upcase}=#{CGI.escape(value.to_s)}" }.join('&') end end end end - diff --git a/lib/active_merchant/billing/gateways/paybox_direct.rb b/lib/active_merchant/billing/gateways/paybox_direct.rb index b4fd36a97c4..de236330928 100644 --- a/lib/active_merchant/billing/gateways/paybox_direct.rb +++ b/lib/active_merchant/billing/gateways/paybox_direct.rb @@ -21,20 +21,21 @@ class PayboxDirectGateway < Gateway } CURRENCY_CODES = { - "AUD"=> '036', - "CAD"=> '124', - "CZK"=> '203', - "DKK"=> '208', - "HKD"=> '344', - "ICK"=> '352', - "JPY"=> '392', - "NOK"=> '578', - "SGD"=> '702', - "SEK"=> '752', - "CHF"=> '756', - "GBP"=> '826', - "USD"=> '840', - "EUR"=> '978' + 'AUD'=> '036', + 'CAD'=> '124', + 'CZK'=> '203', + 'DKK'=> '208', + 'HKD'=> '344', + 'ICK'=> '352', + 'JPY'=> '392', + 'NOK'=> '578', + 'SGD'=> '702', + 'SEK'=> '752', + 'CHF'=> '756', + 'GBP'=> '826', + 'USD'=> '840', + 'EUR'=> '978', + 'XPF'=> '953' } SUCCESS_CODES = ['00000'] @@ -86,8 +87,8 @@ def capture(money, authorization, options = {}) post = {} add_invoice(post, options) add_amount(post, money, options) - post[:numappel] = authorization[0,10] - post[:numtrans] = authorization[10,10] + post[:numappel] = authorization[0, 10] + post[:numtrans] = authorization[10, 10] commit('capture', money, post) end @@ -130,8 +131,8 @@ def add_creditcard(post, creditcard) end def add_reference(post, identification) - post[:numappel] = identification[0,10] - post[:numtrans] = identification[10,10] + post[:numappel] = identification[0, 10] + post[:numtrans] = identification[10, 10] end def add_amount(post, money, options) @@ -142,14 +143,14 @@ def add_amount(post, money, options) def parse(body) results = {} body.split(/&/).each do |pair| - key,val = pair.split(/\=/) + key, val = pair.split(/\=/) results[key.downcase.to_sym] = CGI.unescape(val) if val end results end def commit(action, money = nil, parameters = nil) - request_data = post_data(action,parameters) + request_data = post_data(action, parameters) response = parse(ssl_post(test? ? self.test_url : self.live_url, request_data)) response = parse(ssl_post(self.live_url_backup, request_data)) if service_unavailable?(response) && !test? Response.new(success?(response), message_from(response), response.merge( @@ -157,7 +158,7 @@ def commit(action, money = nil, parameters = nil) :test => test?, :authorization => response[:numappel].to_s + response[:numtrans].to_s, :fraud_review => false, - :sent_params => parameters.delete_if{|key,value| ['porteur','dateval','cvv'].include?(key.to_s)} + :sent_params => parameters.delete_if { |key, value| ['porteur', 'dateval', 'cvv'].include?(key.to_s) } ) end @@ -174,20 +175,19 @@ def message_from(response) end def post_data(action, parameters = {}) - parameters.update( :version => API_VERSION, :type => TRANSACTIONS[action.to_sym], :dateq => Time.now.strftime('%d%m%Y%H%M%S'), :numquestion => unique_id(parameters[:order_id]), - :site => @options[:login].to_s[0,7], + :site => @options[:login].to_s[0, 7], :rang => @options[:rang] || @options[:login].to_s[7..-1], :cle => @options[:password], :pays => '', :archivage => parameters[:order_id] ) - parameters.collect { |key, value| "#{key.to_s.upcase}=#{CGI.escape(value.to_s)}" }.join("&") + parameters.collect { |key, value| "#{key.to_s.upcase}=#{CGI.escape(value.to_s)}" }.join('&') end def unique_id(seed = 0) diff --git a/lib/active_merchant/billing/gateways/payeezy.rb b/lib/active_merchant/billing/gateways/payeezy.rb index 1d6f72191ec..cb2e4ff4c13 100644 --- a/lib/active_merchant/billing/gateways/payeezy.rb +++ b/lib/active_merchant/billing/gateways/payeezy.rb @@ -3,9 +3,9 @@ module Billing class PayeezyGateway < Gateway class_attribute :integration_url - self.test_url = 'https://api-cert.payeezy.com/v1/transactions' - self.integration_url = 'https://api-cat.payeezy.com/v1/transactions' - self.live_url = 'https://api.payeezy.com/v1/transactions' + self.test_url = 'https://api-cert.payeezy.com/v1' + self.integration_url = 'https://api-cat.payeezy.com/v1' + self.live_url = 'https://api.payeezy.com/v1' self.default_currency = 'USD' self.money_format = :cents @@ -31,12 +31,14 @@ def initialize(options = {}) end def purchase(amount, payment_method, options = {}) - params = {transaction_type: 'purchase'} + params = payment_method.is_a?(String) ? { transaction_type: 'recurring' } : { transaction_type: 'purchase' } add_invoice(params, options) - add_payment_method(params, payment_method) + add_reversal_id(params, options) + add_payment_method(params, payment_method, options) add_address(params, options) add_amount(params, amount, options) + add_soft_descriptors(params, options) commit(params, options) end @@ -45,9 +47,11 @@ def authorize(amount, payment_method, options = {}) params = {transaction_type: 'authorize'} add_invoice(params, options) - add_payment_method(params, payment_method) + add_reversal_id(params, options) + add_payment_method(params, payment_method, options) add_address(params, options) add_amount(params, amount, options) + add_soft_descriptors(params, options) commit(params, options) end @@ -57,6 +61,7 @@ def capture(amount, authorization, options = {}) add_authorization_info(params, authorization) add_amount(params, amount, options) + add_soft_descriptors(params, options) commit(params, options) end @@ -70,10 +75,18 @@ def refund(amount, authorization, options = {}) commit(params, options) end + def store(payment_method, options = {}) + params = {transaction_type: 'store'} + + add_creditcard_for_tokenization(params, payment_method, options) + + commit(params, options) + end + def void(authorization, options = {}) params = {transaction_type: 'void'} - add_authorization_info(params, authorization) + add_authorization_info(params, authorization, options) add_amount(params, amount_from_authorization(authorization), options) commit(params, options) @@ -81,7 +94,7 @@ def void(authorization, options = {}) def verify(credit_card, options={}) MultiResponse.run(:use_first_response) do |r| - r.process { authorize(100, credit_card, options) } + r.process { authorize(0, credit_card, options) } r.process(:ignore_result) { void(r.authorization, options) } end end @@ -93,10 +106,17 @@ def supports_scrubbing? def scrub(transcript) transcript. gsub(%r((Token: )(\w|-)+), '\1[FILTERED]'). + gsub(%r((Apikey: )(\w|-)+), '\1[FILTERED]'). gsub(%r((\\?"card_number\\?":\\?")\d+), '\1[FILTERED]'). gsub(%r((\\?"cvv\\?":\\?")\d+), '\1[FILTERED]'). gsub(%r((\\?"account_number\\?":\\?")\d+), '\1[FILTERED]'). - gsub(%r((\\?"routing_number\\?":\\?")\d+), '\1[FILTERED]') + gsub(%r((\\?"routing_number\\?":\\?")\d+), '\1[FILTERED]'). + gsub(%r((\\?card_number=)\d+(&?)), '\1[FILTERED]'). + gsub(%r((\\?cvv=)\d+(&?)), '\1[FILTERED]'). + gsub(%r((\\?apikey=)\w+(&?)), '\1[FILTERED]'). + gsub(%r{(\\?"credit_card\.card_number\\?":)(\\?"[^"]+\\?")}, '\1[FILTERED]'). + gsub(%r{(\\?"credit_card\.cvv\\?":)(\\?"[^"]+\\?")}, '\1[FILTERED]'). + gsub(%r{(\\?"apikey\\?":)(\\?"[^"]+\\?")}, '\1[FILTERED]') end private @@ -105,51 +125,102 @@ def add_invoice(params, options) params[:merchant_ref] = options[:order_id] end + def add_reversal_id(params, options) + params[:reversal_id] = options[:reversal_id] if options[:reversal_id] + end + def amount_from_authorization(authorization) authorization.split('|').last.to_i end - def add_authorization_info(params, authorization) + def add_authorization_info(params, authorization, options = {}) transaction_id, transaction_tag, method, _ = authorization.split('|') - params[:transaction_id] = transaction_id - params[:transaction_tag] = transaction_tag - params[:method] = method - end + params[:method] = method == 'token' ? 'credit_card' : method - def add_payment_method(params, payment_method) - if payment_method.is_a? Check - add_echeck(params, payment_method) + if options[:reversal_id] + params[:reversal_id] = options[:reversal_id] else - add_creditcard(params, payment_method) + params[:transaction_id] = transaction_id + params[:transaction_tag] = transaction_tag end end - def add_creditcard(params, creditcard) - credit_card = {} + def add_creditcard_for_tokenization(params, payment_method, options) + params[:apikey] = @options[:apikey] + params[:ta_token] = options[:ta_token] + params[:type] = 'FDToken' + params[:credit_card] = add_card_data(payment_method) + params[:auth] = 'false' + end - credit_card[:type] = CREDIT_CARD_BRAND[creditcard.brand] - credit_card[:cardholder_name] = creditcard.name - credit_card[:card_number] = creditcard.number - credit_card[:exp_date] = "#{format(creditcard.month, :two_digits)}#{format(creditcard.year, :two_digits)}" - credit_card[:cvv] = creditcard.verification_value if creditcard.verification_value? + def is_store_action?(params) + params[:transaction_type] == 'store' + end - params[:method] = 'credit_card' - params[:credit_card] = credit_card + def add_payment_method(params, payment_method, options) + if payment_method.is_a? Check + add_echeck(params, payment_method, options) + elsif payment_method.is_a? String + add_token(params, payment_method, options) + else + add_creditcard(params, payment_method) + end end - def add_echeck(params, echeck) + def add_echeck(params, echeck, options) tele_check = {} - tele_check[:check_number] = echeck.number - tele_check[:check_type] = "P" + tele_check[:check_number] = echeck.number || '001' + tele_check[:check_type] = 'P' tele_check[:routing_number] = echeck.routing_number tele_check[:account_number] = echeck.account_number tele_check[:accountholder_name] = "#{echeck.first_name} #{echeck.last_name}" + tele_check[:customer_id_type] = options[:customer_id_type] if options[:customer_id_type] + tele_check[:customer_id_number] = options[:customer_id_number] if options[:customer_id_number] + tele_check[:client_email] = options[:client_email] if options[:client_email] params[:method] = 'tele_check' params[:tele_check] = tele_check end + def add_token(params, payment_method, options) + token = {} + token[:token_type] = 'FDToken' + + type, cardholder_name, exp_date, card_number = payment_method.split('|') + + token[:token_data] = {} + token[:token_data][:type] = type + token[:token_data][:cardholder_name] = cardholder_name + token[:token_data][:value] = card_number + token[:token_data][:exp_date] = exp_date + token[:token_data][:cvv] = options[:cvv] if options[:cvv] + + params[:method] = 'token' + params[:token] = token + end + + def add_creditcard(params, creditcard) + credit_card = add_card_data(creditcard) + + params[:method] = 'credit_card' + params[:credit_card] = credit_card + end + + def add_card_data(payment_method) + card = {} + card[:type] = CREDIT_CARD_BRAND[payment_method.brand] + card[:cardholder_name] = payment_method.name + card[:card_number] = payment_method.number + card[:exp_date] = format_exp_date(payment_method.month, payment_method.year) + card[:cvv] = payment_method.verification_value if payment_method.verification_value? + card + end + + def format_exp_date(month, year) + "#{format(month, :two_digits)}#{format(year, :two_digits)}" + end + def add_address(params, options) address = options[:billing_address] return unless address @@ -169,26 +240,23 @@ def add_amount(params, money, options) params[:amount] = amount(money) end + def add_soft_descriptors(params, options) + params[:soft_descriptors] = options[:soft_descriptors] if options[:soft_descriptors] + end + def commit(params, options) - url = if options[:integration] - integration_url - elsif test? - test_url - else - live_url - end + url = base_url(options) + endpoint(params) if transaction_id = params.delete(:transaction_id) url = "#{url}/#{transaction_id}" end begin - body = params.to_json - response = parse(ssl_post(url, body, headers(body))) + response = api_request(url, params) rescue ResponseError => e response = response_error(e.response.body) rescue JSON::ParserError - response = json_error(raw_response) + response = json_error(e.response.body) end Response.new( @@ -203,17 +271,28 @@ def commit(params, options) ) end - def success_from(response) - response['transaction_status'] == 'approved' + def base_url(options) + if options[:integration] + integration_url + elsif test? + test_url + else + live_url + end end - def authorization_from(params, response) - [ - response['transaction_id'], - response['transaction_tag'], - params[:method], - (response['amount'] && response['amount'].to_i) - ].join('|') + def endpoint(params) + is_store_action?(params) ? '/transactions/tokens' : '/transactions' + end + + def api_request(url, params) + body = params.to_json + parse(ssl_post(url, body, headers(body))) + end + + def post_data(params) + return nil unless params + params.reject { |k, v| v.blank? }.collect { |k, v| "#{k}=#{CGI.escape(v.to_s)}" }.join('&') end def generate_hmac(nonce, current_timestamp, payload) @@ -223,7 +302,7 @@ def generate_hmac(nonce, current_timestamp, payload) current_timestamp.to_s, @options[:token], payload - ].join("") + ].join('') hash = Base64.strict_encode64(OpenSSL::HMAC.hexdigest('sha256', @options[:apisecret], message)) hash end @@ -246,19 +325,57 @@ def error_code(response, success) response['Error'].to_h['messages'].to_a.map { |e| e['code'] }.join(', ') end + def success_from(response) + if response['transaction_status'] + response['transaction_status'] == 'approved' + elsif response['results'] + response['results']['status'] == 'success' + elsif response['status'] + response['status'] == 'success' + else + false + end + end + def handle_message(response, success) - if success + if success && response['status'].present? + 'Token successfully created.' + elsif success "#{response['gateway_message']} - #{response['bank_message']}" elsif %w(401 403).include?(response['code']) response['message'] elsif response.key?('Error') response['Error']['messages'].first['description'] + elsif response.key?('results') + response['results']['Error']['messages'].first['description'] elsif response.key?('error') response['error'] elsif response.key?('fault') response['fault'].to_h['faultstring'] else - response['bank_message'] + response['bank_message'] || response['gateway_message'] || 'Failure to successfully create token.' + end + end + + def authorization_from(params, response) + if is_store_action?(params) + if success_from(response) + [ + response['token']['type'], + response['token']['cardholder_name'], + response['token']['exp_date'], + response['token']['value'] + ].join('|') + else + nil + end + else + [ + response['transaction_id'], + response['transaction_tag'], + params[:method], + response['amount']&.to_i + ].join('|') end end @@ -273,7 +390,7 @@ def response_error(raw_response) end def json_error(raw_response) - {"error" => "Unable to parse response: #{raw_response.inspect}"} + {'error' => "Unable to parse response: #{raw_response.inspect}"} end end end diff --git a/lib/active_merchant/billing/gateways/payex.rb b/lib/active_merchant/billing/gateways/payex.rb index 047effa7f10..c43e36bb13f 100644 --- a/lib/active_merchant/billing/gateways/payex.rb +++ b/lib/active_merchant/billing/gateways/payex.rb @@ -1,4 +1,4 @@ -require "nokogiri" +require 'nokogiri' module ActiveMerchant #:nodoc: module Billing #:nodoc: @@ -16,7 +16,7 @@ class PayexGateway < Gateway self.supported_cardtypes = [:visa, :master, :american_express, :discover] self.homepage_url = 'http://payex.com/' self.display_name = 'Payex' - self.default_currency = "EUR" + self.default_currency = 'EUR' TRANSACTION_STATUS = { sale: '0', @@ -63,14 +63,13 @@ def authorize(amount, payment_method, options = {}) if payment_method.respond_to?(:number) # credit card authorization MultiResponse.new.tap do |r| - r.process {send_initialize(amount, true, options)} - r.process {send_purchasecc(payment_method, r.params['orderref'])} + r.process { send_initialize(amount, true, options) } + r.process { send_purchasecc(payment_method, r.params['orderref']) } end else # stored authorization send_autopay(amount, payment_method, true, options) end - end # Public: Send a purchase Payex request @@ -92,8 +91,8 @@ def purchase(amount, payment_method, options = {}) if payment_method.respond_to?(:number) # credit card purchase MultiResponse.new.tap do |r| - r.process {send_initialize(amount, false, options)} - r.process {send_purchasecc(payment_method, r.params['orderref'])} + r.process { send_initialize(amount, false, options) } + r.process { send_purchasecc(payment_method, r.params['orderref']) } end else # stored purchase @@ -155,10 +154,10 @@ def store(creditcard, options = {}) requires!(options, :order_id) amount = amount(1) # 1 cent for authorization MultiResponse.run(:first) do |r| - r.process {send_create_agreement(options)} - r.process {send_initialize(amount, true, options.merge({agreement_ref: r.authorization}))} + r.process { send_create_agreement(options) } + r.process { send_initialize(amount, true, options.merge({agreement_ref: r.authorization})) } order_ref = r.params['orderref'] - r.process {send_purchasecc(creditcard, order_ref)} + r.process { send_purchasecc(creditcard, order_ref) } end end @@ -360,12 +359,12 @@ def parse(xml) response = {} xmldoc = Nokogiri::XML(xml) - body = xmldoc.xpath("//soap:Body/*[1]")[0].inner_text + body = xmldoc.xpath('//soap:Body/*[1]')[0].inner_text doc = Nokogiri::XML(body) - doc.root.xpath("*").each do |node| - if (node.elements.size == 0) + doc.root&.xpath('*')&.each do |node| + if node.elements.size == 0 response[node.name.downcase.to_sym] = node.text else node.elements.each do |childnode| @@ -373,7 +372,7 @@ def parse(xml) response[name.to_sym] = childnode.text end end - end unless doc.root.nil? + end response end @@ -387,11 +386,11 @@ def commit(soap_action, request) } response = parse(ssl_post(url, request, headers)) Response.new(success?(response), - message_from(response), - response, - test: test?, - authorization: build_authorization(response) - ) + message_from(response), + response, + test: test?, + authorization: build_authorization(response) + ) end def build_authorization(response) @@ -409,4 +408,3 @@ def message_from(response) end end end - diff --git a/lib/active_merchant/billing/gateways/payflow.rb b/lib/active_merchant/billing/gateways/payflow.rb index 817ff39712d..3123693a84d 100644 --- a/lib/active_merchant/billing/gateways/payflow.rb +++ b/lib/active_merchant/billing/gateways/payflow.rb @@ -45,12 +45,19 @@ def refund(money, reference, options = {}) end def verify(payment, options={}) - authorize(0, payment, options) + if credit_card_type(payment) == 'Amex' + MultiResponse.run(:use_first_response) do |r| + r.process { authorize(100, payment, options) } + r.process(:ignore_result) { void(r.authorization, options) } + end + else + authorize(0, payment, options) + end end def verify_credentials - response = void("0") - response.params["result"] != "26" + response = void('0') + response.params['result'] != '26' end # Adds or modifies a recurring Payflow profile. See the Payflow Pro Recurring Billing Guide for more details: @@ -85,7 +92,7 @@ def cancel_recurring(profile_id) def recurring_inquiry(profile_id, options = {}) ActiveMerchant.deprecated RECURRING_DEPRECATION_MESSAGE - request = build_recurring_request(:inquiry, nil, options.update( :profile_id => profile_id )) + request = build_recurring_request(:inquiry, nil, options.update(:profile_id => profile_id)) commit(request, options.merge(:request_type => :recurring)) end @@ -93,8 +100,20 @@ def express @express ||= PayflowExpressGateway.new(@options) end + def supports_scrubbing? + true + end + + def scrub(transcript) + transcript. + gsub(%r(()[^<]*()), '\1[FILTERED]\2'). + gsub(%r(()[^<]*()), '\1[FILTERED]\2'). + gsub(%r(()[^<]*()), '\1[FILTERED]\2'). + gsub(%r(()[^<]*()), '\1[FILTERED]\2') + end private + def build_sale_or_authorization_request(action, money, funding_source, options) if funding_source.is_a?(String) build_reference_sale_or_authorization_request(action, money, funding_source, options) @@ -114,6 +133,7 @@ def build_reference_sale_or_authorization_request(action, money, reference, opti xml.tag! 'CustIP', options[:ip] unless options[:ip].blank? xml.tag! 'InvNum', options[:order_id].to_s.gsub(/[^\w.]/, '') unless options[:order_id].blank? xml.tag! 'Description', options[:description] unless options[:description].blank? + xml.tag! 'OrderDesc', options[:order_desc] unless options[:order_desc].blank? xml.tag! 'Comment', options[:comment] unless options[:comment].blank? xml.tag!('ExtData', 'Name'=> 'COMMENT2', 'Value'=> options[:comment2]) unless options[:comment2].blank? xml.tag! 'TaxAmt', options[:taxamt] unless options[:taxamt].blank? @@ -123,7 +143,7 @@ def build_reference_sale_or_authorization_request(action, money, reference, opti billing_address = options[:billing_address] || options[:address] add_address(xml, 'BillTo', billing_address, options) if billing_address - add_address(xml, 'ShipTo', options[:shipping_address],options) if options[:shipping_address] + add_address(xml, 'ShipTo', options[:shipping_address], options) if options[:shipping_address] xml.tag! 'TotalAmt', amount(money), 'Currency' => options[:currency] || currency(money) end @@ -145,6 +165,7 @@ def build_credit_card_request(action, money, credit_card, options) xml.tag! 'CustIP', options[:ip] unless options[:ip].blank? xml.tag! 'InvNum', options[:order_id].to_s.gsub(/[^\w.]/, '') unless options[:order_id].blank? xml.tag! 'Description', options[:description] unless options[:description].blank? + xml.tag! 'OrderDesc', options[:order_desc] unless options[:order_desc].blank? # Comment and Comment2 will show up in manager.paypal.com as Comment1 and Comment2 xml.tag! 'Comment', options[:comment] unless options[:comment].blank? xml.tag!('ExtData', 'Name'=> 'COMMENT2', 'Value'=> options[:comment2]) unless options[:comment2].blank? @@ -152,6 +173,7 @@ def build_credit_card_request(action, money, credit_card, options) xml.tag! 'FreightAmt', options[:freightamt] unless options[:freightamt].blank? xml.tag! 'DutyAmt', options[:dutyamt] unless options[:dutyamt].blank? xml.tag! 'DiscountAmt', options[:discountamt] unless options[:discountamt].blank? + xml.tag! 'EMail', options[:email] unless options[:email].nil? billing_address = options[:billing_address] || options[:address] add_address(xml, 'BillTo', billing_address, options) if billing_address @@ -176,6 +198,7 @@ def build_check_request(action, money, check, options) xml.tag! 'CustIP', options[:ip] unless options[:ip].blank? xml.tag! 'InvNum', options[:order_id].to_s.gsub(/[^\w.]/, '') unless options[:order_id].blank? xml.tag! 'Description', options[:description] unless options[:description].blank? + xml.tag! 'OrderDesc', options[:order_desc] unless options[:order_desc].blank? xml.tag! 'BillTo' do xml.tag! 'Name', check.name end @@ -214,10 +237,6 @@ def add_credit_card(xml, credit_card, options = {}) end end - if requires_start_date_or_issue_number?(credit_card) - xml.tag!('ExtData', 'Name' => 'CardStart', 'Value' => startdate(credit_card)) unless credit_card.start_month.blank? || credit_card.start_year.blank? - xml.tag!('ExtData', 'Name' => 'CardIssue', 'Value' => format(credit_card.issue_number, :two_digits)) unless credit_card.issue_number.blank? - end xml.tag! 'ExtData', 'Name' => 'LASTNAME', 'Value' => credit_card.last_name end end @@ -229,8 +248,8 @@ def credit_card_type(credit_card) end def expdate(creditcard) - year = sprintf("%.4i", creditcard.year.to_s.sub(/^0+/, '')) - month = sprintf("%.2i", creditcard.month.to_s.sub(/^0+/, '')) + year = sprintf('%.4i', creditcard.year.to_s.sub(/^0+/, '')) + month = sprintf('%.2i', creditcard.month.to_s.sub(/^0+/, '')) "#{year}#{month}" end @@ -270,7 +289,7 @@ def build_recurring_request(action, money, options) end if action == :add - xml.tag! 'Start', format_rp_date(options[:starting_at] || Date.today + 1 ) + xml.tag! 'Start', format_rp_date(options[:starting_at] || Date.today + 1) else xml.tag! 'Start', format_rp_date(options[:starting_at]) unless options[:starting_at].nil? end @@ -286,10 +305,10 @@ def build_recurring_request(action, money, options) end end if action != :add - xml.tag! "ProfileID", options[:profile_id] + xml.tag! 'ProfileID', options[:profile_id] end if action == :inquiry - xml.tag! "PaymentHistory", ( options[:history] ? 'Y' : 'N' ) + xml.tag! 'PaymentHistory', (options[:history] ? 'Y' : 'N') end end end @@ -299,20 +318,20 @@ def build_recurring_request(action, money, options) def get_pay_period(options) requires!(options, [:periodicity, :bimonthly, :monthly, :biweekly, :weekly, :yearly, :daily, :semimonthly, :quadweekly, :quarterly, :semiyearly]) case options[:periodicity] - when :weekly then 'Weekly' - when :biweekly then 'Bi-weekly' - when :semimonthly then 'Semi-monthly' - when :quadweekly then 'Every four weeks' - when :monthly then 'Monthly' - when :quarterly then 'Quarterly' - when :semiyearly then 'Semi-yearly' - when :yearly then 'Yearly' + when :weekly then 'Weekly' + when :biweekly then 'Bi-weekly' + when :semimonthly then 'Semi-monthly' + when :quadweekly then 'Every four weeks' + when :monthly then 'Monthly' + when :quarterly then 'Quarterly' + when :semiyearly then 'Semi-yearly' + when :yearly then 'Yearly' end end def format_rp_date(time) case time - when Time, Date then time.strftime("%m%d%Y") + when Time, Date then time.strftime('%m%d%Y') else time.to_s end @@ -324,4 +343,3 @@ def build_response(success, message, response, options = {}) end end end - diff --git a/lib/active_merchant/billing/gateways/payflow/payflow_common_api.rb b/lib/active_merchant/billing/gateways/payflow/payflow_common_api.rb index e7ff8684417..4ad1bd00739 100644 --- a/lib/active_merchant/billing/gateways/payflow/payflow_common_api.rb +++ b/lib/active_merchant/billing/gateways/payflow/payflow_common_api.rb @@ -25,6 +25,13 @@ def self.included(base) # subsequent Responses will have a :duplicate parameter set in the params # hash. base.retry_safe = true + + # Send Payflow requests to PayPal directly by activating the NVP protocol. + # Valid XMLPay documents may have issues being parsed correctly by + # Payflow but will be accepted by PayPal if a PAYPAL-NVP request header + # is declared. + base.class_attribute :use_paypal_nvp + base.use_paypal_nvp = false end XMLNS = 'http://www.paypal.com/XMLPay' @@ -36,16 +43,14 @@ def self.included(base) :american_express => 'Amex', :jcb => 'JCB', :diners_club => 'DinersClub', - :switch => 'Switch', - :solo => 'Solo' } TRANSACTIONS = { - :purchase => "Sale", - :authorization => "Authorization", - :capture => "Capture", - :void => "Void", - :credit => "Credit" + :purchase => 'Sale', + :authorization => 'Authorization', + :capture => 'Capture', + :void => 'Void', + :credit => 'Credit' } CVV_CODE = { @@ -73,10 +78,11 @@ def void(authorization, options = {}) end private + def build_request(body, options = {}) xml = Builder::XmlMarkup.new xml.instruct! - xml.tag! 'XMLPayRequest', 'Timeout' => timeout.to_s, 'version' => "2.1", "xmlns" => XMLNS do + xml.tag! 'XMLPayRequest', 'Timeout' => timeout.to_s, 'version' => '2.1', 'xmlns' => XMLNS do xml.tag! 'RequestData' do xml.tag! 'Vendor', @options[:login] xml.tag! 'Partner', @options[:partner] @@ -112,6 +118,11 @@ def build_reference_request(action, money, authorization, options) xml.tag!('Description', options[:description]) unless options[:description].blank? xml.tag!('Comment', options[:comment]) unless options[:comment].blank? xml.tag!('ExtData', 'Name'=> 'COMMENT2', 'Value'=> options[:comment2]) unless options[:comment2].blank? + xml.tag!( + 'ExtData', + 'Name' => 'CAPTURECOMPLETE', + 'Value' => options[:capture_complete] + ) unless options[:capture_complete].blank? end end end @@ -130,8 +141,9 @@ def add_address(xml, tag, address, options) xml.tag! 'Address' do xml.tag! 'Street', address[:address1] unless address[:address1].blank? + xml.tag! 'Street2', address[:address2] unless address[:address2].blank? xml.tag! 'City', address[:city] unless address[:city].blank? - xml.tag! 'State', address[:state].blank? ? "N/A" : address[:state] + xml.tag! 'State', address[:state].blank? ? 'N/A' : address[:state] xml.tag! 'Country', address[:country] unless address[:country].blank? xml.tag! 'Zip', address[:zip] unless address[:zip].blank? end @@ -142,16 +154,16 @@ def parse(data) response = {} xml = Nokogiri::XML(data) xml.remove_namespaces! - root = xml.xpath("//ResponseData") + root = xml.xpath('//ResponseData') # REXML::XPath in Ruby 1.8.6 is now unable to match nodes based on their attributes - tx_result = root.xpath(".//TransactionResult").first + tx_result = root.xpath('.//TransactionResult').first - if tx_result && tx_result.attributes['Duplicate'].to_s == "true" + if tx_result && tx_result.attributes['Duplicate'].to_s == 'true' response[:duplicate] = true end - root.xpath(".//*").each do |node| + root.xpath('.//*').each do |node| parse_element(response, node) end @@ -166,10 +178,10 @@ def parse_element(response, node) # down as we do everywhere else. RPPaymentResult elements are not contained # in an RPPaymentResults element so we'll come here multiple times response[node_name] ||= [] - response[node_name] << ( payment_result_response = {} ) - node.xpath(".//*").each{ |e| parse_element(payment_result_response, e) } - when node.xpath(".//*").to_a.any? - node.xpath(".//*").each{|e| parse_element(response, e) } + response[node_name] << (payment_result_response = {}) + node.xpath('.//*').each { |e| parse_element(payment_result_response, e) } + when node.xpath('.//*').to_a.any? + node.xpath('.//*').each { |e| parse_element(response, e) } when node_name.to_s =~ /amt$/ # *Amt elements don't put the value in the #text - instead they use a Currency attribute response[node_name] = node.attributes['Currency'].to_s @@ -181,17 +193,20 @@ def parse_element(response, node) end def build_headers(content_length) - { - "Content-Type" => "text/xml", - "Content-Length" => content_length.to_s, - "X-VPS-Client-Timeout" => timeout.to_s, - "X-VPS-VIT-Integration-Product" => "ActiveMerchant", - "X-VPS-VIT-Runtime-Version" => RUBY_VERSION, - "X-VPS-Request-ID" => SecureRandom.hex(16) + headers = { + 'Content-Type' => 'text/xml', + 'Content-Length' => content_length.to_s, + 'X-VPS-Client-Timeout' => timeout.to_s, + 'X-VPS-VIT-Integration-Product' => 'ActiveMerchant', + 'X-VPS-VIT-Runtime-Version' => RUBY_VERSION, + 'X-VPS-Request-ID' => SecureRandom.hex(16) } + + headers['PAYPAL-NVP'] = 'Y' if self.use_paypal_nvp + headers end - def commit(request_body, options = {}) + def commit(request_body, options = {}) request = build_request(request_body, options) headers = build_headers(request.size) @@ -213,7 +228,7 @@ def success_for(response) end def under_fraud_review?(response) - (response[:result] == "126") + (response[:result] == '126') end end end diff --git a/lib/active_merchant/billing/gateways/payflow/payflow_express_response.rb b/lib/active_merchant/billing/gateways/payflow/payflow_express_response.rb index 7b4068dea05..3c43642265f 100644 --- a/lib/active_merchant/billing/gateways/payflow/payflow_express_response.rb +++ b/lib/active_merchant/billing/gateways/payflow/payflow_express_response.rb @@ -4,26 +4,30 @@ class PayflowExpressResponse < Response def email @params['e_mail'] end - + def full_name "#{@params['name']} #{@params['lastname']}" end - + def token @params['token'] end - + def payer_id @params['payer_id'] end - + # Really the shipping country, but it is all the information provided def payer_country address['country'] end - + + def phone + @params['phone'] + end + def address - { 'name' => full_name, + { 'name' => @params['shiptoname'] || full_name, 'company' => nil, 'address1' => @params['street'], 'address2' => @params['shiptostreet2'] || @params['street2'], @@ -31,7 +35,7 @@ def address 'state' => @params['state'], 'country' => @params['country'], 'zip' => @params['zip'], - 'phone' => nil + 'phone' => phone, } end end diff --git a/lib/active_merchant/billing/gateways/payflow/payflow_response.rb b/lib/active_merchant/billing/gateways/payflow/payflow_response.rb index d2b6e670009..83caaff5800 100644 --- a/lib/active_merchant/billing/gateways/payflow/payflow_response.rb +++ b/lib/active_merchant/billing/gateways/payflow/payflow_response.rb @@ -4,10 +4,10 @@ class PayflowResponse < Response def profile_id @params['profile_id'] end - + def payment_history - @payment_history ||= @params['rp_payment_result'].collect{ |result| result.stringify_keys } rescue [] + @payment_history ||= @params['rp_payment_result'].collect(&:stringify_keys) rescue [] end end end -end \ No newline at end of file +end diff --git a/lib/active_merchant/billing/gateways/payflow_express.rb b/lib/active_merchant/billing/gateways/payflow_express.rb index 1f8b10ea182..9676d2b1cf2 100644 --- a/lib/active_merchant/billing/gateways/payflow_express.rb +++ b/lib/active_merchant/billing/gateways/payflow_express.rb @@ -4,62 +4,59 @@ module ActiveMerchant #:nodoc: module Billing #:nodoc: - # ==General Parameters - # The following parameters are supported for #setup_authorization, #setup_purchase, #authorize and #purchase transactions. I've read - # in the docs that they recommend you pass the exact same parameters to both setup and authorize/purchase. - # - # This information was gleaned from a mix of: - # * PayFlow documentation - # * for key value pairs: {Express Checkout for Payflow Pro (PDF)}[https://cms.paypal.com/cms_content/US/en_US/files/developer/PFP_ExpressCheckout_PP.pdf] - # * XMLPay: {Payflow Pro XMLPay Developer's Guide (PDF)}[https://cms.paypal.com/cms_content/US/en_US/files/developer/PP_PayflowPro_XMLPay_Guide.pdf] - # * previous ActiveMerchant code - # * trial & error - # - # The following parameters are currently supported. - # [:ip] (opt) Customer IP Address - # [:order_id] (opt) An order or invoice number. This will be passed through to the Payflow backend at manager.paypal.com, and show up as "Supplier Reference #" - # [:description] (opt) Order description, shown to buyer (after redirected to PayPal). If Order Line Items are used (see below), then the description is suppressed. This will not be passed through to the Payflow backend. - # [:billing_address] (opt) See ActiveMerchant::Billing::Gateway for details - # [:shipping_address] (opt) See ActiveMerchant::Billing::Gateway for details - # [:currency] (req) Currency of transaction, will be set to USD by default for PayFlow Express if not specified - # [:email] (opt) Email of buyer; used to pre-fill PayPal login screen - # [:payer_id] (opt) Unique PayPal buyer account identification number, as returned by details_for request - # [:token] (req for #authorize & #purchase) Token returned by setup transaction - # [:no_shipping] (opt) Boolean for whether or not to display shipping address to buyer - # [:address_override] (opt) Boolean. If true, display shipping address passed by parameters, rather than shipping address on file with PayPal - # [:allow_note] (opt) Boolean for permitting buyer to add note during checkout. Note contents can be retrieved with details_for transaction - # [:return_url] (req) URL to which the buyer’s browser is returned after choosing to pay. - # [:cancel_return_url] (req) URL to which the buyer is returned if the buyer cancels the order. - # [:notify_url] (opt) Your URL for receiving Instant Payment Notification (IPN) about this transaction. - # [:comment] (opt) Comment field which will be reported to Payflow backend (at manager.paypal.com) as Comment1 - # [:comment2] (opt) Comment field which will be reported to Payflow backend (at manager.paypal.com) as Comment2 - # [:discount] (opt) Total discounts in cents - # - # ==Line Items - # Support for order line items is available, but has to be enabled on the PayFlow backend. This is what I was told by Todd Sieber at Technical Support: - # - # You will need to call Payflow Support at 1-888-883-9770, choose option #2. Request that they update your account in "Pandora" under Product Settings >> PayPal Mark and update the Features Bitmap to 1111111111111112. This is 15 ones and a two. - # - # See here[https://www.x.com/message/206214#206214] for the forum discussion (requires login to {x.com}[https://x.com] - # - # [:items] (opt) Array of Order Line Items hashes. These are shown to the buyer after redirect to PayPal. - # - # - # - # The following keys are supported for line items: - # [:name] Name of line item - # [:description] Description of line item - # [:amount] Line Item Amount in Cents (as Integer) - # [:quantity] Line Item Quantity (default to 1 if left blank) - # - # ====Customization of Payment Page - # [:page_style] (opt) Your URL for receiving Instant Payment Notification (IPN) about this transaction. - # [:header_image] (opt) Your URL for receiving Instant Payment Notification (IPN) about this transaction. - # [:background_color] (opt) Your URL for receiving Instant Payment Notification (IPN) about this transaction. - # ====Additional options for old Checkout Experience, being phased out in 2010 and 2011 - # [:header_background_color] (opt) Your URL for receiving Instant Payment Notification (IPN) about this transaction. - # [:header_border_color] (opt) Your URL for receiving Instant Payment Notification (IPN) about this transaction. - + # ==General Parameters + # The following parameters are supported for #setup_authorization, #setup_purchase, #authorize and #purchase transactions. I've read + # in the docs that they recommend you pass the exact same parameters to both setup and authorize/purchase. + # + # This information was gleaned from a mix of: + # * {PayFlow documentation}[https://developer.paypal.com/docs/classic/payflow/integration-guide/] + # * previous ActiveMerchant code + # * trial & error + # + # The following parameters are currently supported. + # [:ip] (opt) Customer IP Address + # [:order_id] (opt) An order or invoice number. This will be passed through to the Payflow backend at manager.paypal.com, and show up as "Supplier Reference #" + # [:description] (opt) Order description, shown to buyer (after redirected to PayPal). If Order Line Items are used (see below), then the description is suppressed. This will not be passed through to the Payflow backend. + # [:billing_address] (opt) See ActiveMerchant::Billing::Gateway for details + # [:shipping_address] (opt) See ActiveMerchant::Billing::Gateway for details + # [:currency] (req) Currency of transaction, will be set to USD by default for PayFlow Express if not specified + # [:email] (opt) Email of buyer; used to pre-fill PayPal login screen + # [:payer_id] (opt) Unique PayPal buyer account identification number, as returned by details_for request + # [:token] (req for #authorize & #purchase) Token returned by setup transaction + # [:no_shipping] (opt) Boolean for whether or not to display shipping address to buyer + # [:address_override] (opt) Boolean. If true, display shipping address passed by parameters, rather than shipping address on file with PayPal + # [:allow_note] (opt) Boolean for permitting buyer to add note during checkout. Note contents can be retrieved with details_for transaction + # [:return_url] (req) URL to which the buyer’s browser is returned after choosing to pay. + # [:cancel_return_url] (req) URL to which the buyer is returned if the buyer cancels the order. + # [:notify_url] (opt) Your URL for receiving Instant Payment Notification (IPN) about this transaction. + # [:comment] (opt) Comment field which will be reported to Payflow backend (at manager.paypal.com) as Comment1 + # [:comment2] (opt) Comment field which will be reported to Payflow backend (at manager.paypal.com) as Comment2 + # [:discount] (opt) Total discounts in cents + # + # ==Line Items + # Support for order line items is available, but has to be enabled on the PayFlow backend. This is what I was told by Todd Sieber at Technical Support: + # + # You will need to call Payflow Support at 1-888-883-9770, choose option #2. Request that they update your account in "Pandora" under Product Settings >> PayPal Mark and update the Features Bitmap to 1111111111111112. This is 15 ones and a two. + # + # See here[https://www.x.com/message/206214#206214] for the forum discussion (requires login to {x.com}[https://x.com] + # + # [:items] (opt) Array of Order Line Items hashes. These are shown to the buyer after redirect to PayPal. + # + # + # + # The following keys are supported for line items: + # [:name] Name of line item + # [:description] Description of line item + # [:amount] Line Item Amount in Cents (as Integer) + # [:quantity] Line Item Quantity (default to 1 if left blank) + # + # ====Customization of Payment Page + # [:page_style] (opt) Your URL for receiving Instant Payment Notification (IPN) about this transaction. + # [:header_image] (opt) Your URL for receiving Instant Payment Notification (IPN) about this transaction. + # [:background_color] (opt) Your URL for receiving Instant Payment Notification (IPN) about this transaction. + # ====Additional options for old Checkout Experience, being phased out in 2010 and 2011 + # [:header_background_color] (opt) Your URL for receiving Instant Payment Notification (IPN) about this transaction. + # [:header_border_color] (opt) Your URL for receiving Instant Payment Notification (IPN) about this transaction. class PayflowExpressGateway < Gateway include PayflowCommonAPI @@ -111,6 +108,7 @@ def details_for(token) end private + def build_get_express_details_request(token) xml = Builder::XmlMarkup.new :indent => 2 xml.tag! 'GetExpressCheckout' do @@ -178,11 +176,10 @@ def add_pay_data(xml, money, options) end if items.any? xml.tag! 'ExtData', 'Name' => 'CURRENCY', 'Value' => options[:currency] || currency(money) - xml.tag! 'ExtData', 'Name' => "ITEMAMT", 'Value' => amount(options[:subtotal] || money) + xml.tag! 'ExtData', 'Name' => 'ITEMAMT', 'Value' => amount(options[:subtotal] || money) end xml.tag! 'DiscountAmt', amount(options[:discount]) if options[:discount] xml.tag! 'TotalAmt', amount(money), 'Currency' => options[:currency] || currency(money) - end xml.tag! 'Tender' do @@ -192,7 +189,7 @@ def add_pay_data(xml, money, options) end def add_paypal_details(xml, options) - xml.tag! 'PayPal' do + xml.tag! 'PayPal' do xml.tag! 'EMail', options[:email] unless options[:email].blank? xml.tag! 'ReturnURL', options[:return_url] unless options[:return_url].blank? xml.tag! 'CancelURL', options[:cancel_return_url] unless options[:cancel_return_url].blank? @@ -201,7 +198,7 @@ def add_paypal_details(xml, options) xml.tag! 'Token', options[:token] unless options[:token].blank? xml.tag! 'NoShipping', options[:no_shipping] ? '1' : '0' xml.tag! 'AddressOverride', options[:address_override] ? '1' : '0' - xml.tag! 'ButtonSource', application_id.to_s.slice(0,32) unless application_id.blank? + xml.tag! 'ButtonSource', application_id.to_s.slice(0, 32) unless application_id.blank? # Customization of the payment page xml.tag! 'PageStyle', options[:page_style] unless options[:page_style].blank? @@ -221,4 +218,3 @@ def build_response(success, message, response, options = {}) end end end - diff --git a/lib/active_merchant/billing/gateways/payflow_express_uk.rb b/lib/active_merchant/billing/gateways/payflow_express_uk.rb index 79bf204de91..a314bad48c4 100644 --- a/lib/active_merchant/billing/gateways/payflow_express_uk.rb +++ b/lib/active_merchant/billing/gateways/payflow_express_uk.rb @@ -12,4 +12,3 @@ class PayflowExpressUkGateway < PayflowExpressGateway end end end - diff --git a/lib/active_merchant/billing/gateways/payflow_uk.rb b/lib/active_merchant/billing/gateways/payflow_uk.rb index b8c3a711a44..e963c152ef0 100644 --- a/lib/active_merchant/billing/gateways/payflow_uk.rb +++ b/lib/active_merchant/billing/gateways/payflow_uk.rb @@ -11,11 +11,10 @@ def express @express ||= PayflowExpressUkGateway.new(@options) end - self.supported_cardtypes = [:visa, :master, :american_express, :discover, :solo, :switch] + self.supported_cardtypes = [:visa, :master, :american_express, :discover] self.supported_countries = ['GB'] self.homepage_url = 'https://www.paypal.com/uk/webapps/mpp/pro' self.display_name = 'PayPal Payments Pro (UK)' end end end - diff --git a/lib/active_merchant/billing/gateways/payment_express.rb b/lib/active_merchant/billing/gateways/payment_express.rb index 2c6cedb74a9..d3e28786d8e 100644 --- a/lib/active_merchant/billing/gateways/payment_express.rb +++ b/lib/active_merchant/billing/gateways/payment_express.rb @@ -2,7 +2,6 @@ module ActiveMerchant #:nodoc: module Billing #:nodoc: - # In NZ DPS supports ANZ, Westpac, National Bank, ASB and BNZ. # In Australia DPS supports ANZ, NAB, Westpac, CBA, St George and Bank of South Australia. # The Maybank in Malaysia is supported and the Citibank for Singapore. @@ -21,7 +20,8 @@ class PaymentExpressGateway < Gateway self.homepage_url = 'http://www.paymentexpress.com/' self.display_name = 'PaymentExpress' - self.live_url = self.test_url = 'https://sec.paymentexpress.com/pxpost.aspx' + self.live_url = 'https://sec.paymentexpress.com/pxpost.aspx' + self.test_url = 'https://uat.paymentexpress.com/pxpost.aspx' APPROVED = '1' @@ -128,7 +128,8 @@ def supports_scrubbing def scrub(transcript) transcript. - gsub(%r((Authorization: Basic )\w+), '\1[FILTERED]'). + gsub(%r(().+()), '\1[FILTERED]\2'). + gsub(%r((Authorization: Basic )\w+), '\1[FILTERED]\2'). gsub(%r(()\d+()), '\1[FILTERED]\2'). gsub(%r(()\d+()), '\1[FILTERED]\2') end @@ -168,73 +169,68 @@ def build_capture_or_credit_request(money, identification, options) def build_token_request(credit_card, options) result = new_transaction add_credit_card(result, credit_card) - add_amount(result, 100, options) #need to make an auth request for $1 + add_amount(result, 100, options) # need to make an auth request for $1 add_token_request(result, options) add_optional_elements(result, options) result end def add_credentials(xml) - xml.add_element("PostUsername").text = @options[:login] - xml.add_element("PostPassword").text = @options[:password] + xml.add_element('PostUsername').text = @options[:login] + xml.add_element('PostPassword').text = @options[:password] end def add_reference(xml, identification) - xml.add_element("DpsTxnRef").text = identification + xml.add_element('DpsTxnRef').text = identification end def add_credit_card(xml, credit_card) - xml.add_element("CardHolderName").text = credit_card.name - xml.add_element("CardNumber").text = credit_card.number - xml.add_element("DateExpiry").text = format_date(credit_card.month, credit_card.year) + xml.add_element('CardHolderName').text = credit_card.name + xml.add_element('CardNumber').text = credit_card.number + xml.add_element('DateExpiry').text = format_date(credit_card.month, credit_card.year) if credit_card.verification_value? - xml.add_element("Cvc2").text = credit_card.verification_value - xml.add_element("Cvc2Presence").text = "1" - end - - if requires_start_date_or_issue_number?(credit_card) - xml.add_element("DateStart").text = format_date(credit_card.start_month, credit_card.start_year) unless credit_card.start_month.blank? || credit_card.start_year.blank? - xml.add_element("IssueNumber").text = credit_card.issue_number unless credit_card.issue_number.blank? + xml.add_element('Cvc2').text = credit_card.verification_value + xml.add_element('Cvc2Presence').text = '1' end end def add_billing_token(xml, token) if use_custom_payment_token? - xml.add_element("BillingId").text = token + xml.add_element('BillingId').text = token else - xml.add_element("DpsBillingId").text = token + xml.add_element('DpsBillingId').text = token end end def add_token_request(xml, options) - xml.add_element("BillingId").text = options[:billing_id] if options[:billing_id] - xml.add_element("EnableAddBillCard").text = 1 + xml.add_element('BillingId').text = options[:billing_id] if options[:billing_id] + xml.add_element('EnableAddBillCard').text = 1 end def add_amount(xml, money, options) - xml.add_element("Amount").text = amount(money) - xml.add_element("InputCurrency").text = options[:currency] || currency(money) + xml.add_element('Amount').text = amount(money) + xml.add_element('InputCurrency').text = options[:currency] || currency(money) end def add_transaction_type(xml, action) - xml.add_element("TxnType").text = TRANSACTIONS[action] + xml.add_element('TxnType').text = TRANSACTIONS[action] end def add_invoice(xml, options) - xml.add_element("TxnId").text = options[:order_id].to_s.slice(0, 16) unless options[:order_id].blank? - xml.add_element("MerchantReference").text = options[:description].to_s.slice(0, 50) unless options[:description].blank? + xml.add_element('TxnId').text = options[:order_id].to_s.slice(0, 16) unless options[:order_id].blank? + xml.add_element('MerchantReference').text = options[:description].to_s.slice(0, 50) unless options[:description].blank? end def add_address_verification_data(xml, options) address = options[:billing_address] || options[:address] return if address.nil? - xml.add_element("EnableAvsData").text = 1 - xml.add_element("AvsAction").text = 1 + xml.add_element('EnableAvsData').text = 1 + xml.add_element('AvsAction').text = 1 - xml.add_element("AvsStreetAddress").text = address[:address1] - xml.add_element("AvsPostCode").text = address[:zip] + xml.add_element('AvsStreetAddress').text = address[:address1] + xml.add_element('AvsPostCode').text = address[:zip] end # The options hash may contain optional data which will be passed @@ -275,16 +271,16 @@ def add_address_verification_data(xml, options) # +purchase+, +authorize+, +capture+, +refund+, +store+ def add_optional_elements(xml, options) if client_type = normalized_client_type(options[:client_type]) - xml.add_element("ClientType").text = client_type + xml.add_element('ClientType').text = client_type end - xml.add_element("TxnData1").text = options[:txn_data1].to_s.slice(0,255) unless options[:txn_data1].blank? - xml.add_element("TxnData2").text = options[:txn_data2].to_s.slice(0,255) unless options[:txn_data2].blank? - xml.add_element("TxnData3").text = options[:txn_data3].to_s.slice(0,255) unless options[:txn_data3].blank? + xml.add_element('TxnData1').text = options[:txn_data1].to_s.slice(0, 255) unless options[:txn_data1].blank? + xml.add_element('TxnData2').text = options[:txn_data2].to_s.slice(0, 255) unless options[:txn_data2].blank? + xml.add_element('TxnData3').text = options[:txn_data3].to_s.slice(0, 255) unless options[:txn_data3].blank? end def new_transaction - REXML::Document.new.add_element("Txn") + REXML::Document.new.add_element('Txn') end # Take in the request and post it to DPS @@ -292,8 +288,10 @@ def commit(action, request) add_credentials(request) add_transaction_type(request, action) + url = test? ? self.test_url : self.live_url + # Parse the XML response - response = parse( ssl_post(self.live_url, request.to_s) ) + response = parse(ssl_post(url, request.to_s)) # Return a response PaymentExpressResponse.new(response[:success] == APPROVED, message_from(response), response, @@ -342,13 +340,13 @@ def format_date(month, year) def normalized_client_type(client_type_from_options) case client_type_from_options.to_s.downcase - when 'web' then "Web" - when 'ivr' then "IVR" - when 'moto' then "MOTO" - when 'unattended' then "Unattended" - when 'internet' then "Internet" - when 'recurring' then "Recurring" - else nil + when 'web' then 'Web' + when 'ivr' then 'IVR' + when 'moto' then 'MOTO' + when 'unattended' then 'Unattended' + when 'internet' then 'Internet' + when 'recurring' then 'Recurring' + else nil end end end @@ -357,7 +355,7 @@ class PaymentExpressResponse < Response # add a method to response so we can easily get the token # for Validate transactions def token - @params["billing_id"] || @params["dps_billing_id"] + @params['billing_id'] || @params['dps_billing_id'] end end end diff --git a/lib/active_merchant/billing/gateways/paymentez.rb b/lib/active_merchant/billing/gateways/paymentez.rb new file mode 100644 index 00000000000..cbdaa48d867 --- /dev/null +++ b/lib/active_merchant/billing/gateways/paymentez.rb @@ -0,0 +1,290 @@ +require 'base64' +require 'digest' + +module ActiveMerchant #:nodoc: + module Billing #:nodoc: + class PaymentezGateway < Gateway #:nodoc: + self.test_url = 'https://ccapi-stg.paymentez.com/v2/' + self.live_url = 'https://ccapi.paymentez.com/v2/' + + self.supported_countries = %w[MX EC VE CO BR CL] + self.default_currency = 'USD' + self.supported_cardtypes = %i[visa master american_express diners_club] + + self.homepage_url = 'https://secure.paymentez.com/' + self.display_name = 'Paymentez' + + STANDARD_ERROR_CODE_MAPPING = { + 1 => :processing_error, + 6 => :card_declined, + 9 => :card_declined, + 10 => :processing_error, + 11 => :card_declined, + 12 => :config_error, + 13 => :config_error, + 19 => :invalid_cvc, + 20 => :config_error, + 21 => :card_declined, + 22 => :card_declined, + 23 => :card_declined, + 24 => :card_declined, + 25 => :card_declined, + 26 => :card_declined, + 27 => :card_declined, + 28 => :card_declined + }.freeze + + CARD_MAPPING = { + 'visa' => 'vi', + 'master' => 'mc', + 'american_express' => 'ax', + 'diners_club' => 'di' + }.freeze + + def initialize(options = {}) + requires!(options, :application_code, :app_key) + super + end + + def purchase(money, payment, options = {}) + post = {} + + add_invoice(post, money, options) + add_payment(post, payment) + add_customer_data(post, options) + action = payment.is_a?(String) ? 'debit' : 'debit_cc' + + commit_transaction(action, post) + end + + def authorize(money, payment, options = {}) + post = {} + + add_invoice(post, money, options) + add_payment(post, payment) + add_customer_data(post, options) + + commit_transaction('authorize', post) + end + + def capture(money, authorization, _options = {}) + post = { + transaction: { id: authorization } + } + post[:order] = {amount: amount(money).to_f} if money + + commit_transaction('capture', post) + end + + def refund(money, authorization, options = {}) + post = {transaction: {id: authorization}} + post[:order] = {amount: amount(money).to_f} if money + + commit_transaction('refund', post) + end + + def void(authorization, _options = {}) + post = { transaction: { id: authorization } } + commit_transaction('refund', post) + end + + def verify(credit_card, options = {}) + MultiResponse.run do |r| + r.process { authorize(100, credit_card, options) } + r.process { void(r.authorization, options) } + end + end + + def store(credit_card, options = {}) + post = {} + + add_customer_data(post, options) + add_payment(post, credit_card) + + response = commit_card('add', post) + if !response.success? && !(token = extract_previous_card_token(response)).nil? + unstore(token, options) + response = commit_card('add', post) + end + response + end + + def unstore(identification, options = {}) + post = { card: { token: identification }, user: { id: options[:user_id] }} + commit_card('delete', post) + end + + def supports_scrubbing? + true + end + + def scrub(transcript) + transcript. + gsub(%r{(\\?"number\\?":)(\\?"[^"]+\\?")}, '\1[FILTERED]'). + gsub(%r{(\\?"cvc\\?":)(\\?"[^"]+\\?")}, '\1[FILTERED]'). + gsub(%r{(Auth-Token: )([A-Za-z0-9=]+)}, '\1[FILTERED]') + end + + private + + def add_customer_data(post, options) + requires!(options, :user_id, :email) + post[:user] ||= {} + post[:user][:id] = options[:user_id] + post[:user][:email] = options[:email] + post[:user][:ip_address] = options[:ip] if options[:ip] + post[:user][:fiscal_number] = options[:fiscal_number] if options[:fiscal_number] + if phone = options[:phone] || options.dig(:billing_address, :phone) + post[:user][:phone] = phone + end + end + + def add_invoice(post, money, options) + post[:session_id] = options[:session_id] if options[:session_id] + + post[:order] ||= {} + post[:order][:amount] = amount(money).to_f + post[:order][:vat] = options[:vat] if options[:vat] + post[:order][:dev_reference] = options[:dev_reference] if options[:dev_reference] + post[:order][:description] = options[:description] if options[:description] + post[:order][:discount] = options[:discount] if options[:discount] + post[:order][:installments] = options[:installments] if options[:installments] + post[:order][:installments_type] = options[:installments_type] if options[:installments_type] + post[:order][:taxable_amount] = options[:taxable_amount] if options[:taxable_amount] + post[:order][:tax_percentage] = options[:tax_percentage] if options[:tax_percentage] + end + + def add_payment(post, payment) + post[:card] ||= {} + if payment.is_a?(String) + post[:card][:token] = payment + else + post[:card][:number] = payment.number + post[:card][:holder_name] = payment.name + post[:card][:expiry_month] = payment.month + post[:card][:expiry_year] = payment.year + post[:card][:cvc] = payment.verification_value + post[:card][:type] = CARD_MAPPING[payment.brand] + end + end + + def parse(body) + JSON.parse(body) + end + + def commit_raw(object, action, parameters) + url = "#{(test? ? test_url : live_url)}#{object}/#{action}" + + begin + raw_response = ssl_post(url, post_data(parameters), headers) + rescue ResponseError => e + raw_response = e.response.body + end + + begin + parse(raw_response) + rescue JSON::ParserError + {'status' => 'Internal server error'} + end + end + + def commit_transaction(action, parameters) + response = commit_raw('transaction', action, parameters) + Response.new( + success_from(response), + message_from(response), + response, + authorization: authorization_from(response), + test: test?, + error_code: error_code_from(response) + ) + end + + def commit_card(action, parameters) + response = commit_raw('card', action, parameters) + Response.new( + card_success_from(response), + card_message_from(response), + response, + authorization: card_authorization_from(response), + test: test?, + error_code: card_error_code_from(response) + ) + end + + def headers + { + 'Auth-Token' => authentication_code, + 'Content-Type' => 'application/json' + } + end + + def success_from(response) + !response.include?('error') && (response['status'] || response['transaction']['status']) == 'success' + end + + def card_success_from(response) + return false if response.include?('error') + return true if response['message'] == 'card deleted' + response['card']['status'] == 'valid' + end + + def message_from(response) + if !success_from(response) && response['error'] + response['error'] && response['error']['type'] + else + response['transaction'] && response['transaction']['message'] + end + end + + def card_message_from(response) + if !response.include?('error') + response['message'] || response['card']['message'] + else + response['error']['type'] + end + end + + def authorization_from(response) + response['transaction'] && response['transaction']['id'] + end + + def card_authorization_from(response) + response['card'] && response['card']['token'] + end + + def extract_previous_card_token(response) + match = /Card already added: (\d+)/.match(response.message) + match && match[1] + end + + def post_data(parameters = {}) + JSON.dump(parameters) + end + + def error_code_from(response) + return if success_from(response) + if response['transaction'] + detail = response['transaction']['status_detail'] + if STANDARD_ERROR_CODE_MAPPING.include?(detail) + return STANDARD_ERROR_CODE[STANDARD_ERROR_CODE_MAPPING[detail]] + end + elsif response['error'] + return STANDARD_ERROR_CODE[:config_error] + end + STANDARD_ERROR_CODE[:processing_error] + end + + def card_error_code_from(response) + STANDARD_ERROR_CODE[:processing_error] unless card_success_from(response) + end + + def authentication_code + timestamp = Time.new.to_i + unique_token = Digest::SHA256.hexdigest("#{@options[:app_key]}#{timestamp}") + authentication_string = "#{@options[:application_code]};#{timestamp};#{unique_token}" + Base64.encode64(authentication_string).delete("\n") + end + end + end +end diff --git a/lib/active_merchant/billing/gateways/paymill.rb b/lib/active_merchant/billing/gateways/paymill.rb index 63bb466bb71..caf64486d8b 100644 --- a/lib/active_merchant/billing/gateways/paymill.rb +++ b/lib/active_merchant/billing/gateways/paymill.rb @@ -10,7 +10,7 @@ class PaymillGateway < Gateway self.display_name = 'PAYMILL' self.money_format = :cents self.default_currency = 'EUR' - self.live_url = "https://api.paymill.com/v2/" + self.live_url = 'https://api.paymill.com/v2/' def initialize(options = {}) requires!(options, :public_key, :private_key) @@ -64,7 +64,7 @@ def scrub(transcript) def verify_credentials begin - ssl_get(live_url + "transactions/nonexistent", headers) + ssl_get(live_url + 'transactions/nonexistent', headers) rescue ResponseError => e return false if e.response.code.to_i == 401 end @@ -75,14 +75,14 @@ def verify_credentials private def add_credit_card(post, credit_card, options) - post['account.holder'] = (credit_card.try(:name) || "") + post['account.holder'] = (credit_card.try(:name) || '') post['account.number'] = credit_card.number - post['account.expiry.month'] = sprintf("%.2i", credit_card.month) - post['account.expiry.year'] = sprintf("%.4i", credit_card.year) + post['account.expiry.month'] = sprintf('%.2i', credit_card.month) + post['account.expiry.year'] = sprintf('%.4i', credit_card.year) post['account.verification'] = credit_card.verification_value post['account.email'] = (options[:email] || nil) post['presentation.amount3D'] = (options[:money] || nil) - post['presentation.currency3D'] = (options[:currency] || currency( options[:money])) + post['presentation.currency3D'] = (options[:currency] || currency(options[:money])) end def headers @@ -122,16 +122,16 @@ def authorization_from(parsed_response) [ parsed_data['id'], parsed_data['preauthorization'].try(:[], 'id') - ].join(";") + ].join(';') end def action_with_token(action, money, payment_method, options) options[:money] = money case payment_method - when String - self.send("#{action}_with_token", money, payment_method, options) - else - MultiResponse.run do |r| + when String + self.send("#{action}_with_token", money, payment_method, options) + else + MultiResponse.run do |r| r.process { save_card(payment_method, options) } r.process { self.send("#{action}_with_token", money, r.authorization, options) } end @@ -194,7 +194,7 @@ def post_data(params) return nil unless params no_blanks = params.reject { |key, value| value.blank? } - no_blanks.map { |key, value| "#{key}=#{CGI.escape(value.to_s)}" }.join("&") + no_blanks.map { |key, value| "#{key}=#{CGI.escape(value.to_s)}" }.join('&') end def add_amount(post, money, options) @@ -203,7 +203,7 @@ def add_amount(post, money, options) end def preauth(authorization) - authorization.split(";").last + authorization.split(';').last end def transaction_id(authorization) @@ -211,121 +211,119 @@ def transaction_id(authorization) end RESPONSE_CODES = { - 10001 => "Undefined response", - 10002 => "Waiting for something", - 11000 => "Retry request at a later time", - - 20000 => "Operation successful", - 20100 => "Funds held by acquirer", - 20101 => "Funds held by acquirer because merchant is new", - 20200 => "Transaction reversed", - 20201 => "Reversed due to chargeback", - 20202 => "Reversed due to money-back guarantee", - 20203 => "Reversed due to complaint by buyer", - 20204 => "Payment has been refunded", - 20300 => "Reversal has been canceled", - 22000 => "Initiation of transaction successful", - - 30000 => "Transaction still in progress", - 30100 => "Transaction has been accepted", - 31000 => "Transaction pending", - 31100 => "Pending due to address", - 31101 => "Pending due to uncleared eCheck", - 31102 => "Pending due to risk review", - 31103 => "Pending due regulatory review", - 31104 => "Pending due to unregistered/unconfirmed receiver", - 31200 => "Pending due to unverified account", - 31201 => "Pending due to non-captured funds", - 31202 => "Pending due to international account (accept manually)", - 31203 => "Pending due to currency conflict (accept manually)", - 31204 => "Pending due to fraud filters (accept manually)", - - - 40000 => "Problem with transaction data", - 40001 => "Problem with payment data", - 40002 => "Invalid checksum", - 40100 => "Problem with credit card data", - 40101 => "Problem with CVV", - 40102 => "Card expired or not yet valid", - 40103 => "Card limit exceeded", - 40104 => "Card is not valid", - 40105 => "Expiry date not valid", - 40106 => "Credit card brand required", - 40200 => "Problem with bank account data", - 40201 => "Bank account data combination mismatch", - 40202 => "User authentication failed", - 40300 => "Problem with 3-D Secure data", - 40301 => "Currency/amount mismatch", - 40400 => "Problem with input data", - 40401 => "Amount too low or zero", - 40402 => "Usage field too long", - 40403 => "Currency not allowed", - 40410 => "Problem with shopping cart data", - 40420 => "Problem with address data", - 40500 => "Permission error with acquirer API", - 40510 => "Rate limit reached for acquirer API", - 42000 => "Initiation of transaction failed", - 42410 => "Initiation of transaction expired", - - 50000 => "Problem with back end", - 50001 => "Country blacklisted", - 50002 => "IP address blacklisted", - 50004 => "Live mode not allowed", - 50005 => "Insufficient permissions (API key)", - 50100 => "Technical error with credit card", - 50101 => "Error limit exceeded", - 50102 => "Card declined", - 50103 => "Manipulation or stolen card", - 50104 => "Card restricted", - 50105 => "Invalid configuration data", - 50200 => "Technical error with bank account", - 50201 => "Account blacklisted", - 50300 => "Technical error with 3-D Secure", - 50400 => "Declined because of risk issues", - 50401 => "Checksum was wrong", - 50402 => "Bank account number was invalid (formal check)", - 50403 => "Technical error with risk check", - 50404 => "Unknown error with risk check", - 50405 => "Unknown bank code", - 50406 => "Open chargeback", - 50407 => "Historical chargeback", - 50408 => "Institution / public bank account (NCA)", - 50409 => "KUNO/Fraud", - 50410 => "Personal Account Protection (PAP)", - 50420 => "Rejected due to acquirer fraud settings", - 50430 => "Rejected due to acquirer risk settings", - 50440 => "Failed due to restrictions with acquirer account", - 50450 => "Failed due to restrictions with user account", - 50500 => "General timeout", - 50501 => "Timeout on side of the acquirer", - 50502 => "Risk management transaction timeout", - 50600 => "Duplicate operation", - 50700 => "Cancelled by user", - 50710 => "Failed due to funding source", - 50711 => "Payment method not usable, use other payment method", - 50712 => "Limit of funding source was exceeded", - 50713 => "Means of payment not reusable (canceled by user)", - 50714 => "Means of payment not reusable (expired)", - 50720 => "Rejected by acquirer", - 50730 => "Transaction denied by merchant", - 50800 => "Preauthorisation failed", - 50810 => "Authorisation has been voided", - 50820 => "Authorisation period expired" + 10001 => 'Undefined response', + 10002 => 'Waiting for something', + 11000 => 'Retry request at a later time', + + 20000 => 'Operation successful', + 20100 => 'Funds held by acquirer', + 20101 => 'Funds held by acquirer because merchant is new', + 20200 => 'Transaction reversed', + 20201 => 'Reversed due to chargeback', + 20202 => 'Reversed due to money-back guarantee', + 20203 => 'Reversed due to complaint by buyer', + 20204 => 'Payment has been refunded', + 20300 => 'Reversal has been canceled', + 22000 => 'Initiation of transaction successful', + + 30000 => 'Transaction still in progress', + 30100 => 'Transaction has been accepted', + 31000 => 'Transaction pending', + 31100 => 'Pending due to address', + 31101 => 'Pending due to uncleared eCheck', + 31102 => 'Pending due to risk review', + 31103 => 'Pending due regulatory review', + 31104 => 'Pending due to unregistered/unconfirmed receiver', + 31200 => 'Pending due to unverified account', + 31201 => 'Pending due to non-captured funds', + 31202 => 'Pending due to international account (accept manually)', + 31203 => 'Pending due to currency conflict (accept manually)', + 31204 => 'Pending due to fraud filters (accept manually)', + + 40000 => 'Problem with transaction data', + 40001 => 'Problem with payment data', + 40002 => 'Invalid checksum', + 40100 => 'Problem with credit card data', + 40101 => 'Problem with CVV', + 40102 => 'Card expired or not yet valid', + 40103 => 'Card limit exceeded', + 40104 => 'Card is not valid', + 40105 => 'Expiry date not valid', + 40106 => 'Credit card brand required', + 40200 => 'Problem with bank account data', + 40201 => 'Bank account data combination mismatch', + 40202 => 'User authentication failed', + 40300 => 'Problem with 3-D Secure data', + 40301 => 'Currency/amount mismatch', + 40400 => 'Problem with input data', + 40401 => 'Amount too low or zero', + 40402 => 'Usage field too long', + 40403 => 'Currency not allowed', + 40410 => 'Problem with shopping cart data', + 40420 => 'Problem with address data', + 40500 => 'Permission error with acquirer API', + 40510 => 'Rate limit reached for acquirer API', + 42000 => 'Initiation of transaction failed', + 42410 => 'Initiation of transaction expired', + + 50000 => 'Problem with back end', + 50001 => 'Country blacklisted', + 50002 => 'IP address blacklisted', + 50004 => 'Live mode not allowed', + 50005 => 'Insufficient permissions (API key)', + 50100 => 'Technical error with credit card', + 50101 => 'Error limit exceeded', + 50102 => 'Card declined', + 50103 => 'Manipulation or stolen card', + 50104 => 'Card restricted', + 50105 => 'Invalid configuration data', + 50200 => 'Technical error with bank account', + 50201 => 'Account blacklisted', + 50300 => 'Technical error with 3-D Secure', + 50400 => 'Declined because of risk issues', + 50401 => 'Checksum was wrong', + 50402 => 'Bank account number was invalid (formal check)', + 50403 => 'Technical error with risk check', + 50404 => 'Unknown error with risk check', + 50405 => 'Unknown bank code', + 50406 => 'Open chargeback', + 50407 => 'Historical chargeback', + 50408 => 'Institution / public bank account (NCA)', + 50409 => 'KUNO/Fraud', + 50410 => 'Personal Account Protection (PAP)', + 50420 => 'Rejected due to acquirer fraud settings', + 50430 => 'Rejected due to acquirer risk settings', + 50440 => 'Failed due to restrictions with acquirer account', + 50450 => 'Failed due to restrictions with user account', + 50500 => 'General timeout', + 50501 => 'Timeout on side of the acquirer', + 50502 => 'Risk management transaction timeout', + 50600 => 'Duplicate operation', + 50700 => 'Cancelled by user', + 50710 => 'Failed due to funding source', + 50711 => 'Payment method not usable, use other payment method', + 50712 => 'Limit of funding source was exceeded', + 50713 => 'Means of payment not reusable (canceled by user)', + 50714 => 'Means of payment not reusable (expired)', + 50720 => 'Rejected by acquirer', + 50730 => 'Transaction denied by merchant', + 50800 => 'Preauthorisation failed', + 50810 => 'Authorisation has been voided', + 50820 => 'Authorisation period expired' } def response_message(parsed_response) - return parsed_response["error"] if parsed_response["error"] - return "Transaction approved." if (parsed_response['data'] == []) + return parsed_response['error'] if parsed_response['error'] + return 'Transaction approved.' if parsed_response['data'] == [] - code = parsed_response["data"]["response_code"].to_i + code = parsed_response['data']['response_code'].to_i RESPONSE_CODES[code] || code.to_s end - class ResponseParser attr_reader :raw_response, :parsed, :succeeded, :message, :options - def initialize(raw_response="", options={}) + def initialize(raw_response='', options={}) @raw_response = raw_response @options = options end diff --git a/lib/active_merchant/billing/gateways/paypal.rb b/lib/active_merchant/billing/gateways/paypal.rb index 56f20ca4bea..465a0dd2b24 100644 --- a/lib/active_merchant/billing/gateways/paypal.rb +++ b/lib/active_merchant/billing/gateways/paypal.rb @@ -38,18 +38,6 @@ def express @express ||= PaypalExpressGateway.new(@options) end - def supports_scrubbing? - true - end - - def scrub(transcript) - transcript. - gsub(%r(().+()), '\1[FILTERED]\2'). - gsub(%r(().+()), '\1[FILTERED]\2'). - gsub(%r(().+()\d+().+()), '\1[FILTERED]\2'). + gsub(%r(().+()), '\1[FILTERED]\2'). + gsub(%r(().+()), '\1[FILTERED]\2'). + gsub(%r(().+()\d+( 2 xml.tag! action + 'Req', 'xmlns' => PAYPAL_NAMESPACE do diff --git a/lib/active_merchant/billing/gateways/paypal_digital_goods.rb b/lib/active_merchant/billing/gateways/paypal_digital_goods.rb index 80f3b5064a7..653a8c59015 100644 --- a/lib/active_merchant/billing/gateways/paypal_digital_goods.rb +++ b/lib/active_merchant/billing/gateways/paypal_digital_goods.rb @@ -30,7 +30,7 @@ def redirect_url_for(token, options = {}) # :category => "Digital" } ] ) def build_setup_request(action, money, options) requires!(options, :items) - raise ArgumentError, "Must include at least 1 Item" unless options[:items].length > 0 + raise ArgumentError, 'Must include at least 1 Item' unless options[:items].length > 0 options[:items].each do |item| requires!(item, :name, :number, :quantity, :amount, :description, :category) raise ArgumentError, "Each of the items must have the category 'Digital'" unless item[:category] == 'Digital' diff --git a/lib/active_merchant/billing/gateways/payscout.rb b/lib/active_merchant/billing/gateways/payscout.rb index 5fab0d5e67a..d2ad18b5a16 100644 --- a/lib/active_merchant/billing/gateways/payscout.rb +++ b/lib/active_merchant/billing/gateways/payscout.rb @@ -41,7 +41,6 @@ def capture(money, authorization, options = {}) commit('capture', money, post) end - def refund(money, authorization, options = {}) post = {} post[:transactionid] = authorization @@ -103,7 +102,7 @@ def add_creditcard(post, creditcard) end def parse(body) - Hash[body.split('&').map{|x|x.split('=')}] + Hash[body.split('&').map { |x| x.split('=') }] end def commit(action, money, parameters) @@ -153,10 +152,9 @@ def post_data(action, parameters = {}) post[:password] = @options[:password] post[:type] = action - request = post.merge(parameters).collect { |key, value| "#{key}=#{CGI.escape(value.to_s)}" }.join("&") + request = post.merge(parameters).collect { |key, value| "#{key}=#{CGI.escape(value.to_s)}" }.join('&') request end end end end - diff --git a/lib/active_merchant/billing/gateways/paystation.rb b/lib/active_merchant/billing/gateways/paystation.rb index 332899934da..0c2afac4358 100644 --- a/lib/active_merchant/billing/gateways/paystation.rb +++ b/lib/active_merchant/billing/gateways/paystation.rb @@ -2,7 +2,7 @@ module ActiveMerchant #:nodoc: module Billing #:nodoc: class PaystationGateway < Gateway - self.live_url = self.test_url = "https://www.paystation.co.nz/direct/paystation.dll" + self.live_url = self.test_url = 'https://www.paystation.co.nz/direct/paystation.dll' # an "error code" of "0" means "No error - transaction successful" SUCCESSFUL_RESPONSE_CODE = '0' @@ -75,7 +75,6 @@ def store(credit_card, options = {}) commit(post) end - def refund(money, authorization, options={}) post = new_request add_amount(post, money, options) @@ -85,109 +84,123 @@ def refund(money, authorization, options={}) commit(post) end - private + def verify(credit_card, options={}) + authorize(0, credit_card, options) + end - def new_request - { - :pi => @options[:paystation_id], # paystation account id - :gi => @options[:gateway_id], # paystation gateway id - "2p" => "t", # two-party transaction type - :nr => "t", # -- redirect?? - :df => "yymm" # date format: optional sometimes, required others - } - end + def supports_scrubbing? + true + end - def add_customer_data(post, options) - post[:mc] = options[:customer] - end + def scrub(transcript) + transcript. + gsub(%r((pstn_cn=)\d*), '\1[FILTERED]'). + gsub(%r((pstn_cc=)\d*), '\1[FILTERED]') + end - def add_invoice(post, options) - post[:ms] = generate_unique_id - post[:mo] = options[:description] - post[:mr] = options[:order_id] - end + private - def add_credit_card(post, credit_card) - post[:cn] = credit_card.number - post[:ct] = credit_card.brand - post[:ex] = format_date(credit_card.month, credit_card.year) - post[:cc] = credit_card.verification_value if credit_card.verification_value? - end + def new_request + { + :pi => @options[:paystation_id], # paystation account id + :gi => @options[:gateway_id], # paystation gateway id + '2p' => 't', # two-party transaction type + :nr => 't', # -- redirect?? + :df => 'yymm' # date format: optional sometimes, required others + } + end - def add_token(post, token) - post[:fp] = "t" # turn on "future payments" - what paystation calls Token Billing - post[:ft] = token - end + def add_customer_data(post, options) + post[:mc] = options[:customer] + end - def store_credit_card(post, options) - post[:fp] = "t" # turn on "future payments" - what paystation calls Token Billing - post[:fs] = "t" # tells paystation to store right now, not bill - post[:ft] = options[:token] if options[:token] # specify a token to use that, or let Paystation generate one - end + def add_invoice(post, options) + post[:ms] = generate_unique_id + post[:mo] = options[:description] + post[:mr] = options[:order_id] + end - def add_authorize_flag(post, options) - post[:pa] = "t" # tells Paystation that this is a pre-auth authorisation payment (account must be in pre-auth mode) - end + def add_credit_card(post, credit_card) + post[:cn] = credit_card.number + post[:ct] = credit_card.brand + post[:ex] = format_date(credit_card.month, credit_card.year) + post[:cc] = credit_card.verification_value if credit_card.verification_value? + end - def add_refund_specific_fields(post, authorization) - post[:rc] = "t" - post[:rt] = authorization - end + def add_token(post, token) + post[:fp] = 't' # turn on "future payments" - what paystation calls Token Billing + post[:ft] = token + end - def add_authorization_token(post, auth_token, verification_value = nil) - post[:cp] = "t" # Capture Payment flag – tells Paystation this transaction should be treated as a capture payment - post[:cx] = auth_token - post[:cc] = verification_value - end + def store_credit_card(post, options) + post[:fp] = 't' # turn on "future payments" - what paystation calls Token Billing + post[:fs] = 't' # tells paystation to store right now, not bill + post[:ft] = options[:token] if options[:token] # specify a token to use that, or let Paystation generate one + end - def add_amount(post, money, options) - post[:am] = amount(money) - post[:cu] = options[:currency] || currency(money) - end + def add_authorize_flag(post, options) + post[:pa] = 't' # tells Paystation that this is a pre-auth authorisation payment (account must be in pre-auth mode) + end + + def add_refund_specific_fields(post, authorization) + post[:rc] = 't' + post[:rt] = authorization + end - def parse(xml_response) - response = {} + def add_authorization_token(post, auth_token, verification_value = nil) + post[:cp] = 't' # Capture Payment flag – tells Paystation this transaction should be treated as a capture payment + post[:cx] = auth_token + post[:cc] = verification_value + end - xml = REXML::Document.new(xml_response) + def add_amount(post, money, options) + post[:am] = amount(money) + post[:cu] = options[:currency] || currency(money) + end - xml.elements.each("#{xml.root.name}/*") do |element| - response[element.name.underscore.to_sym] = element.text - end + def parse(xml_response) + response = {} - response + xml = REXML::Document.new(xml_response) + + xml.elements.each("#{xml.root.name}/*") do |element| + response[element.name.underscore.to_sym] = element.text end - def commit(post) - post[:tm] = "T" if test? - pstn_prefix_params = post.collect { |key, value| "pstn_#{key}=#{CGI.escape(value.to_s)}" }.join("&") + response + end - data = ssl_post(self.live_url, "#{pstn_prefix_params}&paystation=_empty") - response = parse(data) - message = message_from(response) + def commit(post) + post[:tm] = 'T' if test? + pstn_prefix_params = post.collect { |key, value| "pstn_#{key}=#{CGI.escape(value.to_s)}" }.join('&') - PaystationResponse.new(success?(response), message, response, - :test => (response[:tm] && response[:tm].downcase == "t"), - :authorization => response[:paystation_transaction_id] - ) - end + data = ssl_post(self.live_url, "#{pstn_prefix_params}&paystation=_empty") + response = parse(data) + message = message_from(response) - def success?(response) - (response[:ec] == SUCCESSFUL_RESPONSE_CODE) || (response[:ec] == SUCCESSFUL_FUTURE_PAYMENT) - end + PaystationResponse.new(success?(response), message, response, + :test => (response[:tm]&.casecmp('t')&.zero?), + :authorization => response[:paystation_transaction_id] + ) + end - def message_from(response) - response[:em] - end + def success?(response) + (response[:ec] == SUCCESSFUL_RESPONSE_CODE) || (response[:ec] == SUCCESSFUL_FUTURE_PAYMENT) + end - def format_date(month, year) - "#{format(year, :two_digits)}#{format(month, :two_digits)}" - end + def message_from(response) + response[:em] + end + + def format_date(month, year) + "#{format(year, :two_digits)}#{format(month, :two_digits)}" + end end class PaystationResponse < Response def token - @params["future_payment_token"] + @params['future_payment_token'] end end end diff --git a/lib/active_merchant/billing/gateways/payu_in.rb b/lib/active_merchant/billing/gateways/payu_in.rb index e9820ea315d..eabc32c1cd6 100644 --- a/lib/active_merchant/billing/gateways/payu_in.rb +++ b/lib/active_merchant/billing/gateways/payu_in.rb @@ -3,11 +3,11 @@ module ActiveMerchant #:nodoc: module Billing #:nodoc: class PayuInGateway < Gateway - self.test_url = "https://test.payu.in/_payment" - self.live_url = "https://secure.payu.in/_payment" + self.test_url = 'https://test.payu.in/_payment' + self.live_url = 'https://secure.payu.in/_payment' - TEST_INFO_URL = "https://test.payu.in/merchant/postservice.php?form=2" - LIVE_INFO_URL = "https://info.payu.in/merchant/postservice.php?form=2" + TEST_INFO_URL = 'https://test.payu.in/merchant/postservice.php?form=2' + LIVE_INFO_URL = 'https://info.payu.in/merchant/postservice.php?form=2' self.supported_countries = ['IN'] self.default_currency = 'INR' @@ -32,28 +32,28 @@ def purchase(money, payment, options={}) add_auth(post) MultiResponse.run do |r| - r.process{commit(url("purchase"), post)} - if(r.params["enrolled"].to_s == "0") - r.process{commit(r.params["post_uri"], r.params["form_post_vars"])} + r.process { commit(url('purchase'), post) } + if(r.params['enrolled'].to_s == '0') + r.process { commit(r.params['post_uri'], r.params['form_post_vars']) } else - r.process{handle_3dsecure(r)} + r.process { handle_3dsecure(r) } end end end def refund(money, authorization, options={}) - raise ArgumentError, "Amount is required" unless money + raise ArgumentError, 'Amount is required' unless money post = {} - post[:command] = "cancel_refund_transaction" + post[:command] = 'cancel_refund_transaction' post[:var1] = authorization post[:var2] = generate_unique_id post[:var3] = amount(money) add_auth(post, :command, :var1) - commit(url("refund"), post) + commit(url('refund'), post) end def supports_scrubbing? @@ -82,17 +82,17 @@ def add_auth(post, *digest_keys) digest_keys = PAYMENT_DIGEST_KEYS if digest_keys.empty? digest = Digest::SHA2.new(512) - digest << @options[:key] << "|" + digest << @options[:key] << '|' digest_keys.each do |key| - digest << (post[key.to_sym] || "") << "|" + digest << (post[key.to_sym] || '') << '|' end digest << @options[:salt] post[:hash] = digest.hexdigest end def add_customer_data(post, options) - post[:email] = clean(options[:email] || "unknown@example.com", nil, 50) - post[:phone] = clean((options[:billing_address] && options[:billing_address][:phone]) || "11111111111", :numeric, 50) + post[:email] = clean(options[:email] || 'unknown@example.com', nil, 50) + post[:phone] = clean((options[:billing_address] && options[:billing_address][:phone]) || '11111111111', :numeric, 50) end def add_addresses(post, options) @@ -109,7 +109,7 @@ def add_addresses(post, options) if options[:shipping_address][:name] first, *rest = options[:shipping_address][:name].split(/\s+/) post[:shipping_firstname] = clean(first, :name, 60) - post[:shipping_lastname] = clean(rest.join(" "), :name, 20) + post[:shipping_lastname] = clean(rest.join(' '), :name, 20) end post[:shipping_address1] = clean(options[:shipping_address][:address1], :text, 100) post[:shipping_address2] = clean(options[:shipping_address][:address2], :text, 100) @@ -125,22 +125,22 @@ def add_invoice(post, money, options) post[:amount] = amount(money) post[:txnid] = clean(options[:order_id], :alphanumeric, 30) - post[:productinfo] = clean(options[:description] || "Purchase", nil, 100) + post[:productinfo] = clean(options[:description] || 'Purchase', nil, 100) - post[:surl] = "http://example.com" - post[:furl] = "http://example.com" + post[:surl] = 'http://example.com' + post[:furl] = 'http://example.com' end BRAND_MAP = { - visa: "VISA", - master: "MAST", - american_express: "AMEX", - diners_club: "DINR", - maestro: "MAES" + visa: 'VISA', + master: 'MAST', + american_express: 'AMEX', + diners_club: 'DINR', + maestro: 'MAES' } def add_payment(post, payment) - post[:pg] = "CC" + post[:pg] = 'CC' post[:firstname] = clean(payment.first_name, :name, 60) post[:lastname] = clean(payment.last_name, :name, 20) @@ -153,16 +153,16 @@ def add_payment(post, payment) end def clean(value, format, maxlength) - value ||= "" + value ||= '' value = case format when :alphanumeric - value.gsub(/[^A-Za-z0-9]/, "") + value.gsub(/[^A-Za-z0-9]/, '') when :name - value.gsub(/[^A-Za-z ]/, "") + value.gsub(/[^A-Za-z ]/, '') when :numeric - value.gsub(/[^0-9]/, "") + value.gsub(/[^0-9]/, '') when :text - value.gsub(/[^A-Za-z0-9@\-_\/\. ]/, "") + value.gsub(/[^A-Za-z0-9@\-_\/\. ]/, '') when nil value else @@ -174,10 +174,10 @@ def clean(value, format, maxlength) def parse(body) top = JSON.parse(body) - if result = top.delete("result") - result.split("&").inject({}) do |hash, string| - key, value = string.split("=") - hash[CGI.unescape(key).downcase] = CGI.unescape(value || "") + if result = top.delete('result') + result.split('&').inject({}) do |hash, string| + key, value = string.split('=') + hash[CGI.unescape(key).downcase] = CGI.unescape(value || '') hash end.each do |key, value| if top[key] @@ -188,19 +188,19 @@ def parse(body) end end - if response = top.delete("response") + if response = top.delete('response') top.merge!(response) end top rescue JSON::ParserError { - "error" => "Invalid response received from the PayU API. (The raw response was `#{body}`)." + 'error' => "Invalid response received from the PayU API. (The raw response was `#{body}`)." } end def commit(url, parameters) - response = parse(ssl_post(url, post_data(parameters), "Accept-Encoding" => "identity")) + response = parse(ssl_post(url, post_data(parameters), 'Accept-Encoding' => 'identity')) Response.new( success_from(response), @@ -213,7 +213,7 @@ def commit(url, parameters) def url(action) case action - when "purchase" + when 'purchase' (test? ? test_url : live_url) else (test? ? TEST_INFO_URL : LIVE_INFO_URL) @@ -221,19 +221,19 @@ def url(action) end def success_from(response) - if response["result_status"] - (response["status"] == "success" && response["result_status"] == "success") + if response['result_status'] + (response['status'] == 'success' && response['result_status'] == 'success') else - (response["status"] == "success" || response["status"].to_s == "1") + (response['status'] == 'success' || response['status'].to_s == '1') end end def message_from(response) - (response["error_message"] || response["error"] || response["msg"]) + (response['error_message'] || response['error'] || response['msg']) end def authorization_from(response) - response["mihpayid"] + response['mihpayid'] end def post_data(parameters = {}) @@ -241,7 +241,7 @@ def post_data(parameters = {}) end def handle_3dsecure(response) - Response.new(false, "3D-secure enrolled cards are not supported.") + Response.new(false, '3D-secure enrolled cards are not supported.') end end end diff --git a/lib/active_merchant/billing/gateways/payu_latam.rb b/lib/active_merchant/billing/gateways/payu_latam.rb index 832a6754e70..1d2b995b083 100644 --- a/lib/active_merchant/billing/gateways/payu_latam.rb +++ b/lib/active_merchant/billing/gateways/payu_latam.rb @@ -3,33 +3,33 @@ module ActiveMerchant #:nodoc: module Billing #:nodoc: class PayuLatamGateway < Gateway - self.display_name = "PayU Latam" - self.homepage_url = "http://www.payulatam.com" + self.display_name = 'PayU Latam' + self.homepage_url = 'http://www.payulatam.com' - self.test_url = "https://sandbox.api.payulatam.com/payments-api/4.0/service.cgi" - self.live_url = "https://api.payulatam.com/payments-api/4.0/service.cgi" + self.test_url = 'https://sandbox.api.payulatam.com/payments-api/4.0/service.cgi' + self.live_url = 'https://api.payulatam.com/payments-api/4.0/service.cgi' - self.supported_countries = ["AR", "BR", "CL", "CO", "MX", "PA", "PE"] - self.default_currency = "USD" + self.supported_countries = ['AR', 'BR', 'CL', 'CO', 'MX', 'PA', 'PE'] + self.default_currency = 'USD' self.money_format = :dollars self.supported_cardtypes = [:visa, :master, :american_express, :diners_club] BRAND_MAP = { - "visa" => "VISA", - "master" => "MASTERCARD", - "american_express" => "AMEX", - "diners_club" => "DINERS" + 'visa' => 'VISA', + 'master' => 'MASTERCARD', + 'american_express' => 'AMEX', + 'diners_club' => 'DINERS' } MINIMUMS = { - "ARS" => 1700, - "BRL" => 600, - "MXN" => 3900, - "PEN" => 500 + 'ARS' => 1700, + 'BRL' => 600, + 'MXN' => 3900, + 'PEN' => 500 } def initialize(options={}) - requires!(options, :merchant_id, :account_id, :api_login, :api_key) + requires!(options, :merchant_id, :account_id, :api_login, :api_key, :payment_country) super end @@ -45,21 +45,26 @@ def authorize(amount, payment_method, options={}) commit('auth', post) end - def capture(authorization, options={}) + def capture(amount, authorization, options={}) post = {} - add_credentials(post, 'SUBMIT_TRANSACTION') - add_transaction_type(post, 'CAPTURE') + add_credentials(post, 'SUBMIT_TRANSACTION', options) + add_transaction_elements(post, 'CAPTURE', options) add_reference(post, authorization) + if !amount.nil? && amount.to_f != 0.0 + post[:transaction][:additionalValues] ||= {} + post[:transaction][:additionalValues][:TX_VALUE] = invoice_for(amount, options)[:TX_VALUE] + end + commit('capture', post) end def void(authorization, options={}) post = {} - add_credentials(post, 'SUBMIT_TRANSACTION') - add_transaction_type(post, 'VOID') + add_credentials(post, 'SUBMIT_TRANSACTION', options) + add_transaction_elements(post, 'VOID', options) add_reference(post, authorization) commit('void', post) @@ -68,8 +73,8 @@ def void(authorization, options={}) def refund(amount, authorization, options={}) post = {} - add_credentials(post, 'SUBMIT_TRANSACTION') - add_transaction_type(post, 'REFUND') + add_credentials(post, 'SUBMIT_TRANSACTION', options) + add_transaction_elements(post, 'REFUND', options) add_reference(post, authorization) commit('refund', post) @@ -77,7 +82,7 @@ def refund(amount, authorization, options={}) def verify(credit_card, options={}) minimum = MINIMUMS[options[:currency].upcase] if options[:currency] - amount = minimum || 100 + amount = options[:verify_amount] || minimum || 100 MultiResponse.run(:use_first_response) do |r| r.process { authorize(amount, credit_card, options) } @@ -115,20 +120,20 @@ def scrub(transcript) private def auth_or_sale(post, transaction_type, amount, payment_method, options) - add_credentials(post, 'SUBMIT_TRANSACTION') - add_transaction_type(post, transaction_type) + add_credentials(post, 'SUBMIT_TRANSACTION', options) + add_transaction_elements(post, transaction_type, options) add_order(post, options) - add_buyer(post, options) + add_buyer(post, payment_method, options) add_invoice(post, amount, options) add_signature(post) add_payment_method(post, payment_method, options) - add_payer(post, options) + add_payer(post, payment_method, options) add_extra_parameters(post, options) end - def add_credentials(post, command) + def add_credentials(post, command, options={}) post[:test] = test? unless command == 'CREATE_TOKEN' - post[:language] = 'en' + post[:language] = options[:language] || 'en' post[:command] = command merchant = {} merchant[:apiLogin] = @options[:api_login] @@ -136,47 +141,112 @@ def add_credentials(post, command) post[:merchant] = merchant end - def add_transaction_type(post, type) + def add_transaction_elements(post, type, options) transaction = {} + transaction[:paymentCountry] = @options[:payment_country] transaction[:type] = type + transaction[:ipAddress] = options[:ip] || '' + transaction[:userAgent] = options[:user_agent] if options[:user_agent] + transaction[:cookie] = options[:cookie] if options[:cookie] + transaction[:deviceSessionId] = options[:device_session_id] if options[:device_session_id] post[:transaction] = transaction end def add_order(post, options) order = {} order[:accountId] = @options[:account_id] + order[:partnerId] = options[:partner_id] if options[:partner_id] order[:referenceCode] = options[:order_id] || generate_unique_id - order[:description] = options[:description] || 'unspecified' - order[:language] = 'en' + order[:description] = options[:description] || 'Compra en ' + @options[:merchant_id] + order[:language] = options[:language] || 'en' + order[:shippingAddress] = shipping_address_fields(options) if options[:shipping_address] post[:transaction][:order] = order end - def add_buyer(post, options) - if address = options[:shipping_address] - buyer = {} - buyer[:fullName] = address[:name] - shipping_address = {} - shipping_address[:street1] = address[:address1] - shipping_address[:street2] = address[:address2] - shipping_address[:city] = address[:city] - shipping_address[:state] = address[:state] - shipping_address[:country] = address[:country] - shipping_address[:postalCode] = address[:zip] - shipping_address[:phone] = address[:phone] - buyer[:shippingAddress] = shipping_address - post[:transaction][:order][:buyer] = buyer + def add_payer(post, payment_method, options) + address = options[:billing_address] + payer = {} + payer[:fullName] = payment_method.name.strip + payer[:contactPhone] = address[:phone] if address && address[:phone] + payer[:dniNumber] = options[:dni_number] if options[:dni_number] + payer[:dniType] = options[:dni_type] if options[:dni_type] + payer[:emailAddress] = options[:email] if options[:email] + payer[:birthdate] = options[:birth_date] if options[:birth_date] && @options[:payment_country] == 'MX' + payer[:billingAddress] = billing_address_fields(options) + post[:transaction][:payer] = payer + end + + def billing_address_fields(options) + return unless address = options[:billing_address] + billing_address = {} + billing_address[:street1] = address[:address1] + billing_address[:street2] = address[:address2] + billing_address[:city] = address[:city] + billing_address[:state] = address[:state] + billing_address[:country] = address[:country] + billing_address[:postalCode] = address[:zip] if @options[:payment_country] == 'MX' + billing_address[:phone] = address[:phone] + billing_address + end + + def add_buyer(post, payment_method, options) + buyer = {} + if buyer_hash = options[:buyer] + buyer[:fullName] = buyer_hash[:name] + buyer[:dniNumber] = buyer_hash[:dni_number] + buyer[:dniType] = buyer_hash[:dni_type] + buyer[:cnpj] = buyer_hash[:cnpj] if @options[:payment_country] == 'BR' + buyer[:emailAddress] = buyer_hash[:email] + buyer[:contactPhone] = (options[:billing_address][:phone] if options[:billing_address]) || (options[:shipping_address][:phone] if options[:shipping_address]) || '' + buyer[:shippingAddress] = shipping_address_fields(options) if options[:shipping_address] + else + buyer[:fullName] = payment_method.name.strip + buyer[:dniNumber] = options[:dni_number] + buyer[:dniType] = options[:dni_type] + buyer[:cnpj] = options[:cnpj] if @options[:payment_country] == 'BR' + buyer[:emailAddress] = options[:email] + buyer[:contactPhone] = (options[:billing_address][:phone] if options[:billing_address]) || (options[:shipping_address][:phone] if options[:shipping_address]) || '' + buyer[:shippingAddress] = shipping_address_fields(options) if options[:shipping_address] end + post[:transaction][:order][:buyer] = buyer + end + + def shipping_address_fields(options) + return unless address = options[:shipping_address] + shipping_address = {} + shipping_address[:street1] = address[:address1] + shipping_address[:street2] = address[:address2] + shipping_address[:city] = address[:city] + shipping_address[:state] = address[:state] + shipping_address[:country] = address[:country] + shipping_address[:postalCode] = address[:zip] + shipping_address[:phone] = address[:phone] + shipping_address end def add_invoice(post, money, options) + post[:transaction][:order][:additionalValues] = invoice_for(money, options) + end + + def invoice_for(money, options) tx_value = {} tx_value[:value] = amount(money) tx_value[:currency] = options[:currency] || currency(money) + tx_tax = {} + tx_tax[:value] = options[:tax] || '0' + tx_tax[:currency] = options[:currency] || currency(money) + + tx_tax_return_base = {} + tx_tax_return_base[:value] = options[:tax_return_base] || '0' + tx_tax_return_base[:currency] = options[:currency] || currency(money) + additional_values = {} additional_values[:TX_VALUE] = tx_value + additional_values[:TX_TAX] = tx_tax if @options[:payment_country] == 'CO' + additional_values[:TX_TAX_RETURN_BASE] = tx_tax_return_base if @options[:payment_country] == 'CO' - post[:transaction][:order][:additionalValues] = additional_values + additional_values end def add_signature(post) @@ -190,7 +260,7 @@ def signature_from(post) post[:transaction][:order][:referenceCode], post[:transaction][:order][:additionalValues][:TX_VALUE][:value], post[:transaction][:order][:additionalValues][:TX_VALUE][:currency] - ].compact.join("~") + ].compact.join('~') Digest::MD5.hexdigest(signature_string) end @@ -207,7 +277,7 @@ def add_payment_method(post, payment_method, options) else credit_card = {} credit_card[:number] = payment_method.number - credit_card[:securityCode] = add_security_code(payment_method, options) + credit_card[:securityCode] = payment_method.verification_value || options[:cvv] credit_card[:expirationDate] = format(payment_method.year, :four_digits).to_s + '/' + format(payment_method.month, :two_digits).to_s credit_card[:name] = payment_method.name.strip credit_card[:processWithoutCvv2] = true if add_process_without_cvv2(payment_method, options) @@ -216,37 +286,11 @@ def add_payment_method(post, payment_method, options) end end - def add_security_code(payment_method, options) - return payment_method.verification_value unless payment_method.verification_value.blank? - return options[:cvv] unless options[:cvv].blank? - return "0000" if BRAND_MAP[payment_method.brand.to_s] == "AMEX" - "000" - end - def add_process_without_cvv2(payment_method, options) return true if payment_method.verification_value.blank? && options[:cvv].blank? false end - def add_payer(post, options) - if address = options[:billing_address] - payer = {} - post[:transaction][:paymentCountry] = address[:country] - payer[:fullName] = address[:name] - payer[:contactPhone] = address[:phone] - billing_address = {} - billing_address[:street1] = address[:address1] - billing_address[:street2] = address[:address2] - billing_address[:city] = address[:city] - billing_address[:state] = address[:state] - billing_address[:country] = address[:country] - billing_address[:postalCode] = address[:zip] - billing_address[:phone] = address[:phone] - payer[:billingAddress] = billing_address - post[:transaction][:payer] = payer - end - end - def add_extra_parameters(post, options) extra_parameters = {} extra_parameters[:INSTALLMENTS_NUMBER] = options[:installments_number] || 1 @@ -275,35 +319,34 @@ def add_payment_method_to_be_tokenized(post, payment_method) end def commit(action, params) - begin - raw_response = ssl_post(url, post_data(params), headers) - response = parse(raw_response) - rescue ResponseError => e - raw_response = e.response.body - response_error(raw_response) - rescue JSON::ParserError - unparsable_response(raw_response) - else - success = success_from(action, response) - Response.new( - success, - message_from(action, success, response), - response, - authorization: success ? authorization_from(action, response) : nil, - error_code: success ? nil : error_from(action, response), - test: test? - ) - end + raw_response = ssl_post(url, post_data(params), headers) + response = parse(raw_response) + rescue ResponseError => e + raw_response = e.response.body + response_error(raw_response) + rescue JSON::ParserError + unparsable_response(raw_response) + else + success = success_from(action, response) + Response.new( + success, + message_from(action, success, response), + response, + authorization: success ? authorization_from(action, response) : nil, + error_code: success ? nil : error_from(action, response), + test: test? + ) end def headers { - "Content-Type" => "application/json", - "Accept" => "application/json" + 'Content-Type' => 'application/json', + 'Accept' => 'application/json' } end def post_data(params) + params.merge(test: test?) params.to_json end @@ -318,30 +361,32 @@ def parse(body) def success_from(action, response) case action when 'store' - response["code"] == "SUCCESS" && response["creditCardToken"] && response["creditCardToken"]["creditCardTokenId"].present? + response['code'] == 'SUCCESS' && response['creditCardToken'] && response['creditCardToken']['creditCardTokenId'].present? when 'verify_credentials' - response["code"] == "SUCCESS" - when 'refund' - response["code"] == "SUCCESS" && response["transactionResponse"] && (response["transactionResponse"]["state"] == "PENDING" || response["transactionResponse"]["state"] == "APPROVED") + response['code'] == 'SUCCESS' + when 'refund', 'void' + response['code'] == 'SUCCESS' && response['transactionResponse'] && (response['transactionResponse']['state'] == 'PENDING' || response['transactionResponse']['state'] == 'APPROVED') else - response["code"] == "SUCCESS" && response["transactionResponse"] && (response["transactionResponse"]["state"] == "APPROVED") + response['code'] == 'SUCCESS' && response['transactionResponse'] && (response['transactionResponse']['state'] == 'APPROVED') end end def message_from(action, success, response) case action when 'store' - return response["code"] if success - error_description = response["creditCardToken"]["errorDescription"] if response["creditCardToken"] - response["error"] || error_description || "FAILED" + return response['code'] if success + error_description = response['creditCardToken']['errorDescription'] if response['creditCardToken'] + response['error'] || error_description || 'FAILED' when 'verify_credentials' - return "VERIFIED" if success - "FAILED" + return 'VERIFIED' if success + 'FAILED' else - response_message = response["transactionResponse"]["responseMessage"] if response["transactionResponse"] - response_code = response["transactionResponse"]["responseCode"] if response["transactionResponse"] + if response['transactionResponse'] + response_message = response['transactionResponse']['responseMessage'] + response_code = response['transactionResponse']['responseCode'] || response['transactionResponse']['pendingReason'] + end return response_code if success - response["error"] || response_message || response_code || "FAILED" + response['error'] || response_message || response_code || 'FAILED' end end @@ -349,51 +394,49 @@ def authorization_from(action, response) case action when 'store' [ - response["creditCardToken"]["paymentMethod"], - response["creditCardToken"]["creditCardTokenId"] - ].compact.join("|") + response['creditCardToken']['paymentMethod'], + response['creditCardToken']['creditCardTokenId'] + ].compact.join('|') when 'verify_credentials' nil else [ - response["transactionResponse"]["orderId"], - response["transactionResponse"]["transactionId"] - ].compact.join("|") + response['transactionResponse']['orderId'], + response['transactionResponse']['transactionId'] + ].compact.join('|') end end def split_authorization(authorization) - authorization.split("|") + authorization.split('|') end def error_from(action, response) case action when 'store' - response["creditCardToken"]["errorDescription"] if response["creditCardToken"] + response['creditCardToken']['errorDescription'] if response['creditCardToken'] when 'verify_credentials' - response["error"] || "FAILED" + response['error'] || 'FAILED' else - response["transactionResponse"]["errorCode"] || response["transactionResponse"]["responseCode"] if response["transactionResponse"] + response['transactionResponse']['errorCode'] || response['transactionResponse']['responseCode'] if response['transactionResponse'] end end def response_error(raw_response) - begin - response = parse(raw_response) - rescue JSON::ParserError - unparsable_response(raw_response) - else - return Response.new( - false, - message_from('', false, response), - response, - :test => test? - ) - end + response = parse(raw_response) + rescue JSON::ParserError + unparsable_response(raw_response) + else + return Response.new( + false, + message_from('', false, response), + response, + :test => test? + ) end def unparsable_response(raw_response) - message = "Invalid JSON response received from PayuLatamGateway. Please contact PayuLatamGateway if you continue to receive this message." + message = 'Invalid JSON response received from PayuLatamGateway. Please contact PayuLatamGateway if you continue to receive this message.' message += " (The raw response returned by the API was #{raw_response.inspect})" return Response.new(false, message) end diff --git a/lib/active_merchant/billing/gateways/payway.rb b/lib/active_merchant/billing/gateways/payway.rb index 10777f7b00a..b80e5f937a1 100644 --- a/lib/active_merchant/billing/gateways/payway.rb +++ b/lib/active_merchant/billing/gateways/payway.rb @@ -150,7 +150,7 @@ def add_payment_method(post, payment_method) post['card.cardHolderName'] = "#{payment_method.first_name} #{payment_method.last_name}" post['card.PAN'] = payment_method.number post['card.CVN'] = payment_method.verification_value - post['card.expiryYear'] = payment_method.year.to_s[-2,2] + post['card.expiryYear'] = payment_method.year.to_s[-2, 2] post['card.expiryMonth'] = sprintf('%02d', payment_method.month) else post['customer.customerReferenceNumber'] = payment_method @@ -177,30 +177,30 @@ def add_auth(post) # Creates the request and returns the summarized result def commit(action, post) add_auth(post) - post.merge!('order.type' => TRANSACTIONS[action]) + post['order.type'] = TRANSACTIONS[action] - request = post.map { |k, v| "#{k}=#{CGI.escape(v.to_s)}" }.join("&") + request = post.map { |k, v| "#{k}=#{CGI.escape(v.to_s)}" }.join('&') response = ssl_post(self.live_url, request) params = {} CGI.parse(response).each_pair do |key, value| - actual_key = key.split(".").last + actual_key = key.split('.').last params[actual_key.underscore.to_sym] = value[0] end message = "#{SUMMARY_CODES[params[:summary_code]]} - #{RESPONSE_CODES[params[:response_code]]}" - success = (params[:summary_code] ? (params[:summary_code] == "0") : (params[:response_code] == "00")) + success = (params[:summary_code] ? (params[:summary_code] == '0') : (params[:response_code] == '00')) Response.new(success, message, params, - :test => (@options[:merchant].to_s == "TEST"), + :test => (@options[:merchant].to_s == 'TEST'), :authorization => post[:order_number] ) rescue ActiveMerchant::ResponseError => e raise unless e.response.code == '403' - return Response.new(false, "Invalid credentials", {}, :test => test?) + return Response.new(false, 'Invalid credentials', {}, :test => test?) rescue ActiveMerchant::ClientCertificateError - return Response.new(false, "Invalid certificate", {}, :test => test?) + return Response.new(false, 'Invalid certificate', {}, :test => test?) end end end diff --git a/lib/active_merchant/billing/gateways/pin.rb b/lib/active_merchant/billing/gateways/pin.rb index 5c9b5b86e27..676ffb6f7af 100644 --- a/lib/active_merchant/billing/gateways/pin.rb +++ b/lib/active_merchant/billing/gateways/pin.rb @@ -29,6 +29,7 @@ def purchase(money, creditcard, options = {}) add_creditcard(post, creditcard) add_address(post, creditcard, options) add_capture(post, options) + add_metadata(post, options) commit(:post, 'charges', post, options) end @@ -83,6 +84,7 @@ def scrub(transcript) gsub(/(number\\?":\\?")(\d*)/, '\1[FILTERED]'). gsub(/(cvc\\?":\\?")(\d*)/, '\1[FILTERED]') end + private def add_amount(post, money, options) @@ -112,13 +114,14 @@ def add_address(post, creditcard, options) end def add_invoice(post, options) - post[:description] = options[:description] || "Active Merchant Purchase" + post[:description] = options[:description] || 'Active Merchant Purchase' + post[:reference] = options[:reference] if options[:reference] end def add_capture(post, options) capture = options[:capture] - post[:capture] = capture == false ? false : true + post[:capture] = capture != false end def add_creditcard(post, creditcard) @@ -141,10 +144,14 @@ def add_creditcard(post, creditcard) end end + def add_metadata(post, options) + post[:metadata] = options[:metadata] if options[:metadata] + end + def headers(params = {}) result = { - "Content-Type" => "application/json", - "Authorization" => "Basic #{Base64.strict_encode64(options[:api_key] + ':').strip}" + 'Content-Type' => 'application/json', + 'Authorization' => "Basic #{Base64.strict_encode64(options[:api_key] + ':').strip}" } result['X-Partner-Key'] = params[:partner_key] if params[:partner_key] @@ -162,18 +169,17 @@ def commit(method, action, params, options) body = parse(e.response.body) end - if body["response"] + if body['response'] success_response(body) - elsif body["error"] + elsif body['error'] error_response(body) end - rescue JSON::ParserError return unparsable_response(raw_response) end def success_response(body) - response = body["response"] + response = body['response'] Response.new( true, response['status_message'], @@ -194,7 +200,7 @@ def error_response(body) end def unparsable_response(raw_response) - message = "Invalid JSON response received from Pin Payments. Please contact support@pin.net.au if you continue to receive this message." + message = 'Invalid JSON response received from Pin Payments. Please contact support@pin.net.au if you continue to receive this message.' message += " (The raw response returned by the API was #{raw_response.inspect})" return Response.new(false, message) end diff --git a/lib/active_merchant/billing/gateways/plugnpay.rb b/lib/active_merchant/billing/gateways/plugnpay.rb index bb48c0f228e..36becf69ff8 100644 --- a/lib/active_merchant/billing/gateways/plugnpay.rb +++ b/lib/active_merchant/billing/gateways/plugnpay.rb @@ -3,80 +3,80 @@ module Billing class PlugnpayGateway < Gateway class PlugnpayPostData < PostData # Fields that will be sent even if they are blank - self.required_fields = [ :publisher_name, :publisher_password, - :card_amount, :card_name, :card_number, :card_exp, :orderID ] + self.required_fields = [:publisher_name, :publisher_password, + :card_amount, :card_name, :card_number, :card_exp, :orderID] end self.live_url = self.test_url = 'https://pay1.plugnpay.com/payment/pnpremote.cgi' CARD_CODE_MESSAGES = { - "M" => "Card verification number matched", - "N" => "Card verification number didn't match", - "P" => "Card verification number was not processed", - "S" => "Card verification number should be on card but was not indicated", - "U" => "Issuer was not certified for card verification" + 'M' => 'Card verification number matched', + 'N' => "Card verification number didn't match", + 'P' => 'Card verification number was not processed', + 'S' => 'Card verification number should be on card but was not indicated', + 'U' => 'Issuer was not certified for card verification' } CARD_CODE_ERRORS = %w( N S ) AVS_MESSAGES = { - "A" => "Street address matches billing information, zip/postal code does not", - "B" => "Address information not provided for address verification check", - "E" => "Address verification service error", - "G" => "Non-U.S. card-issuing bank", - "N" => "Neither street address nor zip/postal match billing information", - "P" => "Address verification not applicable for this transaction", - "R" => "Payment gateway was unavailable or timed out", - "S" => "Address verification service not supported by issuer", - "U" => "Address information is unavailable", - "W" => "9-digit zip/postal code matches billing information, street address does not", - "X" => "Street address and 9-digit zip/postal code matches billing information", - "Y" => "Street address and 5-digit zip/postal code matches billing information", - "Z" => "5-digit zip/postal code matches billing information, street address does not", + 'A' => 'Street address matches billing information, zip/postal code does not', + 'B' => 'Address information not provided for address verification check', + 'E' => 'Address verification service error', + 'G' => 'Non-U.S. card-issuing bank', + 'N' => 'Neither street address nor zip/postal match billing information', + 'P' => 'Address verification not applicable for this transaction', + 'R' => 'Payment gateway was unavailable or timed out', + 'S' => 'Address verification service not supported by issuer', + 'U' => 'Address information is unavailable', + 'W' => '9-digit zip/postal code matches billing information, street address does not', + 'X' => 'Street address and 9-digit zip/postal code matches billing information', + 'Y' => 'Street address and 5-digit zip/postal code matches billing information', + 'Z' => '5-digit zip/postal code matches billing information, street address does not', } AVS_ERRORS = %w( A E N R W Z ) PAYMENT_GATEWAY_RESPONSES = { - "P01" => "AVS Mismatch Failure", - "P02" => "CVV2 Mismatch Failure", - "P21" => "Transaction may not be marked", - "P30" => "Test Tran. Bad Card", - "P35" => "Test Tran. Problem", - "P40" => "Username already exists", - "P41" => "Username is blank", - "P50" => "Fraud Screen Failure", - "P51" => "Missing PIN Code", - "P52" => "Invalid Bank Acct. No.", - "P53" => "Invalid Bank Routing No.", - "P54" => "Invalid/Missing Check No.", - "P55" => "Invalid Credit Card No.", - "P56" => "Invalid CVV2/CVC2 No.", - "P57" => "Expired. CC Exp. Date", - "P58" => "Missing Data", - "P59" => "Missing Email Address", - "P60" => "Zip Code does not match Billing State.", - "P61" => "Invalid Billing Zip Code", - "P62" => "Zip Code does not match Shipping State.", - "P63" => "Invalid Shipping Zip Code", - "P64" => "Invalid Credit Card CVV2/CVC2 Format.", - "P65" => "Maximum number of attempts has been exceeded.", - "P66" => "Credit Card number has been flagged and can not be used to access this service.", - "P67" => "IP Address is on Blocked List.", - "P68" => "Billing country does not match ipaddress country.", - "P69" => "US based ipaddresses are currently blocked.", - "P70" => "Credit Cards issued from this bank are currently not being accepted.", - "P71" => "Credit Cards issued from this bank are currently not being accepted.", - "P72" => "Daily volume exceeded.", - "P73" => "Too many transactions within allotted time.", - "P91" => "Missing/incorrect password", - "P92" => "Account not configured for mobil administration", - "P93" => "IP Not registered to username.", - "P94" => "Mode not permitted for this account.", - "P95" => "Currently Blank", - "P96" => "Currently Blank", - "P97" => "Processor not responding", - "P98" => "Missing merchant/publisher name", - "P99" => "Currently Blank" + 'P01' => 'AVS Mismatch Failure', + 'P02' => 'CVV2 Mismatch Failure', + 'P21' => 'Transaction may not be marked', + 'P30' => 'Test Tran. Bad Card', + 'P35' => 'Test Tran. Problem', + 'P40' => 'Username already exists', + 'P41' => 'Username is blank', + 'P50' => 'Fraud Screen Failure', + 'P51' => 'Missing PIN Code', + 'P52' => 'Invalid Bank Acct. No.', + 'P53' => 'Invalid Bank Routing No.', + 'P54' => 'Invalid/Missing Check No.', + 'P55' => 'Invalid Credit Card No.', + 'P56' => 'Invalid CVV2/CVC2 No.', + 'P57' => 'Expired. CC Exp. Date', + 'P58' => 'Missing Data', + 'P59' => 'Missing Email Address', + 'P60' => 'Zip Code does not match Billing State.', + 'P61' => 'Invalid Billing Zip Code', + 'P62' => 'Zip Code does not match Shipping State.', + 'P63' => 'Invalid Shipping Zip Code', + 'P64' => 'Invalid Credit Card CVV2/CVC2 Format.', + 'P65' => 'Maximum number of attempts has been exceeded.', + 'P66' => 'Credit Card number has been flagged and can not be used to access this service.', + 'P67' => 'IP Address is on Blocked List.', + 'P68' => 'Billing country does not match ipaddress country.', + 'P69' => 'US based ipaddresses are currently blocked.', + 'P70' => 'Credit Cards issued from this bank are currently not being accepted.', + 'P71' => 'Credit Cards issued from this bank are currently not being accepted.', + 'P72' => 'Daily volume exceeded.', + 'P73' => 'Too many transactions within allotted time.', + 'P91' => 'Missing/incorrect password', + 'P92' => 'Account not configured for mobil administration', + 'P93' => 'IP Not registered to username.', + 'P94' => 'Mode not permitted for this account.', + 'P95' => 'Currently Blank', + 'P96' => 'Currently Blank', + 'P97' => 'Processor not responding', + 'P98' => 'Missing merchant/publisher name', + 'P99' => 'Currently Blank' } TRANSACTIONS = { @@ -172,8 +172,9 @@ def refund(money, reference, options = {}) end private + def commit(action, post) - response = parse( ssl_post(self.live_url, post_data(action, post)) ) + response = parse(ssl_post(self.live_url, post_data(action, post))) success = SUCCESS_CODES.include?(response[:finalstatus]) message = success ? 'Success' : message_from(response) @@ -188,7 +189,7 @@ def commit(action, post) def parse(body) body = CGI.unescape(body) results = {} - body.split('&').collect { |e| e.split('=') }.each do |key,value| + body.split('&').collect { |e| e.split('=') }.each do |key, value| results[key.downcase.to_sym] = normalize(value.to_s.strip) end @@ -273,8 +274,8 @@ def message_from(results) end def expdate(creditcard) - year = sprintf("%.4i", creditcard.year) - month = sprintf("%.2i", creditcard.month) + year = sprintf('%.4i', creditcard.year) + month = sprintf('%.2i', creditcard.month) "#{month}/#{year[-2..-1]}" end diff --git a/lib/active_merchant/billing/gateways/pro_pay.rb b/lib/active_merchant/billing/gateways/pro_pay.rb new file mode 100644 index 00000000000..d70b1539bb0 --- /dev/null +++ b/lib/active_merchant/billing/gateways/pro_pay.rb @@ -0,0 +1,326 @@ +require 'nokogiri' + +module ActiveMerchant #:nodoc: + module Billing #:nodoc: + class ProPayGateway < Gateway + self.test_url = 'https://xmltest.propay.com/API/PropayAPI.aspx' + self.live_url = 'https://epay.propay.com/api/propayapi.aspx' + + self.supported_countries = ['US', 'CA'] + self.default_currency = 'USD' + self.money_format = :cents + self.supported_cardtypes = [:visa, :master, :american_express, :discover] + + self.homepage_url = 'https://www.propay.com/' + self.display_name = 'ProPay' + + STATUS_RESPONSE_CODES = { + '00' => 'Success', + '20' => 'Invalid username', + '21' => 'Invalid transType', + '22' => 'Invalid Currency Code', + '23' => 'Invalid accountType', + '24' => 'Invalid sourceEmail', + '25' => 'Invalid firstName', + '26' => 'Invalid mInitial', + '27' => 'Invalid lastName', + '28' => 'Invalid billAddr', + '29' => 'Invalid aptNum', + '30' => 'Invalid city', + '31' => 'Invalid state', + '32' => 'Invalid billZip', + '33' => 'Invalid mailAddr', + '34' => 'Invalid mailApt', + '35' => 'Invalid mailCity', + '36' => 'Invalid mailState', + '37' => 'Invalid mailZip', + '38' => 'Invalid dayPhone', + '39' => 'Invalid evenPhone', + '40' => 'Invalid ssn', + '41' => 'Invalid dob', + '42' => 'Invalid recEmail', + '43' => 'Invalid knownAccount', + '44' => 'Invalid amount', + '45' => 'Invalid invNum', + '46' => 'Invalid rtNum', + '47' => 'Invalid accntNum', + '48' => 'Invalid ccNum', + '49' => 'Invalid expDate', + '50' => 'Invalid cvv2', + '51' => 'Invalid transNum and/or Unable to act perform actions on transNum due to funding', + '52' => 'Invalid splitNum', + '53' => 'A ProPay account with this email address already exists AND/OR User has no account number', + '54' => 'A ProPay account with this social security number already exists', + '55' => 'The email address provided does not correspond to a ProPay account.', + '56' => 'Recipient’s email address shouldn’t have a ProPay account and does', + '57' => 'Cannot settle transaction because it already expired', + '58' => 'Credit card declined', + '59' => 'Invalid Credential or IP address not allowed', + '60' => 'Credit card authorization timed out; retry at a later time', + '61' => 'Amount exceeds single transaction limit', + '62' => 'Amount exceeds monthly volume limit', + '63' => 'Insufficient funds in account', + '64' => 'Over credit card use limit', + '65' => 'Miscellaneous error', + '66' => 'Denied a ProPay account', + '67' => 'Unauthorized service requested', + '68' => 'Account not affiliated', + '69' => 'Duplicate invoice number (The same card was charged for the same amount with the same invoice number (including blank invoices) in a 1 minute period. Details about the original transaction are included whenever a 69 response is returned. These details include a repeat of the auth code, the original AVS response, and the original CVV response.)', + '70' => 'Duplicate external ID', + '71' => 'Account previously set up, but problem affiliating it with partner', + '72' => 'The ProPay Account has already been upgraded to a Premium Account', + '73' => 'Invalid Destination Account', + '74' => 'Account or Trans Error', + '75' => 'Money already pulled', + '76' => 'Not Premium (used only for push/pull transactions)', + '77' => 'Empty results', + '78' => 'Invalid Authentication', + '79' => 'Generic account status error', + '80' => 'Invalid Password', + '81' => 'Account Expired', + '82' => 'InvalidUserID', + '83' => 'BatchTransCountError', + '84' => 'InvalidBeginDate', + '85' => 'InvalidEndDate', + '86' => 'InvalidExternalID', + '87' => 'DuplicateUserID', + '88' => 'Invalid track 1', + '89' => 'Invalid track 2', + '90' => 'Transaction already refunded', + '91' => 'Duplicate Batch ID' + } + + TRANSACTION_RESPONSE_CODES = { + '00' => 'Success', + '1' => 'Transaction blocked by issuer', + '4' => 'Pick up card and deny transaction', + '5' => 'Problem with the account', + '6' => 'Customer requested stop to recurring payment', + '7' => 'Customer requested stop to all recurring payments', + '8' => 'Honor with ID only', + '9' => 'Unpaid items on customer account', + '12' => 'Invalid transaction', + '13' => 'Amount Error', + '14' => 'Invalid card number', + '15' => 'No such issuer. Could not route transaction', + '16' => 'Refund error', + '17' => 'Over limit', + '19' => 'Reenter transaction or the merchant account may be boarded incorrectly', + '25' => 'Invalid terminal 41 Lost card', + '43' => 'Stolen card', + '51' => 'Insufficient funds', + '52' => 'No such account', + '54' => 'Expired card', + '55' => 'Incorrect PIN', + '57' => 'Bank does not allow this type of purchase', + '58' => 'Credit card network does not allow this type of purchase for your merchant account.', + '61' => 'Exceeds issuer withdrawal limit', + '62' => 'Issuer does not allow this card to be charged for your business.', + '63' => 'Security Violation', + '65' => 'Activity limit exceeded', + '75' => 'PIN tries exceeded', + '76' => 'Unable to locate account', + '78' => 'Account not recognized', + '80' => 'Invalid Date', + '82' => 'Invalid CVV2', + '83' => 'Cannot verify the PIN', + '85' => 'Service not supported for this card', + '93' => 'Cannot complete transaction. Customer should call 800 number.', + '95' => 'Misc Error Transaction failure', + '96' => 'Issuer system malfunction or timeout.', + '97' => 'Approved for a lesser amount. ProPay will not settle and consider this a decline.', + '98' => 'Failure HV', + '99' => 'Generic decline or unable to parse issuer response code' + } + + def initialize(options={}) + requires!(options, :cert_str) + super + end + + def purchase(money, payment, options={}) + request = build_xml_request do |xml| + add_invoice(xml, money, options) + add_payment(xml, payment, options) + add_address(xml, options) + add_account(xml, options) + add_recurring(xml, options) + xml.transType '04' + end + + commit(request) + end + + def authorize(money, payment, options={}) + request = build_xml_request do |xml| + add_invoice(xml, money, options) + add_payment(xml, payment, options) + add_address(xml, options) + add_account(xml, options) + add_recurring(xml, options) + xml.transType '05' + end + + commit(request) + end + + def capture(money, authorization, options={}) + request = build_xml_request do |xml| + add_invoice(xml, money, options) + add_account(xml, options) + xml.transNum authorization + xml.transType '06' + end + + commit(request) + end + + def refund(money, authorization, options={}) + request = build_xml_request do |xml| + add_invoice(xml, money, options) + add_account(xml, options) + xml.transNum authorization + xml.transType '07' + end + + commit(request) + end + + def void(authorization, options={}) + refund(nil, authorization, options) + end + + def credit(money, payment, options={}) + request = build_xml_request do |xml| + add_invoice(xml, money, options) + add_payment(xml, payment, options) + add_account(xml, options) + xml.transType '35' + end + + commit(request) + end + + def verify(credit_card, options={}) + MultiResponse.run(:use_first_response) do |r| + r.process { authorize(100, credit_card, options) } + r.process(:ignore_result) { void(r.authorization, options) } + end + end + + def supports_scrubbing? + true + end + + def scrub(transcript) + transcript. + gsub(%r(().+()), '\1[FILTERED]\2'). + gsub(%r(().+()), '\1[FILTERED]\2'). + gsub(%r(().+()), '\1[FILTERED]\2') + end + + private + + def add_payment(xml, payment, options) + xml.ccNum payment.number + xml.expDate "#{format(payment.month, :two_digits)}#{format(payment.year, :two_digits)}" + xml.CVV2 payment.verification_value + xml.cardholderName payment.name + end + + def add_address(xml, options) + if address = options[:billing_address] || options[:address] + xml.addr address[:address1] + xml.aptNum address[:address2] + xml.city address[:city] + xml.state address[:state] + xml.zip address[:zip] + end + end + + def add_account(xml, options) + xml.accountNum options[:account_num] + end + + def add_invoice(xml, money, options) + xml.amount amount(money) + xml.currencyCode options[:currency] || currency(money) + xml.invNum options[:order_id] || SecureRandom.hex(25) + end + + def add_recurring(xml, options) + xml.recurringPayment options[:recurring_payment] + end + + def parse(body) + results = {} + xml = Nokogiri::XML(body) + resp = xml.xpath('//XMLResponse/XMLTrans') + resp.children.each do |element| + results[element.name.underscore.downcase.to_sym] = element.text + end + results + end + + def commit(parameters) + url = (test? ? test_url : live_url) + response = parse(ssl_post(url, parameters)) + + Response.new( + success_from(response), + message_from(response), + response, + authorization: authorization_from(response), + avs_result: AVSResult.new(code: response[:avs]), + cvv_result: CVVResult.new(response[:cvv2_resp]), + test: test?, + error_code: error_code_from(response) + ) + end + + def success_from(response) + response[:status] == '00' + end + + def message_from(response) + return 'Success' if success_from(response) + message = STATUS_RESPONSE_CODES[response[:status]] + message += " - #{TRANSACTION_RESPONSE_CODES[response[:response_code]]}" if response[:response_code] + + message + end + + def authorization_from(response) + response[:trans_num] + end + + def error_code_from(response) + unless success_from(response) + response[:status] + end + end + + def build_xml_request + builder = Nokogiri::XML::Builder.new do |xml| + xml.XMLRequest do + xml.certStr @options[:cert_str] + xml.class_ 'partner' + xml.XMLTrans do + yield(xml) + end + end + end + + builder.to_xml + end + end + + def underscore(camel_cased_word) + camel_cased_word.to_s.gsub(/::/, '/'). + gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2'). + gsub(/([a-z\d])([A-Z])/, '\1_\2'). + tr('-', '_'). + downcase + end + end +end diff --git a/lib/active_merchant/billing/gateways/psigate.rb b/lib/active_merchant/billing/gateways/psigate.rb index f6e017359e2..b987dd1e74b 100644 --- a/lib/active_merchant/billing/gateways/psigate.rb +++ b/lib/active_merchant/billing/gateways/psigate.rb @@ -35,8 +35,8 @@ module Billing #:nodoc: # :email => 'jack@yahoo.com' # ) class PsigateGateway < Gateway - self.test_url = 'https://dev.psigate.com:7989/Messenger/XMLMessenger' - self.live_url = 'https://secure.psigate.com:17934/Messenger/XMLMessenger' + self.test_url = 'https://realtimestaging.psigate.com/xml' + self.live_url = 'https://realtime.psigate.com/xml' self.supported_cardtypes = [:visa, :master, :american_express] self.supported_countries = ['CA'] @@ -53,18 +53,18 @@ def initialize(options = {}) def authorize(money, creditcard, options = {}) requires!(options, :order_id) - options[:CardAction] = "1" + options[:CardAction] = '1' commit(money, creditcard, options) end def purchase(money, creditcard, options = {}) requires!(options, :order_id) - options[:CardAction] = "0" + options[:CardAction] = '0' commit(money, creditcard, options) end def capture(money, authorization, options = {}) - options[:CardAction] = "2" + options[:CardAction] = '2' options[:order_id], options[:trans_ref_number] = split_authorization(authorization) commit(money, nil, options) end @@ -75,17 +75,28 @@ def credit(money, authorization, options = {}) end def refund(money, authorization, options = {}) - options[:CardAction] = "3" + options[:CardAction] = '3' options[:order_id], options[:trans_ref_number] = split_authorization(authorization) commit(money, nil, options) end def void(authorization, options = {}) - options[:CardAction] = "9" + options[:CardAction] = '9' options[:order_id], options[:trans_ref_number] = split_authorization(authorization) commit(nil, nil, options) end + def supports_scrubbing? + true + end + + def scrub(transcript) + transcript. + gsub(%r(()[^<]*())i, '\1[FILTERED]\2'). + gsub(%r(()[^<]*())i, '\1[FILTERED]\2'). + gsub(%r(()[^<]*())i, '\1[FILTERED]\2') + end + private def commit(money, creditcard, options = {}) @@ -93,7 +104,7 @@ def commit(money, creditcard, options = {}) Response.new(successful?(response), message_from(response), response, :test => test?, - :authorization => build_authorization(response) , + :authorization => build_authorization(response), :avs_result => { :code => response[:avsresult] }, :cvv_result => response[:cardidresult] ) @@ -104,11 +115,11 @@ def url end def successful?(response) - response[:approved] == "APPROVED" + response[:approved] == 'APPROVED' end def parse(xml) - response = {:message => "Global Error Receipt", :complete => false} + response = {:message => 'Global Error Receipt', :complete => false} xml = REXML::Document.new(xml) xml.elements.each('//Result/*') do |node| @@ -121,7 +132,7 @@ def parse(xml) def post_data(money, creditcard, options) xml = REXML::Document.new xml << REXML::XMLDecl.new - root = xml.add_element("Order") + root = xml.add_element('Order') parameters(money, creditcard, options).each do |key, value| root.add_element(key.to_s).text = value if value @@ -144,7 +155,7 @@ def parameters(money, creditcard, options = {}) :TransRefNumber => options[:trans_ref_number], # Credit Card parameters - :PaymentType => "CC", + :PaymentType => 'CC', :CardAction => options[:CardAction], # Financial parameters @@ -156,9 +167,9 @@ def parameters(money, creditcard, options = {}) } if creditcard - exp_month = sprintf("%.2i", creditcard.month) unless creditcard.month.blank? - exp_year = creditcard.year.to_s[2,2] unless creditcard.year.blank? - card_id_code = (creditcard.verification_value.blank? ? nil : "1") + exp_month = sprintf('%.2i', creditcard.month) unless creditcard.month.blank? + exp_year = creditcard.year.to_s[2, 2] unless creditcard.year.blank? + card_id_code = (creditcard.verification_value.blank? ? nil : '1') params.update( :CardNumber => creditcard.number, @@ -195,11 +206,11 @@ def parameters(money, creditcard, options = {}) end def message_from(response) - if response[:approved] == "APPROVED" + if response[:approved] == 'APPROVED' return SUCCESS_MESSAGE else return FAILURE_MESSAGE if response[:errmsg].blank? - return response[:errmsg].gsub(/[^\w]/, ' ').split.join(" ").capitalize + return response[:errmsg].gsub(/[^\w]/, ' ').split.join(' ').capitalize end end @@ -209,7 +220,7 @@ def split_authorization(authorization) end def build_authorization(response) - [response[:orderid], response[:transrefnumber]].join(";") + [response[:orderid], response[:transrefnumber]].join(';') end end end diff --git a/lib/active_merchant/billing/gateways/psl_card.rb b/lib/active_merchant/billing/gateways/psl_card.rb index 10027303daf..77da4a123db 100644 --- a/lib/active_merchant/billing/gateways/psl_card.rb +++ b/lib/active_merchant/billing/gateways/psl_card.rb @@ -17,11 +17,11 @@ class PslCardGateway < Gateway self.default_currency = 'GBP' self.supported_countries = ['GB'] - # Visa Credit, Visa Debit, Mastercard, Maestro, Solo, Electron, + # Visa Credit, Visa Debit, Mastercard, Maestro, Electron, # American Express, Diners Club, JCB, International Maestro, # Style, Clydesdale Financial Services, Other - self.supported_cardtypes = [ :visa, :master, :american_express, :diners_club, :jcb, :switch, :solo, :maestro ] + self.supported_cardtypes = [ :visa, :master, :american_express, :diners_club, :jcb, :maestro ] self.homepage_url = 'http://www.paymentsolutionsltd.com/' self.display_name = 'PSL Payment Solutions' @@ -46,38 +46,38 @@ class PslCardGateway < Gateway 'USD' => 840 } - #The terminal used - only for swipe transactions, so hard coded to 32 for online + # The terminal used - only for swipe transactions, so hard coded to 32 for online EMV_TERMINAL_TYPE = 32 - #Different Dispatch types + # Different Dispatch types DISPATCH_LATER = 'LATER' DISPATCH_NOW = 'NOW' # Return codes APPROVED = '00' - #Nominal amount to authorize for a 'dispatch later' type - #The nominal amount is held straight away, when the goods are ready - #to be dispatched, PSL is informed and the full amount is the - #taken. + # Nominal amount to authorize for a 'dispatch later' type + # The nominal amount is held straight away, when the goods are ready + # to be dispatched, PSL is informed and the full amount is the + # taken. NOMINAL_AMOUNT = 101 AVS_CODE = { - "ALL MATCH" => 'Y', - "SECURITY CODE MATCH ONLY" => 'N', - "ADDRESS MATCH ONLY" => 'Y', - "NO DATA MATCHES" => 'N', - "DATA NOT CHECKED" => 'R', - "SECURITY CHECKS NOT SUPPORTED" => 'X' + 'ALL MATCH' => 'Y', + 'SECURITY CODE MATCH ONLY' => 'N', + 'ADDRESS MATCH ONLY' => 'Y', + 'NO DATA MATCHES' => 'N', + 'DATA NOT CHECKED' => 'R', + 'SECURITY CHECKS NOT SUPPORTED' => 'X' } CVV_CODE = { - "ALL MATCH" => 'M', - "SECURITY CODE MATCH ONLY" => 'M', - "ADDRESS MATCH ONLY" => 'N', - "NO DATA MATCHES" => 'N', - "DATA NOT CHECKED" => 'P', - "SECURITY CHECKS NOT SUPPORTED" => 'X' + 'ALL MATCH' => 'M', + 'SECURITY CODE MATCH ONLY' => 'M', + 'ADDRESS MATCH ONLY' => 'N', + 'NO DATA MATCHES' => 'N', + 'DATA NOT CHECKED' => 'P', + 'SECURITY CHECKS NOT SUPPORTED' => 'X' } # Create a new PslCardGateway @@ -174,12 +174,6 @@ def add_credit_card(post, credit_card) post[:ExpMonth] = credit_card.month post[:ExpYear] = credit_card.year - if requires_start_date_or_issue_number?(credit_card) - post[:IssueNumber] = credit_card.issue_number unless credit_card.issue_number.blank? - post[:StartMonth] = credit_card.start_month unless credit_card.start_month.blank? - post[:StartYear] = credit_card.start_year unless credit_card.start_year.blank? - end - # CV2 check post[:AVSCV2Check] = credit_card.verification_value? ? 'YES' : 'NO' post[:CV2] = credit_card.verification_value if credit_card.verification_value? @@ -189,7 +183,7 @@ def add_address(post, options) address = options[:billing_address] || options[:address] return if address.nil? - post[:QAAddress] = [:address1, :address2, :city, :state].collect{|a| address[a]}.reject{|a| a.blank?}.join(' ') + post[:QAAddress] = [:address1, :address2, :city, :state].collect { |a| address[a] }.reject(&:blank?).join(' ') post[:QAPostcode] = address[:zip] end @@ -246,10 +240,9 @@ def currency_code(currency) # -a hash with all of the values returned in the PSL response # def parse(body) - fields = {} for line in body.split('&') - key, value = *line.scan( %r{^(\w+)\=(.*)$} ).flatten + key, value = *line.scan(%r{^(\w+)\=(.*)$}).flatten fields[key] = CGI.unescape(value) end fields.symbolize_keys @@ -264,7 +257,7 @@ def parse(body) # - ActiveMerchant::Billing::Response object # def commit(request) - response = parse( ssl_post(self.live_url, post_data(request)) ) + response = parse(ssl_post(self.live_url, post_data(request))) Response.new(response[:ResponseCode] == APPROVED, response[:Message], response, :test => test?, @@ -296,7 +289,7 @@ def post_data(post) post.collect { |key, value| "#{key}=#{CGI.escape(value.to_s.tr('&=', ' '))}" - }.join("&") + }.join('&') end end end diff --git a/lib/active_merchant/billing/gateways/qbms.rb b/lib/active_merchant/billing/gateways/qbms.rb index 2beedc826e4..5d37f900bf4 100644 --- a/lib/active_merchant/billing/gateways/qbms.rb +++ b/lib/active_merchant/billing/gateways/qbms.rb @@ -5,8 +5,8 @@ class QbmsGateway < Gateway class_attribute :test_url, :live_url - self.test_url = "https://webmerchantaccount.ptc.quickbooks.com/j/AppGateway" - self.live_url = "https://webmerchantaccount.quickbooks.com/j/AppGateway" + self.test_url = 'https://webmerchantaccount.ptc.quickbooks.com/j/AppGateway' + self.live_url = 'https://webmerchantaccount.quickbooks.com/j/AppGateway' self.homepage_url = 'http://payments.intuit.com/' self.display_name = 'QuickBooks Merchant Services' @@ -101,7 +101,7 @@ def void(authorization, options = {}) # def credit(money, identification, options = {}) ActiveMerchant.deprecated CREDIT_DEPRECATION_MESSAGE - refund(money, identification, options = {}) + refund(money, identification, {}) end def refund(money, identification, options = {}) @@ -113,6 +113,17 @@ def query commit(:query, nil, {}) end + def supports_scrubbing? + true + end + + def scrub(transcript) + transcript. + gsub(%r(()[^<]*())i, '\1[FILTERED]\2'). + gsub(%r(()[^<]*())i, '\1[FILTERED]\2'). + gsub(%r(()[^<]*())i, '\1[FILTERED]\2') + end + private def hosted? @@ -127,7 +138,7 @@ def commit(action, money, parameters) req = build_request(type, money, parameters) - data = ssl_post(url, req, "Content-Type" => "application/x-qbmsxml") + data = ssl_post(url, req, 'Content-Type' => 'application/x-qbmsxml') response = parse(type, data) message = (response[:status_message] || '').strip @@ -152,20 +163,20 @@ def parse(type, body) xml = REXML::Document.new(body) signon = REXML::XPath.first(xml, "//SignonMsgsRs/#{hosted? ? 'SignonAppCertRs' : 'SignonDesktopRs'}") - status_code = signon.attributes["statusCode"].to_i + status_code = signon.attributes['statusCode'].to_i if status_code != 0 return { :status_code => status_code, - :status_message => signon.attributes["statusMessage"], + :status_message => signon.attributes['statusMessage'], } end response = REXML::XPath.first(xml, "//QBMSXMLMsgsRs/#{type}Rs") results = { - :status_code => response.attributes["statusCode"].to_i, - :status_message => response.attributes["statusMessage"], + :status_code => response.attributes['statusCode'].to_i, + :status_message => response.attributes['statusMessage'], } response.elements.each do |e| @@ -189,16 +200,16 @@ def build_request(type, money, parameters = {}) xml.instruct!(:xml, :version => '1.0', :encoding => 'utf-8') xml.instruct!(:qbmsxml, :version => API_VERSION) - xml.tag!("QBMSXML") do - xml.tag!("SignonMsgsRq") do - xml.tag!(hosted? ? "SignonAppCertRq" : "SignonDesktopRq") do - xml.tag!("ClientDateTime", Time.now.xmlschema) - xml.tag!("ApplicationLogin", @options[:login]) - xml.tag!("ConnectionTicket", @options[:ticket]) + xml.tag!('QBMSXML') do + xml.tag!('SignonMsgsRq') do + xml.tag!(hosted? ? 'SignonAppCertRq' : 'SignonDesktopRq') do + xml.tag!('ClientDateTime', Time.now.xmlschema) + xml.tag!('ApplicationLogin', @options[:login]) + xml.tag!('ConnectionTicket', @options[:ticket]) end end - xml.tag!("QBMSXMLMsgsRq") do + xml.tag!('QBMSXMLMsgsRq') do xml.tag!("#{type}Rq") do method("build_#{type}").call(xml, money, parameters) end @@ -212,47 +223,47 @@ def build_CustomerCreditCardAuth(xml, money, parameters) cc = parameters[:credit_card] name = "#{cc.first_name} #{cc.last_name}"[0...30] - xml.tag!("TransRequestID", parameters[:trans_request_id]) - xml.tag!("CreditCardNumber", cc.number) - xml.tag!("ExpirationMonth", cc.month) - xml.tag!("ExpirationYear", cc.year) - xml.tag!("IsECommerce", "true") - xml.tag!("Amount", amount(money)) - xml.tag!("NameOnCard", name) + xml.tag!('TransRequestID', parameters[:trans_request_id]) + xml.tag!('CreditCardNumber', cc.number) + xml.tag!('ExpirationMonth', cc.month) + xml.tag!('ExpirationYear', cc.year) + xml.tag!('IsECommerce', 'true') + xml.tag!('Amount', amount(money)) + xml.tag!('NameOnCard', name) add_address(xml, parameters) - xml.tag!("CardSecurityCode", cc.verification_value) if cc.verification_value? + xml.tag!('CardSecurityCode', cc.verification_value) if cc.verification_value? end def build_CustomerCreditCardCapture(xml, money, parameters) - xml.tag!("TransRequestID", parameters[:trans_request_id]) - xml.tag!("CreditCardTransID", parameters[:transaction_id]) - xml.tag!("Amount", amount(money)) + xml.tag!('TransRequestID', parameters[:trans_request_id]) + xml.tag!('CreditCardTransID', parameters[:transaction_id]) + xml.tag!('Amount', amount(money)) end def build_CustomerCreditCardCharge(xml, money, parameters) cc = parameters[:credit_card] name = "#{cc.first_name} #{cc.last_name}"[0...30] - xml.tag!("TransRequestID", parameters[:trans_request_id]) - xml.tag!("CreditCardNumber", cc.number) - xml.tag!("ExpirationMonth", cc.month) - xml.tag!("ExpirationYear", cc.year) - xml.tag!("IsECommerce", "true") - xml.tag!("Amount", amount(money)) - xml.tag!("NameOnCard", name) + xml.tag!('TransRequestID', parameters[:trans_request_id]) + xml.tag!('CreditCardNumber', cc.number) + xml.tag!('ExpirationMonth', cc.month) + xml.tag!('ExpirationYear', cc.year) + xml.tag!('IsECommerce', 'true') + xml.tag!('Amount', amount(money)) + xml.tag!('NameOnCard', name) add_address(xml, parameters) - xml.tag!("CardSecurityCode", cc.verification_value) if cc.verification_value? + xml.tag!('CardSecurityCode', cc.verification_value) if cc.verification_value? end def build_CustomerCreditCardTxnVoidOrRefund(xml, money, parameters) - xml.tag!("TransRequestID", parameters[:trans_request_id]) - xml.tag!("CreditCardTransID", parameters[:transaction_id]) - xml.tag!("Amount", amount(money)) + xml.tag!('TransRequestID', parameters[:trans_request_id]) + xml.tag!('CreditCardTransID', parameters[:transaction_id]) + xml.tag!('Amount', amount(money)) end def build_CustomerCreditCardTxnVoid(xml, money, parameters) - xml.tag!("TransRequestID", parameters[:trans_request_id]) - xml.tag!("CreditCardTransID", parameters[:transaction_id]) + xml.tag!('TransRequestID', parameters[:trans_request_id]) + xml.tag!('CreditCardTransID', parameters[:transaction_id]) end # Called reflectively by build_request @@ -261,30 +272,30 @@ def build_MerchantAccountQuery(xml, money, parameters) def add_address(xml, parameters) if address = parameters[:billing_address] || parameters[:address] - xml.tag!("CreditCardAddress", (address[:address1] || "")[0...30]) - xml.tag!("CreditCardPostalCode", (address[:zip] || "")[0...9]) + xml.tag!('CreditCardAddress', (address[:address1] || '')[0...30]) + xml.tag!('CreditCardPostalCode', (address[:zip] || '')[0...9]) end end def cvv_result(response) case response[:card_security_code_match] - when "Pass" then 'M' - when "Fail" then 'N' - when "NotAvailable" then 'P' + when 'Pass' then 'M' + when 'Fail' then 'N' + when 'NotAvailable' then 'P' end end def avs_result(response) case "#{response[:avs_street]}|#{response[:avs_zip]}" - when "Pass|Pass" then "D" - when "Pass|Fail" then "A" - when "Pass|NotAvailable" then "B" - when "Fail|Pass" then "Z" - when "Fail|Fail" then "C" - when "Fail|NotAvailable" then "N" - when "NotAvailable|Pass" then "P" - when "NotAvailable|Fail" then "N" - when "NotAvailable|NotAvailable" then "U" + when 'Pass|Pass' then 'D' + when 'Pass|Fail' then 'A' + when 'Pass|NotAvailable' then 'B' + when 'Fail|Pass' then 'Z' + when 'Fail|Fail' then 'C' + when 'Fail|NotAvailable' then 'N' + when 'NotAvailable|Pass' then 'P' + when 'NotAvailable|Fail' then 'N' + when 'NotAvailable|NotAvailable' then 'U' end end end diff --git a/lib/active_merchant/billing/gateways/quantum.rb b/lib/active_merchant/billing/gateways/quantum.rb index 9dd778eca3f..4fd43ad07ca 100644 --- a/lib/active_merchant/billing/gateways/quantum.rb +++ b/lib/active_merchant/billing/gateways/quantum.rb @@ -44,7 +44,7 @@ def initialize(options = {}) # def authorize(money, creditcard, options = {}) setup_address_hash(options) - commit(build_auth_request(money, creditcard, options), options ) + commit(build_auth_request(money, creditcard, options), options) end # Capture an authorization that has previously been requested @@ -81,7 +81,7 @@ def setup_address_hash(options) def build_auth_request(money, creditcard, options) xml = Builder::XmlMarkup.new - add_common_credit_card_info(xml,'AUTH_ONLY') + add_common_credit_card_info(xml, 'AUTH_ONLY') add_purchase_data(xml, money) add_creditcard(xml, creditcard) add_address(xml, creditcard, options[:billing_address], options) @@ -94,7 +94,7 @@ def build_auth_request(money, creditcard, options) def build_capture_request(money, authorization, options) xml = Builder::XmlMarkup.new - add_common_credit_card_info(xml,'PREVIOUS_SALE') + add_common_credit_card_info(xml, 'PREVIOUS_SALE') transaction_id, _ = authorization_parts_from(authorization) add_transaction_id(xml, transaction_id) xml.target! @@ -115,7 +115,7 @@ def build_purchase_request(money, creditcard, options) def build_void_request(authorization, options) xml = Builder::XmlMarkup.new - add_common_credit_card_info(xml,'VOID') + add_common_credit_card_info(xml, 'VOID') transaction_id, _ = authorization_parts_from(authorization) add_transaction_id(xml, transaction_id) xml.target! @@ -123,7 +123,7 @@ def build_void_request(authorization, options) def build_credit_request(money, authorization, options) xml = Builder::XmlMarkup.new - add_common_credit_card_info(xml,'RETURN') + add_common_credit_card_info(xml, 'RETURN') add_purchase_data(xml, money) transaction_id, cc = authorization_parts_from(authorization) add_transaction_id(xml, transaction_id) @@ -182,7 +182,7 @@ def add_creditcard(xml, creditcard) xml.tag! 'CreditCardNumber', creditcard.number xml.tag! 'ExpireMonth', format(creditcard.month, :two_digits) xml.tag! 'ExpireYear', format(creditcard.year, :four_digits) - xml.tag!('CVV2', creditcard.verification_value) unless (@options[:ignore_cvv] || creditcard.verification_value.blank? ) + xml.tag!('CVV2', creditcard.verification_value) unless @options[:ignore_cvv] || creditcard.verification_value.blank? end # Where we actually build the full SOAP request using builder @@ -206,7 +206,7 @@ def commit(request, options) headers = { 'Content-Type' => 'text/xml' } response = parse(ssl_post(self.live_url, build_request(request, options), headers)) - success = response[:request_status] == "Success" + success = response[:request_status] == 'Success' message = response[:request_message] if success # => checking for connectivity success first @@ -216,10 +216,10 @@ def commit(request, options) end Response.new(success, message, response, - :test => test?, - :authorization => authorization, - :avs_result => { :code => response[:AVSResponseCode] }, - :cvv_result => response[:CVV2ResponseCode] + :test => test?, + :authorization => authorization, + :avs_result => { :code => response[:AVSResponseCode] }, + :cvv_result => response[:CVV2ResponseCode] ) end @@ -231,19 +231,19 @@ def parse(xml) begin xml = REXML::Document.new(xml) - root = REXML::XPath.first(xml, "//QGWRequest/ResponseSummary") + root = REXML::XPath.first(xml, '//QGWRequest/ResponseSummary') parse_element(reply, root) reply[:request_status] = reply[:Status] reply[:request_message] = "#{reply[:Status]}: #{reply[:StatusDescription]}" - if root = REXML::XPath.first(xml, "//QGWRequest/Result") + if root = REXML::XPath.first(xml, '//QGWRequest/Result') root.elements.to_a.each do |node| parse_element(reply, node) end end rescue Exception reply[:request_status] = 'Failure' - reply[:request_message] = "Failure: There was a problem parsing the response XML" + reply[:request_message] = 'Failure: There was a problem parsing the response XML' end return reply @@ -251,10 +251,10 @@ def parse(xml) def parse_element(reply, node) if node.has_elements? - node.elements.each{|e| parse_element(reply, e) } + node.elements.each { |e| parse_element(reply, e) } else if node.parent.name =~ /item/ - parent = node.parent.name + (node.parent.attributes["id"] ? "_" + node.parent.attributes["id"] : '') + parent = node.parent.name + (node.parent.attributes['id'] ? '_' + node.parent.attributes['id'] : '') reply[(parent + '_' + node.name).to_sym] = node.text else reply[node.name.to_sym] = node.text diff --git a/lib/active_merchant/billing/gateways/quickbooks.rb b/lib/active_merchant/billing/gateways/quickbooks.rb index 15ae55d54ce..6759a57aee6 100644 --- a/lib/active_merchant/billing/gateways/quickbooks.rb +++ b/lib/active_merchant/billing/gateways/quickbooks.rb @@ -10,7 +10,7 @@ class QuickbooksGateway < Gateway self.homepage_url = 'http://payments.intuit.com' self.display_name = 'QuickBooks Payments' - ENDPOINT = "/quickbooks/v4/payments/charges" + ENDPOINT = '/quickbooks/v4/payments/charges' OAUTH_ENDPOINTS = { site: 'https://oauth.intuit.com', request_token_path: '/oauth/v1/get_request_token', @@ -48,7 +48,7 @@ class QuickbooksGateway < Gateway 'PMT-6000' => STANDARD_ERROR_CODE[:processing_error], # A temporary Issue prevented this request from being processed. } - FRAUD_WARNING_CODES = ['PMT-1000','PMT-1001','PMT-1002','PMT-1003'] + FRAUD_WARNING_CODES = ['PMT-1000', 'PMT-1001', 'PMT-1002', 'PMT-1003'] def initialize(options = {}) requires!(options, :consumer_key, :consumer_secret, :access_token, :token_secret, :realm) @@ -60,7 +60,7 @@ def purchase(money, payment, options = {}) post = {} add_amount(post, money, options) add_charge_data(post, payment, options) - post[:capture] = "true" + post[:capture] = 'true' commit(ENDPOINT, post) end @@ -69,7 +69,7 @@ def authorize(money, payment, options = {}) post = {} add_amount(post, money, options) add_charge_data(post, payment, options) - post[:capture] = "false" + post[:capture] = 'false' commit(ENDPOINT, post) end @@ -78,6 +78,7 @@ def capture(money, authorization, options = {}) post = {} capture_uri = "#{ENDPOINT}/#{CGI.escape(authorization)}/capture" post[:amount] = localized_amount(money, currency(money)) + add_context(post, options) commit(capture_uri, post) end @@ -85,6 +86,7 @@ def capture(money, authorization, options = {}) def refund(money, authorization, options = {}) post = {} post[:amount] = localized_amount(money, currency(money)) + add_context(post, options) commit(refund_uri(authorization), post) end @@ -116,7 +118,7 @@ def add_charge_data(post, payment, options = {}) end def add_address(post, options) - return unless post[:card] && post[:card].kind_of?(Hash) + return unless post[:card]&.kind_of?(Hash) card_address = {} if address = options[:billing_address] || options[:address] @@ -137,12 +139,13 @@ def add_amount(post, money, options = {}) def add_payment(post, payment, options = {}) add_creditcard(post, payment, options) + add_context(post, options) end def add_creditcard(post, creditcard, options = {}) card = {} card[:number] = creditcard.number - card[:expMonth] = "%02d" % creditcard.month + card[:expMonth] = '%02d' % creditcard.month card[:expYear] = creditcard.year card[:cvc] = creditcard.verification_value if creditcard.verification_value? card[:name] = creditcard.name if creditcard.name @@ -151,6 +154,13 @@ def add_creditcard(post, creditcard, options = {}) post[:card] = card end + def add_context(post, options = {}) + post[:context] = { + mobile: options.fetch(:mobile, false), + isEcommerce: options.fetch(:ecommerce, true) + } + end + def parse(body) JSON.parse(body) end @@ -208,28 +218,28 @@ def headers(method, uri) oauth_nonce: generate_unique_id, oauth_timestamp: Time.now.to_i.to_s, oauth_signature_method: 'HMAC-SHA1', - oauth_version: "1.0", + oauth_version: '1.0', oauth_consumer_key: @options[:consumer_key], oauth_token: @options[:access_token] } # prepare components for signature - oauth_signature_base_string = [method.to_s.upcase, request_uri.to_s, oauth_parameters.to_param].map{|v| CGI.escape(v) }.join('&') - oauth_signing_key = [@options[:consumer_secret], @options[:token_secret]].map{|v| CGI.escape(v)}.join('&') + oauth_signature_base_string = [method.to_s.upcase, request_uri.to_s, oauth_parameters.to_param].map { |v| CGI.escape(v) }.join('&') + oauth_signing_key = [@options[:consumer_secret], @options[:token_secret]].map { |v| CGI.escape(v) }.join('&') hmac_signature = OpenSSL::HMAC.digest(OpenSSL::Digest.new('sha1'), oauth_signing_key, oauth_signature_base_string) # append signature to required OAuth parameters oauth_parameters[:oauth_signature] = CGI.escape(Base64.encode64(hmac_signature).chomp.gsub(/\n/, '')) # prepare Authorization header string - oauth_parameters = Hash[oauth_parameters.sort_by {|k, _| k}] + oauth_parameters = Hash[oauth_parameters.sort_by { |k, _| k }] oauth_headers = ["OAuth realm=\"#{@options[:realm]}\""] - oauth_headers += oauth_parameters.map {|k, v| "#{k}=\"#{v}\""} + oauth_headers += oauth_parameters.map { |k, v| "#{k}=\"#{v}\"" } { - "Content-type" => "application/json", - "Request-Id" => generate_unique_id, - "Authorization" => oauth_headers.join(', ') + 'Content-type' => 'application/json', + 'Request-Id' => generate_unique_id, + 'Authorization' => oauth_headers.join(', ') } end @@ -242,17 +252,17 @@ def cvv_code_from(response) end def success?(response) - return FRAUD_WARNING_CODES.concat(['0']).include?(response['errors'].first['code']) if response['errors'] - - !['DECLINED', 'CANCELLED'].include?(response['status']) + return FRAUD_WARNING_CODES.concat(['0']).include?(response['errors'].first['code']) if response['errors'] + + !['DECLINED', 'CANCELLED'].include?(response['status']) end def message_from(response) - response['errors'].present? ? response["errors"].map {|error_hash| error_hash["message"] }.join(" ") : response['status'] + response['errors'].present? ? response['errors'].map { |error_hash| error_hash['message'] }.join(' ') : response['status'] end def errors_from(response) - response['errors'].present? ? STANDARD_ERROR_CODE_MAPPING[response["errors"].first["code"]] : "" + response['errors'].present? ? STANDARD_ERROR_CODE_MAPPING[response['errors'].first['code']] : '' end def authorization_from(response) diff --git a/lib/active_merchant/billing/gateways/quickpay.rb b/lib/active_merchant/billing/gateways/quickpay.rb index 6fe34125cbc..5c1f6fb33bb 100644 --- a/lib/active_merchant/billing/gateways/quickpay.rb +++ b/lib/active_merchant/billing/gateways/quickpay.rb @@ -10,17 +10,16 @@ class QuickpayGateway < Gateway self.abstract_class = true def self.new(options = {}) - options.fetch(:login) rescue raise ArgumentError.new("Missing required parameter: login") + options.fetch(:login) { raise ArgumentError.new('Missing required parameter: login') } version = options[:login].to_i < 10000000 ? 10 : 7 if version <= 7 QuickpayV4to7Gateway.new(options) else - QuickpayV10Gateway.new(options) + QuickpayV10Gateway.new(options) end end - + end end end - diff --git a/lib/active_merchant/billing/gateways/quickpay/quickpay_common.rb b/lib/active_merchant/billing/gateways/quickpay/quickpay_common.rb index b1b2c5e0099..930958e0cbb 100644 --- a/lib/active_merchant/billing/gateways/quickpay/quickpay_common.rb +++ b/lib/active_merchant/billing/gateways/quickpay/quickpay_common.rb @@ -1,6 +1,4 @@ - module QuickpayCommon - MD5_CHECK_FIELDS = { 3 => { :authorize => %w(protocol msgtype merchant ordernumber amount @@ -138,9 +136,9 @@ module QuickpayCommon :chstatus => %w(protocol msgtype merchant apikey) }, - + 10 => { - :authorize => %w(mobile_number acquirer autofee customer_id extras + :authorize => %w(mobile_number acquirer autofee customer_id extras zero_auth customer_ip), :capture => %w( extras ), :cancel => %w( extras ), @@ -150,7 +148,7 @@ module QuickpayCommon :recurring => %w(auto_capture autofee zero_auth) } } - + RESPONSE_CODES = { 200 => 'OK', 201 => 'Created', @@ -165,24 +163,22 @@ module QuickpayCommon 409 => 'Conflict', 500 => 'Internal Server Error' } - + def self.included(base) base.default_currency = 'DKK' base.money_format = :cents - - base.supported_cardtypes = [:dankort, :forbrugsforeningen, :visa, :master, + + base.supported_cardtypes = [:dankort, :forbrugsforeningen, :visa, :master, :american_express, :diners_club, :jcb, :maestro] base.supported_countries = ['DE', 'DK', 'ES', 'FI', 'FR', 'FO', 'GB', 'IS', 'NO', 'SE'] base.homepage_url = 'http://quickpay.net/' base.display_name = 'QuickPay' - end - + def expdate(credit_card) year = format(credit_card.year, :two_digits) month = format(credit_card.month, :two_digits) "#{year}#{month}" end - end diff --git a/lib/active_merchant/billing/gateways/quickpay/quickpay_v10.rb b/lib/active_merchant/billing/gateways/quickpay/quickpay_v10.rb index 586eec8711c..e1b00768287 100644 --- a/lib/active_merchant/billing/gateways/quickpay/quickpay_v10.rb +++ b/lib/active_merchant/billing/gateways/quickpay/quickpay_v10.rb @@ -15,26 +15,34 @@ def initialize(options = {}) end def purchase(money, credit_card_or_reference, options = {}) - MultiResponse.run(true) do |r| + MultiResponse.run do |r| + if credit_card_or_reference.is_a?(String) + r.process { create_token(credit_card_or_reference, options) } + credit_card_or_reference = r.authorization + end r.process { create_payment(money, options) } r.process { post = authorization_params(money, credit_card_or_reference, options) add_autocapture(post, false) - commit(synchronized_path("/payments/#{r.authorization}/authorize"), post) + commit(synchronized_path("/payments/#{r.responses.last.params["id"]}/authorize"), post) } r.process { post = capture_params(money, credit_card_or_reference, options) - commit(synchronized_path("/payments/#{r.authorization}/capture"), post) + commit(synchronized_path("/payments/#{r.responses.last.params["id"]}/capture"), post) } end end def authorize(money, credit_card_or_reference, options = {}) - MultiResponse.run(true) do |r| + MultiResponse.run do |r| + if credit_card_or_reference.is_a?(String) + r.process { create_token(credit_card_or_reference, options) } + credit_card_or_reference = r.authorization + end r.process { create_payment(money, options) } r.process { post = authorization_params(money, credit_card_or_reference, options) - commit(synchronized_path("/payments/#{r.authorization}/authorize"), post) + commit(synchronized_path("/payments/#{r.responses.last.params["id"]}/authorize"), post) } end end @@ -70,13 +78,11 @@ def verify(credit_card, options={}) def store(credit_card, options = {}) MultiResponse.run do |r| r.process { create_store(options) } - r.process { authorize_store(r.authorization, credit_card, options)} - r.process { create_token(r.authorization, options.merge({id: r.authorization}))} + r.process { authorize_store(r.authorization, credit_card, options) } end end def unstore(identification) - identification = identification.split(";").last commit(synchronized_path "/cards/#{identification}/cancel") end @@ -93,203 +99,197 @@ def scrub(transcript) private - def authorization_params(money, credit_card, options = {}) - post = {} - - add_amount(post, money, options) - add_credit_card_or_reference(post, credit_card) - add_additional_params(:authorize, post, options) + def authorization_params(money, credit_card_or_reference, options = {}) + post = {} - post - end + add_amount(post, money, options) + add_credit_card_or_reference(post, credit_card_or_reference) + add_additional_params(:authorize, post, options) - def capture_params(money, credit_card, options = {}) - post = {} + post + end - add_amount(post, money, options) - add_additional_params(:capture, post, options) + def capture_params(money, credit_card, options = {}) + post = {} - post - end + add_amount(post, money, options) + add_additional_params(:capture, post, options) - def create_store(options = {}) - post = {} - commit('/cards', post) - end + post + end - def authorize_store(identification, credit_card, options = {}) - post = {} + def create_store(options = {}) + post = {} + commit('/cards', post) + end - add_credit_card_or_reference(post, credit_card, options) - commit(synchronized_path("/cards/#{identification}/authorize"), post) - end + def authorize_store(identification, credit_card, options = {}) + post = {} - def create_token(identification, options) - post = {} - post[:id] = options[:id] - commit(synchronized_path("/cards/#{identification}/tokens"), post) - end + add_credit_card_or_reference(post, credit_card, options) + commit(synchronized_path("/cards/#{identification}/authorize"), post) + end - def create_payment(money, options = {}) - post = {} - add_currency(post, money, options) - add_invoice(post, options) - commit('/payments', post) - end + def create_token(identification, options) + post = {} + commit(synchronized_path("/cards/#{identification}/tokens"), post) + end - def commit(action, params = {}) - success = false - begin - response = parse(ssl_post(self.live_url + action, params.to_json, headers)) - success = successful?(response) - rescue ResponseError => e - response = response_error(e.response.body) - rescue JSON::ParserError - response = json_error(response) - end + def create_payment(money, options = {}) + post = {} + add_currency(post, money, options) + add_invoice(post, options) + commit('/payments', post) + end - Response.new(success, message_from(success, response), response, - :test => test?, - :authorization => authorization_from(response, params[:id]) - ) + def commit(action, params = {}) + success = false + begin + response = parse(ssl_post(self.live_url + action, params.to_json, headers)) + success = successful?(response) + rescue ResponseError => e + response = response_error(e.response.body) + rescue JSON::ParserError + response = json_error(response) end - def authorization_from(response, auth_id) - if response["token"] - "#{response["token"]};#{auth_id}" - else - response["id"] - end - end + Response.new(success, message_from(success, response), response, + :test => test?, + :authorization => authorization_from(response) + ) + end - def add_currency(post, money, options) - post[:currency] = options[:currency] || currency(money) + def authorization_from(response) + if response['token'] + response['token'].to_s + else + response['id'].to_s end + end - def add_amount(post, money, options) - post[:amount] = options[:amount] || amount(money) - end + def add_currency(post, money, options) + post[:currency] = options[:currency] || currency(money) + end - def add_autocapture(post, value) - post[:auto_capture] = value - end + def add_amount(post, money, options) + post[:amount] = options[:amount] || amount(money) + end - def add_order_id(post, options) - requires!(options, :order_id) - post[:order_id] = format_order_id(options[:order_id]) - end + def add_autocapture(post, value) + post[:auto_capture] = value + end - def add_invoice(post, options) - add_order_id(post, options) + def add_order_id(post, options) + requires!(options, :order_id) + post[:order_id] = format_order_id(options[:order_id]) + end - if options[:billing_address] - post[:invoice_address] = map_address(options[:billing_address]) - end + def add_invoice(post, options) + add_order_id(post, options) - if options[:shipping_address] - post[:shipping_address] = map_address(options[:shipping_address]) - end + if options[:billing_address] + post[:invoice_address] = map_address(options[:billing_address]) + end - [:metadata, :brading_id, :variables].each do |field| - post[field] = options[field] if options[field] - end + if options[:shipping_address] + post[:shipping_address] = map_address(options[:shipping_address]) end - def add_additional_params(action, post, options = {}) - MD5_CHECK_FIELDS[API_VERSION][action].each do |key| - key = key.to_sym - post[key] = options[key] if options[key] - end + [:metadata, :branding_id, :variables].each do |field| + post[field] = options[field] if options[field] end + end - def add_credit_card_or_reference(post, credit_card_or_reference, options = {}) - post[:card] ||= {} - if credit_card_or_reference.is_a?(String) - reference = credit_card_or_reference.split(";").first - post[:card][:token] = reference - else - post[:card][:number] = credit_card_or_reference.number - post[:card][:cvd] = credit_card_or_reference.verification_value - post[:card][:expiration] = expdate(credit_card_or_reference) - post[:card][:issued_to] = credit_card_or_reference.name - end + def add_additional_params(action, post, options = {}) + MD5_CHECK_FIELDS[API_VERSION][action].each do |key| + key = key.to_sym + post[key] = options[key] if options[key] end + end - def parse(body) - JSON.parse(body) + def add_credit_card_or_reference(post, credit_card_or_reference, options = {}) + post[:card] ||= {} + if credit_card_or_reference.is_a?(String) + post[:card][:token] = credit_card_or_reference + else + post[:card][:number] = credit_card_or_reference.number + post[:card][:cvd] = credit_card_or_reference.verification_value + post[:card][:expiration] = expdate(credit_card_or_reference) + post[:card][:issued_to] = credit_card_or_reference.name end + end - def successful?(response) - has_error = response['errors'] - invalid_code = invalid_operation_code?(response) + def parse(body) + JSON.parse(body) + end - !(has_error || invalid_code) - end + def successful?(response) + has_error = response['errors'] + invalid_code = invalid_operation_code?(response) - def message_from(success, response) - success ? 'OK' : (response['message'] || invalid_operation_message(response) || "Unknown error - please contact QuickPay") - end + !(has_error || invalid_code) + end - def invalid_operation_code?(response) - if response['operations'] - operation = response['operations'].last - operation && operation['qp_status_code'] != "20000" - end - end + def message_from(success, response) + success ? 'OK' : (response['message'] || invalid_operation_message(response) || 'Unknown error - please contact QuickPay') + end - def invalid_operation_message(response) - response['operations'] && response['operations'].last['qp_status_msg'] + def invalid_operation_code?(response) + if response['operations'] + operation = response['operations'].last + operation && operation['qp_status_code'] != '20000' end + end - def map_address(address) - return {} if address.nil? - requires!(address, :name, :address1, :city, :zip, :country) - country = Country.find(address[:country]) - mapped = { - :name => address[:name], - :street => address[:address1], - :city => address[:city], - :region => address[:address2], - :zip_code => address[:zip], - :country_code => country.code(:alpha3).value - } - mapped - end + def invalid_operation_message(response) + response['operations'] && response['operations'].last['qp_status_msg'] + end - def format_order_id(order_id) - truncate(order_id.to_s.gsub(/#/, ''), 20) - end + def map_address(address) + return {} if address.nil? + requires!(address, :name, :address1, :city, :zip, :country) + country = Country.find(address[:country]) + mapped = { + :name => address[:name], + :street => address[:address1], + :city => address[:city], + :region => address[:address2], + :zip_code => address[:zip], + :country_code => country.code(:alpha3).value + } + mapped + end - def headers - auth = Base64.strict_encode64(":#{@options[:api_key]}") - { - "Authorization" => "Basic " + auth, - "User-Agent" => "Quickpay-v#{API_VERSION} ActiveMerchantBindings/#{ActiveMerchant::VERSION}", - "Accept" => "application/json", - "Accept-Version" => "v#{API_VERSION}", - "Content-Type" => "application/json" - } - end + def format_order_id(order_id) + truncate(order_id.to_s.gsub(/#/, ''), 20) + end - def response_error(raw_response) - begin - parse(raw_response) - rescue JSON::ParserError - json_error(raw_response) - end - end + def headers + auth = Base64.strict_encode64(":#{@options[:api_key]}") + { + 'Authorization' => 'Basic ' + auth, + 'User-Agent' => "Quickpay-v#{API_VERSION} ActiveMerchantBindings/#{ActiveMerchant::VERSION}", + 'Accept' => 'application/json', + 'Accept-Version' => "v#{API_VERSION}", + 'Content-Type' => 'application/json' + } + end - def json_error(raw_response) - msg = 'Invalid response received from the Quickpay API.' - msg += " (The raw response returned by the API was #{raw_response.inspect})" - { "message" => msg } - end + def response_error(raw_response) + parse(raw_response) + rescue JSON::ParserError + json_error(raw_response) + end - def synchronized_path(path) - "#{path}?synchronized" - end + def json_error(raw_response) + msg = 'Invalid response received from the Quickpay API.' + msg += " (The raw response returned by the API was #{raw_response.inspect})" + { 'message' => msg } + end + def synchronized_path(path) + "#{path}?synchronized" + end end - end end diff --git a/lib/active_merchant/billing/gateways/quickpay/quickpay_v4to7.rb b/lib/active_merchant/billing/gateways/quickpay/quickpay_v4to7.rb index b1889db2ed2..810d5cdefaa 100644 --- a/lib/active_merchant/billing/gateways/quickpay/quickpay_v4to7.rb +++ b/lib/active_merchant/billing/gateways/quickpay/quickpay_v4to7.rb @@ -6,7 +6,7 @@ module ActiveMerchant #:nodoc: module Billing #:nodoc: class QuickpayV4to7Gateway < Gateway include QuickpayCommon - self.live_url = self.test_url = 'https://secure.quickpay.dk/api' + self.live_url = self.test_url = 'https://secure.quickpay.dk/api' APPROVED = '000' # The login is the QuickpayId @@ -136,7 +136,7 @@ def recurring_or_authorize(credit_card_or_reference) end def add_description(post, options) - post[:description] = options[:description] || "Description" + post[:description] = options[:description] || 'Description' end def add_testmode(post) @@ -196,7 +196,7 @@ def post_data(action, params = {}) params[:apikey] = @options[:apikey] if @options[:apikey] params[:md5check] = generate_check_hash(action, params) - params.collect { |key, value| "#{key}=#{CGI.escape(value.to_s)}" }.join("&") + params.collect { |key, value| "#{key}=#{CGI.escape(value.to_s)}" }.join('&') end def generate_check_hash(action, params) @@ -219,9 +219,8 @@ def expdate(credit_card) # Limited to 20 digits max def format_order_number(number) - number.to_s.gsub(/[^\w]/, '').rjust(4, "0")[0...20] + number.to_s.gsub(/[^\w]/, '').rjust(4, '0')[0...20] end end end end - diff --git a/lib/active_merchant/billing/gateways/qvalent.rb b/lib/active_merchant/billing/gateways/qvalent.rb index 12ba65e879a..46c43aae0cd 100644 --- a/lib/active_merchant/billing/gateways/qvalent.rb +++ b/lib/active_merchant/billing/gateways/qvalent.rb @@ -1,19 +1,19 @@ module ActiveMerchant #:nodoc: module Billing #:nodoc: class QvalentGateway < Gateway - self.display_name = "Qvalent" - self.homepage_url = "https://www.qvalent.com/" + self.display_name = 'Qvalent' + self.homepage_url = 'https://www.qvalent.com/' - self.test_url = "https://ccapi.client.support.qvalent.com/post/CreditCardAPIReceiver" - self.live_url = "https://ccapi.client.qvalent.com/post/CreditCardAPIReceiver" + self.test_url = 'https://ccapi.client.support.qvalent.com/post/CreditCardAPIReceiver' + self.live_url = 'https://ccapi.client.qvalent.com/post/CreditCardAPIReceiver' - self.supported_countries = ["AU"] - self.default_currency = "AUD" + self.supported_countries = ['AU'] + self.default_currency = 'AUD' self.money_format = :cents self.supported_cardtypes = [:visa, :master, :american_express, :discover, :jcb, :diners] def initialize(options={}) - requires!(options, :username, :password, :merchant) + requires!(options, :username, :password, :merchant, :pem, :pem_password) super end @@ -24,8 +24,31 @@ def purchase(amount, payment_method, options={}) add_payment_method(post, payment_method) add_verification_value(post, payment_method) add_customer_data(post, options) + add_soft_descriptors(post, options) - commit("capture", post) + commit('capture', post) + end + + def authorize(amount, payment_method, options={}) + post = {} + add_invoice(post, amount, options) + add_order_number(post, options) + add_payment_method(post, payment_method) + add_verification_value(post, payment_method) + add_customer_data(post, options) + add_soft_descriptors(post, options) + + commit('preauth', post) + end + + def capture(amount, authorization, options={}) + post = {} + add_invoice(post, amount, options) + add_reference(post, authorization, options) + add_customer_data(post, options) + add_soft_descriptors(post, options) + + commit('captureWithoutAuth', post) end def refund(amount, authorization, options={}) @@ -33,8 +56,30 @@ def refund(amount, authorization, options={}) add_invoice(post, amount, options) add_reference(post, authorization, options) add_customer_data(post, options) + add_soft_descriptors(post, options) - commit("refund", post) + commit('refund', post) + end + + # Credit requires the merchant account to be enabled for "Adhoc Refunds" + def credit(amount, payment_method, options={}) + post = {} + add_invoice(post, amount, options) + add_order_number(post, options) + add_payment_method(post, payment_method) + add_customer_data(post, options) + add_soft_descriptors(post, options) + + commit('refund', post) + end + + def void(authorization, options={}) + post = {} + add_reference(post, authorization, options) + add_customer_data(post, options) + add_soft_descriptors(post, options) + + commit('reversal', post) end def store(payment_method, options = {}) @@ -42,7 +87,7 @@ def store(payment_method, options = {}) add_payment_method(post, payment_method) add_card_reference(post) - commit("registerAccount", post) + commit('registerAccount', post) end def supports_scrubbing? @@ -58,59 +103,71 @@ def scrub(transcript) private - CURRENCY_CODES = Hash.new{|h,k| raise ArgumentError.new("Unsupported currency: #{k}")} - CURRENCY_CODES["AUD"] = "AUD" - CURRENCY_CODES["INR"] = "INR" + CURRENCY_CODES = Hash.new { |h, k| raise ArgumentError.new("Unsupported currency: #{k}") } + CURRENCY_CODES['AUD'] = 'AUD' + CURRENCY_CODES['INR'] = 'INR' + + def add_soft_descriptors(post, options) + post['customer.merchantName'] = options[:customer_merchant_name] if options[:customer_merchant_name] + post['customer.merchantStreetAddress'] = options[:customer_merchant_street_address] if options[:customer_merchant_street_address] + post['customer.merchantLocation'] = options[:customer_merchant_location] if options[:customer_merchant_location] + post['customer.merchantState'] = options[:customer_merchant_state] if options[:customer_merchant_state] + post['customer.merchantCountry'] = options[:customer_merchant_country] if options[:customer_merchant_country] + post['customer.merchantPostCode'] = options[:customer_merchant_post_code] if options[:customer_merchant_post_code] + post['customer.subMerchantId'] = options[:customer_sub_merchant_id] if options[:customer_sub_merchant_id] + end def add_invoice(post, money, options) - post["order.amount"] = amount(money) - post["card.currency"] = CURRENCY_CODES[options[:currency] || currency(money)] - post["order.ECI"] = "SSL" + post['order.amount'] = amount(money) + post['card.currency'] = CURRENCY_CODES[options[:currency] || currency(money)] + post['order.ECI'] = options[:eci] || 'SSL' end def add_payment_method(post, payment_method) - post["card.cardHolderName"] = payment_method.name - post["card.PAN"] = payment_method.number - post["card.expiryYear"] = format(payment_method.year, :two_digits) - post["card.expiryMonth"] = format(payment_method.month, :two_digits) + post['card.cardHolderName'] = payment_method.name + post['card.PAN'] = payment_method.number + post['card.expiryYear'] = format(payment_method.year, :two_digits) + post['card.expiryMonth'] = format(payment_method.month, :two_digits) end def add_verification_value(post, payment_method) - post["card.CVN"] = payment_method.verification_value + post['card.CVN'] = payment_method.verification_value end def add_card_reference(post) - post["customer.customerReferenceNumber"] = options[:order_id] + post['customer.customerReferenceNumber'] = options[:order_id] end def add_reference(post, authorization, options) - post["customer.originalOrderNumber"] = authorization + post['customer.originalOrderNumber'] = authorization add_order_number(post, options) end def add_order_number(post, options) - post["customer.orderNumber"] = options[:order_id] || SecureRandom.uuid + post['customer.orderNumber'] = options[:order_id] || SecureRandom.uuid end def add_customer_data(post, options) - post["order.ipAddress"] = options[:ip] + post['order.ipAddress'] = options[:ip] || '127.0.0.1' + post['order.xid'] = options[:xid] if options[:xid] + post['order.cavv'] = options[:cavv] if options[:cavv] end def commit(action, post) - post["customer.username"] = @options[:username] - post["customer.password"] = @options[:password] - post["customer.merchant"] = @options[:merchant] - post["order.type"] = action + post['customer.username'] = @options[:username] + post['customer.password'] = @options[:password] + post['customer.merchant'] = @options[:merchant] + post['order.type'] = action data = build_request(post) raw = parse(ssl_post(url(action), data, headers)) - succeeded = success_from(raw["response.responseCode"]) + succeeded = success_from(raw['response.responseCode']) Response.new( succeeded, message_from(succeeded, raw), raw, - authorization: raw["response.orderNumber"] || raw["response.customerReferenceNumber"], + authorization: raw['response.orderNumber'] || raw['response.customerReferenceNumber'], error_code: error_code_from(succeeded, raw), test: test? ) @@ -118,12 +175,12 @@ def commit(action, post) def headers { - "Content-Type" => "application/x-www-form-urlencoded" + 'Content-Type' => 'application/x-www-form-urlencoded' } end def build_request(post) - post.to_query + "&message.end" + post.to_query + '&message.end' end def url(action) @@ -140,7 +197,7 @@ def parse(body) def parse_element(response, node) if node.has_elements? - node.elements.each{|element| parse_element(response, element) } + node.elements.each { |element| parse_element(response, element) } else response[node.name.underscore.to_sym] = node.text end @@ -154,25 +211,25 @@ def success_from(response) def message_from(succeeded, response) if succeeded - "Succeeded" + 'Succeeded' else - response["response.text"] || "Unable to read error message" + response['response.text'] || 'Unable to read error message' end end STANDARD_ERROR_CODE_MAPPING = { - "14" => STANDARD_ERROR_CODE[:invalid_number], - "QQ" => STANDARD_ERROR_CODE[:invalid_cvc], - "33" => STANDARD_ERROR_CODE[:expired_card], - "NT" => STANDARD_ERROR_CODE[:incorrect_address], - "12" => STANDARD_ERROR_CODE[:card_declined], - "06" => STANDARD_ERROR_CODE[:processing_error], - "01" => STANDARD_ERROR_CODE[:call_issuer], - "04" => STANDARD_ERROR_CODE[:pickup_card], + '14' => STANDARD_ERROR_CODE[:invalid_number], + 'QQ' => STANDARD_ERROR_CODE[:invalid_cvc], + '33' => STANDARD_ERROR_CODE[:expired_card], + 'NT' => STANDARD_ERROR_CODE[:incorrect_address], + '12' => STANDARD_ERROR_CODE[:card_declined], + '06' => STANDARD_ERROR_CODE[:processing_error], + '01' => STANDARD_ERROR_CODE[:call_issuer], + '04' => STANDARD_ERROR_CODE[:pickup_card], } def error_code_from(succeeded, response) - succeeded ? nil : STANDARD_ERROR_CODE_MAPPING[response["response.responseCode"]] + succeeded ? nil : STANDARD_ERROR_CODE_MAPPING[response['response.responseCode']] end end end diff --git a/lib/active_merchant/billing/gateways/realex.rb b/lib/active_merchant/billing/gateways/realex.rb index 7411f87e087..ca0b91517b3 100644 --- a/lib/active_merchant/billing/gateways/realex.rb +++ b/lib/active_merchant/billing/gateways/realex.rb @@ -26,22 +26,19 @@ class RealexGateway < Gateway 'visa' => 'VISA', 'american_express' => 'AMEX', 'diners_club' => 'DINERS', - 'switch' => 'SWITCH', - 'solo' => 'SWITCH', - 'laser' => 'LASER', 'maestro' => 'MC' } self.money_format = :cents self.default_currency = 'EUR' - self.supported_cardtypes = [ :visa, :master, :american_express, :diners_club, :switch, :solo, :laser ] - self.supported_countries = %w(IE GB FR BE NL LU IT) + self.supported_cardtypes = [ :visa, :master, :american_express, :diners_club ] + self.supported_countries = %w(IE GB FR BE NL LU IT US CA ES) self.homepage_url = 'http://www.realexpayments.com/' self.display_name = 'Realex' - SUCCESS, DECLINED = "Successful", "Declined" - BANK_ERROR = REALEX_ERROR = "Gateway is in maintenance. Please try again later." - ERROR = CLIENT_DEACTIVATED = "Gateway Error" + SUCCESS, DECLINED = 'Successful', 'Declined' + BANK_ERROR = REALEX_ERROR = 'Gateway is in maintenance. Please try again later.' + ERROR = CLIENT_DEACTIVATED = 'Gateway Error' def initialize(options = {}) requires!(options, :login, :password) @@ -64,7 +61,7 @@ def authorize(money, creditcard, options = {}) end def capture(money, authorization, options = {}) - request = build_capture_request(authorization, options) + request = build_capture_request(money, authorization, options) commit(request) end @@ -83,31 +80,36 @@ def void(authorization, options = {}) commit(request) end + def verify(credit_card, options = {}) + requires!(options, :order_id) + + request = build_verify_request(credit_card, options) + commit(request) + end + def supports_scrubbing true end def scrub(transcript) transcript. - gsub(%r((Authorization: Basic )\w+), '\1[FILTERED]'). - gsub(%r(()\d+())i, '\1[FILTERED]\2') + gsub(%r((Authorization: Basic )\w+), '\1[FILTERED]'). + gsub(%r(()\d+())i, '\1[FILTERED]\2') end private + def commit(request) response = parse(ssl_post(self.live_url, request)) Response.new( - (response[:result] == "00"), + (response[:result] == '00'), message_from(response), response, :test => (response[:message] =~ %r{\[ test system \]}), :authorization => authorization_from(response), - :cvv_result => response[:cvnresult], - :avs_result => { - :street_match => response[:avspostcoderesponse], - :postal_match => response[:avspostcoderesponse] - } + avs_result: AVSResult.new(code: response[:avspostcoderesponse]), + cvv_result: CVVResult.new(response[:cvnresult]) ) end @@ -116,7 +118,7 @@ def parse(xml) doc = Nokogiri::XML(xml) doc.xpath('//response/*').each do |node| - if (node.elements.size == 0) + if node.elements.size == 0 response[node.name.downcase.to_sym] = normalize(node.text) else node.elements.each do |childnode| @@ -143,20 +145,22 @@ def build_purchase_or_authorization_request(action, money, credit_card, options) add_card(xml, credit_card) xml.tag! 'autosettle', 'flag' => auto_settle_flag(action) add_signed_digest(xml, timestamp, @options[:login], sanitize_order_id(options[:order_id]), amount(money), (options[:currency] || currency(money)), credit_card.number) + add_network_tokenization_card(xml, credit_card) if credit_card.is_a?(NetworkTokenizationCreditCard) add_comments(xml, options) add_address_and_customer_info(xml, options) end xml.target! end - def build_capture_request(authorization, options) + def build_capture_request(money, authorization, options) timestamp = new_timestamp xml = Builder::XmlMarkup.new :indent => 2 xml.tag! 'request', 'timestamp' => timestamp, 'type' => 'settle' do add_merchant_details(xml, options) + add_amount(xml, money, options) add_transaction_identifiers(xml, authorization, options) add_comments(xml, options) - add_signed_digest(xml, timestamp, @options[:login], sanitize_order_id(options[:order_id]), nil, nil, nil) + add_signed_digest(xml, timestamp, @options[:login], sanitize_order_id(options[:order_id]), amount(money), (options[:currency] || currency(money)), nil) end xml.target! end @@ -188,6 +192,20 @@ def build_void_request(authorization, options) xml.target! end + # Verify initiates an OTB (Open To Buy) request + def build_verify_request(credit_card, options) + timestamp = new_timestamp + xml = Builder::XmlMarkup.new :indent => 2 + xml.tag! 'request', 'timestamp' => timestamp, 'type' => 'otb' do + add_merchant_details(xml, options) + xml.tag! 'orderid', sanitize_order_id(options[:order_id]) + add_card(xml, credit_card) + add_comments(xml, options) + add_signed_digest(xml, timestamp, @options[:login], sanitize_order_id(options[:order_id]), credit_card.number) + end + xml.target! + end + def add_address_and_customer_info(xml, options) billing_address = options[:billing_address] || options[:address] shipping_address = options[:shipping_address] @@ -246,7 +264,7 @@ def add_card(xml, credit_card) xml.tag! 'expdate', expiry_date(credit_card) xml.tag! 'chname', credit_card.name xml.tag! 'type', CARD_MAPPING[card_brand(credit_card).to_s] - xml.tag! 'issueno', credit_card.issue_number + xml.tag! 'issueno', '' xml.tag! 'cvn' do xml.tag! 'number', credit_card.verification_value xml.tag! 'presind', (options['presind'] || (credit_card.verification_value? ? 1 : nil)) @@ -254,9 +272,21 @@ def add_card(xml, credit_card) end end + def add_network_tokenization_card(xml, payment) + xml.tag! 'mpi' do + xml.tag! 'cavv', payment.payment_cryptogram + xml.tag! 'eci', payment.eci + end + xml.tag! 'supplementarydata' do + xml.tag! 'item', 'type' => 'mobile' do + xml.tag! 'field01', payment.source.to_s.gsub('_', '-') + end + end + end + def format_address_code(address) code = [address[:zip].to_s, address[:address1].to_s + address[:address2].to_s] - code.collect{|e| e.gsub(/\D/, "")}.reject{|e| e.empty?}.join("|") + code.collect { |e| e.gsub(/\D/, '') }.reject(&:empty?).join('|') end def new_timestamp @@ -264,8 +294,8 @@ def new_timestamp end def add_signed_digest(xml, *values) - string = Digest::SHA1.hexdigest(values.join(".")) - xml.tag! 'sha1hash', Digest::SHA1.hexdigest([string, @options[:password]].join(".")) + string = Digest::SHA1.hexdigest(values.join('.')) + xml.tag! 'sha1hash', Digest::SHA1.hexdigest([string, @options[:password]].join('.')) end def auto_settle_flag(action) @@ -277,26 +307,25 @@ def expiry_date(credit_card) end def message_from(response) - message = nil case response[:result] - when "00" - message = SUCCESS - when "101" - message = response[:message] - when "102", "103" - message = DECLINED + when '00' + SUCCESS + when '101' + response[:message] + when '102', '103' + DECLINED when /^2[0-9][0-9]/ - message = BANK_ERROR + BANK_ERROR when /^3[0-9][0-9]/ - message = REALEX_ERROR + REALEX_ERROR when /^5[0-9][0-9]/ - message = response[:message] - when "600", "601", "603" - message = ERROR - when "666" - message = CLIENT_DEACTIVATED + response[:message] + when '600', '601', '603' + ERROR + when '666' + CLIENT_DEACTIVATED else - message = DECLINED + DECLINED end end diff --git a/lib/active_merchant/billing/gateways/redsys.rb b/lib/active_merchant/billing/gateways/redsys.rb index 4f936dbd34c..792b935d557 100644 --- a/lib/active_merchant/billing/gateways/redsys.rb +++ b/lib/active_merchant/billing/gateways/redsys.rb @@ -1,4 +1,5 @@ # coding: utf-8 + require 'nokogiri' module ActiveMerchant #:nodoc: @@ -35,8 +36,8 @@ module Billing #:nodoc: # # class RedsysGateway < Gateway - self.live_url = "https://sis.sermepa.es/sis/operaciones" - self.test_url = "https://sis-t.redsys.es:25443/sis/operaciones" + self.live_url = 'https://sis.sermepa.es/sis/operaciones' + self.test_url = 'https://sis-t.redsys.es:25443/sis/operaciones' self.supported_countries = ['ES'] self.default_currency = 'EUR' @@ -44,40 +45,46 @@ class RedsysGateway < Gateway # Not all card types may be activated by the bank! self.supported_cardtypes = [:visa, :master, :american_express, :jcb, :diners_club] - self.homepage_url = "http://www.redsys.es/" - self.display_name = "Redsys" + self.homepage_url = 'http://www.redsys.es/' + self.display_name = 'Redsys' CURRENCY_CODES = { - "AED" => '784', - "ARS" => '32', - "AUD" => '36', - "BRL" => '986', - "BOB" => '68', - "CAD" => '124', - "CHF" => '756', - "CLP" => '152', - "COP" => '170', - "CRC" => '188', - "CZK" => '203', - "DOP" => '214', - "EUR" => '978', - "GBP" => '826', - "GTQ" => '320', - "HUF" => '348', - "JPY" => '392', - "MYR" => '458', - "MXN" => '484', - "NOK" => '578', - "NZD" => '554', - "PEN" => '604', - "PLN" => '616', - "RUB" => '643', - "SAR" => '682', - "SEK" => '752', - "SGD" => '702', - "THB" => '764', - "USD" => '840', - "UYU" => '858' + 'AED' => '784', + 'ARS' => '32', + 'AUD' => '36', + 'BRL' => '986', + 'BOB' => '68', + 'CAD' => '124', + 'CHF' => '756', + 'CLP' => '152', + 'CNY' => '156', + 'COP' => '170', + 'CRC' => '188', + 'CZK' => '203', + 'DKK' => '208', + 'DOP' => '214', + 'EUR' => '978', + 'GBP' => '826', + 'GTQ' => '320', + 'HUF' => '348', + 'IDR' => '360', + 'INR' => '356', + 'JPY' => '392', + 'KRW' => '410', + 'MYR' => '458', + 'MXN' => '484', + 'NOK' => '578', + 'NZD' => '554', + 'PEN' => '604', + 'PLN' => '985', + 'RUB' => '643', + 'SAR' => '682', + 'SEK' => '752', + 'SGD' => '702', + 'THB' => '764', + 'TWD' => '901', + 'USD' => '840', + 'UYU' => '858' } # The set of supported transactions for this gateway. @@ -95,72 +102,72 @@ class RedsysGateway < Gateway # a card has been rejected. Syntax or general request errors # are not covered here. RESPONSE_TEXTS = { - 0 => "Transaction Approved", - 400 => "Cancellation Accepted", - 481 => "Cancellation Accepted", - 500 => "Reconciliation Accepted", - 900 => "Refund / Confirmation approved", - - 101 => "Card expired", - 102 => "Card blocked temporarily or under susciption of fraud", - 104 => "Transaction not permitted", - 107 => "Contact the card issuer", - 109 => "Invalid identification by merchant or POS terminal", - 110 => "Invalid amount", - 114 => "Card cannot be used to the requested transaction", - 116 => "Insufficient credit", - 118 => "Non-registered card", - 125 => "Card not effective", - 129 => "CVV2/CVC2 Error", - 167 => "Contact the card issuer: suspected fraud", - 180 => "Card out of service", - 181 => "Card with credit or debit restrictions", - 182 => "Card with credit or debit restrictions", - 184 => "Authentication error", - 190 => "Refusal with no specific reason", - 191 => "Expiry date incorrect", - - 201 => "Card expired", - 202 => "Card blocked temporarily or under suspicion of fraud", - 204 => "Transaction not permitted", - 207 => "Contact the card issuer", - 208 => "Lost or stolen card", - 209 => "Lost or stolen card", - 280 => "CVV2/CVC2 Error", - 290 => "Declined with no specific reason", - - 480 => "Original transaction not located, or time-out exceeded", - 501 => "Original transaction not located, or time-out exceeded", - 502 => "Original transaction not located, or time-out exceeded", - 503 => "Original transaction not located, or time-out exceeded", - - 904 => "Merchant not registered at FUC", - 909 => "System error", - 912 => "Issuer not available", - 913 => "Duplicate transmission", - 916 => "Amount too low", - 928 => "Time-out exceeded", - 940 => "Transaction cancelled previously", - 941 => "Authorization operation already cancelled", - 942 => "Original authorization declined", - 943 => "Different details from origin transaction", - 944 => "Session error", - 945 => "Duplicate transmission", - 946 => "Cancellation of transaction while in progress", - 947 => "Duplicate tranmission while in progress", - 949 => "POS Inoperative", - 950 => "Refund not possible", - 9064 => "Card number incorrect", - 9078 => "No payment method available", - 9093 => "Non-existent card", - 9218 => "Recursive transaction in bad gateway", - 9253 => "Check-digit incorrect", - 9256 => "Preauth not allowed for merchant", - 9257 => "Preauth not allowed for card", - 9261 => "Operating limit exceeded", - 9912 => "Issuer not available", - 9913 => "Confirmation error", - 9914 => "KO Confirmation" + 0 => 'Transaction Approved', + 400 => 'Cancellation Accepted', + 481 => 'Cancellation Accepted', + 500 => 'Reconciliation Accepted', + 900 => 'Refund / Confirmation approved', + + 101 => 'Card expired', + 102 => 'Card blocked temporarily or under susciption of fraud', + 104 => 'Transaction not permitted', + 107 => 'Contact the card issuer', + 109 => 'Invalid identification by merchant or POS terminal', + 110 => 'Invalid amount', + 114 => 'Card cannot be used to the requested transaction', + 116 => 'Insufficient credit', + 118 => 'Non-registered card', + 125 => 'Card not effective', + 129 => 'CVV2/CVC2 Error', + 167 => 'Contact the card issuer: suspected fraud', + 180 => 'Card out of service', + 181 => 'Card with credit or debit restrictions', + 182 => 'Card with credit or debit restrictions', + 184 => 'Authentication error', + 190 => 'Refusal with no specific reason', + 191 => 'Expiry date incorrect', + + 201 => 'Card expired', + 202 => 'Card blocked temporarily or under suspicion of fraud', + 204 => 'Transaction not permitted', + 207 => 'Contact the card issuer', + 208 => 'Lost or stolen card', + 209 => 'Lost or stolen card', + 280 => 'CVV2/CVC2 Error', + 290 => 'Declined with no specific reason', + + 480 => 'Original transaction not located, or time-out exceeded', + 501 => 'Original transaction not located, or time-out exceeded', + 502 => 'Original transaction not located, or time-out exceeded', + 503 => 'Original transaction not located, or time-out exceeded', + + 904 => 'Merchant not registered at FUC', + 909 => 'System error', + 912 => 'Issuer not available', + 913 => 'Duplicate transmission', + 916 => 'Amount too low', + 928 => 'Time-out exceeded', + 940 => 'Transaction cancelled previously', + 941 => 'Authorization operation already cancelled', + 942 => 'Original authorization declined', + 943 => 'Different details from origin transaction', + 944 => 'Session error', + 945 => 'Duplicate transmission', + 946 => 'Cancellation of transaction while in progress', + 947 => 'Duplicate tranmission while in progress', + 949 => 'POS Inoperative', + 950 => 'Refund not possible', + 9064 => 'Card number incorrect', + 9078 => 'No payment method available', + 9093 => 'Non-existent card', + 9218 => 'Recursive transaction in bad gateway', + 9253 => 'Check-digit incorrect', + 9256 => 'Preauth not allowed for merchant', + 9257 => 'Preauth not allowed for card', + 9261 => 'Operating limit exceeded', + 9912 => 'Issuer not available', + 9913 => 'Confirmation error', + 9914 => 'KO Confirmation' } # Creates a new instance @@ -178,7 +185,7 @@ class RedsysGateway < Gateway def initialize(options = {}) requires!(options, :login, :secret_key) options[:terminal] ||= 1 - options[:signature_algorithm] ||= "sha1" + options[:signature_algorithm] ||= 'sha1' super end @@ -293,8 +300,8 @@ def add_payment(data, card) data[:credit_card_token] = card else name = [card.first_name, card.last_name].join(' ').slice(0, 60) - year = sprintf("%.4i", card.year) - month = sprintf("%.2i", card.month) + year = sprintf('%.4i', card.year) + month = sprintf('%.2i', card.month) data[:card] = { :name => name, :pan => card.number, @@ -389,6 +396,7 @@ def build_merchant_data(xml, data) xml.DS_MERCHANT_IDENTIFIER 'REQUIRED' if data[:store_in_vault] elsif data[:credit_card_token] xml.DS_MERCHANT_IDENTIFIER data[:credit_card_token] + xml.DS_MERCHANT_DIRECTPAYMENT 'true' end end end @@ -396,12 +404,12 @@ def build_merchant_data(xml, data) def parse(data) params = {} success = false - message = "" + message = '' options = @options.merge(:test => test?) xml = Nokogiri::XML(data) - code = xml.xpath("//RETORNOXML/CODIGO").text - if code == "0" - op = xml.xpath("//RETORNOXML/OPERACION") + code = xml.xpath('//RETORNOXML/CODIGO').text + if code == '0' + op = xml.xpath('//RETORNOXML/OPERACION') op.children.each do |element| params[element.name.downcase.to_sym] = element.text end @@ -411,7 +419,7 @@ def parse(data) options[:authorization] = build_authorization(params) success = is_success_response?(params[:ds_response]) else - message = "Response failed validation check" + message = 'Response failed validation check' end else # Some kind of programmer error with the request! @@ -424,7 +432,7 @@ def parse(data) def validate_signature(data) if sha256_authentication? sig = Base64.strict_encode64(mac256(get_key(data[:ds_order].to_s), xml_signed_fields(data))) - sig.upcase == data[:ds_signature].to_s.upcase + sig.casecmp(data[:ds_signature].to_s).zero? else str = data[:ds_amount] + data[:ds_order].to_s + @@ -442,11 +450,11 @@ def validate_signature(data) end def build_authorization(params) - [params[:ds_order], params[:ds_amount], params[:ds_currency]].join("|") + [params[:ds_order], params[:ds_amount], params[:ds_currency]].join('|') end def split_authorization(authorization) - order_id, amount, currency = authorization.split("|") + order_id, amount, currency = authorization.split('|') [order_id, amount.to_i, currency] end @@ -463,7 +471,7 @@ def transaction_code(type) def response_text(code) code = code.to_i code = 0 if code < 100 - RESPONSE_TEXTS[code] || "Unkown code, please check in manual" + RESPONSE_TEXTS[code] || 'Unkown code, please check in manual' end def is_success_response?(code) @@ -475,12 +483,12 @@ def clean_order_id(order_id) if cleansed =~ /^\d{4}/ cleansed[0..11] else - "%04d%s" % [rand(0..9999), cleansed[0...8]] + '%04d%s' % [rand(0..9999), cleansed[0...8]] end end def sha256_authentication? - @options[:signature_algorithm] == "sha256" + @options[:signature_algorithm] == 'sha256' end def sign_request(xml_request_string, order_id) @@ -490,7 +498,7 @@ def sign_request(xml_request_string, order_id) def encrypt(key, order_id) block_length = 8 - cipher = OpenSSL::Cipher::Cipher.new('DES3') + cipher = OpenSSL::Cipher.new('DES3') cipher.encrypt cipher.key = Base64.strict_decode64(key) @@ -508,8 +516,14 @@ def mac256(key, data) end def xml_signed_fields(data) - data[:ds_amount] + data[:ds_order] + data[:ds_merchantcode] + data[:ds_currency] + - data[:ds_response] + data[:ds_transactiontype] + data[:ds_securepayment] + xml_signed_fields = data[:ds_amount] + data[:ds_order] + data[:ds_merchantcode] + + data[:ds_currency] + data[:ds_response] + + if data[:ds_cardnumber] + xml_signed_fields += data[:ds_cardnumber] + end + + xml_signed_fields + data[:ds_transactiontype] + data[:ds_securepayment] end def get_key(order_id) diff --git a/lib/active_merchant/billing/gateways/s5.rb b/lib/active_merchant/billing/gateways/s5.rb index 50049e6128b..9f36a91e54e 100644 --- a/lib/active_merchant/billing/gateways/s5.rb +++ b/lib/active_merchant/billing/gateways/s5.rb @@ -80,7 +80,7 @@ def void(authorization, options={}) def store(payment, options = {}) request = build_xml_request do |xml| - xml.Payment(code: SUPPORTED_TRANSACTIONS["store"]) + xml.Payment(code: SUPPORTED_TRANSACTIONS['store']) add_account(xml, payment) add_customer(xml, payment, options) add_recurrence_mode(xml, options) @@ -96,7 +96,6 @@ def verify(credit_card, options={}) end end - def supports_scrubbing? true end @@ -137,7 +136,7 @@ def add_account(xml, payment_method) xml.Holder "#{payment_method.first_name} #{payment_method.last_name}" xml.Brand payment_method.brand xml.Expiry(year: payment_method.year, month: payment_method.month) - xml.Verification payment_method.verification_value + xml.Verification payment_method.verification_value end end end @@ -174,20 +173,20 @@ def add_address(xml, address) def add_recurrence_mode(xml, options) if options[:recurring] == true - xml.Recurrence(mode: "REPEATED") + xml.Recurrence(mode: 'REPEATED') else - xml.Recurrence(mode: "INITIAL") + xml.Recurrence(mode: 'INITIAL') end end def parse(body) results = {} xml = Nokogiri::XML(body) - resp = xml.xpath("//Response/Transaction/Identification") + resp = xml.xpath('//Response/Transaction/Identification') resp.children.each do |element| results[element.name.downcase.to_sym] = element.text end - resp = xml.xpath("//Response/Transaction/Processing") + resp = xml.xpath('//Response/Transaction/Processing') resp.children.each do |element| results[element.name.downcase.to_sym] = element.text end diff --git a/lib/active_merchant/billing/gateways/safe_charge.rb b/lib/active_merchant/billing/gateways/safe_charge.rb new file mode 100644 index 00000000000..8d3cccd3cc6 --- /dev/null +++ b/lib/active_merchant/billing/gateways/safe_charge.rb @@ -0,0 +1,262 @@ +require 'nokogiri' + +module ActiveMerchant #:nodoc: + module Billing #:nodoc: + class SafeChargeGateway < Gateway + self.test_url = 'https://process.sandbox.safecharge.com/service.asmx/Process' + self.live_url = 'https://process.safecharge.com/service.asmx/Process' + + self.supported_countries = ['AT', 'BE', 'BG', 'CY', 'CZ', 'DE', 'DK', 'EE', 'GR', 'ES', 'FI', 'FR', 'HR', 'HU', 'IE', 'IS', 'IT', 'LI', 'LT', 'LU', 'LV', 'MT', 'NL', 'NO', 'PL', 'PT', 'RO', 'SE', 'SI', 'SK', 'GB', 'US'] + self.default_currency = 'USD' + self.supported_cardtypes = [:visa, :master] + + self.homepage_url = 'https://www.safecharge.com' + self.display_name = 'SafeCharge' + + VERSION = '4.1.0' + + def initialize(options={}) + requires!(options, :client_login_id, :client_password) + super + end + + def purchase(money, payment, options={}) + post = {} + post[:sg_APIType] = 1 if options[:three_d_secure] + trans_type = options[:three_d_secure] ? 'Sale3D' : 'Sale' + add_transaction_data(trans_type, post, money, options) + add_payment(post, payment, options) + add_customer_details(post, payment, options) + + commit(post) + end + + def authorize(money, payment, options={}) + post = {} + add_transaction_data('Auth', post, money, options) + add_payment(post, payment, options) + add_customer_details(post, payment, options) + + commit(post) + end + + def capture(money, authorization, options={}) + post = {} + auth, transaction_id, token, exp_month, exp_year, _, original_currency = authorization.split('|') + add_transaction_data('Settle', post, money, options.merge!({currency: original_currency})) + post[:sg_AuthCode] = auth + post[:sg_TransactionID] = transaction_id + post[:sg_CCToken] = token + post[:sg_ExpMonth] = exp_month + post[:sg_ExpYear] = exp_year + + commit(post) + end + + def refund(money, authorization, options={}) + post = {} + auth, transaction_id, token, exp_month, exp_year, _, original_currency = authorization.split('|') + add_transaction_data('Credit', post, money, options.merge!({currency: original_currency})) + post[:sg_CreditType] = 2 + post[:sg_AuthCode] = auth + post[:sg_TransactionID] = transaction_id + post[:sg_CCToken] = token + post[:sg_ExpMonth] = exp_month + post[:sg_ExpYear] = exp_year + + commit(post) + end + + def credit(money, payment, options={}) + post = {} + add_payment(post, payment, options) + add_transaction_data('Credit', post, money, options) + post[:sg_CreditType] = 1 + + commit(post) + end + + def void(authorization, options={}) + post = {} + auth, transaction_id, token, exp_month, exp_year, original_amount, original_currency = authorization.split('|') + add_transaction_data('Void', post, (original_amount.to_f * 100), options.merge!({currency: original_currency})) + post[:sg_CreditType] = 2 + post[:sg_AuthCode] = auth + post[:sg_TransactionID] = transaction_id + post[:sg_CCToken] = token + post[:sg_ExpMonth] = exp_month + post[:sg_ExpYear] = exp_year + + commit(post) + end + + def verify(credit_card, options={}) + MultiResponse.run(:use_first_response) do |r| + r.process { authorize(100, credit_card, options) } + r.process(:ignore_result) { void(r.authorization, options) } + end + end + + def supports_scrubbing? + true + end + + def scrub(transcript) + transcript. + gsub(%r((sg_ClientPassword=)[^&]+(&?)), '\1[FILTERED]\2'). + gsub(%r((sg_CardNumber=)[^&]+(&?)), '\1[FILTERED]\2'). + gsub(%r((sg_CVV2=)\d+), '\1[FILTERED]') + end + + private + + def add_transaction_data(trans_type, post, money, options) + post[:sg_TransType] = trans_type + post[:sg_Currency] = (options[:currency] || currency(money)) + post[:sg_Amount] = amount(money) + post[:sg_ClientLoginID] = @options[:client_login_id] + post[:sg_ClientPassword] = @options[:client_password] + post[:sg_ResponseFormat] = '4' + post[:sg_Version] = VERSION + post[:sg_ClientUniqueID] = options[:order_id] if options[:order_id] + post[:sg_UserID] = options[:user_id] if options[:user_id] + post[:sg_AuthType] = options[:auth_type] if options[:auth_type] + post[:sg_ExpectedFulfillmentCount] = options[:expected_fulfillment_count] if options[:expected_fulfillment_count] + post[:sg_WebsiteID] = options[:website_id] if options[:website_id] + post[:sg_IPAddress] = options[:ip] if options[:ip] + post[:sg_VendorID] = options[:vendor_id] if options[:vendor_id] + post[:sg_Descriptor] = options[:merchant_descriptor] if options[:merchant_descriptor] + post[:sg_MerchantPhoneNumber] = options[:merchant_phone_number] if options[:merchant_phone_number] + post[:sg_MerchantName] = options[:merchant_name] if options[:merchant_name] + end + + def add_payment(post, payment, options={}) + post[:sg_NameOnCard] = payment.name + post[:sg_CardNumber] = payment.number + post[:sg_ExpMonth] = format(payment.month, :two_digits) + post[:sg_ExpYear] = format(payment.year, :two_digits) + post[:sg_CVV2] = payment.verification_value + post[:sg_StoredCredentialMode] = (options[:stored_credential_mode] == true ? 1 : 0) + end + + def add_customer_details(post, payment, options) + if address = options[:billing_address] || options[:address] + post[:sg_FirstName] = payment.first_name + post[:sg_LastName] = payment.last_name + post[:sg_Address] = address[:address1] if address[:address1] + post[:sg_City] = address[:city] if address[:city] + post[:sg_State] = address[:state] if address[:state] + post[:sg_Zip] = address[:zip] if address[:zip] + post[:sg_Country] = address[:country] if address[:country] + post[:sg_Phone] = address[:phone] if address[:phone] + end + + post[:sg_Email] = options[:email] + end + + def parse(xml) + response = {} + + doc = Nokogiri::XML(xml) + doc.root.xpath('*').each do |node| + if node.elements.size == 0 + response[node.name.underscore.downcase.to_sym] = node.text + else + node.traverse do |childnode| + childnode_to_response(response, childnode) + end + end + end + response + end + + def childnode_to_response(response, childnode) + if childnode.elements.size == 0 + element_name_to_symbol(response, childnode) + else + childnode.traverse do |node| + element_name_to_symbol(response, node) + end + end + end + + def element_name_to_symbol(response, childnode) + name = childnode.name.downcase + response[name.to_sym] = childnode.text + end + + def commit(parameters) + url = (test? ? test_url : live_url) + response = parse(ssl_post(url, post_data(parameters))) + + Response.new( + success_from(response), + message_from(response), + response, + authorization: authorization_from(response, parameters), + avs_result: AVSResult.new(code: response[:avs_code]), + cvv_result: CVVResult.new(response[:cvv2_reply]), + test: test?, + error_code: error_code_from(response) + ) + end + + def success_from(response) + response[:status] == 'APPROVED' + end + + def message_from(response) + return 'Success' if success_from(response) + response[:reason_codes] || response[:reason] + end + + def authorization_from(response, parameters) + [ + response[:auth_code], + response[:transaction_id], + response[:token], + parameters[:sg_ExpMonth], + parameters[:sg_ExpYear], + parameters[:sg_Amount], + parameters[:sg_Currency] + ].join('|') + end + + def split_authorization(authorization) + auth_code, transaction_id, token, month, year, original_amount = authorization.split('|') + + { + auth_code: auth_code, + transaction_id: transaction_id, + token: token, + exp_month: month, + exp_year: year, + original_amount: amount(original_amount.to_f * 100) + } + end + + def post_data(params) + return nil unless params + + params.map do |key, value| + next if value != false && value.blank? + "#{key}=#{CGI.escape(value.to_s)}" + end.compact.join('&') + end + + def error_code_from(response) + unless success_from(response) + response[:ex_err_code] || response[:err_code] + end + end + + def underscore(camel_cased_word) + camel_cased_word.to_s.gsub(/::/, '/'). + gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2'). + gsub(/([a-z\d])([A-Z])/, '\1_\2'). + tr('-', '_'). + downcase + end + end + end +end diff --git a/lib/active_merchant/billing/gateways/sage.rb b/lib/active_merchant/billing/gateways/sage.rb index 1400719c04c..09b090778b7 100644 --- a/lib/active_merchant/billing/gateways/sage.rb +++ b/lib/active_merchant/billing/gateways/sage.rb @@ -1,6 +1,8 @@ module ActiveMerchant #:nodoc: module Billing #:nodoc: class SageGateway < Gateway + include Empty + self.display_name = 'http://www.sagepayments.com' self.homepage_url = 'Sage Payment Solutions' self.live_url = 'https://www.sagepayments.net/cgi-bin' @@ -17,8 +19,8 @@ class SageGateway < Gateway :refund => '10' } - SOURCE_CARD = "bankcard" - SOURCE_ECHECK = "virtual_check" + SOURCE_CARD = 'bankcard' + SOURCE_ECHECK = 'virtual_check' def initialize(options = {}) requires!(options, :login, :password) @@ -34,7 +36,7 @@ def authorize(money, credit_card, options = {}) def purchase(money, payment_method, options = {}) post = {} - if card_brand(payment_method) == "check" + if card_brand(payment_method) == 'check' source = SOURCE_ECHECK add_check(post, payment_method) add_check_customer_data(post, options) @@ -57,13 +59,13 @@ def capture(money, reference, options = {}) def void(reference, options = {}) post = {} add_reference(post, reference) - source = reference.split(";").last + source = reference.split(';').last commit(:void, post, source) end def credit(money, payment_method, options = {}) post = {} - if card_brand(payment_method) == "check" + if card_brand(payment_method) == 'check' source = SOURCE_ECHECK add_check(post, payment_method) add_check_customer_data(post, options) @@ -95,11 +97,14 @@ def supports_scrubbing? end def scrub(transcript) - force_utf8(transcript). + force_utf8(transcript). gsub(%r((M_id=)[^&]*), '\1[FILTERED]'). gsub(%r((M_key=)[^&]*), '\1[FILTERED]'). gsub(%r((C_cardnumber=)[^&]*), '\1[FILTERED]'). gsub(%r((C_cvv=)[^&]*), '\1[FILTERED]'). + gsub(%r((C_rte=)[^&]*), '\1[FILTERED]'). + gsub(%r((C_acct=)[^&]*), '\1[FILTERED]'). + gsub(%r((C_ssn=)[^&]*), '\1[FILTERED]'). gsub(%r(().+()), '\1[FILTERED]\2'). gsub(%r(().+()), '\1[FILTERED]\2'). gsub(%r(().+()), '\1[FILTERED]\2') @@ -110,8 +115,8 @@ def scrub(transcript) # use the same method as in pay_conex def force_utf8(string) return nil unless string - binary = string.encode("BINARY", invalid: :replace, undef: :replace, replace: "?") # Needed for Ruby 2.0 since #encode is a no-op if the string is already UTF-8. It's not needed for Ruby 2.1 and up since it's not a no-op there. - binary.encode("UTF-8", invalid: :replace, undef: :replace, replace: "?") + binary = string.encode('BINARY', invalid: :replace, undef: :replace, replace: '?') # Needed for Ruby 2.0 since #encode is a no-op if the string is already UTF-8. It's not needed for Ruby 2.1 and up since it's not a no-op there. + binary.encode('UTF-8', invalid: :replace, undef: :replace, replace: '?') end def add_credit_card(post, credit_card) @@ -131,14 +136,14 @@ def add_check(post, check) end def add_check_customer_data(post, options) - # Required Customer Type – (NACHA Transaction Class) - # CCD for Commercial, Merchant Initiated - # PPD for Personal, Merchant Initiated - # WEB for Internet, Consumer Initiated - # RCK for Returned Checks - # ARC for Account Receivable Entry - # TEL for TelephoneInitiated - post[:C_customer_type] = "WEB" + # Required  Customer Type – (NACHA Transaction Class) + # CCD for Commercial, Merchant Initiated + # PPD for Personal, Merchant Initiated + # WEB for Internet, Consumer Initiated + # RCK for Returned Checks + # ARC for Account Receivable Entry + # TEL for TelephoneInitiated + post[:C_customer_type] = 'WEB' # Optional 10 Digit Originator ID – Assigned By for each transaction class or business purpose. If not provided, the default Originator ID for the specific Customer Type will be applied. post[:C_originator_id] = options[:originator_id] @@ -155,7 +160,7 @@ def add_check_customer_data(post, options) end def format_birth_date(date) - date.respond_to?(:strftime) ? date.strftime("%m/%d/%Y") : date + date.respond_to?(:strftime) ? date.strftime('%m/%d/%Y') : date end # DDA for Checking @@ -174,9 +179,9 @@ def parse(data, source) def parse_check(data) response = {} - response[:success] = data[1,1] - response[:code] = data[2,6].strip - response[:message] = data[8,32].strip + response[:success] = data[1, 1] + response[:code] = data[2, 6].strip + response[:message] = data[8, 32].strip response[:risk] = data[40, 2] response[:reference] = data[42, 10] @@ -189,9 +194,9 @@ def parse_check(data) def parse_credit_card(data) response = {} - response[:success] = data[1,1] - response[:code] = data[2,6] - response[:message] = data[8,32].strip + response[:success] = data[1, 1] + response[:code] = data[2, 6] + response[:message] = data[8, 32].strip response[:front_end] = data[40, 2] response[:cvv_result] = data[42, 1] response[:avs_result] = data[43, 1].strip @@ -204,12 +209,12 @@ def parse_credit_card(data) def add_invoice(post, options) post[:T_ordernum] = (options[:order_id] || generate_unique_id).slice(0, 20) - post[:T_tax] = amount(options[:tax]) unless options[:tax].blank? - post[:T_shipping] = amount(options[:shipping]) unless options[:shipping].blank? + post[:T_tax] = amount(options[:tax]) unless empty?(options[:tax]) + post[:T_shipping] = amount(options[:shipping]) unless empty?(options[:shipping]) end def add_reference(post, reference) - ref, _ = reference.to_s.split(";") + ref, _ = reference.to_s.split(';') post[:T_reference] = ref end @@ -226,7 +231,7 @@ def add_addresses(post, options) post[:C_address] = billing_address[:address1] post[:C_city] = billing_address[:city] - post[:C_state] = billing_address[:state] + post[:C_state] = empty?(billing_address[:state]) ? 'Outside of US' : billing_address[:state] post[:C_zip] = billing_address[:zip] post[:C_country] = billing_address[:country] post[:C_telephone] = billing_address[:phone] @@ -283,7 +288,7 @@ def post_data(action, params = {}) params[:M_key] = @options[:password] params[:T_code] = TRANSACTIONS[action] - params.collect { |key, value| "#{key}=#{CGI.escape(value.to_s)}" }.join("&") + params.collect { |key, value| "#{key}=#{CGI.escape(value.to_s)}" }.join('&') end def vault @@ -352,16 +357,19 @@ def add_identification(xml, identification, options) end def exp_date(credit_card) - year = sprintf("%.4i", credit_card.year) - month = sprintf("%.2i", credit_card.month) + year = sprintf('%.4i', credit_card.year) + month = sprintf('%.2i', credit_card.month) "#{month}#{year[-2..-1]}" end def commit(action, request) - response = parse(@gateway.ssl_post(@live_url, - build_soap_request(action, request), - build_headers(action)) + response = parse( + @gateway.ssl_post( + @live_url, + build_soap_request(action, request), + build_headers(action) + ) ) case action @@ -379,8 +387,8 @@ def commit(action, request) end ENVELOPE_NAMESPACES = { - 'xmlns:SOAP-ENV' => "http://schemas.xmlsoap.org/soap/envelope/", - 'xmlns:ns1' => "https://www.sagepayments.net/web_services/wsVault/wsVault" + 'xmlns:SOAP-ENV' => 'http://schemas.xmlsoap.org/soap/envelope/', + 'xmlns:ns1' => 'https://www.sagepayments.net/web_services/wsVault/wsVault' } ACTION_ELEMENTS = { @@ -410,8 +418,8 @@ def build_soap_request(action, body) def build_headers(action) { - "SOAPAction" => SOAP_ACTIONS[action], - "Content-Type" => "text/xml; charset=utf-8" + 'SOAPAction' => SOAP_ACTIONS[action], + 'Content-Type' => 'text/xml; charset=utf-8' } end @@ -425,12 +433,12 @@ def hashify_xml!(xml, response) xml = REXML::Document.new(xml) # Store - xml.elements.each("//Table1/*") do |node| + xml.elements.each('//Table1/*') do |node| response[node.name.underscore.to_sym] = node.text end # Unstore - xml.elements.each("//DELETE_DATAResponse/*") do |node| + xml.elements.each('//DELETE_DATAResponse/*') do |node| response[node.name.underscore.to_sym] = node.text end end diff --git a/lib/active_merchant/billing/gateways/sage_pay.rb b/lib/active_merchant/billing/gateways/sage_pay.rb index 788c2ada605..a3cd5f7b657 100644 --- a/lib/active_merchant/billing/gateways/sage_pay.rb +++ b/lib/active_merchant/billing/gateways/sage_pay.rb @@ -20,34 +20,40 @@ class SagePayGateway < Gateway :void => 'VOID', :abort => 'ABORT', :store => 'TOKEN', - :unstore => 'REMOVETOKEN' + :unstore => 'REMOVETOKEN', + :repeat => 'REPEAT' } CREDIT_CARDS = { - :visa => "VISA", - :master => "MC", - :delta => "DELTA", - :solo => "SOLO", - :switch => "MAESTRO", - :maestro => "MAESTRO", - :american_express => "AMEX", - :electron => "UKE", - :diners_club => "DC", - :jcb => "JCB" + :visa => 'VISA', + :master => 'MC', + :delta => 'DELTA', + :maestro => 'MAESTRO', + :american_express => 'AMEX', + :electron => 'UKE', + :diners_club => 'DC', + :jcb => 'JCB' } - AVS_CVV_CODE = { - "NOTPROVIDED" => nil, - "NOTCHECKED" => 'X', - "MATCHED" => 'Y', - "NOTMATCHED" => 'N' + AVS_CODE = { + 'NOTPROVIDED' => nil, + 'NOTCHECKED' => 'X', + 'MATCHED' => 'Y', + 'NOTMATCHED' => 'N' + } + + CVV_CODE = { + 'NOTPROVIDED' => 'S', + 'NOTCHECKED' => 'X', + 'MATCHED' => 'M', + 'NOTMATCHED' => 'N' } OPTIONAL_REQUEST_FIELDS = { paypal_callback_url: :PayPalCallbackURL, basket: :Basket, - gift_aid_payment: :GiftAidPayment , - apply_avscv2: :ApplyAVSCV2 , + gift_aid_payment: :GiftAidPayment, + apply_avscv2: :ApplyAVSCV2, apply_3d_secure: :Apply3DSecure, account_type: :AccountType, billing_agreement: :BillingAgreement, @@ -57,13 +63,13 @@ class SagePayGateway < Gateway vendor_data: :VendorData, language: :Language, website: :Website, - recipient_account_number: :FIRecipientAcctNumber , - recipient_surname: :FIRecipientSurname , - recipient_postcode: :FIRecipientPostcode , + recipient_account_number: :FIRecipientAcctNumber, + recipient_surname: :FIRecipientSurname, + recipient_postcode: :FIRecipientPostcode, recipient_dob: :FIRecipientDoB } - self.supported_cardtypes = [:visa, :master, :american_express, :discover, :jcb, :switch, :solo, :maestro, :diners_club] + self.supported_cardtypes = [:visa, :master, :american_express, :discover, :jcb, :maestro, :diners_club] self.supported_countries = ['GB', 'IE'] self.default_currency = 'GBP' @@ -87,7 +93,7 @@ def purchase(money, payment_method, options = {}) add_customer_data(post, options) add_optional_data(post, options) - commit(:purchase, post) + commit((past_purchase_reference?(payment_method) ? :repeat : :purchase), post) end def authorize(money, payment_method, options = {}) @@ -130,7 +136,7 @@ def refund(money, identification, options = {}) post = {} - add_credit_reference(post, identification) + add_related_reference(post, identification) add_amount(post, money, options) add_invoice(post, options) @@ -175,6 +181,7 @@ def scrub(transcript) end private + def truncate(value, max_size) return nil unless value return value.to_s if CGI.escape(value.to_s).length <= max_size @@ -195,7 +202,7 @@ def add_reference(post, identification) add_pair(post, :SecurityKey, security_key) end - def add_credit_reference(post, identification) + def add_related_reference(post, identification) order_id, transaction_id, authorization, security_key = identification.split(';') add_pair(post, :RelatedVendorTxCode, order_id) @@ -267,10 +274,14 @@ def add_invoice(post, options) end def add_payment_method(post, payment_method, options) - if payment_method.respond_to?(:number) - add_credit_card(post, payment_method) + if payment_method.is_a?(String) + if past_purchase_reference?(payment_method) + add_related_reference(post, payment_method) + else + add_token_details(post, payment_method, options) + end else - add_token_details(post, payment_method, options) + add_credit_card(post, payment_method) end end @@ -279,11 +290,6 @@ def add_credit_card(post, credit_card) add_pair(post, :CardNumber, credit_card.number, :required => true) add_pair(post, :ExpiryDate, format_date(credit_card.month, credit_card.year), :required => true) - - if requires_start_date_or_issue_number?(credit_card) - add_pair(post, :StartDate, format_date(credit_card.start_month, credit_card.start_year)) - add_pair(post, :IssueNumber, credit_card.issue_number) - end add_pair(post, :CardType, map_card_type(credit_card)) add_pair(post, :CV2, credit_card.verification_value) @@ -315,7 +321,7 @@ def is_usa(country) end def map_card_type(credit_card) - raise ArgumentError, "The credit card type must be provided" if card_brand(credit_card).blank? + raise ArgumentError, 'The credit card type must be provided' if card_brand(credit_card).blank? card_type = card_brand(credit_card).to_sym @@ -330,23 +336,23 @@ def map_card_type(credit_card) def format_date(month, year) return nil if year.blank? || month.blank? - year = sprintf("%.4i", year) - month = sprintf("%.2i", month) + year = sprintf('%.4i', year) + month = sprintf('%.2i', month) "#{month}#{year[-2..-1]}" end def commit(action, parameters) - response = parse( ssl_post(url_for(action), post_data(action, parameters)) ) + response = parse(ssl_post(url_for(action), post_data(action, parameters))) - Response.new(response["Status"] == APPROVED, message_from(response), response, + Response.new(response['Status'] == APPROVED, message_from(response), response, :test => test?, :authorization => authorization_from(response, parameters, action), :avs_result => { - :street_match => AVS_CVV_CODE[ response["AddressResult"] ], - :postal_match => AVS_CVV_CODE[ response["PostCodeResult"] ], + :street_match => AVS_CODE[response['AddressResult']], + :postal_match => AVS_CODE[response['PostCodeResult']], }, - :cvv_result => AVS_CVV_CODE[ response["CV2Result"] ] + :cvv_result => CVV_CODE[response['CV2Result']] ) end @@ -355,11 +361,11 @@ def authorization_from(response, params, action) when :store response['Token'] else - [ params[:VendorTxCode], - response["VPSTxId"], - response["TxAuthNo"], - response["SecurityKey"], - action ].join(";") + [ params[:VendorTxCode], + response['VPSTxId'] || params[:VPSTxId], + response['TxAuthNo'], + response['SecurityKey'] || params[:SecurityKey], + action ].join(';') end end @@ -374,15 +380,15 @@ def url_for(action) def build_url(action) endpoint = case action - when :purchase, :authorization then "vspdirect-register" - when :store then 'directtoken' - else TRANSACTIONS[action].downcase + when :purchase, :authorization then 'vspdirect-register' + when :store then 'directtoken' + else TRANSACTIONS[action].downcase end "#{test? ? self.test_url : self.live_url}/#{endpoint}.vsp" end def build_simulator_url(action) - endpoint = [ :purchase, :authorization ].include?(action) ? "VSPDirectGateway.asp" : "VSPServerGateway.asp?Service=Vendor#{TRANSACTIONS[action].capitalize}Tx" + endpoint = [ :purchase, :authorization ].include?(action) ? 'VSPDirectGateway.asp' : "VSPServerGateway.asp?Service=Vendor#{TRANSACTIONS[action].capitalize}Tx" "#{self.simulator_url}/#{endpoint}" end @@ -401,7 +407,7 @@ def post_data(action, parameters = {}) parameters.update(:ReferrerID => application_id) end - parameters.collect { |key, value| "#{key}=#{CGI.escape(value.to_s)}" }.join("&") + parameters.collect { |key, value| "#{key}=#{CGI.escape(value.to_s)}" }.join('&') end # SagePay returns data in the following format @@ -419,7 +425,10 @@ def add_pair(post, key, value, options = {}) post[key] = value if !value.blank? || options[:required] end + def past_purchase_reference?(payment_method) + return false unless payment_method.is_a?(String) + payment_method.split(';').last == 'purchase' + end end - end end diff --git a/lib/active_merchant/billing/gateways/sallie_mae.rb b/lib/active_merchant/billing/gateways/sallie_mae.rb index 1098790d292..7e15f08e232 100644 --- a/lib/active_merchant/billing/gateways/sallie_mae.rb +++ b/lib/active_merchant/billing/gateways/sallie_mae.rb @@ -21,7 +21,7 @@ def initialize(options = {}) end def test? - @options[:login] == "TEST0" + @options[:login] == 'TEST0' end def authorize(money, creditcard, options = {}) @@ -94,11 +94,11 @@ def add_creditcard(post, creditcard) def parse(body) h = {} - body.gsub!("", "") + body.gsub!('<html><body><plaintext>', '') body. split("\r\n"). map do |i| - a = i.split("=") + a = i.split('=') h[a.first] = a.last unless a.first.nil? end h @@ -111,33 +111,32 @@ def commit(action, money, parameters) case action when :sale - parameters[:action] = "ns_quicksale_cc" + parameters[:action] = 'ns_quicksale_cc' when :authonly - parameters[:action] = "ns_quicksale_cc" + parameters[:action] = 'ns_quicksale_cc' parameters[:authonly] = 1 when :capture - parameters[:action] = "ns_quicksale_cc" + parameters[:action] = 'ns_quicksale_cc' end - response = parse(ssl_post(self.live_url, parameters.to_post_data) || "") + response = parse(ssl_post(self.live_url, parameters.to_post_data) || '') Response.new(successful?(response), message_from(response), response, :test => test?, - :authorization => response["refcode"] + :authorization => response['refcode'] ) end def successful?(response) - response["Status"] == "Accepted" + response['Status'] == 'Accepted' end def message_from(response) if successful?(response) - "Accepted" + 'Accepted' else - response["Reason"].split(":")[2].capitalize unless response["Reason"].nil? + response['Reason'].split(':')[2].capitalize unless response['Reason'].nil? end end end end end - diff --git a/lib/active_merchant/billing/gateways/secure_net.rb b/lib/active_merchant/billing/gateways/secure_net.rb index abf9d4ebccd..f3abdf29935 100644 --- a/lib/active_merchant/billing/gateways/secure_net.rb +++ b/lib/active_merchant/billing/gateways/secure_net.rb @@ -2,21 +2,21 @@ module ActiveMerchant #:nodoc: module Billing #:nodoc: class SecureNetGateway < Gateway - API_VERSION = "4.0" + API_VERSION = '4.0' TRANSACTIONS = { - :auth_only => "0000", - :auth_capture => "0100", - :prior_auth_capture => "0200", - :void => "0400", - :credit => "0500" + :auth_only => '0000', + :auth_capture => '0100', + :prior_auth_capture => '0200', + :void => '0400', + :credit => '0500' } XML_ATTRIBUTES = { - 'xmlns' => "http://gateway.securenet.com/API/Contracts", - 'xmlns:i' => "http://www.w3.org/2001/XMLSchema-instance" + 'xmlns' => 'http://gateway.securenet.com/API/Contracts', + 'xmlns:i' => 'http://www.w3.org/2001/XMLSchema-instance' } - NIL_ATTRIBUTE = { 'i:nil' => "true" } + NIL_ATTRIBUTE = { 'i:nil' => 'true' } self.supported_countries = ['US'] self.supported_cardtypes = [:visa, :master, :american_express, :discover] @@ -61,12 +61,23 @@ def credit(money, authorization, options = {}) refund(money, authorization, options) end + def supports_scrubbing? + true + end + + def scrub(transcript) + transcript. + gsub(%r((<CARDNUMBER>)\d+(</CARDNUMBER>))i, '\1[FILTERED]\2'). + gsub(%r((<CARDCODE>)\d+(</CARDCODE>))i, '\1[FILTERED]\2'). + gsub(%r((<SECUREKEY>).+(</SECUREKEY>))i, '\1[FILTERED]\2') + end private + def commit(request) xml = build_request(request) url = test? ? self.test_url : self.live_url - data = ssl_post(url, xml, "Content-Type" => "text/xml") + data = ssl_post(url, xml, 'Content-Type' => 'text/xml') response = parse(data) Response.new(success?(response), message_from(response), response, @@ -81,7 +92,7 @@ def build_request(request) xml = Builder::XmlMarkup.new xml.instruct! - xml.tag!("TRANSACTION", XML_ATTRIBUTES) do + xml.tag!('TRANSACTION', XML_ATTRIBUTES) do xml << request end @@ -105,7 +116,7 @@ def build_capture_refund_void(authorization, options, action, money = nil) transaction_id, amount_in_ref, last_four = split_authorization(authorization) xml.tag! 'AMOUNT', amount(money) || amount_in_ref - xml.tag!("CARD") do + xml.tag!('CARD') do xml.tag! 'CARDNUMBER', last_four end @@ -117,7 +128,7 @@ def build_capture_refund_void(authorization, options, action, money = nil) end def add_credit_card(xml, creditcard) - xml.tag!("CARD") do + xml.tag!('CARD') do xml.tag! 'CARDCODE', creditcard.verification_value if creditcard.verification_value? xml.tag! 'CARDNUMBER', creditcard.number xml.tag! 'EXPDATE', expdate(creditcard) @@ -138,7 +149,7 @@ def add_address(xml, creditcard, options) return unless creditcard if address = options[:billing_address] || options[:address] - xml.tag!("CUSTOMER_BILL") do + xml.tag!('CUSTOMER_BILL') do xml.tag! 'ADDRESS', address[:address1].to_s xml.tag! 'CITY', address[:city].to_s xml.tag! 'COMPANY', address[:company].to_s @@ -156,7 +167,7 @@ def add_address(xml, creditcard, options) end if address = options[:shipping_address] - xml.tag!("CUSTOMER_SHIP") do + xml.tag!('CUSTOMER_SHIP') do xml.tag! 'ADDRESS', address[:address1].to_s xml.tag! 'CITY', address[:city].to_s xml.tag! 'COMPANY', address[:company].to_s @@ -178,11 +189,10 @@ def add_address(xml, creditcard, options) xml.tag!('CUSTOMER_SHIP', NIL_ATTRIBUTE) do end end - end def add_merchant_key(xml, options) - xml.tag!("MERCHANT_KEY") do + xml.tag!('MERCHANT_KEY') do xml.tag! 'GROUPID', 0 xml.tag! 'SECUREKEY', @options[:password] xml.tag! 'SECURENETID', @options[:login] @@ -225,7 +235,7 @@ def message_from(response) def parse(xml) response = {} xml = REXML::Document.new(xml) - root = REXML::XPath.first(xml, "//GATEWAYRESPONSE") + root = REXML::XPath.first(xml, '//GATEWAYRESPONSE') if root root.elements.to_a.each do |node| recurring_parse_element(response, node) @@ -237,22 +247,21 @@ def parse(xml) def recurring_parse_element(response, node) if node.has_elements? - node.elements.each{|e| recurring_parse_element(response, e) } + node.elements.each { |e| recurring_parse_element(response, e) } else response[node.name.underscore.to_sym] = node.text end end def split_authorization(authorization) - transaction_id, amount, last_four = authorization.split("|") + transaction_id, amount, last_four = authorization.split('|') [transaction_id, amount, last_four] end def build_authorization(response) - [response[:transactionid], response[:transactionamount], response[:last4_digits]].join("|") + [response[:transactionid], response[:transactionamount], response[:last4_digits]].join('|') end end end end - diff --git a/lib/active_merchant/billing/gateways/secure_pay.rb b/lib/active_merchant/billing/gateways/secure_pay.rb index db3f6ad8f86..4cd0c8a63d3 100644 --- a/lib/active_merchant/billing/gateways/secure_pay.rb +++ b/lib/active_merchant/billing/gateways/secure_pay.rb @@ -95,14 +95,14 @@ def post_data(action, parameters = {}) post[:version] = API_VERSION post[:login] = @options[:login] post[:tran_key] = @options[:password] - post[:relay_response] = "FALSE" + post[:relay_response] = 'FALSE' post[:type] = action - post[:delim_data] = "TRUE" - post[:delim_char] = "," - post[:encap_char] = "$" + post[:delim_data] = 'TRUE' + post[:delim_char] = ',' + post[:encap_char] = '$' post[:solution_ID] = application_id if application_id - request = post.merge(parameters).collect { |key, value| "x_#{key}=#{CGI.escape(value.to_s)}" }.join("&") + request = post.merge(parameters).collect { |key, value| "x_#{key}=#{CGI.escape(value.to_s)}" }.join('&') request end @@ -183,9 +183,9 @@ def add_address(post, options) def message_from(results) if results[:response_code] == DECLINED - return CVVResult.messages[ results[:card_code] ] if CARD_CODE_ERRORS.include?(results[:card_code]) + return CVVResult.messages[results[:card_code]] if CARD_CODE_ERRORS.include?(results[:card_code]) if AVS_REASON_CODES.include?(results[:response_reason_code]) && AVS_ERRORS.include?(results[:avs_result_code]) - return AVSResult.messages[ results[:avs_result_code] ] + return AVSResult.messages[results[:avs_result_code]] end end @@ -198,4 +198,3 @@ def split(response) end end end - diff --git a/lib/active_merchant/billing/gateways/secure_pay_au.rb b/lib/active_merchant/billing/gateways/secure_pay_au.rb index 0bf27eb522d..37a2845bbd5 100644 --- a/lib/active_merchant/billing/gateways/secure_pay_au.rb +++ b/lib/active_merchant/billing/gateways/secure_pay_au.rb @@ -43,9 +43,9 @@ class SecurePayAuGateway < Gateway } PERIODIC_ACTIONS = { - :add_triggered => "add", - :remove_triggered => "delete", - :trigger => "trigger" + :add_triggered => 'add', + :remove_triggered => 'delete', + :trigger => 'trigger' } PERIODIC_TYPES = { @@ -167,8 +167,8 @@ def build_request(action, body) xml.tag! 'RequestType', 'Payment' xml.tag! 'Payment' do - xml.tag! 'TxnList', "count" => 1 do - xml.tag! 'Txn', "ID" => 1 do + xml.tag! 'TxnList', 'count' => 1 do + xml.tag! 'Txn', 'ID' => 1 do xml.tag! 'txnType', TRANSACTIONS[action] xml.tag! 'txnSource', 23 xml << body @@ -226,8 +226,8 @@ def build_periodic_request(body) xml.tag! 'RequestType', 'Periodic' xml.tag! 'Periodic' do - xml.tag! 'PeriodicList', "count" => 1 do - xml.tag! 'PeriodicItem', "ID" => 1 do + xml.tag! 'PeriodicList', 'count' => 1 do + xml.tag! 'PeriodicItem', 'ID' => 1 do xml << body end end @@ -238,7 +238,6 @@ def build_periodic_request(body) def commit_periodic(request) my_request = build_periodic_request(request) - #puts my_request response = parse(ssl_post(test? ? self.test_periodic_url : self.live_periodic_url, my_request)) Response.new(success?(response), message_from(response), response, @@ -277,7 +276,7 @@ def parse(body) def parse_element(response, node) if node.has_elements? - node.elements.each{|element| parse_element(response, element) } + node.elements.each { |element| parse_element(response, element) } else response[node.name.underscore.to_sym] = node.text end diff --git a/lib/active_merchant/billing/gateways/secure_pay_tech.rb b/lib/active_merchant/billing/gateways/secure_pay_tech.rb index 7f09342a448..b6980d4cf99 100644 --- a/lib/active_merchant/billing/gateways/secure_pay_tech.rb +++ b/lib/active_merchant/billing/gateways/secure_pay_tech.rb @@ -8,15 +8,15 @@ class SecurePayTechPostData < PostData self.live_url = self.test_url = 'https://tx.securepaytech.com/web/HttpPostPurchase' PAYMENT_GATEWAY_RESPONSES = { - 1 => "Transaction OK", - 2 => "Insufficient funds", - 3 => "Card expired", - 4 => "Card declined", - 5 => "Server error", - 6 => "Communications error", - 7 => "Unsupported transaction type", - 8 => "Bad or malformed request", - 9 => "Invalid card number" + 1 => 'Transaction OK', + 2 => 'Insufficient funds', + 3 => 'Card expired', + 4 => 'Card declined', + 5 => 'Server error', + 6 => 'Communications error', + 7 => 'Unsupported transaction type', + 8 => 'Bad or malformed request', + 9 => 'Invalid card number' } self.default_currency = 'NZD' @@ -82,7 +82,7 @@ def parse(body) end def commit(action, post) - response = parse( ssl_post(self.live_url, post_data(action, post) ) ) + response = parse(ssl_post(self.live_url, post_data(action, post))) Response.new(response[:result_code] == 1, message_from(response), response, :test => test?, @@ -102,4 +102,3 @@ def post_data(action, post) end end end - diff --git a/lib/active_merchant/billing/gateways/securion_pay.rb b/lib/active_merchant/billing/gateways/securion_pay.rb index 5a1048d95ed..c59370bad4d 100644 --- a/lib/active_merchant/billing/gateways/securion_pay.rb +++ b/lib/active_merchant/billing/gateways/securion_pay.rb @@ -4,7 +4,6 @@ class SecurionPayGateway < Gateway self.test_url = 'https://api.securionpay.com/' self.live_url = 'https://api.securionpay.com/' - self.supported_countries = %w(AL AD AT BY BE BG HR CY CZ RE DK EE IS FI FR DE GI GR HU IS IE IT IL LV LI LT LU MK MT MD MC NL NO PL PT RO RU MA RS SK SI ES SE CH UA GB KI CI ME) @@ -44,7 +43,7 @@ def purchase(money, payment, options={}) def authorize(money, payment, options={}) post = create_post_for_auth_or_purchase(money, payment, options) - post[:captured] = "false" + post[:captured] = 'false' commit('charges', post, options) end @@ -74,12 +73,12 @@ def verify(credit_card, options={}) def store(credit_card, options = {}) if options[:customer_id].blank? MultiResponse.run() do |r| - #create charge object + # create charge object r.process { authorize(100, credit_card, options) } - #create customer and save card + # create customer and save card r.process { create_customer_add_card(r.authorization, options) } - #void the charge - r.process(:ignore_result) { void(r.params["metadata"]["chargeId"], options) } + # void the charge + r.process(:ignore_result) { void(r.params['metadata']['chargeId'], options) } end else verify(credit_card, options) @@ -166,7 +165,7 @@ def add_creditcard(post, creditcard, options) end def add_address(post, options) - return unless post[:card] && post[:card].kind_of?(Hash) + return unless post[:card]&.kind_of?(Hash) if address = options[:billing_address] post[:card][:addressLine1] = address[:address1] if address[:address1] post[:card][:addressLine2] = address[:address2] if address[:address2] @@ -183,14 +182,14 @@ def parse(body) def commit(url, parameters = nil, options = {}, method = nil) response = api_request(url, parameters, options, method) - success = !response.key?("error") + success = !response.key?('error') Response.new(success, - (success ? "Transaction approved" : response["error"]["message"]), + (success ? 'Transaction approved' : response['error']['message']), response, test: test?, - authorization: (success ? response["id"] : response["error"]["charge"]), - error_code: (success ? nil : STANDARD_ERROR_CODE_MAPPING[response["error"]["code"]]) + authorization: (success ? response['id'] : response['error']['charge']), + error_code: (success ? nil : STANDARD_ERROR_CODE_MAPPING[response['error']['code']]) ) end @@ -198,18 +197,16 @@ def headers(options = {}) secret_key = options[:secret_key] || @options[:secret_key] headers = { - "Authorization" => "Basic " + Base64.encode64(secret_key.to_s + ":").strip, - "User-Agent" => "SecurionPay/v1 ActiveMerchantBindings/#{ActiveMerchant::VERSION}" + 'Authorization' => 'Basic ' + Base64.encode64(secret_key.to_s + ':').strip, + 'User-Agent' => "SecurionPay/v1 ActiveMerchantBindings/#{ActiveMerchant::VERSION}" } headers end def response_error(raw_response) - begin - parse(raw_response) - rescue JSON::ParserError - json_error(raw_response) - end + parse(raw_response) + rescue JSON::ParserError + json_error(raw_response) end def post_data(params) @@ -224,11 +221,11 @@ def post_data(params) end post_data(h) elsif value.is_a?(Array) - value.map { |v| "#{key}[]=#{CGI.escape(v.to_s)}" }.join("&") + value.map { |v| "#{key}[]=#{CGI.escape(v.to_s)}" }.join('&') else "#{key}=#{CGI.escape(value.to_s)}" end - end.compact.join("&") + end.compact.join('&') end def api_request(endpoint, parameters = nil, options = {}, method = nil) @@ -253,14 +250,14 @@ def json_error(raw_response) msg = 'Invalid response received from the SecurionPay API.' msg += " (The raw response returned by the API was #{raw_response.inspect})" { - "error" => { - "message" => msg + 'error' => { + 'message' => msg } } end def test? - (@options[:secret_key] && @options[:secret_key].include?('_test_')) + (@options[:secret_key]&.include?('_test_')) end end end diff --git a/lib/active_merchant/billing/gateways/skip_jack.rb b/lib/active_merchant/billing/gateways/skip_jack.rb index ef483288b32..158742d58f7 100644 --- a/lib/active_merchant/billing/gateways/skip_jack.rb +++ b/lib/active_merchant/billing/gateways/skip_jack.rb @@ -1,4 +1,3 @@ -#!ruby19 # encoding: utf-8 module ActiveMerchant #:nodoc: @@ -6,11 +5,11 @@ module Billing #:nodoc: class SkipJackGateway < Gateway API_VERSION = '?.?' - self.live_url = "https://www.skipjackic.com" - self.test_url = "https://developer.skipjackic.com" + self.live_url = 'https://www.skipjackic.com' + self.test_url = 'https://developer.skipjackic.com' - BASIC_PATH = "/scripts/evolvcc.dll" - ADVANCED_PATH = "/evolvcc/evolvcc.aspx" + BASIC_PATH = '/scripts/evolvcc.dll' + ADVANCED_PATH = '/evolvcc/evolvcc.aspx' ACTIONS = { :authorization => 'AuthorizeAPI', @@ -25,34 +24,34 @@ class SkipJackGateway < Gateway CARD_CODE_ERRORS = %w( N S "" ) CARD_CODE_MESSAGES = { - "M" => "Card verification number matched", - "N" => "Card verification number didn't match", - "P" => "Card verification number was not processed", - "S" => "Card verification number should be on card but was not indicated", - "U" => "Issuer was not certified for card verification", - "" => "Transaction failed because incorrect card verification number was entered or no number was entered" + 'M' => 'Card verification number matched', + 'N' => "Card verification number didn't match", + 'P' => 'Card verification number was not processed', + 'S' => 'Card verification number should be on card but was not indicated', + 'U' => 'Issuer was not certified for card verification', + '' => 'Transaction failed because incorrect card verification number was entered or no number was entered' } AVS_ERRORS = %w( A B C E I N O P R W Z ) AVS_MESSAGES = { - "A" => "Street address matches billing information, zip/postal code does not", - "B" => "Street address match for international transaction. Postal code not verified due to incompatible formats", - "C" => "Street address and postal code not verified for internation transaction due to incompatible formats", - "D" => "Street address and postal code match for international transaction", - "E" => "Address verification service error", - "I" => "Address information not verified by international issuer", - "M" => "Street address and postal code match for international transaction", - "N" => "Neither street address nor zip/postal match billing information", - "O" => "Non-US issuer does not participate", - "P" => "Postal codes match for international transaction but street address not verified due to incompatible formats", - "R" => "Payment gateway was unavailable or timed out", - "S" => "Address verification service not supported by issuer", - "U" => "Address information is unavailable", - "W" => "9-digit zip/postal code matches billing information, street address does not", - "X" => "Street address and 9-digit zip/postal code matches billing information", - "Y" => "Street address and 5-digit zip/postal code matches billing information", - "Z" => "5-digit zip/postal code matches billing information, street address does not", + 'A' => 'Street address matches billing information, zip/postal code does not', + 'B' => 'Street address match for international transaction. Postal code not verified due to incompatible formats', + 'C' => 'Street address and postal code not verified for internation transaction due to incompatible formats', + 'D' => 'Street address and postal code match for international transaction', + 'E' => 'Address verification service error', + 'I' => 'Address information not verified by international issuer', + 'M' => 'Street address and postal code match for international transaction', + 'N' => 'Neither street address nor zip/postal match billing information', + 'O' => 'Non-US issuer does not participate', + 'P' => 'Postal codes match for international transaction but street address not verified due to incompatible formats', + 'R' => 'Payment gateway was unavailable or timed out', + 'S' => 'Address verification service not supported by issuer', + 'U' => 'Address information is unavailable', + 'W' => '9-digit zip/postal code matches billing information, street address does not', + 'X' => 'Street address and 9-digit zip/postal code matches billing information', + 'Y' => 'Street address and 5-digit zip/postal code matches billing information', + 'Z' => '5-digit zip/postal code matches billing information, street address does not', } CHANGE_STATUS_ERROR_MESSAGES = { @@ -261,7 +260,7 @@ def add_status_action(post, action) end def commit(action, money, parameters) - response = parse( ssl_post( url_for(action), post_data(action, money, parameters) ), action ) + response = parse(ssl_post(url_for(action), post_data(action, money, parameters)), action) # Pass along the original transaction id in the case an update transaction Response.new(response[:success], message_from(response, action), response, @@ -275,7 +274,7 @@ def commit(action, money, parameters) def url_for(action) result = test? ? self.test_url : self.live_url result += advanced? && action == :authorization ? ADVANCED_PATH : BASIC_PATH - result += "?#{ACTIONS[action]}" + result + "?#{ACTIONS[action]}" end def add_credentials(params, action) @@ -318,7 +317,7 @@ def split_line(line) def authorize_response_map(body) lines = split_lines(body) keys, values = split_line(lines[0]), split_line(lines[1]) - Hash[*(keys.zip(values).flatten)].symbolize_keys + Hash[*keys.zip(values).flatten].symbolize_keys end def parse_authorization_response(body) @@ -333,7 +332,7 @@ def parse_status_response(body, response_keys) keys = [ :szSerialNumber, :szErrorCode, :szNumberRecords] values = split_line(lines[0])[0..2] - result = Hash[*(keys.zip(values).flatten)] + result = Hash[*keys.zip(values).flatten] result[:szErrorMessage] = '' result[:success] = (result[:szErrorCode] == '0') @@ -354,8 +353,8 @@ def parse_status_response(body, response_keys) def post_data(action, money, params = {}) add_credentials(params, action) add_amount(params, action, money) - sorted_params = params.to_a.sort{|a,b| a.to_s <=> b.to_s}.reverse - sorted_params.collect { |key, value| "#{key.to_s}=#{CGI.escape(value.to_s)}" }.join("&") + sorted_params = params.to_a.sort_by(&:to_s).reverse + sorted_params.collect { |key, value| "#{key}=#{CGI.escape(value.to_s)}" }.join('&') end def add_transaction_id(post, transaction_id) @@ -369,7 +368,7 @@ def add_invoice(post, options) post[:OrderDescription] = options[:description] if order_items = options[:items] - post[:OrderString] = order_items.collect { |item| "#{item[:sku]}~#{item[:description].tr('~','-')}~#{item[:declared_value]}~#{item[:quantity]}~#{item[:taxable]}~~~~~~~~#{item[:tax_rate]}~||"}.join + post[:OrderString] = order_items.collect { |item| "#{item[:sku]}~#{item[:description].tr('~', '-')}~#{item[:declared_value]}~#{item[:quantity]}~#{item[:taxable]}~~~~~~~~#{item[:tax_rate]}~||" }.join else post[:OrderString] = '1~None~0.00~0~N~||' end diff --git a/lib/active_merchant/billing/gateways/smart_ps.rb b/lib/active_merchant/billing/gateways/smart_ps.rb index 5c03505e725..0e1b7c0a699 100644 --- a/lib/active_merchant/billing/gateways/smart_ps.rb +++ b/lib/active_merchant/billing/gateways/smart_ps.rb @@ -23,9 +23,9 @@ def initialize(options = {}) def authorize(money, creditcard, options = {}) post = {} add_invoice(post, options) - add_payment_source(post, creditcard,options) + add_payment_source(post, creditcard, options) add_address(post, options[:billing_address] || options[:address]) - add_address(post, options[:shipping_address], "shipping") + add_address(post, options[:shipping_address], 'shipping') add_customer_data(post, options) add_currency(post, money, options) add_taxes(post, options) @@ -38,7 +38,7 @@ def purchase(money, payment_source, options = {}) add_invoice(post, options) add_payment_source(post, payment_source, options) add_address(post, options[:billing_address] || options[:address]) - add_address(post, options[:shipping_address], "shipping") + add_address(post, options[:shipping_address], 'shipping') add_customer_data(post, options) add_currency(post, money, options) add_taxes(post, options) @@ -65,7 +65,7 @@ def credit(money, payment_source, options = {}) add_payment_source(post, payment_source, options) add_address(post, options[:billing_address] || options[:address]) add_customer_data(post, options) - add_sku(post,options) + add_sku(post, options) add_currency(post, money, options) add_processor(post, options) commit('credit', money, post) @@ -89,7 +89,7 @@ def verify(credit_card, options = {}) # CreditCard object. def update(vault_id, creditcard, options = {}) post = {} - post[:customer_vault] = "update_customer" + post[:customer_vault] = 'update_customer' add_customer_vault_id(post, vault_id) add_creditcard(post, creditcard, options) add_address(post, options[:billing_address] || options[:address]) @@ -106,10 +106,9 @@ def amend(auth, options = {}) commit('update', nil, post) end - def delete(vault_id) post = {} - post[:customer_vault] = "delete_customer" + post[:customer_vault] = 'delete_customer' add_customer_vault_id(post, vault_id) commit(nil, nil, post) end @@ -128,6 +127,7 @@ def store(payment_source, options = {}) alias_method :unstore, :delete private + def add_customer_data(post, options) if options.has_key? :email post[:email] = options[:email] @@ -138,17 +138,17 @@ def add_customer_data(post, options) end end - def add_address(post, address,prefix="") - prefix +="_" unless prefix.blank? + def add_address(post, address, prefix='') + prefix +='_' unless prefix.blank? unless address.blank? or address.values.blank? - post[prefix+"address1"] = address[:address1].to_s - post[prefix+"address2"] = address[:address2].to_s unless address[:address2].blank? - post[prefix+"company"] = address[:company].to_s - post[prefix+"phone"] = address[:phone].to_s - post[prefix+"zip"] = address[:zip].to_s - post[prefix+"city"] = address[:city].to_s - post[prefix+"country"] = address[:country].to_s - post[prefix+"state"] = address[:state].blank? ? 'n/a' : address[:state] + post[prefix+'address1'] = address[:address1].to_s + post[prefix+'address2'] = address[:address2].to_s unless address[:address2].blank? + post[prefix+'company'] = address[:company].to_s + post[prefix+'phone'] = address[:phone].to_s + post[prefix+'zip'] = address[:zip].to_s + post[prefix+'city'] = address[:city].to_s + post[prefix+'country'] = address[:country].to_s + post[prefix+'state'] = address[:state].blank? ? 'n/a' : address[:state] end end @@ -182,7 +182,7 @@ def add_customer_vault_id(params, vault_id) def add_creditcard(post, creditcard, options) if options[:store] - post[:customer_vault] = "add_customer" + post[:customer_vault] = 'add_customer' post[:customer_vault_id] = options[:store] unless options[:store] == true end post[:ccnumber] = creditcard.number @@ -194,7 +194,7 @@ def add_creditcard(post, creditcard, options) def add_check(post, check, options) if options[:store] - post[:customer_vault] = "add_customer" + post[:customer_vault] = 'add_customer' post[:customer_vault_id] = options[:store] unless options[:store] == true end @@ -206,8 +206,8 @@ def add_check(post, check, options) post[:account_type] = check.account_type # The customer's type of ACH account end - def add_sku(post,options) - post["product_sku_#"] = options[:sku] || options["product_sku_#"] + def add_sku(post, options) + post['product_sku_#'] = options[:sku] || options['product_sku_#'] end def add_transaction(post, auth) @@ -221,7 +221,7 @@ def add_eci(post, options) def parse(body) results = {} body.split(/&/).each do |pair| - key,val = pair.split(/=/) + key, val = pair.split(/=/) results[key] = val end @@ -229,33 +229,31 @@ def parse(body) end def commit(action, money, parameters) - parameters[:amount] = amount(money) if money - response = parse( ssl_post(self.live_url, post_data(action,parameters)) ) - Response.new(response["response"] == "1", message_from(response), response, - :authorization => (response["transactionid"] || response["customer_vault_id"]), + parameters[:amount] = localized_amount(money, parameters[:currency] || default_currency) if money + response = parse(ssl_post(self.live_url, post_data(action, parameters))) + Response.new(response['response'] == '1', message_from(response), response, + :authorization => (response['transactionid'] || response['customer_vault_id']), :test => test?, - :cvv_result => response["cvvresponse"], - :avs_result => { :code => response["avsresponse"] } + :cvv_result => response['cvvresponse'], + :avs_result => { :code => response['avsresponse'] } ) - end def expdate(creditcard) - year = sprintf("%.04i", creditcard.year) - month = sprintf("%.02i", creditcard.month) + year = sprintf('%.04i', creditcard.year) + month = sprintf('%.02i', creditcard.month) "#{month}#{year[-2..-1]}" end - def message_from(response) - case response["responsetext"] - when "SUCCESS", "Approved", nil # This is dubious, but responses from UPDATE are nil. - "This transaction has been approved" - when "DECLINE" - "This transaction has been declined" + case response['responsetext'] + when 'SUCCESS', 'Approved', nil # This is dubious, but responses from UPDATE are nil. + 'This transaction has been approved' + when 'DECLINE' + 'This transaction has been declined' else - response["responsetext"] + response['responsetext'] end end @@ -265,19 +263,18 @@ def post_data(action, parameters = {}) post[:password] = @options[:password] post[:type] = action if action - request = post.merge(parameters).map {|key,value| "#{key}=#{CGI.escape(value.to_s)}"}.join("&") + request = post.merge(parameters).map { |key, value| "#{key}=#{CGI.escape(value.to_s)}" }.join('&') request end def determine_funding_source(source) case when source.is_a?(String) then :vault - when CreditCard.card_companies.keys.include?(card_brand(source)) then :credit_card + when CreditCard.card_companies.include?(card_brand(source)) then :credit_card when card_brand(source) == 'check' then :check - else raise ArgumentError, "Unsupported funding source provided" + else raise ArgumentError, 'Unsupported funding source provided' end end end end end - diff --git a/lib/active_merchant/billing/gateways/so_easy_pay.rb b/lib/active_merchant/billing/gateways/so_easy_pay.rb index 2227a74ebe4..f0fa4523322 100644 --- a/lib/active_merchant/billing/gateways/so_easy_pay.rb +++ b/lib/active_merchant/billing/gateways/so_easy_pay.rb @@ -10,7 +10,7 @@ class SoEasyPayGateway < Gateway 'MT', 'NL', 'PL', 'PT', 'RO', 'SK', 'SI', 'ES', 'SE', 'GB', 'IS', 'NO', 'CH' ] - self.supported_cardtypes = [:visa, :master, :american_express, :discover, :maestro, :jcb, :solo, :diners_club] + self.supported_cardtypes = [:visa, :master, :american_express, :discover, :maestro, :jcb, :diners_club] self.homepage_url = 'http://www.soeasypay.com/' self.display_name = 'SoEasyPay' @@ -114,7 +114,7 @@ def fill_credentials(soap, options) def fill_cardholder(soap, card, options) ch_info = options[:billing_address] || options[:address] - soap.tag!('customerIP',options[:ip].to_s) + soap.tag!('customerIP', options[:ip].to_s) name = card.name || ch_info[:name] soap.tag!('cardHolderName', name.to_s) address = ch_info[:address1] || '' @@ -135,7 +135,7 @@ def fill_transaction_id(soap, transaction_id) def fill_card(soap, card) soap.tag!('cardNumber', card.number.to_s) soap.tag!('cardSecurityCode', card.verification_value.to_s) - soap.tag!('cardExpireMonth', card.month.to_s.rjust(2, "0")) + soap.tag!('cardExpireMonth', card.month.to_s.rjust(2, '0')) soap.tag!('cardExpireYear', card.year.to_s) end @@ -157,15 +157,15 @@ def parse(response, action) end def commit(soap_action, soap, options) - headers = {"SOAPAction" => "\"urn:Interface##{soap_action}\"", - "Content-Type" => "text/xml; charset=utf-8"} + headers = {'SOAPAction' => "\"urn:Interface##{soap_action}\"", + 'Content-Type' => 'text/xml; charset=utf-8'} response_string = ssl_post(test? ? self.test_url : self.live_url, soap, headers) response = parse(response_string, soap_action) return Response.new(response['errorcode'] == '000', - response['errormessage'], - response, - :test => test?, - :authorization => response['transaction_id']) + response['errormessage'], + response, + :test => test?, + :authorization => response['transaction_id']) end def build_soap(request) diff --git a/lib/active_merchant/billing/gateways/spreedly_core.rb b/lib/active_merchant/billing/gateways/spreedly_core.rb index e4c43db48c0..d3d3e91af87 100644 --- a/lib/active_merchant/billing/gateways/spreedly_core.rb +++ b/lib/active_merchant/billing/gateways/spreedly_core.rb @@ -44,7 +44,7 @@ def purchase(money, payment_method, options = {}) purchase_with_token(money, payment_method, options) else MultiResponse.run do |r| - r.process { save_card(false, payment_method, options) } + r.process { save_card(options[:store], payment_method, options) } r.process { purchase_with_token(money, r.authorization, options) } end end @@ -62,7 +62,7 @@ def authorize(money, payment_method, options = {}) authorize_with_token(money, payment_method, options) else MultiResponse.run do |r| - r.process { save_card(false, payment_method, options) } + r.process { save_card(options[:store], payment_method, options) } r.process { authorize_with_token(money, r.authorization, options) } end end @@ -88,6 +88,23 @@ def void(authorization, options={}) commit("transactions/#{authorization}/void.xml", '') end + # Public: Determine whether a credit card is chargeable card and available for purchases. + # + # payment_method - The CreditCard or the Spreedly payment method token. + # options - A hash of options: + # :store - Retain the payment method if the verify + # succeeds. Defaults to false. (optional) + def verify(payment_method, options = {}) + if payment_method.is_a?(String) + verify_with_token(payment_method, options) + else + MultiResponse.run do |r| + r.process { save_card(options[:store], payment_method, options) } + r.process { verify_with_token(r.authorization, options) } + end + end + end + # Public: Store a credit card in the Spreedly vault and retain it. # # credit_card - The CreditCard to store @@ -106,6 +123,25 @@ def unstore(authorization, options={}) commit("payment_methods/#{authorization}/redact.xml", '', :put) end + # Public: Get the transaction with the given token. + def find(transaction_token) + commit("transactions/#{transaction_token}.xml", nil, :get) + end + + alias_method :status, :find + + def supports_scrubbing? + true + end + + def scrub(transcript) + transcript. + gsub(%r((Authorization: Basic )\w+), '\1[FILTERED]'). + gsub(%r((<number>).+(</number>)), '\1[FILTERED]\2'). + gsub(%r((<verification_value>).+(</verification_value>)), '\1[FILTERED]\2'). + gsub(%r((<payment_method_token>).+(</payment_method_token>)), '\1[FILTERED]\2') + end + private def save_card(retain, credit_card, options) @@ -115,7 +151,7 @@ def save_card(retain, credit_card, options) doc.retained(true) if retain end - commit("payment_methods.xml", request, :post, :payment_method_token) + commit('payment_methods.xml', request, :post, :payment_method_token) end def purchase_with_token(money, payment_method_token, options) @@ -128,10 +164,20 @@ def authorize_with_token(money, payment_method_token, options) commit("gateways/#{@options[:gateway_token]}/authorize.xml", request) end + def verify_with_token(payment_method_token, options) + request = build_xml_request('transaction') do |doc| + add_invoice(doc, nil, options) + doc.payment_method_token(payment_method_token) + doc.retain_on_success(true) if options[:store] + add_extra_options(:gateway_specific_fields, doc, options) + end + + commit("gateways/#{@options[:gateway_token]}/verify.xml", request) + end + def auth_purchase_request(money, payment_method_token, options) build_xml_request('transaction') do |doc| add_invoice(doc, money, options) - doc.ip(options[:ip]) add_extra_options(:gateway_specific_fields, doc, options) doc.payment_method_token(payment_method_token) doc.retain_on_success(true) if options[:store] @@ -139,11 +185,11 @@ def auth_purchase_request(money, payment_method_token, options) end def add_invoice(doc, money, options) - doc.amount amount(money) + doc.amount amount(money) unless money.nil? doc.currency_code(options[:currency] || currency(money) || default_currency) doc.order_id(options[:order_id]) - doc.ip(options[:ip]) - doc.description(options[:description]) + doc.ip(options[:ip]) if options[:ip] + doc.description(options[:description]) if options[:description] end def add_credit_card(doc, credit_card, options) @@ -184,7 +230,7 @@ def parse(xml) doc = Nokogiri::XML(xml) doc.root.xpath('*').each do |node| - if (node.elements.empty?) + if node.elements.empty? response[node.name.downcase.to_sym] = node.text else node.elements.each do |childnode| @@ -244,4 +290,3 @@ def headers end end end - diff --git a/lib/active_merchant/billing/gateways/stripe.rb b/lib/active_merchant/billing/gateways/stripe.rb index f75a569a847..4e107af5eaf 100644 --- a/lib/active_merchant/billing/gateways/stripe.rb +++ b/lib/active_merchant/billing/gateways/stripe.rb @@ -25,7 +25,7 @@ class StripeGateway < Gateway self.default_currency = 'USD' self.money_format = :cents self.supported_cardtypes = [:visa, :master, :american_express, :discover, :jcb, :diners_club, :maestro] - self.currencies_without_fractions = %w(BIF CLP DJF GNF JPY KMF KRW MGA PYG RWF VND VUV XAF XOF XPF) + self.currencies_without_fractions = %w(BIF CLP DJF GNF JPY KMF KRW MGA PYG RWF VND VUV XAF XOF XPF UGX) self.homepage_url = 'https://stripe.com/' self.display_name = 'Stripe' @@ -43,28 +43,29 @@ class StripeGateway < Gateway 'call_issuer' => STANDARD_ERROR_CODE[:call_issuer], 'processing_error' => STANDARD_ERROR_CODE[:processing_error], 'incorrect_pin' => STANDARD_ERROR_CODE[:incorrect_pin], - 'test_mode_live_card' => STANDARD_ERROR_CODE[:test_mode_live_card] + 'test_mode_live_card' => STANDARD_ERROR_CODE[:test_mode_live_card], + 'pickup_card' => STANDARD_ERROR_CODE[:pickup_card] } BANK_ACCOUNT_HOLDER_TYPE_MAPPING = { - "personal" => "individual", - "business" => "company", + 'personal' => 'individual', + 'business' => 'company', } MINIMUM_AUTHORIZE_AMOUNTS = { - "USD" => 100, - "CAD" => 100, - "GBP" => 60, - "EUR" => 100, - "DKK" => 500, - "NOK" => 600, - "SEK" => 600, - "CHF" => 100, - "AUD" => 100, - "JPY" => 100, - "MXN" => 2000, - "SGD" => 100, - "HKD" => 800 + 'USD' => 100, + 'CAD' => 100, + 'GBP' => 60, + 'EUR' => 100, + 'DKK' => 500, + 'NOK' => 600, + 'SEK' => 600, + 'CHF' => 100, + 'AUD' => 100, + 'JPY' => 100, + 'MXN' => 2000, + 'SGD' => 100, + 'HKD' => 800 } def initialize(options = {}) @@ -78,14 +79,14 @@ def authorize(money, payment, options = {}) MultiResponse.run do |r| if payment.is_a?(ApplePayPaymentToken) r.process { tokenize_apple_pay_token(payment) } - payment = StripePaymentToken.new(r.params["token"]) if r.success? + payment = StripePaymentToken.new(r.params['token']) if r.success? end r.process do post = create_post_for_auth_or_purchase(money, payment, options) if emv_payment?(payment) add_application_fee(post, options) else - post[:capture] = "false" + post[:capture] = 'false' end commit(:post, 'charges', post, options) end @@ -101,17 +102,18 @@ def authorize(money, payment, options = {}) # purchase(money, nil, { :customer => id, ... }) def purchase(money, payment, options = {}) if ach?(payment) - direct_bank_error = "Direct bank account transactions are not supported. Bank accounts must be stored and verified before use." + direct_bank_error = 'Direct bank account transactions are not supported. Bank accounts must be stored and verified before use.' return Response.new(false, direct_bank_error) end MultiResponse.run do |r| if payment.is_a?(ApplePayPaymentToken) r.process { tokenize_apple_pay_token(payment) } - payment = StripePaymentToken.new(r.params["token"]) if r.success? + payment = StripePaymentToken.new(r.params['token']) if r.success? end r.process do post = create_post_for_auth_or_purchase(money, payment, options) + post[:card][:processing_method] = 'quick_chip' if quickchip_payment?(payment) commit(:post, 'charges', post, options) end end.responses.last @@ -126,6 +128,7 @@ def capture(money, authorization, options = {}) else add_application_fee(post, options) add_amount(post, money, options) + add_exchange_rate(post, options) commit(:post, "charges/#{CGI.escape(authorization)}/capture", post, options) end end @@ -133,6 +136,7 @@ def capture(money, authorization, options = {}) def void(identification, options = {}) post = {} post[:metadata] = options[:metadata] if options[:metadata] + post[:reason] = options[:reason] if options[:reason] post[:expand] = [:charge] commit(:post, "charges/#{CGI.escape(identification)}/refunds", post, options) end @@ -143,15 +147,16 @@ def refund(money, identification, options = {}) post[:refund_application_fee] = true if options[:refund_application_fee] post[:reverse_transfer] = options[:reverse_transfer] if options[:reverse_transfer] post[:metadata] = options[:metadata] if options[:metadata] + post[:reason] = options[:reason] if options[:reason] post[:expand] = [:charge] MultiResponse.run(:first) do |r| r.process { commit(:post, "charges/#{CGI.escape(identification)}/refunds", post, options) } - return r unless options[:refund_fee_amount] - - r.process { fetch_application_fees(identification, options) } - r.process { refund_application_fee(options[:refund_fee_amount], application_fee_from_response(r.responses.last), options) } + if options[:refund_fee_amount] && options[:refund_fee_amount].to_s != '0' + r.process { fetch_application_fee(identification, options) } + r.process { refund_application_fee(options[:refund_fee_amount].to_i, application_fee_from_response(r.responses.last), options) } + end end end @@ -165,19 +170,19 @@ def verify(payment, options = {}) def application_fee_from_response(response) return unless response.success? - - application_fees = response.params["data"].select { |fee| fee["object"] == "application_fee" } - application_fees.first["id"] unless application_fees.empty? + response.params['application_fee'] unless response.params['application_fee'].empty? end def refund_application_fee(money, identification, options = {}) - return Response.new(false, "Application fee id could not be found") unless identification + return Response.new(false, 'Application fee id could not be found') unless identification post = {} add_amount(post, money, options) - options.merge!(:key => @fee_refund_api_key) + options[:key] = @fee_refund_api_key if @fee_refund_api_key + options.delete(:stripe_account) - commit(:post, "application_fees/#{CGI.escape(identification)}/refund", post, options) + refund_fee = commit(:post, "application_fees/#{CGI.escape(identification)}/refunds", post, options) + application_fee_response!(refund_fee, "Application fee could not be refunded: #{refund_fee.message}") end # Note: creating a new credit card will not change the customer's existing default credit card (use :set_default => true) @@ -187,13 +192,13 @@ def store(payment, options = {}) if payment.is_a?(ApplePayPaymentToken) token_exchange_response = tokenize_apple_pay_token(payment) - params = { card: token_exchange_response.params["token"]["id"] } if token_exchange_response.success? + params = { card: token_exchange_response.params['token']['id'] } if token_exchange_response.success? elsif payment.is_a?(StripePaymentToken) add_payment_token(params, payment, options) elsif payment.is_a?(Check) bank_token_response = tokenize_bank_account(payment) return bank_token_response unless bank_token_response.success? - params = { source: bank_token_response.params["token"]["id"] } + params = { source: bank_token_response.params['token']['id'] } else add_creditcard(params, payment, options) end @@ -232,10 +237,10 @@ def update_customer(customer_id, options = {}) end def unstore(identification, options = {}, deprecated_options = {}) - customer_id, card_id = identification.split("|") + customer_id, card_id = identification.split('|') if options.kind_of?(String) - ActiveMerchant.deprecated "Passing the card_id as the 2nd parameter is deprecated. The response authorization includes both the customer_id and the card_id." + ActiveMerchant.deprecated 'Passing the card_id as the 2nd parameter is deprecated. The response authorization includes both the customer_id and the card_id.' card_id ||= options options = deprecated_options end @@ -245,18 +250,18 @@ def unstore(identification, options = {}, deprecated_options = {}) def tokenize_apple_pay_token(apple_pay_payment_token, options = {}) token_response = api_request(:post, "tokens?pk_token=#{CGI.escape(apple_pay_payment_token.payment_data.to_json)}") - success = !token_response.key?("error") + success = !token_response.key?('error') - if success && token_response.key?("id") + if success && token_response.key?('id') Response.new(success, nil, token: token_response) else - Response.new(success, token_response["error"]["message"]) + Response.new(success, token_response['error']['message']) end end def verify_credentials begin - ssl_get(live_url + "charges/nonexistent", headers) + ssl_get(live_url + 'charges/nonexistent', headers) rescue ResponseError => e return false if e.response.code.to_i == 401 end @@ -303,7 +308,10 @@ def create_post_for_auth_or_purchase(money, payment, options) add_creditcard(post, payment, options) end - unless emv_payment?(payment) + if emv_payment?(payment) + add_statement_address(post, options) + add_emv_metadata(post, payment) + else add_amount(post, money, options, true) add_customer_data(post, options) post[:description] = options[:description] @@ -315,7 +323,9 @@ def create_post_for_auth_or_purchase(money, payment, options) add_metadata(post, options) add_application_fee(post, options) + add_exchange_rate(post, options) add_destination(post, options) + add_level_three(post, options) post end @@ -329,8 +339,31 @@ def add_application_fee(post, options) post[:application_fee] = options[:application_fee] if options[:application_fee] end + def add_exchange_rate(post, options) + post[:exchange_rate] = options[:exchange_rate] if options[:exchange_rate] + end + def add_destination(post, options) - post[:destination] = options[:destination] if options[:destination] + if options[:destination] + post[:destination] = {} + post[:destination][:account] = options[:destination] + post[:destination][:amount] = options[:destination_amount] if options[:destination_amount] + end + end + + def add_level_three(post, options) + level_three = {} + + copy_when_present(level_three, [:merchant_reference], options) + copy_when_present(level_three, [:customer_reference], options) + copy_when_present(level_three, [:shipping_address_zip], options) + copy_when_present(level_three, [:shipping_from_zip], options) + copy_when_present(level_three, [:shipping_amount], options) + copy_when_present(level_three, [:line_items], options) + + unless level_three.empty? + post[:level3] = level_three + end end def add_expand_parameters(post, options) @@ -340,7 +373,7 @@ def add_expand_parameters(post, options) def add_external_account(post, card_params, payment) external_account = {} - external_account[:object] ="card" + external_account[:object] ='card' external_account[:currency] = (options[:currency] || currency(payment)).downcase post[:external_account] = external_account.merge(card_params[:card]) end @@ -354,7 +387,7 @@ def add_customer_data(post, options) end def add_address(post, options) - return unless post[:card] && post[:card].kind_of?(Hash) + return unless post[:card]&.kind_of?(Hash) if address = options[:billing_address] || options[:address] post[:card][:address_line1] = address[:address1] if address[:address1] post[:card][:address_line2] = address[:address2] if address[:address2] @@ -365,12 +398,24 @@ def add_address(post, options) end end + def add_statement_address(post, options) + return unless statement_address = options[:statement_address] + return unless [:address1, :city, :zip, :state].all? { |key| statement_address[key].present? } + + post[:statement_address] = {} + post[:statement_address][:line1] = statement_address[:address1] + post[:statement_address][:line2] = statement_address[:address2] if statement_address[:address2].present? + post[:statement_address][:city] = statement_address[:city] + post[:statement_address][:postal_code] = statement_address[:zip] + post[:statement_address][:state] = statement_address[:state] + end + def add_creditcard(post, creditcard, options) card = {} if emv_payment?(creditcard) add_emv_creditcard(post, creditcard.icc_data) - post[:card][:read_method] = "contactless" if creditcard.contactless_emv - post[:card][:read_method] = "contactless_magstripe_mode" if creditcard.contactless_magstripe + post[:card][:read_method] = 'contactless' if creditcard.read_method == 'contactless' + post[:card][:read_method] = 'contactless_magstripe_mode' if creditcard.read_method == 'contactless_magstripe' if creditcard.encrypted_pin_cryptogram.present? && creditcard.encrypted_pin_ksn.present? post[:card][:encrypted_pin] = creditcard.encrypted_pin_cryptogram post[:card][:encrypted_pin_key_id] = creditcard.encrypted_pin_ksn @@ -378,9 +423,11 @@ def add_creditcard(post, creditcard, options) elsif creditcard.respond_to?(:number) if creditcard.respond_to?(:track_data) && creditcard.track_data.present? card[:swipe_data] = creditcard.track_data - card[:fallback_reason] = creditcard.fallback_reason if creditcard.fallback_reason - card[:read_method] = "contactless" if creditcard.contactless_emv - card[:read_method] = "contactless_magstripe_mode" if creditcard.contactless_magstripe + if creditcard.respond_to?(:read_method) + card[:fallback_reason] = 'no_chip' if creditcard.read_method == 'fallback_no_chip' + card[:fallback_reason] = 'chip_error' if creditcard.read_method == 'fallback_chip_error' + card[:read_method] = 'contactless_magstripe_mode' if creditcard.read_method == 'contactless_magstripe' + end else card[:number] = creditcard.number card[:exp_month] = creditcard.month @@ -400,8 +447,8 @@ def add_creditcard(post, creditcard, options) elsif creditcard.kind_of?(String) if options[:track_data] card[:swipe_data] = options[:track_data] - elsif creditcard.include?("|") - customer_id, card_id = creditcard.split("|") + elsif creditcard.include?('|') + customer_id, card_id = creditcard.split('|') card = card_id post[:customer] = customer_id else @@ -416,32 +463,43 @@ def add_emv_creditcard(post, icc_data, options = {}) end def add_payment_token(post, token, options = {}) - post[:card] = token.payment_data["id"] + post[:card] = token.payment_data['id'] end def add_customer(post, payment, options) if options[:customer] && !payment.respond_to?(:number) - ActiveMerchant.deprecated "Passing the customer in the options is deprecated. Just use the response.authorization instead." + ActiveMerchant.deprecated 'Passing the customer in the options is deprecated. Just use the response.authorization instead.' post[:customer] = options[:customer] end end def add_flags(post, options) post[:uncaptured] = true if options[:uncaptured] - post[:recurring] = true if (options[:eci] == 'recurring' || options[:recurring]) + post[:recurring] = true if options[:eci] == 'recurring' || options[:recurring] end def add_metadata(post, options = {}) - post[:metadata] = options[:metadata] || {} + post[:metadata] ||= {} + post[:metadata].merge!(options[:metadata]) if options[:metadata] post[:metadata][:email] = options[:email] if options[:email] post[:metadata][:order_id] = options[:order_id] if options[:order_id] post.delete(:metadata) if post[:metadata].empty? end - def fetch_application_fees(identification, options = {}) - options.merge!(:key => @fee_refund_api_key) + def add_emv_metadata(post, creditcard) + post[:metadata] ||= {} + post[:metadata][:card_read_method] = creditcard.read_method if creditcard.respond_to?(:read_method) + end + + def fetch_application_fee(identification, options = {}) + options[:key] = @fee_refund_api_key - commit(:get, "application_fees?charge=#{identification}", nil, options) + fetch_charge = commit(:get, "charges/#{CGI.escape(identification)}", nil, options) + application_fee_response!(fetch_charge, "Application fee id could not be retrieved: #{fetch_charge.message}") + end + + def application_fee_response!(response, message) + response.success? ? response : Response.new(false, message) end def parse(body) @@ -450,41 +508,60 @@ def parse(body) def post_data(params) return nil unless params + flatten_params([], params).join('&') + end - params.map do |key, value| + def flatten_params(flattened, params, prefix = nil) + params.each do |key, value| next if value != false && value.blank? + flattened_key = prefix.nil? ? key : "#{prefix}[#{key}]" if value.is_a?(Hash) - h = {} - value.each do |k, v| - h["#{key}[#{k}]"] = v unless v.blank? - end - post_data(h) + flatten_params(flattened, value, flattened_key) elsif value.is_a?(Array) - value.map { |v| "#{key}[]=#{CGI.escape(v.to_s)}" }.join("&") + flatten_array(flattened, value, flattened_key) + else + flattened << "#{flattened_key}=#{CGI.escape(value.to_s)}" + end + end + flattened + end + + def flatten_array(flattened, array, prefix) + array.each_with_index do |item, idx| + key = "#{prefix}[#{idx}]" + if item.is_a?(Hash) + flatten_params(flattened, item, key) + elsif item.is_a?(Array) + flatten_array(flattened, item, key) else - "#{key}=#{CGI.escape(value.to_s)}" + flattened << "#{key}=#{CGI.escape(item.to_s)}" end - end.compact.join("&") + end end def headers(options = {}) - key = options[:key] || @api_key + key = options[:key] || @api_key idempotency_key = options[:idempotency_key] headers = { - "Authorization" => "Basic " + Base64.encode64(key.to_s + ":").strip, - "User-Agent" => "Stripe/v1 ActiveMerchantBindings/#{ActiveMerchant::VERSION}", - "Stripe-Version" => api_version(options), - "X-Stripe-Client-User-Agent" => user_agent, - "X-Stripe-Client-User-Metadata" => {:ip => options[:ip]}.to_json + 'Authorization' => 'Basic ' + Base64.encode64(key.to_s + ':').strip, + 'User-Agent' => "Stripe/v1 ActiveMerchantBindings/#{ActiveMerchant::VERSION}", + 'Stripe-Version' => api_version(options), + 'X-Stripe-Client-User-Agent' => stripe_client_user_agent(options), + 'X-Stripe-Client-User-Metadata' => {:ip => options[:ip]}.to_json } - headers.merge!("Idempotency-Key" => idempotency_key) if idempotency_key - headers.merge!("Stripe-Account" => options[:stripe_account]) if options[:stripe_account] + headers['Idempotency-Key'] = idempotency_key if idempotency_key + headers['Stripe-Account'] = options[:stripe_account] if options[:stripe_account] headers end + def stripe_client_user_agent(options) + return user_agent unless options[:application] + JSON.dump(JSON.parse(user_agent).merge!({application: options[:application]})) + end + def api_version(options) - options[:version] || @options[:version] || "2015-04-07" + options[:version] || @options[:version] || '2015-04-07' end def api_request(method, endpoint, parameters = nil, options = {}) @@ -505,14 +582,14 @@ def commit(method, url, parameters = nil, options = {}) add_expand_parameters(parameters, options) if parameters response = api_request(method, url, parameters, options) - success = !response.key?("error") + success = success_from(response) card = card_from_response(response) avs_code = AVS_CODE_TRANSLATOR["line1: #{card["address_line1_check"]}, zip: #{card["address_zip_check"]}"] - cvc_code = CVC_CODE_TRANSLATOR[card["cvc_check"]] + cvc_code = CVC_CODE_TRANSLATOR[card['cvc_check']] Response.new(success, - success ? "Transaction approved" : response["error"]["message"], + message_from(success, response), response, :test => response_is_test?(response), :authorization => authorization_from(success, url, method, response), @@ -524,31 +601,37 @@ def commit(method, url, parameters = nil, options = {}) end def authorization_from(success, url, method, response) - return response["error"]["charge"] unless success + return response.fetch('error', {})['charge'] unless success - if url == "customers" - [response["id"], response["sources"]["data"].first["id"]].join("|") + if url == 'customers' + [response['id'], response['sources']['data'].first['id']].join('|') elsif method == :post && url.match(/customers\/.*\/cards/) - [response["customer"], response["id"]].join("|") + [response['customer'], response['id']].join('|') else - response["id"] + response['id'] end end + def message_from(success, response) + success ? 'Transaction approved' : response.fetch('error', {'message' => 'No error details'})['message'] + end + + def success_from(response) + !response.key?('error') && response['status'] != 'failed' + end + def response_error(raw_response) - begin - parse(raw_response) - rescue JSON::ParserError - json_error(raw_response) - end + parse(raw_response) + rescue JSON::ParserError + json_error(raw_response) end def json_error(raw_response) msg = 'Invalid response received from the Stripe API. Please contact support@stripe.com if you continue to receive this message.' msg += " (The raw response returned by the API was #{raw_response.inspect})" { - "error" => { - "message" => msg + 'error' => { + 'message' => msg } } end @@ -567,17 +650,23 @@ def emv_payment?(payment) payment.respond_to?(:emv?) && payment.emv? end + def quickchip_payment?(payment) + payment.respond_to?(:read_method) && payment.read_method == 'contact_quickchip' + end + def card_from_response(response) - response["card"] || response["active_card"] || response["source"] || {} + response['card'] || response['active_card'] || response['source'] || {} end def emv_authorization_from_response(response) - return response["error"]["emv_auth_data"] if response["error"] + return response['error']['emv_auth_data'] if response['error'] - card_from_response(response)["emv_auth_data"] + card_from_response(response)['emv_auth_data'] end def error_code_from(response) + return STANDARD_ERROR_CODE_MAPPING['processing_error'] unless response['error'] + code = response['error']['code'] decline_code = response['error']['decline_code'] if code == 'card_declined' @@ -601,12 +690,12 @@ def tokenize_bank_account(bank_account, options = {}) } token_response = api_request(:post, "tokens?#{post_data(post)}") - success = token_response["error"].nil? + success = token_response['error'].nil? - if success && token_response["id"] + if success && token_response['id'] Response.new(success, nil, token: token_response) else - Response.new(success, token_response["error"]["message"]) + Response.new(success, token_response['error']['message']) end end @@ -615,7 +704,7 @@ def ach?(payment_method) when String, nil false else - card_brand(payment_method) == "check" + card_brand(payment_method) == 'check' end end @@ -623,6 +712,22 @@ def auth_minimum_amount(options) return 100 unless options[:currency] return MINIMUM_AUTHORIZE_AMOUNTS[options[:currency].upcase] || 100 end + + def copy_when_present(dest, dest_path, source, source_path = nil) + source_path ||= dest_path + source_path.each do |key| + return nil unless source[key] + source = source[key] + end + + if source + dest_path.first(dest_path.size - 1).each do |key| + dest[key] ||= {} + dest = dest[key] + end + dest[dest_path.last] = source + end + end end end end diff --git a/lib/active_merchant/billing/gateways/swipe_checkout.rb b/lib/active_merchant/billing/gateways/swipe_checkout.rb index 78ad5f5da43..aaf4002d355 100644 --- a/lib/active_merchant/billing/gateways/swipe_checkout.rb +++ b/lib/active_merchant/billing/gateways/swipe_checkout.rb @@ -6,10 +6,7 @@ class SwipeCheckoutGateway < Gateway TRANSACTION_APPROVED_MSG = 'Transaction approved' TRANSACTION_DECLINED_MSG = 'Transaction declined' - LIVE_URLS = { - 'NZ' => 'https://api.swipehq.com', - 'CA' => 'https://api.swipehq.ca' - } + self.live_url = 'https://api.swipehq.com' self.test_url = 'https://api.swipehq.com' TRANSACTION_API = '/createShopifyTransaction.php' @@ -69,7 +66,7 @@ def add_invoice(post, options) post[:td_user_data] = options[:order_id] if options[:order_id] post[:td_item] = options[:description] if options[:description] post[:td_description] = options[:description] if options[:description] - post[:item_quantity] = "1" + post[:item_quantity] = '1' end def add_creditcard(post, creditcard) @@ -95,16 +92,16 @@ def add_amount(post, money, options) def commit(action, money, parameters) case action - when "sale" + when 'sale' begin response = call_api(TRANSACTION_API, parameters) # response code and message params should always be present - code = response["response_code"] - message = response["message"] + code = response['response_code'] + message = response['message'] if code == 200 - result = response["data"]["result"] + result = response['data']['result'] success = (result == 'accepted' || (test? && result == 'test-accepted')) Response.new(success, @@ -120,8 +117,8 @@ def commit(action, money, parameters) rescue ResponseError => e build_error_response("ssl_post() with url #{url} raised ResponseError: #{e}") rescue JSON::ParserError => e - msg = 'Invalid response received from the Swipe Checkout API. ' + - 'Please contact support@optimizerhq.com if you continue to receive this message.' + + msg = 'Invalid response received from the Swipe Checkout API. ' \ + 'Please contact support@optimizerhq.com if you continue to receive this message.' \ " (Full error message: #{e})" build_error_response(msg) end @@ -135,11 +132,11 @@ def call_api(api, params=nil) # ssl_post() returns the response body as a string on success, # or raises a ResponseError exception on failure - JSON.parse(ssl_post(url(@options[:region], api), params.to_query)) + JSON.parse(ssl_post(url(api), params.to_query)) end - def url(region, api) - ((test? ? self.test_url : LIVE_URLS[region]) + api) + def url(api) + (test? ? self.test_url : self.live_url) + api end def build_error_response(message, params={}) @@ -153,4 +150,3 @@ def build_error_response(message, params={}) end end end - diff --git a/lib/active_merchant/billing/gateways/telr.rb b/lib/active_merchant/billing/gateways/telr.rb index 6211af9abd6..c39b0a17e34 100644 --- a/lib/active_merchant/billing/gateways/telr.rb +++ b/lib/active_merchant/billing/gateways/telr.rb @@ -3,15 +3,15 @@ module ActiveMerchant #:nodoc: module Billing #:nodoc: class TelrGateway < Gateway - self.display_name = "Telr" - self.homepage_url = "http://www.telr.com/" + self.display_name = 'Telr' + self.homepage_url = 'http://www.telr.com/' - self.live_url = "https://secure.telr.com/gateway/remote.xml" + self.live_url = 'https://secure.telr.com/gateway/remote.xml' - self.supported_countries = ["AE", "IN", "SA"] - self.default_currency = "AED" + self.supported_countries = ['AE', 'IN', 'SA'] + self.default_currency = 'AED' self.money_format = :dollars - self.supported_cardtypes = [:visa, :master, :american_express, :maestro, :solo, :jcb] + self.supported_cardtypes = [:visa, :master, :american_express, :maestro, :jcb] CVC_CODE_TRANSLATOR = { 'Y' => 'M', @@ -35,7 +35,7 @@ def initialize(options={}) def purchase(amount, payment_method, options={}) commit(:purchase, amount, options[:currency]) do |doc| - add_invoice(doc, "sale", amount, payment_method, options) + add_invoice(doc, 'sale', amount, payment_method, options) add_payment_method(doc, payment_method, options) add_customer_data(doc, payment_method, options) end @@ -43,7 +43,7 @@ def purchase(amount, payment_method, options={}) def authorize(amount, payment_method, options={}) commit(:authorize, amount, options[:currency]) do |doc| - add_invoice(doc, "auth", amount, payment_method, options) + add_invoice(doc, 'auth', amount, payment_method, options) add_payment_method(doc, payment_method, options) add_customer_data(doc, payment_method, options) end @@ -51,34 +51,34 @@ def authorize(amount, payment_method, options={}) def capture(amount, authorization, options={}) commit(:capture) do |doc| - add_invoice(doc, "capture", amount, authorization, options) + add_invoice(doc, 'capture', amount, authorization, options) end end def void(authorization, options={}) _, amount, currency = split_authorization(authorization) commit(:void) do |doc| - add_invoice(doc, "void", amount.to_i, authorization, options.merge(currency: currency)) + add_invoice(doc, 'void', amount.to_i, authorization, options.merge(currency: currency)) end end def refund(amount, authorization, options={}) commit(:refund) do |doc| - add_invoice(doc, "refund", amount, authorization, options) + add_invoice(doc, 'refund', amount, authorization, options) end end def verify(credit_card, options={}) commit(:verify) do |doc| - add_invoice(doc, "verify", 100, credit_card, options) + add_invoice(doc, 'verify', 100, credit_card, options) add_payment_method(doc, credit_card, options) add_customer_data(doc, credit_card, options) end end def verify_credentials - response = void("0") - !["01", "04"].include?(response.error_code) + response = void('0') + !['01', '04'].include?(response.error_code) end def supports_scrubbing? @@ -87,9 +87,9 @@ def supports_scrubbing? def scrub(transcript) transcript. - gsub(%r((<Number>)[^<]+(<))i, '\1[FILTERED]\2'). - gsub(%r((<CVV>)[^<]+(<))i, '\1[FILTERED]\2'). - gsub(%r((<Key>)[^<]+(<))i, '\1[FILTERED]\2') + gsub(%r((<Number>)[^<]+(<))i, '\1[FILTERED]\2'). + gsub(%r((<CVV>)[^<]+(<))i, '\1[FILTERED]\2'). + gsub(%r((<Key>)[^<]+(<))i, '\1[FILTERED]\2') end private @@ -101,7 +101,7 @@ def add_invoice(doc, action, money, payment_method, options) doc.currency(options[:currency] || currency(money)) doc.cartid(options[:order_id]) doc.class_(transaction_class(action, payment_method)) - doc.description(options[:description] || "Description") + doc.description(options[:description] || 'Description') doc.test_(test_mode) add_ref(doc, action, payment_method) end @@ -126,7 +126,7 @@ def add_customer_data(doc, payment_method, options) doc.first(payment_method.first_name) doc.last(payment_method.last_name) end - doc.email(options[:email] || "unspecified@email.com") + doc.email(options[:email] || 'unspecified@email.com') doc.ip(options[:ip]) if options[:ip] doc.address do add_address(doc, options) @@ -136,9 +136,9 @@ def add_customer_data(doc, payment_method, options) def add_address(doc, options) address = options[:billing_address] || {} - doc.country(address[:country] ? lookup_country_code(address[:country]) : "NA") - doc.city(address[:city] || "City") - doc.line1(address[:address1] || "Address") + doc.country(address[:country] ? lookup_country_code(address[:country]) : 'NA') + doc.city(address[:city] || 'City') + doc.line1(address[:address1] || 'Address') return unless address doc.line2(address[:address2]) if address[:address2] doc.zip(address[:zip]) if address[:zip] @@ -146,7 +146,7 @@ def add_address(doc, options) end def add_ref(doc, action, payment_method) - if ["capture", "refund", "void"].include?(action) || payment_method.is_a?(String) + if ['capture', 'refund', 'void'].include?(action) || payment_method.is_a?(String) doc.ref(split_authorization(payment_method)[0]) end end @@ -190,7 +190,6 @@ def root_attributes def build_xml_request builder = Nokogiri::XML::Builder.new(encoding: 'UTF-8') do |xml| xml.remote do |doc| - add_authentication(doc) yield(doc) end @@ -204,10 +203,10 @@ def test_mode end def transaction_class(action, payment_method) - if payment_method.is_a?(String) && action == "sale" - return "cont" + if payment_method.is_a?(String) && action == 'sale' + return 'cont' else - return "moto" + return 'moto' end end @@ -215,16 +214,16 @@ def parse(xml) response = {} doc = Nokogiri::XML(xml) - doc.root.xpath("*").each do |node| - if (node.elements.size == 0) + doc.root&.xpath('*')&.each do |node| + if node.elements.size == 0 response[node.name.downcase.to_sym] = node.text else node.elements.each do |childnode| - name = "#{childnode.name.downcase}" + name = childnode.name.downcase response[name.to_sym] = childnode.text end end - end unless doc.root.nil? + end response end @@ -240,12 +239,12 @@ def split_authorization(authorization) end def success_from(response) - response[:status] == "A" + response[:status] == 'A' end def message_from(succeeded, response) if succeeded - "Succeeded" + 'Succeeded' else response[:message] end @@ -267,7 +266,7 @@ def avs_result(parsed) def headers { - "Content-Type" => "text/xml" + 'Content-Type' => 'text/xml' } end end diff --git a/lib/active_merchant/billing/gateways/tns.rb b/lib/active_merchant/billing/gateways/tns.rb index e1568130a9e..25ed79306a9 100644 --- a/lib/active_merchant/billing/gateways/tns.rb +++ b/lib/active_merchant/billing/gateways/tns.rb @@ -15,8 +15,7 @@ class TnsGateway < Gateway self.homepage_url = 'http://www.tnsi.com/' self.supported_countries = %w(AR AU BR FR DE HK MX NZ SG GB US) self.default_currency = 'USD' - self.supported_cardtypes = [:visa, :master, :american_express, :discover, :diners_club, :jcb, :maestro, :laser] - self.ssl_version = :TLSv1 + self.supported_cardtypes = [:visa, :master, :american_express, :discover, :diners_club, :jcb, :maestro] end end diff --git a/lib/active_merchant/billing/gateways/trans_first.rb b/lib/active_merchant/billing/gateways/trans_first.rb index cc2c8c084bf..8b2c579683f 100644 --- a/lib/active_merchant/billing/gateways/trans_first.rb +++ b/lib/active_merchant/billing/gateways/trans_first.rb @@ -14,19 +14,19 @@ class TransFirstGateway < Gateway DECLINED = 'The transaction was declined' ACTIONS = { - purchase: "CCSale", - purchase_echeck: "ACHDebit", - refund: "CreditCardAutoRefundorVoid", - refund_echeck: "ACHVoidTransaction", - void: "CreditCardAutoRefundorVoid", + purchase: 'CCSale', + purchase_echeck: 'ACHDebit', + refund: 'CreditCardCredit', + refund_echeck: 'ACHVoidTransaction', + void: 'CreditCardAutoRefundorVoid', } ENDPOINTS = { - purchase: "creditcard.asmx", - purchase_echeck: "checkverifyws/checkverifyws.asmx", - refund: "creditcard.asmx", - refund_echeck: "checkverifyws/checkverifyws.asmx", - void: "creditcard.asmx" + purchase: 'creditcard.asmx', + purchase_echeck: 'checkverifyws/checkverifyws.asmx', + refund: 'creditcard.asmx', + refund_echeck: 'checkverifyws/checkverifyws.asmx', + void: 'creditcard.asmx' } def initialize(options = {}) @@ -52,8 +52,9 @@ def refund(money, authorization, options={}) transaction_id, payment_type = split_authorization(authorization) add_amount(post, money) add_pair(post, :TransID, transaction_id) + add_pair(post, :RefID, options[:order_id], required: true) - commit((payment_type == "check" ? :refund_echeck : :refund), post) + commit((payment_type == 'check' ? :refund_echeck : :refund), post) end def void(authorization, options={}) @@ -91,8 +92,8 @@ def add_address(post, options) add_pair(post, :Address, address[:address1], required: true) add_pair(post, :ZipCode, address[:zip], required: true) else - add_pair(post, :Address, "", required: true) - add_pair(post, :ZipCode, "", required: true) + add_pair(post, :Address, '', required: true) + add_pair(post, :ZipCode, '', required: true) end end @@ -101,8 +102,8 @@ def add_invoice(post, options) add_pair(post, :PONumber, options[:invoice], required: true) add_pair(post, :SaleTaxAmount, amount(options[:tax] || 0)) add_pair(post, :TaxIndicator, 0) - add_pair(post, :PaymentDesc, options[:description] || "", required: true) - add_pair(post, :CompanyName, options[:company_name] || "", required: true) + add_pair(post, :PaymentDesc, options[:description] || '', required: true) + add_pair(post, :CompanyName, options[:company_name] || '', required: true) end def add_payment(post, payment) @@ -123,11 +124,11 @@ def add_credit_card(post, payment) def add_echeck(post, payment) add_pair(post, :TransRoute, payment.routing_number, required: true) add_pair(post, :BankAccountNo, payment.account_number, required: true) - add_pair(post, :BankAccountType, add_or_use_default(payment.account_type, "Checking"), required: true) - add_pair(post, :CheckType, add_or_use_default(payment.account_holder_type, "Personal"), required: true) + add_pair(post, :BankAccountType, add_or_use_default(payment.account_type, 'Checking'), required: true) + add_pair(post, :CheckType, add_or_use_default(payment.account_holder_type, 'Personal'), required: true) add_pair(post, :Name, payment.name, required: true) - add_pair(post, :ProcessDate, Time.now.strftime("%m%d%y"), required: true) - add_pair(post, :Description, "", required: true) + add_pair(post, :ProcessDate, Time.now.strftime('%m%d%y'), required: true) + add_pair(post, :Description, '', required: true) end def add_or_use_default(payment_data, default_value) @@ -139,7 +140,7 @@ def add_unused_fields(action, post) return unless action == :purchase UNUSED_CREDIT_CARD_FIELDS.each do |f| - post[f] = "" + post[f] = '' end end @@ -154,7 +155,7 @@ def parse(data) response = {} xml = REXML::Document.new(data) - root = REXML::XPath.first(xml, "*") + root = REXML::XPath.first(xml, '*') if root.nil? response[:message] = data.to_s.strip @@ -169,7 +170,6 @@ def parse(data) def commit(action, params) response = parse(ssl_post(url(action), post_data(action, params))) - Response.new( success_from(response), message_from(response), @@ -182,7 +182,7 @@ def commit(action, params) end def authorization_from(response) - if response[:status] == "APPROVED" + if response[:status] == 'APPROVED' "#{response[:trans_id]}|check" else "#{response[:trans_id]}|creditcard" @@ -191,13 +191,13 @@ def authorization_from(response) def success_from(response) case response[:status] - when "Authorized" + when 'Authorized' true - when "Voided" + when 'Voided' true - when "APPROVED" + when 'APPROVED' true - when "VOIDED" + when 'VOIDED' true else false @@ -218,7 +218,7 @@ def post_data(action, params = {}) params[:MerchantID] = @options[:login] params[:RegKey] = @options[:password] - request = params.collect { |key, value| "#{key}=#{CGI.escape(value.to_s)}" }.join("&") + request = params.collect { |key, value| "#{key}=#{CGI.escape(value.to_s)}" }.join('&') request end @@ -232,7 +232,7 @@ def url(action) end def split_authorization(authorization) - authorization.split("|") + authorization.split('|') end end end diff --git a/lib/active_merchant/billing/gateways/trans_first_transaction_express.rb b/lib/active_merchant/billing/gateways/trans_first_transaction_express.rb index 1e30c9a290e..e9ac1ac2a9f 100644 --- a/lib/active_merchant/billing/gateways/trans_first_transaction_express.rb +++ b/lib/active_merchant/billing/gateways/trans_first_transaction_express.rb @@ -1,162 +1,162 @@ -require "nokogiri" +require 'nokogiri' module ActiveMerchant #:nodoc: module Billing #:nodoc: class TransFirstTransactionExpressGateway < Gateway - self.display_name = "TransFirst Transaction Express" - self.homepage_url = "http://transactionexpress.com/" + self.display_name = 'TransFirst Transaction Express' + self.homepage_url = 'http://transactionexpress.com/' - self.test_url = "https://ws.cert.transactionexpress.com/portal/merchantframework/MerchantWebServices-v1?wsdl" - self.live_url = "https://ws.transactionexpress.com/portal/merchantframework/MerchantWebServices-v1?wsdl" + self.test_url = 'https://ws.cert.transactionexpress.com/portal/merchantframework/MerchantWebServices-v1?wsdl' + self.live_url = 'https://ws.transactionexpress.com/portal/merchantframework/MerchantWebServices-v1?wsdl' - self.supported_countries = ["US"] - self.default_currency = "USD" + self.supported_countries = ['US'] + self.default_currency = 'USD' self.money_format = :cents self.supported_cardtypes = [:visa, :master, :american_express, :discover, :diners_club] - V1_NAMESPACE = "http://postilion/realtime/merchantframework/xsd/v1/" - SOAPENV_NAMESPACE = "http://schemas.xmlsoap.org/soap/envelope/" - AUTHORIZATION_FIELD_SEPARATOR = "|" + V1_NAMESPACE = 'http://postilion/realtime/merchantframework/xsd/v1/' + SOAPENV_NAMESPACE = 'http://schemas.xmlsoap.org/soap/envelope/' + AUTHORIZATION_FIELD_SEPARATOR = '|' APPROVAL_CODES = %w(00 10) RESPONSE_MESSAGES = { - "00" => "Approved", - "01" => "Refer to card issuer", - "02" => "Refer to card issuer, special condition", - "03" => "Invalid merchant", - "04" => "Pick-up card", - "05" => "Do not honor", - "06" => "Error", - "07" => "Pick-up card, special condition", - "08" => "Honor with identification", - "09" => "Request in progress", - "10" => "Approved, partial authorization", - "11" => "VIP Approval", - "12" => "Invalid transaction", - "13" => "Invalid amount", - "14" => "Invalid card number", - "15" => "No such issuer", - "16" => "Approved, update track 3", - "17" => "Customer cancellation", - "18" => "Customer dispute", - "19" => "Re-enter transaction", - "20" => "Invalid response", - "21" => "No action taken", - "22" => "Suspected malfunction", - "23" => "Unacceptable transaction fee", - "24" => "File update not supported", - "25" => "Unable to locate record", - "26" => "Duplicate record", - "27" => "File update field edit error", - "28" => "File update file locked", - "29" => "File update failed", - "30" => "Format error", - "31" => "Bank not supported", - "33" => "Expired card, pick-up", - "34" => "Suspected fraud, pick-up", - "35" => "Contact acquirer, pick-up", - "36" => "Restricted card, pick-up", - "37" => "Call acquirer security, pick-up", - "38" => "PIN tries exceeded, pick-up", - "39" => "No credit account", - "40" => "Function not supported", - "41" => "Lost card, pick-up", - "42" => "No universal account", - "43" => "Stolen card, pick-up", - "44" => "No investment account", - "45" => "Account closed", - "46" => "Identification required", - "47" => "Identification cross-check required", - "48" => "No customer record", - "49" => "Reserved for future Realtime use", - "50" => "Reserved for future Realtime use", - "51" => "Not sufficient funds", - "52" => "No checking account", - "53" => "No savings account", - "54" => "Expired card", - "55" => "Incorrect PIN", - "56" => "No card record", - "57" => "Transaction not permitted to cardholder", - "58" => "Transaction not permitted on terminal", - "59" => "Suspected fraud", - "60" => "Contact acquirer", - "61" => "Exceeds withdrawal limit", - "62" => "Restricted card", - "63" => "Security violation", - "64" => "Original amount incorrect", - "65" => "Exceeds withdrawal frequency", - "66" => "Call acquirer security", - "67" => "Hard capture", - "68" => "Response received too late", - "69" => "Advice received too late (the response from a request was received too late )", - "70" => "Reserved for future use", - "71" => "Reserved for future Realtime use", - "72" => "Reserved for future Realtime use", - "73" => "Reserved for future Realtime use", - "74" => "Reserved for future Realtime use", - "75" => "PIN tries exceeded", - "76" => "Reversal: Unable to locate previous message (no match on Retrieval Reference Number)/ Reserved for future Realtime use", - "77" => "Previous message located for a repeat or reversal, but repeat or reversal data is inconsistent with original message/ Intervene, bank approval required", - "78" => "Invalid/non-existent account – Decline (MasterCard specific)/ Intervene, bank approval required for partial amount", - "79" => "Already reversed (by Switch)/ Reserved for client-specific use (declined)", - "80" => "No financial Impact (Reserved for declined debit)/ Reserved for client-specific use (declined)", - "81" => "PIN cryptographic error found by the Visa security module during PIN decryption/ Reserved for client-specific use (declined)", - "82" => "Incorrect CVV/ Reserved for client-specific use (declined)", - "83" => "Unable to verify PIN/ Reserved for client-specific use (declined)", - "84" => "Invalid Authorization Life Cycle – Decline (MasterCard) or Duplicate Transaction Detected (Visa)/ Reserved for client-specific use (declined)", - "85" => "No reason to decline a request for Account Number Verification or Address Verification/ Reserved for client-specific use (declined)", - "86" => "Cannot verify PIN/ Reserved for client-specific use (declined)", - "87" => "Reserved for client-specific use (declined)", - "88" => "Reserved for client-specific use (declined)", - "89" => "Reserved for client-specific use (declined)", - "90" => "Cut-off in progress", - "91" => "Issuer or switch inoperative", - "92" => "Routing error", - "93" => "Violation of law", - "94" => "Duplicate Transmission (Integrated Debit and MasterCard)", - "95" => "Reconcile error", - "96" => "System malfunction", - "97" => "Reserved for future Realtime use", - "98" => "Exceeds cash limit", - "99" => "Reserved for future Realtime use", - "1106" => "Reserved for future Realtime use", - "0A" => "Reserved for future Realtime use", - "A0" => "Reserved for future Realtime use", - "A1" => "ATC not incremented", - "A2" => "ATC limit exceeded", - "A3" => "ATC configuration error", - "A4" => "CVR check failure", - "A5" => "CVR configuration error", - "A6" => "TVR check failure", - "A7" => "TVR configuration error", - "A8" => "Reserved for future Realtime use", - "B1" => "Surcharge amount not permitted on Visa cards or EBT Food Stamps/ Reserved for future Realtime use", - "B2" => "Surcharge amount not supported by debit network issuer/ Reserved for future Realtime use", - "C1" => "Unacceptable PIN", - "C2" => "PIN Change failed", - "C3" => "PIN Unblock failed", - "D1" => "MAC Error", - "E1" => "Prepay error", - "N1" => "Network Error within the TXP platform", - "N0" => "Force STIP/ Reserved for client-specific use (declined)", - "N3" => "Cash service not available/ Reserved for client-specific use (declined)", - "N4" => "Cash request exceeds Issuer limit/ Reserved for client-specific use (declined)", - "N5" => "Ineligible for re-submission/ Reserved for client-specific use (declined)", - "N7" => "Decline for CVV2 failure/ Reserved for client-specific use (declined)", - "N8" => "Transaction amount exceeds preauthorized approval amount/ Reserved for client-specific use (declined)", - "P0" => "Approved; PVID code is missing, invalid, or has expired", - "P1" => "Declined; PVID code is missing, invalid, or has expired/ Reserved for client-specific use (declined)", - "P2" => "Invalid biller Information/ Reserved for client-specific use (declined)/ Reserved for client-specific use (declined)", - "R0" => "The transaction was declined or returned, because the cardholder requested that payment of a specific recurring or installment payment transaction be stopped/ Reserved for client-specific use (declined)", - "R1" => "The transaction was declined or returned, because the cardholder requested that payment of all recurring or installment payment transactions for a specific merchant account be stopped/ Reserved for client-specific use (declined)", - "Q1" => "Card Authentication failed/ Reserved for client-specific use (declined)", - "XA" => "Forward to Issuer/ Reserved for client-specific use (declined)", - "XD" => "Forward to Issuer/ Reserved for client-specific use (declined)", + '00' => 'Approved', + '01' => 'Refer to card issuer', + '02' => 'Refer to card issuer, special condition', + '03' => 'Invalid merchant', + '04' => 'Pick-up card', + '05' => 'Do not honor', + '06' => 'Error', + '07' => 'Pick-up card, special condition', + '08' => 'Honor with identification', + '09' => 'Request in progress', + '10' => 'Approved, partial authorization', + '11' => 'VIP Approval', + '12' => 'Invalid transaction', + '13' => 'Invalid amount', + '14' => 'Invalid card number', + '15' => 'No such issuer', + '16' => 'Approved, update track 3', + '17' => 'Customer cancellation', + '18' => 'Customer dispute', + '19' => 'Re-enter transaction', + '20' => 'Invalid response', + '21' => 'No action taken', + '22' => 'Suspected malfunction', + '23' => 'Unacceptable transaction fee', + '24' => 'File update not supported', + '25' => 'Unable to locate record', + '26' => 'Duplicate record', + '27' => 'File update field edit error', + '28' => 'File update file locked', + '29' => 'File update failed', + '30' => 'Format error', + '31' => 'Bank not supported', + '33' => 'Expired card, pick-up', + '34' => 'Suspected fraud, pick-up', + '35' => 'Contact acquirer, pick-up', + '36' => 'Restricted card, pick-up', + '37' => 'Call acquirer security, pick-up', + '38' => 'PIN tries exceeded, pick-up', + '39' => 'No credit account', + '40' => 'Function not supported', + '41' => 'Lost card, pick-up', + '42' => 'No universal account', + '43' => 'Stolen card, pick-up', + '44' => 'No investment account', + '45' => 'Account closed', + '46' => 'Identification required', + '47' => 'Identification cross-check required', + '48' => 'No customer record', + '49' => 'Reserved for future Realtime use', + '50' => 'Reserved for future Realtime use', + '51' => 'Not sufficient funds', + '52' => 'No checking account', + '53' => 'No savings account', + '54' => 'Expired card', + '55' => 'Incorrect PIN', + '56' => 'No card record', + '57' => 'Transaction not permitted to cardholder', + '58' => 'Transaction not permitted on terminal', + '59' => 'Suspected fraud', + '60' => 'Contact acquirer', + '61' => 'Exceeds withdrawal limit', + '62' => 'Restricted card', + '63' => 'Security violation', + '64' => 'Original amount incorrect', + '65' => 'Exceeds withdrawal frequency', + '66' => 'Call acquirer security', + '67' => 'Hard capture', + '68' => 'Response received too late', + '69' => 'Advice received too late (the response from a request was received too late )', + '70' => 'Reserved for future use', + '71' => 'Reserved for future Realtime use', + '72' => 'Reserved for future Realtime use', + '73' => 'Reserved for future Realtime use', + '74' => 'Reserved for future Realtime use', + '75' => 'PIN tries exceeded', + '76' => 'Reversal: Unable to locate previous message (no match on Retrieval Reference Number)/ Reserved for future Realtime use', + '77' => 'Previous message located for a repeat or reversal, but repeat or reversal data is inconsistent with original message/ Intervene, bank approval required', + '78' => 'Invalid/non-existent account – Decline (MasterCard specific)/ Intervene, bank approval required for partial amount', + '79' => 'Already reversed (by Switch)/ Reserved for client-specific use (declined)', + '80' => 'No financial Impact (Reserved for declined debit)/ Reserved for client-specific use (declined)', + '81' => 'PIN cryptographic error found by the Visa security module during PIN decryption/ Reserved for client-specific use (declined)', + '82' => 'Incorrect CVV/ Reserved for client-specific use (declined)', + '83' => 'Unable to verify PIN/ Reserved for client-specific use (declined)', + '84' => 'Invalid Authorization Life Cycle – Decline (MasterCard) or Duplicate Transaction Detected (Visa)/ Reserved for client-specific use (declined)', + '85' => 'No reason to decline a request for Account Number Verification or Address Verification/ Reserved for client-specific use (declined)', + '86' => 'Cannot verify PIN/ Reserved for client-specific use (declined)', + '87' => 'Reserved for client-specific use (declined)', + '88' => 'Reserved for client-specific use (declined)', + '89' => 'Reserved for client-specific use (declined)', + '90' => 'Cut-off in progress', + '91' => 'Issuer or switch inoperative', + '92' => 'Routing error', + '93' => 'Violation of law', + '94' => 'Duplicate Transmission (Integrated Debit and MasterCard)', + '95' => 'Reconcile error', + '96' => 'System malfunction', + '97' => 'Reserved for future Realtime use', + '98' => 'Exceeds cash limit', + '99' => 'Reserved for future Realtime use', + '1106' => 'Reserved for future Realtime use', + '0A' => 'Reserved for future Realtime use', + 'A0' => 'Reserved for future Realtime use', + 'A1' => 'ATC not incremented', + 'A2' => 'ATC limit exceeded', + 'A3' => 'ATC configuration error', + 'A4' => 'CVR check failure', + 'A5' => 'CVR configuration error', + 'A6' => 'TVR check failure', + 'A7' => 'TVR configuration error', + 'A8' => 'Reserved for future Realtime use', + 'B1' => 'Surcharge amount not permitted on Visa cards or EBT Food Stamps/ Reserved for future Realtime use', + 'B2' => 'Surcharge amount not supported by debit network issuer/ Reserved for future Realtime use', + 'C1' => 'Unacceptable PIN', + 'C2' => 'PIN Change failed', + 'C3' => 'PIN Unblock failed', + 'D1' => 'MAC Error', + 'E1' => 'Prepay error', + 'N1' => 'Network Error within the TXP platform', + 'N0' => 'Force STIP/ Reserved for client-specific use (declined)', + 'N3' => 'Cash service not available/ Reserved for client-specific use (declined)', + 'N4' => 'Cash request exceeds Issuer limit/ Reserved for client-specific use (declined)', + 'N5' => 'Ineligible for re-submission/ Reserved for client-specific use (declined)', + 'N7' => 'Decline for CVV2 failure/ Reserved for client-specific use (declined)', + 'N8' => 'Transaction amount exceeds preauthorized approval amount/ Reserved for client-specific use (declined)', + 'P0' => 'Approved; PVID code is missing, invalid, or has expired', + 'P1' => 'Declined; PVID code is missing, invalid, or has expired/ Reserved for client-specific use (declined)', + 'P2' => 'Invalid biller Information/ Reserved for client-specific use (declined)/ Reserved for client-specific use (declined)', + 'R0' => 'The transaction was declined or returned, because the cardholder requested that payment of a specific recurring or installment payment transaction be stopped/ Reserved for client-specific use (declined)', + 'R1' => 'The transaction was declined or returned, because the cardholder requested that payment of all recurring or installment payment transactions for a specific merchant account be stopped/ Reserved for client-specific use (declined)', + 'Q1' => 'Card Authentication failed/ Reserved for client-specific use (declined)', + 'XA' => 'Forward to Issuer/ Reserved for client-specific use (declined)', + 'XD' => 'Forward to Issuer/ Reserved for client-specific use (declined)', } EXTENDED_RESPONSE_MESSAGES = { - "B40K" => "Declined Post – Credit linked to unextracted settle transaction" + 'B40K' => 'Declined Post – Credit linked to unextracted settle transaction' } TRANSACTION_CODES = { @@ -175,6 +175,10 @@ class TransFirstTransactionExpressGateway < Gateway verify: 9, + purchase_echeck: 11, + refund_echeck: 16, + void_echeck: 16, + wallet_sale: 14, } @@ -187,7 +191,15 @@ def purchase(amount, payment_method, options={}) if credit_card?(payment_method) action = :purchase request = build_xml_transaction_request do |doc| - add_payment_method(doc, payment_method) + add_credit_card(doc, payment_method) + add_contact(doc, payment_method.name, options) + add_amount(doc, amount) + add_order_number(doc, options) + end + elsif echeck?(payment_method) + action = :purchase_echeck + request = build_xml_transaction_request do |doc| + add_echeck(doc, payment_method) add_contact(doc, payment_method.name, options) add_amount(doc, amount) add_order_number(doc, options) @@ -207,7 +219,7 @@ def purchase(amount, payment_method, options={}) def authorize(amount, payment_method, options={}) if credit_card?(payment_method) request = build_xml_transaction_request do |doc| - add_payment_method(doc, payment_method) + add_credit_card(doc, payment_method) add_contact(doc, payment_method.name, options) add_amount(doc, amount) end @@ -243,15 +255,14 @@ def void(authorization, options={}) end def refund(amount, authorization, options={}) - transaction_id = split_authorization(authorization)[1] + action, transaction_id = split_authorization(authorization) request = build_xml_transaction_request do |doc| - add_amount(doc, amount) + add_amount(doc, amount) unless action == 'purchase_echeck' add_original_transaction_data(doc, transaction_id) - add_order_number(doc, options) end - commit(:refund, request) + commit(refund_type(action), request) end def credit(amount, payment_method, options={}) @@ -265,7 +276,7 @@ def credit(amount, payment_method, options={}) def verify(credit_card, options={}) request = build_xml_transaction_request do |doc| - add_payment_method(doc, credit_card) + add_credit_card(doc, credit_card) add_contact(doc, credit_card.name, options) end @@ -279,15 +290,15 @@ def store(payment_method, options={}) MultiResponse.run do |r| r.process { commit(:store, store_customer_request) } - return r unless r.success? && r.params["custId"] - customer_id = r.params["custId"] + return r unless r.success? && r.params['custId'] + customer_id = r.params['custId'] store_payment_method_request = build_xml_payment_storage_request do |doc| - doc["v1"].cust do + doc['v1'].cust do add_customer_id(doc, customer_id) - doc["v1"].pmt do - doc["v1"].type 0 # add - add_payment_method(doc, payment_method) + doc['v1'].pmt do + doc['v1'].type 0 # add + add_credit_card(doc, payment_method) end end end @@ -310,12 +321,12 @@ def scrub(transcript) private - CURRENCY_CODES = Hash.new{|h,k| raise ArgumentError.new("Unsupported currency: #{k}")} - CURRENCY_CODES["USD"] = "840" + CURRENCY_CODES = Hash.new { |h, k| raise ArgumentError.new("Unsupported currency: #{k}") } + CURRENCY_CODES['USD'] = '840' def headers { - "Content-Type" => "text/xml" + 'Content-Type' => 'text/xml' } end @@ -338,8 +349,8 @@ def commit(action, request) response, error_code: error_code_from(succeeded, response), authorization: authorization_from(action, response), - avs_result: AVSResult.new(code: response["AVSCode"]), - cvv_result: CVVResult.new(response["CVV2Response"]), + avs_result: AVSResult.new(code: response['avsRslt']), + cvv_result: CVVResult.new(response['secRslt']), test: test? ) end @@ -352,7 +363,7 @@ def parse(xml) response = {} doc = Nokogiri::XML(xml).remove_namespaces! - doc.css("Envelope Body *").each do |node| + doc.css('Envelope Body *').each do |node| # node.name is more readable, but uniq_name is occasionally necessary uniq_name = [node.parent.name, node.name].join('_') response[uniq_name] = node.text @@ -363,36 +374,37 @@ def parse(xml) end def success_from(response) - fault = response["Fault"] - approved_transaction = APPROVAL_CODES.include?(response["rspCode"]) - found_contact = response["FndRecurrProfResponse"] + fault = response['Fault'] + approved_transaction = APPROVAL_CODES.include?(response['rspCode']) + found_contact = response['FndRecurrProfResponse'] return !fault && (approved_transaction || found_contact) end def error_code_from(succeeded, response) return if succeeded - response["errorCode"] || response["rspCode"] + response['errorCode'] || response['rspCode'] end def message_from(succeeded, response) - return "Succeeded" if succeeded + return 'Succeeded' if succeeded - if response["rspCode"] - code = response["rspCode"] - extended_code = response["extRspCode"] + if response['rspCode'] + code = response['rspCode'] + extended_code = response['extRspCode'] message = RESPONSE_MESSAGES[code] extended = EXTENDED_RESPONSE_MESSAGES[extended_code] + ach_response = response['achResponse'] - [message, extended].compact.join('. ') + [message, extended, ach_response].compact.join('. ') else - response["faultstring"] + response['faultstring'] end end def authorization_from(action, response) - authorization = response["tranNr"] || response["pmtId"] + authorization = response['tranNr'] || response['pmtId'] # guard so we don't return something like "purchase|" return unless authorization @@ -402,7 +414,11 @@ def authorization_from(action, response) # -- helper methods ---------------------------------------------------- def credit_card?(payment_method) - payment_method.respond_to?(:number) + payment_method.respond_to?(:verification_value) + end + + def echeck?(payment_method) + payment_method.respond_to?(:routing_number) end def split_authorization(authorization) @@ -410,40 +426,44 @@ def split_authorization(authorization) end def void_type(action) - :"void_#{action}" + action == 'purchase_echeck' ? :void_echeck : :"void_#{action}" + end + + def refund_type(action) + action == 'purchase_echeck' ? :refund_echeck : :refund end # -- request methods --------------------------------------------------- def build_xml_transaction_request - build_xml_request("SendTranRequest") do |doc| + build_xml_request('SendTranRequest') do |doc| yield doc end end def build_xml_payment_storage_request - build_xml_request("UpdtRecurrProfRequest") do |doc| + build_xml_request('UpdtRecurrProfRequest') do |doc| yield doc end end def build_xml_payment_update_request merchant_product_type = 5 # credit card - build_xml_request("UpdtRecurrProfRequest", merchant_product_type) do |doc| + build_xml_request('UpdtRecurrProfRequest', merchant_product_type) do |doc| yield doc end end def build_xml_payment_search_request - build_xml_request("FndRecurrProfRequest") do |doc| + build_xml_request('FndRecurrProfRequest') do |doc| yield doc end end def build_xml_request(wrapper, merchant_product_type=nil) - Nokogiri::XML::Builder.new(encoding: "UTF-8") do |xml| - xml["soapenv"].Envelope("xmlns:soapenv" => SOAPENV_NAMESPACE) do - xml["soapenv"].Body do - xml["v1"].send(wrapper, "xmlns:v1" => V1_NAMESPACE) do + Nokogiri::XML::Builder.new(encoding: 'UTF-8') do |xml| + xml['soapenv'].Envelope('xmlns:soapenv' => SOAPENV_NAMESPACE) do + xml['soapenv'].Body do + xml['v1'].send(wrapper, 'xmlns:v1' => V1_NAMESPACE) do add_merchant(xml) yield(xml) end @@ -463,31 +483,38 @@ def add_transaction_code_to_request(request, action) end def add_merchant(doc, product_type=nil) - doc["v1"].merc do - doc["v1"].id @options[:gateway_id] - doc["v1"].regKey @options[:reg_key] - doc["v1"].inType "1" - doc["v1"].prodType product_type if product_type + doc['v1'].merc do + doc['v1'].id @options[:gateway_id] + doc['v1'].regKey @options[:reg_key] + doc['v1'].inType '1' + doc['v1'].prodType product_type if product_type end end def add_amount(doc, money) - doc["v1"].reqAmt amount(money) + doc['v1'].reqAmt amount(money) end def add_order_number(doc, options) return unless options[:order_id] - doc["v1"].authReq { - doc["v1"].ordNr options[:order_id] + doc['v1'].authReq { + doc['v1'].ordNr options[:order_id] + } + end + + def add_credit_card(doc, payment_method) + doc['v1'].card { + doc['v1'].pan payment_method.number + doc['v1'].sec payment_method.verification_value if payment_method.verification_value? + doc['v1'].xprDt expiration_date(payment_method) } end - def add_payment_method(doc, payment_method) - doc["v1"].card { - doc["v1"].pan payment_method.number - doc["v1"].sec payment_method.verification_value if payment_method.verification_value? - doc["v1"].xprDt expiration_date(payment_method) + def add_echeck(doc, payment_method) + doc['v1'].achEcheck { + doc['v1'].bankRtNr payment_method.routing_number + doc['v1'].acctNr payment_method.account_number } end @@ -498,52 +525,60 @@ def expiration_date(payment_method) end def add_pan(doc, payment_method) - doc["v1"].card do - doc["v1"].pan payment_method.number + doc['v1'].card do + doc['v1'].pan payment_method.number end end def add_contact(doc, fullname, options) - doc["v1"].contact do - doc["v1"].fullName fullname - doc["v1"].coName options[:company_name] if options[:company_name] - doc["v1"].title options[:title] if options[:title] + doc['v1'].contact do + doc['v1'].fullName fullname + doc['v1'].coName options[:company_name] if options[:company_name] + doc['v1'].title options[:title] if options[:title] if (billing_address = options[:billing_address]) - doc["v1"].phone do - doc["v1"].type (options[:phone_number_type] || "4") - doc["v1"].nr billing_address[:phone].gsub(/\D/, '') if billing_address[:phone] + if billing_address[:phone] + doc['v1'].phone do + doc['v1'].type(options[:phone_number_type] || '4') + doc['v1'].nr billing_address[:phone].gsub(/\D/, '') + end end - doc["v1"].addrLn1 billing_address[:address1] - doc["v1"].addrLn2 billing_address[:address2] - doc["v1"].city billing_address[:city] - doc["v1"].state billing_address[:state] - doc["v1"].zipCode billing_address[:zip] - doc["v1"].ctry "US" + doc['v1'].addrLn1 billing_address[:address1] if billing_address[:address1] + doc['v1'].addrLn2 billing_address[:address2] if billing_address[:address2] + doc['v1'].city billing_address[:city] if billing_address[:city] + doc['v1'].state billing_address[:state] if billing_address[:state] + doc['v1'].zipCode billing_address[:zip] if billing_address[:zip] + doc['v1'].ctry 'US' end - doc["v1"].email options[:email] if options[:email] - doc["v1"].type options[:contact_type] if options[:contact_type] - doc["v1"].stat options[:contact_stat] if options[:contact_stat] + doc['v1'].email options[:email] if options[:email] + doc['v1'].type options[:contact_type] if options[:contact_type] + doc['v1'].stat options[:contact_stat] if options[:contact_stat] if (shipping_address = options[:shipping_address]) - doc["v1"].ship do - doc["v1"].fullName fullname - doc["v1"].addrLn1 shipping_address[:address1] - doc["v1"].addrLn2 shipping_address[:address2] if shipping_address[:address2] - doc["v1"].city shipping_address[:city] - doc["v1"].state shipping_address[:state] - doc["v1"].zipCode shipping_address[:zip] - doc["v1"].phone shipping_address[:phone].gsub(/\D/, '') if shipping_address[:phone] - doc["v1"].email shipping_address[:email] if shipping_address[:email] + doc['v1'].ship do + doc['v1'].fullName fullname + doc['v1'].addrLn1 shipping_address[:address1] if shipping_address[:address1] + doc['v1'].addrLn2 shipping_address[:address2] if shipping_address[:address2] + doc['v1'].city shipping_address[:city] if shipping_address[:city] + doc['v1'].state shipping_address[:state] if shipping_address[:state] + doc['v1'].zipCode shipping_address[:zip] if shipping_address[:zip] + doc['v1'].phone shipping_address[:phone].gsub(/\D/, '') if shipping_address[:phone] + doc['v1'].email shipping_address[:email] if shipping_address[:email] end end end end + def add_name(doc, payment_method) + doc['v1'].contact do + doc['v1'].fullName payment_method.name + end + end + def add_original_transaction_data(doc, authorization) - doc["v1"].origTranData do - doc["v1"].tranNr authorization + doc['v1'].origTranData do + doc['v1'].tranNr authorization end end @@ -551,21 +586,21 @@ def store_customer_details(doc, fullname, options) options[:contact_type] = 1 # recurring options[:contact_stat] = 1 # active - doc["v1"].cust do - doc["v1"].type 0 # add + doc['v1'].cust do + doc['v1'].type 0 # add add_contact(doc, fullname, options) end end def add_customer_id(doc, customer_id) - doc["v1"].contact do - doc["v1"].id customer_id + doc['v1'].contact do + doc['v1'].id customer_id end end def add_wallet_id(doc, wallet_id) - doc["v1"].recurMan do - doc["v1"].id wallet_id + doc['v1'].recurMan do + doc['v1'].id wallet_id end end end diff --git a/lib/active_merchant/billing/gateways/transact_pro.rb b/lib/active_merchant/billing/gateways/transact_pro.rb index eae571d017d..5aaa36d756d 100644 --- a/lib/active_merchant/billing/gateways/transact_pro.rb +++ b/lib/active_merchant/billing/gateways/transact_pro.rb @@ -32,7 +32,7 @@ def purchase(amount, payment, options={}) post[:rs] = @options[:terminal] MultiResponse.run do |r| - r.process{commit('init', post)} + r.process { commit('init', post) } r.process do post = PostData.new post[:init_transaction_id] = r.authorization @@ -54,7 +54,7 @@ def authorize(amount, payment, options={}) post[:rs] = @options[:terminal] MultiResponse.run do |r| - r.process{commit('init_dms', post)} + r.process { commit('init_dms', post) } r.process do post = PostData.new post[:init_transaction_id] = r.authorization @@ -122,7 +122,7 @@ def add_address(post, creditcard, options) post[:state] = (address[:state].blank? ? 'NA' : address[:state].to_s) post[:zip] = address[:zip].to_s post[:country] = address[:country].to_s - post[:phone] = (address[:phone].to_s.gsub(/[^0-9]/, '') || "0000000") + post[:phone] = (address[:phone].to_s.gsub(/[^0-9]/, '') || '0000000') end if address = options[:shipping_address] @@ -153,8 +153,8 @@ def add_payment(post, payment) def add_payment_cc(post, credit_card) post[:cc] = credit_card.number post[:cvv] = credit_card.verification_value if credit_card.verification_value? - year = sprintf("%.4i", credit_card.year) - month = sprintf("%.2i", credit_card.month) + year = sprintf('%.4i', credit_card.year) + month = sprintf('%.2i', credit_card.month) post[:expire] = "#{month}/#{year[2..3]}" end @@ -165,22 +165,22 @@ def add_credentials(post, key=:guid) def parse(body) if body =~ /^ID:/ - body.split('~').reduce(Hash.new) { |h,v| - m = v.match("(.*?):(.*)") + body.split('~').reduce(Hash.new) { |h, v| + m = v.match('(.*?):(.*)') h.merge!(m[1].underscore.to_sym => m[2]) } - elsif (m = body.match("(.*?):(.*)")) + elsif (m = body.match('(.*?):(.*)')) m[1] == 'OK' ? { status: 'success', id: m[2] } : { status: 'failure', message: m[2] } else - Hash[ status: body ] + Hash[status: body] end end def commit(action, parameters, amount=nil) url = (test? ? test_url : live_url) - response = parse(ssl_post(url, post_data(action,parameters))) + response = parse(ssl_post(url, post_data(action, parameters))) Response.new( success_from(response), @@ -195,12 +195,12 @@ def authorization_from(parameters, response, amount) identifier = (response[:id] || parameters[:init_transaction_id]) authorization = [identifier] authorization << amount if amount - authorization.join("|") + authorization.join('|') end def split_authorization(authorization) if authorization =~ /|/ - identifier, amount = authorization.split("|") + identifier, amount = authorization.split('|') [identifier, amount.to_i] else authorization diff --git a/lib/active_merchant/billing/gateways/transax.rb b/lib/active_merchant/billing/gateways/transax.rb index c11c830bac9..336a7fb31c3 100644 --- a/lib/active_merchant/billing/gateways/transax.rb +++ b/lib/active_merchant/billing/gateways/transax.rb @@ -1,23 +1,22 @@ -require File.join(File.dirname(__FILE__),'smart_ps.rb') +require File.join(File.dirname(__FILE__), 'smart_ps.rb') module ActiveMerchant #:nodoc: module Billing #:nodoc: class TransaxGateway < SmartPs self.live_url = self.test_url = 'https://secure.nelixtransax.net/api/transact.php' - + # The countries the gateway supports merchants from as 2 digit ISO country codes self.supported_countries = ['US'] - + # The card types supported by the payment gateway self.supported_cardtypes = [:visa, :master, :american_express, :discover] - + # The homepage URL of the gateway self.homepage_url = 'https://www.nelixtransax.com/' - + # The name of the gateway self.display_name = 'NELiX TransaX' end end end - diff --git a/lib/active_merchant/billing/gateways/transnational.rb b/lib/active_merchant/billing/gateways/transnational.rb index 2e0be041683..350a2e91857 100644 --- a/lib/active_merchant/billing/gateways/transnational.rb +++ b/lib/active_merchant/billing/gateways/transnational.rb @@ -3,8 +3,7 @@ module Billing #:nodoc: class TransnationalGateway < NetworkMerchantsGateway self.homepage_url = 'http://www.tnbci.com/' self.display_name = 'Transnational' - self.supported_countries = ["US"] + self.supported_countries = ['US'] end end end - diff --git a/lib/active_merchant/billing/gateways/trexle.rb b/lib/active_merchant/billing/gateways/trexle.rb new file mode 100644 index 00000000000..42451539b2c --- /dev/null +++ b/lib/active_merchant/billing/gateways/trexle.rb @@ -0,0 +1,218 @@ +module ActiveMerchant #:nodoc: + module Billing #:nodoc: + class TrexleGateway < Gateway + self.test_url = 'https://core.trexle.com/api/v1' + self.live_url = 'https://core.trexle.com/api/v1' + + self.default_currency = 'USD' + self.money_format = :cents + self.supported_countries = %w(AD AE AT AU BD BE BG BN CA CH CY CZ DE DK EE EG ES FI FR GB + GI GR HK HU ID IE IL IM IN IS IT JO KW LB LI LK LT LU LV MC + MT MU MV MX MY NL NO NZ OM PH PL PT QA RO SA SE SG SI SK SM + TR TT UM US VA VN ZA) + self.supported_cardtypes = [:visa, :master, :american_express] + self.homepage_url = 'https://trexle.com' + self.display_name = 'Trexle' + + def initialize(options = {}) + requires!(options, :api_key) + super + end + + # Create a charge using a credit card, card token or customer token + # + # To charge a credit card: purchase([money], [creditcard hash], ...) + # To charge a customer: purchase([money], [token], ...) + def purchase(money, creditcard, options = {}) + post = {} + + add_amount(post, money, options) + add_customer_data(post, options) + add_invoice(post, options) + add_creditcard(post, creditcard) + add_address(post, creditcard, options) + commit(:post, 'charges', post, options) + end + + # Create a customer and associated credit card. The token that is returned + # can be used instead of a credit card parameter in the purchase method + def store(creditcard, options = {}) + post = {} + + add_creditcard(post, creditcard) + add_customer_data(post, options) + add_address(post, creditcard, options) + commit(:post, 'customers', post, options) + end + + # Refund a transaction + def refund(money, token, options = {}) + commit(:post, "charges/#{CGI.escape(token)}/refunds", { amount: amount(money) }, options) + end + + # Authorize an amount on a credit card. Once authorized, you can later + # capture this charge using the charge token that is returned. + def authorize(money, creditcard, options = {}) + post = {} + + add_amount(post, money, options) + add_customer_data(post, options) + add_invoice(post, options) + add_creditcard(post, creditcard) + add_address(post, creditcard, options) + post[:capture] = false + commit(:post, 'charges', post, options) + end + + # Captures a previously authorized charge. Capturing only part of the original + # authorization is currently not supported. + def capture(money, token, options = {}) + commit(:put, "charges/#{CGI.escape(token)}/capture", { amount: amount(money) }, options) + end + + # Updates the credit card for the customer. + def update(token, creditcard, options = {}) + post = {} + + add_creditcard(post, creditcard) + add_customer_data(post, options) + add_address(post, creditcard, options) + commit(:put, "customers/#{CGI.escape(token)}", post, options) + end + + def supports_scrubbing + true + end + + def scrub(transcript) + transcript. + gsub(%r((Authorization: Basic )\w+), '\1[FILTERED]'). + gsub(/(number\\?":\\?")(\d*)/, '\1[FILTERED]'). + gsub(/(cvc\\?":\\?")(\d*)/, '\1[FILTERED]') + end + + private + + def add_amount(post, money, options) + post[:amount] = amount(money) + post[:currency] = (options[:currency] || currency(money)) + post[:currency] = post[:currency].upcase if post[:currency] + end + + def add_customer_data(post, options) + post[:email] = options[:email] if options[:email] + post[:ip_address] = options[:ip] if options[:ip] + end + + def add_address(post, creditcard, options) + return if creditcard.kind_of?(String) + address = (options[:billing_address] || options[:address]) + return unless address + + post[:card] ||= {} + post[:card].merge!( + address_line1: address[:address1], + address_line2: address[:address_line2], + address_city: address[:city], + address_postcode: address[:zip], + address_state: address[:state], + address_country: address[:country] + ) + end + + def add_invoice(post, options) + post[:description] = options[:description] || 'Active Merchant Purchase' + end + + def add_creditcard(post, creditcard) + if creditcard.respond_to?(:number) + post[:card] ||= {} + + post[:card].merge!( + number: creditcard.number, + expiry_month: creditcard.month, + expiry_year: creditcard.year, + cvc: creditcard.verification_value, + name: creditcard.name + ) + elsif creditcard.kind_of?(String) + if creditcard =~ /^token_/ + post[:card_token] = creditcard + else + post[:customer_token] = creditcard + end + end + end + + def headers(params = {}) + result = { + 'Content-Type' => 'application/json', + 'Authorization' => "Basic #{Base64.strict_encode64(options[:api_key] + ':').strip}" + } + + result['X-Partner-Key'] = params[:partner_key] if params[:partner_key] + result['X-Safe-Card'] = params[:safe_card] if params[:safe_card] + result + end + + def commit(method, action, params, options) + url = "#{test? ? test_url : live_url}/#{action}" + raw_response = ssl_request(method, url, post_data(params), headers(options)) + parsed_response = parse(raw_response) + success_response(parsed_response) + rescue ResponseError => e + error_response(parse(e.response.body)) + rescue JSON::ParserError + unparsable_response(raw_response) + end + + def success_response(body) + return invalid_response unless body['response'] + + response = body['response'] + Response.new( + true, + response['status_message'], + body, + authorization: token(response), + test: test? + ) + end + + def error_response(body) + return invalid_response unless body['error'] + Response.new( + false, + body['error'], + body, + authorization: nil, + test: test? + ) + end + + def unparsable_response(raw_response) + message = 'Invalid JSON response received from Trexle. Please contact support@trexle.com if you continue to receive this message.' + message += " (The raw response returned by the API was #{raw_response.inspect})" + return Response.new(false, message) + end + + def invalid_response + message = 'Invalid response.' + return Response.new(false, message) + end + + def token(response) + response['token'] + end + + def parse(body) + return {} if body.blank? + JSON.parse(body) + end + + def post_data(parameters = {}) + parameters.to_json + end + end + end +end diff --git a/lib/active_merchant/billing/gateways/trust_commerce.rb b/lib/active_merchant/billing/gateways/trust_commerce.rb index 68fbd4a5b23..40466fcc006 100644 --- a/lib/active_merchant/billing/gateways/trust_commerce.rb +++ b/lib/active_merchant/billing/gateways/trust_commerce.rb @@ -19,10 +19,10 @@ module Billing #:nodoc: # Next, create a credit card object using a TC approved test card. # # creditcard = ActiveMerchant::Billing::CreditCard.new( - # :number => '4111111111111111', - # :month => 8, - # :year => 2006, - # :first_name => 'Longbob', + # :number => '4111111111111111', + # :month => 8, + # :year => 2006, + # :first_name => 'Longbob', # :last_name => 'Longsen' # ) # @@ -67,38 +67,38 @@ module Billing #:nodoc: class TrustCommerceGateway < Gateway self.live_url = self.test_url = 'https://vault.trustcommerce.com/trans/' - SUCCESS_TYPES = ["approved", "accepted"] + SUCCESS_TYPES = ['approved', 'accepted'] DECLINE_CODES = { - "decline" => "The credit card was declined", - "avs" => "AVS failed; the address entered does not match the billing address on file at the bank", - "cvv" => "CVV failed; the number provided is not the correct verification number for the card", - "call" => "The card must be authorized manually over the phone", - "expiredcard" => "Issuer was not certified for card verification", - "carderror" => "Card number is invalid", - "authexpired" => "Attempt to postauth an expired (more than 14 days old) preauth", - "fraud" => "CrediGuard fraud score was below requested threshold", - "blacklist" => "CrediGuard blacklist value was triggered", - "velocity" => "CrediGuard velocity control value was triggered", - "dailylimit" => "Daily limit in transaction count or amount as been reached", - "weeklylimit" => "Weekly limit in transaction count or amount as been reached", - "monthlylimit" => "Monthly limit in transaction count or amount as been reached" + 'decline' => 'The credit card was declined', + 'avs' => 'AVS failed; the address entered does not match the billing address on file at the bank', + 'cvv' => 'CVV failed; the number provided is not the correct verification number for the card', + 'call' => 'The card must be authorized manually over the phone', + 'expiredcard' => 'Issuer was not certified for card verification', + 'carderror' => 'Card number is invalid', + 'authexpired' => 'Attempt to postauth an expired (more than 14 days old) preauth', + 'fraud' => 'CrediGuard fraud score was below requested threshold', + 'blacklist' => 'CrediGuard blacklist value was triggered', + 'velocity' => 'CrediGuard velocity control value was triggered', + 'dailylimit' => 'Daily limit in transaction count or amount as been reached', + 'weeklylimit' => 'Weekly limit in transaction count or amount as been reached', + 'monthlylimit' => 'Monthly limit in transaction count or amount as been reached' } BADDATA_CODES = { - "missingfields" => "One or more parameters required for this transaction type were not sent", - "extrafields" => "Parameters not allowed for this transaction type were sent", - "badformat" => "A field was improperly formatted, such as non-digit characters in a number field", - "badlength" => "A field was longer or shorter than the server allows", - "merchantcantaccept" => "The merchant can't accept data passed in this field", - "mismatch" => "Data in one of the offending fields did not cross-check with the other offending field" + 'missingfields' => 'One or more parameters required for this transaction type were not sent', + 'extrafields' => 'Parameters not allowed for this transaction type were sent', + 'badformat' => 'A field was improperly formatted, such as non-digit characters in a number field', + 'badlength' => 'A field was longer or shorter than the server allows', + 'merchantcantaccept' => "The merchant can't accept data passed in this field", + 'mismatch' => 'Data in one of the offending fields did not cross-check with the other offending field' } ERROR_CODES = { - "cantconnect" => "Couldn't connect to the TrustCommerce gateway", - "dnsfailure" => "The TCLink software was unable to resolve DNS hostnames", - "linkfailure" => "The connection was established, but was severed before the transaction could complete", - "failtoprocess" => "The bank servers are offline and unable to authorize transactions" + 'cantconnect' => "Couldn't connect to the TrustCommerce gateway", + 'dnsfailure' => 'The TCLink software was unable to resolve DNS hostnames', + 'linkfailure' => 'The connection was established, but was severed before the transaction could complete', + 'failtoprocess' => 'The bank servers are offline and unable to authorize transactions' } TEST_LOGIN = 'TestMerchant' @@ -153,6 +153,7 @@ def authorize(money, creditcard_or_billing_id, options = {}) } add_order_id(parameters, options) + add_aggregator(parameters, options) add_customer_data(parameters, options) add_payment_source(parameters, creditcard_or_billing_id) add_addresses(parameters, options) @@ -167,6 +168,7 @@ def purchase(money, creditcard_or_billing_id, options = {}) } add_order_id(parameters, options) + add_aggregator(parameters, options) add_customer_data(parameters, options) add_payment_source(parameters, creditcard_or_billing_id) add_addresses(parameters, options) @@ -181,6 +183,7 @@ def capture(money, authorization, options = {}) :amount => amount(money), :transid => authorization, } + add_aggregator(parameters, options) commit('postauth', parameters) end @@ -192,6 +195,7 @@ def refund(money, identification, options = {}) :amount => amount(money), :transid => identification } + add_aggregator(parameters, options) commit('credit', parameters) end @@ -219,6 +223,7 @@ def void(authorization, options = {}) parameters = { :transid => authorization, } + add_aggregator(parameters, options) commit('reversal', parameters) end @@ -237,7 +242,7 @@ def void(authorization, options = {}) def recurring(money, creditcard, options = {}) ActiveMerchant.deprecated RECURRING_DEPRECATION_MESSAGE - requires!(options, [:periodicity, :bimonthly, :monthly, :biweekly, :weekly, :yearly, :daily] ) + requires!(options, [:periodicity, :bimonthly, :monthly, :biweekly, :weekly, :yearly, :daily]) cycle = case options[:periodicity] when :monthly @@ -300,20 +305,38 @@ def scrub(transcript) transcript. gsub(%r((Authorization: Basic )\w+), '\1[FILTERED]'). gsub(%r((&?cc=)\d*(&?)), '\1[FILTERED]\2'). + gsub(%r((&?password=)[^&]+(&?)), '\1[FILTERED]\2'). gsub(%r((&?cvv=)\d*(&?)), '\1[FILTERED]\2') end private + + def add_aggregator(params, options) + if @options[:aggregator_id] + params[:aggregators] = 1 + params[:aggregator1] = @options[:aggregator_id] + end + end + def add_payment_source(params, source) if source.is_a?(String) add_billing_id(params, source) + elsif card_brand(source) == 'check' + add_check(params, source) else add_creditcard(params, source) end end + def add_check(params, check) + params[:media] = 'ach' + params[:routing] = check.routing_number + params[:account] = check.account_number + params[:savings] = 'y' if check.account_type == 'savings' + end + def add_creditcard(params, creditcard) - params[:media] = "cc" + params[:media] = 'cc' params[:name] = creditcard.name params[:cc] = creditcard.number params[:exp] = expdate(creditcard) @@ -352,7 +375,7 @@ def add_addresses(params, options) params[:shipto_address2] = shipping_address[:address2] unless shipping_address[:address2].blank? params[:shipto_city] = shipping_address[:city] unless shipping_address[:city].blank? params[:shipto_state] = shipping_address[:state] unless shipping_address[:state].blank? - params[:shipto_zip] = shipping_address[:zip] unless shipping_address[:zip].blank? + params[:shipto_zip] = shipping_address[:zip] unless shipping_address[:zip].blank? params[:shipto_country] = shipping_address[:country] unless shipping_address[:country].blank? end end @@ -361,7 +384,7 @@ def clean_and_stringify_params(parameters) # TCLink wants us to send a hash with string keys, and activemerchant pushes everything around with # symbol keys. Before sending our input to TCLink, we convert all our keys to strings and dump the symbol keys. # We also remove any pairs with nil values, as these confuse TCLink. - parameters.keys.reverse.each do |key| + parameters.keys.reverse_each do |key| if parameters[key] parameters[key.to_s] = parameters[key] end @@ -370,7 +393,7 @@ def clean_and_stringify_params(parameters) end def post_data(parameters) - parameters.collect { |key, value| "#{key}=#{ CGI.escape(value.to_s)}" }.join("&") + parameters.collect { |key, value| "#{key}=#{CGI.escape(value.to_s)}" }.join('&') end def commit(action, parameters) @@ -382,19 +405,19 @@ def commit(action, parameters) clean_and_stringify_params(parameters) data = if tclink? - TCLink.send(parameters) - else - parse( ssl_post(self.live_url, post_data(parameters)) ) + TCLink.send(parameters) + else + parse(ssl_post(self.live_url, post_data(parameters))) end # to be considered successful, transaction status must be either "approved" or "accepted" - success = SUCCESS_TYPES.include?(data["status"]) + success = SUCCESS_TYPES.include?(data['status']) message = message_from(data) Response.new(success, message, data, :test => test?, - :authorization => data["transid"], - :cvv_result => data["cvv"], - :avs_result => { :code => data["avs"] } + :authorization => data['transid'], + :cvv_result => data['cvv'], + :avs_result => { :code => data['avs'] } ) end @@ -402,7 +425,7 @@ def parse(body) results = {} body.split(/\n/).each do |pair| - key,val = pair.split(/=/) + key, val = pair.split(/=/) results[key] = val end @@ -410,15 +433,15 @@ def parse(body) end def message_from(data) - case data["status"] - when "decline" - return DECLINE_CODES[data["declinetype"]] - when "baddata" - return BADDATA_CODES[data["error"]] - when "error" - return ERROR_CODES[data["errortype"]] + case data['status'] + when 'decline' + return DECLINE_CODES[data['declinetype']] + when 'baddata' + return BADDATA_CODES[data['error']] + when 'error' + return ERROR_CODES[data['errortype']] else - return "The transaction was successful" + return 'The transaction was successful' end end diff --git a/lib/active_merchant/billing/gateways/usa_epay.rb b/lib/active_merchant/billing/gateways/usa_epay.rb index 2ca57cdd0cf..0558311bc11 100644 --- a/lib/active_merchant/billing/gateways/usa_epay.rb +++ b/lib/active_merchant/billing/gateways/usa_epay.rb @@ -9,15 +9,15 @@ class UsaEpayGateway < Gateway self.abstract_class = true ## - # Creates an instance of UsaEpayTransactionGateway by default, but if + # Creates an instance of UsaEpayTransactionGateway by default, but if # :software id or :live_url are passed in the options hash it will # create an instance of UsaEpayAdvancedGateway. # def self.new(options={}) - unless options.has_key?(:software_id) || options.has_key?(:live_url) - UsaEpayTransactionGateway.new(options) - else + if options.has_key?(:software_id) || options.has_key?(:live_url) UsaEpayAdvancedGateway.new(options) + else + UsaEpayTransactionGateway.new(options) end end end diff --git a/lib/active_merchant/billing/gateways/usa_epay_advanced.rb b/lib/active_merchant/billing/gateways/usa_epay_advanced.rb index 497f4b54e5d..23077a0fd87 100644 --- a/lib/active_merchant/billing/gateways/usa_epay_advanced.rb +++ b/lib/active_merchant/billing/gateways/usa_epay_advanced.rb @@ -62,7 +62,7 @@ module Billing #:nodoc: # * {USA ePay Developer Login}[https://www.usaepay.com/developer/login] # class UsaEpayAdvancedGateway < Gateway - API_VERSION = "1.4" + API_VERSION = '1.4' TEST_URL_BASE = 'https://sandbox.usaepay.com/soap/gate/' #:nodoc: LIVE_URL_BASE = 'https://www.usaepay.com/soap/gate/' #:nodoc: @@ -70,19 +70,21 @@ class UsaEpayAdvancedGateway < Gateway self.test_url = TEST_URL_BASE self.live_url = LIVE_URL_BASE - FAILURE_MESSAGE = "Default Failure" #:nodoc: + FAILURE_MESSAGE = 'Default Failure' #:nodoc: self.supported_countries = ['US'] self.supported_cardtypes = [:visa, :master, :american_express, :discover, :diners_club, :jcb] self.homepage_url = 'http://www.usaepay.com/' self.display_name = 'USA ePay Advanced SOAP Interface' - CUSTOMER_OPTIONS = { + CUSTOMER_PROFILE_OPTIONS = { :id => [:string, 'CustomerID'], # merchant assigned number :notes => [:string, 'Notes'], :data => [:string, 'CustomData'], - :url => [:string, 'URL'], - # Recurring Billing + :url => [:string, 'URL'] + } #:nodoc: + + CUSTOMER_RECURRING_BILLING_OPTIONS = { :enabled => [:boolean, 'Enabled'], :schedule => [:string, 'Schedule'], :number_left => [:integer, 'NumLeft'], @@ -92,18 +94,24 @@ class UsaEpayAdvancedGateway < Gateway :user => [:string, 'User'], :source => [:string, 'Source'], :send_receipt => [:boolean, 'SendReceipt'], - :receipt_note => [:string, 'ReceiptNote'], - # Point of Sale + :receipt_note => [:string, 'ReceiptNote'] + } #:nodoc: + + CUSTOMER_POINT_OF_SALE_OPTIONS = { :price_tier => [:string, 'PriceTier'], :tax_class => [:string, 'TaxClass'], :lookup_code => [:string, 'LookupCode'] } #:nodoc: - ADDRESS_OPTIONS = { + CUSTOMER_OPTIONS = [ + CUSTOMER_PROFILE_OPTIONS, + CUSTOMER_RECURRING_BILLING_OPTIONS, + CUSTOMER_POINT_OF_SALE_OPTIONS + ].inject(:merge) #:nodoc: + + COMMON_ADDRESS_OPTIONS = { :first_name => [:string, 'FirstName'], :last_name => [:string, 'LastName'], - :address1 => [:string, 'Street'], - :address2 => [:string, 'Street2'], :city => [:string, 'City'], :state => [:string, 'State'], :zip => [:string, 'Zip'], @@ -114,6 +122,32 @@ class UsaEpayAdvancedGateway < Gateway :company => [:string, 'Company'] } #:nodoc: + ADDRESS_OPTIONS = [ + COMMON_ADDRESS_OPTIONS, + { + :address1 => [:string, 'Street'], + :address2 => [:string, 'Street2'], + } + ].inject(:merge) #:nodoc + + CUSTOMER_UPDATE_DATA_FIELDS = [ + CUSTOMER_PROFILE_OPTIONS, + CUSTOMER_RECURRING_BILLING_OPTIONS, + COMMON_ADDRESS_OPTIONS, + { + :address1 => [:string, 'Address'], + :address2 => [:string, 'Address2'], + }, + { + :card_number => [:string, 'CardNumber'], + :card_exp => [:string, 'CardExp'], + :account => [:string, 'Account'], + :routing => [:string, 'Routing'], + :check_format => [:string, 'CheckFormat'], + :record_type => [:string, 'RecordType'], + } + ].inject(:merge) #:nodoc + CUSTOMER_TRANSACTION_REQUEST_OPTIONS = { :command => [:string, 'Command'], :ignore_duplicate => [:boolean, 'IgnoreDuplicate'], @@ -238,8 +272,8 @@ def initialize(options = {}) requires!(options, :login, :password) if options[:software_id] - self.live_url = "#{LIVE_URL_BASE}#{options[:software_id].to_s}" - self.test_url = "#{TEST_URL_BASE}#{options[:software_id].to_s}" + self.live_url = "#{LIVE_URL_BASE}#{options[:software_id]}" + self.test_url = "#{TEST_URL_BASE}#{options[:software_id]}" else self.live_url = options[:live_url].to_s self.test_url = options[:test_url].to_s if options[:test_url] @@ -354,6 +388,55 @@ def update_customer(options={}) commit(__method__, request) end + # Update a customer by replacing only the provided fields. + # + # ==== Required + # * <tt>:customer_number</tt> -- customer to update + # * <tt>:update_data</tt> -- FieldValue array of fields to retrieve + # * <tt>:first_name</tt> + # * <tt>:last_name</tt> + # * <tt>:id</tt> + # * <tt>:company</tt> + # * <tt>:address</tt> + # * <tt>:address2</tt> + # * <tt>:city</tt> + # * <tt>:state</tt> + # * <tt>:zip</tt> + # * <tt>:country</tt> + # * <tt>:phone</tt> + # * <tt>:fax</tt> + # * <tt>:email</tt> + # * <tt>:url</tt> + # * <tt>:receipt_note</tt> + # * <tt>:send_receipt</tt> + # * <tt>:notes</tt> + # * <tt>:description</tt> + # * <tt>:order_id</tt> + # * <tt>:enabled</tt> + # * <tt>:schedule</tt> + # * <tt>:next</tt> + # * <tt>:num_left</tt> + # * <tt>:amount</tt> + # * <tt>:custom_data</tt> + # * <tt>:source</tt> + # * <tt>:user</tt> + # * <tt>:card_number</tt> + # * <tt>:card_exp</tt> + # * <tt>:account</tt> + # * <tt>:routing</tt> + # * <tt>:check_format</tt> or <tt>:record_type</tt> + # + # ==== Response + # * <tt>#message</tt> -- boolean; Returns true if successful. Exception thrown all failures. + # + def quick_update_customer(options={}) + requires! options, :customer_number + requires! options, :update_data + + request = build_request(__method__, options) + commit(__method__, request) + end + # Enable a customer for recurring billing. # # Note: Customer does not need to have all recurring parameters to succeed. @@ -949,14 +1032,14 @@ def get_account_details def build_request(action, options = {}) soap = Builder::XmlMarkup.new soap.instruct!(:xml, :version => '1.0', :encoding => 'utf-8') - soap.tag! "SOAP-ENV:Envelope", + soap.tag! 'SOAP-ENV:Envelope', 'xmlns:SOAP-ENV' => 'http://schemas.xmlsoap.org/soap/envelope/', 'xmlns:ns1' => 'urn:usaepay', 'xmlns:xsd' => 'http://www.w3.org/2001/XMLSchema', 'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance', 'xmlns:SOAP-ENC' => 'http://schemas.xmlsoap.org/soap/encoding/', 'SOAP-ENV:encodingStyle' => 'http://schemas.xmlsoap.org/soap/encoding/' do - soap.tag! "SOAP-ENV:Body" do + soap.tag! 'SOAP-ENV:Body' do send("build_#{action}", soap, options) end end @@ -975,9 +1058,9 @@ def build_token(soap, options) soap.Token 'xsi:type' => 'ns1:ueSecurityToken' do build_tag soap, :string, 'ClientIP', options[:client_ip] soap.PinHash 'xsi:type' => 'ns1:ueHash' do - build_tag soap, :string, "HashValue", hash - build_tag soap, :string, "Seed", seed - build_tag soap, :string, "Type", 'sha1' + build_tag soap, :string, 'HashValue', hash + build_tag soap, :string, 'Seed', seed + build_tag soap, :string, 'Type', 'sha1' end build_tag soap, :string, 'SourceKey', @options[:login] end @@ -986,12 +1069,12 @@ def build_token(soap, options) # Customer ====================================================== def build_add_customer(soap, options) - soap.tag! "ns1:addCustomer" do + soap.tag! 'ns1:addCustomer' do build_token soap, options build_customer_data soap, options build_tag soap, :double, 'Amount', amount(options[:amount]) build_tag soap, :double, 'Tax', amount(options[:tax]) - build_tag soap, :string, 'Next', options[:next].strftime("%Y-%m-%d") if options[:next] + build_tag soap, :string, 'Next', options[:next].strftime('%Y-%m-%d') if options[:next] end end @@ -1019,8 +1102,16 @@ def build_delete_customer(soap, options) build_customer(soap, options, 'deleteCustomer') end + def build_quick_update_customer(soap, options) + soap.tag! 'ns1:quickUpdateCustomer' do + build_token soap, options + build_tag soap, :integer, 'CustNum', options[:customer_number] + build_field_value_array soap, 'UpdateData', 'FieldValue', options[:update_data], CUSTOMER_UPDATE_DATA_FIELDS + end + end + def build_add_customer_payment_method(soap, options) - soap.tag! "ns1:addCustomerPaymentMethod" do + soap.tag! 'ns1:addCustomerPaymentMethod' do build_token soap, options build_tag soap, :integer, 'CustNum', options[:customer_number] build_customer_payment_methods soap, options @@ -1050,7 +1141,7 @@ def build_update_customer_payment_method(soap, options) end def build_delete_customer_payment_method(soap, options) - soap.tag! "ns1:deleteCustomerPaymentMethod" do + soap.tag! 'ns1:deleteCustomerPaymentMethod' do build_token soap, options build_tag soap, :integer, 'Custnum', options[:customer_number] build_tag soap, :integer, 'PaymentMethodID', options[:method_id] @@ -1058,7 +1149,7 @@ def build_delete_customer_payment_method(soap, options) end def build_run_customer_transaction(soap, options) - soap.tag! "ns1:runCustomerTransaction" do + soap.tag! 'ns1:runCustomerTransaction' do build_token soap, options build_tag soap, :integer, 'CustNum', options[:customer_number] build_tag soap, :integer, 'PaymentMethodID', options[:method_id] || 0 @@ -1135,21 +1226,21 @@ def build_run_quick_credit(soap, options) end def build_get_transaction(soap, options) - soap.tag! "ns1:getTransaction" do + soap.tag! 'ns1:getTransaction' do build_token soap, options build_tag soap, :integer, 'RefNum', options[:reference_number] end end def build_get_transaction_status(soap, options) - soap.tag! "ns1:getTransactionStatus" do + soap.tag! 'ns1:getTransactionStatus' do build_token soap, options build_tag soap, :integer, 'RefNum', options[:reference_number] end end def build_get_transaction_custom(soap, options) - soap.tag! "ns1:getTransactionCustom" do + soap.tag! 'ns1:getTransactionCustom' do build_token soap, options build_tag soap, :integer, 'RefNum', options[:reference_number] build_transaction_field_array soap, options @@ -1157,14 +1248,14 @@ def build_get_transaction_custom(soap, options) end def build_get_check_trace(soap, options) - soap.tag! "ns1:getCheckTrace" do + soap.tag! 'ns1:getCheckTrace' do build_token soap, options build_tag soap, :integer, 'RefNum', options[:reference_number] end end def build_capture_transaction(soap, options) - soap.tag! "ns1:captureTransaction" do + soap.tag! 'ns1:captureTransaction' do build_token soap, options build_tag soap, :integer, 'RefNum', options[:reference_number] build_tag soap, :double, 'Amount', amount(options[:amount]) @@ -1172,14 +1263,14 @@ def build_capture_transaction(soap, options) end def build_void_transaction(soap, options) - soap.tag! "ns1:voidTransaction" do + soap.tag! 'ns1:voidTransaction' do build_token soap, options build_tag soap, :integer, 'RefNum', options[:reference_number] end end def build_refund_transaction(soap, options) - soap.tag! "ns1:refundTransaction" do + soap.tag! 'ns1:refundTransaction' do build_token soap, options build_tag soap, :integer, 'RefNum', options[:reference_number] build_tag soap, :integer, 'Amount', amount(options[:amount]) @@ -1187,7 +1278,7 @@ def build_refund_transaction(soap, options) end def build_override_transaction(soap, options) - soap.tag! "ns1:overrideTransaction" do + soap.tag! 'ns1:overrideTransaction' do build_token soap, options build_tag soap, :integer, 'RefNum', options[:reference_number] build_tag soap, :string, 'Reason', options[:reason] @@ -1197,7 +1288,7 @@ def build_override_transaction(soap, options) # Account ======================================================= def build_get_account_details(soap, options) - soap.tag! "ns1:getAccountDetails" do + soap.tag! 'ns1:getAccountDetails' do build_token soap, options end end @@ -1206,7 +1297,7 @@ def build_get_account_details(soap, options) def build_customer_data(soap, options) soap.CustomerData 'xsi:type' => 'ns1:CustomerObject' do - CUSTOMER_OPTIONS.each do |k,v| + CUSTOMER_OPTIONS.each do |k, v| build_tag soap, v[0], v[1], options[k] end build_billing_address soap, options @@ -1219,7 +1310,7 @@ def build_customer_payments(soap, options) if options[:payment_methods] length = options[:payment_methods].length soap.PaymentMethods 'SOAP-ENC:arrayType' => "ns1:PaymentMethod[#{length}]", - 'xsi:type' =>"ns1:PaymentMethodArray" do + 'xsi:type' =>'ns1:PaymentMethodArray' do build_customer_payment_methods soap, options end end @@ -1266,7 +1357,7 @@ def build_credit_card_or_check(soap, payment_method) def build_customer_payment_methods(soap, options) payment_methods, tag_name = extract_methods_and_tag(options) payment_methods.each do |payment_method| - soap.tag! tag_name, 'xsi:type' => "ns1:PaymentMethod" do + soap.tag! tag_name, 'xsi:type' => 'ns1:PaymentMethod' do build_tag soap, :integer, 'MethodID', payment_method[:method_id] build_tag soap, :string, 'MethodType', payment_method[:type] build_tag soap, :string, 'MethodName', payment_method[:name] @@ -1277,9 +1368,9 @@ def build_customer_payment_methods(soap, options) end def build_customer_transaction(soap, options) - soap.Parameters 'xsi:type' => "ns1:CustomerTransactionRequest" do + soap.Parameters 'xsi:type' => 'ns1:CustomerTransactionRequest' do build_transaction_detail soap, options - CUSTOMER_TRANSACTION_REQUEST_OPTIONS.each do |k,v| + CUSTOMER_TRANSACTION_REQUEST_OPTIONS.each do |k, v| build_tag soap, v[0], v[1], options[k] end build_custom_fields soap, options @@ -1290,12 +1381,13 @@ def build_customer_transaction(soap, options) # Transaction Helpers =========================================== def build_transaction_request_object(soap, options, name='Params') - soap.tag! name, 'xsi:type' => "ns1:TransactionRequestObject" do - TRANSACTION_REQUEST_OBJECT_OPTIONS.each do |k,v| + soap.tag! name, 'xsi:type' => 'ns1:TransactionRequestObject' do + TRANSACTION_REQUEST_OBJECT_OPTIONS.each do |k, v| build_tag soap, v[0], v[1], options[k] end case - when options[:payment_method] == nil + when options[:payment_method].nil? + nil when options[:payment_method].kind_of?(ActiveMerchant::Billing::CreditCard) build_credit_card_data soap, options when options[:payment_method].kind_of?(ActiveMerchant::Billing::Check) @@ -1313,18 +1405,18 @@ def build_transaction_request_object(soap, options, name='Params') end def build_transaction_detail(soap, options) - soap.Details 'xsi:type' => "ns1:TransactionDetail" do - TRANSACTION_DETAIL_OPTIONS.each do |k,v| + soap.Details 'xsi:type' => 'ns1:TransactionDetail' do + TRANSACTION_DETAIL_OPTIONS.each do |k, v| build_tag soap, v[0], v[1], options[k] end - TRANSACTION_DETAIL_MONEY_OPTIONS.each do |k,v| + TRANSACTION_DETAIL_MONEY_OPTIONS.each do |k, v| build_tag soap, v[0], v[1], amount(options[k]) end end end def build_credit_card_data(soap, options) - soap.CreditCardData 'xsi:type' => "ns1:CreditCardData" do + soap.CreditCardData 'xsi:type' => 'ns1:CreditCardData' do build_tag soap, :string, 'CardNumber', options[:payment_method].number build_tag soap, :string, 'CardExpiration', build_card_expiration(options) if options[:billing_address] @@ -1333,7 +1425,7 @@ def build_credit_card_data(soap, options) end build_tag soap, :string, 'CardCode', options[:payment_method].verification_value build_tag soap, :boolean, 'CardPresent', options[:card_present] || false - CREDIT_CARD_DATA_OPTIONS.each do |k,v| + CREDIT_CARD_DATA_OPTIONS.each do |k, v| build_tag soap, v[0], v[1], options[k] end end @@ -1348,12 +1440,12 @@ def build_card_expiration(options) end def build_check_data(soap, options) - soap.CheckData 'xsi:type' => "ns1:CheckData" do + soap.CheckData 'xsi:type' => 'ns1:CheckData' do build_tag soap, :integer, 'CheckNumber', options[:payment_method].number build_tag soap, :string, 'Account', options[:payment_method].account_number build_tag soap, :string, 'Routing', options[:payment_method].routing_number build_tag soap, :string, 'AccountType', options[:payment_method].account_type.capitalize - CHECK_DATA_OPTIONS.each do |k,v| + CHECK_DATA_OPTIONS.each do |k, v| build_tag soap, v[0], v[1], options[k] end end @@ -1361,11 +1453,11 @@ def build_check_data(soap, options) def build_recurring_billing(soap, options) if options[:recurring] - soap.RecurringBilling 'xsi:type' => "ns1:RecurringBilling" do + soap.RecurringBilling 'xsi:type' => 'ns1:RecurringBilling' do build_tag soap, :double, 'Amount', amount(options[:recurring][:amount]) - build_tag soap, :string, 'Next', options[:recurring][:next].strftime("%Y-%m-%d") if options[:recurring][:next] - build_tag soap, :string, 'Expire', options[:recurring][:expire].strftime("%Y-%m-%d") if options[:recurring][:expire] - RECURRING_BILLING_OPTIONS.each do |k,v| + build_tag soap, :string, 'Next', options[:recurring][:next].strftime('%Y-%m-%d') if options[:recurring][:next] + build_tag soap, :string, 'Expire', options[:recurring][:expire].strftime('%Y-%m-%d') if options[:recurring][:expire] + RECURRING_BILLING_OPTIONS.each do |k, v| build_tag soap, v[0], v[1], options[:recurring][k] end end @@ -1387,8 +1479,8 @@ def build_billing_address(soap, options) if options[:billing_address][:name] options[:billing_address][:first_name], options[:billing_address][:last_name] = split_names(options[:billing_address][:name]) end - soap.BillingAddress 'xsi:type' => "ns1:Address" do - ADDRESS_OPTIONS.each do |k,v| + soap.BillingAddress 'xsi:type' => 'ns1:Address' do + ADDRESS_OPTIONS.each do |k, v| build_tag soap, v[0], v[1], options[:billing_address][k] end end @@ -1400,14 +1492,29 @@ def build_shipping_address(soap, options) if options[:shipping_address][:name] options[:shipping_address][:first_name], options[:shipping_address][:last_name] = split_names(options[:shipping_address][:name]) end - soap.ShippingAddress 'xsi:type' => "ns1:Address" do - ADDRESS_OPTIONS.each do |k,v| + soap.ShippingAddress 'xsi:type' => 'ns1:Address' do + ADDRESS_OPTIONS.each do |k, v| build_tag soap, v[0], v[1], options[:shipping_address][k] end end end end + def build_field_value_array(soap, tag_name, type, custom_data, fields) + soap.tag! tag_name, 'SOAP-ENC:arryType' => "xsd:#{type}[#{options.length}]", 'xsi:type' => "ns1:#{type}Array" do + custom_data.each do |k, v| + build_field_value soap, fields[k][1], v, fields[k][0] if fields.key?(k) + end + end + end + + def build_field_value(soap, field, value, value_type) + soap.FieldValue 'xsi:type' => 'ns1:FieldValue' do + build_tag soap, :string, 'Field', field + build_tag soap, value_type, 'Value', value + end + end + def build_line_items(soap, options) # TODO end @@ -1420,7 +1527,7 @@ def commit(action, request) url = test? ? test_url : live_url begin - soap = ssl_post(url, request, "Content-Type" => "text/xml") + soap = ssl_post(url, request, 'Content-Type' => 'text/xml') rescue ActiveMerchant::ResponseError => error soap = error.response.body end @@ -1431,7 +1538,7 @@ def commit(action, request) def build_response(action, soap) response_params, success, message, authorization, avs, cvv = parse(action, soap) - response_params.merge!('soap_response' => soap) if @options[:soap_response] + response_params['soap_response'] = soap if @options[:soap_response] Response.new( success, @@ -1446,23 +1553,23 @@ def build_response(action, soap) def avs_from(avs) avs_params = { :code => avs } - avs_params.merge!(:message => AVS_CUSTOM_MESSAGES[avs]) if AVS_CUSTOM_MESSAGES.key?(avs) + avs_params[:message] = AVS_CUSTOM_MESSAGES[avs] if AVS_CUSTOM_MESSAGES.key?(avs) avs_params end def parse(action, soap) xml = REXML::Document.new(soap) - root = REXML::XPath.first(xml, "//SOAP-ENV:Body") + root = REXML::XPath.first(xml, '//SOAP-ENV:Body') response = root ? parse_element(root[0]) : { :response => soap } success, message, authorization, avs, cvv = false, FAILURE_MESSAGE, nil, nil, nil - fault = (!response) || (response.length < 1) || response.has_key?('faultcode') + fault = !response || (response.length < 1) || response.has_key?('faultcode') return [response, success, response['faultstring'], authorization, avs, cvv] if fault if response.respond_to?(:[]) && p = response["#{action}_return"] if p.respond_to?(:key?) && p.key?('result_code') - success = p['result_code'] == 'A' ? true : false + success = p['result_code'] == 'A' authorization = p['ref_num'] avs = AVS_RESULTS[p['avs_result_code']] cvv = p['card_code_result_code'] @@ -1511,4 +1618,3 @@ def parse_element(node) end end end - diff --git a/lib/active_merchant/billing/gateways/usa_epay_transaction.rb b/lib/active_merchant/billing/gateways/usa_epay_transaction.rb index 65cde2fe40d..fb0b277a164 100644 --- a/lib/active_merchant/billing/gateways/usa_epay_transaction.rb +++ b/lib/active_merchant/billing/gateways/usa_epay_transaction.rb @@ -1,6 +1,5 @@ module ActiveMerchant #:nodoc: module Billing #:nodoc: - class UsaEpayTransactionGateway < Gateway self.live_url = 'https://www.usaepay.com/gate' self.test_url = 'https://sandbox.usaepay.com/gate' @@ -16,7 +15,8 @@ class UsaEpayTransactionGateway < Gateway :capture => 'cc:capture', :refund => 'cc:refund', :void => 'cc:void', - :void_release => 'cc:void:release' + :void_release => 'cc:void:release', + :check_purchase => 'check:sale' } STANDARD_ERROR_CODE_MAPPING = { @@ -48,31 +48,37 @@ def authorize(money, credit_card, options = {}) add_amount(post, money) add_invoice(post, options) - add_credit_card(post, credit_card) + add_payment(post, credit_card) unless credit_card.track_data.present? add_address(post, credit_card, options) add_customer_data(post, options) end add_split_payments(post, options) + add_recurring_fields(post, options) + add_custom_fields(post, options) + add_line_items(post, options) add_test_mode(post, options) commit(:authorization, post) end - def purchase(money, credit_card, options = {}) + def purchase(money, payment, options = {}) post = {} add_amount(post, money) add_invoice(post, options) - add_credit_card(post, credit_card) - unless credit_card.track_data.present? - add_address(post, credit_card, options) + add_payment(post, payment, options) + unless payment.respond_to?(:track_data) && payment.track_data.present? + add_address(post, payment, options) add_customer_data(post, options) end add_split_payments(post, options) + add_recurring_fields(post, options) + add_custom_fields(post, options) + add_line_items(post, options) add_test_mode(post, options) - commit(:purchase, post) + payment.respond_to?(:routing_number) ? commit(:check_purchase, post) : commit(:purchase, post) end def capture(money, authorization, options = {}) @@ -106,7 +112,20 @@ def void(authorization, options = {}) commit(command, post) end - private + def supports_scrubbing? + true + end + + def scrub(transcript) + transcript. + gsub(%r((&?UMcard=)\d*(&?))i, '\1[FILTERED]\2'). + gsub(%r((&?UMcvv2=)\d*(&?))i, '\1[FILTERED]\2'). + gsub(%r((&?UMmagstripe=)[^&]*)i, '\1[FILTERED]\2'). + gsub(%r((&?UMaccount=)[^&]*)i, '\1[FILTERED]'). + gsub(%r((&?UMkey=)[^&]*)i, '\1[FILTERED]') + end + + private def add_amount(post, money) post[:amount] = amount(money) @@ -126,7 +145,12 @@ def add_customer_data(post, options) if options.has_key? :email post[:custemail] = options[:email] - post[:custreceipt] = 'No' + if options[:cust_receipt] + post[:custreceipt] = options[:cust_receipt] + post[:custreceiptname] = options[:cust_receipt_name] if options[:cust_receipt_name] + else + post[:custreceipt] = 'No' + end end if options.has_key? :customer @@ -138,19 +162,19 @@ def add_customer_data(post, options) end end - def add_address(post, credit_card, options) + def add_address(post, payment, options) billing_address = options[:billing_address] || options[:address] - add_address_for_type(:billing, post, credit_card, billing_address) if billing_address - add_address_for_type(:shipping, post, credit_card, options[:shipping_address]) if options[:shipping_address] + add_address_for_type(:billing, post, payment, billing_address) if billing_address + add_address_for_type(:shipping, post, payment, options[:shipping_address]) if options[:shipping_address] end - def add_address_for_type(type, post, credit_card, address) + def add_address_for_type(type, post, payment, address) prefix = address_key_prefix(type) first_name, last_name = split_names(address[:name]) - post[address_key(prefix, 'fname')] = first_name.blank? && last_name.blank? ? credit_card.first_name : first_name - post[address_key(prefix, 'lname')] = first_name.blank? && last_name.blank? ? credit_card.last_name : last_name + post[address_key(prefix, 'fname')] = first_name.blank? && last_name.blank? ? payment.first_name : first_name + post[address_key(prefix, 'lname')] = first_name.blank? && last_name.blank? ? payment.last_name : last_name post[address_key(prefix, 'company')] = address[:company] unless address[:company].blank? post[address_key(prefix, 'street')] = address[:address1] unless address[:address1].blank? post[address_key(prefix, 'street2')] = address[:address2] unless address[:address2].blank? @@ -177,16 +201,22 @@ def add_invoice(post, options) post[:description] = options[:description] end - def add_credit_card(post, credit_card) - if credit_card.track_data.present? - post[:magstripe] = credit_card.track_data + def add_payment(post, payment, options={}) + if payment.respond_to?(:routing_number) + post[:checkformat] = options[:check_format] if options[:check_format] + post[:accounttype] = options[:account_type] if options[:account_type] + post[:account] = payment.account_number + post[:routing] = payment.routing_number + post[:name] = payment.name unless payment.name.blank? + elsif payment.respond_to?(:track_data) && payment.track_data.present? + post[:magstripe] = payment.track_data post[:cardpresent] = true else - post[:card] = credit_card.number - post[:cvv2] = credit_card.verification_value if credit_card.verification_value? - post[:expir] = expdate(credit_card) - post[:name] = credit_card.name unless credit_card.name.blank? - post[:cardpresent] = true if credit_card.manual_entry + post[:card] = payment.number + post[:cvv2] = payment.verification_value if payment.verification_value? + post[:expir] = expdate(payment) + post[:name] = payment.name unless payment.name.blank? + post[:cardpresent] = true if payment.manual_entry end end @@ -208,10 +238,54 @@ def add_split_payments(post, options) post['onError'] = options[:on_error] || 'Void' end + def add_recurring_fields(post, options) + return unless options[:recurring_fields].is_a?(Hash) + options[:recurring_fields].each do |key, value| + if value == true + value = 'yes' + elsif value == false + next + end + + if key == :bill_amount + value = amount(value) + end + + post[key.to_s.delete('_')] = value + end + end + + # see: https://wiki.usaepay.com/developer/transactionapi#merchant_defined_custom_fields + def add_custom_fields(post, options) + return unless options[:custom_fields].is_a?(Hash) + options[:custom_fields].each do |index, custom| + post["custom#{index}"] = custom + end + end + + # see: https://wiki.usaepay.com/developer/transactionapi#line_item_details + def add_line_items(post, options) + return unless options[:line_items].is_a?(Array) + options[:line_items].each_with_index do |line_item, index| + %w(product_ref_num sku name description taxable tax_rate tax_amount commodity_code discount_rate discount_amount).each do |key| + post["line#{index}#{key.delete('_')}"] = line_item[key.to_sym] if line_item.has_key?(key.to_sym) + end + + { + quantity: 'qty', + unit: 'um', + }.each do |key, umkey| + post["line#{index}#{umkey}"] = line_item[key.to_sym] if line_item.has_key?(key.to_sym) + end + + post["line#{index}cost"] = amount(line_item[:cost]) + end + end + def parse(body) fields = {} for line in body.split('&') - key, value = *line.scan( %r{^(\w+)\=(.*)$} ).flatten + key, value = *line.scan(%r{^(\w+)\=(.*)$}).flatten fields[key] = CGI.unescape(value.to_s) end @@ -230,7 +304,7 @@ def parse(body) :error_code => fields['UMerrorcode'], :acs_url => fields['UMacsurl'], :payload => fields['UMpayload'] - }.delete_if{|k, v| v.nil?} + }.delete_if { |k, v| v.nil? } end def commit(action, parameters) @@ -246,7 +320,7 @@ def commit(action, parameters) end def message_from(response) - if response[:status] == "Approved" + if response[:status] == 'Approved' return 'Success' else return 'Unspecified error' if response[:error].blank? @@ -263,7 +337,7 @@ def post_data(action, parameters = {}) hash = Digest::SHA1.hexdigest("#{parameters[:command]}:#{@options[:password]}:#{parameters[:amount]}:#{parameters[:invoice]}:#{seed}") parameters[:hash] = "s/#{seed}/#{hash}/n" - parameters.collect { |key, value| "UM#{key}=#{CGI.escape(value.to_s)}" }.join("&") + parameters.collect { |key, value| "UM#{key}=#{CGI.escape(value.to_s)}" }.join('&') end end end diff --git a/lib/active_merchant/billing/gateways/vanco.rb b/lib/active_merchant/billing/gateways/vanco.rb index e8a3617de91..546eedbca4e 100644 --- a/lib/active_merchant/billing/gateways/vanco.rb +++ b/lib/active_merchant/billing/gateways/vanco.rb @@ -23,14 +23,14 @@ def initialize(options={}) def purchase(money, payment_method, options={}) MultiResponse.run do |r| r.process { login } - r.process { commit(purchase_request(money, payment_method, r.params["response_sessionid"], options), :response_transactionref) } + r.process { commit(purchase_request(money, payment_method, r.params['response_sessionid'], options), :response_transactionref) } end end def refund(money, authorization, options={}) MultiResponse.run do |r| r.process { login } - r.process { commit(refund_request(money, authorization, r.params["response_sessionid"]), :response_creditrequestreceived) } + r.process { commit(refund_request(money, authorization, r.params['response_sessionid']), :response_creditrequestreceived) } end end @@ -52,7 +52,7 @@ def parse(xml) doc = Nokogiri::XML(xml) doc.root.xpath('*').each do |node| - if (node.elements.empty?) + if node.elements.empty? response[node.name.downcase.to_sym] = node.text else node.elements.each do |childnode| @@ -66,7 +66,7 @@ def parse(xml) def childnode_to_response(response, node, childnode) name = "#{node.name.downcase}_#{childnode.name.downcase}" - if name == "response_errors" && !childnode.elements.empty? + if name == 'response_errors' && !childnode.elements.empty? add_errors_to_response(response, childnode.to_s) else response[name.downcase.to_sym] = childnode.text @@ -77,13 +77,13 @@ def add_errors_to_response(response, errors_xml) errors_hash = Hash.from_xml(errors_xml).values.first response[:response_errors] = errors_hash - error = errors_hash["Error"] + error = errors_hash['Error'] if error.kind_of?(Hash) - response[:error_message] = error["ErrorDescription"] - response[:error_codes] = error["ErrorCode"] + response[:error_message] = error['ErrorDescription'] + response[:error_codes] = error['ErrorCode'] elsif error.kind_of?(Array) - error_str = error.map { |e| e["ErrorDescription"]}.join(". ") - error_codes = error.map { |e| e["ErrorCode"]}.join(", ") + error_str = error.map { |e| e['ErrorDescription'] }.join('. ') + error_codes = error.map { |e| e['ErrorCode'] }.join(', ') response[:error_message] = "#{error_str}." response[:error_codes] = error_codes end @@ -107,7 +107,7 @@ def success_from(response, success_field_name) end def message_from(succeeded, response) - return "Success" if succeeded + return 'Success' if succeeded response[:error_message] end @@ -116,7 +116,7 @@ def authorization_from(response) response[:response_customerref], response[:response_paymentmethodref], response[:response_transactionref] - ].join("|") + ].join('|') end def split_authorization(authorization) @@ -125,7 +125,7 @@ def split_authorization(authorization) def purchase_request(money, payment_method, session_id, options) build_xml_request do |doc| - add_auth(doc, "EFTAddCompleteTransaction", session_id) + add_auth(doc, 'EFTAddCompleteTransaction', session_id) doc.Request do doc.RequestVars do @@ -141,7 +141,7 @@ def purchase_request(money, payment_method, session_id, options) def refund_request(money, authorization, session_id) build_xml_request do |doc| - add_auth(doc, "EFTAddCredit", session_id) + add_auth(doc, 'EFTAddCredit', session_id) doc.Request do doc.RequestVars do @@ -203,7 +203,7 @@ def add_credit_card(doc, credit_card, options) doc.CardExpYear(format(credit_card.year, :two_digits)) doc.CardCVV2(credit_card.verification_value) doc.CardBillingName(credit_card.name) - doc.AccountType("CC") + doc.AccountType('CC') add_billing_address(doc, options) end @@ -220,28 +220,28 @@ def add_billing_address(doc, options) end def add_echeck(doc, echeck) - if echeck.account_type == "savings" - doc.AccountType("S") + if echeck.account_type == 'savings' + doc.AccountType('S') else - doc.AccountType("C") + doc.AccountType('C') end doc.CustomerName("#{echeck.last_name}, #{echeck.first_name}") doc.AccountNumber(echeck.account_number) doc.RoutingNumber(echeck.routing_number) - doc.TransactionTypeCode("WEB") + doc.TransactionTypeCode('WEB') end def add_purchase_noise(doc) - doc.StartDate("0000-00-00") - doc.FrequencyCode("O") + doc.StartDate('0000-00-00') + doc.FrequencyCode('O') end def add_refund_noise(doc) - doc.ContactName("Bilbo Baggins") - doc.ContactPhone("1234567890") - doc.ContactExtension("None") - doc.ReasonForCredit("Refund requested") + doc.ContactName('Bilbo Baggins') + doc.ContactPhone('1234567890') + doc.ContactExtension('None') + doc.ReasonForCredit('Refund requested') end def add_options(doc, options) @@ -259,7 +259,7 @@ def login def login_request build_xml_request do |doc| doc.Auth do - add_request(doc, "Login") + add_request(doc, 'Login') end doc.Request do @@ -273,7 +273,7 @@ def login_request def build_xml_request builder = Nokogiri::XML::Builder.new - builder.__send__("VancoWS") do |doc| + builder.__send__('VancoWS') do |doc| yield(doc) end builder.to_xml diff --git a/lib/active_merchant/billing/gateways/verifi.rb b/lib/active_merchant/billing/gateways/verifi.rb index 26e7d414905..e435505d8be 100644 --- a/lib/active_merchant/billing/gateways/verifi.rb +++ b/lib/active_merchant/billing/gateways/verifi.rb @@ -5,46 +5,46 @@ module Billing #:nodoc: class VerifiGateway < Gateway class VerifiPostData < PostData # Fields that will be sent even if they are blank - self.required_fields = [ :amount, :type, :ccnumber, :ccexp, :firstname, :lastname, - :company, :address1, :address2, :city, :state, :zip, :country, :phone ] + self.required_fields = [:amount, :type, :ccnumber, :ccexp, :firstname, :lastname, + :company, :address1, :address2, :city, :state, :zip, :country, :phone] end self.live_url = self.test_url = 'https://secure.verifi.com/gw/api/transact.php' RESPONSE_CODE_MESSAGES = { - "100" => "Transaction was Approved", - "200" => "Transaction was Declined by Processor", - "201" => "Do Not Honor", - "202" => "Insufficient Funds", - "203" => "Over Limit", - "204" => "Transaction not allowed", - "220" => "Incorrect payment Data", - "221" => "No Such Card Issuer", - "222" => "No Card Number on file with Issuer", - "223" => "Expired Card", - "224" => "Invalid Expiration Date", - "225" => "Invalid Card Security Code", - "240" => "Call Issuer for Further Information", - "250" => "Pick Up Card", - "251" => "Lost Card", - "252" => "Stolen Card", - "253" => "Fraudulent Card", - "260" => "Declined With further Instructions Available (see response text)", - "261" => "Declined - Stop All Recurring Payments", - "262" => "Declined - Stop this Recurring Program", - "263" => "Declined - Update Cardholder Data Available", - "264" => "Declined - Retry in a few days", - "300" => "Transaction was Rejected by Gateway", - "400" => "Transaction Error Returned by Processor", - "410" => "Invalid Merchant Configuration", - "411" => "Merchant Account is Inactive", - "420" => "Communication Error", - "421" => "Communication Error with Issuer", - "430" => "Duplicate Transaction at Processor", - "440" => "Processor Format Error", - "441" => "Invalid Transaction Information", - "460" => "Processor Feature Not Available", - "461" => "Unsupported Card Type" + '100' => 'Transaction was Approved', + '200' => 'Transaction was Declined by Processor', + '201' => 'Do Not Honor', + '202' => 'Insufficient Funds', + '203' => 'Over Limit', + '204' => 'Transaction not allowed', + '220' => 'Incorrect payment Data', + '221' => 'No Such Card Issuer', + '222' => 'No Card Number on file with Issuer', + '223' => 'Expired Card', + '224' => 'Invalid Expiration Date', + '225' => 'Invalid Card Security Code', + '240' => 'Call Issuer for Further Information', + '250' => 'Pick Up Card', + '251' => 'Lost Card', + '252' => 'Stolen Card', + '253' => 'Fraudulent Card', + '260' => 'Declined With further Instructions Available (see response text)', + '261' => 'Declined - Stop All Recurring Payments', + '262' => 'Declined - Stop this Recurring Program', + '263' => 'Declined - Update Cardholder Data Available', + '264' => 'Declined - Retry in a few days', + '300' => 'Transaction was Rejected by Gateway', + '400' => 'Transaction Error Returned by Processor', + '410' => 'Invalid Merchant Configuration', + '411' => 'Merchant Account is Inactive', + '420' => 'Communication Error', + '421' => 'Communication Error with Issuer', + '430' => 'Duplicate Transaction at Processor', + '440' => 'Processor Format Error', + '441' => 'Invalid Transaction Information', + '460' => 'Processor Feature Not Available', + '461' => 'Unsupported Card Type' } SUCCESS = 1 @@ -180,10 +180,10 @@ def add_security_key_data(post, options, money) # MD5(username|password|orderid|amount|time) now = Time.now.to_i.to_s md5 = Digest::MD5.new - md5 << @options[:login].to_s + "|" - md5 << @options[:password].to_s + "|" - md5 << options[:order_id].to_s + "|" - md5 << amount(money).to_s + "|" + md5 << @options[:login].to_s + '|' + md5 << @options[:password].to_s + '|' + md5 << options[:order_id].to_s + '|' + md5 << amount(money).to_s + '|' md5 << now post[:key] = md5.hexdigest post[:time] = now @@ -192,7 +192,7 @@ def add_security_key_data(post, options, money) def commit(trx_type, money, post) post[:amount] = amount(money) - response = parse( ssl_post(self.live_url, post_data(trx_type, post)) ) + response = parse(ssl_post(self.live_url, post_data(trx_type, post))) Response.new(response[:response].to_i == SUCCESS, message_from(response), response, :test => test?, @@ -203,7 +203,7 @@ def commit(trx_type, money, post) end def message_from(response) - response[:response_code_message] ? response[:response_code_message] : "" + response[:response_code_message] || '' end def parse(body) diff --git a/lib/active_merchant/billing/gateways/viaklix.rb b/lib/active_merchant/billing/gateways/viaklix.rb index 3229e05406d..b68a8ec3ac9 100644 --- a/lib/active_merchant/billing/gateways/viaklix.rb +++ b/lib/active_merchant/billing/gateways/viaklix.rb @@ -50,7 +50,7 @@ def purchase(money, creditcard, options = {}) # Viaklix does not support credits by reference. You must pass in the credit card def credit(money, creditcard, options = {}) if creditcard.is_a?(String) - raise ArgumentError, "Reference credits are not supported. Please supply the original credit card" + raise ArgumentError, 'Reference credits are not supported. Please supply the original credit card' end form = {} @@ -63,6 +63,7 @@ def credit(money, creditcard, options = {}) end private + def add_test_mode(form, options) form[:test_mode] = 'TRUE' if options[:test_mode] end @@ -72,12 +73,12 @@ def add_customer_data(form, options) form[:customer_code] = options[:customer].to_s.slice(0, 10) unless options[:customer].blank? end - def add_invoice(form,options) + def add_invoice(form, options) form[:invoice_number] = (options[:order_id] || options[:invoice]).to_s.slice(0, 10) form[:description] = options[:description].to_s.slice(0, 255) end - def add_address(form,options) + def add_address(form, options) billing_address = options[:billing_address] || options[:address] if billing_address @@ -137,7 +138,7 @@ def commit(action, money, parameters) parameters[:amount] = amount(money) parameters[:transaction_type] = self.actions[action] - response = parse( ssl_post(test? ? self.test_url : self.live_url, post_data(parameters)) ) + response = parse(ssl_post(test? ? self.test_url : self.live_url, post_data(parameters))) Response.new(response['result'] == APPROVED, message_from(response), response, :test => @options[:test] || test?, @@ -158,16 +159,16 @@ def message_from(response) def post_data(parameters) result = preamble result.merge!(parameters) - result.collect { |key, value| "ssl_#{key}=#{CGI.escape(value.to_s)}" }.join("&") + result.collect { |key, value| "ssl_#{key}=#{CGI.escape(value.to_s)}" }.join('&') end # Parse the response message def parse(msg) resp = {} - msg.split(self.delimiter).collect{|li| - key, value = li.split("=") - resp[key.strip.gsub(/^ssl_/, '')] = value.to_s.strip - } + msg.split(self.delimiter).collect { |li| + key, value = li.split('=') + resp[key.strip.gsub(/^ssl_/, '')] = value.to_s.strip + } resp end end diff --git a/lib/active_merchant/billing/gateways/visanet_peru.rb b/lib/active_merchant/billing/gateways/visanet_peru.rb index 724057994ba..70999dc58ee 100644 --- a/lib/active_merchant/billing/gateways/visanet_peru.rb +++ b/lib/active_merchant/billing/gateways/visanet_peru.rb @@ -2,14 +2,14 @@ module ActiveMerchant #:nodoc: module Billing #:nodoc: class VisanetPeruGateway < Gateway include Empty - self.display_name = "VisaNet Peru Gateway" - self.homepage_url = "http://www.visanet.com.pe" + self.display_name = 'VisaNet Peru Gateway' + self.homepage_url = 'http://www.visanet.com.pe' - self.test_url = "https://devapi.vnforapps.com/api.tokenization/api/v2/merchant" - self.live_url = "https://api.vnforapps.com/api.tokenization/api/v2/merchant" + self.test_url = 'https://devapi.vnforapps.com/api.tokenization/api/v2/merchant' + self.live_url = 'https://api.vnforapps.com/api.tokenization/api/v2/merchant' - self.supported_countries = ["US", "PE"] - self.default_currency = "PEN" + self.supported_countries = ['US', 'PE'] + self.default_currency = 'PEN' self.money_format = :dollars self.supported_cardtypes = [:visa, :master, :american_express, :discover] @@ -34,25 +34,32 @@ def authorize(amount, payment_method, options={}) params[:email] = options[:email] || 'unknown@email.com' params[:createAlias] = false - commit("authorize", params) + commit('authorize', params, options) end def capture(authorization, options={}) params = {} + options[:id_unico] = split_authorization(authorization)[1] add_auth_order_id(params, authorization, options) - commit("deposit", params) + commit('deposit', params, options) end def void(authorization, options={}) params = {} add_auth_order_id(params, authorization, options) - commit("void", params) + commit('void', params, options) end def refund(amount, authorization, options={}) params = {} + params[:amount] = amount(amount) if amount add_auth_order_id(params, authorization, options) - commit("cancelDeposit", params) + response = commit('cancelDeposit', params, options) + return response if response.success? || split_authorization(authorization).length == 1 || !options[:force_full_refund_if_unsettled] + + # Attempt RefundSingleTransaction if unsettled + prepare_refund_data(params, authorization, options) + commit('refund', params, options) end def verify(credit_card, options={}) @@ -75,9 +82,9 @@ def scrub(transcript) private - CURRENCY_CODES = Hash.new{|h,k| raise ArgumentError.new("Unsupported currency: #{k}")} - CURRENCY_CODES["USD"] = 840 - CURRENCY_CODES["PEN"] = 604 + CURRENCY_CODES = Hash.new { |h, k| raise ArgumentError.new("Unsupported currency: #{k}") } + CURRENCY_CODES['USD'] = 840 + CURRENCY_CODES['PEN'] = 604 def add_invoice(params, money, options) # Visanet Peru expects a 9-digit numeric purchaseNumber @@ -88,7 +95,8 @@ def add_invoice(params, money, options) end def add_auth_order_id(params, authorization, options) - params[:purchaseNumber] = authorization + purchase_number, _ = split_authorization(authorization) + params[:purchaseNumber] = purchase_number params[:externalTransactionId] = options[:order_id] end @@ -118,48 +126,62 @@ def add_antifraud_data(params, options) params[:antifraud] = antifraud end - def commit(action, params) - begin - raw_response = ssl_request(method(action), url(action, params), params.to_json, headers) - response = parse(raw_response) - rescue ResponseError => e - raw_response = e.response.body - response_error(raw_response) - rescue JSON::ParserError - unparsable_response(raw_response) - else - Response.new( - success_from(response), - message_from(response), - response, - :test => test?, - :authorization => authorization_from(params), - :error_code => response["errorCode"] - ) - end + def prepare_refund_data(params, authorization, options) + params.delete(:purchaseNumber) + params[:externalReferenceId] = params.delete(:externalTransactionId) + _, transaction_id = split_authorization(authorization) + + options.update(transaction_id: transaction_id) + params[:ruc] = options[:ruc] + end + + def split_authorization(authorization) + authorization.split('|') + end + + def commit(action, params, options={}) + raw_response = ssl_request(method(action), url(action, params, options), params.to_json, headers) + response = parse(raw_response) + rescue ResponseError => e + raw_response = e.response.body + response_error(raw_response, options, action) + rescue JSON::ParserError + unparsable_response(raw_response) + else + Response.new( + success_from(response), + message_from(response, options, action), + response, + :test => test?, + :authorization => authorization_from(params, response, options), + :error_code => response['errorCode'] + ) end def headers { - "Authorization" => "Basic " + Base64.strict_encode64("#{@options[:access_key_id]}:#{@options[:secret_access_key]}").strip, - "Content-Type" => "application/json" + 'Authorization' => 'Basic ' + Base64.strict_encode64("#{@options[:access_key_id]}:#{@options[:secret_access_key]}").strip, + 'Content-Type' => 'application/json' } end - def url(action, params) - if (action == "authorize") + def url(action, params, options={}) + if action == 'authorize' "#{base_url}/#{@options[:merchant_id]}" + elsif action == 'refund' + "#{base_url}/#{@options[:merchant_id]}/#{action}/#{options[:transaction_id]}" else "#{base_url}/#{@options[:merchant_id]}/#{action}/#{params[:purchaseNumber]}" end end def method(action) - (action == "authorize") ? :post : :put + %w(authorize refund).include?(action) ? :post : :put end - def authorization_from(params) - params[:purchaseNumber] + def authorization_from(params, response, options) + id_unico = response['data']['ID_UNICO'] || options[:id_unico] + "#{params[:purchaseNumber]}|#{id_unico}" end def base_url @@ -171,36 +193,38 @@ def parse(body) end def success_from(response) - response["errorCode"] == 0 + response['errorCode'] == 0 end - def message_from(response) - if empty?(response["errorMessage"]) || response["errorMessage"] == "[ ]" - response["data"]["DSC_COD_ACCION"] + def message_from(response, options, action) + if empty?(response['errorMessage']) || response['errorMessage'] == '[ ]' + action == 'refund' ? "#{response['data']['DSC_COD_ACCION']}, #{options[:error_message]}" : response['data']['DSC_COD_ACCION'] + elsif action == 'refund' + message = "#{response['errorMessage']}, #{options[:error_message]}" + options[:error_message] = response['errorMessage'] + message else - response["errorMessage"] + response['errorMessage'] end end - def response_error(raw_response) - begin - response = parse(raw_response) - rescue JSON::ParserError - unparsable_response(raw_response) - else - return Response.new( - false, - message_from(response), - response, - :test => test?, - :authorization => response["transactionUUID"], - :error_code => response["errorCode"] - ) - end + def response_error(raw_response, options, action) + response = parse(raw_response) + rescue JSON::ParserError + unparsable_response(raw_response) + else + return Response.new( + false, + message_from(response, options, action), + response, + :test => test?, + :authorization => response['transactionUUID'], + :error_code => response['errorCode'] + ) end def unparsable_response(raw_response) - message = "Invalid JSON response received from VisanetPeruGateway. Please contact VisanetPeruGateway if you continue to receive this message." + message = 'Invalid JSON response received from VisanetPeruGateway. Please contact VisanetPeruGateway if you continue to receive this message.' message += " (The raw response returned by the API was #{raw_response.inspect})" return Response.new(false, message) end diff --git a/lib/active_merchant/billing/gateways/webpay.rb b/lib/active_merchant/billing/gateways/webpay.rb index f35d8c5250e..29636897892 100644 --- a/lib/active_merchant/billing/gateways/webpay.rb +++ b/lib/active_merchant/billing/gateways/webpay.rb @@ -51,9 +51,9 @@ def store(creditcard, options = {}) MultiResponse.run(:first) do |r| r.process { commit(:post, "customers/#{CGI.escape(options[:customer])}/", post, options) } - return r unless options[:set_default] and r.success? and !r.params["id"].blank? + return r unless options[:set_default] and r.success? and !r.params['id'].blank? - r.process { update_customer(options[:customer], :default_card => r.params["id"]) } + r.process { update_customer(options[:customer], :default_card => r.params['id']) } end else commit(:post, 'customers', post, options) @@ -78,18 +78,18 @@ def json_error(raw_response) msg = 'Invalid response received from the WebPay API. Please contact support@webpay.jp if you continue to receive this message.' msg += " (The raw response returned by the API was #{raw_response.inspect})" { - "error" => { - "message" => msg + 'error' => { + 'message' => msg } } end def headers(options = {}) { - "Authorization" => "Basic " + Base64.encode64(@api_key.to_s + ":").strip, - "User-Agent" => "Webpay/v1 ActiveMerchantBindings/#{ActiveMerchant::VERSION}", - "X-Webpay-Client-User-Agent" => user_agent, - "X-Webpay-Client-User-Metadata" => {:ip => options[:ip]}.to_json + 'Authorization' => 'Basic ' + Base64.encode64(@api_key.to_s + ':').strip, + 'User-Agent' => "Webpay/v1 ActiveMerchantBindings/#{ActiveMerchant::VERSION}", + 'X-Webpay-Client-User-Agent' => user_agent, + 'X-Webpay-Client-User-Metadata' => {:ip => options[:ip]}.to_json } end end diff --git a/lib/active_merchant/billing/gateways/wepay.rb b/lib/active_merchant/billing/gateways/wepay.rb index 650891a1bc1..9ec05da7f7f 100644 --- a/lib/active_merchant/billing/gateways/wepay.rb +++ b/lib/active_merchant/billing/gateways/wepay.rb @@ -4,14 +4,12 @@ class WepayGateway < Gateway self.test_url = 'https://stage.wepayapi.com/v2' self.live_url = 'https://wepayapi.com/v2' - self.supported_countries = ['US'] + self.supported_countries = ['US', 'CA'] self.supported_cardtypes = [:visa, :master, :american_express, :discover] self.homepage_url = 'https://www.wepay.com/' self.default_currency = 'USD' self.display_name = 'WePay' - API_VERSION = "2016-12-07" - def initialize(options = {}) requires!(options, :client_id, :account_id, :access_token) super(options) @@ -59,7 +57,7 @@ def capture(money, identifier, options = {}) def void(identifier, options = {}) post = {} post[:checkout_id] = split_authorization(identifier).first - post[:cancel_reason] = (options[:description] || "Void") + post[:cancel_reason] = (options[:description] || 'Void') commit('/checkout/cancel', post, options) end @@ -71,43 +69,52 @@ def refund(money, identifier, options = {}) if(money && (original_amount != amount(money))) post[:amount] = amount(money) end - post[:refund_reason] = (options[:description] || "Refund") + post[:refund_reason] = (options[:description] || 'Refund') post[:payer_email_message] = options[:payer_email_message] if options[:payer_email_message] post[:payee_email_message] = options[:payee_email_message] if options[:payee_email_message] - commit("/checkout/refund", post, options) + commit('/checkout/refund', post, options) end def store(creditcard, options = {}) - requires!(options, :email) - post = {} post[:client_id] = @options[:client_id] post[:user_name] = "#{creditcard.first_name} #{creditcard.last_name}" - post[:email] = options[:email] || "unspecified@example.com" + post[:email] = options[:email] || 'unspecified@example.com' post[:cc_number] = creditcard.number post[:cvv] = creditcard.verification_value unless options[:recurring] post[:expiration_month] = creditcard.month post[:expiration_year] = creditcard.year - post[:original_ip] = options[:ip] if options[:ip] - post[:original_device] = options[:device_fingerprint] if options[:device_fingerprint] if(billing_address = (options[:billing_address] || options[:address])) post[:address] = {} - post[:address]["address1"] = billing_address[:address1] if billing_address[:address1] - post[:address]["city"] = billing_address[:city] if billing_address[:city] - post[:address]["country"] = billing_address[:country] if billing_address[:country] - post[:address]["region"] = billing_address[:state] if billing_address[:state] - post[:address]["postal_code"] = billing_address[:zip] + post[:address]['address1'] = billing_address[:address1] if billing_address[:address1] + post[:address]['city'] = billing_address[:city] if billing_address[:city] + post[:address]['country'] = billing_address[:country] if billing_address[:country] + post[:address]['region'] = billing_address[:state] if billing_address[:state] + post[:address]['postal_code'] = billing_address[:zip] end if options[:recurring] == true post[:client_secret] = @options[:client_secret] commit('/credit_card/transfer', post, options) else + post[:original_device] = options[:device_fingerprint] if options[:device_fingerprint] + post[:original_ip] = options[:ip] if options[:ip] commit('/credit_card/create', post, options) end end + def supports_scrubbing? + true + end + + def scrub(transcript) + transcript. + gsub(%r((\\?"cc_number\\?":\\?")[^\\"]+(\\?"))i, '\1[FILTERED]\2'). + gsub(%r((\\?"cvv\\?":\\?")[^\\"]+(\\?"))i, '\1[FILTERED]\2'). + gsub(%r((Authorization: Bearer )\w+)i, '\1[FILTERED]\2') + end + private def authorize_with_token(post, money, token, options) @@ -119,13 +126,14 @@ def authorize_with_token(post, money, token, options) def add_product_data(post, money, options) post[:account_id] = @options[:account_id] post[:amount] = amount(money) - post[:short_description] = (options[:description] || "Purchase") - post[:type] = (options[:type] || "goods") + post[:short_description] = (options[:description] || 'Purchase') + post[:type] = (options[:type] || 'goods') post[:currency] = (options[:currency] || currency(money)) post[:long_description] = options[:long_description] if options[:long_description] post[:payer_email_message] = options[:payer_email_message] if options[:payer_email_message] post[:payee_email_message] = options[:payee_email_message] if options[:payee_email_message] post[:reference_id] = options[:order_id] if options[:order_id] + post[:unique_id] = options[:unique_id] if options[:unique_id] post[:redirect_uri] = options[:redirect_uri] if options[:redirect_uri] post[:callback_uri] = options[:callback_uri] if options[:callback_uri] post[:fallback_uri] = options[:fallback_uri] if options[:fallback_uri] @@ -136,12 +144,14 @@ def add_product_data(post, money, options) post[:preapproval_id] = options[:preapproval_id] if options[:preapproval_id] post[:prefill_info] = options[:prefill_info] if options[:prefill_info] post[:funding_sources] = options[:funding_sources] if options[:funding_sources] + post[:payer_rbits] = options[:payer_rbits] if options[:payer_rbits] + post[:transaction_rbits] = options[:transaction_rbits] if options[:transaction_rbits] add_fee(post, options) end def add_token(post, token) payment_method = {} - payment_method[:type] = "credit_card" + payment_method[:type] = 'credit_card' payment_method[:credit_card] = { id: token, auto_capture: false @@ -180,48 +190,47 @@ def commit(action, params, options={}) authorization: authorization_from(response, params), test: test? ) - rescue JSON::ParserError return unparsable_response(response) end def success_from(response) - (!response["error"]) + (!response['error']) end def message_from(response) - (response["error"] ? response["error_description"] : "Success") + (response['error'] ? response['error_description'] : 'Success') end def authorization_from(response, params) - return response["credit_card_id"].to_s if response["credit_card_id"] + return response['credit_card_id'].to_s if response['credit_card_id'] - original_amount = response["amount"].nil? ? nil : sprintf("%0.02f", response["amount"]) - [response["checkout_id"], original_amount].join('|') + original_amount = response['amount'].nil? ? nil : sprintf('%0.02f', response['amount']) + [response['checkout_id'], original_amount].join('|') end def split_authorization(authorization) - auth, original_amount = authorization.to_s.split("|") + auth, original_amount = authorization.to_s.split('|') [auth, original_amount] end def unparsable_response(raw_response) - message = "Invalid JSON response received from WePay. Please contact WePay support if you continue to receive this message." + message = 'Invalid JSON response received from WePay. Please contact WePay support if you continue to receive this message.' message += " (The raw response returned by the API was #{raw_response.inspect})" return Response.new(false, message) end def headers(options) - { - "Content-Type" => "application/json", - "User-Agent" => "ActiveMerchantBindings/#{ActiveMerchant::VERSION}", - "Authorization" => "Bearer #{@options[:access_token]}", - "Api-Version" => api_version(options) + headers = { + 'Content-Type' => 'application/json', + 'User-Agent' => "ActiveMerchantBindings/#{ActiveMerchant::VERSION}", + 'Authorization' => "Bearer #{@options[:access_token]}" } - end + headers['Api-Version'] = options[:version] if options[:version] + headers['Client-IP'] = options[:ip] if options[:ip] + headers['WePay-Risk-Token'] = options[:risk_token] if options[:risk_token] - def api_version(options) - options[:version] || API_VERSION + headers end end end diff --git a/lib/active_merchant/billing/gateways/wirecard.rb b/lib/active_merchant/billing/gateways/wirecard.rb index 5649bc2d61f..21218896b6a 100644 --- a/lib/active_merchant/billing/gateways/wirecard.rb +++ b/lib/active_merchant/billing/gateways/wirecard.rb @@ -26,7 +26,7 @@ class WirecardGateway < Gateway # number 5551234 within area code 202 (country code 1). VALID_PHONE_FORMAT = /\+\d{1,3}(\(?\d{3}\)?)?\d{3}-\d{4}-\d{3}/ - self.supported_cardtypes = [ :visa, :master, :american_express, :diners_club, :jcb, :switch ] + self.supported_cardtypes = [ :visa, :master, :american_express, :diners_club, :jcb ] self.supported_countries = %w(AD CY GI IM MT RO CH AT DK GR IT MC SM TR BE EE HU LV NL SK GB BG FI IS LI NO SI VA FR IL LT PL ES CZ DE IE LU PT SE) self.homepage_url = 'http://www.wirecard.com' self.display_name = 'Wirecard' @@ -138,8 +138,9 @@ def scrub(transcript) end private + def clean_description(description) - description.to_s.slice(0,32).encode("US-ASCII", invalid: :replace, undef: :replace, replace: '?') + description.to_s.slice(0, 32).encode('US-ASCII', invalid: :replace, undef: :replace, replace: '?') end def prepare_options_hash(options) @@ -174,7 +175,7 @@ def commit(action, money, options) response = parse(ssl_post(test? ? self.test_url : self.live_url, request, headers)) # Pending Status also means Acknowledged (as stated in their specification) - success = response[:FunctionResult] == "ACK" || response[:FunctionResult] == "PENDING" + success = response[:FunctionResult] == 'ACK' || response[:FunctionResult] == 'PENDING' message = response[:Message] authorization = response[:GuWID] @@ -185,8 +186,8 @@ def commit(action, money, options) :cvv_result => response[:CVCResponseCode] ) rescue ResponseError => e - if e.response.code == "401" - return Response.new(false, "Invalid Login") + if e.response.code == '401' + return Response.new(false, 'Invalid Login') else raise end @@ -200,7 +201,7 @@ def build_request(action, money, options) xml.instruct! xml.tag! 'WIRECARD_BXML' do xml.tag! 'W_REQUEST' do - xml.tag! 'W_JOB' do + xml.tag! 'W_JOB' do xml.tag! 'JobID', '' # UserID for this transaction xml.tag! 'BusinessCaseSignature', options[:signature] || options[:login] @@ -235,7 +236,7 @@ def add_transaction_data(xml, money, options) add_address(xml, options[:billing_address]) when :capture, :bookback xml.tag! 'GuWID', options[:preauthorization] - add_amount(xml, money) + add_amount(xml, money, options) when :reversal xml.tag! 'GuWID', options[:preauthorization] end @@ -246,7 +247,7 @@ def add_transaction_data(xml, money, options) # Includes the payment (amount, currency, country) to the transaction-xml def add_invoice(xml, money, options) - add_amount(xml, money) + add_amount(xml, money, options) xml.tag! 'Currency', options[:currency] || currency(money) xml.tag! 'CountryCode', options[:billing_address][:country] xml.tag! 'RECURRING_TRANSACTION' do @@ -255,13 +256,13 @@ def add_invoice(xml, money, options) end # Include the amount in the transaction-xml - def add_amount(xml, money) - xml.tag! 'Amount', amount(money) + def add_amount(xml, money, options) + xml.tag! 'Amount', localized_amount(money, options[:currency] || currency(money)) end # Includes the credit-card data to the transaction-xml def add_creditcard(xml, creditcard) - raise "Creditcard must be supplied!" if creditcard.nil? + raise 'Creditcard must be supplied!' if creditcard.nil? xml.tag! 'CREDIT_CARD_DATA' do xml.tag! 'CreditCardNumber', creditcard.number xml.tag! 'CVC2', creditcard.verification_value @@ -309,7 +310,7 @@ def parse(xml) xml = REXML::Document.new(xml) if root = REXML::XPath.first(xml, "#{basepath}/W_JOB") parse_response(response, root) - elsif root = REXML::XPath.first(xml, "//ERROR") + elsif root = REXML::XPath.first(xml, '//ERROR') parse_error_only_response(response, root) else response[:Message] = "No valid XML response message received. \ @@ -320,7 +321,7 @@ def parse(xml) end def parse_error_only_response(response, root) - error_code = REXML::XPath.first(root, "Number") + error_code = REXML::XPath.first(root, 'Number') response[:ErrorCode] = error_code.text if error_code response[:Message] = parse_error(root) end @@ -331,18 +332,18 @@ def parse_response(response, root) root.elements.to_a.each do |node| if node.name =~ /FNC_CC_/ - status = REXML::XPath.first(node, "CC_TRANSACTION/PROCESSING_STATUS") + status = REXML::XPath.first(node, 'CC_TRANSACTION/PROCESSING_STATUS') end end - message = "" + message = '' if status if info = status.elements['Info'] message << info.text end status.elements.to_a.each do |node| - if (node.elements.size == 0) + if node.elements.size == 0 response[node.name.to_sym] = (node.text || '').strip else node.elements.each do |childnode| @@ -352,7 +353,7 @@ def parse_response(response, root) end end - error_code = REXML::XPath.first(status, "ERROR/Number") + error_code = REXML::XPath.first(status, 'ERROR/Number') response['ErrorCode'] = error_code.text if error_code end @@ -361,7 +362,7 @@ def parse_response(response, root) end # Parse a generic error response from the gateway - def parse_error(root, message = "") + def parse_error(root, message = '') # Get errors if available and append them to the message errors = errors_to_string(root) unless errors.strip.blank? @@ -376,7 +377,7 @@ def parse_error(root, message = "") def errors_to_string(root) # Get context error messages (can be 0..*) errors = [] - REXML::XPath.each(root, "//ERROR") do |error_elem| + REXML::XPath.each(root, '//ERROR') do |error_elem| error = {} error[:Advice] = [] error[:Message] = error_elem.elements['Message'].text @@ -401,18 +402,18 @@ def errors_to_string(root) # Amex have different AVS response codes AMEX_TRANSLATED_AVS_CODES = { - "A" => "B", # CSC and Address Matched - "F" => "D", # All Data Matched - "N" => "I", # CSC Match - "U" => "U", # Data Not Checked - "Y" => "D", # All Data Matched - "Z" => "P", # CSC and Postcode Matched + 'A' => 'B', # CSC and Address Matched + 'F' => 'D', # All Data Matched + 'N' => 'I', # CSC Match + 'U' => 'U', # Data Not Checked + 'Y' => 'D', # All Data Matched + 'Z' => 'P', # CSC and Postcode Matched } # Amex have different AVS response codes to visa etc def avs_code(response, options) if response.has_key?(:AVS_ProviderResultCode) - if options[:credit_card].present? && ActiveMerchant::Billing::CreditCard.brand?(options[:credit_card].number) == "american_express" + if options[:credit_card].present? && ActiveMerchant::Billing::CreditCard.brand?(options[:credit_card].number) == 'american_express' AMEX_TRANSLATED_AVS_CODES[response[:AVS_ProviderResultCode]] else response[:AVS_ProviderResultCode] @@ -424,7 +425,7 @@ def avs_code(response, options) # (for http basic authentication) def encoded_credentials credentials = [@options[:login], @options[:password]].join(':') - "Basic " << Base64.encode64(credentials).strip + 'Basic ' << Base64.encode64(credentials).strip end end end diff --git a/lib/active_merchant/billing/gateways/world_net.rb b/lib/active_merchant/billing/gateways/world_net.rb index fc7eb38f9fc..70699b1a139 100644 --- a/lib/active_merchant/billing/gateways/world_net.rb +++ b/lib/active_merchant/billing/gateways/world_net.rb @@ -113,9 +113,9 @@ def supports_scrubbing? end def scrub(transcript) - transcript - .gsub(%r{(<CARDNUMBER>\d{6})\d+(\d{4}</CARDNUMBER>)}, '\1...\2') - .gsub(%r{(<CVV>)\d+(</CVV)}, '\1...\2') + transcript. + gsub(%r{(<CARDNUMBER>\d{6})\d+(\d{4}</CARDNUMBER>)}, '\1...\2'). + gsub(%r{(<CVV>)\d+(</CVV)}, '\1...\2') end private diff --git a/lib/active_merchant/billing/gateways/worldpay.rb b/lib/active_merchant/billing/gateways/worldpay.rb index 56a24fcd5d0..aca906ae7f4 100644 --- a/lib/active_merchant/billing/gateways/worldpay.rb +++ b/lib/active_merchant/billing/gateways/worldpay.rb @@ -6,9 +6,10 @@ class WorldpayGateway < Gateway self.default_currency = 'GBP' self.money_format = :cents - self.supported_countries = %w(HK GB AU AD BE CH CY CZ DE DK ES FI FR GI GR HU IE IL IT LI LU MC MT NL NO NZ PL PT SE SG SI SM TR UM VA) - self.supported_cardtypes = [:visa, :master, :american_express, :discover, :jcb, :maestro, :laser, :switch] + self.supported_countries = %w(HK GB AU AD AR BE BR CA CH CN CO CR CY CZ DE DK ES FI FR GI GR HU IE IN IT JP LI LU MC MT MY MX NL NO NZ PA PE PL PT SE SG SI SM TR UM VA) + self.supported_cardtypes = [:visa, :master, :american_express, :discover, :jcb, :maestro] self.currencies_without_fractions = %w(HUF IDR ISK JPY KRW) + self.currencies_with_three_decimal_places = %w(BHD KWD OMR RSD TND) self.homepage_url = 'http://www.worldpay.com/' self.display_name = 'Worldpay Global' @@ -19,9 +20,7 @@ class WorldpayGateway < Gateway 'american_express' => 'AMEX-SSL', 'jcb' => 'JCB-SSL', 'maestro' => 'MAESTRO-SSL', - 'laser' => 'LASER-SSL', 'diners_club' => 'DINERS-SSL', - 'switch' => 'MAESTRO-SSL' } def initialize(options = {}) @@ -31,8 +30,8 @@ def initialize(options = {}) def purchase(money, payment_method, options = {}) MultiResponse.run do |r| - r.process{authorize(money, payment_method, options)} - r.process{capture(money, r.authorization, options.merge(:authorization_validated => true))} + r.process { authorize(money, payment_method, options) } + r.process { capture(money, r.authorization, options.merge(:authorization_validated => true)) } end end @@ -43,33 +42,46 @@ def authorize(money, payment_method, options = {}) def capture(money, authorization, options = {}) MultiResponse.run do |r| - r.process{inquire_request(authorization, options, "AUTHORISED")} unless options[:authorization_validated] + r.process { inquire_request(authorization, options, 'AUTHORISED') } unless options[:authorization_validated] if r.params authorization_currency = r.params['amount_currency_code'] options = options.merge(:currency => authorization_currency) if authorization_currency.present? end - r.process{capture_request(money, authorization, options)} + r.process { capture_request(money, authorization, options) } end end def void(authorization, options = {}) MultiResponse.run do |r| - r.process{inquire_request(authorization, options, "AUTHORISED")} - r.process{cancel_request(authorization, options)} + r.process { inquire_request(authorization, options, 'AUTHORISED') } unless options[:authorization_validated] + r.process { cancel_request(authorization, options) } end end def refund(money, authorization, options = {}) - MultiResponse.run do |r| - r.process{inquire_request(authorization, options, "CAPTURED", "SETTLED", "SETTLED_BY_MERCHANT")} - r.process{refund_request(money, authorization, options)} + response = MultiResponse.run do |r| + r.process { inquire_request(authorization, options, 'CAPTURED', 'SETTLED', 'SETTLED_BY_MERCHANT') } + r.process { refund_request(money, authorization, options) } end + + return response if response.success? + return response unless options[:force_full_refund_if_unsettled] + + void(authorization, options) if response.params['last_event'] == 'AUTHORISED' + end + + # Credits only function on a Merchant ID/login/profile flagged for Payouts + # aka Credit Fund Transfers (CFT), whereas normal purchases, refunds, + # and other transactions should be performed on a normal eCom-flagged + # merchant ID. + def credit(money, payment_method, options = {}) + credit_request(money, payment_method, options.merge(:credit => true)) end def verify(credit_card, options={}) MultiResponse.run(:use_first_response) do |r| r.process { authorize(100, credit_card, options) } - r.process(:ignore_result) { void(r.authorization, options) } + r.process(:ignore_result) { void(r.authorization, options.merge(:authorization_validated => true)) } end end @@ -87,30 +99,34 @@ def scrub(transcript) private def authorize_request(money, payment_method, options) - commit('authorize', build_authorization_request(money, payment_method, options), "AUTHORISED") + commit('authorize', build_authorization_request(money, payment_method, options), 'AUTHORISED', options) end def capture_request(money, authorization, options) - commit('capture', build_capture_request(money, authorization, options), :ok) + commit('capture', build_capture_request(money, authorization, options), :ok, options) end def cancel_request(authorization, options) - commit('cancel', build_void_request(authorization, options), :ok) + commit('cancel', build_void_request(authorization, options), :ok, options) end def inquire_request(authorization, options, *success_criteria) - commit('inquiry', build_order_inquiry_request(authorization, options), *success_criteria) + commit('inquiry', build_order_inquiry_request(authorization, options), *success_criteria, options) end def refund_request(money, authorization, options) - commit('refund', build_refund_request(money, authorization, options), :ok) + commit('refund', build_refund_request(money, authorization, options), :ok, options) + end + + def credit_request(money, payment_method, options) + commit('credit', build_authorization_request(money, payment_method, options), :ok, 'SENT_FOR_REFUND', options) end def build_request xml = Builder::XmlMarkup.new :indent => 2 xml.instruct! :xml, :encoding => 'UTF-8' - xml.declare! :DOCTYPE, :paymentService, :PUBLIC, "-//WorldPay//DTD WorldPay PaymentService v1//EN", "http://dtd.worldpay.com/paymentService_v1.dtd" - xml.tag! 'paymentService', 'version' => "1.4", 'merchantCode' => @options[:login] do + xml.declare! :DOCTYPE, :paymentService, :PUBLIC, '-//WorldPay//DTD WorldPay PaymentService v1//EN', 'http://dtd.worldpay.com/paymentService_v1.dtd' + xml.tag! 'paymentService', 'version' => '1.4', 'merchantCode' => @options[:login] do yield xml end xml.target! @@ -138,7 +154,7 @@ def build_authorization_request(money, payment_method, options) build_request do |xml| xml.tag! 'submit' do xml.tag! 'order', order_tag_attributes(options) do - xml.description(options[:description].blank? ? "Purchase" : options[:description]) + xml.description(options[:description].blank? ? 'Purchase' : options[:description]) add_amount(xml, money, options) if options[:order_content] xml.tag! 'orderContent' do @@ -150,13 +166,16 @@ def build_authorization_request(money, payment_method, options) if options[:hcg_additional_data] add_hcg_additional_data(xml, options) end + if options[:instalments] + add_instalments_data(xml, options) + end end end end end def order_tag_attributes(options) - { 'orderCode' => options[:order_id], 'installationId' => options[:inst_id] || @options[:inst_id] }.reject{|_,v| !v} + { 'orderCode' => options[:order_id], 'installationId' => options[:inst_id] || @options[:inst_id] }.reject { |_, v| !v } end def build_capture_request(money, authorization, options) @@ -178,7 +197,7 @@ def build_void_request(authorization, options) def build_refund_request(money, authorization, options) build_order_modify_request(authorization) do |xml| xml.tag! 'refund' do - add_amount(xml, money, options.merge(:debit_credit_indicator => "credit")) + add_amount(xml, money, options.merge(:debit_credit_indicator => 'credit')) end end end @@ -189,11 +208,11 @@ def add_amount(xml, money, options) amount_hash = { :value => localized_amount(money, currency), 'currencyCode' => currency, - 'exponent' => non_fractional_currency?(currency) ? 0 : 2 + 'exponent' => currency_exponent(currency) } if options[:debit_credit_indicator] - amount_hash.merge!('debitCreditIndicator' => options[:debit_credit_indicator]) + amount_hash['debitCreditIndicator'] = options[:debit_credit_indicator] end xml.tag! 'amount', amount_hash @@ -211,14 +230,14 @@ def add_payment_method(xml, amount, payment_method, options) end end else - xml.tag! 'paymentDetails' do + xml.tag! 'paymentDetails', credit_fund_transfer_attribute(options) do xml.tag! CARD_CODES[card_brand(payment_method)] do xml.tag! 'cardNumber', payment_method.number xml.tag! 'expiryDate' do xml.tag! 'date', 'month' => format(payment_method.month, :two_digits), 'year' => format(payment_method.year, :four_digits) end - xml.tag! 'cardHolderName', payment_method.name + xml.tag! 'cardHolderName', options[:execute_threed] ? '3D' : payment_method.name xml.tag! 'cvc', payment_method.verification_value add_address(xml, (options[:billing_address] || options[:address])) @@ -229,14 +248,29 @@ def add_payment_method(xml, amount, payment_method, options) xml.tag! 'session', 'shopperIPAddress' => options[:ip] if options[:ip] xml.tag! 'session', 'id' => options[:session_id] if options[:session_id] end + add_stored_credential_options(xml, options) if options[:stored_credential_usage] end end end + def add_stored_credential_options(xml, options={}) + if options[:stored_credential_initiated_reason] + xml.tag! 'storedCredentials', 'usage' => options[:stored_credential_usage], 'merchantInitiatedReason' => options[:stored_credential_initiated_reason] do + xml.tag! 'schemeTransactionIdentifier', options[:stored_credential_transaction_id] if options[:stored_credential_transaction_id] + end + else + xml.tag! 'storedCredentials', 'usage' => options[:stored_credential_usage] + end + end + def add_email(xml, options) - return unless options[:email] + return unless options[:execute_threed] || options[:email] xml.tag! 'shopper' do - xml.tag! 'shopperEmailAddress', options[:email] + xml.tag! 'shopperEmailAddress', options[:email] if options[:email] + xml.tag! 'browser' do + xml.tag! 'acceptHeader', options[:accept_header] + xml.tag! 'userAgentHeader', options[:user_agent] + end end end @@ -265,11 +299,18 @@ def add_address(xml, address) def add_hcg_additional_data(xml, options) xml.tag! 'hcgAdditionalData' do options[:hcg_additional_data].each do |k, v| - xml.tag! "param", {name: k.to_s}, v + xml.tag! 'param', {name: k.to_s}, v end end end + def add_instalments_data(xml, options) + xml.tag! 'thirdPartyData' do + xml.tag! 'instalments', options[:instalments] + xml.tag! 'cpf', options[:cpf] if options[:cpf] + end + end + def address_with_defaults(address) address ||= {} address.delete_if { |_, v| v.blank? } @@ -296,16 +337,31 @@ def parse_element(raw, node) end if node.has_elements? raw[node.name.underscore.to_sym] = true unless node.name.blank? - node.elements.each{|e| parse_element(raw, e) } + node.elements.each { |e| parse_element(raw, e) } else raw[node.name.underscore.to_sym] = node.text unless node.text.nil? end raw end - def commit(action, request, *success_criteria) - xmr = ssl_post(url, request, 'Content-Type' => 'text/xml', 'Authorization' => encoded_credentials) - raw = parse(action, xmr) + def headers(options) + headers = { + 'Content-Type' => 'text/xml', + 'Authorization' => encoded_credentials + } + if options[:cookie] + headers['Set-Cookie'] = options[:cookie] if options[:cookie] + end + headers + end + + def commit(action, request, *success_criteria, options) + xml = ssl_post(url, request, headers(options)) + raw = parse(action, xml) + if options[:execute_threed] + raw[:cookie] = @cookie + raw[:session_id] = options[:session_id] + end success, message = success_and_message_from(raw, success_criteria) Response.new( @@ -315,10 +371,9 @@ def commit(action, request, *success_criteria) :authorization => authorization_from(raw), :error_code => error_code_from(success, raw), :test => test?) - rescue ActiveMerchant::ResponseError => e - if e.response.code.to_s == "401" - return Response.new(false, "Invalid credentials", {}, :test => test?) + if e.response.code.to_s == '401' + return Response.new(false, 'Invalid credentials', {}, :test => test?) else raise e end @@ -328,6 +383,18 @@ def url test? ? self.test_url : self.live_url end + # Override the regular handle response so we can access the headers + # Set-Cookie value is needed for 3DS transactions + def handle_response(response) + case response.code.to_i + when 200...300 + @cookie = response['Set-Cookie'] + response.body + else + raise ResponseError.new(response) + end + end + # success_criteria can be: # - a string or an array of strings (if one of many responses) # - An array of strings if one of many responses could be considered a @@ -335,7 +402,7 @@ def url def success_and_message_from(raw, success_criteria) success = (success_criteria.include?(raw[:last_event]) || raw[:ok].present?) if success - message = "SUCCESS" + message = 'SUCCESS' else message = (raw[:iso8583_return_code_description] || raw[:error] || required_status_message(raw, success_criteria)) end @@ -344,26 +411,37 @@ def success_and_message_from(raw, success_criteria) end def error_code_from(success, raw) - unless success == "SUCCESS" + unless success == 'SUCCESS' raw[:iso8583_return_code_code] || raw[:error_code] || nil end end def required_status_message(raw, success_criteria) if(!success_criteria.include?(raw[:last_event])) - "A transaction status of #{success_criteria.collect{|c| "'#{c}'"}.join(" or ")} is required." + "A transaction status of #{success_criteria.collect { |c| "'#{c}'" }.join(" or ")} is required." end end def authorization_from(raw) - pair = raw.detect{|k,v| k.to_s =~ /_order_code$/} + pair = raw.detect { |k, v| k.to_s =~ /_order_code$/ } (pair ? pair.last : nil) end + def credit_fund_transfer_attribute(options) + return unless options[:credit] + {'action' => 'REFUND'} + end + def encoded_credentials credentials = "#{@options[:login]}:#{@options[:password]}" "Basic #{[credentials].pack('m').strip}" end + + def currency_exponent(currency) + return 0 if non_fractional_currency?(currency) + return 3 if three_decimal_currency?(currency) + return 2 + end end end end diff --git a/lib/active_merchant/billing/gateways/worldpay_online_payments.rb b/lib/active_merchant/billing/gateways/worldpay_online_payments.rb index f9ffe71cad3..d3a03ffbeec 100644 --- a/lib/active_merchant/billing/gateways/worldpay_online_payments.rb +++ b/lib/active_merchant/billing/gateways/worldpay_online_payments.rb @@ -8,7 +8,7 @@ class WorldpayOnlinePaymentsGateway < Gateway self.money_format = :cents self.supported_countries = %w(HK US GB BE CH CZ DE DK ES FI FR GR HU IE IT LU MT NL NO PL PT SE SG TR) - self.supported_cardtypes = [:visa, :master, :american_express, :discover, :jcb, :maestro, :laser, :switch] + self.supported_cardtypes = [:visa, :master, :american_express, :discover, :jcb, :maestro] self.homepage_url = 'http://online.worldpay.com' self.display_name = 'Worldpay Online Payments' @@ -32,7 +32,7 @@ def authorize(money, credit_card, options={}) def capture(money, authorization, options={}) if authorization - commit(:post, "orders/#{CGI.escape(authorization)}/capture", {"captureAmount"=>money}, options, 'capture') + commit(:post, "orders/#{CGI.escape(authorization)}/capture", {'captureAmount'=>money}, options, 'capture') else Response.new(false, 'FAILED', @@ -56,7 +56,7 @@ def purchase(money, credit_card, options={}) end def refund(money, orderCode, options={}) - obj = money ? {"refundAmount" => money} : {} + obj = money ? {'refundAmount' => money} : {} commit(:post, "orders/#{CGI.escape(orderCode)}/refund", obj, options, 'refund') end @@ -76,40 +76,40 @@ def verify(credit_card, options={}) def create_token(reusable, name, exp_month, exp_year, number, cvc) obj = { - "reusable"=> reusable, - "paymentMethod"=> { - "type"=> "Card", - "name"=> name, - "expiryMonth"=> exp_month, - "expiryYear"=> exp_year, - "cardNumber"=> number, - "cvc"=> cvc + 'reusable'=> reusable, + 'paymentMethod'=> { + 'type'=> 'Card', + 'name'=> name, + 'expiryMonth'=> exp_month, + 'expiryYear'=> exp_year, + 'cardNumber'=> number, + 'cvc'=> cvc }, - "clientKey"=> @client_key + 'clientKey'=> @client_key } token_response = commit(:post, 'tokens', obj, {'Authorization' => @service_key}, 'token') token_response end def create_post_for_auth_or_purchase(token, money, options) - { - "token" => token, - "orderDescription" => options[:description] || 'Worldpay Order', - "amount" => money, - "currencyCode" => options[:currency] || default_currency, - "name" => options[:billing_address]&&options[:billing_address][:name] ? options[:billing_address][:name] : '', - "billingAddress" => { - "address1"=>options[:billing_address]&&options[:billing_address][:address1] ? options[:billing_address][:address1] : '', - "address2"=>options[:billing_address]&&options[:billing_address][:address2] ? options[:billing_address][:address2] : '', - "address3"=>"", - "postalCode"=>options[:billing_address]&&options[:billing_address][:zip] ? options[:billing_address][:zip] : '', - "city"=>options[:billing_address]&&options[:billing_address][:city] ? options[:billing_address][:city] : '', - "state"=>options[:billing_address]&&options[:billing_address][:state] ? options[:billing_address][:state] : '', - "countryCode"=>options[:billing_address]&&options[:billing_address][:country] ? options[:billing_address][:country] : '' - }, - "customerOrderCode" => options[:order_id], - "orderType" => "ECOM", - "authorizeOnly" => options[:authorizeOnly] ? true : false + { + 'token' => token, + 'orderDescription' => options[:description] || 'Worldpay Order', + 'amount' => money, + 'currencyCode' => options[:currency] || default_currency, + 'name' => options[:billing_address]&&options[:billing_address][:name] ? options[:billing_address][:name] : '', + 'billingAddress' => { + 'address1'=>options[:billing_address]&&options[:billing_address][:address1] ? options[:billing_address][:address1] : '', + 'address2'=>options[:billing_address]&&options[:billing_address][:address2] ? options[:billing_address][:address2] : '', + 'address3'=>'', + 'postalCode'=>options[:billing_address]&&options[:billing_address][:zip] ? options[:billing_address][:zip] : '', + 'city'=>options[:billing_address]&&options[:billing_address][:city] ? options[:billing_address][:city] : '', + 'state'=>options[:billing_address]&&options[:billing_address][:state] ? options[:billing_address][:state] : '', + 'countryCode'=>options[:billing_address]&&options[:billing_address][:country] ? options[:billing_address][:country] : '' + }, + 'customerOrderCode' => options[:order_id], + 'orderType' => 'ECOM', + 'authorizeOnly' => options[:authorizeOnly] ? true : false } end @@ -119,11 +119,11 @@ def parse(body) def headers(options = {}) headers = { - "Authorization" => @service_key, - "Content-Type" => 'application/json', - "User-Agent" => "Worldpay/v1 ActiveMerchantBindings/#{ActiveMerchant::VERSION}", - "X-Worldpay-Client-User-Agent" => user_agent, - "X-Worldpay-Client-User-Metadata" => {:ip => options[:ip]}.to_json + 'Authorization' => @service_key, + 'Content-Type' => 'application/json', + 'User-Agent' => "Worldpay/v1 ActiveMerchantBindings/#{ActiveMerchant::VERSION}", + 'X-Worldpay-Client-User-Agent' => user_agent, + 'X-Worldpay-Client-User-Metadata' => {:ip => options[:ip]}.to_json } if options['Authorization'] headers['Authorization'] = options['Authorization'] @@ -139,7 +139,7 @@ def commit(method, url, parameters=nil, options = {}, type = false) raw_response = ssl_request(method, self.live_url + url, json, headers(options)) - if (raw_response != '') + if raw_response != '' response = parse(raw_response) if type == 'token' success = response.key?('token') @@ -160,51 +160,48 @@ def commit(method, url, parameters=nil, options = {}, type = false) success = true response = {} end - rescue ResponseError => e raw_response = e.response.body response = response_error(raw_response) - rescue JSON::ParserError => e + rescue JSON::ParserError response = json_error(raw_response) end - if response["orderCode"] - authorization = response["orderCode"] - elsif response["token"] - authorization = response["token"] + if response['orderCode'] + authorization = response['orderCode'] + elsif response['token'] + authorization = response['token'] else - authorization = response["message"] + authorization = response['message'] end Response.new(success, - success ? "SUCCESS" : response["message"], + success ? 'SUCCESS' : response['message'], response, :test => test?, :authorization => authorization, :avs_result => {}, :cvv_result => {}, - :error_code => success ? nil : response["customCode"] + :error_code => success ? nil : response['customCode'] ) end def test? - @service_key[0]=="T" ? true : false + @service_key[0] == 'T' end def response_error(raw_response) - begin - parse(raw_response) - rescue JSON::ParserError - json_error(raw_response) - end + parse(raw_response) + rescue JSON::ParserError + json_error(raw_response) end def json_error(raw_response) msg = 'Invalid response received from the Worldpay Online Payments API. Please contact techsupport.online@worldpay.com if you continue to receive this message.' msg += " (The raw response returned by the API was #{raw_response.inspect})" { - "error" => { - "message" => msg + 'error' => { + 'message' => msg } } end diff --git a/lib/active_merchant/billing/gateways/worldpay_us.rb b/lib/active_merchant/billing/gateways/worldpay_us.rb index e66901e376e..303b5b1767e 100644 --- a/lib/active_merchant/billing/gateways/worldpay_us.rb +++ b/lib/active_merchant/billing/gateways/worldpay_us.rb @@ -1,13 +1,16 @@ -require "nokogiri" +require 'nokogiri' module ActiveMerchant #:nodoc: module Billing #:nodoc: class WorldpayUsGateway < Gateway - self.display_name = "Worldpay US" - self.homepage_url = "http://www.worldpay.com/us" + class_attribute :backup_url + + self.display_name = 'Worldpay US' + self.homepage_url = 'http://www.worldpay.com/us' # No sandbox, just use test cards. - self.live_url = 'https://trans.worldpay.us/cgi-bin/process.cgi' + self.live_url = 'https://trans.worldpay.us/cgi-bin/process.cgi' + self.backup_url = 'https://trans.gwtx01.com/cgi-bin/process.cgi' self.supported_countries = ['US'] self.default_currency = 'USD' @@ -25,7 +28,7 @@ def purchase(money, payment_method, options={}) add_payment_method(post, payment_method) add_customer_data(post, options) - commit('purchase', post) + commit('purchase', options, post) end def authorize(money, payment, options={}) @@ -34,7 +37,7 @@ def authorize(money, payment, options={}) add_credit_card(post, payment) add_customer_data(post, options) - commit('authorize', post) + commit('authorize', options, post) end def capture(amount, authorization, options={}) @@ -43,7 +46,7 @@ def capture(amount, authorization, options={}) add_reference(post, authorization) add_customer_data(post, options) - commit('capture', post) + commit('capture', options, post) end def refund(amount, authorization, options={}) @@ -52,14 +55,14 @@ def refund(amount, authorization, options={}) add_reference(post, authorization) add_customer_data(post, options) - commit("refund", post) + commit('refund', options, post) end def void(authorization, options={}) post = {} add_reference(post, authorization) - commit('void', post) + commit('void', options, post) end def verify(credit_card, options={}) @@ -69,8 +72,24 @@ def verify(credit_card, options={}) end end + def supports_scrubbing? + true + end + + def scrub(transcript) + transcript. + gsub(%r((&?merchantpin=)[^&]*)i, '\1[FILTERED]'). + gsub(%r((&?ccnum=)[^&]*)i, '\1[FILTERED]'). + gsub(%r((&?ckacct=)[^&]*)i, '\1[FILTERED]'). + gsub(%r((&?cvv2=)[^&]*)i, '\1[FILTERED]') + end + private + def url(options) + options[:use_backup_url].to_s == 'true' ? self.backup_url : self.live_url + end + def add_customer_data(post, options) if(billing_address = (options[:billing_address] || options[:address])) post[:ci_companyname] = billing_address[:company] @@ -119,8 +138,8 @@ def add_credit_card(post, payment_method) end ACCOUNT_TYPES = { - "checking" => "1", - "savings" => "2", + 'checking' => '1', + 'savings' => '2', } def add_check(post, payment_method) @@ -132,7 +151,7 @@ def add_check(post, payment_method) end def split_authorization(authorization) - historyid, orderid = authorization.split("|") + historyid, orderid = authorization.split('|') [historyid, orderid] end @@ -146,7 +165,7 @@ def add_reference(post, authorization) def parse(xml) response = {} doc = Nokogiri::XML(xml) - message = doc.xpath("//plaintext") + message = doc.xpath('//plaintext') message.text.split(/\r?\n/).each do |line| key, value = line.split(%r{=}) response[key] = value if key @@ -155,14 +174,14 @@ def parse(xml) end ACTIONS = { - "purchase" => "ns_quicksale_cc", - "refund" => "ns_credit", - "authorize" => "ns_quicksale_cc", - "capture" => "ns_quicksale_cc", - "void" => "ns_void", + 'purchase' => 'ns_quicksale_cc', + 'refund' => 'ns_credit', + 'authorize' => 'ns_quicksale_cc', + 'capture' => 'ns_quicksale_cc', + 'void' => 'ns_void', } - def commit(action, post) + def commit(action, options, post) post[:action] = ACTIONS[action] unless post[:action] post[:acctid] = @options[:acctid] post[:subid] = @options[:subid] @@ -170,7 +189,7 @@ def commit(action, post) post[:authonly] = '1' if action == 'authorize' - raw = parse(ssl_post(live_url, post.to_query)) + raw = parse(ssl_post(url(options), post.to_query)) succeeded = success_from(raw['result']) Response.new( @@ -188,14 +207,14 @@ def success_from(result) def message_from(succeeded, response) if succeeded - "Succeeded" + 'Succeeded' else - (response['transresult'] || response['Reason'] || "Unable to read error message") + (response['transresult'] || response['Reason'] || 'Unable to read error message') end end def authorization_from(response) - [response['historyid'], response['orderid']].join("|") + [response['historyid'], response['orderid']].join('|') end end end diff --git a/lib/active_merchant/billing/model.rb b/lib/active_merchant/billing/model.rb index c7ee4a69448..ba280a1211e 100644 --- a/lib/active_merchant/billing/model.rb +++ b/lib/active_merchant/billing/model.rb @@ -1,5 +1,5 @@ -require "active_merchant/billing/compatibility" -require "active_merchant/empty" +require 'active_merchant/billing/compatibility' +require 'active_merchant/empty' module ActiveMerchant module Billing diff --git a/lib/active_merchant/billing/network_tokenization_credit_card.rb b/lib/active_merchant/billing/network_tokenization_credit_card.rb index cab84f2b748..0f358948ab8 100644 --- a/lib/active_merchant/billing/network_tokenization_credit_card.rb +++ b/lib/active_merchant/billing/network_tokenization_credit_card.rb @@ -17,7 +17,7 @@ class NetworkTokenizationCreditCard < CreditCard attr_accessor :payment_cryptogram, :eci, :transaction_id attr_writer :source - SOURCES = [:apple_pay, :android_pay] + SOURCES = %i(apple_pay android_pay google_pay) def source if defined?(@source) && SOURCES.include?(@source) @@ -32,7 +32,7 @@ def credit_card? end def type - "network_tokenization" + 'network_tokenization' end end end diff --git a/lib/active_merchant/billing/rails.rb b/lib/active_merchant/billing/rails.rb index f4098fd2ed3..afa9eeb973a 100644 --- a/lib/active_merchant/billing/rails.rb +++ b/lib/active_merchant/billing/rails.rb @@ -1,3 +1,3 @@ -require "active_merchant/billing/compatibility" +require 'active_merchant/billing/compatibility' ActiveMerchant::Billing::Compatibility.rails_required! diff --git a/lib/active_merchant/billing/response.rb b/lib/active_merchant/billing/response.rb index a59174ceb7c..491bb0cab5b 100644 --- a/lib/active_merchant/billing/response.rb +++ b/lib/active_merchant/billing/response.rb @@ -27,15 +27,15 @@ def initialize(success, message, params = {}, options = {}) @emv_authorization = options[:emv_authorization] @avs_result = if options[:avs_result].kind_of?(AVSResult) - options[:avs_result].to_hash - else - AVSResult.new(options[:avs_result]).to_hash + options[:avs_result].to_hash + else + AVSResult.new(options[:avs_result]).to_hash end @cvv_result = if options[:cvv_result].kind_of?(CVVResult) - options[:cvv_result].to_hash - else - CVVResult.new(options[:cvv_result]).to_hash + options[:cvv_result].to_hash + else + CVVResult.new(options[:cvv_result]).to_hash end end end @@ -70,7 +70,7 @@ def process(ignore_result=false) def <<(response) if response.is_a?(MultiResponse) - response.responses.each{|r| @responses << r} + response.responses.each { |r| @responses << r } else @responses << response end diff --git a/lib/active_merchant/connection.rb b/lib/active_merchant/connection.rb index 34c4f2991af..e6731ed8566 100644 --- a/lib/active_merchant/connection.rb +++ b/lib/active_merchant/connection.rb @@ -5,6 +5,7 @@ module ActiveMerchant class Connection + using NetHttpSslConnection include NetworkConnectionRetries MAX_RETRIES = 3 @@ -13,19 +14,25 @@ class Connection VERIFY_PEER = true CA_FILE = File.expand_path('../certs/cacert.pem', File.dirname(__FILE__)) CA_PATH = nil + MIN_VERSION = :TLS1_1 RETRY_SAFE = false - RUBY_184_POST_HEADERS = { "Content-Type" => "application/x-www-form-urlencoded" } + RUBY_184_POST_HEADERS = { 'Content-Type' => 'application/x-www-form-urlencoded' } attr_accessor :endpoint attr_accessor :open_timeout attr_accessor :read_timeout attr_accessor :verify_peer attr_accessor :ssl_version + if Net::HTTP.instance_methods.include?(:min_version=) + attr_accessor :min_version + attr_accessor :max_version + end + attr_reader :ssl_connection attr_accessor :ca_file attr_accessor :ca_path attr_accessor :pem attr_accessor :pem_password - attr_accessor :wiredump_device + attr_reader :wiredump_device attr_accessor :logger attr_accessor :tag attr_accessor :ignore_http_status @@ -44,12 +51,25 @@ def initialize(endpoint) @max_retries = MAX_RETRIES @ignore_http_status = false @ssl_version = nil - @proxy_address = nil + if Net::HTTP.instance_methods.include?(:min_version=) + @min_version = MIN_VERSION + @max_version = nil + end + @ssl_connection = {} + @proxy_address = :ENV @proxy_port = nil end + def wiredump_device=(device) + raise ArgumentError, "can't wiredump to frozen #{device.class}" if device&.frozen? + @wiredump_device = device + end + def request(method, body, headers = {}) - request_start = Time.now.to_f + request_start = Process.clock_gettime(Process::CLOCK_MONOTONIC) + + headers = headers.dup + headers['connection'] ||= 'close' retry_exceptions(:max_retries => max_retries, :logger => logger, :tag => tag) do begin @@ -58,9 +78,13 @@ def request(method, body, headers = {}) result = nil realtime = Benchmark.realtime do + http.start unless http.started? + @ssl_connection = http.ssl_connection + info "connection_ssl_version=#{ssl_connection[:version]} connection_ssl_cipher=#{ssl_connection[:cipher]}", tag + result = case method when :get - raise ArgumentError, "GET requests do not support a request body" if body + raise ArgumentError, 'GET requests do not support a request body' if body http.get(endpoint.request_uri, headers) when :post debug body @@ -75,34 +99,40 @@ def request(method, body, headers = {}) # It's kind of ambiguous whether the RFC allows bodies # for DELETE requests. But Net::HTTP's delete method # very unambiguously does not. - raise ArgumentError, "DELETE requests do not support a request body" if body - http.delete(endpoint.request_uri, headers) - when :delete_with_body - debug body - http.request(DeleteWithBody.new(endpoint.request_uri, headers), body) + if body + debug body + req = Net::HTTP::Delete.new(endpoint.request_uri, headers) + req.body = body + http.request(req) + else + http.delete(endpoint.request_uri, headers) + end else raise ArgumentError, "Unsupported request method #{method.to_s.upcase}" end end - info "--> %d %s (%d %.4fs)" % [result.code, result.message, result.body ? result.body.length : 0, realtime], tag + info '--> %d %s (%d %.4fs)' % [result.code, result.message, result.body ? result.body.length : 0, realtime], tag debug result.body result end end - ensure - info "connection_request_total_time=%.4fs" % [Time.now.to_f - request_start], tag + info 'connection_request_total_time=%.4fs' % [Process.clock_gettime(Process::CLOCK_MONOTONIC) - request_start], tag + http.finish if http.started? end private + def http - http = Net::HTTP.new(endpoint.host, endpoint.port, proxy_address, proxy_port) - configure_debugging(http) - configure_timeouts(http) - configure_ssl(http) - configure_cert(http) - http + @http ||= begin + http = Net::HTTP.new(endpoint.host, endpoint.port, proxy_address, proxy_port) + configure_debugging(http) + configure_timeouts(http) + configure_ssl(http) + configure_cert(http) + http + end end def configure_debugging(http) @@ -115,10 +145,14 @@ def configure_timeouts(http) end def configure_ssl(http) - return unless endpoint.scheme == "https" + return unless endpoint.scheme == 'https' http.use_ssl = true http.ssl_version = ssl_version if ssl_version + if http.respond_to?(:min_version=) + http.min_version = min_version if min_version + http.max_version = max_version if max_version + end if verify_peer http.verify_mode = OpenSSL::SSL::VERIFY_PEER @@ -127,7 +161,6 @@ def configure_ssl(http) else http.verify_mode = OpenSSL::SSL::VERIFY_NONE end - end def configure_cert(http) @@ -142,19 +175,6 @@ def configure_cert(http) end end - def handle_response(response) - if @ignore_http_status then - return response.body - else - case response.code.to_i - when 200...300 - response.body - else - raise ResponseError.new(response) - end - end - end - def debug(message, tag = nil) log(:debug, message, tag) end @@ -169,7 +189,7 @@ def error(message, tag = nil) def log(level, message, tag) message = "[#{tag}] #{message}" if tag - logger.send(level, message) if logger + logger&.send(level, message) end end end diff --git a/lib/active_merchant/country.rb b/lib/active_merchant/country.rb index 85ae1fa67d6..bdc25799900 100644 --- a/lib/active_merchant/country.rb +++ b/lib/active_merchant/country.rb @@ -39,11 +39,11 @@ class Country def initialize(options = {}) @name = options.delete(:name) - @codes = options.collect{|k,v| CountryCode.new(v)} + @codes = options.collect { |k, v| CountryCode.new(v) } end def code(format) - @codes.detect{|c| c.format == format} + @codes.detect { |c| c.format == format } end def ==(other) @@ -246,6 +246,7 @@ def to_s { alpha2: 'QA', name: 'Qatar', alpha3: 'QAT', numeric: '634' }, { alpha2: 'RE', name: 'Reunion', alpha3: 'REU', numeric: '638' }, { alpha2: 'RO', name: 'Romania', alpha3: 'ROM', numeric: '642' }, + { alpha2: 'RO', name: 'Romania', alpha3: 'ROU', numeric: '642' }, { alpha2: 'RU', name: 'Russian Federation', alpha3: 'RUS', numeric: '643' }, { alpha2: 'RW', name: 'Rwanda', alpha3: 'RWA', numeric: '646' }, { alpha2: 'BL', name: 'Saint Barthélemy', alpha3: 'BLM', numeric: '652' }, @@ -317,15 +318,15 @@ def to_s ] def self.find(name) - raise InvalidCountryCodeError, "Cannot lookup country for an empty name" if name.blank? + raise InvalidCountryCodeError, 'Cannot lookup country for an empty name' if name.blank? case name.length when 2, 3 upcase_name = name.upcase country_code = CountryCode.new(name) - country = COUNTRIES.detect{|c| c[country_code.format] == upcase_name } + country = COUNTRIES.detect { |c| c[country_code.format] == upcase_name } else - country = COUNTRIES.detect{|c| c[:name].upcase == name.upcase } + country = COUNTRIES.detect { |c| c[:name].casecmp(name).zero? } end raise InvalidCountryCodeError, "No country could be found for the country #{name}" if country.nil? Country.new(country.dup) diff --git a/lib/active_merchant/delete_with_body.rb b/lib/active_merchant/delete_with_body.rb deleted file mode 100644 index cc03926646b..00000000000 --- a/lib/active_merchant/delete_with_body.rb +++ /dev/null @@ -1,10 +0,0 @@ -require 'net/http' -require 'net/https' - -module ActiveMerchant - class DeleteWithBody < Net::HTTPRequest - METHOD = 'DELETE' - REQUEST_HAS_BODY = true - RESPONSE_HAS_BODY = true - end -end diff --git a/lib/active_merchant/net_http_ssl_connection.rb b/lib/active_merchant/net_http_ssl_connection.rb new file mode 100644 index 00000000000..c0ae5ce1080 --- /dev/null +++ b/lib/active_merchant/net_http_ssl_connection.rb @@ -0,0 +1,10 @@ +require 'net/http' + +module NetHttpSslConnection + refine Net::HTTP do + def ssl_connection + return {} unless use_ssl? && @socket.present? + { version: @socket.io.ssl_version, cipher: @socket.io.cipher[0] } + end + end +end diff --git a/lib/active_merchant/network_connection_retries.rb b/lib/active_merchant/network_connection_retries.rb index 4793dcf83b6..09e1b146f30 100644 --- a/lib/active_merchant/network_connection_retries.rb +++ b/lib/active_merchant/network_connection_retries.rb @@ -1,14 +1,16 @@ +require 'openssl' + module ActiveMerchant module NetworkConnectionRetries DEFAULT_RETRIES = 3 DEFAULT_CONNECTION_ERRORS = { - EOFError => "The remote server dropped the connection", - Errno::ECONNRESET => "The remote server reset the connection", - Timeout::Error => "The connection to the remote server timed out", - Errno::ETIMEDOUT => "The connection to the remote server timed out", - SocketError => "The connection to the remote server could not be established", - Errno::EHOSTUNREACH => "The connection to the remote server could not be established", - OpenSSL::SSL::SSLError => "The SSL connection to the remote server could not be established" + EOFError => 'The remote server dropped the connection', + Errno::ECONNRESET => 'The remote server reset the connection', + Timeout::Error => 'The connection to the remote server timed out', + Errno::ETIMEDOUT => 'The connection to the remote server timed out', + SocketError => 'The connection to the remote server could not be established', + Errno::EHOSTUNREACH => 'The connection to the remote server could not be established', + OpenSSL::SSL::SSLError => 'The SSL connection to the remote server could not be established' } def self.included(base) @@ -22,18 +24,24 @@ def retry_exceptions(options={}) begin yield rescue Errno::ECONNREFUSED => e - raise ActiveMerchant::RetriableConnectionError.new("The remote server refused the connection", e) + raise ActiveMerchant::RetriableConnectionError.new('The remote server refused the connection', e) rescue OpenSSL::X509::CertificateError => e NetworkConnectionRetries.log(options[:logger], :error, e.message, options[:tag]) - raise ActiveMerchant::ClientCertificateError, "The remote server did not accept the provided SSL certificate" - rescue Zlib::BufError => e - raise ActiveMerchant::InvalidResponseError, "The remote server replied with an invalid response" + raise ActiveMerchant::ClientCertificateError, 'The remote server did not accept the provided SSL certificate' + rescue Zlib::BufError + raise ActiveMerchant::InvalidResponseError, 'The remote server replied with an invalid response' rescue *connection_errors.keys => e raise ActiveMerchant::ConnectionError.new(derived_error_message(connection_errors, e.class), e) end end end + def self.log(logger, level, message, tag=nil) + tag ||= self.class.to_s + message = "[#{tag}] #{message}" + logger&.send(level, message) + end + private def retry_network_exceptions(options = {}) @@ -42,33 +50,26 @@ def retry_network_exceptions(options = {}) request_start = nil begin - request_start = Time.now.to_f + request_start = Process.clock_gettime(Process::CLOCK_MONOTONIC) result = yield - log_with_retry_details(options[:logger], initial_retries-retries + 1, Time.now.to_f - request_start, "success", options[:tag]) + log_with_retry_details(options[:logger], initial_retries-retries + 1, Process.clock_gettime(Process::CLOCK_MONOTONIC) - request_start, 'success', options[:tag]) result rescue ActiveMerchant::RetriableConnectionError => e retries -= 1 - log_with_retry_details(options[:logger], initial_retries-retries, Time.now.to_f - request_start, e.message, options[:tag]) + log_with_retry_details(options[:logger], initial_retries-retries, Process.clock_gettime(Process::CLOCK_MONOTONIC) - request_start, e.message, options[:tag]) retry unless retries.zero? raise ActiveMerchant::ConnectionError.new(e.message, e) rescue ActiveMerchant::ConnectionError, ActiveMerchant::InvalidResponseError => e retries -= 1 - log_with_retry_details(options[:logger], initial_retries-retries, Time.now.to_f - request_start, e.message, options[:tag]) + log_with_retry_details(options[:logger], initial_retries-retries, Process.clock_gettime(Process::CLOCK_MONOTONIC) - request_start, e.message, options[:tag]) retry if (options[:retry_safe] || retry_safe) && !retries.zero? raise end end - def self.log(logger, level, message, tag=nil) - tag ||= self.class.to_s - message = "[#{tag}] #{message}" - logger.send(level, message) if logger - end - - private def log_with_retry_details(logger, attempts, time, message, tag) - NetworkConnectionRetries.log(logger, :info, "connection_attempt=%d connection_request_time=%.4fs connection_msg=\"%s\"" % [attempts, time, message], tag) + NetworkConnectionRetries.log(logger, :info, 'connection_attempt=%d connection_request_time=%.4fs connection_msg="%s"' % [attempts, time, message], tag) end def derived_error_message(errors, klass) diff --git a/lib/active_merchant/post_data.rb b/lib/active_merchant/post_data.rb index 192d08e853e..c95b85244d2 100644 --- a/lib/active_merchant/post_data.rb +++ b/lib/active_merchant/post_data.rb @@ -11,12 +11,13 @@ def []=(key, value) end def to_post_data - collect { |key, value| "#{key}=#{CGI.escape(value.to_s)}" }.join("&") + collect { |key, value| "#{key}=#{CGI.escape(value.to_s)}" }.join('&') end alias_method :to_s, :to_post_data private + def required?(key) required_fields.include?(key) end diff --git a/lib/active_merchant/posts_data.rb b/lib/active_merchant/posts_data.rb index ad5e03ebd15..15446c09fd8 100644 --- a/lib/active_merchant/posts_data.rb +++ b/lib/active_merchant/posts_data.rb @@ -1,6 +1,5 @@ module ActiveMerchant #:nodoc: module PostsData #:nodoc: - def self.included(base) base.class_attribute :ssl_strict base.ssl_strict = true @@ -8,6 +7,12 @@ def self.included(base) base.class_attribute :ssl_version base.ssl_version = nil + base.class_attribute :min_version + base.min_version = Connection::MIN_VERSION + + base.class_attribute :max_version + base.max_version = nil + base.class_attribute :retry_safe base.retry_safe = false @@ -40,8 +45,8 @@ def ssl_request(method, endpoint, data, headers) end def raw_ssl_request(method, endpoint, data, headers = {}) - logger.warn "#{self.class} using ssl_strict=false, which is insecure" if logger unless ssl_strict - logger.warn "#{self.class} posting to plaintext endpoint, which is insecure" if logger unless endpoint =~ /^https:/ + logger&.warn "#{self.class} using ssl_strict=false, which is insecure" unless ssl_strict + logger&.warn "#{self.class} posting to plaintext endpoint, which is insecure" unless endpoint.to_s =~ /^https:/ connection = new_connection(endpoint) connection.open_timeout = open_timeout @@ -53,6 +58,10 @@ def raw_ssl_request(method, endpoint, data, headers = {}) connection.max_retries = max_retries connection.tag = self.class.name connection.wiredump_device = wiredump_device + if connection.respond_to?(:min_version=) + connection.min_version = min_version + connection.max_version = max_version + end connection.pem = @options[:pem] if @options connection.pem_password = @options[:pem_password] if @options @@ -79,6 +88,5 @@ def handle_response(response) raise ResponseError.new(response) end end - end end diff --git a/lib/active_merchant/version.rb b/lib/active_merchant/version.rb index 722aa6a8aa8..5af2175368e 100644 --- a/lib/active_merchant/version.rb +++ b/lib/active_merchant/version.rb @@ -1,3 +1,3 @@ module ActiveMerchant - VERSION = "1.63.0" + VERSION = '1.88.0' end diff --git a/lib/activemerchant.rb b/lib/activemerchant.rb index 0a3f08fee3f..118568f06b3 100644 --- a/lib/activemerchant.rb +++ b/lib/activemerchant.rb @@ -1 +1 @@ -require 'active_merchant' \ No newline at end of file +require 'active_merchant' diff --git a/lib/certs/cacert.pem b/lib/certs/cacert.pem index 9794dfb70f4..72bbb947fe5 100644 --- a/lib/certs/cacert.pem +++ b/lib/certs/cacert.pem @@ -501,6 +501,66 @@ W3iDVuycNsMm4hH2Z0kdkquM++v/eu6FSqdQgPCnXEqULl8FmTxSQeDNtGPPAUO6nIPcj2A781q0 tHuu2guQOHXvgR1m0vdXcDazv/wor3ElhVsT/h5/WrQ8 -----END CERTIFICATE----- +Entrust G2 Root Certificate Authority +===================================== +-----BEGIN CERTIFICATE----- +MIIEPjCCAyagAwIBAgIESlOMKDANBgkqhkiG9w0BAQsFADCBvjELMAkGA1UEBhMC +VVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50 +cnVzdC5uZXQvbGVnYWwtdGVybXMxOTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3Qs +IEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ugb25seTEyMDAGA1UEAxMpRW50cnVz +dCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzIwHhcNMDkwNzA3MTcy +NTU0WhcNMzAxMjA3MTc1NTU0WjCBvjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUVu +dHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50cnVzdC5uZXQvbGVnYWwt +dGVybXMxOTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0 +aG9yaXplZCB1c2Ugb25seTEyMDAGA1UEAxMpRW50cnVzdCBSb290IENlcnRpZmlj +YXRpb24gQXV0aG9yaXR5IC0gRzIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK +AoIBAQC6hLZy254Ma+KZ6TABp3bqMriVQRrJ2mFOWHLP/vaCeb9zYQYKpSfYs1/T +RU4cctZOMvJyig/3gxnQaoCAAEUesMfnmr8SVycco2gvCoe9amsOXmXzHHfV1IWN +cCG0szLni6LVhjkCsbjSR87kyUnEO6fe+1R9V77w6G7CebI6C1XiUJgWMhNcL3hW +wcKUs/Ja5CeanyTXxuzQmyWC48zCxEXFjJd6BmsqEZ+pCm5IO2/b1BEZQvePB7/1 +U1+cPvQXLOZprE4yTGJ36rfo5bs0vBmLrpxR57d+tVOxMyLlbc9wPBr64ptntoP0 +jaWvYkxN4FisZDQSA/i2jZRjJKRxAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAP +BgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqciZ60B7vfec7aVHUbI2fkBJmqzAN +BgkqhkiG9w0BAQsFAAOCAQEAeZ8dlsa2eT8ijYfThwMEYGprmi5ZiXMRrEPR9RP/ +jTkrwPK9T3CMqS/qF8QLVJ7UG5aYMzyorWKiAHarWWluBh1+xLlEjZivEtRh2woZ +Rkfz6/djwUAFQKXSt/S1mja/qYh2iARVBCuch38aNzx+LaUa2NSJXsq9rD1s2G2v +1fN2D807iDginWyTmsQ9v4IbZT+mD12q/OWyFcq1rca8PdCE6OoGcrBNOTJ4vz4R +nAuknZoh8/CbCzB428Hch0P+vGOaysXCHMnHjf87ElgI5rY97HosTvuDls4MPGmH +VHOkc8KT/1EQrBVUAdj8BbGJoX90g5pJ19xOe4pIb4tF9g== +-----END CERTIFICATE----- + +Entrust L1M Chain Root Certificate +================================== +-----BEGIN CERTIFICATE----- +MIIE/zCCA+egAwIBAgIEUdNARDANBgkqhkiG9w0BAQsFADCBsDELMAkGA1UEBhMC +VVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xOTA3BgNVBAsTMHd3dy5lbnRydXN0 +Lm5ldC9DUFMgaXMgaW5jb3Jwb3JhdGVkIGJ5IHJlZmVyZW5jZTEfMB0GA1UECxMW +KGMpIDIwMDYgRW50cnVzdCwgSW5jLjEtMCsGA1UEAxMkRW50cnVzdCBSb290IENl +cnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTE0MDkyMjE3MTQ1N1oXDTI0MDkyMzAx +MzE1M1owgb4xCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMSgw +JgYDVQQLEx9TZWUgd3d3LmVudHJ1c3QubmV0L2xlZ2FsLXRlcm1zMTkwNwYDVQQL +EzAoYykgMjAwOSBFbnRydXN0LCBJbmMuIC0gZm9yIGF1dGhvcml6ZWQgdXNlIG9u +bHkxMjAwBgNVBAMTKUVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0 +eSAtIEcyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuoS2ctueDGvi +mekwAad26jK4lUEaydphTlhyz/72gnm/c2EGCqUn2LNf00VOHHLWTjLycooP94MZ +0GqAgABFHrDH55q/ElcnHKNoLwqHvWprDl5l8xx31dSFjXAhtLMy54ui1YY5ArG4 +0kfO5MlJxDun3vtUfVe+8OhuwnmyOgtV4lCYFjITXC94VsHClLPyWuQnmp8k18bs +0JslguPMwsRFxYyXegZrKhGfqQpuSDtv29QRGUL3jwe/9VNfnD70FyzmaaxOMkxi +d+q36OW7NLwZi66cUee3frVTsTMi5W3PcDwa+uKbZ7aD9I2lr2JMTeBYrGQ0EgP4 +to2UYySkcQIDAQABo4IBDzCCAQswDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQI +MAYBAf8CAQEwMwYIKwYBBQUHAQEEJzAlMCMGCCsGAQUFBzABhhdodHRwOi8vb2Nz +cC5lbnRydXN0Lm5ldDAzBgNVHR8ELDAqMCigJqAkhiJodHRwOi8vY3JsLmVudHJ1 +c3QubmV0L3Jvb3RjYTEuY3JsMDsGA1UdIAQ0MDIwMAYEVR0gADAoMCYGCCsGAQUF +BwIBFhpodHRwOi8vd3d3LmVudHJ1c3QubmV0L0NQUzAdBgNVHQ4EFgQUanImetAe +733nO2lR1GyNn5ASZqswHwYDVR0jBBgwFoAUaJDkZ6SmU4DHhmak8fdLQ/uEvW0w +DQYJKoZIhvcNAQELBQADggEBAGkzg/woem99751V68U+ep11s8zDODbZNKIoaBjq +HmnTvefQd9q4AINOSs9v0fHBIj905PeYSZ6btp7h25h3LVY0sag82f3Azce/BQPU +AsXx5cbaCKUTx2IjEdFhMB1ghEXveajGJpOkt800uGnFE/aRs8lFc3a2kvZ2Clvh +A0e36SlMkTIjN0qcNdh4/R0f5IOJJICtt/nP5F2l1HHEhVtwH9s/HAHrGkUmMRTM +Zb9n3srMM2XlQZHXN75BGpad5oqXnafOrE6aPb0BoGrZTyIAi0TVaWJ7LuvMuueS +fWlnPfy4fN5Bh9Bp6roKGHoalUOzeXEodm2h+1dK7E3IDhA= +-----END CERTIFICATE----- + RSA Security 2048 v3 ==================== -----BEGIN CERTIFICATE----- @@ -1394,6 +1454,31 @@ UAb3LujEV0lsYSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4= -----END CERTIFICATE----- +DigiCert Global Root G2 +======================= +-----BEGIN CERTIFICATE----- +MIIDjjCCAnagAwIBAgIQAzrx5qcRqaC7KGSxHQn65TANBgkqhkiG9w0BAQsFADBh +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBH +MjAeFw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAwMDBaMGExCzAJBgNVBAYTAlVT +MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j +b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEcyMIIBIjANBgkqhkiG +9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuzfNNNx7a8myaJCtSnX/RrohCgiN9RlUyfuI +2/Ou8jqJkTx65qsGGmvPrC3oXgkkRLpimn7Wo6h+4FR1IAWsULecYxpsMNzaHxmx +1x7e/dfgy5SDN67sH0NO3Xss0r0upS/kqbitOtSZpLYl6ZtrAGCSYP9PIUkY92eQ +q2EGnI/yuum06ZIya7XzV+hdG82MHauVBJVJ8zUtluNJbd134/tJS7SsVQepj5Wz +tCO7TG1F8PapspUwtP1MVYwnSlcUfIKdzXOS0xZKBgyMUNGPHgm+F6HmIcr9g+UQ +vIOlCsRnKPZzFBQ9RnbDhxSJITRNrw9FDKZJobq7nMWxM4MphQIDAQABo0IwQDAP +BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUTiJUIBiV +5uNu5g/6+rkS7QYXjzkwDQYJKoZIhvcNAQELBQADggEBAGBnKJRvDkhj6zHd6mcY +1Yl9PMWLSn/pvtsrF9+wX3N3KjITOYFnQoQj8kVnNeyIv/iPsGEMNKSuIEyExtv4 +NeF22d+mQrvHRAiGfzZ0JFrabA0UWTW98kndth/Jsw1HKj2ZL7tcu7XUIOGZX1NG +Fdtom/DzMNU+MeKNhJ7jitralj41E6Vf8PlwUHBHQRFXGU7Aj64GxJUTFy8bJZ91 +8rGOmaFvE7FBcf6IKshPECBV1/MUReXgRPTqh5Uykw7+U0b6LJ3/iyK5S9kJRaTe +pLiaWN0bfVKfjllDiIGknibVb63dDcY3fe0Dkhvld1927jyNxF1WW6LZZm6zNTfl +MrY= +-----END CERTIFICATE----- + DigiCert High Assurance EV Root CA ================================== -----BEGIN CERTIFICATE----- @@ -3864,3 +3949,40 @@ TZVHO8mvbaG0weyJ9rQPOLXiZNwlz6bb65pcmaHFCN795trV1lpFDMS3wrUU77QR/w4VtfX128a9 61qn8FYiqTxlVMYVqL2Gns2Dlmh6cYGJ4Qvh6hEbaAjMaZ7snkGeRDImeuKHCnE96+RapNLbxc3G 3mB/ufNPRJLvKrcYPqcZ2Qt9sTdBQrC6YB3y/gkRsPCHe6ed -----END CERTIFICATE----- + +COMODO RSA Certification Authority +================================== +-----BEGIN CERTIFICATE----- +MIIF2DCCA8CgAwIBAgIQTKr5yttjb+Af907YWwOGnTANBgkqhkiG9w0BAQwFADCB +hTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G +A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNV +BAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAwMTE5 +MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMCR0IxGzAZBgNVBAgT +EkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMR +Q09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNh +dGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCR +6FSS0gpWsawNJN3Fz0RndJkrN6N9I3AAcbxT38T6KhKPS38QVr2fcHK3YX/JSw8X +pz3jsARh7v8Rl8f0hj4K+j5c+ZPmNHrZFGvnnLOFoIJ6dq9xkNfs/Q36nGz637CC +9BR++b7Epi9Pf5l/tfxnQ3K9DADWietrLNPtj5gcFKt+5eNu/Nio5JIk2kNrYrhV +/erBvGy2i/MOjZrkm2xpmfh4SDBF1a3hDTxFYPwyllEnvGfDyi62a+pGx8cgoLEf +Zd5ICLqkTqnyg0Y3hOvozIFIQ2dOciqbXL1MGyiKXCJ7tKuY2e7gUYPDCUZObT6Z ++pUX2nwzV0E8jVHtC7ZcryxjGt9XyD+86V3Em69FmeKjWiS0uqlWPc9vqv9JWL7w +qP/0uK3pN/u6uPQLOvnoQ0IeidiEyxPx2bvhiWC4jChWrBQdnArncevPDt09qZah +SL0896+1DSJMwBGB7FY79tOi4lu3sgQiUpWAk2nojkxl8ZEDLXB0AuqLZxUpaVIC +u9ffUGpVRr+goyhhf3DQw6KqLCGqR84onAZFdr+CGCe01a60y1Dma/RMhnEw6abf +Fobg2P9A3fvQQoh/ozM6LlweQRGBY84YcWsr7KaKtzFcOmpH4MN5WdYgGq/yapiq +crxXStJLnbsQ/LBMQeXtHT1eKJ2czL+zUdqnR+WEUwIDAQABo0IwQDAdBgNVHQ4E +FgQUu69+Aj36pvE8hI6t7jiY7NkyMtQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB +/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAArx1UaEt65Ru2yyTUEUAJNMnMvl +wFTPoCWOAvn9sKIN9SCYPBMtrFaisNZ+EZLpLrqeLppysb0ZRGxhNaKatBYSaVqM +4dc+pBroLwP0rmEdEBsqpIt6xf4FpuHA1sj+nq6PK7o9mfjYcwlYRm6mnPTXJ9OV +2jeDchzTc+CiR5kDOF3VSXkAKRzH7JsgHAckaVd4sjn8OoSgtZx8jb8uk2Intzna +FxiuvTwJaP+EmzzV1gsD41eeFPfR60/IvYcjt7ZJQ3mFXLrrkguhxuhoqEwWsRqZ +CuhTLJK7oQkYdQxlqHvLI7cawiiFwxv/0Cti76R7CZGYZ4wUAc1oBmpjIXUDgIiK +boHGhfKppC3n9KUkEEeDys30jXlYsQab5xoq2Z0B15R97QNKyvDb6KkBPvVWmcke +jkk9u+UJueBPSZI9FoJAzMxZxuY67RIuaTxslbH9qh17f4a+Hg4yRvv7E491f0yL +S0Zj/gA0QHDBw7mh3aZw4gSzQbzpgJHqZJx64SIDqZxubw5lT2yHh17zbqD5daWb +QOhTsiedSrnAdyGN/4fy3ryM7xfft0kL0fJuMAsaDk527RH89elWsn2/x20Kk4yl +0MC2Hb46TpSi125sC8KKfPog88Tk5c0NqMuRkrF8hey1FGlmDoLnzc7ILaZRfyHB +NVOFBkpdn627G190 +-----END CERTIFICATE----- diff --git a/lib/support/gateway_support.rb b/lib/support/gateway_support.rb index ef649e59adf..b3bb28e54cf 100644 --- a/lib/support/gateway_support.rb +++ b/lib/support/gateway_support.rb @@ -2,7 +2,6 @@ require 'active_support' require 'active_merchant' - class GatewaySupport #:nodoc: ACTIONS = [:purchase, :authorize, :capture, :void, :credit, :recurring] @@ -15,9 +14,9 @@ def initialize filename = File.basename(f, '.rb') gateway_name = filename + '_gateway' begin - gateway_class = ('ActiveMerchant::Billing::' + gateway_name.camelize).constantize + ('ActiveMerchant::Billing::' + gateway_name.camelize).constantize rescue NameError - puts "Could not load gateway " + gateway_name.camelize + " from " + f + "." + puts 'Could not load gateway ' + gateway_name.camelize + ' from ' + f + '.' end end @gateways = Gateway.implementations.sort_by(&:name) @@ -25,20 +24,20 @@ def initialize end def each_gateway - @gateways.each{|g| yield g } + @gateways.each { |g| yield g } end def features width = 15 - print "Name".center(width + 20) - ACTIONS.each{|f| print "#{f.to_s.capitalize.center(width)}" } + print 'Name'.center(width + 20) + ACTIONS.each { |f| print f.to_s.capitalize.center(width) } puts each_gateway do |g| - print "#{g.display_name.ljust(width + 20)}" + print g.display_name.ljust(width + 20) ACTIONS.each do |f| - print "#{(g.instance_methods.include?(f.to_s) ? "Y" : "N").center(width)}" + print((g.instance_methods.include?(f.to_s) ? 'Y' : 'N').center(width)) end puts end @@ -68,4 +67,3 @@ def to_s end end end - diff --git a/lib/support/ssl_verify.rb b/lib/support/ssl_verify.rb index 1ba28878a72..5570e7fde47 100644 --- a/lib/support/ssl_verify.rb +++ b/lib/support/ssl_verify.rb @@ -23,16 +23,16 @@ def test_gateways end uri = URI.parse(g.live_url) - result,message = ssl_verify_peer?(uri) + result, message = ssl_verify_peer?(uri) case result when :success - print "." + print '.' success << g when :fail - print "F" + print 'F' failed << {:gateway => g, :message => message} when :error - print "E" + print 'E' errored << {:gateway => g, :message => message} end end @@ -60,13 +60,12 @@ def test_gateways puts d.name end end - end def try_host(http, path) http.get(path) rescue Net::HTTPBadResponse, EOFError, SocketError - http.post(path, "") + http.post(path, '') end def ssl_verify_peer?(uri) @@ -78,7 +77,7 @@ def ssl_verify_peer?(uri) http.read_timeout = 60 if uri.path.blank? - try_host(http, "/") + try_host(http, '/') else try_host(http, uri.path) end diff --git a/lib/support/ssl_version.rb b/lib/support/ssl_version.rb new file mode 100644 index 00000000000..ed7c716c9c0 --- /dev/null +++ b/lib/support/ssl_version.rb @@ -0,0 +1,87 @@ +require 'active_merchant' +require 'support/gateway_support' + +class SSLVersion + attr_accessor :success, :failed, :missing, :errored + + def initialize + @gateways = GatewaySupport.new.gateways + @success, @failed, @missing, @errored = [], [], [], [] + end + + def test_gateways(min_version = :TLS1_1) + raise 'Requires Ruby 2.5 or better' unless Net::HTTP.instance_methods.include?(:min_version=) + + puts "Verifying #{@gateways.count} gateways for SSL min_version=#{min_version}\n\n" + + @gateways.each do |g| + unless g.live_url + missing << g unless g.abstract_class + next + end + + uri = URI.parse(g.live_url) + result, message = test_min_version(uri, min_version) + + case result + when :success + print '.' + success << g + when :fail + print 'F' + failed << {:gateway => g, :message => message} + when :error + print 'E' + errored << {:gateway => g, :message => message} + end + end + + print_summary + end + + def print_summary + puts "\n\nSucceeded gateways (#{success.length})" + + puts "\n\nFailed Gateways (#{failed.length}):" + failed.each do |f| + puts "#{f[:gateway].name} - #{f[:message]}" + end + + puts "\n\nError Gateways (#{errored.length}):" + errored.each do |e| + puts "#{e[:gateway].name} - #{e[:message]}" + end + + if missing.length > 0 + puts "\n\nGateways missing live_url (#{missing.length}):" + missing.each do |m| + puts m.name + end + end + end + + private + + def test_min_version(uri, min_version) + http = Net::HTTP.new(uri.host, uri.port) + http.use_ssl = true + http.verify_mode = OpenSSL::SSL::VERIFY_NONE # don't care about certificate validity, just protocol version + http.min_version = min_version + http.open_timeout = 10 + http.read_timeout = 10 + + http.post('/', '') + + return :success + rescue Net::HTTPBadResponse + return :success # version negotiation succeeded + rescue OpenSSL::SSL::SSLError => ex + return :fail, ex.inspect + rescue Interrupt => ex + print_summary + raise ex + rescue StandardError => ex + return :error, ex.inspect + end + +end diff --git a/script/generate b/script/generate index 2988763f103..6312f82aa0c 100755 --- a/script/generate +++ b/script/generate @@ -1,15 +1,15 @@ #!/usr/bin/env ruby -require "rubygems" -require "thor" +require 'rubygems' +require 'thor' -require File.expand_path("../../generators/active_merchant_generator", __FILE__) +require File.expand_path('../../generators/active_merchant_generator', __FILE__) -Dir[File.expand_path("../..", __FILE__) + "/generators/*/*.rb"].each do |generator| +Dir[File.expand_path('../..', __FILE__) + '/generators/*/*.rb'].each do |generator| require generator end class Generate < Thor - register(GatewayGenerator, "gateway", "gateway NAME", "Generates a new gateway.") + register(GatewayGenerator, 'gateway', 'gateway NAME', 'Generates a new gateway.') end Generate.start diff --git a/test/comm_stub.rb b/test/comm_stub.rb index 2d4c95013b4..9293ef77955 100644 --- a/test/comm_stub.rb +++ b/test/comm_stub.rb @@ -19,7 +19,7 @@ def respond_with(*responses) singleton_class = (class << @gateway; self; end) singleton_class.send(:undef_method, @method_to_stub) singleton_class.send(:define_method, @method_to_stub) do |*args| - check.call(*args) if check + check&.call(*args) (responses.size == 1 ? responses.last : responses.shift) end @action.call diff --git a/test/fixtures.yml b/test/fixtures.yml index df749af71fd..be2d8930f18 100644 --- a/test/fixtures.yml +++ b/test/fixtures.yml @@ -11,6 +11,11 @@ # Paste any required PEM certificates after the pem key. # +adyen: + username: '' + password: '' + merchant_account: '' + allied_wallet: site_id: site_id merchant_id: merchant_id @@ -47,11 +52,6 @@ barclaycard_smartpay: merchant: merchant password: password -barclays_epdq: - login: test - password: test - client_id: 1234 - barclays_epdq_extra_plus: login: merchant number user: username @@ -67,6 +67,7 @@ beanstream: password: password secure_profile_api_key: API Access Passcode recurring_api_key: API Access Passcode + api_key: API KEY beanstream_interac: login: merchant id @@ -122,6 +123,12 @@ cams: username: testintegrationc password: password9 +# Working credentials, no need to replace +card_connect: + merchant_id: "496160873888" + username: testing + password: testing123 + #Username/Password given in sign up email. Not MMS credentials card_save: login: merchant_id @@ -135,6 +142,12 @@ card_stream: cardknox: api_key: ActiveMerchant_Test +# Working credentials, no need to replace +cardprocess: + user_id: 8a8294174e735d0c014e78beb6c5154f + password: cTZjAm9c87 + entity_id: 8a8294174e735d0c014e78beb6b9154b + # Cashnet doesn't provide public testing data cashnet: merchant: 'X' @@ -196,7 +209,7 @@ commercegate: card_number: "XXXXXXXXXXXXXXXX" conekta: - key: key_eYvWV7gSDkNYXsmr + key: key_6FTbuwqhYs6zvyyeL3PySg # Working credentials, no need to replace creditcall: @@ -207,6 +220,11 @@ credorax: merchant_id: 'merchant_id' cipher_key: 'cipher_key' +ct_payment: + api_key: SOMECREDENTIAL + company_number: '12345' + merchant_number: '12345678' + # Culqi does not provide public testing data culqi: merchant_id: MERCHANT @@ -230,17 +248,27 @@ dibs: merchant_id: SOMECREDENTIAL secret_key: NOPUBLICCREDENTIAL +# Working credentials, no need to replace +digitzs: + app_key: tcwtTux8SPZYO44Gf0UHZH74Z1HSutqCxmIV2PFj2jRc9Poroh3Z3R1BBQNRQ98Q + api_key: 0HhRdOU2AsWVEu3gRIKi2UpMMmj8Fj48qggBYTo4 + direc_pay: login: 200904281000001 +# Working credentials, no need to replace +ebanx: + integration_key: 1231000 + efsnet: login: X password: Y +# Provided for url update test elavon: - login: LOGIN - password: PASSWORD - user: USER (often the same as LOGIN) + login: "000127" + user: ssltest + password: "IERAOBEE5V0D6Q3Q6R51TG89XAIVGEQ3LGLKMKCKCVQBGGGAU7FN627GPA54P5HR" element: account_id: "1013963" @@ -309,6 +337,12 @@ firstdata_e4: login: SD8821-67 password: T6bxSywbcccbJ19eDXNIGaCDOBg1W7T8 +firstdata_e4_v27: + login: ALOGIN + password: APASSWORD + key_id: ANINTEGER + hmac_key: AMAGICALKEY + flo2cash: username: SOMECREDENTIAL password: ANOTHERCREDENTIAL @@ -332,9 +366,9 @@ garanti: password: "123qweASD" global_collect: - merchant_id: 1428 - api_key_id: 96f16a41890565d0 - secret_api_key: g/VQ432G02bFpwg/6EY7uiPRSZxKMbQ87Kal716XORA= + merchant_id: 2196 + api_key_id: c91d6752cbbf9cf1 + secret_api_key: xHjQr5gL9Wcihkqoj4w/UQugdSCNXM2oUQHG5C82jy4= global_transport: global_user_name: "USERNAME" @@ -354,15 +388,6 @@ iats_payments: password: TEST88 region: na -# login: merchant number -# password: password for the PEM secret key -# pem: public certificate and PEM secret key -ideal_rabobank: - login: LOGIN - password: PASSWORD - pem: | - PASTE YOUR PEM FILE HERE - inspire: login: demo password: password @@ -385,9 +410,17 @@ itransact: password: API_ACCESS_KEY gateway_id: GATEWAY_ID +# Working credentials, no need to replace +iveri: + cert_id: CB69E68D-C7E7-46B9-9B7A-025DCABAD6EF + app_id: d10a603d-4ade-405b-93f1-826dfc0181e8 + jetpay: login: TESTTERMINAL +jetpay_v2: + login: TESTMCC3136X + komoju: login: sk_f1dd75ce3d5cad477eac0c827c1cac8eaa51ede3 @@ -415,6 +448,10 @@ maxipago: login: "100" password: "21g8u6gh6szw1gywfs165vui" +# Working credentials, no need to replace +mercado_pago: + access_token: "TEST-8527269031909288-071213-0fc96cb7cd3633189bfbe29f63722700__LB_LA__-263489584" + # Working test credentials, no need to replace merchant_esolutions: login: "94100008043900000004" @@ -474,9 +511,6 @@ modern_payments: login: login password: password -mollie_ideal: - api_key: 'test_8isBjQoJXJoiXRSzjhwKPO1Bo9AkVA' - # Working credentials, no need to replace monei: sender_id: 8a829417488d34c401489a5cd1350977 @@ -486,7 +520,7 @@ monei: # Working credentials, no need to replace moneris: - login: store1 + login: store3 password: yesguy moneris_us: @@ -497,6 +531,10 @@ money_movers: login: demo password: password +mundipagg: + api_key: api_key + gateway_id: gateway_id + # Working credentials, no need to replace nab_transact: login: ABC0001 @@ -623,8 +661,8 @@ paybox_direct: # Working credentials, no need to replace payeezy: - apikey: oKB61AAxbN3xwC6gVAH3dp58FmioHSAT - apisecret: 36ef1fc3b908b7a79ad2c29de931d2ccff26fcec35602c709a9e34318e936683 + apikey: UyDMTXx6TD9WErF6ynw7xeEfCAn8fcGs + apisecret: 2a4974e242c91cab7f38910938f2a5db79e89756b084bbf7cab7849b50a9930f token: fdoa-a480ce8951daa73262734cf102641994c1e55e7cdf4c02b6 payex: @@ -634,9 +672,9 @@ payex: # Working credentials, no need to replace payflow: - login: spreedly - password: 'ibB4Z8=d;G' - partner: PayPal + login: 'spreedlyIntegrations' + password: 'L9DjqEKjXCkU' + partner: 'PayPal' payflow_uk: login: LOGIN @@ -647,6 +685,10 @@ payment_express: login: LOGIN password: PASSWORD +paymentez: + application_code: APPCODE + app_key: APPKEY + paymill: private_key: a9580be4a7b9d0151a3da88c6c935ce0 public_key: 57313835619696ac361dc591bc973626 @@ -725,6 +767,10 @@ plugnpay: login: LOGIN password: PASSWORD +# Working credentials, no need to replace +pro_pay: + cert_str: "5ab9cddef2e4911b77e0c4ffb70f03" + # Working credentials, no need to replace psigate: login: teststore @@ -825,9 +871,102 @@ quickpay_with_api_key: version: 7 qvalent: - username: TEST - password: TEST - merchant: TEST + username: "QRSL" + password: "QRSLTEST" + merchant: 24436057 + pem_password: "Ceic4s4ig" + pem: | + Bag Attributes + localKeyID: 01 00 00 00 + friendlyName: CCAPI Client Certificate + Key Attributes + X509v3 Key Usage: 10 + -----BEGIN RSA PRIVATE KEY----- + MIIEpAIBAAKCAQEAtgPNEzLEFAm2CXCiaJeEFQxzkxXHn+Lyf65FjTDIOMknXnmw + gtoPTrFHtDVLJqWHaccLg9/lMKHivW1iGPTeZj4Uke07EcmIaDQD3Gq33gukDbgx + d5QDN+mEPRs0TF6FHlKKELKGIZdw4BlM+Jg7hebwZnBC/g9cetmB3ny99g0e5ANk + pPESguo+HTFk5vwHkLjMtDB+0zM5y6AyU6z+PaCDr3Q7+vcR50kQLNxpSWH1Il1g + BewIHAroN4lJjPvKLnDWvK5SsxW9XB14gLAyQg6qCHDYOdTsdiG6BFG1eijT+3W7 + iXm8uTDiXSj+PiADEeKvnbEsWqXu+DvUsR/m8wIDAQABAoIBADtC/ZBUpRbJGqX0 + MEzRmEWqKi8nljlukPoVabvQuEAU7maKRHg2O2mpuujnuTI6Dt7X2d30FhFBhCuc + 46WwhIDRkaz5ipP+BBW5adBoRrlbHO0CnciLPokD1PR4WQzMcZcv1JgfKCDjx/KP + CkqedjLgwED6KDXEFp5BF1GzV742dfux0Bgq+5kzLp0uAe0+ADxGll1Fx1wWbP/e + 4XSTWz4P1q3fmGAJB7fgXcfdp+Yri1x0RNDjBUa6YsR5fFVZBXcFEmPcRGbcsO3J + ApJTrskt4H0rQafcx/LmUj3pBVsl/tcyMBHHGHUb0N5pKypf2X+79IYhV+b9K9Ll + 5EHVV+ECgYEA8TTci5PsysRvzN5HIgpfsd3ZK/JrTkJ2z3Xx2HFL9XU8EAx9gO5h + Qa7CnJY+myoes+x90I7uKqfJdB1JDq2Bek6Jfj8stVd/YTtrOMt7WhHc6OW2S+qY + TpvtdeoVcJ2rKGFyo5/mj0aO+Hg1i6wxsIhDPKvSEqSqUrbjmLi5AfkCgYEAwS2V + IVzmMZIaRg0FxRccWl/XgpK9JNVjNr4PRiSkjsbFktVNLkbBcFOvrbmPPkBuHW8t + XDK6goRcNraxkkzB81mx0glW/zHfEQS4GWuQQEqIWwBfC9QEvC+AlGLaNhQYMleC + omLzTDTkBPtQSc72H0ov8TpowgeyM1+U2uozq0sCgYEAm+Szag64KzEcpQdAaDLW + OIoO04WBbvor+dfb8C0Bj+ouYJ0B/HOVLjN6GmRMoFJvt4/wnPvT2IPLAx3uWusu + 1NKvsIW6KpYbgMc7fGCfH86NvYTB9nzv5VaH+f7JzphIx/d7dV9iT1WmD9b5nIU1 + NEhNVIgkZOJCJuWHYex5vlkCgYAF4uqxapBFIGuWiN0NJWgixNrfSrNixPHSADac + 747oHtx0XfWNHHDWiGZJB+d6gSIZ2YJrVcxjH79jl2uPxrD+RlRpzwkMm6ttbFRj + yehKXTsMctVymdJPHa9wVhbKIRCfsBT198fsIYx1LmdC6ICNcYhGdH4us2dVs2ro + xMwwQwKBgQDgNA9bGhiajsOI//M9ndH8KZCGdOoYM+6JBurHKX2fF8INRX+sxWix + DbUr9rQXkDrX1CY5RNs9kZpNxLJpOSHOpYlIytnGghYTrU1nzXoKLVopkO9Oz1A6 + WzrOd297XdEoyEbAeCgcLr2WtjMiFHonesjeWIgbqXSKZ+W1oek0vQ== + -----END RSA PRIVATE KEY----- + Bag Attributes + localKeyID: 01 00 00 00 + friendlyName: CCAPI Client Certificate + subject=/CN=Returned &#38; Services League of Australia (Queensland Branch) - Support/OU=IT/O=Returned &#38; Services League of Australia (Queensland Branch)/ST=NSW/C=AU/EMAILADDRESS=pp_support@qvalent.com + issuer=/CN=eQvalent/OU=Operations/O=QValent Pty Ltd/L=Wallsend/ST=NSW/C=AU + -----BEGIN CERTIFICATE----- + MIIE0DCCA7igAwIBAgIEWLX2pzANBgkqhkiG9w0BAQUFADBwMQswCQYDVQQGEwJB + VTEMMAoGA1UECBMDTlNXMREwDwYDVQQHEwhXYWxsc2VuZDEYMBYGA1UEChMPUVZh + bGVudCBQdHkgTHRkMRMwEQYDVQQLEwpPcGVyYXRpb25zMREwDwYDVQQDEwhlUXZh + bGVudDAeFw0xNzAyMjgyMjE2MDdaFw0xOTAyMjgyMjE2MDdaMIHtMSUwIwYJKoZI + hvcNAQkBFhZwcF9zdXBwb3J0QHF2YWxlbnQuY29tMQswCQYDVQQGEwJBVTEMMAoG + A1UECAwDTlNXMUgwRgYDVQQKDD9SZXR1cm5lZCAmIzM4OyBTZXJ2aWNlcyBMZWFn + dWUgb2YgQXVzdHJhbGlhIChRdWVlbnNsYW5kIEJyYW5jaCkxCzAJBgNVBAsMAklU + MVIwUAYDVQQDDElSZXR1cm5lZCAmIzM4OyBTZXJ2aWNlcyBMZWFndWUgb2YgQXVz + dHJhbGlhIChRdWVlbnNsYW5kIEJyYW5jaCkgLSBTdXBwb3J0MIIBIjANBgkqhkiG + 9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtgPNEzLEFAm2CXCiaJeEFQxzkxXHn+Lyf65F + jTDIOMknXnmwgtoPTrFHtDVLJqWHaccLg9/lMKHivW1iGPTeZj4Uke07EcmIaDQD + 3Gq33gukDbgxd5QDN+mEPRs0TF6FHlKKELKGIZdw4BlM+Jg7hebwZnBC/g9cetmB + 3ny99g0e5ANkpPESguo+HTFk5vwHkLjMtDB+0zM5y6AyU6z+PaCDr3Q7+vcR50kQ + LNxpSWH1Il1gBewIHAroN4lJjPvKLnDWvK5SsxW9XB14gLAyQg6qCHDYOdTsdiG6 + BFG1eijT+3W7iXm8uTDiXSj+PiADEeKvnbEsWqXu+DvUsR/m8wIDAQABo4HzMIHw + MBMGA1UdJQQMMAoGCCsGAQUFBwMCMB0GA1UdDgQWBBTujPN/magozRJ8XJxAVYPw + v5/HsDCBqQYDVR0jBIGhMIGegBQ2QKUf9O24xKZrWTyUqRmZeq04IqF0pHIwcDEL + MAkGA1UEBhMCQVUxDDAKBgNVBAgTA05TVzERMA8GA1UEBxMIV2FsbHNlbmQxGDAW + BgNVBAoTD1FWYWxlbnQgUHR5IEx0ZDETMBEGA1UECxMKT3BlcmF0aW9uczERMA8G + A1UEAxMIZVF2YWxlbnSCEG49SZXSVViNQE7XcOvVjwYwDgYDVR0PAQH/BAQDAgTw + MA0GCSqGSIb3DQEBBQUAA4IBAQCQwdv8D4B5sRnA9/ppDfwlix6omzh/SdA3SI4m + BNcImoqzBEq1OokdWKDkRQXlP6822aJn8fzDMV1/YsmomC4fT0wdag0DvBEvRlhy + roQRFjQai6CKRUgoH/p0q4EwxKLOa/H0kix+cn6Nszl07wu6YtHzvISXf4MC72au + /xTf/qwXI1uXnQghb4sFM9/ubYlsNEFiNHt7CHBK7ivhFGcT7eI9rmSOTMKsZfmV + pALJ58Ynz08xLYRMq54FxzwhN3CZ7AWRA+9JpzJacJ6lzHX9Y4FAjzRzoqn5h/IN + dgMIW+HoTgCe4+M1aDx2A0SKJCSK9tYZCYSsPMi9JXdLDU+k + -----END CERTIFICATE----- + Bag Attributes + localKeyID: 02 00 00 00 + subject=/CN=eQvalent/OU=Operations/O=QValent Pty Ltd/L=Wallsend/ST=NSW/C=AU + issuer=/CN=eQvalent/OU=Operations/O=QValent Pty Ltd/L=Wallsend/ST=NSW/C=AU + -----BEGIN CERTIFICATE----- + MIIDuzCCAqOgAwIBAgIQbj1JldJVWI1ATtdw69WPBjANBgkqhkiG9w0BAQUFADBw + MQswCQYDVQQGEwJBVTEMMAoGA1UECBMDTlNXMREwDwYDVQQHEwhXYWxsc2VuZDEY + MBYGA1UEChMPUVZhbGVudCBQdHkgTHRkMRMwEQYDVQQLEwpPcGVyYXRpb25zMREw + DwYDVQQDEwhlUXZhbGVudDAeFw0xMDA0MDcwNTUyMThaFw0zMDA0MDcwNjAyMTda + MHAxCzAJBgNVBAYTAkFVMQwwCgYDVQQIEwNOU1cxETAPBgNVBAcTCFdhbGxzZW5k + MRgwFgYDVQQKEw9RVmFsZW50IFB0eSBMdGQxEzARBgNVBAsTCk9wZXJhdGlvbnMx + ETAPBgNVBAMTCGVRdmFsZW50MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC + AQEAxKuwonFlg53dyb0zFyS0JPUbxKmHwBDZcTT78eV4hs9TveOR34yT9xv+y7R1 + GbUdtXxidGaXW6lfkWvVnS1mkDbj84OY2FzRTHeKuNmkcPddQDUgE+gaOGV6GKW7 + v/s5jMt6pz075teLKvNO2Gs2alpPl4NYU5zJfa+AGFzqE1z7Zxbl9N/Sc6Y8ZbWI + IGWKJFeaTic8tE05hIGuWw1KfxbhH0QMKnTSzW5fJi4Pce3iIftkCTjIXdTg+El8 + 9b+Jn5VMk+bQZQiusPbPbHZTvAADX/WCUuzAlFqyyNtutJmUlD/TiEB12YYp9R6U + 1MGRvC9+c+sz2bBccW3c+Zm7cQIDAQABo1EwTzALBgNVHQ8EBAMCAYYwDwYDVR0T + AQH/BAUwAwEB/zAdBgNVHQ4EFgQUNkClH/TtuMSma1k8lKkZmXqtOCIwEAYJKwYB + BAGCNxUBBAMCAQAwDQYJKoZIhvcNAQEFBQADggEBAAJRMGZzxO3lcTXoFdmOpo8P + Ptf/agwrlGT8krwKcZt42YZ98VoIaCTI83kkACYlTlkTTNkDdHtAwF7ROteZmbfQ + 5ky0nqZTpdQ2IPfGXpxcMIrGqrSJ6GbLTxrm0kXDH6TgYeY1dVTHtJD9wEgWwdI9 + coRkKQVjK/QucPuVX0uoRppCz0rCiJfCQf2825BrcbaY4HyDHvNxRXKV9ECuYwrk + HYDy3bnYWVB2ekk8xOEiocjQI3T//V36ZfiGubKlUZ4xsSed410hkLtB6ttCyZB1 + RFjxWKtn9pXbM1PLmUXCkKQnSJSeD1K0NjV+g8KFChTEgmhnLogyF/7YYw/amfc= + -----END CERTIFICATE----- raven_pac_net: user: ernest @@ -839,64 +978,69 @@ realex: password: Y realex_mastercard: - number: + number: '5425230000004415' month: '6' year: '2020' verification_value: '123' + brand: 'master' realex_mastercard_coms_error: - number: + number: '5135020000005871' month: '6' year: '2020' verification_value: '123' + brand: 'master' realex_mastercard_declined: - number: + number: '5114610000004778' month: '6' year: '2020' verification_value: '123' + brand: 'master' realex_mastercard_referral_a: - number: + number: '5121220000006921' month: '6' year: '2020' verification_value: '123' + brand: 'master' realex_mastercard_referral_b: - number: + number: '5114630000009791' month: '6' year: '2020' verification_value: '123' + brand: 'master' # Realex doesn't provide public testing data # Fill in the card numbers with the Realex test # data. realex_visa: - number: + number: '4263970000005262' month: '6' year: '2020' verification_value: '123' realex_visa_coms_error: - number: + number: '4009830000001985' month: '6' year: '2020' verification_value: '123' realex_visa_declined: - number: + number: '4000120000001154' month: '6' year: '2020' verification_value: '123' realex_visa_referral_a: - number: + number: '4000160000004147' month: '6' year: '2020' verification_value: '123' realex_visa_referral_b: - number: + number: '4000130000001724' month: '6' year: '2020' verification_value: '123' @@ -923,12 +1067,21 @@ s5: login: 8a82941847c4d0780147cea1d1730dcc password: n3yNMBGK +# Working credentials, no need to replace +safe_charge: + client_login_id: 'SpreedlyTestTRX' + client_password: '5Jp5xKmgqY' + +safe_charge_three_ds: + client_login_id: 'SpreedlyManTestTRX' + client_password: 'iGx9DQQHQG' + sage: login: 214282982451 password: 'Z5W2S8J7X8T5' sage_pay: - login: LOGIN + login: spreedly sallie_mae: login: TEST0 @@ -975,16 +1128,6 @@ stripe: stripe_destination: stripe_user_id: "acct_17FRNfIPBJTitsen" -# Used only for remote tests that use EMV credit card mocks -stripe_emv_uk: - login: - fee_refund_login: - -# Used only for remote tests that use EMV credit card mocks -stripe_emv_us: - login: - fee_refund_login: - # Externally verified bank account for testing stripe_verified_bank_account: customer_id: "cus_7s22nNueP2Hjj6" @@ -1032,10 +1175,15 @@ transax: login: transaxdemo password: nelix123 +# Working credentials, no need to replace +trexle: + api_key: "J5RGMpDlFlTfv9mEFvNWYoqHufyukPP4" + # Working credentials, no need to replace trust_commerce: login: 'TestMerchant' password: 'password' + aggregator_id: 'abc123' # Working credentials, no need to replace usa_epay: @@ -1069,9 +1217,10 @@ viaklix: # test credentails visanet_peru: - access_key_id: "AKIAJPOQZ7BAXJZ5K35A" - secret_access_key: "Ur+U0pn1bkjRhPGz+G+OLNjqIi7OBlwkZ2eTHySG" - merchant_id: "101266802" + access_key_id: "AKIAJLJTVQYHO4P76YYA" + secret_access_key: "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" + merchant_id: "543025501" + ruc: '20341198217' webpay: login: "test_secret_eHn4TTgsGguBcW764a2KA8Yd" @@ -1100,8 +1249,12 @@ world_net: secret: 'sandboxEUR' world_pay_gateway: - login: LOGIN - password: PASSWORD + login: 'SPREEDLY' + password: 'KZ#P2aR+' + +world_pay_gateway_cft: + login: 'SPREEDLYCFT' + password: 'Xbf+6#pD' worldpay_online_payments: client_key: "T_C_b9f629e7-cea7-4edb-8206-24bbe351d699" diff --git a/test/remote/gateways/remote_adyen_test.rb b/test/remote/gateways/remote_adyen_test.rb new file mode 100644 index 00000000000..d9f2bfead67 --- /dev/null +++ b/test/remote/gateways/remote_adyen_test.rb @@ -0,0 +1,316 @@ +require 'test_helper' + +class RemoteAdyenTest < Test::Unit::TestCase + def setup + @gateway = AdyenGateway.new(fixtures(:adyen)) + + @amount = 100 + + @credit_card = credit_card('4111111111111111', + :month => 10, + :year => 2020, + :first_name => 'John', + :last_name => 'Smith', + :verification_value => '737', + :brand => 'visa' + ) + + @declined_card = credit_card('4000300011112220') + + @improperly_branded_maestro = credit_card( + '5500000000000004', + month: 8, + year: 2018, + first_name: 'John', + last_name: 'Smith', + verification_value: '737', + brand: 'mastercard' + ) + + @apple_pay_card = network_tokenization_credit_card('4111111111111111', + :payment_cryptogram => 'YwAAAAAABaYcCMX/OhNRQAAAAAA=', + :month => '08', + :year => '2018', + :source => :apple_pay, + :verification_value => nil + ) + + @google_pay_card = network_tokenization_credit_card('4111111111111111', + :payment_cryptogram => 'YwAAAAAABaYcCMX/OhNRQAAAAAA=', + :month => '08', + :year => '2018', + :source => :google_pay, + :verification_value => nil + ) + + @options = { + reference: '345123', + shopper_email: 'john.smith@test.com', + shopper_ip: '77.110.174.153', + shopper_reference: 'John Smith', + billing_address: address(), + order_id: '123', + recurring_processing_model: 'CardOnFile' + } + end + + def test_successful_authorize + response = @gateway.authorize(@amount, @credit_card, @options) + assert_success response + assert_equal 'Authorised', response.message + end + + def test_failed_authorize + response = @gateway.authorize(@amount, @declined_card, @options) + assert_failure response + assert_equal 'Refused', response.message + end + + def test_successful_purchase + response = @gateway.purchase(@amount, @credit_card, @options) + assert_success response + assert_equal '[capture-received]', response.message + end + + def test_successful_purchase_no_cvv + credit_card = @credit_card + credit_card.verification_value = nil + response = @gateway.purchase(@amount, credit_card, @options) + assert_success response + assert_equal '[capture-received]', response.message + end + + def test_successful_purchase_with_more_options + options = @options.merge!(fraudOffset: '1', installments: 2) + response = @gateway.purchase(@amount, @credit_card, options) + assert_success response + assert_equal '[capture-received]', response.message + end + + def test_successful_purchase_with_apple_pay + response = @gateway.purchase(@amount, @apple_pay_card, @options) + assert_success response + assert_equal '[capture-received]', response.message + end + + def test_succesful_purchase_with_brand_override + response = @gateway.purchase(@amount, @improperly_branded_maestro, @options.merge({overwrite_brand: true, selected_brand: 'maestro'})) + assert_success response + assert_equal '[capture-received]', response.message + end + + def test_successful_purchase_with_google_pay + response = @gateway.purchase(@amount, @google_pay_card, @options) + assert_success response + assert_equal '[capture-received]', response.message + end + + def test_failed_purchase + response = @gateway.purchase(@amount, @declined_card, @options) + assert_failure response + assert_equal 'Refused', response.message + end + + def test_successful_authorize_and_capture + auth = @gateway.authorize(@amount, @credit_card, @options) + assert_success auth + + assert capture = @gateway.capture(@amount, auth.authorization) + assert_success capture + assert_equal '[capture-received]', capture.message + end + + def test_partial_capture + auth = @gateway.authorize(@amount, @credit_card, @options) + assert_success auth + + assert capture = @gateway.capture(@amount-1, auth.authorization) + assert_success capture + end + + def test_failed_capture + response = @gateway.capture(@amount, '') + assert_failure response + assert_equal 'Original pspReference required for this operation', response.message + end + + def test_successful_refund + purchase = @gateway.purchase(@amount, @credit_card, @options) + assert_success purchase + + assert refund = @gateway.refund(@amount, purchase.authorization) + assert_success refund + assert_equal '[refund-received]', refund.message + end + + def test_partial_refund + purchase = @gateway.purchase(@amount, @credit_card, @options) + assert_success purchase + + assert refund = @gateway.refund(@amount-1, purchase.authorization) + assert_success refund + end + + def test_failed_refund + response = @gateway.refund(@amount, '') + assert_failure response + assert_equal 'Original pspReference required for this operation', response.message + end + + def test_successful_void + auth = @gateway.authorize(@amount, @credit_card, @options) + assert_success auth + + assert void = @gateway.void(auth.authorization) + assert_success void + assert_equal '[cancel-received]', void.message + end + + def test_failed_void + response = @gateway.void('') + assert_failure response + assert_equal 'Original pspReference required for this operation', response.message + end + + def test_successful_store + assert response = @gateway.store(@credit_card, @options) + + assert_success response + assert !response.authorization.split('#')[2].nil? + assert_equal 'Authorised', response.message + end + + def test_failed_store + assert response = @gateway.store(@declined_card, @options) + + assert_failure response + assert_equal 'Refused', response.message + end + + def test_successful_purchase_using_stored_card + assert store_response = @gateway.store(@credit_card, @options) + assert_success store_response + + response = @gateway.purchase(@amount, store_response.authorization, @options) + assert_success response + assert_equal '[capture-received]', response.message + end + + def test_successful_authorize_using_stored_card + assert store_response = @gateway.store(@credit_card, @options) + assert_success store_response + + response = @gateway.authorize(@amount, store_response.authorization, @options) + assert_success response + assert_equal 'Authorised', response.message + end + + def test_successful_verify + response = @gateway.verify(@credit_card, @options) + assert_success response + assert_match 'Authorised', response.message + end + + def test_failed_verify + response = @gateway.verify(@declined_card, @options) + assert_failure response + assert_match 'Refused', response.message + end + + def test_invalid_login + gateway = AdyenGateway.new(username: '', password: '', merchant_account: '') + + response = gateway.purchase(@amount, @credit_card, @options) + assert_failure response + end + + def test_transcript_scrubbing + transcript = capture_transcript(@gateway) do + @gateway.purchase(@amount, @credit_card, @options) + end + transcript = @gateway.scrub(transcript) + + assert_scrubbed(@credit_card.number, transcript) + assert_scrubbed(@credit_card.verification_value, transcript) + assert_scrubbed(@gateway.options[:password], transcript) + end + + def test_transcript_scrubbing_network_tokenization_card + transcript = capture_transcript(@gateway) do + @gateway.purchase(@amount, @apple_pay_card, @options) + end + transcript = @gateway.scrub(transcript) + + assert_scrubbed(@apple_pay_card.number, transcript) + assert_scrubbed(@apple_pay_card.payment_cryptogram, transcript) + assert_scrubbed(@gateway.options[:password], transcript) + end + + def test_incorrect_number_for_purchase + card = credit_card('4242424242424241') + assert response = @gateway.purchase(@amount, card, @options) + assert_failure response + assert_match Gateway::STANDARD_ERROR_CODE[:incorrect_number], response.error_code + end + + def test_invalid_number_for_purchase + card = credit_card('-1') + assert response = @gateway.purchase(@amount, card, @options) + assert_failure response + assert_match Gateway::STANDARD_ERROR_CODE[:incorrect_number], response.error_code + end + + def test_invalid_expiry_month_for_purchase + card = credit_card('4242424242424242', month: 16) + assert response = @gateway.purchase(@amount, card, @options) + assert_failure response + assert_equal 'Expiry Date Invalid: Expiry month should be between 1 and 12 inclusive', response.message + end + + def test_invalid_expiry_year_for_purchase + card = credit_card('4242424242424242', year: 'xx') + assert response = @gateway.purchase(@amount, card, @options) + assert_failure response + assert response.message.include?('Expiry year should be a 4 digit number greater than') + end + + def test_invalid_cvc_for_purchase + card = credit_card('4242424242424242', verification_value: -1) + assert response = @gateway.purchase(@amount, card, @options) + assert_failure response + assert_match Gateway::STANDARD_ERROR_CODE[:invalid_cvc], response.error_code + end + + def test_missing_address_for_purchase + @options[:billing_address].delete(:address1) + @options[:billing_address].delete(:address2) + response = @gateway.authorize(@amount, @credit_card, @options) + assert_success response + end + + def test_missing_city_for_purchase + @options[:billing_address].delete(:city) + response = @gateway.authorize(@amount, @credit_card, @options) + assert_success response + end + + def test_missing_house_number_or_name_for_purchase + @options[:billing_address].delete(:address2) + response = @gateway.authorize(@amount, @credit_card, @options) + assert_success response + end + + def test_invalid_country_for_purchase + @options[:billing_address][:country] = '' + response = @gateway.authorize(@amount, @credit_card, @options) + assert_failure response + assert_match Gateway::STANDARD_ERROR_CODE[:incorrect_address], response.error_code + end + + def test_invalid_state_for_purchase + @options[:billing_address][:state] = '' + response = @gateway.authorize(@amount, @credit_card, @options) + assert_failure response + assert_match Gateway::STANDARD_ERROR_CODE[:incorrect_address], response.error_code + end +end diff --git a/test/remote/gateways/remote_allied_wallet_test.rb b/test/remote/gateways/remote_allied_wallet_test.rb index 427ef1792f5..8ab761e508b 100644 --- a/test/remote/gateways/remote_allied_wallet_test.rb +++ b/test/remote/gateways/remote_allied_wallet_test.rb @@ -6,7 +6,7 @@ def setup @amount = 100 @credit_card = credit_card - @declined_card = credit_card('4242424242424242', verification_value: "555") + @declined_card = credit_card('4242424242424242', verification_value: '555') @options = { billing_address: address, @@ -16,13 +16,13 @@ def setup def test_successful_purchase response = @gateway.purchase(@amount, @credit_card, @options) assert_success response - assert_equal "Succeeded", response.message + assert_equal 'Succeeded', response.message end def test_failed_purchase response = @gateway.purchase(@amount, @declined_card, @options) assert_failure response - assert_equal "The test operation was declined.", response.message + assert_equal 'The test operation was declined.', response.message end def test_failed_purchase_no_address @@ -34,32 +34,32 @@ def test_failed_purchase_no_address def test_successful_purchase_with_more_options response = @gateway.purchase(@amount, @credit_card, @options.merge( order_id: generate_unique_id, - ip: "127.0.0.1", - email: "jim_smith@example.com" + ip: '127.0.0.1', + email: 'jim_smith@example.com' )) assert_success response - assert_equal "Succeeded", response.message + assert_equal 'Succeeded', response.message end def test_successful_authorize_and_capture response = @gateway.authorize(@amount, @credit_card, @options) assert_success response - assert_equal "Succeeded", response.message + assert_equal 'Succeeded', response.message assert response.authorization capture = @gateway.capture(@amount, response.authorization) assert_success capture - assert_equal "Succeeded", capture.message + assert_equal 'Succeeded', capture.message end def test_failed_authorize response = @gateway.authorize(@amount, @declined_card, @options) assert_failure response - assert_equal "The test operation was declined.", response.message + assert_equal 'The test operation was declined.', response.message end def test_failed_capture - response = @gateway.capture(@amount, "") + response = @gateway.capture(@amount, '') assert_failure response assert_equal "'Authorize Transaction Id' should not be empty.", response.message end @@ -70,11 +70,11 @@ def test_successful_void void = @gateway.void(response.authorization) assert_success void - assert_equal "Succeeded", void.message + assert_equal 'Succeeded', void.message end def test_failed_void - response = @gateway.void("") + response = @gateway.void('') assert_failure response assert_equal "'Authorize Transaction Id' should not be empty.", response.message end @@ -85,11 +85,11 @@ def test_successful_refund refund = @gateway.refund(@amount, response.authorization) assert_success refund - assert_equal "Succeeded", refund.message + assert_equal 'Succeeded', refund.message end def test_failed_refund - response = @gateway.refund(@amount, "UnknownAuthorization") + response = @gateway.refund(@amount, 'UnknownAuthorization') assert_failure response assert_match(/An internal exception has occurred/, response.message) end @@ -103,7 +103,7 @@ def test_successful_verify def test_failed_verify response = @gateway.verify(@declined_card, @options) assert_failure response - assert_equal "The test operation was declined.", response.message + assert_equal 'The test operation was declined.', response.message end def test_transcript_scrubbing @@ -128,7 +128,7 @@ def test_nil_cvv_transcript_scrubbing end def test_empty_string_cvv_transcript_scrubbing - @credit_card.verification_value = "" + @credit_card.verification_value = '' transcript = capture_transcript(@gateway) do @gateway.purchase(@amount, @credit_card, @options) end @@ -138,7 +138,7 @@ def test_empty_string_cvv_transcript_scrubbing end def test_whitespace_string_cvv_transcript_scrubbing - @credit_card.verification_value = " " + @credit_card.verification_value = ' ' transcript = capture_transcript(@gateway) do @gateway.purchase(@amount, @credit_card, @options) end diff --git a/test/remote/gateways/remote_authorize_net_apple_pay_test.rb b/test/remote/gateways/remote_authorize_net_apple_pay_test.rb index 94c867b8009..cf430b4a975 100644 --- a/test/remote/gateways/remote_authorize_net_apple_pay_test.rb +++ b/test/remote/gateways/remote_authorize_net_apple_pay_test.rb @@ -60,7 +60,6 @@ def test_failed_apple_pay_purchase assert_equal 'processing_error', response.error_code end - private def apple_pay_payment_token(options = {}) @@ -78,9 +77,9 @@ def apple_pay_payment_token(options = {}) }, 'signature' => 'MIIDQgYJKoZIhvcNAQcCoIIDMzCCAy8CAQExCzAJBgUrDgMCGgUAMAsGCSqGSIb3DQEHAaCCAiswggInMIIBlKADAgECAhBcl+Pf3+U4pk13nVD9nwQQMAkGBSsOAwIdBQAwJzElMCMGA1UEAx4cAGMAaABtAGEAaQBAAHYAaQBzAGEALgBjAG8AbTAeFw0xNDAxMDEwNjAwMDBaFw0yNDAxMDEwNjAwMDBaMCcxJTAjBgNVBAMeHABjAGgAbQBhAGkAQAB2AGkAcwBhAC4AYwBvAG0wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANC8+kgtgmvWF1OzjgDNrjTEBRuo/5MKvlM146pAf7Gx41blE9w4fIXJAD7FfO7QKjIXYNt39rLyy7xDwb/5IkZM60TZ2iI1pj55Uc8fd4fzOpk3ftZaQGXNLYptG1d9V7IS82Oup9MMo1BPVrXTPHNcsM99EPUnPqdbeGc87m0rAgMBAAGjXDBaMFgGA1UdAQRRME+AEHZWPrWtJd7YZ431hCg7YFShKTAnMSUwIwYDVQQDHhwAYwBoAG0AYQBpAEAAdgBpAHMAYQAuAGMAbwBtghBcl+Pf3+U4pk13nVD9nwQQMAkGBSsOAwIdBQADgYEAbUKYCkuIKS9QQ2mFcMYREIm2l+Xg8/JXv+GBVQJkOKoscY4iNDFA/bQlogf9LLU84THwNRnsvV3Prv7RTY81gq0dtC8zYcAaAkCHII3yqMnJ4AOu6EOW9kJk232gSE7WlCtHbfLSKfuSgQX8KXQYuZLk2Rr63N8ApXsXwBL3cJ0xgeAwgd0CAQEwOzAnMSUwIwYDVQQDHhwAYwBoAG0AYQBpAEAAdgBpAHMAYQAuAGMAbwBtAhBcl+Pf3+U4pk13nVD9nwQQMAkGBSsOAwIaBQAwDQYJKoZIhvcNAQEBBQAEgYBaK3ElOstbH8WooseDABf+Jg/129JcIawm7c6Vxn7ZasNbAq3tAt8Pty+uQCgssXqZkLA7kz2GzMolNtv9wYmu9Ujwar1PHYS+B/oGnoz591wjagXWRz0nMo5y3O1KzX0d8CRHAVa88SrV1a5JIiRev3oStIqwv5xuZldag6Tr8w==' }, - payment_instrument_name: "SomeBank Points Card", - payment_network: "MasterCard", - transaction_identifier: "uniqueidentifier123" + payment_instrument_name: 'SomeBank Points Card', + payment_network: 'MasterCard', + transaction_identifier: 'uniqueidentifier123' }.update(options) ActiveMerchant::Billing::ApplePayPaymentToken.new(defaults[:payment_data], diff --git a/test/remote/gateways/remote_authorize_net_cim_test.rb b/test/remote/gateways/remote_authorize_net_cim_test.rb index 8ffd06d7996..124b81c7753 100644 --- a/test/remote/gateways/remote_authorize_net_cim_test.rb +++ b/test/remote/gateways/remote_authorize_net_cim_test.rb @@ -102,8 +102,8 @@ def test_successful_create_customer_profile_transaction_auth_only_and_then_captu assert_equal response.authorization, response.params['direct_response']['transaction_id'] assert_match %r{(?:(TESTMODE) )?This transaction has been approved.}, response.params['direct_response']['message'] assert response.params['direct_response']['approval_code'] =~ /\w{6}/ - assert_equal "auth_only", response.params['direct_response']['transaction_type'] - assert_equal "100.00", response.params['direct_response']['amount'] + assert_equal 'auth_only', response.params['direct_response']['transaction_type'] + assert_equal '100.00', response.params['direct_response']['amount'] assert_match %r{\d+}, response.params['direct_response']['transaction_id'] approval_code = response.params['direct_response']['approval_code'] @@ -125,8 +125,8 @@ def test_successful_create_customer_profile_transaction_auth_only_and_then_captu assert_equal response.authorization, response.params['direct_response']['transaction_id'] assert_match %r{(?:(TESTMODE) )?This transaction has been approved.}, response.params['direct_response']['message'] assert_equal approval_code, response.params['direct_response']['approval_code'] - assert_equal "capture_only", response.params['direct_response']['transaction_type'] - assert_equal "100.00", response.params['direct_response']['amount'] + assert_equal 'capture_only', response.params['direct_response']['transaction_type'] + assert_equal '100.00', response.params['direct_response']['amount'] end def test_successful_create_customer_profile_transaction_auth_capture_request @@ -157,8 +157,8 @@ def test_successful_create_customer_profile_transaction_auth_capture_request assert_equal response.authorization, response.params['direct_response']['transaction_id'] assert_match %r{(?:(TESTMODE) )?This transaction has been approved.}, response.params['direct_response']['message'] assert response.params['direct_response']['approval_code'] =~ /\w{6}/ - assert_equal "auth_capture", response.params['direct_response']['transaction_type'] - assert_equal "100.00", response.params['direct_response']['amount'] + assert_equal 'auth_capture', response.params['direct_response']['transaction_type'] + assert_equal '100.00', response.params['direct_response']['amount'] assert_equal response.params['direct_response']['invoice_number'], '1234' assert_equal response.params['direct_response']['order_description'], 'Test Order Description' assert_equal response.params['direct_response']['purchase_order_number'], '4321' @@ -185,7 +185,7 @@ def test_successful_create_customer_payment_profile_request end def test_successful_create_customer_payment_profile_request_with_bank_account - payment_profile = @options[:profile].delete(:payment_profiles) + @options[:profile].delete(:payment_profiles) assert response = @gateway.create_customer_profile(@options) @customer_profile_id = response.authorization @@ -254,7 +254,7 @@ def test_successful_get_customer_profile_with_multiple_payment_profiles assert response = @gateway.create_customer_profile(@options) @customer_profile_id = response.authorization - assert response = @gateway.get_customer_profile(:customer_profile_id => @customer_profile_id) + assert @gateway.get_customer_profile(:customer_profile_id => @customer_profile_id) assert response = @gateway.create_customer_payment_profile( :customer_profile_id => @customer_profile_id, @@ -391,7 +391,7 @@ def test_successful_update_customer_payment_profile_request ) # The value before updating - assert_equal "XXXX4242", response.params['payment_profile']['payment']['credit_card']['card_number'], "The card number should contain the last 4 digits of the card we passed in 4242" + assert_equal 'XXXX4242', response.params['payment_profile']['payment']['credit_card']['card_number'], 'The card number should contain the last 4 digits of the card we passed in 4242' # Update the payment profile assert response = @gateway.update_customer_payment_profile( @@ -414,7 +414,7 @@ def test_successful_update_customer_payment_profile_request ) # Show that the payment profile was updated - assert_equal "XXXX1234", response.params['payment_profile']['payment']['credit_card']['card_number'], "The card number should contain the last 4 digits of the card we passed in: 1234" + assert_equal 'XXXX1234', response.params['payment_profile']['payment']['credit_card']['card_number'], 'The card number should contain the last 4 digits of the card we passed in: 1234' # Show that fields that were left out of the update were cleared assert_nil response.params['payment_profile']['customer_type'] @@ -423,7 +423,7 @@ def test_successful_update_customer_payment_profile_request masked_credit_card = ActiveMerchant::Billing::CreditCard.new(:number => response.params['payment_profile']['payment']['credit_card']['card_number']) # Update only the billing address with a masked card and expiration date - assert response = @gateway.update_customer_payment_profile( + assert @gateway.update_customer_payment_profile( :customer_profile_id => @customer_profile_id, :payment_profile => { :customer_payment_profile_id => customer_payment_profile_id, @@ -441,7 +441,7 @@ def test_successful_update_customer_payment_profile_request ) # Show that the billing address on the payment profile was updated - assert_equal "Frank", response.params['payment_profile']['bill_to']['first_name'], "The billing address should contain the first name we passed in: Frank" + assert_equal 'Frank', response.params['payment_profile']['bill_to']['first_name'], 'The billing address should contain the first name we passed in: Frank' end def test_successful_update_customer_payment_profile_request_with_credit_card_last_four @@ -460,16 +460,16 @@ def test_successful_update_customer_payment_profile_request_with_credit_card_las ) # Card number last 4 digits is 4242 - assert_equal "XXXX4242", response.params['payment_profile']['payment']['credit_card']['card_number'], "The card number should contain the last 4 digits of the card we passed in 4242" + assert_equal 'XXXX4242', response.params['payment_profile']['payment']['credit_card']['card_number'], 'The card number should contain the last 4 digits of the card we passed in 4242' new_billing_address = response.params['payment_profile']['bill_to'] new_billing_address.update(:first_name => 'Frank', :last_name => 'Brown') # Initialize credit card with only last 4 digits as the number - last_four_credit_card = ActiveMerchant::Billing::CreditCard.new(:number => "4242") #Credit card with only last four digits + last_four_credit_card = ActiveMerchant::Billing::CreditCard.new(:number => '4242') # Credit card with only last four digits # Update only the billing address with a card with the last 4 digits and expiration date - assert response = @gateway.update_customer_payment_profile( + assert @gateway.update_customer_payment_profile( :customer_profile_id => @customer_profile_id, :payment_profile => { :customer_payment_profile_id => customer_payment_profile_id, @@ -487,7 +487,7 @@ def test_successful_update_customer_payment_profile_request_with_credit_card_las ) # Show that the billing address on the payment profile was updated - assert_equal "Frank", response.params['payment_profile']['bill_to']['first_name'], "The billing address should contain the first name we passed in: Frank" + assert_equal 'Frank', response.params['payment_profile']['bill_to']['first_name'], 'The billing address should contain the first name we passed in: Frank' end def test_successful_update_customer_shipping_address_request @@ -507,7 +507,7 @@ def test_successful_update_customer_shipping_address_request assert address = response.params['address'] # The value before updating - assert_equal "1234 Fake Street", address['address'] + assert_equal '1234 Fake Street', address['address'] # Update the address and remove the phone_number new_address = address.symbolize_keys.merge!( @@ -515,7 +515,7 @@ def test_successful_update_customer_shipping_address_request ) new_address.delete(:phone_number) - #Update the shipping address + # Update the shipping address assert response = @gateway.update_customer_shipping_address( :customer_profile_id => @customer_profile_id, :address => new_address @@ -531,7 +531,7 @@ def test_successful_update_customer_shipping_address_request ) # Show that the shipping address was updated - assert_equal "5678 Fake Street", response.params['address']['address'] + assert_equal '5678 Fake Street', response.params['address']['address'] # Show that fields that were left out of the update were cleared assert_nil response.params['address']['phone_number'] end @@ -575,7 +575,7 @@ def test_validate_customer_payment_profile_request_live_requires_billing_address assert response.test? assert_failure response - assert_equal "There is one or more missing or invalid required fields.", response.message + assert_equal 'There is one or more missing or invalid required fields.', response.message end def test_validate_customer_payment_profile_request_old_does_not_require_billing_address @@ -596,7 +596,7 @@ def test_validate_customer_payment_profile_request_old_does_not_require_billing_ assert response.test? assert_success response - assert_equal "Successful.", response.message + assert_equal 'Successful.', response.message end def test_should_create_duplicate_customer_profile_transactions_with_duplicate_window_alteration @@ -615,23 +615,23 @@ def test_should_create_duplicate_customer_profile_transactions_with_duplicate_wi :type => :auth_capture, :order => { :invoice_number => key.to_s, - :description => "Test Order Description #{key.to_s}", + :description => "Test Order Description #{key}", :purchase_order_number => key.to_s }, :amount => @amount }, - :extra_options => { "x_duplicate_window" => 1 } + :extra_options => { 'x_duplicate_window' => 1 } } assert response = @gateway.create_customer_profile_transaction(customer_profile_transaction) assert_success response - assert_equal "Successful.", response.message + assert_equal 'Successful.', response.message sleep(5) assert response = @gateway.create_customer_profile_transaction(customer_profile_transaction) assert_success response - assert_equal "Successful.", response.message + assert_equal 'Successful.', response.message assert_nil response.error_code end @@ -651,7 +651,7 @@ def test_should_not_create_duplicate_customer_profile_transactions_without_dupli :type => :auth_capture, :order => { :invoice_number => key.to_s, - :description => "Test Order Description #{key.to_s}", + :description => "Test Order Description #{key}", :purchase_order_number => key.to_s }, :amount => @amount @@ -660,14 +660,14 @@ def test_should_not_create_duplicate_customer_profile_transactions_without_dupli assert response = @gateway.create_customer_profile_transaction(customer_profile_transaction) assert_success response - assert_equal "Successful.", response.message + assert_equal 'Successful.', response.message sleep(5) assert response = @gateway.create_customer_profile_transaction(customer_profile_transaction) assert_failure response - assert_equal "A duplicate transaction has been submitted.", response.message - assert_equal "E00027", response.error_code + assert_equal 'A duplicate transaction has been submitted.', response.message + assert_equal 'E00027', response.error_code end def test_should_create_customer_profile_transaction_auth_capture_and_then_void_request @@ -766,7 +766,7 @@ def test_should_create_customer_profile_transaction_auth_only_and_then_prior_aut end def get_and_validate_customer_payment_profile_request_with_bank_account_response - payment_profile = @options[:profile].delete(:payment_profiles) + @options[:profile].delete(:payment_profiles) assert response = @gateway.create_customer_profile(@options) @customer_profile_id = response.authorization @@ -821,7 +821,7 @@ def get_and_validate_auth_capture_response :type => :auth_capture, :order => { :invoice_number => key.to_s, - :description => "Test Order Description #{key.to_s}", + :description => "Test Order Description #{key}", :purchase_order_number => key.to_s }, :amount => @amount @@ -833,10 +833,10 @@ def get_and_validate_auth_capture_response assert_equal response.authorization, response.params['direct_response']['transaction_id'] assert_match %r{(?:(TESTMODE) )?This transaction has been approved.}, response.params['direct_response']['message'] assert response.params['direct_response']['approval_code'] =~ /\w{6}/ - assert_equal "auth_capture", response.params['direct_response']['transaction_type'] - assert_equal "100.00", response.params['direct_response']['amount'] + assert_equal 'auth_capture', response.params['direct_response']['transaction_type'] + assert_equal '100.00', response.params['direct_response']['amount'] assert_equal response.params['direct_response']['invoice_number'], key.to_s - assert_equal response.params['direct_response']['order_description'], "Test Order Description #{key.to_s}" + assert_equal response.params['direct_response']['order_description'], "Test Order Description #{key}" assert_equal response.params['direct_response']['purchase_order_number'], key.to_s return response end @@ -850,28 +850,27 @@ def get_and_validate_auth_only_response assert response = @gateway.get_customer_profile(:customer_profile_id => @customer_profile_id) @customer_payment_profile_id = response.params['profile']['payment_profiles']['customer_payment_profile_id'] assert response = @gateway.create_customer_profile_transaction( - :transaction => { - :customer_profile_id => @customer_profile_id, - :customer_payment_profile_id => @customer_payment_profile_id, - :type => :auth_only, - :order => { + :transaction => { + :customer_profile_id => @customer_profile_id, + :customer_payment_profile_id => @customer_payment_profile_id, + :type => :auth_only, + :order => { :invoice_number => key.to_s, - :description => "Test Order Description #{key.to_s}", + :description => "Test Order Description #{key}", :purchase_order_number => key.to_s }, - :amount => @amount - } + :amount => @amount + } ) assert response.test? assert_success response assert_equal response.authorization, response.params['direct_response']['transaction_id'] assert response.params['direct_response']['approval_code'] =~ /\w{6}/ - assert_equal "auth_only", response.params['direct_response']['transaction_type'] - assert_equal "100.00", response.params['direct_response']['amount'] + assert_equal 'auth_only', response.params['direct_response']['transaction_type'] + assert_equal '100.00', response.params['direct_response']['amount'] return response end - end diff --git a/test/remote/gateways/remote_authorize_net_test.rb b/test/remote/gateways/remote_authorize_net_test.rb index 79921c148ca..2b239ad18bb 100644 --- a/test/remote/gateways/remote_authorize_net_test.rb +++ b/test/remote/gateways/remote_authorize_net_test.rb @@ -11,10 +11,41 @@ def setup @options = { order_id: '1', + email: 'anet@example.com', duplicate_window: 0, billing_address: address, description: 'Store Purchase' } + + @level_2_options = { + tax: { + amount: '100', + name: 'tax name', + description: 'tax description' + }, + duty: { + amount: '200', + name: 'duty name', + description: 'duty description' + }, + shipping: { + amount: '300', + name: 'shipping name', + description: 'shipping description', + }, + tax_exempt: 'false', + po_number: '123' + } + + @level_3_options = { + ship_from_address: { + zip: '27701', + country: 'US' + }, + summary_commodity_code: 'CODE' + } + + @level_2_and_3_options = @level_2_options.merge(@level_3_options) end def test_successful_purchase @@ -26,7 +57,7 @@ def test_successful_purchase end def test_successful_purchase_with_minimal_options - response = @gateway.purchase(@amount, @credit_card, duplicate_window: 0) + response = @gateway.purchase(@amount, @credit_card, duplicate_window: 0, email: 'anet@example.com', billing_address: address) assert_success response assert response.test? assert_equal 'This transaction has been approved', response.message @@ -34,7 +65,15 @@ def test_successful_purchase_with_minimal_options end def test_successful_purchase_with_email_customer - response = @gateway.purchase(@amount, @credit_card, duplicate_window: 0, email_customer: true) + response = @gateway.purchase(@amount, @credit_card, duplicate_window: 0, email_customer: true, email: 'anet@example.com', billing_address: address) + assert_success response + assert response.test? + assert_equal 'This transaction has been approved', response.message + assert response.authorization + end + + def test_successful_purchase_with_false_email_customer + response = @gateway.purchase(@amount, @credit_card, duplicate_window: 0, email_customer: false, email: 'anet@example.com', billing_address: address) assert_success response assert response.test? assert_equal 'This transaction has been approved', response.message @@ -42,7 +81,7 @@ def test_successful_purchase_with_email_customer end def test_successful_purchase_with_header_email_receipt - response = @gateway.purchase(@amount, @credit_card, duplicate_window: 0, header_email_receipt: "subject line") + response = @gateway.purchase(@amount, @credit_card, duplicate_window: 0, header_email_receipt: 'subject line', email: 'anet@example.com', billing_address: address) assert_success response assert response.test? assert_equal 'This transaction has been approved', response.message @@ -51,21 +90,44 @@ def test_successful_purchase_with_header_email_receipt def test_successful_purchase_with_line_items additional_options = { - email: "anet@example.com", + email: 'anet@example.com', line_items: [ { - item_id: "1", - name: "mug", - description: "coffee", - quantity: "100", - unit_price: "10" + item_id: '1', + name: 'mug', + description: 'coffee', + quantity: '100', + unit_price: '10' }, { - item_id: "2", - name: "vase", - description: "floral", - quantity: "200", - unit_price: "20" + item_id: '2', + name: 'vase', + description: 'floral', + quantity: '200', + unit_price: '20' + } + ] + } + response = @gateway.purchase(@amount, @credit_card, @options.merge(additional_options)) + assert_success response + assert response.test? + assert_equal 'This transaction has been approved', response.message + assert response.authorization + end + + def test_successful_purchase_with_level_3_line_item_data + additional_options = { + email: 'anet@example.com', + line_items: [ + { + item_id: '1', + name: 'mug', + description: 'coffee', + quantity: '100', + unit_price: '10', + unit_of_measure: 'yards', + total_amount: '1000', + product_code: 'coupon' } ] } @@ -76,6 +138,18 @@ def test_successful_purchase_with_line_items assert response.authorization end + def test_successful_purchase_with_level_2_and_3_data + response = @gateway.purchase(@amount, @credit_card, @options.merge(@level_2_and_3_options)) + assert_success response + assert_equal 'This transaction has been approved', response.message + end + + def test_successful_purchase_with_customer + response = @gateway.purchase(@amount, @credit_card, @options.merge(customer: 'abcd_123')) + assert_success response + assert_equal 'This transaction has been approved', response.message + end + def test_failed_purchase response = @gateway.purchase(@amount, @declined_card, @options) assert_failure response @@ -164,7 +238,7 @@ def test_successful_echeck_authorization end def test_failed_echeck_authorization - response = @gateway.authorize(@amount, check(routing_number: "121042883"), @options) + response = @gateway.authorize(@amount, check(routing_number: '121042883'), @options) assert_failure response assert_equal 'The ABA code is invalid', response.message assert response.authorization @@ -219,8 +293,8 @@ def test_successful_authorization_with_moto_retail_type def test_successful_verify response = @gateway.verify(@credit_card, @options) assert_success response - assert_equal "This transaction has been approved", response.message - assert_success response.responses.last, "The void should succeed" + assert_equal 'This transaction has been approved', response.message + assert_success response.responses.last, 'The void should succeed' end def test_failed_verify @@ -234,8 +308,8 @@ def test_successful_store assert response = @gateway.store(@credit_card) assert_success response assert response.authorization - assert_equal "Successful", response.message - assert_equal "1", response.params["message_code"] + assert_equal 'Successful', response.message + assert_equal '1', response.params['message_code'] end def test_successful_store_new_payment_profile @@ -244,12 +318,12 @@ def test_successful_store_new_payment_profile assert store.authorization new_card = credit_card('4424222222222222') - customer_profile_id, _, _ = store.authorization.split("#") + customer_profile_id, _, _ = store.authorization.split('#') assert response = @gateway.store(new_card, customer_profile_id: customer_profile_id) assert_success response - assert_equal "Successful", response.message - assert_equal "1", response.params["message_code"] + assert_equal 'Successful', response.message + assert_equal '1', response.params['message_code'] end def test_failed_store_new_payment_profile @@ -258,27 +332,37 @@ def test_failed_store_new_payment_profile assert store.authorization new_card = credit_card('141241') - customer_profile_id, _, _ = store.authorization.split("#") + customer_profile_id, _, _ = store.authorization.split('#') assert response = @gateway.store(new_card, customer_profile_id: customer_profile_id) assert_failure response - assert_equal "The field length is invalid for Card Number", response.message + assert_equal 'The field length is invalid for Card Number', response.message end def test_failed_store - assert response = @gateway.store(credit_card("141241")) + assert response = @gateway.store(credit_card('141241')) assert_failure response - assert_equal "The field length is invalid for Card Number", response.message - assert_equal "15", response.params["message_code"] + assert_equal 'The field length is invalid for Card Number', response.message + assert_equal '15', response.params['message_code'] end def test_successful_purchase_using_stored_card - response = @gateway.store(@credit_card) + response = @gateway.store(@credit_card, @options) assert_success response response = @gateway.purchase(@amount, response.authorization, @options) assert_success response - assert_equal "This transaction has been approved.", response.message + assert_equal 'This transaction has been approved.', response.message + end + + def test_successful_purchase_using_stored_card_with_delimiter + response = @gateway.store(@credit_card, @options.merge(delimiter: '|')) + assert_success response + + response = @gateway.purchase(@amount, response.authorization, @options.merge(delimiter: '|', description: 'description, with, commas')) + assert_success response + assert_equal 'This transaction has been approved.', response.message + assert_equal 'description, with, commas', response.params['order_description'] end def test_failed_purchase_using_stored_card @@ -287,40 +371,62 @@ def test_failed_purchase_using_stored_card response = @gateway.purchase(@amount, response.authorization, @options) assert_failure response - assert_equal "The credit card number is invalid.", response.message - assert_equal "incorrect_number", response.error_code - assert_equal "27", response.params["message_code"] - assert_equal "6", response.params["response_reason_code"] - assert_match %r{Address not verified}, response.avs_result["message"] + assert_equal 'The credit card number is invalid.', response.message + assert_equal 'incorrect_number', response.error_code + assert_equal '27', response.params['message_code'] + assert_equal '6', response.params['response_reason_code'] + assert_match %r{Address not verified}, response.avs_result['message'] end def test_successful_purchase_using_stored_card_new_payment_profile - assert store = @gateway.store(@credit_card) + assert store = @gateway.store(@credit_card, @options) assert_success store assert store.authorization new_card = credit_card('4007000000027') - customer_profile_id, _, _ = store.authorization.split("#") + customer_profile_id, _, _ = store.authorization.split('#') - assert response = @gateway.store(new_card, customer_profile_id: customer_profile_id) + assert response = @gateway.store(new_card, customer_profile_id: customer_profile_id, email: 'anet@example.com', billing_address: address) assert_success response response = @gateway.purchase(@amount, response.authorization, @options) assert_success response - assert_equal "This transaction has been approved.", response.message + assert_equal 'This transaction has been approved.', response.message + end + + def test_successful_purchase_with_stored_card_and_level_2_and_3_data + store_response = @gateway.store(@credit_card, @options) + assert_success store_response + + response = @gateway.purchase(@amount, store_response.authorization, @options.merge(@level_2_and_3_options)) + assert_success response + assert_equal 'This transaction has been approved.', response.message end def test_successful_authorize_and_capture_using_stored_card - store = @gateway.store(@credit_card) + store = @gateway.store(@credit_card, @options) assert_success store auth = @gateway.authorize(@amount, store.authorization, @options) assert_success auth - assert_equal "This transaction has been approved.", auth.message + assert_equal 'This transaction has been approved.', auth.message - capture = @gateway.capture(@amount, auth.authorization) + capture = @gateway.capture(@amount, auth.authorization, @options) + assert_success capture + assert_equal 'This transaction has been approved.', capture.message + end + + def test_successful_authorize_and_capture_using_stored_card_with_level_2_and_3_data + store = @gateway.store(@credit_card, @options) + assert_success store + + auth = @gateway.authorize(@amount, store.authorization, @options.merge(@level_2_and_3_options)) + assert_success auth + assert_equal 'This transaction has been approved.', auth.message + + capture = @gateway.capture(@amount, auth.authorization, @options.merge(@level_2_and_3_options)) assert_success capture - assert_equal "This transaction has been approved.", capture.message + assert_equal 'This transaction has been approved.', capture.message end def test_failed_authorize_using_stored_card @@ -330,27 +436,60 @@ def test_failed_authorize_using_stored_card response = @gateway.authorize(@amount, response.authorization, @options) assert_failure response - assert_equal "The credit card number is invalid.", response.message - assert_equal "incorrect_number", response.error_code - assert_equal "27", response.params["message_code"] - assert_equal "6", response.params["response_reason_code"] - assert_match %r{Address not verified}, response.avs_result["message"] + assert_equal 'The credit card number is invalid.', response.message + assert_equal 'incorrect_number', response.error_code + assert_equal '27', response.params['message_code'] + assert_equal '6', response.params['response_reason_code'] + assert_match %r{Address not verified}, response.avs_result['message'] + end + + def test_failed_authorize_using_wrong_token + response = @gateway.store(@declined_card) + assert_success response + + responseA = @gateway.authorize(@amount, response.authorization, @options.merge(customer_payment_profile_id: 12345)) + responseB = @gateway.authorize(@amount, response.authorization, @options.merge(customer_profile_id: 12345)) + assert_failure responseA + assert_failure responseB + + assert_equal 'Customer Profile ID or Customer Payment Profile ID not found', responseA.message + assert_equal 'Customer Profile ID or Customer Payment Profile ID not found', responseB.message end def test_failed_capture_using_stored_card - store = @gateway.store(@credit_card) + store = @gateway.store(@credit_card, @options) assert_success store auth = @gateway.authorize(@amount, store.authorization, @options) assert_success auth - capture = @gateway.capture(@amount + 4000, auth.authorization) + capture = @gateway.capture(@amount + 4000, auth.authorization, @options) assert_failure capture assert_match %r{The amount requested for settlement cannot be greater}, capture.message end + def test_faux_successful_refund_with_billing_address + purchase = @gateway.purchase(@amount, @credit_card, @options) + assert_success purchase + + refund = @gateway.refund(@amount, purchase.authorization, @options.merge(first_name: 'Jim', last_name: 'Smith')) + assert_failure refund + assert_match %r{does not meet the criteria for issuing a credit}, refund.message, 'Only allowed to refund transactions that have settled. This is the best we can do for now testing wise.' + end + + def test_faux_successful_refund_without_billing_address + purchase = @gateway.purchase(@amount, @credit_card, @options) + assert_success purchase + + @options[:billing_address] = nil + + refund = @gateway.refund(@amount, purchase.authorization, @options.merge(first_name: 'Jim', last_name: 'Smith')) + assert_failure refund + assert_match %r{does not meet the criteria for issuing a credit}, refund.message, 'Only allowed to refund transactions that have settled. This is the best we can do for now testing wise.' + end + def test_faux_successful_refund_using_stored_card - store = @gateway.store(@credit_card) + store = @gateway.store(@credit_card, @options) assert_success store purchase = @gateway.purchase(@amount, store.authorization, @options) @@ -358,47 +497,59 @@ def test_faux_successful_refund_using_stored_card refund = @gateway.refund(@amount, purchase.authorization, @options) assert_failure refund - assert_match %r{does not meet the criteria for issuing a credit}, refund.message, "Only allowed to refund transactions that have settled. This is the best we can do for now testing wise." + assert_match %r{does not meet the criteria for issuing a credit}, refund.message, 'Only allowed to refund transactions that have settled. This is the best we can do for now testing wise.' + end + + def test_faux_successful_refund_using_stored_card_and_level_2_and_3_data + store = @gateway.store(@credit_card, @options) + assert_success store + + purchase = @gateway.purchase(@amount, store.authorization, @options.merge(@level_2_and_3_options)) + assert_success purchase + + refund = @gateway.refund(@amount, purchase.authorization, @options.merge(@level_2_and_3_options)) + assert_failure refund + assert_match %r{does not meet the criteria for issuing a credit}, refund.message, 'Only allowed to refund transactions that have settled. This is the best we can do for now testing wise.' end def test_failed_refund_using_stored_card - store = @gateway.store(@credit_card) + store = @gateway.store(@credit_card, @options) assert_success store purchase = @gateway.purchase(@amount, store.authorization, @options) assert_success purchase - unknown_authorization = "2235494048#XXXX2224#cim_purchase" + unknown_authorization = '2235494048#XXXX2224#cim_purchase' refund = @gateway.refund(@amount, unknown_authorization, @options) assert_failure refund - assert_equal "The record cannot be found", refund.message + assert_equal 'The record cannot be found', refund.message end def test_successful_void_using_stored_card - store = @gateway.store(@credit_card) + store = @gateway.store(@credit_card, @options) assert_success store auth = @gateway.authorize(@amount, store.authorization, @options) assert_success auth - void = @gateway.void(auth.authorization) + void = @gateway.void(auth.authorization, @options) assert_success void - assert_equal "This transaction has been approved.", void.message + assert_equal 'This transaction has been approved.', void.message end def test_failed_void_using_stored_card - store = @gateway.store(@credit_card) + store = @gateway.store(@credit_card, @options) assert_success store auth = @gateway.authorize(@amount, store.authorization, @options) assert_success auth - void = @gateway.void(auth.authorization) + void = @gateway.void(auth.authorization, @options) assert_success void - another_void = @gateway.void(auth.authorization) + another_void = @gateway.void(auth.authorization, @options) assert_failure another_void - assert_equal "This transaction has already been voided.", another_void.message + assert_equal 'This transaction has already been voided.', another_void.message end def test_bad_login @@ -417,6 +568,7 @@ def test_bad_login avs_result_code card_code cardholder_authentication_code + full_response_code response_code response_reason_code response_reason_text @@ -424,7 +576,7 @@ def test_bad_login transaction_id ), response.params.keys.sort - assert_equal "User authentication failed due to invalid authentication values", response.message + assert_equal 'User authentication failed due to invalid authentication values', response.message end def test_partial_capture @@ -482,6 +634,16 @@ def test_successful_echeck_credit assert response.authorization end + def test_successful_echeck_refund + purchase = @gateway.purchase(@amount, @check, @options) + assert_success purchase + + @options.update(transaction_id: purchase.params['transaction_id'], test_request: true) + refund = @gateway.credit(@amount, @check, @options) + assert_failure refund + assert_match %r{The transaction cannot be found}, refund.message, 'Only allowed to refund transactions that have settled. This is the best we can do for now testing wise.' + end + def test_failed_credit response = @gateway.credit(@amount, @declined_card, @options) assert_failure response @@ -490,13 +652,13 @@ def test_failed_credit end def test_bad_currency - response = @gateway.purchase(@amount, @credit_card, currency: "XYZ") + response = @gateway.purchase(@amount, @credit_card, currency: 'XYZ') assert_failure response assert_equal 'The supplied currency code is either invalid, not supported, not allowed for this merchant or doesn\'t have an exchange rate', response.message end def test_usd_currency - @options[:currency] = "USD" + @options[:currency] = 'USD' response = @gateway.purchase(@amount, @credit_card, @options) assert_success response assert response.authorization @@ -508,7 +670,7 @@ def test_dump_transcript def test_successful_authorize_and_capture_with_network_tokenization credit_card = network_tokenization_credit_card('4000100011112224', - payment_cryptogram: "EHuWW9PiBkWvqE5juRwDzAUFBAk=", + payment_cryptogram: 'EHuWW9PiBkWvqE5juRwDzAUFBAk=', verification_value: nil ) auth = @gateway.authorize(@amount, credit_card, @options) @@ -519,11 +681,39 @@ def test_successful_authorize_and_capture_with_network_tokenization assert_success capture end + def test_successful_refund_with_network_tokenization + credit_card = network_tokenization_credit_card('4000100011112224', + payment_cryptogram: 'EHuWW9PiBkWvqE5juRwDzAUFBAk=', + verification_value: nil + ) + + purchase = @gateway.purchase(@amount, credit_card, @options) + assert_success purchase + + @options[:billing_address] = nil + + refund = @gateway.refund(@amount, purchase.authorization, @options.merge(first_name: 'Jim', last_name: 'Smith')) + assert_failure refund + assert_match %r{does not meet the criteria for issuing a credit}, refund.message, 'Only allowed to refund transactions that have settled. This is the best we can do for now testing wise.' + end + + def test_successful_credit_with_network_tokenization + credit_card = network_tokenization_credit_card('4000100011112224', + payment_cryptogram: 'EHuWW9PiBkWvqE5juRwDzAUFBAk=', + verification_value: nil + ) + + response = @gateway.credit(@amount, credit_card, @options) + assert_success response + assert_equal 'This transaction has been approved', response.message + assert response.authorization + end + def test_network_tokenization_transcript_scrubbing credit_card = network_tokenization_credit_card('4111111111111111', :brand => 'visa', - :eci => "05", - :payment_cryptogram => "EHuWW9PiBkWvqE5juRwDzAUFBAk=" + :eci => '05', + :payment_cryptogram => 'EHuWW9PiBkWvqE5juRwDzAUFBAk=' ) transcript = capture_transcript(@gateway) do @@ -550,7 +740,7 @@ def test_purchase_scrubbing def test_verify_credentials assert @gateway.verify_credentials - gateway = AuthorizeNetGateway.new(login: "unknown_login", password: "not_right") + gateway = AuthorizeNetGateway.new(login: 'unknown_login', password: 'not_right') assert !gateway.verify_credentials end diff --git a/test/remote/gateways/remote_axcessms_test.rb b/test/remote/gateways/remote_axcessms_test.rb index 205f828b4b0..54b1c82213a 100644 --- a/test/remote/gateways/remote_axcessms_test.rb +++ b/test/remote/gateways/remote_axcessms_test.rb @@ -5,15 +5,15 @@ def setup @gateway = AxcessmsGateway.new(fixtures(:axcessms)) @amount = 1500 - @credit_card = credit_card("4200000000000000", month: 05, year: 2022) - @declined_card = credit_card("4444444444444444", month: 05, year: 2022) - @mode = "CONNECTOR_TEST" + @credit_card = credit_card('4200000000000000', month: 05, year: 2022) + @declined_card = credit_card('4444444444444444', month: 05, year: 2022) + @mode = 'CONNECTOR_TEST' @options = { order_id: generate_unique_id, - email: "customer@example.com", + email: 'customer@example.com', description: "Order Number #{Time.now.to_f.divmod(2473)[1]}", - ip: "0.0.0.0", + ip: '0.0.0.0', mode: @mode, billing_address: address } @@ -21,37 +21,37 @@ def setup def test_successful_authorization auth = @gateway.authorize(@amount, @credit_card, @options) - assert_success auth, "Authorize failed" + assert_success auth, 'Authorize failed' assert_match %r{Successful Processing - Request successfully processed}, auth.message end def test_successful_authorize_and_capture auth = @gateway.authorize(@amount, @credit_card, @options) - assert_success auth, "Authorize failed" + assert_success auth, 'Authorize failed' assert_match %r{Successful Processing - Request successfully processed}, auth.message assert capture = @gateway.capture(@amount, auth.authorization, {mode: @mode}) - assert_success capture, "Capture failed" + assert_success capture, 'Capture failed' assert_match %r{Successful Processing - Request successfully processed}, capture.message end def test_successful_authorize_and_partial_capture auth = @gateway.authorize(@amount, @credit_card, @options) - assert_success auth, "Authorize failed" + assert_success auth, 'Authorize failed' assert_match %r{Successful Processing - Request successfully processed}, auth.message assert capture = @gateway.capture(@amount-30, auth.authorization, {mode: @mode}) - assert_success capture, "Capture failed" + assert_success capture, 'Capture failed' assert_match %r{Successful Processing - Request successfully processed}, capture.message end def test_successful_authorize_and_void auth = @gateway.authorize(@amount, @credit_card, @options) - assert_success auth, "Authorize failed" + assert_success auth, 'Authorize failed' assert_match %r{Successful Processing - Request successfully processed}, auth.message assert void = @gateway.void(auth.authorization, {mode: @mode}) - assert_success void, "Void failed" + assert_success void, 'Void failed' assert_match %r{Successful Processing - Request successfully processed}, void.message end @@ -79,44 +79,44 @@ def test_successful_reference_purchase def test_successful_purchase_and_refund purchase = @gateway.purchase(@amount, @credit_card, @options) - assert_success purchase, "Purchase failed" + assert_success purchase, 'Purchase failed' assert_match %r{Successful Processing - Request successfully processed}, purchase.message assert refund = @gateway.refund(@amount, purchase.authorization, {mode: @mode}) - assert_success refund, "Refund failed" + assert_success refund, 'Refund failed' assert_match %r{Successful Processing - Request successfully processed}, refund.message end def test_successful_purchase_and_partial_refund purchase = @gateway.purchase(@amount, @credit_card, @options) - assert_success purchase, "Purchase failed" + assert_success purchase, 'Purchase failed' assert_match %r{Successful Processing - Request successfully processed}, purchase.message assert refund = @gateway.refund(@amount-50, purchase.authorization, {mode: @mode}) - assert_success refund, "Refund failed" + assert_success refund, 'Refund failed' assert_match %r{Successful Processing - Request successfully processed}, refund.message end # Failure tested def test_utf8_description_does_not_blow_up - assert response = @gateway.purchase(@amount, @credit_card, @options.merge(description: "Habitación")) + assert response = @gateway.purchase(@amount, @credit_card, @options.merge(description: 'Habitación')) assert_success response assert_match %r{Successful Processing - Request successfully processed}, response.message end def test_failed_capture - assert capture = @gateway.capture(@amount, "invalid authorization") + assert capture = @gateway.capture(@amount, 'invalid authorization') assert_failure capture assert_match %r{Reference Error - capture}, capture.message end def test_failed_bigger_capture_then_authorised auth = @gateway.authorize(@amount, @credit_card, @options) - assert_success auth, "Authorize failed" + assert_success auth, 'Authorize failed' assert capture = @gateway.capture(@amount+30, auth.authorization, {mode: @mode}) - assert_failure capture, "Capture failed" + assert_failure capture, 'Capture failed' assert_match %r{PA value exceeded}, capture.message end @@ -127,27 +127,27 @@ def test_failed_authorize end def test_failed_refund - assert refund = @gateway.refund(@amount, "invalid authorization", {mode: @mode}) + assert refund = @gateway.refund(@amount, 'invalid authorization', {mode: @mode}) assert_failure refund assert_match %r{Configuration Validation - Invalid payment data}, refund.message end def test_failed_void - void = @gateway.void("invalid authorization", {mode: @mode}) + void = @gateway.void('invalid authorization', {mode: @mode}) assert_failure void assert_match %r{Reference Error - reversal}, void.message end def test_unauthorized_capture - assert response = @gateway.capture(@amount, "1234567890123456789012") + assert response = @gateway.capture(@amount, '1234567890123456789012') assert_failure response - assert_equal "Reference Error - capture needs at least one successful transaction of type (PA)", response.message + assert_equal 'Reference Error - capture needs at least one successful transaction of type (PA)', response.message end def test_unauthorized_purchase_by_reference - assert response = @gateway.purchase(@amount, "1234567890123456789012") + assert response = @gateway.purchase(@amount, '1234567890123456789012') assert_failure response - assert_equal "Reference Error - reference id not existing", response.message + assert_equal 'Reference Error - reference id not existing', response.message end def test_failed_purchase_by_card @@ -157,7 +157,7 @@ def test_failed_purchase_by_card end def test_invalid_login - credentials = fixtures(:axcessms).merge(password: "invalid") + credentials = fixtures(:axcessms).merge(password: 'invalid') response = AxcessmsGateway.new(credentials).purchase(@amount, @credit_card, @options) assert_failure response end @@ -166,7 +166,7 @@ def test_successful_verify assert response = @gateway.verify(@credit_card, @options) assert_success response assert_match %r{success}i, response.message - assert_success response.responses.last, "The void should succeed" + assert_success response.responses.last, 'The void should succeed' end def test_failed_verify diff --git a/test/remote/gateways/remote_balanced_test.rb b/test/remote/gateways/remote_balanced_test.rb index f253b666811..d5930116419 100644 --- a/test/remote/gateways/remote_balanced_test.rb +++ b/test/remote/gateways/remote_balanced_test.rb @@ -19,7 +19,7 @@ def setup def test_successful_purchase response = @gateway.purchase(@amount, @credit_card, @options) assert_success response - assert_equal "Success", response.message + assert_equal 'Success', response.message assert_equal @amount, response.params['debits'][0]['amount'] end @@ -27,7 +27,7 @@ def test_successful_purchase_with_outside_token outside_token = @gateway.store(@credit_card).params['cards'][0]['href'] response = @gateway.purchase(@amount, outside_token, @options) assert_success response - assert_equal "Success", response.message + assert_equal 'Success', response.message assert_equal @amount, response.params['debits'][0]['amount'] end @@ -44,19 +44,19 @@ def test_unsuccessful_purchase end def test_passing_appears_on_statement - options = @options.merge(appears_on_statement_as: "Homer Electric") + options = @options.merge(appears_on_statement_as: 'Homer Electric') response = @gateway.purchase(@amount, @credit_card, options) assert_success response - assert_equal "BAL*Homer Electric", response.params['debits'][0]['appears_on_statement_as'] + assert_equal 'BAL*Homer Electric', response.params['debits'][0]['appears_on_statement_as'] end def test_passing_meta - options = @options.merge(meta: { "order_number" => '12345' }) + options = @options.merge(meta: { 'order_number' => '12345' }) response = @gateway.purchase(@amount, @credit_card, options) assert_success response - assert_equal options[:meta], response.params["debits"][0]["meta"] + assert_equal options[:meta], response.params['debits'][0]['meta'] end def test_authorize_and_capture @@ -90,7 +90,7 @@ def test_void_authorization assert void = @gateway.void(authorize.authorization) assert_success void - assert void.params["card_holds"][0]['voided_at'], void.inspect + assert void.params['card_holds'][0]['voided_at'], void.inspect end def test_voiding_a_capture_not_allowed diff --git a/test/remote/gateways/remote_bank_frick_test.rb b/test/remote/gateways/remote_bank_frick_test.rb index a7202c677d4..d1bb6447d4e 100644 --- a/test/remote/gateways/remote_bank_frick_test.rb +++ b/test/remote/gateways/remote_bank_frick_test.rb @@ -123,7 +123,7 @@ def test_invalid_login sender: '', channel: '', userid: '', - userpwd: '', + userpwd: '' ) response = gateway.purchase(@amount, @credit_card, @options) assert_failure response diff --git a/test/remote/gateways/remote_banwire_test.rb b/test/remote/gateways/remote_banwire_test.rb index b7319efd349..0af462e9a7b 100644 --- a/test/remote/gateways/remote_banwire_test.rb +++ b/test/remote/gateways/remote_banwire_test.rb @@ -1,4 +1,5 @@ # encoding: utf-8 + require 'test_helper' class RemoteBanwireTest < Test::Unit::TestCase @@ -28,7 +29,7 @@ def test_successful_visa_purchase def test_successful_purchase_with_extra_options options = { order_id: '1', - email: "test@email.com", + email: 'test@email.com', billing_address: address, description: 'Store Purchase' } @@ -36,7 +37,6 @@ def test_successful_purchase_with_extra_options assert_success response end - def test_unsuccessful_purchase assert response = @gateway.purchase(@amount, @declined_card, @options) assert_failure response @@ -53,14 +53,14 @@ def test_invalid_login assert_equal 'ID de cuenta invalido', response.message end -def test_transcript_scrubbing - transcript = capture_transcript(@gateway) do - @gateway.purchase(@amount, @credit_card, @options) - end - clean_transcript = @gateway.scrub(transcript) + def test_transcript_scrubbing + transcript = capture_transcript(@gateway) do + @gateway.purchase(@amount, @credit_card, @options) + end + clean_transcript = @gateway.scrub(transcript) - assert_scrubbed(@credit_card.number, clean_transcript) - assert_scrubbed(@credit_card.verification_value.to_s, clean_transcript) -end + assert_scrubbed(@credit_card.number, clean_transcript) + assert_scrubbed(@credit_card.verification_value.to_s, clean_transcript) + end end diff --git a/test/remote/gateways/remote_barclaycard_smartpay_test.rb b/test/remote/gateways/remote_barclaycard_smartpay_test.rb index d7d7e7bec06..1f0444d6a08 100644 --- a/test/remote/gateways/remote_barclaycard_smartpay_test.rb +++ b/test/remote/gateways/remote_barclaycard_smartpay_test.rb @@ -3,10 +3,13 @@ class RemoteBarclaycardSmartpayTest < Test::Unit::TestCase def setup @gateway = BarclaycardSmartpayGateway.new(fixtures(:barclaycard_smartpay)) + BarclaycardSmartpayGateway.ssl_strict = false @amount = 100 - @credit_card = credit_card('4111111111111111', :month => 8, :year => 2018, :verification_value => 737) - @declined_card = credit_card('4000300011112220', :month => 8, :year => 2018, :verification_value => 737) + @error_amount = 1_000_000_000_000_000_000_000 + @credit_card = credit_card('4111111111111111', :month => 10, :year => 2020, :verification_value => 737) + @declined_card = credit_card('4000300011112220', :month => 3, :year => 2030, :verification_value => 737) + @three_ds_enrolled_card = credit_card('4212345678901237', brand: :visa) @options = { order_id: '1', @@ -25,12 +28,81 @@ def setup description: 'Store Purchase' } + @options_with_alternate_address = { + order_id: '1', + billing_address: { + name: 'PU JOI SO', + address1: '新北市店溪路3579號139樓', + company: 'Widgets Inc', + city: '新北市', + zip: '231509', + country: 'TW', + phone: '(555)555-5555', + fax: '(555)555-6666' + }, + email: 'pujoi@so.com', + customer: 'PU JOI SO', + description: 'Store Purchase' + } + + @options_with_house_number_and_street = { + order_id: '1', + house_number: '100', + street: 'Top Level Drive', + billing_address: { + name: 'Jim Smith', + address1: '100 Top Level Dr', + company: 'Widgets Inc', + city: 'Ottawa', + state: 'ON', + zip: 'K1C2N6', + country: 'CA', + phone: '(555)555-5555', + fax: '(555)555-6666' + }, + email: 'long@deb.com', + customer: 'Longdeb Longsen', + description: 'Store Purchase' + } + + @options_with_no_address = { + order_id: '1', + email: 'long@bob.com', + customer: 'Longbob Longsen', + description: 'Store Purchase' + } + + @options_with_credit_fields = { + order_id: '1', + billing_address: { + name: 'Jim Smith', + address1: '100 Street', + company: 'Widgets Inc', + city: 'Ottawa', + state: 'ON', + zip: 'K1C2N6', + country: 'CA', + phone: '(555)555-5555', + fax: '(555)555-6666'}, + email: 'long@bob.com', + customer: 'Longbob Longsen', + description: 'Store Purchase', + date_of_birth: '1990-10-11', + entity_type: 'NaturalPerson', + nationality: 'US', + shopper_name: { + firstName: 'Longbob', + lastName: 'Longsen', + gender: 'MALE' + } + } + @avs_credit_card = credit_card('4400000000000008', - :month => 8, - :year => 2018, - :verification_value => 737) + :month => 8, + :year => 2018, + :verification_value => 737) - @avs_address = @options + @avs_address = @options.clone @avs_address.update(billing_address: { name: 'Jim Smith', street: 'Test AVS result', @@ -42,6 +114,10 @@ def setup }) end + def teardown + BarclaycardSmartpayGateway.ssl_strict = true + end + def test_successful_purchase response = @gateway.purchase(@amount, @credit_card, @options) assert_success response @@ -54,6 +130,52 @@ def test_failed_purchase assert_equal 'Refused', response.message end + def test_successful_purchase_with_unusual_address + response = @gateway.purchase(@amount, + @credit_card, + @options_with_alternate_address) + assert_success response + assert_equal '[capture-received]', response.message + end + + def test_successful_purchase_with_house_number_and_street + response = @gateway.purchase(@amount, + @credit_card, + @options.merge(street: 'Top Level Drive', house_number: '100')) + assert_success response + assert_equal '[capture-received]', response.message + end + + def test_successful_purchase_with_no_address + response = @gateway.purchase(@amount, + @credit_card, + @options_with_no_address) + assert_success response + assert_equal '[capture-received]', response.message + end + + def test_successful_purchase_with_shopper_interaction + response = @gateway.purchase(@amount, @credit_card, @options.merge(shopper_interaction: 'ContAuth')) + assert_success response + assert_equal '[capture-received]', response.message + end + + def test_successful_purchase_with_device_fingerprint + response = @gateway.purchase(@amount, @credit_card, @options.merge(device_fingerprint: 'abcde1123')) + assert_success response + assert_equal '[capture-received]', response.message + end + + def test_successful_authorize_with_3ds + assert response = @gateway.authorize(@amount, @three_ds_enrolled_card, @options.merge(execute_threed: true)) + assert_equal 'RedirectShopper', response.message + assert response.test? + refute response.authorization.blank? + refute response.params['issuerUrl'].blank? + refute response.params['md'].blank? + refute response.params['paRequest'].blank? + end + def test_successful_authorize_and_capture auth = @gateway.authorize(@amount, @credit_card, @options) assert_success auth @@ -75,9 +197,16 @@ def test_partial_capture assert_success capture end - def test_failed_capture + def test_failed_capture_with_bad_auth + response = @gateway.capture(100, '0000000000000000', @options) + assert_failure response + assert_equal('167: Original pspReference required for this operation', response.message) + end + + def test_failed_capture_with_bad_amount response = @gateway.capture(nil, '', @options) assert_failure response + assert_equal('137: Invalid amount specified', response.message) end def test_successful_refund @@ -102,7 +231,7 @@ def test_failed_refund end def test_successful_credit - response = @gateway.credit(@amount, @credit_card, @options) + response = @gateway.credit(@amount, @credit_card, @options_with_credit_fields) assert_success response end @@ -111,6 +240,17 @@ def test_failed_credit assert_failure response end + def test_failed_credit_insufficient_validation + # This test will fail currently (the credit will succeed), but it should succeed after October 29th + # response = @gateway.credit(@amount, @credit_card, @options) + # assert_failure response + end + + def test_successful_third_party_payout + response = @gateway.credit(@amount, @credit_card, @options_with_credit_fields.merge({third_party_payout: true})) + assert_success response + end + def test_successful_void auth = @gateway.authorize(@amount, @credit_card, @options) assert_success auth @@ -128,21 +268,21 @@ def test_successful_verify assert response = @gateway.verify(@credit_card, @options) assert_success response - assert_equal "Authorised", response.message + assert_equal 'Authorised', response.message assert response.authorization end def test_unsuccessful_verify assert response = @gateway.verify(@declined_card, @options) assert_failure response - assert_equal "Refused", response.message + assert_equal 'Refused', response.message end def test_invalid_login gateway = BarclaycardSmartpayGateway.new( - company: '', - merchant: '', - password: '' + company: '', + merchant: '', + password: '' ) response = gateway.purchase(@amount, @credit_card, @options) assert_failure response @@ -151,13 +291,13 @@ def test_invalid_login def test_successful_store response = @gateway.store(@credit_card, @options) assert_success response - assert_equal "Success", response.message + assert_equal 'Success', response.message end def test_failed_store - response = @gateway.store(credit_card('', :month => '', :year => '', :verification_value => ''), @options) + response = @gateway.store(credit_card('4111111111111111', :month => '', :year => '', :verification_value => ''), @options) assert_failure response - assert_equal "Unprocessable Entity", response.message + assert_equal '129: Expiry Date Invalid', response.message end # AVS must be enabled on the gateway's end for the test account used @@ -166,6 +306,28 @@ def test_avs_result assert_equal 'N', response.avs_result['code'] end + def test_avs_no_with_house_number + avs_nohousenumber = @avs_address + avs_nohousenumber[:billing_address].delete(:houseNumberOrName) + response = @gateway.authorize(@amount, @avs_credit_card, avs_nohousenumber) + assert_equal 'Z', response.avs_result['code'] + end + + def test_nonfractional_currency + response = @gateway.authorize(1234, @credit_card, @options.merge(:currency => 'JPY')) + assert_success response + response = @gateway.purchase(1234, @credit_card, @options.merge(:currency => 'JPY')) + assert_success response + end + + def test_three_decimal_currency + response = @gateway.authorize(1234, @credit_card, @options.merge(:currency => 'OMR')) + assert_success response + + response = @gateway.purchase(1234, @credit_card, @options.merge(:currency => 'OMR')) + assert_success response + end + def test_transcript_scrubbing transcript = capture_transcript(@gateway) do @gateway.purchase(@amount, @credit_card, @options) @@ -176,4 +338,10 @@ def test_transcript_scrubbing assert_scrubbed(@credit_card.verification_value.to_s, clean_transcript) assert_scrubbed(@gateway.options[:password], clean_transcript) end + + def test_proper_error_response_handling + response = @gateway.purchase(@error_amount, @credit_card, @options) + assert_equal('702: Internal error', response.message) + assert_not_equal(response.message, 'Unable to communicate with the payment system.') + end end diff --git a/test/remote/gateways/remote_barclays_epdq_extra_plus_test.rb b/test/remote/gateways/remote_barclays_epdq_extra_plus_test.rb index b8fb97c8265..dd06e16d724 100644 --- a/test/remote/gateways/remote_barclays_epdq_extra_plus_test.rb +++ b/test/remote/gateways/remote_barclays_epdq_extra_plus_test.rb @@ -1,12 +1,13 @@ # coding: utf-8 + require 'test_helper' class RemoteBarclaysEpdqExtraPlusTest < Test::Unit::TestCase def setup @gateway = BarclaysEpdqExtraPlusGateway.new(fixtures(:barclays_epdq_extra_plus)) @amount = 100 - @credit_card = credit_card('4000100011112224') - @mastercard = credit_card('5399999999999999', :brand => "mastercard") + @credit_card = credit_card('4000100011112224', :verification_value => '987') + @mastercard = credit_card('5399999999999999', :brand => 'mastercard') @declined_card = credit_card('1111111111111111') @credit_card_d3d = credit_card('4000000000000002', :verification_value => '111') @options = { @@ -21,7 +22,7 @@ def test_successful_purchase assert response = @gateway.purchase(@amount, @credit_card, @options) assert_success response assert_equal BarclaysEpdqExtraPlusGateway::SUCCESS_MESSAGE, response.message - assert_equal @options[:currency], response.params["currency"] + assert_equal @options[:currency], response.params['currency'] assert_equal @options[:order_id], response.order_id end @@ -31,18 +32,18 @@ def test_successful_purchase_with_minimal_info assert response = @gateway.purchase(@amount, @credit_card, @options) assert_success response assert_equal BarclaysEpdqExtraPlusGateway::SUCCESS_MESSAGE, response.message - assert_equal @options[:currency], response.params["currency"] + assert_equal @options[:currency], response.params['currency'] assert_equal @options[:order_id], response.order_id end def test_successful_purchase_with_utf8_encoding_1 - assert response = @gateway.purchase(@amount, credit_card('4000100011112224', :first_name => "Rémy", :last_name => "Fröåïør"), @options) + assert response = @gateway.purchase(@amount, credit_card('4000100011112224', :first_name => 'Rémy', :last_name => 'Fröåïør'), @options) assert_success response assert_equal BarclaysEpdqExtraPlusGateway::SUCCESS_MESSAGE, response.message end def test_successful_purchase_with_utf8_encoding_2 - assert response = @gateway.purchase(@amount, credit_card('4000100011112224', :first_name => "ワタシ", :last_name => "ёжзийклмнопрсуфхцч"), @options) + assert response = @gateway.purchase(@amount, credit_card('4000100011112224', :first_name => 'ワタシ', :last_name => 'ёжзийклмнопрсуфхцч'), @options) assert_success response assert_equal BarclaysEpdqExtraPlusGateway::SUCCESS_MESSAGE, response.message end @@ -218,10 +219,20 @@ def test_invalid_login :login => '', :user => '', :password => '', - :signature_encryptor => "none" + :signature_encryptor => 'none' ) assert response = gateway.purchase(@amount, @credit_card, @options) assert_failure response assert_equal 'Some of the data entered is incorrect. please retry.', response.message end + + def test_transcript_scrubbing + transcript = capture_transcript(@gateway) do + @gateway.purchase(@amount, @credit_card, @options) + end + transcript = @gateway.scrub(transcript) + + assert_scrubbed(@credit_card.number, transcript) + assert_scrubbed(@credit_card.verification_value, transcript) + end end diff --git a/test/remote/gateways/remote_barclays_epdq_test.rb b/test/remote/gateways/remote_barclays_epdq_test.rb deleted file mode 100644 index 346390280c8..00000000000 --- a/test/remote/gateways/remote_barclays_epdq_test.rb +++ /dev/null @@ -1,212 +0,0 @@ -require 'test_helper' - -class RemoteBarclaysEpdqTest < Test::Unit::TestCase - def setup - @gateway = BarclaysEpdqGateway.new(fixtures(:barclays_epdq).merge(:test => true)) - - @approved_amount = 3900 - @declined_amount = 4205 - @approved_card = credit_card('4715320629000001') - @declined_card = credit_card('4715320629000027') - - @options = { - :order_id => generate_unique_id, - :billing_address => address, - :description => 'Store Purchase' - } - - @periodic_options = @options.merge( - :payment_number => 1, - :total_payments => 3, - :group_id => 'MyTestPaymentGroup' - ) - end - - def test_successful_purchase - assert response = @gateway.purchase(@approved_amount, @approved_card, @options) - assert_success response - assert_equal 'Approved.', response.message - assert_equal @options[:order_id], response.authorization - assert_no_match(/PaymentNoFraud/, response.params["raw_response"]) - end - - def test_successful_purchase_with_mastercard - assert response = @gateway.purchase(@approved_amount, credit_card('5301250070000050', :brand => :master), @options) - assert_success response - end - - def test_successful_purchase_with_maestro - assert response = @gateway.purchase(@approved_amount, credit_card('675938410597000022', :brand => :maestro, :issue_number => '5'), @options) - assert_success response - end - - def test_successful_purchase_with_switch - assert response = @gateway.purchase(@approved_amount, credit_card('6759560045005727054', :brand => :switch, :issue_number => '1'), @options) - assert_success response - end - - def test_successful_purchase_with_minimal_options - delete_address_details! - - assert response = @gateway.purchase(@approved_amount, @approved_card, @options) - assert_success response - assert_equal 'Approved.', response.message - assert_equal @options[:order_id], response.authorization - assert_no_match(/PaymentNoFraud/, response.params["raw_response"]) - end - - def test_successful_purchase_with_no_fraud - @options[:no_fraud] = true - assert response = @gateway.purchase(@approved_amount, @approved_card, @options) - assert_success response - assert_equal 'Approved.', response.message - assert_equal @options[:order_id], response.authorization - assert_match(/PaymentNoFraud/, response.params["raw_response"]) - end - - def test_successful_purchase_with_no_fraud_and_minimal_options - delete_address_details! - - @options[:no_fraud] = true - assert response = @gateway.purchase(@approved_amount, @approved_card, @options) - assert_success response - assert_equal 'Approved.', response.message - assert_equal @options[:order_id], response.authorization - assert_match(/PaymentNoFraud/, response.params["raw_response"]) - end - - def test_successful_purchase_with_no_address_or_order_id_or_description - assert response = @gateway.purchase(@approved_amount, @approved_card, {}) - assert_success response - assert_equal 'Approved.', response.message - end - - def test_unsuccessful_purchase - assert response = @gateway.purchase(@declined_amount, @declined_card, @options) - assert_failure response - assert_match(/^Declined/, response.message) - end - - def test_credit_new_order - assert response = @gateway.credit(@approved_amount, @approved_card, @options) - assert_success response - assert_equal 'Approved.', response.message - end - - def test_refund_existing_order - assert response = @gateway.purchase(@approved_amount, @approved_card, @options) - assert_success response - - assert refund = @gateway.refund(@approved_amount, response.authorization) - assert_success refund - assert_equal 'Approved.', refund.message - end - - def test_refund_nonexisting_order_fails - assert refund = @gateway.refund(@approved_amount, "DOESNOTEXIST", @options) - assert_failure refund - assert_match(/^Payment Mechanism CreditCard information not found/, refund.message) - end - - def test_authorize_and_capture - amount = @approved_amount - assert auth = @gateway.authorize(amount, @approved_card, @options) - assert_success auth - assert_equal 'Approved.', auth.message - assert auth.authorization - assert_equal @options[:order_id], auth.authorization - - assert capture = @gateway.capture(amount, auth.authorization) - assert_success capture - assert_equal 'Approved.', capture.message - end - - def test_authorize_and_capture_without_order_id - @options.delete(:order_id) - amount = @approved_amount - assert auth = @gateway.authorize(amount, @approved_card, @options) - assert_success auth - assert_equal 'Approved.', auth.message - assert auth.authorization - assert_match(/[0-9a-f\-]{36}/, auth.authorization) - - assert capture = @gateway.capture(amount, auth.authorization) - assert_success capture - assert_equal 'Approved.', capture.message - end - - def test_authorize_void_and_failed_capture - amount = @approved_amount - assert auth = @gateway.authorize(amount, @approved_card, @options) - assert_success auth - - assert void = @gateway.void(auth.authorization) - assert_success void - assert_equal 'Approved.', void.message - - assert capture = @gateway.capture(amount, auth.authorization) - assert_failure capture - assert_match(/^Did not find a unique, qualifying transaction for Order/, capture.message) - end - - def test_failed_authorize - assert auth = @gateway.authorize(@declined_amount, @approved_card, @options) - assert_failure auth - assert_match(/^Declined/, auth.message) - end - - def test_failed_capture - amount = @approved_amount - assert auth = @gateway.authorize(amount, @approved_card, @options) - assert_success auth - - @too_much = amount * 10 - assert capture = @gateway.capture(@too_much, auth.authorization) - assert_success capture - assert_match(/^The PostAuth is not valid because the amount/, capture.message) - end - - def test_three_successful_periodic_orders - amount = @approved_amount - assert auth1 = @gateway.purchase(amount, @approved_card, @periodic_options) - assert auth1.success? - assert_equal 'Approved.', auth1.message - - @periodic_options[:payment_number] = 2 - @periodic_options[:order_id] = generate_unique_id - assert auth2 = @gateway.purchase(amount, @approved_card, @periodic_options) - assert auth2.success? - assert_equal 'Approved.', auth2.message - - @periodic_options[:payment_number] = 3 - @periodic_options[:order_id] = generate_unique_id - assert auth3 = @gateway.purchase(amount, @approved_card, @periodic_options) - assert auth3.success? - assert_equal 'Approved.', auth3.message - end - - def test_invalid_login - gateway = BarclaysEpdqGateway.new( - :login => 'NOBODY', - :password => 'HOME', - :client_id => '1234' - ) - assert response = gateway.purchase(@approved_amount, @approved_card, @options) - assert_failure response - assert_equal 'Insufficient permissions to perform requested operation.', response.message - end - - protected - def delete_address_details! - @options[:billing_address].delete :city - @options[:billing_address].delete :state - @options[:billing_address].delete :country - @options[:billing_address].delete :address1 - @options[:billing_address].delete :phone - @options[:billing_address].delete :address1 - @options[:billing_address].delete :address2 - @options[:billing_address].delete :name - @options[:billing_address].delete :fax - @options[:billing_address].delete :company - end -end diff --git a/test/remote/gateways/remote_beanstream_interac_test.rb b/test/remote/gateways/remote_beanstream_interac_test.rb index a4a053d6b70..4f4d1b9b79e 100644 --- a/test/remote/gateways/remote_beanstream_interac_test.rb +++ b/test/remote/gateways/remote_beanstream_interac_test.rb @@ -1,13 +1,13 @@ require 'test_helper' class RemoteBeanstreamInteracTest < Test::Unit::TestCase - + def setup @gateway = BeanstreamInteracGateway.new(fixtures(:beanstream_interac)) - + @amount = 100 - - @options = { + + @options = { :order_id => generate_unique_id, :billing_address => { :name => 'xiaobo zzz', @@ -27,19 +27,19 @@ def setup :custom => 'reference one' } end - + def test_successful_purchase assert response = @gateway.purchase(@amount, @options) assert_success response - assert_equal "R", response.params["responseType"] + assert_equal 'R', response.params['responseType'] assert_false response.redirect.blank? end - + def test_failed_confirmation - assert response = @gateway.confirm("") + assert response = @gateway.confirm('') assert_failure response end - + def test_invalid_login gateway = BeanstreamInteracGateway.new( :merchant_id => '', diff --git a/test/remote/gateways/remote_beanstream_test.rb b/test/remote/gateways/remote_beanstream_test.rb index 2362f197f62..eed3b72531f 100644 --- a/test/remote/gateways/remote_beanstream_test.rb +++ b/test/remote/gateways/remote_beanstream_test.rb @@ -13,12 +13,13 @@ def setup # Beanstream test cards. Cards require a CVV of 123, which is the default of the credit card helper @visa = credit_card('4030000010001234') @declined_visa = credit_card('4003050500040005') + @visa_no_cvv = credit_card('4030000010001234', verification_value: nil) @mastercard = credit_card('5100000010001004') @declined_mastercard = credit_card('5100000020002000') @amex = credit_card('371100001000131', {:verification_value => 1234}) - @declined_amex = credit_card('342400001000180') + @declined_amex = credit_card('342400001000180', {:verification_value => 1234}) # Canadian EFT @check = check( @@ -36,10 +37,20 @@ def setup :address1 => '4444 Levesque St.', :address2 => 'Apt B', :city => 'Montreal', - :state => 'QC', + :state => 'Quebec', :country => 'CA', :zip => 'H2C1X8' }, + :shipping_address => { + :name => 'shippy', + :phone => '888-888-8888', + :address1 => '777 Foster Street', + :address2 => 'Ste #100', + :city => 'Durham', + :state => 'North Carolina', + :country => 'US', + :zip => '27701' + }, :email => 'xiaobozzz@example.com', :subtotal => 800, :shipping => 100, @@ -57,7 +68,27 @@ def test_successful_visa_purchase assert response = @gateway.purchase(@amount, @visa, @options) assert_success response assert_false response.authorization.blank? - assert_equal "Approved", response.message + assert_equal 'Approved', response.message + end + + def test_successful_visa_purchase_with_recurring + assert response = @gateway.purchase(@amount, @visa, @options.merge(recurring: true)) + assert_success response + assert_false response.authorization.blank? + assert_equal 'Approved', response.message + end + + def test_successful_visa_purchase_no_cvv + assert response = @gateway.purchase(@amount, @visa_no_cvv, @options.merge(recurring: true)) + assert_success response + assert_false response.authorization.blank? + assert_equal 'Approved', response.message + end + + def test_unsuccessful_visa_purchase_with_no_cvv + assert response = @gateway.purchase(@amount, @visa_no_cvv, @options) + assert_failure response + assert_equal 'Card CVD is invalid.', response.message end def test_unsuccessful_visa_purchase @@ -70,7 +101,14 @@ def test_successful_mastercard_purchase assert response = @gateway.purchase(@amount, @mastercard, @options) assert_success response assert_false response.authorization.blank? - assert_equal "Approved", response.message + assert_equal 'Approved', response.message + end + + def test_successful_mastercard_purchase_with_recurring + assert response = @gateway.purchase(@amount, @mastercard, @options.merge(recurring: true)) + assert_success response + assert_false response.authorization.blank? + assert_equal 'Approved', response.message end def test_unsuccessful_mastercard_purchase @@ -83,7 +121,14 @@ def test_successful_amex_purchase assert response = @gateway.purchase(@amount, @amex, @options) assert_success response assert_false response.authorization.blank? - assert_equal "Approved", response.message + assert_equal 'Approved', response.message + end + + def test_successful_amex_purchase_with_recurring + assert response = @gateway.purchase(@amount, @amex, @options.merge(recurring: true)) + assert_success response + assert_false response.authorization.blank? + assert_equal 'Approved', response.message end def test_unsuccessful_amex_purchase @@ -92,10 +137,60 @@ def test_unsuccessful_amex_purchase assert_equal 'DECLINE', response.message end + def test_successful_purchase_with_state_in_iso_format + assert response = @gateway.purchase(@amount, @visa, @options.merge(billing_address: address, shipping_address: address)) + assert_success response + assert_false response.authorization.blank? + assert_equal 'Approved', response.message + end + + def test_successful_purchase_with_only_email + options = { + :order_id => generate_unique_id, + :email => 'xiaobozzz@example.com', + :shipping_email => 'ship@mail.com' + } + + assert response = @gateway.purchase(@amount, @visa, options) + assert_success response + assert_false response.authorization.blank? + assert_equal 'Approved', response.message + end + + def test_successful_purchase_with_no_addresses + @options[:billing_address] = {} + @options[:shipping_address] = {} + assert response = @gateway.purchase(@amount, @visa, @options) + assert_success response + assert_false response.authorization.blank? + assert_equal 'Approved', response.message + end + + def test_failed_purchase_due_to_invalid_billing_state + @options[:billing_address][:state] = 'Invalid' + assert response = @gateway.purchase(@amount, @visa, @options) + assert_failure response + assert_match %r{province does not match country}, response.message + end + + def test_failed_purchase_due_to_invalid_shipping_state + @options[:shipping_address][:state] = 'North' + assert response = @gateway.purchase(@amount, @visa, @options) + assert_failure response + assert_match %r{Invalid shipping province}, response.message + end + + def test_failed_purchase_due_to_missing_country_with_state + @options[:shipping_address][:country] = nil + assert response = @gateway.purchase(@amount, @visa, @options) + assert_failure response + assert_match %r{Invalid shipping country id}, response.message + end + def test_authorize_and_capture assert auth = @gateway.authorize(@amount, @visa, @options) assert_success auth - assert_equal "Approved", auth.message + assert_equal 'Approved', auth.message assert_false auth.authorization.blank? assert capture = @gateway.capture(@amount, auth.authorization) @@ -103,10 +198,21 @@ def test_authorize_and_capture assert_false capture.authorization.blank? end + def test_authorize_and_capture_with_recurring + assert auth = @gateway.authorize(@amount, @visa, @options.merge(recurring: true)) + assert_success auth + assert_equal 'Approved', auth.message + assert_false auth.authorization.blank? + + assert capture = @gateway.capture(@amount, auth.authorization, recurring: true) + assert_success capture + assert_false capture.authorization.blank? + end + def test_successful_verify response = @gateway.verify(@visa, @options) assert_success response - assert_match "Approved", response.message + assert_match 'Approved', response.message end def test_failed_verify @@ -118,7 +224,7 @@ def test_failed_verify def test_failed_capture assert response = @gateway.capture(@amount, '') assert_failure response - assert_no_match %r{You are not authorized}, response.message, "You need to enable username/password validation" + assert_no_match %r{You are not authorized}, response.message, 'You need to enable username/password validation' assert_match %r{Missing or invalid adjustment id.}, response.message end @@ -130,6 +236,14 @@ def test_successful_purchase_and_void assert_success void end + def test_successful_purchase_and_void_with_recurring + assert purchase = @gateway.purchase(@amount, @visa, @options.merge(recurring: true)) + assert_success purchase + + assert void = @gateway.void(purchase.authorization) + assert_success void + end + def test_successful_purchase_and_refund_and_void_refund assert purchase = @gateway.purchase(@amount, @visa, @options) assert_success purchase @@ -153,7 +267,7 @@ def test_successful_check_purchase_and_refund assert_success purchase assert refund = @gateway.refund(@amount, purchase.authorization) - assert_success credit + assert_success refund end def test_successful_recurring @@ -169,7 +283,7 @@ def test_successful_update_recurring assert response.test? assert_false response.authorization.blank? - assert response = @gateway.update_recurring(@amount + 500, @visa, @recurring_options.merge(:account_id => response.params["rbAccountId"])) + assert response = @gateway.update_recurring(@amount + 500, @visa, @recurring_options.merge(:account_id => response.params['rbAccountId'])) assert_success response end @@ -179,7 +293,7 @@ def test_successful_cancel_recurring assert response.test? assert_false response.authorization.blank? - assert response = @gateway.cancel_recurring(:account_id => response.params["rbAccountId"]) + assert response = @gateway.cancel_recurring(:account_id => response.params['rbAccountId']) assert_success response end @@ -191,29 +305,29 @@ def test_invalid_login ) assert response = gateway.purchase(@amount, @visa, @options) assert_failure response - assert_equal 'Invalid merchant id (merchant_id = 0)', response.message + assert_equal 'merchantid=Invalid merchant id (merchant_id = )', response.message end def test_successful_add_to_vault_with_store_method - assert response = @gateway.store(@visa,@options) + assert response = @gateway.store(@visa, @options) assert_equal 'Operation Successful', response.message assert_success response - assert_not_nil response.params["customer_vault_id"] + assert_not_nil response.params['customer_vault_id'] end def test_add_to_vault_with_custom_vault_id_with_store_method - @options[:vault_id] = rand(100000)+10001 + @options[:vault_id] = rand(10001..110000) assert response = @gateway.store(@visa, @options.dup) assert_equal 'Operation Successful', response.message assert_success response - assert_equal @options[:vault_id], response.params["customer_vault_id"].to_i + assert_equal @options[:vault_id], response.params['customer_vault_id'].to_i end def test_successful_add_to_vault_with_single_use_token assert response = @gateway.store(generate_single_use_token(@visa)) assert_equal 'Operation Successful', response.message, response.inspect assert_success response - assert_not_nil response.params["customer_vault_id"] + assert_not_nil response.params['customer_vault_id'] end def test_update_vault @@ -276,6 +390,7 @@ def test_transcript_scrubbing assert_scrubbed(@visa.number, clean_transcript) assert_scrubbed(@visa.verification_value.to_s, clean_transcript) assert_scrubbed(@gateway.options[:password], clean_transcript) + assert_scrubbed(@gateway.options[:api_key], clean_transcript) end private @@ -287,15 +402,15 @@ def generate_single_use_token(credit_card) http.verify_mode = OpenSSL::SSL::VERIFY_NONE request = Net::HTTP::Post.new(uri.path) - request.content_type = "application/json" + request.content_type = 'application/json' request.body = { - "number" => credit_card.number, - "expiry_month" => "01", - "expiry_year" => (Time.now.year + 1) % 100, - "cvd" => credit_card.verification_value, + 'number' => credit_card.number, + 'expiry_month' => '01', + 'expiry_year' => (Time.now.year + 1) % 100, + 'cvd' => credit_card.verification_value, }.to_json response = http.request(request) - JSON.parse(response.body)["token"] + JSON.parse(response.body)['token'] end end diff --git a/test/remote/gateways/remote_blue_pay_test.rb b/test/remote/gateways/remote_blue_pay_test.rb index 161f3a115d5..ee6b779e1b9 100644 --- a/test/remote/gateways/remote_blue_pay_test.rb +++ b/test/remote/gateways/remote_blue_pay_test.rb @@ -72,8 +72,8 @@ def test_that_we_understand_and_parse_all_keys_in_standard_response unknown_response_keys = response_keys - BluePayGateway::FIELD_MAP.values missing_response_keys = BluePayGateway::FIELD_MAP.values - response_keys - assert_empty unknown_response_keys, "unknown_response_keys" - assert_empty missing_response_keys, "missing response_keys" + assert_empty unknown_response_keys, 'unknown_response_keys' + assert_empty missing_response_keys, 'missing response_keys' end def test_that_we_understand_and_parse_all_keys_in_rebilling_response @@ -87,8 +87,8 @@ def test_that_we_understand_and_parse_all_keys_in_rebilling_response unknown_response_keys = response_keys - BluePayGateway::REBILL_FIELD_MAP.values missing_response_keys = BluePayGateway::REBILL_FIELD_MAP.values - response_keys - assert_empty unknown_response_keys, "unknown_response_keys" - assert_empty missing_response_keys, "missing response_keys" + assert_empty unknown_response_keys, 'unknown_response_keys' + assert_empty missing_response_keys, 'missing response_keys' end def test_authorization_and_capture diff --git a/test/remote/gateways/remote_blue_snap_test.rb b/test/remote/gateways/remote_blue_snap_test.rb index 36142d9b468..30394d3fa76 100644 --- a/test/remote/gateways/remote_blue_snap_test.rb +++ b/test/remote/gateways/remote_blue_snap_test.rb @@ -7,7 +7,7 @@ def setup @amount = 100 @check = check('4099999992','011075150') @credit_card = credit_card('4263982640269299') - @declined_card = credit_card('4917484589897107', month: 1, year: 2018) + @declined_card = credit_card('4917484589897107', month: 1, year: 2023) @options = { billing_address: address } end @@ -32,36 +32,44 @@ def test_successful_purchase_sans_options def test_successful_purchase_with_more_options more_options = @options.merge({ order_id: '1', - ip: "127.0.0.1", - email: "joe@example.com", - description: "Product Description", - soft_descriptor: "OnCardStatement" + ip: '127.0.0.1', + email: 'joe@example.com', + description: 'Product Description', + soft_descriptor: 'OnCardStatement' }) response = @gateway.purchase(@amount, @credit_card, more_options) assert_success response - assert_equal "Success", response.message + assert_equal 'Success', response.message + end + + def test_successful_purchase_with_currency + response = @gateway.purchase(@amount, @credit_card, @options.merge(currency: 'CAD')) + assert_success response + + assert_equal 'Success', response.message + assert_equal 'CAD', response.params['currency'] end def test_failed_purchase response = @gateway.purchase(@amount, @declined_card, @options) assert_failure response - assert_match /Authorization has failed for this transaction/, response.message - assert_equal "14002", response.error_code + assert_match(/Authorization has failed for this transaction/, response.message) + assert_equal '14002', response.error_code end def test_cvv_result response = @gateway.purchase(@amount, @credit_card, @options) assert_success response - assert_equal "CVV not processed", response.cvv_result["message"] - assert_equal "P", response.cvv_result["code"] + assert_equal 'CVV not processed', response.cvv_result['message'] + assert_equal 'P', response.cvv_result['code'] end def test_avs_result response = @gateway.purchase(@amount, @credit_card, @options) assert_success response - assert_equal "Address not verified.", response.avs_result["message"] - assert_equal "I", response.avs_result["code"] + assert_equal 'Address not verified.', response.avs_result['message'] + assert_equal 'I', response.avs_result['code'] end def test_successful_authorize_and_capture @@ -70,13 +78,13 @@ def test_successful_authorize_and_capture assert capture = @gateway.capture(@amount, auth.authorization) assert_success capture - assert_equal "Success", capture.message + assert_equal 'Success', capture.message end def test_failed_authorize response = @gateway.authorize(@amount, @declined_card, @options) assert_failure response - assert_match /Authorization has failed for this transaction/, response.message + assert_match(/Authorization has failed for this transaction/, response.message) end def test_partial_capture_succeeds_even_though_amount_is_ignored_by_gateway @@ -90,7 +98,7 @@ def test_partial_capture_succeeds_even_though_amount_is_ignored_by_gateway def test_failed_capture response = @gateway.capture(@amount, '') assert_failure response - assert_match /due to missing transaction ID/, response.message + assert_match(/due to missing transaction ID/, response.message) end def test_successful_refund @@ -99,7 +107,7 @@ def test_successful_refund assert refund = @gateway.refund(@amount, purchase.authorization, @options) assert_success refund - assert_equal "Success", refund.message + assert_equal 'Success', refund.message end def test_partial_refund @@ -107,14 +115,13 @@ def test_partial_refund assert_success purchase assert refund = @gateway.refund(@amount-1, purchase.authorization) - assert_failure refund - assert_match /failed because the financial transaction was created less than 24 hours ago/, refund.message + assert_success refund end def test_failed_refund response = @gateway.refund(@amount, '') assert_failure response - assert_match /cannot be completed due to missing transaction ID/, response.message + assert_match(/cannot be completed due to missing transaction ID/, response.message) end def test_successful_void @@ -123,44 +130,44 @@ def test_successful_void assert void = @gateway.void(auth.authorization) assert_success void - assert_equal "Success", void.message + assert_equal 'Success', void.message end def test_failed_void response = @gateway.void('') assert_failure response - assert_match /cannot be completed due to missing transaction ID/, response.message + assert_match(/cannot be completed due to missing transaction ID/, response.message) end def test_successful_verify response = @gateway.verify(@credit_card, @options) assert_success response - assert_equal "Success", response.message + assert_equal 'Success', response.message end def test_failed_verify response = @gateway.verify(@declined_card, @options) assert_failure response - assert_match /Authorization has failed for this transaction/, response.message + assert_match(/Authorization has failed for this transaction/, response.message) end def test_successful_store assert response = @gateway.store(@credit_card, @options) assert_success response - assert_equal "Success", response.message + assert_equal 'Success', response.message assert response.authorization - assert_equal "I", response.avs_result["code"] - assert_equal "P", response.cvv_result["code"] - assert_match /services\/2\/vaulted-shoppers/, response.params["content-location-header"] + assert_equal 'I', response.avs_result['code'] + assert_equal 'P', response.cvv_result['code'] + assert_match(/services\/2\/vaulted-shoppers/, response.params['content-location-header']) end def test_failed_store assert response = @gateway.store(@declined_card, @options) assert_failure response - assert_match /Transaction failed because of payment processing failure/, response.message - assert_equal "14002", response.error_code + assert_match(/Transaction failed because of payment processing failure/, response.message) + assert_equal '14002', response.error_code end def test_successful_purchase_using_stored_card @@ -186,7 +193,7 @@ def test_invalid_login response = gateway.purchase(@amount, @credit_card, @options) assert_failure response - assert_match "Unable to authenticate. Please check your credentials.", response.message + assert_match 'Unable to authenticate. Please check your credentials.', response.message end def test_verify_credentials @@ -196,7 +203,6 @@ def test_verify_credentials assert !gateway.verify_credentials end - def test_transcript_scrubbing transcript = capture_transcript(@gateway) do @gateway.purchase(@amount, @credit_card, @options) diff --git a/test/remote/gateways/remote_borgun_test.rb b/test/remote/gateways/remote_borgun_test.rb index 1d41f1f8b99..32f7b1b6fc7 100644 --- a/test/remote/gateways/remote_borgun_test.rb +++ b/test/remote/gateways/remote_borgun_test.rb @@ -8,7 +8,7 @@ def setup @gateway = BorgunGateway.new(fixtures(:borgun)) @amount = 100 - @credit_card = credit_card('5587402000012011', year: 2014, month: 9, verification_value: 415) + @credit_card = credit_card('5587402000012011', year: 2018, month: 9, verification_value: 415) @declined_card = credit_card('4155520000000002') @options = { @@ -28,6 +28,12 @@ def test_successful_purchase assert_equal 'Succeeded', response.message end + def test_successful_purchase_usd + response = @gateway.purchase(@amount, @credit_card, @options.merge(currency: 'USD')) + assert_success response + assert_equal 'Succeeded', response.message + end + def test_successful_purchase_without_options response = @gateway.purchase(@amount, @credit_card) assert_success response @@ -48,6 +54,14 @@ def test_successful_authorize_and_capture assert_success capture end + def test_successful_authorize_and_capture_usd + auth = @gateway.authorize(@amount, @credit_card, @options.merge(currency: 'USD')) + assert_success auth + + assert capture = @gateway.capture(@amount, auth.authorization, currency: 'USD') + assert_success capture + end + def test_failed_authorize response = @gateway.authorize(@amount, @declined_card, @options) assert_failure response @@ -74,6 +88,14 @@ def test_successful_refund assert_success refund end + def test_successful_refund_usd + purchase = @gateway.purchase(@amount, @credit_card, @options.merge(currency: 'USD')) + assert_success purchase + + assert refund = @gateway.refund(@amount, purchase.authorization, currency: 'USD') + assert_success refund + end + def test_partial_refund purchase = @gateway.purchase(@amount, @credit_card, @options) assert_success purchase @@ -95,11 +117,39 @@ def test_successful_void assert_success void end + def test_successful_void_with_no_currency_in_authorization + auth = @gateway.authorize(@amount, @credit_card, @options) + assert_success auth + + *new_auth, _ = auth.authorization.split('|') + assert void = @gateway.void(new_auth.join('|')) + assert_success void + end + + def test_successful_void_usd + auth = @gateway.authorize(@amount, @credit_card, @options.merge(currency: 'USD')) + assert_success auth + + assert void = @gateway.void(auth.authorization) + assert_success void + end + + def test_successful_void_usd_with_options + auth = @gateway.authorize(@amount, @credit_card, @options.merge(currency: 'USD')) + assert_success auth + + assert void = @gateway.void(auth.authorization, @options.merge(currency: 'USD')) + assert_success void + end + def test_failed_void response = @gateway.void('') assert_failure response end + # This test does not consistently pass. When run multiple times within 1 minute, + # an ActiveMerchant::ConnectionError(<The remote server reset the connection>) + # exception is raised. def test_invalid_login gateway = BorgunGateway.new( processor: '0', @@ -107,10 +157,20 @@ def test_invalid_login username: 'not', password: 'right' ) - authentication_exception = assert_raise ActiveMerchant::ResponseError, 'Failed with 500 Internal Server Error' do + authentication_exception = assert_raise ActiveMerchant::ResponseError, 'Failed with 401 [ISS.0084.9001] Invalid credentials' do gateway.purchase(@amount, @credit_card, @options) end assert response = authentication_exception.response assert_match(/Access Denied/, response.body) end + + def test_transcript_scrubbing + transcript = capture_transcript(@gateway) do + @gateway.purchase(@amount, @credit_card, @options) + end + transcript = @gateway.scrub(transcript) + + assert_scrubbed(@credit_card.number, transcript) + assert_scrubbed(@credit_card.verification_value, transcript) + end end diff --git a/test/remote/gateways/remote_bpoint_test.rb b/test/remote/gateways/remote_bpoint_test.rb index e430cb9eb34..32f0124e787 100644 --- a/test/remote/gateways/remote_bpoint_test.rb +++ b/test/remote/gateways/remote_bpoint_test.rb @@ -21,7 +21,7 @@ def setup def test_successful_store response = @gateway.store(@credit_card, { crn1: 'TEST' }) assert_success response - assert_equal "Success", response.message + assert_equal 'Success', response.message token_key = 'AddTokenResult_Token' assert_not_nil response.params[token_key] assert_not_nil response.authorization @@ -31,7 +31,7 @@ def test_successful_store def test_failed_store response = @gateway.store(@error_card) assert_failure response - assert_equal "Error", response.message + assert_equal 'Error', response.message end def test_successful_purchase diff --git a/test/remote/gateways/remote_braintree_blue_test.rb b/test/remote/gateways/remote_braintree_blue_test.rb index 973c4eae67e..c6cd935e7db 100644 --- a/test/remote/gateways/remote_braintree_blue_test.rb +++ b/test/remote/gateways/remote_braintree_blue_test.rb @@ -3,7 +3,7 @@ class RemoteBraintreeBlueTest < Test::Unit::TestCase def setup @gateway = BraintreeGateway.new(fixtures(:braintree_blue)) - @braintree_backend = @gateway.instance_eval{@braintree_gateway} + @braintree_backend = @gateway.instance_eval { @braintree_gateway } @amount = 100 @declined_amount = 2000_00 @@ -12,7 +12,7 @@ def setup @options = { :order_id => '1', - :billing_address => address(:country_name => "United States of America"), + :billing_address => address(:country_name => 'United States of America'), :description => 'Store Purchase' } end @@ -20,37 +20,58 @@ def setup def test_credit_card_details_on_store assert response = @gateway.store(@credit_card) assert_success response - assert_equal '5100', response.params["braintree_customer"]["credit_cards"].first["last_4"] - assert_equal('510510******5100', response.params["braintree_customer"]["credit_cards"].first["masked_number"]) - assert_equal('5100', response.params["braintree_customer"]["credit_cards"].first["last_4"]) - assert_equal('MasterCard', response.params["braintree_customer"]["credit_cards"].first["card_type"]) - assert_equal('510510', response.params["braintree_customer"]["credit_cards"].first["bin"]) - assert_match %r{^\d+$}, response.params["customer_vault_id"] - assert_equal response.params["customer_vault_id"], response.authorization - assert_match %r{^\w+$}, response.params["credit_card_token"] - assert_equal response.params["credit_card_token"], response.params["braintree_customer"]["credit_cards"].first["token"] + assert_equal '5100', response.params['braintree_customer']['credit_cards'].first['last_4'] + assert_equal('510510******5100', response.params['braintree_customer']['credit_cards'].first['masked_number']) + assert_equal('5100', response.params['braintree_customer']['credit_cards'].first['last_4']) + assert_equal('MasterCard', response.params['braintree_customer']['credit_cards'].first['card_type']) + assert_equal('510510', response.params['braintree_customer']['credit_cards'].first['bin']) + assert_match %r{^\d+$}, response.params['customer_vault_id'] + assert_equal response.params['customer_vault_id'], response.authorization + assert_match %r{^\w+$}, response.params['credit_card_token'] + assert_equal response.params['credit_card_token'], response.params['braintree_customer']['credit_cards'].first['token'] end def test_successful_authorize assert response = @gateway.authorize(@amount, @credit_card, @options) assert_success response assert_equal '1000 Approved', response.message - assert_equal 'authorized', response.params["braintree_transaction"]["status"] + assert_equal 'authorized', response.params['braintree_transaction']['status'] + end + + def test_successful_authorize_with_nil_billing_address_options + credit_card = credit_card('5105105105105100') + options = { + :billing_address => { + :name => 'John Smith', + :phone => '123-456-7890', + :company => nil, + :address1 => nil, + :address2 => '', + :city => nil, + :state => nil, + :zip => nil, + :country_name => nil + } + } + assert response = @gateway.authorize(@amount, credit_card, options) + assert_success response + assert_equal '1000 Approved', response.message + assert_equal 'authorized', response.params['braintree_transaction']['status'] end def test_masked_card_number assert response = @gateway.authorize(@amount, @credit_card, @options) - assert_equal('510510******5100', response.params["braintree_transaction"]["credit_card_details"]["masked_number"]) - assert_equal('5100', response.params["braintree_transaction"]["credit_card_details"]["last_4"]) - assert_equal('MasterCard', response.params["braintree_transaction"]["credit_card_details"]["card_type"]) - assert_equal('510510', response.params["braintree_transaction"]["credit_card_details"]["bin"]) + assert_equal('510510******5100', response.params['braintree_transaction']['credit_card_details']['masked_number']) + assert_equal('5100', response.params['braintree_transaction']['credit_card_details']['last_4']) + assert_equal('MasterCard', response.params['braintree_transaction']['credit_card_details']['card_type']) + assert_equal('510510', response.params['braintree_transaction']['credit_card_details']['bin']) end def test_successful_authorize_with_order_id assert response = @gateway.authorize(@amount, @credit_card, :order_id => '123') assert_success response assert_equal '1000 Approved', response.message - assert_equal '123', response.params["braintree_transaction"]["order_id"] + assert_equal '123', response.params['braintree_transaction']['order_id'] end def test_successful_purchase_with_hold_in_escrow @@ -64,47 +85,47 @@ def test_successful_purchase_using_vault_id assert response = @gateway.store(@credit_card) assert_success response assert_equal 'OK', response.message - customer_vault_id = response.params["customer_vault_id"] + customer_vault_id = response.params['customer_vault_id'] assert_match(/\A\d+\z/, customer_vault_id) assert response = @gateway.purchase(@amount, customer_vault_id) assert_success response assert_equal '1000 Approved', response.message - assert_equal 'submitted_for_settlement', response.params["braintree_transaction"]["status"] - assert_equal customer_vault_id, response.params["braintree_transaction"]["customer_details"]["id"] + assert_equal 'submitted_for_settlement', response.params['braintree_transaction']['status'] + assert_equal customer_vault_id, response.params['braintree_transaction']['customer_details']['id'] end def test_successful_purchase_using_vault_id_as_integer assert response = @gateway.store(@credit_card) assert_success response assert_equal 'OK', response.message - customer_vault_id = response.params["customer_vault_id"] + customer_vault_id = response.params['customer_vault_id'] assert_match %r{\A\d+\z}, customer_vault_id assert response = @gateway.purchase(@amount, customer_vault_id.to_i) assert_success response assert_equal '1000 Approved', response.message - assert_equal 'submitted_for_settlement', response.params["braintree_transaction"]["status"] - assert_equal customer_vault_id, response.params["braintree_transaction"]["customer_details"]["id"] + assert_equal 'submitted_for_settlement', response.params['braintree_transaction']['status'] + assert_equal customer_vault_id, response.params['braintree_transaction']['customer_details']['id'] end def test_successful_purchase_using_card_token assert response = @gateway.store(@credit_card) assert_success response assert_equal 'OK', response.message - credit_card_token = response.params["credit_card_token"] + credit_card_token = response.params['credit_card_token'] assert_match %r{^\w+$}, credit_card_token assert response = @gateway.purchase(@amount, credit_card_token, :payment_method_token => true) assert_success response assert_equal '1000 Approved', response.message - assert_equal 'submitted_for_settlement', response.params["braintree_transaction"]["status"] + assert_equal 'submitted_for_settlement', response.params['braintree_transaction']['status'] end def test_successful_verify assert response = @gateway.verify(@credit_card, @options) assert_success response - assert_equal "1000 Approved", response.message + assert_equal '1000 Approved', response.message end def test_failed_verify @@ -142,12 +163,12 @@ def test_successful_store_with_invalid_card def test_successful_store_with_billing_address billing_address = { - :address1 => "1 E Main St", - :address2 => "Suite 403", - :city => "Chicago", - :state => "Illinois", - :zip => "60622", - :country_name => "United States of America" + :address1 => '1 E Main St', + :address2 => 'Suite 403', + :city => 'Chicago', + :state => 'Illinois', + :zip => '60622', + :country_name => 'United States of America' } credit_card = credit_card('5105105105105100') assert response = @gateway.store(credit_card, :billing_address => billing_address) @@ -157,24 +178,46 @@ def test_successful_store_with_billing_address vault_id = response.params['customer_vault_id'] purchase_response = @gateway.purchase(@amount, vault_id) response_billing_details = { - "country_name"=>"United States of America", - "region"=>"Illinois", - "company"=>nil, - "postal_code"=>"60622", - "extended_address"=>"Suite 403", - "street_address"=>"1 E Main St", - "locality"=>"Chicago" + 'country_name'=>'United States of America', + 'region'=>'Illinois', + 'company'=>nil, + 'postal_code'=>'60622', + 'extended_address'=>'Suite 403', + 'street_address'=>'1 E Main St', + 'locality'=>'Chicago' } assert_equal purchase_response.params['braintree_transaction']['billing_details'], response_billing_details end + def test_successful_store_with_nil_billing_address_options + billing_address = { + :name => 'John Smith', + :phone => '123-456-7890', + :company => nil, + :address1 => nil, + :address2 => nil, + :city => nil, + :state => nil, + :zip => nil, + :country_name => nil + } + credit_card = credit_card('5105105105105100') + assert response = @gateway.store(credit_card, :billing_address => billing_address) + assert_success response + assert_equal 'OK', response.message + + vault_id = response.params['customer_vault_id'] + purchase_response = @gateway.purchase(@amount, vault_id) + assert_success purchase_response + end + def test_successful_store_with_credit_card_token credit_card = credit_card('5105105105105100') credit_card_token = generate_unique_id assert response = @gateway.store(credit_card, credit_card_token: credit_card_token) assert_success response assert_equal 'OK', response.message - assert_equal credit_card_token, response.params["braintree_customer"]["credit_cards"][0]["token"] + assert_equal credit_card_token, response.params['braintree_customer']['credit_cards'][0]['token'] end def test_successful_store_with_new_customer_id @@ -184,7 +227,7 @@ def test_successful_store_with_new_customer_id assert_success response assert_equal 'OK', response.message assert_equal customer_id, response.authorization - assert_equal customer_id, response.params["braintree_customer"]["id"] + assert_equal customer_id, response.params['braintree_customer']['id'] end def test_successful_store_with_existing_customer_id @@ -197,16 +240,45 @@ def test_successful_store_with_existing_customer_id assert response = @gateway.store(credit_card, customer: customer_id) assert_success response assert_equal 2, @braintree_backend.customer.find(customer_id).credit_cards.size - assert_equal customer_id, response.params["customer_vault_id"] + assert_equal customer_id, response.params['customer_vault_id'] assert_equal customer_id, response.authorization - assert_not_nil response.params["credit_card_token"] + assert_not_nil response.params['credit_card_token'] + end + + def test_successful_store_with_existing_customer_id_and_nil_billing_address_options + credit_card = credit_card('5105105105105100') + customer_id = generate_unique_id + options = { + :customer => customer_id, + :billing_address => { + :name => 'John Smith', + :phone => '123-456-7890', + :company => nil, + :address1 => nil, + :address2 => nil, + :city => nil, + :state => nil, + :zip => nil, + :country_name => nil + } + } + assert response = @gateway.store(credit_card, options) + assert_success response + assert_equal 1, @braintree_backend.customer.find(customer_id).credit_cards.size + + assert response = @gateway.store(credit_card, options) + assert_success response + assert_equal 2, @braintree_backend.customer.find(customer_id).credit_cards.size + assert_equal customer_id, response.params['customer_vault_id'] + assert_equal customer_id, response.authorization + assert_not_nil response.params['credit_card_token'] end def test_successful_purchase assert response = @gateway.purchase(@amount, @credit_card, @options) assert_success response assert_equal '1000 Approved', response.message - assert_equal 'submitted_for_settlement', response.params["braintree_transaction"]["status"] + assert_equal 'submitted_for_settlement', response.params['braintree_transaction']['status'] end def test_successful_purchase_with_solution_id @@ -214,34 +286,34 @@ def test_successful_purchase_with_solution_id assert response = @gateway.purchase(@amount, @credit_card, @options) assert_success response assert_equal '1000 Approved', response.message - assert_equal 'submitted_for_settlement', response.params["braintree_transaction"]["status"] + assert_equal 'submitted_for_settlement', response.params['braintree_transaction']['status'] ensure ActiveMerchant::Billing::BraintreeBlueGateway.application_id = nil end def test_avs - assert_avs("1 Elm", "60622", "M") - assert_avs("1 Elm", "20000", "A") - assert_avs("1 Elm", "20001", "B") - assert_avs("1 Elm", "", "B") + assert_avs('1 Elm', '60622', 'M') + assert_avs('1 Elm', '20000', 'A') + assert_avs('1 Elm', '20001', 'B') + assert_avs('1 Elm', '', 'B') - assert_avs("200 Elm", "60622", "Z") - assert_avs("200 Elm", "20000", "C") - assert_avs("200 Elm", "20001", "C") - assert_avs("200 Elm", "", "C") + assert_avs('200 Elm', '60622', 'Z') + assert_avs('200 Elm', '20000', 'C') + assert_avs('200 Elm', '20001', 'C') + assert_avs('200 Elm', '', 'C') - assert_avs("201 Elm", "60622", "P") - assert_avs("201 Elm", "20000", "N") - assert_avs("201 Elm", "20001", "I") - assert_avs("201 Elm", "", "I") + assert_avs('201 Elm', '60622', 'P') + assert_avs('201 Elm', '20000', 'N') + assert_avs('201 Elm', '20001', 'I') + assert_avs('201 Elm', '', 'I') - assert_avs("", "60622", "P") - assert_avs("", "20000", "C") - assert_avs("", "20001", "I") - assert_avs("", "", "I") + assert_avs('', '60622', 'P') + assert_avs('', '20000', 'C') + assert_avs('', '20001', 'I') + assert_avs('', '', 'I') - assert_avs("1 Elm", "30000", "E") - assert_avs("1 Elm", "30001", "S") + assert_avs('1 Elm', '30000', 'E') + assert_avs('1 Elm', '30001', 'S') end def test_cvv_match @@ -258,11 +330,32 @@ def test_cvv_no_match def test_successful_purchase_with_email assert response = @gateway.purchase(@amount, @credit_card, - :email => "customer@example.com" + :email => 'customer@example.com' ) assert_success response - transaction = response.params["braintree_transaction"] - assert_equal 'customer@example.com', transaction["customer_details"]["email"] + transaction = response.params['braintree_transaction'] + assert_equal 'customer@example.com', transaction['customer_details']['email'] + end + + def test_successful_purchase_with_phone + assert response = @gateway.purchase(@amount, @credit_card, :phone => '123-345-5678') + assert_success response + transaction = response.params['braintree_transaction'] + assert_equal '123-345-5678', transaction['customer_details']['phone'] + end + + def test_successful_purchase_with_phone_from_address + assert response = @gateway.purchase(@amount, @credit_card, @options) + assert_success response + transaction = response.params['braintree_transaction'] + assert_equal '(555)555-5555', transaction['customer_details']['phone'] + end + + def test_successful_purchase_with_skip_advanced_fraud_checking_option + assert response = @gateway.purchase(@amount, @credit_card, @options.merge(skip_advanced_fraud_checking: true)) + assert_success response + assert_equal '1000 Approved', response.message + assert_equal 'submitted_for_settlement', response.params['braintree_transaction']['status'] end def test_purchase_with_store_using_random_customer_id @@ -271,9 +364,9 @@ def test_purchase_with_store_using_random_customer_id ) assert_success response assert_equal '1000 Approved', response.message - assert_match(/\A\d+\z/, response.params["customer_vault_id"]) - assert_equal '510510', response.params["braintree_transaction"]["vault_customer"]["credit_cards"][0]["bin"] - assert_equal '510510', @braintree_backend.customer.find(response.params["customer_vault_id"]).credit_cards[0].bin + assert_match(/\A\d+\z/, response.params['customer_vault_id']) + assert_equal '510510', response.params['braintree_transaction']['vault_customer']['credit_cards'][0]['bin'] + assert_equal '510510', @braintree_backend.customer.find(response.params['customer_vault_id']).credit_cards[0].bin end def test_purchase_with_store_using_specified_customer_id @@ -283,9 +376,9 @@ def test_purchase_with_store_using_specified_customer_id ) assert_success response assert_equal '1000 Approved', response.message - assert_equal customer_id, response.params["customer_vault_id"] - assert_equal '510510', response.params["braintree_transaction"]["vault_customer"]["credit_cards"][0]["bin"] - assert_equal '510510', @braintree_backend.customer.find(response.params["customer_vault_id"]).credit_cards[0].bin + assert_equal customer_id, response.params['customer_vault_id'] + assert_equal '510510', response.params['braintree_transaction']['vault_customer']['credit_cards'][0]['bin'] + assert_equal '510510', @braintree_backend.customer.find(response.params['customer_vault_id']).credit_cards[0].bin end def test_purchase_using_specified_payment_method_token @@ -294,15 +387,16 @@ def test_purchase_using_specified_payment_method_token :first_name => 'Old First', :last_name => 'Old Last', :month => 9, :year => 2012 ), - :email => "old@example.com" + :email => 'old@example.com', + :phone => '321-654-0987' ) - payment_method_token = response.params["braintree_customer"]["credit_cards"][0]["token"] + payment_method_token = response.params['braintree_customer']['credit_cards'][0]['token'] assert response = @gateway.purchase( @amount, payment_method_token, @options.merge(payment_method_token: true) ) assert_success response assert_equal '1000 Approved', response.message - assert_equal payment_method_token, response.params["braintree_transaction"]["credit_card_details"]["token"] + assert_equal payment_method_token, response.params['braintree_transaction']['credit_card_details']['token'] end def test_successful_purchase_with_addresses @@ -329,21 +423,29 @@ def test_successful_purchase_with_addresses :shipping_address => shipping_address ) assert_success response - transaction = response.params["braintree_transaction"] - assert_equal '1 E Main St', transaction["billing_details"]["street_address"] - assert_equal 'Suite 101', transaction["billing_details"]["extended_address"] - assert_equal 'Widgets Co', transaction["billing_details"]["company"] - assert_equal 'Chicago', transaction["billing_details"]["locality"] - assert_equal 'IL', transaction["billing_details"]["region"] - assert_equal '60622', transaction["billing_details"]["postal_code"] - assert_equal 'United States of America', transaction["billing_details"]["country_name"] - assert_equal '1 W Main St', transaction["shipping_details"]["street_address"] - assert_equal 'Suite 102', transaction["shipping_details"]["extended_address"] - assert_equal 'Widgets Company', transaction["shipping_details"]["company"] - assert_equal 'Bartlett', transaction["shipping_details"]["locality"] - assert_equal 'Illinois', transaction["shipping_details"]["region"] - assert_equal '60103', transaction["shipping_details"]["postal_code"] - assert_equal 'Mexico', transaction["shipping_details"]["country_name"] + transaction = response.params['braintree_transaction'] + assert_equal '1 E Main St', transaction['billing_details']['street_address'] + assert_equal 'Suite 101', transaction['billing_details']['extended_address'] + assert_equal 'Widgets Co', transaction['billing_details']['company'] + assert_equal 'Chicago', transaction['billing_details']['locality'] + assert_equal 'IL', transaction['billing_details']['region'] + assert_equal '60622', transaction['billing_details']['postal_code'] + assert_equal 'United States of America', transaction['billing_details']['country_name'] + assert_equal '1 W Main St', transaction['shipping_details']['street_address'] + assert_equal 'Suite 102', transaction['shipping_details']['extended_address'] + assert_equal 'Widgets Company', transaction['shipping_details']['company'] + assert_equal 'Bartlett', transaction['shipping_details']['locality'] + assert_equal 'Illinois', transaction['shipping_details']['region'] + assert_equal '60103', transaction['shipping_details']['postal_code'] + assert_equal 'Mexico', transaction['shipping_details']['country_name'] + end + + def test_successful_purchase_with_three_d_secure_pass_thru + three_d_secure_params = { eci: '05', cavv: 'cavv', xid: 'xid' } + assert response = @gateway.purchase(@amount, @credit_card, + three_d_secure: three_d_secure_params + ) + assert_success response end def test_unsuccessful_purchase_declined @@ -357,7 +459,7 @@ def test_unsuccessful_purchase_validation_error assert response = @gateway.purchase(@amount, credit_card('51051051051051000')) assert_failure response assert_match %r{Credit card number is invalid\. \(81715\)}, response.message - assert_equal({"processor_response_code"=>"91577"}, response.params["braintree_transaction"]) + assert_equal({'processor_response_code'=>'91577'}, response.params['braintree_transaction']) end def test_authorize_and_capture @@ -372,8 +474,8 @@ def test_authorize_and_capture def test_authorize_and_capture_with_apple_pay_card credit_card = network_tokenization_credit_card('4111111111111111', :brand => 'visa', - :eci => "05", - :payment_cryptogram => "EHuWW9PiBkWvqE5juRwDzAUFBAk=" + :eci => '05', + :payment_cryptogram => 'EHuWW9PiBkWvqE5juRwDzAUFBAk=' ) assert auth = @gateway.authorize(@amount, credit_card, @options) @@ -386,11 +488,30 @@ def test_authorize_and_capture_with_apple_pay_card def test_authorize_and_capture_with_android_pay_card credit_card = network_tokenization_credit_card('4111111111111111', - :payment_cryptogram => "EHuWW9PiBkWvqE5juRwDzAUFBAk=", - :month => "01", - :year => "2024", + :payment_cryptogram => 'EHuWW9PiBkWvqE5juRwDzAUFBAk=', + :month => '01', + :year => '2024', :source => :android_pay, - :transaction_id => "123456789" + :transaction_id => '123456789', + :eci => '05' + ) + + assert auth = @gateway.authorize(@amount, credit_card, @options) + assert_success auth + assert_equal '1000 Approved', auth.message + assert auth.authorization + assert capture = @gateway.capture(@amount, auth.authorization) + assert_success capture + end + + def test_authorize_and_capture_with_google_pay_card + credit_card = network_tokenization_credit_card('4111111111111111', + :payment_cryptogram => 'EHuWW9PiBkWvqE5juRwDzAUFBAk=', + :month => '01', + :year => '2024', + :source => :google_pay, + :transaction_id => '123456789', + :eci => '05' ) assert auth = @gateway.authorize(@amount, credit_card, @options) @@ -408,7 +529,7 @@ def test_authorize_and_void assert auth.authorization assert void = @gateway.void(auth.authorization) assert_success void - assert_equal 'voided', void.params["braintree_transaction"]["status"] + assert_equal 'voided', void.params['braintree_transaction']['status'] end def test_purchase_and_void @@ -416,7 +537,7 @@ def test_purchase_and_void assert_success purchase assert void = @gateway.void(purchase.authorization) assert_success void - assert_equal 'voided', void.params["braintree_transaction"]["status"] + assert_equal 'voided', void.params['braintree_transaction']['status'] end def test_capture_and_void @@ -428,7 +549,7 @@ def test_capture_and_void assert void = @gateway.void(capture.authorization) assert_success void - assert_equal 'voided', void.params["braintree_transaction"]["status"] + assert_equal 'voided', void.params['braintree_transaction']['status'] end def test_failed_void @@ -438,11 +559,11 @@ def test_failed_void assert auth.authorization assert void = @gateway.void(auth.authorization) assert_success void - assert_equal 'voided', void.params["braintree_transaction"]["status"] + assert_equal 'voided', void.params['braintree_transaction']['status'] assert failed_void = @gateway.void(auth.authorization) assert_failure failed_void - assert_equal 'Transaction can only be voided if status is authorized or submitted_for_settlement. (91504)', failed_void.message - assert_equal({"processor_response_code"=>"91504"}, failed_void.params["braintree_transaction"]) + assert_match('Transaction can only be voided if status is authorized', failed_void.message) + assert_equal({'processor_response_code'=>'91504'}, failed_void.params['braintree_transaction']) end def test_failed_capture_with_invalid_transaction_id @@ -452,7 +573,7 @@ def test_failed_capture_with_invalid_transaction_id end def test_invalid_login - gateway = BraintreeBlueGateway.new(:merchant_id => "invalid", :public_key => "invalid", :private_key => "invalid") + gateway = BraintreeBlueGateway.new(:merchant_id => 'invalid', :public_key => 'invalid', :private_key => 'invalid') assert response = gateway.purchase(@amount, @credit_card, @options) assert_failure response assert_equal 'Braintree::AuthenticationError', response.message @@ -462,22 +583,22 @@ def test_successful_add_to_vault_with_store_method assert response = @gateway.store(@credit_card) assert_success response assert_equal 'OK', response.message - assert_match(/\A\d+\z/, response.params["customer_vault_id"]) + assert_match(/\A\d+\z/, response.params['customer_vault_id']) end def test_failed_add_to_vault assert response = @gateway.store(credit_card('5105105105105101')) assert_failure response assert_equal 'Credit card number is invalid. (81715)', response.message - assert_equal nil, response.params["braintree_customer"] - assert_equal nil, response.params["customer_vault_id"] + assert_equal nil, response.params['braintree_customer'] + assert_equal nil, response.params['customer_vault_id'] end def test_unstore_customer assert response = @gateway.store(@credit_card) assert_success response assert_equal 'OK', response.message - assert customer_vault_id = response.params["customer_vault_id"] + assert customer_vault_id = response.params['customer_vault_id'] assert delete_response = @gateway.unstore(customer_vault_id) assert_success delete_response end @@ -486,7 +607,7 @@ def test_unstore_credit_card assert response = @gateway.store(@credit_card) assert_success response assert_equal 'OK', response.message - assert credit_card_token = response.params["credit_card_token"] + assert credit_card_token = response.params['credit_card_token'] assert delete_response = @gateway.unstore(nil, credit_card_token: credit_card_token) assert_success delete_response end @@ -495,7 +616,7 @@ def test_unstore_with_delete_method assert response = @gateway.store(@credit_card) assert_success response assert_equal 'OK', response.message - assert customer_vault_id = response.params["customer_vault_id"] + assert customer_vault_id = response.params['customer_vault_id'] assert delete_response = @gateway.delete(customer_vault_id) assert_success delete_response end @@ -506,19 +627,21 @@ def test_successful_update :first_name => 'Old First', :last_name => 'Old Last', :month => 9, :year => 2012 ), - :email => "old@example.com" + :email => 'old@example.com', + :phone => '321-654-0987' ) assert_success response assert_equal 'OK', response.message - customer_vault_id = response.params["customer_vault_id"] + customer_vault_id = response.params['customer_vault_id'] assert_match(/\A\d+\z/, customer_vault_id) - assert_equal "old@example.com", response.params["braintree_customer"]["email"] - assert_equal "Old First", response.params["braintree_customer"]["first_name"] - assert_equal "Old Last", response.params["braintree_customer"]["last_name"] - assert_equal "411111", response.params["braintree_customer"]["credit_cards"][0]["bin"] - assert_equal "09/2012", response.params["braintree_customer"]["credit_cards"][0]["expiration_date"] - assert_not_nil response.params["braintree_customer"]["credit_cards"][0]["token"] - assert_equal customer_vault_id, response.params["braintree_customer"]["id"] + assert_equal 'old@example.com', response.params['braintree_customer']['email'] + assert_equal '321-654-0987', response.params['braintree_customer']['phone'] + assert_equal 'Old First', response.params['braintree_customer']['first_name'] + assert_equal 'Old Last', response.params['braintree_customer']['last_name'] + assert_equal '411111', response.params['braintree_customer']['credit_cards'][0]['bin'] + assert_equal '09/2012', response.params['braintree_customer']['credit_cards'][0]['expiration_date'] + assert_not_nil response.params['braintree_customer']['credit_cards'][0]['token'] + assert_equal customer_vault_id, response.params['braintree_customer']['id'] assert response = @gateway.update( customer_vault_id, @@ -526,23 +649,25 @@ def test_successful_update :first_name => 'New First', :last_name => 'New Last', :month => 10, :year => 2014 ), - :email => "new@example.com" + :email => 'new@example.com', + :phone => '987-765-5432' ) assert_success response - assert_equal "new@example.com", response.params["braintree_customer"]["email"] - assert_equal "New First", response.params["braintree_customer"]["first_name"] - assert_equal "New Last", response.params["braintree_customer"]["last_name"] - assert_equal "510510", response.params["braintree_customer"]["credit_cards"][0]["bin"] - assert_equal "10/2014", response.params["braintree_customer"]["credit_cards"][0]["expiration_date"] - assert_not_nil response.params["braintree_customer"]["credit_cards"][0]["token"] - assert_equal customer_vault_id, response.params["braintree_customer"]["id"] + assert_equal 'new@example.com', response.params['braintree_customer']['email'] + assert_equal '987-765-5432', response.params['braintree_customer']['phone'] + assert_equal 'New First', response.params['braintree_customer']['first_name'] + assert_equal 'New Last', response.params['braintree_customer']['last_name'] + assert_equal '510510', response.params['braintree_customer']['credit_cards'][0]['bin'] + assert_equal '10/2014', response.params['braintree_customer']['credit_cards'][0]['expiration_date'] + assert_not_nil response.params['braintree_customer']['credit_cards'][0]['token'] + assert_equal customer_vault_id, response.params['braintree_customer']['id'] end def test_failed_customer_update - assert response = @gateway.store(credit_card('4111111111111111'), :email => "email@example.com") + assert response = @gateway.store(credit_card('4111111111111111'), :email => 'email@example.com', :phone => '321-654-0987') assert_success response assert_equal 'OK', response.message - assert customer_vault_id = response.params["customer_vault_id"] + assert customer_vault_id = response.params['customer_vault_id'] assert response = @gateway.update( customer_vault_id, @@ -550,8 +675,8 @@ def test_failed_customer_update ) assert_failure response assert_equal 'Credit card number is invalid. (81715)', response.message - assert_equal nil, response.params["braintree_customer"] - assert_equal nil, response.params["customer_vault_id"] + assert_equal nil, response.params['braintree_customer'] + assert_equal nil, response.params['customer_vault_id'] end def test_failed_customer_update_invalid_vault_id @@ -564,7 +689,7 @@ def test_failed_credit_card_update assert response = @gateway.store(credit_card('4111111111111111')) assert_success response assert_equal 'OK', response.message - assert customer_vault_id = response.params["customer_vault_id"] + assert customer_vault_id = response.params['customer_vault_id'] assert response = @gateway.update( customer_vault_id, @@ -578,7 +703,7 @@ def test_failed_credit_card_update_on_verify assert response = @gateway.store(credit_card('4111111111111111')) assert_success response assert_equal 'OK', response.message - assert customer_vault_id = response.params["customer_vault_id"] + assert customer_vault_id = response.params['customer_vault_id'] assert response = @gateway.update( customer_vault_id, @@ -598,40 +723,40 @@ def test_customer_does_not_have_credit_card_failed_update def test_successful_credit assert response = @gateway.credit(@amount, @credit_card, @options) - assert_success response, "You must get credits enabled in your Sandbox account for this to pass." + assert_success response, 'You must get credits enabled in your Sandbox account for this to pass.' assert_equal '1002 Processed', response.message - assert_equal 'submitted_for_settlement', response.params["braintree_transaction"]["status"] + assert_equal 'submitted_for_settlement', response.params['braintree_transaction']['status'] end def test_failed_credit assert response = @gateway.credit(@amount, credit_card('5105105105105101'), @options) assert_failure response - assert_equal 'Credit card number is invalid. (81715)', response.message, "You must get credits enabled in your Sandbox account for this to pass" + assert_equal 'Credit card number is invalid. (81715)', response.message, 'You must get credits enabled in your Sandbox account for this to pass' end def test_successful_credit_with_merchant_account_id assert response = @gateway.credit(@amount, @credit_card, :merchant_account_id => fixtures(:braintree_blue)[:merchant_account_id]) - assert_success response, "You must specify a valid :merchant_account_id key in your fixtures.yml AND get credits enabled in your Sandbox account for this to pass." + assert_success response, 'You must specify a valid :merchant_account_id key in your fixtures.yml AND get credits enabled in your Sandbox account for this to pass.' assert_equal '1002 Processed', response.message - assert_equal 'submitted_for_settlement', response.params["braintree_transaction"]["status"] + assert_equal 'submitted_for_settlement', response.params['braintree_transaction']['status'] end def test_successful_authorize_with_merchant_account_id assert response = @gateway.authorize(@amount, @credit_card, :merchant_account_id => fixtures(:braintree_blue)[:merchant_account_id]) - assert_success response, "You must specify a valid :merchant_account_id key in your fixtures.yml for this to pass." + assert_success response, 'You must specify a valid :merchant_account_id key in your fixtures.yml for this to pass.' assert_equal '1000 Approved', response.message - assert_equal fixtures(:braintree_blue)[:merchant_account_id], response.params["braintree_transaction"]["merchant_account_id"] + assert_equal 'authorized', response.params['braintree_transaction']['status'] end def test_authorize_with_descriptor - assert auth = @gateway.authorize(@amount, @credit_card, descriptor_name: "company*theproduct", descriptor_phone: "1331131131", descriptor_url: "company.com") + assert auth = @gateway.authorize(@amount, @credit_card, descriptor_name: 'company*theproduct', descriptor_phone: '1331131131', descriptor_url: 'company.com') assert_success auth end def test_successful_validate_on_store_with_verification_merchant_account card = credit_card('4111111111111111', :verification_value => '101') assert response = @gateway.store(card, :verify_card => true, :verification_merchant_account_id => fixtures(:braintree_blue)[:merchant_account_id]) - assert_success response, "You must specify a valid :merchant_account_id key in your fixtures.yml for this to pass." + assert_success response, 'You must specify a valid :merchant_account_id key in your fixtures.yml for this to pass.' assert_equal 'OK', response.message end @@ -648,12 +773,12 @@ def test_transcript_scrubbing def test_verify_credentials assert @gateway.verify_credentials - gateway = BraintreeGateway.new(merchant_id: "UNKNOWN", public_key: "UNKONWN", private_key: "UNKONWN") + gateway = BraintreeGateway.new(merchant_id: 'UNKNOWN', public_key: 'UNKONWN', private_key: 'UNKONWN') assert !gateway.verify_credentials end - private + def assert_avs(address1, zip, expected_avs_code) response = @gateway.purchase(@amount, @credit_card, billing_address: {address1: address1, zip: zip}) diff --git a/test/remote/gateways/remote_braintree_orange_test.rb b/test/remote/gateways/remote_braintree_orange_test.rb index 8bde4c2f561..0816eb1821b 100644 --- a/test/remote/gateways/remote_braintree_orange_test.rb +++ b/test/remote/gateways/remote_braintree_orange_test.rb @@ -4,7 +4,7 @@ class RemoteBraintreeOrangeTest < Test::Unit::TestCase def setup @gateway = BraintreeGateway.new(fixtures(:braintree_orange)) - @amount = rand(10000) + 1001 + @amount = rand(1001..11000) @credit_card = credit_card('4111111111111111') @check = check() @declined_amount = rand(99) @@ -27,7 +27,7 @@ def test_successful_purchase_with_echeck :account_holder_type => 'personal', :account_type => 'checking' ) - assert response = @gateway.purchase(@amount, @check, @options) + assert response = @gateway.purchase(@amount, check, @options) assert_equal 'This transaction has been approved', response.message assert_success response end @@ -37,15 +37,15 @@ def test_successful_add_to_vault assert response = @gateway.purchase(@amount, @credit_card, @options) assert_equal 'This transaction has been approved', response.message assert_success response - assert_not_nil response.params["customer_vault_id"] + assert_not_nil response.params['customer_vault_id'] end def test_successful_add_to_vault_with_store_method assert response = @gateway.store(@credit_card) assert_equal 'Customer Added', response.message assert_success response - assert_match %r{^\d+$}, response.params["customer_vault_id"] - assert_equal response.params["customer_vault_id"], response.authorization + assert_match %r{^\d+$}, response.params['customer_vault_id'] + assert_equal response.params['customer_vault_id'], response.authorization end def test_failed_add_to_vault_with_store_method @@ -59,7 +59,7 @@ def test_successful_add_to_vault_and_use assert response = @gateway.purchase(@amount, @credit_card, @options) assert_equal 'This transaction has been approved', response.message assert_success response - assert_not_nil customer_id = response.params["customer_vault_id"] + assert_not_nil customer_id = response.params['customer_vault_id'] assert second_response = @gateway.purchase(@amount*2, customer_id, @options) assert_equal 'This transaction has been approved', second_response.message @@ -67,19 +67,19 @@ def test_successful_add_to_vault_and_use end def test_add_to_vault_with_custom_vault_id - @options[:store] = rand(100000)+10001 + @options[:store] = rand(10001..110000) assert response = @gateway.purchase(@amount, @credit_card, @options) assert_equal 'This transaction has been approved', response.message assert_success response - assert_equal @options[:store], response.params["customer_vault_id"].to_i + assert_equal @options[:store], response.params['customer_vault_id'].to_i end def test_add_to_vault_with_custom_vault_id_with_store_method - @options[:billing_id] = rand(100000)+10001 + @options[:billing_id] = rand(10001..110000) assert response = @gateway.store(@credit_card, @options.dup) assert_equal 'Customer Added', response.message assert_success response - assert_equal @options[:billing_id], response.params["customer_vault_id"].to_i + assert_equal @options[:billing_id], response.params['customer_vault_id'].to_i end def test_add_to_vault_with_store_and_check @@ -139,13 +139,19 @@ def test_authorize_and_void def test_failed_capture assert response = @gateway.capture(@amount, '') assert_failure response - assert response.message.match(/Invalid Transaction ID \/ Object ID specified:/) + assert response.message.match(/Invalid Transaction ID \/ Object ID specified:/) + end + + def test_authorize_with_three_d_secure_pass_thru + assert auth = @gateway.authorize(@amount, @credit_card, @options.merge(eci: '05', xid: 'xid', cavv: 'cavv')) + assert_success auth + assert_equal 'This transaction has been approved', auth.message end def test_successful_verify assert response = @gateway.verify(@credit_card, @options) assert_success response - assert_equal "This transaction has been approved", response.message + assert_equal 'This transaction has been approved', response.message end def test_failed_verify @@ -170,7 +176,7 @@ def test_transcript_scrubbing @gateway.purchase(@declined_amount, @credit_card, @options) end clean_transcript = @gateway.scrub(transcript) - + assert_scrubbed(@credit_card.number, clean_transcript) assert_scrubbed(@credit_card.verification_value.to_s, clean_transcript) end diff --git a/test/remote/gateways/remote_bridge_pay_test.rb b/test/remote/gateways/remote_bridge_pay_test.rb index a5ca8f46680..88f91a8212c 100644 --- a/test/remote/gateways/remote_bridge_pay_test.rb +++ b/test/remote/gateways/remote_bridge_pay_test.rb @@ -103,10 +103,10 @@ def test_failed_void def test_successful_verify assert response = @gateway.verify(@credit_card, @options) assert_success response - assert_equal "Approved", response.message + assert_equal 'Approved', response.message - assert_success response.responses.last, "The void should succeed" - assert_equal "Approved", response.responses.last.params["respmsg"] + assert_success response.responses.last, 'The void should succeed' + assert_equal 'Approved', response.responses.last.params['respmsg'] end def test_unsuccessful_verify diff --git a/test/remote/gateways/remote_card_connect_test.rb b/test/remote/gateways/remote_card_connect_test.rb new file mode 100644 index 00000000000..10cf459c550 --- /dev/null +++ b/test/remote/gateways/remote_card_connect_test.rb @@ -0,0 +1,227 @@ +require 'test_helper' + +class RemoteCardConnectTest < Test::Unit::TestCase + def setup + @gateway = CardConnectGateway.new(fixtures(:card_connect)) + + @amount = 100 + @credit_card = credit_card('4788250000121443') + @declined_card = credit_card('4387751111111053') + @options = { + billing_address: address, + description: 'Store Purchase' + } + @check = check(routing_number: '053000196') + @invalid_txn = '23221' + end + + def test_successful_purchase + response = @gateway.purchase(@amount, @credit_card, @options) + assert_success response + assert_equal 'Approval', response.message + end + + def test_successful_purchase_with_more_options + options = { + order_id: '1', + ip: '127.0.0.1', + email: 'joe@example.com', + po_number: '5FSD4', + tax_amount: '50', + freight_amount: '29', + duty_amount: '67', + order_date: '20170507', + ship_from_date: '20877', + items: [ + { + line_no: '1', + material: 'MATERIAL-1', + description: 'DESCRIPTION-1', + upc: 'UPC-1', + quantity: '1000', + uom: 'CS', + unit_cost: '900', + net_amnt: '150', + tax_amnt: '117', + disc_amnt: '0' + }, + { + line_no: '2', + material: 'MATERIAL-2', + description: 'DESCRIPTION-2', + upc: 'UPC-1', + quantity: '2000', + uom: 'CS', + unit_cost: '450', + net_amnt: '300', + tax_amnt: '117', + disc_amnt: '0' + } + ] + } + + response = @gateway.purchase(@amount, @credit_card, options) + assert_success response + assert_equal 'Approval Queued for Capture', response.message + end + + def test_successful_purchase_3DS + three_ds_options = @options.merge( + secure_flag: 'se3453', + secure_value: '233frdf', + secure_xid: '334ef34' + ) + response = @gateway.purchase(@amount, @credit_card, three_ds_options) + assert_success response + assert_equal 'Approval', response.message + end + + def test_successful_purchase_with_profile + store_response = @gateway.store(@credit_card, @options) + assert_success store_response + purchase_response = @gateway.purchase(@amount, store_response.authorization, @options) + assert_success purchase_response + end + + def test_failed_purchase + response = @gateway.purchase(@amount, @declined_card, @options) + assert_failure response + assert_equal 'Insufficient funds', response.message + end + + def test_successful_authorize_and_capture + auth = @gateway.authorize(@amount, @credit_card, @options) + assert_success auth + + assert capture = @gateway.capture(@amount, auth.authorization) + assert_success capture + assert_includes ['Approval Queued for Capture', 'Approval Accepted'], capture.message + end + + def test_failed_authorize + response = @gateway.authorize(@amount, @declined_card, @options) + assert_failure response + assert_equal 'Insufficient funds', response.message + end + + def test_partial_capture + auth = @gateway.authorize(@amount, @credit_card, @options) + assert_success auth + + assert capture = @gateway.capture(@amount - 1, auth.authorization) + assert_success capture + end + + def test_failed_capture + response = @gateway.capture(@amount, @invalid_txn) + assert_failure response + assert_equal 'Txn not found', response.message + end + + def test_successful_echeck_purchase + response = @gateway.purchase(@amount, @check, @options) + assert_equal 'Success', response.message + assert_success response + end + + def test_failed_echeck_purchase + response = @gateway.purchase(@amount, check(routing_number: '23433'), @options) + assert_failure response + assert_equal 'Invalid card', response.message + end + + def test_successful_refund + purchase = @gateway.purchase(@amount, @credit_card, @options) + assert_success purchase + + assert refund = @gateway.refund(@amount, purchase.authorization) + assert_success refund + assert_equal 'Approval', refund.message + end + + def test_partial_refund + purchase = @gateway.purchase(@amount, @credit_card, @options) + assert_success purchase + + assert refund = @gateway.refund(@amount - 1, purchase.authorization) + assert_success refund + end + + def test_failed_refund + response = @gateway.refund(@amount, @invalid_txn) + assert_failure response + assert_equal 'Txn not found', response.message + end + + def test_successful_void + auth = @gateway.authorize(@amount, @credit_card, @options) + assert_success auth + + assert void = @gateway.void(auth.authorization) + assert_success void + assert_equal 'Approval', void.message + end + + def test_failed_void + response = @gateway.void(@invalid_txn) + assert_failure response + end + + def test_successful_verify + response = @gateway.verify(@credit_card, @options) + assert_success response + assert_match %r{Approval}, response.message + end + + def test_failed_verify + response = @gateway.verify(@declined_card, @options) + assert_failure response + assert_match %r{Insufficient funds}, response.message + end + + def test_successful_store + response = @gateway.store(@credit_card, @options) + + assert_success response + assert_equal 'Profile Saved', response.message + end + + def test_successful_unstore + store_response = @gateway.store(@credit_card, @options) + assert_success store_response + + unstore_response = @gateway.unstore(store_response.authorization, @options) + assert_success unstore_response + end + + def test_failed_unstore + response = @gateway.unstore('0|abcdefghijklmnopq', @options) + assert_failure response + end + + def test_invalid_login + gateway = CardConnectGateway.new(username: '', password: '', merchant_id: '') + assert_raises(ActiveMerchant::ResponseError) do + gateway.purchase(@amount, @credit_card, @options) + end + end + + def test_transcript_scrubbing + transcript = capture_transcript(@gateway) do + @gateway.purchase(@amount, @credit_card, @options) + end + transcript = @gateway.scrub(transcript) + + assert_scrubbed(@credit_card.number, transcript) + assert_scrubbed(@credit_card.verification_value, transcript) + assert_scrubbed(@gateway.options[:password], transcript) + + transcript = capture_transcript(@gateway) do + @gateway.purchase(@amount, @check, @options) + end + transcript = @gateway.scrub(transcript) + + assert_scrubbed(@check.account_number, transcript) + assert_scrubbed(@gateway.options[:password], transcript) + end +end diff --git a/test/remote/gateways/remote_card_save_test.rb b/test/remote/gateways/remote_card_save_test.rb index 5774414fc17..06ee56d1053 100644 --- a/test/remote/gateways/remote_card_save_test.rb +++ b/test/remote/gateways/remote_card_save_test.rb @@ -1,23 +1,23 @@ require 'test_helper' -class RemoteCardSaveTest < Test::Unit::TestCase +class RemoteCardSaveTest < Test::Unit::TestCase def setup @gateway = CardSaveGateway.new(fixtures(:card_save)) - + @amount = 100 @credit_card = credit_card('4976000000003436', :verification_value => '452') @declined_card = credit_card('4221690000004963', :verification_value => '125') @addresses = {'4976000000003436' => { :name => 'John Watson', :address1 => '32 Edward Street', :city => 'Camborne,', :state => 'Cornwall', :country => 'GB', :zip => 'TR14 8PA' }, '4221690000004963' => { :name => 'Ian Lee', :address1 => '274 Lymington Avenue', :city => 'London', :state => 'London', :country => 'GB', :zip => 'N22 6JN' }} - - @options = { + + @options = { :order_id => '1', :billing_address => @addresses[@credit_card.number], :description => 'Store Purchase' } end - + def test_successful_purchase assert response = @gateway.purchase(@amount, @credit_card, @options) assert_success response @@ -25,7 +25,7 @@ def test_successful_purchase end def test_unsuccessful_purchase - @options.merge!(:billing_address => @addresses[@declined_card.number]) + @options[:billing_address] = @addresses[@declined_card.number] assert response = @gateway.purchase(@amount, @declined_card, @options) assert_failure response assert_equal 'Card declined', response.message @@ -49,8 +49,8 @@ def test_failed_capture def test_invalid_login gateway = CardSaveGateway.new( - :login => '', - :password => '' + :login => '', + :password => '' ) assert response = gateway.purchase(@amount, @credit_card, @options) assert_failure response diff --git a/test/remote/gateways/remote_card_stream_test.rb b/test/remote/gateways/remote_card_stream_test.rb index 99b6282f80d..fd6d3e8e3ef 100644 --- a/test/remote/gateways/remote_card_stream_test.rb +++ b/test/remote/gateways/remote_card_stream_test.rb @@ -13,14 +13,6 @@ def setup :brand => :american_express ) - @uk_maestro = credit_card('6759015050123445002', - :month => '12', - :year => '2014', - :issue_number => '0', - :verification_value => '309', - :brand => :switch - ) - @mastercard = credit_card('5301250070000191', :month => '12', :year => '2014', @@ -29,10 +21,10 @@ def setup ) @visacreditcard = credit_card('4929421234600821', - :month => '12', - :year => '2014', - :verification_value => '356', - :brand => :visa + :month => '12', + :year => '2014', + :verification_value => '356', + :brand => :visa ) @visadebitcard = credit_card('4539791001730106', @@ -50,76 +42,75 @@ def setup @amex_options = { :billing_address => { :address1 => 'The Hunts Way', - :city => "", - :state => "Leicester", - :zip => 'SO18 1GW' + :city => '', + :state => 'Leicester', + :zip => 'SO18 1GW', + :country => 'GB' }, :order_id => generate_unique_id, - :description => 'AM test purchase' + :description => 'AM test purchase', + :ip => '1.1.1.1' } @visacredit_options = { :billing_address => { - :address1 => "Flat 6, Primrose Rise", - :address2 => "347 Lavender Road", - :city => "", - :state => "Northampton", - :zip => 'NN17 8YG ' + :address1 => 'Flat 6, Primrose Rise', + :address2 => '347 Lavender Road', + :city => '', + :state => 'Northampton', + :zip => 'NN17 8YG', + :country => 'GB' }, :order_id => generate_unique_id, - :description => 'AM test purchase' + :description => 'AM test purchase', + :ip => '1.1.1.1' } @visacredit_descriptor_options = { :billing_address => { - :address1 => "Flat 6, Primrose Rise", - :address2 => "347 Lavender Road", - :city => "", - :state => "Northampton", - :zip => 'NN17 8YG ' + :address1 => 'Flat 6, Primrose Rise', + :address2 => '347 Lavender Road', + :city => '', + :state => 'Northampton', + :zip => 'NN17 8YG', + :country => 'GB' }, :merchant_name => 'merchant', - :dynamic_descriptor => 'product' + :dynamic_descriptor => 'product', + :ip => '1.1.1.1', } @visacredit_reference_options = { :order_id => generate_unique_id, - :description => 'AM test purchase' - } + :description => 'AM test purchase', + :ip => '1.1.1.1' + } @visadebit_options = { :billing_address => { :address1 => 'Unit 5, Pickwick Walk', - :address2 => "120 Uxbridge Road", - :city => "Hatch End", - :state => "Middlesex", - :zip => "HA6 7HJ" + :address2 => '120 Uxbridge Road', + :city => 'Hatch End', + :state => 'Middlesex', + :zip => 'HA6 7HJ', + :country => 'GB' }, :order_id => generate_unique_id, - :description => 'AM test purchase' + :description => 'AM test purchase', + :ip => '1.1.1.1' } @mastercard_options = { :billing_address => { :address1 => '25 The Larches', - :city => "Narborough", - :state => "Leicester", - :zip => 'LE10 2RT' - }, - :order_id => generate_unique_id, - :description => 'AM test purchase' - } - - @uk_maestro_options = { - :billing_address => { - :address1 => 'The Parkway', - :address2 => "5258 Larches Approach", - :city => "Hull", - :state => "North Humberside", - :zip => 'HU10 5OP' + :city => 'Narborough', + :state => 'Leicester', + :zip => 'LE10 2RT', + :country => 'GB' }, :order_id => generate_unique_id, - :description => 'AM test purchase' + :description => 'AM test purchase', + :ip => '1.1.1.1' } @three_ds_enrolled_card = credit_card('4012001037141112', @@ -141,18 +132,44 @@ def test_successful_visacreditcard_authorization_and_capture assert responseCapture.test? end - def test_successful_visacreditcard_purchase_and_refund + def test_successful_visacreditcard_authorization_and_capture_no_billing_address + assert responseAuthorization = @gateway.authorize(142, @visacreditcard, @visacredit_options.delete(:billing_address)) + assert_equal 'APPROVED', responseAuthorization.message + assert_success responseAuthorization + assert responseAuthorization.test? + assert !responseAuthorization.authorization.blank? + assert responseCapture = @gateway.capture(142, responseAuthorization.authorization, @visacredit_options) + assert_equal 'APPROVED', responseCapture.message + assert_success responseCapture + assert responseCapture.test? + end + + def test_successful_visacreditcard_purchase_and_refund_with_force_refund assert responsePurchase = @gateway.purchase(284, @visacreditcard, @visacredit_options) assert_equal 'APPROVED', responsePurchase.message assert_success responsePurchase assert responsePurchase.test? assert !responsePurchase.authorization.blank? - assert responseRefund = @gateway.refund(142, responsePurchase.authorization, @visacredit_options) + + assert responseRefund = @gateway.refund(142, responsePurchase.authorization, @visacredit_options.merge(force_full_refund_if_unsettled: true)) assert_equal 'APPROVED', responseRefund.message assert_success responseRefund assert responseRefund.test? end + def test_failed_visacreditcard_purchase_and_refund + assert responsePurchase = @gateway.purchase(284, @visacreditcard, @visacredit_options) + assert_equal 'APPROVED', responsePurchase.message + assert_success responsePurchase + assert responsePurchase.test? + assert !responsePurchase.authorization.blank? + + assert responseRefund = @gateway.refund(142, responsePurchase.authorization, @visacredit_options) + assert_failure responseRefund + assert_equal 'Can not REFUND this SALE transaction', responseRefund.message + assert responseRefund.test? + end + def test_successful_visacreditcard_purchase_with_dynamic_descriptors assert responsePurchase = @gateway.purchase(284, @visacreditcard, @visacredit_descriptor_options) assert_equal 'APPROVED', responsePurchase.message @@ -185,18 +202,32 @@ def test_successful_visadebitcard_authorization_and_capture assert responseCapture.test? end - def test_successful_visadebitcard_purchase_and_refund + def test_successful_visadebitcard_purchase_and_refund_with_force_refund assert responsePurchase = @gateway.purchase(284, @visadebitcard, @visadebit_options) assert_equal 'APPROVED', responsePurchase.message assert_success responsePurchase assert responsePurchase.test? assert !responsePurchase.authorization.blank? - assert responseRefund = @gateway.refund(142, responsePurchase.authorization, @visadebit_options) + + assert responseRefund = @gateway.refund(142, responsePurchase.authorization, @visadebit_options.merge(force_full_refund_if_unsettled: true)) assert_equal 'APPROVED', responseRefund.message assert_success responseRefund assert responseRefund.test? end + def test_failed_visadebitcard_purchase_and_refund + assert responsePurchase = @gateway.purchase(284, @visadebitcard, @visadebit_options) + assert_equal 'APPROVED', responsePurchase.message + assert_success responsePurchase + assert responsePurchase.test? + assert !responsePurchase.authorization.blank? + + assert responseRefund = @gateway.refund(142, responsePurchase.authorization, @visadebit_options) + assert_equal 'Can not REFUND this SALE transaction', responseRefund.message + assert_failure responseRefund + assert responseRefund.test? + end + def test_successful_amex_authorization_and_capture assert responseAuthorization = @gateway.authorize(142, @amex, @amex_options) assert_equal 'APPROVED', responseAuthorization.message @@ -209,18 +240,32 @@ def test_successful_amex_authorization_and_capture assert responseCapture.test? end - def test_successful_amex_purchase_and_refund + def test_successful_amex_purchase_and_refund_with_force_refund assert responsePurchase = @gateway.purchase(284, @amex, @amex_options) assert_equal 'APPROVED', responsePurchase.message assert_success responsePurchase assert responsePurchase.test? assert !responsePurchase.authorization.blank? - assert responseRefund = @gateway.refund(142, responsePurchase.authorization, @amex_options) + + assert responseRefund = @gateway.refund(142, responsePurchase.authorization, @amex_options.merge(force_full_refund_if_unsettled: true)) assert_equal 'APPROVED', responseRefund.message assert_success responseRefund assert responseRefund.test? end + def test_failed_amex_purchase_and_refund + assert responsePurchase = @gateway.purchase(284, @amex, @amex_options) + assert_equal 'APPROVED', responsePurchase.message + assert_success responsePurchase + assert responsePurchase.test? + assert !responsePurchase.authorization.blank? + + assert responseRefund = @gateway.refund(142, responsePurchase.authorization, @amex_options) + assert_equal 'Can not REFUND this SALE transaction', responseRefund.message + assert_failure responseRefund + assert responseRefund.test? + end + def test_successful_mastercard_authorization_and_capture assert responseAuthorization = @gateway.authorize(142, @mastercard, @mastercard_options) assert_equal 'APPROVED', responseAuthorization.message @@ -233,18 +278,32 @@ def test_successful_mastercard_authorization_and_capture assert responseCapture.test? end - def test_successful_mastercard_purchase_and_refund + def test_successful_mastercard_purchase_and_refund_with_force_refund assert responsePurchase = @gateway.purchase(284, @mastercard, @mastercard_options) assert_equal 'APPROVED', responsePurchase.message assert_success responsePurchase assert responsePurchase.test? assert !responsePurchase.authorization.blank? - assert responseRefund = @gateway.refund(142, responsePurchase.authorization, @mastercard_options) + + assert responseRefund = @gateway.refund(142, responsePurchase.authorization, @mastercard_options.merge(force_full_refund_if_unsettled: true)) assert_equal 'APPROVED', responseRefund.message assert_success responseRefund assert responseRefund.test? end + def test_failed_mastercard_purchase_and_refund + assert responsePurchase = @gateway.purchase(284, @mastercard, @mastercard_options) + assert_equal 'APPROVED', responsePurchase.message + assert_success responsePurchase + assert responsePurchase.test? + assert !responsePurchase.authorization.blank? + + assert responseRefund = @gateway.refund(142, responsePurchase.authorization, @mastercard_options) + assert_equal 'Can not REFUND this SALE transaction', responseRefund.message + assert_failure responseRefund + assert responseRefund.test? + end + def test_successful_visacreditcard_purchase assert response = @gateway.purchase(142, @visacreditcard, @visacredit_options) assert_equal 'APPROVED', response.message @@ -274,12 +333,12 @@ def test_failed_visacreditcard_purchase_via_reference def test_purchase_no_currency_specified_defaults_to_GBP assert response = @gateway.purchase(142, @visacreditcard, @visacredit_options.merge(currency: nil)) assert_success response - assert_equal "826", response.params["currencyCode"] + assert_equal '826', response.params['currencyCode'] assert_equal 'APPROVED', response.message end def test_failed_purchase_non_existent_currency - assert response = @gateway.purchase(142, @visacreditcard, @visacredit_options.merge(currency: "CEO")) + assert response = @gateway.purchase(142, @visacreditcard, @visacredit_options.merge(currency: 'CEO')) assert_failure response assert_match %r{MISSING_CURRENCYCODE}, response.message end @@ -307,20 +366,6 @@ def test_declined_mastercard_purchase assert response.test? end - def test_expired_mastercard - @mastercard.year = 2012 - assert response = @gateway.purchase(142, @mastercard, @mastercard_options) - assert_equal 'CARD EXPIRED', response.message - assert_failure response - assert response.test? - end - - def test_successful_maestro_purchase - assert response = @gateway.purchase(142, @uk_maestro, @uk_maestro_options) - assert_equal 'APPROVED', response.message - assert_success response - end - def test_successful_amex_purchase assert response = @gateway.purchase(142, @amex, @amex_options) assert_equal 'APPROVED', response.message @@ -339,13 +384,6 @@ def test_invalid_login assert_failure response end - def test_usd_merchant_currency - assert response = @gateway.purchase(142, @mastercard, @mastercard_options.update(:currency => 'USD')) - assert_equal 'APPROVED', response.message - assert_success response - assert response.test? - end - def test_successful_verify response = @gateway.verify(@mastercard, @mastercard_options) assert_success response @@ -361,23 +399,23 @@ def test_failed_verify def test_successful_3dsecure_purchase assert response = @gateway.purchase(1202, @three_ds_enrolled_card, @mastercard_options.merge(threeds_required: true)) assert_equal '3DS AUTHENTICATION REQUIRED', response.message - assert_equal "65802", response.params["responseCode"] + assert_equal '65802', response.params['responseCode'] assert response.test? assert !response.authorization.blank? - assert !response.params["threeDSACSURL"].blank? - assert !response.params["threeDSMD"].blank? - assert !response.params["threeDSPaReq"].blank? + assert !response.params['threeDSACSURL'].blank? + assert !response.params['threeDSMD'].blank? + assert !response.params['threeDSPaReq'].blank? end def test_successful_3dsecure_auth assert response = @gateway.authorize(1202, @three_ds_enrolled_card, @mastercard_options.merge(threeds_required: true)) assert_equal '3DS AUTHENTICATION REQUIRED', response.message - assert_equal "65802", response.params["responseCode"] + assert_equal '65802', response.params['responseCode'] assert response.test? assert !response.authorization.blank? - assert !response.params["threeDSACSURL"].blank? - assert !response.params["threeDSMD"].blank? - assert !response.params["threeDSPaReq"].blank? + assert !response.params['threeDSACSURL'].blank? + assert !response.params['threeDSMD'].blank? + assert !response.params['threeDSPaReq'].blank? end def test_transcript_scrubbing @@ -386,8 +424,8 @@ def test_transcript_scrubbing end clean_transcript = @gateway.scrub(transcript) - assert_scrubbed( @visacreditcard.number, clean_transcript) - assert_scrubbed( @visacreditcard.verification_value.to_s, clean_transcript) + assert_scrubbed(@visacreditcard.number, clean_transcript) + assert_scrubbed(@visacreditcard.verification_value.to_s, clean_transcript) assert_scrubbed(@gateway.options[:shared_secret], clean_transcript) end end diff --git a/test/remote/gateways/remote_cardknox_test.rb b/test/remote/gateways/remote_cardknox_test.rb index 58fc15e4fc3..211e1e9afcb 100644 --- a/test/remote/gateways/remote_cardknox_test.rb +++ b/test/remote/gateways/remote_cardknox_test.rb @@ -16,8 +16,8 @@ def setup order_id: generate_unique_id, invoice: generate_unique_id, name: 'Jim Smith', - ip: "127.0.0.1", - email: "joe@example.com", + ip: '127.0.0.1', + email: 'joe@example.com', tip: 2, tax: 3, custom02: 'mycustom', @@ -37,7 +37,7 @@ def setup } } - @options = {} + @options = {} end def test_successful_credit_card_purchase @@ -149,7 +149,6 @@ def test_failed_credit_card_authorize_partial_refund assert refund = @gateway.refund(@amount-1, auth.authorization) assert_failure refund assert_equal 'Refund not allowed on non-captured auth.', refund.message - end def test_failed_partial_check_refund # the gate way does not support this transaction diff --git a/test/remote/gateways/remote_cardprocess_test.rb b/test/remote/gateways/remote_cardprocess_test.rb new file mode 100644 index 00000000000..951c07e0ab3 --- /dev/null +++ b/test/remote/gateways/remote_cardprocess_test.rb @@ -0,0 +1,149 @@ +require 'test_helper' + +class RemoteCardprocessTest < Test::Unit::TestCase + def setup + @gateway = CardprocessGateway.new(fixtures(:cardprocess)) + + @amount = 100 + @credit_card = credit_card('4200000000000000') + @credit_card_3ds = credit_card('4711100000000000') + + @options = { + billing_address: address, + description: 'Store Purchase' + } + end + + def test_successful_purchase + response = @gateway.purchase(@amount, @credit_card, @options) + assert_success response + assert_match %r{^Request successfully processed}, response.message + end + + def test_successful_purchase_with_more_options + options = { + order_id: '1', + ip: '127.0.0.1', + email: 'joe@example.com' + } + + response = @gateway.purchase(@amount, @credit_card, options) + assert_success response + assert_match %r{^Request successfully processed}, response.message + end + + def test_failed_purchase + bad_credit_card = credit_card('4200000000000001') + response = @gateway.purchase(@amount, bad_credit_card, @options) + assert_failure response + assert_equal Gateway::STANDARD_ERROR_CODE[:incorrect_number], response.error_code + assert_equal 'invalid creditcard, bank account number or bank name', response.message + end + + def test_successful_authorize_and_capture + auth = @gateway.authorize(@amount, @credit_card, @options) + assert_success auth + + assert capture = @gateway.capture(@amount, auth.authorization) + assert_success capture + assert_match %r{^Request successfully processed}, capture.message + end + + def test_failed_authorize + @gateway.instance_variable_set(:@test_options, {'customParameters[forceResultCode]' => '800.100.151'}) + response = @gateway.authorize(@amount, @credit_card, @options) + assert_failure response + assert_equal 'transaction declined (invalid card)', response.message + end + + def test_partial_capture + auth = @gateway.authorize(@amount, @credit_card, @options) + assert_success auth + + assert capture = @gateway.capture(@amount-1, auth.authorization) + assert_success capture + end + + def test_failed_capture + response = @gateway.capture(@amount, '12345678123456781234567812345678') + assert_failure response + assert_equal 'capture needs at least one successful transaction of type (PA)', response.message + end + + def test_successful_refund + purchase = @gateway.purchase(@amount, @credit_card, @options) + assert_success purchase + + assert refund = @gateway.refund(@amount, purchase.authorization) + assert_success refund + assert_match %r{^Request successfully processed}, refund.message + end + + def test_successful_credit + response = @gateway.credit(@amount, @credit_card, @options) + assert_success response + assert_match %r{^Request successfully processed}, response.message + end + + def test_partial_refund + purchase = @gateway.purchase(@amount, @credit_card, @options) + assert_success purchase + + assert refund = @gateway.refund(@amount-1, purchase.authorization) + assert_success refund + end + + def test_failed_refund + response = @gateway.refund(@amount, '') + assert_failure response + assert_equal 'invalid or missing parameter', response.message + end + + def test_successful_void + auth = @gateway.authorize(@amount, @credit_card, @options) + assert_success auth + + assert void = @gateway.void(auth.authorization) + assert_success void + assert_match %r{^Request successfully processed}, void.message + end + + def test_failed_void + response = @gateway.void('') + assert_failure response + assert_equal 'invalid or missing parameter', response.message + end + + def test_successful_verify + response = @gateway.verify(@credit_card, @options) + assert_success response + assert_match %r{^Request successfully processed}, response.message + end + + def test_failed_verify + @gateway.instance_variable_set(:@test_options, {'customParameters[forceResultCode]' => '600.200.100'}) + response = @gateway.verify(@credit_card, @options) + assert_failure response + assert_match %r{invalid Payment Method}, response.message + end + + def test_invalid_login + gateway = CardprocessGateway.new(user_id: '00000000000000000000000000000000', password: 'qwerty', entity_id: '00000000000000000000000000000000') + + response = gateway.purchase(@amount, @credit_card, @options) + assert_failure response + assert_equal 'invalid authentication information', response.message + end + + def test_transcript_scrubbing + transcript = capture_transcript(@gateway) do + @gateway.purchase(@amount, @credit_card, @options) + end + transcript = @gateway.scrub(transcript) + + assert_scrubbed(@credit_card.number, transcript) + assert_scrubbed(@credit_card.verification_value, transcript) + assert_scrubbed(@gateway.options[:password], transcript) + assert_scrubbed(@gateway.options[:entity_id], transcript) + end +end diff --git a/test/remote/gateways/remote_cashnet_test.rb b/test/remote/gateways/remote_cashnet_test.rb index b30925b2bbe..87aea788007 100644 --- a/test/remote/gateways/remote_cashnet_test.rb +++ b/test/remote/gateways/remote_cashnet_test.rb @@ -5,7 +5,7 @@ def setup @gateway = CashnetGateway.new(fixtures(:cashnet)) @amount = 100 @credit_card = credit_card( - "5454545454545454", + '5454545454545454', month: 12, year: 2015 ) @@ -29,10 +29,10 @@ def test_successful_purchase_and_refund end def test_successful_refund_with_options - assert purchase = @gateway.purchase(@amount, @credit_card, custcode: "TheCustCode") + assert purchase = @gateway.purchase(@amount, @credit_card, custcode: 'TheCustCode') assert_success purchase - assert refund = @gateway.refund(@amount, purchase.authorization, email: "wow@example.com", custcode: "TheCustCode") + assert refund = @gateway.refund(@amount, purchase.authorization, email: 'wow@example.com', custcode: 'TheCustCode') assert_success refund end @@ -40,7 +40,7 @@ def test_failed_purchase assert response = @gateway.purchase(-44, @credit_card, @options) assert_failure response assert_match %r{Negative amount is not allowed}, response.message - assert_equal "5", response.params["result"] + assert_equal '5', response.params['result'] end def test_failed_refund @@ -50,6 +50,17 @@ def test_failed_refund assert refund = @gateway.refund(@amount + 50, purchase.authorization) assert_failure refund assert_match %r{Amount to refund exceeds}, refund.message - assert_equal "302", refund.params["result"] + assert_equal '302', refund.params['result'] + end + + def test_transcript_scrubbing + transcript = capture_transcript(@gateway) do + @gateway.purchase(@amount, @credit_card, @options) + end + transcript = @gateway.scrub(transcript) + + assert_scrubbed(@credit_card.number, transcript) + assert_scrubbed(@credit_card.verification_value, transcript) + assert_scrubbed(@gateway.options[:password], transcript) end end diff --git a/test/remote/gateways/remote_cecabank_test.rb b/test/remote/gateways/remote_cecabank_test.rb index ef91178c9ea..108fb3ea106 100644 --- a/test/remote/gateways/remote_cecabank_test.rb +++ b/test/remote/gateways/remote_cecabank_test.rb @@ -26,7 +26,6 @@ def test_unsuccessful_purchase assert_equal 'ERROR', response.message end - def test_successful_refund purchase = @gateway.purchase(@amount, @credit_card, @options) assert_success purchase @@ -37,7 +36,7 @@ def test_successful_refund end def test_unsuccessful_refund - assert response = @gateway.refund(@amount, "wrongreference", @options) + assert response = @gateway.refund(@amount, 'wrongreference', @options) assert_failure response assert_equal 'ERROR', response.message end diff --git a/test/remote/gateways/remote_cenpos_test.rb b/test/remote/gateways/remote_cenpos_test.rb index 64adf71cf44..a3474658bbc 100644 --- a/test/remote/gateways/remote_cenpos_test.rb +++ b/test/remote/gateways/remote_cenpos_test.rb @@ -1,13 +1,13 @@ -require "test_helper" +require 'test_helper' class RemoteCenposTest < Test::Unit::TestCase def setup @gateway = CenposGateway.new(fixtures(:cenpos)) @amount = SecureRandom.random_number(10000) - @credit_card = credit_card("4111111111111111", month: 02, year: 18, verification_value: 999) - @declined_card = credit_card("4000300011112220") - @invalid_card = credit_card("9999999999999999") + @credit_card = credit_card('4111111111111111', month: 02, year: 18, verification_value: 999) + @declined_card = credit_card('4000300011112220') + @invalid_card = credit_card('9999999999999999') @options = { order_id: SecureRandom.random_number(1000000), @@ -17,53 +17,53 @@ def setup def test_invalid_login gateway = CenposGateway.new( - merchant_id: "", - password: "", - user_id: "" + merchant_id: '', + password: '', + user_id: '' ) response = gateway.purchase(@amount, @credit_card, @options) assert_failure response - assert_equal "See transcript for detailed error description.", response.message + assert_equal 'See transcript for detailed error description.', response.message end def test_successful_purchase response = @gateway.purchase(@amount, @credit_card, @options) assert_success response - assert_equal "Succeeded", response.message + assert_equal 'Succeeded', response.message end def test_successful_purchase_cvv_result response = @gateway.purchase(@amount, @credit_card, @options) - assert_equal "M", response.cvv_result["code"] + assert_equal 'M', response.cvv_result['code'] end def test_successful_purchase_avs_result response = @gateway.purchase(@amount, @credit_card, @options) - assert_equal "D", response.avs_result["code"] + assert_equal 'D', response.avs_result['code'] end def test_successful_purchase_with_invoice_detail - response = @gateway.purchase(@amount, @credit_card, @options.merge(invoice_detail: "<xml><description/></xml>")) + response = @gateway.purchase(@amount, @credit_card, @options.merge(invoice_detail: '<xml><description/></xml>')) assert_success response - assert_equal "Succeeded", response.message + assert_equal 'Succeeded', response.message end def test_successful_purchase_with_customer_code - response = @gateway.purchase(@amount, @credit_card, @options.merge(customer_code: "3214")) + response = @gateway.purchase(@amount, @credit_card, @options.merge(customer_code: '3214')) assert_success response - assert_equal "Succeeded", response.message + assert_equal 'Succeeded', response.message end def test_successful_purchase_with_currency - response = @gateway.purchase(@amount, @credit_card, @options.merge(currency: "EUR")) + response = @gateway.purchase(@amount, @credit_card, @options.merge(currency: 'EUR')) assert_success response - assert_equal "Succeeded", response.message + assert_equal 'Succeeded', response.message end def test_failed_purchase response = @gateway.purchase(@amount, @declined_card, @options) assert_failure response - assert_equal "Decline transaction", response.message + assert_equal 'Decline transaction', response.message assert_equal Gateway::STANDARD_ERROR_CODE[:card_declined], response.error_code end @@ -84,30 +84,30 @@ def test_failed_purchase_avs_result def test_successful_authorize_and_capture response = @gateway.authorize(@amount, @credit_card, @options) assert_success response - assert_equal "Succeeded", response.message + assert_equal 'Succeeded', response.message assert_match %r(^\d+\|.+$), response.authorization capture = @gateway.capture(@amount, response.authorization) assert_success capture - assert_equal "Succeeded", capture.message + assert_equal 'Succeeded', capture.message end def test_failed_authorize response = @gateway.authorize(@amount, @declined_card, @options) assert_failure response - assert_equal "Decline transaction", response.message + assert_equal 'Decline transaction', response.message assert_equal Gateway::STANDARD_ERROR_CODE[:card_declined], response.error_code end def test_failed_capture response = @gateway.authorize(@amount, @credit_card, @options) assert_success response - assert_equal "Succeeded", response.message + assert_equal 'Succeeded', response.message - capture = @gateway.capture(@amount, response.authorization) + @gateway.capture(@amount, response.authorization) capture = @gateway.capture(@amount, response.authorization) assert_failure capture - assert_equal "Duplicated transaction", capture.message + assert_equal 'Duplicated force transaction.', capture.message end def test_successful_void @@ -116,7 +116,7 @@ def test_successful_void void = @gateway.void(response.authorization) assert_success void - assert_equal "Succeeded", void.message + assert_equal 'Succeeded', void.message end def test_void_can_receive_order_id @@ -125,17 +125,17 @@ def test_void_can_receive_order_id void = @gateway.void(response.authorization, order_id: SecureRandom.random_number(1000000)) assert_success void - assert_equal "Succeeded", void.message + assert_equal 'Succeeded', void.message end def test_failed_void response = @gateway.authorize(@amount, @credit_card, @options) assert_success response - void = @gateway.void(response.authorization) + @gateway.void(response.authorization) void = @gateway.void(response.authorization) assert_failure void - assert_equal "Original Transaction not found", void.message + assert_equal 'Original Transaction not found', void.message end def test_successful_refund @@ -144,25 +144,25 @@ def test_successful_refund refund = @gateway.refund(@amount, response.authorization) assert_success refund - assert_equal "Succeeded", refund.message + assert_equal 'Succeeded', refund.message end def test_failed_refund - response = @gateway.refund(nil, "") + response = @gateway.refund(nil, '') assert_failure response - assert_equal "See transcript for detailed error description.", response.message + assert_equal 'See transcript for detailed error description.', response.message end def test_successful_credit response = @gateway.credit(@amount, @credit_card, @options) assert_success response - assert_equal "Succeeded", response.message + assert_equal 'Succeeded', response.message end def test_failed_credit response = @gateway.credit(@amount, @invalid_card, @options) assert_failure response - assert_equal "Invalid card number", response.message + assert_equal 'Invalid card number', response.message assert_equal Gateway::STANDARD_ERROR_CODE[:invalid_number], response.error_code end @@ -175,7 +175,7 @@ def test_successful_verify def test_failed_verify response = @gateway.verify(@declined_card, @options) assert_failure response - assert_equal "Decline transaction", response.message + assert_equal 'Decline transaction', response.message assert_equal Gateway::STANDARD_ERROR_CODE[:card_declined], response.error_code end diff --git a/test/remote/gateways/remote_checkout_test.rb b/test/remote/gateways/remote_checkout_test.rb index 149c3837031..206442a70fa 100644 --- a/test/remote/gateways/remote_checkout_test.rb +++ b/test/remote/gateways/remote_checkout_test.rb @@ -4,10 +4,10 @@ class RemoteCheckoutTest < Test::Unit::TestCase def setup @gateway = ActiveMerchant::Billing::CheckoutGateway.new(fixtures(:checkout)) @credit_card = credit_card( - "4543474002249996", - month: "06", - year: "2017", - verification_value: "956" + '4543474002249996', + month: '06', + year: '2017', + verification_value: '956' ) @declined_card = credit_card( '4543474002249996', @@ -16,7 +16,7 @@ def setup verification_value: '958' ) @options = { - currency: "CAD" + currency: 'CAD' } end @@ -28,11 +28,11 @@ def test_successful_purchase def test_successful_purchase_with_extra_options response = @gateway.purchase(100, @credit_card, @options.merge( - currency: "EUR", - email: "bob@example.com", + currency: 'EUR', + email: 'bob@example.com', order_id: generate_unique_id, customer: generate_unique_id, - ip: "127.0.0.1" + ip: '127.0.0.1' )) assert_success response assert_equal 'Successful', response.message @@ -45,7 +45,7 @@ def test_successful_purchase_without_billing_address end def test_successful_purchase_with_descriptors - response = @gateway.purchase(100, @credit_card, descriptor_name: "TheName", descriptor_city: "Wanaque") + response = @gateway.purchase(100, @credit_card, descriptor_name: 'TheName', descriptor_city: 'Wanaque') assert_success response assert_equal 'Successful', response.message end @@ -60,7 +60,7 @@ def test_successful_authorize_and_capture auth = @gateway.authorize(100, @credit_card, @options) assert_success auth - assert capture = @gateway.capture(100, auth.authorization, {currency: "CAD"}) + assert capture = @gateway.capture(100, auth.authorization, {currency: 'CAD'}) assert_success capture assert_equal 'Successful', capture.message end @@ -101,26 +101,26 @@ def test_successful_refund assert response = @gateway.purchase(100, @credit_card, @options) assert_success response - assert refund = @gateway.refund(100, response.authorization, {currency: "CAD"}) + assert refund = @gateway.refund(100, response.authorization, {currency: 'CAD'}) assert_success refund - assert_equal "Successful", refund.message + assert_equal 'Successful', refund.message end def test_failed_refund assert response = @gateway.purchase(100, @credit_card, @options) assert_success response - assert refund = @gateway.refund(100, '||||', {currency: "CAD"}) + assert refund = @gateway.refund(100, '||||', {currency: 'CAD'}) assert_failure refund end def test_successful_verify assert response = @gateway.verify(@credit_card, @options) assert_success response - assert_equal "Successful", response.message + assert_equal 'Successful', response.message - assert_success response.responses.last, "The void should succeed" - assert_equal "Successful", response.responses.last.params["result"] + assert_success response.responses.last, 'The void should succeed' + assert_equal 'Successful', response.responses.last.params['result'] end def test_failed_verify diff --git a/test/remote/gateways/remote_checkout_v2_test.rb b/test/remote/gateways/remote_checkout_v2_test.rb index e196c849134..893347aa7f8 100644 --- a/test/remote/gateways/remote_checkout_v2_test.rb +++ b/test/remote/gateways/remote_checkout_v2_test.rb @@ -6,14 +6,20 @@ def setup @amount = 200 @credit_card = credit_card('4242424242424242', verification_value: '100', month: '6', year: '2018') + @expired_card = credit_card('4242424242424242', verification_value: '100', month: '6', year: '2010') @declined_card = credit_card('4000300011112220') @options = { order_id: '1', billing_address: address, description: 'Purchase', - email: "longbob.longsen@example.com" + email: 'longbob.longsen@example.com' } + @additional_options = @options.merge( + card_on_file: true, + transaction_indicator: 2, + previous_charge_id: 'charge_12312' + ) end def test_transcript_scrubbing @@ -33,8 +39,44 @@ def test_successful_purchase assert_equal 'Succeeded', response.message end + def test_successful_purchase_with_additional_options + response = @gateway.purchase(@amount, @credit_card, @additional_options) + assert_success response + assert_equal 'Succeeded', response.message + end + + def test_successful_purchase_includes_avs_result + response = @gateway.purchase(@amount, @credit_card, @options) + assert_success response + assert_equal 'Succeeded', response.message + assert_equal 'S', response.avs_result['code'] + assert_equal 'U.S.-issuing bank does not support AVS.', response.avs_result['message'] + end + + def test_successful_authorize_includes_avs_result + response = @gateway.authorize(@amount, @credit_card, @options) + assert_success response + assert_equal 'Succeeded', response.message + assert_equal 'S', response.avs_result['code'] + assert_equal 'U.S.-issuing bank does not support AVS.', response.avs_result['message'] + end + + def test_successful_purchase_includes_cvv_result + response = @gateway.purchase(@amount, @credit_card, @options) + assert_success response + assert_equal 'Succeeded', response.message + assert_equal 'Y', response.cvv_result['code'] + end + + def test_successful_authorize_includes_cvv_result + response = @gateway.authorize(@amount, @credit_card, @options) + assert_success response + assert_equal 'Succeeded', response.message + assert_equal 'Y', response.cvv_result['code'] + end + def test_successful_purchase_with_descriptors - options = @options.merge(descriptor_name: "shop", descriptor_city: "london") + options = @options.merge(descriptor_name: 'shop', descriptor_city: 'london') response = @gateway.purchase(@amount, @credit_card, options) assert_success response assert_equal 'Succeeded', response.message @@ -52,12 +94,30 @@ def test_successful_purchase_without_phone_number assert_equal 'Succeeded', response.message end + def test_successful_purchase_with_ip + response = @gateway.purchase(@amount, @credit_card, ip: '96.125.185.52') + assert_success response + assert_equal 'Succeeded', response.message + end + def test_failed_purchase response = @gateway.purchase(@amount, @declined_card, @options) assert_failure response assert_equal 'Invalid Card Number', response.message end + def test_avs_failed_purchase + response = @gateway.purchase(@amount, @credit_card, billing_address: address.update(address1: 'Test_A')) + assert_failure response + assert_equal '40111 - Street Match Only', response.message + end + + def test_avs_failed_authorize + response = @gateway.authorize(@amount, @credit_card, billing_address: address.update(address1: 'Test_A')) + assert_failure response + assert_equal '40111 - Street Match Only', response.message + end + def test_successful_authorize_and_capture auth = @gateway.authorize(@amount, @credit_card, @options) assert_success auth @@ -66,6 +126,14 @@ def test_successful_authorize_and_capture assert_success capture end + def test_successful_authorize_and_capture_with_additional_options + auth = @gateway.authorize(@amount, @credit_card, @additional_options) + assert_success auth + + assert capture = @gateway.capture(nil, auth.authorization) + assert_success capture + end + def test_failed_authorize response = @gateway.authorize(@amount, @declined_card, @options) assert_failure response @@ -130,4 +198,11 @@ def test_failed_verify assert_match %r{Invalid Card Number}, response.message assert_equal Gateway::STANDARD_ERROR_CODE[:invalid_number], response.error_code end + + def test_expired_card_returns_error_code + response = @gateway.purchase(@amount, @expired_card, @options) + assert_failure response + assert_equal 'Validation error: Expired Card', response.message + assert_equal '70000: 70077', response.error_code + end end diff --git a/test/remote/gateways/remote_citrus_pay_test.rb b/test/remote/gateways/remote_citrus_pay_test.rb index 704d11cf8e0..cf7d131b942 100644 --- a/test/remote/gateways/remote_citrus_pay_test.rb +++ b/test/remote/gateways/remote_citrus_pay_test.rb @@ -22,58 +22,58 @@ def teardown def test_successful_purchase assert response = @gateway.purchase(@amount, @credit_card, @options) assert_success response - assert_equal "Succeeded", response.message + assert_equal 'Succeeded', response.message end def test_successful_purchase_sans_options assert response = @gateway.purchase(@amount, @credit_card) assert_success response - assert_equal "Succeeded", response.message + assert_equal 'Succeeded', response.message end def test_successful_purchase_with_more_options more_options = @options.merge({ - ip: "127.0.0.1", - email: "joe@example.com", + ip: '127.0.0.1', + email: 'joe@example.com', }) assert response = @gateway.purchase(@amount, @credit_card, @options.merge(more_options)) assert_success response - assert_equal "Succeeded", response.message + assert_equal 'Succeeded', response.message end def test_adds_3dsecure_id_to_authorize more_options = @options.merge({ - ip: "127.0.0.1", - email: "joe@example.com", - threed_secure_id: "abc123" + ip: '127.0.0.1', + email: 'joe@example.com', + threed_secure_id: 'abc123' }) assert response = @gateway.purchase(@amount, @credit_card, @options.merge(more_options)) - assert_match "No check has been performed for this merchant and 3D Secure Id.", response.message + assert_match 'No check has been performed for this merchant and 3D Secure Id.', response.message end def test_failed_purchase assert response = @gateway.purchase(@amount, @declined_card, @options) assert_failure response - assert_match /FAILURE/, response.message + assert_match %r{FAILURE}, response.message end def test_successful_authorize_and_capture assert response = @gateway.authorize(@amount, @credit_card, @options) assert_success response - assert_equal "Succeeded", response.message + assert_equal 'Succeeded', response.message assert_match %r(^.+\|\d+$), response.authorization assert capture = @gateway.capture(@amount, response.authorization) assert_success capture - assert_equal "Succeeded", capture.message + assert_equal 'Succeeded', capture.message end def test_failed_authorize assert response = @gateway.authorize(@amount, @declined_card, @options) assert_failure response - assert_match /FAILURE/, response.message + assert_match(/FAILURE/, response.message) end def test_successful_refund @@ -82,7 +82,7 @@ def test_successful_refund assert refund = @gateway.refund(@amount, response.authorization) assert_success refund - assert_equal "Succeeded", refund.message + assert_equal 'Succeeded', refund.message end def test_successful_void @@ -96,10 +96,10 @@ def test_successful_void def test_successful_verify assert response = @gateway.verify(@credit_card, @options) assert_success response - assert_equal "Succeeded", response.message + assert_equal 'Succeeded', response.message - assert_success response.responses.last, "The void should succeed" - assert_equal "SUCCESS", response.responses.last.params["result"] + assert_success response.responses.last, 'The void should succeed' + assert_equal 'SUCCESS', response.responses.last.params['result'] end def test_invalid_login @@ -109,11 +109,11 @@ def test_invalid_login ) response = gateway.authorize(@amount, @credit_card, @options) assert_failure response - assert_equal "ERROR - INVALID_REQUEST - Invalid credentials.", response.message + assert_equal 'ERROR - INVALID_REQUEST - Invalid credentials.', response.message end def test_transcript_scrubbing - card = credit_card("4987654321098769", verification_value: "134") + card = credit_card('4987654321098769', verification_value: '134') transcript = capture_transcript(@gateway) do @gateway.purchase(@amount, card, @options) end diff --git a/test/remote/gateways/remote_clearhaus_test.rb b/test/remote/gateways/remote_clearhaus_test.rb index 48da7c9b1a8..9a716294dcb 100644 --- a/test/remote/gateways/remote_clearhaus_test.rb +++ b/test/remote/gateways/remote_clearhaus_test.rb @@ -38,22 +38,22 @@ def test_cleans_whitespace_from_private_key def test_unsuccessful_signing_request credentials = fixtures(:clearhaus_secure) - credentials[:private_key] = "foo" + credentials[:private_key] = 'foo' gateway = ClearhausGateway.new(credentials) assert gateway.options[:private_key] assert auth = gateway.authorize(@amount, @credit_card, @options) assert_failure auth - assert_equal "Neither PUB key nor PRIV key: not enough data", auth.message + assert_equal 'Neither PUB key nor PRIV key: not enough data', auth.message credentials = fixtures(:clearhaus_secure) - credentials[:signing_key] = "foo" + credentials[:signing_key] = 'foo' gateway = ClearhausGateway.new(credentials) assert gateway.options[:signing_key] assert auth = gateway.authorize(@amount, @credit_card, @options) assert_failure auth - assert_equal "invalid signing api-key", auth.message + assert_equal 'invalid signing api-key', auth.message end def test_successful_purchase_without_cvv @@ -66,18 +66,18 @@ def test_successful_purchase_without_cvv end def test_successful_purchase_with_text_on_statement - options = { text_on_statement: "hello" } + options = { text_on_statement: 'hello' } response = @gateway.purchase(@amount, @credit_card, @options.merge(options)) assert_success response - assert_equal response.params["text_on_statement"], "hello" + assert_equal response.params['text_on_statement'], 'hello' assert_equal 'Approved', response.message end def test_successful_purchase_with_more_options options = { order_id: '1', - ip: "127.0.0.1", + ip: '127.0.0.1', } response = @gateway.purchase(@amount, @credit_card, @options.merge(options)) @@ -118,7 +118,7 @@ def test_partial_capture end def test_failed_capture - response = @gateway.capture(@amount, '') + response = @gateway.capture(@amount, 'z') assert_failure response assert_equal 'invalid transaction id', response.message end @@ -196,4 +196,14 @@ def test_invalid_login gateway.purchase(@amount, @credit_card, @options) end end + + def test_transcript_scrubbing + transcript = capture_transcript(@gateway) do + @gateway.purchase(@amount, @credit_card, @options) + end + transcript = @gateway.scrub(transcript) + + assert_scrubbed(@credit_card.number, transcript) + assert_scrubbed(@credit_card.verification_value, transcript) + end end diff --git a/test/remote/gateways/remote_commercegate_test.rb b/test/remote/gateways/remote_commercegate_test.rb index 7077742a19b..3ca37b555c2 100644 --- a/test/remote/gateways/remote_commercegate_test.rb +++ b/test/remote/gateways/remote_commercegate_test.rb @@ -18,24 +18,24 @@ def test_successful_authorize assert response = @gateway.authorize(@amount, @credit_card, @options) assert_success response assert_equal response.params['action'], 'AUTH' - assert_equal 'U', response.avs_result["code"] - assert_equal 'M', response.cvv_result["code"] + assert_equal 'U', response.avs_result['code'] + assert_equal 'M', response.cvv_result['code'] end def test_successful_authorize_without_options assert response = @gateway.authorize(@amount, @credit_card) assert_success response assert_equal response.params['action'], 'AUTH' - assert_nil response.avs_result["code"] - assert_equal 'M', response.cvv_result["code"] + assert_nil response.avs_result['code'] + assert_equal 'M', response.cvv_result['code'] end def test_successful_purchase assert response = @gateway.purchase(@amount, @credit_card, @options) assert_success response assert_equal response.params['action'], 'SALE' - assert_equal 'U', response.avs_result["code"] - assert_equal 'M', response.cvv_result["code"] + assert_equal 'U', response.avs_result['code'] + assert_equal 'M', response.cvv_result['code'] end def test_unsuccessful_purchase diff --git a/test/remote/gateways/remote_conekta_test.rb b/test/remote/gateways/remote_conekta_test.rb index 10206246124..c466b8ad74c 100644 --- a/test/remote/gateways/remote_conekta_test.rb +++ b/test/remote/gateways/remote_conekta_test.rb @@ -7,36 +7,45 @@ def setup @amount = 300 @credit_card = ActiveMerchant::Billing::CreditCard.new( - number: "4242424242424242", - verification_value: "183", - month: "01", - year: "2018", - first_name: "Mario F.", - last_name: "Moreno Reyes" + number: '4242424242424242', + verification_value: '183', + month: '01', + year: '2019', + first_name: 'Mario F.', + last_name: 'Moreno Reyes' ) @declined_card = ActiveMerchant::Billing::CreditCard.new( - number: "4000000000000002", - verification_value: "183", - month: "01", - year: "2018", - first_name: "Mario F.", - last_name: "Moreno Reyes" + number: '4000000000000002', + verification_value: '183', + month: '01', + year: '2019', + first_name: 'Mario F.', + last_name: 'Moreno Reyes' ) @options = { - :device_fingerprint => "41l9l92hjco6cuekf0c7dq68v4", + :device_fingerprint => '41l9l92hjco6cuekf0c7dq68v4', description: 'Blue clip', billing_address: { - address1: "Rio Missisipi #123", - address2: "Paris", - city: "Guerrero", - country: "Mexico", - zip: "5555", - name: "Mario Reyes", - phone: "12345678", + address1: 'Rio Missisipi #123', + address2: 'Paris', + city: 'Guerrero', + country: 'Mexico', + zip: '5555', + name: 'Mario Reyes', + phone: '12345678', }, - carrier: "Estafeta" + carrier: 'Estafeta', + email: 'bob@something.com', + line_items: [{ + name: 'Box of Cohiba S1s', + description: 'Imported From Mex.', + unit_price: 20000, + quantity: 1, + sku: '7500244909', + type: 'food' + }] } end @@ -46,6 +55,12 @@ def test_successful_purchase assert_equal nil, response.message end + def test_successful_purchase_with_installments + assert response = @gateway.purchase(@amount * 300, @credit_card, @options.merge({monthly_installments: 3})) + assert_success response + assert_equal nil, response.message + end + def test_unsuccessful_purchase assert response = @gateway.purchase(@amount, @declined_card, @options) assert_failure response @@ -53,7 +68,7 @@ def test_unsuccessful_purchase def test_successful_refund assert response = @gateway.purchase(@amount, @credit_card, @options) - @options[:order_id] = response.params["id"] + @options[:order_id] = response.params['id'] assert_success response assert_equal nil, response.message @@ -67,7 +82,7 @@ def test_successful_void assert_success response assert_equal nil, response.message - identifier = response.params["id"] + identifier = response.params['id'] assert response = @gateway.void(identifier) assert_success response @@ -79,17 +94,17 @@ def test_unsuccessful_void assert_success response assert_equal nil, response.message - identifier = response.params["id"] + identifier = response.params['id'] assert response = @gateway.void(identifier) assert_failure response - assert_equal "El cargo no existe o no es apto para esta operación.", response.message + assert_equal 'El cargo no existe o no es apto para esta operación.', response.message end def test_unsuccessful_refund - assert response = @gateway.refund(@amount, "1", @options) + assert response = @gateway.refund(@amount, '1', @options) assert_failure response - assert_equal "El recurso no ha sido encontrado.", response.message + assert_equal 'El recurso no ha sido encontrado.', response.message end def test_successful_authorize @@ -114,54 +129,60 @@ def test_successful_capture end def test_unsuccessful_capture - assert response = @gateway.capture(@amount, "1", @options) + assert response = @gateway.capture(@amount, '1', @options) assert_failure response - assert_equal "El recurso no ha sido encontrado.", response.message + assert_equal 'El recurso no ha sido encontrado.', response.message end def test_successful_purchase_passing_more_details more_options = { - customer: "TheCustomerName", + customer: 'TheCustomerName', shipping_address: { - address1: "33 Main Street", - address2: "Apartment 3", - city: "Wanaque", - state: "NJ", - country: "USA", - zip: "01085", + address1: '33 Main Street', + address2: 'Apartment 3', + city: 'Wanaque', + state: 'NJ', + country: 'USA', + zip: '01085', }, line_items: [ { - rname: "Box of Cohiba S1s", - description: "Imported From Mex.", + name: 'Box of Cohiba S1s', + description: 'Imported From Mex.', unit_price: 20000, quantity: 1, - sku: "cohb_s1", - type: "other_human_consumption" + sku: 'cohb_s1', + type: 'other_human_consumption' }, { - name: "Basic Toothpicks", - description: "Wooden", + name: 'Basic Toothpicks', + description: 'Wooden', unit_price: 100, quantity: 250, - sku: "tooth_r3", - type: "Extra pointy" + sku: 'tooth_r3', + type: 'Extra pointy' } ] } assert response = @gateway.purchase(@amount, @credit_card, @options.merge(more_options)) assert_success response - assert_equal "Wanaque", response.params['details']['shipment']['address']['city'] - assert_equal "Wooden", response.params['details']['line_items'][-1]['description'] - assert_equal "TheCustomerName", response.params['details']['name'] - assert_equal "Guerrero", response.params['details']['billing_address']['city'] + assert_equal 'Wanaque', response.params['details']['shipment']['address']['city'] + assert_equal 'Wooden', response.params['details']['line_items'][-1]['description'] + assert_equal 'TheCustomerName', response.params['details']['name'] + assert_equal 'Guerrero', response.params['details']['billing_address']['city'] + end + + def test_failed_purchase_with_no_details + assert response = @gateway.purchase(@amount, @credit_card, {}) + assert_failure response + assert_equal 'Falta el correo del comprador.', response.message end def test_invalid_key gateway = ConektaGateway.new(key: 'invalid_token') assert response = gateway.purchase(@amount, @credit_card, @options) assert_failure response - assert_equal "Acceso no autorizado.", response.message + assert_equal 'Acceso no autorizado.', response.message end def test_transcript_scrubbing diff --git a/test/remote/gateways/remote_creditcall_test.rb b/test/remote/gateways/remote_creditcall_test.rb index abf6c18ff49..527d60979a6 100644 --- a/test/remote/gateways/remote_creditcall_test.rb +++ b/test/remote/gateways/remote_creditcall_test.rb @@ -22,14 +22,17 @@ def test_successful_purchase def test_successful_purchase_sans_options response = @gateway.purchase(@amount, @credit_card) assert_success response + assert_equal response.params['Zip'], 'notchecked' + assert_equal response.params['Address'], 'notchecked' assert_equal 'Succeeded', response.message end def test_successful_purchase_with_more_options options = { order_id: '1', - ip: "127.0.0.1", - email: "joe@example.com" + ip: '127.0.0.1', + email: 'joe@example.com', + manual_type: 'cnp' } response = @gateway.purchase(@amount, @credit_card, options) @@ -50,6 +53,22 @@ def test_successful_authorize assert_equal 'Succeeded', auth.message end + def test_successful_authorize_with_zip_verification + response = @gateway.authorize(@amount, @credit_card, @options.merge(verify_zip: 'true')) + assert_success response + assert_equal response.params['Zip'], 'matched' + assert_equal response.params['Address'], 'notchecked' + assert_equal 'Succeeded', response.message + end + + def test_successful_authorize_with_address_verification + response = @gateway.authorize(@amount, @credit_card, @options.merge(verify_address: 'true')) + assert_success response + assert_equal response.params['Zip'], 'notchecked' + assert_equal response.params['Address'], 'matched' + assert_equal 'Succeeded', response.message + end + def test_successful_authorize_and_capture auth = @gateway.authorize(@amount, @credit_card, @options) assert_success auth @@ -125,7 +144,7 @@ def test_successful_verify end def test_failed_verify - @declined_card.number = "" + @declined_card.number = '' response = @gateway.verify(@declined_card, @options) assert_failure response assert_match %r{PAN Must be >= 13 Digits}, response.message @@ -148,6 +167,5 @@ def test_transcript_scrubbing assert_scrubbed(@credit_card.number, transcript) assert_scrubbed(@credit_card.verification_value, transcript) assert_scrubbed(@gateway.options[:transaction_key], transcript) - end end diff --git a/test/remote/gateways/remote_credorax_test.rb b/test/remote/gateways/remote_credorax_test.rb index 6787b6567a5..52f611fa200 100644 --- a/test/remote/gateways/remote_credorax_test.rb +++ b/test/remote/gateways/remote_credorax_test.rb @@ -5,18 +5,18 @@ def setup @gateway = CredoraxGateway.new(fixtures(:credorax)) @amount = 100 - @credit_card = credit_card('5223450000000007', verification_value: "090", month: "12", year: "2025") - @declined_card = credit_card('4000300011112220') + @credit_card = credit_card('4176661000001015', verification_value: '281', month: '12', year: '2022') + @declined_card = credit_card('4176661000001111', verification_value: '681', month: '12', year: '2022') @options = { - order_id: "1", - currency: "EUR", + order_id: '1', + currency: 'EUR', billing_address: address, description: 'Store Purchase' } end def test_invalid_login - gateway = CredoraxGateway.new(merchant_id: "", cipher_key: "") + gateway = CredoraxGateway.new(merchant_id: '', cipher_key: '') response = gateway.purchase(@amount, @credit_card, @options) assert_failure response end @@ -24,39 +24,47 @@ def test_invalid_login def test_successful_purchase response = @gateway.purchase(@amount, @credit_card, @options) assert_success response - assert_equal "1", response.params["H9"] - assert_equal "Succeeded", response.message + assert_equal '1', response.params['H9'] + assert_equal 'Succeeded', response.message + end + + def test_successful_purchase_with_extra_options + response = @gateway.purchase(@amount, @credit_card, @options.merge(transaction_type: '10')) + assert_success response + assert_equal '1', response.params['H9'] + assert_equal 'Succeeded', response.message end def test_failed_purchase response = @gateway.purchase(@amount, @declined_card, @options) assert_failure response - assert_equal "Transaction has been declined.", response.message + assert_equal 'Transaction not allowed for cardholder', response.message end def test_successful_authorize_and_capture response = @gateway.authorize(@amount, @credit_card, @options) assert_success response - assert_equal "Succeeded", response.message + assert_equal 'Succeeded', response.message assert response.authorization capture = @gateway.capture(@amount, response.authorization) assert_success capture - assert_equal "Succeeded", capture.message + assert_equal 'Succeeded', capture.message end def test_failed_authorize response = @gateway.authorize(@amount, @declined_card, @options) assert_failure response - assert_equal "Transaction has been declined.", response.message - assert_equal "05", response.params["Z2"] + assert_equal 'Transaction not allowed for cardholder', response.message end def test_failed_capture - response = @gateway.capture(@amount, "") - assert_failure response - assert_equal "2. At least one of input parameters is malformed.: Parameter [g4] cannot be empty.", response.message - assert_equal "-9", response.params["Z2"] + auth = @gateway.authorize(@amount, @credit_card, @options) + assert_success auth + + capture = @gateway.capture(0, auth.authorization) + assert_failure capture + assert_equal 'Invalid amount', capture.message end def test_successful_purchase_and_void @@ -65,7 +73,7 @@ def test_successful_purchase_and_void void = @gateway.void(response.authorization) assert_success void - assert_equal "Succeeded", void.message + assert_equal 'Succeeded', void.message end def test_successful_authorize_and_void @@ -74,29 +82,28 @@ def test_successful_authorize_and_void void = @gateway.void(response.authorization) assert_success void - assert_equal "Succeeded", void.message + assert_equal 'Succeeded', void.message end def test_successful_capture_and_void response = @gateway.authorize(@amount, @credit_card, @options) assert_success response - assert_equal "Succeeded", response.message + assert_equal 'Succeeded', response.message assert response.authorization capture = @gateway.capture(@amount, response.authorization) assert_success capture - assert_equal "Succeeded", capture.message + assert_equal 'Succeeded', capture.message void = @gateway.void(capture.authorization) assert_success void - assert_equal "Succeeded", void.message + assert_equal 'Succeeded', void.message end def test_failed_void - response = @gateway.void("") + response = @gateway.void('') assert_failure response - assert_equal "2. At least one of input parameters is malformed.: Parameter [g4] cannot be empty.", response.message - assert_equal "-9", response.params["Z2"] + assert_equal 'Referred to transaction has not been found.', response.message end def test_successful_refund @@ -105,7 +112,7 @@ def test_successful_refund refund = @gateway.refund(@amount, response.authorization) assert_success refund - assert_equal "Succeeded", refund.message + assert_equal 'Succeeded', refund.message end def test_successful_refund_and_void @@ -114,43 +121,41 @@ def test_successful_refund_and_void refund = @gateway.refund(@amount, response.authorization) assert_success refund - assert_equal "Succeeded", refund.message + assert_equal 'Succeeded', refund.message void = @gateway.void(refund.authorization) assert_success void - assert_equal "Succeeded", void.message + assert_equal 'Succeeded', void.message end def test_failed_refund - response = @gateway.refund(nil, "") + response = @gateway.refund(nil, '123;123;123') assert_failure response - assert_equal "2. At least one of input parameters is malformed.: Parameter [g4] cannot be empty.", response.message - assert_equal "-9", response.params["Z2"] + assert_equal 'Referred to transaction has not been found.', response.message end def test_successful_credit response = @gateway.credit(@amount, @credit_card, @options) assert_success response - assert_equal "Succeeded", response.message + assert_equal 'Succeeded', response.message end def test_failed_credit - response = @gateway.credit(@amount, @declined_card, @options) + response = @gateway.credit(0, @declined_card, @options) assert_failure response - assert_equal "Transaction has been declined.", response.message + assert_equal 'Invalid amount', response.message end def test_successful_verify response = @gateway.verify(@credit_card, @options) assert_success response - assert_equal "Succeeded", response.message + assert_equal 'Succeeded', response.message end def test_failed_verify response = @gateway.verify(@declined_card, @options) assert_failure response - assert_equal "Transaction has been declined.", response.message - assert_equal "05", response.params["Z2"] + assert_equal 'Transaction not allowed for cardholder', response.message end def test_transcript_scrubbing @@ -163,314 +168,314 @@ def test_transcript_scrubbing assert_scrubbed(@credit_card.verification_value.to_s, clean_transcript) end - ######################################################################### - # CERTIFICATION SPECIFIC REMOTE TESTS - ######################################################################### - - # Send [a5] currency code parameter as "AFN" - def test_certification_error_unregistered_currency - @options[:echo] = "33BE888" - @options[:currency] = "AFN" - response = @gateway.purchase(@amount, @credit_card, @options) - assert_failure response - end - - # Send [b2] parameter as "6" - def test_certification_error_unregistered_card - @options[:echo] = "33BE889" - response = @gateway.purchase(@amount, @credit_card, @options) - assert_failure response - end - - # In the future, merchant expected to investigate each such case offline. - def test_certification_error_no_response_from_the_gate - @options[:echo] = "33BE88A" - response = @gateway.purchase(@amount, @credit_card, @options) - assert_failure response - end - - # Merchant is expected to verify if the code is "0" - in this case the - # transaction should be considered approved. In all other cases the - # offline investigation should take place. - def test_certification_error_unknown_result_code - @options[:echo] = "33BE88B" - response = @gateway.purchase(@amount, @credit_card, @options) - assert_failure response - end - - # Merchant is expected to verify if the code is "00" - in this case the - # transaction should be considered approved. In all other cases the - # transaction is declined. The exact reason should be investigated offline. - def test_certification_error_unknown_response_reason_code - @options[:echo] = "33BE88C" - @options[:email] = "brucewayne@dccomics.com" - @options[:billing_address] = { - address1: "5050 Gotham Drive", - city: "Toronto", - zip: "B2M 1Y9", - state: "ON", - country: "CA", - phone: "(0800)228626" - } - - credit_card = credit_card('4176661000001015', - brand: "visa", - verification_value: "281", - month: "12", - year: "17", - first_name: "Bruce", - last_name: "Wayne") - - response = @gateway.purchase(@amount, credit_card, @options) - assert_failure response - end - - # All fields marked as mandatory are expected to be populated with the - # above default values. Mandatory fields with no values on the - # certification template should be populated with your own meaningful - # values and comply with our API specifications. The d2 parameter is - # mandatory during certification only to allow for tracking of tests. - # Expected result of this test: Time out - def test_certification_time_out - @options[:echo] = "33BE88D" - @options[:email] = "brucewayne@dccomics.com" - @options[:billing_address] = { - address1: "5050 Gotham Drive", - city: "Toronto", - zip: "B2M 1Y9", - state: "ON", - country: "CA", - phone: "(0800)228626" - } - - credit_card = credit_card('5473470000000010', - brand: "master", - verification_value: "939", - month: "12", - year: "17", - first_name: "Bruce", - last_name: "Wayne") - - response = @gateway.purchase(@amount, credit_card, @options) - assert_failure response - end - - # All fields marked as mandatory are expected to be populated - # with the above default values. Mandatory fields with no values - # on the certification template should be populated with your - # own meaningful values and comply with our API specifications. - # The d2 parameter is mandatory during certification only to - # allow for tracking of tests. - def test_certification_za_zb_zc - @options[:echo] = "33BE88E" - @options[:email] = "brucewayne@dccomics.com" - @options[:billing_address] = { - address1: "5050 Gotham Drive", - city: "Toronto", - zip: "B2M 1Y9", - state: "ON", - country: "CA", - phone: "(0800)228626" - } - - credit_card = credit_card('5473470000000010', - verification_value: "939", - month: "12", - year: "17", - first_name: "Bruce", - last_name: "Wayne") - - purchase = @gateway.purchase(@amount, credit_card, @options) - assert_success purchase - assert_equal "Succeeded", purchase.message - - refund_options = {echo: "33BE892"} - refund = @gateway.refund(@amount, purchase.authorization, refund_options) - assert_success refund - assert_equal "Succeeded", refund.message - - void_options = {echo: "33BE895"} - void = @gateway.void(refund.authorization, void_options) - assert_success void - assert_equal "Succeeded", refund.message - end - - # All fields marked as mandatory are expected to be populated - # with the above default values. Mandatory fields with no values - # on the certification template should be populated with your - # own meaningful values and comply with our API specifications. - # The d2 parameter is mandatory during certification only to - # allow for tracking of tests. - def test_certification_zg_zh - @options[:echo] = "33BE88F" - @options[:email] = "clark.kent@dccomics.com" - @options[:billing_address] = { - address1: "2020 Krypton Drive", - city: "Toronto", - zip: "S2M 1YR", - state: "ON", - country: "CA", - phone: "(0800) 78737626" - } - - credit_card = credit_card('4176661000001015', - brand: "visa", - verification_value: "281", - month: "12", - year: "17", - first_name: "Clark", - last_name: "Kent") - - response = @gateway.authorize(@amount, credit_card, @options) - assert_success response - assert_equal "Succeeded", response.message - - capture_options = {echo: "33BE890"} - capture = @gateway.capture(@amount, response.authorization, capture_options) - assert_success capture - assert_equal "Succeeded", capture.message - end - - # All fields marked as mandatory are expected to be populated - # with the above default values. Mandatory fields with no values - # on the certification template should be populated with your - # own meaningful values and comply with our API specifications. - # The d2 parameter is mandatory during certification only to - # allow for tracking of tests. - def test_certification_zg_zj - @options[:echo] = "33BE88F" - @options[:email] = "clark.kent@dccomics.com" - @options[:billing_address] = { - address1: "2020 Krypton Drive", - city: "Toronto", - zip: "S2M 1YR", - state: "ON", - country: "CA", - phone: "(0800) 78737626" - } - - credit_card = credit_card('4176661000001015', - brand: "visa", - verification_value: "281", - month: "12", - year: "17", - first_name: "Clark", - last_name: "Kent") - - response = @gateway.authorize(@amount, credit_card, @options) - assert_success response - assert_equal "Succeeded", response.message - - auth_void_options = {echo: "33BE891"} - auth_void = @gateway.void(response.authorization, auth_void_options) - assert_success auth_void - assert_equal "Succeeded", auth_void.message - end - - # All fields marked as mandatory are expected to be populated - # with the above default values. Mandatory fields with no values - # on the certification template should be populated with your - # own meaningful values and comply with our API specifications. - # The d2 parameter is mandatory during certification only to - # allow for tracking of tests. - # - # Certification for independent credit (credit) - def test_certification_zd - @options[:echo] = "33BE893" - @options[:email] = "wadewilson@marvel.com" - @options[:billing_address] = { - address1: "5050 Deadpool Drive", - city: "Toronto", - zip: "D2P 1Y9", - state: "ON", - country: "CA", - phone: "+1(555)123-4567" - } - - credit_card = credit_card('4176661000001015', - brand: "visa", - verification_value: "281", - month: "12", - year: "17", - first_name: "Wade", - last_name: "Wilson") - - response = @gateway.credit(@amount, credit_card, @options) - assert_success response - assert_equal "Succeeded", response.message - end - - # Use the above values to fill the mandatory parameters in your - # certification test transactions. Note:The d2 parameter is only - # mandatory during certification to allow for tracking of tests. - # - # Certification for purchase void - def test_certification_zf - @options[:echo] = "33BE88E" - @options[:email] = "brucewayne@dccomics.com" - @options[:billing_address] = { - address1: "5050 Gotham Drive", - city: "Toronto", - zip: "B2M 1Y9", - state: "ON", - country: "CA", - phone: "(0800)228626" - } - - credit_card = credit_card('5473470000000010', - verification_value: "939", - month: "12", - year: "17", - first_name: "Bruce", - last_name: "Wayne") - - response = @gateway.purchase(@amount, credit_card, @options) - assert_success response - assert_equal "Succeeded", response.message - - void_options = {echo: "33BE894"} - void = @gateway.void(response.authorization, void_options) - assert_success void - assert_equal "Succeeded", void.message - end - - # Use the above values to fill the mandatory parameters in your - # certification test transactions. Note:The d2 parameter is only - # mandatory during certification to allow for tracking of tests. - # - # Certification for capture void - def test_certification_zi - @options[:echo] = "33BE88F" - @options[:email] = "clark.kent@dccomics.com" - @options[:billing_address] = { - address1: "2020 Krypton Drive", - city: "Toronto", - zip: "S2M 1YR", - state: "ON", - country: "CA", - phone: "(0800) 78737626" - } - - credit_card = credit_card('4176661000001015', - brand: "visa", - verification_value: "281", - month: "12", - year: "17", - first_name: "Clark", - last_name: "Kent") - - authorize = @gateway.authorize(@amount, credit_card, @options) - assert_success authorize - assert_equal "Succeeded", authorize.message - - capture_options = {echo: "33BE890"} - capture = @gateway.capture(@amount, authorize.authorization, capture_options) - assert_success capture - assert_equal "Succeeded", capture.message - - void_options = {echo: "33BE896"} - void = @gateway.void(capture.authorization, void_options) - assert_success void - assert_equal "Succeeded", void.message - end + # ######################################################################### + # # CERTIFICATION SPECIFIC REMOTE TESTS + # ######################################################################### + # + # # Send [a5] currency code parameter as "AFN" + # def test_certification_error_unregistered_currency + # @options[:echo] = "33BE888" + # @options[:currency] = "AFN" + # response = @gateway.purchase(@amount, @credit_card, @options) + # assert_failure response + # end + # + # # Send [b2] parameter as "6" + # def test_certification_error_unregistered_card + # @options[:echo] = "33BE889" + # response = @gateway.purchase(@amount, @credit_card, @options) + # assert_failure response + # end + # + # # In the future, merchant expected to investigate each such case offline. + # def test_certification_error_no_response_from_the_gate + # @options[:echo] = "33BE88A" + # response = @gateway.purchase(@amount, @credit_card, @options) + # assert_failure response + # end + # + # # Merchant is expected to verify if the code is "0" - in this case the + # # transaction should be considered approved. In all other cases the + # # offline investigation should take place. + # def test_certification_error_unknown_result_code + # @options[:echo] = "33BE88B" + # response = @gateway.purchase(@amount, @credit_card, @options) + # assert_failure response + # end + # + # # Merchant is expected to verify if the code is "00" - in this case the + # # transaction should be considered approved. In all other cases the + # # transaction is declined. The exact reason should be investigated offline. + # def test_certification_error_unknown_response_reason_code + # @options[:echo] = "33BE88C" + # @options[:email] = "brucewayne@dccomics.com" + # @options[:billing_address] = { + # address1: "5050 Gotham Drive", + # city: "Toronto", + # zip: "B2M 1Y9", + # state: "ON", + # country: "CA", + # phone: "(0800)228626" + # } + # + # credit_card = credit_card('4176661000001015', + # brand: "visa", + # verification_value: "281", + # month: "12", + # year: "17", + # first_name: "Bruce", + # last_name: "Wayne") + # + # response = @gateway.purchase(@amount, credit_card, @options) + # assert_failure response + # end + # + # # All fields marked as mandatory are expected to be populated with the + # # above default values. Mandatory fields with no values on the + # # certification template should be populated with your own meaningful + # # values and comply with our API specifications. The d2 parameter is + # # mandatory during certification only to allow for tracking of tests. + # # Expected result of this test: Time out + # def test_certification_time_out + # @options[:echo] = "33BE88D" + # @options[:email] = "brucewayne@dccomics.com" + # @options[:billing_address] = { + # address1: "5050 Gotham Drive", + # city: "Toronto", + # zip: "B2M 1Y9", + # state: "ON", + # country: "CA", + # phone: "(0800)228626" + # } + # + # credit_card = credit_card('5473470000000010', + # brand: "master", + # verification_value: "939", + # month: "12", + # year: "17", + # first_name: "Bruce", + # last_name: "Wayne") + # + # response = @gateway.purchase(@amount, credit_card, @options) + # assert_failure response + # end + # + # # All fields marked as mandatory are expected to be populated + # # with the above default values. Mandatory fields with no values + # # on the certification template should be populated with your + # # own meaningful values and comply with our API specifications. + # # The d2 parameter is mandatory during certification only to + # # allow for tracking of tests. + # def test_certification_za_zb_zc + # @options[:echo] = "33BE88E" + # @options[:email] = "brucewayne@dccomics.com" + # @options[:billing_address] = { + # address1: "5050 Gotham Drive", + # city: "Toronto", + # zip: "B2M 1Y9", + # state: "ON", + # country: "CA", + # phone: "(0800)228626" + # } + # + # credit_card = credit_card('5473470000000010', + # verification_value: "939", + # month: "12", + # year: "17", + # first_name: "Bruce", + # last_name: "Wayne") + # + # purchase = @gateway.purchase(@amount, credit_card, @options) + # assert_success purchase + # assert_equal "Succeeded", purchase.message + # + # refund_options = {echo: "33BE892"} + # refund = @gateway.refund(@amount, purchase.authorization, refund_options) + # assert_success refund + # assert_equal "Succeeded", refund.message + # + # void_options = {echo: "33BE895"} + # void = @gateway.void(refund.authorization, void_options) + # assert_success void + # assert_equal "Succeeded", refund.message + # end + # + # # All fields marked as mandatory are expected to be populated + # # with the above default values. Mandatory fields with no values + # # on the certification template should be populated with your + # # own meaningful values and comply with our API specifications. + # # The d2 parameter is mandatory during certification only to + # # allow for tracking of tests. + # def test_certification_zg_zh + # @options[:echo] = "33BE88F" + # @options[:email] = "clark.kent@dccomics.com" + # @options[:billing_address] = { + # address1: "2020 Krypton Drive", + # city: "Toronto", + # zip: "S2M 1YR", + # state: "ON", + # country: "CA", + # phone: "(0800) 78737626" + # } + # + # credit_card = credit_card('4176661000001015', + # brand: "visa", + # verification_value: "281", + # month: "12", + # year: "17", + # first_name: "Clark", + # last_name: "Kent") + # + # response = @gateway.authorize(@amount, credit_card, @options) + # assert_success response + # assert_equal "Succeeded", response.message + # + # capture_options = {echo: "33BE890"} + # capture = @gateway.capture(@amount, response.authorization, capture_options) + # assert_success capture + # assert_equal "Succeeded", capture.message + # end + # + # # All fields marked as mandatory are expected to be populated + # # with the above default values. Mandatory fields with no values + # # on the certification template should be populated with your + # # own meaningful values and comply with our API specifications. + # # The d2 parameter is mandatory during certification only to + # # allow for tracking of tests. + # def test_certification_zg_zj + # @options[:echo] = "33BE88F" + # @options[:email] = "clark.kent@dccomics.com" + # @options[:billing_address] = { + # address1: "2020 Krypton Drive", + # city: "Toronto", + # zip: "S2M 1YR", + # state: "ON", + # country: "CA", + # phone: "(0800) 78737626" + # } + # + # credit_card = credit_card('4176661000001015', + # brand: "visa", + # verification_value: "281", + # month: "12", + # year: "17", + # first_name: "Clark", + # last_name: "Kent") + # + # response = @gateway.authorize(@amount, credit_card, @options) + # assert_success response + # assert_equal "Succeeded", response.message + # + # auth_void_options = {echo: "33BE891"} + # auth_void = @gateway.void(response.authorization, auth_void_options) + # assert_success auth_void + # assert_equal "Succeeded", auth_void.message + # end + # + # # All fields marked as mandatory are expected to be populated + # # with the above default values. Mandatory fields with no values + # # on the certification template should be populated with your + # # own meaningful values and comply with our API specifications. + # # The d2 parameter is mandatory during certification only to + # # allow for tracking of tests. + # # + # # Certification for independent credit (credit) + # def test_certification_zd + # @options[:echo] = "33BE893" + # @options[:email] = "wadewilson@marvel.com" + # @options[:billing_address] = { + # address1: "5050 Deadpool Drive", + # city: "Toronto", + # zip: "D2P 1Y9", + # state: "ON", + # country: "CA", + # phone: "+1(555)123-4567" + # } + # + # credit_card = credit_card('4176661000001015', + # brand: "visa", + # verification_value: "281", + # month: "12", + # year: "17", + # first_name: "Wade", + # last_name: "Wilson") + # + # response = @gateway.credit(@amount, credit_card, @options) + # assert_success response + # assert_equal "Succeeded", response.message + # end + # + # # Use the above values to fill the mandatory parameters in your + # # certification test transactions. Note:The d2 parameter is only + # # mandatory during certification to allow for tracking of tests. + # # + # # Certification for purchase void + # def test_certification_zf + # @options[:echo] = "33BE88E" + # @options[:email] = "brucewayne@dccomics.com" + # @options[:billing_address] = { + # address1: "5050 Gotham Drive", + # city: "Toronto", + # zip: "B2M 1Y9", + # state: "ON", + # country: "CA", + # phone: "(0800)228626" + # } + # + # credit_card = credit_card('5473470000000010', + # verification_value: "939", + # month: "12", + # year: "17", + # first_name: "Bruce", + # last_name: "Wayne") + # + # response = @gateway.purchase(@amount, credit_card, @options) + # assert_success response + # assert_equal "Succeeded", response.message + # + # void_options = {echo: "33BE894"} + # void = @gateway.void(response.authorization, void_options) + # assert_success void + # assert_equal "Succeeded", void.message + # end + # + # # Use the above values to fill the mandatory parameters in your + # # certification test transactions. Note:The d2 parameter is only + # # mandatory during certification to allow for tracking of tests. + # # + # # Certification for capture void + # def test_certification_zi + # @options[:echo] = "33BE88F" + # @options[:email] = "clark.kent@dccomics.com" + # @options[:billing_address] = { + # address1: "2020 Krypton Drive", + # city: "Toronto", + # zip: "S2M 1YR", + # state: "ON", + # country: "CA", + # phone: "(0800) 78737626" + # } + # + # credit_card = credit_card('4176661000001015', + # brand: "visa", + # verification_value: "281", + # month: "12", + # year: "17", + # first_name: "Clark", + # last_name: "Kent") + # + # authorize = @gateway.authorize(@amount, credit_card, @options) + # assert_success authorize + # assert_equal "Succeeded", authorize.message + # + # capture_options = {echo: "33BE890"} + # capture = @gateway.capture(@amount, authorize.authorization, capture_options) + # assert_success capture + # assert_equal "Succeeded", capture.message + # + # void_options = {echo: "33BE896"} + # void = @gateway.void(capture.authorization, void_options) + # assert_success void + # assert_equal "Succeeded", void.message + # end end diff --git a/test/remote/gateways/remote_ct_payment_certification_test.rb b/test/remote/gateways/remote_ct_payment_certification_test.rb new file mode 100644 index 00000000000..7a4ef3988f4 --- /dev/null +++ b/test/remote/gateways/remote_ct_payment_certification_test.rb @@ -0,0 +1,243 @@ +require 'test_helper' + +class RemoteCtPaymentCertificationTest < Test::Unit::TestCase + def setup + @gateway = CtPaymentGateway.new(fixtures(:ct_payment)) + + @amount = 100 + @declined_card = credit_card('4502244713161718') + @options = { + billing_address: address, + description: 'Store Purchase', + merchant_terminal_number: ' ', + order_id: generate_unique_id[0, 11] + } + end + + def test1 + @credit_card = credit_card('4501161107217214', month: '07', year: 2025) + response = @gateway.purchase(@amount, @credit_card, @options) + print_result(1, response) + end + + def test2 + @credit_card = credit_card('5194419000000007', month: '07', year: 2025) + @credit_card.brand = 'master' + response = @gateway.purchase(@amount, @credit_card, @options) + print_result(2, response) + end + + def test3 + @credit_card = credit_card('341400000000000', month: '07', year: 2025, verification_value: '1234') + @credit_card.brand = 'american_express' + response = @gateway.purchase(@amount, @credit_card, @options) + print_result(3, response) + end + + def test6 + @credit_card = credit_card('341400000000000', month: '07', year: 2025, verification_value: '1234') + @credit_card.brand = 'american_express' + response = @gateway.credit(@amount, @credit_card, @options) + print_result(6, response) + end + + def test4 + @credit_card = credit_card('4501161107217214', month: '07', year: 2025) + response = @gateway.credit(@amount, @credit_card, @options) + print_result(4, response) + end + + def test5 + @credit_card = credit_card('5194419000000007', month: '07', year: 2025) + @credit_card.brand = 'master' + response = @gateway.credit(@amount, @credit_card, @options) + print_result(5, response) + end + + def test7 + @credit_card = credit_card('4501161107217214', month: '07', year: 2025) + response = @gateway.authorize(@amount, @credit_card, @options) + print_result(7, response) + + capture_response = @gateway.capture(@amount, response.authorization, @options.merge(order_id: generate_unique_id[0, 11])) + print_result(10, capture_response) + end + + def test8 + @credit_card = credit_card('5194419000000007', month: '07', year: 2025) + @credit_card.brand = 'master' + response = @gateway.authorize(@amount, @credit_card, @options) + print_result(8, response) + + capture_response = @gateway.capture(@amount, response.authorization, @options.merge(order_id: generate_unique_id[0, 11])) + print_result(11, capture_response) + end + + def test9 + @credit_card = credit_card('341400000000000', month: '07', year: 2025, verification_value: '1234') + @credit_card.brand = 'american_express' + response = @gateway.authorize(@amount, @credit_card, @options.merge(order_id: generate_unique_id[0, 11])) + print_result(9, response) + + capture_response = @gateway.capture(@amount, response.authorization, @options) + print_result(12, capture_response) + end + + def test13 + @credit_card = credit_card('4501161107217214', month: '07', year: 2025) + response = @gateway.purchase('000', @credit_card, @options) + print_result(13, response) + end + + def test14 + @credit_card = credit_card('4501161107217214', month: '07', year: 2025) + response = @gateway.purchase(-100, @credit_card, @options) + print_result(14, response) + end + + def test15 + @credit_card = credit_card('4501161107217214', month: '07', year: 2025) + response = @gateway.purchase('-1A0', @credit_card, @options) + print_result(15, response) + end + + def test16 + @credit_card = credit_card('5194419000000007', month: '07', year: 2025) + @credit_card.brand = 'visa' + response = @gateway.purchase(@amount, @credit_card, @options) + print_result(16, response) + end + + def test17 + @credit_card = credit_card('4501161107217214', month: '07', year: 2025) + @credit_card.brand = 'master' + response = @gateway.purchase(@amount, @credit_card, @options) + print_result(17, response) + end + + def test18 + @credit_card = credit_card('', month: '07', year: 2025) + response = @gateway.purchase(@amount, @credit_card, @options) + print_result(18, response) + end + + def test19 + @credit_card = credit_card('4501123412341234', month: '07', year: 2025) + response = @gateway.purchase(@amount, @credit_card, @options) + print_result(19, response) + end + + def test20 + # requires editing the model to run with a 3 digit expiration date + @credit_card = credit_card('4501161107217214', month: '07', year: 2) + response = @gateway.purchase(@amount, @credit_card, @options) + print_result(20, response) + end + + def test21 + @credit_card = credit_card('4501161107217214', month: 17, year: 2017) + response = @gateway.purchase(@amount, @credit_card, @options) + print_result(21, response) + end + + def test22 + @credit_card = credit_card('4501161107217214', month: '01', year: 2016) + response = @gateway.purchase(@amount, @credit_card, @options) + print_result(22, response) + end + + def test24 + @credit_card = credit_card('4502244713161718', month: '07', year: 2025) + response = @gateway.purchase(@amount, @credit_card, @options) + print_result(24, response) + end + + def test25 + # Needs an edit to the Model to run + @credit_card = credit_card('4501161107217214', month: '07', year: 2025) + response = @gateway.purchase(@amount, @credit_card, @options) + print_result(25, response) + end + + def test26 + @credit_card = credit_card('4501161107217214', month: '07', year: 2025) + response = @gateway.credit('000', @credit_card, @options) + print_result(26, response) + end + + def test27 + @credit_card = credit_card('4501161107217214', month: '07', year: 2025) + response = @gateway.credit(-100, @credit_card, @options) + print_result(27, response) + end + + def test28 + @credit_card = credit_card('4501161107217214', month: '07', year: 2025) + response = @gateway.credit('-1A0', @credit_card, @options) + print_result(28, response) + end + + def test29 + @credit_card = credit_card('5194419000000007', month: '07', year: 2025) + @credit_card.brand = 'visa' + response = @gateway.credit(@amount, @credit_card, @options) + print_result(29, response) + end + + def test30 + @credit_card = credit_card('4501161107217214', month: '07', year: 2025) + @credit_card.brand = 'master' + response = @gateway.credit(@amount, @credit_card, @options) + print_result(30, response) + end + + def test31 + @credit_card = credit_card('', month: '07', year: 2025) + response = @gateway.purchase(@amount, @credit_card, @options) + print_result(31, response) + end + + def test32 + @credit_card = credit_card('4501123412341234', month: '07', year: 2025) + response = @gateway.credit(@amount, @credit_card, @options) + print_result(32, response) + end + + def test33 + # requires edit to model to make 3 digit expiration date + @credit_card = credit_card('4501161107217214', month: '07', year: 2) + response = @gateway.credit(@amount, @credit_card, @options) + print_result(33, response) + end + + def test34 + @credit_card = credit_card('4501161107217214', month: 17, year: 2017) + response = @gateway.credit(@amount, @credit_card, @options) + print_result(34, response) + end + + def test35 + @credit_card = credit_card('4501161107217214', month: '01', year: 2016) + response = @gateway.credit(@amount, @credit_card, @options) + print_result(35, response) + end + + def test37 + @credit_card = credit_card('4502244713161718', month: '07', year: 2025) + response = @gateway.purchase(@amount, @credit_card, @options) + print_result(37, response) + end + + def test38 + # Needs an edit to the Model to run + @credit_card = credit_card('4501161107217214', month: '07', year: 2025) + response = @gateway.purchase(@amount, @credit_card, @options) + print_result(38, response) + end + + def print_result(test_number, response) + puts "Test #{test_number} | transaction number: #{response.params['transactionNumber']}, invoice number #{response.params['invoiceNumber']}, timestamp: #{response.params['timeStamp']}, result: #{response.params['returnCode']}" + puts response.inspect + end + +end diff --git a/test/remote/gateways/remote_ct_payment_test.rb b/test/remote/gateways/remote_ct_payment_test.rb new file mode 100644 index 00000000000..4fd0ba8738a --- /dev/null +++ b/test/remote/gateways/remote_ct_payment_test.rb @@ -0,0 +1,173 @@ +require 'test_helper' + +class RemoteCtPaymentTest < Test::Unit::TestCase + def setup + @gateway = CtPaymentGateway.new(fixtures(:ct_payment)) + + @amount = 100 + @credit_card = credit_card('4501161107217214', month: '07', year: 2020) + @declined_card = credit_card('4502244713161718') + @options = { + billing_address: address, + description: 'Store Purchase', + order_id: generate_unique_id[0, 11], + email: 'bigbird@sesamestreet.com' + + } + end + + def test_successful_purchase + response = @gateway.purchase(@amount, @credit_card, @options) + assert_success response + assert_equal 'APPROVED', response.message + end + + def test_failed_purchase + response = @gateway.purchase(@amount, @declined_card, @options) + assert_failure response + assert_equal 'Transaction declined', response.message + end + + def test_successful_authorize_and_capture + auth = @gateway.authorize(@amount, @credit_card, @options) + assert_success auth + + assert capture = @gateway.capture(@amount, auth.authorization, @options.merge(order_id: generate_unique_id[0, 11])) + assert_success capture + assert_equal 'APPROVED', capture.message + end + + def test_failed_authorize + response = @gateway.authorize(@amount, @declined_card, @options) + assert_failure response + assert_equal 'Transaction declined', response.message + end + + def test_partial_capture + auth = @gateway.authorize(@amount, @credit_card, @options) + assert_success auth + + assert capture = @gateway.capture(@amount-1, auth.authorization, @options.merge(order_id: generate_unique_id[0, 11])) + assert_success capture + end + + def test_failed_capture + response = @gateway.capture(@amount, '0123456789asd;0123456789asdf;12345678', @options) + assert_failure response + assert_equal 'The original transaction number does not match any actual transaction', response.message + end + + def test_successful_refund + purchase = @gateway.purchase(@amount, @credit_card, @options) + assert_success purchase + + assert refund = @gateway.refund(@amount, purchase.authorization, @options.merge(order_id: generate_unique_id[0, 11])) + assert_success refund + assert_equal 'APPROVED', refund.message + end + + def test_partial_refund + purchase = @gateway.purchase(@amount, @credit_card, @options) + assert_success purchase + + assert refund = @gateway.refund(@amount-1, purchase.authorization, @options.merge(order_id: generate_unique_id[0, 11])) + assert_success refund + end + + def test_failed_refund + response = @gateway.refund(@amount, '0123456789asd;0123456789asdf;12345678', @options.merge(order_id: generate_unique_id[0, 11])) + assert_failure response + assert_equal 'The original transaction number does not match any actual transaction', response.message + end + + def test_successful_void + purchase = @gateway.purchase(@amount, @credit_card, @options) + assert_success purchase + + assert void = @gateway.void(purchase.authorization) + assert_success void + assert_equal 'APPROVED', void.message + end + + def test_failed_void + response = @gateway.void('0123456789asd;0123456789asdf;12345678') + assert_failure response + assert_equal 'The original transaction number does not match any actual transaction', response.message + end + + def test_successful_credit + assert response = @gateway.credit(@amount, @credit_card, @options) + assert_success response + assert_equal 'APPROVED', response.message + end + + def test_successful_store + assert response = @gateway.store(@credit_card, @options) + + assert_success response + assert !response.authorization.split(';')[3].nil? + end + + def test_successful_purchase_using_stored_card + assert store_response = @gateway.store(@credit_card, @options) + assert_success store_response + + response = @gateway.purchase(@amount, store_response.authorization, @options) + assert_success response + assert_equal 'APPROVED', response.message + end + + def test_successful_authorize_using_stored_card + assert store_response = @gateway.store(@credit_card, @options) + assert_success store_response + + response = @gateway.authorize(@amount, store_response.authorization, @options) + assert_success response + assert_equal 'APPROVED', response.message + end + + def test_successful_verify + response = @gateway.verify(@credit_card, @options) + assert_success response + assert_match %r{APPROVED}, response.message + end + + def test_failed_verify + response = @gateway.verify(@declined_card, @options) + assert_failure response + assert_match %r{Transaction declined}, response.message + end + + def test_invalid_login + gateway = CtPaymentGateway.new(api_key: '', company_number: '12345', merchant_number: '12345') + + response = gateway.purchase(@amount, @credit_card, @options) + assert_failure response + assert_match %r{Invalid API KEY}, response.message + end + + def test_transcript_scrubbing + transcript = capture_transcript(@gateway) do + @gateway.purchase(@amount, @credit_card, @options) + end + transcript = @gateway.scrub(transcript) + + assert_scrubbed(@credit_card.number, transcript) + assert_scrubbed(@credit_card.verification_value, transcript) + assert_scrubbed(Base64.strict_encode64(@credit_card.number), transcript) + assert_scrubbed(@gateway.options[:api_key], transcript) + end + + def test_transcript_scrubbing_store + transcript = capture_transcript(@gateway) do + @gateway.store(@credit_card, @options) + end + transcript = @gateway.scrub(transcript) + + assert_scrubbed(@credit_card.number, transcript) + assert_scrubbed(@credit_card.verification_value, transcript) + assert_scrubbed(Base64.strict_encode64(@credit_card.number), transcript) + assert_scrubbed(@gateway.options[:api_key], transcript) + end + +end diff --git a/test/remote/gateways/remote_culqi_test.rb b/test/remote/gateways/remote_culqi_test.rb index 1913fd76141..d8241b2aef3 100644 --- a/test/remote/gateways/remote_culqi_test.rb +++ b/test/remote/gateways/remote_culqi_test.rb @@ -1,4 +1,4 @@ -require "test_helper" +require 'test_helper' class RemoteCulqiTest < Test::Unit::TestCase def setup @@ -6,8 +6,8 @@ def setup @gateway = CulqiGateway.new(fixtures(:culqi)) @amount = 1000 - @credit_card = credit_card("4111111111111111") - @declined_card = credit_card("4000300011112220", month: 06, year: 2016) + @credit_card = credit_card('4111111111111111') + @declined_card = credit_card('4000300011112220', month: 06, year: 2016) @options = { order_id: generate_unique_id, @@ -20,7 +20,7 @@ def teardown end def test_invalid_login - gateway = CulqiGateway.new(merchant_id: "", terminal_id: "", secret_key: "") + gateway = CulqiGateway.new(merchant_id: '', terminal_id: '', secret_key: '') response = gateway.purchase(@amount, @credit_card, @options) assert_failure response end @@ -64,7 +64,7 @@ def test_partial_capture end def test_failed_capture - response = @gateway.capture(@amount, "0") + response = @gateway.capture(@amount, '0') assert_failure response assert_match %r{Transaction not found}, response.message end @@ -79,7 +79,7 @@ def test_successful_void end def test_failed_void - response = @gateway.void("0", @options) + response = @gateway.void('0', @options) assert_failure response assert_match %r{Transaction not found}, response.message end @@ -103,7 +103,7 @@ def test_partial_refund end def test_failed_refund - response = @gateway.refund(@amount, "0") + response = @gateway.refund(@amount, '0') assert_failure response assert_match %r{Transaction not found}, response.message end @@ -130,7 +130,7 @@ def test_verify_credentials end def test_successful_store_and_purchase - credit_card = credit_card("4929927409600297") + credit_card = credit_card('4929927409600297') response = @gateway.store(credit_card, @options.merge(partner_id: fixtures(:culqi)[:partner_id])) assert_success response @@ -146,7 +146,7 @@ def test_successful_store_and_purchase end def test_failed_store - credit_card = credit_card("4929927409600297") + credit_card = credit_card('4929927409600297') store = @gateway.store(credit_card, @options.merge(partner_id: fixtures(:culqi)[:partner_id])) assert_success store diff --git a/test/remote/gateways/remote_cyber_source_test.rb b/test/remote/gateways/remote_cyber_source_test.rb index 1c7843281b8..dbb9bfd6c10 100644 --- a/test/remote/gateways/remote_cyber_source_test.rb +++ b/test/remote/gateways/remote_cyber_source_test.rb @@ -4,11 +4,29 @@ class RemoteCyberSourceTest < Test::Unit::TestCase def setup Base.mode = :test - @gateway = CyberSourceGateway.new({nexus: "NC"}.merge(fixtures(:cyber_source))) + @gateway = CyberSourceGateway.new({nexus: 'NC'}.merge(fixtures(:cyber_source))) @credit_card = credit_card('4111111111111111', verification_value: '321') @declined_card = credit_card('801111111111111') @pinless_debit_card = credit_card('4002269999999999') + @three_ds_unenrolled_card = credit_card('4000000000000051', + verification_value: '321', + month: '12', + year: (Time.now.year + 2).to_s, + brand: :visa + ) + @three_ds_enrolled_card = credit_card('4000000000000002', + verification_value: '321', + month: '12', + year: (Time.now.year + 2).to_s, + brand: :visa + ) + @three_ds_invalid_card = credit_card('4000000000000010', + verification_value: '321', + month: '12', + year: (Time.now.year + 2).to_s, + brand: :visa + ) @amount = 100 @@ -38,7 +56,7 @@ def setup :order_id => generate_unique_id, :credit_card => @credit_card, :subscription => { - :frequency => "weekly", + :frequency => 'weekly', :start_date => Date.today.next_week, :occurrences => 4, :auto_renew => true, @@ -61,8 +79,8 @@ def test_transcript_scrubbing def test_network_tokenization_transcript_scrubbing credit_card = network_tokenization_credit_card('4111111111111111', :brand => 'visa', - :eci => "05", - :payment_cryptogram => "EHuWW9PiBkWvqE5juRwDzAUFBAk=" + :eci => '05', + :payment_cryptogram => 'EHuWW9PiBkWvqE5juRwDzAUFBAk=' ) transcript = capture_transcript(@gateway) do @@ -114,7 +132,7 @@ def test_successful_tax_calculation assert response = @gateway.calculate_tax(@credit_card, @options) assert_equal 'Successful transaction', response.message assert response.params['totalTaxAmount'] - assert_not_equal "0", response.params['totalTaxAmount'] + assert_not_equal '0', response.params['totalTaxAmount'] assert_success response end @@ -140,7 +158,7 @@ def test_successful_purchase_with_billing_address_override end def test_successful_purchase_with_long_country_name - @options[:billing_address] = address(country: "united states", state: "NC") + @options[:billing_address] = address(country: 'united states', state: 'NC') assert response = @gateway.purchase(@amount, @credit_card, @options) assert_equal 'Successful transaction', response.message assert_success response @@ -191,17 +209,17 @@ def test_successful_authorization_and_failed_capture assert capture = @gateway.capture(@amount + 10, auth.authorization, @options) assert_failure capture - assert_equal "The requested amount exceeds the originally authorized amount", capture.message + assert_equal 'The requested amount exceeds the originally authorized amount', capture.message end def test_failed_capture_bad_auth_info - assert auth = @gateway.authorize(@amount, @credit_card, @options) - assert capture = @gateway.capture(@amount, "a;b;c", @options) + assert @gateway.authorize(@amount, @credit_card, @options) + assert capture = @gateway.capture(@amount, 'a;b;c', @options) assert_failure capture end def test_invalid_login - gateway = CyberSourceGateway.new( :login => 'asdf', :password => 'qwer' ) + gateway = CyberSourceGateway.new(:login => 'asdf', :password => 'qwer') assert response = gateway.purchase(@amount, @credit_card, @options) assert_failure response assert_equal "wsse:FailedCheck: \nSecurity Data : UsernameToken authentication failed.\n", response.message @@ -220,15 +238,15 @@ def test_successful_refund def test_successful_validate_pinless_debit_card assert response = @gateway.validate_pinless_debit_card(@pinless_debit_card, @options) assert response.test? - assert_equal 'Y', response.params["status"] + assert_equal 'Y', response.params['status'] assert_equal true, response.success? end def test_network_tokenization_authorize_and_capture credit_card = network_tokenization_credit_card('4111111111111111', :brand => 'visa', - :eci => "05", - :payment_cryptogram => "EHuWW9PiBkWvqE5juRwDzAUFBAk=" + :eci => '05', + :payment_cryptogram => 'EHuWW9PiBkWvqE5juRwDzAUFBAk=' ) assert auth = @gateway.authorize(@amount, credit_card, @options) @@ -253,7 +271,7 @@ def test_successful_purchase_with_mdd_fields def test_successful_authorize_with_nonfractional_currency assert response = @gateway.authorize(100, @credit_card, @options.merge(:currency => 'JPY')) - assert_equal "1", response.params['amount'] + assert_equal '1', response.params['amount'] assert_success response end @@ -282,7 +300,6 @@ def test_successful_subscription_purchase assert response.test? end - def test_successful_subscription_credit assert response = @gateway.store(@credit_card, @subscription_options) assert_equal 'Successful transaction', response.message @@ -313,8 +330,8 @@ def test_successful_create_subscription_with_setup_fee def test_successful_create_subscription_with_monthly_options response = @gateway.store(@credit_card, @subscription_options.merge(:setup_fee => 99.0, :subscription => {:amount => 49.0, :automatic_renew => false, frequency: 'monthly'})) assert_equal 'Successful transaction', response.message - response = @gateway.retrieve(";#{response.params['subscriptionID']};", :order_id => @subscription_options[:order_id]) - assert_equal "0.49", response.params['recurringAmount'] + response = @gateway.retrieve(response.authorization, order_id: @subscription_options[:order_id]) + assert_equal '0.49', response.params['recurringAmount'] assert_equal 'monthly', response.params['frequency'] end @@ -363,10 +380,68 @@ def test_successful_retrieve_subscription assert response.test? end + def test_3ds_enroll_request_via_purchase + assert response = @gateway.purchase(1202, @three_ds_enrolled_card, @options.merge(payer_auth_enroll_service: true)) + assert_equal '475', response.params['reasonCode'] + assert !response.params['acsURL'].blank? + assert !response.params['paReq'].blank? + assert !response.params['xid'].blank? + assert !response.success? + end + + def test_3ds_enroll_request_via_authorize + assert response = @gateway.authorize(1202, @three_ds_enrolled_card, @options.merge(payer_auth_enroll_service: true)) + assert_equal '475', response.params['reasonCode'] + assert !response.params['acsURL'].blank? + assert !response.params['paReq'].blank? + assert !response.params['xid'].blank? + assert !response.success? + end + + def test_successful_3ds_requests_with_unenrolled_card + assert response = @gateway.purchase(1202, @three_ds_unenrolled_card, @options.merge(payer_auth_enroll_service: true)) + assert response.success? + + assert response = @gateway.authorize(1202, @three_ds_unenrolled_card, @options.merge(payer_auth_enroll_service: true)) + assert response.success? + end + + def test_successful_3ds_validate_purchase_request + assert response = @gateway.purchase(1202, @three_ds_enrolled_card, @options.merge(payer_auth_validate_service: true, pares: pares)) + assert_equal '100', response.params['reasonCode'] + assert_equal '0', response.params['authenticationResult'] + assert response.success? + end + + def test_failed_3ds_validate_purchase_request + assert response = @gateway.purchase(1202, @three_ds_invalid_card, @options.merge(payer_auth_validate_service: true, pares: pares)) + assert_equal '476', response.params['reasonCode'] + assert !response.success? + end + + def test_successful_3ds_validate_authorize_request + assert response = @gateway.authorize(1202, @three_ds_enrolled_card, @options.merge(payer_auth_validate_service: true, pares: pares)) + assert_equal '100', response.params['reasonCode'] + assert_equal '0', response.params['authenticationResult'] + assert response.success? + end + + def test_failed_3ds_validate_authorize_request + assert response = @gateway.authorize(1202, @three_ds_invalid_card, @options.merge(payer_auth_validate_service: true, pares: pares)) + assert_equal '476', response.params['reasonCode'] + assert !response.success? + end + + def pares + <<-PARES +eNqdmFuTqkgSgN+N8D90zD46M4B3J+yOKO6goNyFN25yEUHkUsiv31K7T/ec6dg9u75YlWRlZVVmflWw1uNrGNJa6DfX8G0thVXlRuFLErz+tgm67sRlbJr3ky4G9LWn8N/e1nughtVD4dFawFAodT8OqbBx4NLdj/o8y3JqKlavSLsNr1VS5G/En/if4zX20UUTXf3Yzeu3teuXpCC/TeerMTFfY+/d9Tm8CvRbEB7dJqvX2LO7xj7H7Zt7q0JOd0nwpo3VacjVvMc4pZcXfcjFpMqLc6UHr2vsrrEO3Dp8G+P4Ap+PZy/E9C+c+AtfrrGHfH25mwPnokG2CRxfY18Fa7Q71zD3b2/LKXr0o7cOu0uRh0gDre1He419+nZx8zf87z+kepeu9cPbuk7OX31a3X0iFmvsIV9XtVs31Zu9xt5ba99t2zcAAAksNjsr4N5MVctyGIaN2H6E1vpQWYd+8obPkFPo/zEKZFFxTer4fHf174I1dncFe4Tzba0lUY4mu4Yv3TnLURDjur78hWEQwj/h5M/iGmHIYRzDVxhSCKok+tdvz1FhIOTH4n8aRrl5kSe+myW9W6PEkMI6LoKXH759Z0ZX75YITGWoP5CpP3ximv9xl+ATYoZsYt8b/bKyX5nlZ2evlftHFbvEfYKfDL2t1fAY3jMifDFU4fW3f/1KZdBJFFb1/+PKhxtfLXzYM92sCd8qN5U5lrrNDZOFzkiecUIszvyCVJjXj3FPzTX2w/f3hT2j+GW3noobXm8xXJ3KK2aZztNbVdsLWbbOASZgzSY45eYqFNiK5ReRNLKbzvZSIDJj+zqBzIEkIx1L9ZTabYeDJa/MV51fF9A0dxDvxzf5CiPmttuVVBLHxmZSNp53lnBcJzh+IS3YpejKebycHjQlvMggwkvHdZjhYBHf8M1R4ikKjHxMGxlCfuCv+IqmxjTRk9GMnO2ynnXsWMvZSYdlk+Vmvpz1pVns4v05ugRWIGZNMhxUGLzoqs+VDe14Jtzli63TT06WBvpJg2+2UVLie+5mgGDlEVjip+7EmZhCvRdndtQHmKm0vaUDejhYTRgglbR5qysx6I1gf+vTyWJ3ahaXNOWBUrXRYnwasbKlbi3XsJLNuA3g6+uXrHqPzCa8PSNxmKElubX7bGmNl4Z+LbuIEJT8SrnXIMnd7IUOz8XLI4DX3192xucDQGlI8NmnijOiqR/+/rJ9lRCvCqSv6a+7OCl+f6FeDW2N/TzPY2IqvNbJEdUVwqUkCLTVo32vtAhAgQSRQAFNgLRii5vCEeLWl4HCsKQCoJMyWwmcOEAYDBlLlGlKHa2DLRnJ5nCAhkoksypca9nxKfDvUhIUEmvIsX9WL96ZrZTxqvYs82aPjQi1bz7NaBIJHhYpCEXplJ2GA8ea4a7lXCRVgUxk06ai0DSoDecg4wIvE3ZC0ooOQhbinUQzNyn1OzkFM5kWXSS7PWVKNxx8SCV+2VE9EJ8+2TrITF1ScEjBh3WBgere5bJWUpb3ld9lPAMd+e6JNxGQJS4F9vuKdObLigRGbj2LyPyznEmqAZmnxS0DO9o+iCfXmsUeRZIKIXW8Djy0Tw8rks4yX62omWctI2Oc5d7ZvKGokEIKZDI6lfEp4VYQJ+9RAGBHAWUJ7s+HAyraoB4DSmYSEIl4LuOMDMYCIZJ71pj7U99OwbapLHXFMLI66s7eKosO9qmWU56LwmJCul2tccin+XTKE4tV7EatfZaSNCQFH9bYXMNCetuoK2kl0SN6An3f3xmIMwGIT8KlZZS5pV/wpTIz8FzIF9fhIK6EhVLuzEDAg4MI+sybxjVzA/TGuEmsEHDZbZFBtjKxdKfgilSRZDLRoGjQmpWlzUEZGeJ+7CK6jCNPPgQe2ZInYsxH5YEWZoId7i5G2RJNax3USyCJo1OXS/jNLKdCtZiMSaCR4jKPaXvXqjl/6Et+OMBDRoth7MfSnLa3o7ItpxyV8CZcmjrVbJtyWykIypti158qotvx1VkJTm48GzeYBAUaKIAsJhUcDkL9mUO8KjEgBUCiIEdZFKcBjhsxAkpL5cjGxN7nzMYgZElgguweT/ugZg5F0s5BfGT2cGCPWdzRQfCwpkzRoa8YasSpRuIhBMUdRVxBGyn1FouIkytA/p5XKp4iAEO2AMZRSKQkIPDhgLC0ZSKTIV5IsXXC55ue+a566chmgKyLBwZfHlr7igWzo4Dn4m63WjXm3kMV3G7GNc3KJz9Ur5pt1AxBnafhdFf03bi2pnQlT8pZhWNWN7Mu+6RtWe/I6AbUz1wcFd6puR7FdrSYDwcYP5lcIsJ0ZNh7zOxcqcSFOjoUhaui645OzZ5qHGeazOnrqlxJ1+2eSJtTNOo7bBrgyvIanQyHuh9xP/PqO4BROI0Alp6/AOzbLYAh/asAo/t78d0L1ZdQ/mVerrZ+yoQSCZ+wiqCpjNmbw2WNbXW0NyZqFNzU0Uh0dHgTEUqqABnwhAENTjfNUu9WLs751LE60N8xINGsmvkTJTLOqzag/g624UDS72hjelmXP9GmKz9kEmf/R7DR4Ak2ZEmdQv7pz4YmzU84fQHYHWZ+DjomBcrTYiVRuig6KJ1R5Z5dhD5kiRQeewAg3Jqc2SOv+8ASIgVnYOQsf9558pl8OIIWJ4KCQ4u+QWKmIqgK7g5MOZ+0XJ4jemPuucVRUPf5rma5LL6U7RxuXQ4ax+NodrIvC4k53wRDanhGdkGrnhJRq2/UajccHM67ebQItvRyk3PEnFrl1y5dFuT0PEFYMqbn0dG2dlx+js/7Yt7HZFuSVXvsV5OYiTYHec4EG7kxo+GgKfvamoPtDhry3CPLjaJN7okBAJeGPTl7z5+AgQolAQC3wBZtwRGA7U2ViJFJcmnxxgo+jjHdwGGkjs0G5UYccOYJ7XDmP7IgS+9QkEj8YY2OFIsk1WUi3MTJQTed7U3A2YUW3Vh3OND14irp4PiAhSYxHA2siFSZKN1jhOVFme2MOa7LKcst80SEKId+OjqM+9GBjoxIIZfNxsBWkyVmbmYUa4iJghm7gzu+8jeiAxMvJwhiR80zcl4FSr2Q01jx442ebHWlimZHrNQymRgOto7dtFMgbPTdxmG4ayKWQJ+Lp3K0OcQ1rU2jtLyw+XKXOqWoLo7ulVFHgTebYaLWXho+Sr1OPy7AcHCGCar/njbEqWk2ib1Z6iWb3cbm1eTZ6PVXIdCmCAJJ+AEBEYh0tx8xmanGGwngHKWVnCZ4E/qRkgaQ+OgfpYOS+5vi+XoroMHnreA/3XIQBP7LPefzlvPj1oBuOd3zlsOKrYegcC+p4YCPfRmFv5NSZiLpNpR1cLPusvQhw3/IUnIqKRWknr5yDBRNo2dkCVSPmdGNAUBGH8cXr2f29z15gBBCTrfuBb66/SokhoP/gglTIqUPSEjvkNC88QpHo0kEguNHRIaDj5igJAWIBjKgKTJRNmSkUNPwevRaVWGow9Vezev9QtlZJaWDcZpjs3SywiKsxD0p8RVKHQ6u49ExWZz6zY28KaVz4ntbnC0nGDi0G9GFeM2id5cJkwbRKezMS2ZrYcnsZzuDlqaRqx0XJS9F5h6VycYt8nF7TfnOCimzY5NpNyWLIBPzY4ZhNZdu8FKm+3pxwqZyqLHWzSsT5f2mQACop8+THcXu42wXhB5bmeepaHFBHFcOzM7lZZr4DPOPs/073eHgQ5sGD22dBAZE4SSx/vtijxSQsEuSy0gWSqEshkxiw9xVEJhqg78mbmrU3nxGzJe1fLxwDDO59rxHzgrpzPiHrvK8WlDJpo33y3MdhU7GZ81W6fFSHfnjYpbBcDjo4CLNjoAvSxRlLaU2W76plphc5At/tEhKra8VXiLN0FuM59Ddt5zgHZitL1vFyttHamkZ44sToxvD5ubwK/BtsWOfr03Yj1epz5esx7ekx8eu+/ePrx/B/g0UAjN8 + PARES + end + def test_verify_credentials assert @gateway.verify_credentials - gateway = CyberSourceGateway.new(login: "an_unknown_login", password: "unknown_password") + gateway = CyberSourceGateway.new(login: 'an_unknown_login', password: 'unknown_password') assert !gateway.verify_credentials end diff --git a/test/remote/gateways/remote_data_cash_test.rb b/test/remote/gateways/remote_data_cash_test.rb index f6fffda0131..9fb77b19a6f 100644 --- a/test/remote/gateways/remote_data_cash_test.rb +++ b/test/remote/gateways/remote_data_cash_test.rb @@ -44,8 +44,7 @@ def setup :brand => :solo, :issue_number => 5, :start_month => 12, - :start_year => 2006, - :verification_value => 444 + :start_year => 2006 ) @address = { @@ -73,8 +72,8 @@ def test_successful_purchase assert response.test? end - #the amount is changed to £1.99 - the DC test server won't check the - #address details - this is more a check on the passed ExtendedPolicy + # the amount is changed to £1.99 - the DC test server won't check the + # address details - this is more a check on the passed ExtendedPolicy def test_successful_purchase_without_address_check response = @gateway.purchase(199, @mastercard, @params) assert_success response @@ -110,7 +109,7 @@ def test_successful_purchase_with_account_set_up_and_repeat_payments assert !response.authorization.to_s.split(';')[2].blank? assert response.test? - #Make second payment on the continuous authorization that was set up in the first purchase + # Make second payment on the continuous authorization that was set up in the first purchase second_order_params = { :order_id => generate_unique_id } purchase = @gateway.purchase(201, response.authorization, second_order_params) assert_success purchase @@ -122,7 +121,7 @@ def test_successful_purchase_with_account_set_up_and_repeat_payments_with_visa_d assert_success response assert !response.authorization.to_s.split(';')[2].blank? - #Make second payment on the continuous authorization that was set up in the first purchase + # Make second payment on the continuous authorization that was set up in the first purchase second_order_params = { :order_id => generate_unique_id } purchase = @gateway.purchase(201, response.authorization, second_order_params) assert_success purchase @@ -136,19 +135,19 @@ def test_purchase_with_account_set_up_for_repeat_payments_fails_for_solo_card end def test_successful_authorization_and_capture_with_account_set_up_and_second_purchase - #Authorize first payment + # Authorize first payment @params[:set_up_continuous_authority] = true first_authorization = @gateway.authorize(@amount, @mastercard, @params) assert_success first_authorization assert !first_authorization.authorization.to_s.split(';')[2].blank? assert first_authorization.test? - #Capture first payment + # Capture first payment capture = @gateway.capture(@amount, first_authorization.authorization, @params) assert_success capture assert capture.test? - #Collect second purchase + # Collect second purchase second_order_params = { :order_id => generate_unique_id } purchase = @gateway.purchase(201, first_authorization.authorization, second_order_params) assert_success purchase @@ -303,6 +302,23 @@ def test_fail_to_refund_purchase_which_is_already_refunded assert_equal '1.98 > remaining funds 0.00', second_refund.message end + def test_successful_refund_of_a_repeat_payment + @params[:set_up_continuous_authority] = true + response = @gateway.purchase(@amount, @mastercard, @params) + assert_success response + assert !response.authorization.to_s.split(';')[2].blank? + assert response.test? + + # Make second payment on the continuous authorization that was set up in the first purchase + second_order_params = { :order_id => generate_unique_id } + purchase = @gateway.purchase(201, response.authorization, second_order_params) + assert_success purchase + + # Refund payment that was made via the continuous authorization payment above + refund = @gateway.refund(201, purchase.authorization) + assert_success refund + end + def test_order_id_that_is_too_short @params[:order_id] = @params[:order_id].first(5) response = @gateway.purchase(@amount, @mastercard, @params) @@ -316,4 +332,14 @@ def test_order_id_that_is_too_long assert response.test? end + def test_transcript_scrubbing + transcript = capture_transcript(@gateway) do + @gateway.purchase(@amount, @visa_delta, @params) + end + transcript = @gateway.scrub(transcript) + + assert_scrubbed(@visa_delta.number, transcript) + assert_scrubbed(@visa_delta.verification_value, transcript) + assert_scrubbed(@gateway.options[:password], transcript) + end end diff --git a/test/remote/gateways/remote_dibs_test.rb b/test/remote/gateways/remote_dibs_test.rb index ab7079dfc93..1e6b16e36b1 100644 --- a/test/remote/gateways/remote_dibs_test.rb +++ b/test/remote/gateways/remote_dibs_test.rb @@ -12,9 +12,9 @@ def setup } @amount = 100 - @credit_card = credit_card("4711100000000000", cc_options) - @declined_card_auth = credit_card("4711000000000000", cc_options) - @declined_card_capture = credit_card("4711100000000001", cc_options) + @credit_card = credit_card('4711100000000000', cc_options) + @declined_card_auth = credit_card('4711000000000000', cc_options) + @declined_card_capture = credit_card('4711100000000001', cc_options) @options = { order_id: generate_unique_id @@ -23,8 +23,8 @@ def setup def test_invalid_login gateway = DibsGateway.new( - merchant_id: "123456789", - secret_key: "987654321" + merchant_id: '123456789', + secret_key: '987654321' ) response = gateway.authorize(@amount, @credit_card, @options) assert_failure response @@ -33,7 +33,7 @@ def test_invalid_login def test_successful_purchase response = @gateway.purchase(@amount, @credit_card, @options) assert_success response - assert_equal "Succeeded", response.message + assert_equal 'Succeeded', response.message end def test_failed_purchase @@ -45,19 +45,19 @@ def test_failed_purchase def test_successful_authorize response = @gateway.authorize(@amount, @credit_card, @options) assert_success response - assert_equal "Succeeded", response.message + assert_equal 'Succeeded', response.message assert_match %r(^\d+$), response.authorization end def test_successful_authorize_and_capture response = @gateway.authorize(@amount, @credit_card, @options) assert_success response - assert_equal "Succeeded", response.message + assert_equal 'Succeeded', response.message assert_match %r(^\d+$), response.authorization capture = @gateway.capture(@amount, response.authorization) assert_success capture - assert_equal "Succeeded", capture.message + assert_equal 'Succeeded', capture.message end def test_failed_authorize @@ -69,7 +69,7 @@ def test_failed_authorize def test_successful_authorize_and_failed_capture response = @gateway.authorize(@amount, @declined_card_capture, @options) assert_success response - assert_equal "Succeeded", response.message + assert_equal 'Succeeded', response.message assert_match %r(^\d+$), response.authorization capture = @gateway.capture(@amount, response.authorization) @@ -78,7 +78,7 @@ def test_successful_authorize_and_failed_capture end def test_failed_capture - response = @gateway.capture(@amount, "") + response = @gateway.capture(@amount, '') assert_failure response assert_match %r(ERROR.+), response.message end @@ -89,7 +89,7 @@ def test_successful_void void = @gateway.void(response.authorization) assert_success void - assert_equal "Succeeded", void.message + assert_equal 'Succeeded', void.message capture = @gateway.capture(@amount, response.authorization) assert_failure capture @@ -97,7 +97,7 @@ def test_successful_void end def test_failed_void - response = @gateway.void("") + response = @gateway.void('') assert_failure response assert_match %r(ERROR.+), response.message end @@ -107,11 +107,11 @@ def test_successful_refund assert_success response refund = @gateway.refund(@amount, response.authorization) assert_success refund - assert_equal "Succeeded", refund.message + assert_equal 'Succeeded', refund.message end def test_failed_refund - response = @gateway.refund(nil, "") + response = @gateway.refund(nil, '') assert_failure response assert_match %r(ERROR.+), response.message end @@ -131,7 +131,7 @@ def test_failed_verify def test_successful_store response = @gateway.store(@credit_card, @options) assert_success response - assert_equal "Succeeded", response.message + assert_equal 'Succeeded', response.message assert_not_nil response.params['ticketId'] assert_not_nil response.authorization assert_equal response.params['ticketId'], response.authorization @@ -149,7 +149,7 @@ def test_successful_authorize_with_stored_card assert_not_nil response.authorization response = @gateway.authorize(@amount, response.authorization, @options) assert_success response - assert_equal "Succeeded", response.message + assert_equal 'Succeeded', response.message assert_match %r(^\d+$), response.authorization end @@ -159,12 +159,12 @@ def test_successful_authorize_and_capture_with_stored_card assert_not_nil response.authorization response = @gateway.authorize(@amount, response.authorization, @options) assert_success response - assert_equal "Succeeded", response.message + assert_equal 'Succeeded', response.message assert_match %r(^\d+$), response.authorization capture = @gateway.capture(@amount, response.authorization) assert_success capture - assert_equal "Succeeded", capture.message + assert_equal 'Succeeded', capture.message end def test_transcript_scrubbing @@ -172,7 +172,9 @@ def test_transcript_scrubbing @gateway.purchase(@amount, @credit_card, @options) end clean_transcript = @gateway.scrub(transcript) + assert_scrubbed(@credit_card.number, clean_transcript) assert_scrubbed(@credit_card.verification_value.to_s, clean_transcript) + assert_scrubbed(@gateway.options[:secret_key], clean_transcript) end end diff --git a/test/remote/gateways/remote_digitzs_test.rb b/test/remote/gateways/remote_digitzs_test.rb new file mode 100644 index 00000000000..285dd840f9d --- /dev/null +++ b/test/remote/gateways/remote_digitzs_test.rb @@ -0,0 +1,136 @@ +require 'test_helper' + +class RemoteDigitzsTest < Test::Unit::TestCase + def setup + @gateway = DigitzsGateway.new(fixtures(:digitzs)) + + @amount = 500 + @credit_card = credit_card('4747474747474747', verification_value: '999') + @declined_card = credit_card('4616161616161616') + @options = { + merchant_id: 'spreedly-susanswidg-32268973-2091076-148408385', + billing_address: address, + description: 'Store Purchase' + } + + @options_card_split = { + merchant_id: 'spreedly-susanswidg-32268973-2091076-148408385', + billing_address: address, + description: 'Split Purchase', + payment_type: 'card_split', + split_amount: 100, + split_merchant_id: 'spreedly-susanswidg-32270590-2095203-148657924' + } + + @options_token_split = { + merchant_id: 'spreedly-susanswidg-32268973-2091076-148408385', + billing_address: address, + description: 'Token Split Purchase', + payment_type: 'token_split', + split_amount: 100, + split_merchant_id: 'spreedly-susanswidg-32270590-2095203-148657924' + } + end + + def test_successful_purchase + response = @gateway.purchase(@amount, @credit_card, @options) + assert_success response + assert_equal 'Success', response.message + end + + def test_successful_token_purchase + assert store = @gateway.store(@credit_card, @options) + assert_success store + + response = @gateway.purchase(@amount, store.authorization, @options) + assert_success response + assert_equal 'Success', response.message + end + + def test_successful_token_split_purchase + assert store = @gateway.store(@credit_card, @options) + assert_success store + + response = @gateway.purchase(@amount, store.authorization, @options_token_split) + assert_success response + assert_equal 'Success', response.message + assert response.params['data']['attributes']['split']['splitId'] + end + + def test_successful_card_split_purchase + response = @gateway.purchase(@amount, @credit_card, @options_card_split) + assert_success response + assert_equal 'Success', response.message + assert response.params['data']['attributes']['split']['splitId'] + end + + def test_failed_purchase + response = @gateway.purchase(@amount, @declined_card, @options) + assert_failure response + assert_equal 'Partner error: Credit card declined (transaction element shows reason for decline)', response.message + end + + def test_successful_refund + purchase = @gateway.purchase(@amount, @credit_card, @options) + assert_success purchase + + assert refund = @gateway.refund(@amount, purchase.authorization, @options) + assert_success refund + assert_equal 'Success', refund.message + end + + def test_partial_refund + purchase = @gateway.purchase(@amount, @credit_card, @options) + assert_success purchase + + assert refund = @gateway.refund(@amount-1, purchase.authorization, @options) + assert_success refund + end + + def test_failed_refund + response = @gateway.refund(@amount, '', @options) + assert_failure response + assert_equal '"id" is not allowed to be empty', response.message + end + + def test_successful_store + assert response = @gateway.store(@credit_card, @options) + assert_success response + end + + def test_successful_store_without_billing_address + assert response = @gateway.store(@credit_card, {merchant_id: 'spreedly-susanswidg-32268973-2091076-148408385'}) + assert_success response + end + + def test_store_adds_card_to_existing_customer + assert response = @gateway.store(@credit_card, @options.merge({customer_id: 'spreedly-susanswidg-32268973-2091076-148408385-5980208887457495-148700575'})) + assert_success response + end + + def test_store_creates_new_customer_and_adds_card + assert response = @gateway.store(@credit_card, @options.merge({customer_id: 'nonexistant'})) + assert_success response + end + + def test_invalid_login + gateway = DigitzsGateway.new(app_key: '', api_key: '', merchant_id: '') + + response = gateway.purchase(@amount, @credit_card, @options) + assert_failure response + assert_match %r{Forbidden}, response.message + end + + def test_transcript_scrubbing + transcript = capture_transcript(@gateway) do + @gateway.purchase(@amount, @credit_card, @options) + end + transcript = @gateway.scrub(transcript) + + assert_scrubbed(@credit_card.number, transcript) + assert_scrubbed(@credit_card.verification_value, transcript) + assert_scrubbed(@gateway.options[:api_key], transcript) + assert_scrubbed(@gateway.options[:app_key], transcript) + end + +end diff --git a/test/remote/gateways/remote_ebanx_test.rb b/test/remote/gateways/remote_ebanx_test.rb new file mode 100644 index 00000000000..d1035d9b62b --- /dev/null +++ b/test/remote/gateways/remote_ebanx_test.rb @@ -0,0 +1,218 @@ +require 'test_helper' + +class RemoteEbanxTest < Test::Unit::TestCase + def setup + @gateway = EbanxGateway.new(fixtures(:ebanx)) + + @amount = 100 + @credit_card = credit_card('4111111111111111') + @declined_card = credit_card('5102026827345142') + @options = { + billing_address: address({ + address1: '1040 Rua E', + city: 'Maracanaú', + state: 'CE', + zip: '61919-230', + country: 'BR', + phone_number: '8522847035' + }), + order_id: generate_unique_id, + document: '853.513.468-93' + } + end + + def test_successful_purchase + response = @gateway.purchase(@amount, @credit_card, @options) + assert_success response + assert_equal 'Accepted', response.message + end + + def test_successful_purchase_with_more_options + options = @options.merge({ + order_id: generate_unique_id, + ip: '127.0.0.1', + email: 'joe@example.com', + birth_date: '10/11/1980', + person_type: 'personal' + }) + + response = @gateway.purchase(@amount, @credit_card, options) + assert_success response + assert_equal 'Accepted', response.message + end + + def test_successful_purchase_as_brazil_business_with_responsible_fields + options = @options.update(document: '32593371000110', + person_type: 'business', + responsible_name: 'Business Person', + responsible_document: '32593371000111', + responsible_birth_date: '1/11/1975') + + response = @gateway.purchase(@amount, @credit_card, options) + assert_success response + assert_equal 'Accepted', response.message + end + + def test_successful_purchase_as_colombian + options = @options.merge({ + order_id: generate_unique_id, + ip: '127.0.0.1', + email: 'jose@example.com.co', + birth_date: '10/11/1980', + billing_address: address({ + address1: '1040 Rua E', + city: 'Medellín', + state: 'AN', + zip: '29269', + country: 'CO', + phone_number: '8522847035' + }) + }) + + response = @gateway.purchase(500, @credit_card, options) + assert_success response + assert_equal 'Sandbox - Test credit card, transaction captured', response.message + end + + def test_failed_purchase + response = @gateway.purchase(@amount, @declined_card, @options) + assert_failure response + assert_equal 'Sandbox - Test credit card, transaction declined reason insufficientFunds', response.message + assert_equal 'NOK', response.error_code + end + + def test_successful_authorize_and_capture + auth = @gateway.authorize(@amount, @credit_card, @options) + assert_success auth + assert_equal 'Accepted', auth.message + + assert capture = @gateway.capture(@amount, auth.authorization) + assert_success capture + assert_equal 'Accepted', capture.message + end + + def test_failed_authorize + response = @gateway.authorize(@amount, @declined_card, @options) + assert_failure response + assert_equal 'Sandbox - Test credit card, transaction declined reason insufficientFunds', response.message + assert_equal 'NOK', response.error_code + end + + def test_partial_capture + auth = @gateway.authorize(@amount, @credit_card, @options) + assert_success auth + + assert capture = @gateway.capture(@amount-1, auth.authorization) + assert_success capture + end + + def test_failed_capture + response = @gateway.capture(@amount, '') + assert_failure response + assert_equal 'Parameters hash or merchant_payment_code not informed', response.message + end + + def test_successful_refund + purchase = @gateway.purchase(@amount, @credit_card, @options) + assert_success purchase + + refund_options = @options.merge({description: 'full refund'}) + assert refund = @gateway.refund(@amount, purchase.authorization, refund_options) + assert_success refund + assert_equal 'Accepted', refund.message + end + + def test_partial_refund + purchase = @gateway.purchase(@amount, @credit_card, @options) + assert_success purchase + + refund_options = @options.merge(description: 'refund due to returned item') + assert refund = @gateway.refund(@amount-1, purchase.authorization, refund_options) + assert_success refund + end + + def test_failed_refund + response = @gateway.refund(@amount, '') + assert_failure response + assert_match('Parameter hash not informed', response.message) + end + + def test_successful_void + auth = @gateway.authorize(@amount, @credit_card, @options) + assert_success auth + + assert void = @gateway.void(auth.authorization) + assert_success void + assert_equal 'Accepted', void.message + end + + def test_failed_void + response = @gateway.void('') + assert_failure response + assert_equal 'Parameter hash not informed', response.message + end + + def test_successful_store_and_purchase + store = @gateway.store(@credit_card, @options) + assert_success store + + assert purchase = @gateway.purchase(@amount, store.authorization, @options) + assert_success purchase + assert_equal 'Accepted', purchase.message + end + + def test_successful_store_and_purchase_as_brazil_business + options = @options.update(document: '32593371000110', + person_type: 'business', + responsible_name: 'Business Person', + responsible_document: '32593371000111', + responsible_birth_date: '1/11/1975') + + store = @gateway.store(@credit_card, options) + assert_success store + + assert purchase = @gateway.purchase(@amount, store.authorization, options) + assert_success purchase + assert_equal 'Accepted', purchase.message + end + + def test_failed_purchase_with_stored_card + store = @gateway.store(@declined_card, @options) + assert_success store + + assert purchase = @gateway.purchase(@amount, store.authorization, @options) + assert_failure purchase + end + + def test_successful_verify + response = @gateway.verify(@credit_card, @options) + assert_success response + assert_match %r{Accepted}, response.message + end + + def test_failed_verify + response = @gateway.verify(@declined_card, @options) + assert_failure response + assert_match %r{Accepted}, response.message + end + + def test_invalid_login + gateway = EbanxGateway.new(integration_key: '') + + response = gateway.purchase(@amount, @credit_card, @options) + assert_failure response + assert_match %r{Field integration_key is required}, response.message + end + + def test_transcript_scrubbing + transcript = capture_transcript(@gateway) do + @gateway.purchase(@amount, @credit_card, @options) + end + transcript = @gateway.scrub(transcript) + + assert_scrubbed(@credit_card.number, transcript) + assert_scrubbed(@credit_card.verification_value, transcript) + assert_scrubbed(@gateway.options[:integration_key], transcript) + end + +end diff --git a/test/remote/gateways/remote_efsnet_test.rb b/test/remote/gateways/remote_efsnet_test.rb index 052ab40a589..4e6f22499b7 100644 --- a/test/remote/gateways/remote_efsnet_test.rb +++ b/test/remote/gateways/remote_efsnet_test.rb @@ -1,22 +1,22 @@ require 'test_helper' class RemoteEfsnetTest < Test::Unit::TestCase - + def setup Base.mode = :test @gateway = EfsnetGateway.new(fixtures(:efsnet)) - + @credit_card = credit_card('4000100011112224') - + @amount = 100 @declined_amount = 156 - @options = { :order_id => generate_unique_id, + @options = { :order_id => generate_unique_id, :billing_address => address } end - + def test_successful_purchase assert response = @gateway.purchase(@amount, @credit_card, @options) assert_success response @@ -45,10 +45,10 @@ def test_unsuccessful_purchase def test_authorize_and_capture amount = @amount assert auth = @gateway.authorize(amount, @credit_card, @options) - assert_success auth + assert_success auth assert_equal 'Approved', auth.message assert auth.authorization - + assert capture = @gateway.capture(amount, auth.authorization, @options) assert_success capture end diff --git a/test/remote/gateways/remote_elavon_test.rb b/test/remote/gateways/remote_elavon_test.rb index fefb5f3fe1c..9c560e7ec77 100644 --- a/test/remote/gateways/remote_elavon_test.rb +++ b/test/remote/gateways/remote_elavon_test.rb @@ -4,11 +4,11 @@ class RemoteElavonTest < Test::Unit::TestCase def setup @gateway = ElavonGateway.new(fixtures(:elavon)) - @credit_card = credit_card('4111111111111111') + @credit_card = credit_card('4124939999999990') @bad_credit_card = credit_card('invalid') @options = { - :email => "paul@domain.com", + :email => 'paul@domain.com', :description => 'Test Transaction', :billing_address => address, :ip => '203.0.113.0' @@ -60,8 +60,7 @@ def test_unsuccessful_capture end def test_unsuccessful_authorization - @credit_card.number = "1234567890123" - assert response = @gateway.authorize(@amount, @credit_card, @options) + assert response = @gateway.authorize(@amount, @bad_credit_card, @options) assert_failure response assert_equal 'The Credit Card Number supplied in the authorization request appears to be invalid.', response.message end @@ -69,8 +68,8 @@ def test_unsuccessful_authorization def test_successful_verify assert response = @gateway.verify(@credit_card, @options) assert_success response - assert_equal "APPROVAL", response.message - assert_success response.responses.last, "The void should succeed" + assert_equal 'APPROVAL', response.message + assert_success response.responses.last, 'The void should succeed' end def test_failed_verify @@ -121,7 +120,7 @@ def test_purchase_and_unsuccessful_void assert purchase = @gateway.purchase(@amount, @credit_card, @options) assert_success purchase - assert response = @gateway.void(purchase.authorization) + assert @gateway.void(purchase.authorization) assert response = @gateway.void(purchase.authorization) assert_failure response assert_equal 'The transaction ID is invalid for this transaction type', response.message @@ -161,14 +160,14 @@ def test_successful_store_with_verify_true def test_unsuccessful_store assert response = @gateway.store(@bad_credit_card, @options) assert_failure response - assert_equal "The Credit Card Number supplied in the authorization request appears to be invalid.", response.message + assert_equal 'The Credit Card Number supplied in the authorization request appears to be invalid.', response.message assert response.test? end def test_successful_update store_response = @gateway.store(@credit_card, @options) - token = store_response.params["token"] - credit_card = credit_card('4111111111111111', :month => 10) + token = store_response.params['token'] + credit_card = credit_card('4124939999999990', :month => 10) assert response = @gateway.update(token, credit_card, @options) assert_success response assert response.test? @@ -183,7 +182,7 @@ def test_unsuccessful_update def test_successful_purchase_with_token store_response = @gateway.store(@credit_card, @options) - token = store_response.params["token"] + token = store_response.params['token'] assert response = @gateway.purchase(@amount, token, @options) assert_success response assert response.test? @@ -196,4 +195,25 @@ def test_failed_purchase_with_token assert response.test? assert_match %r{invalid}i, response.message end + + def test_successful_purchase_with_custom_fields + assert response = @gateway.purchase(@amount, @credit_card, @options.merge(custom_fields: {a_key: 'a value'})) + + assert_success response + assert response.test? + assert_equal 'APPROVAL', response.message + assert response.authorization + end + + def test_transcript_scrubbing + transcript = capture_transcript(@gateway) do + @gateway.purchase(@amount, @credit_card, @options) + end + transcript = @gateway.scrub(transcript) + + assert_scrubbed(@credit_card.number, transcript) + assert_scrubbed(@credit_card.verification_value, transcript) + assert_scrubbed(@gateway.options[:password], transcript) + end + end diff --git a/test/remote/gateways/remote_element_test.rb b/test/remote/gateways/remote_element_test.rb index b6a1da7a1b6..4cc1b565471 100644 --- a/test/remote/gateways/remote_element_test.rb +++ b/test/remote/gateways/remote_element_test.rb @@ -18,8 +18,8 @@ def test_successful_purchase response = @gateway.purchase(@amount, @credit_card, @options) assert_success response assert_equal 'Approved', response.message - assert_match %r{Street address and postal code do not match}, response.avs_result["message"] - assert_match %r{CVV matches}, response.cvv_result["message"] + assert_match %r{Street address and postal code do not match}, response.avs_result['message'] + assert_match %r{CVV matches}, response.cvv_result['message'] end def test_failed_purchase @@ -45,7 +45,7 @@ def test_successful_purchase_with_payment_account_token end def test_successful_purchase_with_shipping_address - response = @gateway.purchase(@amount, @credit_card, @options.merge(shipping_address: address(address1: "Shipping"))) + response = @gateway.purchase(@amount, @credit_card, @options.merge(shipping_address: address(address1: 'Shipping'))) assert_success response assert_equal 'Approved', response.message end diff --git a/test/remote/gateways/remote_eway_managed_test.rb b/test/remote/gateways/remote_eway_managed_test.rb index f4914ac6eff..1322e32676c 100644 --- a/test/remote/gateways/remote_eway_managed_test.rb +++ b/test/remote/gateways/remote_eway_managed_test.rb @@ -21,7 +21,7 @@ def setup def test_successful_purchase assert response = @gateway.purchase(@amount, @valid_customer_id, @options) - assert_equal "00,Transaction Approved(Test Gateway)", response.message + assert_equal '00,Transaction Approved(Test Gateway)', response.message assert_success response assert response.test? assert_not_nil response.authorization @@ -41,7 +41,7 @@ def test_invalid_login def test_store_credit_card assert response = @gateway.store(@credit_card, @options) assert_success response - assert_equal "OK", response.message + assert_equal 'OK', response.message assert !response.token.blank? assert_not_nil response.token end @@ -49,7 +49,7 @@ def test_store_credit_card def test_update_credit_card assert response = @gateway.update(@valid_customer_id, @credit_card, @options) assert_success response - assert_equal "OK", response.message + assert_equal 'OK', response.message assert response.token.blank? end @@ -64,7 +64,7 @@ def test_store_invalid_credit_card def test_retrieve assert response = @gateway.retrieve(@valid_customer_id) assert_success response - assert_equal "OK", response.message + assert_equal 'OK', response.message assert response.test? end end diff --git a/test/remote/gateways/remote_eway_rapid_test.rb b/test/remote/gateways/remote_eway_rapid_test.rb index 733fef285d1..f0c33ba61e8 100644 --- a/test/remote/gateways/remote_eway_rapid_test.rb +++ b/test/remote/gateways/remote_eway_rapid_test.rb @@ -6,60 +6,60 @@ def setup @amount = 100 @failed_amount = -100 - @credit_card = credit_card("4444333322221111") + @credit_card = credit_card('4444333322221111') @options = { - order_id: "1", - invoice: "I1234", + order_id: '1', + invoice: 'I1234', billing_address: address, - description: "Store Purchase", - redirect_url: "http://bogus.com" + description: 'Store Purchase', + redirect_url: 'http://bogus.com' } end def test_successful_purchase response = @gateway.purchase(@amount, @credit_card, @options) assert_success response - assert_equal "Transaction Approved Successful", response.message + assert_equal 'Transaction Approved Successful', response.message end def test_fully_loaded_purchase response = @gateway.purchase(@amount, @credit_card, - redirect_url: "http://awesomesauce.com", - ip: "0.0.0.0", - application_id: "Woohoo", - partner_id: "Woohoo", - transaction_type: "Purchase", - description: "Description", - order_id: "orderid1", - invoice: "I1234", - currency: "AUD", - email: "jim@example.com", + redirect_url: 'http://awesomesauce.com', + ip: '0.0.0.0', + application_id: 'Woohoo', + partner_id: 'Woohoo', + transaction_type: 'Purchase', + description: 'Description', + order_id: 'orderid1', + invoice: 'I1234', + currency: 'AUD', + email: 'jim@example.com', billing_address: { - title: "Mr.", - name: "Jim Awesome Smith", - company: "Awesome Co", - address1: "1234 My Street", - address2: "Apt 1", - city: "Ottawa", - state: "ON", - zip: "K1C2N6", - country: "CA", - phone: "(555)555-5555", - fax: "(555)555-6666" + title: 'Mr.', + name: 'Jim Awesome Smith', + company: 'Awesome Co', + address1: '1234 My Street', + address2: 'Apt 1', + city: 'Ottawa', + state: 'ON', + zip: 'K1C2N6', + country: 'CA', + phone: '(555)555-5555', + fax: '(555)555-6666' }, shipping_address: { - title: "Ms.", - name: "Baker", - company: "Elsewhere Inc.", - address1: "4321 Their St.", - address2: "Apt 2", - city: "Chicago", - state: "IL", - zip: "60625", - country: "US", - phone: "1115555555", - fax: "1115556666" + title: 'Ms.', + name: 'Baker', + company: 'Elsewhere Inc.', + address1: '4321 Their St.', + address2: 'Apt 2', + city: 'Chicago', + state: 'IL', + zip: '60625', + country: 'US', + phone: '1115555555', + fax: '1115556666' } ) assert_success response @@ -67,38 +67,38 @@ def test_fully_loaded_purchase def test_successful_purchase_with_overly_long_fields options = { - order_id: "OrderId must be less than 50 characters otherwise it fails", - invoice: "Max 12 chars", - description: "EWay Rapid transactions fail if the description is more than 64 characters.", + order_id: 'OrderId must be less than 50 characters otherwise it fails', + invoice: 'Max 12 chars', + description: 'EWay Rapid transactions fail if the description is more than 64 characters.', billing_address: { - address1: "The Billing Address 1 Cannot Be More Than Fifty Characters.", - address2: "The Billing Address 2 Cannot Be More Than Fifty Characters.", - city: "TheCityCannotBeMoreThanFiftyCharactersOrItAllFallsApart", + address1: 'The Billing Address 1 Cannot Be More Than Fifty Characters.', + address2: 'The Billing Address 2 Cannot Be More Than Fifty Characters.', + city: 'TheCityCannotBeMoreThanFiftyCharactersOrItAllFallsApart', }, shipping_address: { - address1: "The Shipping Address 1 Cannot Be More Than Fifty Characters.", - address2: "The Shipping Address 2 Cannot Be More Than Fifty Characters.", - city: "TheCityCannotBeMoreThanFiftyCharactersOrItAllFallsApart", + address1: 'The Shipping Address 1 Cannot Be More Than Fifty Characters.', + address2: 'The Shipping Address 2 Cannot Be More Than Fifty Characters.', + city: 'TheCityCannotBeMoreThanFiftyCharactersOrItAllFallsApart', } } - @credit_card.first_name = "FullNameOnACardMustBeLessThanFiftyCharacters" - @credit_card.last_name = "LastName" + @credit_card.first_name = 'FullNameOnACardMustBeLessThanFiftyCharacters' + @credit_card.last_name = 'LastName' response = @gateway.purchase(@amount, @credit_card, options) assert_success response - assert_equal "Transaction Approved Successful", response.message + assert_equal 'Transaction Approved Successful', response.message end def test_failed_purchase response = @gateway.purchase(@failed_amount, @credit_card, @options) assert_failure response - assert_equal "Invalid Payment TotalAmount", response.message + assert_equal 'Invalid Payment TotalAmount', response.message end def test_successful_authorize_and_capture authorize = @gateway.authorize(@amount, @credit_card, @options) assert_success authorize - assert_equal "Transaction Approved Successful", authorize.message + assert_equal 'Transaction Approved Successful', authorize.message capture = @gateway.capture(nil, authorize.authorization) assert_success capture @@ -107,13 +107,13 @@ def test_successful_authorize_and_capture def test_failed_authorize response = @gateway.authorize(@failed_amount, @credit_card, @options) assert_failure response - assert_equal "Error Failed", response.message + assert_equal 'Error Failed', response.message end def test_failed_capture - response = @gateway.capture(@amount, "bogus") + response = @gateway.capture(@amount, 'bogus') assert_failure response - assert_equal "Invalid Auth Transaction ID for Capture/Void", response.message + assert_equal 'Invalid Auth Transaction ID for Capture/Void', response.message end def test_successful_void @@ -125,68 +125,68 @@ def test_successful_void end def test_failed_void - response = @gateway.void("bogus") + response = @gateway.void('bogus') assert_failure response - assert_equal "Invalid Auth Transaction ID for Capture/Void", response.message + assert_equal 'Invalid Auth Transaction ID for Capture/Void', response.message end def test_successful_refund response = @gateway.purchase(@amount, @credit_card, @options) assert_success response - assert_equal "Transaction Approved Successful", response.message + assert_equal 'Transaction Approved Successful', response.message response = @gateway.refund(@amount, response.authorization, @options) assert_success response - assert_equal "Transaction Approved Successful", response.message + assert_equal 'Transaction Approved Successful', response.message end def test_failed_refund response = @gateway.refund(@amount, 'fakeid', @options) assert_failure response - assert_equal "Invalid DirectRefundRequest, Transaction ID", response.message + assert_equal 'Invalid DirectRefundRequest, Transaction ID', response.message end def test_successful_store response = @gateway.store(@credit_card, @options) assert_success response - assert_equal "Transaction Approved Successful", response.message + assert_equal 'Transaction Approved Successful', response.message end def test_failed_store - @options[:billing_address].merge!(country: nil) + @options[:billing_address][:country] = nil response = @gateway.store(@credit_card, @options) assert_failure response - assert_equal "V6044", response.params["Errors"] - assert_equal "Customer CountryCode Required", response.message + assert_equal 'V6044', response.params['Errors'] + assert_equal 'Customer CountryCode Required', response.message end def test_successful_update response = @gateway.store(@credit_card, @options) assert_success response - assert_equal "Transaction Approved Successful", response.message + assert_equal 'Transaction Approved Successful', response.message response = @gateway.update(response.authorization, @credit_card, @options) assert_success response - assert_equal "Transaction Approved Successful", response.message + assert_equal 'Transaction Approved Successful', response.message end def test_successful_store_purchase response = @gateway.store(@credit_card, @options) assert_success response - assert_equal "Transaction Approved Successful", response.message + assert_equal 'Transaction Approved Successful', response.message response = @gateway.purchase(@amount, response.authorization, transaction_type: 'MOTO') assert_success response - assert_equal "Transaction Approved Successful", response.message + assert_equal 'Transaction Approved Successful', response.message end def test_invalid_login gateway = EwayRapidGateway.new( - login: "bogus", - password: "bogus" + login: 'bogus', + password: 'bogus' ) response = gateway.purchase(@amount, @credit_card, @options) assert_failure response - assert_equal "Unauthorized", response.message + assert_equal 'Unauthorized', response.message end def test_transcript_scrubbing diff --git a/test/remote/gateways/remote_eway_test.rb b/test/remote/gateways/remote_eway_test.rb index eaedc481950..a8d7d583874 100644 --- a/test/remote/gateways/remote_eway_test.rb +++ b/test/remote/gateways/remote_eway_test.rb @@ -17,7 +17,7 @@ def setup :state => 'WA', :country => 'AU', :zip => '2000' - } , + }, :description => 'purchased items' } end @@ -26,7 +26,7 @@ def test_invalid_amount assert response = @gateway.purchase(101, @credit_card_success, @params) assert_failure response assert response.test? - assert_equal EwayGateway::MESSAGES["01"], response.message + assert_equal EwayGateway::MESSAGES['01'], response.message end def test_purchase_success_with_verification_value @@ -34,7 +34,7 @@ def test_purchase_success_with_verification_value assert response.authorization assert_success response assert response.test? - assert_equal EwayGateway::MESSAGES["00"], response.message + assert_equal EwayGateway::MESSAGES['00'], response.message end def test_purchase_success_without_verification_value @@ -44,7 +44,7 @@ def test_purchase_success_without_verification_value assert response.authorization assert_success response assert response.test? - assert_equal EwayGateway::MESSAGES["00"], response.message + assert_equal EwayGateway::MESSAGES['00'], response.message end def test_purchase_error @@ -72,7 +72,7 @@ def test_failed_refund end def test_transcript_scrubbing - @credit_card_success.verification_value = "431" + @credit_card_success.verification_value = '431' transcript = capture_transcript(@gateway) do @gateway.purchase(100, @credit_card_success, @params) end diff --git a/test/remote/gateways/remote_exact_test.rb b/test/remote/gateways/remote_exact_test.rb index 455b495bd7f..8843e170d74 100644 --- a/test/remote/gateways/remote_exact_test.rb +++ b/test/remote/gateways/remote_exact_test.rb @@ -21,7 +21,7 @@ def test_successful_purchase def test_unsuccessful_purchase # ask for error 13 response (Amount Error) via dollar amount 5,000 + error @amount = 501300 - assert response = @gateway.purchase(@amount, @credit_card, @options ) + assert response = @gateway.purchase(@amount, @credit_card, @options) assert_match %r{Transaction Normal}, response.message assert_failure response end @@ -49,8 +49,8 @@ def test_failed_capture end def test_invalid_login - gateway = ExactGateway.new( :login => "NotARealUser", - :password => "NotARealPassword" ) + gateway = ExactGateway.new(:login => 'NotARealUser', + :password => 'NotARealPassword') assert response = gateway.purchase(@amount, @credit_card, @options) assert_match %r{^Invalid Login}, response.message assert_failure response diff --git a/test/remote/gateways/remote_ezic_test.rb b/test/remote/gateways/remote_ezic_test.rb index ac5d7dc955a..7aacb3f3a74 100644 --- a/test/remote/gateways/remote_ezic_test.rb +++ b/test/remote/gateways/remote_ezic_test.rb @@ -18,13 +18,13 @@ def setup def test_successful_purchase response = @gateway.purchase(@amount, @credit_card, @options) assert_success response - assert_equal "TEST APPROVED", response.message + assert_equal 'TEST APPROVED', response.message end def test_failed_purchase response = @gateway.purchase(@failed_amount, @credit_card, @options) assert_failure response - assert_equal "TEST DECLINED", response.message + assert_equal 'TEST DECLINED', response.message end def test_successful_authorize_and_capture @@ -33,13 +33,13 @@ def test_successful_authorize_and_capture assert capture = @gateway.capture(@amount, auth.authorization) assert_success capture - assert_equal "TEST CAPTURED", capture.message + assert_equal 'TEST CAPTURED', capture.message end def test_failed_authorize response = @gateway.authorize(@failed_amount, @credit_card, @options) assert_failure response - assert_equal "TEST DECLINED", response.message + assert_equal 'TEST DECLINED', response.message end def test_failed_capture @@ -48,7 +48,7 @@ def test_failed_capture assert capture = @gateway.capture(@amount+30, auth.authorization) assert_failure capture - assert_match /Settlement amount cannot exceed authorized amount/, capture.message + assert_match(/Settlement amount cannot exceed authorized amount/, capture.message) end def test_successful_refund @@ -57,7 +57,7 @@ def test_successful_refund assert refund = @gateway.refund(@amount, purchase.authorization) assert_success refund - assert_equal "TEST RETURNED", refund.message + assert_equal 'TEST RETURNED', refund.message end def test_partial_refund @@ -66,8 +66,8 @@ def test_partial_refund assert refund = @gateway.refund(@amount-1, purchase.authorization) assert_success refund - assert_equal "TEST RETURNED", refund.message - assert_equal "-0.99", refund.params["settle_amount"] + assert_equal 'TEST RETURNED', refund.message + assert_equal '-0.99', refund.params['settle_amount'] end def test_failed_refund @@ -76,7 +76,7 @@ def test_failed_refund assert refund = @gateway.refund(@amount + 49, purchase.authorization) assert_failure refund - assert_match /Amount of refunds exceed original sale/, refund.message + assert_match(/Amount of refunds exceed original sale/, refund.message) end def test_failed_void @@ -85,17 +85,17 @@ def test_failed_void assert void = @gateway.void(authorize.authorization) assert_failure void - assert_equal "Processor/Network Error", void.message + assert_equal 'Processor/Network Error', void.message end def test_successful_verify response = @gateway.verify(@credit_card, @options) assert_success response - assert_equal "TEST APPROVED", response.message + assert_equal 'TEST APPROVED', response.message end def test_failed_verify - response = @gateway.verify(credit_card(""), @options) + response = @gateway.verify(credit_card(''), @options) assert_failure response assert_match %r{Missing card or check number}, response.message end @@ -114,6 +114,6 @@ def test_invalid_login gateway = EzicGateway.new(account_id: '11231') response = gateway.purchase(@amount, @credit_card, @options) assert_failure response - assert_match /Invalid account number/, response.message + assert_match(/Invalid account number/, response.message) end end diff --git a/test/remote/gateways/remote_fat_zebra_test.rb b/test/remote/gateways/remote_fat_zebra_test.rb index d63efaf3a4c..dd4d594751e 100644 --- a/test/remote/gateways/remote_fat_zebra_test.rb +++ b/test/remote/gateways/remote_fat_zebra_test.rb @@ -10,7 +10,7 @@ def setup @options = { :order_id => rand(100000).to_s, - :ip => "123.1.2.3" + :ip => '1.2.3.4' } end @@ -30,7 +30,7 @@ def test_successful_multi_currency_purchase def test_unsuccessful_multi_currency_purchase assert response = @gateway.purchase(@amount, @credit_card, @options.merge(:currency => 'XYZ')) assert_failure response - assert_match /Currency XYZ is not valid for this merchant/, response.message + assert_match(/Currency XYZ is not valid for this merchant/, response.message) end def test_successful_purchase_sans_cvv @@ -148,4 +148,14 @@ def test_invalid_login assert_failure response assert_equal 'Invalid Login', response.message end + + def test_transcript_scrubbing + transcript = capture_transcript(@gateway) do + @gateway.purchase(@amount, @credit_card, @options) + end + transcript = @gateway.scrub(transcript) + + assert_scrubbed(@credit_card.number, transcript) + assert_scrubbed(@credit_card.verification_value, transcript) + end end diff --git a/test/remote/gateways/remote_federated_canada_test.rb b/test/remote/gateways/remote_federated_canada_test.rb index 9b3ebcb2512..3b48d1795af 100644 --- a/test/remote/gateways/remote_federated_canada_test.rb +++ b/test/remote/gateways/remote_federated_canada_test.rb @@ -24,54 +24,54 @@ def test_gateway_should_exist def test_successful_purchase assert response = @gateway.purchase(@amount, @credit_card, @options) assert_success response - assert_equal "Transaction Approved", response.message + assert_equal 'Transaction Approved', response.message end def test_unsuccessful_purchase assert response = @gateway.purchase(@declined_amount, @credit_card, @options) assert_failure response - assert_equal "Transaction Declined", response.message + assert_equal 'Transaction Declined', response.message end def test_successful_authorization assert response = @gateway.authorize(@amount, @credit_card, @options) assert_success response - assert_equal "Transaction Approved", response.message + assert_equal 'Transaction Approved', response.message end def test_failed_capture assert response = @gateway.capture(@amount, '') assert_failure response - assert_equal "Error in transaction data or system error", response.message + assert_equal 'Error in transaction data or system error', response.message end def test_purchase_and_refund assert auth = @gateway.purchase(@amount, @credit_card, @options) assert_success auth - assert_equal "Transaction Approved", auth.message + assert_equal 'Transaction Approved', auth.message assert auth.authorization assert capture = @gateway.refund(@amount, auth.authorization) - assert_equal "Transaction Approved", capture.message + assert_equal 'Transaction Approved', capture.message assert_success capture end def test_authorize_and_void assert auth = @gateway.authorize(@amount, @credit_card, @options) assert_success auth - assert_equal "Transaction Approved", auth.message + assert_equal 'Transaction Approved', auth.message assert auth.authorization assert capture = @gateway.void(auth.authorization) - assert_equal "Transaction Approved", capture.message + assert_equal 'Transaction Approved', capture.message assert_success capture end def test_authorize_and_capture assert auth = @gateway.authorize(@amount, @credit_card, @options) assert_success auth - assert_equal "Transaction Approved", auth.message + assert_equal 'Transaction Approved', auth.message assert auth.authorization assert capture = @gateway.capture(@amount, auth.authorization) - assert_equal "Transaction Approved", capture.message + assert_equal 'Transaction Approved', capture.message assert_success capture end @@ -82,6 +82,6 @@ def test_invalid_login ) assert response = gateway.purchase(@amount, @credit_card, @options) assert_failure response - assert_equal "Error in transaction data or system error", response.message + assert_equal 'Error in transaction data or system error', response.message end end diff --git a/test/remote/gateways/remote_finansbank_test.rb b/test/remote/gateways/remote_finansbank_test.rb index c8887cf4ae4..753df513fe9 100644 --- a/test/remote/gateways/remote_finansbank_test.rb +++ b/test/remote/gateways/remote_finansbank_test.rb @@ -1,13 +1,9 @@ # encoding: utf-8 + require 'test_helper' class RemoteFinansbankTest < Test::Unit::TestCase def setup - if RUBY_VERSION < '1.9' && $KCODE == "NONE" - @original_kcode = $KCODE - $KCODE = 'u' - end - @gateway = FinansbankGateway.new(fixtures(:finansbank)) @amount = 100 @@ -80,7 +76,7 @@ def test_unsuccessful_refund assert_failure void assert_nil void.params['order_id'] assert_equal 'Declined (Reason: 99 - Net miktardan fazlasi iade edilemez.)', void.message - assert_equal "CORE-2503", void.params['errorcode'] + assert_equal 'CORE-2503', void.params['errorcode'] end def test_void @@ -100,6 +96,6 @@ def test_invalid_login assert response = gateway.purchase(@amount, @credit_card, @options) assert_failure response assert_equal 'Declined (Reason: 99 - System based initialization problem. Please try again later.)', response.message - assert_equal "2100", response.params['errorcode'] + assert_equal '2100', response.params['errorcode'] end end diff --git a/test/remote/gateways/remote_first_giving_test.rb b/test/remote/gateways/remote_first_giving_test.rb index 1038c0bb9c6..aa37014c925 100644 --- a/test/remote/gateways/remote_first_giving_test.rb +++ b/test/remote/gateways/remote_first_giving_test.rb @@ -2,58 +2,57 @@ class RemoteFirstGivingTest < Test::Unit::TestCase - def setup @gateway = FirstGivingGateway.new(fixtures(:first_giving)) @amount = 100 - @credit_card = credit_card("4457010000000009") - @declined_card = credit_card("445701000000000") + @credit_card = credit_card('4457010000000009') + @declined_card = credit_card('445701000000000') @options = { - billing_address: address(state: "MA", zip: "01803", country: "US"), - ip: "127.0.0.1" + billing_address: address(state: 'MA', zip: '01803', country: 'US'), + ip: '127.0.0.1' } end def test_successful_purchase assert response = @gateway.purchase(@amount, @credit_card, @options) assert_success response - assert_equal "Success", response.message + assert_equal 'Success', response.message end def test_failed_purchase assert response = @gateway.purchase(@amount, @declined_card, @options) assert_failure response assert_equal( - "Unfortunately, we were unable to perform credit card number validation. The credit card number validator responded with the following message ccNumber failed data validation for the following reasons : creditcardLength: 445701000000000 contains an invalid amount of digits.", + 'Unfortunately, we were unable to perform credit card number validation. The credit card number validator responded with the following message ccNumber failed data validation for the following reasons : creditcardLength: 445701000000000 contains an invalid amount of digits.', response.message, response.params.inspect ) end def test_successful_refund - assert purchase = @gateway.purchase(@amount, @credit_card, @options) - assert_success purchase + assert purchase = @gateway.purchase(@amount, @credit_card, @options) + assert_success purchase - assert response = @gateway.refund(@amount, purchase.authorization) - assert_equal "REFUND_REQUESTED_AWAITING_REFUND", response.message + assert response = @gateway.refund(@amount, purchase.authorization) + assert_equal 'REFUND_REQUESTED_AWAITING_REFUND', response.message end def test_failed_refund - assert response = @gateway.refund(@amount, "1234") + assert response = @gateway.refund(@amount, '1234') assert_failure response - assert_equal "An error occurred. Please check your input and try again.", response.message + assert_equal 'An error occurred. Please check your input and try again.', response.message end def test_invalid_login gateway = FirstGivingGateway.new( - application_key: "25151616", - security_token: "63131jnkj", - charity_id: "1234" + application_key: '25151616', + security_token: '63131jnkj', + charity_id: '1234' ) assert response = gateway.purchase(@amount, @credit_card, @options) assert_failure response - assert_equal "An error occurred. Please check your input and try again.", response.message + assert_equal 'An error occurred. Please check your input and try again.', response.message end end diff --git a/test/remote/gateways/remote_first_pay_test.rb b/test/remote/gateways/remote_first_pay_test.rb index b64b05e578f..6e174f76976 100644 --- a/test/remote/gateways/remote_first_pay_test.rb +++ b/test/remote/gateways/remote_first_pay_test.rb @@ -27,6 +27,14 @@ def test_failed_purchase assert_equal 'Declined', response.message end + def test_failed_purchase_with_no_address + @options.delete(:billing_address) + response = @gateway.purchase(@amount, @credit_card, @options) + + assert_failure response + assert_equal 'Address is invalid (street, city, zip, state and or country fields)', response.message + end + def test_successful_authorize_and_capture auth = @gateway.authorize(@amount, @credit_card, @options) assert_success auth @@ -100,5 +108,25 @@ def test_invalid_login ) response = gateway.purchase(@amount, @credit_card, @options) assert_failure response + assert_match(/Merchant: 1234 has encountered error #DTO-200-TC./, response.error_code) + end + + def test_recurring_payment + @options.merge!({recurring: 1, recurring_start_date: DateTime.now.strftime('%m/%d/%Y'), recurring_end_date: DateTime.now.strftime('%m/%d/%Y'), recurring_type: 'monthly'}) + response = @gateway.purchase(@amount, @credit_card, @options) + assert_success response + assert_equal 'Approved', response.message + end + + def test_transcript_scrubbing + @credit_card.verification_value = 789 + transcript = capture_transcript(@gateway) do + @gateway.purchase(@amount, @credit_card, @options) + end + transcript = @gateway.scrub(transcript) + + assert_scrubbed(@credit_card.number, transcript) + assert_scrubbed(@credit_card.verification_value, transcript) + assert_scrubbed(@gateway.options[:gateway_id], transcript) end end diff --git a/test/remote/gateways/remote_firstdata_e4_test.rb b/test/remote/gateways/remote_firstdata_e4_test.rb index 80cce2aaf04..f7d88e60197 100755 --- a/test/remote/gateways/remote_firstdata_e4_test.rb +++ b/test/remote/gateways/remote_firstdata_e4_test.rb @@ -13,9 +13,9 @@ def setup :description => 'Store Purchase' } @options_with_authentication_data = @options.merge({ - eci: "5", - cavv: "TESTCAVV", - xid: "TESTXID" + eci: '5', + cavv: 'TESTCAVV', + xid: 'TESTXID' }) end @@ -25,6 +25,17 @@ def test_successful_purchase assert_success response end + def test_successful_purchase_with_network_tokenization + @credit_card = network_tokenization_credit_card('4242424242424242', + payment_cryptogram: 'BwABB4JRdgAAAAAAiFF2AAAAAAA=', + verification_value: nil + ) + assert response = @gateway.purchase(@amount, @credit_card, @options) + assert_success response + assert_equal 'Transaction Normal - Approved', response.message + assert_false response.authorization.blank? + end + def test_successful_purchase_with_specified_currency options_with_specified_currency = @options.merge({currency: 'GBP'}) assert response = @gateway.purchase(@amount, @credit_card, options_with_specified_currency) @@ -51,34 +62,34 @@ def test_successful_purchase_with_level_3 response = @gateway.purchase(500, @credit_card, @options.merge(level_3: level_3_xml)) assert_success response - assert_equal "Transaction Normal - Approved", response.message + assert_equal 'Transaction Normal - Approved', response.message end def test_successful_purchase_with_tax_fields - response = @gateway.purchase(500, @credit_card, @options.merge(tax1_amount: 50, tax1_number: "A458")) + response = @gateway.purchase(500, @credit_card, @options.merge(tax1_amount: 50, tax1_number: 'A458')) assert_success response - assert_equal "50.0", response.params["tax1_amount"] - assert_equal "", response.params["tax1_number"], "E4 blanks this out in the response" + assert_equal '50.0', response.params['tax1_amount'] + assert_equal '', response.params['tax1_number'], 'E4 blanks this out in the response' end def test_successful_purchase_with_customer_ref - response = @gateway.purchase(500, @credit_card, @options.merge(customer: "267")) + response = @gateway.purchase(500, @credit_card, @options.merge(customer: '267')) assert_success response - assert_equal "267", response.params["customer_ref"] + assert_equal '267', response.params['customer_ref'] end def test_successful_purchase_with_card_authentication assert response = @gateway.purchase(@amount, @credit_card, @options_with_authentication_data) - assert_equal response.params["cavv"], @options_with_authentication_data[:cavv] - assert_equal response.params["ecommerce_flag"], @options_with_authentication_data[:eci] - assert_equal response.params["xid"], @options_with_authentication_data[:xid] + assert_equal response.params['cavv'], @options_with_authentication_data[:cavv] + assert_equal response.params['ecommerce_flag'], @options_with_authentication_data[:eci] + assert_equal response.params['xid'], @options_with_authentication_data[:xid] assert_success response end def test_unsuccessful_purchase # ask for error 13 response (Amount Error) via dollar amount 5,000 + error @amount = 501300 - assert response = @gateway.purchase(@amount, @credit_card, @options ) + assert response = @gateway.purchase(@amount, @credit_card, @options) assert_match(/Transaction Normal/, response.message) assert_failure response end @@ -87,16 +98,16 @@ def test_bad_creditcard_number assert response = @gateway.purchase(@amount, @bad_credit_card, @options) assert_match(/Invalid Credit Card/, response.message) assert_failure response - assert_equal response.error_code, "invalid_number" + assert_equal response.error_code, 'invalid_number' end def test_trans_error # ask for error 42 (unable to send trans) as the cents bit... @amount = 500042 - assert response = @gateway.purchase(@amount, @credit_card, @options ) + assert response = @gateway.purchase(@amount, @credit_card, @options) assert_match(/Unable to Send Transaction/, response.message) # 42 is 'unable to send trans' assert_failure response - assert_equal response.error_code, "processing_error" + assert_equal response.error_code, 'processing_error' end def test_purchase_and_credit @@ -154,21 +165,21 @@ def test_successful_verify assert response = @gateway.verify(@credit_card, @options) assert_success response - assert_equal "Transaction Normal - Approved", response.message - assert_equal "0.0", response.params["dollar_amount"] - assert_equal "05", response.params["transaction_type"] + assert_equal 'Transaction Normal - Approved', response.message + assert_equal '0.0', response.params['dollar_amount'] + assert_equal '05', response.params['transaction_type'] end def test_failed_verify assert response = @gateway.verify(@bad_credit_card, @options) assert_failure response assert_match %r{Invalid Credit Card Number}, response.message - assert_equal response.error_code, "invalid_number" + assert_equal response.error_code, 'invalid_number' end def test_invalid_login - gateway = FirstdataE4Gateway.new(:login => "NotARealUser", - :password => "NotARealPassword" ) + gateway = FirstdataE4Gateway.new(:login => 'NotARealUser', + :password => 'NotARealPassword') assert response = gateway.purchase(@amount, @credit_card, @options) assert_match %r{Unauthorized Request}, response.message assert_failure response @@ -177,8 +188,8 @@ def test_invalid_login def test_response_contains_cvv_and_avs_results response = @gateway.purchase(@amount, @credit_card, @options) assert_success response - assert_equal 'M', response.cvv_result["code"] - assert_equal '4', response.avs_result["code"] + assert_equal 'M', response.cvv_result['code'] + assert_equal '4', response.avs_result['code'] end def test_refund @@ -226,7 +237,16 @@ def test_verify_credentials assert !gateway.verify_credentials end - def test_dump_transcript - # See firstdata_e4_test.rb for an example of a scrubbed transcript + def test_transcript_scrubbing + cc_with_different_cvc = credit_card(verification_value: '999') + transcript = capture_transcript(@gateway) do + @gateway.purchase(@amount, cc_with_different_cvc, @options) + end + transcript = @gateway.scrub(transcript) + + assert_scrubbed(cc_with_different_cvc.number, transcript) + assert_scrubbed(cc_with_different_cvc.verification_value, transcript) + assert_scrubbed(@gateway.options[:password], transcript) end + end diff --git a/test/remote/gateways/remote_firstdata_e4_v27_test.rb b/test/remote/gateways/remote_firstdata_e4_v27_test.rb new file mode 100644 index 00000000000..4233159fc39 --- /dev/null +++ b/test/remote/gateways/remote_firstdata_e4_v27_test.rb @@ -0,0 +1,222 @@ +require 'test_helper' + +class RemoteFirstdataE4V27Test < Test::Unit::TestCase + def setup + @gateway = FirstdataE4V27Gateway.new(fixtures(:firstdata_e4_v27)) + @credit_card = credit_card + @bad_credit_card = credit_card('4111111111111113') + @credit_card_with_track_data = credit_card_with_track_data('4003000123456781') + @amount = 100 + @options = { + :order_id => '1', + :billing_address => address, + :description => 'Store Purchase' + } + @options_with_authentication_data = @options.merge({ + eci: '5', + cavv: 'TESTCAVV', + xid: 'TESTXID' + }) + end + + def test_successful_purchase + assert response = @gateway.purchase(@amount, @credit_card, @options) + assert_match(/Transaction Normal/, response.message) + assert_success response + end + + def test_successful_purchase_with_network_tokenization + @credit_card = network_tokenization_credit_card('4242424242424242', + payment_cryptogram: 'BwABB4JRdgAAAAAAiFF2AAAAAAA=', + verification_value: nil + ) + assert response = @gateway.purchase(@amount, @credit_card, @options) + assert_success response + assert_equal 'Transaction Normal - Approved', response.message + assert_false response.authorization.blank? + end + + def test_successful_purchase_with_track_data + assert response = @gateway.purchase(@amount, @credit_card_with_track_data, @options) + assert_match(/Transaction Normal/, response.message) + assert_success response + end + + def test_successful_purchase_with_level_3 + level_3_xml = <<-LEVEL3 + <LineItem> + <LineItemTotal>107.20</LineItemTotal> + <Quantity>3</Quantity> + <Description>The Description</Description> + <UnitCost>2.33</UnitCost> + </LineItem> + LEVEL3 + + response = @gateway.purchase(500, @credit_card, @options.merge(level_3: level_3_xml)) + assert_success response + assert_equal 'Transaction Normal - Approved', response.message + end + + def test_successful_purchase_with_tax_fields + response = @gateway.purchase(500, @credit_card, @options.merge(tax1_amount: 50, tax1_number: 'A458')) + assert_success response + assert_equal '50.0', response.params['tax1_amount'] + assert_equal '', response.params['tax1_number'], 'E4 blanks this out in the response' + end + + def test_successful_purchase_with_customer_ref + response = @gateway.purchase(500, @credit_card, @options.merge(customer: '267')) + assert_success response + assert_equal '267', response.params['customer_ref'] + end + + def test_successful_purchase_with_card_authentication + assert response = @gateway.purchase(@amount, @credit_card, @options_with_authentication_data) + assert_equal response.params['cavv'], @options_with_authentication_data[:cavv] + assert_equal response.params['ecommerce_flag'], @options_with_authentication_data[:eci] + assert_equal response.params['xid'], @options_with_authentication_data[:xid] + assert_success response + end + + def test_unsuccessful_purchase + # ask for error 13 response (Amount Error) via dollar amount 5,000 + error + @amount = 501300 + assert response = @gateway.purchase(@amount, @credit_card, @options) + assert_match(/Transaction Normal/, response.message) + assert_failure response + end + + def test_bad_creditcard_number + assert response = @gateway.purchase(@amount, @bad_credit_card, @options) + assert_match(/Invalid Credit Card/, response.message) + assert_failure response + assert_equal response.error_code, 'invalid_number' + end + + def test_trans_error + # ask for error 42 (unable to send trans) as the cents bit... + @amount = 500042 + assert response = @gateway.purchase(@amount, @credit_card, @options) + assert_match(/Unable to Send Transaction/, response.message) # 42 is 'unable to send trans' + assert_failure response + assert_equal response.error_code, 'processing_error' + end + + def test_purchase_and_credit + assert purchase = @gateway.purchase(@amount, @credit_card, @options) + assert_success purchase + assert purchase.authorization + assert credit = @gateway.refund(@amount, purchase.authorization) + assert_success credit + end + + def test_purchase_and_void + assert purchase = @gateway.purchase(29234, @credit_card, @options) + assert_success purchase + + assert purchase.authorization + assert void = @gateway.void(purchase.authorization) + assert_success void + end + + def test_purchase_and_void_with_even_dollar_amount + assert purchase = @gateway.purchase(5000, @credit_card, @options) + assert_success purchase + + assert purchase.authorization + assert void = @gateway.void(purchase.authorization) + assert_success void + end + + def test_authorize_and_capture + assert auth = @gateway.authorize(@amount, @credit_card, @options) + assert_success auth + assert auth.authorization + assert capture = @gateway.capture(@amount, auth.authorization) + assert_success capture + end + + def test_failed_capture + assert response = @gateway.capture(@amount, 'ET838747474;frob') + assert_failure response + assert_match(/Invalid Authorization Number/i, response.message) + end + + def test_successful_verify + assert response = @gateway.verify(@credit_card, @options) + assert_success response + + assert_equal 'Transaction Normal - Approved', response.message + assert_equal '0.0', response.params['dollar_amount'] + assert_equal '05', response.params['transaction_type'] + end + + def test_failed_verify + assert response = @gateway.verify(@bad_credit_card, @options) + assert_failure response + assert_match %r{Invalid Credit Card Number}, response.message + assert_equal response.error_code, 'invalid_number' + end + + def test_invalid_login + gateway = FirstdataE4V27Gateway.new(:login => 'NotARealUser', + :password => 'NotARealPassword', + :key_id => 'NotARealKey', + :hmac_key => 'NotARealHMAC') + assert response = gateway.purchase(@amount, @credit_card, @options) + assert_match %r{Unauthorized Request}, response.message + assert_failure response + end + + def test_response_contains_cvv_and_avs_results + response = @gateway.purchase(@amount, @credit_card, @options) + assert_success response + assert_equal 'M', response.cvv_result['code'] + assert_equal '4', response.avs_result['code'] + end + + def test_refund + assert purchase = @gateway.purchase(@amount, @credit_card, @options) + assert_match(/Transaction Normal/, purchase.message) + assert_success purchase + + assert response = @gateway.refund(50, purchase.authorization) + assert_success response + assert_match(/Transaction Normal/, response.message) + assert response.authorization + end + + def test_refund_with_track_data + assert purchase = @gateway.purchase(@amount, @credit_card_with_track_data, @options) + assert_match(/Transaction Normal/, purchase.message) + assert_success purchase + + assert response = @gateway.refund(50, purchase.authorization) + assert_success response + assert_match(/Transaction Normal/, response.message) + assert response.authorization + end + + def test_verify_credentials + assert @gateway.verify_credentials + + gateway = FirstdataE4V27Gateway.new(login: 'unknown', password: 'unknown', key_id: 'unknown', hmac_key: 'unknown') + assert !gateway.verify_credentials + gateway = FirstdataE4V27Gateway.new(login: fixtures(:firstdata_e4)[:login], password: 'unknown', key_id: 'unknown', hmac_key: 'unknown') + assert !gateway.verify_credentials + end + + def test_transcript_scrubbing + cc_with_different_cvc = credit_card(verification_value: '999') + transcript = capture_transcript(@gateway) do + @gateway.purchase(@amount, cc_with_different_cvc, @options) + end + transcript = @gateway.scrub(transcript) + + assert_scrubbed(cc_with_different_cvc.number, transcript) + assert_scrubbed(cc_with_different_cvc.verification_value, transcript) + assert_scrubbed(@gateway.options[:password], transcript) + assert_scrubbed(@gateway.options[:hmac_key], transcript) + end + +end diff --git a/test/remote/gateways/remote_flo2cash_simple_test.rb b/test/remote/gateways/remote_flo2cash_simple_test.rb index e27ad16b874..f952d7c0be1 100644 --- a/test/remote/gateways/remote_flo2cash_simple_test.rb +++ b/test/remote/gateways/remote_flo2cash_simple_test.rb @@ -7,7 +7,7 @@ def setup @gateway = Flo2cashSimpleGateway.new(fixtures(:flo2cash_simple)) @amount = 100 - @credit_card = credit_card('5123456789012346', brand: :master, month: 5, year: 2017, verification_value: 111 ) + @credit_card = credit_card('5123456789012346', brand: :master, month: 5, year: 2017, verification_value: 111) @declined_card = credit_card('4000300011112220') @options = { @@ -25,7 +25,7 @@ def test_invalid_login ) response = gateway.purchase(@amount, @credit_card, @options) assert_failure response - assert_equal "Authentication error. Username and/or Password are incorrect", response.message + assert_equal 'Authentication error. Username and/or Password are incorrect', response.message end def test_successful_purchase @@ -53,7 +53,7 @@ def test_successful_refund def test_failed_refund response = @gateway.refund(@amount, '') assert_failure response - assert_equal "Original transaction not found", response.message + assert_equal 'Original transaction not found', response.message end def test_transcript_scrubbing diff --git a/test/remote/gateways/remote_flo2cash_test.rb b/test/remote/gateways/remote_flo2cash_test.rb index f5a1af2d10f..0c0fe0972f3 100644 --- a/test/remote/gateways/remote_flo2cash_test.rb +++ b/test/remote/gateways/remote_flo2cash_test.rb @@ -25,7 +25,7 @@ def test_invalid_login ) response = gateway.purchase(@amount, @credit_card, @options) assert_failure response - assert_equal "Authentication error. Username and/or Password are incorrect", response.message + assert_equal 'Authentication error. Username and/or Password are incorrect', response.message end def test_successful_purchase @@ -62,7 +62,7 @@ def test_failed_authorize def test_failed_capture response = @gateway.capture(@amount, '') assert_failure response - assert_equal "Original transaction not found", response.message + assert_equal 'Original transaction not found', response.message end def test_successful_refund @@ -77,7 +77,7 @@ def test_successful_refund def test_failed_refund response = @gateway.refund(@amount, '') assert_failure response - assert_equal "Original transaction not found", response.message + assert_equal 'Original transaction not found', response.message end def test_transcript_scrubbing diff --git a/test/remote/gateways/remote_forte_test.rb b/test/remote/gateways/remote_forte_test.rb index 3e8a3a13740..8a2df5bccc8 100644 --- a/test/remote/gateways/remote_forte_test.rb +++ b/test/remote/gateways/remote_forte_test.rb @@ -21,15 +21,16 @@ def setup @options = { billing_address: address, - description: 'Store Purchase' + description: 'Store Purchase', + order_id: '1' } end def test_invalid_login - gateway = ForteGateway.new(api_key: "InvalidKey", secret: "InvalidSecret", location_id: "11", account_id: "323") + gateway = ForteGateway.new(api_key: 'InvalidKey', secret: 'InvalidSecret', location_id: '11', account_id: '323') assert response = gateway.purchase(@amount, @credit_card, @options) assert_failure response - assert_match "combination not found.", response.message + assert_match 'combination not found.', response.message end def test_successful_purchase @@ -53,14 +54,14 @@ def test_failed_purchase_with_echeck def test_successful_purchase_with_more_options options = { order_id: '1', - ip: "127.0.0.1", - email: "joe@example.com", + ip: '127.0.0.1', + email: 'joe@example.com', address: address } response = @gateway.purchase(@amount, @credit_card, options) assert_success response - assert_equal "1", response.params["order_number"] + assert_equal '1', response.params['order_number'] assert_equal 'TEST APPROVAL', response.message end @@ -76,11 +77,27 @@ def test_successful_authorize_and_capture wait_for_authorization_to_clear - assert capture = @gateway.capture(@amount, auth.authorization) + assert capture = @gateway.capture(@amount, auth.authorization, @options) assert_success capture assert_equal 'APPROVED', capture.message end + def test_successful_authorize_capture_void + auth = @gateway.authorize(@amount, @credit_card, @options) + assert_success auth + + wait_for_authorization_to_clear + + assert capture = @gateway.capture(@amount, auth.authorization, @options) + assert_success capture + assert_match auth.authorization.split('#')[0], capture.authorization + assert_match auth.authorization.split('#')[1], capture.authorization + assert_equal 'APPROVED', capture.message + + void = @gateway.void(capture.authorization) + assert_success void + end + def test_failed_authorize @amount = 1985 response = @gateway.authorize(@amount, @declined_card, @options) @@ -94,12 +111,12 @@ def test_partial_capture wait_for_authorization_to_clear - assert capture = @gateway.capture(@amount-1, auth.authorization) + assert capture = @gateway.capture(@amount-1, auth.authorization, @options) assert_success capture end def test_failed_capture - response = @gateway.capture(@amount, '') + response = @gateway.capture(@amount, '', @options) assert_failure response assert_match 'field transaction_id', response.message end @@ -143,6 +160,24 @@ def test_failed_void assert_match 'field transaction_id', response.message end + def test_successful_refund + purchase = @gateway.purchase(@amount, @credit_card, @options) + assert_success purchase + + wait_for_authorization_to_clear + + assert refund = @gateway.refund(@amount, purchase.authorization, @options) + assert_success refund + assert_equal 'TEST APPROVAL', refund.message + end + + def test_failed_refund + response = @gateway.refund(@amount, '', @options) + assert_failure response + assert_match 'field authorization_code', response.message + assert_match 'field original_transaction_id', response.message + end + def test_successful_verify response = @gateway.verify(@credit_card, @options) assert_success response diff --git a/test/remote/gateways/remote_garanti_test.rb b/test/remote/gateways/remote_garanti_test.rb index 706dd627031..189fba6ddd0 100644 --- a/test/remote/gateways/remote_garanti_test.rb +++ b/test/remote/gateways/remote_garanti_test.rb @@ -4,11 +4,6 @@ class RemoteGarantiTest < Test::Unit::TestCase def setup - if RUBY_VERSION < '1.9' && $KCODE == "NONE" - @original_kcode = $KCODE - $KCODE = 'u' - end - @gateway = GarantiGateway.new(fixtures(:garanti)) @amount = 100 # 1 cents = 0.01$ @@ -63,6 +58,6 @@ def test_invalid_login ) assert response = gateway.purchase(@amount, @credit_card, @options) assert_failure response - assert_equal '0651', response.params["reason_code"] + assert_equal '0651', response.params['reason_code'] end end diff --git a/test/remote/gateways/remote_global_collect_test.rb b/test/remote/gateways/remote_global_collect_test.rb index e0b0dc32857..b7497b13f00 100644 --- a/test/remote/gateways/remote_global_collect_test.rb +++ b/test/remote/gateways/remote_global_collect_test.rb @@ -10,6 +10,7 @@ def setup @accepted_amount = 4005 @rejected_amount = 2997 @options = { + email: 'example@example.com', billing_address: address, description: 'Store Purchase' } @@ -21,11 +22,32 @@ def test_successful_purchase assert_equal 'Succeeded', response.message end + def test_successful_purchase_with_fraud_fields + options = @options.merge( + fraud_fields: + { + 'website' => 'www.example.com', + 'giftMessage' => 'Happy Day!' + } + ) + + response = @gateway.purchase(@amount, @credit_card, options) + assert_success response + assert_equal 'Succeeded', response.message + end + def test_successful_purchase_with_more_options options = @options.merge( order_id: '1', - ip: "127.0.0.1", - email: "joe@example.com" + ip: '127.0.0.1', + email: 'joe@example.com', + sdk_identifier: 'Channel', + sdk_creator: 'Bob', + integrator: 'Bill', + creator: 'Super', + name: 'Cala', + version: '1.0', + extension_ID: '5555555' ) response = @gateway.purchase(@amount, @credit_card, options) @@ -33,6 +55,14 @@ def test_successful_purchase_with_more_options assert_equal 'Succeeded', response.message end + def test_successful_purchase_with_very_long_name + credit_card = credit_card('4567350000427977', { first_name: 'thisisaverylongfirstname'}) + + response = @gateway.purchase(@amount, credit_card, @options) + assert_success response + assert_equal 'Succeeded', response.message + end + def test_failed_purchase response = @gateway.purchase(@rejected_amount, @declined_card, @options) assert_failure response @@ -58,14 +88,15 @@ def test_partial_capture auth = @gateway.authorize(@amount, @credit_card, @options) assert_success auth - assert capture = @gateway.capture(@amount-1, auth.authorization) + assert capture = @gateway.capture(@amount - 1, auth.authorization) assert_success capture + assert_equal 99, capture.params['payment']['paymentOutput']['amountOfMoney']['amount'] end def test_failed_capture response = @gateway.capture(@amount, '123', @options) assert_failure response - assert_equal 'UNKNOWN_PAYMENT_ID', response.message + assert_match %r{UNKNOWN_PAYMENT_ID}, response.message end # Because payments are not fully authorized immediately, refunds can only be @@ -89,7 +120,7 @@ def test_failed_capture def test_failed_refund response = @gateway.refund(@amount, '123') assert_failure response - assert_equal 'UNKNOWN_PAYMENT_ID', response.message + assert_match %r{UNKNOWN_PAYMENT_ID}, response.message end def test_successful_void @@ -104,7 +135,7 @@ def test_successful_void def test_failed_void response = @gateway.void('123') assert_failure response - assert_equal 'UNKNOWN_PAYMENT_ID', response.message + assert_match %r{UNKNOWN_PAYMENT_ID}, response.message end def test_successful_verify @@ -124,7 +155,7 @@ def test_invalid_login response = gateway.purchase(@amount, @credit_card, @options) assert_failure response - assert_match %r{MISSING_OR_INVALID_AUTHORIZATION}, response.message + assert_match %r{UNKNOWN_SERVER_ERROR}, response.message end def test_transcript_scrubbing diff --git a/test/remote/gateways/remote_global_transport_test.rb b/test/remote/gateways/remote_global_transport_test.rb index 476d89f3a3c..eac5264fe9c 100644 --- a/test/remote/gateways/remote_global_transport_test.rb +++ b/test/remote/gateways/remote_global_transport_test.rb @@ -19,6 +19,13 @@ def test_successful_purchase assert_equal 'Approved', response.message end + def test_successful_partial_purchase + @credit_card = credit_card('4111111111111111') + response = @gateway.purchase(2354, @credit_card, @options) + assert_success response + assert_equal 'Partial Approval', response.message + end + def test_failed_purchase response = @gateway.purchase(2304, @credit_card, @options) assert_failure response @@ -31,20 +38,22 @@ def test_successful_authorize_and_capture assert capture = @gateway.capture(500, auth.authorization) assert_success capture - assert_equal "Approved", capture.message + assert_equal 'Approved', capture.message end def test_failed_authorize response = @gateway.authorize(40000, @credit_card, @options) assert_failure response - assert_equal "Declined", response.message + assert_equal 'Declined', response.message end - def test_partial_capture - auth = @gateway.authorize(500, @credit_card, @options) + def test_successful_partial_authorize_and_capture + @credit_card = credit_card('4111111111111111') + auth = @gateway.authorize(2354, @credit_card, @options) assert_success auth + assert_equal 'Partial Approval', auth.message - assert capture = @gateway.capture(499, auth.authorization) + assert capture = @gateway.capture(2000, auth.authorization) assert_success capture end @@ -54,7 +63,7 @@ def test_failed_capture assert capture = @gateway.capture(1000, auth.authorization) assert_failure capture - assert_match /must be less than or equal to the original amount/, capture.message + assert_match(/must be less than or equal to the original amount/, capture.message) end def test_successful_refund @@ -63,7 +72,7 @@ def test_successful_refund assert refund = @gateway.refund(500, purchase.authorization) assert_success refund - assert_equal "Approved", refund.message + assert_equal 'Approved', refund.message end def test_partial_refund @@ -72,7 +81,7 @@ def test_partial_refund assert refund = @gateway.refund(490, purchase.authorization) assert_success refund - assert_equal "Approved", refund.message + assert_equal 'Approved', refund.message end def test_failed_refund @@ -81,7 +90,7 @@ def test_failed_refund assert refund = @gateway.refund(1000, purchase.authorization) assert_failure refund - assert_match /Refund Exceeds Available Refund Amount/, refund.message + assert_match(/Refund Exceeds Available Refund Amount/, refund.message) end def test_successful_void @@ -90,31 +99,43 @@ def test_successful_void assert void = @gateway.void(auth.authorization) assert_success void - assert_equal "Approved", void.message + assert_equal 'Approved', void.message end def test_failed_void - assert void = @gateway.void("UnknownAuthorization") + assert void = @gateway.void('UnknownAuthorization') assert_failure void - assert_equal "Invalid PNRef", void.message + assert_equal 'Invalid PNRef', void.message end def test_successful_verify response = @gateway.verify(@credit_card, @options) assert_success response - assert_equal "Approved", response.message + assert_equal 'Approved', response.message end def test_failed_verify response = @gateway.verify(credit_card('4003'), @options) assert_failure response - assert_equal "Invalid Account Number", response.message + assert_equal 'Invalid Account Number', response.message end def test_invalid_login gateway = GlobalTransportGateway.new(global_user_name: '', global_password: '', term_type: '') response = gateway.purchase(500, @credit_card, @options) assert_failure response - assert_equal("Invalid Login Information", response.message) + assert_equal('Invalid Login Information', response.message) end + + def test_transcript_scrubbing + transcript = capture_transcript(@gateway) do + @gateway.purchase(500, @credit_card, @options) + end + transcript = @gateway.scrub(transcript) + + assert_scrubbed(@credit_card.number, transcript) + assert_scrubbed(@credit_card.verification_value, transcript) + assert_scrubbed(@gateway.options[:global_password], transcript) + end + end diff --git a/test/remote/gateways/remote_hdfc_test.rb b/test/remote/gateways/remote_hdfc_test.rb index 22cd4453d96..e3f2ed395d5 100644 --- a/test/remote/gateways/remote_hdfc_test.rb +++ b/test/remote/gateways/remote_hdfc_test.rb @@ -7,48 +7,48 @@ def setup @gateway = HdfcGateway.new(fixtures(:hdfc)) @amount = 100 - @credit_card = credit_card("4012001037141112") + @credit_card = credit_card('4012001037141112') # Use an American Express card to simulate a failure since HDFC does not # support any proper decline cards outside of 3D secure failures. - @declined_card = credit_card("377182068239368", :brand => :american_express) + @declined_card = credit_card('377182068239368', :brand => :american_express) @options = { :order_id => generate_unique_id, :billing_address => address, - :description => "Store Purchase" + :description => 'Store Purchase' } end def test_successful_purchase assert response = @gateway.purchase(@amount, @credit_card, @options) assert_success response - assert_equal "Succeeded", response.message + assert_equal 'Succeeded', response.message end def test_failed_purchase assert response = @gateway.purchase(@amount, @declined_card, @options) assert_failure response - assert_equal "Invalid Brand.", response.message - assert_equal "GW00160", response.params["error_code_tag"] + assert_equal 'Invalid Brand.', response.message + assert_equal 'GW00160', response.params['error_code_tag'] end def test_successful_authorize_and_capture assert response = @gateway.authorize(@amount, @credit_card, @options) assert_success response - assert_equal "Succeeded", response.message + assert_equal 'Succeeded', response.message assert_match %r(^\d+\|.+$), response.authorization assert capture = @gateway.capture(@amount, response.authorization) assert_success capture - assert_equal "Succeeded", capture.message + assert_equal 'Succeeded', capture.message end def test_failed_authorize assert response = @gateway.authorize(@amount, @declined_card, @options) assert_failure response - assert_equal "Invalid Brand.", response.message - assert_equal "GW00160", response.params["error_code_tag"] + assert_equal 'Invalid Brand.', response.message + assert_equal 'GW00160', response.params['error_code_tag'] end def test_successful_refund @@ -57,7 +57,7 @@ def test_successful_refund assert refund = @gateway.refund(@amount, response.authorization) assert_success refund - assert_equal "Succeeded", refund.message + assert_equal 'Succeeded', refund.message end def test_passing_billing_address @@ -67,11 +67,11 @@ def test_passing_billing_address def test_invalid_login gateway = HdfcGateway.new( - :login => "", - :password => "" + :login => '', + :password => '' ) assert response = gateway.purchase(@amount, @credit_card, @options) assert_failure response - assert_equal "TranPortal ID required.", response.message + assert_equal 'TranPortal ID required.', response.message end end diff --git a/test/remote/gateways/remote_hps_test.rb b/test/remote/gateways/remote_hps_test.rb index 132f3b7be61..2650965ecc5 100644 --- a/test/remote/gateways/remote_hps_test.rb +++ b/test/remote/gateways/remote_hps_test.rb @@ -216,8 +216,8 @@ def test_failed_purchase_with_swipe_bad_track_data end def test_successful_purchase_with_swipe_encryption_type_01 - @options[:encryption_type] = "01" - @credit_card.track_data = "&lt;E1052711%B5473501000000014^MC TEST CARD^251200000000000000000000000000000000?|GVEY/MKaKXuqqjKRRueIdCHPPoj1gMccgNOtHC41ymz7bIvyJJVdD3LW8BbwvwoenI+|+++++++C4cI2zjMp|11;5473501000000014=25120000000000000000?|8XqYkQGMdGeiIsgM0pzdCbEGUDP|+++++++C4cI2zjMp|00|||/wECAQECAoFGAgEH2wYcShV78RZwb3NAc2VjdXJlZXhjaGFuZ2UubmV0PX50qfj4dt0lu9oFBESQQNkpoxEVpCW3ZKmoIV3T93zphPS3XKP4+DiVlM8VIOOmAuRrpzxNi0TN/DWXWSjUC8m/PI2dACGdl/hVJ/imfqIs68wYDnp8j0ZfgvM26MlnDbTVRrSx68Nzj2QAgpBCHcaBb/FZm9T7pfMr2Mlh2YcAt6gGG1i2bJgiEJn8IiSDX5M2ybzqRT86PCbKle/XCTwFFe1X|&gt;" + @options[:encryption_type] = '01' + @credit_card.track_data = '&lt;E1052711%B5473501000000014^MC TEST CARD^251200000000000000000000000000000000?|GVEY/MKaKXuqqjKRRueIdCHPPoj1gMccgNOtHC41ymz7bIvyJJVdD3LW8BbwvwoenI+|+++++++C4cI2zjMp|11;5473501000000014=25120000000000000000?|8XqYkQGMdGeiIsgM0pzdCbEGUDP|+++++++C4cI2zjMp|00|||/wECAQECAoFGAgEH2wYcShV78RZwb3NAc2VjdXJlZXhjaGFuZ2UubmV0PX50qfj4dt0lu9oFBESQQNkpoxEVpCW3ZKmoIV3T93zphPS3XKP4+DiVlM8VIOOmAuRrpzxNi0TN/DWXWSjUC8m/PI2dACGdl/hVJ/imfqIs68wYDnp8j0ZfgvM26MlnDbTVRrSx68Nzj2QAgpBCHcaBb/FZm9T7pfMr2Mlh2YcAt6gGG1i2bJgiEJn8IiSDX5M2ybzqRT86PCbKle/XCTwFFe1X|&gt;' response = @gateway.purchase(@amount, @credit_card, @options) assert_success response @@ -250,4 +250,15 @@ def tests_failed_verify assert_failure response assert_equal 'The card number is not a valid credit card number.', response.message end + + def test_transcript_scrubbing + transcript = capture_transcript(@gateway) do + @gateway.purchase(@amount, @credit_card, @options) + end + transcript = @gateway.scrub(transcript) + + assert_scrubbed(@credit_card.number, transcript) + assert_scrubbed(@credit_card.verification_value, transcript) + assert_scrubbed(@gateway.options[:secret_api_key], transcript) + end end diff --git a/test/remote/gateways/remote_iats_payments_test.rb b/test/remote/gateways/remote_iats_payments_test.rb index 5f68a03a1d6..34d604b7b92 100644 --- a/test/remote/gateways/remote_iats_payments_test.rb +++ b/test/remote/gateways/remote_iats_payments_test.rb @@ -75,31 +75,31 @@ def test_successful_check_refund # the original purchase hadn't yet cleared. No way to test immediate failure # due to the delay in original tx processing, even for text txs. assert_failure refund - assert_equal "REJECT: 3", refund.message + assert_equal 'REJECT: 3', refund.message end def test_failed_check_refund - assert refund = @gateway.refund(@amount, "invalidref") + assert refund = @gateway.refund(@amount, 'invalidref') assert_failure refund - assert_equal "REJECT: 39", refund.message + assert_equal 'REJECT: 39', refund.message end def test_successful_store_and_unstore assert store = @gateway.store(@credit_card, @options) assert_success store assert store.authorization - assert_equal "Success", store.message + assert_equal 'Success', store.message assert unstore = @gateway.unstore(store.authorization, @options) assert_success unstore - assert_equal "Success", unstore.message + assert_equal 'Success', unstore.message end def test_failed_store credit_card = credit_card('4111') assert store = @gateway.store(credit_card, @options) assert_failure store - assert_match /Invalid credit card number/, store.message + assert_match(/Invalid credit card number/, store.message) end def test_invalid_login diff --git a/test/remote/gateways/remote_ideal_rabobank_test.rb b/test/remote/gateways/remote_ideal_rabobank_test.rb deleted file mode 100644 index c2ecf00231c..00000000000 --- a/test/remote/gateways/remote_ideal_rabobank_test.rb +++ /dev/null @@ -1,121 +0,0 @@ -require 'test_helper' - -class RemoteIdealRabobankTest < Test::Unit::TestCase - def setup - Base.mode = :test - - @gateway = IdealRabobankGateway.new(fixtures(:ideal_rabobank)) - - @options = { - :issuer_id => '0151', - :return_url => 'http://www.return.url', - :order_id => '1234567890123456', - :currency => 'EUR', - :description => 'A description', - :entrance_code => '1234' - } - end - - def test_issuers - response = @gateway.issuers - list = response.issuer_list - - assert_equal 3, list.length - assert_equal 'Test Issuer', list[0]['issuerName'] - assert_equal '0121', list[0]['issuerID'] - assert_equal 'Short', list[0]['issuerList'] - end - - - def test_set_purchase - response = @gateway.setup_purchase(550, @options) - - assert_success response - assert response.test? - assert_nil response.error, "Response should not have an error" - end - - def test_return_errors - response = @gateway.setup_purchase(0.5, @options) - assert_failure response - assert_equal 'BR1210', response.error[ 'errorCode'] - assert_not_nil response.error['errorMessage'], "Response should contain an Error message" - assert_not_nil response.error['errorDetail'], "Response should contain an Error Detail message" - assert_not_nil response.error['consumerMessage'],"Response should contain an Consumer Error message" - end - - # default payment should succeed - def test_purchase_successful - response = @gateway.setup_purchase(100, @options) - - assert_success response - - assert_equal '1234567890123456', response.transaction['purchaseID'] - assert_equal '0020', response.params['AcquirerTrxRes']['Acquirer']['acquirerID'] - assert_not_nil response.service_url, "Response should contain a service url for payment" - - # now authorize the payment, issuer simulator has completed the payment - response = @gateway.capture(response.transaction['transactionID']) - - assert_success response - assert_equal 'Success', response.transaction['status'] - assert_equal 'DEN HAAG', response.transaction['consumerCity'] - assert_equal "Hr J A T Verf\303\274rth en/of Mw T V Chet", response.transaction['consumerName'] - end - - # payment of 200 should cancel - def test_purchase_cancel - response = @gateway.setup_purchase(200, @options) - - assert_success response - # now try to authorize the payment, issuer simulator has cancelled the payment - response = @gateway.capture(response.transaction['transactionID']) - - assert_failure response - assert_equal 'Cancelled', response.transaction['status'], 'Transaction should cancel' - end - - # payment of 300 should expire - def test_transaction_expired - response = @gateway.setup_purchase(300, @options) - - # now try to authorize the payment, issuer simulator let the payment expire - response = @gateway.capture(response.transaction['transactionID']) - - assert_failure response - assert_equal 'Expired', response.transaction['status'], 'Transaction should expire' - end - - # payment of 400 should remain open - def test_transaction_opened - response = @gateway.setup_purchase(400, @options) - - # now try to authorize the payment, issuer simulator keeps the payment open - response = @gateway.capture(response.transaction['transactionID']) - - assert_failure response - assert_equal 'Open', response.transaction['status'], 'Transaction should remain open' - end - - # payment of 500 should fail at issuer - def test_transaction_failed - response = @gateway.setup_purchase(500, @options) - - # now try to authorize the payment, issuer simulator lets the payment fail - response = @gateway.capture(response.transaction['transactionID']) - assert_failure response - assert_equal 'Failure', response.transaction['status'], 'Transaction should fail' - end - - # payment of 700 should be unknown at issuer - def test_transaction_unknown - response = @gateway.setup_purchase(700, @options) - - # now try to authorize the payment, issuer simulator lets the payment fail - response = @gateway.capture(response.transaction['transactionID']) - - assert_failure response - assert_equal 'SO1000', response.error[ 'errorCode'], 'ErrorCode should be correct' - end - -end diff --git a/test/remote/gateways/remote_inspire_test.rb b/test/remote/gateways/remote_inspire_test.rb index 28c83c656f2..4e137b4d3ff 100644 --- a/test/remote/gateways/remote_inspire_test.rb +++ b/test/remote/gateways/remote_inspire_test.rb @@ -4,7 +4,7 @@ class RemoteBraintreeTest < Test::Unit::TestCase def setup @gateway = InspireGateway.new(fixtures(:inspire)) - @amount = rand(10000) + 1001 + @amount = rand(1001..11000) @credit_card = credit_card('4111111111111111', :brand => 'visa') @declined_amount = rand(99) @options = { :order_id => generate_unique_id, @@ -49,7 +49,7 @@ def test_successful_add_to_vault_and_use response = @gateway.purchase(@amount, @credit_card, @options) assert_success response assert_equal 'This transaction has been approved', response.message - assert_not_nil customer_id = response.params["customer_vault_id"] + assert_not_nil customer_id = response.params['customer_vault_id'] second_response = @gateway.purchase(@amount*2, customer_id, @options) assert_equal 'This transaction has been approved', second_response.message @@ -57,19 +57,19 @@ def test_successful_add_to_vault_and_use end def test_add_to_vault_with_custom_vault_id - @options[:store] = rand(100000)+10001 + @options[:store] = rand(10001..110000) response = @gateway.purchase(@amount, @credit_card, @options) assert_success response assert_equal 'This transaction has been approved', response.message - assert_equal @options[:store], response.params["customer_vault_id"].to_i + assert_equal @options[:store], response.params['customer_vault_id'].to_i end def test_add_to_vault_with_custom_vault_id_with_store_method - @options[:billing_id] = rand(100000)+10001 + @options[:billing_id] = rand(10001..110000) response = @gateway.store(@credit_card, @options.dup) assert_success response assert_equal 'This transaction has been approved', response.message - assert_equal @options[:billing_id], response.params["customer_vault_id"].to_i + assert_equal @options[:billing_id], response.params['customer_vault_id'].to_i end def test_update_vault @@ -145,7 +145,7 @@ def test_partial_refund end def test_failed_refund - response = @gateway.refund(nil, "bogus") + response = @gateway.refund(nil, 'bogus') assert_failure response end @@ -159,5 +159,3 @@ def test_invalid_login assert_failure response end end - - diff --git a/test/remote/gateways/remote_instapay_test.rb b/test/remote/gateways/remote_instapay_test.rb index e43ad00d8ec..5a8286cf234 100644 --- a/test/remote/gateways/remote_instapay_test.rb +++ b/test/remote/gateways/remote_instapay_test.rb @@ -1,7 +1,7 @@ require 'test_helper' class RemoteInstapayTest < Test::Unit::TestCase - + def setup @gateway = InstapayGateway.new(fixtures(:instapay)) @@ -38,24 +38,24 @@ def test_failed_authorization assert response = @gateway.authorize(@amount, @declined_card, @options) assert_failure response end - + def test_authorization_and_capture assert authorization = @gateway.authorize(@amount, @credit_card, @options) assert_success authorization - + assert capture = @gateway.capture(@amount, authorization.authorization) assert_success capture assert_equal InstapayGateway::SUCCESS_MESSAGE, capture.message end - + def test_invalid_login gateway = InstapayGateway.new( :login => 'X', :password => 'Y' ) - + assert response = gateway.purchase(@amount, @credit_card) assert_failure response - assert_equal "Invalid merchant", response.message + assert_equal 'Invalid merchant', response.message end end diff --git a/test/remote/gateways/remote_ipp_test.rb b/test/remote/gateways/remote_ipp_test.rb index 635383bd956..f7e62cad46b 100644 --- a/test/remote/gateways/remote_ipp_test.rb +++ b/test/remote/gateways/remote_ipp_test.rb @@ -14,7 +14,7 @@ def setup end def test_dump_transcript - skip("Transcript scrubbing for this gateway has been tested.") + skip('Transcript scrubbing for this gateway has been tested.') dump_transcript_and_fail(@gateway, @amount, @credit_card, @options) end @@ -76,7 +76,7 @@ def test_failed_refund def test_invalid_login gateway = IppGateway.new( username: '', - password: '', + password: '' ) response = gateway.purchase(200, @credit_card, @options) assert_failure response diff --git a/test/remote/gateways/remote_iridium_test.rb b/test/remote/gateways/remote_iridium_test.rb index 8a8b2eb9ddc..dc033cabe3a 100644 --- a/test/remote/gateways/remote_iridium_test.rb +++ b/test/remote/gateways/remote_iridium_test.rb @@ -13,11 +13,11 @@ def setup @credit_card = credit_card('4976000000003436', {:verification_value => '452'}) @declined_card = credit_card('4221690000004963') - our_address = address(:address1 => "32 Edward Street", - :address2 => "Camborne", - :state => "Cornwall", - :zip => "TR14 8PA", - :country => "826") + our_address = address(:address1 => '32 Edward Street', + :address2 => 'Camborne', + :state => 'Cornwall', + :zip => 'TR14 8PA', + :country => '826') @options = { :order_id => generate_unique_id, :billing_address => our_address, @@ -41,22 +41,22 @@ def test_failed_purchase def test_avs_failure assert response = @gateway.purchase(@amount, @avs_card, @options) assert_failure response - assert_equal response.avs_result["street_match"], "N" - assert_equal response.avs_result["postal_match"], "N" + assert_equal response.avs_result['street_match'], 'N' + assert_equal response.avs_result['postal_match'], 'N' end def test_cv2_failure assert response = @gateway.purchase(@amount, @cv2_card, @options) assert_failure response - assert_equal response.cvv_result["code"], "N" + assert_equal response.cvv_result['code'], 'N' end def test_avs_cv2_failure assert response = @gateway.purchase(@amount, @avs_cv2_card, @options) assert_failure response - assert_equal response.avs_result["street_match"], "N" - assert_equal response.avs_result["postal_match"], "N" - assert_equal response.cvv_result["code"], "N" + assert_equal response.avs_result['street_match'], 'N' + assert_equal response.avs_result['postal_match'], 'N' + assert_equal response.cvv_result['code'], 'N' end def test_authorize_and_capture @@ -101,8 +101,8 @@ def test_successful_authorization_and_failed_capture end def test_failed_capture_bad_auth_info - assert auth = @gateway.authorize(@amount, @credit_card, @options) - assert capture = @gateway.capture(@amount, "a;b;c", @options) + assert @gateway.authorize(@amount, @credit_card, @options) + assert capture = @gateway.capture(@amount, 'a;b;c', @options) assert_failure capture end @@ -118,7 +118,7 @@ def test_successful_purchase_by_reference def test_failed_purchase_by_reference assert response = @gateway.authorize(1, @credit_card, @options) assert_success response - assert(reference = response.authorization) + assert response.authorization assert response = @gateway.purchase(@amount, 'bogusref', {:order_id => generate_unique_id}) assert_failure response @@ -158,7 +158,7 @@ def test_successful_void end def test_failed_void - assert response = @gateway.void("bogus") + assert response = @gateway.void('bogus') assert_failure response end diff --git a/test/remote/gateways/remote_itransact_test.rb b/test/remote/gateways/remote_itransact_test.rb index 3ec0172e6b8..d949b17232d 100644 --- a/test/remote/gateways/remote_itransact_test.rb +++ b/test/remote/gateways/remote_itransact_test.rb @@ -1,36 +1,35 @@ require 'test_helper' class RemoteItransactTest < Test::Unit::TestCase - def setup @gateway = ItransactGateway.new(fixtures(:itransact)) - + @amount = 1065 @credit_card = credit_card('4000100011112224') @declined_card = credit_card('4000300011112220') - - @options = { + + @options = { :order_id => '1', :billing_address => address, :description => 'Store Purchase' } end - + def test_successful_purchase assert response = @gateway.purchase(@amount, @credit_card, @options) assert_success response assert_nil response.message end -# As of March 8, 2012, iTransact does not provide a way to generate unsuccessful transactions through use of a -# production gateway account in test mode. -# def test_unsuccessful_purchase -# assert response = @gateway.purchase(@amount, @credit_card, @options) -# assert_failure response -# assert_equal 'DECLINE', response.params['error_category'] -# assert_equal 'Code: NBE001 Your credit card was declined by the credit card processing network. Please use another card and resubmit your transaction.', response.message -# end + # As of March 8, 2012, iTransact does not provide a way to generate unsuccessful transactions through use of a + # production gateway account in test mode. + # def test_unsuccessful_purchase + # assert response = @gateway.purchase(@amount, @credit_card, @options) + # assert_failure response + # assert_equal 'DECLINE', response.params['error_category'] + # assert_equal 'Code: NBE001 Your credit card was declined by the credit card processing network. Please use another card and resubmit your transaction.', response.message + # end def test_authorize_and_capture amount = @amount @@ -42,13 +41,13 @@ def test_authorize_and_capture assert_success capture end -# As of March 8, 2012, iTransact does not provide a way to generate unsuccessful transactions through use of a -# production gateway account in test mode. -# def test_failed_capture -# assert response = @gateway.capture(@amount, '9999999999') -# assert_failure response -# assert_equal 'REPLACE WITH GATEWAY FAILURE MESSAGE', response.message -# end + # As of March 8, 2012, iTransact does not provide a way to generate unsuccessful transactions through use of a + # production gateway account in test mode. + # def test_failed_capture + # assert response = @gateway.capture(@amount, '9999999999') + # assert_failure response + # assert_equal 'REPLACE WITH GATEWAY FAILURE MESSAGE', response.message + # end def test_authorize_and_void amount = @amount @@ -65,11 +64,11 @@ def test_void assert_success void end -# As of Sep 19, 2012, iTransact REQUIRES the total amount for the refund. -# def test_refund -# assert refund = @gateway.refund(nil, '9999999999') -# assert_success refund -# end + # As of Sep 19, 2012, iTransact REQUIRES the total amount for the refund. + # def test_refund + # assert refund = @gateway.refund(nil, '9999999999') + # assert_success refund + # end def test_refund_partial assert refund = @gateway.refund(555, '9999999999') # $5.55 in cents diff --git a/test/remote/gateways/remote_iveri_test.rb b/test/remote/gateways/remote_iveri_test.rb new file mode 100644 index 00000000000..16733284a46 --- /dev/null +++ b/test/remote/gateways/remote_iveri_test.rb @@ -0,0 +1,164 @@ +require 'test_helper' + +class RemoteIveriTest < Test::Unit::TestCase + def setup + @gateway = IveriGateway.new(fixtures(:iveri)) + + @amount = 100 + @credit_card = credit_card('4242424242424242') + @bad_card = credit_card('2121212121212121') + @timeout_card = credit_card('5454545454545454') + @invalid_card = credit_card('1111222233334444') + @options = { + order_id: generate_unique_id, + billing_address: address, + description: 'Store Purchase' + } + end + + def test_successful_purchase + response = @gateway.purchase(@amount, @credit_card, @options) + + assert_success response + assert_equal 'Succeeded', response.message + assert_equal '100', response.params['amount'] + end + + def test_successful_purchase_with_more_options + options = { + ip: '127.0.0.1', + email: 'joe@example.com', + currency: 'ZAR' + } + + response = @gateway.purchase(@amount, @credit_card, options) + assert_success response + assert_equal 'Succeeded', response.message + end + + def test_successful_purchase_with_3ds_params + options = { + eci: 'ThreeDSecure', + xid: SecureRandom.hex(14), + cavv: SecureRandom.hex(14) + } + + response = @gateway.purchase(@amount, @credit_card, options) + assert_success response + assert_equal 'Succeeded', response.message + end + + def test_failed_purchase + response = @gateway.purchase(@amount, @bad_card, @options) + assert_failure response + assert_includes ['Denied', 'Hot card', 'Please call'], response.message + end + + def test_successful_authorize_and_capture + auth = @gateway.authorize(@amount, @credit_card, @options) + assert_success auth + + assert capture = @gateway.capture(@amount, auth.authorization) + assert_success capture + assert_equal 'Succeeded', capture.message + end + + def test_failed_authorize + response = @gateway.authorize(@amount, @bad_card, @options) + assert_failure response + assert_includes ['Denied', 'Hot card', 'Please call'], response.message + end + + def test_partial_capture + auth = @gateway.authorize(@amount, @credit_card, @options) + assert_success auth + + assert capture = @gateway.capture(@amount-1, auth.authorization) + assert_success capture + end + + def test_failed_capture + response = @gateway.capture(@amount, '') + assert_failure response + assert_equal 'Missing PAN', response.message + end + + def test_successful_refund + purchase = @gateway.purchase(@amount, @credit_card, @options) + assert_success purchase + + assert refund = @gateway.refund(@amount, purchase.authorization, @options) + assert_success refund + assert_equal 'Succeeded', refund.message + end + + def test_partial_refund + purchase = @gateway.purchase(@amount, @credit_card, @options) + assert_success purchase + + assert refund = @gateway.refund(@amount-1, purchase.authorization) + assert_success refund + end + + def test_failed_refund + response = @gateway.refund(@amount, '', @options) + assert_failure response + assert_match %r{Credit is not supported}, response.message + end + + def test_successful_void + auth = @gateway.authorize(@amount, @credit_card, @options) + assert_success auth + + assert void = @gateway.void(auth.authorization) + assert_success void + assert_equal 'Succeeded', void.message + end + + def test_failed_void + response = @gateway.void('') + assert_failure response + assert_equal 'Missing OriginalMerchantTrace', response.message + end + + def test_successful_verify + response = @gateway.verify(@credit_card, @options) + assert_success response + assert_equal 'Succeeded', response.message + end + + def test_failed_verify + response = @gateway.verify(@bad_card, @options) + assert_failure response + assert_includes ['Denied', 'Hot card', 'Please call'], response.message + end + + def test_successful_verify_credentials + assert @gateway.verify_credentials + end + + def test_failed_verify_credentials + gateway = IveriGateway.new(app_id: '11111111-1111-1111-1111-111111111111', cert_id: '11111111-1111-1111-1111-111111111111') + assert !gateway.verify_credentials + end + + def test_invalid_login + gateway = IveriGateway.new(app_id: '', cert_id: '') + + response = gateway.purchase(@amount, @credit_card, @options) + assert_failure response + assert_equal 'No CertificateID specified', response.message + end + + def test_transcript_scrubbing + transcript = capture_transcript(@gateway) do + @gateway.purchase(@amount, @credit_card, @options) + end + transcript = @gateway.scrub(transcript) + + assert_scrubbed(@credit_card.number, transcript) + assert_scrubbed(@credit_card.verification_value, transcript) + assert_scrubbed(@gateway.options[:cert_id], transcript) + end + +end diff --git a/test/remote/gateways/remote_jetpay_test.rb b/test/remote/gateways/remote_jetpay_test.rb index d528a3694b5..d5d331a72f1 100644 --- a/test/remote/gateways/remote_jetpay_test.rb +++ b/test/remote/gateways/remote_jetpay_test.rb @@ -21,23 +21,23 @@ def setup def test_successful_purchase assert response = @gateway.purchase(9900, @credit_card, @options) assert_success response - assert_equal "APPROVED", response.message + assert_equal 'APPROVED', response.message assert_not_nil response.authorization - assert_not_nil response.params["approval"] + assert_not_nil response.params['approval'] end def test_unsuccessful_purchase assert response = @gateway.purchase(5205, @declined_card, @options) assert_failure response - assert_equal "Do not honor.", response.message + assert_equal 'Do not honor.', response.message end def test_successful_purchase_with_origin assert response = @gateway.purchase(9900, @credit_card, {:origin => 'RECURRING'}) assert_success response - assert_equal "APPROVED", response.message + assert_equal 'APPROVED', response.message assert_not_nil response.authorization - assert_not_nil response.params["approval"] + assert_not_nil response.params['approval'] end def test_authorize_and_capture @@ -45,7 +45,7 @@ def test_authorize_and_capture assert_success auth assert_equal 'APPROVED', auth.message assert_not_nil auth.authorization - assert_not_nil auth.params["approval"] + assert_not_nil auth.params['approval'] assert capture = @gateway.capture(9900, auth.authorization) assert_success capture @@ -56,14 +56,14 @@ def test_partial_capture assert_success auth assert_equal 'APPROVED', auth.message assert_not_nil auth.authorization - assert_not_nil auth.params["approval"] + assert_not_nil auth.params['approval'] assert capture = @gateway.capture(4400, auth.authorization) assert_success capture end def test_ud_fields_on_purchase - assert response = @gateway.purchase(9900, @credit_card, @options.merge(ud_field_1: "Value1", ud_field_2: "Value2", ud_field3: "Value3")) + assert response = @gateway.purchase(9900, @credit_card, @options.merge(ud_field_1: 'Value1', ud_field_2: 'Value2', ud_field3: 'Value3')) assert_success response end @@ -71,38 +71,54 @@ def test_ud_fields_on_capture assert auth = @gateway.authorize(9900, @credit_card, @options) assert_success auth - assert capture = @gateway.capture(9900, auth.authorization, @options.merge(ud_field_1: "Value1", ud_field_2: "Value2", ud_field3: "Value3")) + assert capture = @gateway.capture(9900, auth.authorization, @options.merge(ud_field_1: 'Value1', ud_field_2: 'Value2', ud_field3: 'Value3')) assert_success capture end - def test_void # must void a valid auth assert auth = @gateway.authorize(9900, @credit_card, @options) assert_success auth assert_equal 'APPROVED', auth.message assert_not_nil auth.authorization - assert_not_nil auth.params["approval"] - + assert_not_nil auth.params['approval'] assert void = @gateway.void(auth.authorization) assert_success void end - def test_refund_with_token - + def test_purchase_refund_with_token assert response = @gateway.purchase(9900, @credit_card, @options) assert_success response - assert_equal "APPROVED", response.message + assert_equal 'APPROVED', response.message assert_not_nil response.authorization - assert_not_nil response.params["approval"] + assert_not_nil response.params['approval'] # linked to a specific transaction_id assert credit = @gateway.refund(9900, response.authorization) assert_success credit assert_not_nil(credit.authorization) - assert_not_nil(response.params["approval"]) - assert_equal [response.params['transaction_id'], response.params["approval"], 9900, response.params["token"]].join(";"), response.authorization + assert_not_nil(response.params['approval']) + assert_equal [response.params['transaction_id'], response.params['approval'], 9900, response.params['token']].join(';'), response.authorization + end + + def test_capture_refund_with_token + assert auth = @gateway.authorize(9900, @credit_card, @options) + assert_success auth + assert_equal 'APPROVED', auth.message + assert_not_nil auth.authorization + assert_not_nil auth.params['approval'] + assert_equal [auth.params['transaction_id'], auth.params['approval'], 9900, auth.params['token']].join(';'), auth.authorization + + assert capture = @gateway.capture(9900, auth.authorization) + assert_success capture + assert_equal [capture.params['transaction_id'], capture.params['approval'], 9900, auth.params['token']].join(';'), capture.authorization + + # linked to a specific transaction_id + assert refund = @gateway.refund(9900, capture.authorization) + assert_success refund + assert_not_nil(refund.authorization) + assert_not_nil(refund.params['approval']) end def test_refund_backwards_compatible @@ -111,18 +127,18 @@ def test_refund_backwards_compatible assert response = @gateway.purchase(9900, card, @options) assert_success response - assert_equal "APPROVED", response.message + assert_equal 'APPROVED', response.message assert_not_nil response.authorization - assert_not_nil response.params["approval"] + assert_not_nil response.params['approval'] - old_authorization = [response.params['transaction_id'], response.params["approval"], 9900].join(";") + old_authorization = [response.params['transaction_id'], response.params['approval'], 9900].join(';') # linked to a specific transaction_id assert credit = @gateway.refund(9900, old_authorization, :credit_card => card) assert_success credit assert_not_nil(credit.authorization) - assert_not_nil(response.params["approval"]) - assert_equal [response.params['transaction_id'], response.params["approval"], 9900, response.params["token"]].join(";"), response.authorization + assert_not_nil(response.params['approval']) + assert_equal [response.params['transaction_id'], response.params['approval'], 9900, response.params['token']].join(';'), response.authorization end def test_credit @@ -133,7 +149,7 @@ def test_credit assert credit = @gateway.credit(9900, card) assert_success credit assert_not_nil(credit.authorization) - assert_not_nil(credit.params["approval"]) + assert_not_nil(credit.params['approval']) end def test_failed_capture @@ -160,7 +176,7 @@ def test_missing_login def test_transcript_scrubbing @amount = 9900 - @credit_card.verification_value = "421" + @credit_card.verification_value = '421' transcript = capture_transcript(@gateway) do @gateway.purchase(@amount, @credit_card, @options) end diff --git a/test/remote/gateways/remote_jetpay_v2_certification_test.rb b/test/remote/gateways/remote_jetpay_v2_certification_test.rb new file mode 100644 index 00000000000..be182a8be37 --- /dev/null +++ b/test/remote/gateways/remote_jetpay_v2_certification_test.rb @@ -0,0 +1,348 @@ +require 'test_helper' + +class RemoteJetpayV2CertificationTest < Test::Unit::TestCase + + def setup + @gateway = JetpayV2Gateway.new(fixtures(:jetpay_v2)) + + @unique_id = '' + + @options = { + :device => 'spreedly', + :application => 'spreedly', + :developer_id => 'GenkID', + :billing_address => address(:address1 => '1234 Fifth Street', :address2 => '', :city => 'Beaumont', :state => 'TX', :country => 'US', :zip => '77708'), + :shipping_address => address(:address1 => '1234 Fifth Street', :address2 => '', :city => 'Beaumont', :state => 'TX', :country => 'US', :zip => '77708'), + :email => 'test@test.com', + :ip => '127.0.0.1' + } + end + + def teardown + puts "\n#{@options[:order_id]}: #{@unique_id}" + end + + def test_certification_cnp1_authorize_mastercard + @options[:order_id] = 'CNP1' + amount = 1000 + master = credit_card('5111111111111118', :month => 12, :year => 2017, :brand => 'master', :verification_value => '121') + assert response = @gateway.authorize(amount, master, @options) + assert_success response + assert_equal 'APPROVED', response.message + @unique_id = response.params['unique_id'] + end + + def test_certification_cnp2_authorize_visa + @options[:order_id] = 'CNP2' + amount = 1105 + visa = credit_card('4111111111111111', :month => 12, :year => 2017, :brand => 'visa', :verification_value => '121') + assert response = @gateway.authorize(amount, visa, @options) + assert_failure response + assert_equal 'Do not honor.', response.message + @unique_id = response.params['unique_id'] + end + + def test_certification_cnp3_cnp4_authorize_and_capture_amex + @options[:order_id] = 'CNP3' + amount = 1200 + amex = credit_card('378282246310005', :month => 12, :year => 2017, :brand => 'american_express', :verification_value => '1221') + assert response = @gateway.authorize(amount, amex, @options) + assert_success response + assert_equal 'APPROVED', response.message + @unique_id = response.params['unique_id'] + puts "\n#{@options[:order_id]}: #{@unique_id}" + + @options[:order_id] = 'CNP4' + assert response = @gateway.capture(amount, response.authorization, @options) + assert_success response + @unique_id = response.params['unique_id'] + end + + def test_certification_cnp5_purchase_discover + @options[:order_id] = 'CNP5' + amount = 1300 + discover = credit_card('6011111111111117', :month => 12, :year => 2017, :brand => 'discover', :verification_value => '121') + assert response = @gateway.purchase(amount, discover, @options) + assert_success response + assert_equal 'APPROVED', response.message + @unique_id = response.params['unique_id'] + end + + def test_certification_cnp6_purchase_visa + @options[:order_id] = 'CNP6' + amount = 1405 + visa = credit_card('4111111111111111', :month => 12, :year => 2017, :brand => 'visa', :verification_value => '120') + assert response = @gateway.purchase(amount, visa, @options) + assert_failure response + assert_equal 'Do not honor.', response.message + @unique_id = response.params['unique_id'] + end + + def test_certification_cnp7_authorize_mastercard + @options[:order_id] = 'CNP7' + amount = 1500 + master = credit_card('5111111111111118', :month => 12, :year => 2017, :brand => 'master', :verification_value => '120') + assert response = @gateway.authorize(amount, master, @options) + assert_success response + assert_equal 'APPROVED', response.message + @unique_id = response.params['unique_id'] + end + + def test_certification_cnp8_authorize_visa + @options[:order_id] = 'CNP8' + amount = 1605 + visa = credit_card('4111111111111111', :month => 12, :year => 2017, :brand => 'visa', :verification_value => '120') + assert response = @gateway.authorize(amount, visa, @options) + assert_failure response + assert_equal 'Do not honor.', response.message + @unique_id = response.params['unique_id'] + end + + def test_certification_cnp9_cnp10_authorize_and_capture_amex + @options[:order_id] = 'CNP9' + amount = 1700 + amex = credit_card('378282246310005', :month => 12, :year => 2017, :brand => 'american_express', :verification_value => '1220') + assert response = @gateway.authorize(amount, amex, @options) + assert_success response + assert_equal 'APPROVED', response.message + @unique_id = response.params['unique_id'] + puts "\n#{@options[:order_id]}: #{@unique_id}" + + @options[:order_id] = 'CNP10' + assert response = @gateway.capture(amount, response.authorization, @options) + assert_success response + @unique_id = response.params['unique_id'] + end + + def test_certification_cnp11_purchase_discover + @options[:order_id] = 'CNP11' + amount = 1800 + discover = credit_card('6011111111111117', :month => 12, :year => 2017, :brand => 'discover', :verification_value => '120') + assert response = @gateway.purchase(amount, discover, @options) + assert_success response + assert_equal 'APPROVED', response.message + @unique_id = response.params['unique_id'] + end + + def test_certification_rec01_recurring_mastercard + @options[:order_id] = 'REC01' + @options[:origin] = 'RECURRING' + @options[:billing_address] = nil + @options[:shipping_address] = nil + amount = 2000 + master = credit_card('5111111111111118', :month => 12, :year => 2017, :brand => 'master', :verification_value => '120') + assert response = @gateway.purchase(amount, master, @options) + assert_success response + assert_equal 'APPROVED', response.message + @unique_id = response.params['unique_id'] + end + + def test_certification_rec02_recurring_visa + @options[:order_id] = 'REC02' + @options[:origin] = 'RECURRING' + amount = 2100 + visa = credit_card('4111111111111111', :month => 12, :year => 2017, :brand => 'visa', :verification_value => '') + assert response = @gateway.purchase(amount, visa, @options) + assert_success response + assert_equal 'APPROVED', response.message + @unique_id = response.params['unique_id'] + end + + def test_certification_rec03_recurring_amex + @options[:order_id] = 'REC03' + @options[:origin] = 'RECURRING' + amount = 2200 + amex = credit_card('378282246310005', :month => 12, :year => 2017, :brand => 'american_express', :verification_value => '1221') + assert response = @gateway.purchase(amount, amex, @options) + assert_success response + assert_equal 'APPROVED', response.message + @unique_id = response.params['unique_id'] + end + + def test_certification_corp07_corp08_authorize_and_capture_discover + @options[:order_id] = 'CORP07' + amount = 2500 + discover = credit_card('6011111111111117', :month => 12, :year => 2018, :brand => 'discover', :verification_value => '120') + assert response = @gateway.authorize(amount, discover, @options) + assert_success response + assert_equal 'APPROVED', response.message + @unique_id = response.params['unique_id'] + puts "\n#{@options[:order_id]}: #{@unique_id}" + + @options[:order_id] = 'CORP08' + assert response = @gateway.capture(amount, response.authorization, @options.merge(:tax_amount => '200')) + assert_success response + @unique_id = response.params['unique_id'] + end + + def test_certification_corp09_corp10_authorize_and_capture_visa + @options[:order_id] = 'CORP09' + amount = 5000 + visa = credit_card('4111111111111111', :month => 12, :year => 2018, :brand => 'visa', :verification_value => '120') + assert response = @gateway.authorize(amount, visa, @options) + assert_success response + assert_equal 'APPROVED', response.message + @unique_id = response.params['unique_id'] + puts "\n#{@options[:order_id]}: #{@unique_id}" + + @options[:order_id] = 'CORP10' + assert response = @gateway.capture(amount, response.authorization, @options.merge(:tax_amount => '0', :tax_exempt => 'true')) + assert_success response + @unique_id = response.params['unique_id'] + end + + def test_certification_corp11_corp12_authorize_and_capture_mastercard + @options[:order_id] = 'CORP11' + amount = 7500 + master = credit_card('5111111111111118', :month => 12, :year => 2018, :brand => 'master', :verification_value => '120') + assert response = @gateway.authorize(amount, master, @options) + assert_success response + assert_equal 'APPROVED', response.message + @unique_id = response.params['unique_id'] + puts "\n#{@options[:order_id]}: #{@unique_id}" + + @options[:order_id] = 'CORP12' + assert response = @gateway.capture(amount, response.authorization, @options.merge(:tax_amount => '0', :tax_exempt => 'false', :purchase_order => '456456')) + assert_success response + @unique_id = response.params['unique_id'] + end + + def test_certification_cred02_credit_visa + @options[:order_id] = 'CRED02' + amount = 100 + visa = credit_card('4111111111111111', :month => 12, :year => 2017, :brand => 'visa', :verification_value => '120') + assert response = @gateway.credit(amount, visa, @options) + assert_success response + assert_equal 'APPROVED', response.message + @unique_id = response.params['unique_id'] + end + + def test_certification_cred03_credit_amex + @options[:order_id] = 'CRED03' + amount = 200 + amex = credit_card('378282246310005', :month => 12, :year => 2017, :brand => 'american_express', :verification_value => '1220') + assert response = @gateway.credit(amount, amex, @options) + assert_success response + assert_equal 'APPROVED', response.message + @unique_id = response.params['unique_id'] + end + + def test_certification_void03_void04_purchase_void_visa + @options[:order_id] = 'VOID03' + amount = 300 + visa = credit_card('4111111111111111', :month => 12, :year => 2017, :brand => 'visa', :verification_value => '120') + assert response = @gateway.purchase(amount, visa, @options) + assert_success response + assert_equal 'APPROVED', response.message + @unique_id = response.params['unique_id'] + puts "\n#{@options[:order_id]}: #{@unique_id}" + + @options[:order_id] = 'VOID04' + transaction_id, approval, _amount, token = response.authorization.split(';') + amount = 500 + authorization = [transaction_id, approval, amount, token].join(';') + assert response = @gateway.void(authorization, @options) + assert_failure response + @unique_id = response.params['unique_id'] + end + + def test_certification_void07_void08_void09_authorize_capture_void_discover + @options[:order_id] = 'VOID07' + amount = 400 + discover = credit_card('6011111111111117', :month => 12, :year => 2017, :brand => 'discover', :verification_value => '120') + assert response = @gateway.authorize(amount, discover, @options) + assert_success response + assert_equal 'APPROVED', response.message + @unique_id = response.params['unique_id'] + puts "\n#{@options[:order_id]}: #{@unique_id}" + + @options[:order_id] = 'VOID08' + amount = 600 + assert response = @gateway.capture(amount, response.authorization, @options) + assert_success response + @unique_id = response.params['unique_id'] + puts "\n#{@options[:order_id]}: #{@unique_id}" + + @options[:order_id] = 'VOID09' + assert response = @gateway.void(response.authorization, @options) + assert_success response + @unique_id = response.params['unique_id'] + end + + def test_certification_void12_void13_credit_void_visa + @options[:order_id] = 'VOID12' + amount = 800 + visa = credit_card('4111111111111111', :month => 12, :year => 2017, :brand => 'visa', :verification_value => '120') + assert response = @gateway.credit(amount, visa, @options) + assert_success response + assert_equal 'APPROVED', response.message + @unique_id = response.params['unique_id'] + puts "\n#{@options[:order_id]}: #{@unique_id}" + + @options[:order_id] = 'VOID13' + assert response = @gateway.void(response.authorization, @options) + assert_success response + @unique_id = response.params['unique_id'] + end + + def test_certification_tok15_tokenize_mastercard + @options[:order_id] = 'TOK15' + master = credit_card('5111111111111118', :month => 12, :year => 2017, :brand => 'master', :verification_value => '101') + assert response = @gateway.store(master, @options) + assert_success response + assert_equal 'APPROVED', response.message + assert_equal 'TOKENIZED', response.params['response_text'] + @unique_id = response.params['unique_id'] + end + + def test_certification_tok16_authorize_with_token_request_visa + @options[:order_id] = 'TOK16' + amount = 3100 + visa = credit_card('4111111111111111', :month => 12, :year => 2017, :brand => 'visa', :verification_value => '101') + assert response = @gateway.authorize(amount, visa, @options) + assert_success response + assert_equal 'APPROVED', response.message + _transaction_id, _approval, _amount, token = response.authorization.split(';') + assert_equal token, response.params['token'] + @unique_id = response.params['unique_id'] + end + + def test_certification_tok17_purchase_with_token_request_amex + @options[:order_id] = 'TOK17' + amount = 3200 + amex = credit_card('378282246310005', :month => 12, :year => 2017, :brand => 'american_express', :verification_value => '1001') + assert response = @gateway.purchase(amount, amex, @options) + assert_success response + assert_equal 'APPROVED', response.message + _transaction_id, _approval, _amount, token = response.authorization.split(';') + assert_equal token, response.params['token'] + @unique_id = response.params['unique_id'] + end + + def test_certification_tok18_authorize_using_token_mastercard + master = credit_card('5111111111111118', :month => 12, :year => 2017, :brand => 'master', :verification_value => '101') + assert response = @gateway.store(master, @options) + assert_success response + + @options[:order_id] = 'TOK18' + amount = 3300 + assert response = @gateway.authorize(amount, response.authorization, @options) + assert_success response + assert_equal 'APPROVED', response.message + @unique_id = response.params['unique_id'] + end + + def test_certification_tok19_purchase_using_token_visa + visa = credit_card('4111111111111111', :month => 12, :year => 2017, :brand => 'visa', :verification_value => '101') + assert response = @gateway.store(visa, @options) + assert_success response + + @options[:order_id] = 'TOK19' + amount = 3400 + assert response = @gateway.purchase(amount, response.authorization, @options) + assert_success response + assert_equal 'APPROVED', response.message + @unique_id = response.params['unique_id'] + end + +end diff --git a/test/remote/gateways/remote_jetpay_v2_test.rb b/test/remote/gateways/remote_jetpay_v2_test.rb new file mode 100644 index 00000000000..10f1ea6322f --- /dev/null +++ b/test/remote/gateways/remote_jetpay_v2_test.rb @@ -0,0 +1,205 @@ +require 'test_helper' + +class RemoteJetpayV2Test < Test::Unit::TestCase + + def setup + @gateway = JetpayV2Gateway.new(fixtures(:jetpay_v2)) + + @credit_card = credit_card('4000300020001000') + + @amount_approved = 9900 + @amount_declined = 5205 + + @options = { + :device => 'spreedly', + :application => 'spreedly', + :developer_id => 'GenkID', + :billing_address => address(:city => 'Durham', :state => 'NC', :country => 'US', :zip => '27701'), + :shipping_address => address(:city => 'Durham', :state => 'NC', :country => 'US', :zip => '27701'), + :email => 'test@test.com', + :ip => '127.0.0.1', + :order_id => '12345' + } + end + + def test_successful_purchase + assert response = @gateway.purchase(@amount_approved, @credit_card, @options) + assert_success response + assert_equal 'APPROVED', response.message + assert_not_nil response.authorization + assert_not_nil response.params['approval'] + end + + def test_failed_purchase + assert response = @gateway.purchase(@amount_declined, @credit_card, @options) + assert_failure response + assert_equal 'Do not honor.', response.message + end + + def test_successful_purchase_with_minimal_options + assert response = @gateway.purchase(@amount_approved, @credit_card, {:device => 'spreedly', :application => 'spreedly'}) + assert_success response + assert_equal 'APPROVED', response.message + assert_not_nil response.authorization + assert_not_nil response.params['approval'] + end + + def test_successful_purchase_with_additional_options + options = @options.merge( + ud_field_1: 'Value1', + ud_field_2: 'Value2', + ud_field_3: 'Value3' + ) + assert response = @gateway.purchase(@amount_approved, @credit_card, options) + assert_success response + end + + def test_successful_authorize_and_capture + assert auth = @gateway.authorize(@amount_approved, @credit_card, @options) + assert_success auth + assert_equal 'APPROVED', auth.message + assert_not_nil auth.authorization + assert_not_nil auth.params['approval'] + + assert capture = @gateway.capture(@amount_approved, auth.authorization, @options) + assert_success capture + end + + def test_successful_authorize_and_capture_with_tax + assert auth = @gateway.authorize(@amount_approved, @credit_card, @options) + assert_success auth + assert_equal 'APPROVED', auth.message + assert_not_nil auth.authorization + assert_not_nil auth.params['approval'] + + assert capture = @gateway.capture(@amount_approved, auth.authorization, @options.merge(:tax_amount => '990', :purchase_order => 'ABC12345')) + assert_success capture + end + + def test_successful_partial_capture + assert auth = @gateway.authorize(9900, @credit_card, @options) + assert_success auth + assert_equal 'APPROVED', auth.message + assert_not_nil auth.authorization + assert_not_nil auth.params['approval'] + + assert capture = @gateway.capture(4400, auth.authorization, @options) + assert_success capture + end + + def test_failed_capture + assert response = @gateway.capture(@amount_approved, '7605f7c5d6e8f74deb', @options) + assert_failure response + assert_equal 'Transaction Not Found.', response.message + end + + def test_successful_void + assert auth = @gateway.authorize(@amount_approved, @credit_card, @options) + assert_success auth + assert_equal 'APPROVED', auth.message + assert_not_nil auth.authorization + assert_not_nil auth.params['approval'] + + assert void = @gateway.void(auth.authorization, @options) + assert_success void + end + + def test_failed_void + assert void = @gateway.void('bogus', @options) + assert_failure void + end + + def test_successful_purchase_refund + assert response = @gateway.purchase(@amount_approved, @credit_card, @options) + assert_success response + assert_equal 'APPROVED', response.message + assert_not_nil response.authorization + assert_not_nil response.params['approval'] + + assert refund = @gateway.refund(@amount_approved, response.authorization, @options) + assert_success refund + assert_not_nil(refund.authorization) + assert_not_nil(response.params['approval']) + assert_equal [response.params['transaction_id'], response.params['approval'], @amount_approved, response.params['token']].join(';'), response.authorization + end + + def test_successful_capture_refund + assert auth = @gateway.authorize(@amount_approved, @credit_card, @options) + assert_success auth + assert_equal 'APPROVED', auth.message + assert_not_nil auth.authorization + assert_not_nil auth.params['approval'] + assert_equal [auth.params['transaction_id'], auth.params['approval'], @amount_approved, auth.params['token']].join(';'), auth.authorization + + assert capture = @gateway.capture(@amount_approved, auth.authorization, @options) + assert_success capture + assert_equal [capture.params['transaction_id'], capture.params['approval'], @amount_approved, auth.params['token']].join(';'), capture.authorization + + assert refund = @gateway.refund(@amount_approved, capture.authorization, @options) + assert_success refund + assert_not_nil(refund.authorization) + assert_not_nil(refund.params['approval']) + end + + def test_failed_refund + assert refund = @gateway.refund(@amount_approved, 'bogus', @options) + assert_failure refund + end + + def test_successful_credit + card = credit_card('4242424242424242', :verification_value => nil) + + assert credit = @gateway.credit(@amount_approved, card, @options) + assert_success credit + assert_not_nil(credit.authorization) + assert_not_nil(credit.params['approval']) + end + + def test_failed_credit + card = credit_card('2424242424242424', :verification_value => nil) + + assert credit = @gateway.credit(@amount_approved, card, @options) + assert_failure credit + assert_match %r{Invalid card format}, credit.message + end + + def test_successful_verify + assert verify = @gateway.verify(@credit_card, @options) + assert_success verify + end + + def test_failed_verify + card = credit_card('2424242424242424', :verification_value => nil) + + assert verify = @gateway.verify(card, @options) + assert_failure verify + assert_match %r{Invalid card format}, verify.message + end + + def test_invalid_login + gateway = JetpayV2Gateway.new(:login => 'bogus') + assert response = gateway.purchase(@amount_approved, @credit_card, @options) + assert_failure response + + assert_equal 'Bad Terminal ID.', response.message + end + + def test_missing_login + gateway = JetpayV2Gateway.new(:login => '') + assert response = gateway.purchase(@amount_approved, @credit_card, @options) + assert_failure response + + assert_equal 'No response returned (missing credentials?).', response.message + end + + def test_transcript_scrubbing + @credit_card.verification_value = '421' + transcript = capture_transcript(@gateway) do + @gateway.purchase(@amount_approved, @credit_card, @options) + end + clean_transcript = @gateway.scrub(transcript) + + assert_scrubbed(@credit_card.number, clean_transcript) + assert_scrubbed(@credit_card.verification_value.to_s, clean_transcript) + end +end diff --git a/test/remote/gateways/remote_komoju_test.rb b/test/remote/gateways/remote_komoju_test.rb index 1d5a22dc0d2..5214eb01fbf 100644 --- a/test/remote/gateways/remote_komoju_test.rb +++ b/test/remote/gateways/remote_komoju_test.rb @@ -14,10 +14,10 @@ def setup :order_id => generate_unique_id, :description => 'Store Purchase', :tax => '10.0', - :ip => "192.168.0.1", - :email => "valid@email.com", - :browser_language => "en", - :browser_user_agent => "user_agent" + :ip => '192.168.0.1', + :email => 'valid@email.com', + :browser_language => 'en', + :browser_user_agent => 'user_agent' } end @@ -27,7 +27,7 @@ def test_successful_credit_card_purchase assert response.authorization.present? assert_equal 'Transaction succeeded', response.message assert_equal 100, response.params['amount'] - assert_equal "1111", response.params['payment_details']['last_four_digits'] + assert_equal '1111', response.params['payment_details']['last_four_digits'] assert_equal true, response.params['captured_at'].present? end @@ -37,7 +37,7 @@ def test_successful_credit_card_purchase_with_minimal_options assert response.authorization.present? assert_equal 'Transaction succeeded', response.message assert_equal 100, response.params['amount'] - assert_equal "1111", response.params['payment_details']['last_four_digits'] + assert_equal '1111', response.params['payment_details']['last_four_digits'] assert_equal true, response.params['captured_at'].present? end diff --git a/test/remote/gateways/remote_kushki_test.rb b/test/remote/gateways/remote_kushki_test.rb index 79fa277a664..b4eb060de00 100644 --- a/test/remote/gateways/remote_kushki_test.rb +++ b/test/remote/gateways/remote_kushki_test.rb @@ -4,7 +4,7 @@ class RemoteKushkiTest < Test::Unit::TestCase def setup @gateway = KushkiGateway.new(fixtures(:kushki)) @amount = 100 - @credit_card = credit_card('4000100011112224', verification_value: "777") + @credit_card = credit_card('4000100011112224', verification_value: '777') @declined_card = credit_card('4000300011112220') end @@ -17,12 +17,12 @@ def test_successful_purchase def test_successful_purchase_with_options options = { - currency: "USD", + currency: 'USD', amount: { - subtotal_iva_0: "4.95", - subtotal_iva: "10", - iva: "1.54", - ice: "3.50" + subtotal_iva_0: '4.95', + subtotal_iva: '10', + iva: '1.54', + ice: '3.50' } } @@ -42,7 +42,7 @@ def test_successful_purchase_with_options def test_failed_purchase options = { amount: { - subtotal_iva: "200" + subtotal_iva: '200' } } @@ -51,37 +51,37 @@ def test_failed_purchase assert_equal 'Monto de la transacción es diferente al monto de la venta inicial', response.message end - def test_successful_void - options = { - amount: { - subtotal_iva_0: "4.95", - subtotal_iva: "10", - iva: "1.54", - ice: "3.50" - } - } - amount = 100 * ( - options[:amount][:subtotal_iva_0].to_f + - options[:amount][:subtotal_iva].to_f + - options[:amount][:iva].to_f + - options[:amount][:ice].to_f - ) + def test_successful_refund + purchase = @gateway.purchase(@amount, @credit_card) + assert_success purchase - purchase = @gateway.purchase(amount, @credit_card, options) + assert refund = @gateway.refund(@amount, purchase.authorization) + assert_success refund + assert_equal 'Succeeded', refund.message + end + + def test_failed_refund + purchase = @gateway.purchase(@amount, @credit_card) assert_success purchase - assert void = @gateway.void(purchase.authorization, options) - assert_success void - assert_equal 'Succeeded', void.message + assert refund = @gateway.refund(@amount, nil) + assert_failure refund + assert_equal 'Missing Authentication Token', refund.message end - def test_failed_void + def test_successful_void purchase = @gateway.purchase(@amount, @credit_card) assert_success purchase - response = @gateway.void(purchase.authorization) + assert void = @gateway.void(purchase.authorization) + assert_success void + assert_equal 'Succeeded', void.message + end + + def test_failed_void + response = @gateway.void('000') assert_failure response - assert_equal 'El monto es zero', response.message + assert_equal 'El monto de la transacción es requerido', response.message end def test_invalid_login diff --git a/test/remote/gateways/remote_latitude19_test.rb b/test/remote/gateways/remote_latitude19_test.rb index c3be83d3013..ac977badebc 100644 --- a/test/remote/gateways/remote_latitude19_test.rb +++ b/test/remote/gateways/remote_latitude19_test.rb @@ -1,12 +1,12 @@ -require "test_helper" +require 'test_helper' class RemoteLatitude19Test < Test::Unit::TestCase def setup @gateway = Latitude19Gateway.new(fixtures(:latitude19)) @amount = 100 - @credit_card = credit_card("4000100011112224", verification_value: "747") - @declined_card = credit_card("0000000000000000") + @credit_card = credit_card('4000100011112224', verification_value: '747') + @declined_card = credit_card('0000000000000000') @options = { order_id: generate_unique_id, @@ -15,7 +15,7 @@ def setup end def test_invalid_login - gateway = Latitude19Gateway.new(account_number: "", configuration_id: "", secret: "") + gateway = Latitude19Gateway.new(account_number: '', configuration_id: '', secret: '') response = gateway.purchase(@amount, @credit_card, @options) assert_failure response end @@ -23,7 +23,7 @@ def test_invalid_login def test_successful_purchase response = @gateway.purchase(@amount, @credit_card, @options) assert_success response - assert_equal "Approved", response.message + assert_equal 'Approved', response.message assert response.test? end @@ -36,12 +36,12 @@ def test_successful_purchase def test_successful_authorize_and_capture response = @gateway.authorize(@amount, @credit_card, @options) assert_success response - assert_equal "Approved", response.message + assert_equal 'Approved', response.message assert_match %r(^auth\|\w+$), response.authorization capture = @gateway.capture(@amount, response.authorization, @options) assert_success capture - assert_equal "Approved", capture.message + assert_equal 'Approved', capture.message end # def test_failed_authorize @@ -52,11 +52,11 @@ def test_successful_authorize_and_capture # end def test_failed_capture - authorization = "auth" + "|" + SecureRandom.hex(6) + authorization = 'auth' + '|' + SecureRandom.hex(6) response = @gateway.capture(@amount, authorization, @options) assert_failure response - assert_equal "Not submitted", response.message - assert_equal "400", response.error_code + assert_equal 'Not submitted', response.message + assert_equal '400', response.error_code end def test_successful_void @@ -65,7 +65,7 @@ def test_successful_void void = @gateway.void(auth.authorization, @options) assert_success void - assert_equal "Approved", void.message + assert_equal 'Approved', void.message # response = @gateway.authorize(@amount, @credit_card, @options) # assert_success response @@ -84,25 +84,25 @@ def test_successful_void void = @gateway.void(purchase.authorization, @options) assert_success void - assert_equal "Approved", void.message + assert_equal 'Approved', void.message end def test_failed_void auth = @gateway.authorize(@amount, @credit_card, @options) assert_success auth - authorization = auth.authorization[0..9] + "XX" + authorization = auth.authorization[0..9] + 'XX' response = @gateway.void(authorization, @options) assert_failure response - assert_equal "Not submitted", response.message - assert_equal "400", response.error_code + assert_equal 'Not submitted', response.message + assert_equal '400', response.error_code end def test_successful_credit response = @gateway.credit(@amount, @credit_card, @options) assert_success response - assert_equal "Approved", response.message + assert_equal 'Approved', response.message end # def test_failed_credit @@ -114,7 +114,7 @@ def test_successful_credit def test_successful_verify response = @gateway.verify(@credit_card, @options) assert_success response - assert_equal "Approved", response.message + assert_equal 'Approved', response.message end # def test_failed_verify @@ -127,19 +127,19 @@ def test_successful_verify def test_successful_store store = @gateway.store(@credit_card, @options) assert_success store - assert_equal "Approved", store.message + assert_equal 'Approved', store.message purchase = @gateway.purchase(@amount, store.authorization, @options) assert_success purchase - assert_equal "Approved", purchase.message + assert_equal 'Approved', purchase.message credit = @gateway.credit(@amount, store.authorization, @options) assert_success credit - assert_equal "Approved", credit.message + assert_equal 'Approved', credit.message verify = @gateway.verify(store.authorization, @options) assert_success verify - assert_equal "Approved", verify.message + assert_equal 'Approved', verify.message end # def test_failed_store diff --git a/test/remote/gateways/remote_linkpoint_test.rb b/test/remote/gateways/remote_linkpoint_test.rb index 8ad9a942e6f..1a51911712d 100644 --- a/test/remote/gateways/remote_linkpoint_test.rb +++ b/test/remote/gateways/remote_linkpoint_test.rb @@ -44,7 +44,7 @@ def test_successful_authorization assert_instance_of Response, response assert_success response - assert_equal "APPROVED", response.params["approved"] + assert_equal 'APPROVED', response.params['approved'] end def test_successful_authorization_and_capture @@ -62,15 +62,15 @@ def test_successful_purchase_without_cvv2_code assert response = @gateway.purchase(@amount, @credit_card, @options) assert_success response - assert_equal "APPROVED", response.params["approved"] - assert_equal 'NNN', response.params["avs"] + assert_equal 'APPROVED', response.params['approved'] + assert_equal 'NNN', response.params['avs'] end def test_successful_purchase_with_cvv2_code assert response = @gateway.purchase(@amount, @credit_card, @options) assert_success response - assert_equal "APPROVED", response.params["approved"] - assert_equal 'NNNM', response.params["avs"] + assert_equal 'APPROVED', response.params['approved'] + assert_equal 'NNNM', response.params['avs'] end def test_successful_purchase_and_void @@ -90,33 +90,33 @@ def test_successfull_purchase_and_credit end def test_successfull_purchase_with_item_entity - @options.merge!({:line_items => [ - {:id => '123456', :description => "Logo T-Shirt", :price => "12.00", :quantity => '1', :options => - [{:name => "Color", :value => "Red"}, {:name => "Size", :value => "XL"}]}, - {:id => '111', :description => "keychain", :price => "3.00", :quantity => '1'}]}) + @options[:line_items] = [ + {:id => '123456', :description => 'Logo T-Shirt', :price => '12.00', :quantity => '1', + :options => [{:name => 'Color', :value => 'Red'}, {:name => 'Size', :value => 'XL'}]}, + {:id => '111', :description => 'keychain', :price => '3.00', :quantity => '1'} + ] assert purchase = @gateway.purchase(1500, @credit_card, @options) assert_success purchase - end def test_successful_recurring_payment assert response = @gateway.recurring(2400, @credit_card, :order_id => generate_unique_id, :installments => 12, - :startdate => "immediate", + :startdate => 'immediate', :periodicity => :monthly, :billing_address => address ) assert_success response - assert_equal "APPROVED", response.params["approved"] + assert_equal 'APPROVED', response.params['approved'] end def test_declined_purchase_with_invalid_credit_card @credit_card.number = '1111111111111111' assert response = @gateway.purchase(@amount, @credit_card, @options) assert_failure response - assert_equal "DECLINED", response.params["approved"] + assert_equal 'DECLINED', response.params['approved'] end def test_cleans_whitespace_from_pem diff --git a/test/remote/gateways/remote_litle_certification_test.rb b/test/remote/gateways/remote_litle_certification_test.rb index 1c55f9b3182..3a9558c701f 100644 --- a/test/remote/gateways/remote_litle_certification_test.rb +++ b/test/remote/gateways/remote_litle_certification_test.rb @@ -3,14 +3,15 @@ class RemoteLitleCertification < Test::Unit::TestCase def setup Base.mode = :test - @gateway = LitleGateway.new(fixtures(:litle).merge(:url => "https://cert.litle.com/vap/communicator/online")) + @gateway = LitleGateway.new(fixtures(:litle)) + @gateway.test_url = 'https://payments.vantivprelive.com/vap/communicator/online' end def test1 credit_card = CreditCard.new( :number => '4457010000000009', :month => '01', - :year => '2014', + :year => '2021', :verification_value => '349', :brand => 'visa' ) @@ -18,7 +19,7 @@ def test1 options = { :order_id => '1', :billing_address => { - :name => 'John Smith', + :name => 'John & Mary Smith', :address1 => '1 Main St.', :city => 'Burlington', :state => 'MA', @@ -27,24 +28,24 @@ def test1 } } - auth_assertions(10010, credit_card, options, :avs => "X", :cvv => "M") + auth_assertions(10100, credit_card, options, :avs => 'X', :cvv => 'M') - # 1: authorize avs - authorize_avs_assertions(credit_card, options, :avs => "X", :cvv => "M") + authorize_avs_assertions(credit_card, options, :avs => 'X', :cvv => 'M') - sale_assertions(10010, credit_card, options, :avs => "X", :cvv => "M") + sale_assertions(10100, credit_card, options, :avs => 'X', :cvv => 'M') end def test2 credit_card = CreditCard.new(:number => '5112010000000003', :month => '02', - :year => '2014', :brand => 'master', - :verification_value => '261') + :year => '2021', :brand => 'master', + :verification_value => '261', + :name => 'Mike J. Hammer') options = { :order_id => '2', :billing_address => { - :name => 'Mike J. Hammer', :address1 => '2 Main St.', + :address2 => 'Apt. 222', :city => 'Riverside', :state => 'RI', :zip => '02915', @@ -52,19 +53,18 @@ def test2 } } - auth_assertions(20020, credit_card, options, :avs => "Z", :cvv => "M") + auth_assertions(10100, credit_card, options, :avs => 'Z', :cvv => 'M') - # 2: authorize avs - authorize_avs_assertions(credit_card, options, :avs => "Z", :cvv => "M") + authorize_avs_assertions(credit_card, options, :avs => 'Z', :cvv => 'M') - sale_assertions(20020, credit_card, options, :avs => "Z", :cvv => "M") + sale_assertions(10100, credit_card, options, :avs => 'Z', :cvv => 'M') end def test3 credit_card = CreditCard.new( :number => '6011010000000003', :month => '03', - :year => '2014', + :year => '2021', :verification_value => '758', :brand => 'discover' ) @@ -80,19 +80,18 @@ def test3 :country => 'US' } } - auth_assertions(30030, credit_card, options, :avs => "Z", :cvv => "M") + auth_assertions(10100, credit_card, options, :avs => 'Z', :cvv => 'M') - # 3: authorize avs - authorize_avs_assertions(credit_card, options, :avs => "Z", :cvv => "M") + authorize_avs_assertions(credit_card, options, :avs => 'Z', :cvv => 'M') - sale_assertions(30030, credit_card, options, :avs => "Z", :cvv => "M") + sale_assertions(10100, credit_card, options, :avs => 'Z', :cvv => 'M') end def test4 credit_card = CreditCard.new( :number => '375001000000005', :month => '04', - :year => '2014', + :year => '2021', :brand => 'american_express' ) @@ -108,17 +107,37 @@ def test4 } } - auth_assertions(40040, credit_card, options, :avs => "A", :cvv => nil) + auth_assertions(10100, credit_card, options, :avs => 'A', :cvv => nil) + + authorize_avs_assertions(credit_card, options, :avs => 'A') + + sale_assertions(10100, credit_card, options, :avs => 'A', :cvv => nil) + end + + def test5 + credit_card = ActiveMerchant::Billing::NetworkTokenizationCreditCard.new( + :number => '4100200300011001', + :month => '05', + :year => '2021', + :verification_value => '463', + :brand => 'visa', + :payment_cryptogram => 'BwABBJQ1AgAAAAAgJDUCAAAAAAA=' + ) + + options = { + :order_id => '5' + } + + auth_assertions(10100, credit_card, options, :avs => 'U', :cvv => 'M') - # 4: authorize avs - authorize_avs_assertions(credit_card, options, :avs => "A") + authorize_avs_assertions(credit_card, options, :avs => 'U', :cvv => 'M') - sale_assertions(40040, credit_card, options, :avs => "A", :cvv => nil) + sale_assertions(10100, credit_card, options, :avs => 'U', :cvv => 'M') end def test6 credit_card = CreditCard.new(:number => '4457010100000008', :month => '06', - :year => '2014', :brand => 'visa', + :year => '2021', :brand => 'visa', :verification_value => '992') options = { @@ -134,30 +153,33 @@ def test6 } # 6: authorize - assert response = @gateway.authorize(60060, credit_card, options) + assert response = @gateway.authorize(10100, credit_card, options) assert !response.success? - assert_equal '110', response.params['litleOnlineResponse']['authorizationResponse']['response'] + assert_equal '110', response.params['response'] assert_equal 'Insufficient Funds', response.message - assert_equal "I", response.avs_result["code"] - assert_equal "P", response.cvv_result["code"] + assert_equal 'I', response.avs_result['code'] + assert_equal 'P', response.cvv_result['code'] + puts "Test #{options[:order_id]} Authorize: #{txn_id(response)}" # 6. sale - assert response = @gateway.purchase(60060, credit_card, options) + assert response = @gateway.purchase(10100, credit_card, options) assert !response.success? - assert_equal '110', response.params['litleOnlineResponse']['saleResponse']['response'] + assert_equal '110', response.params['response'] assert_equal 'Insufficient Funds', response.message - assert_equal "I", response.avs_result["code"] - assert_equal "P", response.cvv_result["code"] + assert_equal 'I', response.avs_result['code'] + assert_equal 'P', response.cvv_result['code'] + puts "Test #{options[:order_id]} Sale: #{txn_id(response)}" # 6A. void assert response = @gateway.void(response.authorization, {:order_id => '6A'}) - assert_equal '360', response.params['litleOnlineResponse']['voidResponse']['response'] - assert_equal 'No transaction found with specified litleTxnId', response.message + assert_equal '360', response.params['response'] + assert_equal 'No transaction found with specified transaction Id', response.message + puts "Test #{options[:order_id]}A: #{txn_id(response)}" end def test7 credit_card = CreditCard.new(:number => '5112010100000002', :month => '07', - :year => '2014', :brand => 'master', + :year => '2021', :brand => 'master', :verification_value => '251') options = { @@ -173,28 +195,30 @@ def test7 } # 7: authorize - assert response = @gateway.authorize(70070, credit_card, options) + assert response = @gateway.authorize(10100, credit_card, options) assert !response.success? - assert_equal '301', response.params['litleOnlineResponse']['authorizationResponse']['response'] + assert_equal '301', response.params['response'] assert_equal 'Invalid Account Number', response.message - assert_equal "I", response.avs_result["code"] - assert_equal "N", response.cvv_result["code"] + assert_equal 'I', response.avs_result['code'] + assert_equal 'N', response.cvv_result['code'] + puts "Test #{options[:order_id]} Authorize: #{txn_id(response)}" # 7: authorize avs - authorize_avs_assertions(credit_card, options, :avs => "I", :cvv => "N", :message => "Invalid Account Number", :success => false) + authorize_avs_assertions(credit_card, options, :avs => 'I', :cvv => 'N', :message => 'Invalid Account Number', :success => false) # 7. sale - assert response = @gateway.purchase(70070, credit_card, options) + assert response = @gateway.purchase(10100, credit_card, options) assert !response.success? - assert_equal '301', response.params['litleOnlineResponse']['saleResponse']['response'] + assert_equal '301', response.params['response'] assert_equal 'Invalid Account Number', response.message - assert_equal "I", response.avs_result["code"] - assert_equal "N", response.cvv_result["code"] + assert_equal 'I', response.avs_result['code'] + assert_equal 'N', response.cvv_result['code'] + puts "Test #{options[:order_id]} Sale: #{txn_id(response)}" end def test8 credit_card = CreditCard.new(:number => '6011010100000002', :month => '08', - :year => '2014', :brand => 'discover', + :year => '2021', :brand => 'discover', :verification_value => '184') options = { @@ -210,28 +234,30 @@ def test8 } # 8: authorize - assert response = @gateway.authorize(80080, credit_card, options) + assert response = @gateway.authorize(10100, credit_card, options) assert !response.success? - assert_equal '123', response.params['litleOnlineResponse']['authorizationResponse']['response'] + assert_equal '123', response.params['response'] assert_equal 'Call Discover', response.message - assert_equal "I", response.avs_result["code"] - assert_equal "P", response.cvv_result["code"] + assert_equal 'I', response.avs_result['code'] + assert_equal 'P', response.cvv_result['code'] + puts "Test #{options[:order_id]} Authorize: #{txn_id(response)}" # 8: authorize avs - authorize_avs_assertions(credit_card, options, :avs => "I", :cvv => "P", :message => "Call Discover", :success => false) + authorize_avs_assertions(credit_card, options, :avs => 'I', :cvv => 'P', :message => 'Call Discover', :success => false) # 8: sale assert response = @gateway.purchase(80080, credit_card, options) assert !response.success? - assert_equal '123', response.params['litleOnlineResponse']['saleResponse']['response'] + assert_equal '123', response.params['response'] assert_equal 'Call Discover', response.message - assert_equal "I", response.avs_result["code"] - assert_equal "P", response.cvv_result["code"] + assert_equal 'I', response.avs_result['code'] + assert_equal 'P', response.cvv_result['code'] + puts "Test #{options[:order_id]} Sale: #{txn_id(response)}" end def test9 credit_card = CreditCard.new(:number => '375001010000003', :month => '09', - :year => '2014', :brand => 'american_express', + :year => '2021', :brand => 'american_express', :verification_value => '0421') options = { @@ -247,92 +273,597 @@ def test9 } # 9: authorize - assert response = @gateway.authorize(90090, credit_card, options) - + assert response = @gateway.authorize(10100, credit_card, options) assert !response.success? - assert_equal '303', response.params['litleOnlineResponse']['authorizationResponse']['response'] + assert_equal '303', response.params['response'] assert_equal 'Pick Up Card', response.message - assert_equal "I", response.avs_result["code"] + assert_equal 'I', response.avs_result['code'] + puts "Test #{options[:order_id]} Authorize: #{txn_id(response)}" # 9: authorize avs - authorize_avs_assertions(credit_card, options, :avs => "I", :message => "Pick Up Card", :success => false) + authorize_avs_assertions(credit_card, options, :avs => 'I', :message => 'Pick Up Card', :success => false) # 9: sale - assert response = @gateway.purchase(90090, credit_card, options) + assert response = @gateway.purchase(10100, credit_card, options) assert !response.success? - assert_equal '303', response.params['litleOnlineResponse']['saleResponse']['response'] + assert_equal '303', response.params['response'] assert_equal 'Pick Up Card', response.message - assert_equal "I", response.avs_result["code"] + assert_equal 'I', response.avs_result['code'] + puts "Test #{options[:order_id]} Sale: #{txn_id(response)}" end # Authorization Reversal Tests + def test32 + credit_card = CreditCard.new(:number => '4457010000000009', :month => '01', + :year => '2021', :brand => 'visa', + :verification_value => '349') + + options = { + :order_id => '32', + :billing_address => { + :name => 'John Smith', + :address1 => '1 Main St.', + :city => 'Burlington', + :state => 'MA', + :zip => '01803-3747', + :country => 'US' + } + } + + assert auth_response = @gateway.authorize(10010, credit_card, options) + assert_success auth_response + assert_equal '11111 ', auth_response.params['authCode'] + puts "Test #{options[:order_id]}: #{txn_id(auth_response)}" + + assert capture_response = @gateway.capture(5050, auth_response.authorization, options) + assert_success capture_response + puts "Test #{options[:order_id]}A: #{txn_id(capture_response)}" + + assert reversal_response = @gateway.void(auth_response.authorization, options) + assert_failure reversal_response + assert 'Authorization amount has already been depleted', reversal_response.message + puts "Test #{options[:order_id]}B: #{txn_id(reversal_response)}" + end + + def test33 + credit_card = CreditCard.new(:number => '5112010000000003', :month => '01', + :year => '2021', :brand => 'master', + :verification_value => '261') + + options = { + :order_id => '33', + :billing_address => { + :name => 'Mike J. Hammer', + :address1 => '2 Main St.', + :address2 => 'Apt. 222', + :city => 'Riverside', + :state => 'RI', + :zip => '02915', + :country => 'US', + :payment_cryptogram => 'BwABBJQ1AgAAAAAgJDUCAAAAAAA=' + } + } + + assert auth_response = @gateway.authorize(20020, credit_card, options) + assert_success auth_response + assert_equal '22222 ', auth_response.params['authCode'] + puts "Test #{options[:order_id]}: #{txn_id(auth_response)}" + + assert reversal_response = @gateway.void(auth_response.authorization, options) + assert_success reversal_response + puts "Test #{options[:order_id]}A: #{txn_id(reversal_response)}" + end + def test34 - credit_card = CreditCard.new(:number => '6011010000000003', :month => '03', - :year => '2014', :brand => 'discover', + credit_card = CreditCard.new(:number => '6011010000000003', :month => '01', + :year => '2021', :brand => 'discover', :verification_value => '758') options = { - :order_id => '34', - :billing_address => { - :name => 'Eileen Jones', - :address1 => '3 Main St.', - :city => 'Bloomfield', - :state => 'CT', - :zip => '06002', - :country => 'US' - } + :order_id => '34', + :billing_address => { + :name => 'Eileen Jones', + :address1 => '3 Main St.', + :city => 'Bloomfield', + :state => 'CT', + :zip => '06002', + :country => 'US' + } } assert auth_response = @gateway.authorize(30030, credit_card, options) assert_success auth_response + assert '33333 ', auth_response.params['authCode'] + puts "Test #{options[:order_id]}: #{txn_id(auth_response)}" - credit_card = CreditCard.new(:number => '4024720001231239', :month => '12', - :year => '2014', :brand => 'visa') - assert auth_response2 = @gateway.authorize(18699, credit_card, :order_id => '29') - - assert reversal_response = @gateway.void(auth_response2.authorization) + assert reversal_response = @gateway.void(auth_response.authorization, options) assert_success reversal_response + puts "Test #{options[:order_id]}A: #{txn_id(reversal_response)}" end - def test36 + def test35 + credit_card = CreditCard.new(:number => '375001000000005', :month => '01', + :year => '2021', :brand => 'american_express') + options = { - :order_id => '36' + :order_id => '35', + :billing_address => { + :name => 'Bob Black', + :address1 => '4 Main St.', + :city => 'Laurel', + :state => 'MD', + :zip => '20708', + :country => 'US' + } } - credit_card = CreditCard.new(:number => '375000026600004', :month => '05', - :year => '2014', :brand => 'american_express', - :verification_value => '261') + assert auth_response = @gateway.authorize(10100, credit_card, options) + assert_success auth_response + assert_equal '44444 ', auth_response.params['authCode'] + assert_equal 'A', auth_response.avs_result['code'] + puts "Test #{options[:order_id]}: #{txn_id(auth_response)}" + + assert capture_response = @gateway.capture(5050, auth_response.authorization, options) + assert_success capture_response + puts "Test #{options[:order_id]}A: #{txn_id(capture_response)}" + + assert reversal_response = @gateway.void(auth_response.authorization, options) + assert_failure reversal_response + assert 'Reversal amount does not match Authorization amount', reversal_response.message + puts "Test #{options[:order_id]}B: #{txn_id(reversal_response)}" + end + + def test36 + credit_card = CreditCard.new(:number => '375000026600004', :month => '01', + :year => '2021', :brand => 'american_express') + + options = { + :order_id => '36' + } assert auth_response = @gateway.authorize(20500, credit_card, options) assert_success auth_response + puts "Test #{options[:order_id]}: #{txn_id(auth_response)}" + + assert reversal_response = @gateway.void(auth_response.authorization, options) + assert_failure reversal_response + assert 'Reversal amount does not match Authorization amount', reversal_response.message + puts "Test #{options[:order_id]}A: #{txn_id(reversal_response)}" + end + + # Echeck + def test37 + check = check( + name: 'Tom Black', + routing_number: '053100300', + account_number: '10@BC99999', + account_type: 'Checking' + ) + options = { + :order_id => '37', + :billing_address => { + :name => 'Tom Black', + :address1 => '8 Main St.', + :city => 'Manchester', + :state => 'NH', + :zip => '03101', + :country => 'US', + :email => 'test@test.com', + :phone => '2233334444' + } + } + assert auth_response = @gateway.authorize(3001, check, options) + assert_failure auth_response + assert_equal 'Invalid Account Number', auth_response.message + assert_equal '301', auth_response.params['response'] + puts "Test #{options[:order_id]}: #{txn_id(auth_response)}" + end + + def test38 + check = check( + name: 'John Smith', + routing_number: '011075150', + account_number: '1099999999', + account_type: 'Checking' + ) + options = { + :order_id => '38', + :billing_address => { + :name => 'John Smith', + :address1 => '8 Main St.', + :city => 'Manchester', + :state => 'NH', + :zip => '03101', + :country => 'US', + :email => 'test@test.com', + :phone => '2233334444' + } + } + assert auth_response = @gateway.authorize(3002, check, options) + assert_success auth_response + assert_equal 'Approved', auth_response.message + assert_equal '000', auth_response.params['response'] + puts "Test #{options[:order_id]}: #{txn_id(auth_response)}" + end - assert reversal_response = @gateway.void(auth_response.authorization, amount: 10000) - assert !reversal_response.success? - assert_equal '336', reversal_response.params['litleOnlineResponse']['authReversalResponse']['response'] + def test39 + check = check( + name: 'Robert Jones', + routing_number: '053100300', + account_number: '3099999999', + account_type: 'Corporate' + ) + options = { + :order_id => '39', + :billing_address => { + :name => 'John Smith', + :address1 => '8 Main St.', + :city => 'Manchester', + :state => 'NH', + :zip => '03101', + :country => 'US', + :company => 'Good Goods Inc', + :email => 'test@test.com', + :phone => '2233334444' + } + } + assert auth_response = @gateway.authorize(3003, check, options) + assert_failure auth_response + assert_equal 'Decline - Negative Information on File', auth_response.message + assert_equal '950', auth_response.params['response'] + puts "Test #{options[:order_id]}: #{txn_id(auth_response)}" + end + + def test40 + declined_authorize_check = check( + name: 'Peter Green', + routing_number: '011075150', + account_number: '8099999999', + account_type: 'Corporate' + ) + options = { + :order_id => '40', + :billing_address => { + :name => 'Peter Green', + :address1 => '8 Main St.', + :city => 'Manchester', + :state => 'NH', + :zip => '03101', + :country => 'US', + :company => 'Green Co', + :email => 'test@test.com', + :phone => '2233334444' + } + } + assert auth_response = @gateway.authorize(3004, declined_authorize_check, options) + assert_failure auth_response + assert_equal 'Absolute Decline', auth_response.message + assert_equal '951', auth_response.params['response'] + puts "Test #{options[:order_id]}: #{txn_id(auth_response)}" + end + + def test41 + check = check( + name: 'Mike Hammer', + routing_number: '053100300', + account_number: '10@BC99999', + account_type: 'Checking' + ) + options = { + :order_id => '41', + :billing_address => { + :name => 'Mike Hammer', + :address1 => '8 Main St.', + :city => 'Manchester', + :state => 'NH', + :zip => '03101', + :country => 'US', + :email => 'test@test.com', + :phone => '2233334444' + } + } + assert purchase_response = @gateway.purchase(2008, check, options) + assert_failure purchase_response + assert_equal 'Invalid Account Number', purchase_response.message + assert_equal '301', purchase_response.params['response'] + puts "Test #{options[:order_id]}: #{txn_id(purchase_response)}" + end + + def test42 + check = check( + name: 'Tom Black', + routing_number: '011075150', + account_number: '4099999992', + account_type: 'Checking' + ) + options = { + :order_id => '42', + :billing_address => { + :name => 'Tom Black', + :address1 => '8 Main St.', + :city => 'Manchester', + :state => 'NH', + :zip => '03101', + :country => 'US', + :email => 'test@test.com', + :phone => '2233334444' + } + } + assert purchase_response = @gateway.purchase(2004, check, options) + assert_success purchase_response + assert_equal 'Approved', purchase_response.message + assert_equal '000', purchase_response.params['response'] + puts "Test #{options[:order_id]}: #{txn_id(purchase_response)}" + end + + def test43 + check = check( + name: 'Peter Green', + routing_number: '011075150', + account_number: '6099999992', + account_type: 'Corporate' + ) + options = { + :order_id => '43', + :billing_address => { + :name => 'Peter Green', + :address1 => '8 Main St.', + :city => 'Manchester', + :state => 'NH', + :zip => '03101', + :country => 'US', + :company => 'Green Co', + :email => 'test@test.com', + :phone => '2233334444' + } + } + assert purchase_response = @gateway.purchase(2007, check, options) + assert_success purchase_response + assert_equal 'Approved', purchase_response.message + assert_equal '000', purchase_response.params['response'] + puts "Test #{options[:order_id]}: #{txn_id(purchase_response)}" + end + + def test44 + check = check( + name: 'Peter Green', + routing_number: '053133052', + account_number: '9099999992', + account_type: 'Corporate' + ) + options = { + :order_id => '44', + :billing_address => { + :name => 'Peter Green', + :address1 => '8 Main St.', + :city => 'Manchester', + :state => 'NH', + :zip => '03101', + :country => 'US', + :company => 'Green Co', + :email => 'test@test.com', + :phone => '2233334444' + } + } + assert purchase_response = @gateway.purchase(2009, check, options) + assert_failure purchase_response + assert_equal 'Invalid Bank Routing Number', purchase_response.message + assert_equal '900', purchase_response.params['response'] + puts "Test #{options[:order_id]}: #{txn_id(purchase_response)}" + end + + def test45 + check = check( + name: 'John Smith', + routing_number: '053100300', + account_number: '10@BC99999', + account_type: 'Checking' + ) + options = { + :order_id => '45', + :billing_address => { + :name => 'John Smith', + :address1 => '8 Main St.', + :city => 'Manchester', + :state => 'NH', + :zip => '03101', + :country => 'US', + :email => 'test@test.com', + :phone => '2233334444' + } + } + assert refund_response = @gateway.refund(1001, check, options) + assert_failure refund_response + assert_equal 'Invalid Account Number', refund_response.message + assert_equal '301', refund_response.params['response'] + puts "Test #{options[:order_id]}: #{txn_id(refund_response)}" + end + + def test46 + check = check( + name: 'Robert Jones', + routing_number: '011075150', + account_number: '3099999999', + account_type: 'Corporate' + ) + options = { + :order_id => '46', + :order_source => 'telephone', + :billing_address => { + :name => 'Robert Jones', + :address1 => '8 Main St.', + :city => 'Manchester', + :state => 'NH', + :zip => '03101', + :country => 'US', + :email => 'test@test.com', + :phone => '2233334444', + :company => 'Widget Inc' + } + } + assert purchase_response = @gateway.purchase(1003, check, options) + sleep(10) + assert refund_response = @gateway.refund(1003, purchase_response.authorization, options) + assert_success refund_response + assert_equal 'Approved', refund_response.message + assert_equal '000', refund_response.params['response'] + puts "Test #{options[:order_id]}: #{txn_id(refund_response)}" + end + + def test47 + check = check( + name: 'Peter Green', + routing_number: '211370545', + account_number: '6099999993', + account_type: 'Corporate' + ) + options = { + :order_id => '47', + :billing_address => { + :name => 'Peter Green', + :address1 => '8 Main St.', + :city => 'Manchester', + :state => 'NH', + :zip => '03101', + :country => 'US', + :company => 'Green Co', + :email => 'test@test.com', + :phone => '2233334444' + } + } + assert purchase_response = @gateway.purchase(1007, check, options) + assert refund_response = @gateway.refund(1007, purchase_response.authorization, options) + assert_success refund_response + assert_equal 'Approved', refund_response.message + assert_equal '000', refund_response.params['response'] + puts "Test #{options[:order_id]}: #{txn_id(refund_response)}" + end + + def test48 + check = check( + name: 'Peter Green', + routing_number: '011075150', + account_number: '6099999992', + account_type: 'Corporate' + ) + options = { + :order_id => '43', + :billing_address => { + :name => 'Peter Green', + :address1 => '8 Main St.', + :city => 'Manchester', + :state => 'NH', + :zip => '03101', + :country => 'US', + :company => 'Green Co', + :email => 'test@test.com', + :phone => '2233334444' + } + } + assert purchase_response = @gateway.purchase(2007, check, options) + assert_success purchase_response + assert refund_response = @gateway.refund(2007, purchase_response.authorization, options) + assert_equal '000', refund_response.params['response'] + puts "Test 48: #{txn_id(refund_response)}" + end + + def test49 + assert refund_response = @gateway.refund(2007, 2) + assert_failure refund_response + assert_equal '360', refund_response.params['response'] + assert_equal 'No transaction found with specified transaction Id', refund_response.message + puts "Test 49: #{txn_id(refund_response)}" + end + + def test_echeck_void1 + check = check( + name: 'Tom Black', + routing_number: '011075150', + account_number: '4099999992', + account_type: 'Checking' + ) + options = { + :order_id => '42', + :id => '236222', + :billing_address => { + :name => 'Tom Black', + :address1 => '8 Main St.', + :city => 'Manchester', + :state => 'NH', + :zip => '03101', + :country => 'US', + :email => 'test@test.com', + :phone => '2233334444' + } + } + assert purchase_response = @gateway.purchase(2004, check, options) + assert_success purchase_response + sleep(10) + assert void_response = @gateway.void(purchase_response.authorization) + assert_equal '000', void_response.params['response'] + puts "Test void1: #{txn_id(void_response)}" + end + + def test_echeck_void2 + check = check( + name: 'Robert Jones', + routing_number: '011075150', + account_number: '3099999999', + account_type: 'Checking' + ) + options = { + :order_id => '46', + :id => '232222', + :billing_address => { + :name => 'Robert Jones', + :address1 => '8 Main St.', + :city => 'Manchester', + :state => 'NH', + :zip => '03101', + :country => 'US', + :email => 'test@test.com', + :phone => '2233334444' + } + } + assert purchase_response = @gateway.purchase(1003, check, options) + assert_success purchase_response + sleep(20) + assert void_response = @gateway.void(purchase_response.authorization) + assert_equal '000', void_response.params['response'] + puts "Test void2: #{txn_id(void_response)}" + end + + def test_echeck_void3 + assert void_response = @gateway.void(2) + assert_failure void_response + assert_equal '360', void_response.params['response'] + assert_equal 'No transaction found with specified transaction Id', void_response.message + puts "Test void3: #{txn_id(void_response)}" end # Explicit Token Registration Tests def test50 credit_card = CreditCard.new(:number => '4457119922390123') options = { - :order_id => '50' + :order_id => '50' } # store store_response = @gateway.store(credit_card, options) assert_success store_response + assert_equal '445711', store_response.params['bin'] + assert_equal 'VI', store_response.params['type'] + assert_equal '0123', store_response.params['litleToken'][-4, 4] + assert_equal '801', store_response.params['response'] assert_equal 'Account number was successfully registered', store_response.message - assert_equal '445711', store_response.params['litleOnlineResponse']['registerTokenResponse']['bin'] - assert_equal 'VI', store_response.params['litleOnlineResponse']['registerTokenResponse']['type'] #type is on Object in 1.8.7 - later versions can use .registerTokenResponse.type - assert_equal '801', store_response.params['litleOnlineResponse']['registerTokenResponse']['response'] - assert_equal '0123', store_response.params['litleOnlineResponse']['registerTokenResponse']['litleToken'][-4,4] + puts "Test #{options[:order_id]}: #{txn_id(response)}" end def test51 credit_card = CreditCard.new(:number => '4457119999999999') - options = { - :order_id => '51' + options = { + :order_id => '51' } # store @@ -340,14 +871,14 @@ def test51 assert_failure store_response assert_equal 'Credit card number was invalid', store_response.message - assert_equal '820', store_response.params['litleOnlineResponse']['registerTokenResponse']['response'] - assert_equal nil, store_response.params['litleOnlineResponse']['registerTokenResponse']['litleToken'] + assert_equal '820', store_response.params['response'] + assert_equal nil, store_response.params['litleToken'] end def test52 credit_card = CreditCard.new(:number => '4457119922390123') - options = { - :order_id => '52' + options = { + :order_id => '52' } # store @@ -355,10 +886,47 @@ def test52 assert_success store_response assert_equal 'Account number was previously registered', store_response.message - assert_equal '445711', store_response.params['litleOnlineResponse']['registerTokenResponse']['bin'] - assert_equal 'VI', store_response.params['litleOnlineResponse']['registerTokenResponse']['type'] #type is on Object in 1.8.7 - later versions can use .registerTokenResponse.type - assert_equal '802', store_response.params['litleOnlineResponse']['registerTokenResponse']['response'] - assert_equal '0123', store_response.params['litleOnlineResponse']['registerTokenResponse']['litleToken'][-4,4] + assert_equal '445711', store_response.params['bin'] + assert_equal 'VI', store_response.params['type'] + assert_equal '802', store_response.params['response'] + assert_equal '0123', store_response.params['litleToken'][-4, 4] + puts "Test #{options[:order_id]}: #{txn_id(store_response)}" + end + + def test53 + check = check( + routing_number: '011100012', + account_number: '1099999998' + ) + options = { + :order_id => '53' + } + + store_response = @gateway.store(check, options) + + assert_success store_response + assert_equal '998', store_response.params['eCheckAccountSuffix'] + assert_equal 'EC', store_response.params['type'] + assert_equal '801', store_response.params['response'] + assert_equal 'Account number was successfully registered', store_response.message + puts "Test #{options[:order_id]}: #{txn_id(store_response)}" + end + + def test54 + check = check( + routing_number: '1145_7895', + account_number: '1022222102' + ) + options = { + :order_id => '54' + } + + store_response = @gateway.store(check, options) + + assert_failure store_response + assert_equal '900', store_response.params['response'] + assert_equal 'Invalid Bank Routing Number', store_response.message + puts "Test #{options[:order_id]}: #{txn_id(store_response)}" end # Implicit Token Registration Tests @@ -368,23 +936,19 @@ def test55 :year => '2014', :brand => 'master', :verification_value => '987') - options = { - :order_id => '55' + options = { + :order_id => '55' } # authorize assert response = @gateway.authorize(15000, credit_card, options) - #"tokenResponse" => { "litleToken" => "1712000118270196", - # "tokenResponseCode" => "802", - # "tokenMessage" => "Account number was previously registered", - # "type" => "MC", - # "bin" => "543510" } assert_success response assert_equal 'Approved', response.message - assert_equal '0196', response.params['litleOnlineResponse']['authorizationResponse']['tokenResponse']['litleToken'][-4,4] - assert %w(801 802).include? response.params['litleOnlineResponse']['authorizationResponse']['tokenResponse']['tokenResponseCode'] - assert_equal 'MC', response.params['litleOnlineResponse']['authorizationResponse']['tokenResponse']['type'] - assert_equal '543510', response.params['litleOnlineResponse']['authorizationResponse']['tokenResponse']['bin'] + assert_equal '0196', response.params['tokenResponse_litleToken'][-4, 4] + assert %w(801 802).include? response.params['tokenResponse_tokenResponseCode'] + assert_equal 'MC', response.params['tokenResponse_type'] + assert_equal '543510', response.params['tokenResponse_bin'] + puts "Test #{options[:order_id]}: #{txn_id(response)}" end def test56 @@ -393,15 +957,16 @@ def test56 :year => '2014', :brand => 'master', :verification_value => '987') - options = { - :order_id => '56' + options = { + :order_id => '56' } # authorize assert response = @gateway.authorize(15000, credit_card, options) assert_failure response - assert_equal '301', response.params['litleOnlineResponse']['authorizationResponse']['response'] + assert_equal '301', response.params['response'] + puts "Test #{options[:order_id]}: #{txn_id(response)}" end def test57_58 @@ -410,8 +975,8 @@ def test57_58 :year => '2014', :brand => 'master', :verification_value => '987') - options = { - :order_id => '57' + options = { + :order_id => '57' } # authorize card @@ -419,19 +984,20 @@ def test57_58 assert_success response assert_equal 'Approved', response.message - assert_equal '0196', response.params['litleOnlineResponse']['authorizationResponse']['tokenResponse']['litleToken'][-4,4] - assert %w(801 802).include? response.params['litleOnlineResponse']['authorizationResponse']['tokenResponse']['tokenResponseCode'] - assert_equal 'MC', response.params['litleOnlineResponse']['authorizationResponse']['tokenResponse']['type'] - assert_equal '543510', response.params['litleOnlineResponse']['authorizationResponse']['tokenResponse']['bin'] + assert_equal '0196', response.params['tokenResponse_litleToken'][-4, 4] + assert %w(801 802).include? response.params['tokenResponse_tokenResponseCode'] + assert_equal 'MC', response.params['tokenResponse_type'] + assert_equal '543510', response.params['tokenResponse_bin'] + puts "Test #{options[:order_id]}: #{txn_id(response)}" # authorize token - token = response.params['litleOnlineResponse']['authorizationResponse']['tokenResponse']['litleToken'] + token = response.params['tokenResponse_litleToken'] options = { - :order_id => '58', - :token => { - :month => credit_card.month, - :year => credit_card.year - } + :order_id => '58', + :token => { + :month => credit_card.month, + :year => credit_card.year + } } # authorize @@ -439,55 +1005,114 @@ def test57_58 assert_success response assert_equal 'Approved', response.message + puts "Test #{options[:order_id]}: #{txn_id(response)}" end def test59 - token = '1712990000040196' + token = '1111000100092332' options = { - :order_id => '59', - :token => { - :month => '11', - :year => '2014' - } + :order_id => '59', + :token => { + :month => '11', + :year => '2021' + } } # authorize assert response = @gateway.authorize(15000, token, options) assert_failure response - assert_equal '822', response.params['litleOnlineResponse']['authorizationResponse']['response'] + assert_equal '822', response.params['response'] assert_equal 'Token was not found', response.message + puts "Test #{options[:order_id]}: #{txn_id(response)}" end def test60 token = '171299999999999' options = { - :order_id => '60', - :token => { - :month => '11', - :year => '2014' - } + :order_id => '60', + :token => { + :month => '11', + :year => '2014' + } } # authorize assert response = @gateway.authorize(15000, token, options) assert_failure response - assert_equal '823', response.params['litleOnlineResponse']['authorizationResponse']['response'] + assert_equal '823', response.params['response'] assert_equal 'Token was invalid', response.message + puts "Test #{options[:order_id]}: #{txn_id(response)}" + end + + def test_apple_pay_purchase + options = { + :order_id => transaction_id, + } + decrypted_apple_pay = ActiveMerchant::Billing::NetworkTokenizationCreditCard.new( + { + month: '01', + year: '2021', + brand: 'visa', + number: '4457000300000007', + payment_cryptogram: 'BwABBJQ1AgAAAAAgJDUCAAAAAAA=' + }) + + assert response = @gateway.purchase(10010, decrypted_apple_pay, options) + assert_success response + assert_equal 'Approved', response.message + end + + def test_android_pay_purchase + options = { + :order_id => transaction_id, + } + decrypted_android_pay = ActiveMerchant::Billing::NetworkTokenizationCreditCard.new( + { + source: :android_pay, + month: '01', + year: '2021', + brand: 'visa', + number: '4457000300000007', + payment_cryptogram: 'BwABBJQ1AgAAAAAgJDUCAAAAAAA=' + }) + + assert response = @gateway.purchase(10010, decrypted_android_pay, options) + assert_success response + assert_equal 'Approved', response.message + end + + def test_three_d_secure + three_d_secure_assertions('3DS1', '4100200300000004', 'visa', '3dsAuthenticated', '0') + three_d_secure_assertions('3DS2', '4100200300000012', 'visa', '3dsAuthenticated', '1') + three_d_secure_assertions('3DS3', '4100200300000103', 'visa', '3dsAuthenticated', '2') + three_d_secure_assertions('3DS4', '4100200300001002', 'visa', '3dsAuthenticated', 'A') + three_d_secure_assertions('3DS5', '4100200300000020', 'visa', '3dsAuthenticated', '3') + three_d_secure_assertions('3DS6', '4100200300000038', 'visa', '3dsAuthenticated', '4') + three_d_secure_assertions('3DS7', '4100200300000046', 'visa', '3dsAuthenticated', '5') + three_d_secure_assertions('3DS8', '4100200300000053', 'visa', '3dsAuthenticated', '6') + three_d_secure_assertions('3DS9', '4100200300000061', 'visa', '3dsAuthenticated', '7') + three_d_secure_assertions('3DS10', '4100200300000079', 'visa', '3dsAuthenticated', '8') + three_d_secure_assertions('3DS11', '4100200300000087', 'visa', '3dsAuthenticated', '9') + three_d_secure_assertions('3DS12', '4100200300000095', 'visa', '3dsAuthenticated', 'B') + three_d_secure_assertions('3DS13', '4100200300000111', 'visa', '3dsAuthenticated', 'C') + three_d_secure_assertions('3DS14', '4100200300000129', 'visa', '3dsAuthenticated', 'D') + three_d_secure_assertions('3DS15', '5112010200000001', 'master', '3dsAttempted', nil) + three_d_secure_assertions('3DS16', '5112010200000001', 'master', '3dsAttempted', nil) end def test_authorize_and_purchase_and_credit_with_token options = { - :order_id => transaction_id, - :billing_address => { - :name => 'John Smith', - :address1 => '1 Main St.', - :city => 'Burlington', - :state => 'MA', - :zip => '01803-3747', - :country => 'US' - } + :order_id => transaction_id, + :billing_address => { + :name => 'John Smith', + :address1 => '1 Main St.', + :city => 'Burlington', + :state => 'MA', + :zip => '01803-3747', + :country => 'US' + } } credit_card = CreditCard.new(:number => '5435101234510196', @@ -536,63 +1161,71 @@ def test_authorize_and_purchase_and_credit_with_token private - def auth_assertions(amount, card, options, assertions) + def auth_assertions(amount, card, options, assertions={}) # 1: authorize assert response = @gateway.authorize(amount, card, options) assert_success response assert_equal 'Approved', response.message - assert_equal assertions[:avs], response.avs_result["code"] - assert_equal assertions[:cvv], response.cvv_result["code"] if assertions[:cvv] - assert_equal options[:order_id], response.params['litleOnlineResponse']['authorizationResponse']['id'] + assert_equal assertions[:avs], response.avs_result['code'] if assertions[:avs] + assert_equal assertions[:cvv], response.cvv_result['code'] if assertions[:cvv] + assert_equal auth_code(options[:order_id]), response.params['authCode'] # 1A: capture - id = transaction_id - assert response = @gateway.capture(amount, response.authorization, {:id => id}) + assert response = @gateway.capture(amount, response.authorization, {:id => transaction_id}) assert_equal 'Approved', response.message - assert_equal id, response.params['litleOnlineResponse']['captureResponse']['id'] # 1B: credit - id = transaction_id - assert response = @gateway.credit(amount, response.authorization, {:id => id}) + assert response = @gateway.credit(amount, response.authorization, {:id => transaction_id}) assert_equal 'Approved', response.message - assert_equal id, response.params['litleOnlineResponse']['creditResponse']['id'] # 1C: void - id = transaction_id - assert response = @gateway.void(response.authorization, {:id => id}) + assert response = @gateway.void(response.authorization, {:id => transaction_id}) assert_equal 'Approved', response.message - assert_equal id, response.params['litleOnlineResponse']['voidResponse']['id'] end def authorize_avs_assertions(credit_card, options, assertions={}) - assert response = @gateway.authorize(0, credit_card, options) + assert response = @gateway.authorize(000, credit_card, options) assert_equal assertions.key?(:success) ? assertions[:success] : true, response.success? assert_equal assertions[:message] || 'Approved', response.message - assert_equal assertions[:avs], response.avs_result["code"], caller.inspect - assert_equal assertions[:cvv], response.cvv_result["code"], caller.inspect if assertions[:cvv] - assert_equal options[:order_id], response.params['litleOnlineResponse']['authorizationResponse']['id'] + assert_equal assertions[:avs], response.avs_result['code'], caller.inspect + assert_equal assertions[:cvv], response.cvv_result['code'], caller.inspect if assertions[:cvv] end - def sale_assertions(amount, card, options, assertions) + def sale_assertions(amount, card, options, assertions={}) # 1: sale assert response = @gateway.purchase(amount, card, options) assert_success response assert_equal 'Approved', response.message - assert_equal assertions[:avs], response.avs_result["code"] - assert_equal assertions[:cvv], response.cvv_result["code"] if assertions[:cvv] - assert_equal options[:order_id], response.params['litleOnlineResponse']['saleResponse']['id'] + assert_equal assertions[:avs], response.avs_result['code'] if assertions[:avs] + assert_equal assertions[:cvv], response.cvv_result['code'] if assertions[:cvv] + # assert_equal auth_code(options[:order_id]), response.params['authCode'] # 1B: credit - id = transaction_id - assert response = @gateway.credit(amount, response.authorization, {:id => id}) + assert response = @gateway.credit(amount, response.authorization, {:id => transaction_id}) assert_equal 'Approved', response.message - assert_equal id, response.params['litleOnlineResponse']['creditResponse']['id'] # 1C: void - id = transaction_id - assert response = @gateway.void(response.authorization, {:id => id}) + assert response = @gateway.void(response.authorization, {:id => transaction_id}) assert_equal 'Approved', response.message - assert_equal id, response.params['litleOnlineResponse']['voidResponse']['id'] + end + + def three_d_secure_assertions(test_id, card, type, source, result) + credit_card = CreditCard.new(:number => card, :month => '01', + :year => '2021', :brand => type, + :verification_value => '261', + :name => 'Mike J. Hammer') + + options = { + order_id: test_id, + order_source: source, + cavv: 'BwABBJQ1AgAAAAAgJDUCAAAAAAA=', + xid: 'BwABBJQ1AgAAAAAgJDUCAAAAAAA=' + } + + assert response = @gateway.authorize(10100, credit_card, options) + assert_success response + assert_equal result, response.params['fraudResult_authenticationResult'] + puts "Test #{test_id}: #{txn_id(response)}" end def transaction_id @@ -604,4 +1237,12 @@ def transaction_id # minLength = N/A maxLength = 25 generate_unique_id[0, 24] end + + def auth_code(order_id) + order_id * 5 + ' ' + end + + def txn_id(response) + response.authorization.split(';')[0] + end end diff --git a/test/remote/gateways/remote_litle_test.rb b/test/remote/gateways/remote_litle_test.rb index aa3c62ac9c3..6fd3107832f 100644 --- a/test/remote/gateways/remote_litle_test.rb +++ b/test/remote/gateways/remote_litle_test.rb @@ -29,31 +29,56 @@ def setup @credit_card1 = CreditCard.new(@credit_card_hash) @credit_card2 = CreditCard.new( - first_name: "Joe", - last_name: "Green", - month: "06", - year: "2012", - brand: "visa", - number: "4457010100000008", - verification_value: "992" + first_name: 'Joe', + last_name: 'Green', + month: '06', + year: '2012', + brand: 'visa', + number: '4457010100000008', + verification_value: '992' ) @credit_card_nsf = CreditCard.new( - first_name: "Joe", - last_name: "Green", - month: "06", - year: "2012", - brand: "visa", - number: "4488282659650110", - verification_value: "992" + first_name: 'Joe', + last_name: 'Green', + month: '06', + year: '2012', + brand: 'visa', + number: '4488282659650110', + verification_value: '992' ) @decrypted_apple_pay = ActiveMerchant::Billing::NetworkTokenizationCreditCard.new( { month: '01', year: '2012', - brand: "visa", - number: "44444444400009", - payment_cryptogram: "BwABBJQ1AgAAAAAgJDUCAAAAAAA=" + brand: 'visa', + number: '44444444400009', + payment_cryptogram: 'BwABBJQ1AgAAAAAgJDUCAAAAAAA=' }) + @decrypted_android_pay = ActiveMerchant::Billing::NetworkTokenizationCreditCard.new( + { + source: :android_pay, + month: '01', + year: '2021', + brand: 'visa', + number: '4457000300000007', + payment_cryptogram: 'BwABBJQ1AgAAAAAgJDUCAAAAAAA=' + }) + @check = check( + name: 'Tom Black', + routing_number: '011075150', + account_number: '4099999992', + account_type: 'checking' + ) + @authorize_check = check( + name: 'John Smith', + routing_number: '011075150', + account_number: '1099999999', + account_type: 'checking' + ) + @store_check = check( + routing_number: '011100012', + account_number: '1099999998' + ) end def test_successful_authorization @@ -62,10 +87,29 @@ def test_successful_authorization assert_equal 'Approved', response.message end + def test_successful_authorization_with_merchant_data + options = @options.merge( + affiliate: 'some-affiliate', + campaign: 'super-awesome-campaign', + merchant_grouping_id: 'brilliant-group' + ) + assert @gateway.authorize(10010, @credit_card1, options) + end + + def test_successful_authorization_with_echeck + options = @options.merge({ + order_id: '38', + order_source: 'telephone' + }) + assert response = @gateway.authorize(3002, @authorize_check, options) + assert_success response + assert_equal 'Approved', response.message + end + def test_avs_and_cvv_result assert response = @gateway.authorize(10010, @credit_card1, @options) - assert_equal "X", response.avs_result["code"] - assert_equal "M", response.cvv_result["code"] + assert_equal 'X', response.avs_result['code'] + assert_equal 'M', response.cvv_result['code'] end def test_unsuccessful_authorization @@ -109,25 +153,62 @@ def test_successful_purchase_with_debt_repayment_flag assert_equal 'Approved', response.message end + def test_successful_purchase_with_3ds_fields + options = @options.merge({ + order_source: '3dsAuthenticated', + xid: 'BwABBJQ1AgAAAAAgJDUCAAAAAAA=', + cavv: 'BwABBJQ1AgAAAAAgJDUCAAAAAAA=' + }) + assert response = @gateway.purchase(10010, @credit_card1, options) + assert_success response + assert_equal 'Approved', response.message + end + def test_successful_purchase_with_apple_pay assert response = @gateway.purchase(10010, @decrypted_apple_pay) assert_success response assert_equal 'Approved', response.message end + def test_successful_purchase_with_android_pay + assert response = @gateway.purchase(10000, @decrypted_android_pay) + assert_success response + assert_equal 'Approved', response.message + end + + def test_successful_purchase_with_merchant_data + options = @options.merge( + affiliate: 'some-affiliate', + campaign: 'super-awesome-campaign', + merchant_grouping_id: 'brilliant-group' + ) + assert response = @gateway.purchase(10010, @credit_card1, options) + assert_success response + assert_equal 'Approved', response.message + end + + def test_successful_purchase_with_echeck + options = @options.merge({ + order_id: '42', + order_source: 'telephone' + }) + assert response = @gateway.purchase(2004, @check, options) + assert_success response + assert_equal 'Approved', response.message + end + def test_unsuccessful_purchase assert response = @gateway.purchase(60060, @credit_card2, { - :order_id=>'6', - :billing_address=>{ - :name => 'Joe Green', - :address1 => '6 Main St.', - :city => 'Derry', - :state => 'NH', - :zip => '03038', - :country => 'US' - }, - } - ) + :order_id=>'6', + :billing_address=>{ + :name => 'Joe Green', + :address1 => '6 Main St.', + :city => 'Derry', + :state => 'NH', + :zip => '03038', + :country => 'US' + }, + }) assert_failure response assert_equal 'Insufficient Funds', response.message end @@ -150,6 +231,18 @@ def test_authorization_capture_refund_void assert_equal 'Approved', void.message end + def test_void_with_echeck + options = @options.merge({ + order_id: '42', + order_source: 'telephone' + }) + assert sale = @gateway.purchase(2004, @check, options) + + assert void = @gateway.void(sale.authorization) + assert_success void + assert_equal 'Approved', void.message + end + def test_void_authorization assert auth = @gateway.authorize(10010, @credit_card1, @options) @@ -159,7 +252,7 @@ def test_void_authorization end def test_unsuccessful_void - assert void = @gateway.void("123456789012345360;authorization;100") + assert void = @gateway.void('123456789012345360;authorization;100') assert_failure void assert_equal 'No transaction found with specified litleTxnId', void.message end @@ -172,6 +265,18 @@ def test_partial_refund assert_equal 'Approved', refund.message end + def test_partial_refund_with_echeck + options = @options.merge({ + order_id: '82', + order_source: 'telephone' + }) + assert purchase = @gateway.purchase(2004, @check, options) + + assert refund = @gateway.refund(444, purchase.authorization) + assert_success refund + assert_equal 'Approved', refund.message + end + def test_partial_capture assert auth = @gateway.authorize(10010, @credit_card1, @options) assert_success auth @@ -203,19 +308,19 @@ def test_nil_amount_capture end def test_capture_unsuccessful - assert capture_response = @gateway.capture(10010, 123456789012345360) + assert capture_response = @gateway.capture(10010, '123456789012345360') assert_failure capture_response assert_equal 'No transaction found with specified litleTxnId', capture_response.message end def test_refund_unsuccessful - assert credit_response = @gateway.refund(10010, 123456789012345360) + assert credit_response = @gateway.refund(10010, '123456789012345360') assert_failure credit_response assert_equal 'No transaction found with specified litleTxnId', credit_response.message end def test_void_unsuccessful - assert void_response = @gateway.void(123456789012345360) + assert void_response = @gateway.void('123456789012345360') assert_failure void_response assert_equal 'No transaction found with specified litleTxnId', void_response.message end @@ -233,7 +338,7 @@ def test_store_successful end def test_store_with_paypage_registration_id_successful - paypage_registration_id = "cDZJcmd1VjNlYXNaSlRMTGpocVZQY1NNlYE4ZW5UTko4NU9KK3p1L1p1VzE4ZWVPQVlSUHNITG1JN2I0NzlyTg=" + paypage_registration_id = 'cDZJcmd1VjNlYXNaSlRMTGpocVZQY1NNlYE4ZW5UTko4NU9KK3p1L1p1VzE4ZWVPQVlSUHNITG1JN2I0NzlyTg=' assert store_response = @gateway.store(paypage_registration_id, :order_id => '50') assert_success store_response @@ -264,11 +369,24 @@ def test_store_and_purchase_with_token_successful assert_equal 'Approved', response.message end + def test_echeck_store_and_purchase + assert store_response = @gateway.store(@store_check) + assert_success store_response + assert_equal 'Account number was successfully registered', store_response.message + + token = store_response.authorization + assert_equal store_response.params['litleToken'], token + + assert response = @gateway.purchase(10010, token) + assert_success response + assert_equal 'Approved', response.message + end + def test_successful_verify assert response = @gateway.verify(@credit_card1, @options) assert_success response assert_equal 'Approved', response.message - assert_success response.responses.last, "The void should succeed" + assert_success response.responses.last, 'The void should succeed' end def test_unsuccessful_verify @@ -279,8 +397,8 @@ def test_unsuccessful_verify def test_successful_purchase_with_dynamic_descriptors assert response = @gateway.purchase(10010, @credit_card1, @options.merge( - descriptor_name: "SuperCompany", - descriptor_phone: "9193341121", + descriptor_name: 'SuperCompany', + descriptor_phone: '9193341121' )) assert_success response assert_equal 'Approved', response.message @@ -307,4 +425,20 @@ def test_purchase_scrubbing assert_scrubbed(@gateway.options[:login], transcript) assert_scrubbed(@gateway.options[:password], transcript) end + + def test_echeck_scrubbing + options = @options.merge({ + order_id: '42', + order_source: 'telephone' + }) + transcript = capture_transcript(@gateway) do + @gateway.purchase(2004, @check, options) + end + transcript = @gateway.scrub(transcript) + + assert_scrubbed(@check.account_number, transcript) + assert_scrubbed(@check.routing_number, transcript) + assert_scrubbed(@gateway.options[:login], transcript) + assert_scrubbed(@gateway.options[:password], transcript) + end end diff --git a/test/remote/gateways/remote_maxipago_test.rb b/test/remote/gateways/remote_maxipago_test.rb index 9ac1d94c2b5..4e6c852937a 100644 --- a/test/remote/gateways/remote_maxipago_test.rb +++ b/test/remote/gateways/remote_maxipago_test.rb @@ -20,13 +20,13 @@ def setup def test_successful_authorize assert response = @gateway.authorize(@amount, @credit_card, @options) assert_success response - assert_equal "AUTHORIZED", response.message + assert_equal 'AUTHORIZED', response.message end def test_failed_authorize assert response = @gateway.authorize(@amount, @invalid_card, @options) assert_failure response - assert_equal "The transaction has an expired credit card.", response.message + assert_equal 'The transaction has an expired credit card.', response.message end def test_successful_authorize_and_capture @@ -49,7 +49,7 @@ def test_successful_purchase_sans_options end def test_successful_purchase_with_currency - assert response = @gateway.purchase(@amount, @credit_card, @options.merge(currency: "CLP")) + assert response = @gateway.purchase(@amount, @credit_card, @options.merge(currency: 'CLP')) assert_success response end @@ -69,13 +69,13 @@ def test_successful_void void = @gateway.void(auth.authorization) assert_success void - assert_equal "VOIDED", void.message + assert_equal 'VOIDED', void.message end def test_failed_void - response = @gateway.void("NOAUTH|0000000") + response = @gateway.void('NOAUTH|0000000') assert_failure response - assert_equal "Unable to validate, original void transaction not found", response.message + assert_equal 'Unable to validate, original void transaction not found', response.message end def test_successful_refund @@ -84,7 +84,7 @@ def test_successful_refund refund = @gateway.refund(@amount, purchase.authorization, @options) assert_success refund - assert_equal "CAPTURED", refund.message + assert_equal 'CAPTURED', refund.message end def test_failed_refund @@ -94,19 +94,19 @@ def test_failed_refund refund_amount = @amount + 10 refund = @gateway.refund(refund_amount, purchase.authorization, @options) assert_failure refund - assert_equal "The Return amount is greater than the amount that can be returned.", refund.message + assert_equal 'The Return amount is greater than the amount that can be returned.', refund.message end def test_successful_verify response = @gateway.verify(@credit_card, @options) assert_success response - assert_equal "AUTHORIZED", response.message + assert_equal 'AUTHORIZED', response.message end def test_failed_verify response = @gateway.verify(@invalid_card, @options) assert_failure response - assert_equal "The transaction has an expired credit card.", response.message + assert_equal 'The transaction has an expired credit card.', response.message end def test_transcript_scrubbing diff --git a/test/remote/gateways/remote_mercado_pago_test.rb b/test/remote/gateways/remote_mercado_pago_test.rb new file mode 100644 index 00000000000..54ddaa50072 --- /dev/null +++ b/test/remote/gateways/remote_mercado_pago_test.rb @@ -0,0 +1,146 @@ +require 'test_helper' + +class RemoteMercadoPagoTest < Test::Unit::TestCase + def setup + @gateway = MercadoPagoGateway.new(fixtures(:mercado_pago)) + + @amount = 500 + @credit_card = credit_card('4509953566233704') + @declined_card = credit_card('4000300011112220') + @options = { + billing_address: address, + shipping_address: address, + email: 'user+br@example.com', + description: 'Store Purchase' + } + end + + def test_successful_purchase + response = @gateway.purchase(@amount, @credit_card, @options) + assert_success response + assert_equal 'accredited', response.message + end + + def test_successful_purchase_with_binary_false + @options.update(binary_mode: false) + response = @gateway.purchase(@amount, @credit_card, @options) + assert_success response + assert_equal 'accredited', response.message + end + + def test_successful_purchase_with_american_express + amex_card = credit_card('375365153556885', brand: 'american_express', verification_value: '1234') + + response = @gateway.purchase(@amount, amex_card, @options) + assert_success response + assert_equal 'accredited', response.message + end + + def test_failed_purchase + response = @gateway.purchase(@amount, @declined_card, @options) + assert_failure response + assert_equal 'rejected', response.error_code + assert_equal 'cc_rejected_other_reason', response.message + end + + def test_successful_authorize_and_capture + auth = @gateway.authorize(@amount, @credit_card, @options) + assert_success auth + assert_equal 'pending_capture', auth.message + + assert capture = @gateway.capture(@amount, auth.authorization) + assert_success capture + assert_equal 'accredited', capture.message + end + + def test_failed_authorize + response = @gateway.authorize(@amount, @declined_card, @options) + assert_failure response + assert_equal 'cc_rejected_other_reason', response.message + end + + def test_partial_capture + auth = @gateway.authorize(@amount, @credit_card, @options) + assert_success auth + + assert capture = @gateway.capture(@amount-1, auth.authorization) + assert_success capture + assert_equal 'accredited', capture.message + end + + def test_failed_capture + response = @gateway.capture(@amount, '') + assert_failure response + assert_equal 'json_parse_error', response.message + end + + def test_successful_refund + purchase = @gateway.purchase(@amount, @credit_card, @options) + assert_success purchase + + assert refund = @gateway.refund(@amount, purchase.authorization) + assert_success refund + assert_equal nil, refund.message + end + + def test_partial_refund + purchase = @gateway.purchase(@amount, @credit_card, @options) + assert_success purchase + + assert refund = @gateway.refund(@amount-1, purchase.authorization) + assert_success refund + end + + def test_failed_refund + response = @gateway.refund(@amount, '') + assert_failure response + assert_equal 'Not Found', response.message + end + + def test_successful_void + auth = @gateway.authorize(@amount, @credit_card, @options) + assert_success auth + + assert void = @gateway.void(auth.authorization) + assert_success void + assert_equal 'by_collector', void.message + end + + def test_failed_void + response = @gateway.void('') + assert_failure response + assert_equal 'json_parse_error', response.message + end + + def test_successful_verify + response = @gateway.verify(@credit_card, @options) + assert_success response + assert_match %r{pending_capture}, response.message + end + + def test_failed_verify + response = @gateway.verify(@declined_card, @options) + assert_failure response + assert_match %r{cc_rejected_other_reason}, response.message + end + + def test_invalid_login + gateway = MercadoPagoGateway.new(access_token: '') + + response = gateway.purchase(@amount, @credit_card, @options) + assert_failure response + assert_match %r{Invalid access parameters}, response.message + end + + def test_transcript_scrubbing + transcript = capture_transcript(@gateway) do + @gateway.purchase(@amount, @credit_card, @options) + end + transcript = @gateway.scrub(transcript) + + assert_scrubbed(@credit_card.number, transcript) + assert_scrubbed(@credit_card.verification_value, transcript) + assert_scrubbed(@gateway.options[:access_token], transcript) + end + +end diff --git a/test/remote/gateways/remote_merchant_e_solutions_test.rb b/test/remote/gateways/remote_merchant_e_solutions_test.rb index ca016efb882..a9504dac516 100644 --- a/test/remote/gateways/remote_merchant_e_solutions_test.rb +++ b/test/remote/gateways/remote_merchant_e_solutions_test.rb @@ -44,7 +44,7 @@ def test_unsuccessful_purchase end def test_purchase_with_long_order_id - options = {order_id: "thisislongerthan17characters"} + options = {order_id: 'thisislongerthan17characters'} assert response = @gateway.purchase(@amount, @credit_card, options) assert_success response assert_equal 'This transaction has been approved', response.message @@ -198,4 +198,16 @@ def test_successful_purchase_with_3dsecure_params assert_success response assert_equal 'This transaction has been approved', response.message end + + def test_transcript_scrubbing + transcript = capture_transcript(@gateway) do + @gateway.purchase(@amount, @credit_card, @options) + end + transcript = @gateway.scrub(transcript) + + assert_scrubbed(@credit_card.number, transcript) + assert_match(%r{cvv2\=\[FILTERED\]}, transcript) + assert_no_match(%r{cvv2=#{@credit_card.verification_value}}, transcript) + assert_scrubbed(@gateway.options[:password], transcript) + end end diff --git a/test/remote/gateways/remote_merchant_one_test.rb b/test/remote/gateways/remote_merchant_one_test.rb index 936cb70235e..0e4f98fb23e 100644 --- a/test/remote/gateways/remote_merchant_one_test.rb +++ b/test/remote/gateways/remote_merchant_one_test.rb @@ -31,34 +31,34 @@ def test_successful_purchase assert_equal 'SUCCESS', response.message end - def test_unsuccessful_purchase - assert response = @gateway.purchase(@amount, @declined_card, @options) - assert_failure response - assert response.message.include? 'Invalid Credit Card Number' - end + def test_unsuccessful_purchase + assert response = @gateway.purchase(@amount, @declined_card, @options) + assert_failure response + assert response.message.include? 'Invalid Credit Card Number' + end - def test_authorize_and_capture - amount = @amount - assert auth = @gateway.authorize(amount, @credit_card, @options) - assert_success auth - assert_equal 'SUCCESS', auth.message - assert auth.authorization, auth.to_yaml - assert capture = @gateway.capture(amount, auth.authorization) - assert_success capture - end + def test_authorize_and_capture + amount = @amount + assert auth = @gateway.authorize(amount, @credit_card, @options) + assert_success auth + assert_equal 'SUCCESS', auth.message + assert auth.authorization, auth.to_yaml + assert capture = @gateway.capture(amount, auth.authorization) + assert_success capture + end - def test_failed_capture + def test_failed_capture assert response = @gateway.capture(@amount, '') assert_failure response - end + end - def test_invalid_login - gateway = MerchantOneGateway.new( - :username => 'nnn', - :password => 'nnn' - ) - assert response = gateway.purchase(@amount, @credit_card, @options) - assert_failure response - assert_equal 'Authentication Failed', response.message - end + def test_invalid_login + gateway = MerchantOneGateway.new( + :username => 'nnn', + :password => 'nnn' + ) + assert response = gateway.purchase(@amount, @credit_card, @options) + assert_failure response + assert_equal 'Authentication Failed', response.message + end end diff --git a/test/remote/gateways/remote_merchant_partners_test.rb b/test/remote/gateways/remote_merchant_partners_test.rb index b350166ca54..846415b674b 100644 --- a/test/remote/gateways/remote_merchant_partners_test.rb +++ b/test/remote/gateways/remote_merchant_partners_test.rb @@ -1,24 +1,24 @@ -require "test_helper" +require 'test_helper' class RemoteMerchantPartnersTest < Test::Unit::TestCase def setup @gateway = MerchantPartnersGateway.new(fixtures(:merchant_partners)) @amount = 100 - @credit_card = credit_card("4003000123456781") - @declined_card = credit_card("4003000123456782") + @credit_card = credit_card('4003000123456781') + @declined_card = credit_card('4003000123456782') @options = { order_id: generate_unique_id, billing_address: address, - description: "Store Purchase" + description: 'Store Purchase' } end def test_invalid_login gateway = MerchantPartnersGateway.new( - account_id: "TEST0", - merchant_pin: "1" + account_id: 'TEST0', + merchant_pin: '1' ) response = gateway.purchase(@amount, @credit_card, @options) assert_failure response @@ -27,39 +27,39 @@ def test_invalid_login def test_successful_purchase response = @gateway.purchase(@amount, @credit_card, @options) assert_success response - assert_equal "Succeeded", response.message + assert_equal 'Succeeded', response.message end def test_failed_purchase response = @gateway.purchase(@amount, @declined_card, @options) assert_failure response - assert_equal "Invalid account number", response.message - assert response.params["result"].start_with?("DECLINED") + assert_match(/Invalid account/, response.message) + assert response.params['result'].start_with?('DECLINED') end def test_successful_authorize_and_capture response = @gateway.authorize(@amount, @credit_card, @options) assert_success response - assert_equal "Succeeded", response.message + assert_equal 'Succeeded', response.message assert_match %r(^\d+), response.authorization capture = @gateway.capture(@amount, response.authorization) assert_success capture - assert_equal "Succeeded", capture.message + assert_equal 'Succeeded', capture.message end def test_failed_authorize response = @gateway.authorize(@amount, @declined_card, @options) assert_failure response - assert_equal "Invalid account number", response.message - assert response.params["result"].start_with?("DECLINED") + assert_match(/Invalid account/, response.message) + assert response.params['result'].start_with?('DECLINED') end def test_failed_capture - response = @gateway.capture(@amount, "BAD") + response = @gateway.capture(@amount, 'BAD') assert_failure response - assert_equal "Missing account number", response.message - assert response.params["result"].start_with?("DECLINED") + assert_equal 'Missing account number', response.message + assert response.params['result'].start_with?('DECLINED') end def test_successful_void @@ -68,14 +68,14 @@ def test_successful_void void = @gateway.void(response.authorization) assert_success void - assert_equal "Succeeded", void.message + assert_equal 'Succeeded', void.message end def test_failed_void - response = @gateway.void("") + response = @gateway.void('') assert_failure response - assert_equal "Invalid acct type", response.message - assert response.params["result"].start_with?("DECLINED") + assert_equal 'Invalid acct type', response.message + assert response.params['result'].start_with?('DECLINED') end def test_successful_refund @@ -84,27 +84,27 @@ def test_successful_refund refund = @gateway.refund(@amount, response.authorization) assert_success refund - assert_equal "Succeeded", refund.message + assert_equal 'Succeeded', refund.message end def test_failed_refund - response = @gateway.refund(nil, "") + response = @gateway.refund(nil, '') assert_failure response - assert_equal "Missing account number", response.message - assert response.params["result"].start_with?("DECLINED") + assert_equal 'Missing account number', response.message + assert response.params['result'].start_with?('DECLINED') end def test_successful_credit response = @gateway.credit(@amount, @credit_card, @options) assert_success response - assert_equal "Succeeded", response.message + assert_equal 'Succeeded', response.message end def test_failed_credit response = @gateway.credit(@amount, @declined_card, @options) assert_failure response - assert_equal "Invalid account number", response.message - assert response.params["result"].start_with?("DECLINED") + assert_match(/Invalid account/, response.message) + assert response.params['result'].start_with?('DECLINED') end def test_successful_verify @@ -116,28 +116,28 @@ def test_successful_verify def test_failed_verify response = @gateway.verify(@declined_card, @options) assert_failure response - assert_equal "Invalid account number", response.message - assert response.params["result"].start_with?("DECLINED") + assert_match(/Invalid account/, response.message) + assert response.params['result'].start_with?('DECLINED') end def test_successful_store_and_purchase response = @gateway.store(@credit_card, @options) assert_success response - assert_equal "Succeeded", response.message + assert_equal 'Succeeded', response.message purchase = @gateway.purchase(@amount, response.authorization, @options) assert_success purchase - assert_equal "Succeeded", purchase.message + assert_equal 'Succeeded', purchase.message end def test_successful_store_and_credit response = @gateway.store(@credit_card, @options) assert_success response - assert_equal "Succeeded", response.message + assert_equal 'Succeeded', response.message credit = @gateway.credit(@amount, response.authorization, @options) assert_success credit - assert_equal "Succeeded", credit.message + assert_equal 'Succeeded', credit.message end def test_failed_store diff --git a/test/remote/gateways/remote_merchant_ware_test.rb b/test/remote/gateways/remote_merchant_ware_test.rb index 399f0552ce6..b4b4dc2c899 100644 --- a/test/remote/gateways/remote_merchant_ware_test.rb +++ b/test/remote/gateways/remote_merchant_ware_test.rb @@ -4,7 +4,7 @@ class RemoteMerchantWareTest < Test::Unit::TestCase def setup @gateway = MerchantWareGateway.new(fixtures(:merchant_ware)) - @amount = rand(1000) + 200 + @amount = rand(200..1199) @credit_card = credit_card('5424180279791732', {:brand => 'master'}) @@ -21,7 +21,7 @@ def test_successful_authorization end def test_unsuccessful_authorization - @credit_card.number = "1234567890123" + @credit_card.number = '1234567890123' assert response = @gateway.authorize(@amount, @credit_card, @options) assert_failure response end @@ -33,7 +33,7 @@ def test_successful_purchase end def test_unsuccessful_purchase - @credit_card.number = "1234567890123" + @credit_card.number = '1234567890123' assert response = @gateway.purchase(@amount, @credit_card, @options) assert_failure response end diff --git a/test/remote/gateways/remote_merchant_ware_version_four_test.rb b/test/remote/gateways/remote_merchant_ware_version_four_test.rb index 61ca4d2866b..155bdc2e460 100644 --- a/test/remote/gateways/remote_merchant_ware_version_four_test.rb +++ b/test/remote/gateways/remote_merchant_ware_version_four_test.rb @@ -3,17 +3,17 @@ class RemoteMerchantWareVersionFourTest < Test::Unit::TestCase def setup @gateway = MerchantWareVersionFourGateway.new(fixtures(:merchant_ware_version_four)) - @amount = rand(1000) + 200 + @amount = rand(200..1199) @credit_card = credit_card('5424180279791732', {:brand => 'master'}) @declined_card = credit_card('1234567890123') @options = { - :order_id => generate_unique_id[0,8], + :order_id => generate_unique_id[0, 8], :billing_address => address } @reference_purchase_options = { - :order_id => generate_unique_id[0,8] + :order_id => generate_unique_id[0, 8] } end @@ -24,7 +24,7 @@ def test_successful_authorization end def test_unsuccessful_authorization - @credit_card.number = "1234567890123" + @credit_card.number = '1234567890123' assert response = @gateway.authorize(@amount, @credit_card, @options) assert_failure response end @@ -36,7 +36,7 @@ def test_successful_purchase end def test_unsuccessful_purchase - @credit_card.number = "1234567890123" + @credit_card.number = '1234567890123' assert response = @gateway.purchase(@amount, @credit_card, @options) assert_failure response end @@ -70,8 +70,8 @@ def test_purchase_and_reference_purchase assert purchase.authorization assert reference_purchase = @gateway.purchase(@amount, - purchase.authorization, - @reference_purchase_options) + purchase.authorization, + @reference_purchase_options) assert_success reference_purchase assert_not_nil reference_purchase.authorization end diff --git a/test/remote/gateways/remote_merchant_warrior_test.rb b/test/remote/gateways/remote_merchant_warrior_test.rb index 30abcc7684e..d9c5e826c4a 100644 --- a/test/remote/gateways/remote_merchant_warrior_test.rb +++ b/test/remote/gateways/remote_merchant_warrior_test.rb @@ -10,7 +10,7 @@ def setup @credit_card = credit_card( '5123456789012346', :month => 5, - :year => 17, + :year => Time.now.year + 2, :verification_value => '123', :brand => 'master' ) @@ -32,13 +32,13 @@ def test_successful_authorize assert auth = @gateway.authorize(@success_amount, @credit_card, @options) assert_success auth assert_equal 'Transaction approved', auth.message - assert_not_nil auth.params["transaction_id"] - assert_equal auth.params["transaction_id"], auth.authorization + assert_not_nil auth.params['transaction_id'] + assert_equal auth.params['transaction_id'], auth.authorization assert capture = @gateway.capture(@success_amount, auth.authorization) assert_success capture - assert_not_nil capture.params["transaction_id"] - assert_equal capture.params["transaction_id"], capture.authorization + assert_not_nil capture.params['transaction_id'] + assert_equal capture.params['transaction_id'], capture.authorization assert_not_equal auth.authorization, capture.authorization end @@ -46,16 +46,16 @@ def test_successful_purchase assert purchase = @gateway.purchase(@success_amount, @credit_card, @options) assert_equal 'Transaction approved', purchase.message assert_success purchase - assert_not_nil purchase.params["transaction_id"] - assert_equal purchase.params["transaction_id"], purchase.authorization + assert_not_nil purchase.params['transaction_id'] + assert_equal purchase.params['transaction_id'], purchase.authorization end def test_failed_purchase assert purchase = @gateway.purchase(@failure_amount, @credit_card, @options) assert_equal 'Transaction declined', purchase.message assert_failure purchase - assert_not_nil purchase.params["transaction_id"] - assert_equal purchase.params["transaction_id"], purchase.authorization + assert_not_nil purchase.params['transaction_id'] + assert_equal purchase.params['transaction_id'], purchase.authorization end def test_successful_refund @@ -105,12 +105,37 @@ def test_token_auth end def test_successful_purchase_with_funky_names - @credit_card.first_name = "Phillips & Sons" + @credit_card.first_name = 'Phillips & Sons' @credit_card.last_name = "Other-Things; MW. doesn't like" - @options[:billing_address][:name] = "Merchant Warrior wants % alphanumerics" + @options[:billing_address][:name] = 'Merchant Warrior wants % alphanumerics' assert purchase = @gateway.purchase(@success_amount, @credit_card, @options) assert_equal 'Transaction approved', purchase.message assert_success purchase end + + def test_transcript_scrubbing + transcript = capture_transcript(@gateway) do + @gateway.purchase(@success_amount, @credit_card, @options) + end + transcript = @gateway.scrub(transcript) + + assert_scrubbed(@credit_card.number, transcript) + assert_match(%r{paymentCardCSC\=\[FILTERED\]}, transcript) + assert_no_match(%r{paymentCardCSC=#{@credit_card.verification_value}}, transcript) + assert_scrubbed(@gateway.options[:api_passphrase], transcript) + assert_scrubbed(@gateway.options[:api_key], transcript) + end + + def test_transcript_scrubbing_store + transcript = capture_transcript(@gateway) do + @gateway.store(@credit_card, @options) + end + transcript = @gateway.scrub(transcript) + + assert_scrubbed(@credit_card.number, transcript) + assert_scrubbed(@credit_card.verification_value, transcript) + assert_scrubbed(@gateway.options[:api_passphrase], transcript) + assert_scrubbed(@gateway.options[:api_key], transcript) + end end diff --git a/test/remote/gateways/remote_mercury_certification_test.rb b/test/remote/gateways/remote_mercury_certification_test.rb index 9020387e86c..56cb9de3234 100644 --- a/test/remote/gateways/remote_mercury_certification_test.rb +++ b/test/remote/gateways/remote_mercury_certification_test.rb @@ -1,5 +1,5 @@ require 'test_helper' -require "support/mercury_helper" +require 'support/mercury_helper' class RemoteMercuryCertificationTest < Test::Unit::TestCase include MercuryHelper @@ -9,130 +9,106 @@ class RemoteMercuryCertificationTest < Test::Unit::TestCase def test_sale_and_reversal close_batch(tokenization_gateway) - sale = tokenization_gateway.purchase(101, visa, options("1")) + sale = tokenization_gateway.purchase(101, visa, options('1')) assert_success sale - assert_equal "AP", sale.params["text_response"] + assert_equal 'AP', sale.params['text_response'] reversal = tokenization_gateway.void(sale.authorization, options.merge(:try_reversal => true)) assert_success reversal - assert_equal "REVERSED", reversal.params["text_response"] + assert_equal 'REVERSED', reversal.params['text_response'] end def test_sale_and_void close_batch(tokenization_gateway) - sale = tokenization_gateway.purchase(103, visa, options("1")) + sale = tokenization_gateway.purchase(103, visa, options('1')) assert_success sale - assert_equal "AP", sale.params["text_response"] + assert_equal 'AP', sale.params['text_response'] void = tokenization_gateway.void(sale.authorization, options) assert_success void - assert_equal "AP", void.params["text_response"] - end - - def test_preauth_capture_and_reversal - close_batch(tokenization_gateway) - - cc = credit_card( - "4005550000000480", - :brand => "visa", - :month => "12", - :year => "15", - :verification_value => "123" - ) - - preauth = tokenization_gateway.authorize(106, cc, options("1")) - assert_success preauth - assert_equal "AP", preauth.params["text_response"] - - capture = tokenization_gateway.capture(106, preauth.authorization, options) - assert_success capture - assert_equal "AP", capture.params["text_response"] - - reversal = tokenization_gateway.void(capture.authorization, options.merge(:try_reversal => true)) - assert_success reversal - assert_equal "REVERSED", reversal.params["text_response"] + assert_equal 'AP', void.params['text_response'] end def test_return close_batch(tokenization_gateway) - credit = tokenization_gateway.credit(109, visa, options("1")) + credit = tokenization_gateway.credit(109, visa, options('1')) assert_success credit - assert_equal "AP", credit.params["text_response"] + assert_equal 'AP', credit.params['text_response'] end def test_preauth_and_reversal close_batch(tokenization_gateway) - preauth = tokenization_gateway.authorize(113, disc, options("1")) + preauth = tokenization_gateway.authorize(113, disc, options('1')) assert_success preauth - assert_equal "AP", preauth.params["text_response"] + assert_equal 'AP', preauth.params['text_response'] reversal = tokenization_gateway.void(preauth.authorization, options.merge(:try_reversal => true)) assert_success reversal - assert_equal "REVERSED", reversal.params["text_response"] + assert_equal 'REVERSED', reversal.params['text_response'] end def test_preauth_capture_and_reversal close_batch(tokenization_gateway) - preauth = tokenization_gateway.authorize(106, visa, options("1")) + preauth = tokenization_gateway.authorize(106, visa, options('1')) assert_success preauth - assert_equal "AP", preauth.params["text_response"] + assert_equal 'AP', preauth.params['text_response'] capture = tokenization_gateway.capture(206, preauth.authorization, options) assert_success capture - assert_equal "AP", capture.params["text_response"] + assert_equal 'AP', capture.params['text_response'] void = tokenization_gateway.void(capture.authorization, options) assert_success void - assert_equal "AP", void.params["text_response"] + assert_equal 'AP', void.params['text_response'] end private def tokenization_gateway @tokenization_gateway ||= MercuryGateway.new( - :login => "023358150511666", - :password => "xyz" + :login => '023358150511666', + :password => 'xyz' ) end def visa @visa ||= credit_card( - "4003000123456781", - :brand => "visa", - :month => "12", - :year => "15", - :verification_value => "123" + '4003000123456781', + :brand => 'visa', + :month => '12', + :year => '15', + :verification_value => '123' ) end def disc @disc ||= credit_card( - "6011000997235373", - :brand => "discover", - :month => "12", - :year => "15", - :verification_value => "362" + '6011000997235373', + :brand => 'discover', + :month => '12', + :year => '15', + :verification_value => '362' ) end def mc @mc ||= credit_card( - "5439750001500248", - :brand => "master", - :month => "12", - :year => "15", - :verification_value => "123" + '5439750001500248', + :brand => 'master', + :month => '12', + :year => '15', + :verification_value => '123' ) end def options(order_id=nil, other={}) { :order_id => order_id, - :description => "ActiveMerchant", + :description => 'ActiveMerchant', }.merge(other) end end diff --git a/test/remote/gateways/remote_mercury_test.rb b/test/remote/gateways/remote_mercury_test.rb index 4930ddc2417..4dd1a95b80c 100644 --- a/test/remote/gateways/remote_mercury_test.rb +++ b/test/remote/gateways/remote_mercury_test.rb @@ -1,5 +1,5 @@ require 'test_helper' -require "support/mercury_helper" +require 'support/mercury_helper' class RemoteMercuryTest < Test::Unit::TestCase include MercuryHelper @@ -9,14 +9,14 @@ def setup @amount = 100 - @credit_card = credit_card("4003000123456781", :brand => "visa", :month => "12", :year => "15") + @credit_card = credit_card('4003000123456781', :brand => 'visa', :month => '12', :year => '18') - @track_1_data = "%B4003000123456781^LONGSEN/L. ^15121200000000000000**123******?*" - @track_2_data = ";5413330089010608=2512101097750213?" + @track_1_data = '%B4003000123456781^LONGSEN/L. ^18121200000000000000**123******?*' + @track_2_data = ';5413330089010608=2512101097750213?' @options = { - :order_id => "c111111111.1", - :description => "ActiveMerchant" + :order_id => 'c111111111.1', + :description => 'ActiveMerchant' } @options_with_billing = @options.merge( :merchant => '999', @@ -27,9 +27,9 @@ def setup ) @full_options = @options_with_billing.merge( :ip => '123.123.123.123', - :merchant => "Open Dining", - :customer => "Tim", - :tax => "5" + :merchant => 'Open Dining', + :customer => 'Tim', + :tax => '5' ) close_batch @@ -48,7 +48,7 @@ def test_successful_authorize_and_capture def test_failed_authorize response = @gateway.authorize(1100, @credit_card, @options) assert_failure response - assert_equal "DECLINE", response.message + assert_equal 'DECLINE', response.message end def test_purchase_and_void @@ -63,14 +63,14 @@ def test_successful_purchase response = @gateway.purchase(50, @credit_card, @options) assert_success response - assert_equal "0.50", response.params["purchase"] + assert_equal '0.50', response.params['purchase'] end def test_store response = @gateway.store(@credit_card, @options) assert_success response - assert response.params.has_key?("record_no") + assert response.params.has_key?('record_no') assert response.params['record_no'] != '' end @@ -78,13 +78,13 @@ def test_credit response = @gateway.credit(50, @credit_card, @options) assert_success response - assert_equal "0.50", response.params["purchase"], response.inspect + assert_equal '0.50', response.params['purchase'], response.inspect end def test_failed_purchase response = @gateway.purchase(1100, @credit_card, @options) assert_failure response - assert_equal "DECLINE", response.message + assert_equal 'DECLINE', response.message assert_equal Gateway::STANDARD_ERROR_CODE[:card_declined], response.error_code end @@ -94,14 +94,14 @@ def test_avs_and_cvv_results assert_success response assert_equal( { - "code" => "Y", - "postal_match" => "Y", - "street_match" => "Y", - "message" => "Street address and 5-digit postal code match." + 'code' => 'Y', + 'postal_match' => 'Y', + 'street_match' => 'Y', + 'message' => 'Street address and 5-digit postal code match.' }, response.avs_result ) - assert_equal({"code"=>"M", "message"=>"CVV matches"}, response.cvv_result) + assert_equal({'code'=>'M', 'message'=>'CVV matches'}, response.cvv_result) end def test_avs_and_cvv_results_with_track_data @@ -111,18 +111,18 @@ def test_avs_and_cvv_results_with_track_data assert_success response assert_equal( { - "code" => nil, - "postal_match" => nil, - "street_match" => nil, - "message" => nil + 'code' => nil, + 'postal_match' => nil, + 'street_match' => nil, + 'message' => nil }, response.avs_result ) - assert_equal({"code"=>'P', "message"=>'CVV not processed'}, response.cvv_result) + assert_equal({'code'=>'P', 'message'=>'CVV not processed'}, response.cvv_result) end def test_partial_capture - visa_partial_card = credit_card("4005550000000480") + visa_partial_card = credit_card('4005550000000480') response = @gateway.authorize(2354, visa_partial_card, @options) @@ -140,11 +140,11 @@ def test_authorize_with_bad_expiration_date @credit_card.year = 2001 response = @gateway.authorize(575, @credit_card, @options_with_billing) assert_failure response - assert_equal "INVLD EXP DATE", response.message + assert_equal 'INVLD EXP DATE', response.message end def test_mastercard_authorize_and_capture_with_refund - mc = credit_card("5499990123456781", :brand => "master") + mc = credit_card('5499990123456781', :brand => 'master') response = @gateway.authorize(200, mc, @options) assert_success response @@ -161,7 +161,7 @@ def test_mastercard_authorize_and_capture_with_refund end def test_amex_authorize_and_capture_with_refund - amex = credit_card("373953244361001", :brand => "american_express", :verification_value => "1234") + amex = credit_card('373953244361001', :brand => 'american_express', :verification_value => '1234') response = @gateway.authorize(201, amex, @options) assert_success response @@ -177,7 +177,7 @@ def test_amex_authorize_and_capture_with_refund end def test_discover_authorize_and_capture - discover = credit_card("6011000997235373", :brand => "discover") + discover = credit_card('6011000997235373', :brand => 'discover') response = @gateway.authorize(225, discover, @options_with_billing) assert_success response @@ -210,7 +210,7 @@ def test_authorize_and_capture_without_tokenization assert_success capture assert_equal '1.00', capture.params['authorize'] end - + def test_successful_authorize_and_capture_with_track_1_data @credit_card.track_data = @track_1_data response = @gateway.authorize(100, @credit_card, @options) @@ -241,4 +241,15 @@ def test_authorize_and_void void = @gateway.void(response.authorization) assert_success void end + + def test_transcript_scrubbing + transcript = capture_transcript(@gateway) do + @gateway.purchase(@amount, @credit_card, @options) + end + transcript = @gateway.scrub(transcript) + + assert_scrubbed(@credit_card.number, transcript) + assert_scrubbed(@credit_card.verification_value, transcript) + assert_scrubbed(@gateway.options[:password], transcript) + end end diff --git a/test/remote/gateways/remote_metrics_global_test.rb b/test/remote/gateways/remote_metrics_global_test.rb index 4748cdc23c3..3669fd41a11 100644 --- a/test/remote/gateways/remote_metrics_global_test.rb +++ b/test/remote/gateways/remote_metrics_global_test.rb @@ -3,7 +3,7 @@ class MetricsGlobalTest < Test::Unit::TestCase def setup Base.mode = :test - + @gateway = MetricsGlobalGateway.new(fixtures(:metrics_global)) @amount = 100 @credit_card = credit_card('4111111111111111', :verification_value => '999') @@ -13,7 +13,7 @@ def setup :description => 'Store purchase' } end - + def test_successful_purchase assert response = @gateway.purchase(@amount, @credit_card, @options) assert_success response @@ -21,7 +21,7 @@ def test_successful_purchase assert_equal 'This transaction has been approved', response.message assert response.authorization end - + def test_declined_authorization @amount = 10 assert response = @gateway.purchase(@amount, @credit_card, @options) @@ -29,71 +29,71 @@ def test_declined_authorization assert response.test? assert_equal 'This transaction has been declined', response.message end - + def test_successful_authorization assert response = @gateway.authorize(@amount, @credit_card, @options) assert_success response assert_equal 'This transaction has been approved', response.message assert response.authorization end - + def test_authorization_and_capture assert authorization = @gateway.authorize(@amount, @credit_card, @options) assert_success authorization - + assert capture = @gateway.capture(@amount, authorization.authorization) assert_success capture assert_equal 'This transaction has been approved', capture.message end - + def test_authorization_and_void assert authorization = @gateway.authorize(@amount, @credit_card, @options) assert_success authorization - + assert void = @gateway.void(authorization.authorization) assert_success void assert_equal 'This transaction has been approved', void.message end - + def test_bad_login gateway = MetricsGlobalGateway.new( :login => 'X', :password => 'Y' ) - + assert response = gateway.purchase(@amount, @credit_card) - + assert_equal Response, response.class - assert_equal ["avs_result_code", - "card_code", - "response_code", - "response_reason_code", - "response_reason_text", - "transaction_id"], response.params.keys.sort + assert_equal ['avs_result_code', + 'card_code', + 'response_code', + 'response_reason_code', + 'response_reason_text', + 'transaction_id'], response.params.keys.sort assert_match(/Authentication Failed/, response.message) - + assert_equal false, response.success? end - + def test_using_test_request gateway = MetricsGlobalGateway.new( :login => 'X', :password => 'Y' ) - + assert response = gateway.purchase(@amount, @credit_card) - + assert_equal Response, response.class - assert_equal ["avs_result_code", - "card_code", - "response_code", - "response_reason_code", - "response_reason_text", - "transaction_id"], response.params.keys.sort - + assert_equal ['avs_result_code', + 'card_code', + 'response_code', + 'response_reason_code', + 'response_reason_text', + 'transaction_id'], response.params.keys.sort + assert_match(/Authentication Failed/, response.message) - - assert_equal false, response.success? + + assert_equal false, response.success? end end diff --git a/test/remote/gateways/remote_micropayment_test.rb b/test/remote/gateways/remote_micropayment_test.rb index 8d8075f8278..fb4589e7d71 100644 --- a/test/remote/gateways/remote_micropayment_test.rb +++ b/test/remote/gateways/remote_micropayment_test.rb @@ -5,109 +5,109 @@ def setup @gateway = MicropaymentGateway.new(fixtures(:micropayment)) @amount = 250 - @credit_card = credit_card("4111111111111111", verification_value: "666") - @declined_card = credit_card("4111111111111111") + @credit_card = credit_card('4111111111111111', verification_value: '666') + @declined_card = credit_card('4111111111111111') @options = { order_id: generate_unique_id, - description: "Eggcellent", + description: 'Eggcellent', billing_address: address } end def test_invalid_login - gateway = MicropaymentGateway.new(access_key: "invalid", api_key:"invalid") + gateway = MicropaymentGateway.new(access_key: 'invalid', api_key: 'invalid') response = gateway.purchase(@amount, @credit_card, @options) assert_failure response - assert_equal "Authorization failed - Reason: api accesskey wrong", response.message + assert_equal 'Authorization failed - Reason: api accesskey wrong', response.message end def test_successful_purchase response = @gateway.purchase(@amount, @credit_card, @options) assert_success response - assert_equal "Succeeded", response.message + assert_equal 'Succeeded', response.message end def test_failed_purchase response = @gateway.purchase(@amount, @declined_card, @options) assert_failure response - assert_equal "AS stellt falsches Routing fest", response.message + assert_equal 'AS stellt falsches Routing fest', response.message end def test_successful_authorize_and_capture response = @gateway.authorize(@amount, @credit_card) assert_success response - assert_equal "Succeeded", response.message + assert_equal 'Succeeded', response.message assert_match %r(^\w+\|.+$), response.authorization capture = @gateway.capture(@amount, response.authorization) assert_success capture - assert_equal "Succeeded", capture.message + assert_equal 'Succeeded', capture.message end def test_successful_authorize_and_capture_with_recurring - @credit_card.verification_value = "" + @credit_card.verification_value = '' response = @gateway.authorize(@amount, @credit_card, @options.merge(recurring: true)) assert_success response - assert_equal "Succeeded", response.message + assert_equal 'Succeeded', response.message assert_match %r(^\w+\|.+$), response.authorization capture = @gateway.capture(@amount, response.authorization) assert_success capture - assert_equal "Succeeded", capture.message + assert_equal 'Succeeded', capture.message end def test_partial_capture response = @gateway.authorize(@amount, @credit_card, @options) capture = @gateway.capture(100, response.authorization) assert_success capture - assert_equal "Succeeded", capture.message + assert_equal 'Succeeded', capture.message end def test_failed_authorize response = @gateway.authorize(@amount, @declined_card, @options) assert_failure response - assert_equal "AS stellt falsches Routing fest", response.message - assert_equal "ipg92", response.params["transactionResultCode"] + assert_equal 'AS stellt falsches Routing fest', response.message + assert_equal 'ipg92', response.params['transactionResultCode'] end def test_failed_capture - response = @gateway.capture(@amount, "1|2") + response = @gateway.capture(@amount, '1|2') assert_failure response - assert_equal "\"sessionId\" with the value \"1\" does not exist", response.message - assert_equal "3110", response.params["error"] + assert_equal '"sessionId" with the value "1" does not exist', response.message + assert_equal '3110', response.params['error'] end def test_successful_void_for_purchase response = @gateway.purchase(@amount, @credit_card, @options) assert_success response - assert_equal "Succeeded", response.message + assert_equal 'Succeeded', response.message void = @gateway.void(response.authorization) assert_success void - assert_equal "Succeeded", void.message + assert_equal 'Succeeded', void.message end def test_successful_authorize_and_capture_and_refund response = @gateway.authorize(@amount, @credit_card, @options.merge(recurring: false)) assert_success response - assert_equal "Succeeded", response.message + assert_equal 'Succeeded', response.message assert_match %r(^\w+\|.+$), response.authorization capture = @gateway.capture(@amount, response.authorization) assert_success capture - assert_equal "Succeeded", capture.message + assert_equal 'Succeeded', capture.message refund = @gateway.refund(@amount, capture.authorization) assert_success refund - assert_equal "Succeeded", refund.message + assert_equal 'Succeeded', refund.message end def test_failed_void - response = @gateway.void("") + response = @gateway.void('') assert_failure response - assert_equal "\"transactionId\" is empty", response.message - assert_equal "3101", response.params["error"] + assert_equal '"transactionId" is empty', response.message + assert_equal '3101', response.params['error'] end def test_successful_refund @@ -116,26 +116,26 @@ def test_successful_refund refund = @gateway.refund(@amount, response.authorization) assert_success refund - assert_equal "Succeeded", refund.message + assert_equal 'Succeeded', refund.message end def test_failed_refund - response = @gateway.refund(nil, "") + response = @gateway.refund(nil, '') assert_failure response - assert_equal "\"transactionId\" is empty", response.message - assert_equal "3101", response.params["error"] + assert_equal '"transactionId" is empty', response.message + assert_equal '3101', response.params['error'] end def test_successful_verify response = @gateway.verify(@credit_card, @options) assert_success response - assert_match "Succeeded", response.message + assert_match 'Succeeded', response.message end def test_failed_verify response = @gateway.verify(@declined_card, @options) assert_failure response - assert_equal "AS stellt falsches Routing fest", response.message + assert_equal 'AS stellt falsches Routing fest', response.message end def test_transcript_scrubbing diff --git a/test/remote/gateways/remote_migs_test.rb b/test/remote/gateways/remote_migs_test.rb index 2214f8626c7..077762dc30b 100644 --- a/test/remote/gateways/remote_migs_test.rb +++ b/test/remote/gateways/remote_migs_test.rb @@ -10,16 +10,25 @@ def setup @amount = 100 @declined_amount = 105 - @visa = credit_card('4005550000000001', :month => 5, :year => 2017, :brand => 'visa') - @master = credit_card('5123456789012346', :month => 5, :year => 2017, :brand => 'master') - @amex = credit_card('371449635311004', :month => 5, :year => 2017, :brand => 'american_express') - @diners = credit_card('30123456789019', :month => 5, :year => 2017, :brand => 'diners_club') + @visa = credit_card('4987654321098769', :month => 5, :year => 2021, :brand => 'visa') + @master = credit_card('5123456789012346', :month => 5, :year => 2021, :brand => 'master') + @amex = credit_card('371449635311004', :month => 5, :year => 2021, :brand => 'american_express') + @diners = credit_card('30123456789019', :month => 5, :year => 2021, :brand => 'diners_club') @credit_card = @visa @options = { :order_id => '1', :currency => 'SAR' } + + @three_ds_options = { + :VerType => '3DS', + :VerToken => 'AAACAFBEUBgoAhEAIURQAAAAAAA=', + '3DSXID' => 'NWJlZDJmYzkyMTU1NGEwNzk1YjA=', + '3DSECI' => '02', + '3DSenrolled' => 'Y', + '3DSstatus' => 'A' + } end def test_server_purchase_url @@ -32,13 +41,11 @@ def test_server_purchase_url choice_url = @gateway.purchase_offsite_url(@amount, options) - assert_response_match /Pay securely .* by clicking on the card logo below/, choice_url + assert_response_match(/Pay securely .* by clicking on the card logo below/, choice_url) responses = { 'visa' => /You have chosen .*VISA.*/, - 'master' => /You have chosen .*MasterCard.*/, - 'diners_club' => /You have chosen .*Diners Club.*/, - 'american_express' => /You have chosen .*American Express.*/ + 'master' => /You have chosen .*MasterCard.*/ } responses.each_pair do |card_type, response_text| @@ -76,6 +83,12 @@ def test_authorize_and_void assert_equal 'Approved', void.message end + def test_verify + assert verify = @gateway.verify(@credit_card, @options) + assert_success verify + assert_equal 'Approved', verify.message + end + def test_failed_authorize assert response = @gateway.authorize(@declined_amount, @credit_card, @options) assert_failure response @@ -83,11 +96,12 @@ def test_failed_authorize end def test_refund - assert payment_response = @gateway.purchase(@amount, @credit_card, @options) - assert_success payment_response - assert response = @gateway.refund(@amount, payment_response.authorization, @options) - assert_success response - assert_equal 'Approved', response.message + # skip "Refunds are not working in the testing envirnment" + # assert payment_response = @gateway.purchase(@amount, @credit_card, @options) + # assert_success payment_response + # assert response = @gateway.refund(@amount, payment_response.authorization, @options) + # refute_success response + # assert_equal 'Approved', response.message end def test_status @@ -104,6 +118,45 @@ def test_invalid_login assert_equal 'Required field vpc_Merchant was not present in the request', response.message end + def test_transcript_scrubbing + transcript = capture_transcript(@gateway) do + @gateway.purchase(@amount, @credit_card, @options) + end + transcript = @gateway.scrub(transcript) + + assert_scrubbed(@credit_card.number, transcript) + assert_scrubbed(@credit_card.verification_value, transcript) + assert_scrubbed(@gateway.options[:password], transcript) + end + + def test_transcript_scrubbing_of_advanced_password + gateway = MigsGateway.new(fixtures(:migs).merge(advanced_login: 'advlogin', advanced_password: 'advpass')) + purchase = gateway.purchase(@amount, @credit_card, @options) + + transcript = capture_transcript(@gateway) do + gateway.refund(@amount, purchase.authorization, @options) + end + transcript = @gateway.scrub(transcript) + + assert_scrubbed(@credit_card.number, transcript) + assert_scrubbed(@credit_card.verification_value, transcript) + assert_scrubbed(@gateway.options[:advanced_password], transcript) + end + + def test_transcript_scrubbing_of_3ds_cavv_and_xid_values + opts = @options.merge(@three_ds_options) + + transcript = capture_transcript(@gateway) do + @gateway.purchase(@amount, @credit_card, opts) + end + transcript = @gateway.scrub(transcript) + + assert_scrubbed(@credit_card.number, transcript) + assert_scrubbed(@credit_card.verification_value, transcript) + assert_scrubbed(opts[:VerToken], transcript) + assert_scrubbed(opts['3DSXID'], transcript) + end + private def assert_response_match(regexp, url) diff --git a/test/remote/gateways/remote_modern_payments_cim_test.rb b/test/remote/gateways/remote_modern_payments_cim_test.rb index efd3bec9c6f..8c310d0fe17 100644 --- a/test/remote/gateways/remote_modern_payments_cim_test.rb +++ b/test/remote/gateways/remote_modern_payments_cim_test.rb @@ -1,47 +1,46 @@ require 'test_helper' class RemoteModernPaymentsCimTest < Test::Unit::TestCase - def setup @gateway = ModernPaymentsCimGateway.new(fixtures(:modern_payments)) - + @amount = 100 @credit_card = credit_card('4111111111111111') @declined_card = credit_card('4000000000000000') - - @options = { + + @options = { :billing_address => address, :customer => 'JIMSMITH2000' } end - + def test_successful_create_customer response = @gateway.create_customer(@options) assert_success response - assert !response.params["create_customer_result"].blank? + assert !response.params['create_customer_result'].blank? end - + def test_successful_modify_customer_credit_card customer = @gateway.create_customer(@options) assert_success customer - - customer_id = customer.params["create_customer_result"] - + + customer_id = customer.params['create_customer_result'] + credit_card = @gateway.modify_customer_credit_card(customer_id, @credit_card) assert_success credit_card - assert !credit_card.params["modify_customer_credit_card_result"].blank? + assert !credit_card.params['modify_customer_credit_card_result'].blank? end - + def test_succsessful_authorize_credit_card_payment customer = @gateway.create_customer(@options) assert_success customer - - customer_id = customer.params["create_customer_result"] - + + customer_id = customer.params['create_customer_result'] + credit_card = @gateway.modify_customer_credit_card(customer_id, @credit_card) assert_success credit_card - + payment = @gateway.authorize_credit_card_payment(customer_id, @amount) assert_success payment end diff --git a/test/remote/gateways/remote_modern_payments_test.rb b/test/remote/gateways/remote_modern_payments_test.rb index b4b5822a149..e0fff6eeb95 100644 --- a/test/remote/gateways/remote_modern_payments_test.rb +++ b/test/remote/gateways/remote_modern_payments_test.rb @@ -14,7 +14,6 @@ def setup :billing_address => address, :description => 'Store Purchase' } - end def test_successful_purchase @@ -22,24 +21,14 @@ def test_successful_purchase # Test mode seems to not return "approved = true" assert_failure response - assert_match %r{RESPONSECODE=A}, response.params["auth_string"] + assert_match %r{RESPONSECODE=A}, response.params['auth_string'] assert_equal ModernPaymentsCimGateway::FAILURE_MESSAGE, response.message end def test_unsuccessful_purchase assert response = @gateway.purchase(@amount, @declined_card, @options) assert_failure response - assert_match %r{RESPONSECODE=D}, response.params["auth_string"] - assert_equal ModernPaymentsCimGateway::FAILURE_MESSAGE, response.message - end - - def test_invalid_login - gateway = ModernPaymentsGateway.new( - :login => '5000', - :password => 'password' - ) - assert response = gateway.purchase(@amount, @credit_card, @options) - assert_failure response + assert_match %r{RESPONSECODE=D}, response.params['auth_string'] assert_equal ModernPaymentsCimGateway::FAILURE_MESSAGE, response.message end @@ -53,5 +42,4 @@ def test_invalid_login gateway.purchase(@amount, @credit_card, @options) end end - end diff --git a/test/remote/gateways/remote_moneris_test.rb b/test/remote/gateways/remote_moneris_test.rb index 8d0bc4cc103..1e4308bc62d 100644 --- a/test/remote/gateways/remote_moneris_test.rb +++ b/test/remote/gateways/remote_moneris_test.rb @@ -8,9 +8,9 @@ def setup @amount = 100 @credit_card = credit_card('4242424242424242') @options = { - :order_id => generate_unique_id, - :customer => generate_unique_id, - :billing_address => address + :order_id => generate_unique_id, + :customer => generate_unique_id, + :billing_address => address } end @@ -21,9 +21,66 @@ def test_successful_purchase assert_false response.authorization.blank? end + def test_successful_first_purchase_with_credential_on_file + gateway = MonerisGateway.new(fixtures(:moneris).merge(cof_enabled: true)) + assert response = gateway.purchase(@amount, @credit_card, @options.merge(issuer_id: '', payment_indicator: 'C', payment_information: '0')) + assert_success response + assert_equal 'Approved', response.message + assert_false response.authorization.blank? + assert_not_empty response.params['issuer_id'] + end + + def test_successful_purchase_with_cof_enabled_and_no_cof_options + gateway = MonerisGateway.new(fixtures(:moneris).merge(cof_enabled: true)) + assert response = gateway.purchase(@amount, @credit_card, @options) + assert_success response + assert_equal 'Approved', response.message + assert_false response.authorization.blank? + end + + def test_successful_non_cof_purchase_with_cof_enabled_and_only_issuer_id_sent + gateway = MonerisGateway.new(fixtures(:moneris).merge(cof_enabled: true)) + assert response = gateway.purchase(@amount, @credit_card, @options.merge(issuer_id: '')) + assert_success response + assert_equal 'Approved', response.message + assert_false response.authorization.blank? + assert_nil response.params['issuer_id'] + end + + def test_successful_subsequent_purchase_with_credential_on_file + gateway = MonerisGateway.new(fixtures(:moneris).merge(cof_enabled: true)) + assert response = gateway.authorize( + @amount, + @credit_card, + @options.merge( + issuer_id: '', + payment_indicator: 'C', + payment_information: '0' + ) + ) + assert_success response + assert_equal 'Approved', response.message + assert_false response.authorization.blank? + + assert response2 = gateway.purchase( + @amount, + @credit_card, + @options.merge( + order_id: response.authorization, + issuer_id: response.params['issuer_id'], + payment_indicator: 'U', + payment_information: '2' + ) + ) + assert_success response2 + assert_equal 'Approved', response2.message + assert_false response2.authorization.blank? + end + def test_successful_purchase_with_network_tokenization - @credit_card = network_tokenization_credit_card('4242424242424242', - payment_cryptogram: "BwABB4JRdgAAAAAAiFF2AAAAAAA=", + @credit_card = network_tokenization_credit_card( + '4242424242424242', + payment_cryptogram: 'BwABB4JRdgAAAAAAiFF2AAAAAAA=', verification_value: nil ) assert response = @gateway.purchase(@amount, @credit_card, @options) @@ -32,6 +89,19 @@ def test_successful_purchase_with_network_tokenization assert_false response.authorization.blank? end + def test_successful_purchase_with_network_tokenization_apple_pay_source + @credit_card = network_tokenization_credit_card( + '4242424242424242', + payment_cryptogram: 'BwABB4JRdgAAAAAAiFF2AAAAAAA=', + verification_value: nil, + source: :apple_pay + ) + assert response = @gateway.purchase(@amount, @credit_card, @options) + assert_success response + assert_equal 'Approved', response.message + assert_false response.authorization.blank? + end + def test_successful_authorization response = @gateway.authorize(@amount, @credit_card, @options) assert_success response @@ -74,8 +144,9 @@ def test_successful_authorization_and_void end def test_successful_authorization_with_network_tokenization - @credit_card = network_tokenization_credit_card('4242424242424242', - payment_cryptogram: "BwABB4JRdgAAAAAAiFF2AAAAAAA=", + @credit_card = network_tokenization_credit_card( + '4242424242424242', + payment_cryptogram: 'BwABB4JRdgAAAAAAiFF2AAAAAAA=', verification_value: nil ) assert response = @gateway.authorize(@amount, @credit_card, @options) @@ -117,38 +188,38 @@ def test_failed_purchase_from_error def test_successful_verify response = @gateway.verify(@credit_card, @options) assert_success response - assert_match "Approved", response.message + assert_match 'Approved', response.message end def test_successful_store assert response = @gateway.store(@credit_card) assert_success response - assert_equal "Successfully registered cc details", response.message - assert response.params["data_key"].present? - @data_key = response.params["data_key"] + assert_equal 'Successfully registered cc details', response.message + assert response.params['data_key'].present? + @data_key = response.params['data_key'] end def test_successful_unstore test_successful_store assert response = @gateway.unstore(@data_key) assert_success response - assert_equal "Successfully deleted cc details", response.message - assert response.params["data_key"].present? + assert_equal 'Successfully deleted cc details', response.message + assert response.params['data_key'].present? end def test_update test_successful_store assert response = @gateway.update(@data_key, @credit_card) assert_success response - assert_equal "Successfully updated cc details", response.message - assert response.params["data_key"].present? + assert_equal 'Successfully updated cc details', response.message + assert response.params['data_key'].present? end def test_successful_purchase_with_vault test_successful_store assert response = @gateway.purchase(@amount, @data_key, @options) assert_success response - assert_equal "Approved", response.message + assert_equal 'Approved', response.message assert_false response.authorization.blank? end @@ -190,10 +261,10 @@ def test_avs_result_valid_when_enabled assert response = gateway.purchase(1010, @credit_card, @options) assert_success response assert_equal(response.avs_result, { - 'code' => 'A', - 'message' => 'Street address matches, but 5-digit and 9-digit postal code do not match.', - 'street_match' => 'Y', - 'postal_match' => 'N' + 'code' => 'A', + 'message' => 'Street address matches, but 5-digit and 9-digit postal code do not match.', + 'street_match' => 'Y', + 'postal_match' => 'N' }) end @@ -203,10 +274,10 @@ def test_avs_result_nil_when_address_absent assert response = gateway.purchase(1010, @credit_card, @options.tap { |x| x.delete(:billing_address) }) assert_success response assert_equal(response.avs_result, { - 'code' => nil, - 'message' => nil, - 'street_match' => nil, - 'postal_match' => nil + 'code' => nil, + 'message' => nil, + 'street_match' => nil, + 'postal_match' => nil }) end @@ -214,14 +285,14 @@ def test_avs_result_nil_when_efraud_disabled assert response = @gateway.purchase(@amount, @credit_card, @options) assert_success response assert_equal(response.avs_result, { - 'code' => nil, - 'message' => nil, - 'street_match' => nil, - 'postal_match' => nil + 'code' => nil, + 'message' => nil, + 'street_match' => nil, + 'postal_match' => nil }) end - def test_purchase_scrubbing + def test_purchase_scrubbing transcript = capture_transcript(@gateway) do @gateway.purchase(@amount, @credit_card, @options) end diff --git a/test/remote/gateways/remote_moneris_us_test.rb b/test/remote/gateways/remote_moneris_us_test.rb index 51b75e843e9..75bbf7cf52d 100644 --- a/test/remote/gateways/remote_moneris_us_test.rb +++ b/test/remote/gateways/remote_moneris_us_test.rb @@ -12,6 +12,11 @@ def setup :billing_address => address, :description => 'Store Purchase' } + @check = check({ + routing_number: '011000015', + account_number: '1234455', + number: 123 + }) end def test_successful_purchase @@ -21,6 +26,21 @@ def test_successful_purchase assert_false response.authorization.blank? end + def test_successful_echeck_purchase + response = @gateway.purchase(@amount, @check, @options) + assert_success response + assert response.test? + assert_equal 'Registered', response.message + assert response.authorization + end + + def test_failed_echeck_purchase + response = @gateway.purchase(105, check(routing_number: 5), @options) + assert_failure response + assert response.test? + assert_equal 'Unspecified error', response.message + end + def test_successful_authorization response = @gateway.authorize(@amount, @credit_card, @options) assert_success response @@ -30,7 +50,7 @@ def test_successful_authorization def test_successful_verify response = @gateway.verify(@credit_card, @options) assert_success response - assert_equal "Approved", response.message + assert_equal 'Approved', response.message assert response.authorization end @@ -98,32 +118,56 @@ def test_failed_purchase_from_error def test_successful_store assert response = @gateway.store(@credit_card) assert_success response - assert_equal "Successfully registered cc details", response.message - assert response.params["data_key"].present? - @data_key = response.params["data_key"] + assert_equal 'Successfully registered cc details', response.message + assert response.params['data_key'].present? + @data_key = response.params['data_key'] + end + + def test_successful_echeck_store + assert response = @gateway.store(@check) + assert_success response + assert_equal 'Successfully registered ach details', response.message + assert response.params['data_key'].present? + @data_key_echeck = response.params['data_key'] end def test_successful_unstore test_successful_store assert response = @gateway.unstore(@data_key) assert_success response - assert_equal "Successfully deleted cc details", response.message - assert response.params["data_key"].present? + assert_equal 'Successfully deleted cc details', response.message + assert response.params['data_key'].present? + end + + def test_successful_echeck_unstore + test_successful_echeck_store + assert response = @gateway.unstore(@data_key_echeck) + assert_success response + assert_equal 'Successfully deleted ach details', response.message + assert response.params['data_key'].present? end def test_update test_successful_store assert response = @gateway.update(@data_key, @credit_card) assert_success response - assert_equal "Successfully updated cc details", response.message - assert response.params["data_key"].present? + assert_equal 'Successfully updated cc details', response.message + assert response.params['data_key'].present? + end + + def test_echeck_update + test_successful_echeck_store + assert response = @gateway.update(@data_key_echeck, @check) + assert_success response + assert_equal 'Successfully updated ach details', response.message + assert response.params['data_key'].present? end def test_successful_purchase_with_vault test_successful_store assert response = @gateway.purchase(@amount, @data_key, @options) assert_success response - assert_equal "Approved", response.message + assert_equal 'Approved', response.message assert_false response.authorization.blank? end @@ -203,4 +247,15 @@ def test_avs_result_nil_when_efraud_disabled }) end + def test_transcript_scrubbing + transcript = capture_transcript(@gateway) do + @gateway.purchase(@amount, @credit_card, @options) + end + transcript = @gateway.scrub(transcript) + + assert_scrubbed(@credit_card.number, transcript) + assert_scrubbed(@credit_card.verification_value, transcript) + assert_scrubbed(@gateway.options[:password], transcript) + end + end diff --git a/test/remote/gateways/remote_money_movers_test.rb b/test/remote/gateways/remote_money_movers_test.rb index 963cc775f54..64165cb50d8 100644 --- a/test/remote/gateways/remote_money_movers_test.rb +++ b/test/remote/gateways/remote_money_movers_test.rb @@ -19,54 +19,54 @@ def setup def test_successful_purchase assert response = @gateway.purchase(@amount, @credit_card, @options) assert_success response - assert_equal "Transaction Approved", response.message + assert_equal 'Transaction Approved', response.message end def test_unsuccessful_purchase assert response = @gateway.purchase(@declined_amount, @credit_card, @options) assert_failure response - assert_equal "Transaction Declined", response.message + assert_equal 'Transaction Declined', response.message end def test_successful_authorization assert response = @gateway.authorize(@amount, @credit_card, @options) assert_success response - assert_equal "Transaction Approved", response.message + assert_equal 'Transaction Approved', response.message end def test_failed_capture assert response = @gateway.capture(@amount, '') assert_failure response - assert_equal "Error in transaction data or system error", response.message + assert_equal 'Error in transaction data or system error', response.message end def test_purchase_and_refund assert auth = @gateway.purchase(@amount, @credit_card, @options) assert_success auth - assert_equal "Transaction Approved", auth.message + assert_equal 'Transaction Approved', auth.message assert auth.authorization assert capture = @gateway.refund(@amount, auth.authorization) - assert_equal "Transaction Approved", capture.message + assert_equal 'Transaction Approved', capture.message assert_success capture end def test_authorize_and_void assert auth = @gateway.authorize(@amount, @credit_card, @options) assert_success auth - assert_equal "Transaction Approved", auth.message + assert_equal 'Transaction Approved', auth.message assert auth.authorization assert capture = @gateway.void(auth.authorization) - assert_equal "Transaction Approved", capture.message + assert_equal 'Transaction Approved', capture.message assert_success capture end def test_authorize_and_capture assert auth = @gateway.authorize(@amount, @credit_card, @options) assert_success auth - assert_equal "Transaction Approved", auth.message + assert_equal 'Transaction Approved', auth.message assert auth.authorization assert capture = @gateway.capture(@amount, auth.authorization) - assert_equal "Transaction Approved", capture.message + assert_equal 'Transaction Approved', capture.message assert_success capture end @@ -77,6 +77,6 @@ def test_invalid_login ) assert response = gateway.purchase(@amount, @credit_card, @options) assert_failure response - assert_equal "Error in transaction data or system error", response.message + assert_equal 'Error in transaction data or system error', response.message end end diff --git a/test/remote/gateways/remote_mundipagg_test.rb b/test/remote/gateways/remote_mundipagg_test.rb new file mode 100644 index 00000000000..39846fea222 --- /dev/null +++ b/test/remote/gateways/remote_mundipagg_test.rb @@ -0,0 +1,171 @@ +require 'test_helper' + +class RemoteMundipaggTest < Test::Unit::TestCase + def setup + @gateway = MundipaggGateway.new(fixtures(:mundipagg)) + + @amount = 100 + @credit_card = credit_card('4000100011112224') + @declined_card = credit_card('4000300011112220') + @voucher = credit_card('60607044957644', brand: 'sodexo') + @options = { + billing_address: address({neighborhood: 'Sesame Street'}), + description: 'Store Purchase' + } + end + + def test_successful_purchase + response = @gateway.purchase(@amount, @credit_card, @options) + assert_success response + assert_equal 'Simulator|Transação de simulação autorizada com sucesso', response.message + end + + def test_successful_purchase_no_address + @options.delete(:billing_address) + response = @gateway.purchase(@amount, @credit_card, @options) + assert_success response + assert_equal 'Simulator|Transação de simulação autorizada com sucesso', response.message + end + + def test_successful_purchase_with_more_options + options = @options.update({ + order_id: '1', + ip: '127.0.0.1', + email: 'joe@example.com', + shipping_address: address + }) + + response = @gateway.purchase(@amount, @credit_card, options) + assert_success response + end + + def test_successful_purchase_with_voucher + @options.update(holder_document: '93095135270') + response = @gateway.purchase(@amount, @voucher, @options) + assert_success response + assert_equal 'Simulator|Transação de simulação autorizada com sucesso', response.message + end + + def test_failed_purchase + response = @gateway.purchase(105200, @declined_card, @options) + assert_failure response + assert_equal 'Simulator|Transação de simulada negada por falta de crédito, utilizado para realizar simulação de autorização parcial.', response.message + end + + def test_successful_authorize_and_capture + auth = @gateway.authorize(@amount, @credit_card, @options) + assert_success auth + + assert capture = @gateway.capture(@amount, auth.authorization) + assert_success capture + assert_equal 'Simulator|Transação de simulação capturada com sucesso', capture.message + end + + def test_failed_authorize + response = @gateway.authorize(105200, @declined_card, @options) + assert_failure response + assert_equal 'Simulator|Transação de simulada negada por falta de crédito, utilizado para realizar simulação de autorização parcial.', response.message + end + + def test_partial_capture + auth = @gateway.authorize(@amount, @credit_card, @options) + assert_success auth + + assert capture = @gateway.capture(@amount-1, auth.authorization) + assert_success capture + end + + def test_failed_capture + response = @gateway.capture(@amount, 'abc') + assert_failure response + assert_equal 'The requested resource does not exist; Charge not found.', response.message + end + + def test_successful_refund + purchase = @gateway.purchase(@amount, @credit_card, @options) + assert_success purchase + + assert refund = @gateway.refund(@amount, purchase.authorization) + assert_success refund + end + + def test_partial_refund + purchase = @gateway.purchase(@amount, @credit_card, @options) + assert_success purchase + + assert refund = @gateway.refund(@amount - 1, purchase.authorization) + assert_success refund + end + + def test_failed_refund + response = @gateway.refund(@amount, 'abc') + assert_failure response + assert_equal 'The requested resource does not exist; Charge not found.', response.message + end + + def test_successful_void + auth = @gateway.authorize(@amount, @credit_card, @options) + assert_success auth + + assert void = @gateway.void(auth.authorization) + assert_success void + end + + def test_successful_void_with_voucher + @options.update(holder_document: '93095135270') + auth = @gateway.purchase(@amount, @voucher, @options) + assert_success auth + + assert void = @gateway.void(auth.authorization) + assert_success void + end + + def test_successful_refund_with_voucher + @options.update(holder_document: '93095135270') + auth = @gateway.purchase(@amount, @voucher, @options) + assert_success auth + + assert void = @gateway.refund(1, auth.authorization) + assert_success void + end + + def test_failed_void + response = @gateway.void('abc') + assert_failure response + assert_equal 'The requested resource does not exist; Charge not found.', response.message + end + + def test_successful_verify + response = @gateway.verify(@credit_card, @options) + assert_success response + assert_match %r{Simulator|Transação de simulação autorizada com sucesso}, response.message + end + + def test_successful_store_and_purchase + store = @gateway.store(@credit_card, @options) + assert_success store + + assert purchase = @gateway.purchase(@amount, store.authorization, @options) + assert_success purchase + assert_equal 'Simulator|Transação de simulação autorizada com sucesso', purchase.message + end + + def test_invalid_login + gateway = MundipaggGateway.new(api_key: '') + + response = gateway.purchase(@amount, @credit_card, @options) + assert_failure response + assert_match %r{Invalid API key; Authorization has been denied for this request.}, response.message + end + + def test_transcript_scrubbing + transcript = capture_transcript(@gateway) do + @gateway.purchase(@amount, @credit_card, @options) + end + transcript = @gateway.scrub(transcript) + + assert_scrubbed(@credit_card.number, transcript) + assert_scrubbed(@credit_card.verification_value, transcript) + assert_scrubbed(@gateway.options[:api_key], transcript) + end +end diff --git a/test/remote/gateways/remote_nab_transact_test.rb b/test/remote/gateways/remote_nab_transact_test.rb index 5eb8eac4b33..55289ec9ff0 100644 --- a/test/remote/gateways/remote_nab_transact_test.rb +++ b/test/remote/gateways/remote_nab_transact_test.rb @@ -31,16 +31,16 @@ def test_successful_purchase end def test_unsuccessful_purchase_insufficient_funds - #Any total not ending in 00/08/11/16 - failing_amount = 151 #Specifically tests 'Insufficient Funds' + # Any total not ending in 00/08/11/16 + failing_amount = 151 # Specifically tests 'Insufficient Funds' assert response = @gateway.purchase(failing_amount, @credit_card, @options) assert_failure response assert_equal 'Insufficient Funds', response.message end def test_unsuccessful_purchase_do_not_honour - #Any total not ending in 00/08/11/16 - failing_amount = 105 #Specifically tests 'do not honour' + # Any total not ending in 00/08/11/16 + failing_amount = 105 # Specifically tests 'do not honour' assert response = @gateway.purchase(failing_amount, @credit_card, @options) assert_failure response assert_equal 'Do Not Honour', response.message @@ -177,7 +177,7 @@ def test_failed_refund authorization = response.authorization assert response = @gateway.refund(@amount+1, authorization) assert_failure response - assert_equal 'Only $2.0 available for refund', response.message + assert_equal 'Only 2.00 AUD available for refund', response.message end def test_invalid_login @@ -222,7 +222,7 @@ def test_unstore assert card_id = response.authorization assert unstore_response = @gateway.unstore(card_id) assert_success unstore_response - assert_equal "Successful", unstore_response.message + assert_equal 'Successful', unstore_response.message end def test_successful_purchase_using_stored_card @@ -246,7 +246,7 @@ def test_failure_trigger_purchase purchase_response = @gateway.purchase(trigger_amount, gateway_id) - assert gateway_id = purchase_response.params["crn"] + assert purchase_response.params['crn'] assert_failure purchase_response assert_equal 'Invalid Amount', purchase_response.message end diff --git a/test/remote/gateways/remote_net_registry_test.rb b/test/remote/gateways/remote_net_registry_test.rb index c97ddc7dd91..aeadc59b83d 100644 --- a/test/remote/gateways/remote_net_registry_test.rb +++ b/test/remote/gateways/remote_net_registry_test.rb @@ -58,8 +58,8 @@ def test_successful_authorization_and_capture assert_match(/\A\d{6}\z/, response.authorization) response = @gateway.capture(@amount, - response.authorization, - :credit_card => @valid_creditcard) + response.authorization, + :credit_card => @valid_creditcard) assert_success response assert_equal 'approved', response.params['status'] end diff --git a/test/remote/gateways/remote_netaxept_test.rb b/test/remote/gateways/remote_netaxept_test.rb index a7ea2c36715..0ae763f5876 100644 --- a/test/remote/gateways/remote_netaxept_test.rb +++ b/test/remote/gateways/remote_netaxept_test.rb @@ -20,24 +20,24 @@ def test_successful_purchase end def test_failed_purchase - assert response = @gateway.purchase(@amount, @declined_card, @options) - assert_failure response - assert_match(/failure/i, response.message) + assert response = @gateway.purchase(@amount, @declined_card, @options) + assert_failure response + assert_match(/failure/i, response.message) end def test_authorize_and_capture - assert auth = @gateway.authorize(@amount, @credit_card, @options) - assert_success auth - assert_equal 'OK', auth.message - assert auth.authorization - assert capture = @gateway.capture(@amount, auth.authorization) - assert_success capture + assert auth = @gateway.authorize(@amount, @credit_card, @options) + assert_success auth + assert_equal 'OK', auth.message + assert auth.authorization + assert capture = @gateway.capture(@amount, auth.authorization) + assert_success capture end def test_failed_capture - assert response = @gateway.capture(@amount, '') - assert_failure response - assert_equal "Unable to find transaction", response.message + assert response = @gateway.capture(@amount, '') + assert_failure response + assert_equal 'Unable to find transaction', response.message end def test_successful_refund @@ -49,12 +49,12 @@ def test_successful_refund end def test_failed_refund - assert response = @gateway.purchase(@amount, @credit_card, @options) - assert_success response + assert response = @gateway.purchase(@amount, @credit_card, @options) + assert_success response - response = @gateway.refund(@amount+100, response.authorization) - assert_failure response - assert_equal "Unable to credit more than captured amount", response.message + response = @gateway.refund(@amount+100, response.authorization) + assert_failure response + assert_equal 'Unable to credit more than captured amount', response.message end def test_successful_void @@ -66,12 +66,18 @@ def test_successful_void end def test_failed_void - assert response = @gateway.purchase(@amount, @credit_card, @options) - assert_success response + assert response = @gateway.purchase(@amount, @credit_card, @options) + assert_success response + + response = @gateway.void(response.authorization) + assert_failure response + assert_equal 'Unable to annul, wrong state', response.message + end - response = @gateway.void(response.authorization) - assert_failure response - assert_equal "Unable to annul, wrong state", response.message + def test_error_in_transaction_setup + assert response = @gateway.purchase(@amount, @credit_card, @options.merge(:currency => 'BOGG')) + assert_failure response + assert_match(/currency code/, response.message) end def test_successful_amex_purchase @@ -88,53 +94,33 @@ def test_successful_master_purchase assert_equal 'OK', response.message end - def test_error_in_transaction_setup - assert response = @gateway.purchase(@amount, @credit_card, @options.merge(:currency => 'BOGG')) - assert_failure response - assert_match(/currency code/, response.message) - end - - def test_successful_amex_purchase - credit_card = credit_card('378282246310005', :brand => 'american_express') - assert response = @gateway.purchase(@amount, credit_card, @options) - assert_success response - assert_equal 'OK', response.message - end - - def test_successful_master_purchase - credit_card = credit_card('5413000000000000', :brand => 'master') - assert response = @gateway.purchase(@amount, credit_card, @options) - assert_success response - assert_equal 'OK', response.message - end - def test_error_in_payment_details - assert response = @gateway.purchase(@amount, credit_card(''), @options) - assert_failure response - assert_equal "Cardnumber:Required", response.message + assert response = @gateway.purchase(@amount, credit_card(''), @options) + assert_failure response + assert_equal 'Cardnumber:Required', response.message end def test_amount_is_not_required_again_when_capturing_authorization - assert response = @gateway.authorize(@amount, @credit_card, @options) - assert_success response + assert response = @gateway.authorize(@amount, @credit_card, @options) + assert_success response - assert response = @gateway.capture(nil, response.authorization) - assert_equal "OK", response.message + assert response = @gateway.capture(nil, response.authorization) + assert_equal 'OK', response.message end def test_query_fails - query = @gateway.send(:query_transaction, "bogus", @options) + query = @gateway.send(:query_transaction, 'bogus', @options) assert_failure query assert_match(/unable to find/i, query.message) end def test_invalid_login - gateway = NetaxeptGateway.new( - :login => '', - :password => '' - ) - assert response = gateway.purchase(@amount, @credit_card, @options) - assert_failure response - assert_match(/Unable to authenticate merchant/, response.message) + gateway = NetaxeptGateway.new( + :login => '', + :password => '' + ) + assert response = gateway.purchase(@amount, @credit_card, @options) + assert_failure response + assert_match(/Unable to authenticate merchant/, response.message) end end diff --git a/test/remote/gateways/remote_netbanx_test.rb b/test/remote/gateways/remote_netbanx_test.rb index 5d2731659c1..19b4faddd5c 100644 --- a/test/remote/gateways/remote_netbanx_test.rb +++ b/test/remote/gateways/remote_netbanx_test.rb @@ -3,13 +3,13 @@ class RemoteNetbanxTest < Test::Unit::TestCase def setup @gateway = NetbanxGateway.new(fixtures(:netbanx)) - @amount = 100 @credit_card = credit_card('4530910000012345') @declined_amount = 11 @options = { billing_address: address, - description: 'Store Purchase' + description: 'Store Purchase', + currency: 'CAD' } end @@ -23,9 +23,9 @@ def test_successful_purchase def test_successful_purchase_with_more_options options = { order_id: SecureRandom.uuid, - ip: "127.0.0.1", + ip: '127.0.0.1', billing_address: address, - email: "joe@example.com" + email: 'joe@example.com' } response = @gateway.purchase(@amount, @credit_card, options) @@ -54,7 +54,7 @@ def test_successful_authorize_and_capture auth = @gateway.authorize(@amount, @credit_card, @options) assert_success auth - assert capture = @gateway.capture(@amount, auth.authorization) + assert capture = @gateway.capture(@amount, auth.authorization, @options) assert_success capture assert_equal 'OK', capture.message end @@ -63,7 +63,7 @@ def test_partial_capture auth = @gateway.authorize(@amount, @credit_card, @options) assert_success auth - assert capture = @gateway.capture(@amount-1, auth.authorization) + assert capture = @gateway.capture(@amount-1, auth.authorization, @options) assert_success capture end @@ -127,7 +127,7 @@ def test_failed_refund auth = @gateway.authorize(@amount, @credit_card, @options) assert_success auth - assert capture = @gateway.capture(@amount, auth.authorization) + assert capture = @gateway.capture(@amount, auth.authorization, @options) assert_success capture # the following shall fail if you run it immediately after the capture @@ -141,7 +141,7 @@ def test_successful_void auth = @gateway.authorize(@amount, @credit_card, @options) assert_success auth - assert void = @gateway.void(auth.authorization) + assert void = @gateway.void(auth.authorization, @options) assert_success void assert_equal 'OK', void.message end @@ -172,20 +172,20 @@ def test_transcript_scrubbing def test_successful_store merchant_customer_id = SecureRandom.hex - assert response = @gateway.store(@credit_card, locale: 'en_GB', merchant_customer_id: merchant_customer_id, email: "email@example.com") + assert response = @gateway.store(@credit_card, locale: 'en_GB', merchant_customer_id: merchant_customer_id, email: 'email@example.com') assert_success response - assert_equal merchant_customer_id, response.params["merchantCustomerId"] - first_card = response.params["cards"].first - assert_equal @credit_card.last_digits, first_card["lastDigits"] + assert_equal merchant_customer_id, response.params['merchantCustomerId'] + first_card = response.params['cards'].first + assert_equal @credit_card.last_digits, first_card['lastDigits'] end def test_successful_unstore merchant_customer_id = SecureRandom.hex - assert response = @gateway.store(@credit_card, locale: 'en_GB', merchant_customer_id: merchant_customer_id, email: "email@example.com") + assert response = @gateway.store(@credit_card, locale: 'en_GB', merchant_customer_id: merchant_customer_id, email: 'email@example.com') assert_success response - assert_equal merchant_customer_id, response.params["merchantCustomerId"] - first_card = response.params["cards"].first - assert_equal @credit_card.last_digits, first_card["lastDigits"] + assert_equal merchant_customer_id, response.params['merchantCustomerId'] + first_card = response.params['cards'].first + assert_equal @credit_card.last_digits, first_card['lastDigits'] identification = "#{response.params['id']}|#{first_card['id']}" assert unstore_card = @gateway.unstore(identification) assert_success unstore_card @@ -200,6 +200,6 @@ def test_successful_purchase_using_stored_card assert response = @gateway.purchase(@amount, store.authorization.split('|').last) assert_success response - assert_equal "OK", response.message + assert_equal 'OK', response.message end end diff --git a/test/remote/gateways/remote_network_merchants_test.rb b/test/remote/gateways/remote_network_merchants_test.rb index 020c6f1a676..290a0cad4c6 100644 --- a/test/remote/gateways/remote_network_merchants_test.rb +++ b/test/remote/gateways/remote_network_merchants_test.rb @@ -7,7 +7,7 @@ def setup @amount = 100 @decline_amount = 1 @credit_card = credit_card('4111111111111111') - @credit_card_with_track_data = credit_card_with_track_data("4111111111111111") + @credit_card_with_track_data = credit_card_with_track_data('4111111111111111') @check = check @options = { @@ -83,7 +83,7 @@ def test_void assert response = @gateway.void(purchase.authorization) assert_success response - assert_equal "Transaction Void Successful", response.message + assert_equal 'Transaction Void Successful', response.message end def test_refund @@ -93,7 +93,7 @@ def test_refund assert response = @gateway.refund(50, purchase.authorization) assert_success response - assert_equal "SUCCESS", response.message + assert_equal 'SUCCESS', response.message assert response.authorization end @@ -104,7 +104,7 @@ def test_refund_with_track_data assert response = @gateway.refund(50, purchase.authorization) assert_success response - assert_equal "SUCCESS", response.message + assert_equal 'SUCCESS', response.message assert response.authorization end @@ -123,7 +123,7 @@ def test_store_check end def test_store_failure - @credit_card.number = "123" + @credit_card.number = '123' assert store = @gateway.store(@credit_card, @options) assert_failure store assert store.message.include?('Invalid Credit Card Number') @@ -138,7 +138,7 @@ def test_unstore assert unstore = @gateway.unstore(store.params['customer_vault_id']) assert_success unstore - assert_equal "Customer Deleted", unstore.message + assert_equal 'Customer Deleted', unstore.message end def test_purchase_on_stored_card @@ -148,7 +148,7 @@ def test_purchase_on_stored_card assert purchase = @gateway.purchase(@amount, store.params['customer_vault_id'], @options) assert_success purchase - assert_equal "SUCCESS", purchase.message + assert_equal 'SUCCESS', purchase.message end def test_invalid_login diff --git a/test/remote/gateways/remote_nmi_test.rb b/test/remote/gateways/remote_nmi_test.rb index 241b0f819b5..e6d3701994a 100644 --- a/test/remote/gateways/remote_nmi_test.rb +++ b/test/remote/gateways/remote_nmi_test.rb @@ -9,6 +9,14 @@ def setup :routing_number => '123123123', :account_number => '123123123' ) + @apple_pay_card = network_tokenization_credit_card('4111111111111111', + :payment_cryptogram => 'EHuWW9PiBkWvqE5juRwDzAUFBAk=', + :month => '01', + :year => '2024', + :source => :apple_pay, + :eci => '5', + :transaction_id => '123456789' + ) @options = { :order_id => generate_unique_id, :billing_address => address, @@ -17,10 +25,10 @@ def setup end def test_invalid_login - @gateway = NmiGateway.new(login: "invalid", password: "no") + @gateway = NmiGateway.new(login: 'invalid', password: 'no') assert response = @gateway.purchase(@amount, @credit_card, @options) assert_failure response - assert_equal "Authentication Failed", response.message + assert_equal 'Authentication Failed', response.message end def test_successful_purchase @@ -62,6 +70,22 @@ def test_failed_purchase_with_echeck assert_equal 'FAILED', response.message end + def test_successful_purchase_with_apple_pay_card + assert @gateway.supports_network_tokenization? + assert response = @gateway.purchase(@amount, @apple_pay_card, @options) + assert_success response + assert response.test? + assert_equal 'Succeeded', response.message + assert response.authorization + end + + def test_failed_purchase_with_apple_pay_card + assert response = @gateway.purchase(99, @apple_pay_card, @options) + assert_failure response + assert response.test? + assert_equal 'DECLINE', response.message + end + def test_successful_authorization assert response = @gateway.authorize(@amount, @credit_card, @options) assert_success response @@ -86,7 +110,7 @@ def test_authorization_and_capture end def test_failed_capture - assert capture = @gateway.capture(@amount, "badauth") + assert capture = @gateway.capture(@amount, 'badauth') assert_failure capture end @@ -100,7 +124,7 @@ def test_authorization_and_void end def test_failed_void - assert void = @gateway.void("badauth") + assert void = @gateway.void('badauth') assert_failure void end @@ -123,7 +147,7 @@ def test_successful_refund end def test_failed_refund - assert response = @gateway.refund(@amount, "badauth") + assert response = @gateway.refund(@amount, 'badauth') assert_failure response end @@ -136,11 +160,10 @@ def test_successful_refund_with_echeck assert_equal 'Succeeded', response.message end - def test_successful_credit response = @gateway.credit(@amount, @credit_card, @options) assert_success response - assert_equal "Succeeded", response.message + assert_equal 'Succeeded', response.message end def test_failed_credit @@ -152,56 +175,56 @@ def test_failed_credit def test_successful_verify response = @gateway.verify(@credit_card, @options) assert_success response - assert_match "Succeeded", response.message + assert_match 'Succeeded', response.message end def test_failed_verify card = credit_card(year: 2010) response = @gateway.verify(card, @options) assert_failure response - assert_match "Invalid Credit Card", response.message + assert_match 'Invalid Credit Card', response.message end def test_successful_store response = @gateway.store(@credit_card, @options) assert_success response - assert_equal "Succeeded", response.message - assert response.params["customer_vault_id"] + assert_equal 'Succeeded', response.message + assert response.params['customer_vault_id'] end def test_failed_store card = credit_card(year: 2010) response = @gateway.store(card, @options) assert_failure response - assert_nil response.params["customer_vault_id"] + assert_nil response.params['customer_vault_id'] end def test_successful_store_with_echeck response = @gateway.store(@check, @options) assert_success response - assert_equal "Succeeded", response.message - assert response.params["customer_vault_id"] + assert_equal 'Succeeded', response.message + assert response.params['customer_vault_id'] end def test_successful_store_and_purchase - vault_id = @gateway.store(@credit_card, @options).params["customer_vault_id"] + vault_id = @gateway.store(@credit_card, @options).params['customer_vault_id'] purchase = @gateway.purchase(@amount, vault_id, @options) assert_success purchase - assert_equal "Succeeded", purchase.message + assert_equal 'Succeeded', purchase.message end def test_successful_store_and_auth - vault_id = @gateway.store(@credit_card, @options).params["customer_vault_id"] + vault_id = @gateway.store(@credit_card, @options).params['customer_vault_id'] auth = @gateway.authorize(@amount, vault_id, @options) assert_success auth - assert_equal "Succeeded", auth.message + assert_equal 'Succeeded', auth.message end def test_successful_store_and_credit - vault_id = @gateway.store(@credit_card, @options).params["customer_vault_id"] + vault_id = @gateway.store(@credit_card, @options).params['customer_vault_id'] credit = @gateway.credit(@amount, vault_id, @options) assert_success credit - assert_equal "Succeeded", credit.message + assert_equal 'Succeeded', credit.message end def test_merchant_defined_fields @@ -243,4 +266,17 @@ def test_check_transcript_scrubbing # "password=password is filtered, but can't be tested b/c of key match" # assert_scrubbed(@gateway.options[:password], clean_transcript) end + + def test_network_tokenization_transcript_scrubbing + transcript = capture_transcript(@gateway) do + @gateway.purchase(@amount, @apple_pay_card, @options) + end + clean_transcript = @gateway.scrub(transcript) + + assert_scrubbed(@apple_pay_card.number, clean_transcript) + assert_scrubbed(@apple_pay_card.payment_cryptogram, clean_transcript) + + # "password=password is filtered, but can't be tested b/c of key match" + # assert_scrubbed(@gateway.options[:password], clean_transcript) + end end diff --git a/test/remote/gateways/remote_ogone_test.rb b/test/remote/gateways/remote_ogone_test.rb index d5a369ebab6..3d2b878db33 100644 --- a/test/remote/gateways/remote_ogone_test.rb +++ b/test/remote/gateways/remote_ogone_test.rb @@ -1,4 +1,5 @@ # coding: utf-8 + require 'test_helper' class RemoteOgoneTest < Test::Unit::TestCase @@ -7,14 +8,15 @@ def setup @gateway = OgoneGateway.new(fixtures(:ogone)) @amount = 100 @credit_card = credit_card('4000100011112224') - @mastercard = credit_card('5399999999999999', :brand => "mastercard") + @mastercard = credit_card('5399999999999999', :brand => 'mastercard') @declined_card = credit_card('1111111111111111') @credit_card_d3d = credit_card('4000000000000002', :verification_value => '111') @options = { :order_id => generate_unique_id[0...30], :billing_address => address, :description => 'Store Purchase', - :currency => fixtures(:ogone)[:currency] || 'EUR' + :currency => fixtures(:ogone)[:currency] || 'EUR', + :origin => 'STORE' } end @@ -26,13 +28,13 @@ def test_successful_purchase end def test_successful_purchase_with_utf8_encoding_1 - assert response = @gateway.purchase(@amount, credit_card('4000100011112224', :first_name => "Rémy", :last_name => "Fröåïør"), @options) + assert response = @gateway.purchase(@amount, credit_card('4000100011112224', :first_name => 'Rémy', :last_name => 'Fröåïør'), @options) assert_success response assert_equal OgoneGateway::SUCCESS_MESSAGE, response.message end def test_successful_purchase_with_utf8_encoding_2 - assert response = @gateway.purchase(@amount, credit_card('4000100011112224', :first_name => "ワタシ", :last_name => "ёжзийклмнопрсуфхцч"), @options) + assert response = @gateway.purchase(@amount, credit_card('4000100011112224', :first_name => 'ワタシ', :last_name => 'ёжзийклмнопрсуфхцч'), @options) assert_success response assert_equal OgoneGateway::SUCCESS_MESSAGE, response.message end @@ -70,9 +72,9 @@ def test_successful_purchase_with_signature_encryptor_to_sha512 def test_successful_purchase_with_3d_secure assert response = @gateway.purchase(@amount, @credit_card_d3d, @options.merge(:d3d => true)) assert_success response - assert_equal '46', response.params["STATUS"] + assert_equal '46', response.params['STATUS'] assert_equal OgoneGateway::SUCCESS_MESSAGE, response.message - assert response.params["HTML_ANSWER"] + assert response.params['HTML_ANSWER'] end def test_successful_with_non_numeric_order_id @@ -208,24 +210,24 @@ def test_successful_credit def test_successful_verify response = @gateway.verify(@credit_card, @options) assert_success response - assert_equal "The transaction was successful", response.message + assert_equal 'The transaction was successful', response.message end def test_failed_verify response = @gateway.verify(@declined_card, @options) assert_failure response - assert_equal "No brand", response.message + assert_equal 'No brand', response.message end def test_reference_transactions # Setting an alias - assert response = @gateway.purchase(@amount, credit_card('4000100011112224'), @options.merge(:billing_id => "awesomeman", :order_id=>Time.now.to_i.to_s+"1")) + assert response = @gateway.purchase(@amount, credit_card('4000100011112224'), @options.merge(:billing_id => 'awesomeman', :order_id=>Time.now.to_i.to_s+'1')) assert_success response # Updating an alias - assert response = @gateway.purchase(@amount, credit_card('4111111111111111'), @options.merge(:billing_id => "awesomeman", :order_id=>Time.now.to_i.to_s+"2")) + assert response = @gateway.purchase(@amount, credit_card('4111111111111111'), @options.merge(:billing_id => 'awesomeman', :order_id=>Time.now.to_i.to_s+'2')) assert_success response # Using an alias (i.e. don't provide the credit card) - assert response = @gateway.purchase(@amount, "awesomeman", @options.merge(:order_id => Time.now.to_i.to_s + "3")) + assert response = @gateway.purchase(@amount, 'awesomeman', @options.merge(:order_id => Time.now.to_i.to_s + '3')) assert_success response end @@ -239,4 +241,15 @@ def test_invalid_login assert response = gateway.purchase(@amount, @credit_card, @options) assert_failure response end + + def test_transcript_scrubbing + transcript = capture_transcript(@gateway) do + @gateway.purchase(@amount, @credit_card, @options) + end + transcript = @gateway.scrub(transcript) + + assert_scrubbed(@credit_card.number, transcript) + assert_scrubbed(@credit_card.verification_value, transcript) + assert_scrubbed(@gateway.options[:password], transcript) + end end diff --git a/test/remote/gateways/remote_openpay_test.rb b/test/remote/gateways/remote_openpay_test.rb index bd44baa7b49..079b4d09279 100644 --- a/test/remote/gateways/remote_openpay_test.rb +++ b/test/remote/gateways/remote_openpay_test.rb @@ -21,10 +21,17 @@ def test_successful_purchase assert_nil response.message end + def test_successful_purchase_with_email + @options[:email] = '%d@example.org' % Time.now + assert response = @gateway.purchase(@amount, @credit_card, @options) + assert_success response + assert_nil response.message + end + def test_unsuccessful_purchase assert response = @gateway.purchase(@amount, @declined_card, @options) assert_failure response - assert_equal 'The card is not supported on online transactions', response.message + assert_equal 'The card was declined', response.message end def test_successful_refund @@ -52,10 +59,17 @@ def test_successful_authorize assert_nil response.message end + def test_successful_authorize_with_email + @options[:email] = '%d@example.org' % Time.now + assert response = @gateway.authorize(@amount, @credit_card, @options) + assert_success response + assert_nil response.message + end + def test_unsuccessful_authorize assert response = @gateway.authorize(@amount, @declined_card, @options) assert_failure response - assert_equal 'The card is not supported on online transactions', response.message + assert_equal 'The card was declined', response.message end def test_successful_capture @@ -106,6 +120,22 @@ def test_successful_purchase_with_device_session_id assert_success response end + def test_successful_purchase_with_card_points + assert response = @gateway.purchase(@amount, @credit_card, @options.merge(use_card_points: 'NONE')) + assert_success response + end + + def test_failed_purchase_with_card_points + assert response = @gateway.purchase(@amount, @credit_card, @options.merge(use_card_points: 'MIXED')) + assert_failure response + assert_match %r{cardNumber not allowed for Card points}, response.message + end + + def test_successful_purchase_with_installments + assert response = @gateway.purchase(@amount * 300, @store_card, @options.merge(payments: '3')) + assert_success response + end + def test_successful_store new_email_address = '%d@example.org' % Time.now assert response = @gateway.store(@credit_card, name: 'Test User', email: new_email_address) @@ -135,7 +165,7 @@ def test_successful_verify def test_unsuccessful_verify response = @gateway.verify(@declined_card, @options) assert_failure response - assert_match /The card is not supported/, response.message + assert_match(/The card was declined/, response.message) end def test_invalid_login @@ -170,7 +200,7 @@ def test_nil_cvv_scrubbing end def test_empty_string_cvv_scrubbing - @credit_card.verification_value = "" + @credit_card.verification_value = '' transcript = capture_transcript(@gateway) do @gateway.purchase(@amount, @credit_card, @options) end @@ -180,7 +210,7 @@ def test_empty_string_cvv_scrubbing end def test_whitespace_string_cvv_scrubbing - @credit_card.verification_value = " " + @credit_card.verification_value = ' ' transcript = capture_transcript(@gateway) do @gateway.purchase(@amount, @credit_card, @options) end diff --git a/test/remote/gateways/remote_opp_test.rb b/test/remote/gateways/remote_opp_test.rb index e5f00172bcd..652059e87ad 100644 --- a/test/remote/gateways/remote_opp_test.rb +++ b/test/remote/gateways/remote_opp_test.rb @@ -6,11 +6,11 @@ def setup @gateway = OppGateway.new(fixtures(:opp)) @amount = 100 - @valid_card = credit_card("4200000000000000", month: 05, year: 2018) - @invalid_card = credit_card("4444444444444444", month: 05, year: 2018) - @amex_card = credit_card("377777777777770 ", month: 05, year: 2018, brand: 'amex', verification_value: '1234') + @valid_card = credit_card('4200000000000000', month: 05, year: 2018) + @invalid_card = credit_card('4444444444444444', month: 05, year: 2018) + @amex_card = credit_card('377777777777770 ', month: 05, year: 2018, brand: 'amex', verification_value: '1234') - request_type = 'complete' # 'minimal' || 'complete' + request_type = 'complete' # 'minimal' || 'complete' time = Time.now.to_i ip = '101.102.103.104' @complete_request_options = { @@ -18,61 +18,70 @@ def setup merchant_transaction_id: "active_merchant_test_complete #{time}", address: address, description: 'Store Purchase - Books', -# riskWorkflow: true, -# testMode: 'EXTERNAL' # or 'INTERNAL', valid only for test system - - billing_address: { - address1: '123 Test Street', - city: 'Test', - state: 'TE', - zip: 'AB12CD', - country: 'GB', - }, - shipping_address: { - name: 'Muton DeMicelis', - address1: 'My Street On Upiter, Apt 3.14/2.78', - city: 'Munich', - state: 'Bov', - zip: '81675', - country: 'DE', - }, - customer: { - merchant_customer_id: "your merchant/customer id", - givenName: 'Jane', - surname: 'Jones', - birthDate: '1965-05-01', - phone: '(?!?)555-5555', - mobile: '(?!?)234-23423', - email: 'jane@jones.com', - company_name: 'JJ Ltd.', - identification_doctype: 'PASSPORT', - identification_docid: 'FakeID2342431234123', - ip: ip, - }, + # riskWorkflow: true, + # testMode: 'EXTERNAL' # or 'INTERNAL', valid only for test system + + billing_address: { + address1: '123 Test Street', + city: 'Test', + state: 'TE', + zip: 'AB12CD', + country: 'GB', + }, + shipping_address: { + name: 'Muton DeMicelis', + address1: 'My Street On Upiter, Apt 3.14/2.78', + city: 'Munich', + state: 'Bov', + zip: '81675', + country: 'DE', + }, + customer: { + merchant_customer_id: 'your merchant/customer id', + givenName: 'Jane', + surname: 'Jones', + birthDate: '1965-05-01', + phone: '(?!?)555-5555', + mobile: '(?!?)234-23423', + email: 'jane@jones.com', + company_name: 'JJ Ltd.', + identification_doctype: 'PASSPORT', + identification_docid: 'FakeID2342431234123', + ip: ip, + }, } - + @minimal_request_options = { order_id: "Order #{time}", description: 'Store Purchase - Books', } - @complete_request_options['customParameters[SHOPPER_test124TestName009]'] = 'customParameters_test' - @complete_request_options['customParameters[SHOPPER_otherCustomerParameter]'] = 'otherCustomerParameter_test' + @complete_request_options['customParameters[SHOPPER_test124TestName009]'] = 'customParameters_test' + @complete_request_options['customParameters[SHOPPER_otherCustomerParameter]'] = 'otherCustomerParameter_test' + + @test_success_id = '8a82944a4e008ca9014e1273e0696122' + @test_failure_id = '8a8294494e0078a6014e12b371fb6a8e' + @test_wrong_reference_id = '8a8444494a0033a6014e12b371fb6a1e' - @test_success_id = "8a82944a4e008ca9014e1273e0696122" - @test_failure_id = "8a8294494e0078a6014e12b371fb6a8e" - @test_wrong_reference_id = "8a8444494a0033a6014e12b371fb6a1e" - @options = @minimal_request_options if request_type == 'minimal' @options = @complete_request_options if request_type == 'complete' end - -# ****************************************** SUCCESSFUL TESTS ****************************************** + + # ****************************************** SUCCESSFUL TESTS ****************************************** def test_successful_purchase @options[:description] = __method__ - + response = @gateway.purchase(@amount, @valid_card, @options) - assert_success response, "Failed purchase" + assert_success response, 'Failed purchase' + assert_match %r{Request successfully processed}, response.message + + assert response.test? + end + + def test_successful_purchase_sans_options + response = @gateway.purchase(@amount, @valid_card) + assert_success response + assert_match %r{Request successfully processed}, response.message assert response.test? end @@ -81,40 +90,48 @@ def test_successful_authorize @options[:description] = __method__ response = @gateway.authorize(@amount, @valid_card, @options) - assert_success response, "Authorization Failed" + assert_success response, 'Authorization Failed' + assert_match %r{Request successfully processed}, response.message + assert response.test? end def test_successful_capture @options[:description] = __method__ auth = @gateway.authorize(@amount, @valid_card, @options) - assert_success auth, "Authorization Failed" + assert_success auth, 'Authorization Failed' assert auth.test? - + capt = @gateway.capture(@amount, auth.authorization, @options) - assert_success capt, "Capture failed" + assert_success capt, 'Capture failed' + assert_match %r{Request successfully processed}, capt.message + assert capt.test? end def test_successful_refund @options[:description] = __method__ purchase = @gateway.purchase(@amount, @valid_card, @options) - assert_success purchase, "Purchase failed" + assert_success purchase, 'Purchase failed' assert purchase.test? refund = @gateway.refund(@amount, purchase.authorization, @options) - assert_success refund, "Refund failed" + assert_success refund, 'Refund failed' + assert_match %r{Request successfully processed}, refund.message + assert refund.test? end def test_successful_void @options[:description] = __method__ purchase = @gateway.purchase(@amount, @valid_card, @options) - assert_success purchase, "Purchase failed" + assert_success purchase, 'Purchase failed' assert purchase.test? void = @gateway.void(purchase.authorization, @options) - assert_success void, "Void failed" + assert_success void, 'Void failed' + assert_match %r{Request successfully processed}, void.message + assert void.test? end @@ -125,6 +142,7 @@ def test_successful_partial_capture assert capture = @gateway.capture(@amount-1, auth.authorization) assert_success capture + assert_match %r{Request successfully processed}, capture.message end def test_successful_partial_refund @@ -134,49 +152,65 @@ def test_successful_partial_refund assert refund = @gateway.refund(@amount-1, purchase.authorization) assert_success refund + assert_match %r{Request successfully processed}, refund.message end def test_successful_verify @options[:description] = __method__ response = @gateway.verify(@valid_card, @options) assert_success response + assert_match %r{Request successfully processed}, response.message end -# ****************************************** FAILURE TESTS ****************************************** + # ****************************************** FAILURE TESTS ****************************************** def test_failed_purchase @options[:description] = __method__ response = @gateway.purchase(@amount, @invalid_card, @options) assert_failure response - assert_equal Gateway::STANDARD_ERROR_CODE[:incorrect_number], response.error_code + assert_match %r{invalid creditcard}, response.message end def test_failed_authorize @options[:description] = __method__ response = @gateway.authorize(@amount, @invalid_card, @options) assert_failure response - assert_equal Gateway::STANDARD_ERROR_CODE[:incorrect_number], response.error_code + assert_match %r{invalid creditcard}, response.message end def test_failed_capture @options[:description] = __method__ response = @gateway.capture(@amount, @test_wrong_reference_id) assert_failure response - assert_equal Gateway::STANDARD_ERROR_CODE[:processing_error], response.error_code + assert_match %r{capture needs at least one successful transaction}, response.message end def test_failed_refund @options[:description] = __method__ response = @gateway.refund(@amount, @test_wrong_reference_id) assert_failure response - assert_equal Gateway::STANDARD_ERROR_CODE[:processing_error], response.error_code + assert_match %r{Invalid payment data}, response.message end def test_failed_void @options[:description] = __method__ response = @gateway.void(@test_wrong_reference_id, @options) assert_failure response - assert_equal Gateway::STANDARD_ERROR_CODE[:processing_error], response.error_code + assert_match %r{reversal needs at least one successful transaction}, response.message end + # ************************************** TRANSCRIPT SCRUB ****************************************** + + def test_transcript_scrubbing + assert @gateway.supports_scrubbing? + + transcript = capture_transcript(@gateway) do + @gateway.purchase(@amount, @valid_card) + end + transcript = @gateway.scrub(transcript) + + assert_scrubbed(@valid_card.number, transcript) + assert_scrubbed(@valid_card.verification_value, transcript) + assert_scrubbed(@gateway.options[:password], transcript) + end end diff --git a/test/remote/gateways/remote_optimal_payment_test.rb b/test/remote/gateways/remote_optimal_payment_test.rb index fa034da690d..6061a306300 100644 --- a/test/remote/gateways/remote_optimal_payment_test.rb +++ b/test/remote/gateways/remote_optimal_payment_test.rb @@ -24,15 +24,15 @@ def test_successful_purchase end def test_unsuccessful_purchase_with_shipping_address - @options.merge!(:shipping_address => address) + @options[:shipping_address] = address assert response = @gateway.purchase(@amount, @credit_card, @options) assert_success response assert_equal 'no_error', response.message end def test_successful_great_britain - @options[:billing_address][:country] = "GB" - @options[:billing_address][:state] = "North West England" + @options[:billing_address][:country] = 'GB' + @options[:billing_address][:state] = 'North West England' assert response = @gateway.purchase(@amount, @credit_card, @options) assert_success response assert_equal 'no_error', response.message @@ -44,6 +44,19 @@ def test_unsuccessful_purchase assert_equal 'auth declined', response.message end + def test_purchase_with_no_cvv + @credit_card.verification_value = '' + assert response = @gateway.purchase(@amount, @credit_card, @options) + assert_success response + assert_equal 'no_error', response.message + end + + def test_successful_verify + response = @gateway.verify(@credit_card, @options) + assert_success response + assert_equal 'no_error', response.message + end + def test_authorize_and_capture assert auth = @gateway.authorize(@amount, @credit_card, @options) assert_success auth @@ -134,6 +147,18 @@ def test_invalid_login ) assert response = gateway.purchase(@amount, @credit_card, @options) assert_failure response - assert_equal 'invalid credentials', response.message + assert_equal 'invalid merchant account', response.message + end + + # Password assertion hard-coded due to the value being the same as the login, which would cause a false-positive + def test_transcript_scrubbing + transcript = capture_transcript(@gateway) do + @gateway.purchase(@amount, @credit_card, @options) + end + transcript = @gateway.scrub(transcript) + + assert_scrubbed(@credit_card.number, transcript) + assert_scrubbed(@credit_card.verification_value, transcript) + assert_scrubbed('%3CstorePwd%3Etest%3C/storePwd%3E', transcript) end end diff --git a/test/remote/gateways/remote_orbital_test.rb b/test/remote/gateways/remote_orbital_test.rb index 67f9cd4c628..62fe766500c 100644 --- a/test/remote/gateways/remote_orbital_test.rb +++ b/test/remote/gateways/remote_orbital_test.rb @@ -1,4 +1,4 @@ -require "test_helper.rb" +require 'test_helper.rb' class RemoteOrbitalGatewayTest < Test::Unit::TestCase def setup @@ -6,32 +6,50 @@ def setup @gateway = ActiveMerchant::Billing::OrbitalGateway.new(fixtures(:orbital_gateway)) @amount = 100 - @credit_card = credit_card('4111111111111111') + @credit_card = credit_card('4112344112344113') @declined_card = credit_card('4000300011112220') @options = { :order_id => generate_unique_id, :address => address, + :merchant_id => 'merchant1234' } @cards = { - :visa => "4788250000028291", - :mc => "5454545454545454", - :amex => "371449635398431", - :ds => "6011000995500000", - :diners => "36438999960016", - :jcb => "3566002020140006"} + :visa => '4788250000028291', + :mc => '5454545454545454', + :amex => '371449635398431', + :ds => '6011000995500000', + :diners => '36438999960016', + :jcb => '3566002020140006'} + + @level_2_options = { + tax_indicator: '1', + tax: '75', + advice_addendum_1: 'taa1 - test', + advice_addendum_2: 'taa2 - test', + advice_addendum_3: 'taa3 - test', + advice_addendum_4: 'taa4 - test', + purchase_order: '123abc', + name: address[:name], + address1: address[:address1], + address2: address[:address2], + city: address[:city], + state: address[:state], + zip: address[:zip], + } @test_suite = [ - {:card => :visa, :AVSzip => 11111, :CVD => 111, :amount => 3000}, - {:card => :visa, :AVSzip => 33333, :CVD => nil, :amount => 3801}, - {:card => :mc, :AVSzip => 44444, :CVD => nil, :amount => 4100}, - {:card => :mc, :AVSzip => 88888, :CVD => 666, :amount => 1102}, - {:card => :amex, :AVSzip => 55555, :CVD => nil, :amount => 105500}, - {:card => :amex, :AVSzip => 66666, :CVD => 2222, :amount => 7500}, - {:card => :ds, :AVSzip => 77777, :CVD => nil, :amount => 1000}, - {:card => :ds, :AVSzip => 88888, :CVD => 444, :amount => 6303}, - {:card => :jcb, :AVSzip => 33333, :CVD => nil, :amount => 2900}] + {:card => :visa, :AVSzip => 11111, :CVD => 111, :amount => 3000}, + {:card => :visa, :AVSzip => 33333, :CVD => nil, :amount => 3801}, + {:card => :mc, :AVSzip => 44444, :CVD => nil, :amount => 4100}, + {:card => :mc, :AVSzip => 88888, :CVD => 666, :amount => 1102}, + {:card => :amex, :AVSzip => 55555, :CVD => nil, :amount => 105500}, + {:card => :amex, :AVSzip => 66666, :CVD => 2222, :amount => 7500}, + {:card => :ds, :AVSzip => 77777, :CVD => nil, :amount => 1000}, + {:card => :ds, :AVSzip => 88888, :CVD => 444, :amount => 6303}, + {:card => :jcb, :AVSzip => 33333, :CVD => nil, :amount => 2900} + ] end def test_successful_purchase @@ -40,11 +58,85 @@ def test_successful_purchase assert_equal 'Approved', response.message end + def test_successful_purchase_with_soft_descriptor_hash + assert response = @gateway.purchase( + @amount, @credit_card, @options.merge( + soft_descriptors: { + merchant_name: 'Merch', + product_description: 'Description', + merchant_email: 'email@example', + } + ) + ) + assert_success response + assert_equal 'Approved', response.message + end + + def test_successful_purchase_with_level_2_data + response = @gateway.purchase(@amount, @credit_card, @options.merge(level_2_data: @level_2_options)) + + assert_success response + assert_equal 'Approved', response.message + end + + def test_successful_purchase_with_visa_network_tokenization_credit_card_with_eci + network_card = network_tokenization_credit_card('4788250000028291', + payment_cryptogram: 'BwABB4JRdgAAAAAAiFF2AAAAAAA=', + transaction_id: 'BwABB4JRdgAAAAAAiFF2AAAAAAA=', + verification_value: '111', + brand: 'visa', + eci: '5' + ) + assert response = @gateway.purchase(3000, network_card, @options) + assert_success response + assert_equal 'Approved', response.message + assert_false response.authorization.blank? + end + + def test_successful_purchase_with_master_card_network_tokenization_credit_card + network_card = network_tokenization_credit_card('4788250000028291', + payment_cryptogram: 'BwABB4JRdgAAAAAAiFF2AAAAAAA=', + transaction_id: 'BwABB4JRdgAAAAAAiFF2AAAAAAA=', + verification_value: '111', + brand: 'master' + ) + assert response = @gateway.purchase(3000, network_card, @options) + assert_success response + assert_equal 'Approved', response.message + assert_false response.authorization.blank? + end + + def test_successful_purchase_with_american_express_network_tokenization_credit_card + network_card = network_tokenization_credit_card('4788250000028291', + payment_cryptogram: 'BwABB4JRdgAAAAAAiFF2AAAAAAA=', + transaction_id: 'BwABB4JRdgAAAAAAiFF2AAAAAAA=', + verification_value: '111', + brand: 'american_express' + ) + assert response = @gateway.purchase(3000, network_card, @options) + assert_success response + assert_equal 'Approved', response.message + assert_false response.authorization.blank? + end + + def test_successful_purchase_with_discover_network_tokenization_credit_card + network_card = network_tokenization_credit_card('4788250000028291', + payment_cryptogram: 'BwABB4JRdgAAAAAAiFF2AAAAAAA=', + transaction_id: 'BwABB4JRdgAAAAAAiFF2AAAAAAA=', + verification_value: '111', + brand: 'discover' + ) + assert response = @gateway.purchase(3000, network_card, @options) + assert_success response + assert_equal 'Approved', response.message + assert_false response.authorization.blank? + end + # Amounts of x.01 will fail def test_unsuccessful_purchase assert response = @gateway.purchase(101, @declined_card, @options) assert_failure response - assert_equal 'AUTH DECLINED 12001', response.message + assert_equal 'Invalid CC Number', response.message end def test_authorize_and_capture @@ -57,6 +149,15 @@ def test_authorize_and_capture assert_success capture end + def test_successful_authorize_and_capture_with_level_2_data + auth = @gateway.authorize(@amount, @credit_card, @options.merge(level_2_data: @level_2_options)) + assert_success auth + assert_equal 'Approved', auth.message + + capture = @gateway.capture(@amount, auth.authorization, @options.merge(level_2_data: @level_2_options)) + assert_success capture + end + def test_authorize_and_void assert auth = @gateway.authorize(@amount, @credit_card, @options.merge(:order_id => '2')) assert_success auth @@ -75,6 +176,15 @@ def test_refund assert_success refund end + def test_successful_refund_with_level_2_data + amount = @amount + assert response = @gateway.purchase(amount, @credit_card, @options.merge(level_2_data: @level_2_options)) + assert_success response + assert response.authorization + assert refund = @gateway.refund(amount, response.authorization, @options.merge(level_2_data: @level_2_options)) + assert_success refund + end + def test_failed_capture assert response = @gateway.capture(@amount, '') assert_failure response @@ -88,7 +198,7 @@ def test_auth_only_transactions for suite in @test_suite do amount = suite[:amount] card = credit_card(@cards[suite[:card]], :verification_value => suite[:CVD]) - @options[:address].merge!(:zip => suite[:AVSzip]) + @options[:address][:zip] = suite[:AVSzip] assert response = @gateway.authorize(amount, card, @options) assert_kind_of Response, response @@ -106,7 +216,7 @@ def test_auth_capture_transactions for suite in @test_suite do amount = suite[:amount] card = credit_card(@cards[suite[:card]], :verification_value => suite[:CVD]) - options = @options; options[:address].merge!(:zip => suite[:AVSzip]) + options = @options; options[:address][:zip] = suite[:AVSzip] assert response = @gateway.purchase(amount, card, options) assert_kind_of Response, response @@ -121,7 +231,7 @@ def test_auth_capture_transactions # ==== Section C def test_mark_for_capture_transactions - [[:visa, 3000],[:mc, 4100],[:amex, 105500],[:ds, 1000],[:jcb, 2900]].each do |suite| + [[:visa, 3000], [:mc, 4100], [:amex, 105500], [:ds, 1000], [:jcb, 2900]].each do |suite| amount = suite[1] card = credit_card(@cards[suite[0]]) assert auth_response = @gateway.authorize(amount, card, @options) @@ -137,7 +247,7 @@ def test_mark_for_capture_transactions # ==== Section D def test_refund_transactions - [[:visa, 1200],[:mc, 1100],[:amex, 105500],[:ds, 1000],[:jcb, 2900]].each do |suite| + [[:visa, 1200], [:mc, 1100], [:amex, 105500], [:ds, 1000], [:jcb, 2900]].each do |suite| amount = suite[1] card = credit_card(@cards[suite[0]]) assert purchase_response = @gateway.purchase(amount, card, @options) @@ -173,7 +283,7 @@ def test_successful_verify def test_failed_verify response = @gateway.verify(@declined_card, @options) assert_failure response - assert_equal 'AUTH DECLINED 12001', response.message + assert_equal 'Invalid CC Number', response.message end def test_transcript_scrubbing @@ -185,5 +295,20 @@ def test_transcript_scrubbing assert_scrubbed(@credit_card.number, transcript) assert_scrubbed(@credit_card.verification_value, transcript) assert_scrubbed(@gateway.options[:password], transcript) + assert_scrubbed(@gateway.options[:login], transcript) + assert_scrubbed(@gateway.options[:merchant_id], transcript) + end + + def test_transcript_scrubbing_profile + transcript = capture_transcript(@gateway) do + @gateway.add_customer_profile(@credit_card, @options) + end + transcript = @gateway.scrub(transcript) + + assert_scrubbed(@credit_card.number, transcript) + assert_scrubbed(@credit_card.verification_value, transcript) + assert_scrubbed(@gateway.options[:password], transcript) + assert_scrubbed(@gateway.options[:login], transcript) + assert_scrubbed(@gateway.options[:merchant_id], transcript) end end diff --git a/test/remote/gateways/remote_pac_net_raven_test.rb b/test/remote/gateways/remote_pac_net_raven_test.rb index 3d5e9dffe37..a1473031fbc 100644 --- a/test/remote/gateways/remote_pac_net_raven_test.rb +++ b/test/remote/gateways/remote_pac_net_raven_test.rb @@ -34,7 +34,7 @@ def test_invalid_credit_card_number_purchese assert_equal 'invalid:cardNumber', purchase.params['ErrorCode'] assert_equal 'Invalid:CardNumber', purchase.params['Status'] assert_equal 'ok', purchase.params['RequestResult'] - assert_equal "Error processing transaction because CardNumber \"0000\" is not between 12 and 19 in length.", purchase.params['Message'] + assert_equal 'Error processing transaction because CardNumber "0000" is not between 12 and 19 in length.', purchase.params['Message'] end def test_expired_credit_card_purchese @@ -47,7 +47,7 @@ def test_expired_credit_card_purchese assert_equal 'invalid:CustomerCardExpiryDate', purchase.params['ErrorCode'] assert_equal 'Invalid:CustomerCardExpiryDate', purchase.params['Status'] assert_equal 'ok', purchase.params['RequestResult'] - assert_equal "Invalid because the card expiry date (mmyy) \"0912\" is not a date in the future", purchase.params['Message'] + assert_equal 'Invalid because the card expiry date (mmyy) "0912" is not a date in the future', purchase.params['Message'] end def test_declined_purchase @@ -77,7 +77,7 @@ def test_invalid_credit_card_number_authorization assert_equal 'invalid:cardNumber', auth.params['ErrorCode'] assert_equal 'Invalid:CardNumber', auth.params['Status'] assert_equal 'ok', auth.params['RequestResult'] - assert_equal "Error processing transaction because CardNumber \"0000\" is not between 12 and 19 in length.", auth.params['Message'] + assert_equal 'Error processing transaction because CardNumber "0000" is not between 12 and 19 in length.', auth.params['Message'] end def test_expired_credit_card_authorization @@ -90,7 +90,7 @@ def test_expired_credit_card_authorization assert_equal 'invalid:CustomerCardExpiryDate', auth.params['ErrorCode'] assert_equal 'Invalid:CustomerCardExpiryDate', auth.params['Status'] assert_equal 'ok', auth.params['RequestResult'] - assert_equal "Invalid because the card expiry date (mmyy) \"0912\" is not a date in the future", auth.params['Message'] + assert_equal 'Invalid because the card expiry date (mmyy) "0912" is not a date in the future', auth.params['Message'] end def test_declined_authorization @@ -123,7 +123,7 @@ def test_amount_greater_than_original_amount_refund assert_equal 'invalid:RefundAmountGreaterThanOriginalAmount', refund.params['ErrorCode'] assert_equal 'Invalid:RefundAmountGreaterThanOriginalAmount', refund.params['Status'] assert_equal 'ok', refund.params['RequestResult'] - assert_equal "Invalid because the payment amount cannot be greater than the original charge.", refund.params['Message'] + assert_equal 'Invalid because the payment amount cannot be greater than the original charge.', refund.params['Message'] assert_equal 'Invalid because the payment amount cannot be greater than the original charge.', refund.message end @@ -137,7 +137,7 @@ def test_purchase_and_void assert_equal 'ok', void.params['RequestResult'] assert_nil void.params['Message'] assert_equal 'Voided', void.params['Status'] - assert_equal "This transaction has been voided", void.message + assert_equal 'This transaction has been voided', void.message end def test_authorize_and_void @@ -150,7 +150,7 @@ def test_authorize_and_void assert_equal 'ok', void.params['RequestResult'] assert_nil void.params['Message'] assert_equal 'Voided', void.params['Status'] - assert_equal "This transaction has been voided", void.message + assert_equal 'This transaction has been voided', void.message end def test_authorize_capture_and_void @@ -164,7 +164,7 @@ def test_authorize_capture_and_void assert_equal 'ok', void.params['RequestResult'] assert_nil void.params['Message'] assert_equal 'Voided', void.params['Status'] - assert_equal "This transaction has been voided", void.message + assert_equal 'This transaction has been voided', void.message end def test_successful_capture diff --git a/test/remote/gateways/remote_pagarme_test.rb b/test/remote/gateways/remote_pagarme_test.rb index 27f6f465fb9..868ff0a48c3 100644 --- a/test/remote/gateways/remote_pagarme_test.rb +++ b/test/remote/gateways/remote_pagarme_test.rb @@ -29,7 +29,7 @@ def test_successful_purchase assert_equal 'Transação aprovada', response.message # Assert metadata - assert_equal response.params["metadata"]["description"], @options[:description] + assert_equal response.params['metadata']['description'], @options[:description] end def test_successful_purchase_with_more_options @@ -49,13 +49,13 @@ def test_successful_purchase_with_more_options assert_equal 'Transação aprovada', response.message # Assert metadata - assert_equal response.params["metadata"]["order_id"], options[:order_id] - assert_equal response.params["metadata"]["ip"], options[:ip] - assert_equal response.params["metadata"]["customer"], options[:customer] - assert_equal response.params["metadata"]["invoice"], options[:invoice] - assert_equal response.params["metadata"]["merchant"], options[:merchant] - assert_equal response.params["metadata"]["description"], options[:description] - assert_equal response.params["metadata"]["email"], options[:email] + assert_equal response.params['metadata']['order_id'], options[:order_id] + assert_equal response.params['metadata']['ip'], options[:ip] + assert_equal response.params['metadata']['customer'], options[:customer] + assert_equal response.params['metadata']['invoice'], options[:invoice] + assert_equal response.params['metadata']['merchant'], options[:merchant] + assert_equal response.params['metadata']['description'], options[:description] + assert_equal response.params['metadata']['email'], options[:email] end def test_successful_purchase_without_options diff --git a/test/remote/gateways/remote_pago_facil_test.rb b/test/remote/gateways/remote_pago_facil_test.rb index 03404228d02..254ebd33dec 100644 --- a/test/remote/gateways/remote_pago_facil_test.rb +++ b/test/remote/gateways/remote_pago_facil_test.rb @@ -87,7 +87,7 @@ def successful_response_to if random_response.success? return random_response elsif(attempts > 2) - raise "Unable to get a successful response" + raise 'Unable to get a successful response' else assert_equal 'Declined_(General).', random_response.params.fetch('error') attempts += 1 diff --git a/test/remote/gateways/remote_pay_conex_test.rb b/test/remote/gateways/remote_pay_conex_test.rb index 43c4f0b4e6b..22ed010bcbd 100644 --- a/test/remote/gateways/remote_pay_conex_test.rb +++ b/test/remote/gateways/remote_pay_conex_test.rb @@ -13,12 +13,12 @@ def setup order_id: '1', billing_address: address, description: 'Store Purchase', - email: "joe@example.com" + email: 'joe@example.com' } end def test_transcript_scrubbing - @credit_card.verification_value = "447" + @credit_card.verification_value = '447' transcript = capture_transcript(@gateway) do @gateway.purchase(@amount, @credit_card, @options) end @@ -27,34 +27,34 @@ def test_transcript_scrubbing assert_scrubbed(@credit_card.number, transcript) assert_scrubbed(@credit_card.verification_value, transcript) assert_scrubbed(@gateway.options[:api_accesskey], transcript) - end + end def test_successful_purchase response = @gateway.purchase(@amount, @credit_card, @options) assert_success response - assert_equal "APPROVED", response.message + assert_equal 'APPROVED', response.message end def test_failed_purchase response = @gateway.purchase(@failed_amount, @credit_card, @options) assert_failure response - assert_equal "DECLINED", response.message + assert_equal 'DECLINED', response.message end def test_successful_authorize_and_capture auth = @gateway.authorize(@amount, @credit_card, @options) assert_success auth - assert_equal "APPROVED", auth.message + assert_equal 'APPROVED', auth.message assert capture = @gateway.capture(@amount, auth.authorization) assert_success capture - assert_equal "CAPTURED", capture.message + assert_equal 'CAPTURED', capture.message end def test_failed_authorize response = @gateway.authorize(@failed_amount, @credit_card, @options) assert_failure response - assert_equal "DECLINED", response.message + assert_equal 'DECLINED', response.message end def test_partial_capture @@ -63,13 +63,13 @@ def test_partial_capture assert capture = @gateway.capture(@amount-1, auth.authorization) assert_success capture - assert_equal "CAPTURED", capture.message + assert_equal 'CAPTURED', capture.message end def test_failed_capture response = @gateway.capture(@amount, 'UnknownAuth') assert_failure response - assert_equal "Invalid token_id", response.message + assert_equal 'Invalid token_id', response.message end def test_successful_refund @@ -78,7 +78,7 @@ def test_successful_refund assert refund = @gateway.refund(@amount, purchase.authorization) assert_success refund - assert_equal "VOID", refund.message + assert_equal 'VOID', refund.message end def test_partial_refund @@ -87,7 +87,7 @@ def test_partial_refund assert refund = @gateway.refund(@amount-1, purchase.authorization) assert_success refund - assert_equal "REFUND", refund.message + assert_equal 'REFUND', refund.message end def test_failed_refund @@ -96,7 +96,7 @@ def test_failed_refund response = @gateway.refund(@amount + 400, purchase.authorization) assert_failure response - assert_equal "INVALID REFUND AMOUNT", response.message + assert_equal 'INVALID REFUND AMOUNT', response.message end def test_successful_void @@ -105,7 +105,7 @@ def test_successful_void assert void = @gateway.void(auth.authorization) assert_success void - assert_equal "APPROVED", void.message + assert_equal 'APPROVED', void.message end def test_failed_void @@ -117,32 +117,32 @@ def test_failed_void response = @gateway.void(auth.authorization) assert_failure response - assert_equal "TRANSACTION ID ALREADY REVERSED", response.message + assert_equal 'TRANSACTION ID ALREADY REVERSED', response.message end def test_successful_verify response = @gateway.verify(@credit_card, @options) assert_success response - assert_equal "APPROVED", response.message + assert_equal 'APPROVED', response.message end def test_failed_verify - response = @gateway.verify(credit_card("BogusCard"), @options) + response = @gateway.verify(credit_card('BogusCard'), @options) assert_failure response - assert_equal "INVALID CARD NUMBER", response.message + assert_equal 'INVALID CARD NUMBER', response.message end def test_successful_store assert response = @gateway.store(@credit_card) assert_success response assert response.authorization - assert_equal "2224", response.params["last4"] + assert_equal '2224', response.params['last4'] end def test_failed_store - assert response = @gateway.store(credit_card("141241")) + assert response = @gateway.store(credit_card('141241')) assert_failure response - assert_equal "CARD DATA UNREADABLE", response.message + assert_equal 'CARD DATA UNREADABLE', response.message end def test_purchase_using_stored_card @@ -151,32 +151,32 @@ def test_purchase_using_stored_card response = @gateway.purchase(@amount, response.authorization, @options) assert_success response - assert_equal "APPROVED", response.message + assert_equal 'APPROVED', response.message end def test_successful_credit response = @gateway.credit(@amount, @credit_card, @options) assert_success response - assert_equal "CREDIT", response.message + assert_equal 'CREDIT', response.message end def test_failed_credit - response = @gateway.credit(@amount, credit_card("12321"), @options) + response = @gateway.credit(@amount, credit_card('12321'), @options) assert_failure response - assert_equal "CARD DATA UNREADABLE", response.message + assert_equal 'CARD DATA UNREADABLE', response.message end def test_successful_card_present_purchase response = @gateway.purchase(@amount, credit_card_with_track_data('4000100011112224'), @options) assert_success response - assert_equal "APPROVED", response.message + assert_equal 'APPROVED', response.message end def test_failed_card_present_purchase card = CreditCard.new(track_data: '%B37826310005^LOB^17001130504392?') response = @gateway.purchase(@amount, card, @options) assert_failure response - assert_equal "CARD DATA UNREADABLE", response.message + assert_equal 'CARD DATA UNREADABLE', response.message end def test_successful_echeck_purchase @@ -188,7 +188,7 @@ def test_successful_echeck_purchase end def test_failed_echeck_purchase - response = @gateway.purchase(@amount, check(routing_number: "23433"), @options) + response = @gateway.purchase(@amount, check(routing_number: '23433'), @options) assert_failure response assert_equal 'Invalid bank_routing_number', response.message end @@ -197,6 +197,6 @@ def test_invalid_login gateway = PayConexGateway.new(account_id: 'Unknown', api_accesskey: 'Incorrect') response = gateway.purchase(@amount, @credit_card, @options) assert_failure response - assert_equal "Invalid account_id", response.message + assert_equal 'Invalid account_id', response.message end end diff --git a/test/remote/gateways/remote_pay_gate_xml_test.rb b/test/remote/gateways/remote_pay_gate_xml_test.rb index 35b257c48ef..b16cedb0678 100644 --- a/test/remote/gateways/remote_pay_gate_xml_test.rb +++ b/test/remote/gateways/remote_pay_gate_xml_test.rb @@ -26,7 +26,7 @@ def test_successful_purchase def test_unsuccessful_purchase assert response = @gateway.purchase(@amount, @declined_card, @options) assert_failure response - assert_equal "Declined", response.message + assert_equal 'Declined', response.message end def test_authorize_and_capture diff --git a/test/remote/gateways/remote_pay_hub_test.rb b/test/remote/gateways/remote_pay_hub_test.rb index ff5191474c0..e57fe048e4a 100644 --- a/test/remote/gateways/remote_pay_hub_test.rb +++ b/test/remote/gateways/remote_pay_hub_test.rb @@ -4,8 +4,8 @@ class RemotePayHubTest < Test::Unit::TestCase def setup @gateway = PayHubGateway.new(fixtures(:pay_hub)) @amount = 100 - @credit_card = credit_card('5466410004374507', verification_value: "998") - @invalid_card = credit_card('371449635398431', verification_value: "9997") + @credit_card = credit_card('5466410004374507', verification_value: '998') + @invalid_card = credit_card('371449635398431', verification_value: '9997') @options = { :first_name => 'Garrya', :last_name => 'Barrya', @@ -47,7 +47,7 @@ def test_unsuccessful_auth end def test_unsuccessful_capture - assert_failure @gateway.capture(@amount, "bogus") + assert_failure @gateway.capture(@amount, 'bogus') end def test_partial_capture @@ -69,7 +69,7 @@ def test_successful_refund end def test_unsuccessful_refund - assert_failure @gateway.refund(@amount, "bogus") + assert_failure @gateway.refund(@amount, 'bogus') end def test_successful_verify @@ -77,6 +77,6 @@ def test_successful_verify end def test_failed_verify - assert_failure @gateway.verify(credit_card("4111111111111111")) + assert_failure @gateway.verify(credit_card('4111111111111111')) end end diff --git a/test/remote/gateways/remote_pay_junction_test.rb b/test/remote/gateways/remote_pay_junction_test.rb index 4744ea59995..1db822d8bb1 100644 --- a/test/remote/gateways/remote_pay_junction_test.rb +++ b/test/remote/gateways/remote_pay_junction_test.rb @@ -37,8 +37,8 @@ def setup def test_successful_purchase assert response = @gateway.purchase(AMOUNT, @credit_card, @options) assert_equal PayJunctionGateway::SUCCESS_MESSAGE, response.message - assert_equal 'capture', response.params["posture"], 'Should be captured funds' - assert_equal 'charge', response.params["transaction_action"] + assert_equal 'capture', response.params['posture'], 'Should be captured funds' + assert_equal 'charge', response.params['transaction_action'] assert_success response assert response.test? end @@ -48,18 +48,18 @@ def test_successful_purchase_with_cvv assert response = @gateway.purchase(AMOUNT, @credit_card, @options) assert_equal PayJunctionGateway::SUCCESS_MESSAGE, response.message - assert_equal 'capture', response.params["posture"], 'Should be captured funds' - assert_equal 'charge', response.params["transaction_action"] + assert_equal 'capture', response.params['posture'], 'Should be captured funds' + assert_equal 'charge', response.params['transaction_action'] assert_success response end def test_successful_authorize - assert response = @gateway.authorize( AMOUNT, @credit_card, @options) + assert response = @gateway.authorize(AMOUNT, @credit_card, @options) assert_equal PayJunctionGateway::SUCCESS_MESSAGE, response.message - assert_equal 'hold', response.params["posture"], 'Should be a held charge' - assert_equal 'charge', response.params["transaction_action"] + assert_equal 'hold', response.params['posture'], 'Should be a held charge' + assert_equal 'charge', response.params['transaction_action'] assert_success response end @@ -70,9 +70,9 @@ def test_successful_capture response = @gateway.capture(AMOUNT, auth.authorization, @options) assert_success response - assert_equal 'capture', response.params["posture"], 'Should be a capture' + assert_equal 'capture', response.params['posture'], 'Should be a capture' assert_equal auth.authorization, response.authorization, - "Should maintain transaction ID across request" + 'Should maintain transaction ID across request' end def test_successful_credit @@ -80,7 +80,7 @@ def test_successful_credit assert_success purchase assert response = @gateway.credit(success_price, purchase.authorization) - assert_equal 'refund', response.params["transaction_action"] + assert_equal 'refund', response.params['transaction_action'] assert_success response end @@ -92,9 +92,9 @@ def test_successful_void assert response = @gateway.void(purchase.authorization, :order_id => order_id) assert_success response - assert_equal 'void', response.params["posture"], 'Should be a capture' + assert_equal 'void', response.params['posture'], 'Should be a capture' assert_equal purchase.authorization, response.authorization, - "Should maintain transaction ID across request" + 'Should maintain transaction ID across request' end def test_successful_instant_purchase @@ -102,29 +102,29 @@ def test_successful_instant_purchase # transaction can be executed if you have the transaction ID of a # previous successful transaction. - purchase = @gateway.purchase( AMOUNT, @credit_card, @options) + purchase = @gateway.purchase(AMOUNT, @credit_card, @options) assert_success purchase assert response = @gateway.purchase(AMOUNT, purchase.authorization, :order_id => generate_unique_id) assert_equal PayJunctionGateway::SUCCESS_MESSAGE, response.message - assert_equal 'capture', response.params["posture"], 'Should be captured funds' - assert_equal 'charge', response.params["transaction_action"] + assert_equal 'capture', response.params['posture'], 'Should be captured funds' + assert_equal 'charge', response.params['transaction_action'] assert_not_equal purchase.authorization, response.authorization, - 'Should have recieved new transaction ID' + 'Should have recieved new transaction ID' assert_success response end def test_successful_recurring assert response = @gateway.recurring(AMOUNT, @credit_card, - :periodicity => :monthly, - :payments => 12, - :order_id => generate_unique_id[0..15] - ) + :periodicity => :monthly, + :payments => 12, + :order_id => generate_unique_id[0..15] + ) assert_equal PayJunctionGateway::SUCCESS_MESSAGE, response.message - assert_equal 'charge', response.params["transaction_action"] + assert_equal 'charge', response.params['transaction_action'] assert_success response end @@ -132,11 +132,12 @@ def test_should_send_invoice response = @gateway.purchase(AMOUNT, @credit_card, @options) assert_success response - assert_equal @options[:order_id], response.params["invoice_number"], 'Should have set invoice' + assert_equal @options[:order_id], response.params['invoice_number'], 'Should have set invoice' end private + def success_price - 200 + rand(200) + rand(200..399) end end diff --git a/test/remote/gateways/remote_pay_junction_v2_test.rb b/test/remote/gateways/remote_pay_junction_v2_test.rb index 99bfac7792c..62954ff4496 100644 --- a/test/remote/gateways/remote_pay_junction_v2_test.rb +++ b/test/remote/gateways/remote_pay_junction_v2_test.rb @@ -12,7 +12,7 @@ def setup end def test_invalid_login - gateway = PayJunctionV2Gateway.new(api_login: "", api_password: "", api_key: "") + gateway = PayJunctionV2Gateway.new(api_login: '', api_password: '', api_key: '') response = gateway.purchase(@amount, @credit_card, @options) assert_failure response @@ -62,7 +62,7 @@ def test_partial_capture assert capture = @gateway.capture(@amount-1, auth.authorization) assert_success capture - assert_equal sprintf("%.2f", (@amount-1).to_f / 100), capture.params["amountTotal"] + assert_equal sprintf('%.2f', (@amount-1).to_f / 100), capture.params['amountTotal'] end def test_failed_capture @@ -87,7 +87,7 @@ def test_partial_refund assert refund = @gateway.refund(@amount-50, purchase.authorization) assert_success refund assert_equal 'Approved', refund.message - assert_equal sprintf("%.2f", (@amount-50).to_f / 100), refund.params["amountTotal"] + assert_equal sprintf('%.2f', (@amount-50).to_f / 100), refund.params['amountTotal'] end def test_failed_refund @@ -99,14 +99,14 @@ def test_failed_refund def test_successful_credit response = @gateway.credit(@amount, @credit_card, @options) assert_success response - assert_equal "Approved", response.message + assert_equal 'Approved', response.message end def test_failed_credit amount = 0 response = @gateway.credit(amount, @credit_card, @options) assert_failure response - assert_equal "Amount Base must be greater than 0.|", response.message + assert_equal 'Amount Base must be greater than 0.|', response.message end def test_successful_void @@ -127,7 +127,7 @@ def test_failed_void def test_successful_verify response = @gateway.verify(@credit_card, @options) assert_success response - assert_equal "Approved", response.message + assert_equal 'Approved', response.message end def test_failed_verify @@ -141,7 +141,7 @@ def test_successful_store_and_purchase response = @gateway.store(@credit_card, @options) assert_success response assert response.authorization - assert_equal "Approved", response.message + assert_equal 'Approved', response.message response = @gateway.purchase(@amount, response.authorization, @options) assert_success response diff --git a/test/remote/gateways/remote_pay_secure_test.rb b/test/remote/gateways/remote_pay_secure_test.rb index 8dd8837adc1..ee153752bb9 100644 --- a/test/remote/gateways/remote_pay_secure_test.rb +++ b/test/remote/gateways/remote_pay_secure_test.rb @@ -4,15 +4,15 @@ class RemotePaySecureTest < Test::Unit::TestCase def setup @gateway = PaySecureGateway.new(fixtures(:pay_secure)) - + @credit_card = credit_card('4000100011112224') - @options = { + @options = { :billing_address => address, :order_id => generate_unique_id } @amount = 100 end - + def test_successful_purchase assert response = @gateway.purchase(@amount, @credit_card, @options) assert_success response @@ -26,7 +26,7 @@ def test_unsuccessful_purchase assert_equal 'Declined, card expired', response.message assert_failure response end - + def test_invalid_login gateway = PaySecureGateway.new( :login => '', diff --git a/test/remote/gateways/remote_paybox_direct_test.rb b/test/remote/gateways/remote_paybox_direct_test.rb index a76d61ab23d..25c03d67804 100644 --- a/test/remote/gateways/remote_paybox_direct_test.rb +++ b/test/remote/gateways/remote_paybox_direct_test.rb @@ -6,18 +6,18 @@ class RemotePayboxDirectTest < Test::Unit::TestCase def setup @gateway = PayboxDirectGateway.new(fixtures(:paybox_direct)) - + @amount = 100 @credit_card = credit_card('1111222233334444') @declined_card = credit_card('1111222233334445') - - @options = { + + @options = { :order_id => '1', :billing_address => address, :description => 'Store Purchase' } end - + def test_successful_purchase assert response = @gateway.purchase(@amount, @credit_card, @options) assert_success response @@ -39,7 +39,7 @@ def test_authorize_and_capture assert capture = @gateway.capture(amount, auth.authorization, :order_id => '1') assert_success capture end - + def test_purchase_and_void assert purchase = @gateway.purchase(@amount, @credit_card, @options) assert_success purchase @@ -54,9 +54,9 @@ def test_purchase_and_void def test_failed_capture assert response = @gateway.capture(@amount, '', :order_id => '1') assert_failure response - assert_equal "Invalid data", response.message + assert_equal 'Invalid data', response.message end - + def test_purchase_and_partial_credit assert purchase = @gateway.purchase(@amount, @credit_card, @options) assert_success purchase @@ -66,7 +66,7 @@ def test_purchase_and_partial_credit assert_equal 'The transaction was approved', credit.message assert_success credit end - + def test_successful_refund assert purchase = @gateway.purchase(@amount, @credit_card, @options) assert_success purchase @@ -84,7 +84,7 @@ def test_partial_refund end def test_failed_refund - refund = @gateway.refund(@amount, '', order_id: '2') + refund = @gateway.refund(@amount, '', order_id: '2') assert_failure refund assert_equal 'Invalid data', refund.message end @@ -97,16 +97,16 @@ def test_invalid_login ) assert response = gateway.purchase(@amount, @credit_card, @options) assert_failure response - assert_equal "Non autorise", response.message + assert_equal 'Non autorise', response.message end def test_invalid_login_without_rang gateway = PayboxDirectGateway.new( login: '199988899', - password: '1999888F', + password: '1999888F' ) assert response = gateway.purchase(@amount, @credit_card, @options) assert_failure response - assert_equal "Non autorise", response.message + assert_equal 'Non autorise', response.message end end diff --git a/test/remote/gateways/remote_payeezy_test.rb b/test/remote/gateways/remote_payeezy_test.rb index a94283207bd..24871731678 100644 --- a/test/remote/gateways/remote_payeezy_test.rb +++ b/test/remote/gateways/remote_payeezy_test.rb @@ -7,10 +7,46 @@ def setup @bad_credit_card = credit_card('4111111111111113') @check = check @amount = 100 + @reversal_id = "REV-#{SecureRandom.random_number(1000000)}" @options = { :billing_address => address, - :merchant_ref => 'Store Purchase' + :merchant_ref => 'Store Purchase', + :ta_token => 'NOIW' } + @options_mdd = { + soft_descriptors: { + dba_name: 'Caddyshack', + street: '1234 Any Street', + city: 'Durham', + region: 'North Carolina', + mid: 'mid_1234', + mcc: 'mcc_5678', + postal_code: '27701', + country_code: 'US', + merchant_contact_info: '8885551212' + } + } + end + + def test_successful_store + assert response = @gateway.store(@credit_card, @options) + assert_success response + assert_equal 'Token successfully created.', response.message + assert response.authorization + end + + def test_successful_store_and_purchase + assert response = @gateway.store(@credit_card, @options) + assert_success response + assert !response.authorization.blank? + assert purchase = @gateway.purchase(@amount, response.authorization, @options) + assert_success purchase + end + + def test_unsuccessful_store + assert response = @gateway.store(@bad_credit_card, @options) + assert_failure response + assert_equal 'The credit card number check failed', response.message end def test_successful_purchase @@ -20,14 +56,21 @@ def test_successful_purchase end def test_successful_purchase_with_echeck - assert response = @gateway.purchase(@amount, @check, @options) + options = @options.merge({customer_id_type: '1', customer_id_number: '1', client_email: 'test@example.com'}) + assert response = @gateway.purchase(@amount, @check, options) + assert_match(/Transaction Normal/, response.message) + assert_success response + end + + def test_successful_purchase_with_soft_descriptors + assert response = @gateway.purchase(@amount, @credit_card, @options.merge(@options_mdd)) assert_match(/Transaction Normal/, response.message) assert_success response end def test_failed_purchase @amount = 501300 - assert response = @gateway.purchase(@amount, @credit_card, @options ) + assert response = @gateway.purchase(@amount, @credit_card, @options) assert_match(/Transaction not approved/, response.message) assert_failure response end @@ -40,6 +83,18 @@ def test_authorize_and_capture assert_success capture end + def test_successful_store_and_auth_and_capture + assert response = @gateway.store(@credit_card, @options) + assert_success response + + assert auth = @gateway.authorize(@amount, response.authorization, @options) + assert_success auth + assert auth.authorization + + assert capture = @gateway.capture(@amount, auth.authorization) + assert_success capture + end + def test_failed_authorize @amount = 501300 assert auth = @gateway.authorize(@amount, @credit_card, @options) @@ -82,6 +137,20 @@ def test_successful_refund_with_echeck assert response.authorization end + def test_successful_refund_with_stored_card + response = @gateway.store(@credit_card, @options) + assert_success response + + assert purchase = @gateway.purchase(@amount, response.authorization, @options) + assert_match(/Transaction Normal/, purchase.message) + assert_success purchase + + assert response = @gateway.refund(50, purchase.authorization) + assert_success response + assert_match(/Transaction Normal/, response.message) + assert response.authorization + end + def test_partial_refund purchase = @gateway.purchase(@amount, @credit_card, @options) assert_success purchase @@ -95,7 +164,7 @@ def test_failed_refund assert_match(/Transaction Normal/, purchase.message) assert_success purchase - assert response = @gateway.refund(50, "bad-authorization") + assert response = @gateway.refund(50, 'bad-authorization') assert_failure response assert_match(/The transaction tag is not provided/, response.message) assert response.authorization @@ -110,6 +179,48 @@ def test_successful_void assert_equal 'Transaction Normal - Approved', void.message end + def test_successful_auth_void_with_reversal_id + auth = @gateway.authorize(@amount, @credit_card, @options.merge(reversal_id: @reversal_id)) + assert_success auth + + assert void = @gateway.void(auth.authorization, reversal_id: @reversal_id) + assert_success void + assert_equal 'Transaction Normal - Approved', void.message + end + + def test_successful_void_purchase_with_reversal_id + response = @gateway.purchase(@amount, @credit_card, @options.merge(reversal_id: @reversal_id)) + assert_success response + + assert void = @gateway.void(response.authorization, reversal_id: @reversal_id) + assert_success void + assert_equal 'Transaction Normal - Approved', void.message + end + + def test_successful_void_with_stored_card_and_reversal_id + response = @gateway.store(@credit_card, @options) + assert_success response + + auth = @gateway.authorize(@amount, response.authorization, @options.merge(reversal_id: @reversal_id)) + assert_success auth + + assert void = @gateway.void(auth.authorization, reversal_id: @reversal_id) + assert_success void + assert_equal 'Transaction Normal - Approved', void.message + end + + def test_successful_void_with_stored_card + response = @gateway.store(@credit_card, @options) + assert_success response + + auth = @gateway.authorize(@amount, response.authorization, @options) + assert_success auth + + assert void = @gateway.void(auth.authorization) + assert_success void + assert_equal 'Transaction Normal - Approved', void.message + end + def test_failed_void response = @gateway.void('') assert_failure response @@ -125,17 +236,17 @@ def test_successful_verify def test_failed_verify response = @gateway.verify(@bad_credit_card, @options) assert_failure response - assert_match %r{The card number must be numeric}, response.message + assert_match %r{The credit card number check failed}, response.message end def test_bad_creditcard_number assert response = @gateway.purchase(@amount, @bad_credit_card, @options) assert_failure response - assert_equal response.error_code, "invalid_card_number" + assert_equal response.error_code, 'invalid_card_number' end def test_invalid_login - gateway = PayeezyGateway.new(apikey: "NotARealUser", apisecret: "NotARealPassword", token: "token") + gateway = PayeezyGateway.new(apikey: 'NotARealUser', apisecret: 'NotARealPassword', token: 'token') assert response = gateway.purchase(@amount, @credit_card, @options) assert_match %r{Invalid Api Key}, response.message assert_failure response @@ -144,17 +255,42 @@ def test_invalid_login def test_response_contains_cvv_and_avs_results response = @gateway.purchase(@amount, @credit_card, @options) assert_success response - assert_equal 'M', response.cvv_result["code"] - assert_equal '4', response.avs_result["code"] + assert_equal 'M', response.cvv_result['code'] + assert_equal '4', response.avs_result['code'] end def test_trans_error # ask for error 42 (unable to send trans) as the cents bit... @amount = 500042 - assert response = @gateway.purchase(@amount, @credit_card, @options ) - assert_match(/Internal Server Error/, response.message) # 42 is 'unable to send trans' + assert response = @gateway.purchase(@amount, @credit_card, @options) + assert_match(/Server Error/, response.message) # 42 is 'unable to send trans' assert_failure response - assert_equal response.error_code, "internal_server_error" + assert_equal '500', response.error_code + end + + def test_transcript_scrubbing_store + transcript = capture_transcript(@gateway) do + @gateway.store(@credit_card, @options) + end + + transcript = @gateway.scrub(transcript) + assert_scrubbed(@credit_card.number, transcript) + assert_scrubbed(@credit_card.verification_value, transcript) + assert_scrubbed(@gateway.options[:token], transcript) + assert_scrubbed(@gateway.options[:apikey], transcript) + end + + def test_transcript_scrubbing_store_with_missing_ta_token + transcript = capture_transcript(@gateway) do + @options.delete(:ta_token) + @gateway.store(@credit_card, @options) + end + + transcript = @gateway.scrub(transcript) + assert_scrubbed(@credit_card.number, transcript) + assert_scrubbed(@credit_card.verification_value, transcript) + assert_scrubbed(@gateway.options[:token], transcript) + assert_scrubbed(@gateway.options[:apikey], transcript) end def test_transcript_scrubbing diff --git a/test/remote/gateways/remote_payex_test.rb b/test/remote/gateways/remote_payex_test.rb index a66385b6927..fd37ddb6164 100644 --- a/test/remote/gateways/remote_payex_test.rb +++ b/test/remote/gateways/remote_payex_test.rb @@ -54,7 +54,7 @@ def test_authorization_and_void end def test_unsuccessful_void - assert response = @gateway.void("1") + assert response = @gateway.void('1') assert_failure response assert_not_equal 'OK', response.message assert_match %r{1}, response.message @@ -69,7 +69,7 @@ def test_successful_refund end def test_unsuccessful_refund - assert response = @gateway.refund(@amount, "1", order_id: '123') + assert response = @gateway.refund(@amount, '1', order_id: '123') assert_failure response assert_not_equal 'OK', response.message assert_match %r{1}, response.message diff --git a/test/remote/gateways/remote_payflow_express_test.rb b/test/remote/gateways/remote_payflow_express_test.rb index cbe24df044b..827907d02d9 100644 --- a/test/remote/gateways/remote_payflow_express_test.rb +++ b/test/remote/gateways/remote_payflow_express_test.rb @@ -3,22 +3,24 @@ class RemotePayflowExpressTest < Test::Unit::TestCase def setup Base.mode = :test - + @gateway = PayflowExpressGateway.new(fixtures(:payflow)) - @options = { :billing_address => { - :name => 'Cody Fauser', - :address1 => '1234 Shady Brook Lane', - :city => 'Ottawa', - :state => 'ON', - :country => 'CA', - :zip => '90210', - :phone => '555-555-5555' - }, - :email => 'cody@example.com' - } + @options = { + :billing_address => + { + :name => 'Cody Fauser', + :address1 => '1234 Shady Brook Lane', + :city => 'Ottawa', + :state => 'ON', + :country => 'CA', + :zip => '90210', + :phone => '555-555-5555' + }, + :email => 'cody@example.com' + } end - + # Only works with a Payflow 2.0 account or by requesting the addition # of Express checkout to an existing Payflow Pro account. This can be done # by contacting Payflow sales. The PayPal account used must be a business @@ -35,7 +37,7 @@ def test_set_express_authorization assert response.test? assert !response.params['token'].blank? end - + def test_set_express_purchase @options.update( :return_url => 'http://example.com', @@ -50,66 +52,81 @@ def test_set_express_purchase def test_setup_authorization_discount_taxes_included_free_shipping amount = 2518 - options = {:ip=>"127.0.0.1", - :return_url=>"http://localhost:3000/orders/1/8e06ea26f8add7608671d433f13c2193/commit_paypal?buyer_accepts_marketing=true&utm_nooverride=1", - :cancel_return_url=>"http://localhost:3000/orders/1/8e06ea26f8add7608671d433f13c2193/commit_paypal?utm_nooverride=1", - :customer=>"test6@test.com", - :email=>"test6@test.com", - :order_id=>"#1092", - :currency=>"USD", + options = { + :ip=>'127.0.0.1', + :return_url=>'http://localhost:3000/orders/1/8e06ea26f8add7608671d433f13c2193/commit_paypal?buyer_accepts_marketing=true&utm_nooverride=1', + :cancel_return_url=>'http://localhost:3000/orders/1/8e06ea26f8add7608671d433f13c2193/commit_paypal?utm_nooverride=1', + :customer=>'test6@test.com', + :email=>'test6@test.com', + :order_id=>'#1092', + :currency=>'USD', :subtotal=>2798, :items => [ - {:name => "test4", - :description => "test4", - :quantity=>2 , - :amount=> 1399 , - :url=>"http://localhost:3000/products/test4"}], + { + :name => 'test4', + :description => 'test4', + :quantity=>2, + :amount=> 1399, + :url=>'http://localhost:3000/products/test4' + } + ], :discount=>280, - :no_shipping=>true} + :no_shipping=>true + } response = @gateway.setup_authorization(amount, options) assert response.success?, response.message end def test_setup_authorization_with_discount_taxes_additional amount = 2518 - options = {:ip=>"127.0.0.1", - :return_url=>"http://localhost:3000/orders/1/8e06ea26f8add7608671d433f13c2193/commit_paypal?buyer_accepts_marketing=true&utm_nooverride=1", - :cancel_return_url=>"http://localhost:3000/orders/1/8e06ea26f8add7608671d433f13c2193/commit_paypal?utm_nooverride=1", - :customer=>"test6@test.com", - :email=>"test6@test.com", - :order_id=>"#1092", - :currency=>"USD", + options = { + :ip=>'127.0.0.1', + :return_url=>'http://localhost:3000/orders/1/8e06ea26f8add7608671d433f13c2193/commit_paypal?buyer_accepts_marketing=true&utm_nooverride=1', + :cancel_return_url=>'http://localhost:3000/orders/1/8e06ea26f8add7608671d433f13c2193/commit_paypal?utm_nooverride=1', + :customer=>'test6@test.com', + :email=>'test6@test.com', + :order_id=>'#1092', + :currency=>'USD', :subtotal=>2798, :items => [ - {:name => "test4", - :description => "test4", - :quantity=>2 , - :amount=> 1399 , - :url=>"http://localhost:3000/products/test4"}], + { + :name => 'test4', + :description => 'test4', + :quantity=>2, + :amount=> 1399, + :url=>'http://localhost:3000/products/test4' + } + ], :discount=>280, - :no_shipping=>true} + :no_shipping=>true + } response = @gateway.setup_authorization(amount, options) assert response.success?, response.message end def test_setup_authorization_with_discount_taxes_and_shipping_addtiional amount = 2518 - options = {:ip=>"127.0.0.1", - :return_url=>"http://localhost:3000/orders/1/8e06ea26f8add7608671d433f13c2193/commit_paypal?buyer_accepts_marketing=true&utm_nooverride=1", - :cancel_return_url=>"http://localhost:3000/orders/1/8e06ea26f8add7608671d433f13c2193/commit_paypal?utm_nooverride=1", - :customer=>"test6@test.com", - :email=>"test6@test.com", - :order_id=>"#1092", - :currency=>"USD", + options = { + :ip=>'127.0.0.1', + :return_url=>'http://localhost:3000/orders/1/8e06ea26f8add7608671d433f13c2193/commit_paypal?buyer_accepts_marketing=true&utm_nooverride=1', + :cancel_return_url=>'http://localhost:3000/orders/1/8e06ea26f8add7608671d433f13c2193/commit_paypal?utm_nooverride=1', + :customer=>'test6@test.com', + :email=>'test6@test.com', + :order_id=>'#1092', + :currency=>'USD', :subtotal=>2798, :items => [ - {:name => "test4", - :description => "test4", - :quantity=>2 , - :amount=> 1399 , - :url=>"http://localhost:3000/products/test4"}], + { + :name => 'test4', + :description => 'test4', + :quantity=>2, + :amount=> 1399, + :url=>'http://localhost:3000/products/test4' + } + ], :discount=>280, - :no_shipping=>false} + :no_shipping=>false + } response = @gateway.setup_authorization(amount, options) assert response.success?, response.message end @@ -123,69 +140,81 @@ def setup def test_setup_authorization_discount_taxes_included_free_shipping amount = 2518 - options = {:ip=>"127.0.0.1", - :return_url=>"http://localhost:3000/orders/1/8e06ea26f8add7608671d433f13c2193/commit_paypal?buyer_accepts_marketing=true&utm_nooverride=1", - :cancel_return_url=>"http://localhost:3000/orders/1/8e06ea26f8add7608671d433f13c2193/commit_paypal?utm_nooverride=1", - :customer=>"test6@test.com", - :email=>"test6@test.com", - :order_id=>"#1092", - :currency=>"GBP", + options = { + :ip=>'127.0.0.1', + :return_url=>'http://localhost:3000/orders/1/8e06ea26f8add7608671d433f13c2193/commit_paypal?buyer_accepts_marketing=true&utm_nooverride=1', + :cancel_return_url=>'http://localhost:3000/orders/1/8e06ea26f8add7608671d433f13c2193/commit_paypal?utm_nooverride=1', + :customer=>'test6@test.com', + :email=>'test6@test.com', + :order_id=>'#1092', + :currency=>'GBP', :subtotal=>2798, :items=> [ - {:name=>"test4", - :description=>"test4", + { + :name=>'test4', + :description=>'test4', :quantity=>2, :amount=>1399, - :url=>"http://localhost:3000/products/test4"}, - ], + :url=>'http://localhost:3000/products/test4' + } + ], :discount=>280, - :no_shipping=>true} + :no_shipping=>true + } response = @gateway.setup_authorization(amount, options) assert response.success?, response.message end def test_setup_authorization_with_discount_taxes_additional amount = 2518 - options = {:ip=>"127.0.0.1", - :return_url=>"http://localhost:3000/orders/1/8e06ea26f8add7608671d433f13c2193/commit_paypal?buyer_accepts_marketing=true&utm_nooverride=1", - :cancel_return_url=>"http://localhost:3000/orders/1/8e06ea26f8add7608671d433f13c2193/commit_paypal?utm_nooverride=1", - :customer=>"test6@test.com", - :email=>"test6@test.com", - :order_id=>"#1092", - :currency=>"GBP", + options = { + :ip=>'127.0.0.1', + :return_url=>'http://localhost:3000/orders/1/8e06ea26f8add7608671d433f13c2193/commit_paypal?buyer_accepts_marketing=true&utm_nooverride=1', + :cancel_return_url=>'http://localhost:3000/orders/1/8e06ea26f8add7608671d433f13c2193/commit_paypal?utm_nooverride=1', + :customer=>'test6@test.com', + :email=>'test6@test.com', + :order_id=>'#1092', + :currency=>'GBP', :subtotal=>2798, :items=> [ - {:name=>"test4", - :description=>"test4", + { + :name=>'test4', + :description=>'test4', :quantity=>2, :amount=>1399, - :url=>"http://localhost:3000/products/test4"}, - ], + :url=>'http://localhost:3000/products/test4' + } + ], :discount=>280, - :no_shipping=>true} + :no_shipping=>true + } response = @gateway.setup_authorization(amount, options) assert response.success?, response.message end def test_setup_authorization_with_discount_taxes_and_shipping_addtiional amount = 2518 - options = {:ip=>"127.0.0.1", - :return_url=>"http://localhost:3000/orders/1/8e06ea26f8add7608671d433f13c2193/commit_paypal?buyer_accepts_marketing=true&utm_nooverride=1", - :cancel_return_url=>"http://localhost:3000/orders/1/8e06ea26f8add7608671d433f13c2193/commit_paypal?utm_nooverride=1", - :customer=>"test6@test.com", - :email=>"test6@test.com", - :order_id=>"#1092", - :currency=>"GBP", + options = { + :ip=>'127.0.0.1', + :return_url=>'http://localhost:3000/orders/1/8e06ea26f8add7608671d433f13c2193/commit_paypal?buyer_accepts_marketing=true&utm_nooverride=1', + :cancel_return_url=>'http://localhost:3000/orders/1/8e06ea26f8add7608671d433f13c2193/commit_paypal?utm_nooverride=1', + :customer=>'test6@test.com', + :email=>'test6@test.com', + :order_id=>'#1092', + :currency=>'GBP', :subtotal=>2798, :items=> [ - {:name=>"test4", - :description=>"test4", + { + :name=>'test4', + :description=>'test4', :quantity=>2, :amount=>1399, - :url=>"http://localhost:3000/products/test4"}, - ], + :url=>'http://localhost:3000/products/test4' + } + ], :discount=>280, - :no_shipping=>false} + :no_shipping=>false + } response = @gateway.setup_authorization(amount, options) assert response.success?, response.message end diff --git a/test/remote/gateways/remote_payflow_test.rb b/test/remote/gateways/remote_payflow_test.rb index b0068e50c96..6104f8e45bd 100644 --- a/test/remote/gateways/remote_payflow_test.rb +++ b/test/remote/gateways/remote_payflow_test.rb @@ -17,15 +17,32 @@ def setup :customer => 'codyexample' } + @extra_options = { + :order_id => '123', + :description => 'Description string', + :order_desc => 'OrderDesc string', + :comment => 'Comment string', + :comment2 => 'Comment2 string' + } + @check = check( :routing_number => '111111118', - :account_number => '1234567801' + :account_number => '1111111111' ) end def test_successful_purchase assert response = @gateway.purchase(100000, @credit_card, @options) - assert_equal "Approved", response.message + assert_equal 'Approved', response.message + assert_success response + assert response.test? + assert_not_nil response.authorization + assert !response.fraud_review? + end + + def test_successful_purchase_with_extra_options + assert response = @gateway.purchase(100000, @credit_card, @options.merge(@extra_options)) + assert_equal 'Approved', response.message assert_success response assert response.test? assert_not_nil response.authorization @@ -44,10 +61,10 @@ def test_successful_purchase def test_successful_purchase_with_fraud_review assert response = @gateway.purchase( 100000, - credit_card("5555555555554444", verification_value: "") + credit_card('5555555555554444', verification_value: '') ) - assert_success response, "This is probably failing due to your Payflow test account not being set up for fraud filters." - assert_equal "126", response.params["result"] + assert_success response, 'This is probably failing due to your Payflow test account not being set up for fraud filters.' + assert_equal '126', response.params['result'] assert response.fraud_review? end @@ -66,15 +83,25 @@ def test_declined_purchase # This can be accomplished by sending an email to payflow-support@paypal.com with your Merchant Login. def test_successful_ach_purchase assert response = @gateway.purchase(50, @check) - assert_success response, "This is probably failing due to your Payflow test account not being set up for ACH." - assert_equal "Approved", response.message + assert_success response, 'This is probably failing due to your Payflow test account not being set up for ACH.' + assert_equal 'Approved', response.message assert response.test? assert_not_nil response.authorization end + def test_ach_purchase_and_refund + assert response = @gateway.purchase(50, @check) + assert_success response + assert_equal 'Approved', response.message + assert !response.authorization.blank? + + assert credit = @gateway.refund(50, response.authorization) + assert_success credit + end + def test_successful_authorization assert response = @gateway.authorize(100, @credit_card, @options) - assert_equal "Approved", response.message + assert_equal 'Approved', response.message assert_success response assert response.test? assert_not_nil response.authorization @@ -108,6 +135,32 @@ def test_authorize_and_partial_capture assert_success capture end + def test_authorize_and_complete_capture + assert auth = @gateway.authorize(100 * 2, @credit_card, @options) + assert_success auth + assert_equal 'Approved', auth.message + assert auth.authorization + + assert capture = @gateway.capture(100, auth.authorization, :capture_complete => 'Y') + assert_success capture + + assert capture = @gateway.capture(100, auth.authorization) + assert_failure capture + end + + def test_authorize_and_uncomplete_capture + assert auth = @gateway.authorize(100 * 2, @credit_card, @options) + assert_success auth + assert_equal 'Approved', auth.message + assert auth.authorization + + assert capture = @gateway.capture(100, auth.authorization, :capture_complete => 'N') + assert_success capture + + assert capture = @gateway.capture(100, auth.authorization) + assert_success capture + end + def test_failed_capture assert response = @gateway.capture(100, '999') assert_failure response @@ -126,13 +179,23 @@ def test_authorize_and_void def test_successful_verify assert response = @gateway.verify(@credit_card, @options) assert_success response - assert_equal "Verified", response.message + assert_equal 'Verified', response.message + end + + def test_successful_verify_amex + @amex_credit_card = credit_card( + '378282246310005', + :brand => 'american_express' + ) + assert response = @gateway.verify(@amex_credit_card, @options) + assert_success response + assert_equal 'Approved', response.message end def test_failed_verify - assert response = @gateway.verify(credit_card("4000056655665556"), @options) + assert response = @gateway.verify(credit_card('4000056655665556'), @options) assert_failure response - assert_equal "Declined", response.message + assert_equal 'Declined', response.message end def test_invalid_login @@ -150,7 +213,7 @@ def test_duplicate_request_id SecureRandom.expects(:hex).times(2).returns(request_id) response1 = @gateway.purchase(100, @credit_card, @options) - assert response1.success? + assert response1.success? assert_nil response1.params['duplicate'] response2 = @gateway.purchase(100, @credit_card, @options) @@ -198,13 +261,13 @@ def test_full_feature_set_for_recurring_profiles :periodicity => :weekly, :payments => '12', :starting_at => Time.now + 1.day, - :comment => "Test Profile" + :comment => 'Test Profile' ) response = assert_deprecation_warning(Gateway::RECURRING_DEPRECATION_MESSAGE) do @gateway.recurring(100, @credit_card, @options) end - assert_equal "Approved", response.params['message'] - assert_equal "0", response.params['result'] + assert_equal 'Approved', response.params['message'] + assert_equal '0', response.params['result'] assert_success response assert response.test? assert !response.params['profile_id'].blank? @@ -220,8 +283,8 @@ def test_full_feature_set_for_recurring_profiles response = assert_deprecation_warning(Gateway::RECURRING_DEPRECATION_MESSAGE) do @gateway.recurring(400, @credit_card, @options) end - assert_equal "Approved", response.params['message'] - assert_equal "0", response.params['result'] + assert_equal 'Approved', response.params['message'] + assert_equal '0', response.params['result'] assert_success response assert response.test? @@ -229,7 +292,7 @@ def test_full_feature_set_for_recurring_profiles response = assert_deprecation_warning(Gateway::RECURRING_DEPRECATION_MESSAGE) do @gateway.recurring_inquiry(@recurring_profile_id) end - assert_equal "0", response.params['result'] + assert_equal '0', response.params['result'] assert_success response assert response.test? @@ -245,8 +308,8 @@ def test_full_feature_set_for_recurring_profiles response = assert_deprecation_warning(Gateway::RECURRING_DEPRECATION_MESSAGE) do @gateway.cancel_recurring(@recurring_profile_id) end - assert_equal "Approved", response.params['message'] - assert_equal "0", response.params['result'] + assert_equal 'Approved', response.params['message'] + assert_equal '0', response.params['result'] assert_success response assert response.test? end @@ -254,14 +317,14 @@ def test_full_feature_set_for_recurring_profiles # Note that this test will only work if you enable reference transactions!! def test_reference_purchase assert response = @gateway.purchase(10000, @credit_card, @options) - assert_equal "Approved", response.message + assert_equal 'Approved', response.message assert_success response assert response.test? assert_not_nil pn_ref = response.authorization # now another purchase, by reference assert response = @gateway.purchase(10000, pn_ref) - assert_equal "Approved", response.message + assert_equal 'Approved', response.message assert_success response assert response.test? end @@ -297,7 +360,7 @@ def test_purchase_and_refund def test_verify_credentials assert @gateway.verify_credentials - gateway = PayflowGateway.new(login: "unknown_login", password: "unknown_password", partner: "PayPal") + gateway = PayflowGateway.new(login: 'unknown_login', password: 'unknown_password', partner: 'PayPal') assert !gateway.verify_credentials end @@ -320,13 +383,13 @@ def test_purchase_and_refund_with_three_d_secure_option # check) unless Allow non-referenced credits = Yes in PayPal manager def test_purchase_and_credit assert credit = @gateway.credit(100, @credit_card, @options) - assert_success credit, "This is probably failing due to your Payflow test account not being set up to allow non-referenced credits." + assert_success credit, 'This is probably failing due to your Payflow test account not being set up to allow non-referenced credits.' end def test_successful_ach_credit assert response = @gateway.credit(50, @check) - assert_success response, "This is probably failing due to your Payflow test account not being set up for ACH." - assert_equal "Approved", response.message + assert_success response, 'This is probably failing due to your Payflow test account not being set up for ACH.' + assert_equal 'Approved', response.message assert response.test? assert_not_nil response.authorization end @@ -350,4 +413,23 @@ def three_d_secure_option } } end + + def test_transcript_scrubbing + transcript = capture_transcript(@gateway) do + @gateway.purchase(@amount, @credit_card, @options) + end + transcript = @gateway.scrub(transcript) + + assert_scrubbed(@credit_card.number, transcript) + assert_scrubbed(@credit_card.verification_value, transcript) + assert_scrubbed(@gateway.options[:password], transcript) + + transcript = capture_transcript(@gateway) do + @gateway.purchase(50, @check) + end + transcript = @gateway.scrub(transcript) + + assert_scrubbed(@check.account_number, transcript) + assert_scrubbed(@gateway.options[:password], transcript) + end end diff --git a/test/remote/gateways/remote_payflow_uk_test.rb b/test/remote/gateways/remote_payflow_uk_test.rb index 86d532693c0..afe6791cfc8 100644 --- a/test/remote/gateways/remote_payflow_uk_test.rb +++ b/test/remote/gateways/remote_payflow_uk_test.rb @@ -6,7 +6,7 @@ def setup # The default partner is PayPalUk @gateway = PayflowUkGateway.new(fixtures(:payflow_uk)) - + @creditcard = CreditCard.new( :number => '5105105105105100', :month => 11, @@ -16,28 +16,8 @@ def setup :verification_value => '000', :brand => 'master' ) - - @solo = CreditCard.new( - :brand => "solo", - :number => "6334900000000005", - :month => Time.now.month, - :year => Time.now.year + 1, - :first_name => "Test", - :last_name => "Mensch", - :issue_number => '01' - ) - - @switch = CreditCard.new( - :brand => "switch", - :number => "5641820000000005", - :verification_value => "000", - :month => 1, - :year => 2008, - :first_name => 'Fred', - :last_name => 'Brooks' - ) - - @options = { + + @options = { :billing_address => { :name => 'Cody Fauser', :address1 => '1234 Shady Brook Lane', @@ -50,72 +30,72 @@ def setup :email => 'cody@example.com' } end - + def test_successful_purchase assert response = @gateway.purchase(100000, @creditcard, @options) - assert_equal "Approved", response.message + assert_equal 'Approved', response.message assert_success response assert response.test? assert_not_nil response.authorization end - + def test_declined_purchase assert response = @gateway.purchase(210000, @creditcard, @options) assert_equal 'Failed merchant rule check', response.message assert_failure response assert response.test? end - + def test_successful_purchase_solo - assert response = @gateway.purchase(100000, @solo, @options) - assert_equal "Approved", response.message - assert_success response - assert response.test? - assert_not_nil response.authorization - end - + assert response = @gateway.purchase(100000, @solo, @options) + assert_equal 'Approved', response.message + assert_success response + assert response.test? + assert_not_nil response.authorization + end + def test_no_card_issue_or_card_start_with_switch assert response = @gateway.purchase(100000, @switch, @options) assert_failure response - - assert_equal "Field format error: CARDSTART or CARDISSUE must be present", response.message + + assert_equal 'Field format error: CARDSTART or CARDISSUE must be present', response.message assert_failure response assert response.test? end - + def test_successful_purchase_switch_with_issue_number @switch.issue_number = '01' assert response = @gateway.purchase(100000, @switch, @options) - assert_equal "Approved", response.message + assert_equal 'Approved', response.message assert_success response assert response.test? assert_not_nil response.authorization end - + def test_successful_purchase_switch_with_start_date @switch.start_month = 12 @switch.start_year = 1999 assert response = @gateway.purchase(100000, @switch, @options) - assert_equal "Approved", response.message + assert_equal 'Approved', response.message assert_success response assert response.test? assert_not_nil response.authorization end - + def test_successful_purchase_switch_with_start_date_and_issue_number @switch.issue_number = '05' @switch.start_month = 12 @switch.start_year = 1999 assert response = @gateway.purchase(100000, @switch, @options) - assert_equal "Approved", response.message + assert_equal 'Approved', response.message assert_success response assert response.test? assert_not_nil response.authorization end - + def test_successful_authorization assert response = @gateway.authorize(100, @creditcard, @options) - assert_equal "Approved", response.message + assert_equal 'Approved', response.message assert_success response assert response.test? assert_not_nil response.authorization @@ -130,13 +110,13 @@ def test_authorize_and_capture assert capture = @gateway.capture(amount, auth.authorization) assert_success capture end - + def test_failed_capture assert response = @gateway.capture(100, '999') assert_failure response assert_equal 'Invalid tender', response.message end - + def test_authorize_and_void assert auth = @gateway.authorize(100, @creditcard, @options) assert_success auth @@ -145,7 +125,7 @@ def test_authorize_and_void assert void = @gateway.void(auth.authorization) assert_success void end - + def test_invalid_login gateway = PayflowGateway.new( :login => '', @@ -155,16 +135,16 @@ def test_invalid_login assert_equal 'Invalid vendor account', response.message assert_failure response end - + def test_duplicate_request_id gateway = PayflowUkGateway.new( :login => @login, :password => @password ) - - request_id = Digest::SHA1.hexdigest(rand.to_s).slice(0,32) + + request_id = Digest::SHA1.hexdigest(rand.to_s).slice(0, 32) gateway.expects(:generate_unique_id).times(2).returns(request_id) - + response1 = gateway.purchase(100, @creditcard, @options) assert_nil response1.params['duplicate'] response2 = gateway.purchase(100, @creditcard, @options) diff --git a/test/remote/gateways/remote_payment_express_test.rb b/test/remote/gateways/remote_payment_express_test.rb index ce2dda8a764..355f1830817 100644 --- a/test/remote/gateways/remote_payment_express_test.rb +++ b/test/remote/gateways/remote_payment_express_test.rb @@ -20,26 +20,26 @@ def setup def test_successful_purchase assert response = @gateway.purchase(@amount, @credit_card, @options) assert_success response - assert_equal "The Transaction was approved", response.message + assert_equal 'The Transaction was approved', response.message assert_not_nil response.authorization end def test_successful_purchase_with_reference_id assert response = @gateway.purchase(@amount, @credit_card, @options) - assert_equal "The Transaction was approved", response.message + assert_equal 'The Transaction was approved', response.message assert_success response assert_not_nil response.authorization end def test_declined_purchase - assert response = @gateway.purchase(@amount, credit_card("5431111111111228"), @options) + assert response = @gateway.purchase(@amount, credit_card('5431111111111228'), @options) assert_match %r{declined}i, response.message assert_failure response end def test_successful_authorization assert response = @gateway.authorize(@amount, @credit_card, @options) - assert_equal "The Transaction was approved", response.message + assert_equal 'The Transaction was approved', response.message assert_success response assert_not_nil response.authorization end @@ -59,7 +59,7 @@ def test_purchase_and_refund assert_success purchase assert_equal 'The Transaction was approved', purchase.message assert !purchase.authorization.blank? - assert refund = @gateway.refund(amount, purchase.authorization, :description => "Giving a refund") + assert refund = @gateway.refund(amount, purchase.authorization, :description => 'Giving a refund') assert_success refund end @@ -75,29 +75,28 @@ def test_invalid_login :password => '' ) assert response = gateway.purchase(@amount, @credit_card, @options) - assert_match %r{error}i, response.message + assert_match %r{Invalid Credentials}i, response.message assert_failure response end def test_store_credit_card assert response = @gateway.store(@credit_card) assert_success response - assert_equal "The Transaction was approved", response.message + assert_equal 'The Transaction was approved', response.message assert_not_nil token = response.authorization assert_equal token, response.token end def test_store_with_custom_token - token = Time.now.to_i.to_s #hehe + token = Time.now.to_i.to_s assert response = @gateway.store(@credit_card, :billing_id => token) assert_success response - assert_equal "The Transaction was approved", response.message + assert_equal 'The Transaction was approved', response.message assert_not_nil response.authorization assert_equal token, response.authorization end def test_store_invalid_credit_card - original_number = @credit_card.number @credit_card.number = 2 assert response = @gateway.store(@credit_card) @@ -107,11 +106,11 @@ def test_store_invalid_credit_card def test_store_and_charge assert response = @gateway.store(@credit_card) assert_success response - assert_equal "The Transaction was approved", response.message - assert (token = response.authorization) + assert_equal 'The Transaction was approved', response.message + assert(token = response.authorization) - assert purchase = @gateway.purchase( @amount, token) - assert_equal "The Transaction was approved", purchase.message + assert purchase = @gateway.purchase(@amount, token) + assert_equal 'The Transaction was approved', purchase.message assert_success purchase assert_not_nil purchase.authorization end @@ -119,8 +118,8 @@ def test_store_and_charge def test_store_and_authorize_and_capture assert response = @gateway.store(@credit_card) assert_success response - assert_equal "The Transaction was approved", response.message - assert (token = response.authorization) + assert_equal 'The Transaction was approved', response.message + assert(token = response.authorization) assert auth = @gateway.authorize(@amount, token, @options) assert_success auth @@ -138,6 +137,7 @@ def test_transcript_scrubbing assert_scrubbed(@credit_card.number, clean_transcript) assert_scrubbed(@credit_card.verification_value.to_s, clean_transcript) + assert_scrubbed(@gateway.options[:password], clean_transcript) end end diff --git a/test/remote/gateways/remote_paymentez_test.rb b/test/remote/gateways/remote_paymentez_test.rb new file mode 100644 index 00000000000..a09a19f1581 --- /dev/null +++ b/test/remote/gateways/remote_paymentez_test.rb @@ -0,0 +1,177 @@ +require 'test_helper' + +class RemotePaymentezTest < Test::Unit::TestCase + def setup + @gateway = PaymentezGateway.new(fixtures(:paymentez)) + + @amount = 100 + @credit_card = credit_card('4111111111111111', verification_value: '666') + @declined_card = credit_card('4242424242424242', verification_value: '666') + @options = { + billing_address: address, + description: 'Store Purchase', + user_id: '998', + email: 'joe@example.com', + vat: 0, + dev_reference: 'Testing' + } + end + + def test_successful_purchase + response = @gateway.purchase(@amount, @credit_card, @options) + assert_success response + end + + def test_successful_purchase_with_more_options + options = { + order_id: '1', + ip: '127.0.0.1', + tax_percentage: 0.07, + phone: '333 333 3333' + } + + response = @gateway.purchase(@amount, @credit_card, @options.merge(options)) + assert_success response + end + + def test_successful_purchase_without_phone_billing_address_option + options = { + order_id: '1', + ip: '127.0.0.1', + tax_percentage: 0.07, + billing_address: { + phone: nil + } + } + + response = @gateway.purchase(@amount, @credit_card, @options.merge(options)) + assert_success response + end + + def test_successful_purchase_without_phone_option + options = { + order_id: '1', + ip: '127.0.0.1', + tax_percentage: 0.07 + } + + response = @gateway.purchase(@amount, @credit_card, @options.merge(options)) + assert_success response + end + + def test_successful_purchase_with_token + store_response = @gateway.store(@credit_card, @options) + assert_success store_response + token = store_response.authorization + purchase_response = @gateway.purchase(@amount, token, @options) + assert_success purchase_response + end + + def test_failed_purchase + response = @gateway.purchase(@amount, @declined_card, @options) + assert_failure response + assert_equal Gateway::STANDARD_ERROR_CODE[:card_declined], response.error_code + end + + def test_successful_refund + auth = @gateway.purchase(@amount, @credit_card, @options) + assert_success auth + + assert refund = @gateway.refund(@amount, @credit_card, @options) + assert_success refund + end + + def test_successful_void + auth = @gateway.purchase(@amount, @credit_card, @options) + assert_success auth + + assert void = @gateway.void(auth.authorization) + assert_success void + end + + def test_failed_void + response = @gateway.void('') + assert_failure response + assert_equal 'Carrier not supported', response.message + assert_equal Gateway::STANDARD_ERROR_CODE[:config_error], response.error_code + end + + def test_successful_authorize_and_capture + auth = @gateway.authorize(@amount, @credit_card, @options) + assert_success auth + assert capture = @gateway.capture(@amount, auth.authorization) + assert_success capture + assert_equal 'Response by mock', capture.message + end + + def test_successful_authorize_and_capture_with_token + store_response = @gateway.store(@credit_card, @options) + assert_success store_response + token = store_response.authorization + auth = @gateway.authorize(@amount, token, @options) + assert_success auth + assert capture = @gateway.capture(@amount, auth.authorization) + assert_success capture + assert_equal 'Response by mock', capture.message + end + + def test_successful_authorize_and_capture_with_different_amount + auth = @gateway.authorize(@amount, @credit_card, @options) + assert_success auth + assert capture = @gateway.capture(@amount + 100, auth.authorization) + assert_success capture + assert_equal 'Response by mock', capture.message + end + + def test_failed_authorize + response = @gateway.authorize(@amount, @declined_card, @options) + assert_failure response + assert_equal 'Response by mock', response.message + end + + def test_partial_capture + auth = @gateway.authorize(@amount, @credit_card, @options) + assert_success auth + assert capture = @gateway.capture(@amount - 1, auth.authorization) + assert_failure capture # Paymentez explicitly does not support partial capture; only GREATER than auth capture + end + + def test_failed_capture + response = @gateway.capture(@amount, '') + assert_failure response + assert_equal 'The modification of the amount is not supported by carrier', response.message + end + + def test_store + response = @gateway.store(@credit_card, @options) + assert_success response + end + + def test_unstore + response = @gateway.store(@credit_card, @options) + assert_success response + auth = response.authorization + response = @gateway.unstore(auth, @options) + assert_success response + end + + def test_invalid_login + gateway = PaymentezGateway.new(application_code: '9z8y7w6x', app_key: '1a2b3c4d') + + response = gateway.purchase(@amount, @credit_card, @options) + assert_failure response + assert_equal 'BackendResponseException', response.message + assert_equal Gateway::STANDARD_ERROR_CODE[:config_error], response.error_code + end + + def test_transcript_scrubbing + transcript = capture_transcript(@gateway) do + @gateway.purchase(@amount, @credit_card, @options) + end + transcript = @gateway.scrub(transcript) + + assert_scrubbed(@credit_card.number, transcript) + assert_scrubbed(@credit_card.verification_value, transcript) + assert_scrubbed(@gateway.options[:app_key], transcript) + end +end diff --git a/test/remote/gateways/remote_paymill_test.rb b/test/remote/gateways/remote_paymill_test.rb index 66750bf524d..880f346a47d 100644 --- a/test/remote/gateways/remote_paymill_test.rb +++ b/test/remote/gateways/remote_paymill_test.rb @@ -124,7 +124,7 @@ def test_failed_refund end def test_invalid_login - gateway = PaymillGateway.new(public_key: fixtures(:paymill)[:public_key], private_key: "SomeBogusValue") + gateway = PaymillGateway.new(public_key: fixtures(:paymill)[:public_key], private_key: 'SomeBogusValue') response = gateway.purchase(@amount, @credit_card) assert_failure response assert_equal 'Access Denied', response.message @@ -168,7 +168,7 @@ def test_transcript_scrubbing def test_verify_credentials assert @gateway.verify_credentials - gateway = PaymillGateway.new(public_key: "unknown_key", private_key: "unknown_key") + gateway = PaymillGateway.new(public_key: 'unknown_key', private_key: 'unknown_key') assert !gateway.verify_credentials end diff --git a/test/remote/gateways/remote_paypal_express_test.rb b/test/remote/gateways/remote_paypal_express_test.rb index 0563993f0da..c599649a814 100644 --- a/test/remote/gateways/remote_paypal_express_test.rb +++ b/test/remote/gateways/remote_paypal_express_test.rb @@ -3,26 +3,28 @@ class PaypalExpressTest < Test::Unit::TestCase def setup Base.mode = :test - + @gateway = PaypalExpressGateway.new(fixtures(:paypal_certificate)) - + @options = { :order_id => '230000', :email => 'buyer@jadedpallet.com', - :billing_address => { :name => 'Fred Brooks', - :address1 => '1234 Penny Lane', - :city => 'Jonsetown', - :state => 'NC', - :country => 'US', - :zip => '23456' - } , + :billing_address => + { + :name => 'Fred Brooks', + :address1 => '1234 Penny Lane', + :city => 'Jonsetown', + :state => 'NC', + :country => 'US', + :zip => '23456' + }, :description => 'Stuff that you purchased, yo!', :ip => '10.0.0.1', :return_url => 'http://example.com/return', :cancel_return_url => 'http://example.com/cancel' } end - + def test_set_express_authorization @options.update( :return_url => 'http://example.com', @@ -34,7 +36,7 @@ def test_set_express_authorization assert response.test? assert !response.params['token'].blank? end - + def test_set_express_purchase @options.update( :return_url => 'http://example.com', @@ -46,4 +48,14 @@ def test_set_express_purchase assert response.test? assert !response.params['token'].blank? end -end + + def test_transcript_scrubbing + transcript = capture_transcript(@gateway) do + @gateway.setup_authorization(500, @options) + end + transcript = @gateway.scrub(transcript) + + assert_scrubbed(@gateway.options[:login], transcript) + assert_scrubbed(@gateway.options[:password], transcript) + end +end diff --git a/test/remote/gateways/remote_paypal_test.rb b/test/remote/gateways/remote_paypal_test.rb index 7027d394cf0..7465a369da7 100644 --- a/test/remote/gateways/remote_paypal_test.rb +++ b/test/remote/gateways/remote_paypal_test.rb @@ -4,19 +4,21 @@ class PaypalTest < Test::Unit::TestCase def setup @gateway = PaypalGateway.new(fixtures(:paypal_signature)) - @credit_card = credit_card("4381258770269608") # Use a generated CC from the paypal Sandbox + @credit_card = credit_card('4381258770269608') # Use a generated CC from the paypal Sandbox @declined_card = credit_card('234234234234') @params = { :order_id => generate_unique_id, :email => 'buyer@jadedpallet.com', - :billing_address => { :name => 'Longbob Longsen', - :address1 => '4321 Penny Lane', - :city => 'Jonsetown', - :state => 'NC', - :country => 'US', - :zip => '23456' - } , + :billing_address => + { + :name => 'Longbob Longsen', + :address1 => '4321 Penny Lane', + :city => 'Jonsetown', + :state => 'NC', + :country => 'US', + :zip => '23456' + }, :description => 'Stuff that you purchased, yo!', :ip => '10.0.0.1' } @@ -27,8 +29,8 @@ def setup # each auth-id can only be reauthorized and tested once. # leave it commented if you don't want to test reauthorization. # - #@three_days_old_auth_id = "9J780651TU4465545" - #@three_days_old_auth_id2 = "62503445A3738160X" + # @three_days_old_auth_id = "9J780651TU4465545" + # @three_days_old_auth_id2 = "62503445A3738160X" end def test_transcript_scrubbing @@ -41,6 +43,7 @@ def test_transcript_scrubbing assert_scrubbed(@credit_card.verification_value, transcript) assert_scrubbed(@gateway.options[:login], transcript) assert_scrubbed(@gateway.options[:password], transcript) + assert_scrubbed(@gateway.options[:signature], transcript) end def test_successful_purchase @@ -57,7 +60,7 @@ def test_successful_purchase_sans_cvv end def test_successful_purchase_with_descriptors - response = @gateway.purchase(@amount, @credit_card, @params.merge(soft_descriptor: "Active Merchant TXN", soft_descriptor_city: "800-883-3931")) + response = @gateway.purchase(@amount, @credit_card, @params.merge(soft_descriptor: 'Active Merchant TXN', soft_descriptor_city: '800-883-3931')) assert_success response assert response.params['transaction_id'] end @@ -115,7 +118,7 @@ def test_successful_capture def test_successful_incomplete_captures auth = @gateway.authorize(100, @credit_card, @params) assert_success auth - response = @gateway.capture(60, auth.authorization, {:complete_type => "NotComplete"}) + response = @gateway.capture(60, auth.authorization, {:complete_type => 'NotComplete'}) assert_success response assert response.params['transaction_id'] assert_equal '0.60', response.params['gross_amount'] @@ -165,7 +168,7 @@ def test_failed_voiding def test_successful_verify assert response = @gateway.verify(@credit_card, @params) assert_success response - assert_equal "0.00", response.params['amount'] + assert_equal '0.00', response.params['amount'] assert_match %r{This card authorization verification is not a payment transaction}, response.message end @@ -179,9 +182,9 @@ def test_successful_verify_non_visa_mc amex_card = credit_card('371449635398431', brand: nil, verification_value: '1234') assert response = @gateway.verify(amex_card, @params) assert_success response - assert_equal "1.00", response.params['amount'] + assert_equal '1.00', response.params['amount'] assert_match %r{Success}, response.message - assert_success response.responses.last, "The void should succeed" + assert_success response.responses.last, 'The void should succeed' end def test_successful_transfer @@ -193,7 +196,7 @@ def test_successful_transfer end def test_failed_transfer - # paypal allows a max transfer of $10,000 + # paypal allows a max transfer of $10,000 response = @gateway.transfer(1000001, 'joe@example.com') assert_failure response end @@ -213,7 +216,7 @@ def test_failed_multiple_transfer assert_success response # You can only include up to 250 recipients - recipients = (1..251).collect {|i| [100, "person#{i}@example.com"]} + recipients = (1..251).collect { |i| [100, "person#{i}@example.com"] } response = @gateway.transfer(*recipients) assert_failure response end diff --git a/test/remote/gateways/remote_payscout_test.rb b/test/remote/gateways/remote_payscout_test.rb index e3ad29ce708..ce0a0768a1e 100644 --- a/test/remote/gateways/remote_payscout_test.rb +++ b/test/remote/gateways/remote_payscout_test.rb @@ -21,13 +21,11 @@ def test_cvv_fail_purchase @credit_card = credit_card('4111111111111111') assert response = @gateway.purchase(@amount, @credit_card, @options) - assert_success response assert_equal 'The transaction has been approved', response.message assert_equal 'N', response.cvv_result['code'] end - def test_approved_purchase assert response = @gateway.purchase(@amount, @credit_card, @options) assert_success response @@ -98,26 +96,26 @@ def test_approved_refund purchase = @gateway.purchase(@amount, @credit_card, @options) assert refund = @gateway.refund(@amount, purchase.authorization) assert_success refund - assert_equal "The transaction has been approved", refund.message + assert_equal 'The transaction has been approved', refund.message end def test_not_found_transaction_id_refund assert refund = @gateway.refund(@amount, '1234567890') assert_failure refund - assert_match "Transaction not found", refund.message + assert_match 'Transaction not found', refund.message end def test_invalid_transaction_id_refund assert refund = @gateway.refund(@amount, '') assert_failure refund - assert_match "Invalid Transaction ID", refund.message + assert_match 'Invalid Transaction ID', refund.message end def test_invalid_amount_refund purchase = @gateway.purchase(@amount, @credit_card, @options) assert refund = @gateway.refund(200, purchase.authorization) assert_failure refund - assert_match "Refund amount may not exceed the transaction balance", refund.message + assert_match 'Refund amount may not exceed the transaction balance', refund.message end ########## Void ########## @@ -126,26 +124,26 @@ def test_approved_void_purchase purchase = @gateway.purchase(@amount, @credit_card, @options) assert void = @gateway.void(purchase.authorization) assert_success void - assert_equal "The transaction has been approved", void.message + assert_equal 'The transaction has been approved', void.message end def test_approved_void_authorization auth = @gateway.authorize(@amount, @credit_card, @options) assert void = @gateway.void(auth.authorization) assert_success void - assert_equal "The transaction has been approved", void.message + assert_equal 'The transaction has been approved', void.message end def test_invalid_transaction_id_void assert void = @gateway.void('') assert_failure void - assert_match "Invalid Transaction ID", void.message + assert_match 'Invalid Transaction ID', void.message end def test_not_found_transaction_id_void assert void = @gateway.void('1234567890') assert_failure void - assert_match "Transaction not found", void.message + assert_match 'Transaction not found', void.message end def test_invalid_credentials diff --git a/test/remote/gateways/remote_paystation_test.rb b/test/remote/gateways/remote_paystation_test.rb index ea773793dcc..84285905003 100644 --- a/test/remote/gateways/remote_paystation_test.rb +++ b/test/remote/gateways/remote_paystation_test.rb @@ -27,7 +27,7 @@ def test_successful_purchase end def test_successful_purchase_in_gbp - assert response = @gateway.purchase(@successful_amount, @credit_card, @options.merge(:currency => "GBP")) + assert response = @gateway.purchase(@successful_amount, @credit_card, @options.merge(:currency => 'GBP')) assert_success response assert_equal 'Transaction successful', response.message @@ -35,16 +35,14 @@ def test_successful_purchase_in_gbp def test_failed_purchases [ - ["insufficient_funds", @insufficient_funds_amount, "Insufficient Funds"], - ["invalid_transaction", @invalid_transaction_amount, "Transaction Type Not Supported"], - ["expired_card", @expired_card_amount, "Expired Card"], - ["bank_error", @bank_error_amount, "Error Communicating with Bank"] + ['insufficient_funds', @insufficient_funds_amount, 'Insufficient Funds'], + ['invalid_transaction', @invalid_transaction_amount, 'Transaction Type Not Supported'], + ['expired_card', @expired_card_amount, 'Expired Card'], + ['bank_error', @bank_error_amount, 'Error Communicating with Bank'] ].each do |name, amount, message| - - assert response = @gateway.purchase(amount, @credit_card, @options) - assert_failure response - assert_equal message, response.message - + assert response = @gateway.purchase(amount, @credit_card, @options) + assert_failure response + assert_equal message, response.message end end @@ -53,7 +51,7 @@ def test_storing_token assert response = @gateway.store(@credit_card, @options.merge(:token => "justatest#{time}")) assert_success response - assert_equal "Future Payment Saved Ok", response.message + assert_equal 'Future Payment Saved Ok', response.message assert_equal "justatest#{time}", response.token end @@ -63,7 +61,7 @@ def test_billing_stored_token assert charge_response = @gateway.purchase(@successful_amount, store_response.token, @options) assert_success charge_response - assert_equal "Transaction successful", charge_response.message + assert_equal 'Transaction successful', charge_response.message end def test_authorize_and_capture @@ -85,7 +83,7 @@ def test_capture_without_cvv assert capture = @gateway.capture(@successful_amount, auth.authorization, @options) assert_failure capture - assert_equal "Card Security Code (CVV/CSC) Required", capture.message + assert_equal 'Card Security Code (CVV/CSC) Required', capture.message end def test_invalid_login @@ -101,13 +99,28 @@ def test_successful_refund assert_success response refund = @gateway.refund(@successful_amount, response.authorization, @options) assert_success refund - assert_equal "Transaction successful", refund.message + assert_equal 'Transaction successful', refund.message end def test_failed_refund - response = @gateway.refund(nil, "", @options) + response = @gateway.refund(nil, '', @options) assert_failure response - assert_equal "Error 11:", response.params["strong"] + assert_equal 'Error 11:', response.params['strong'] + end + + def test_successful_verify + response = @gateway.verify(@credit_card, @options) + assert_success response + assert_match %r{Transaction successful}, response.message end + def test_transcript_scrubbing + transcript = capture_transcript(@gateway) do + @gateway.purchase(@amount, @credit_card, @options) + end + transcript = @gateway.scrub(transcript) + + assert_scrubbed(@credit_card.number, transcript) + assert_scrubbed(@credit_card.verification_value, transcript) + end end diff --git a/test/remote/gateways/remote_payu_in_test.rb b/test/remote/gateways/remote_payu_in_test.rb index f8929893e05..182c3a1cc17 100644 --- a/test/remote/gateways/remote_payu_in_test.rb +++ b/test/remote/gateways/remote_payu_in_test.rb @@ -23,27 +23,27 @@ def test_successful_purchase_with_full_options @amount, @credit_card, order_id: generate_unique_id, - description: "Awesome!", - email: "jim@example.com", + description: 'Awesome!', + email: 'jim@example.com', billing_address: { - name: "Jim Smith", - address1: "123 Road", - address2: "Suite 123", - city: "Somewhere", - state: "ZZ", - country: "US", - zip: "12345", - phone: "12223334444" + name: 'Jim Smith', + address1: '123 Road', + address2: 'Suite 123', + city: 'Somewhere', + state: 'ZZ', + country: 'US', + zip: '12345', + phone: '12223334444' }, shipping_address: { - name: "Joe Bob", - address1: "987 Street", - address2: "Suite 987", - city: "Anyplace", - state: "AA", - country: "IN", - zip: "98765", - phone: "98887776666" + name: 'Joe Bob', + address1: '987 Street', + address2: 'Suite 987', + city: 'Anyplace', + state: 'AA', + country: 'IN', + zip: '98765', + phone: '98887776666' } ) @@ -78,9 +78,9 @@ def test_failed_refund end def test_3ds_enrolled_card_fails - response = @gateway.purchase(@amount, credit_card("4012001037141112"), @options) + response = @gateway.purchase(@amount, credit_card('4012001037141112'), @options) assert_failure response - assert_equal "3D-secure enrolled cards are not supported.", response.message + assert_equal '3D-secure enrolled cards are not supported.', response.message =begin # This is handy for testing that 3DS is working with PayU @@ -115,7 +115,7 @@ def test_transcript_scrubbing transcript = @gateway.scrub(transcript) assert_scrubbed(@credit_card.number, transcript) - refute_match %r{[^\d]#{@credit_card.verification_value}(?:[^\d]|$)}, "Expected CVV to be scrubbed out of transcript" + refute_match %r{[^\d]#{@credit_card.verification_value}(?:[^\d]|$)}, 'Expected CVV to be scrubbed out of transcript' end def test_invalid_login diff --git a/test/remote/gateways/remote_payu_latam_test.rb b/test/remote/gateways/remote_payu_latam_test.rb index 5685fa8feb1..8f6518fc4b1 100644 --- a/test/remote/gateways/remote_payu_latam_test.rb +++ b/test/remote/gateways/remote_payu_latam_test.rb @@ -1,27 +1,34 @@ -require "test_helper" +require 'test_helper' class RemotePayuLatamTest < Test::Unit::TestCase def setup - @gateway = PayuLatamGateway.new(fixtures(:payu_latam)) + @gateway = PayuLatamGateway.new(fixtures(:payu_latam).update(payment_country: 'AR')) @amount = 4000 - @credit_card = credit_card("4097440000000004", verification_value: "444", first_name: "APPROVED", last_name: "") - @declined_card = credit_card("4097440000000004", verification_value: "333", first_name: "REJECTED", last_name: "") - @pending_card = credit_card("4097440000000004", verification_value: "222", first_name: "PENDING", last_name: "") + @credit_card = credit_card('4097440000000004', verification_value: '444', first_name: 'APPROVED', last_name: '') + @declined_card = credit_card('4097440000000004', verification_value: '444', first_name: 'REJECTED', last_name: '') + @pending_card = credit_card('4097440000000004', verification_value: '444', first_name: 'PENDING', last_name: '') @options = { - currency: "ARS", + dni_number: '5415668464654', + currency: 'ARS', order_id: generate_unique_id, - description: "Active Merchant Transaction", + description: 'Active Merchant Transaction', installments_number: 1, + tax: 0, + email: 'username@domain.com', + ip: '127.0.0.1', + device_session_id: 'vghs6tvkcle931686k1900o6e1', + cookie: 'pt1t38347bs6jc9ruv2ecpv7o2', + user_agent: 'Mozilla/5.0 (Windows NT 5.1; rv:18.0) Gecko/20100101 Firefox/18.0', billing_address: address( - address1: "Viamonte", - address2: "1366", - city: "Plata", - state: "Buenos Aires", - country: "AR", - zip: "64000", - phone: "7563126" + address1: 'Viamonte', + address2: '1366', + city: 'Plata', + state: 'Buenos Aires', + country: 'AR', + zip: '64000', + phone: '7563126' ) } end @@ -30,7 +37,7 @@ def setup # supports auth and purchase transactions only def test_invalid_login - gateway = PayuLatamGateway.new(merchant_id: "", account_id: "", api_login: "U", api_key: "U") + gateway = PayuLatamGateway.new(merchant_id: '', account_id: '', api_login: 'U', api_key: 'U', payment_country: 'AR') response = gateway.purchase(@amount, @credit_card, @options) assert_failure response end @@ -38,105 +45,340 @@ def test_invalid_login def test_successful_purchase response = @gateway.purchase(@amount, @credit_card, @options) assert_success response - assert_equal "APPROVED", response.message + assert_equal 'APPROVED', response.message + assert response.test? + end + + def test_successful_purchase_with_specified_language + response = @gateway.purchase(@amount, @credit_card, @options.merge(language: 'es')) + assert_success response + assert_equal 'APPROVED', response.message + assert response.test? + end + + def test_successul_purchase_with_buyer + gateway = PayuLatamGateway.new(fixtures(:payu_latam).update(:account_id => '512327', payment_country: 'BR')) + + options_buyer = { + currency: 'BRL', + billing_address: address( + address1: 'Calle 100', + address2: 'BL4', + city: 'Sao Paulo', + state: 'SP', + country: 'BR', + zip: '09210710', + phone: '(11)756312633' + ), + shipping_address: address( + address1: 'Calle 200', + address2: 'N107', + city: 'Sao Paulo', + state: 'SP', + country: 'BR', + zip: '01019-030', + phone: '(11)756312633' + ), + buyer: { + name: 'Jorge Borges', + dni_number: '5415668464123', + dni_type: 'TI', + cnpj: '32593371000110', + email: 'axaxaxas@mlo.org' + } + } + + response = gateway.purchase(@amount, @credit_card, @options.update(options_buyer)) + assert_success response + assert_equal 'APPROVED', response.message assert response.test? end def test_successful_purchase_brazil - gateway = PayuLatamGateway.new(fixtures(:payu_latam).update(:account_id => "512327")) + gateway = PayuLatamGateway.new(fixtures(:payu_latam).update(:account_id => '512327', payment_country: 'BR')) options_brazil = { - currency: "BRL", + payment_country: 'BR', + currency: 'BRL', billing_address: address( - address1: "Calle 100", - address2: "BL4", - city: "Sao Paulo", - state: "SP", - country: "BR", - zip: "09210710", - phone: "(11)756312633" + address1: 'Calle 100', + address2: 'BL4', + city: 'Sao Paulo', + state: 'SP', + country: 'BR', + zip: '09210710', + phone: '(11)756312633' ), shipping_address: address( - address1: "Calle 200", - address2: "N107", - city: "Sao Paulo", - state: "SP", - country: "BR", - zip: "01019-030", - phone: "(11)756312633" - ) + address1: 'Calle 200', + address2: 'N107', + city: 'Sao Paulo', + state: 'SP', + country: 'BR', + zip: '01019-030', + phone: '(11)756312633' + ), + buyer: { + cnpj: '32593371000110' + } } response = gateway.purchase(@amount, @credit_card, @options.update(options_brazil)) assert_success response - assert_equal "APPROVED", response.message + assert_equal 'APPROVED', response.message assert response.test? end - def test_successful_purchase_sans_options - response = @gateway.purchase(@amount, @credit_card) + def test_successful_purchase_colombia + gateway = PayuLatamGateway.new(fixtures(:payu_latam).update(:account_id => '512321', payment_country: 'CO')) + + options_colombia = { + payment_country: 'CO', + currency: 'COP', + billing_address: address( + address1: 'Calle 100', + address2: 'BL4', + city: 'Bogota', + state: 'Bogota DC', + country: 'CO', + zip: '09210710', + phone: '(11)756312633' + ), + shipping_address: address( + address1: 'Calle 200', + address2: 'N107', + city: 'Bogota', + state: 'Bogota DC', + country: 'CO', + zip: '01019-030', + phone: '(11)756312633' + ), + tax: '3193', + tax_return_base: '16806' + } + + response = gateway.purchase(2000000, @credit_card, @options.update(options_colombia)) assert_success response - assert_equal "APPROVED", response.message + assert_equal 'APPROVED', response.message + assert response.test? + end + + def test_successful_purchase_mexico + gateway = PayuLatamGateway.new(fixtures(:payu_latam).update(:account_id => '512324', payment_country: 'MX')) + + options_mexico = { + payment_country: 'MX', + currency: 'MXN', + billing_address: address( + address1: 'Calle 100', + address2: 'BL4', + city: 'Guadalajara', + state: 'Jalisco', + country: 'MX', + zip: '09210710', + phone: '(11)756312633' + ), + shipping_address: address( + address1: 'Calle 200', + address2: 'N107', + city: 'Guadalajara', + state: 'Jalisco', + country: 'MX', + zip: '01019-030', + phone: '(11)756312633' + ), + birth_date: '1985-05-25' + } + + response = gateway.purchase(@amount, @credit_card, @options.update(options_mexico)) + assert_success response + assert_equal 'APPROVED', response.message + assert response.test? + end + + def test_successful_purchase_no_description + options = @options + options.delete(:description) + response = @gateway.purchase(@amount, @credit_card, options) + assert_success response + assert_equal 'APPROVED', response.message assert response.test? end def test_failed_purchase response = @gateway.purchase(@amount, @declined_card, @options) assert_failure response - assert_equal "ANTIFRAUD_REJECTED", response.message - assert_equal "DECLINED", response.params["transactionResponse"]["state"] + assert_equal 'DECLINED', response.params['transactionResponse']['state'] + end + + def test_failed_purchase_with_no_options + response = @gateway.purchase(@amount, @declined_card, {}) + assert_failure response + assert_equal 'DECLINED', response.params['transactionResponse']['state'] + end + + def test_failed_purchase_with_specified_language + gateway = PayuLatamGateway.new(merchant_id: '', account_id: '', api_login: 'U', api_key: 'U', payment_country: 'AR') + response = gateway.purchase(@amount, @declined_card, @options.merge(language: 'es')) + assert_failure response + assert_equal 'Credenciales inválidas', response.message end def test_successful_authorize response = @gateway.authorize(@amount, @credit_card, @options) assert_success response - assert_equal "APPROVED", response.message + assert_equal 'APPROVED', response.message + assert_match %r(^\d+\|(\w|-)+$), response.authorization + end + + def test_successful_authorize_with_specified_language + response = @gateway.authorize(@amount, @credit_card, @options.merge(language: 'es')) + assert_success response + assert_equal 'APPROVED', response.message assert_match %r(^\d+\|(\w|-)+$), response.authorization end def test_failed_authorize response = @gateway.authorize(@amount, @pending_card, @options) assert_failure response - assert_equal "PENDING_TRANSACTION_REVIEW", response.message - assert_equal "PENDING", response.params["transactionResponse"]["state"] + assert_equal 'DECLINED', response.params['transactionResponse']['state'] end + def test_failed_authorize_with_specified_language + gateway = PayuLatamGateway.new(merchant_id: '', account_id: '', api_login: 'U', api_key: 'U', payment_country: 'AR') + response = gateway.authorize(@amount, @pending_card, @options.merge(language: 'es')) + assert_failure response + assert_equal 'Credenciales inválidas', response.message + end + + # As noted above, capture transactions are currently not supported, but in the hope + # they will one day be, here you go + + # def test_successful_capture + # response = @gateway.authorize(@amount, @credit_card, @options) + # assert_success response + # assert_equal 'APPROVED', response.message + # assert_match %r(^\d+\|(\w|-)+$), response.authorization + + # capture = @gateway.capture(@amount, response.authorization, @options) + # assert_success capture + # assert_equal 'APPROVED', response.message + # assert response.test? + # end + + # def test_successful_partial_capture + # response = @gateway.authorize(@amount, @credit_card, @options) + # assert_success response + # assert_equal 'APPROVED', response.message + # assert_match %r(^\d+\|(\w|-)+$), response.authorization + + # capture = @gateway.capture(@amount - 1, response.authorization, @options) + # assert_success capture + # assert_equal 'APPROVED', response.message + # assert_equal '39.99', response.params['TX_VALUE']['value'] + # assert response.test? + # end + def test_well_formed_refund_fails_as_expected purchase = @gateway.purchase(@amount, @credit_card, @options) assert_success purchase assert refund = @gateway.refund(@amount, purchase.authorization, @options) - assert_equal "The payment plan id cannot be empty", refund.message + assert_equal 'The payment plan id cannot be empty', refund.message end def test_failed_refund response = @gateway.refund(@amount, '') assert_failure response - assert_match /property: parentTransactionId, message: must not be null/, response.message + assert_match(/property: parentTransactionId, message: must not be null/, response.message) + end + + def test_failed_refund_with_specified_language + response = @gateway.refund(@amount, '', language: 'es') + assert_failure response + assert_match(/property: parentTransactionId, message: No puede ser vacio/, response.message) end - def test_successful_void + # If this test fails, support for void may have been added to the sandbox + def test_unsupported_test_void_fails_as_expected auth = @gateway.authorize(@amount, @credit_card, @options) assert_success auth assert void = @gateway.void(auth.authorization) - assert_success void - assert_equal "APPROVED", void.message + assert_failure void + assert_equal 'Internal payment provider error. ', void.message end def test_failed_void response = @gateway.void('') assert_failure response - assert_match /property: parentTransactionId, message: must not be null/, response.message + assert_match(/property: parentTransactionId, message: must not be null/, response.message) + end + + def test_failed_void_with_specified_language + response = @gateway.void('', language: 'es') + assert_failure response + assert_match(/property: parentTransactionId, message: No puede ser vacio/, response.message) + end + + # If this test fails, support for captures may have been added to the sandbox + def test_unsupported_test_capture_fails_as_expected + auth = @gateway.authorize(@amount, @credit_card, @options) + assert_success auth + + assert capture = @gateway.capture(@amount, auth.authorization, @options) + assert_failure capture + assert_equal 'Internal payment provider error. ', capture.message + end + + def test_failed_capture + response = @gateway.capture(@amount, '') + assert_failure response + assert_match(/must not be null/, response.message) end def test_verify_credentials assert @gateway.verify_credentials - gateway = PayuLatamGateway.new(merchant_id: "X", account_id: "512322", api_login: "X", api_key: "X") + gateway = PayuLatamGateway.new(merchant_id: 'X', account_id: '512322', api_login: 'X', api_key: 'X', payment_country: 'AR') assert !gateway.verify_credentials end + def test_successful_verify + verify = @gateway.verify(@credit_card, @options) + + assert_success verify + assert_equal 'APPROVED', verify.message + end + + def test_successful_verify_with_specified_amount + verify = @gateway.verify(@credit_card, @options.merge(verify_amount: 5100)) + + assert_success verify + assert_equal 'APPROVED', verify.message + end + + def test_successful_verify_with_specified_language + verify = @gateway.verify(@credit_card, @options.merge(language: 'es')) + + assert_success verify + assert_equal 'APPROVED', verify.message + end + + def test_failed_verify_with_specified_amount + verify = @gateway.verify(@credit_card, @options.merge(verify_amount: 1699)) + + assert_failure verify + assert_equal 'The order value is less than minimum allowed. Minimum value allowed 17 ARS', verify.message + end + + def test_failed_verify_with_specified_language + verify = @gateway.verify(@credit_card, @options.merge(verify_amount: 1699, language: 'es')) + + assert_failure verify + assert_equal 'The order value is less than minimum allowed. Minimum value allowed 17 ARS', verify.message + end + def test_transcript_scrubbing transcript = capture_transcript(@gateway) do @gateway.purchase(@amount, @credit_card, @options) diff --git a/test/remote/gateways/remote_payway_test.rb b/test/remote/gateways/remote_payway_test.rb index a0dc5e6b086..9d900c8528b 100644 --- a/test/remote/gateways/remote_payway_test.rb +++ b/test/remote/gateways/remote_payway_test.rb @@ -8,42 +8,42 @@ def setup @gateway = ActiveMerchant::Billing::PaywayGateway.new(fixtures(:payway)) - @visa = credit_card("4564710000000004", + @visa = credit_card('4564710000000004', :month => 2, :year => 2019, - :verification_value => "847" + :verification_value => '847' ) - @mastercard = credit_card("5163200000000008", + @mastercard = credit_card('5163200000000008', :month => 8, :year => 2020, - :verification_value => "070", - :brand => "master" + :verification_value => '070', + :brand => 'master' ) - @expired = credit_card("4564710000000012", + @expired = credit_card('4564710000000012', :month => 2, :year => 2005, - :verification_value => "963" + :verification_value => '963' ) - @low = credit_card("4564710000000020", + @low = credit_card('4564710000000020', :month => 5, :year => 2020, - :verification_value => "234" + :verification_value => '234' ) - @stolen_mastercard = credit_card("5163200000000016", + @stolen_mastercard = credit_card('5163200000000016', :month => 12, :year => 2019, - :verification_value => "728", - :brand => "master" + :verification_value => '728', + :brand => 'master' ) - @invalid = credit_card("4564720000000037", + @invalid = credit_card('4564720000000037', :month => 9, :year => 2019, - :verification_value => "030" + :verification_value => '030' ) end diff --git a/test/remote/gateways/remote_pin_test.rb b/test/remote/gateways/remote_pin_test.rb index 8ad2f9ce593..e9851eacdf6 100644 --- a/test/remote/gateways/remote_pin_test.rb +++ b/test/remote/gateways/remote_pin_test.rb @@ -24,6 +24,25 @@ def test_successful_purchase assert_equal true, response.params['response']['captured'] end + def test_successful_purchase_with_metadata + options_with_metadata = { + metadata: { + order_id: generate_unique_id, + purchase_number: generate_unique_id + } + } + response = @gateway.purchase(@amount, @credit_card, @options.merge(options_with_metadata)) + assert_success response + assert_equal true, response.params['response']['captured'] + assert_equal options_with_metadata[:metadata][:order_id], response.params['response']['metadata']['order_id'] + assert_equal options_with_metadata[:metadata][:purchase_number], response.params['response']['metadata']['purchase_number'] + end + + def test_successful_purchase_with_reference + response = @gateway.purchase(@amount, @credit_card, @options.merge(reference: 'statement descriptor')) + assert_success response + end + def test_successful_authorize_and_capture authorization = @gateway.authorize(@amount, @credit_card, @options) assert_success authorization @@ -40,7 +59,7 @@ def test_failed_authorize end def test_failed_capture_due_to_invalid_token - response = @gateway.capture(@amount, "bogus", @options) + response = @gateway.capture(@amount, 'bogus', @options) assert_failure response end @@ -70,8 +89,8 @@ def test_unsuccessful_purchase # falls outside of active merchant def test_store_and_charge_with_pinjs_card_token headers = { - "Content-Type" => "application/json", - "Authorization" => "Basic #{Base64.strict_encode64(@gateway.options[:api_key] + ':').strip}" + 'Content-Type' => 'application/json', + 'Authorization' => "Basic #{Base64.strict_encode64(@gateway.options[:api_key] + ':').strip}" } # Get a token equivalent to what is returned by Pin.js card_attrs = { @@ -80,17 +99,17 @@ def test_store_and_charge_with_pinjs_card_token :expiry_year => @credit_card.year, :cvc => @credit_card.verification_value, :name => "#{@credit_card.first_name} #{@credit_card.last_name}", - :address_line1 => "42 Sevenoaks St", - :address_city => "Lathlain", - :address_postcode => "6454", - :address_start => "WA", - :address_country => "Australia" + :address_line1 => '42 Sevenoaks St', + :address_city => 'Lathlain', + :address_postcode => '6454', + :address_start => 'WA', + :address_country => 'Australia' } - url = @gateway.test_url + "/cards" + url = @gateway.test_url + '/cards' body = JSON.parse(@gateway.ssl_post(url, card_attrs.to_json, headers)) - card_token = body["response"]["token"] + card_token = body['response']['token'] store = @gateway.store(card_token, @options) assert_success store @@ -162,7 +181,7 @@ def test_transcript_scrubbing @gateway.purchase(@amount, @credit_card, @options) end clean_transcript = @gateway.scrub(transcript) - + assert_scrubbed(@credit_card.number, clean_transcript) assert_scrubbed(@credit_card.verification_value.to_s, clean_transcript) end diff --git a/test/remote/gateways/remote_plugnpay_test.rb b/test/remote/gateways/remote_plugnpay_test.rb index 1c57a5ec65d..f05f4dc7701 100644 --- a/test/remote/gateways/remote_plugnpay_test.rb +++ b/test/remote/gateways/remote_plugnpay_test.rb @@ -3,7 +3,7 @@ class PlugnpayTest < Test::Unit::TestCase def setup @gateway = PlugnpayGateway.new(fixtures(:plugnpay)) - @good_card = credit_card("4111111111111111", first_name: 'cardtest') + @good_card = credit_card('4111111111111111', first_name: 'cardtest') @bad_card = credit_card('1234123412341234') @options = { :billing_address => address, @@ -47,7 +47,7 @@ def test_authorization_and_capture assert capture = @gateway.capture(@amount, authorization.authorization) assert_success capture - assert capture.params['aux_msg'].include? "has been successfully marked for settlement." + assert capture.params['aux_msg'].include? 'has been successfully marked for settlement.' assert_equal 'Success', capture.message end @@ -57,7 +57,7 @@ def test_authorization_and_partial_capture assert capture = @gateway.capture(@amount - 1, authorization.authorization) assert_success capture - assert capture.params['aux_msg'].include? "has been successfully reauthed for usd 0.99" + assert capture.params['aux_msg'].include? 'has been successfully reauthed for usd 0.99' assert_equal 'Success', capture.message end diff --git a/test/remote/gateways/remote_pro_pay_test.rb b/test/remote/gateways/remote_pro_pay_test.rb new file mode 100644 index 00000000000..c447f996862 --- /dev/null +++ b/test/remote/gateways/remote_pro_pay_test.rb @@ -0,0 +1,160 @@ +require 'test_helper' + +class RemoteProPayTest < Test::Unit::TestCase + def setup + @gateway = ProPayGateway.new(fixtures(:pro_pay)) + + @amount = 100 + @credit_card = credit_card('4747474747474747', verification_value: 999) + @declined_card = credit_card('4616161616161616') + @credit_card_without_cvv = credit_card('4747474747474747', verification_value: nil) + @options = { + billing_address: address, + account_num: '32287391' + } + end + + def test_successful_purchase + response = @gateway.purchase(@amount, @credit_card, @options) + assert_success response + assert_equal 'Success', response.message + end + + def test_successful_purchase_with_more_options + options = { + order_id: '1', + ip: '127.0.0.1', + email: 'joe@example.com', + account_num: '32287391' + } + + response = @gateway.purchase(@amount, @credit_card, options) + assert_success response + assert_equal 'Success', response.message + end + + def test_successful_recurring_purchase_without_cvv + @options[:recurring_payment] = 'Y' + response = @gateway.purchase(@amount, @credit_card_without_cvv, @options) + assert_success response + assert_equal 'Success', response.message + end + + def test_failed_purchase + response = @gateway.purchase(@amount, @declined_card, @options) + assert_failure response + assert_match(/declined/, response.message) + assert_match(/Insufficient funds/, response.message) + end + + def test_successful_authorize_and_capture + auth = @gateway.authorize(@amount, @credit_card, @options) + assert_success auth + + assert capture = @gateway.capture(@amount, auth.authorization, @options) + assert_success capture + assert_equal 'Success', capture.message + end + + def test_failed_authorize + response = @gateway.authorize(@amount, @declined_card, @options) + assert_failure response + assert_match(/declined/, response.message) + assert_match(/Insufficient funds/, response.message) + end + + def test_partial_capture + auth = @gateway.authorize(@amount, @credit_card, @options) + assert_success auth + + assert capture = @gateway.capture(@amount-1, auth.authorization, @options) + assert_success capture + end + + def test_failed_capture + response = @gateway.capture(@amount, '', @options) + assert_failure response + assert_match(/Invalid/, response.message) + end + + def test_successful_refund + purchase = @gateway.purchase(@amount, @credit_card, @options) + assert_success purchase + + assert refund = @gateway.refund(@amount, purchase.authorization, @options) + assert_success refund + assert_equal 'Success', refund.message + end + + def test_partial_refund + purchase = @gateway.purchase(@amount, @credit_card, @options) + assert_success purchase + + assert refund = @gateway.refund(@amount-1, purchase.authorization, @options) + assert_success refund + end + + def test_failed_refund + response = @gateway.refund(@amount, '', @options) + assert_failure response + assert_match(/Invalid/, response.message) + end + + def test_successful_void + auth = @gateway.authorize(@amount, @credit_card, @options) + assert_success auth + + assert void = @gateway.void(auth.authorization, @options) + assert_success void + assert_equal 'Success', void.message + end + + def test_failed_void + response = @gateway.void('', @options) + assert_failure response + assert_match(/Invalid/, response.message) + end + + def test_successful_credit + response = @gateway.credit(@amount, @credit_card, @options) + assert_success response + assert_equal 'Success', response.message + end + + def test_failed_credit + response = @gateway.credit(@amount, credit_card(''), @options) + assert_failure response + assert_equal 'Invalid ccNum', response.message + end + + def test_successful_verify + response = @gateway.verify(@credit_card, @options) + assert_success response + assert_match 'Success', response.message + end + + def test_failed_verify + response = @gateway.verify(@declined_card, @options) + assert_failure response + assert_match(/declined/, response.message) + assert_match(/Insufficient funds/, response.message) + end + + def test_invalid_login + gateway = ProPayGateway.new(cert_str: 'bad_cert_str') + + response = gateway.purchase(@amount, @credit_card, @options) + assert_failure response + end + + def test_transcript_scrubbing + transcript = capture_transcript(@gateway) do + @gateway.purchase(@amount, @credit_card, @options) + end + transcript = @gateway.scrub(transcript) + + assert_scrubbed(@credit_card.number, transcript) + assert_scrubbed(@credit_card.verification_value, transcript) + assert_scrubbed(@gateway.options[:cert_str], transcript) + end +end diff --git a/test/remote/gateways/remote_psigate_test.rb b/test/remote/gateways/remote_psigate_test.rb index ec740a3ed37..74d643794fe 100644 --- a/test/remote/gateways/remote_psigate_test.rb +++ b/test/remote/gateways/remote_psigate_test.rb @@ -5,9 +5,10 @@ class PsigateRemoteTest < Test::Unit::TestCase def setup Base.mode = :test @gateway = PsigateGateway.new(fixtures(:psigate)) + PsigateGateway.ssl_strict = false @amount = 2400 - @creditcard = credit_card('4242424242424242') + @creditcard = credit_card('4111111111111111') @options = { :order_id => generate_unique_id, :billing_address => address, @@ -55,4 +56,15 @@ def test_successful_void assert void = @gateway.void(authorization.authorization) assert_success void end + + def test_transcript_scrubbing + transcript = capture_transcript(@gateway) do + @gateway.purchase(@amount, @creditcard, @options) + end + transcript = @gateway.scrub(transcript) + + assert_scrubbed(@creditcard.number, transcript) + assert_scrubbed(@creditcard.verification_value, transcript) + assert_scrubbed(@gateway.options[:password], transcript) + end end diff --git a/test/remote/gateways/remote_psl_card_test.rb b/test/remote/gateways/remote_psl_card_test.rb index 36af7abf443..6b1b9e6e215 100644 --- a/test/remote/gateways/remote_psl_card_test.rb +++ b/test/remote/gateways/remote_psl_card_test.rb @@ -1,29 +1,29 @@ require 'test_helper' class RemotePslCardTest < Test::Unit::TestCase - + def setup @gateway = PslCardGateway.new(fixtures(:psl_card)) - + @uk_maestro = CreditCard.new(fixtures(:psl_maestro)) @uk_maestro_address = fixtures(:psl_maestro_address) - + @solo = CreditCard.new(fixtures(:psl_solo)) @solo_address = fixtures(:psl_solo_address) - + @visa = CreditCard.new(fixtures(:psl_visa)) @visa_address = fixtures(:psl_visa_address) - + @visa_debit = CreditCard.new(fixtures(:psl_visa_debit)) @visa_address = fixtures(:psl_visa_debit_address) - + # The test results are determined by the amount of the transaction @accept_amount = 1000 @referred_amount = 6000 @declined_amount = 11000 @keep_card_amount = 15000 end - + def test_successful_visa_purchase response = @gateway.purchase(@accept_amount, @visa, :billing_address => @visa_address @@ -31,23 +31,23 @@ def test_successful_visa_purchase assert_success response assert response.test? end - + def test_successful_visa_debit_purchase response = @gateway.purchase(@accept_amount, @visa_debit, :billing_address => @visa_debit_address ) assert_success response end - + # Fix regression discovered in production def test_visa_debit_purchase_should_not_send_debit_info_if_present - @visa_debit.start_month = "07" + @visa_debit.start_month = '07' response = @gateway.purchase(@accept_amount, @visa_debit, :billing_address => @visa_debit_address ) assert_success response end - + def test_successful_visa_purchase_specifying_currency response = @gateway.purchase(@accept_amount, @visa, :billing_address => @visa_address, @@ -56,67 +56,67 @@ def test_successful_visa_purchase_specifying_currency assert_success response assert response.test? end - + def test_successful_solo_purchase - response = @gateway.purchase(@accept_amount, @solo, + response = @gateway.purchase(@accept_amount, @solo, :billing_address => @solo_address ) assert_success response assert response.test? end - + def test_referred_purchase - response = @gateway.purchase(@referred_amount, @uk_maestro, + response = @gateway.purchase(@referred_amount, @uk_maestro, :billing_address => @uk_maestro_address ) assert_failure response assert response.test? end - + def test_declined_purchase - response = @gateway.purchase(@declined_amount, @uk_maestro, + response = @gateway.purchase(@declined_amount, @uk_maestro, :billing_address => @uk_maestro_address ) assert_failure response assert response.test? end - + def test_declined_keep_card_purchase - response = @gateway.purchase(@keep_card_amount, @uk_maestro, + response = @gateway.purchase(@keep_card_amount, @uk_maestro, :billing_address => @uk_maestro_address ) assert_failure response assert response.test? end - + def test_successful_authorization - response = @gateway.authorize(@accept_amount, @visa, + response = @gateway.authorize(@accept_amount, @visa, :billing_address => @visa_address ) assert_success response assert response.test? end - + def test_no_login @gateway = PslCardGateway.new( :login => '' ) - response = @gateway.authorize(@accept_amount, @uk_maestro, + response = @gateway.authorize(@accept_amount, @uk_maestro, :billing_address => @uk_maestro_address ) assert_failure response assert response.test? end - + def test_successful_authorization_and_capture authorization = @gateway.authorize(@accept_amount, @visa, :billing_address => @visa_address ) assert_success authorization assert authorization.test? - + capture = @gateway.capture(@accept_amount, authorization.authorization) - + assert_success capture assert capture.test? end diff --git a/test/remote/gateways/remote_qbms_test.rb b/test/remote/gateways/remote_qbms_test.rb index d88553ec1c8..017ebd1fc95 100644 --- a/test/remote/gateways/remote_qbms_test.rb +++ b/test/remote/gateways/remote_qbms_test.rb @@ -66,31 +66,42 @@ def test_successful_credit end def test_invalid_ticket - gateway = QbmsGateway.new(@gateway_options.merge(:ticket => "test123")) + gateway = QbmsGateway.new(@gateway_options.merge(:ticket => 'test123')) assert response = gateway.authorize(@amount, @card, @options) assert_instance_of Response, response assert_failure response - assert_equal "Application agent not found test123", response.message + assert_equal 'Application agent not found test123', response.message end def test_invalid_card_number assert response = @gateway.authorize(@amount, error_card('10301_ccinvalid'), @options) assert_instance_of Response, response assert_failure response - assert_equal "This credit card number is invalid.", response.message + assert_equal 'This credit card number is invalid.', response.message end def test_decline assert response = @gateway.authorize(@amount, error_card('10401_decline'), @options) assert_instance_of Response, response assert_failure response - assert_equal "The request to process this transaction has been declined.", response.message + assert_equal 'The request to process this transaction has been declined.', response.message + end + + def test_transcript_scrubbing + transcript = capture_transcript(@gateway) do + @gateway.purchase(@amount, @credit_card, @options) + end + transcript = @gateway.scrub(transcript) + + assert_scrubbed(@credit_card.number, transcript) + assert_scrubbed(@credit_card.verification_value, transcript) + assert_scrubbed(@gateway.options[:ticket], transcript) end private def error_card(config_id) - credit_card('4111111111111111', :first_name => "configid=#{config_id}", :last_name => "") + credit_card('4111111111111111', :first_name => "configid=#{config_id}", :last_name => '') end end diff --git a/test/remote/gateways/remote_quantum_test.rb b/test/remote/gateways/remote_quantum_test.rb index dfa3b5682a5..370e802d66c 100644 --- a/test/remote/gateways/remote_quantum_test.rb +++ b/test/remote/gateways/remote_quantum_test.rb @@ -1,15 +1,14 @@ require 'test_helper' class RemoteQuantumTest < Test::Unit::TestCase - def setup @gateway = QuantumGateway.new(fixtures(:quantum)) - + @amount = 100 @credit_card = credit_card('4000100011112224') end - + def test_successful_purchase assert response = @gateway.purchase(@amount, @credit_card) assert_success response @@ -53,7 +52,7 @@ def test_void assert response = @gateway.void(response.authorization) assert_success response end - + def test_passing_billing_address options = {:billing_address => address} assert response = @gateway.purchase(@amount, @credit_card, options) diff --git a/test/remote/gateways/remote_quickbooks_test.rb b/test/remote/gateways/remote_quickbooks_test.rb index e1f061c6e04..c9e95c959c8 100644 --- a/test/remote/gateways/remote_quickbooks_test.rb +++ b/test/remote/gateways/remote_quickbooks_test.rb @@ -28,7 +28,7 @@ def test_successful_purchase def test_failed_purchase response = @gateway.purchase(@amount, @declined_card, @options) assert_failure response - assert_equal "cardNumber is invalid.", response.message + assert_equal 'cardNumber is invalid.', response.message end def test_successful_authorize_and_capture @@ -49,7 +49,7 @@ def test_partial_capture assert_success auth assert capture = @gateway.capture(@partial_amount, auth.authorization) - assert_equal capture.params['captureDetail']['amount'], sprintf("%.2f", @partial_amount.to_f / 100) + assert_equal capture.params['captureDetail']['amount'], sprintf('%.2f', @partial_amount.to_f / 100) assert_success capture end @@ -71,7 +71,7 @@ def test_partial_refund assert_success purchase assert refund = @gateway.refund(@partial_amount, purchase.authorization) - assert_equal refund.params['amount'], sprintf("%.2f", @partial_amount.to_f / 100) + assert_equal refund.params['amount'], sprintf('%.2f', @partial_amount.to_f / 100) assert_success refund end diff --git a/test/remote/gateways/remote_quickpay_test.rb b/test/remote/gateways/remote_quickpay_test.rb index 2733ee7eac3..760c71f096e 100644 --- a/test/remote/gateways/remote_quickpay_test.rb +++ b/test/remote/gateways/remote_quickpay_test.rb @@ -174,22 +174,22 @@ def test_successful_purchase_and_credit end def test_successful_store_and_reference_purchase - assert store = @gateway.store(@visa, @options.merge(:description => "New subscription")) + assert store = @gateway.store(@visa, @options.merge(:description => 'New subscription')) assert_success store assert purchase = @gateway.purchase(@amount, store.authorization, @options.merge(:order_id => generate_unique_id[0...10])) assert_success purchase end def test_failed_store - assert store = @gateway.store(credit_card('4'), @options.merge(:description => "New subscription")) + assert store = @gateway.store(credit_card('4'), @options.merge(:description => 'New subscription')) assert_failure store - assert_equal "Error in field: cardnumber", store.message + assert_equal 'Error in field: cardnumber', store.message end def test_invalid_login gateway = QuickpayGateway.new( - :login => '', - :password => '' + :login => '', + :password => '' ) assert response = gateway.purchase(@amount, @visa, @options) assert_equal 'Invalid merchant id', response.message diff --git a/test/remote/gateways/remote_quickpay_v10_test.rb b/test/remote/gateways/remote_quickpay_v10_test.rb index fe87601ddd7..4a349cecafd 100644 --- a/test/remote/gateways/remote_quickpay_v10_test.rb +++ b/test/remote/gateways/remote_quickpay_v10_test.rb @@ -68,13 +68,13 @@ def test_successful_usd_purchase end def test_successful_purchase_with_acquirers - assert response = @gateway.purchase(@amount, @valid_card, @options.update(:acquirer => "nets")) + assert response = @gateway.purchase(@amount, @valid_card, @options.update(:acquirer => 'nets')) assert_equal 'OK', response.message assert_success response end def test_unsuccessful_purchase_with_invalid_acquirers - assert response = @gateway.purchase(@amount, @valid_card, @options.update(:acquirer => "invalid")) + assert response = @gateway.purchase(@amount, @valid_card, @options.update(:acquirer => 'invalid')) assert_failure response assert_equal 'Validation error', response.message end @@ -82,7 +82,7 @@ def test_unsuccessful_purchase_with_invalid_acquirers def test_unsuccessful_authorize_with_invalid_card assert response = @gateway.authorize(@amount, @invalid_card, @options) assert_failure response - assert_match /Rejected test operation/, response.message + assert_match(/Rejected test operation/, response.message) end def test_successful_authorize_and_capture @@ -108,7 +108,7 @@ def test_unsuccessful_authorize_and_capture def test_failed_capture assert response = @gateway.capture(@amount, '1111') assert_failure response - assert_equal 'Unknown error - please contact QuickPay', response.message + assert_equal 'Not found: No Payment with id 1111', response.message end def test_successful_purchase_and_void @@ -121,6 +121,12 @@ def test_successful_purchase_and_void assert_equal 'OK', void.message end + def test_unsuccessful_void + assert void = @gateway.void('123') + assert_failure void + assert_equal 'Not found: No Payment with id 123', void.message + end + def test_successful_authorization_capture_and_credit assert auth = @gateway.authorize(@amount, @valid_card, @options) assert_success auth @@ -159,7 +165,7 @@ def test_successful_verify def test_failed_verify response = @gateway.verify(@invalid_card, @options) assert_failure response - assert_equal "Rejected test operation", response.message + assert_equal 'Rejected test operation', response.message end def test_successful_store @@ -174,6 +180,52 @@ def test_successful_store_and_reference_purchase assert_success purchase end + def test_successful_store_and_reference_recurring_purchase + assert store = @gateway.store(@valid_card, @options) + assert_success store + assert signup = @gateway.purchase(@amount, store.authorization, @options) + assert_success signup + @options[:order_id] = generate_unique_id[0...10] + assert renewal = @gateway.purchase(@amount, store.authorization, @options) + assert_success renewal + end + + def test_successful_store_and_reference_authorize + assert store = @gateway.store(@valid_card, @options) + assert_success store + assert authorization = @gateway.authorize(@amount, store.authorization, @options) + assert_success authorization + end + + def test_successful_store_and_credit + assert store = @gateway.store(@valid_card, @options) + assert_success store + assert purchase = @gateway.purchase(@amount, store.authorization, @options) + assert_success purchase + assert credit = @gateway.refund(@amount, purchase.authorization) + assert_success credit + end + + def test_unsuccessful_store_and_credit + assert store = @gateway.store(@refund_rejected_card, @options) + assert_success store + assert purchase = @gateway.purchase(@amount, store.authorization, @options) + assert_success purchase + assert credit = @gateway.refund(@amount, purchase.authorization) + assert_failure credit + assert_match(/Rejected test operation/, credit.message) + end + + def test_successful_store_and_void_authorize + assert store = @gateway.store(@valid_card, @options) + assert_success store + assert authorize = @gateway.authorize(@amount, store.authorization, @options) + assert_success authorize + assert void = @gateway.void(authorize.authorization) + assert_success void + assert_equal 'OK', void.message + end + def test_successful_unstore assert response = @gateway.store(@valid_card, @options) assert_success response diff --git a/test/remote/gateways/remote_quickpay_v4_test.rb b/test/remote/gateways/remote_quickpay_v4_test.rb index a17b1a15c12..9eb4ca69970 100644 --- a/test/remote/gateways/remote_quickpay_v4_test.rb +++ b/test/remote/gateways/remote_quickpay_v4_test.rb @@ -39,10 +39,10 @@ def test_successful_purchase_with_all_fraud_parameters @options[:fraud_http_referer] = 'http://www.excample.com' @options[:fraud_remote_addr] = '127.0.0.1' @options[:fraud_http_accept] = 'foo' - @options[:fraud_http_accept_language] = "DK" - @options[:fraud_http_accept_encoding] = "UFT8" - @options[:fraud_http_accept_charset] = "Latin" - @options[:fraud_http_user_agent] = "Safari" + @options[:fraud_http_accept_language] = 'DK' + @options[:fraud_http_accept_encoding] = 'UFT8' + @options[:fraud_http_accept_charset] = 'Latin' + @options[:fraud_http_user_agent] = 'Safari' assert response = @gateway.purchase(@amount, @visa, @options) assert_equal 'OK', response.message @@ -51,8 +51,6 @@ def test_successful_purchase_with_all_fraud_parameters assert !response.authorization.blank? end - - def test_successful_usd_purchase assert response = @gateway.purchase(@amount, @visa, @options.update(:currency => 'USD')) assert_equal 'OK', response.message @@ -191,7 +189,7 @@ def test_successful_purchase_and_credit end def test_successful_store_and_reference_purchase - assert store = @gateway.store(@visa, @options.merge(:description => "New subscription")) + assert store = @gateway.store(@visa, @options.merge(:description => 'New subscription')) assert_success store assert purchase = @gateway.purchase(@amount, store.authorization, @options.merge(:order_id => generate_unique_id[0...10])) assert_success purchase @@ -199,8 +197,8 @@ def test_successful_store_and_reference_purchase def test_invalid_login gateway = QuickpayGateway.new( - :login => '999999999', - :password => '' + :login => '999999999', + :password => '' ) assert response = gateway.purchase(@amount, @visa, @options) assert_equal 'Invalid merchant id', response.message diff --git a/test/remote/gateways/remote_quickpay_v5_test.rb b/test/remote/gateways/remote_quickpay_v5_test.rb index 4b4c3795ad8..02838bf2bb8 100644 --- a/test/remote/gateways/remote_quickpay_v5_test.rb +++ b/test/remote/gateways/remote_quickpay_v5_test.rb @@ -39,10 +39,10 @@ def test_successful_purchase_with_all_fraud_parameters @options[:fraud_http_referer] = 'http://www.excample.com' @options[:fraud_remote_addr] = '127.0.0.1' @options[:fraud_http_accept] = 'foo' - @options[:fraud_http_accept_language] = "DK" - @options[:fraud_http_accept_encoding] = "UFT8" - @options[:fraud_http_accept_charset] = "Latin" - @options[:fraud_http_user_agent] = "Safari" + @options[:fraud_http_accept_language] = 'DK' + @options[:fraud_http_accept_encoding] = 'UFT8' + @options[:fraud_http_accept_charset] = 'Latin' + @options[:fraud_http_user_agent] = 'Safari' assert response = @gateway.purchase(@amount, @visa, @options) assert_equal 'OK', response.message @@ -51,8 +51,6 @@ def test_successful_purchase_with_all_fraud_parameters assert !response.authorization.blank? end - - def test_successful_usd_purchase assert response = @gateway.purchase(@amount, @visa, @options.update(:currency => 'USD')) assert_equal 'OK', response.message @@ -191,7 +189,7 @@ def test_successful_purchase_and_credit end def test_successful_store_and_reference_purchase - assert store = @gateway.store(@visa, @options.merge(:description => "New subscription")) + assert store = @gateway.store(@visa, @options.merge(:description => 'New subscription')) assert_success store assert purchase = @gateway.purchase(@amount, store.authorization, @options.merge(:order_id => generate_unique_id[0...10])) assert_success purchase @@ -199,8 +197,8 @@ def test_successful_store_and_reference_purchase def test_invalid_login gateway = QuickpayGateway.new( - :login => '999999999', - :password => '' + :login => '999999999', + :password => '' ) assert response = gateway.purchase(@amount, @visa, @options) assert_equal 'Invalid merchant id', response.message diff --git a/test/remote/gateways/remote_quickpay_v6_test.rb b/test/remote/gateways/remote_quickpay_v6_test.rb index 817cdef9bdd..2d113657c0c 100644 --- a/test/remote/gateways/remote_quickpay_v6_test.rb +++ b/test/remote/gateways/remote_quickpay_v6_test.rb @@ -39,10 +39,10 @@ def test_successful_purchase_with_all_fraud_parameters @options[:fraud_http_referer] = 'http://www.excample.com' @options[:fraud_remote_addr] = '127.0.0.1' @options[:fraud_http_accept] = 'foo' - @options[:fraud_http_accept_language] = "DK" - @options[:fraud_http_accept_encoding] = "UFT8" - @options[:fraud_http_accept_charset] = "Latin" - @options[:fraud_http_user_agent] = "Safari" + @options[:fraud_http_accept_language] = 'DK' + @options[:fraud_http_accept_encoding] = 'UFT8' + @options[:fraud_http_accept_charset] = 'Latin' + @options[:fraud_http_user_agent] = 'Safari' assert response = @gateway.purchase(@amount, @visa, @options) assert_equal 'OK', response.message @@ -51,8 +51,6 @@ def test_successful_purchase_with_all_fraud_parameters assert !response.authorization.blank? end - - def test_successful_usd_purchase assert response = @gateway.purchase(@amount, @visa, @options.update(:currency => 'USD')) assert_equal 'OK', response.message @@ -191,7 +189,7 @@ def test_successful_purchase_and_credit end def test_successful_store_and_reference_purchase - assert store = @gateway.store(@visa, @options.merge(:description => "New subscription")) + assert store = @gateway.store(@visa, @options.merge(:description => 'New subscription')) assert_success store assert purchase = @gateway.purchase(@amount, store.authorization, @options.merge(:order_id => generate_unique_id[0...10])) assert_success purchase @@ -199,8 +197,8 @@ def test_successful_store_and_reference_purchase def test_invalid_login gateway = QuickpayGateway.new( - :login => '999999999', - :password => '' + :login => '999999999', + :password => '' ) assert response = gateway.purchase(@amount, @visa, @options) assert_equal 'Invalid merchant id', response.message diff --git a/test/remote/gateways/remote_quickpay_v7_test.rb b/test/remote/gateways/remote_quickpay_v7_test.rb index 8af4cc14267..8b8def4f168 100644 --- a/test/remote/gateways/remote_quickpay_v7_test.rb +++ b/test/remote/gateways/remote_quickpay_v7_test.rb @@ -39,10 +39,10 @@ def test_successful_purchase_with_all_fraud_parameters @options[:ip] = '127.0.0.1' # will set :fraud_remote_addr @options[:fraud_http_referer] = 'http://www.excample.com' @options[:fraud_http_accept] = 'foo' - @options[:fraud_http_accept_language] = "DK" - @options[:fraud_http_accept_encoding] = "UFT8" - @options[:fraud_http_accept_charset] = "Latin" - @options[:fraud_http_user_agent] = "Safari" + @options[:fraud_http_accept_language] = 'DK' + @options[:fraud_http_accept_encoding] = 'UFT8' + @options[:fraud_http_accept_charset] = 'Latin' + @options[:fraud_http_user_agent] = 'Safari' assert response = @gateway.purchase(@amount, @visa, @options) assert_equal 'OK', response.message @@ -60,13 +60,13 @@ def test_successful_usd_purchase end def test_successful_purchase_with_acquirers - assert response = @gateway.purchase(@amount, @visa, @options.update(:acquirers => "nets")) + assert response = @gateway.purchase(@amount, @visa, @options.update(:acquirers => 'nets')) assert_equal 'OK', response.message assert_success response end def test_unsuccessful_purchase_with_invalid_acquirers - assert response = @gateway.purchase(@amount, @visa, @options.update(:acquirers => "invalid")) + assert response = @gateway.purchase(@amount, @visa, @options.update(:acquirers => 'invalid')) assert_equal 'Error in field: acquirers', response.message assert_failure response end @@ -201,26 +201,26 @@ def test_successful_purchase_and_credit end def test_successful_store_and_reference_purchase - assert store = @gateway.store(@visa, @options.merge(:description => "New subscription")) + assert store = @gateway.store(@visa, @options.merge(:description => 'New subscription')) assert_success store assert purchase = @gateway.purchase(@amount, store.authorization, @options.merge(:order_id => generate_unique_id[0...10])) assert_success purchase end def test_successful_store_with_acquirers - assert store = @gateway.store(@visa, @options.merge(:description => "New subscription", :acquirers => "nets")) + assert store = @gateway.store(@visa, @options.merge(:description => 'New subscription', :acquirers => 'nets')) assert_success store end def test_successful_store_sans_description - assert store = @gateway.store(@visa, @options.merge(:acquirers => "nets")) + assert store = @gateway.store(@visa, @options.merge(:acquirers => 'nets')) assert_success store end def test_invalid_login gateway = QuickpayGateway.new( - :login => '999999999', - :password => '' + :login => '999999999', + :password => '' ) assert response = gateway.purchase(@amount, @visa, @options) assert_equal 'Invalid merchant id', response.message diff --git a/test/remote/gateways/remote_qvalent_test.rb b/test/remote/gateways/remote_qvalent_test.rb index e18f376c613..9c21e25b889 100644 --- a/test/remote/gateways/remote_qvalent_test.rb +++ b/test/remote/gateways/remote_qvalent_test.rb @@ -1,73 +1,181 @@ -require "test_helper" +require 'test_helper' class RemoteQvalentTest < Test::Unit::TestCase def setup @gateway = QvalentGateway.new(fixtures(:qvalent)) @amount = 100 - @credit_card = credit_card("4000100011112224") - @declined_card = credit_card("4000000000000000") + @credit_card = credit_card('4000100011112224') + @declined_card = credit_card('4000000000000000') + @expired_card = credit_card('4111111113444494') @options = { order_id: generate_unique_id, billing_address: address, - description: "Store Purchase" + description: 'Store Purchase' } end def test_invalid_login gateway = QvalentGateway.new( - username: "bad", - password: "bad", - merchant: "101" + username: 'bad', + password: 'bad', + merchant: '101', + pem: 'bad', + pem_password: 'bad' ) - authentication_exception = assert_raise ActiveMerchant::ResponseError do + assert_raise ActiveMerchant::ClientCertificateError do gateway.purchase(@amount, @credit_card, @options) end - response = authentication_exception.response - assert_match(%r{Error 403: Missing authentication}, response.body) end def test_successful_purchase response = @gateway.purchase(@amount, @credit_card, @options) assert_success response - assert_equal "Succeeded", response.message + assert_equal 'Succeeded', response.message + end + + def test_successful_purchase_with_soft_descriptors + options = { + order_id: generate_unique_id, + billing_address: address, + description: 'Store Purchase', + customer_merchant_name: 'Some Merchant', + customer_merchant_street_address: '42 Wallaby Way', + customer_merchant_location: 'Sydney', + customer_merchant_country: 'AU', + customer_merchant_post_code: '2060', + customer_merchant_state: 'NSW' + } + + response = @gateway.purchase(@amount, @credit_card, options) + assert_success response + assert_equal 'Succeeded', response.message + end + + def test_successful_purchase_with_3d_secure + options = { + order_id: generate_unique_id, + billing_address: address, + description: 'Store Purchase', + xid: '123', + cavv: '456', + eci: '5' + } + + response = @gateway.purchase(@amount, @credit_card, options) + assert_success response + assert_equal 'Succeeded', response.message end def test_failed_purchase response = @gateway.purchase(@amount, @declined_card, @options) assert_failure response - assert_equal "Invalid card number (no such number)", response.message + assert_equal 'Invalid card number (no such number)', response.message assert_equal Gateway::STANDARD_ERROR_CODE[:invalid_number], response.error_code end + def test_successful_authorize + response = @gateway.authorize(@amount, @credit_card, @options) + assert_success response + assert_equal 'Succeeded', response.message + end + + def test_failed_authorize + response = @gateway.authorize(@amount, @declined_card, @options) + assert_failure response + assert_equal 'Invalid card number (no such number)', response.message + end + + def test_successful_capture + assert auth = @gateway.authorize(@amount, @credit_card, @options) + assert_success auth + assert_equal 'Succeeded', auth.message + assert_not_nil auth.authorization + + assert capture = @gateway.capture(@amount, auth.authorization, @options.merge({ order_id: generate_unique_id })) + assert_success capture + end + + def test_failed_capture + assert auth = @gateway.authorize(@amount, @credit_card, @options) + assert_success auth + assert_equal 'Succeeded', auth.message + assert_not_nil auth.authorization + + assert capture = @gateway.capture(@amount, '', @options.merge({ order_id: generate_unique_id })) + assert_failure capture + end + + def test_successful_partial_capture + assert auth = @gateway.authorize(200, @credit_card, @options) + assert_success auth + assert_equal 'Succeeded', auth.message + assert_not_nil auth.authorization + + assert capture = @gateway.capture(100, auth.authorization, @options.merge({ order_id: generate_unique_id })) + assert_success capture + end + + def test_successful_void + assert auth = @gateway.authorize(@amount, @credit_card, @options) + assert_success auth + assert_equal 'Succeeded', auth.message + assert_not_nil auth.authorization + + assert void = @gateway.void(auth.authorization, @options.merge({ order_id: generate_unique_id })) + assert_success void + end + + def test_failed_void + assert auth = @gateway.authorize(@amount, @credit_card, @options) + assert_success auth + assert_equal 'Succeeded', auth.message + assert_not_nil auth.authorization + + assert void = @gateway.void('', @options.merge({ order_id: generate_unique_id })) + assert_failure void + end + def test_successful_refund response = @gateway.purchase(@amount, @credit_card, @options) assert_success response assert refund = @gateway.refund(@amount, response.authorization) assert_success refund - assert_equal "Succeeded", refund.message + assert_equal 'Succeeded', refund.message end def test_failed_refund - response = @gateway.refund(nil, "") + response = @gateway.refund(nil, '') assert_failure response assert_match %r{Invalid card number}, response.message assert_equal Gateway::STANDARD_ERROR_CODE[:invalid_number], response.error_code end + def test_successful_credit + response = @gateway.credit(@amount, @credit_card, @options) + assert_success response + assert_equal 'Succeeded', response.message + end + + def test_failed_credit + response = @gateway.credit(@amount, @declined_card, @options) + assert_failure response + assert_equal 'Invalid card number (no such number)', response.message + end + def test_successful_store response = @gateway.store(@credit_card, @options) assert_success response - assert_equal "Succeeded", response.message + assert_equal 'Succeeded', response.message end def test_failed_store response = @gateway.store(@declined_card, @options) assert_failure response - assert_equal "Invalid card number (no such number)", response.message + assert_equal 'Invalid card number (no such number)', response.message assert_equal Gateway::STANDARD_ERROR_CODE[:invalid_number], response.error_code end diff --git a/test/remote/gateways/remote_realex_test.rb b/test/remote/gateways/remote_realex_test.rb index 2cd9c6ff568..b8280a6d8bc 100644 --- a/test/remote/gateways/remote_realex_test.rb +++ b/test/remote/gateways/remote_realex_test.rb @@ -18,6 +18,19 @@ def setup @mastercard_referral_a = card_fixtures(:realex_mastercard_referral_a) @mastercard_coms_error = card_fixtures(:realex_mastercard_coms_error) + @apple_pay = network_tokenization_credit_card('4242424242424242', + payment_cryptogram: 'EHuWW9PiBkWvqE5juRwDzAUFBAk=', + verification_value: nil, + eci: '05', + source: :apple_pay + ) + + @declined_apple_pay = network_tokenization_credit_card('4000120000001154', + payment_cryptogram: 'EHuWW9PiBkWvqE5juRwDzAUFBAk=', + verification_value: nil, + eci: '05', + source: :apple_pay + ) @amount = 10000 end @@ -27,7 +40,6 @@ def card_fixtures(name) def test_realex_purchase [ @visa, @mastercard ].each do |card| - response = @gateway.purchase(@amount, card, :order_id => generate_unique_id, :description => 'Test Realex Purchase', @@ -40,7 +52,7 @@ def test_realex_purchase assert_success response assert response.test? assert response.authorization.length > 0 - assert_equal "Successful", response.message + assert_equal 'Successful', response.message end end @@ -57,7 +69,7 @@ def test_realex_purchase_with_invalid_login assert_not_nil response assert_failure response - assert_equal '506', response.params['result'] + assert_equal '504', response.params['result'] assert_match %r{no such}i, response.message end @@ -70,14 +82,19 @@ def test_realex_purchase_with_invalid_account assert_not_nil response assert_failure response - assert_equal '506', response.params['result'] + assert_equal '504', response.params['result'] assert_match %r{no such}i, response.message end - def test_realex_purchase_declined + def test_realex_purchase_with_apple_pay + response = @gateway.purchase(1000, @apple_pay, :order_id => generate_unique_id, :description => 'Test Realex with ApplePay') + assert_success response + assert response.test? + assert_equal 'Successful', response.message + end + def test_realex_purchase_declined [ @visa_declined, @mastercard_declined ].each do |card| - response = @gateway.purchase(@amount, card, :order_id => generate_unique_id, :description => 'Test Realex purchase declined' @@ -88,12 +105,18 @@ def test_realex_purchase_declined assert_equal '101', response.params['result'] assert_equal response.params['message'], response.message end + end + def test_realex_purchase_with_apple_pay_declined + response = @gateway.purchase(1101, @declined_apple_pay, :order_id => generate_unique_id, :description => 'Test Realex with ApplePay') + assert_failure response + assert response.test? + assert_equal '101', response.params['result'] + assert_match %r{DECLINED}i, response.message end def test_realex_purchase_referral_b [ @visa_referral_b, @mastercard_referral_b ].each do |card| - response = @gateway.purchase(@amount, card, :order_id => generate_unique_id, :description => 'Test Realex Referral B' @@ -108,7 +131,6 @@ def test_realex_purchase_referral_b def test_realex_purchase_referral_a [ @visa_referral_a, @mastercard_referral_a ].each do |card| - response = @gateway.purchase(@amount, card, :order_id => generate_unique_id, :description => 'Test Realex Rqeferral A' @@ -118,13 +140,10 @@ def test_realex_purchase_referral_a assert_equal '103', response.params['result'] assert_equal RealexGateway::DECLINED, response.message end - end def test_realex_purchase_coms_error - [ @visa_coms_error, @mastercard_coms_error ].each do |card| - response = @gateway.purchase(@amount, card, :order_id => generate_unique_id, :description => 'Test Realex coms error' @@ -136,7 +155,6 @@ def test_realex_purchase_coms_error assert_equal '200', response.params['result'] assert_equal RealexGateway::BANK_ERROR, response.message end - end def test_realex_expiry_month_error @@ -164,12 +182,12 @@ def test_realex_expiry_year_error assert_failure response assert_equal '509', response.params['result'] - assert_equal "Expiry date invalid", response.message + assert_equal 'Expiry date invalid', response.message end def test_invalid_credit_card_name - @visa.first_name = "" - @visa.last_name = "" + @visa.first_name = '' + @visa.last_name = '' response = @gateway.purchase(@amount, @visa, :order_id => generate_unique_id, @@ -178,13 +196,13 @@ def test_invalid_credit_card_name assert_not_nil response assert_failure response - assert_equal '502', response.params['result'] - assert_match(/missing/i, response.message) + assert_equal '506', response.params['result'] + assert_match(/does not conform/i, response.message) end def test_cvn @visa_cvn = @visa.clone - @visa_cvn.verification_value = "111" + @visa_cvn.verification_value = '111' response = @gateway.purchase(@amount, @visa_cvn, :order_id => generate_unique_id, :description => 'test_cvn' @@ -235,6 +253,28 @@ def test_realex_authorize_then_capture ) assert auth_response.test? + capture_response = @gateway.capture(nil, auth_response.authorization) + + assert_not_nil capture_response + assert_success capture_response + assert capture_response.authorization.length > 0 + assert_equal 'Successful', capture_response.message + assert_match(/Settled Successfully/, capture_response.params['message']) + end + + def test_realex_authorize_then_capture_with_extra_amount + order_id = generate_unique_id + + auth_response = @gateway.authorize(@amount*115, @visa, + :order_id => order_id, + :description => 'Test Realex Purchase', + :billing_address => { + :zip => '90210', + :country => 'US' + } + ) + assert auth_response.test? + capture_response = @gateway.capture(@amount, auth_response.authorization) assert_not_nil capture_response @@ -284,21 +324,63 @@ def test_realex_purchase_then_refund assert_not_nil rebate_response assert_success rebate_response - assert rebate_response.test? assert rebate_response.authorization.length > 0 assert_equal 'Successful', rebate_response.message end + def test_realex_verify + response = @gateway.verify(@visa, + :order_id => generate_unique_id, + :description => 'Test Realex verify' + ) + + assert_not_nil response + assert_success response + assert response.test? + assert response.authorization.length > 0 + assert_equal 'Successful', response.message + end + + def test_realex_verify_declined + response = @gateway.verify(@visa_declined, + :order_id => generate_unique_id, + :description => 'Test Realex verify declined' + ) + + assert_not_nil response + assert_failure response + assert response.test? + assert_equal '101', response.params['result'] + assert_match %r{DECLINED}i, response.message + end + + def test_maps_avs_and_cvv_response_codes + [ @visa, @mastercard ].each do |card| + response = @gateway.purchase(@amount, card, + :order_id => generate_unique_id, + :description => 'Test Realex Purchase', + :billing_address => { + :zip => '90210', + :country => 'US' + } + ) + assert_not_nil response + assert_success response + assert_equal 'M', response.avs_result['code'] + assert_equal 'M', response.cvv_result['code'] + end + end + def test_transcript_scrubbing transcript = capture_transcript(@gateway) do @gateway.purchase(@amount, @visa_declined, - :order_id => generate_unique_id, - :description => 'Test Realex Purchase', - :billing_address => { - :zip => '90210', - :country => 'US' - } - ) + :order_id => generate_unique_id, + :description => 'Test Realex Purchase', + :billing_address => { + :zip => '90210', + :country => 'US' + } + ) end clean_transcript = @gateway.scrub(transcript) diff --git a/test/remote/gateways/remote_redsys_sha256_test.rb b/test/remote/gateways/remote_redsys_sha256_test.rb index 93e94cb7dce..43718a5f67a 100644 --- a/test/remote/gateways/remote_redsys_sha256_test.rb +++ b/test/remote/gateways/remote_redsys_sha256_test.rb @@ -13,33 +13,33 @@ def setup def test_successful_purchase response = @gateway.purchase(100, @credit_card, @options) assert_success response - assert_equal "Transaction Approved", response.message + assert_equal 'Transaction Approved', response.message end def test_purchase_with_invalid_order_id response = @gateway.purchase(100, @credit_card, order_id: "a%4#{generate_order_id}") assert_success response - assert_equal "Transaction Approved", response.message + assert_equal 'Transaction Approved', response.message end def test_successful_purchase_using_vault_id response = @gateway.purchase(100, @credit_card, @options.merge(store: true)) assert_success response - assert_equal "Transaction Approved", response.message + assert_equal 'Transaction Approved', response.message - credit_card_token = response.params["ds_merchant_identifier"] + credit_card_token = response.params['ds_merchant_identifier'] assert_not_nil credit_card_token @options[:order_id] = generate_order_id response = @gateway.purchase(100, credit_card_token, @options) assert_success response - assert_equal "Transaction Approved", response.message + assert_equal 'Transaction Approved', response.message end def test_failed_purchase response = @gateway.purchase(100, @declined_card, @options) assert_failure response - assert_equal "SIS0093 ERROR", response.message + assert_equal 'SIS0093 ERROR', response.message end def test_purchase_and_refund @@ -53,40 +53,40 @@ def test_purchase_and_refund def test_purchase_and_refund_with_currency response = @gateway.purchase(600, @credit_card, @options.merge(:currency => 'PEN')) assert_failure response - assert_equal "SIS0027 ERROR", response.message + assert_equal 'SIS0027 ERROR', response.message end def test_successful_authorise_and_capture authorize = @gateway.authorize(100, @credit_card, @options) assert_success authorize - assert_equal "Transaction Approved", authorize.message + assert_equal 'Transaction Approved', authorize.message assert_not_nil authorize.authorization capture = @gateway.capture(100, authorize.authorization) assert_success capture - assert_match /Refund.*approved/, capture.message + assert_match(/Refund.*approved/, capture.message) end def test_successful_authorise_using_vault_id authorize = @gateway.authorize(100, @credit_card, @options.merge(store: true)) assert_success authorize - assert_equal "Transaction Approved", authorize.message + assert_equal 'Transaction Approved', authorize.message assert_not_nil authorize.authorization - credit_card_token = authorize.params["ds_merchant_identifier"] + credit_card_token = authorize.params['ds_merchant_identifier'] assert_not_nil credit_card_token @options[:order_id] = generate_order_id authorize = @gateway.authorize(100, credit_card_token, @options) assert_success authorize - assert_equal "Transaction Approved", authorize.message + assert_equal 'Transaction Approved', authorize.message assert_not_nil authorize.authorization end def test_failed_authorize response = @gateway.authorize(100, @declined_card, @options) assert_failure response - assert_equal "SIS0093 ERROR", response.message + assert_equal 'SIS0093 ERROR', response.message end def test_successful_void @@ -95,8 +95,8 @@ def test_successful_void void = @gateway.void(authorize.authorization) assert_success void - assert_equal "100", void.params["ds_amount"] - assert_equal "Cancellation Accepted", void.message + assert_equal '100', void.params['ds_amount'] + assert_equal 'Cancellation Accepted', void.message end def test_failed_void @@ -108,22 +108,22 @@ def test_failed_void another_void = @gateway.void(authorize.authorization) assert_failure another_void - assert_equal "SIS0222 ERROR", another_void.message + assert_equal 'SIS0222 ERROR', another_void.message end def test_successful_verify assert response = @gateway.verify(@credit_card, @options) assert_success response - assert_equal "Transaction Approved", response.message - assert_success response.responses.last, "The void should succeed" - assert_equal "Cancellation Accepted", response.responses.last.message + assert_equal 'Transaction Approved', response.message + assert_success response.responses.last, 'The void should succeed' + assert_equal 'Cancellation Accepted', response.responses.last.message end def test_unsuccessful_verify assert response = @gateway.verify(@declined_card, @options) assert_failure response - assert_equal "SIS0093 ERROR", response.message + assert_equal 'SIS0093 ERROR', response.message end def test_transcript_scrubbing @@ -155,28 +155,29 @@ def test_nil_cvv_transcript_scrubbing end clean_transcript = @gateway.scrub(transcript) - assert_equal clean_transcript.include?("[BLANK]"), true + assert_equal clean_transcript.include?('[BLANK]'), true end def test_empty_string_cvv_transcript_scrubbing - @credit_card.verification_value = "" + @credit_card.verification_value = '' transcript = capture_transcript(@gateway) do @gateway.purchase(@amount, @credit_card, @options) end clean_transcript = @gateway.scrub(transcript) - assert_equal clean_transcript.include?("[BLANK]"), true + assert_equal clean_transcript.include?('[BLANK]'), true end def test_whitespace_string_cvv_transcript_scrubbing - @credit_card.verification_value = " " + @credit_card.verification_value = ' ' transcript = capture_transcript(@gateway) do @gateway.purchase(@amount, @credit_card, @options) end clean_transcript = @gateway.scrub(transcript) - assert_equal clean_transcript.include?("[BLANK]"), true + assert_equal clean_transcript.include?('[BLANK]'), true end + private def generate_order_id diff --git a/test/remote/gateways/remote_redsys_test.rb b/test/remote/gateways/remote_redsys_test.rb index 7ecb83a1024..cfaf52723b2 100644 --- a/test/remote/gateways/remote_redsys_test.rb +++ b/test/remote/gateways/remote_redsys_test.rb @@ -9,38 +9,39 @@ def setup order_id: generate_order_id, description: 'Test Description' } + @amount = 100 end def test_successful_purchase response = @gateway.purchase(100, @credit_card, @options) assert_success response - assert_equal "Transaction Approved", response.message + assert_equal 'Transaction Approved', response.message end def test_purchase_with_invalid_order_id response = @gateway.purchase(100, @credit_card, order_id: "a%4#{generate_order_id}") assert_success response - assert_equal "Transaction Approved", response.message + assert_equal 'Transaction Approved', response.message end def test_successful_purchase_using_vault_id response = @gateway.purchase(100, @credit_card, @options.merge(store: true)) assert_success response - assert_equal "Transaction Approved", response.message + assert_equal 'Transaction Approved', response.message - credit_card_token = response.params["ds_merchant_identifier"] + credit_card_token = response.params['ds_merchant_identifier'] assert_not_nil credit_card_token @options[:order_id] = generate_order_id response = @gateway.purchase(100, credit_card_token, @options) assert_success response - assert_equal "Transaction Approved", response.message + assert_equal 'Transaction Approved', response.message end def test_failed_purchase response = @gateway.purchase(100, @declined_card, @options) assert_failure response - assert_equal "SIS0093 ERROR", response.message + assert_equal 'SIS0093 ERROR', response.message end def test_purchase_and_refund @@ -54,40 +55,40 @@ def test_purchase_and_refund def test_purchase_and_refund_with_currency response = @gateway.purchase(600, @credit_card, @options.merge(:currency => 'PEN')) assert_failure response - assert_equal "SIS0027 ERROR", response.message + assert_equal 'SIS0027 ERROR', response.message end def test_successful_authorise_and_capture authorize = @gateway.authorize(100, @credit_card, @options) assert_success authorize - assert_equal "Transaction Approved", authorize.message + assert_equal 'Transaction Approved', authorize.message assert_not_nil authorize.authorization capture = @gateway.capture(100, authorize.authorization) assert_success capture - assert_match /Refund.*approved/, capture.message + assert_match(/Refund.*approved/, capture.message) end def test_successful_authorise_using_vault_id authorize = @gateway.authorize(100, @credit_card, @options.merge(store: true)) assert_success authorize - assert_equal "Transaction Approved", authorize.message + assert_equal 'Transaction Approved', authorize.message assert_not_nil authorize.authorization - credit_card_token = authorize.params["ds_merchant_identifier"] + credit_card_token = authorize.params['ds_merchant_identifier'] assert_not_nil credit_card_token @options[:order_id] = generate_order_id authorize = @gateway.authorize(100, credit_card_token, @options) assert_success authorize - assert_equal "Transaction Approved", authorize.message + assert_equal 'Transaction Approved', authorize.message assert_not_nil authorize.authorization end def test_failed_authorize response = @gateway.authorize(100, @declined_card, @options) assert_failure response - assert_equal "SIS0093 ERROR", response.message + assert_equal 'SIS0093 ERROR', response.message end def test_successful_void @@ -96,8 +97,8 @@ def test_successful_void void = @gateway.void(authorize.authorization) assert_success void - assert_equal "100", void.params["ds_amount"] - assert_equal "Cancellation Accepted", void.message + assert_equal '100', void.params['ds_amount'] + assert_equal 'Cancellation Accepted', void.message end def test_failed_void @@ -109,22 +110,22 @@ def test_failed_void another_void = @gateway.void(authorize.authorization) assert_failure another_void - assert_equal "SIS0222 ERROR", another_void.message + assert_equal 'SIS0222 ERROR', another_void.message end def test_successful_verify assert response = @gateway.verify(@credit_card, @options) assert_success response - assert_equal "Transaction Approved", response.message - assert_success response.responses.last, "The void should succeed" - assert_equal "Cancellation Accepted", response.responses.last.message + assert_equal 'Transaction Approved', response.message + assert_success response.responses.last, 'The void should succeed' + assert_equal 'Cancellation Accepted', response.responses.last.message end def test_unsuccessful_verify assert response = @gateway.verify(@declined_card, @options) assert_failure response - assert_equal "SIS0093 ERROR", response.message + assert_equal 'SIS0093 ERROR', response.message end def test_transcript_scrubbing @@ -156,28 +157,29 @@ def test_nil_cvv_transcript_scrubbing end clean_transcript = @gateway.scrub(transcript) - assert_equal clean_transcript.include?("[BLANK]"), true + assert_equal clean_transcript.include?('[BLANK]'), true end def test_empty_string_cvv_transcript_scrubbing - @credit_card.verification_value = "" + @credit_card.verification_value = '' transcript = capture_transcript(@gateway) do @gateway.purchase(@amount, @credit_card, @options) end clean_transcript = @gateway.scrub(transcript) - assert_equal clean_transcript.include?("[BLANK]"), true + assert_equal clean_transcript.include?('[BLANK]'), true end def test_whitespace_string_cvv_transcript_scrubbing - @credit_card.verification_value = " " + @credit_card.verification_value = ' ' transcript = capture_transcript(@gateway) do @gateway.purchase(@amount, @credit_card, @options) end clean_transcript = @gateway.scrub(transcript) - assert_equal clean_transcript.include?("[BLANK]"), true + assert_equal clean_transcript.include?('[BLANK]'), true end + private def generate_order_id diff --git a/test/remote/gateways/remote_s5_test.rb b/test/remote/gateways/remote_s5_test.rb index 8ecb3dfa530..1c9f31bf0ab 100644 --- a/test/remote/gateways/remote_s5_test.rb +++ b/test/remote/gateways/remote_s5_test.rb @@ -54,7 +54,7 @@ def test_successful_purchase_without_address end def test_failed_purchase - @options[:memo] = "800.100.151" + @options[:memo] = '800.100.151' response = @gateway.purchase(@amount, @declined_card, @options) assert_failure response assert_equal 'transaction declined (invalid card)', response.message @@ -81,7 +81,7 @@ def test_successful_authorize_and_capture end def test_failed_authorize - @options[:memo] = "100.400.080" + @options[:memo] = '100.400.080' response = @gateway.authorize(@amount, @declined_card, @options) assert_failure response end @@ -140,7 +140,7 @@ def test_successful_verify end def test_failed_verify - @options[:memo] = "100.400.080" + @options[:memo] = '100.400.080' response = @gateway.verify(@declined_card, @options) assert_failure response assert_match %r{authorization failure}, response.message diff --git a/test/remote/gateways/remote_safe_charge_test.rb b/test/remote/gateways/remote_safe_charge_test.rb new file mode 100644 index 00000000000..fc64bacb1c1 --- /dev/null +++ b/test/remote/gateways/remote_safe_charge_test.rb @@ -0,0 +1,234 @@ +require 'test_helper' + +class RemoteSafeChargeTest < Test::Unit::TestCase + def setup + @gateway = SafeChargeGateway.new(fixtures(:safe_charge)) + + @amount = 100 + @credit_card = credit_card('4000100011112224', verification_value: '912') + @declined_card = credit_card('4000300011112220') + @options = { + order_id: generate_unique_id, + billing_address: address, + description: 'Store Purchase', + currency: 'EUR' + } + + @three_ds_options = @options.merge(three_d_secure: true) + @three_ds_gateway = SafeChargeGateway.new(fixtures(:safe_charge_three_ds)) + @three_ds_enrolled_card = credit_card('4012 0010 3749 0014') + @three_ds_non_enrolled_card = credit_card('5333 3062 3122 6927') + @three_ds_invalid_pa_res_card = credit_card('4012 0010 3749 0006') + end + + def test_successful_3ds_purchase + response = @three_ds_gateway.purchase(@amount, @three_ds_enrolled_card, @three_ds_options) + assert_success response + assert !response.params['acsurl'].blank? + assert !response.params['pareq'].blank? + assert !response.params['xid'].blank? + assert_equal 'Success', response.message + end + + def test_successful_regular_purchase_through_3ds_flow_with_non_enrolled_card + response = @three_ds_gateway.purchase(@amount, @three_ds_non_enrolled_card, @three_ds_options) + assert_success response + assert response.params['acsurl'].blank? + assert response.params['pareq'].blank? + assert response.params['xid'].blank? + assert response.params['threedflow'] = 1 + assert_equal 'Success', response.message + end + + def test_successful_regular_purchase_through_3ds_flow_with_invalid_pa_res + response = @three_ds_gateway.purchase(@amount, @three_ds_invalid_pa_res_card, @three_ds_options) + assert_success response + assert !response.params['acsurl'].blank? + assert !response.params['pareq'].blank? + assert !response.params['xid'].blank? + assert response.params['threedflow'] = 1 + assert_equal 'Success', response.message + end + + def test_successful_purchase + response = @gateway.purchase(@amount, @credit_card, @options) + assert_success response + assert_equal 'Success', response.message + end + + def test_successful_purchase_with_more_options + options = { + order_id: '1', + ip: '127.0.0.1', + email: 'joe@example.com', + user_id: '123', + auth_type: '2', + expected_fulfillment_count: '3', + merchant_descriptor: 'Test Descriptor', + merchant_phone_number: '(555)555-5555', + merchant_name: 'Test Merchant', + stored_credential_mode: true + } + + response = @gateway.purchase(@amount, @credit_card, options) + assert_success response + assert_equal 'Success', response.message + end + + def test_failed_purchase + response = @gateway.purchase(@amount, @declined_card, @options) + assert_failure response + assert_equal 'Decline', response.message + end + + def test_successful_authorize_and_capture + auth = @gateway.authorize(@amount, @credit_card, @options) + assert_success auth + + assert capture = @gateway.capture(@amount, auth.authorization) + assert_success capture + assert_equal 'Success', capture.message + end + + def test_successful_authorize_and_capture_with_more_options + extra = { + order_id: '1', + ip: '127.0.0.1', + email: 'joe@example.com', + user_id: '123', + auth_type: '2', + expected_fulfillment_count: '3', + merchant_descriptor: 'Test Descriptor', + merchant_phone_number: '(555)555-5555', + merchant_name: 'Test Merchant', + stored_credential_mode: true + } + auth = @gateway.authorize(@amount, @credit_card, extra) + assert_success auth + + assert capture = @gateway.capture(@amount, auth.authorization) + assert_success capture + assert_equal 'Success', capture.message + end + + def test_failed_authorize + response = @gateway.authorize(@amount, @declined_card, @options) + assert_failure response + assert_equal 'Decline', response.message + end + + def test_partial_capture + auth = @gateway.authorize(@amount, @credit_card, @options) + assert_success auth + + assert capture = @gateway.capture(@amount-1, auth.authorization) + assert_success capture + end + + def test_failed_capture + response = @gateway.capture(@amount, '') + assert_failure response + assert_equal 'Transaction must contain a Card/Token/Account', response.message + end + + def test_successful_refund + purchase = @gateway.purchase(@amount, @credit_card, @options) + assert_success purchase + + assert refund = @gateway.refund(@amount, purchase.authorization) + assert_success refund + assert_equal 'Success', refund.message + end + + def test_partial_refund + purchase = @gateway.purchase(200, @credit_card, @options) + assert_success purchase + + assert refund = @gateway.refund(100, purchase.authorization) + assert_success refund + end + + def test_failed_refund + response = @gateway.refund(@amount, '') + assert_failure response + assert_equal 'Transaction must contain a Card/Token/Account', response.message + end + + def test_successful_credit + response = @gateway.credit(@amount, credit_card('4444436501403986'), @options) + assert_success response + assert_equal 'Success', response.message + end + + def test_successful_credit_with_extra_options + extra = { + order_id: '1', + ip: '127.0.0.1', + email: 'joe@example.com', + user_id: '123', + auth_type: '2', + expected_fulfillment_count: '3', + merchant_descriptor: 'Test Descriptor', + merchant_phone_number: '(555)555-5555', + merchant_name: 'Test Merchant', + stored_credential_mode: true + } + + response = @gateway.credit(@amount, credit_card('4444436501403986'), extra) + assert_success response + assert_equal 'Success', response.message + end + + def test_failed_credit + response = @gateway.credit(@amount, @declined_card, @options) + assert_failure response + assert_equal 'Decline', response.message + end + + def test_successful_void + auth = @gateway.authorize(@amount, @credit_card, @options) + assert_success auth + + assert void = @gateway.void(auth.authorization) + assert_success void + assert_equal 'Success', void.message + end + + def test_failed_void + response = @gateway.void('') + assert_failure response + assert_equal 'Invalid Amount', response.message + end + + def test_successful_verify + response = @gateway.verify(@credit_card, @options) + assert_success response + assert_match 'Success', response.message + end + + def test_failed_verify + response = @gateway.verify(@declined_card, @options) + assert_failure response + assert_match 'Decline', response.message + end + + def test_invalid_login + gateway = SafeChargeGateway.new(client_login_id: '', client_password: '') + + response = gateway.purchase(@amount, @credit_card, @options) + assert_failure response + assert_match 'Invalid login', response.message + end + + def test_transcript_scrubbing + transcript = capture_transcript(@gateway) do + @gateway.purchase(@amount, @credit_card, @options) + end + transcript = @gateway.scrub(transcript) + + assert_scrubbed(@credit_card.number, transcript) + assert_scrubbed(@credit_card.verification_value, transcript) + assert_scrubbed(@gateway.options[:client_password], transcript) + end + +end diff --git a/test/remote/gateways/remote_sage_pay_test.rb b/test/remote/gateways/remote_sage_pay_test.rb index fb3e17c3cdd..c7647d53969 100644 --- a/test/remote/gateways/remote_sage_pay_test.rb +++ b/test/remote/gateways/remote_sage_pay_test.rb @@ -78,7 +78,7 @@ def setup :name => 'Tekin Suleyman', :address1 => 'Flat 10 Lapwing Court', :address2 => 'West Didsbury', - :city => "Manchester", + :city => 'Manchester', :county => 'Greater Manchester', :country => 'GB', :zip => 'M20 2PS' @@ -86,7 +86,7 @@ def setup :shipping_address => { :name => 'Tekin Suleyman', :address1 => '120 Grosvenor St', - :city => "Manchester", + :city => 'Manchester', :county => 'Greater Manchester', :country => 'GB', :zip => 'M1 7QW' @@ -124,6 +124,20 @@ def test_successful_authorization_and_capture assert_success capture end + def test_successful_authorization_and_capture_and_refund + assert auth = @gateway.authorize(@amount, @mastercard, @options) + assert_success auth + + assert capture = @gateway.capture(@amount, auth.authorization) + assert_success capture + + assert refund = @gateway.refund(@amount, capture.authorization, + :description => 'Crediting trx', + :order_id => generate_unique_id + ) + assert_success refund + end + def test_successful_authorization_and_void assert auth = @gateway.authorize(@amount, @mastercard, @options) assert_success auth @@ -159,13 +173,6 @@ def test_successful_visa_purchase assert !response.authorization.blank? end - def test_successful_maestro_purchase - assert response = @gateway.purchase(@amount, @maestro, @options) - assert_success response - assert response.test? - assert !response.authorization.blank? - end - def test_successful_amex_purchase assert response = @gateway.purchase(@amount, @amex, @options) assert_success response @@ -182,15 +189,15 @@ def test_successful_electron_purchase def test_successful_purchase_with_overly_long_fields options = { - description: "SagePay transactions fail if the description is more than 100 characters. Therefore, we truncate it to 100 characters.", + description: 'SagePay transactions fail if the description is more than 100 characters. Therefore, we truncate it to 100 characters.', order_id: "#{generate_unique_id} SagePay order_id cannot be more than 40 characters.", billing_address: { name: 'FirstNameCannotBeMoreThanTwentyChars SurnameCannotBeMoreThanTwenty', address1: 'The Billing Address 1 Cannot Be More Than One Hundred Characters if it is it will fail. Therefore, we truncate it.', address2: 'The Billing Address 2 Cannot Be More Than One Hundred Characters if it is it will fail. Therefore, we truncate it.', - phone: "111222333444555666777888999", - city: "TheCityCannotBeMoreThanFortyCharactersReally", - state: "NCStateIsTwoChars", + phone: '111222333444555666777888999', + city: 'TheCityCannotBeMoreThanFortyCharactersReally', + state: 'NCStateIsTwoChars', country: 'USMustBeTwoChars', zip: 'PostalCodeCannotExceedTenChars' }, @@ -198,16 +205,16 @@ def test_successful_purchase_with_overly_long_fields name: 'FirstNameCannotBeMoreThanTwentyChars SurnameCannotBeMoreThanTwenty', address1: 'The Shipping Address 1 Cannot Be More Than One Hundred Characters if it is it will fail. Therefore, we truncate it.', address2: 'The Shipping Address 2 Cannot Be More Than One Hundred Characters if it is it will fail. Therefore, we truncate it.', - phone: "111222333444555666777888999", - city: "TheCityCannotBeMoreThanFortyCharactersReally", - state: "NCStateIsTwoChars", + phone: '111222333444555666777888999', + city: 'TheCityCannotBeMoreThanFortyCharactersReally', + state: 'NCStateIsTwoChars', country: 'USMustBeTwoChars', zip: 'PostalCodeCannotExceedTenChars' } } - @visa.first_name = "FullNameOnACardMustBeLessThanFiftyCharacters" - @visa.last_name = "OtherwiseSagePayFailsIt" + @visa.first_name = 'FullNameOnACardMustBeLessThanFiftyCharacters' + @visa.last_name = 'OtherwiseSagePayFailsIt' assert response = @gateway.purchase(@amount, @visa, options) assert_success response @@ -229,7 +236,7 @@ def test_successful_purchase_with_apply_avscv2_field @options[:apply_avscv2] = 1 response = @gateway.purchase(@amount, @visa, @options) assert_success response - assert_equal "Y", response.cvv_result['code'] + assert_equal 'Y', response.cvv_result['code'] end def test_successful_purchase_with_pay_pal_callback_url @@ -313,11 +320,18 @@ def test_successful_purchase_with_website assert_success response end + def test_successful_repeat_purchase + response = @gateway.purchase(@amount, @visa, @options) + assert_success response + repeat = @gateway.purchase(@amount, response.authorization, @options.merge(order_id: generate_unique_id)) + assert_success repeat + end + def test_invalid_login message = SagePayGateway.simulate ? 'VSP Simulator cannot find your vendor name. Ensure you have have supplied a Vendor field with your VSP Vendor name assigned to it.' : '3034 : The Vendor or VendorName value is required.' gateway = SagePayGateway.new( - :login => '' + :login => '' ) assert response = gateway.purchase(@amount, @mastercard, @options) assert_equal message, response.message @@ -336,8 +350,8 @@ def test_successful_store_and_repurchase_with_resupplied_verification_value assert response = @gateway.store(@visa) assert_success response assert !response.authorization.blank? - assert purchase = @gateway.purchase(@amount, response.authorization, @options.merge(customer: 1)) - assert purchase = @gateway.purchase(@amount, response.authorization, @options.merge(verification_value: '123', order_id: 'foobar123')) + assert @gateway.purchase(@amount, response.authorization, @options.merge(customer: 1)) + assert purchase = @gateway.purchase(@amount, response.authorization, @options.merge(verification_value: '123', order_id: generate_unique_id)) assert_success purchase end @@ -372,7 +386,7 @@ def test_successful_unstore def test_successful_verify response = @gateway.verify(@visa, @options) assert_success response - assert_equal "Success", response.message + assert_equal 'Success', response.message end def test_failed_verify @@ -417,13 +431,13 @@ def basket_xml # Example from http://www.sagepay.co.uk/support/customer-xml def customer_xml <<-XML -<customer> - <customerMiddleInitial>W</customerMiddleInitial> - <customerBirth>1983-01-01</customerBirth> - <customerWorkPhone>020 1234567</customerWorkPhone> - <customerMobilePhone>0799 1234567</customerMobilePhone> - <previousCust>0</previousCust> - <timeOnFile>10</timeOnFile> +<customer> + <customerMiddleInitial>W</customerMiddleInitial> + <customerBirth>1983-01-01</customerBirth> + <customerWorkPhone>020 1234567</customerWorkPhone> + <customerMobilePhone>0799 1234567</customerMobilePhone> + <previousCust>0</previousCust> + <timeOnFile>10</timeOnFile> <customerId>CUST123</customerId> </customer> XML diff --git a/test/remote/gateways/remote_sage_test.rb b/test/remote/gateways/remote_sage_test.rb index d196d4ada97..5107a12e97d 100644 --- a/test/remote/gateways/remote_sage_test.rb +++ b/test/remote/gateways/remote_sage_test.rb @@ -7,11 +7,11 @@ def setup @amount = 100 - @visa = credit_card("4111111111111111") + @visa = credit_card('4111111111111111') @check = check - @mastercard = credit_card("5499740000000057") - @discover = credit_card("6011000993026909") - @amex = credit_card("371449635392376") + @mastercard = credit_card('5499740000000057') + @discover = credit_card('6011000993026909') + @amex = credit_card('371449635392376') @declined_card = credit_card('4000') @@ -80,6 +80,13 @@ def test_successful_with_minimal_options assert_false response.authorization.blank? end + def test_successful_purchase_with_blank_state + assert response = @gateway.purchase(@amount, @visa, billing_address: address(state: '')) + assert_success response + assert response.test? + assert_false response.authorization.blank? + end + def test_authorization_and_capture assert auth = @gateway.authorize(@amount, @visa, @options) assert_success auth @@ -134,16 +141,16 @@ def test_visa_refund assert refund = @gateway.refund(@amount, purchase.authorization, @options) assert_success refund - assert_equal "APPROVED", refund.message + assert_equal 'APPROVED', refund.message end def test_visa_failed_refund purchase = @gateway.purchase(@amount, @visa, @options) assert_success purchase - response = @gateway.refund(@amount, "UnknownReference", @options) + response = @gateway.refund(@amount, 'UnknownReference', @options) assert_failure response - assert_equal "INVALID T_REFERENCE", response.message + assert_equal 'INVALID T_REFERENCE', response.message end def test_partial_refund @@ -152,14 +159,14 @@ def test_partial_refund assert refund = @gateway.refund(@amount-1, purchase.authorization, @options) assert_success refund - assert_equal "APPROVED", refund.message + assert_equal 'APPROVED', refund.message end def test_store_visa assert response = @gateway.store(@visa, @options) assert_success response - assert auth = response.authorization, - "Store card authorization should not be nil" + assert response.authorization, + 'Store card authorization should not be nil' assert_not_nil response.message end @@ -171,14 +178,14 @@ def test_failed_store def test_unstore_visa assert auth = @gateway.store(@visa, @options).authorization, - "Unstore card authorization should not be nil" + 'Unstore card authorization should not be nil' assert response = @gateway.unstore(auth, @options) assert_success response end def test_failed_unstore_visa assert auth = @gateway.store(@visa, @options).authorization, - "Unstore card authorization should not be nil" + 'Unstore card authorization should not be nil' assert response = @gateway.unstore(auth, @options) assert_success response end @@ -214,4 +221,15 @@ def test_transcript_scrubbing_store assert_scrubbed(@gateway.options[:password], transcript) end + def test_echeck_scrubbing + transcript = capture_transcript(@gateway) do + @gateway.purchase(@amount, @check, @options) + end + transcript = @gateway.scrub(transcript) + + assert_scrubbed(@check.account_number, transcript) + assert_scrubbed(@check.routing_number, transcript) + assert_scrubbed(@gateway.options[:password], transcript) + end + end diff --git a/test/remote/gateways/remote_sallie_mae_test.rb b/test/remote/gateways/remote_sallie_mae_test.rb index 09f14cb2337..f2b47acef22 100644 --- a/test/remote/gateways/remote_sallie_mae_test.rb +++ b/test/remote/gateways/remote_sallie_mae_test.rb @@ -3,12 +3,12 @@ class RemoteSallieMaeTest < Test::Unit::TestCase def setup @gateway = SallieMaeGateway.new(fixtures(:sallie_mae)) - + @amount = 100 @credit_card = credit_card('5454545454545454') @declined_card = credit_card('4000300011112220') - - @options = { + + @options = { :billing_address => address, :description => 'Store Purchase' } diff --git a/test/remote/gateways/remote_secure_net_test.rb b/test/remote/gateways/remote_secure_net_test.rb index 424f16f44e6..fc92a5276e1 100644 --- a/test/remote/gateways/remote_secure_net_test.rb +++ b/test/remote/gateways/remote_secure_net_test.rb @@ -97,7 +97,7 @@ def test_unsuccessful_capture def test_unsuccessful_purchase assert response = @gateway.purchase(@amount, @bad_card_number, @options) assert_failure response - assert_equal "CARD TYPE COULD NOT BE IDENTIFIED", response.message + assert_equal 'CARD TYPE COULD NOT BE IDENTIFIED', response.message end def test_unsuccessful_purchase_and_credit @@ -113,8 +113,8 @@ def test_unsuccessful_purchase_and_credit def test_invoice_description_and_number options = @options.merge({ - invoice_description: "TheInvoiceDescriptions", - invoice_number: "TheInvoiceNumber" + invoice_description: 'TheInvoiceDescriptions', + invoice_number: 'TheInvoiceNumber' }) assert auth = @gateway.authorize(@amount, @credit_card, options) @@ -125,4 +125,15 @@ def test_invoice_description_and_number assert_equal 'Approved', capture.message end + def test_transcript_scrubbing + transcript = capture_transcript(@gateway) do + @gateway.purchase(@amount, @credit_card, @options) + end + transcript = @gateway.scrub(transcript) + + assert_scrubbed(@credit_card.number, transcript) + assert_scrubbed(@credit_card.verification_value, transcript) + assert_scrubbed(@gateway.options[:password], transcript) + end + end diff --git a/test/remote/gateways/remote_secure_pay_au_test.rb b/test/remote/gateways/remote_secure_pay_au_test.rb index 5f340c19f7c..fc99db2ef81 100644 --- a/test/remote/gateways/remote_secure_pay_au_test.rb +++ b/test/remote/gateways/remote_secure_pay_au_test.rb @@ -130,7 +130,7 @@ def test_successful_unstore end def test_repeat_unstore - @gateway.unstore('test1234') rescue nil #Ensure it is already missing + @gateway.unstore('test1234') rescue nil # Ensure it is already missing response = @gateway.unstore('test1234') @@ -147,7 +147,7 @@ def test_successful_store end def test_failed_store - @gateway.store(@credit_card, {:billing_id => 'test1234', :amount => 15000}) rescue nil #Ensure it already exists + @gateway.store(@credit_card, {:billing_id => 'test1234', :amount => 15000}) rescue nil # Ensure it already exists assert response = @gateway.store(@credit_card, {:billing_id => 'test1234', :amount => 15000}) assert_failure response @@ -156,7 +156,7 @@ def test_failed_store end def test_successful_triggered_payment - @gateway.store(@credit_card, {:billing_id => 'test1234', :amount => 15000}) rescue nil #Ensure it already exists + @gateway.store(@credit_card, {:billing_id => 'test1234', :amount => 15000}) rescue nil # Ensure it already exists assert response = @gateway.purchase(12300, 'test1234', @options) assert_success response @@ -166,7 +166,7 @@ def test_successful_triggered_payment end def test_failure_triggered_payment - @gateway.unstore('test1234') rescue nil #Ensure its no longer there + @gateway.unstore('test1234') rescue nil # Ensure its no longer there assert response = @gateway.purchase(12300, 'test1234', @options) assert_failure response @@ -181,7 +181,7 @@ def test_invalid_login ) assert response = gateway.purchase(@amount, @credit_card, @options) assert_failure response - assert_equal "Invalid merchant ID", response.message + assert_equal 'Invalid merchant ID', response.message end def test_purchase_scrubbing diff --git a/test/remote/gateways/remote_secure_pay_tech_test.rb b/test/remote/gateways/remote_secure_pay_tech_test.rb index 737d2d92280..3b76bf77eef 100644 --- a/test/remote/gateways/remote_secure_pay_tech_test.rb +++ b/test/remote/gateways/remote_secure_pay_tech_test.rb @@ -5,14 +5,14 @@ class RemoteSecurePayTechTest < Test::Unit::TestCase def setup @gateway = SecurePayTechGateway.new(fixtures(:secure_pay_tech)) - + @accepted_amount = 10000 @declined_amount = 10075 - + @credit_card = credit_card('4987654321098769', :month => '5', :year => '2013') @options = { :billing_address => address } end - + def test_successful_purchase assert response = @gateway.purchase(@accepted_amount, @credit_card, @options) assert_equal 'Transaction OK', response.message diff --git a/test/remote/gateways/remote_secure_pay_test.rb b/test/remote/gateways/remote_secure_pay_test.rb index 5806fd0ab72..63f83f5e40b 100644 --- a/test/remote/gateways/remote_secure_pay_test.rb +++ b/test/remote/gateways/remote_secure_pay_test.rb @@ -1,7 +1,7 @@ require 'test_helper' -class RemoteSecurePayTest < Test::Unit::TestCase - +class RemoteSecurePayTest < Test::Unit::TestCase + def setup @gateway = SecurePayGateway.new(fixtures(:secure_pay)) @@ -9,15 +9,16 @@ def setup :month => '7', :year => '2014' ) - - @options = { :order_id => generate_unique_id, + + @options = { + :order_id => generate_unique_id, :description => 'Store purchase', :billing_address => address } - + @amount = 100 end - + def test_successful_purchase assert response = @gateway.purchase(@amount, @credit_card, @options) assert response.success? diff --git a/test/remote/gateways/remote_securion_pay_test.rb b/test/remote/gateways/remote_securion_pay_test.rb index 7cae9189157..59b600899f1 100644 --- a/test/remote/gateways/remote_securion_pay_test.rb +++ b/test/remote/gateways/remote_securion_pay_test.rb @@ -24,23 +24,23 @@ def test_successful_store response = @gateway.store(@credit_card, @options) assert_success response assert_match %r(^cust_\w+$), response.authorization - assert_equal "customer", response.params["objectType"] - assert_match %r(^card_\w+$), response.params["cards"][0]["id"] - assert_equal "card", response.params["cards"][0]["objectType"] + assert_equal 'customer', response.params['objectType'] + assert_match %r(^card_\w+$), response.params['cards'][0]['id'] + assert_equal 'card', response.params['cards'][0]['objectType'] @options[:customer_id] = response.authorization response = @gateway.store(@new_credit_card, @options) assert_success response - assert_match %r(^card_\w+$), response.params["card"]["id"] - assert_equal @options[:customer_id], response.params["card"]["customerId"] + assert_match %r(^card_\w+$), response.params['card']['id'] + assert_equal @options[:customer_id], response.params['card']['customerId'] response = @gateway.customer(@options) assert_success response - assert_equal @options[:customer_id], response.params["id"] - assert_equal "401288", response.params["cards"][0]["first6"] - assert_equal "1881", response.params["cards"][0]["last4"] - assert_equal "424242", response.params["cards"][1]["first6"] - assert_equal "4242", response.params["cards"][1]["last4"] + assert_equal @options[:customer_id], response.params['id'] + assert_equal '401288', response.params['cards'][0]['first6'] + assert_equal '1881', response.params['cards'][0]['last4'] + assert_equal '424242', response.params['cards'][1]['first6'] + assert_equal '4242', response.params['cards'][1]['last4'] end # def test_dump_transcript @@ -61,8 +61,8 @@ def test_transcript_scrubbing def test_successful_purchase response = @gateway.purchase(@amount, @credit_card, @options) assert_success response - assert_equal "Transaction approved", response.message - assert_equal "foo@example.com", response.params["metadata"]["email"] + assert_equal 'Transaction approved', response.message + assert_equal 'foo@example.com', response.params['metadata']['email'] assert_match CHARGE_ID_REGEX, response.authorization end @@ -76,9 +76,9 @@ def test_unsuccessful_purchase def test_authorization_and_capture authorization = @gateway.authorize(@amount, @credit_card, @options) assert_success authorization - assert !authorization.params["captured"] - assert_equal @options[:description], authorization.params["description"] - assert_equal @options[:email], authorization.params["metadata"]["email"] + assert !authorization.params['captured'] + assert_equal @options[:description], authorization.params['description'] + assert_equal @options[:email], authorization.params['metadata']['email'] response = @gateway.capture(@amount, authorization.authorization) assert_success response @@ -103,10 +103,10 @@ def test_successful_full_refund refund = @gateway.refund(@amount, purchase.authorization) assert_success refund - assert refund.params["refunded"] - assert_equal 0, refund.params["amount"] - assert_equal 1, refund.params["refunds"].size - assert_equal @amount, refund.params["refunds"].map{|r| r["amount"]}.sum + assert refund.params['refunded'] + assert_equal 0, refund.params['amount'] + assert_equal 1, refund.params['refunds'].size + assert_equal @amount, refund.params['refunds'].map { |r| r['amount'] }.sum assert refund.authorization end @@ -121,10 +121,10 @@ def test_successful_partially_refund second_refund = @gateway.refund(@refund_amount, purchase.authorization) assert_success second_refund - assert second_refund.params["refunded"] - assert_equal @amount - 2 * @refund_amount, second_refund.params["amount"] - assert_equal 2, second_refund.params["refunds"].size - assert_equal 2 * @refund_amount, second_refund.params["refunds"].map{|r| r["amount"]}.sum + assert second_refund.params['refunded'] + assert_equal @amount - 2 * @refund_amount, second_refund.params['amount'] + assert_equal 2, second_refund.params['refunds'].size + assert_equal 2 * @refund_amount, second_refund.params['refunds'].map { |r| r['amount'] }.sum assert second_refund.authorization end @@ -147,14 +147,14 @@ def test_unsuccessful_refund def test_successful_void authorization = @gateway.authorize(@amount, @credit_card, @options) assert_success authorization - assert !authorization.params["captured"] + assert !authorization.params['captured'] void = @gateway.void(authorization.authorization, @options) assert_success void - assert void.params["refunded"] - assert_equal 0, void.params["amount"] - assert_equal 1, void.params["refunds"].size - assert_equal @amount, void.params["refunds"].map{|r| r["amount"]}.sum + assert void.params['refunded'] + assert_equal 0, void.params['amount'] + assert_equal 1, void.params['refunds'].size + assert_equal @amount, void.params['refunds'].map { |r| r['amount'] }.sum assert void.authorization end @@ -188,7 +188,7 @@ def test_invalid_login gateway = SecurionPayGateway.new(secret_key: 'active_merchant_test') response = gateway.purchase(@amount, @credit_card, @options) assert_failure response - assert_match "Provided API key is invalid", response.message + assert_match 'Provided API key is invalid', response.message end def test_invalid_number_for_purchase diff --git a/test/remote/gateways/remote_skipjack_test.rb b/test/remote/gateways/remote_skipjack_test.rb index 9c339063b54..d8ec78f732b 100644 --- a/test/remote/gateways/remote_skipjack_test.rb +++ b/test/remote/gateways/remote_skipjack_test.rb @@ -7,8 +7,8 @@ def setup @gateway = SkipJackGateway.new(fixtures(:skip_jack)) @credit_card = credit_card('4445999922225', - :verification_value => '999' - ) + :verification_value => '999' + ) @amount = 100 @@ -61,7 +61,7 @@ def test_successful_authorization_and_partial_capture capture = @gateway.capture(1000, authorization.authorization) assert_success capture - assert_equal "1000", capture.params["TransactionAmount"] + assert_equal '1000', capture.params['TransactionAmount'] end def test_authorization_and_void diff --git a/test/remote/gateways/remote_so_easy_pay_test.rb b/test/remote/gateways/remote_so_easy_pay_test.rb index 8803620f610..e24d837703b 100644 --- a/test/remote/gateways/remote_so_easy_pay_test.rb +++ b/test/remote/gateways/remote_so_easy_pay_test.rb @@ -2,7 +2,6 @@ class RemoteSoEasyPayTest < Test::Unit::TestCase - def setup @gateway = SoEasyPayGateway.new(fixtures(:so_easy_pay)) @@ -63,4 +62,3 @@ def test_invalid_login assert_equal 'Website verification failed, wrong websiteID or password', response.message end end - diff --git a/test/remote/gateways/remote_spreedly_core_test.rb b/test/remote/gateways/remote_spreedly_core_test.rb index 3a3bfb8e9a1..c9ea36a7d2c 100644 --- a/test/remote/gateways/remote_spreedly_core_test.rb +++ b/test/remote/gateways/remote_spreedly_core_test.rb @@ -8,8 +8,10 @@ def setup @amount = 100 @credit_card = credit_card('5555555555554444') @declined_card = credit_card('4012888888881881') - @existing_payment_method = '9AjLflWs7SOKuqJLveOZya9bixa' - @declined_payment_method = 'n3JElNt9joT1mJ3CxvWjyEN39N' + @existing_payment_method = '3rEkRlZur2hXKbwwRBidHJAIUTO' + @declined_payment_method = 'UPfh3J3JbekLeYC88BP741JWnS5' + @existing_transaction = 'PJ5ICgM6h7v9pBNxDCJjRHDDxBC' + @not_found_transaction = 'AdyQXaG0SVpSoMPdmFlvd3aA3uz' end def test_successful_purchase_with_token @@ -21,7 +23,7 @@ def test_successful_purchase_with_token def test_failed_purchase_with_token assert response = @gateway.purchase(@amount, @declined_payment_method) assert_failure response - assert_match %r(Unable to process the transaction), response.message + assert_match %r(Unable to process the purchase transaction), response.message end def test_successful_authorize_with_token_and_capture @@ -38,7 +40,7 @@ def test_successful_authorize_with_token_and_capture def test_failed_authorize_with_token assert response = @gateway.authorize(@amount, @declined_payment_method) assert_failure response - assert_match %r(Unable to process the transaction), response.message + assert_match %r(Unable to process the authorize transaction), response.message end def test_failed_capture @@ -55,7 +57,7 @@ def test_successful_purchase_with_credit_card assert_success response assert_equal 'Succeeded!', response.message assert_equal 'Purchase', response.params['transaction_type'] - assert_equal 'used', response.params['payment_method_storage_state'] + assert_equal 'cached', response.params['payment_method_storage_state'] end def test_successful_purchase_with_card_and_address @@ -69,7 +71,7 @@ def test_successful_purchase_with_card_and_address assert_equal 'Succeeded!', response.message assert_equal 'joebob@example.com', response.params['payment_method_email'] - assert_equal '1234 My Street', response.params['payment_method_address1'] + assert_equal '456 My Street', response.params['payment_method_address1'] assert_equal 'Apt 1', response.params['payment_method_address2'] assert_equal 'Ottawa', response.params['payment_method_city'] assert_equal 'ON', response.params['payment_method_state'] @@ -122,7 +124,7 @@ def test_successful_authorize_with_card_and_address assert_equal 'Authorization', response.params['transaction_type'] assert_equal 'joebob@example.com', response.params['payment_method_email'] - assert_equal '1234 My Street', response.params['payment_method_address1'] + assert_equal '456 My Street', response.params['payment_method_address1'] assert_equal 'Apt 1', response.params['payment_method_address2'] assert_equal 'Ottawa', response.params['payment_method_city'] assert_equal 'ON', response.params['payment_method_state'] @@ -188,7 +190,7 @@ def test_successful_store_with_address assert response = @gateway.store(@credit_card, options) assert_success response assert_equal 'joebob@example.com', response.params['payment_method_email'] - assert_equal '1234 My Street', response.params['payment_method_address1'] + assert_equal '456 My Street', response.params['payment_method_address1'] assert_equal 'Apt 1', response.params['payment_method_address2'] assert_equal 'Ottawa', response.params['payment_method_city'] assert_equal 'ON', response.params['payment_method_state'] @@ -238,6 +240,46 @@ def test_successful_void assert_equal 'Succeeded!', response.message end + def test_successful_verify_with_token + assert response = @gateway.verify(@existing_payment_method) + assert_success response + assert_equal 'Succeeded!', response.message + assert_equal 'Verification', response.params['transaction_type'] + assert_includes %w(cached retained), response.params['payment_method_storage_state'] + end + + def test_failed_verify_with_token + assert response = @gateway.verify(@declined_payment_method) + assert_failure response + end + + def test_successful_verify_with_credit_card + assert response = @gateway.verify(@credit_card) + assert_success response + assert_equal 'Succeeded!', response.message + assert_equal 'Verification', response.params['transaction_type'] + assert_includes %w(cached retained), response.params['payment_method_storage_state'] + end + + def test_failed_verify_with_declined_credit_card + assert response = @gateway.verify(@declined_card) + assert_failure response + assert_match %r(Unable to process the verify transaction), response.message + end + + def test_successful_find_transaction + assert response = @gateway.find(@existing_transaction) + assert_success response + assert_equal 'Succeeded!', response.message + assert_equal 'Purchase', response.params['transaction_type'] + end + + def test_failed_find_transaction + assert response = @gateway.find(@not_found_transaction) + assert_failure response + assert_match %r(Unable to find the transaction), response.message + end + def test_invalid_login gateway = SpreedlyCoreGateway.new(:login => 'Bogus', :password => 'MoreBogus', :gateway_token => 'EvenMoreBogus') @@ -245,4 +287,27 @@ def test_invalid_login assert_failure response assert_match %r{Unable to authenticate}, response.message end + + def test_scrubbing_purchase + transcript = capture_transcript(@gateway) do + @gateway.purchase(@amount, @credit_card) + end + transcript = @gateway.scrub(transcript) + + assert_scrubbed(@credit_card.number, transcript) + assert_scrubbed(@credit_card.verification_value, transcript) + assert_scrubbed(@gateway.options[:login], transcript) + assert_scrubbed(@gateway.options[:password], transcript) + end + + def test_scrubbing_purchase_with_token + transcript = capture_transcript(@gateway) do + @gateway.purchase(@amount, @existing_payment_method) + end + transcript = @gateway.scrub(transcript) + + assert_scrubbed(@existing_payment_method, transcript) + assert_scrubbed(@gateway.options[:login], transcript) + assert_scrubbed(@gateway.options[:password], transcript) + end end diff --git a/test/remote/gateways/remote_stripe_android_pay_test.rb b/test/remote/gateways/remote_stripe_android_pay_test.rb index 3061f01997e..5abf0974a17 100644 --- a/test/remote/gateways/remote_stripe_android_pay_test.rb +++ b/test/remote/gateways/remote_stripe_android_pay_test.rb @@ -8,7 +8,7 @@ def setup @amount = 100 @options = { - :currency => "USD", + :currency => 'USD', :description => 'ActiveMerchant Test Purchase', :email => 'wow@example.com' } @@ -16,33 +16,33 @@ def setup def test_successful_purchase_with_android_pay_raw_cryptogram credit_card = network_tokenization_credit_card('4242424242424242', - payment_cryptogram: "EHuWW9PiBkWvqE5juRwDzAUFBAk=", + payment_cryptogram: 'EHuWW9PiBkWvqE5juRwDzAUFBAk=', verification_value: nil, eci: '05', source: :android_pay ) assert response = @gateway.purchase(@amount, credit_card, @options) assert_success response - assert_equal "charge", response.params["object"] - assert response.params["paid"] - assert_equal "ActiveMerchant Test Purchase", response.params["description"] - assert_equal "wow@example.com", response.params["metadata"]["email"] + assert_equal 'charge', response.params['object'] + assert response.params['paid'] + assert_equal 'ActiveMerchant Test Purchase', response.params['description'] + assert_equal 'wow@example.com', response.params['metadata']['email'] assert_match CHARGE_ID_REGEX, response.authorization end def test_successful_auth_with_android_pay_raw_cryptogram credit_card = network_tokenization_credit_card('4242424242424242', - payment_cryptogram: "EHuWW9PiBkWvqE5juRwDzAUFBAk=", + payment_cryptogram: 'EHuWW9PiBkWvqE5juRwDzAUFBAk=', verification_value: nil, eci: '05', source: :android_pay ) assert response = @gateway.authorize(@amount, credit_card, @options) assert_success response - assert_equal "charge", response.params["object"] - assert response.params["paid"] - assert_equal "ActiveMerchant Test Purchase", response.params["description"] - assert_equal "wow@example.com", response.params["metadata"]["email"] + assert_equal 'charge', response.params['object'] + assert response.params['paid'] + assert_equal 'ActiveMerchant Test Purchase', response.params['description'] + assert_equal 'wow@example.com', response.params['metadata']['email'] assert_match CHARGE_ID_REGEX, response.authorization end -end \ No newline at end of file +end diff --git a/test/remote/gateways/remote_stripe_apple_pay_test.rb b/test/remote/gateways/remote_stripe_apple_pay_test.rb index 821b36ee6fc..c5231114490 100644 --- a/test/remote/gateways/remote_stripe_apple_pay_test.rb +++ b/test/remote/gateways/remote_stripe_apple_pay_test.rb @@ -8,7 +8,7 @@ def setup @amount = 100 @options = { - :currency => "USD", + :currency => 'USD', :description => 'ActiveMerchant Test Purchase', :email => 'wow@example.com' } @@ -18,19 +18,19 @@ def setup def test_successful_purchase_with_apple_pay_payment_token assert response = @gateway.purchase(@amount, @apple_pay_payment_token, @options) assert_success response - assert_equal "charge", response.params["object"] - assert response.params["paid"] - assert_equal "ActiveMerchant Test Purchase", response.params["description"] - assert_equal "wow@example.com", response.params["metadata"]["email"] + assert_equal 'charge', response.params['object'] + assert response.params['paid'] + assert_equal 'ActiveMerchant Test Purchase', response.params['description'] + assert_equal 'wow@example.com', response.params['metadata']['email'] assert_match CHARGE_ID_REGEX, response.authorization end def test_authorization_and_capture_with_apple_pay_payment_token assert authorization = @gateway.authorize(@amount, @apple_pay_payment_token, @options) assert_success authorization - refute authorization.params["captured"] - assert_equal "ActiveMerchant Test Purchase", authorization.params["description"] - assert_equal "wow@example.com", authorization.params["metadata"]["email"] + refute authorization.params['captured'] + assert_equal 'ActiveMerchant Test Purchase', authorization.params['description'] + assert_equal 'wow@example.com', authorization.params['metadata']['email'] assert capture = @gateway.capture(@amount, authorization.authorization) assert_success capture @@ -39,7 +39,7 @@ def test_authorization_and_capture_with_apple_pay_payment_token def test_authorization_and_void_with_apple_pay_payment_token assert authorization = @gateway.authorize(@amount, @apple_pay_payment_token, @options) assert_success authorization - refute authorization.params["captured"] + refute authorization.params['captured'] assert void = @gateway.void(authorization.authorization) assert_success void @@ -54,45 +54,45 @@ def test_successful_void_with_apple_pay_payment_token end def test_successful_store_with_apple_pay_payment_token - assert response = @gateway.store(@apple_pay_payment_token, {:description => "Active Merchant Test Customer", :email => "email@example.com"}) + assert response = @gateway.store(@apple_pay_payment_token, {:description => 'Active Merchant Test Customer', :email => 'email@example.com'}) assert_success response - assert_equal "customer", response.params["object"] - assert_equal "Active Merchant Test Customer", response.params["description"] - assert_equal "email@example.com", response.params["email"] - first_card = response.params["cards"]["data"].first - assert_equal response.params["default_card"], first_card["id"] - assert_equal "4242", first_card["dynamic_last4"] # when stripe is in test mode, token exchanged will return a test card with dynamic_last4 4242 - assert_equal "0000", first_card["last4"] # last4 is 0000 when using an apple pay token + assert_equal 'customer', response.params['object'] + assert_equal 'Active Merchant Test Customer', response.params['description'] + assert_equal 'email@example.com', response.params['email'] + first_card = response.params['cards']['data'].first + assert_equal response.params['default_card'], first_card['id'] + assert_equal '4242', first_card['dynamic_last4'] # when stripe is in test mode, token exchanged will return a test card with dynamic_last4 4242 + assert_equal '0000', first_card['last4'] # last4 is 0000 when using an apple pay token end def test_successful_store_with_existing_customer_and_apple_pay_payment_token - assert response = @gateway.store(@credit_card, {:description => "Active Merchant Test Customer"}) + assert response = @gateway.store(@credit_card, {:description => 'Active Merchant Test Customer'}) assert_success response - assert response = @gateway.store(@apple_pay_payment_token, {:customer => response.params['id'], :description => "Active Merchant Test Customer", :email => "email@example.com"}) + assert response = @gateway.store(@apple_pay_payment_token, {:customer => response.params['id'], :description => 'Active Merchant Test Customer', :email => 'email@example.com'}) assert_success response assert_equal 2, response.responses.size card_response = response.responses[0] - assert_equal "card", card_response.params["object"] - assert_equal "4242", card_response.params["dynamic_last4"] # when stripe is in test mode, token exchanged will return a test card with dynamic_last4 4242 - assert_equal "0000", card_response.params["last4"] # last4 is 0000 when using an apple pay token + assert_equal 'card', card_response.params['object'] + assert_equal '4242', card_response.params['dynamic_last4'] # when stripe is in test mode, token exchanged will return a test card with dynamic_last4 4242 + assert_equal '0000', card_response.params['last4'] # last4 is 0000 when using an apple pay token customer_response = response.responses[1] - assert_equal "customer", customer_response.params["object"] - assert_equal "Active Merchant Test Customer", customer_response.params["description"] - assert_equal "email@example.com", customer_response.params["email"] - assert_equal 2, customer_response.params["cards"]["count"] + assert_equal 'customer', customer_response.params['object'] + assert_equal 'Active Merchant Test Customer', customer_response.params['description'] + assert_equal 'email@example.com', customer_response.params['email'] + assert_equal 2, customer_response.params['cards']['count'] end def test_successful_recurring_with_apple_pay_payment_token - assert response = @gateway.store(@apple_pay_payment_token, {:description => "Active Merchant Test Customer", :email => "email@example.com"}) + assert response = @gateway.store(@apple_pay_payment_token, {:description => 'Active Merchant Test Customer', :email => 'email@example.com'}) assert_success response - assert recharge_options = @options.merge(:customer => response.params["id"]) + assert recharge_options = @options.merge(:customer => response.params['id']) assert response = @gateway.purchase(@amount, nil, recharge_options) assert_success response - assert_equal "charge", response.params["object"] - assert response.params["paid"] + assert_equal 'charge', response.params['object'] + assert response.params['paid'] end def test_purchase_with_unsuccessful_apple_pay_token_exchange @@ -102,65 +102,64 @@ def test_purchase_with_unsuccessful_apple_pay_token_exchange def test_successful_purchase_with_apple_pay_raw_cryptogram_with_eci credit_card = network_tokenization_credit_card('4242424242424242', - payment_cryptogram: "EHuWW9PiBkWvqE5juRwDzAUFBAk=", + payment_cryptogram: 'EHuWW9PiBkWvqE5juRwDzAUFBAk=', verification_value: nil, eci: '05', source: :apple_pay ) assert response = @gateway.purchase(@amount, credit_card, @options) assert_success response - assert_equal "charge", response.params["object"] - assert response.params["paid"] - assert_equal "ActiveMerchant Test Purchase", response.params["description"] - assert_equal "wow@example.com", response.params["metadata"]["email"] + assert_equal 'charge', response.params['object'] + assert response.params['paid'] + assert_equal 'ActiveMerchant Test Purchase', response.params['description'] + assert_equal 'wow@example.com', response.params['metadata']['email'] assert_match CHARGE_ID_REGEX, response.authorization end def test_successful_purchase_with_apple_pay_raw_cryptogram_without_eci credit_card = network_tokenization_credit_card('4242424242424242', - payment_cryptogram: "EHuWW9PiBkWvqE5juRwDzAUFBAk=", + payment_cryptogram: 'EHuWW9PiBkWvqE5juRwDzAUFBAk=', verification_value: nil, source: :apple_pay ) assert response = @gateway.purchase(@amount, credit_card, @options) assert_success response - assert_equal "charge", response.params["object"] - assert response.params["paid"] - assert_equal "ActiveMerchant Test Purchase", response.params["description"] - assert_equal "wow@example.com", response.params["metadata"]["email"] + assert_equal 'charge', response.params['object'] + assert response.params['paid'] + assert_equal 'ActiveMerchant Test Purchase', response.params['description'] + assert_equal 'wow@example.com', response.params['metadata']['email'] assert_match CHARGE_ID_REGEX, response.authorization end def test_successful_auth_with_apple_pay_raw_cryptogram_with_eci credit_card = network_tokenization_credit_card('4242424242424242', - payment_cryptogram: "EHuWW9PiBkWvqE5juRwDzAUFBAk=", + payment_cryptogram: 'EHuWW9PiBkWvqE5juRwDzAUFBAk=', verification_value: nil, eci: '05', source: :apple_pay ) assert response = @gateway.authorize(@amount, credit_card, @options) assert_success response - assert_equal "charge", response.params["object"] - assert response.params["paid"] - assert_equal "ActiveMerchant Test Purchase", response.params["description"] - assert_equal "wow@example.com", response.params["metadata"]["email"] + assert_equal 'charge', response.params['object'] + assert response.params['paid'] + assert_equal 'ActiveMerchant Test Purchase', response.params['description'] + assert_equal 'wow@example.com', response.params['metadata']['email'] assert_match CHARGE_ID_REGEX, response.authorization end def test_successful_auth_with_apple_pay_raw_cryptogram_without_eci credit_card = network_tokenization_credit_card('4242424242424242', - payment_cryptogram: "EHuWW9PiBkWvqE5juRwDzAUFBAk=", + payment_cryptogram: 'EHuWW9PiBkWvqE5juRwDzAUFBAk=', verification_value: nil, source: :apple_pay ) assert response = @gateway.authorize(@amount, credit_card, @options) assert_success response - assert_equal "charge", response.params["object"] - assert response.params["paid"] - assert_equal "ActiveMerchant Test Purchase", response.params["description"] - assert_equal "wow@example.com", response.params["metadata"]["email"] + assert_equal 'charge', response.params['object'] + assert response.params['paid'] + assert_equal 'ActiveMerchant Test Purchase', response.params['description'] + assert_equal 'wow@example.com', response.params['metadata']['email'] assert_match CHARGE_ID_REGEX, response.authorization end end - diff --git a/test/remote/gateways/remote_stripe_connect_test.rb b/test/remote/gateways/remote_stripe_connect_test.rb index c5bbd77d339..8309d62f98d 100644 --- a/test/remote/gateways/remote_stripe_connect_test.rb +++ b/test/remote/gateways/remote_stripe_connect_test.rb @@ -10,33 +10,51 @@ def setup @new_credit_card = credit_card('5105105105105100') @options = { - :currency => "USD", + :currency => 'USD', :description => 'ActiveMerchant Test Purchase', - :email => 'wow@example.com' + :email => 'wow@example.com', + :stripe_account => fixtures(:stripe_destination)[:stripe_user_id] } end def test_application_fee_for_stripe_connect - assert response = @gateway.purchase(@amount, @credit_card, @options.merge(:application_fee => 12 )) - assert response.params['fee_details'], 'This test will only work if your gateway login is a Stripe Connect access_token.' - assert response.params['fee_details'].any? do |fee| - (fee['type'] == 'application_fee') && (fee['amount'] == 12) - end + assert response = @gateway.purchase(@amount, @credit_card, @options.merge(:application_fee => 12)) + assert_success response end def test_successful_refund_with_application_fee assert response = @gateway.purchase(@amount, @credit_card, @options.merge(:application_fee => 12)) - assert response.params['fee_details'], 'This test will only work if your gateway login is a Stripe Connect access_token.' - assert refund = @gateway.refund(@amount, response.authorization, :refund_application_fee => true) + assert refund = @gateway.refund(@amount, response.authorization, @options.merge(:refund_application_fee => true)) assert_success refund - assert_equal 0, refund.params["fee"] + + # Verify the application fee is refunded + fetch_fee_id = @gateway.send(:fetch_application_fee, response.authorization, @options) + fee_id = @gateway.send(:application_fee_from_response, fetch_fee_id) + refund_check = @gateway.send(:refund_application_fee, 10, fee_id, @options) + assert_equal 'Application fee could not be refunded: Refund amount ($0.10) is greater than unrefunded amount on fee ($0.00)', refund_check.message end def test_refund_partial_application_fee assert response = @gateway.purchase(@amount, @credit_card, @options.merge(:application_fee => 12)) - assert response.params['fee_details'], 'This test will only work if your gateway login is a Stripe Connect access_token.' - assert refund = @gateway.refund(@amount - 20, response.authorization, { :refund_fee_amount => 10 }) + assert refund = @gateway.refund(@amount-20, response.authorization, @options.merge(:refund_fee_amount => '10')) assert_success refund + + # Verify the application fee is partially refunded + fetch_fee_id = @gateway.send(:fetch_application_fee, response.authorization, @options) + fee_id = @gateway.send(:application_fee_from_response, fetch_fee_id) + refund_check = @gateway.send(:refund_application_fee, 10, fee_id, @options) + assert_equal 'Application fee could not be refunded: Refund amount ($0.10) is greater than unrefunded amount on fee ($0.02)', refund_check.message end + def test_refund_application_fee_amount_zero + assert response = @gateway.purchase(@amount, @credit_card, @options.merge(:application_fee => 12)) + assert refund = @gateway.refund(@amount-20, response.authorization, @options.merge(:refund_fee_amount => '0')) + assert_success refund + + # Verify the application fee is not refunded + fetch_fee_id = @gateway.send(:fetch_application_fee, response.authorization, @options) + fee_id = @gateway.send(:application_fee_from_response, fetch_fee_id) + refund_check = @gateway.send(:refund_application_fee, 14, fee_id, @options) + assert_equal 'Application fee could not be refunded: Refund amount ($0.14) is greater than fee amount ($0.12)', refund_check.message + end end diff --git a/test/remote/gateways/remote_stripe_emv_test.rb b/test/remote/gateways/remote_stripe_emv_test.rb index 076d504ff1c..6d2742d7d35 100644 --- a/test/remote/gateways/remote_stripe_emv_test.rb +++ b/test/remote/gateways/remote_stripe_emv_test.rb @@ -1,151 +1,146 @@ require 'test_helper' class RemoteStripeEmvTest < Test::Unit::TestCase + CHARGE_ID_REGEX = /ch_[a-zA-Z\d]{24}/ + def setup @gateway = StripeGateway.new(fixtures(:stripe)) @amount = 100 @emv_credit_cards = { - uk: ActiveMerchant::Billing::CreditCard.new(icc_data: '500B56495341204352454449545F201A56495341204143515549524552205445535420434152442030315F24031512315F280208405F2A0208265F300202015F34010182025C008407A0000000031010950502000080009A031408259B02E8009C01009F02060000000734499F03060000000000009F0607A00000000310109F0902008C9F100706010A03A080009F120F4352454449544F20444520564953419F1A0208269F1C0831373030303437309F1E0831373030303437309F2608EB2EC0F472BEA0A49F2701809F3303E0B8C89F34031E03009F3501229F360200C39F37040A27296F9F4104000001319F4502DAC5DFAE5711476173FFFFFF0119D15122011758989389DFAE5A08476173FFFFFF011957114761739001010119D151220117589893895A084761739001010119'), - us: ActiveMerchant::Billing::CreditCard.new(icc_data: '50074D41455354524F571167999989000018123D25122200835506065A0967999989000018123F5F20134D54495032362D204D41455354524F203132415F24032512315F280200565F2A0208405F300202205F340101820278008407A0000000043060950500000080009A031504219B02E8009C01009F02060000000010009F03060000000000009F0607A00000000430609F090200029F10120210A7800F040000000000000000000000FF9F12074D61657374726F9F1A0208409F1C0831303030333331369F1E0831303030333331369F2608460245B808BCA1369F2701809F3303E0B8C89F34034403029F3501229F360200279F3704EA2C3A7A9F410400000094DF280104DFAE5711679999FFFFFFF8123D2512220083550606DFAE5A09679999FFFFFFF8123F'), - contactless: ActiveMerchant::Billing::CreditCard.new(icc_data: '500D5649534120454C454354524F4E5F20175649534120434445542032312F434152443035202020205F2A0208405F340111820200008407A00000000320109A031505119C01009F02060000000006959F0607A00000000320109F090200019F100706011103A000009F1A0200569F1C0831323334353637389F1E0831303030333236389F260852A5A96394EDA96D9F2701809F3303E0B8C89F3501229F360200069F3704A4428D7A9F410400000289DF280100DF30020301DFAE021885D6E511F8844CEA0DC72883180AC081AF4593A8A3C5FDD8DFAE030AFFFF0102628D1100005EDFAE5712476173FFFFFFFFF2234D151220114524040FDFAE021892FC2C940487F43AC64AB3DFD54C7B72F445FE409D80FDF5DFAE030AFFFF0102628D1100005F') + uk: ActiveMerchant::Billing::CreditCard.new(icc_data: '5A08476173900101011957114761739001010119D221220117589288899F131F3137353839383930303238383030303030304F07A0000000031010500B564953412043524544495482025C008407A00000000310108A025A318E0E00000000000000001E0302031F00950542000080009A031707259B02E8009C01005F24032212315F25030907015F2A0208265F3401019F01060000000000019F02060000000001009F03060000000000009F0607A00000000310109F0702FF009F0902008C9F0D05F0400088009F0E0500100000009F0F05F0400098009F100706010A03A000009F120F4352454449544F20444520564953419F160F3132333435363738393031323334359F1A0208269F1C0831313232333334349F1E0831323334353637389F21031137269F26084A3000C111F061539F2701809F33036028C89F34031E03009F3501219F360200029F370467D5DD109F3901059F40057E0000A0019F4104000001979F4E0D54657374204D65726368616E749F110101DF834F0F434842313136373235303030343439DF83620100'), + us: ActiveMerchant::Billing::CreditCard.new(icc_data: '5A08476173900101011957114761739001010119D221220117589288899F131F3137353839383930303238383030303030304F07A0000000031010500B564953412043524544495482025C008407A00000000310108A025A318E0E00000000000000001E0302031F00950542000080009A031707259B02E8009C01005F24032212315F25030907015F2A0208405F3401019F01060000000000019F02060000000001009F03060000000000009F0607A00000000310109F0702FF009F0902008C9F0D05F0400088009F0E0500100000009F0F05F0400098009F100706010A03A000009F120F4352454449544F20444520564953419F160F3132333435363738393031323334359F1A0208409F1C0831313232333334349F1E0831323334353637389F21031137269F26084A3000C111F061539F2701809F33036028C89F34031E03009F3501219F360200029F370467D5DD109F3901059F40057E0000A0019F4104000001979F4E0D54657374204D65726368616E749F110101DF834F0F434842313136373235303030343439DF83620100'), + contactless: ActiveMerchant::Billing::CreditCard.new(icc_data: '5A08476173900101011957114761739001010119D22122011758928889500D5649534120454C454354524F4E5F20175649534120434445542032312F434152443035202020205F2A0208405F340111820200008407A00000000320109A031505119C01009F02060000000006009F0607A00000000320109F090200019F100706011103A000009F1A0200569F1C0831323334353637389F1E0831303030333236389F260852A5A96394EDA96D9F2701809F3303E0B8C89F3501229F360200069F3704A4428D7A9F410400000289') } @options = { - :currency => "USD", + :currency => 'USD', :description => 'ActiveMerchant Test Purchase', :email => 'wow@example.com' } + + # This capture hex says that the payload is a transaction cryptogram (TC) but does not + # provide the actual cryptogram. This will only work in test mode and would cause real + # cards to be declined. + @capture_options = { icc_data: '9F270140' } end # for EMV contact transactions, it's advised to do a separate auth + capture # to satisfy the EMV chip's transaction flow, but this works as a legal # API call. You shouldn't use it in a real EMV implementation, though. def test_successful_purchase_with_emv_credit_card_in_uk - @gateway = StripeGateway.new(fixtures(:stripe_emv_uk)) assert response = @gateway.purchase(@amount, @emv_credit_cards[:uk], @options) assert_success response - assert_equal "charge", response.params["object"] - assert response.params["paid"] + assert_equal 'charge', response.params['object'] + assert response.params['paid'] assert_match CHARGE_ID_REGEX, response.authorization end # perform separate auth & capture rather than a purchase in practice for the # reasons mentioned above. def test_successful_purchase_with_emv_credit_card_in_us - @gateway = StripeGateway.new(fixtures(:stripe_emv_us)) assert response = @gateway.purchase(@amount, @emv_credit_cards[:us], @options) assert_success response - assert_equal "charge", response.params["object"] - assert response.params["paid"] + assert_equal 'charge', response.params['object'] + assert response.params['paid'] + assert_match CHARGE_ID_REGEX, response.authorization + end + + def test_successful_purchase_with_quickchip_credit_card_in_us + credit_card = @emv_credit_cards[:us] + credit_card.read_method = 'contact_quickchip' + assert response = @gateway.purchase(@amount, credit_card, @options) + assert_success response + assert_equal 'charge', response.params['object'] + assert response.params['captured'] + assert response.params['paid'] assert_match CHARGE_ID_REGEX, response.authorization end # For EMV contactless transactions, generally a purchase is preferred since # a TC is typically generated at the point of sale. def test_successful_purchase_with_emv_contactless_credit_card - @gateway = StripeGateway.new(fixtures(:stripe_emv_us)) emv_credit_card = @emv_credit_cards[:contactless] - emv_credit_card.contactless = true + emv_credit_card.read_method = 'contactless' assert response = @gateway.purchase(@amount, emv_credit_card, @options) assert_success response - assert_equal "charge", response.params["object"] - assert response.params["paid"] + assert_equal 'charge', response.params['object'] + assert response.params['paid'] assert_match CHARGE_ID_REGEX, response.authorization end def test_authorization_and_capture_with_emv_credit_card_in_uk - @gateway = StripeGateway.new(fixtures(:stripe_emv_uk)) assert authorization = @gateway.authorize(@amount, @emv_credit_cards[:uk], @options) assert_success authorization - assert authorization.emv_authorization, "Authorization should contain emv_authorization containing the EMV ARPC" - refute authorization.params["captured"] + assert authorization.emv_authorization, 'Authorization should contain emv_authorization containing the EMV ARPC' + refute authorization.params['captured'] - assert capture = @gateway.capture(@amount, authorization.authorization) + assert capture = @gateway.capture(@amount, authorization.authorization, @capture_options) assert_success capture - assert capture.emv_authorization, "Capture should contain emv_authorization containing the EMV TC" + assert capture.emv_authorization, 'Capture should contain emv_authorization containing the EMV TC' end def test_authorization_and_capture_with_emv_credit_card_in_us - @gateway = StripeGateway.new(fixtures(:stripe_emv_us)) assert authorization = @gateway.authorize(@amount, @emv_credit_cards[:us], @options) assert_success authorization - assert authorization.emv_authorization, "Authorization should contain emv_authorization containing the EMV ARPC" - refute authorization.params["captured"] + assert authorization.emv_authorization, 'Authorization should contain emv_authorization containing the EMV ARPC' + refute authorization.params['captured'] - assert capture = @gateway.capture(@amount, authorization.authorization) + assert capture = @gateway.capture(@amount, authorization.authorization, @capture_options) assert_success capture - assert capture.emv_authorization, "Capture should contain emv_authorization containing the EMV TC" + assert capture.emv_authorization, 'Capture should contain emv_authorization containing the EMV TC' end def test_authorization_and_capture_of_online_pin_with_emv_credit_card_in_us - @gateway = StripeGateway.new(fixtures(:stripe_emv_us)) emv_credit_card = @emv_credit_cards[:us] - emv_credit_card.encrypted_pin_cryptogram = "8b68af72199529b8" - emv_credit_card.encrypted_pin_ksn = "ffff0102628d12000001" + emv_credit_card.encrypted_pin_cryptogram = '8b68af72199529b8' + emv_credit_card.encrypted_pin_ksn = 'ffff0102628d12000001' assert authorization = @gateway.authorize(@amount, emv_credit_card, @options) assert_success authorization - assert authorization.emv_authorization, "Authorization should contain emv_authorization containing the EMV ARPC" - refute authorization.params["captured"] + assert authorization.emv_authorization, 'Authorization should contain emv_authorization containing the EMV ARPC' + refute authorization.params['captured'] - assert capture = @gateway.capture(@amount, authorization.authorization) + assert capture = @gateway.capture(@amount, authorization.authorization, @capture_options) assert_success capture - assert capture.emv_authorization, "Capture should contain emv_authorization containing the EMV TC" - end - - def test_authorization_and_capture_with_emv_contactless_credit_card - @gateway = StripeGateway.new(fixtures(:stripe_emv_us)) - emv_credit_card = @emv_credit_cards[:contactless] - emv_credit_card.contactless = true - assert authorization = @gateway.authorize(@amount, emv_credit_card, @options) - assert_success authorization - assert authorization.emv_authorization, "Authorization should contain emv_authorization containing the EMV ARPC" - refute authorization.params["captured"] - - assert capture = @gateway.capture(@amount, authorization.authorization) - assert_success capture - assert capture.emv_authorization, "Capture should contain emv_authorization containing the EMV TC" + assert capture.emv_authorization, 'Capture should contain emv_authorization containing the EMV TC' end def test_authorization_and_void_with_emv_credit_card_in_us - @gateway = StripeGateway.new(fixtures(:stripe_emv_us)) assert authorization = @gateway.authorize(@amount, @emv_credit_cards[:us], @options) assert_success authorization - assert authorization.emv_authorization, "Authorization should contain emv_authorization containing the EMV ARPC" - refute authorization.params["captured"] + assert authorization.emv_authorization, 'Authorization should contain emv_authorization containing the EMV ARPC' + refute authorization.params['captured'] assert void = @gateway.void(authorization.authorization) assert_success void end def test_authorization_and_void_with_emv_credit_card_in_uk - @gateway = StripeGateway.new(fixtures(:stripe_emv_uk)) assert authorization = @gateway.authorize(@amount, @emv_credit_cards[:uk], @options) assert_success authorization - assert authorization.emv_authorization, "Authorization should contain emv_authorization containing the EMV ARPC" - refute authorization.params["captured"] + assert authorization.emv_authorization, 'Authorization should contain emv_authorization containing the EMV ARPC' + refute authorization.params['captured'] assert void = @gateway.void(authorization.authorization) assert_success void end - def test_authorization_and_void_with_emv_contactless_credit_card - @gateway = StripeGateway.new(fixtures(:stripe_emv_us)) + def test_purchase_and_void_with_emv_contactless_credit_card emv_credit_card = @emv_credit_cards[:contactless] - emv_credit_card.contactless = true - assert authorization = @gateway.authorize(@amount, emv_credit_card, @options) - assert_success authorization - assert authorization.emv_authorization, "Authorization should contain emv_authorization containing the EMV ARPC" - refute authorization.params["captured"] - - assert void = @gateway.void(authorization.authorization) + emv_credit_card.read_method = 'contactless' + assert purchase = @gateway.purchase(@amount, emv_credit_card, @options) + assert_success purchase + assert purchase.emv_authorization, 'Authorization should contain emv_authorization containing the EMV ARPC' + assert purchase.params['captured'] + assert purchase.params['paid'] + + assert void = @gateway.void(purchase.authorization) assert_success void end def test_authorization_emv_credit_card_in_us_with_metadata - @gateway = StripeGateway.new(fixtures(:stripe_emv_us)) - assert authorization = @gateway.authorize(@amount, @emv_credit_cards[:us], @options.merge({:metadata => {:this_is_a_random_key_name => 'with a random value', :i_made_up_this_key_too => 'canyoutell'}, :order_id => "42", :email => "foo@wonderfullyfakedomain.com"})) + assert authorization = @gateway.authorize(@amount, @emv_credit_cards[:us], @options.merge({:metadata => {:this_is_a_random_key_name => 'with a random value', :i_made_up_this_key_too => 'canyoutell'}, :order_id => '42', :email => 'foo@wonderfullyfakedomain.com'})) assert_success authorization end end diff --git a/test/remote/gateways/remote_stripe_test.rb b/test/remote/gateways/remote_stripe_test.rb index 854f0672a83..04a5b144138 100644 --- a/test/remote/gateways/remote_stripe_test.rb +++ b/test/remote/gateways/remote_stripe_test.rb @@ -11,14 +11,14 @@ def setup @debit_card = credit_card('4000056655665556') @check = check({ - bank_name: "STRIPE TEST BANK", - account_number: "000123456789", - routing_number: "110000000", + bank_name: 'STRIPE TEST BANK', + account_number: '000123456789', + routing_number: '110000000', }) @verified_bank_account = fixtures(:stripe_verified_bank_account) @options = { - :currency => "USD", + :currency => 'USD', :description => 'ActiveMerchant Test Purchase', :email => 'wow@example.com' } @@ -38,32 +38,88 @@ def test_transcript_scrubbing def test_successful_purchase assert response = @gateway.purchase(@amount, @credit_card, @options) assert_success response - assert_equal "charge", response.params["object"] - assert_equal response.authorization, response.params["id"] - assert response.params["paid"] - assert_equal "ActiveMerchant Test Purchase", response.params["description"] - assert_equal "wow@example.com", response.params["metadata"]["email"] + assert_equal 'charge', response.params['object'] + assert_equal response.authorization, response.params['id'] + assert response.params['paid'] + assert_equal 'ActiveMerchant Test Purchase', response.params['description'] + assert_equal 'wow@example.com', response.params['metadata']['email'] end def test_successful_purchase_with_blank_referer - options = @options.merge({referrer: ""}) + options = @options.merge({referrer: ''}) assert response = @gateway.purchase(@amount, @credit_card, options) assert_success response - assert_equal "charge", response.params["object"] - assert_equal response.authorization, response.params["id"] - assert response.params["paid"] - assert_equal "ActiveMerchant Test Purchase", response.params["description"] - assert_equal "wow@example.com", response.params["metadata"]["email"] + assert_equal 'charge', response.params['object'] + assert_equal response.authorization, response.params['id'] + assert response.params['paid'] + assert_equal 'ActiveMerchant Test Purchase', response.params['description'] + assert_equal 'wow@example.com', response.params['metadata']['email'] end def test_successful_purchase_with_recurring_flag custom_options = @options.merge(:eci => 'recurring') assert response = @gateway.purchase(@amount, @credit_card, custom_options) assert_success response - assert_equal "charge", response.params["object"] - assert response.params["paid"] - assert_equal "ActiveMerchant Test Purchase", response.params["description"] - assert_equal "wow@example.com", response.params["metadata"]["email"] + assert_equal 'charge', response.params['object'] + assert response.params['paid'] + assert_equal 'ActiveMerchant Test Purchase', response.params['description'] + assert_equal 'wow@example.com', response.params['metadata']['email'] + end + + def test_successful_purchase_with_destination + destination = fixtures(:stripe_destination)[:stripe_user_id] + custom_options = @options.merge(:destination => destination) + assert response = @gateway.purchase(@amount, @credit_card, custom_options) + assert_success response + assert_equal 'charge', response.params['object'] + assert_equal destination, response.params['destination'] + assert response.params['paid'] + assert_equal 'ActiveMerchant Test Purchase', response.params['description'] + assert_equal 'wow@example.com', response.params['metadata']['email'] + end + + def test_successful_purchase_with_destination_and_amount + destination = fixtures(:stripe_destination)[:stripe_user_id] + custom_options = @options.merge(:destination => destination, :destination_amount => @amount - 20) + assert response = @gateway.purchase(@amount, @credit_card, custom_options) + assert_success response + assert_equal 'charge', response.params['object'] + assert_equal destination, response.params['destination'] + assert response.params['paid'] + assert_equal 'ActiveMerchant Test Purchase', response.params['description'] + assert_equal 'wow@example.com', response.params['metadata']['email'] + end + + def test_successful_purchase_with_level3_data + @options[:merchant_reference] = 123 + @options[:customer_reference] = 456 + @options[:shipping_address_zip] = 98765 + @options[:shipping_from_zip] = 54321 + @options[:shipping_amount] = 10 + @options[:line_items] = [ + { + 'product_code' => 1234, + 'product_description' => 'An item', + 'unit_cost' => 15, + 'quantity' => 2, + 'tax_amount' => 0 + }, + { + 'product_code' => 999, + 'product_description' => 'A totes different item', + 'tax_amount' => 10, + 'unit_cost' => 50, + 'quantity' => 1, + } + ] + + assert response = @gateway.purchase(@amount, @credit_card, @options) + assert_success response + assert_equal 'charge', response.params['object'] + assert_equal response.authorization, response.params['id'] + assert response.params['paid'] + assert_equal 'ActiveMerchant Test Purchase', response.params['description'] + assert_equal 'wow@example.com', response.params['metadata']['email'] end def test_unsuccessful_purchase @@ -71,7 +127,15 @@ def test_unsuccessful_purchase assert_failure response assert_match %r{Your card was declined}, response.message assert_match Gateway::STANDARD_ERROR_CODE[:card_declined], response.error_code - assert_match /ch_[a-zA-Z\d]+/, response.authorization + assert_match(/ch_[a-zA-Z\d]+/, response.authorization) + end + + def test_unsuccessful_purchase_with_destination_and_amount + destination = fixtures(:stripe_destination)[:stripe_user_id] + custom_options = @options.merge(:destination => destination, :destination_amount => @amount + 20) + assert response = @gateway.purchase(@amount, @credit_card, custom_options) + assert_failure response + assert_match %r{must be less than or equal to the charge amount}, response.message end def test_successful_echeck_purchase_with_verified_account @@ -83,21 +147,51 @@ def test_successful_echeck_purchase_with_verified_account response = @gateway.purchase(@amount, payment, @options) assert_success response assert response.test? - assert_equal "Transaction approved", response.message + assert_equal 'Transaction approved', response.message end def test_unsuccessful_direct_bank_account_purchase response = @gateway.purchase(@amount, @check, @options) assert_failure response - assert_equal "Direct bank account transactions are not supported. Bank accounts must be stored and verified before use.", response.message + assert_equal 'Direct bank account transactions are not supported. Bank accounts must be stored and verified before use.', response.message end def test_authorization_and_capture assert authorization = @gateway.authorize(@amount, @credit_card, @options) assert_success authorization - refute authorization.params["captured"] - assert_equal "ActiveMerchant Test Purchase", authorization.params["description"] - assert_equal "wow@example.com", authorization.params["metadata"]["email"] + refute authorization.params['captured'] + assert_equal 'ActiveMerchant Test Purchase', authorization.params['description'] + assert_equal 'wow@example.com', authorization.params['metadata']['email'] + + assert capture = @gateway.capture(@amount, authorization.authorization) + assert_success capture + end + + def test_authorization_and_capture_with_destination + destination = fixtures(:stripe_destination)[:stripe_user_id] + custom_options = @options.merge(:destination => destination) + + assert authorization = @gateway.authorize(@amount, @credit_card, custom_options) + assert_success authorization + refute authorization.params['captured'] + assert_equal destination, authorization.params['destination'] + assert_equal 'ActiveMerchant Test Purchase', authorization.params['description'] + assert_equal 'wow@example.com', authorization.params['metadata']['email'] + + assert capture = @gateway.capture(@amount, authorization.authorization) + assert_success capture + end + + def test_authorization_and_capture_with_destination_and_amount + destination = fixtures(:stripe_destination)[:stripe_user_id] + custom_options = @options.merge(:destination => destination, :destination_amount => @amount - 20) + + assert authorization = @gateway.authorize(@amount, @credit_card, custom_options) + assert_success authorization + refute authorization.params['captured'] + assert_equal destination, authorization.params['destination'] + assert_equal 'ActiveMerchant Test Purchase', authorization.params['description'] + assert_equal 'wow@example.com', authorization.params['metadata']['email'] assert capture = @gateway.capture(@amount, authorization.authorization) assert_success capture @@ -106,7 +200,7 @@ def test_authorization_and_capture def test_authorization_and_void assert authorization = @gateway.authorize(@amount, @credit_card, @options) assert_success authorization - refute authorization.params["captured"] + refute authorization.params['captured'] assert void = @gateway.void(authorization.authorization) assert_success void @@ -129,11 +223,22 @@ def test_successful_void_with_metadata assert void = @gateway.void(response.authorization, metadata: { test_metadata: 123 }) assert void.test? assert_success void - assert_equal "123", void.params["metadata"]["test_metadata"] + assert_equal '123', void.params['metadata']['test_metadata'] + end + + def test_successful_void_with_reason + assert response = @gateway.authorize(@amount, @credit_card, @options) + assert_success response + assert response.authorization + + assert void = @gateway.void(response.authorization, reason: 'fraudulent') + assert void.test? + assert_success void + assert_equal 'fraudulent', void.params['reason'] end def test_unsuccessful_void - assert void = @gateway.void("active_merchant_fake_charge") + assert void = @gateway.void('active_merchant_fake_charge') assert_failure void assert_match %r{active_merchant_fake_charge}, void.message end @@ -144,11 +249,24 @@ def test_successful_refund assert response.authorization assert refund = @gateway.refund(@amount - 20, response.authorization) assert refund.test? - refund_id = refund.params["id"] + refund_id = refund.params['id'] assert_equal refund.authorization, refund_id assert_success refund end + def test_successful_refund_with_reason + assert response = @gateway.purchase(@amount, @credit_card, @options) + assert_success response + assert response.authorization + + assert refund = @gateway.refund(@amount - 20, response.authorization, reason: 'fraudulent') + assert refund.test? + refund_id = refund.params['id'] + assert_equal refund.authorization, refund_id + assert_success refund + assert_equal 'fraudulent', refund.params['reason'] + end + def test_successful_refund_on_verified_bank_account customer_id = @verified_bank_account[:customer_id] bank_account_id = @verified_bank_account[:bank_account_id] @@ -160,7 +278,7 @@ def test_successful_refund_on_verified_bank_account refund = @gateway.refund(@amount, purchase.authorization) assert_success refund assert refund.test? - refund_id = refund.params["id"] + refund_id = refund.params['id'] assert_equal refund.authorization, refund_id end @@ -171,11 +289,11 @@ def test_refund_with_reverse_transfer assert refund = @gateway.refund(@amount - 20, response.authorization, reverse_transfer: true) assert_success refund - assert_equal "Transaction approved", refund.message + assert_equal 'Transaction approved', refund.message end def test_unsuccessful_refund - assert refund = @gateway.refund(@amount, "active_merchant_fake_charge") + assert refund = @gateway.refund(@amount, 'active_merchant_fake_charge') assert_failure refund assert_match %r{active_merchant_fake_charge}, refund.message end @@ -184,95 +302,95 @@ def test_successful_verify assert response = @gateway.verify(@credit_card, @options) assert_success response - assert_equal "Transaction approved", response.message - assert_equal "wow@example.com", response.params["metadata"]["email"] - assert_equal "charge", response.params["object"] - assert_success response.responses.last, "The void should succeed" - assert_equal "refund", response.responses.last.params["object"] + assert_equal 'Transaction approved', response.message + assert_equal 'wow@example.com', response.params['metadata']['email'] + assert_equal 'charge', response.params['object'] + assert_success response.responses.last, 'The void should succeed' + assert_equal 'refund', response.responses.last.params['object'] end def test_successful_verify_cad - assert response = @gateway.verify(@credit_card, @options.merge(currency: "cad")) + assert response = @gateway.verify(@credit_card, @options.merge(currency: 'cad')) assert_success response - assert_equal 100, response.params["amount"] - assert_equal "cad", response.params["currency"] + assert_equal 100, response.params['amount'] + assert_equal 'cad', response.params['currency'] end def test_successful_verify_gbp - assert response = @gateway.verify(@credit_card, @options.merge(currency: "gbp")) + assert response = @gateway.verify(@credit_card, @options.merge(currency: 'gbp')) assert_success response - assert_equal 60, response.params["amount"] - assert_equal "gbp", response.params["currency"] + assert_equal 60, response.params['amount'] + assert_equal 'gbp', response.params['currency'] end def test_successful_verify_eur - assert response = @gateway.verify(@credit_card, @options.merge(currency: "eur")) + assert response = @gateway.verify(@credit_card, @options.merge(currency: 'eur')) assert_success response - assert_equal 100, response.params["amount"] - assert_equal "eur", response.params["currency"] + assert_equal 100, response.params['amount'] + assert_equal 'eur', response.params['currency'] end def test_successful_verify_dkk - assert response = @gateway.verify(@credit_card, @options.merge(currency: "dkk")) + assert response = @gateway.verify(@credit_card, @options.merge(currency: 'dkk')) assert_success response - assert_equal 500, response.params["amount"] - assert_equal "dkk", response.params["currency"] + assert_equal 500, response.params['amount'] + assert_equal 'dkk', response.params['currency'] end def test_successful_verify_nok - assert response = @gateway.verify(@credit_card, @options.merge(currency: "nok")) + assert response = @gateway.verify(@credit_card, @options.merge(currency: 'nok')) assert_success response - assert_equal 600, response.params["amount"] - assert_equal "nok", response.params["currency"] + assert_equal 600, response.params['amount'] + assert_equal 'nok', response.params['currency'] end def test_successful_verify_sek - assert response = @gateway.verify(@credit_card, @options.merge(currency: "sek")) + assert response = @gateway.verify(@credit_card, @options.merge(currency: 'sek')) assert_success response - assert_equal 600, response.params["amount"] - assert_equal "sek", response.params["currency"] + assert_equal 600, response.params['amount'] + assert_equal 'sek', response.params['currency'] end def test_successful_verify_chf - assert response = @gateway.verify(@credit_card, @options.merge(currency: "chf")) + assert response = @gateway.verify(@credit_card, @options.merge(currency: 'chf')) assert_success response - assert_equal 100, response.params["amount"] - assert_equal "chf", response.params["currency"] + assert_equal 100, response.params['amount'] + assert_equal 'chf', response.params['currency'] end def test_successful_verify_aud - assert response = @gateway.verify(@credit_card, @options.merge(currency: "aud")) + assert response = @gateway.verify(@credit_card, @options.merge(currency: 'aud')) assert_success response - assert_equal 100, response.params["amount"] - assert_equal "aud", response.params["currency"] + assert_equal 100, response.params['amount'] + assert_equal 'aud', response.params['currency'] end def test_successful_verify_jpy - assert response = @gateway.verify(@credit_card, @options.merge(currency: "jpy")) + assert response = @gateway.verify(@credit_card, @options.merge(currency: 'jpy')) assert_success response - assert_equal 100, response.params["amount"] - assert_equal "jpy", response.params["currency"] + assert_equal 100, response.params['amount'] + assert_equal 'jpy', response.params['currency'] end def test_successful_verify_mxn - assert response = @gateway.verify(@credit_card, @options.merge(currency: "mxn")) + assert response = @gateway.verify(@credit_card, @options.merge(currency: 'mxn')) assert_success response - assert_equal 2000, response.params["amount"] - assert_equal "mxn", response.params["currency"] + assert_equal 2000, response.params['amount'] + assert_equal 'mxn', response.params['currency'] end def test_successful_verify_sgd - assert response = @gateway.verify(@credit_card, @options.merge(currency: "sgd")) + assert response = @gateway.verify(@credit_card, @options.merge(currency: 'sgd')) assert_success response - assert_equal 100, response.params["amount"] - assert_equal "sgd", response.params["currency"] + assert_equal 100, response.params['amount'] + assert_equal 'sgd', response.params['currency'] end def test_successful_verify_hkd - assert response = @gateway.verify(@credit_card, @options.merge(currency: "hkd")) + assert response = @gateway.verify(@credit_card, @options.merge(currency: 'hkd')) assert_success response - assert_equal 800, response.params["amount"] - assert_equal "hkd", response.params["currency"] + assert_equal 800, response.params['amount'] + assert_equal 'hkd', response.params['currency'] end def test_unsuccessful_verify @@ -282,39 +400,39 @@ def test_unsuccessful_verify end def test_successful_store - assert response = @gateway.store(@credit_card, description: "TheDescription", email: "email@example.com") + assert response = @gateway.store(@credit_card, description: 'TheDescription', email: 'email@example.com') assert_success response - assert_equal "customer", response.params["object"] - assert_equal "TheDescription", response.params["description"] - assert_equal "email@example.com", response.params["email"] - first_card = response.params["sources"]["data"].first - assert_equal response.params["default_source"], first_card["id"] - assert_equal @credit_card.last_digits, first_card["last4"] + assert_equal 'customer', response.params['object'] + assert_equal 'TheDescription', response.params['description'] + assert_equal 'email@example.com', response.params['email'] + first_card = response.params['sources']['data'].first + assert_equal response.params['default_source'], first_card['id'] + assert_equal @credit_card.last_digits, first_card['last4'] end def test_successful_store_with_validate_false assert response = @gateway.store(@credit_card, validate: false) assert_success response - assert_equal "customer", response.params["object"] + assert_equal 'customer', response.params['object'] end def test_successful_store_with_existing_customer assert response = @gateway.store(@credit_card) assert_success response - assert response = @gateway.store(@new_credit_card, customer: response.params['id'], email: "email@example.com", description: "TheDesc") + assert response = @gateway.store(@new_credit_card, customer: response.params['id'], email: 'email@example.com', description: 'TheDesc') assert_success response assert_equal 2, response.responses.size card_response = response.responses[0] - assert_equal "card", card_response.params["object"] - assert_equal @new_credit_card.last_digits, card_response.params["last4"] + assert_equal 'card', card_response.params['object'] + assert_equal @new_credit_card.last_digits, card_response.params['last4'] customer_response = response.responses[1] - assert_equal "customer", customer_response.params["object"] - assert_equal "TheDesc", customer_response.params["description"] - assert_equal "email@example.com", customer_response.params["email"] - assert_equal 2, customer_response.params["sources"]["total_count"] + assert_equal 'customer', customer_response.params['object'] + assert_equal 'TheDesc', customer_response.params['description'] + assert_equal 'email@example.com', customer_response.params['email'] + assert_equal 2, customer_response.params['sources']['total_count'] end def test_successful_store_with_existing_account @@ -322,7 +440,7 @@ def test_successful_store_with_existing_account assert response = @gateway.store(@debit_card, account: account) assert_success response - assert_equal "card", response.params["object"] + assert_equal 'card', response.params['object'] end def test_successful_purchase_using_stored_card @@ -331,10 +449,10 @@ def test_successful_purchase_using_stored_card assert response = @gateway.purchase(@amount, store.authorization) assert_success response - assert_equal "Transaction approved", response.message + assert_equal 'Transaction approved', response.message - assert response.params["paid"] - assert_equal "4242", response.params["source"]["last4"] + assert response.params['paid'] + assert_equal '4242', response.params['source']['last4'] end def test_successful_purchase_using_stored_card_on_existing_customer @@ -346,36 +464,36 @@ def test_successful_purchase_using_stored_card_on_existing_customer assert response = @gateway.purchase(@amount, second_store_response.authorization) assert_success response - assert_equal "5100", response.params["source"]["last4"] + assert_equal '5100', response.params['source']['last4'] end def test_successful_purchase_using_stored_card_and_deprecated_api assert store = @gateway.store(@credit_card) assert_success store - recharge_options = @options.merge(:customer => store.params["id"]) + recharge_options = @options.merge(:customer => store.params['id']) assert_deprecation_warning do response = @gateway.purchase(@amount, nil, recharge_options) assert_success response - assert_equal "4242", response.params["source"]["last4"] + assert_equal '4242', response.params['source']['last4'] end end def test_successful_unstore - creation = @gateway.store(@credit_card, {:description => "Active Merchant Unstore Customer"}) + creation = @gateway.store(@credit_card, {:description => 'Active Merchant Unstore Customer'}) card_id = creation.params['sources']['data'].first['id'] assert response = @gateway.unstore(creation.authorization) assert_success response assert_equal card_id, response.params['id'] assert_equal true, response.params['deleted'] - assert_equal "Transaction approved", response.message + assert_equal 'Transaction approved', response.message end def test_successful_unstore_using_deprecated_api - creation = @gateway.store(@credit_card, {:description => "Active Merchant Unstore Customer"}) + creation = @gateway.store(@credit_card, {:description => 'Active Merchant Unstore Customer'}) card_id = creation.params['sources']['data'].first['id'] - customer_id = creation.params["id"] + customer_id = creation.params['id'] assert_deprecation_warning do response = @gateway.unstore(customer_id, card_id) @@ -388,8 +506,8 @@ def test_successful_store_of_bank_account response = @gateway.store(@check, @options) assert_success response customer_id, bank_account_id = response.authorization.split('|') - assert_match /^cus_/, customer_id - assert_match /^ba_/, bank_account_id + assert_match(/^cus_/, customer_id) + assert_match(/^ba_/, bank_account_id) end def test_unsuccessful_purchase_from_stored_but_unverified_bank_account @@ -410,7 +528,7 @@ def test_successful_purchase_from_stored_and_verified_bank_account customer_id, bank_account_id = store.authorization.split('|') verify_url = "customers/#{customer_id}/sources/#{bank_account_id}/verify" verify_response = @gateway.send(:api_request, :post, verify_url, { amounts: [32, 45] }) - assert_match "verified", verify_response["status"] + assert_match 'verified', verify_response['status'] purchase = @gateway.purchase(@amount, store.authorization, @options) assert_success purchase @@ -420,22 +538,24 @@ def test_invalid_login gateway = StripeGateway.new(:login => 'active_merchant_test') assert response = gateway.purchase(@amount, @credit_card, @options) assert_failure response - assert_match "Invalid API Key provided", response.message + assert_match 'Invalid API Key provided', response.message end + # These "track data present" tests fail with invalid expiration dates. The + # test track data probably needs to be updated. def test_card_present_purchase - @credit_card.track_data = '%B378282246310005^LONGSON/LONGBOB^1705101130504392?' + @credit_card.track_data = '%B378282246310005^LONGSON/LONGBOB^2205101130504392?' assert response = @gateway.purchase(@amount, @credit_card, @options) assert_success response - assert_equal "charge", response.params["object"] - assert response.params["paid"] + assert_equal 'charge', response.params['object'] + assert response.params['paid'] end def test_card_present_authorize_and_capture - @credit_card.track_data = '%B378282246310005^LONGSON/LONGBOB^1705101130504392?' + @credit_card.track_data = '%B378282246310005^LONGSON/LONGBOB^2205101130504392?' assert authorization = @gateway.authorize(@amount, @credit_card, @options) assert_success authorization - refute authorization.params["captured"] + refute authorization.params['captured'] assert capture = @gateway.capture(@amount, authorization.authorization) assert_success capture @@ -444,8 +564,8 @@ def test_card_present_authorize_and_capture def test_creditcard_purchase_with_customer assert response = @gateway.purchase(@amount, @credit_card, @options.merge(:customer => '1234')) assert_success response - assert_equal "charge", response.params["object"] - assert response.params["paid"] + assert_equal 'charge', response.params['object'] + assert response.params['paid'] end def test_expanding_objects @@ -456,19 +576,19 @@ def test_expanding_objects end def test_successful_update - creation = @gateway.store(@credit_card, {:description => "Active Merchant Update Credit Card"}) + creation = @gateway.store(@credit_card, {:description => 'Active Merchant Update Credit Card'}) customer_id = creation.params['id'] card_id = creation.params['sources']['data'].first['id'] - assert response = @gateway.update(customer_id, card_id, { :name => "John Doe", :address_line1 => "123 Main Street", :address_city => "Pleasantville", :address_state => "NY", :address_zip => "12345", :exp_year => Time.now.year + 2, :exp_month => 6 }) + assert response = @gateway.update(customer_id, card_id, { :name => 'John Doe', :address_line1 => '123 Main Street', :address_city => 'Pleasantville', :address_state => 'NY', :address_zip => '12345', :exp_year => Time.now.year + 2, :exp_month => 6 }) assert_success response - assert_equal "John Doe", response.params["name"] - assert_equal "123 Main Street", response.params["address_line1"] - assert_equal "Pleasantville", response.params["address_city"] - assert_equal "NY", response.params["address_state"] - assert_equal "12345", response.params["address_zip"] - assert_equal Time.now.year + 2, response.params["exp_year"] - assert_equal 6, response.params["exp_month"] + assert_equal 'John Doe', response.params['name'] + assert_equal '123 Main Street', response.params['address_line1'] + assert_equal 'Pleasantville', response.params['address_city'] + assert_equal 'NY', response.params['address_state'] + assert_equal '12345', response.params['address_zip'] + assert_equal Time.now.year + 2, response.params['exp_year'] + assert_equal 6, response.params['exp_month'] end def test_incorrect_number_for_purchase @@ -528,9 +648,9 @@ def test_processing_error end def test_statement_description - assert response = @gateway.purchase(@amount, @credit_card, statement_description: "Eggcellent Description") + assert response = @gateway.purchase(@amount, @credit_card, statement_description: 'Eggcellent Description') assert_success response - assert_equal "Eggcellent Description", response.params["statement_descriptor"] + assert_equal 'Eggcellent Description', response.params['statement_descriptor'] end def test_stripe_account_header diff --git a/test/remote/gateways/remote_telr_test.rb b/test/remote/gateways/remote_telr_test.rb index 4ce3d2871e8..bf0477ac36f 100644 --- a/test/remote/gateways/remote_telr_test.rb +++ b/test/remote/gateways/remote_telr_test.rb @@ -1,45 +1,45 @@ -require "test_helper" +require 'test_helper' class RemoteTelrTest < Test::Unit::TestCase def setup @gateway = TelrGateway.new(fixtures(:telr)) @amount = 100 - @credit_card = credit_card("5105105105105100") - @declined_card = credit_card("5105105105105100", verification_value: "031") + @credit_card = credit_card('5105105105105100') + @declined_card = credit_card('5105105105105100', verification_value: '031') @options = { order_id: generate_unique_id, billing_address: address, - description: "Test transaction", - email: "email@address.com" + description: 'Test transaction', + email: 'email@address.com' } end def test_invalid_login - gateway = TelrGateway.new(merchant_id: "", api_key: "") + gateway = TelrGateway.new(merchant_id: '', api_key: '') response = gateway.purchase(@amount, @credit_card, @options) assert_failure response - assert_equal "Invalid request", response.message + assert_equal 'Invalid request', response.message end def test_successful_purchase response = @gateway.purchase(@amount, @credit_card, @options) assert_success response - assert_equal "Succeeded", response.message + assert_equal 'Succeeded', response.message end def test_successful_purchase_sans_options response = @gateway.purchase(@amount, @credit_card) assert_success response - assert_equal "Succeeded", response.message + assert_equal 'Succeeded', response.message end def test_failed_purchase response = @gateway.purchase(@amount, @declined_card, @options) assert_failure response - assert_equal "Not authorised", response.message - assert_equal "31", response.error_code + assert_equal 'Not authorised', response.message + assert_equal '31', response.error_code end def test_successful_reference_purchase @@ -62,14 +62,14 @@ def test_successful_authorize_and_capture def test_failed_authorize response = @gateway.authorize(@amount, @declined_card, @options) assert_failure response - assert_equal "Not authorised", response.message + assert_equal 'Not authorised', response.message end def test_failed_capture - response = @gateway.capture(@amount, "") + response = @gateway.capture(@amount, '') assert_failure response - assert_equal "Invalid transaction reference", response.message - assert_equal "22", response.error_code + assert_equal 'Invalid transaction reference', response.message + assert_equal '22', response.error_code end def test_successful_void @@ -77,14 +77,14 @@ def test_successful_void assert_success response void = @gateway.void(response.authorization) assert_success void - assert_equal "Succeeded", void.message + assert_equal 'Succeeded', void.message end def test_failed_void - response = @gateway.void("") + response = @gateway.void('') assert_failure response - assert_equal "Transaction cost or currency not valid", response.message - assert_equal "05", response.error_code + assert_equal 'Transaction cost or currency not valid', response.message + assert_equal '05', response.error_code end def test_successful_refund @@ -104,10 +104,10 @@ def test_partial_refund end def test_failed_refund - response = @gateway.refund(@amount, "0") + response = @gateway.refund(@amount, '0') assert_failure response - assert_equal "Invalid transaction reference", response.message - assert_equal "22", response.error_code + assert_equal 'Invalid transaction reference', response.message + assert_equal '22', response.error_code end def test_excess_refund @@ -116,8 +116,8 @@ def test_excess_refund refund = @gateway.refund(200, response.authorization) assert_failure refund - assert_equal "Amount greater than available balance", refund.message - assert_equal "29", refund.error_code + assert_equal 'Amount greater than available balance', refund.message + assert_equal '29', refund.error_code end def test_successful_verify @@ -129,8 +129,8 @@ def test_successful_verify def test_failed_verify response = @gateway.verify(@declined_card, @options) assert_failure response - assert_equal "Not authorised", response.message - assert_equal "31", response.error_code + assert_equal 'Not authorised', response.message + assert_equal '31', response.error_code end def test_verify_credentials @@ -145,13 +145,13 @@ def test_verify_credentials def test_cvv_result response = @gateway.purchase(@amount, @credit_card, @options) assert_success response - assert_equal "M", response.cvv_result["code"] + assert_equal 'M', response.cvv_result['code'] end def test_avs_result response = @gateway.purchase(@amount, @credit_card, @options) assert_success response - assert_equal "I", response.avs_result["code"] + assert_equal 'I', response.avs_result['code'] end def test_transcript_scrubbing diff --git a/test/remote/gateways/remote_tns_test.rb b/test/remote/gateways/remote_tns_test.rb index 6b2cd886060..d420d6f7335 100644 --- a/test/remote/gateways/remote_tns_test.rb +++ b/test/remote/gateways/remote_tns_test.rb @@ -25,55 +25,55 @@ def teardown def test_successful_purchase assert response = @gateway.purchase(@amount, @credit_card, @options) assert_success response - assert_equal "Succeeded", response.message + assert_equal 'Succeeded', response.message end def test_successful_purchase_sans_options assert response = @gateway.purchase(@amount, @credit_card) assert_success response - assert_equal "Succeeded", response.message + assert_equal 'Succeeded', response.message end def test_successful_purchase_with_more_options more_options = @options.merge({ - ip: "127.0.0.1", - email: "joe@example.com", + ip: '127.0.0.1', + email: 'joe@example.com', }) assert response = @gateway.purchase(@amount, @credit_card, @options.merge(more_options)) assert_success response - assert_equal "Succeeded", response.message + assert_equal 'Succeeded', response.message end def test_successful_purchase_with_region @gateway = TnsGateway.new(fixtures(:tns_ap).merge(region: 'asia_pacific')) - assert response = @gateway.purchase(@amount, @ap_credit_card, @options.merge(currency: "AUD")) + assert response = @gateway.purchase(@amount, @ap_credit_card, @options.merge(currency: 'AUD')) assert_success response - assert_equal "Succeeded", response.message + assert_equal 'Succeeded', response.message end def test_failed_purchase assert response = @gateway.purchase(@amount, @declined_card, @options) assert_failure response - assert_equal "FAILURE - DECLINED", response.message + assert_equal 'FAILURE - DECLINED', response.message end def test_successful_authorize_and_capture assert response = @gateway.authorize(@amount, @credit_card, @options) assert_success response - assert_equal "Succeeded", response.message + assert_equal 'Succeeded', response.message assert_match %r(^.+\|\d+$), response.authorization assert capture = @gateway.capture(@amount, response.authorization) assert_success capture - assert_equal "Succeeded", capture.message + assert_equal 'Succeeded', capture.message end def test_failed_authorize assert response = @gateway.authorize(@amount, @declined_card, @options) assert_failure response - assert_equal "FAILURE - DECLINED", response.message + assert_equal 'FAILURE - DECLINED', response.message end def test_successful_refund @@ -82,7 +82,7 @@ def test_successful_refund assert refund = @gateway.refund(@amount, response.authorization) assert_success refund - assert_equal "Succeeded", refund.message + assert_equal 'Succeeded', refund.message end def test_successful_void @@ -96,10 +96,10 @@ def test_successful_void def test_successful_verify assert response = @gateway.verify(@credit_card, @options) assert_success response - assert_equal "Succeeded", response.message + assert_equal 'Succeeded', response.message - assert_success response.responses.last, "The void should succeed" - assert_equal "SUCCESS", response.responses.last.params["result"] + assert_success response.responses.last, 'The void should succeed' + assert_equal 'SUCCESS', response.responses.last.params['result'] end def test_invalid_login @@ -109,11 +109,11 @@ def test_invalid_login ) response = gateway.authorize(@amount, @credit_card, @options) assert_failure response - assert_equal "ERROR - INVALID_REQUEST - Invalid credentials.", response.message + assert_equal 'ERROR - INVALID_REQUEST - Invalid credentials.', response.message end def test_transcript_scrubbing - card = credit_card("5123456789012346", verification_value: "834") + card = credit_card('5123456789012346', verification_value: '834') transcript = capture_transcript(@gateway) do @gateway.purchase(@amount, card, @options) end diff --git a/test/remote/gateways/remote_trans_first_test.rb b/test/remote/gateways/remote_trans_first_test.rb index 46e3946ef89..3423954560e 100644 --- a/test/remote/gateways/remote_trans_first_test.rb +++ b/test/remote/gateways/remote_trans_first_test.rb @@ -35,7 +35,7 @@ def test_successful_purchase_no_address end def test_successful_purchase_sans_cvv - @credit_card.verification_value = "" + @credit_card.verification_value = '' assert response = @gateway.purchase(@amount, @credit_card, @options) assert_success response end @@ -70,14 +70,33 @@ def test_failed_purchase assert_equal 'Insufficient funds', response.message end - def test_successful_refund + def test_successful_void assert purchase = @gateway.purchase(@amount, @credit_card, @options) assert_success purchase - assert refund = @gateway.refund(@amount, purchase.authorization) - assert_success refund + assert void = @gateway.void(purchase.authorization) + assert_success void end + # Refunds can only be successfully run on settled transactions which take 24 hours + # def test_successful_refund + # assert purchase = @gateway.purchase(@amount, @credit_card, @options) + # assert_success purchase + + # assert refund = @gateway.refund(@amount, purchase.authorization) + # assert_equal @amount, refund.params["amount"].to_i*100 + # assert_success refund + # end + + # def test_successful_partial_refund + # assert purchase = @gateway.purchase(@amount, @credit_card, @options) + # assert_success purchase + + # assert refund = @gateway.refund(@amount-1, purchase.authorization) + # assert_equal @amount-1, refund.params["amount"].to_i*100 + # assert_success refund + # end + def test_successful_refund_with_echeck assert purchase = @gateway.purchase(@amount, @check, @options) assert_success purchase diff --git a/test/remote/gateways/remote_trans_first_transaction_express_test.rb b/test/remote/gateways/remote_trans_first_transaction_express_test.rb index 4976e69ed25..32f0f08a199 100644 --- a/test/remote/gateways/remote_trans_first_transaction_express_test.rb +++ b/test/remote/gateways/remote_trans_first_transaction_express_test.rb @@ -1,36 +1,37 @@ -require "test_helper" +require 'test_helper' class RemoteTransFirstTransactionExpressTest < Test::Unit::TestCase + def setup @gateway = TransFirstTransactionExpressGateway.new(fixtures(:trans_first_transaction_express)) @amount = 100 @declined_amount = 21 - @partial_amount = 1110 - @credit_card = credit_card("4485896261017708") + @credit_card = credit_card('4485896261017708') + @check = check billing_address = address({ - address1: "450 Main", - address2: "Suite 100", - city: "Broomfield", - state: "CO", - zip: "85284", - phone: "(333) 444-5555", + address1: '450 Main', + address2: 'Suite 100', + city: 'Broomfield', + state: 'CO', + zip: '85284', + phone: '(333) 444-5555', }) @options = { order_id: generate_unique_id, - company_name: "Acme", - title: "QA Manager", + company_name: 'Acme', + title: 'QA Manager', billing_address: billing_address, shipping_address: billing_address, - email: "example@example.com", - description: "Store Purchase" + email: 'example@example.com', + description: 'Store Purchase' } end def test_invalid_login - gateway = TransFirstTransactionExpressGateway.new(gateway_id: "", reg_key: "") + gateway = TransFirstTransactionExpressGateway.new(gateway_id: '', reg_key: '') response = gateway.purchase(@amount, @credit_card, @options) assert_failure response end @@ -38,7 +39,41 @@ def test_invalid_login def test_successful_purchase response = @gateway.purchase(@amount, @credit_card, @options) assert_success response - assert_equal "Succeeded", response.message + assert_equal 'Succeeded', response.message + assert_not_nil response.avs_result + assert_not_nil response.cvv_result + assert_equal 'Street address does not match, but 5-digit postal code matches.', response.avs_result['message'] + assert_equal 'CVV matches', response.cvv_result['message'] + end + + def test_successful_purchase_no_avs + options = @options.dup + options[:shipping_address] = nil + options[:billing_address] = nil + response = @gateway.purchase(@amount, @credit_card, options) + assert_success response + end + + def test_successful_purchase_with_only_required + # Test the purchase with only the required billing and shipping information + options = @options.dup + options[:shipping_address] = { + address1: '450 Main', + zip: '85284', + } + + options[:billing_address] = { + address1: '450 Main', + zip: '85284', + } + + response = @gateway.purchase(@amount, @credit_card, options) + assert_success response + assert_equal 'Succeeded', response.message + assert_not_nil response.avs_result + assert_not_nil response.cvv_result + assert_equal 'Street address does not match, but 5-digit postal code matches.', response.avs_result['message'] + assert_equal 'CVV matches', response.cvv_result['message'] end def test_successful_purchase_without_cvv @@ -54,7 +89,7 @@ def test_successful_purchase_without_cvv credit_card = CreditCard.new(credit_card_opts) response = @gateway.purchase(@amount, credit_card, @options) assert_success response - assert_equal "Succeeded", response.message + assert_equal 'Succeeded', response.message end def test_successful_purchase_with_empty_string_cvv @@ -71,39 +106,44 @@ def test_successful_purchase_with_empty_string_cvv credit_card = CreditCard.new(credit_card_opts) response = @gateway.purchase(@amount, credit_card, @options) assert_success response - assert_equal "Succeeded", response.message + assert_equal 'Succeeded', response.message end - def test_partial_purchase - response = @gateway.purchase(@partial_amount, @credit_card, @options) + def test_successful_purchase_with_echeck + assert response = @gateway.purchase(@amount, @check, @options) assert_success response - assert_equal "Succeeded", response.message - assert_match /0*555$/, response.params["amt"] + assert_equal 'Succeeded', response.message end def test_failed_purchase response = @gateway.purchase(@declined_amount, @credit_card, @options) assert_failure response - assert_equal "Not sufficient funds", response.message - assert_equal "51", response.params["rspCode"] + assert_equal 'Not sufficient funds', response.message + assert_equal '51', response.params['rspCode'] + end + + def test_failed_purchase_with_echeck + assert response = @gateway.purchase(@amount, check(routing_number: '121042883'), @options) + assert_failure response + assert_equal 'Error. Bank routing number validation negative (ABA).', response.message end def test_successful_authorize_and_capture response = @gateway.authorize(@amount, @credit_card, @options) assert_success response - assert_equal "Succeeded", response.message + assert_equal 'Succeeded', response.message assert_match %r(^authorize\|\d+$), response.authorization capture = @gateway.capture(@amount, response.authorization) assert_success capture - assert_equal "Succeeded", capture.message + assert_equal 'Succeeded', capture.message end def test_failed_authorize response = @gateway.authorize(@declined_amount, @credit_card, @options) assert_failure response - assert_equal "Not sufficient funds", response.message - assert_equal "51", response.error_code + assert_equal 'Not sufficient funds', response.message + assert_equal '51', response.error_code end def test_failed_capture @@ -112,8 +152,8 @@ def test_failed_capture response = @gateway.capture(@amount, authorize.authorization) assert_failure response - assert_equal "Invalid transaction", response.message - assert_equal "12", response.error_code + assert_equal 'Invalid transaction', response.message + assert_equal '12', response.error_code end def test_successful_purchase_void @@ -122,7 +162,7 @@ def test_successful_purchase_void void = @gateway.void(response.authorization) assert_success void - assert_equal "Succeeded", void.message + assert_equal 'Succeeded', void.message end def test_successful_authorization_void @@ -131,7 +171,7 @@ def test_successful_authorization_void void = @gateway.void(authorize.authorization) assert_success void - assert_equal "Succeeded", void.message + assert_equal 'Succeeded', void.message end def test_successful_capture_void @@ -143,14 +183,23 @@ def test_successful_capture_void void = @gateway.void(capture.authorization, void_type: :void_capture) assert_success void - assert_equal "Succeeded", void.message + assert_equal 'Succeeded', void.message end def test_failed_void - response = @gateway.void("") + response = @gateway.void('purchase|000015212561') assert_failure response - assert_equal "Validation Failure", response.message - assert_equal "50011", response.error_code + assert_equal 'Invalid transaction', response.message + assert_equal '12', response.error_code + end + + def test_successful_echeck_purchase_void + response = @gateway.purchase(@amount, @check, @options) + assert_success response + + void = @gateway.void(response.authorization) + assert_success void + assert_equal 'Succeeded', void.message end # gateway does not settle fast enough to test refunds @@ -170,14 +219,29 @@ def test_helpful_message_when_refunding_unsettled_purchase refund = @gateway.refund(@amount, purchase.authorization) assert_failure refund - assert_equal "Invalid transaction. Declined Post – Credit linked to unextracted settle transaction", refund.message + assert_equal 'Invalid transaction. Declined Post – Credit linked to unextracted settle transaction', refund.message end def test_failed_refund - response = @gateway.refund(nil, "") + response = @gateway.refund(nil, '') assert_failure response - assert_equal "Validation Failure", response.message - assert_equal "50011", response.error_code + assert_equal 'Validation Failure', response.message + assert_equal '50011', response.error_code + end + + def test_successful_refund_with_echeck + purchase = @gateway.purchase(@amount, @check, @options) + assert_success purchase + assert_match(/purchase_echeck/, purchase.authorization) + + refund = @gateway.refund(@amount, purchase.authorization) + assert_success refund + end + + def test_failed_refund_with_echeck + refund = @gateway.refund(@amount, 'purchase_echeck|000028706091') + assert_failure refund + assert_equal 'Invalid transaction', refund.message end # Credit is only supported with specific approval from Transaction Express @@ -190,34 +254,34 @@ def test_failed_refund def test_failed_credit response = @gateway.credit(0, @credit_card, @options) assert_failure response - assert_equal "51334", response.error_code - assert_equal "Validation Error", response.message + assert_equal '51334', response.error_code + assert_equal 'Validation Error', response.message end def test_successful_verify - visa = credit_card("4485896261017708") - amex = credit_card("371449635392376", verification_value: 1234) - mastercard = credit_card("5499740000000057") - discover = credit_card("6011000991001201") + visa = credit_card('4485896261017708') + amex = credit_card('371449635392376', verification_value: 1234) + mastercard = credit_card('5499740000000057') + discover = credit_card('6011000991001201') [visa, amex, mastercard, discover].each do |credit_card| response = @gateway.verify(credit_card, @options) assert_success response - assert_match "Succeeded", response.message + assert_match 'Succeeded', response.message end end def test_failed_verify - response = @gateway.verify(credit_card(""), @options) + response = @gateway.verify(credit_card(''), @options) assert_failure response - assert_equal "Validation Failure", response.message - assert_equal "50011", response.error_code + assert_equal 'Validation Failure', response.message + assert_equal '51308', response.error_code end def test_successful_store response = @gateway.store(@credit_card, @options) assert_success response - assert_equal "Succeeded", response.message + assert_equal 'Succeeded', response.message assert response.authorization end @@ -227,7 +291,7 @@ def test_successful_authorize_using_stored_card response = @gateway.authorize(@amount, response.authorization, @options) assert_success response - assert_match "Succeeded", response.message + assert_match 'Succeeded', response.message end def test_failed_authorize_using_stored_card @@ -236,7 +300,7 @@ def test_failed_authorize_using_stored_card response = @gateway.authorize(@declined_amount, response.authorization, @options) assert_failure response - assert_match "Not sufficient funds", response.message + assert_match 'Not sufficient funds', response.message end def test_successful_purchase_using_stored_card @@ -245,7 +309,7 @@ def test_successful_purchase_using_stored_card response = @gateway.purchase(@amount, response.authorization, @options) assert_success response - assert_match "Succeeded", response.message + assert_match 'Succeeded', response.message end def test_failed_purchase_using_stored_card @@ -254,14 +318,14 @@ def test_failed_purchase_using_stored_card response = @gateway.purchase(@declined_amount, response.authorization, @options) assert_failure response - assert_match "Not sufficient funds", response.message + assert_match 'Not sufficient funds', response.message end def test_failed_store - response = @gateway.store(credit_card("123"), @options) + response = @gateway.store(credit_card('123'), @options) assert_failure response - assert_equal "Validation Failure", response.message - assert_equal "50011", response.error_code + assert_equal 'Validation Failure', response.message + assert_equal '51308', response.error_code end # def test_dump_transcript diff --git a/test/remote/gateways/remote_transact_pro_test.rb b/test/remote/gateways/remote_transact_pro_test.rb index b89f99b3ab8..5e5c428ae29 100644 --- a/test/remote/gateways/remote_transact_pro_test.rb +++ b/test/remote/gateways/remote_transact_pro_test.rb @@ -64,7 +64,7 @@ def test_partial_capture def test_failed_capture response = @gateway.capture(nil, 'bogus|100') assert_failure response - assert_equal "bogus|100", response.authorization + assert_equal 'bogus|100', response.authorization end def test_successful_refund diff --git a/test/remote/gateways/remote_transax_test.rb b/test/remote/gateways/remote_transax_test.rb index efd0339925d..1e7bbc00399 100644 --- a/test/remote/gateways/remote_transax_test.rb +++ b/test/remote/gateways/remote_transax_test.rb @@ -20,7 +20,7 @@ def setup def test_successful_purchase assert response = @gateway.purchase(@amount, @credit_card, @options) assert_success response - assert_equal "This transaction has been approved", response.message + assert_equal 'This transaction has been approved', response.message end def test_unsuccessful_purchase @@ -32,7 +32,7 @@ def test_unsuccessful_purchase def test_authorize_and_capture assert auth = @gateway.authorize(@amount, @credit_card, @options) assert_success auth - assert_equal "This transaction has been approved", auth.message + assert_equal 'This transaction has been approved', auth.message assert auth.authorization assert capture = @gateway.capture(@amount, auth.authorization) assert_success capture @@ -41,20 +41,20 @@ def test_authorize_and_capture def test_authorize_and_void assert auth = @gateway.authorize(@amount, @credit_card, @options) assert_success auth - assert_equal "This transaction has been approved", auth.message + assert_equal 'This transaction has been approved', auth.message assert auth.authorization assert void = @gateway.void(auth.authorization) - assert_equal "Transaction Void Successful", void.message + assert_equal 'Transaction Void Successful', void.message assert_success void end def test_purchase_and_refund assert response = @gateway.purchase(@amount, @credit_card, @options) assert_success response - assert_equal "This transaction has been approved", response.message + assert_equal 'This transaction has been approved', response.message assert response.authorization assert refund = @gateway.refund(nil, response.authorization) - assert_equal "This transaction has been approved", refund.message + assert_equal 'This transaction has been approved', refund.message assert_success refund end @@ -68,16 +68,16 @@ def test_credit assert response = @gateway.credit(@amount, @credit_card, @options) assert_success response assert response.authorization - assert_equal "This transaction has been approved", response.message + assert_equal 'This transaction has been approved', response.message end def test_purchase_and_update assert response = @gateway.purchase(@amount, @credit_card, @options) assert_success response - assert_equal "This transaction has been approved", response.message + assert_equal 'This transaction has been approved', response.message assert response.authorization assert update = @gateway.amend(response.authorization, :shipping_carrier => 'usps') - assert_equal "This transaction has been approved", update.message + assert_equal 'This transaction has been approved', update.message assert_success update end @@ -85,7 +85,7 @@ def test_successful_purchase_with_sku @options['product_sku_#']='123456' assert response = @gateway.purchase(@amount, @credit_card, @options) assert_success response - assert_equal "This transaction has been approved", response.message + assert_equal 'This transaction has been approved', response.message end def test_store_credit_card @@ -103,7 +103,7 @@ def test_store_check def test_successful_verify assert response = @gateway.verify(@credit_card, @options) assert_success response - assert_equal "This transaction has been approved", response.message + assert_equal 'This transaction has been approved', response.message end def test_failed_verify @@ -120,6 +120,6 @@ def test_invalid_login ) assert response = gateway.purchase(@amount, @credit_card, @options) assert_failure response - assert_equal "Invalid Username", response.message + assert_equal 'Invalid Username', response.message end end diff --git a/test/remote/gateways/remote_trexle_test.rb b/test/remote/gateways/remote_trexle_test.rb new file mode 100644 index 00000000000..149a8530797 --- /dev/null +++ b/test/remote/gateways/remote_trexle_test.rb @@ -0,0 +1,170 @@ +require 'test_helper' + +class RemoteTrexleTest < Test::Unit::TestCase + def setup + @gateway = TrexleGateway.new(fixtures(:trexle)) + + @amount = 100 + @credit_card = credit_card('5555555555554444', year: Time.now.year + 2) + @visa_credit_card = credit_card('4242424242424242', year: Time.now.year + 3) + @declined_card = credit_card('4000000000000119') + + @options = { + email: 'john@trexle.com', + ip: '66.249.79.118', + order_id: '1', + billing_address: address, + description: "ActiveMerchant Demo Purchase #{DateTime.now.to_i}" + } + end + + def test_successful_purchase + response = @gateway.purchase(@amount, @credit_card, @options) + assert_success response + assert_equal true, response.params['response']['captured'] + end + + def test_successful_authorize_and_capture + authorization = @gateway.authorize(@amount, @credit_card, @options) + assert_success authorization + assert_equal false, authorization.params['response']['captured'] + + response = @gateway.capture(@amount, authorization.authorization, @options) + assert_success response + assert_equal true, response.params['response']['captured'] + end + + def test_failed_authorize + response = @gateway.authorize(@amount, @declined_card, @options) + assert_failure response + end + + def test_failed_capture_due_to_invalid_token + response = @gateway.capture(@amount, 'bogus', @options) + assert_failure response + end + + def test_failed_capture_due_to_invalid_amount + authorization = @gateway.authorize(@amount, @credit_card, @options) + assert_success authorization + assert_equal authorization.params['response']['captured'], false + + response = @gateway.capture(@amount + 1, authorization.authorization, @options) + assert_failure response + assert_equal 'Payment failed', response.params['error'] + end + + def test_successful_purchase_without_description + @options.delete(:description) + response = @gateway.purchase(@amount, @credit_card, @options) + assert_success response + end + + def test_unsuccessful_purchase + response = @gateway.purchase(@amount, @declined_card, @options) + assert_failure response + end + + # This is a bit manual as we have to create a working card token as + # would be returned from trexle.js / the card tokens API which + # falls outside of active merchant + def test_store_and_charge_with_trexle_js_card_token + headers = { + 'Content-Type' => 'application/json', + 'Authorization' => "Basic #{Base64.strict_encode64(@gateway.options[:api_key] + ':').strip}" + } + # Get a token equivalent to what is returned by trexle.js + card_attrs = { + number: @credit_card.number, + expiry_month: @credit_card.month, + expiry_year: @credit_card.year, + cvc: @credit_card.verification_value, + name: "#{@credit_card.first_name} #{@credit_card.last_name}", + address_line1: '321 Shoreline Park', + address_line2: 'suite #7', + address_city: 'Mountain View', + address_postcode: '94043', + address_state: 'CA', + address_country: 'United States' + } + url = @gateway.test_url + '/tokens' + + body = JSON.parse(@gateway.ssl_post(url, card_attrs.to_json, headers)) + + card_token = body['response']['token'] + + store = @gateway.store(card_token, @options) + assert_success store + assert_not_nil store.authorization + + purchase = @gateway.purchase(@amount, card_token, @options) + assert_success purchase + assert_not_nil purchase.authorization + end + + def test_store_and_customer_token_charge + response = @gateway.store(@credit_card, @options) + assert_success response + assert_not_nil response.authorization + + token = response.params['response']['card']['token'] + + assert response1 = @gateway.purchase(@amount, token, @options) + assert_success response1 + + assert response2 = @gateway.purchase(@amount, token, @options) + assert_success response2 + assert_not_equal response1.authorization, response2.authorization + end + + def test_store_and_update + response = @gateway.store(@credit_card, @options) + assert_success response + assert_not_nil response.authorization + assert_equal @credit_card.year, response.params['response']['card']['expiry_year'] + + response = @gateway.update(response.authorization, @credit_card, address: address) + assert_success response + assert_not_nil response.authorization + assert_equal @credit_card.year, response.params['response']['card']['expiry_year'] + end + + def test_refund + response = @gateway.purchase(@amount, @credit_card, @options) + assert_success response + assert_not_nil response.authorization + + token = response.authorization + + response = @gateway.refund(@amount, token, @options) + assert_success response + assert_not_nil response.authorization + end + + def test_failed_refund + response = @gateway.purchase(@amount, @credit_card, @options) + assert_success response + assert_not_nil response.authorization + + token = response.authorization + + response = @gateway.refund(@amount, token.reverse, @options) + assert_failure response + end + + def test_invalid_login + gateway = TrexleGateway.new(api_key: '') + response = gateway.purchase(@amount, @credit_card, @options) + assert_failure response + end + + def test_transcript_scrubbing + transcript = capture_transcript(@gateway) do + @gateway.purchase(@amount, @credit_card, @options) + end + clean_transcript = @gateway.scrub(transcript) + + assert_scrubbed(@credit_card.number, clean_transcript) + assert_scrubbed(@credit_card.verification_value.to_s, clean_transcript) + end +end diff --git a/test/remote/gateways/remote_trust_commerce_test.rb b/test/remote/gateways/remote_trust_commerce_test.rb index 7131cbe1c17..196ffe26c7f 100644 --- a/test/remote/gateways/remote_trust_commerce_test.rb +++ b/test/remote/gateways/remote_trust_commerce_test.rb @@ -5,6 +5,7 @@ def setup @gateway = TrustCommerceGateway.new(fixtures(:trust_commerce)) @credit_card = credit_card('4111111111111111') + @check = check({account_number: 55544433221, routing_number: 789456124}) @amount = 100 @@ -41,9 +42,9 @@ def test_bad_login assert response = @gateway.purchase(@amount, @credit_card, @options) assert_equal Response, response.class - assert_equal ["error", - "offenders", - "status"], response.params.keys.sort + assert_equal ['error', + 'offenders', + 'status'], response.params.keys.sort assert_match %r{A field was improperly formatted, such as non-digit characters in a number field}, response.message @@ -59,6 +60,14 @@ def test_successful_purchase_with_avs assert !response.authorization.blank? end + def test_successful_purchase_with_check + assert response = @gateway.purchase(@amount, @check, @options) + assert_match %r{The transaction was successful}, response.message + + assert_success response + assert !response.authorization.blank? + end + def test_unsuccessful_purchase_with_invalid_cvv @credit_card.verification_value = @invalid_verification_value assert response = @gateway.purchase(@amount, @credit_card, @options) @@ -70,7 +79,7 @@ def test_unsuccessful_purchase_with_invalid_cvv def test_purchase_with_avs_for_invalid_address assert response = @gateway.purchase(@amount, @credit_card, @options.update(:billing_address => @invalid_address)) - assert_equal "N", response.params["avs"] + assert_equal 'N', response.params['avs'] assert_match %r{The transaction was successful}, response.message assert_success response end @@ -78,7 +87,7 @@ def test_purchase_with_avs_for_invalid_address def test_successful_authorize_with_avs assert response = @gateway.authorize(@amount, @credit_card, :billing_address => @valid_address) - assert_equal "Y", response.avs_result["code"] + assert_equal 'Y', response.avs_result['code'] assert_match %r{The transaction was successful}, response.message assert_success response @@ -94,7 +103,7 @@ def test_unsuccessful_authorize_with_invalid_cvv def test_authorization_with_avs_for_invalid_address assert response = @gateway.authorize(@amount, @credit_card, @options.update(:billing_address => @invalid_address)) - assert_equal "N", response.params["avs"] + assert_equal 'N', response.params['avs'] assert_match %r{The transaction was successful}, response.message assert_success response end @@ -128,6 +137,15 @@ def test_successful_credit assert_success response end + def test_successful_check_refund + purchase = @gateway.purchase(@amount, @check, @options) + + assert response = @gateway.refund(@amount, purchase.authorization) + + assert_match %r{The transaction was successful}, response.message + assert_success response + end + def test_store_failure assert response = @gateway.store(@credit_card) @@ -156,7 +174,7 @@ def test_transcript_scrubbing @gateway.purchase(@amount, @credit_card, @options) end clean_transcript = @gateway.scrub(transcript) - + assert_scrubbed(@credit_card.number, clean_transcript) assert_scrubbed(@credit_card.verification_value.to_s, clean_transcript) end diff --git a/test/remote/gateways/remote_usa_epay_advanced_test.rb b/test/remote/gateways/remote_usa_epay_advanced_test.rb index 6bac49c18e1..021f73d910a 100644 --- a/test/remote/gateways/remote_usa_epay_advanced_test.rb +++ b/test/remote/gateways/remote_usa_epay_advanced_test.rb @@ -13,8 +13,8 @@ def setup :year => Time.now.year + 1, :brand => 'visa', :verification_value => '123', - :first_name => "Fred", - :last_name => "Flintstone" + :first_name => 'Fred', + :last_name => 'Flintstone' ) @bad_credit_card = ActiveMerchant::Billing::CreditCard.new( @@ -23,21 +23,21 @@ def setup :year => 14, :brand => 'visa', :verification_value => '999', - :first_name => "Fred", - :last_name => "Flintstone" + :first_name => 'Fred', + :last_name => 'Flintstone' ) @check = ActiveMerchant::Billing::Check.new( :account_number => '123456789', :routing_number => '120450780', :account_type => 'checking', - :first_name => "Fred", - :last_name => "Flintstone" + :first_name => 'Fred', + :last_name => 'Flintstone' ) cc_method = [ - {:name => "My CC", :sort => 5, :method => @credit_card}, - {:name => "Other CC", :sort => 12, :method => @credit_card} + {:name => 'My CC', :sort => 5, :method => @credit_card}, + {:name => 'Other CC', :sort => 12, :method => @credit_card} ] @options = { @@ -52,20 +52,20 @@ def setup @customer_options = { :id => 123, - :notes => "Customer note.", - :data => "complex data", - :url => "somesite.com", + :notes => 'Customer note.', + :data => 'complex data', + :url => 'somesite.com', :payment_methods => cc_method } @update_customer_options = { - :notes => "NEW NOTE!" + :notes => 'NEW NOTE!' } @add_payment_options = { :make_default => true, :payment_method => { - :name => "My new card.", + :name => 'My new card.', :sort => 10, :method => @credit_card } @@ -92,18 +92,6 @@ def setup :payment_method => @check, :amount => 2500 } - - payment_methods = [ - { - :name => "My Visa", # optional - :sort => 2, # optional - :method => @credit_card - }, - { - :name => "My Checking", - :method => @check - } - ] end # Standard Gateway ================================================== @@ -175,6 +163,14 @@ def test_update_customer assert response.params['update_customer_return'] end + def test_quick_update_customer + response = @gateway.add_customer(@options.merge(@customer_options)) + customer_number = response.params['add_customer_return'] + + response = @gateway.quick_update_customer({customer_number: customer_number, update_data: @update_customer_options}) + assert response.params['quick_update_customer_return'] + end + def test_enable_disable_customer response = @gateway.add_customer(@options.merge(@customer_options)) customer_number = response.params['add_customer_return'] @@ -233,7 +229,7 @@ def test_update_customer_payment_method payment_method_id = response.params['add_customer_payment_method_return'] update_payment_options = @add_payment_options[:payment_method].merge(:method_id => payment_method_id, - :name => "Updated Card.") + :name => 'Updated Card.') response = @gateway.update_customer_payment_method(update_payment_options) assert response.params['update_customer_payment_method_return'] @@ -263,8 +259,8 @@ def test_run_customer_transaction response = @gateway.add_customer(@options.merge(@customer_options)) customer_number = response.params['add_customer_return'] - response = @gateway.run_customer_transaction(:customer_number => customer_number,# :method_id => 0, # optional - :command => "Sale", :amount => 3000) + response = @gateway.run_customer_transaction(:customer_number => customer_number, # :method_id => 0, # optional + :command => 'Sale', :amount => 3000) assert response.params['run_customer_transaction_return'] end @@ -316,7 +312,7 @@ def test_run_check_credit # TODO get offline auth_code? def test_post_auth - @options.merge!(:authorization_code => 123456) + @options[:authorization_code] = 123456 response = @gateway.post_auth(@options) assert response.params['post_auth_return'] end @@ -357,7 +353,7 @@ def test_override_transaction response = @gateway.run_check_sale(options) reference_number = response.params['run_check_sale_return']['ref_num'] - response = @gateway.override_transaction(:reference_number => reference_number, :reason => "Because I said so") + response = @gateway.override_transaction(:reference_number => reference_number, :reason => 'Because I said so') assert response.params['faultstring'] end diff --git a/test/remote/gateways/remote_usa_epay_transaction_test.rb b/test/remote/gateways/remote_usa_epay_transaction_test.rb index 9aafa893b3f..52c24f212c9 100644 --- a/test/remote/gateways/remote_usa_epay_transaction_test.rb +++ b/test/remote/gateways/remote_usa_epay_transaction_test.rb @@ -6,7 +6,8 @@ def setup @credit_card = credit_card('4000100011112224') @declined_card = credit_card('4000300011112220') @credit_card_with_track_data = credit_card_with_track_data('4000100011112224') - @options = { :billing_address => address(:zip => "27614", :state => "NC"), :shipping_address => address } + @check = check + @options = { :billing_address => address(:zip => '27614', :state => 'NC'), :shipping_address => address } @amount = 100 end @@ -22,6 +23,19 @@ def test_successful_purchase_with_track_data assert_success response end + def test_successful_purchase_with_echeck + assert response = @gateway.purchase(@amount, @check, @options) + assert_equal 'Success', response.message + assert_success response + end + + def test_successful_purchase_with_echeck_and_extra_options + extra_options = @options.merge(check_format: 'ARC', account_type: 'savings') + assert response = @gateway.purchase(@amount, @check, extra_options) + assert_equal 'Success', response.message + assert_success response + end + def test_successful_authorization_with_manual_entry @credit_card.manual_entry = true assert response = @gateway.authorize(@amount, @credit_card, @options) @@ -29,15 +43,15 @@ def test_successful_authorization_with_manual_entry assert_success response end - def test_successful_purchase_with_manual_entry + def test_successful_purchase_with_manual_entry @credit_card.manual_entry = true assert response = @gateway.purchase(@amount, @credit_card, @options) assert_equal 'Success', response.message assert_success response - end + end def test_successful_purchase_with_extra_details - assert response = @gateway.purchase(@amount, @credit_card, @options.merge(:order_id => generate_unique_id, :description => "socool")) + assert response = @gateway.purchase(@amount, @credit_card, @options.merge(:order_id => generate_unique_id, :description => 'socool')) assert_equal 'Success', response.message assert_success response end @@ -48,6 +62,52 @@ def test_successful_purchase_with_extra_test_mode assert_success response end + def test_successful_purchase_with_email_receipt + assert response = @gateway.purchase(@amount, @credit_card, @options.merge(:email => 'hank@hill.com', :cust_receipt => 'Yes')) + assert_equal 'Success', response.message + assert_success response + end + + def test_successful_purchase_with_recurring_fields + recurring_fields = [ + add_customer: true, + schedule: 'quarterly', + bill_source_key: 'bill source key', + bill_amount: 123, + num_left: 5, + start: '20501212', + recurring_receipt: true + ] + + assert response = @gateway.purchase(@amount, @credit_card, @options.merge(recurring_fields: recurring_fields)) + assert_equal 'Success', response.message + assert_success response + end + + def test_successful_purchase_with_custom_fields + custom_fields = { + 1 => 'multi', + 2 => 'pass', + 3 => 'korben', + 4 => 'dallas' + } + + assert response = @gateway.purchase(@amount, @credit_card, @options.merge(custom_fields: custom_fields)) + assert_equal 'Success', response.message + assert_success response + end + + def test_successful_purchase_with_line_items + line_items = [ + {sku: 'abc123', cost: 119, quantity: 1}, + {sku: 'def456', cost: 200, quantity: 2, name: 'an item' } + ] + + assert response = @gateway.purchase(@amount, @credit_card, @options.merge(line_items: line_items)) + assert_equal 'Success', response.message + assert_success response + end + def test_unsuccessful_purchase # For some reason this will fail with "You have tried this card too # many times, please contact merchant" unless a unique order id is @@ -89,8 +149,16 @@ def test_successful_refund_with_track_data assert_success refund end + def test_successful_refund_of_echeck + assert response = @gateway.purchase(@amount, @check, @options) + assert_success response + assert response.authorization + assert refund = @gateway.refund(@amount - 20, response.authorization) + assert_success refund + end + def test_unsuccessful_refund - assert refund = @gateway.refund(@amount - 20, "unknown_authorization") + assert refund = @gateway.refund(@amount - 20, 'unknown_authorization') assert_failure refund assert_match(/Unable to find original transaction/, refund.message) end @@ -103,8 +171,16 @@ def test_successful_void assert_success void end + def test_successful_void_with_echeck + assert response = @gateway.purchase(@amount, @check, @options) + assert_success response + assert response.authorization + assert void = @gateway.void(response.authorization) + assert_success void + end + def test_unsuccessful_void - assert void = @gateway.void("unknown_authorization") + assert void = @gateway.void('unknown_authorization') assert_failure void assert_match(/Unable to locate transaction/, void.message) end @@ -117,8 +193,16 @@ def test_successful_void_release assert_success void end + def test_successful_void_release_with_echeck + assert response = @gateway.purchase(@amount, @check, @options) + assert_success response + assert response.authorization + assert void = @gateway.void(response.authorization, void_mode: :void_release) + assert_success void + end + def test_unsuccessful_void_release - assert void = @gateway.void("unknown_authorization", void_mode: :void_release) + assert void = @gateway.void('unknown_authorization', void_mode: :void_release) assert_failure void assert_match(/Unable to locate transaction/, void.message) end @@ -133,14 +217,40 @@ def test_invalid_key def test_successful_verify assert response = @gateway.verify(@credit_card, @options) assert_success response - assert_equal "Success", response.message - assert_success response.responses.last, "The void should succeed" + assert_equal 'Success', response.message + assert_success response.responses.last, 'The void should succeed' end def test_failed_verify assert response = @gateway.verify(@declined_card, @options) assert_failure response - assert_match "Card Declined (00)", response.message + assert_match 'Card Declined (00)', response.message end + def test_transcript_scrubbing + transcript = capture_transcript(@gateway) do + @gateway.purchase(@amount, @credit_card, @options) + end + transcript = @gateway.scrub(transcript) + + assert_scrubbed(@credit_card.number, transcript) + assert_scrubbed(@credit_card.verification_value, transcript) + assert_scrubbed(@gateway.options[:login], transcript) + + transcript = capture_transcript(@gateway) do + @gateway.purchase(@amount, @credit_card_with_track_data, @options) + end + transcript = @gateway.scrub(transcript) + + assert_scrubbed(@credit_card_with_track_data.track_data, transcript) + assert_scrubbed(@gateway.options[:login], transcript) + + transcript = capture_transcript(@gateway) do + @gateway.purchase(@amount, @check, @options) + end + transcript = @gateway.scrub(transcript) + + assert_scrubbed(@check.account_number, transcript) + assert_scrubbed(@gateway.options[:login], transcript) + end end diff --git a/test/remote/gateways/remote_vanco_test.rb b/test/remote/gateways/remote_vanco_test.rb index af1bd190e3a..077b9b1a248 100644 --- a/test/remote/gateways/remote_vanco_test.rb +++ b/test/remote/gateways/remote_vanco_test.rb @@ -11,7 +11,7 @@ def setup @options = { order_id: '1', - billing_address: address(country: "US", state: "NC", zip: "06085"), + billing_address: address(country: 'US', state: 'NC', zip: '06085'), description: 'Store Purchase' } end @@ -19,32 +19,32 @@ def setup def test_successful_purchase response = @gateway.purchase(@amount, @credit_card, @options) assert_success response - assert_equal "Success", response.message + assert_equal 'Success', response.message end def test_successful_purchase_with_fund_id - response = @gateway.purchase(@amount, @credit_card, @options.merge(fund_id: "TheFund")) + response = @gateway.purchase(@amount, @credit_card, @options.merge(fund_id: 'TheFund')) assert_success response - assert_equal "Success", response.message + assert_equal 'Success', response.message end def test_successful_purchase_with_ip_address - response = @gateway.purchase(@amount, @credit_card, @options.merge(ip: "192.168.19.123")) + response = @gateway.purchase(@amount, @credit_card, @options.merge(ip: '192.168.19.123')) assert_success response - assert_equal "Success", response.message + assert_equal 'Success', response.message end def test_successful_purchase_sans_minimal_options response = @gateway.purchase(@amount, @credit_card) assert_success response - assert_equal "Success", response.message + assert_equal 'Success', response.message end def test_failed_purchase response = @gateway.purchase(@amount, @declined_card) assert_failure response - assert_equal("Invalid Expiration Date", response.message) - assert_equal("183", response.params["error_codes"]) + assert_equal('Invalid Expiration Date', response.message) + assert_equal('183', response.params['error_codes']) end def test_successful_echeck_purchase @@ -55,7 +55,7 @@ def test_successful_echeck_purchase end def test_failed_echeck_purchase - response = @gateway.purchase(@amount, check(routing_number: "121042883"), @options) + response = @gateway.purchase(@amount, check(routing_number: '121042883'), @options) assert_failure response assert_equal 'Invalid Routing Number', response.message end @@ -66,7 +66,7 @@ def test_successful_refund refund = @gateway.refund(@amount, purchase.authorization) assert_success refund - assert_equal "Success", refund.message + assert_equal 'Success', refund.message end def test_partial_refund @@ -105,6 +105,6 @@ def test_invalid_login ) response = gateway.purchase(@amount, @credit_card, @options) assert_failure response - assert_equal "Invalid Login Key", response.message + assert_equal 'Invalid Login Key', response.message end end diff --git a/test/remote/gateways/remote_verifi_test.rb b/test/remote/gateways/remote_verifi_test.rb index 9580810e574..2514864a96f 100644 --- a/test/remote/gateways/remote_verifi_test.rb +++ b/test/remote/gateways/remote_verifi_test.rb @@ -11,7 +11,7 @@ def setup # Replace with your login and password for the Verifi test environment @options = { :order_id => '37', - :email => "test@example.com", + :email => 'test@example.com', :billing_address => address } @@ -58,15 +58,6 @@ def test_authorization_and_capture assert_equal 'Transaction was Approved', capture.message end - def test_authorization_and_void - assert authorization = @gateway.authorize(@amount, @credit_card, @options) - assert_success authorization - assert authorization - assert void = @gateway.void(authorization.authorization, @options) - assert_success void - assert_equal 'Transaction was Approved', void.message - end - # Credits are not enabled on test accounts, so this should always fail def test_credit assert response = @gateway.credit(@amount, @credit_card, @options) diff --git a/test/remote/gateways/remote_viaklix_test.rb b/test/remote/gateways/remote_viaklix_test.rb index 319914004dc..c3dc47c1a43 100644 --- a/test/remote/gateways/remote_viaklix_test.rb +++ b/test/remote/gateways/remote_viaklix_test.rb @@ -3,41 +3,41 @@ class RemoteViaklixTest < Test::Unit::TestCase def setup @gateway = ViaklixGateway.new(fixtures(:viaklix)) - - @credit_card = credit_card + + @credit_card = credit_card @bad_credit_card = credit_card('invalid') - + @options = { :order_id => '#1000.1', - :email => "paul@domain.com", + :email => 'paul@domain.com', :description => 'Test Transaction', :billing_address => address } @amount = 100 end - + def test_successful_purchase assert response = @gateway.purchase(@amount, @credit_card, @options) - + assert_success response assert response.test? assert_equal 'APPROVED', response.message assert response.authorization end - + def test_failed_purchase assert response = @gateway.purchase(@amount, @bad_credit_card, @options) - + assert_failure response assert response.test? assert_equal 'The Credit Card Number supplied in the authorization request appears invalid.', response.message end - + def test_credit assert purchase = @gateway.purchase(@amount, @credit_card, @options) assert_success purchase - + assert credit = @gateway.credit(@amount, @credit_card) assert_success credit end -end \ No newline at end of file +end diff --git a/test/remote/gateways/remote_visanet_peru_test.rb b/test/remote/gateways/remote_visanet_peru_test.rb index 9eb37e3e71d..d596f4b451e 100644 --- a/test/remote/gateways/remote_visanet_peru_test.rb +++ b/test/remote/gateways/remote_visanet_peru_test.rb @@ -1,22 +1,22 @@ -require "test_helper" +require 'test_helper' class RemoteVisanetPeruTest < Test::Unit::TestCase def setup @gateway = VisanetPeruGateway.new(fixtures(:visanet_peru)) @amount = 100 - @credit_card = credit_card("4500340090000016", verification_value: "377") - @declined_card = credit_card("4111111111111111") + @credit_card = credit_card('4500340090000016', verification_value: '377') + @declined_card = credit_card('4111111111111111') @options = { billing_address: address, order_id: generate_unique_id, - email: "visanetperutest@mailinator.com" + email: 'visanetperutest@mailinator.com' } end def test_invalid_login - gateway = VisanetPeruGateway.new(access_key_id: "", secret_access_key: "", merchant_id: "") + gateway = VisanetPeruGateway.new(access_key_id: '', secret_access_key: '', merchant_id: '') response = gateway.purchase(@amount, @credit_card, @options) assert_failure response end @@ -24,72 +24,72 @@ def test_invalid_login def test_successful_purchase response = @gateway.purchase(@amount, @credit_card, @options) assert_success response - assert_equal "OK", response.message + assert_equal 'OK', response.message assert response.authorization - assert_equal @options[:order_id], response.params["externalTransactionId"] + assert_equal @options[:order_id], response.params['externalTransactionId'] assert response.test? end def test_successful_purchase_with_merchant_define_data - options = @options.merge(merchant_define_data: { field3: "movil", field91: "101266802", field92: "TheMerchant" }) + options = @options.merge(merchant_define_data: { field3: 'movil', field91: '101266802', field92: 'TheMerchant' }) response = @gateway.purchase(@amount, @credit_card, options) assert_success response - assert_equal "OK", response.message + assert_equal 'OK', response.message end def test_successful_purchase_sans_options response = @gateway.purchase(@amount, @credit_card) assert_success response - assert_equal "OK", response.message + assert_equal 'OK', response.message end def test_failed_purchase response = @gateway.purchase(@amount, @declined_card, @options) assert_failure response assert_equal 400, response.error_code - assert_equal "Operacion Denegada.", response.message + assert_equal 'Operacion Denegada.', response.message end def test_successful_authorize_and_capture response = @gateway.authorize(@amount, @credit_card, @options) assert_success response - assert_equal "OK", response.message + assert_equal 'OK', response.message assert response.authorization - assert_equal @options[:order_id], response.params["externalTransactionId"] - assert_equal "1.00", response.params["data"]["IMP_AUTORIZADO"] + assert_equal @options[:order_id], response.params['externalTransactionId'] + assert_equal '1.00', response.params['data']['IMP_AUTORIZADO'] capture = @gateway.capture(response.authorization, @options) assert_success capture - assert_equal "OK", capture.message + assert_equal 'OK', capture.message assert capture.authorization - assert_equal @options[:order_id], capture.params["externalTransactionId"] + assert_equal @options[:order_id], capture.params['externalTransactionId'] end def test_successful_authorize_fractional_amount amount = 199 response = @gateway.authorize(amount, @credit_card) assert_success response - assert_equal "OK", response.message - assert_equal "1.99", response.params["data"]["IMP_AUTORIZADO"] + assert_equal 'OK', response.message + assert_equal '1.99', response.params['data']['IMP_AUTORIZADO'] end def test_failed_authorize response = @gateway.authorize(@amount, @declined_card, @options) assert_failure response assert_equal 400, response.error_code - assert_equal "Operacion Denegada.", response.message + assert_equal 'Operacion Denegada.', response.message - @options[:email] = "cybersource@reject.com" + @options[:email] = 'cybersource@reject.com' response = @gateway.authorize(@amount, @credit_card, @options) assert_failure response assert_equal 400, response.error_code - assert_equal "El pedido ha sido rechazado por Decision Manager", response.message + assert_equal 'REJECT', response.message end def test_failed_capture - response = @gateway.capture("900000044") + response = @gateway.capture('900000044') assert_failure response - assert_match /NUMORDEN 900000044 no se encuentra registrado/, response.message + assert_match(/NUMORDEN 900000044 no se encuentra registrado/, response.message) assert_equal 400, response.error_code end @@ -99,13 +99,24 @@ def test_successful_refund refund = @gateway.refund(@amount, response.authorization) assert_success refund - assert_equal "OK", refund.message + assert_equal 'OK', refund.message + end + + def test_successful_refund_unsettled + response = @gateway.purchase(@amount, @credit_card, @options) + assert_success response + + new_auth = "_|#{response.authorization.split('|')[1]}" + @gateway.refund(@amount, new_auth, @options.merge(force_full_refund_if_unsettled: true, ruc: '20341198217')) + # this test will fail currently because there is no E2E test working for visanet + # assert_success refund + # assert_equal "OK", refund.message end def test_failed_refund - response = @gateway.refund(@amount, "900000044" ) + response = @gateway.refund(@amount, '900000044') assert_failure response - assert_match /NUMORDEN 900000044 no se encuentra registrado/, response.message + assert_match(/NUMORDEN 900000044 no se encuentra registrado/, response.message) assert_equal 400, response.error_code end @@ -115,28 +126,28 @@ def test_successful_void void = @gateway.void(response.authorization) assert_success void - assert_equal "OK", void.message + assert_equal 'OK', void.message end def test_failed_void - response = @gateway.void("900000044") + response = @gateway.void('900000044') assert_failure response - assert_match /NUMORDEN no se encuentra registrado/, response.message + assert_match(/NUMORDEN no se encuentra registrado/, response.message) assert_equal 400, response.error_code end def test_successful_verify response = @gateway.verify(@credit_card, @options) assert_success response - assert_equal "OK", response.message - assert_equal @options[:order_id], response.params["externalTransactionId"] + assert_equal 'OK', response.message + assert_equal @options[:order_id], response.params['externalTransactionId'] end def test_failed_verify response = @gateway.verify(@declined_card, @options) assert_failure response assert_equal 400, response.error_code - assert_equal "Operacion Denegada.", response.message + assert_equal 'Operacion Denegada.', response.message end def test_transcript_scrubbing diff --git a/test/remote/gateways/remote_webpay_test.rb b/test/remote/gateways/remote_webpay_test.rb index aced3b29797..3b0e099ea33 100644 --- a/test/remote/gateways/remote_webpay_test.rb +++ b/test/remote/gateways/remote_webpay_test.rb @@ -1,4 +1,5 @@ # coding: utf-8 + require 'test_helper' class RemoteWebpayTest < Test::Unit::TestCase @@ -21,25 +22,25 @@ def setup def test_successful_purchase assert response = @gateway.purchase(@amount, @credit_card, @options) assert_success response - assert_equal "charge", response.params["object"] - assert response.params["paid"] + assert_equal 'charge', response.params['object'] + assert response.params['paid'] end def test_appropriate_purchase_amount assert response = @gateway.purchase(@amount, @credit_card, @options) assert_success response - assert_equal @amount / 100, response.params["amount"] + assert_equal @amount / 100, response.params['amount'] end def test_purchase_description - assert response = @gateway.purchase(@amount, @credit_card, { :description => "TheDescription", :email => "email@example.com" }) - assert_equal "TheDescription", response.params["description"], "Use the description if it's specified." + assert response = @gateway.purchase(@amount, @credit_card, { :description => 'TheDescription', :email => 'email@example.com' }) + assert_equal 'TheDescription', response.params['description'], "Use the description if it's specified." - assert response = @gateway.purchase(@amount, @credit_card, { :email => "email@example.com" }) - assert_equal "email@example.com", response.params["description"], "Use the email if no description is specified." + assert response = @gateway.purchase(@amount, @credit_card, { :email => 'email@example.com' }) + assert_equal 'email@example.com', response.params['description'], 'Use the email if no description is specified.' assert response = @gateway.purchase(@amount, @credit_card, { }) - assert_nil response.params["description"], "No description or email specified." + assert_nil response.params['description'], 'No description or email specified.' end def test_unsuccessful_purchase @@ -51,7 +52,7 @@ def test_unsuccessful_purchase def test_authorization_and_capture assert authorization = @gateway.authorize(@amount, @credit_card, @options) assert_success authorization - assert !authorization.params["captured"] + assert !authorization.params['captured'] assert capture = @gateway.capture(@amount, authorization.authorization) assert_success capture @@ -60,7 +61,7 @@ def test_authorization_and_capture def test_authorization_and_void assert authorization = @gateway.authorize(@amount, @credit_card, @options) assert_success authorization - assert !authorization.params["captured"] + assert !authorization.params['captured'] assert void = @gateway.void(authorization.authorization) assert_success void @@ -75,7 +76,7 @@ def test_successful_void end def test_unsuccessful_void - assert void = @gateway.void("active_merchant_fake_charge") + assert void = @gateway.void('active_merchant_fake_charge') assert_failure void assert_match 'No such charge', void.message end @@ -94,44 +95,44 @@ def test_appropriate_refund_amount assert response.authorization assert void = @gateway.refund(@refund_amount, response.authorization) assert_success void - assert_equal @refund_amount / 100, void.params["amount_refunded"] + assert_equal @refund_amount / 100, void.params['amount_refunded'] end def test_unsuccessful_refund - assert refund = @gateway.refund(@amount, "active_merchant_fake_charge") + assert refund = @gateway.refund(@amount, 'active_merchant_fake_charge') assert_failure refund assert_match 'No such charge', refund.message end def test_successful_store - assert response = @gateway.store(@credit_card, {:description => "Active Merchant Test Customer", :email => "email@example.com"}) + assert response = @gateway.store(@credit_card, {:description => 'Active Merchant Test Customer', :email => 'email@example.com'}) assert_success response - assert_equal "customer", response.params["object"] - assert_equal "Active Merchant Test Customer", response.params["description"] - assert_equal "email@example.com", response.params["email"] - assert_equal @credit_card.last_digits, response.params["active_card"]["last4"] + assert_equal 'customer', response.params['object'] + assert_equal 'Active Merchant Test Customer', response.params['description'] + assert_equal 'email@example.com', response.params['email'] + assert_equal @credit_card.last_digits, response.params['active_card']['last4'] end def test_successful_update - creation = @gateway.store(@credit_card, {:description => "Active Merchant Update Customer"}) + creation = @gateway.store(@credit_card, {:description => 'Active Merchant Update Customer'}) assert response = @gateway.update(creation.params['id'], @new_credit_card) assert_success response - assert_equal "Active Merchant Update Customer", response.params["description"] - assert_equal @new_credit_card.last_digits, response.params["active_card"]["last4"] + assert_equal 'Active Merchant Update Customer', response.params['description'] + assert_equal @new_credit_card.last_digits, response.params['active_card']['last4'] end def test_successful_unstore - creation = @gateway.store(@credit_card, {:description => "Active Merchant Unstore Customer"}) + creation = @gateway.store(@credit_card, {:description => 'Active Merchant Unstore Customer'}) assert response = @gateway.unstore(creation.params['id']) assert_success response - assert_equal true, response.params["deleted"] + assert_equal true, response.params['deleted'] end def test_invalid_login gateway = WebpayGateway.new(:login => 'active_merchant_test') assert response = gateway.purchase(@amount, @credit_card, @options) assert_failure response - assert_equal "Invalid API key provided. Check your API key is correct.", response.message + assert_equal 'Invalid API key provided. Check your API key is correct.', response.message end end diff --git a/test/remote/gateways/remote_wepay_test.rb b/test/remote/gateways/remote_wepay_test.rb index 51b156d52f5..4a1b01f061d 100644 --- a/test/remote/gateways/remote_wepay_test.rb +++ b/test/remote/gateways/remote_wepay_test.rb @@ -5,12 +5,14 @@ def setup @gateway = WepayGateway.new(fixtures(:wepay)) @amount = 2000 - @credit_card = credit_card('5496198584584769') + @credit_card = credit_card('5496198584584769', verification_value: '321') + @credit_card_without_cvv = credit_card('5496198584584769', verification_value: nil) + @declined_card = credit_card('') @options = { billing_address: address, - email: "test@example.com" + email: 'test@example.com' } end @@ -33,6 +35,14 @@ def test_successful_purchase_with_token assert_success response end + def test_successful_purchase_with_recurring_and_ip + store = @gateway.store(@credit_card, @options.merge(recurring: true, ip: '127.0.0.1')) + assert_success store + + response = @gateway.purchase(@amount, store.authorization, @options) + assert_success response + end + def test_successful_purchase_sans_cvv @options[:recurring] = true store = @gateway.store(@credit_card, @options) @@ -43,7 +53,7 @@ def test_successful_purchase_sans_cvv end def test_successful_purchase_with_few_options - options = { address: { zip: "27701" }, email: "test@example.com" } + options = { address: { zip: '27701' }, email: 'test@example.com' } response = @gateway.purchase(@amount, @credit_card, options) assert_success response assert_equal 'Success', response.message @@ -56,12 +66,24 @@ def test_failed_purchase_sans_ccv end def test_failed_purchase_with_token - response = @gateway.purchase(@amount, "12345", @options) + response = @gateway.purchase(@amount, '12345', @options) assert_failure response end def test_successful_purchase_with_fee - response = @gateway.purchase(@amount, @credit_card, @options.merge(application_fee: 3, fee_payer: "payee")) + response = @gateway.purchase(@amount, @credit_card, @options.merge(application_fee: 3, fee_payer: 'payee')) + assert_success response + assert_equal 'Success', response.message + end + + def test_successful_purchase_with_unique_id + response = @gateway.purchase(@amount, @credit_card, @options.merge(unique_id: generate_unique_id)) + assert_success response + assert_equal 'Success', response.message + end + + def test_successful_purchase_with_ip_and_risk_token + response = @gateway.purchase(@amount, @credit_card, @options.merge(ip: '100.166.99.123', risk_token: '123e4567-e89b-12d3-a456-426655440000')) assert_success response assert_equal 'Success', response.message end @@ -76,11 +98,40 @@ def test_failed_authorize response = @gateway.authorize(@amount, @declined_card, @options) assert_failure response end - def test_successful_store + + def test_successful_store_via_create_with_cvv + # POST /credit_card/create response = @gateway.store(@credit_card, @options) assert_success response end + def test_successful_store_via_transfer_without_cvv + # special permission required + # POST /credit_card/transfer + response = @gateway.store(@credit_card_without_cvv, @options.merge(recurring: true)) + assert_success response + end + + def test_unsuccessful_store_via_create_with_cvv + response = @gateway.store(@credit_card_without_cvv, @options) + + assert_failure response + assert_equal('This app does not have permissions to create credit cards without a cvv', response.message) + end + + # # Requires commenting out `unless options[:recurring]` when building post hash in `store` method. + # def test_unsuccessful_store_via_transfer_with_cvv + # response = @gateway.store(@credit_card, @options.merge(recurring: true)) + # + # assert_failure response + # assert_equal('cvv parameter is unexpected', response.message) + # end + + def test_successful_store_with_defaulted_email + response = @gateway.store(@credit_card, {billing_address: address}) + assert_success response + end + def test_failed_store response = @gateway.store(@declined_card, @options) assert_failure response @@ -127,10 +178,17 @@ def test_authorize_and_void authorize = @gateway.authorize(@amount, @credit_card, @options) assert_success authorize - void = @gateway.void(authorize.authorization, cancel_reason: "Cancel") + void = @gateway.void(authorize.authorization, cancel_reason: 'Cancel') assert_success void end + # Version sent here will need to match or be one ahead of the version set in the test account's dashboard + def test_successful_purchase_with_version + response = @gateway.purchase(@amount, @credit_card, @options.merge(version: '2017-05-31')) + assert_success response + assert_equal 'Success', response.message + end + def test_invalid_login gateway = WepayGateway.new( client_id: 12515, @@ -140,4 +198,15 @@ def test_invalid_login response = gateway.purchase(@amount, @credit_card, @options) assert_failure response end + + def test_transcript_scrubbing + transcript = capture_transcript(@gateway) do + @gateway.purchase(@amount, @credit_card, @options) + end + transcript = @gateway.scrub(transcript) + + assert_scrubbed(@credit_card.number, transcript) + assert_scrubbed(@credit_card.verification_value, transcript) + assert_scrubbed(@gateway.options[:access_token], transcript) + end end diff --git a/test/remote/gateways/remote_wirecard_test.rb b/test/remote/gateways/remote_wirecard_test.rb index a345caa255f..586e1567351 100644 --- a/test/remote/gateways/remote_wirecard_test.rb +++ b/test/remote/gateways/remote_wirecard_test.rb @@ -1,4 +1,5 @@ # encoding: UTF-8 + require 'test_helper' class RemoteWirecardTest < Test::Unit::TestCase @@ -57,7 +58,7 @@ def test_successful_authorize_and_partial_capture assert_match %r{THIS IS A DEMO}, auth.message assert auth.authorization - #Capture some of the authorized amount + # Capture some of the authorized amount assert capture = @gateway.capture(@amount - 10, auth.authorization, @options) assert_success capture end @@ -89,7 +90,7 @@ def test_successful_purchase end def test_successful_purchase_with_commerce_type - assert response = @gateway.purchase(@amount, @credit_card, @options.merge(commerce_type: "MOTO")) + assert response = @gateway.purchase(@amount, @credit_card, @options.merge(commerce_type: 'MOTO')) assert_success response assert_match %r{THIS IS A DEMO}, response.message end @@ -105,7 +106,7 @@ def test_successful_reference_purchase end def test_utf8_description_does_not_blow_up - assert response = @gateway.purchase(@amount, @credit_card, @options.merge(description: "Habitación")) + assert response = @gateway.purchase(@amount, @credit_card, @options.merge(description: 'Habitación')) assert_success response assert_match %r{THIS IS A DEMO}, response.message end @@ -132,11 +133,11 @@ def test_successful_purchase_with_german_address_and_valid_phone end def test_successful_cvv_result - @credit_card.verification_value = "666" # Magic Value = "Matched (correct) CVC-2" + @credit_card.verification_value = '666' # Magic Value = "Matched (correct) CVC-2" assert response = @gateway.purchase(@amount, @credit_card, @options) assert_success response - assert_equal "M", response.cvv_result["code"] + assert_equal 'M', response.cvv_result['code'] end def test_successful_visa_avs_result @@ -151,7 +152,7 @@ def test_successful_visa_avs_result assert response = @gateway.purchase(@amount, @credit_card, @options.merge(billing_address: m_address)) assert_success response - assert_equal "M", response.avs_result["code"] + assert_equal 'M', response.avs_result['code'] end def test_successful_amex_avs_result @@ -165,7 +166,7 @@ def test_successful_amex_avs_result assert response = @gateway.purchase(@amount, @amex_card, @options.merge(billing_address: a_address)) assert_success response - assert_equal "U", response.avs_result["code"] + assert_equal 'U', response.avs_result['code'] end def test_successful_store @@ -189,13 +190,13 @@ def test_successful_store_then_purchase_by_reference end def test_successful_authorization_as_recurring_transaction_type_initial - assert response = @gateway.authorize(@amount, @credit_card, @options.merge(:recurring => "Initial")) + assert response = @gateway.authorize(@amount, @credit_card, @options.merge(:recurring => 'Initial')) assert_success response assert response.authorization end def test_successful_purchase_as_recurring_transaction_type_initial - assert response = @gateway.purchase(@amount, @credit_card, @options.merge(:recurring => "Initial")) + assert response = @gateway.purchase(@amount, @credit_card, @options.merge(:recurring => 'Initial')) assert_success response assert response.authorization end @@ -213,21 +214,21 @@ def test_wrong_creditcard_purchase assert response = @gateway.purchase(@amount, @declined_card, @options) assert response.test? assert_failure response - assert response.message[ /Credit card number not allowed in demo mode/ ], "Got wrong response message" - assert_equal "24997", response.params['ErrorCode'] + assert response.message[/Credit card number not allowed in demo mode/], 'Got wrong response message' + assert_equal '24997', response.params['ErrorCode'] end def test_wrong_creditcard_store assert response = @gateway.store(@declined_card, @options) assert response.test? assert_failure response - assert response.message[ /Credit card number not allowed in demo mode/ ], "Got wrong response message" + assert response.message[/Credit card number not allowed in demo mode/], 'Got wrong response message' end def test_unauthorized_capture - assert response = @gateway.capture(@amount, "1234567890123456789012") + assert response = @gateway.capture(@amount, '1234567890123456789012') assert_failure response - assert_equal "Could not find referenced transaction for GuWID 1234567890123456789012.", response.message + assert_equal 'Could not find referenced transaction for GuWID 1234567890123456789012.', response.message end def test_failed_refund @@ -243,16 +244,16 @@ def test_failed_void end def test_unauthorized_purchase - assert response = @gateway.purchase(@amount, "1234567890123456789012") + assert response = @gateway.purchase(@amount, '1234567890123456789012') assert_failure response - assert_equal "Could not find referenced transaction for GuWID 1234567890123456789012.", response.message + assert_equal 'Could not find referenced transaction for GuWID 1234567890123456789012.', response.message end def test_invalid_login gateway = WirecardGateway.new(login: '', password: '', signature: '') assert response = gateway.purchase(@amount, @credit_card, @options) assert_failure response - assert_equal "Invalid Login", response.message + assert_equal 'Invalid Login', response.message end def test_transcript_scrubbing diff --git a/test/remote/gateways/remote_world_net_test.rb b/test/remote/gateways/remote_world_net_test.rb index 530212fe10a..67d198f1fbf 100644 --- a/test/remote/gateways/remote_world_net_test.rb +++ b/test/remote/gateways/remote_world_net_test.rb @@ -25,10 +25,10 @@ def test_successful_purchase def test_successful_purchase_with_more_options options = { order_id: generate_order_id, - email: "joe@example.com", + email: 'joe@example.com', billing_address: address, description: 'Store Purchase', - ip: "127.0.0.1", + ip: '127.0.0.1', } response = @gateway.purchase(@amount, @credit_card, options) @@ -109,10 +109,10 @@ def test_successful_void auth = @gateway.authorize(@amount, @credit_card, @options) assert_success auth - assert void = @gateway.void(auth.authorization) - # UNSUPPORTED - # assert_success void - # assert_equal 'REPLACE WITH SUCCESSFUL VOID MESSAGE', response.message + assert @gateway.void(auth.authorization) + # UNSUPPORTED + # assert_success void + # assert_equal 'REPLACE WITH SUCCESSFUL VOID MESSAGE', response.message end def test_failed_void @@ -156,7 +156,6 @@ def test_unsuccessful_unstore response = @gateway.store(@credit_card, @options) assert_success response assert_equal nil, response.message - card_reference = response.authorization assert response = @gateway.unstore('123456789', @options) assert_failure response diff --git a/test/remote/gateways/remote_worldpay_online_payments_test.rb b/test/remote/gateways/remote_worldpay_online_payments_test.rb index 17d965a1716..4f0b2ff05c2 100644 --- a/test/remote/gateways/remote_worldpay_online_payments_test.rb +++ b/test/remote/gateways/remote_worldpay_online_payments_test.rb @@ -154,8 +154,8 @@ def test_failed_verify def test_invalid_login badgateway = WorldpayOnlinePaymentsGateway.new( - client_key: "T_C_NOT_VALID", - service_key: "T_S_NOT_VALID" + client_key: 'T_C_NOT_VALID', + service_key: 'T_S_NOT_VALID' ) response = badgateway.purchase(@amount, @credit_card, @options) assert_failure response diff --git a/test/remote/gateways/remote_worldpay_test.rb b/test/remote/gateways/remote_worldpay_test.rb index 3d9769abf17..c87d9539397 100644 --- a/test/remote/gateways/remote_worldpay_test.rb +++ b/test/remote/gateways/remote_worldpay_test.rb @@ -4,12 +4,17 @@ class RemoteWorldpayTest < Test::Unit::TestCase def setup @gateway = WorldpayGateway.new(fixtures(:world_pay_gateway)) + @cftgateway = WorldpayGateway.new(fixtures(:world_pay_gateway_cft)) @amount = 100 @credit_card = credit_card('4111111111111111') @declined_card = credit_card('4111111111111111', :first_name => nil, :last_name => 'REFUSED') + @threeDS_card = credit_card('4111111111111111', :first_name => nil, :last_name => '3D') - @options = {order_id: generate_unique_id, email: "wow@example.com"} + @options = { + order_id: generate_unique_id, + email: 'wow@example.com' + } end def test_successful_purchase @@ -19,11 +24,11 @@ def test_successful_purchase end def test_successful_purchase_with_hcg_additional_data - @options.merge!(hcg_additional_data: { - key1: "value1", - key2: "value2", - key3: "value3" - }) + @options[:hcg_additional_data] = { + key1: 'value1', + key2: 'value2', + key3: 'value3' + } assert response = @gateway.purchase(@amount, @credit_card, @options) assert_success response @@ -42,7 +47,8 @@ def test_authorize_and_capture assert_success auth assert_equal 'SUCCESS', auth.message assert auth.authorization - assert capture = @gateway.capture(@amount, auth.authorization) + + assert capture = @gateway.capture(@amount, auth.authorization, authorization_validated: true) assert_success capture end @@ -50,13 +56,14 @@ def test_authorize_and_capture_by_reference assert auth = @gateway.authorize(@amount, @credit_card, @options) assert_success auth assert_equal 'SUCCESS', auth.message - assert capture = @gateway.capture(@amount, auth.authorization) - assert_success capture + assert capture = @gateway.capture(@amount, auth.authorization, authorization_validated: true) + assert_success capture assert reference = auth.authorization @options[:order_id] = generate_unique_id + assert auth = @gateway.authorize(@amount, reference, @options) - assert capture = @gateway.capture(@amount, auth.authorization) + assert capture = @gateway.capture(@amount, auth.authorization, authorization_validated: true) assert_success capture end @@ -64,17 +71,113 @@ def test_authorize_and_purchase_by_reference assert auth = @gateway.authorize(@amount, @credit_card, @options) assert_success auth assert_equal 'SUCCESS', auth.message - assert capture = @gateway.capture(@amount, auth.authorization) - assert_success capture + assert capture = @gateway.capture(@amount, auth.authorization, authorization_validated: true) + assert_success capture assert reference = auth.authorization + @options[:order_id] = generate_unique_id assert auth = @gateway.authorize(@amount, reference, @options) + @options[:order_id] = generate_unique_id assert capture = @gateway.purchase(@amount, auth.authorization, @options) assert_success capture end + def test_authorize_and_purchase_with_instalments + assert auth = @gateway.authorize(@amount, @credit_card, @options.merge(instalment: 3)) + assert_success auth + assert_equal 'SUCCESS', auth.message + assert auth.authorization + + assert capture = @gateway.capture(@amount, auth.authorization, authorization_validated: true) + assert_success capture + end + + def test_successful_authorize_with_3ds + session_id = generate_unique_id + options = @options.merge( + { + execute_threed: true, + accept_header: 'text/html', + user_agent: 'Mozilla/5.0', + session_id: session_id, + ip: '127.0.0.1', + cookie: 'machine=32423423' + }) + assert first_message = @gateway.authorize(@amount, @threeDS_card, options) + assert_equal "A transaction status of 'AUTHORISED' is required.", first_message.message + assert first_message.test? + refute first_message.authorization.blank? + refute first_message.params['issuer_url'].blank? + refute first_message.params['pa_request'].blank? + refute first_message.params['cookie'].blank? + refute first_message.params['session_id'].blank? + end + + def test_successful_auth_and_capture_with_stored_cred_options + assert auth = @gateway.authorize(@amount, @credit_card, @options.merge(stored_credential_usage: 'FIRST')) + assert_success auth + assert auth.authorization + assert auth.params['scheme_response'] + assert auth.params['transaction_identifier'] + + assert capture = @gateway.capture(@amount, auth.authorization, authorization_validated: true) + assert_success capture + + options = @options.merge( + order_id: generate_unique_id, + stored_credential_usage: 'USED', + stored_credential_initiated_reason: 'UNSCHEDULED', + stored_credential_transaction_id: auth.params['transaction_identifier'] + ) + assert next_auth = @gateway.authorize(@amount, @credit_card, options) + assert next_auth.authorization + assert next_auth.params['scheme_response'] + assert next_auth.params['transaction_identifier'] + + assert capture = @gateway.capture(@amount, next_auth.authorization, authorization_validated: true) + assert_success capture + end + + # Fails currently because the sandbox doesn't actually validate the stored_credential options + # def test_failed_authorize_with_bad_stored_cred_options + # assert auth = @gateway.authorize(@amount, @credit_card, @options.merge(stored_credential_usage: 'FIRST')) + # assert_success auth + # assert auth.authorization + # assert auth.params['scheme_response'] + # assert auth.params['transaction_identifier'] + # + # assert capture = @gateway.capture(@amount, auth.authorization, authorization_validated: true) + # assert_success capture + # + # options = @options.merge( + # order_id: generate_unique_id, + # stored_credential_usage: 'MEH', + # stored_credential_initiated_reason: 'BLAH', + # stored_credential_transaction_id: 'nah' + # ) + # assert next_auth = @gateway.authorize(@amount, @credit_card, options) + # assert_failure next_auth + # end + + def test_failed_authorize_with_3ds + session_id = generate_unique_id + options = @options.merge( + { + execute_threed: true, + accept_header: 'text/html', + session_id: session_id, + ip: '127.0.0.1', + cookie: 'machine=32423423' + }) + assert first_message = @gateway.authorize(@amount, @threeDS_card, options) + assert_match %r{missing info for 3D-secure transaction}i, first_message.message + assert first_message.test? + assert first_message.params['issuer_url'].blank? + assert first_message.params['pa_request'].blank? + end + def test_failed_capture assert response = @gateway.capture(@amount, 'bogus') assert_failure response @@ -94,33 +197,40 @@ def test_partial_address end def test_ip_address - assert_success @gateway.authorize(@amount, @credit_card, @options.merge(ip: "192.18.123.12")) + assert_success @gateway.authorize(@amount, @credit_card, @options.merge(ip: '192.18.123.12')) end def test_void - assert_success(response = @gateway.authorize(@amount, @credit_card, @options)) - assert_success (void = @gateway.void(response.authorization)) - assert_equal "SUCCESS", void.message - assert void.params["cancel_received_order_code"] + assert_success response = @gateway.authorize(@amount, @credit_card, @options) + assert_success void = @gateway.void(response.authorization, authorization_validated: true) + assert_equal 'SUCCESS', void.message + assert void.params['cancel_received_order_code'] end def test_void_nonexistent_transaction assert_failure response = @gateway.void('non_existent_authorization') - assert_equal "Could not find payment for order", response.message + assert_equal 'Could not find payment for order', response.message end def test_authorize_fractional_currency assert_success(result = @gateway.authorize(1234, @credit_card, @options.merge(:currency => 'USD'))) - assert_equal "USD", result.params['amount_currency_code'] - assert_equal "1234", result.params['amount_value'] - assert_equal "2", result.params['amount_exponent'] + assert_equal 'USD', result.params['amount_currency_code'] + assert_equal '1234', result.params['amount_value'] + assert_equal '2', result.params['amount_exponent'] end def test_authorize_nonfractional_currency assert_success(result = @gateway.authorize(1234, @credit_card, @options.merge(:currency => 'IDR'))) - assert_equal "IDR", result.params['amount_currency_code'] - assert_equal "12", result.params['amount_value'] - assert_equal "0", result.params['amount_exponent'] + assert_equal 'IDR', result.params['amount_currency_code'] + assert_equal '12', result.params['amount_value'] + assert_equal '0', result.params['amount_exponent'] + end + + def test_authorize_three_decimal_currency + assert_success(result = @gateway.authorize(1234, @credit_card, @options.merge(:currency => 'OMR'))) + assert_equal 'OMR', result.params['amount_currency_code'] + assert_equal '1234', result.params['amount_value'] + assert_equal '3', result.params['amount_exponent'] end def test_reference_transaction @@ -141,12 +251,12 @@ def test_refund_fails_unless_status_is_captured assert refund = @gateway.refund(30, response.authorization) assert_failure refund - assert_equal "A transaction status of 'CAPTURED' or 'SETTLED' or 'SETTLED_BY_MERCHANT' is required.", refund.message + assert_equal 'Order not ready', refund.message end def test_refund_nonexistent_transaction - assert_failure response = @gateway.refund(@amount, "non_existent_authorization") - assert_equal "Could not find payment for order", response.message + assert_failure response = @gateway.refund(@amount, 'non_existent_authorization') + assert_equal 'Could not find payment for order', response.message end def test_successful_verify @@ -161,6 +271,19 @@ def test_failed_verify assert_match %r{REFUSED}, response.message end + def test_successful_visa_credit_on_cft_gateway + credit = @cftgateway.credit(@amount, @credit_card, @options) + assert_success credit + assert_equal 'SUCCESS', credit.message + end + + def test_successful_mastercard_credit_on_cft_gateway + cc = credit_card('5555555555554444') + credit = @cftgateway.credit(@amount, cc, @options) + assert_success credit + assert_equal 'SUCCESS', credit.message + end + def test_transcript_scrubbing transcript = capture_transcript(@gateway) do @gateway.purchase(@amount, @credit_card, @options) @@ -171,22 +294,25 @@ def test_transcript_scrubbing assert_scrubbed(@credit_card.verification_value.to_s, clean_transcript) end - # Worldpay has a delay between asking for a transaction to be captured and actually marking it as captured - # These 2 tests work if you take the auth code, wait some time and then perform the next operation. - - # def test_refund - # assert_success(response = @gateway.purchase(@amount, @credit_card, @options)) + # These 2 tests work if you get authorizations from a purchase, wait some time and then perform the refund/void operation. + # + # def test_get_authorization + # response = @gateway.purchase(@amount, @credit_card, @options) # assert response.authorization - # refund = @gateway.refund(@amount, capture.authorization) + # puts 'auth: ' + response.authorization + # end + # + # def test_refund + # refund = @gateway.refund(@amount, '39270fd70be13aab55f84e28be45cad3') # assert_success refund - # assert_equal "SUCCESS", refund.message + # assert_equal 'SUCCESS', refund.message # end - + # # def test_void_fails_unless_status_is_authorised - # response = @gateway.void("33d6dfa9726198d44a743488cf611d3b") # existing transaction in CAPTURED state + # response = @gateway.void('replace_with_authorization') # existing transaction in CAPTURED state # assert_failure response - # assert_equal "A transaction status of 'AUTHORISED' is required.", response.message + # assert_equal 'A transaction status of 'AUTHORISED' is required.', response.message # end end diff --git a/test/remote/gateways/remote_worldpay_us_test.rb b/test/remote/gateways/remote_worldpay_us_test.rb index d9e786ff3d4..a0e50945fa6 100644 --- a/test/remote/gateways/remote_worldpay_us_test.rb +++ b/test/remote/gateways/remote_worldpay_us_test.rb @@ -5,9 +5,9 @@ def setup @gateway = WorldpayUsGateway.new(fixtures(:worldpay_us)) @amount = 100 - @credit_card = credit_card('4446661234567892') + @credit_card = credit_card('4446661234567892', :verification_value => '987') @declined_card = credit_card('4000300011112220') - @check = check + @check = check(:number => '12345654321') @options = { order_id: generate_unique_id, @@ -22,6 +22,13 @@ def test_successful_purchase assert_equal 'Succeeded', response.message end + def test_successful_purchase_on_backup_url + gateway = WorldpayUsGateway.new(fixtures(:worldpay_us).merge({ use_backup_url: true})) + response = gateway.purchase(@amount, @credit_card, @options) + assert_success response + assert_equal 'Succeeded', response.message + end + def test_failed_purchase response = @gateway.purchase(@amount, @declined_card, @options) assert_failure response @@ -35,7 +42,7 @@ def test_successful_echeck_purchase end def test_failed_echeck_purchase - response = @gateway.purchase(@amount, check(routing_number: "23433"), @options) + response = @gateway.purchase(@amount, check(routing_number: '23433'), @options) assert_failure response assert response.message =~ /DECLINED/ end @@ -43,12 +50,12 @@ def test_failed_echeck_purchase def test_successful_authorize_and_capture assert response = @gateway.authorize(@amount, @credit_card, @options) assert_success response - assert_equal "Succeeded", response.message + assert_equal 'Succeeded', response.message assert_match %r(^\d+\|.+$), response.authorization assert capture = @gateway.capture(@amount, response.authorization) assert_success capture - assert_equal "Succeeded", capture.message + assert_equal 'Succeeded', capture.message end def test_failed_authorize @@ -63,7 +70,7 @@ def test_successful_refund assert refund = @gateway.refund(@amount, response.authorization) assert_success refund - assert_equal "Succeeded", refund.message + assert_equal 'Succeeded', refund.message end def test_successful_void @@ -82,8 +89,8 @@ def test_failed_void def test_successful_verify assert response = @gateway.verify(@credit_card, @options) assert_success response - assert_equal "Succeeded", response.message - assert_success response.responses.last, "The void should succeed" + assert_equal 'Succeeded', response.message + assert_success response.responses.last, 'The void should succeed' end def test_failed_verify @@ -100,13 +107,31 @@ def test_passing_billing_address def test_invalid_login gateway = WorldpayUsGateway.new( - :acctid => "", - :subid => "", - :merchantpin => "" + :acctid => '', + :subid => '', + :merchantpin => '' ) assert response = gateway.purchase(@amount, @credit_card, @options) assert_failure response assert response.message =~ /DECLINED/ end + def test_transcript_scrubbing + transcript = capture_transcript(@gateway) do + @gateway.purchase(@amount, @credit_card, @options) + end + transcript = @gateway.scrub(transcript) + + assert_scrubbed(@credit_card.number, transcript) + assert_scrubbed(@credit_card.verification_value, transcript) + assert_scrubbed(@gateway.options[:merchantpin], transcript) + + transcript = capture_transcript(@gateway) do + @gateway.purchase(@amount, @check, @options) + end + transcript = @gateway.scrub(transcript) + + assert_scrubbed(@check.account_number, transcript) + assert_scrubbed(@gateway.options[:merchantpin], transcript) + end end diff --git a/test/schema/cyber_source/CyberSourceTransaction_1.121.xsd b/test/schema/cyber_source/CyberSourceTransaction_1.121.xsd new file mode 100644 index 00000000000..dbf57b71011 --- /dev/null +++ b/test/schema/cyber_source/CyberSourceTransaction_1.121.xsd @@ -0,0 +1,3627 @@ +<?xml version="1.0" encoding="utf-8"?> +<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:tns="urn:schemas-cybersource-com:transaction-data-1.121" targetNamespace="urn:schemas-cybersource-com:transaction-data-1.121" elementFormDefault="qualified" attributeFormDefault="unqualified"> + <xsd:simpleType name="amount"> + <xsd:restriction base="xsd:string"/> + </xsd:simpleType> + <xsd:simpleType name="boolean"> + <xsd:restriction base="xsd:string"/> + </xsd:simpleType> + <xsd:simpleType name="dateTime"> + <xsd:restriction base="xsd:string"/> + </xsd:simpleType> + <xsd:complexType name="Item"> + <xsd:sequence> + <xsd:element name="unitPrice" type="tns:amount" minOccurs="0"/> + <xsd:element name="quantity" type="tns:amount" minOccurs="0"/> + <xsd:element name="productCode" type="xsd:string" minOccurs="0"/> + <xsd:element name="productName" type="xsd:string" minOccurs="0"/> + <xsd:element name="productSKU" type="xsd:string" minOccurs="0"/> + <xsd:element name="productRisk" type="xsd:string" minOccurs="0"/> + <xsd:element name="taxAmount" type="tns:amount" minOccurs="0"/> + <xsd:element name="cityOverrideAmount" type="tns:amount" minOccurs="0"/> + <xsd:element name="cityOverrideRate" type="tns:amount" minOccurs="0"/> + <xsd:element name="countyOverrideAmount" type="tns:amount" minOccurs="0"/> + <xsd:element name="countyOverrideRate" type="tns:amount" minOccurs="0"/> + <xsd:element name="districtOverrideAmount" type="tns:amount" minOccurs="0"/> + <xsd:element name="districtOverrideRate" type="tns:amount" minOccurs="0"/> + <xsd:element name="stateOverrideAmount" type="tns:amount" minOccurs="0"/> + <xsd:element name="stateOverrideRate" type="tns:amount" minOccurs="0"/> + <xsd:element name="countryOverrideAmount" type="tns:amount" minOccurs="0"/> + <xsd:element name="countryOverrideRate" type="tns:amount" minOccurs="0"/> + <xsd:element name="orderAcceptanceCity" type="xsd:string" minOccurs="0"/> + <xsd:element name="orderAcceptanceCounty" type="xsd:string" minOccurs="0"/> + <xsd:element name="orderAcceptanceCountry" type="xsd:string" minOccurs="0"/> + <xsd:element name="orderAcceptanceState" type="xsd:string" minOccurs="0"/> + <xsd:element name="orderAcceptancePostalCode" type="xsd:string" minOccurs="0"/> + <xsd:element name="orderOriginCity" type="xsd:string" minOccurs="0"/> + <xsd:element name="orderOriginCounty" type="xsd:string" minOccurs="0"/> + <xsd:element name="orderOriginCountry" type="xsd:string" minOccurs="0"/> + <xsd:element name="orderOriginState" type="xsd:string" minOccurs="0"/> + <xsd:element name="orderOriginPostalCode" type="xsd:string" minOccurs="0"/> + <xsd:element name="shipFromCity" type="xsd:string" minOccurs="0"/> + <xsd:element name="shipFromCounty" type="xsd:string" minOccurs="0"/> + <xsd:element name="shipFromCountry" type="xsd:string" minOccurs="0"/> + <xsd:element name="shipFromState" type="xsd:string" minOccurs="0"/> + <xsd:element name="shipFromPostalCode" type="xsd:string" minOccurs="0"/> + <xsd:element name="export" type="xsd:string" minOccurs="0"/> + <xsd:element name="noExport" type="xsd:string" minOccurs="0"/> + <xsd:element name="nationalTax" type="tns:amount" minOccurs="0"/> + <xsd:element name="vatRate" type="tns:amount" minOccurs="0"/> + <xsd:element name="sellerRegistration" type="xsd:string" minOccurs="0"/> + <xsd:element name="sellerRegistration0" type="xsd:string" minOccurs="0"/> + <xsd:element name="sellerRegistration1" type="xsd:string" minOccurs="0"/> + <xsd:element name="sellerRegistration2" type="xsd:string" minOccurs="0"/> + <xsd:element name="sellerRegistration3" type="xsd:string" minOccurs="0"/> + <xsd:element name="sellerRegistration4" type="xsd:string" minOccurs="0"/> + <xsd:element name="sellerRegistration5" type="xsd:string" minOccurs="0"/> + <xsd:element name="sellerRegistration6" type="xsd:string" minOccurs="0"/> + <xsd:element name="sellerRegistration7" type="xsd:string" minOccurs="0"/> + <xsd:element name="sellerRegistration8" type="xsd:string" minOccurs="0"/> + <xsd:element name="sellerRegistration9" type="xsd:string" minOccurs="0"/> + <xsd:element name="buyerRegistration" type="xsd:string" minOccurs="0"/> + <xsd:element name="middlemanRegistration" type="xsd:string" minOccurs="0"/> + <xsd:element name="pointOfTitleTransfer" type="xsd:string" minOccurs="0"/> + <xsd:element name="giftCategory" type="tns:boolean" minOccurs="0"/> + <xsd:element name="timeCategory" type="xsd:string" minOccurs="0"/> + <xsd:element name="hostHedge" type="xsd:string" minOccurs="0"/> + <xsd:element name="timeHedge" type="xsd:string" minOccurs="0"/> + <xsd:element name="velocityHedge" type="xsd:string" minOccurs="0"/> + <xsd:element name="nonsensicalHedge" type="xsd:string" minOccurs="0"/> + <xsd:element name="phoneHedge" type="xsd:string" minOccurs="0"/> + <xsd:element name="obscenitiesHedge" type="xsd:string" minOccurs="0"/> + <xsd:element name="unitOfMeasure" type="xsd:string" minOccurs="0"/> + <xsd:element name="taxRate" type="tns:amount" minOccurs="0"/> + <xsd:element name="totalAmount" type="tns:amount" minOccurs="0"/> + <xsd:element name="discountAmount" type="tns:amount" minOccurs="0"/> + <xsd:element name="discountRate" type="tns:amount" minOccurs="0"/> + <xsd:element name="commodityCode" type="xsd:string" minOccurs="0"/> + <xsd:element name="grossNetIndicator" type="xsd:string" minOccurs="0"/> + <xsd:element name="taxTypeApplied" type="xsd:string" minOccurs="0"/> + <xsd:element name="discountIndicator" type="xsd:string" minOccurs="0"/> + <xsd:element name="alternateTaxID" type="xsd:string" minOccurs="0"/> + <xsd:element name="alternateTaxAmount" type="tns:amount" minOccurs="0"/> + <xsd:element name="alternateTaxTypeApplied" type="xsd:string" minOccurs="0"/> + <xsd:element name="alternateTaxRate" type="tns:amount" minOccurs="0"/> + <xsd:element name="alternateTaxType" type="xsd:string" minOccurs="0"/> + <xsd:element name="localTax" type="tns:amount" minOccurs="0"/> + <xsd:element name="zeroCostToCustomerIndicator" type="xsd:string" minOccurs="0"/> + <xsd:element name="passengerFirstName" type="xsd:string" minOccurs="0"/> + <xsd:element name="passengerLastName" type="xsd:string" minOccurs="0"/> + <xsd:element name="passengerID" type="xsd:string" minOccurs="0"/> + <xsd:element name="passengerStatus" type="xsd:string" minOccurs="0"/> + <xsd:element name="passengerType" type="xsd:string" minOccurs="0"/> + <xsd:element name="passengerEmail" type="xsd:string" minOccurs="0"/> + <xsd:element name="passengerPhone" type="xsd:string" minOccurs="0"/> + <xsd:element name="invoiceNumber" type="xsd:string" minOccurs="0"/> + <xsd:element name="productDescription" type="xsd:string" minOccurs="0"/> + <xsd:element name="taxStatusIndicator" type="xsd:string" minOccurs="0"/> + <xsd:element name="discountManagementIndicator" type="xsd:string" minOccurs="0"/> + <xsd:element name="typeOfSupply" type="xsd:string" minOccurs="0"/> + <xsd:element name="sign" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + <xsd:attribute name="id" type="xsd:integer" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CCAuthService"> + <xsd:sequence> + <xsd:element name="cavv" type="xsd:string" minOccurs="0"/> + <xsd:element name="cavvAlgorithm" type="xsd:string" minOccurs="0"/> + <xsd:element name="commerceIndicator" type="xsd:string" minOccurs="0"/> + <xsd:element name="eciRaw" type="xsd:string" minOccurs="0"/> + <xsd:element name="xid" type="xsd:string" minOccurs="0"/> + <xsd:element name="reconciliationID" type="xsd:string" minOccurs="0"/> + <xsd:element name="avsLevel" type="xsd:string" minOccurs="0"/> + <xsd:element name="fxQuoteID" type="xsd:string" minOccurs="0"/> + <xsd:element name="returnAuthRecord" type="tns:boolean" minOccurs="0"/> + <xsd:element name="authType" type="xsd:string" minOccurs="0"/> + <xsd:element name="verbalAuthCode" type="xsd:string" minOccurs="0"/> + <xsd:element name="billPayment" type="tns:boolean" minOccurs="0"/> + <xsd:element name="authenticationXID" type="xsd:string" minOccurs="0"/> + <xsd:element name="authorizationXID" type="xsd:string" minOccurs="0"/> + <xsd:element name="industryDatatype" type="xsd:string" minOccurs="0"/> + <xsd:element name="traceNumber" type="xsd:string" minOccurs="0"/> + <xsd:element name="checksumKey" type="xsd:string" minOccurs="0"/> + <xsd:element name="aggregatorID" type="xsd:string" minOccurs="0"/> + <xsd:element name="aggregatorName" type="xsd:string" minOccurs="0"/> + <xsd:element name="splitTenderIndicator" type="xsd:string" minOccurs="0"/> + <xsd:element name="veresEnrolled" type="xsd:string" minOccurs="0"/> + <xsd:element name="paresStatus" type="xsd:string" minOccurs="0"/> + <xsd:element name="partialAuthIndicator" type="tns:boolean" minOccurs="0"/> + <xsd:element name="captureDate" type="xsd:string" minOccurs="0"/> + <xsd:element name="firstRecurringPayment" type="xsd:string" minOccurs="0"/> + <xsd:element name="duration" type="xsd:integer" minOccurs="0"/> + <xsd:element name="overridePaymentMethod" type="xsd:string" minOccurs="0"/> + <xsd:element name="mobileRemotePaymentType" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + <xsd:attribute name="run" type="tns:boolean" use="required"/> + </xsd:complexType> + <xsd:complexType name="OCTService"> + <xsd:sequence> + <xsd:element name="commerceIndicator" type="xsd:string" minOccurs="0"/> + <xsd:element name="reconciliationID" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + <xsd:attribute name="run" type="tns:boolean" use="required"/> + </xsd:complexType> + + <xsd:complexType name="CCSaleService"> + <xsd:sequence> + <xsd:element name="overridePaymentMethod" type="xsd:string" minOccurs="0"/> + <xsd:element name="commerceIndicator" type="xsd:string" minOccurs="0"/> + <xsd:element name="partialAuthIndicator" type="tns:boolean" minOccurs="0"/> + <xsd:element name="cavv" type="xsd:string" minOccurs="0"/> + <xsd:element name="xid" type="xsd:string" minOccurs="0"/> + <xsd:element name="reconciliationID" type="xsd:string" minOccurs="0"/> +</xsd:sequence> + <xsd:attribute name="run" type="tns:boolean" use="required"/> + </xsd:complexType> + + <xsd:complexType name="CCSaleCreditService"> + <xsd:sequence> + <xsd:element name="overridePaymentMethod" type="xsd:string" minOccurs="0"/> + <xsd:element name="commerceIndicator" type="xsd:string" minOccurs="0"/> + <xsd:element name="reconciliationID" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + <xsd:attribute name="run" type="tns:boolean" use="required"/> + </xsd:complexType> + + <xsd:complexType name="CCSaleReversalService"> + <xsd:sequence> + <xsd:element name="saleRequestID" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + <xsd:attribute name="run" type="tns:boolean" use="required"/> + </xsd:complexType> + + <xsd:complexType name="CCIncrementalAuthService"> + <xsd:sequence> + <xsd:element name="authRequestID" type="xsd:string" minOccurs="0" /> + <xsd:element name="duration" type="xsd:integer" minOccurs="0" /> + </xsd:sequence> + <xsd:attribute name="run" type="tns:boolean" use="required" /> + </xsd:complexType> + <xsd:complexType name="CCCaptureService"> + <xsd:sequence> + <xsd:element name="authType" type="xsd:string" minOccurs="0"/> + <xsd:element name="verbalAuthCode" type="xsd:string" minOccurs="0"/> + <xsd:element name="authRequestID" type="xsd:string" minOccurs="0"/> + <xsd:element name="reconciliationID" type="xsd:string" minOccurs="0"/> + <xsd:element name="partialPaymentID" type="xsd:string" minOccurs="0"/> + <xsd:element name="purchasingLevel" type="xsd:string" minOccurs="0"/> + <xsd:element name="industryDatatype" type="xsd:string" minOccurs="0"/> + <xsd:element name="authRequestToken" type="xsd:string" minOccurs="0"/> + <xsd:element name="merchantReceiptNumber" type="xsd:string" minOccurs="0"/> + <xsd:element name="posData" type="xsd:string" minOccurs="0"/> + <xsd:element name="transactionID" type="xsd:string" minOccurs="0"/> + <xsd:element name="checksumKey" type="xsd:string" minOccurs="0"/> + <xsd:element name="gratuityAmount" type="xsd:string" minOccurs="0"/> + <xsd:element name="duration" type="xsd:integer" minOccurs="0"/> + <xsd:element name="dpdeBillingMonth" type="xsd:integer" minOccurs="0"/> + <xsd:element name="sequence" type="xsd:string" minOccurs="0"/> + <xsd:element name="totalCount" type="xsd:string" minOccurs="0"/> + <xsd:element name="reconciliationIDAlternate" type="xsd:string" minOccurs="0"/> + <xsd:element name="aggregatorID" type="xsd:string" minOccurs="0"/> + <xsd:element name="aggregatorName" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + <xsd:attribute name="run" type="tns:boolean" use="required"/> + </xsd:complexType> + <xsd:complexType name="CCCreditService"> + <xsd:sequence> + <xsd:element name="captureRequestID" type="xsd:string" minOccurs="0"/> + <xsd:element name="reconciliationID" type="xsd:string" minOccurs="0"/> + <xsd:element name="partialPaymentID" type="xsd:string" minOccurs="0"/> + <xsd:element name="purchasingLevel" type="xsd:string" minOccurs="0"/> + <xsd:element name="industryDatatype" type="xsd:string" minOccurs="0"/> + <xsd:element name="commerceIndicator" type="xsd:string" minOccurs="0"/> + <xsd:element name="billPayment" type="tns:boolean" minOccurs="0"/> + <xsd:element name="authorizationXID" type="xsd:string" minOccurs="0"/> + <xsd:element name="occurrenceNumber" type="xsd:string" minOccurs="0"/> + <xsd:element name="authCode" type="xsd:string" minOccurs="0"/> + <xsd:element name="captureRequestToken" type="xsd:string" minOccurs="0"/> + <xsd:element name="merchantReceiptNumber" type="xsd:string" minOccurs="0"/> + <xsd:element name="checksumKey" type="xsd:string" minOccurs="0"/> + <xsd:element name="aggregatorID" type="xsd:string" minOccurs="0"/> + <xsd:element name="aggregatorName" type="xsd:string" minOccurs="0"/> + <xsd:element name="duration" type="xsd:integer" minOccurs="0"/> + <xsd:element name="dpdeBillingMonth" type="xsd:integer" minOccurs="0"/> + <xsd:element name="reconciliationIDAlternate" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + <xsd:attribute name="run" type="tns:boolean" use="required"/> + </xsd:complexType> + <xsd:complexType name="CCAuthReversalService"> + <xsd:sequence> + <xsd:element name="authRequestID" type="xsd:string" minOccurs="0"/> + <xsd:element name="authRequestToken" type="xsd:string" minOccurs="0"/> + <xsd:element name="reversalReason" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + <xsd:attribute name="run" type="tns:boolean" use="required"/> + </xsd:complexType> + <xsd:complexType name="CCAutoAuthReversalService"> + <xsd:sequence> + <xsd:element name="authPaymentServiceData" type="xsd:string" minOccurs="0"/> + <xsd:element name="reconciliationID" type="xsd:string" minOccurs="0"/> + <xsd:element name="authAmount" type="xsd:string" minOccurs="0"/> + <xsd:element name="commerceIndicator" type="xsd:string" minOccurs="0"/> + <xsd:element name="authRequestID" type="xsd:string" minOccurs="0"/> + <xsd:element name="billAmount" type="xsd:string" minOccurs="0"/> + <xsd:element name="authCode" type="xsd:string" minOccurs="0"/> + <xsd:element name="authType" type="xsd:string" minOccurs="0"/> + <xsd:element name="billPayment" type="tns:boolean" minOccurs="0"/> + <xsd:element name="dateAdded" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + <xsd:attribute name="run" type="tns:boolean" use="required"/> + </xsd:complexType> + <xsd:complexType name="CCDCCService"> + <xsd:attribute name="run" type="tns:boolean" use="required"/> + </xsd:complexType> + <xsd:complexType name="ServiceFeeCalculateService"> + <xsd:attribute name="run" type="tns:boolean" use="required"/> + </xsd:complexType> + <xsd:complexType name="ECDebitService"> + <xsd:sequence> + <xsd:element name="paymentMode" type="xsd:integer" minOccurs="0"/> + <xsd:element name="referenceNumber" type="xsd:string" minOccurs="0"/> + <xsd:element name="settlementMethod" type="xsd:string" minOccurs="0"/> + <xsd:element name="transactionToken" type="xsd:string" minOccurs="0"/> + <xsd:element name="verificationLevel" type="xsd:integer" minOccurs="0"/> + <xsd:element name="partialPaymentID" type="xsd:string" minOccurs="0"/> + <xsd:element name="commerceIndicator" type="xsd:string" minOccurs="0"/> + <xsd:element name="debitRequestID" type="xsd:string" minOccurs="0"/> + <xsd:element name="effectiveDate" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + <xsd:attribute name="run" type="tns:boolean" use="required"/> + </xsd:complexType> + <xsd:complexType name="ECCreditService"> + <xsd:sequence> + <xsd:element name="referenceNumber" type="xsd:string" minOccurs="0"/> + <xsd:element name="settlementMethod" type="xsd:string" minOccurs="0"/> + <xsd:element name="transactionToken" type="xsd:string" minOccurs="0"/> + <xsd:element name="debitRequestID" type="xsd:string" minOccurs="0"/> + <xsd:element name="partialPaymentID" type="xsd:string" minOccurs="0"/> + <xsd:element name="commerceIndicator" type="xsd:string" minOccurs="0"/> + <xsd:element name="debitRequestToken" type="xsd:string" minOccurs="0"/> + <xsd:element name="effectiveDate" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + <xsd:attribute name="run" type="tns:boolean" use="required"/> + </xsd:complexType> + <xsd:complexType name="ECAuthenticateService"> + <xsd:sequence> + <xsd:element name="referenceNumber" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + <xsd:attribute name="run" type="tns:boolean" use="required"/> + </xsd:complexType> + <xsd:complexType name="PayerAuthEnrollService"> + <xsd:sequence> + <xsd:element name="httpAccept" type="xsd:string" minOccurs="0"/> + <xsd:element name="httpUserAgent" type="xsd:string" minOccurs="0"/> + <xsd:element name="merchantName" type="xsd:string" minOccurs="0"/> + <xsd:element name="merchantURL" type="xsd:string" minOccurs="0"/> + <xsd:element name="purchaseDescription" type="xsd:string" minOccurs="0"/> + <xsd:element name="purchaseTime" type="tns:dateTime" minOccurs="0"/> + <xsd:element name="countryCode" type="xsd:string" minOccurs="0"/> + <xsd:element name="acquirerBin" type="xsd:string" minOccurs="0"/> + <xsd:element name="loginID" type="xsd:string" minOccurs="0"/> + <xsd:element name="password" type="xsd:string" minOccurs="0"/> + <xsd:element name="merchantID" type="xsd:string" minOccurs="0"/> + <xsd:element name="overridePaymentMethod" type="xsd:string" minOccurs="0"/> + <xsd:element name="mobilePhone" type="xsd:string" minOccurs="0"/> + <xsd:element name="MCC" type="xsd:string" minOccurs="0"/> + <xsd:element name="productCode" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + <xsd:attribute name="run" type="tns:boolean" use="required"/> + </xsd:complexType> + <xsd:complexType name="PayerAuthValidateService"> + <xsd:sequence> + <xsd:element name="signedPARes" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + <xsd:attribute name="run" type="tns:boolean" use="required"/> + </xsd:complexType> + <xsd:complexType name="TaxService"> + <xsd:sequence> + <xsd:element name="nexus" type="xsd:string" minOccurs="0"/> + <xsd:element name="noNexus" type="xsd:string" minOccurs="0"/> + <xsd:element name="orderAcceptanceCity" type="xsd:string" minOccurs="0"/> + <xsd:element name="orderAcceptanceCounty" type="xsd:string" minOccurs="0"/> + <xsd:element name="orderAcceptanceCountry" type="xsd:string" minOccurs="0"/> + <xsd:element name="orderAcceptanceState" type="xsd:string" minOccurs="0"/> + <xsd:element name="orderAcceptancePostalCode" type="xsd:string" minOccurs="0"/> + <xsd:element name="orderOriginCity" type="xsd:string" minOccurs="0"/> + <xsd:element name="orderOriginCounty" type="xsd:string" minOccurs="0"/> + <xsd:element name="orderOriginCountry" type="xsd:string" minOccurs="0"/> + <xsd:element name="orderOriginState" type="xsd:string" minOccurs="0"/> + <xsd:element name="orderOriginPostalCode" type="xsd:string" minOccurs="0"/> + <xsd:element name="sellerRegistration" type="xsd:string" minOccurs="0"/> + <xsd:element name="sellerRegistration0" type="xsd:string" minOccurs="0"/> + <xsd:element name="sellerRegistration1" type="xsd:string" minOccurs="0"/> + <xsd:element name="sellerRegistration2" type="xsd:string" minOccurs="0"/> + <xsd:element name="sellerRegistration3" type="xsd:string" minOccurs="0"/> + <xsd:element name="sellerRegistration4" type="xsd:string" minOccurs="0"/> + <xsd:element name="sellerRegistration5" type="xsd:string" minOccurs="0"/> + <xsd:element name="sellerRegistration6" type="xsd:string" minOccurs="0"/> + <xsd:element name="sellerRegistration7" type="xsd:string" minOccurs="0"/> + <xsd:element name="sellerRegistration8" type="xsd:string" minOccurs="0"/> + <xsd:element name="sellerRegistration9" type="xsd:string" minOccurs="0"/> + <xsd:element name="buyerRegistration" type="xsd:string" minOccurs="0"/> + <xsd:element name="middlemanRegistration" type="xsd:string" minOccurs="0"/> + <xsd:element name="pointOfTitleTransfer" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + <xsd:attribute name="run" type="tns:boolean" use="required"/> + </xsd:complexType> + <!-- DME --> + <xsd:complexType name="DMEService"> + <xsd:sequence> + <xsd:element name="eventType" type="xsd:string" minOccurs="0" /> + <xsd:element name="eventPolicy" type="xsd:string" minOccurs="0" /> + </xsd:sequence> + <xsd:attribute name="run" type="tns:boolean" use="required" /> + </xsd:complexType> + <xsd:complexType name="AFSService"> + <xsd:sequence> + <xsd:element name="avsCode" type="xsd:string" minOccurs="0"/> + <xsd:element name="cvCode" type="xsd:string" minOccurs="0"/> + <xsd:element name="disableAVSScoring" type="tns:boolean" minOccurs="0"/> + <xsd:element name="customRiskModel" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + <xsd:attribute name="run" type="tns:boolean" use="required"/> + </xsd:complexType> + <xsd:complexType name="DAVService"> + <xsd:attribute name="run" type="tns:boolean" use="required"/> + </xsd:complexType> + <xsd:complexType name="ExportService"> + <xsd:sequence> + <xsd:element name="addressOperator" type="xsd:string" minOccurs="0"/> + <xsd:element name="addressWeight" type="xsd:string" minOccurs="0"/> + <xsd:element name="companyWeight" type="xsd:string" minOccurs="0"/> + <xsd:element name="nameWeight" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + <xsd:attribute name="run" type="tns:boolean" use="required"/> + </xsd:complexType> + <xsd:complexType name="FXRatesService"> + <xsd:attribute name="run" type="tns:boolean" use="required"/> + </xsd:complexType> + <xsd:complexType name="BankTransferService"> + <xsd:attribute name="run" type="tns:boolean" use="required"/> + </xsd:complexType> + <xsd:complexType name="BankTransferRefundService"> + <xsd:sequence> + <xsd:element name="bankTransferRequestID" type="xsd:string" minOccurs="0"/> + <xsd:element name="bankTransferRealTimeRequestID" type="xsd:string" minOccurs="0"/> + <xsd:element name="reconciliationID" type="xsd:string" minOccurs="0"/> + <xsd:element name="bankTransferRealTimeReconciliationID" type="xsd:string" minOccurs="0"/> + <xsd:element name="bankTransferRequestToken" type="xsd:string" minOccurs="0"/> + <xsd:element name="bankTransferRealTimeRequestToken" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + <xsd:attribute name="run" type="tns:boolean" use="required"/> + </xsd:complexType> + <xsd:complexType name="BankTransferRealTimeService"> + <xsd:sequence> + <xsd:element name="bankTransferRealTimeType" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + <xsd:attribute name="run" type="tns:boolean" use="required"/> + </xsd:complexType> + <xsd:complexType name="DirectDebitMandateService"> + <xsd:sequence> + <xsd:element name="mandateDescriptor" type="xsd:string" minOccurs="0"/> + <xsd:element name="firstDebitDate" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + <xsd:attribute name="run" type="tns:boolean" use="required"/> + </xsd:complexType> + <xsd:complexType name="DirectDebitService"> + <xsd:sequence> + <xsd:element name="dateCollect" type="xsd:string" minOccurs="0"/> + <xsd:element name="directDebitText" type="xsd:string" minOccurs="0"/> + <xsd:element name="authorizationID" type="xsd:string" minOccurs="0"/> + <xsd:element name="transactionType" type="xsd:string" minOccurs="0"/> + <xsd:element name="directDebitType" type="xsd:string" minOccurs="0"/> + <xsd:element name="validateRequestID" type="xsd:string" minOccurs="0"/> + <xsd:element name="recurringType" type="xsd:string" minOccurs="0"/> + <xsd:element name="mandateID" type="xsd:string" minOccurs="0"/> + <xsd:element name="validateRequestToken" type="xsd:string" minOccurs="0"/> + <xsd:element name="reconciliationID" type="xsd:string" minOccurs="0"/> + <xsd:element name="mandateAuthenticationDate" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + <xsd:attribute name="run" type="tns:boolean" use="required"/> + </xsd:complexType> + <xsd:complexType name="DirectDebitRefundService"> + <xsd:sequence> + <xsd:element name="directDebitRequestID" type="xsd:string" minOccurs="0"/> + <xsd:element name="reconciliationID" type="xsd:string" minOccurs="0"/> + <xsd:element name="directDebitRequestToken" type="xsd:string" minOccurs="0"/> + <xsd:element name="directDebitType" type="xsd:string" minOccurs="0"/> + <xsd:element name="recurringType" type="xsd:string" minOccurs="0"/> + <xsd:element name="mandateID" type="xsd:string" minOccurs="0"/> + <xsd:element name="mandateAuthenticationDate" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + <xsd:attribute name="run" type="tns:boolean" use="required"/> + </xsd:complexType> + <xsd:complexType name="DirectDebitValidateService"> + <xsd:sequence> + <xsd:element name="directDebitValidateText" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + <xsd:attribute name="run" type="tns:boolean" use="required"/> + </xsd:complexType> + <xsd:complexType name="PaySubscriptionCreateService"> + <xsd:sequence> + <xsd:element name="paymentRequestID" type="xsd:string" minOccurs="0"/> + <xsd:element name="paymentRequestToken" type="xsd:string" minOccurs="0"/> + <xsd:element name="disableAutoAuth" type="tns:boolean" minOccurs="0"/> + </xsd:sequence> + <xsd:attribute name="run" type="tns:boolean" use="required"/> + </xsd:complexType> + <xsd:complexType name="PaySubscriptionUpdateService"> + <xsd:attribute name="run" type="tns:boolean" use="required"/> + </xsd:complexType> + <xsd:complexType name="PaySubscriptionEventUpdateService"> + <xsd:sequence> + <xsd:element name="action" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + <xsd:attribute name="run" type="tns:boolean" use="required"/> + </xsd:complexType> + <xsd:complexType name="PaySubscriptionRetrieveService"> + <xsd:attribute name="run" type="tns:boolean" use="required"/> + </xsd:complexType> + <xsd:complexType name="PaySubscriptionDeleteService"> + <xsd:attribute name="run" type="tns:boolean" use="required"/> + </xsd:complexType> + <xsd:complexType name="PayPalPaymentService"> + <xsd:sequence> + <xsd:element name="cancelURL" type="xsd:string" minOccurs="0"/> + <xsd:element name="successURL" type="xsd:string" minOccurs="0"/> + <xsd:element name="reconciliationID" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + <xsd:attribute name="run" type="tns:boolean" use="required"/> + </xsd:complexType> + <xsd:complexType name="PayPalCreditService"> + <xsd:sequence> + <xsd:element name="payPalPaymentRequestID" type="xsd:string" minOccurs="0"/> + <xsd:element name="reconciliationID" type="xsd:string" minOccurs="0"/> + <xsd:element name="payPalPaymentRequestToken" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + <xsd:attribute name="run" type="tns:boolean" use="required"/> + </xsd:complexType> + <!--PayPalEcSet--> + <xsd:complexType name="PayPalEcSetService"> + <xsd:sequence> + <xsd:element name="paypalReturn" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalCancelReturn" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalMaxamt" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalCustomerEmail" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalDesc" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalReqconfirmshipping" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalNoshipping" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalAddressOverride" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalToken" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalLc" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalPagestyle" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalHdrimg" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalHdrbordercolor" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalHdrbackcolor" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalPayflowcolor" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalEcSetRequestID" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalEcSetRequestToken" type="xsd:string" minOccurs="0"/> + <xsd:element name="promoCode0" type="xsd:string" minOccurs="0"/> + <xsd:element name="requestBillingAddress" type="xsd:string" minOccurs="0"/> + <xsd:element name="invoiceNumber" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalBillingType" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalBillingAgreementDesc" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalPaymentType" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalBillingAgreementCustom" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalLogoimg" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + <xsd:attribute name="run" type="tns:boolean" use="required"/> + </xsd:complexType> + <!--PayPalEcGetDetails--> + <xsd:complexType name="PayPalEcGetDetailsService"> + <xsd:sequence> + <xsd:element name="paypalToken" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalEcSetRequestID" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalEcSetRequestToken" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + <xsd:attribute name="run" type="tns:boolean" use="required"/> + </xsd:complexType> + <!--PayPalEcDoPayment--> + <xsd:complexType name="PayPalEcDoPaymentService"> + <xsd:sequence> + <xsd:element name="paypalToken" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalPayerId" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalCustomerEmail" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalDesc" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalEcSetRequestID" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalEcSetRequestToken" type="xsd:string" minOccurs="0"/> + <xsd:element name="promoCode0" type="xsd:string" minOccurs="0"/> + <xsd:element name="invoiceNumber" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + <xsd:attribute name="run" type="tns:boolean" use="required"/> + </xsd:complexType> + <!--PayPalDoCapture--> + <xsd:complexType name="PayPalDoCaptureService"> + <xsd:sequence> + <xsd:element name="paypalAuthorizationId" type="xsd:string" minOccurs="0"/> + <xsd:element name="completeType" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalEcDoPaymentRequestID" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalEcDoPaymentRequestToken" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalAuthorizationRequestID" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalAuthorizationRequestToken" type="xsd:string" minOccurs="0"/> + <xsd:element name="invoiceNumber" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + <xsd:attribute name="run" type="tns:boolean" use="required"/> + </xsd:complexType> + <!--PayPalAuthReversal--> + <xsd:complexType name="PayPalAuthReversalService"> + <xsd:sequence> + <xsd:element name="paypalAuthorizationId" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalEcDoPaymentRequestID" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalEcDoPaymentRequestToken" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalAuthorizationRequestID" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalAuthorizationRequestToken" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalEcOrderSetupRequestID" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalEcOrderSetupRequestToken" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + <xsd:attribute name="run" type="tns:boolean" use="required"/> + </xsd:complexType> + <!--PayPalRefund--> + <xsd:complexType name="PayPalRefundService"> + <xsd:sequence> + <xsd:element name="paypalDoCaptureRequestID" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalDoCaptureRequestToken" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalCaptureId" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalNote" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + <xsd:attribute name="run" type="tns:boolean" use="required"/> + </xsd:complexType> + <!--PayPalEcOrderSetup--> + <xsd:complexType name="PayPalEcOrderSetupService"> + <xsd:sequence> + <xsd:element name="paypalToken" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalPayerId" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalCustomerEmail" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalDesc" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalEcSetRequestID" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalEcSetRequestToken" type="xsd:string" minOccurs="0"/> + <xsd:element name="promoCode0" type="xsd:string" minOccurs="0"/> + <xsd:element name="invoiceNumber" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + <xsd:attribute name="run" type="tns:boolean" use="required"/> + </xsd:complexType> + <!--PayPalAuthorization--> + <xsd:complexType name="PayPalAuthorizationService"> + <xsd:sequence> + <xsd:element name="paypalOrderId" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalEcOrderSetupRequestID" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalEcOrderSetupRequestToken" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalDoRefTransactionRequestID" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalDoRefTransactionRequestToken" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalCustomerEmail" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + <xsd:attribute name="run" type="tns:boolean" use="required"/> + </xsd:complexType> + <!--PayPalUpdateAgreement--> + <xsd:complexType name="PayPalUpdateAgreementService"> + <xsd:sequence> + <xsd:element name="paypalBillingAgreementId" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalBillingAgreementStatus" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalBillingAgreementDesc" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalBillingAgreementCustom" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + <xsd:attribute name="run" type="tns:boolean" use="required"/> + </xsd:complexType> + <!--PayPalCreateAgreement--> + <xsd:complexType name="PayPalCreateAgreementService"> + <xsd:sequence> + <xsd:element name="paypalToken" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalEcSetRequestID" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalEcSetRequestToken" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + <xsd:attribute name="run" type="tns:boolean" use="required"/> + </xsd:complexType> + <!--PayPalDoRefTransaction--> + <xsd:complexType name="PayPalDoRefTransactionService"> + <xsd:sequence> + <xsd:element name="paypalBillingAgreementId" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalPaymentType" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalReqconfirmshipping" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalReturnFmfDetails" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalSoftDescriptor" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalShippingdiscount" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalDesc" type="xsd:string" minOccurs="0"/> + <xsd:element name="invoiceNumber" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalEcNotifyUrl" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + <xsd:attribute name="run" type="tns:boolean" use="required"/> + </xsd:complexType> + <xsd:complexType name="VoidService"> + <xsd:sequence> + <xsd:element name="voidRequestID" type="xsd:string" minOccurs="0"/> + <xsd:element name="voidRequestToken" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + <xsd:attribute name="run" type="tns:boolean" use="required"/> + </xsd:complexType> + <xsd:complexType name="PinlessDebitService"> + <xsd:sequence> + <xsd:element name="reconciliationID" type="xsd:string" minOccurs="0"/> + <xsd:element name="commerceIndicator" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + <xsd:attribute name="run" type="tns:boolean" use="required"/> + </xsd:complexType> + <xsd:complexType name="PinlessDebitValidateService"> + <xsd:attribute name="run" type="tns:boolean" use="required"/> + </xsd:complexType> + <xsd:complexType name="PinlessDebitReversalService"> + <xsd:sequence> + <xsd:element name="pinlessDebitRequestID" type="xsd:string" minOccurs="0"/> + <xsd:element name="pinlessDebitRequestToken" type="xsd:string" minOccurs="0"/> + <xsd:element name="reconciliationID" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + <xsd:attribute name="run" type="tns:boolean" use="required"/> + </xsd:complexType> + + <!--PinDebitPurchaseService--> + <xsd:complexType name="PinDebitPurchaseService"> + <xsd:sequence> + <xsd:element name="networkOrder" type="xsd:string" minOccurs="0"/> + <xsd:element name="commerceIndicator" type="xsd:string" minOccurs="0"/> + <xsd:element name="reconciliationID" type="xsd:string" minOccurs="0"/> + <xsd:element name="partialAuthIndicator" type="tns:boolean" minOccurs="0"/> + <xsd:element name="overridePaymentMethod" type="xsd:string" minOccurs="0"/> + <xsd:element name="paymentType" type="xsd:string" minOccurs="0"/> + <xsd:element name="ebtCategory" type="xsd:string" minOccurs="0"/> + <xsd:element name="transactionType" type="xsd:string" minOccurs="0"/> + <xsd:element name="ebtVoucherSerialNumber" type="xsd:string" minOccurs="0"/> + <xsd:element name="authorizationCode" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + <xsd:attribute name="run" type="tns:boolean" use="required"/> + </xsd:complexType> + <!--End of PinDebitPurchaseService--> + <!--PinDebitCreditService--> + <xsd:complexType name="PinDebitCreditService"> + <xsd:sequence> + <xsd:element name="networkOrder" type="xsd:string" minOccurs="0"/> + <xsd:element name="commerceIndicator" type="xsd:string" minOccurs="0"/> + <xsd:element name="reconciliationID" type="xsd:string" minOccurs="0"/> + <xsd:element name="overridePaymentMethod" type="xsd:string" minOccurs="0"/> + <xsd:element name="paymentType" type="xsd:string" minOccurs="0"/> + <xsd:element name="ebtCategory" type="xsd:string" minOccurs="0"/> + <xsd:element name="transactionType" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + <xsd:attribute name="run" type="tns:boolean" use="required"/> + </xsd:complexType> + <!--End of PinDebitCreditService--> + <!--PinDebitReversalService--> + <xsd:complexType name="PinDebitReversalService"> + <xsd:sequence> + <xsd:element name="pinDebitRequestID" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + <xsd:attribute name="run" type="tns:boolean" use="required"/> + </xsd:complexType> + <!--End of PinDebitReversalService--> + + <!--PayPal upgrade services --> + <xsd:complexType name="PayPalButtonCreateService"> + <xsd:sequence> + <xsd:element name="buttonType" type="xsd:string" minOccurs="0"/> + <xsd:element name="reconciliationID" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + <xsd:attribute name="run" type="tns:boolean" use="required"/> + </xsd:complexType> + <xsd:complexType name="PayPalPreapprovedPaymentService"> + <xsd:sequence> + <xsd:element name="mpID" type="xsd:string" minOccurs="0"/> + <xsd:element name="reconciliationID" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + <xsd:attribute name="run" type="tns:boolean" use="required"/> + </xsd:complexType> + <xsd:complexType name="PayPalPreapprovedUpdateService"> + <xsd:sequence> + <xsd:element name="mpID" type="xsd:string" minOccurs="0"/> + <xsd:element name="reconciliationID" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + <xsd:attribute name="run" type="tns:boolean" use="required"/> + </xsd:complexType> + <!-- China Payment --> + <xsd:complexType name="ChinaPaymentService"> + <xsd:sequence> + <xsd:element name="paymentMode" type="xsd:string" minOccurs="0"/> + <xsd:element name="returnURL" type="xsd:string" minOccurs="0"/> + <xsd:element name="pickUpAddress" type="xsd:string" minOccurs="0"/> + <xsd:element name="pickUpPhoneNumber" type="xsd:string" minOccurs="0"/> + <xsd:element name="pickUpPostalCode" type="xsd:string" minOccurs="0"/> + <xsd:element name="pickUpName" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + <xsd:attribute name="run" type="tns:boolean" use="required"/> + </xsd:complexType> + <!-- China Refund --> + <xsd:complexType name="ChinaRefundService"> + <xsd:sequence> + <xsd:element name="chinaPaymentRequestID" type="xsd:string" minOccurs="0"/> + <xsd:element name="chinaPaymentRequestToken" type="xsd:string" minOccurs="0"/> + <xsd:element name="refundReason" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + <xsd:attribute name="run" type="tns:boolean" use="required"/> + </xsd:complexType> + <!--Boleto Payment --> + <xsd:complexType name="BoletoPaymentService"> + <xsd:sequence> + <xsd:element name="instruction" type="xsd:string" minOccurs="0"/> + <xsd:element name="expirationDate" type="xsd:string" minOccurs="0"/> + <xsd:element name="reconciliationID" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + <xsd:attribute name="run" type="tns:boolean" use="required"/> + </xsd:complexType> + <xsd:complexType name="Address"> + <xsd:sequence> + <xsd:element name="street1" type="xsd:string" minOccurs="0"/> + <xsd:element name="street2" type="xsd:string" minOccurs="0"/> + <xsd:element name="city" type="xsd:string" minOccurs="0"/> + <xsd:element name="state" type="xsd:string" minOccurs="0"/> + <xsd:element name="postalCode" type="xsd:string" minOccurs="0"/> + <xsd:element name="country" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="APInitiateService"> + <xsd:sequence> + <xsd:element name="returnURL" type="xsd:string" minOccurs="0"/> + <xsd:element name="productName" type="xsd:string" minOccurs="0"/> + <xsd:element name="productDescription" type="xsd:string" minOccurs="0"/> + <xsd:element name="reconciliationID" type="xsd:string" minOccurs="0"/> + <xsd:element name="bankID" type="xsd:string" minOccurs="0"/> + <xsd:element name="countryCode" type="xsd:string" minOccurs="0"/> + <xsd:element name="escrowAgreement" type="xsd:string" minOccurs="0"/> + <xsd:element name="languageInterface" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + <xsd:attribute name="run" type="tns:boolean" use="required"/> + </xsd:complexType> + <xsd:complexType name="APCheckStatusService"> + <xsd:sequence> + <xsd:element name="apInitiateRequestID" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + <xsd:attribute name="run" type="tns:boolean" use="required"/> + </xsd:complexType> + <xsd:complexType name="RiskUpdateService"> + <xsd:sequence> + <xsd:element name="actionCode" type="xsd:string" minOccurs="0"/> + <xsd:element name="recordID" type="xsd:string" minOccurs="0"/> + <xsd:element name="recordName" type="xsd:string" minOccurs="0"/> + <xsd:element name="negativeAddress" type="tns:Address" minOccurs="0"/> + <xsd:element name="markingReason" type="xsd:string" minOccurs="0"/> + <xsd:element name="markingNotes" type="xsd:string" minOccurs="0"/> + <xsd:element name="markingRequestID" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + <xsd:attribute name="run" type="tns:boolean" use="required"/> + </xsd:complexType> + <xsd:complexType name="FraudUpdateService"> + <xsd:sequence> + <xsd:element name="actionCode" type="xsd:string" minOccurs="0"/> + <xsd:element name="markedData" type="xsd:string" minOccurs="0"/> + <xsd:element name="markingReason" type="xsd:string" minOccurs="0"/> + <xsd:element name="markingNotes" type="xsd:string" minOccurs="0"/> + <xsd:element name="markingRequestID" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + <xsd:attribute name="run" type="tns:boolean" use="required"/> + </xsd:complexType> + <xsd:complexType name="CaseManagementActionService"> + <xsd:sequence> + <xsd:element name="actionCode" type="xsd:string" minOccurs="0"/> + <xsd:element name="requestID" type="xsd:string" minOccurs="0"/> + <xsd:element name="comments" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + <xsd:attribute name="run" type="tns:boolean" use="required"/> + </xsd:complexType> + <xsd:complexType name="EncryptPaymentDataService"> + <xsd:attribute name="run" type="tns:boolean" use="required"/> + </xsd:complexType> + <xsd:complexType name="InvoiceHeader"> + <xsd:sequence> + <xsd:element name="merchantDescriptor" type="xsd:string" minOccurs="0"/> + <xsd:element name="merchantDescriptorContact" type="xsd:string" minOccurs="0"/> + <xsd:element name="merchantDescriptorAlternate" type="xsd:string" minOccurs="0"/> + <xsd:element name="merchantDescriptorStreet" type="xsd:string" minOccurs="0"/> + <xsd:element name="merchantDescriptorCity" type="xsd:string" minOccurs="0"/> + <xsd:element name="merchantDescriptorState" type="xsd:string" minOccurs="0"/> + <xsd:element name="merchantDescriptorPostalCode" type="xsd:string" minOccurs="0"/> + <xsd:element name="merchantDescriptorCountry" type="xsd:string" minOccurs="0"/> + <xsd:element name="isGift" type="tns:boolean" minOccurs="0"/> + <xsd:element name="returnsAccepted" type="tns:boolean" minOccurs="0"/> + <xsd:element name="tenderType" type="xsd:string" minOccurs="0"/> + <xsd:element name="merchantVATRegistrationNumber" type="xsd:string" minOccurs="0"/> + <xsd:element name="purchaserOrderDate" type="xsd:string" minOccurs="0"/> + <!-- xsd:date --> + <xsd:element name="purchaserVATRegistrationNumber" type="xsd:string" minOccurs="0"/> + <xsd:element name="vatInvoiceReferenceNumber" type="xsd:string" minOccurs="0"/> + <xsd:element name="summaryCommodityCode" type="xsd:string" minOccurs="0"/> + <xsd:element name="supplierOrderReference" type="xsd:string" minOccurs="0"/> + <xsd:element name="userPO" type="xsd:string" minOccurs="0"/> + <xsd:element name="costCenter" type="xsd:string" minOccurs="0"/> + <xsd:element name="purchaserCode" type="xsd:string" minOccurs="0"/> + <xsd:element name="taxable" type="tns:boolean" minOccurs="0"/> + <xsd:element name="amexDataTAA1" type="xsd:string" minOccurs="0"/> + <xsd:element name="amexDataTAA2" type="xsd:string" minOccurs="0"/> + <xsd:element name="amexDataTAA3" type="xsd:string" minOccurs="0"/> + <xsd:element name="amexDataTAA4" type="xsd:string" minOccurs="0"/> + <xsd:element name="invoiceDate" type="xsd:string" minOccurs="0"/> + <xsd:element name="totalTaxTypeCode" type="xsd:string" minOccurs="0"/> + <xsd:element name="cardAcceptorRefNumber" type="xsd:string" minOccurs="0"/> + <xsd:element name="authorizedContactName" type="xsd:string" minOccurs="0"/> + <xsd:element name="businessApplicationID" type="xsd:string" minOccurs="0"/> + <xsd:element name="salesOrganizationID" type="xsd:integer" minOccurs="0"/> + <xsd:element name="submerchantID" type="xsd:string" minOccurs="0"/> + <xsd:element name="submerchantName" type="xsd:string" minOccurs="0"/> + <xsd:element name="submerchantStreet" type="xsd:string" minOccurs="0"/> + <xsd:element name="submerchantCity" type="xsd:string" minOccurs="0"/> + <xsd:element name="submerchantPostalCode" type="xsd:string" minOccurs="0"/> + <xsd:element name="submerchantState" type="xsd:string" minOccurs="0"/> + <xsd:element name="submerchantCountry" type="xsd:string" minOccurs="0"/> + <xsd:element name="submerchantEmail" type="xsd:string" minOccurs="0"/> + <xsd:element name="submerchantTelephoneNumber" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="BusinessRules"> + <xsd:sequence> + <xsd:element name="ignoreAVSResult" type="tns:boolean" minOccurs="0"/> + <xsd:element name="ignoreCVResult" type="tns:boolean" minOccurs="0"/> + <xsd:element name="ignoreDAVResult" type="tns:boolean" minOccurs="0"/> + <xsd:element name="ignoreExportResult" type="tns:boolean" minOccurs="0"/> + <xsd:element name="ignoreValidateResult" type="tns:boolean" minOccurs="0"/> + <xsd:element name="declineAVSFlags" type="xsd:string" minOccurs="0"/> + <xsd:element name="scoreThreshold" type="xsd:integer" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="BillTo"> + <xsd:sequence> + <xsd:element name="title" type="xsd:string" minOccurs="0"/> + <xsd:element name="firstName" type="xsd:string" minOccurs="0"/> + <xsd:element name="middleName" type="xsd:string" minOccurs="0"/> + <xsd:element name="lastName" type="xsd:string" minOccurs="0"/> + <xsd:element name="suffix" type="xsd:string" minOccurs="0"/> + <xsd:element name="buildingNumber" type="xsd:string" minOccurs="0"/> + <xsd:element name="street1" type="xsd:string" minOccurs="0"/> + <xsd:element name="street2" type="xsd:string" minOccurs="0"/> + <xsd:element name="street3" type="xsd:string" minOccurs="0"/> + <xsd:element name="street4" type="xsd:string" minOccurs="0"/> + <xsd:element name="city" type="xsd:string" minOccurs="0"/> + <xsd:element name="district" type="xsd:string" minOccurs="0"/> + <xsd:element name="county" type="xsd:string" minOccurs="0"/> + <xsd:element name="state" type="xsd:string" minOccurs="0"/> + <xsd:element name="postalCode" type="xsd:string" minOccurs="0"/> + <xsd:element name="country" type="xsd:string" minOccurs="0"/> + <xsd:element name="company" type="xsd:string" minOccurs="0"/> + <xsd:element name="companyTaxID" type="xsd:string" minOccurs="0"/> + <xsd:element name="phoneNumber" type="xsd:string" minOccurs="0"/> + <xsd:element name="email" type="xsd:string" minOccurs="0"/> + <xsd:element name="ipAddress" type="xsd:string" minOccurs="0"/> + <xsd:element name="customerUserName" type="xsd:string" minOccurs="0"/> + <xsd:element name="customerPassword" type="xsd:string" minOccurs="0"/> + <xsd:element name="ipNetworkAddress" type="xsd:string" minOccurs="0"/> + <xsd:element name="hostname" type="xsd:string" minOccurs="0"/> + <xsd:element name="domainName" type="xsd:string" minOccurs="0"/> + <xsd:element name="dateOfBirth" type="xsd:string" minOccurs="0"/> + <!-- xsd:date --> + <xsd:element name="driversLicenseNumber" type="xsd:string" minOccurs="0"/> + <xsd:element name="driversLicenseState" type="xsd:string" minOccurs="0"/> + <xsd:element name="ssn" type="xsd:string" minOccurs="0"/> + <xsd:element name="customerID" type="xsd:string" minOccurs="0"/> + <xsd:element name="httpBrowserType" type="xsd:string" minOccurs="0"/> + <xsd:element name="httpBrowserEmail" type="xsd:string" minOccurs="0"/> + <xsd:element name="httpBrowserCookiesAccepted" type="tns:boolean" minOccurs="0"/> + <xsd:element name="nif" type="xsd:string" minOccurs="0"/> + <xsd:element name="personalID" type="xsd:string" minOccurs="0"/> + <xsd:element name="language" type="xsd:string" minOccurs="0"/> + <xsd:element name="name" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="ShipTo"> + <xsd:sequence> + <xsd:element name="title" type="xsd:string" minOccurs="0"/> + <xsd:element name="firstName" type="xsd:string" minOccurs="0"/> + <xsd:element name="middleName" type="xsd:string" minOccurs="0"/> + <xsd:element name="lastName" type="xsd:string" minOccurs="0"/> + <xsd:element name="suffix" type="xsd:string" minOccurs="0"/> + <xsd:element name="street1" type="xsd:string" minOccurs="0"/> + <xsd:element name="street2" type="xsd:string" minOccurs="0"/> + <xsd:element name="street3" type="xsd:string" minOccurs="0"/> + <xsd:element name="street4" type="xsd:string" minOccurs="0"/> + <xsd:element name="city" type="xsd:string" minOccurs="0"/> + <xsd:element name="county" type="xsd:string" minOccurs="0"/> + <xsd:element name="state" type="xsd:string" minOccurs="0"/> + <xsd:element name="postalCode" type="xsd:string" minOccurs="0"/> + <xsd:element name="country" type="xsd:string" minOccurs="0"/> + <xsd:element name="company" type="xsd:string" minOccurs="0"/> + <xsd:element name="phoneNumber" type="xsd:string" minOccurs="0"/> + <xsd:element name="email" type="xsd:string" minOccurs="0"/> + <xsd:element name="shippingMethod" type="xsd:string" minOccurs="0"/> + <xsd:element name="name" type="xsd:string" minOccurs="0"/> + <xsd:element name="id" type="xsd:string" minOccurs="0"/> + <xsd:element name="addressVerificationStatus" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="ShipFrom"> + <xsd:sequence> + <xsd:element name="title" type="xsd:string" minOccurs="0"/> + <xsd:element name="firstName" type="xsd:string" minOccurs="0"/> + <xsd:element name="middleName" type="xsd:string" minOccurs="0"/> + <xsd:element name="lastName" type="xsd:string" minOccurs="0"/> + <xsd:element name="suffix" type="xsd:string" minOccurs="0"/> + <xsd:element name="street1" type="xsd:string" minOccurs="0"/> + <xsd:element name="street2" type="xsd:string" minOccurs="0"/> + <xsd:element name="street3" type="xsd:string" minOccurs="0"/> + <xsd:element name="street4" type="xsd:string" minOccurs="0"/> + <xsd:element name="city" type="xsd:string" minOccurs="0"/> + <xsd:element name="county" type="xsd:string" minOccurs="0"/> + <xsd:element name="state" type="xsd:string" minOccurs="0"/> + <xsd:element name="postalCode" type="xsd:string" minOccurs="0"/> + <xsd:element name="country" type="xsd:string" minOccurs="0"/> + <xsd:element name="company" type="xsd:string" minOccurs="0"/> + <xsd:element name="phoneNumber" type="xsd:string" minOccurs="0"/> + <xsd:element name="email" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="Card"> + <xsd:sequence> + <xsd:element name="fullName" type="xsd:string" minOccurs="0"/> + <xsd:element name="accountNumber" type="xsd:string" minOccurs="0"/> + <xsd:element name="expirationMonth" type="xsd:integer" minOccurs="0"/> + <xsd:element name="expirationYear" type="xsd:integer" minOccurs="0"/> + <xsd:element name="cvIndicator" type="xsd:string" minOccurs="0"/> + <xsd:element name="cvNumber" type="xsd:string" minOccurs="0"/> + <xsd:element name="cardType" type="xsd:string" minOccurs="0"/> + <xsd:element name="issueNumber" type="xsd:string" minOccurs="0"/> + <xsd:element name="startMonth" type="xsd:integer" minOccurs="0"/> + <xsd:element name="startYear" type="xsd:integer" minOccurs="0"/> + <xsd:element name="pin" type="xsd:string" minOccurs="0"/> + <xsd:element name="accountEncoderID" type="xsd:string" minOccurs="0"/> + <xsd:element name="bin" type="xsd:string" minOccurs="0"/> + <xsd:element name="encryptedData" type="xsd:string" minOccurs="0"/> + <xsd:element name="suffix" type="xsd:string" minOccurs="0"/> + <xsd:element name="prefix" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="Check"> + <xsd:sequence> + <xsd:element name="fullName" type="xsd:string" minOccurs="0"/> + <xsd:element name="accountNumber" type="xsd:string" minOccurs="0"/> + <xsd:element name="accountType" type="xsd:string" minOccurs="0"/> + <xsd:element name="bankTransitNumber" type="xsd:string" minOccurs="0"/> + <xsd:element name="checkNumber" type="xsd:string" minOccurs="0"/> + <xsd:element name="secCode" type="xsd:string" minOccurs="0"/> + <xsd:element name="accountEncoderID" type="xsd:string" minOccurs="0"/> + <xsd:element name="authenticateID" type="xsd:string" minOccurs="0"/> + <xsd:element name="paymentInfo" type="xsd:string" minOccurs="0"/> + <xsd:element name="imageReferenceNumber" type="xsd:string" minOccurs="0"/> + <xsd:element name="terminalCity" type="xsd:string" minOccurs="0"/> + <xsd:element name="terminalState" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="BML"> + <xsd:sequence> + <xsd:element name="customerBillingAddressChange" type="tns:boolean" minOccurs="0"/> + <xsd:element name="customerEmailChange" type="tns:boolean" minOccurs="0"/> + <xsd:element name="customerHasCheckingAccount" type="tns:boolean" minOccurs="0"/> + <xsd:element name="customerHasSavingsAccount" type="tns:boolean" minOccurs="0"/> + <xsd:element name="customerPasswordChange" type="tns:boolean" minOccurs="0"/> + <xsd:element name="customerPhoneChange" type="tns:boolean" minOccurs="0"/> + <xsd:element name="customerRegistrationDate" type="xsd:string" minOccurs="0"/> + <!-- xsd:date --> + <xsd:element name="customerTypeFlag" type="xsd:string" minOccurs="0"/> + <xsd:element name="grossHouseholdIncome" type="tns:amount" minOccurs="0"/> + <xsd:element name="householdIncomeCurrency" type="xsd:string" minOccurs="0"/> + <xsd:element name="itemCategory" type="xsd:string" minOccurs="0"/> + <xsd:element name="merchantPromotionCode" type="xsd:string" minOccurs="0"/> + <xsd:element name="preapprovalNumber" type="xsd:string" minOccurs="0"/> + <xsd:element name="productDeliveryTypeIndicator" type="xsd:string" minOccurs="0"/> + <xsd:element name="residenceStatus" type="xsd:string" minOccurs="0"/> + <xsd:element name="tcVersion" type="xsd:string" minOccurs="0"/> + <xsd:element name="yearsAtCurrentResidence" type="xsd:integer" minOccurs="0"/> + <xsd:element name="yearsWithCurrentEmployer" type="xsd:integer" minOccurs="0"/> + <xsd:element name="employerStreet1" type="xsd:string" minOccurs="0"/> + <xsd:element name="employerStreet2" type="xsd:string" minOccurs="0"/> + <xsd:element name="employerCity" type="xsd:string" minOccurs="0"/> + <xsd:element name="employerCompanyName" type="xsd:string" minOccurs="0"/> + <xsd:element name="employerCountry" type="xsd:string" minOccurs="0"/> + <xsd:element name="employerPhoneNumber" type="xsd:string" minOccurs="0"/> + <xsd:element name="employerPhoneType" type="xsd:string" minOccurs="0"/> + <xsd:element name="employerState" type="xsd:string" minOccurs="0"/> + <xsd:element name="employerPostalCode" type="xsd:string" minOccurs="0"/> + <xsd:element name="shipToPhoneType" type="xsd:string" minOccurs="0"/> + <xsd:element name="billToPhoneType" type="xsd:string" minOccurs="0"/> + <xsd:element name="methodOfPayment" type="xsd:string" minOccurs="0"/> + <xsd:element name="productType" type="xsd:string" minOccurs="0"/> + <xsd:element name="customerAuthenticatedByMerchant" type="xsd:string" minOccurs="0"/> + <xsd:element name="backOfficeIndicator" type="xsd:string" minOccurs="0"/> + <xsd:element name="shipToEqualsBillToNameIndicator" type="xsd:string" minOccurs="0"/> + <xsd:element name="shipToEqualsBillToAddressIndicator" type="xsd:string" minOccurs="0"/> + <xsd:element name="alternateIPAddress" type="xsd:string" minOccurs="0"/> + <xsd:element name="businessLegalName" type="xsd:string" minOccurs="0"/> + <xsd:element name="dbaName" type="xsd:string" minOccurs="0"/> + <xsd:element name="businessAddress1" type="xsd:string" minOccurs="0"/> + <xsd:element name="businessAddress2" type="xsd:string" minOccurs="0"/> + <xsd:element name="businessCity" type="xsd:string" minOccurs="0"/> + <xsd:element name="businessState" type="xsd:string" minOccurs="0"/> + <xsd:element name="businessPostalCode" type="xsd:string" minOccurs="0"/> + <xsd:element name="businessCountry" type="xsd:string" minOccurs="0"/> + <xsd:element name="businessMainPhone" type="xsd:string" minOccurs="0"/> + <xsd:element name="userID" type="xsd:string" minOccurs="0"/> + <xsd:element name="pin" type="xsd:string" minOccurs="0"/> + <xsd:element name="adminLastName" type="xsd:string" minOccurs="0"/> + <xsd:element name="adminFirstName" type="xsd:string" minOccurs="0"/> + <xsd:element name="adminPhone" type="xsd:string" minOccurs="0"/> + <xsd:element name="adminFax" type="xsd:string" minOccurs="0"/> + <xsd:element name="adminEmailAddress" type="xsd:string" minOccurs="0"/> + <xsd:element name="adminTitle" type="xsd:string" minOccurs="0"/> + <xsd:element name="supervisorLastName" type="xsd:string" minOccurs="0"/> + <xsd:element name="supervisorFirstName" type="xsd:string" minOccurs="0"/> + <xsd:element name="supervisorEmailAddress" type="xsd:string" minOccurs="0"/> + <xsd:element name="businessDAndBNumber" type="xsd:string" minOccurs="0"/> + <xsd:element name="businessTaxID" type="xsd:string" minOccurs="0"/> + <xsd:element name="businessNAICSCode" type="xsd:string" minOccurs="0"/> + <xsd:element name="businessType" type="xsd:string" minOccurs="0"/> + <xsd:element name="businessYearsInBusiness" type="xsd:string" minOccurs="0"/> + <xsd:element name="businessNumberOfEmployees" type="xsd:string" minOccurs="0"/> + <xsd:element name="businessPONumber" type="xsd:string" minOccurs="0"/> + <xsd:element name="businessLoanType" type="xsd:string" minOccurs="0"/> + <xsd:element name="businessApplicationID" type="xsd:string" minOccurs="0"/> + <xsd:element name="businessProductCode" type="xsd:string" minOccurs="0"/> + <xsd:element name="pgLastName" type="xsd:string" minOccurs="0"/> + <xsd:element name="pgFirstName" type="xsd:string" minOccurs="0"/> + <xsd:element name="pgSSN" type="xsd:string" minOccurs="0"/> + <xsd:element name="pgDateOfBirth" type="xsd:string" minOccurs="0"/> + <xsd:element name="pgAnnualIncome" type="xsd:string" minOccurs="0"/> + <xsd:element name="pgIncomeCurrencyType" type="xsd:string" minOccurs="0"/> + <xsd:element name="pgResidenceStatus" type="xsd:string" minOccurs="0"/> + <xsd:element name="pgCheckingAccountIndicator" type="xsd:string" minOccurs="0"/> + <xsd:element name="pgSavingsAccountIndicator" type="xsd:string" minOccurs="0"/> + <xsd:element name="pgYearsAtEmployer" type="xsd:string" minOccurs="0"/> + <xsd:element name="pgYearsAtResidence" type="xsd:string" minOccurs="0"/> + <xsd:element name="pgHomeAddress1" type="xsd:string" minOccurs="0"/> + <xsd:element name="pgHomeAddress2" type="xsd:string" minOccurs="0"/> + <xsd:element name="pgHomeCity" type="xsd:string" minOccurs="0"/> + <xsd:element name="pgHomeState" type="xsd:string" minOccurs="0"/> + <xsd:element name="pgHomePostalCode" type="xsd:string" minOccurs="0"/> + <xsd:element name="pgHomeCountry" type="xsd:string" minOccurs="0"/> + <xsd:element name="pgEmailAddress" type="xsd:string" minOccurs="0"/> + <xsd:element name="pgHomePhone" type="xsd:string" minOccurs="0"/> + <xsd:element name="pgTitle" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="OtherTax"> + <xsd:sequence> + <xsd:element name="vatTaxAmount" type="tns:amount" minOccurs="0"/> + <xsd:element name="vatTaxRate" type="tns:amount" minOccurs="0"/> + <xsd:element name="vatTaxAmountSign" type="xsd:string" minOccurs="0"/> + <xsd:element name="alternateTaxAmount" type="tns:amount" minOccurs="0"/> + <xsd:element name="alternateTaxIndicator" type="xsd:string" minOccurs="0"/> + <xsd:element name="alternateTaxID" type="xsd:string" minOccurs="0"/> + <xsd:element name="localTaxAmount" type="tns:amount" minOccurs="0"/> + <xsd:element name="localTaxIndicator" type="xsd:integer" minOccurs="0"/> + <xsd:element name="nationalTaxAmount" type="tns:amount" minOccurs="0"/> + <xsd:element name="nationalTaxIndicator" type="xsd:integer" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + + <xsd:complexType name="Aft"> + <xsd:sequence> + <xsd:element name="indicator" type="xsd:string" minOccurs="0" /> + <xsd:element name="serviceFee" type="xsd:string" minOccurs="0" /> + <xsd:element name="foreignExchangeFee" type="xsd:string" minOccurs="0" /> + </xsd:sequence> + </xsd:complexType> + + <xsd:complexType name="Wallet"> + <xsd:sequence> + <xsd:element name="type" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="PurchaseTotals"> + <xsd:sequence> + <xsd:element name="currency" type="xsd:string" minOccurs="0"/> + <xsd:element name="discountAmount" type="tns:amount" minOccurs="0"/> + <xsd:element name="discountAmountSign" type="xsd:string" minOccurs="0"/> + <xsd:element name="discountManagementIndicator" type="xsd:string" minOccurs="0"/> + <xsd:element name="taxAmount" type="tns:amount" minOccurs="0"/> + <xsd:element name="dutyAmount" type="tns:amount" minOccurs="0"/> + <xsd:element name="dutyAmountSign" type="xsd:string" minOccurs="0"/> + <xsd:element name="grandTotalAmount" type="tns:amount" minOccurs="0"/> + <xsd:element name="freightAmount" type="tns:amount" minOccurs="0"/> + <xsd:element name="freightAmountSign" type="xsd:string" minOccurs="0"/> + <xsd:element name="foreignAmount" type="tns:amount" minOccurs="0"/> + <xsd:element name="foreignCurrency" type="xsd:string" minOccurs="0"/> + <xsd:element name="originalAmount" type="tns:amount" minOccurs="0"/> + <xsd:element name="originalCurrency" type="xsd:string" minOccurs="0"/> + <xsd:element name="exchangeRate" type="tns:amount" minOccurs="0"/> + <xsd:element name="exchangeRateTimeStamp" type="xsd:string" minOccurs="0"/> + <xsd:element name="additionalAmountType0" type="xsd:string" minOccurs="0"/> + <xsd:element name="additionalAmount0" type="xsd:string" minOccurs="0"/> + <xsd:element name="additionalAmountType1" type="xsd:string" minOccurs="0"/> + <xsd:element name="additionalAmount1" type="xsd:string" minOccurs="0"/> + <xsd:element name="additionalAmountType2" type="xsd:string" minOccurs="0"/> + <xsd:element name="additionalAmount2" type="xsd:string" minOccurs="0"/> + <xsd:element name="additionalAmountType3" type="xsd:string" minOccurs="0"/> + <xsd:element name="additionalAmount3" type="xsd:string" minOccurs="0"/> + <xsd:element name="additionalAmountType4" type="xsd:string" minOccurs="0"/> + <xsd:element name="additionalAmount4" type="xsd:string" minOccurs="0"/> + <xsd:element name="serviceFeeAmount" type="tns:amount" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="FundingTotals"> + <xsd:sequence> + <xsd:element name="currency" type="xsd:string" minOccurs="0"/> + <xsd:element name="grandTotalAmount" type="tns:amount" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="GECC"> + <xsd:sequence> + <xsd:element name="saleType" type="xsd:string" minOccurs="0"/> + <xsd:element name="planNumber" type="xsd:string" minOccurs="0"/> + <xsd:element name="sequenceNumber" type="xsd:string" minOccurs="0"/> + <xsd:element name="promotionEndDate" type="xsd:string" minOccurs="0"/> + <xsd:element name="promotionPlan" type="xsd:string" minOccurs="0"/> + <xsd:element name="line" type="xsd:string" minOccurs="0" maxOccurs="7"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="UCAF"> + <xsd:sequence> + <xsd:element name="authenticationData" type="xsd:string" minOccurs="0"/> + <xsd:element name="collectionIndicator" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="FundTransfer"> + <xsd:sequence> + <xsd:element name="accountNumber" type="xsd:string" minOccurs="0"/> + <xsd:element name="accountName" type="xsd:string" minOccurs="0"/> + <xsd:element name="bankCheckDigit" type="xsd:string" minOccurs="0"/> + <xsd:element name="iban" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="BankInfo"> + <xsd:sequence> + <xsd:element name="bankCode" type="xsd:string" minOccurs="0"/> + <xsd:element name="name" type="xsd:string" minOccurs="0"/> + <xsd:element name="address" type="xsd:string" minOccurs="0"/> + <xsd:element name="city" type="xsd:string" minOccurs="0"/> + <xsd:element name="country" type="xsd:string" minOccurs="0"/> + <xsd:element name="branchCode" type="xsd:string" minOccurs="0"/> + <xsd:element name="swiftCode" type="xsd:string" minOccurs="0"/> + <xsd:element name="sortCode" type="xsd:string" minOccurs="0"/> + <xsd:element name="issuerID" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="RecurringSubscriptionInfo"> + <xsd:sequence> + <xsd:element name="subscriptionID" type="xsd:string" minOccurs="0"/> + <xsd:element name="status" type="xsd:string" minOccurs="0"/> + <xsd:element name="amount" type="tns:amount" minOccurs="0"/> + <xsd:element name="numberOfPayments" type="xsd:integer" minOccurs="0"/> + <xsd:element name="numberOfPaymentsToAdd" type="xsd:integer" minOccurs="0"/> + <xsd:element name="automaticRenew" type="tns:boolean" minOccurs="0"/> + <xsd:element name="frequency" type="xsd:string" minOccurs="0"/> + <xsd:element name="startDate" type="xsd:string" minOccurs="0"/> + <xsd:element name="endDate" type="xsd:string" minOccurs="0"/> + <xsd:element name="approvalRequired" type="tns:boolean" minOccurs="0"/> + <xsd:element name="event" type="tns:PaySubscriptionEvent" minOccurs="0"/> + <xsd:element name="billPayment" type="tns:boolean" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="PaySubscriptionEvent"> + <xsd:sequence> + <xsd:element name="amount" type="tns:amount" minOccurs="0"/> + <xsd:element name="approvedBy" type="xsd:string" minOccurs="0"/> + <xsd:element name="number" type="xsd:integer" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="Subscription"> + <xsd:sequence> + <xsd:element name="title" type="xsd:string" minOccurs="0"/> + <xsd:element name="paymentMethod" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="PaymentNetworkToken"> + <xsd:sequence> + <xsd:element name="requestorID" type="xsd:string" minOccurs="0"/> + <xsd:element name="transactionType" type="xsd:string" minOccurs="0"/> + <xsd:element name="assuranceLevel" type="xsd:string" minOccurs="0"/> + <xsd:element name="accountStatus" type="xsd:string" minOccurs="0"/> + <xsd:element name="originalCardCategory" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="DecisionManager"> + <xsd:sequence> + <xsd:element name="enabled" type="tns:boolean" minOccurs="0"/> + <xsd:element name="profile" type="xsd:string" minOccurs="0"/> + <xsd:element name="travelData" type="tns:DecisionManagerTravelData" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="DecisionManagerTravelData"> + <xsd:sequence> + <xsd:element name="leg" type="tns:DecisionManagerTravelLeg" minOccurs="0" maxOccurs="100"/> + <xsd:element name="departureDateTime" type="tns:dateTime" minOccurs="0"/> + <xsd:element name="completeRoute" type="xsd:string" minOccurs="0"/> + <xsd:element name="journeyType" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="DecisionManagerTravelLeg"> + <xsd:sequence> + <xsd:element name="origin" type="xsd:string" minOccurs="0"/> + <xsd:element name="destination" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + <xsd:attribute name="id" type="xsd:integer" use="optional"/> + </xsd:complexType> + <xsd:complexType name="Batch"> + <xsd:sequence> + <xsd:element name="batchID" type="xsd:string" minOccurs="0"/> + <xsd:element name="recordID" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="PayPal"> + <xsd:sequence> + <xsd:any processContents="skip" minOccurs="0" maxOccurs="999"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="JPO"> + <xsd:sequence> + <xsd:element name="paymentMethod" type="xsd:integer" minOccurs="0"/> + <xsd:element name="bonusAmount" type="tns:amount" minOccurs="0"/> + <xsd:element name="bonuses" type="xsd:integer" minOccurs="0"/> + <xsd:element name="installments" type="xsd:integer" minOccurs="0"/> + <xsd:element name="firstBillingMonth" type="xsd:integer" minOccurs="0"/> + <xsd:element name="jccaTerminalID" type="xsd:integer" minOccurs="0"/> + <xsd:element name="issuerMessage" type="xsd:integer" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <!-- Vme Reseller Service--> + <xsd:complexType name="AP"> + <xsd:sequence> + <xsd:element name="orderID" type="xsd:string" minOccurs="0"/> + <xsd:element name="customerRepresentativeID" type="xsd:string" minOccurs="0" /> + <xsd:element name="productDescription" type="xsd:string" minOccurs="0" /> + <xsd:element name="settlementCurrency" type="xsd:string" minOccurs="0" /> + <xsd:element name="subtotalAmount" type="xsd:string" minOccurs="0" /> + <xsd:element name="shippingAmount" type="xsd:string" minOccurs="0" /> + <xsd:element name="handlingAmount" type="xsd:string" minOccurs="0" /> + <xsd:element name="shippingHandlingAmount" type="xsd:string" minOccurs="0" /> + <xsd:element name="additionalAmount" type="xsd:string" minOccurs="0" /> + <xsd:element name="taxAmount" type="xsd:string" minOccurs="0" /> + <xsd:element name="giftWrapAmount" type="xsd:string" minOccurs="0" /> + <xsd:element name="discountAmount" type="xsd:string" minOccurs="0" /> + <xsd:element name="purchaseID" type="xsd:string" minOccurs="0" /> + <xsd:element name="productID" type="xsd:string" minOccurs="0" /> + </xsd:sequence> + </xsd:complexType> + <!-- apAuthService --> + <xsd:complexType name="APAuthService"> + <xsd:attribute name="run" type="tns:boolean" use="required"/> + </xsd:complexType> + <!-- End of apAuthService --> + <!-- apAuthReversalService --> + <xsd:complexType name="APAuthReversalService"> + <xsd:sequence> + <xsd:element name="authRequestID" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + <xsd:attribute name="run" type="tns:boolean" use="required"/> + </xsd:complexType> + <!-- End of apAuthReversalService --> + <!-- apCaptureService --> + <xsd:complexType name="APCaptureService"> + <xsd:sequence> + <xsd:element name="authRequestID" type="xsd:string" minOccurs="0"/> + <xsd:element name="reconciliationID" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + <xsd:attribute name="run" type="tns:boolean" use="required"/> + </xsd:complexType> + <!-- End of apCaptureService --> + <!-- apRefundService --> + <xsd:complexType name="APRefundService"> + <xsd:sequence> + <xsd:element name="captureRequestID" type="xsd:string" minOccurs="0"/> + <xsd:element name="reason" type="xsd:string" minOccurs="0"/> + <xsd:element name="note" type="xsd:string" minOccurs="0"/> + <xsd:element name="apInitiateRequestID" type="xsd:string" minOccurs="0"/> + <xsd:element name="returnRef" type="xsd:string" minOccurs="0"/> + <xsd:element name="reconciliationID" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + <xsd:attribute name="run" type="tns:boolean" use="required"/> + </xsd:complexType> + <!-- End of apRefundService --> + <xsd:complexType name="APCheckOutDetailsService"> + <xsd:attribute name="run" type="tns:boolean" use="required"/> + </xsd:complexType> + <!-- End of apCheckoutDetailsService --> + <xsd:complexType name="APTransactionDetailsService"> + <xsd:sequence> + <xsd:element name="transactionDetailsRequestID" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + <xsd:attribute name="run" type="tns:boolean" use="required"/> + </xsd:complexType> + <!-- APConfirmPurchaseService --> + <xsd:complexType name="APConfirmPurchaseService"> + <xsd:attribute name="run" type="tns:boolean" use="required"/> + </xsd:complexType> + <!-- End of APConfirmPurchaseService --> + <!--PayPalGetTxnDetails--> + <xsd:complexType name="PayPalGetTxnDetailsService"> + <xsd:sequence> + <xsd:element name="transactionID" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + <xsd:attribute name="run" type="tns:boolean" use="required"/> + </xsd:complexType> + <!-- End of PayPalGetTxnDetails --> + <!--PayPalTransactionSearch--> + <xsd:complexType name="PayPalTransactionSearchService"> + <xsd:sequence> + <xsd:element name="startDate" type="xsd:string" minOccurs="0"/> + <xsd:element name="endDate" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalCustomerEmail" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalReceiptId" type="xsd:string" minOccurs="0"/> + <xsd:element name="transactionID" type="xsd:string" minOccurs="0"/> + <xsd:element name="invoiceNumber" type="xsd:string" minOccurs="0"/> + <xsd:element name="grandTotalAmount" type="tns:amount" minOccurs="0"/> + <xsd:element name="currency" type="xsd:string" minOccurs="0"/> + <xsd:element name="paymentStatus" type="xsd:string" minOccurs="0"/> + <xsd:element name="payerSalutation" type="xsd:string" minOccurs="0"/> + <xsd:element name="payerFirstname" type="xsd:string" minOccurs="0"/> + <xsd:element name="payerMiddlename" type="xsd:string" minOccurs="0"/> + <xsd:element name="payerLastname" type="xsd:string" minOccurs="0"/> + <xsd:element name="payerSuffix" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + <xsd:attribute name="run" type="tns:boolean" use="required"/> + </xsd:complexType> + <!-- End of PayPalTransactionSearch --> + <!-- Credit card recipient data --> + <xsd:complexType name="Recipient"> +<xsd:sequence> + <xsd:element name="dateOfBirth" type="xsd:string" minOccurs="0"/> + <xsd:element name="postalCode" type="xsd:string" minOccurs="0"/> + <xsd:element name="accountID" type="xsd:string" minOccurs="0"/> + <xsd:element name="lastName" type="xsd:string" minOccurs="0"/> + <xsd:element name="name" type="xsd:string" minOccurs="0"/> +</xsd:sequence> + </xsd:complexType> + <!-- End of Credit card recipient data --> + <xsd:complexType name="Sender"> + <xsd:sequence> + <xsd:element name="referenceNumber" type="xsd:string" minOccurs="0"/> + <xsd:element name="sourceOfFunds" type="xsd:string" minOccurs="0"/> + <xsd:element name="name" type="xsd:string" minOccurs="0"/> + <xsd:element name="address" type="xsd:string" minOccurs="0"/> + <xsd:element name="city" type="xsd:string" minOccurs="0"/> + <xsd:element name="state" type="xsd:string" minOccurs="0"/> + <xsd:element name="postalCode" type="xsd:string" minOccurs="0"/> + <xsd:element name="country" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="RequestMessage"> + <xsd:sequence> + <xsd:element name="merchantID" type="xsd:string" + minOccurs="0" /> + <xsd:element name="merchantReferenceCode" type="xsd:string" + minOccurs="0" /> + <xsd:element name="debtIndicator" type="tns:boolean" + minOccurs="0" /> + <xsd:element name="clientLibrary" type="xsd:string" + minOccurs="0" /> + <xsd:element name="clientLibraryVersion" type="xsd:string" + minOccurs="0" /> + <xsd:element name="clientEnvironment" type="xsd:string" + minOccurs="0" /> + <xsd:element name="clientSecurityLibraryVersion" + type="xsd:string" minOccurs="0" /> + <xsd:element name="clientApplication" type="xsd:string" + minOccurs="0" /> + <xsd:element name="clientApplicationVersion" + type="xsd:string" minOccurs="0" /> + <xsd:element name="clientApplicationUser" type="xsd:string" + minOccurs="0" /> + <xsd:element name="routingCode" type="xsd:string" + minOccurs="0" /> + <xsd:element name="comments" type="xsd:string" + minOccurs="0" /> + <xsd:element name="returnURL" type="xsd:string" + minOccurs="0" /> + <xsd:element name="invoiceHeader" type="tns:InvoiceHeader" + minOccurs="0" /> + <xsd:element name="aggregatorMerchantIdentifier" type="xsd:string" minOccurs="0"/> + <xsd:element name="customerID" type="xsd:string" minOccurs="0"/> + <xsd:element name="customerFirstName" type="xsd:string" minOccurs="0"/> + <xsd:element name="customerLastName" type="xsd:string" minOccurs="0"/> + <xsd:element name="billTo" type="tns:BillTo" minOccurs="0" /> + <xsd:element name="shipTo" type="tns:ShipTo" minOccurs="0" /> + <xsd:element name="shipFrom" type="tns:ShipFrom" + minOccurs="0" /> + <xsd:element name="item" type="tns:Item" minOccurs="0" + maxOccurs="1000" /> + <xsd:element name="purchaseTotals" type="tns:PurchaseTotals" + minOccurs="0" /> + <xsd:element name="fundingTotals" type="tns:FundingTotals" + minOccurs="0" /> + <xsd:element name="dcc" type="tns:DCC" minOccurs="0" /> + <xsd:element name="pos" type="tns:Pos" minOccurs="0" /> + <xsd:element name="encryptedPayment" type="tns:EncryptedPayment" minOccurs="0" /> + <xsd:element name="installment" type="tns:Installment" + minOccurs="0" /> + <xsd:element name="card" type="tns:Card" minOccurs="0" /> + <xsd:element name="check" type="tns:Check" minOccurs="0" /> + <xsd:element name="bml" type="tns:BML" minOccurs="0" /> + <xsd:element name="gecc" type="tns:GECC" minOccurs="0" /> + <xsd:element name="ucaf" type="tns:UCAF" minOccurs="0" /> + <xsd:element name="fundTransfer" type="tns:FundTransfer" + minOccurs="0" /> + <xsd:element name="bankInfo" type="tns:BankInfo" + minOccurs="0" /> + <xsd:element name="subscription" type="tns:Subscription" + minOccurs="0" /> + <xsd:element name="recurringSubscriptionInfo" + type="tns:RecurringSubscriptionInfo" minOccurs="0" /> + <xsd:element name="decisionManager" + type="tns:DecisionManager" minOccurs="0" /> + <xsd:element name="otherTax" type="tns:OtherTax" + minOccurs="0" /> + <xsd:element name="paypal" type="tns:PayPal" minOccurs="0" /> + <xsd:element name="merchantDefinedData" + type="tns:MerchantDefinedData" minOccurs="0" /> + <xsd:element name="merchantSecureData" + type="tns:MerchantSecureData" minOccurs="0" /> + <xsd:element name="jpo" type="tns:JPO" minOccurs="0" /> + <xsd:element name="orderRequestToken" type="xsd:string" + minOccurs="0" /> + <xsd:element name="linkToRequest" type="xsd:string" + minOccurs="0" /> + <xsd:element name="serviceFee" type="tns:ServiceFee" minOccurs="0" /> + <xsd:element name="ccAuthService" type="tns:CCAuthService" + minOccurs="0" /> + <xsd:element name="octService" type="tns:OCTService" + minOccurs="0" /> + <xsd:element name="ccSaleService" type="tns:CCSaleService" minOccurs="0" /> + + <xsd:element name="ccSaleCreditService" type="tns:CCSaleCreditService" minOccurs="0" /> + + <xsd:element name="ccSaleReversalService" type="tns:CCSaleReversalService" minOccurs="0" /> + <xsd:element name="ccIncrementalAuthService" type="tns:CCIncrementalAuthService" minOccurs="0" /> + <xsd:element name="ccCaptureService" + type="tns:CCCaptureService" minOccurs="0" /> + <xsd:element name="ccCreditService" + type="tns:CCCreditService" minOccurs="0" /> + <xsd:element name="ccAuthReversalService" + type="tns:CCAuthReversalService" minOccurs="0" /> + <xsd:element name="ccAutoAuthReversalService" + type="tns:CCAutoAuthReversalService" minOccurs="0" /> + <xsd:element name="ccDCCService" type="tns:CCDCCService" + minOccurs="0" /> + <xsd:element name="serviceFeeCalculateService" type="tns:ServiceFeeCalculateService" + minOccurs="0" /> + <xsd:element name="ecDebitService" type="tns:ECDebitService" + minOccurs="0" /> + <xsd:element name="ecCreditService" + type="tns:ECCreditService" minOccurs="0" /> + <xsd:element name="ecAuthenticateService" + type="tns:ECAuthenticateService" minOccurs="0" /> + <xsd:element name="payerAuthEnrollService" + type="tns:PayerAuthEnrollService" minOccurs="0" /> + <xsd:element name="payerAuthValidateService" + type="tns:PayerAuthValidateService" minOccurs="0" /> + <xsd:element name="taxService" type="tns:TaxService" + minOccurs="0" /> + <xsd:element name="dmeService" type="tns:DMEService" + minOccurs="0" /> + <xsd:element name="afsService" type="tns:AFSService" + minOccurs="0" /> + <xsd:element name="davService" type="tns:DAVService" + minOccurs="0" /> + <xsd:element name="exportService" type="tns:ExportService" + minOccurs="0" /> + <xsd:element name="fxRatesService" type="tns:FXRatesService" + minOccurs="0" /> + <xsd:element name="bankTransferService" + type="tns:BankTransferService" minOccurs="0" /> + <xsd:element name="bankTransferRefundService" + type="tns:BankTransferRefundService" minOccurs="0" /> + <xsd:element name="bankTransferRealTimeService" + type="tns:BankTransferRealTimeService" minOccurs="0" /> + <xsd:element name="directDebitMandateService" + type="tns:DirectDebitMandateService" minOccurs="0" /> + <xsd:element name="directDebitService" + type="tns:DirectDebitService" minOccurs="0" /> + <xsd:element name="directDebitRefundService" + type="tns:DirectDebitRefundService" minOccurs="0" /> + <xsd:element name="directDebitValidateService" + type="tns:DirectDebitValidateService" minOccurs="0" /> + <xsd:element name="paySubscriptionCreateService" + type="tns:PaySubscriptionCreateService" minOccurs="0" /> + <xsd:element name="paySubscriptionUpdateService" + type="tns:PaySubscriptionUpdateService" minOccurs="0" /> + <xsd:element name="paySubscriptionEventUpdateService" + type="tns:PaySubscriptionEventUpdateService" minOccurs="0" /> + <xsd:element name="paySubscriptionRetrieveService" + type="tns:PaySubscriptionRetrieveService" minOccurs="0" /> + <xsd:element name="paySubscriptionDeleteService" + type="tns:PaySubscriptionDeleteService" minOccurs="0" /> + <xsd:element name="payPalPaymentService" + type="tns:PayPalPaymentService" minOccurs="0" /> + <xsd:element name="payPalCreditService" + type="tns:PayPalCreditService" minOccurs="0" /> + <xsd:element name="voidService" type="tns:VoidService" + minOccurs="0" /> + <xsd:element name="businessRules" type="tns:BusinessRules" + minOccurs="0" /> + <xsd:element name="pinlessDebitService" + type="tns:PinlessDebitService" minOccurs="0" /> + <xsd:element name="pinlessDebitValidateService" + type="tns:PinlessDebitValidateService" minOccurs="0" /> + <xsd:element name="pinlessDebitReversalService" + type="tns:PinlessDebitReversalService" minOccurs="0" /> + <xsd:element name="batch" type="tns:Batch" minOccurs="0" /> + <xsd:element name="airlineData" type="tns:AirlineData" + minOccurs="0" /> + <xsd:element name="ancillaryData" type="tns:AncillaryData" + minOccurs="0" /> + <xsd:element name="lodgingData" type="tns:LodgingData" minOccurs="0" /> + <xsd:element name="payPalButtonCreateService" + type="tns:PayPalButtonCreateService" minOccurs="0" /> + <xsd:element name="payPalPreapprovedPaymentService" + type="tns:PayPalPreapprovedPaymentService" minOccurs="0" /> + <xsd:element name="payPalPreapprovedUpdateService" + type="tns:PayPalPreapprovedUpdateService" minOccurs="0" /> + <xsd:element name="riskUpdateService" + type="tns:RiskUpdateService" minOccurs="0" /> + <xsd:element name="fraudUpdateService" + type="tns:FraudUpdateService" minOccurs="0" /> + <xsd:element name="caseManagementActionService" + type="tns:CaseManagementActionService" minOccurs="0" /> + <xsd:element name="reserved" type="tns:RequestReserved" + minOccurs="0" maxOccurs="999" /> + <xsd:element name="deviceFingerprintID" type="xsd:string" + minOccurs="0" /> + <xsd:element name="deviceFingerprintRaw" type="tns:boolean" + minOccurs="0" /> + <xsd:element name="deviceFingerprintHash" type="xsd:string" + minOccurs="0" /> + <xsd:element name="payPalRefundService" + type="tns:PayPalRefundService" minOccurs="0" /> + <xsd:element name="payPalAuthReversalService" + type="tns:PayPalAuthReversalService" minOccurs="0" /> + <xsd:element name="payPalDoCaptureService" + type="tns:PayPalDoCaptureService" minOccurs="0" /> + <xsd:element name="payPalEcDoPaymentService" + type="tns:PayPalEcDoPaymentService" minOccurs="0" /> + <xsd:element name="payPalEcGetDetailsService" + type="tns:PayPalEcGetDetailsService" minOccurs="0" /> + <xsd:element name="payPalEcSetService" + type="tns:PayPalEcSetService" minOccurs="0" /> + <xsd:element name="payPalEcOrderSetupService" + type="tns:PayPalEcOrderSetupService" minOccurs="0" /> + <xsd:element name="payPalAuthorizationService" + type="tns:PayPalAuthorizationService" minOccurs="0" /> + <xsd:element name="payPalUpdateAgreementService" + type="tns:PayPalUpdateAgreementService" minOccurs="0" /> + <xsd:element name="payPalCreateAgreementService" + type="tns:PayPalCreateAgreementService" minOccurs="0" /> + <xsd:element name="payPalDoRefTransactionService" + type="tns:PayPalDoRefTransactionService" minOccurs="0" /> + <xsd:element name="chinaPaymentService" + type="tns:ChinaPaymentService" minOccurs="0" /> + <xsd:element name="chinaRefundService" + type="tns:ChinaRefundService" minOccurs="0" /> + <xsd:element name="boletoPaymentService" + type="tns:BoletoPaymentService" minOccurs="0" /> + <xsd:element name="apPaymentType" type="xsd:string" + minOccurs="0"/> + <xsd:element name="apInitiateService" + type="tns:APInitiateService" minOccurs="0" /> + <xsd:element name="apCheckStatusService" + type="tns:APCheckStatusService" minOccurs="0" /> + <xsd:element name="ignoreCardExpiration" type="tns:boolean" + minOccurs="0" /> + <xsd:element name="reportGroup" type="xsd:string" + minOccurs="0" /> + <xsd:element name="processorID" type="xsd:string" + minOccurs="0" /> + <xsd:element name="thirdPartyCertificationNumber" type="xsd:string" minOccurs="0"/> + <xsd:element name="transactionLocalDateTime" type="tns:dateTime" minOccurs="0"/> + <xsd:element name="solutionProviderTransactionID" type="xsd:string" minOccurs="0" /> + <xsd:element name="surchargeAmount" type="tns:amount" minOccurs="0"/> + <xsd:element name="surchargeSign" type="xsd:string" minOccurs="0"/> + <xsd:element name="pinDataEncryptedPIN" type="xsd:string" minOccurs="0"/> + <xsd:element name="pinDataKeySerialNumber" type="xsd:string" minOccurs="0"/> + <xsd:element name="cashbackAmount" type="tns:amount" minOccurs="0"/> + <xsd:element name="pinDebitPurchaseService" type="tns:PinDebitPurchaseService" minOccurs="0"/> + <xsd:element name="pinDebitCreditService" type="tns:PinDebitCreditService" minOccurs="0"/> + <xsd:element name="pinDebitReversalService" type="tns:PinDebitReversalService" minOccurs="0"/> + <xsd:element name="ap" type="tns:AP" minOccurs="0" /> + <xsd:element name="apAuthService" type="tns:APAuthService" minOccurs="0" /> + <xsd:element name="apAuthReversalService" type="tns:APAuthReversalService" minOccurs="0" /> + <xsd:element name="apCaptureService" type="tns:APCaptureService" minOccurs="0" /> + <xsd:element name="apRefundService" type="tns:APRefundService" minOccurs="0" /> + <xsd:element name="apCheckoutDetailsService" type="tns:APCheckOutDetailsService" minOccurs="0" /> + <xsd:element name="apTransactionDetailsService" type="tns:APTransactionDetailsService" minOccurs="0" /> + <xsd:element name="apConfirmPurchaseService" type="tns:APConfirmPurchaseService" minOccurs="0" /> + <xsd:element name="payPalGetTxnDetailsService" type="tns:PayPalGetTxnDetailsService" minOccurs="0" /> + <xsd:element name="payPalTransactionSearchService" type="tns:PayPalTransactionSearchService" minOccurs="0" /> + <xsd:element name="ccDCCUpdateService" type="tns:CCDCCUpdateService" minOccurs="0"/> + <xsd:element name="emvRequest" type="tns:EmvRequest" minOccurs="0" /> + <xsd:element name="merchantTransactionIdentifier" type="xsd:string" minOccurs="0" /> + <xsd:element name="hostedDataCreateService" type="tns:HostedDataCreateService" minOccurs="0"/> + <xsd:element name="hostedDataRetrieveService" type="tns:HostedDataRetrieveService" minOccurs="0"/> + <xsd:element name="merchantCategoryCode" type="xsd:string" minOccurs="0" /> + <xsd:element name="salesSlipNumber" type="xsd:string" minOccurs="0" /> + <xsd:element name="merchandiseCode" type="xsd:string" minOccurs="0" /> + <xsd:element name="paymentInitiationChannel" type="xsd:string" minOccurs="0" /> + <xsd:element name="extendedCreditTotalCount" type="xsd:string" minOccurs="0" /> + <xsd:element name="authIndicator" type="xsd:string" minOccurs="0"/> + <xsd:element name="paymentNetworkToken" type="tns:PaymentNetworkToken" minOccurs="0"/> + <xsd:element name="recipient" type="tns:Recipient" minOccurs="0"/> + <xsd:element name="sender" type="tns:Sender" minOccurs="0"/> + <xsd:element name="autoRentalData" type="tns:AutoRentalData" minOccurs="0" /> + <xsd:element name="paymentSolution" type="xsd:string" minOccurs="0" /> + <xsd:element name="vc" type="tns:VC" minOccurs="0" /> + <xsd:element name="decryptVisaCheckoutDataService" type="tns:DecryptVisaCheckoutDataService" minOccurs="0" /> + <xsd:element name="taxManagementIndicator" type="xsd:string" minOccurs="0"/> + <xsd:element name="promotionGroup" type="tns:PromotionGroup" minOccurs="0" maxOccurs="100"/> + <xsd:element name="wallet" type="tns:Wallet" minOccurs="0" /> + <xsd:element name="aft" type="tns:Aft" minOccurs="0" /> + <xsd:element name="balanceInquiry" type="tns:boolean" minOccurs="0" /> + <xsd:element name="prenoteTransaction" type="tns:boolean" minOccurs="0"/> + <xsd:element name="encryptPaymentDataService" type="tns:EncryptPaymentDataService" minOccurs="0"/> + <xsd:element name="nationalNetDomesticData" type="xsd:string" minOccurs="0"/> + <xsd:element name="subsequentAuth" type="xsd:string" minOccurs="0"/> + <xsd:element name="binLookupService" type="tns:BinLookupService" minOccurs="0" /> + </xsd:sequence> + </xsd:complexType> + + <!-- added for Visa Checkout --> + <xsd:complexType name="VC"> + <xsd:sequence> + <xsd:element name="orderID" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="DecryptVisaCheckoutDataService"> + <xsd:attribute name="run" type="tns:boolean" use="required"/> + </xsd:complexType> + + <xsd:complexType name="DCC"> + <xsd:sequence> + <xsd:element name="dccIndicator" type="xsd:integer" minOccurs="0"/> + <xsd:element name="referenceNumber" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + + <xsd:complexType name="Promotion"> + <xsd:sequence> + <xsd:element name="discountedAmount" type="tns:amount" minOccurs="0"/> + <xsd:element name="type" type="xsd:string" minOccurs="0"/> + <xsd:element name="code" type="xsd:string" minOccurs="0"/> + <xsd:element name="receiptData" type="xsd:string" minOccurs="0"/> + <xsd:element name="discountApplied" type="tns:amount" minOccurs="0"/> + <xsd:element name="description" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + + <xsd:complexType name="PromotionGroup"> + <xsd:sequence> + <xsd:element name="subtotalAmount" type="tns:amount" minOccurs="0"/> + <xsd:element name="taxRate" type="tns:amount" minOccurs="0"/> + </xsd:sequence> + <xsd:attribute name="id" type="xsd:integer" use="optional"/> + </xsd:complexType> + + <xsd:complexType name="PromotionGroupReply"> + <xsd:sequence> + <xsd:element name="discountApplied" type="tns:amount" minOccurs="0"/> + </xsd:sequence> + <xsd:attribute name="id" type="xsd:integer" use="optional"/> + </xsd:complexType> + + <xsd:complexType name="CCAuthReply"> + <xsd:sequence> + <xsd:element name="reasonCode" type="xsd:integer"/> + <xsd:element name="amount" type="tns:amount" minOccurs="0"/> + <xsd:element name="authorizationCode" type="xsd:string" minOccurs="0"/> + <xsd:element name="avsCode" type="xsd:string" minOccurs="0"/> + <xsd:element name="avsCodeRaw" type="xsd:string" minOccurs="0"/> + <xsd:element name="cvCode" type="xsd:string" minOccurs="0"/> + <xsd:element name="cvCodeRaw" type="xsd:string" minOccurs="0"/> + <xsd:element name="personalIDCode" type="xsd:string" minOccurs="0"/> + <xsd:element name="authorizedDateTime" type="tns:dateTime" minOccurs="0"/> + <!-- dateTime --> + <xsd:element name="processorResponse" type="xsd:string" minOccurs="0"/> + <xsd:element name="bmlAccountNumber" type="xsd:string" minOccurs="0"/> + <xsd:element name="authFactorCode" type="xsd:string" minOccurs="0"/> + <xsd:element name="reconciliationID" type="xsd:string" minOccurs="0"/> + <xsd:element name="fundingTotals" type="tns:FundingTotals" minOccurs="0"/> + <xsd:element name="fxQuoteID" type="xsd:string" minOccurs="0"/> + <xsd:element name="fxQuoteRate" type="tns:dateTime" minOccurs="0"/> + <xsd:element name="fxQuoteType" type="xsd:string" minOccurs="0"/> + <xsd:element name="fxQuoteExpirationDateTime" type="tns:dateTime" minOccurs="0"/> + <xsd:element name="authRecord" type="xsd:string" minOccurs="0"/> + <xsd:element name="merchantAdviceCode" type="xsd:string" minOccurs="0"/> + <xsd:element name="merchantAdviceCodeRaw" type="xsd:string" minOccurs="0"/> + <xsd:element name="cavvResponseCode" type="xsd:string" minOccurs="0"/> + <xsd:element name="cavvResponseCodeRaw" type="xsd:string" minOccurs="0"/> + <xsd:element name="authenticationXID" type="xsd:string" minOccurs="0"/> + <xsd:element name="authorizationXID" type="xsd:string" minOccurs="0"/> + <xsd:element name="processorCardType" type="xsd:string" minOccurs="0"/> + <xsd:element name="accountBalance" type="tns:amount" minOccurs="0"/> + <xsd:element name="forwardCode" type="xsd:string" minOccurs="0"/> + <xsd:element name="enhancedDataEnabled" type="xsd:string" minOccurs="0"/> + <xsd:element name="referralResponseNumber" type="xsd:string" minOccurs="0"/> + <xsd:element name="subResponseCode" type="xsd:string" minOccurs="0"/> + <xsd:element name="approvedAmount" type="xsd:string" minOccurs="0"/> + <xsd:element name="creditLine" type="xsd:string" minOccurs="0"/> + <xsd:element name="approvedTerms" type="xsd:string" minOccurs="0"/> + <xsd:element name="paymentNetworkTransactionID" type="xsd:string" minOccurs="0"/> + <xsd:element name="cardCategory" type="xsd:string" minOccurs="0"/> + <xsd:element name="ownerMerchantID" type="xsd:string" minOccurs="0"/> + <xsd:element name="requestAmount" type="tns:amount" minOccurs="0"/> + <xsd:element name="requestCurrency" type="xsd:string" minOccurs="0"/> + <xsd:element name="accountBalanceCurrency" type="xsd:string" minOccurs="0"/> + <xsd:element name="accountBalanceSign" type="xsd:string" minOccurs="0"/> + <xsd:element name="amountType" type="xsd:string" minOccurs="0"/> + <xsd:element name="accountType" type="xsd:string" minOccurs="0"/> + <xsd:element name="affluenceIndicator" type="xsd:string" minOccurs="0"/> + <xsd:element name="evEmail" type="xsd:string" minOccurs="0"/> + <xsd:element name="evPhoneNumber" type="xsd:string" minOccurs="0"/> + <xsd:element name="evPostalCode" type="xsd:string" minOccurs="0"/> + <xsd:element name="evName" type="xsd:string" minOccurs="0"/> + <xsd:element name="evStreet" type="xsd:string" minOccurs="0"/> + <xsd:element name="evEmailRaw" type="xsd:string" minOccurs="0"/> + <xsd:element name="evPhoneNumberRaw" type="xsd:string" minOccurs="0"/> + <xsd:element name="evPostalCodeRaw" type="xsd:string" minOccurs="0"/> + <xsd:element name="evNameRaw" type="xsd:string" minOccurs="0"/> + <xsd:element name="evStreetRaw" type="xsd:string" minOccurs="0"/> + <xsd:element name="cardGroup" type="xsd:string" minOccurs="0"/> + <xsd:element name="posData" type="xsd:string" minOccurs="0"/> + <xsd:element name="transactionID" type="xsd:string" minOccurs="0"/> + <xsd:element name="cardIssuerCountry" type="xsd:string" minOccurs="0"/> + <xsd:element name="cardRegulated" type="xsd:string" minOccurs="0"/> + <xsd:element name="cardCommercial" type="xsd:string" minOccurs="0"/> + <xsd:element name="cardPrepaid" type="xsd:string" minOccurs="0"/> + <xsd:element name="cardPayroll" type="xsd:string" minOccurs="0"/> + <xsd:element name="cardHealthcare" type="xsd:string" minOccurs="0"/> + <xsd:element name="cardSignatureDebit" type="xsd:string" minOccurs="0"/> + <xsd:element name="cardPINlessDebit" type="xsd:string" minOccurs="0"/> + <xsd:element name="cardLevel3Eligible" type="xsd:string" minOccurs="0"/> + <xsd:element name="processorTransactionID" type="xsd:string" minOccurs="0"/> + <xsd:element name="providerReasonCode" type="xsd:string" minOccurs="0"/> + <xsd:element name="providerReasonDescription" type="xsd:string" minOccurs="0"/> + <xsd:element name="providerPassThroughData" type="xsd:string" minOccurs="0"/> + <xsd:element name="providerCVNResponseCode" type="xsd:string" minOccurs="0"/> + <xsd:element name="providerAVSResponseCode" type="xsd:string" minOccurs="0"/> + <xsd:element name="providerAcquirerBankCode" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + + <xsd:complexType name="OCTReply"> + <xsd:sequence> + <xsd:element name="reasonCode" type="xsd:integer"/> + <xsd:element name="requestDateTime" type="tns:dateTime" minOccurs="0"/> + <xsd:element name="reconciliationID" type="xsd:string" minOccurs="0"/> + <xsd:element name="processorResponse" type="xsd:string" minOccurs="0"/> + <xsd:element name="approvalCode" type="xsd:string" minOccurs="0"/> + <xsd:element name="amount" type="tns:amount" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + + <xsd:complexType name="CCSaleReply"> + <xsd:sequence> + <xsd:element name="reasonCode" type="xsd:integer"/> + <xsd:element name="amount" type="tns:amount" minOccurs="0"/> + <xsd:element name="authorizationCode" type="xsd:string" minOccurs="0"/> + <xsd:element name="processorResponse" type="xsd:string" minOccurs="0"/> + <xsd:element name="avsCode" type="xsd:string" minOccurs="0"/> + <xsd:element name="avsCodeRaw" type="xsd:string" minOccurs="0"/> + <xsd:element name="cvCode" type="xsd:string" minOccurs="0"/> + <xsd:element name="cvCodeRaw" type="xsd:string" minOccurs="0"/> + <xsd:element name="cavvResponseCode" type="xsd:string" minOccurs="0"/> + <xsd:element name="cavvResponseCodeRaw" type="xsd:string" minOccurs="0"/> + <xsd:element name="cardGroup" type="xsd:string" minOccurs="0"/> + <xsd:element name="paymentNetworkTransactionID" type="xsd:string" minOccurs="0"/> + <xsd:element name="cardCategory" type="xsd:string" minOccurs="0"/> + <xsd:element name="accountBalance" type="tns:amount" minOccurs="0"/> + <xsd:element name="authorizedDateTime" type="tns:dateTime" minOccurs="0"/> + <xsd:element name="requestAmount" type="tns:amount" minOccurs="0"/> + <xsd:element name="reconciliationID" type="xsd:string" minOccurs="0"/> + <xsd:element name="accountBalanceCurrency" type="xsd:string" minOccurs="0"/> + <xsd:element name="accountBalanceSign" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + + <xsd:complexType name="CCSaleCreditReply"> + <xsd:sequence> + <xsd:element name="reasonCode" type="xsd:integer"/> + <xsd:element name="amount" type="tns:amount" minOccurs="0"/> + <xsd:element name="authorizationCode" type="xsd:string" minOccurs="0"/> + <xsd:element name="processorResponse" type="xsd:string" minOccurs="0"/> + <xsd:element name="authorizedDateTime" type="tns:dateTime" minOccurs="0"/> + <xsd:element name="reconciliationID" type="xsd:string" minOccurs="0"/> + <xsd:element name="paymentNetworkTransactionID" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + + <xsd:complexType name="CCSaleReversalReply"> + <xsd:sequence> + <xsd:element name="reasonCode" type="xsd:integer"/> + <xsd:element name="amount" type="tns:amount" minOccurs="0"/> + <xsd:element name="authorizationCode" type="xsd:string" minOccurs="0"/> + <xsd:element name="processorResponse" type="xsd:string" minOccurs="0"/> + <xsd:element name="reconciliationID" type="xsd:string" minOccurs="0"/> + <xsd:element name="requestDateTime" type="tns:dateTime" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + + <xsd:complexType name="CCIncrementalAuthReply"> + <xsd:sequence> + <xsd:element name="reasonCode" type="xsd:integer"/> + <xsd:element name="amount" type="tns:amount" minOccurs="0" /> + <xsd:element name="authorizationCode" type="xsd:string" minOccurs="0" /> + <xsd:element name="processorResponse" type="xsd:string" minOccurs="0" /> + <xsd:element name="authorizedDateTime" type="tns:dateTime" minOccurs="0" /> + <xsd:element name="reconciliationID" type="xsd:string" minOccurs="0" /> + <xsd:element name="paymentNetworkTransactionID" type="xsd:string" minOccurs="0" /> + <xsd:element name="cardCategory" type="xsd:string" minOccurs="0" /> + </xsd:sequence> + </xsd:complexType> + + <xsd:complexType name="CCCaptureReply"> + <xsd:sequence> + <xsd:element name="reasonCode" type="xsd:integer"/> + <xsd:element name="requestDateTime" type="tns:dateTime" minOccurs="0"/> + <xsd:element name="amount" type="tns:amount" minOccurs="0"/> + <xsd:element name="reconciliationID" type="xsd:string" minOccurs="0"/> + <xsd:element name="fundingTotals" type="tns:FundingTotals" minOccurs="0"/> + <xsd:element name="fxQuoteID" type="xsd:string" minOccurs="0"/> + <xsd:element name="fxQuoteRate" type="tns:dateTime" minOccurs="0"/> + <xsd:element name="fxQuoteType" type="xsd:string" minOccurs="0"/> + <xsd:element name="fxQuoteExpirationDateTime" type="tns:dateTime" minOccurs="0"/> + <xsd:element name="purchasingLevel3Enabled" type="xsd:string" minOccurs="0"/> + <xsd:element name="enhancedDataEnabled" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="ServiceFeeCalculateReply"> + <xsd:sequence> + <xsd:element name="reasonCode" type="xsd:integer" /> + <xsd:element name="amount" type="tns:amount" minOccurs="0" /> + <xsd:element name="requestDateTime" type="tns:dateTime" minOccurs="0" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CCCreditReply"> + <xsd:sequence> + <xsd:element name="reasonCode" type="xsd:integer"/> + <xsd:element name="requestDateTime" type="tns:dateTime" minOccurs="0"/> + <xsd:element name="amount" type="tns:amount" minOccurs="0"/> + <xsd:element name="reconciliationID" type="xsd:string" minOccurs="0"/> + <xsd:element name="purchasingLevel3Enabled" type="xsd:string" minOccurs="0"/> + <xsd:element name="enhancedDataEnabled" type="xsd:string" minOccurs="0"/> + <xsd:element name="authorizationXID" type="xsd:string" minOccurs="0"/> + <xsd:element name="forwardCode" type="xsd:string" minOccurs="0"/> + <xsd:element name="ownerMerchantID" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="PinDebitPurchaseReply"> + <xsd:sequence> + <xsd:element name="reasonCode" type="xsd:integer"/> + <xsd:element name="processorResponse" type="xsd:string" minOccurs="0"/> + <xsd:element name="authorizationCode" type="xsd:string" minOccurs="0"/> + <xsd:element name="reconciliationID" type="xsd:string" minOccurs="0"/> + <xsd:element name="networkCode" type="xsd:string" minOccurs="0"/> + <xsd:element name="transactionID" type="xsd:string" minOccurs="0"/> + <xsd:element name="requestAmount" type="tns:amount" minOccurs="0"/> + <xsd:element name="requestCurrency" type="xsd:string" minOccurs="0"/> + <xsd:element name="amount" type="tns:amount" minOccurs="0"/> + <xsd:element name="dateTime" type="tns:dateTime" minOccurs="0"/> + <xsd:element name="accountType" type="xsd:string" minOccurs="0"/> + <xsd:element name="amountType" type="xsd:string" minOccurs="0"/> + <xsd:element name="accountBalance" type="xsd:string" minOccurs="0"/> + <xsd:element name="accountBalanceCurrency" type="xsd:string" minOccurs="0"/> + <xsd:element name="accountBalanceSign" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="PinDebitCreditReply"> + <xsd:sequence> + <xsd:element name="reasonCode" type="xsd:integer"/> + <xsd:element name="processorResponse" type="xsd:string" minOccurs="0"/> + <xsd:element name="authorizationCode" type="xsd:string" minOccurs="0"/> + <xsd:element name="reconciliationID" type="xsd:string" minOccurs="0"/> + <xsd:element name="networkCode" type="xsd:string" minOccurs="0"/> + <xsd:element name="transactionID" type="xsd:string" minOccurs="0"/> + <xsd:element name="amount" type="tns:amount" minOccurs="0"/> + <xsd:element name="dateTime" type="tns:dateTime" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="PinDebitReversalReply"> + <xsd:sequence> + <xsd:element name="reasonCode" type="xsd:integer"/> + <xsd:element name="processorResponse" type="xsd:string" minOccurs="0"/> + <xsd:element name="reconciliationID" type="xsd:string" minOccurs="0"/> + <xsd:element name="amount" type="tns:amount" minOccurs="0"/> + <xsd:element name="dateTime" type="tns:dateTime" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CCAuthReversalReply"> + <xsd:sequence> + <xsd:element name="reasonCode" type="xsd:integer"/> + <xsd:element name="amount" type="tns:amount" minOccurs="0"/> + <xsd:element name="authorizationCode" type="xsd:string" minOccurs="0"/> + <xsd:element name="processorResponse" type="xsd:string" minOccurs="0"/> + <xsd:element name="requestDateTime" type="tns:dateTime" minOccurs="0"/> + <xsd:element name="forwardCode" type="xsd:string" minOccurs="0"/> + <xsd:element name="reconciliationID" type="xsd:string" minOccurs="0"/> + <xsd:element name="processorTransactionID" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CCAutoAuthReversalReply"> + <xsd:sequence> + <xsd:element name="reasonCode" type="xsd:integer"/> + <xsd:element name="processorResponse" type="xsd:string" minOccurs="0"/> + <xsd:element name="result" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="ECDebitReply"> + <xsd:sequence> + <xsd:element name="reasonCode" type="xsd:integer"/> + <xsd:element name="settlementMethod" type="xsd:string" minOccurs="0"/> + <xsd:element name="requestDateTime" type="tns:dateTime" minOccurs="0"/> + <xsd:element name="amount" type="tns:amount" minOccurs="0"/> + <xsd:element name="verificationLevel" type="xsd:integer" minOccurs="0"/> + <xsd:element name="processorTransactionID" type="xsd:string" minOccurs="0"/> + <xsd:element name="reconciliationID" type="xsd:string" minOccurs="0"/> + <xsd:element name="processorResponse" type="xsd:string" minOccurs="0"/> + <xsd:element name="avsCode" type="xsd:string" minOccurs="0"/> + <xsd:element name="avsCodeRaw" type="xsd:string" minOccurs="0"/> + <xsd:element name="verificationCode" type="xsd:string" minOccurs="0"/> + <xsd:element name="verificationCodeRaw" type="xsd:string" minOccurs="0"/> + <xsd:element name="correctedAccountNumber" type="xsd:string" minOccurs="0"/> + <xsd:element name="correctedRoutingNumber" type="xsd:string" minOccurs="0"/> + <xsd:element name="ownerMerchantID" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="ECCreditReply"> + <xsd:sequence> + <xsd:element name="reasonCode" type="xsd:integer"/> + <xsd:element name="settlementMethod" type="xsd:string" minOccurs="0"/> + <xsd:element name="requestDateTime" type="tns:dateTime" minOccurs="0"/> + <xsd:element name="amount" type="tns:amount" minOccurs="0"/> + <xsd:element name="processorTransactionID" type="xsd:string" minOccurs="0"/> + <xsd:element name="reconciliationID" type="xsd:string" minOccurs="0"/> + <xsd:element name="processorResponse" type="xsd:string" minOccurs="0"/> + <xsd:element name="verificationCode" type="xsd:string" minOccurs="0"/> + <xsd:element name="verificationCodeRaw" type="xsd:string" minOccurs="0"/> + <xsd:element name="correctedAccountNumber" type="xsd:string" minOccurs="0"/> + <xsd:element name="correctedRoutingNumber" type="xsd:string" minOccurs="0"/> + <xsd:element name="ownerMerchantID" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="ECAuthenticateReply"> + <xsd:sequence> + <xsd:element name="reasonCode" type="xsd:integer"/> + <xsd:element name="requestDateTime" type="tns:dateTime" minOccurs="0"/> + <xsd:element name="processorResponse" type="xsd:string" minOccurs="0"/> + <xsd:element name="reconciliationID" type="xsd:string" minOccurs="0"/> + <xsd:element name="checkpointSummary" type="xsd:string" minOccurs="0"/> + <xsd:element name="fraudShieldIndicators" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="PayerAuthEnrollReply"> + <xsd:sequence> + <xsd:element name="reasonCode" type="xsd:integer"/> + <xsd:element name="acsURL" type="xsd:string" minOccurs="0"/> + <xsd:element name="commerceIndicator" type="xsd:string" minOccurs="0"/> + <xsd:element name="eci" type="xsd:string" minOccurs="0"/> + <xsd:element name="paReq" type="xsd:string" minOccurs="0"/> + <xsd:element name="proxyPAN" type="xsd:string" minOccurs="0"/> + <xsd:element name="xid" type="xsd:string" minOccurs="0"/> + <xsd:element name="proofXML" type="xsd:string" minOccurs="0"/> + <xsd:element name="ucafCollectionIndicator" type="xsd:string" minOccurs="0"/> + <xsd:element name="veresEnrolled" type="xsd:string" minOccurs="0"/> + <xsd:element name="authenticationPath" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="PayerAuthValidateReply"> + <xsd:sequence> + <xsd:element name="reasonCode" type="xsd:integer"/> + <xsd:element name="authenticationResult" type="xsd:string" minOccurs="0"/> + <xsd:element name="authenticationStatusMessage" type="xsd:string" minOccurs="0"/> + <xsd:element name="cavv" type="xsd:string" minOccurs="0"/> + <xsd:element name="cavvAlgorithm" type="xsd:string" minOccurs="0"/> + <xsd:element name="commerceIndicator" type="xsd:string" minOccurs="0"/> + <xsd:element name="eci" type="xsd:string" minOccurs="0"/> + <xsd:element name="eciRaw" type="xsd:string" minOccurs="0"/> + <xsd:element name="xid" type="xsd:string" minOccurs="0"/> + <xsd:element name="ucafAuthenticationData" type="xsd:string" minOccurs="0"/> + <xsd:element name="ucafCollectionIndicator" type="xsd:string" minOccurs="0"/> + <xsd:element name="paresStatus" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="TaxReplyItem"> + <xsd:sequence> + <xsd:element name="cityTaxAmount" type="tns:amount" minOccurs="0"/> + <xsd:element name="countyTaxAmount" type="tns:amount" minOccurs="0"/> + <xsd:element name="districtTaxAmount" type="tns:amount" minOccurs="0"/> + <xsd:element name="stateTaxAmount" type="tns:amount" minOccurs="0"/> + <xsd:element name="totalTaxAmount" type="tns:amount"/> + </xsd:sequence> + <xsd:attribute name="id" type="xsd:integer" use="required"/> + </xsd:complexType> + <xsd:complexType name="TaxReply"> + <xsd:sequence> + <xsd:element name="reasonCode" type="xsd:integer"/> + <xsd:element name="currency" type="xsd:string" minOccurs="0"/> + <xsd:element name="grandTotalAmount" type="tns:amount" minOccurs="0"/> + <xsd:element name="totalCityTaxAmount" type="tns:amount" minOccurs="0"/> + <xsd:element name="city" type="xsd:string" minOccurs="0"/> + <xsd:element name="totalCountyTaxAmount" type="tns:amount" minOccurs="0"/> + <xsd:element name="county" type="xsd:string" minOccurs="0"/> + <xsd:element name="totalDistrictTaxAmount" type="tns:amount" minOccurs="0"/> + <xsd:element name="totalStateTaxAmount" type="tns:amount" minOccurs="0"/> + <xsd:element name="state" type="xsd:string" minOccurs="0"/> + <xsd:element name="totalTaxAmount" type="tns:amount" minOccurs="0"/> + <xsd:element name="postalCode" type="xsd:string" minOccurs="0"/> + <xsd:element name="geocode" type="xsd:string" minOccurs="0"/> + <xsd:element name="item" type="tns:TaxReplyItem" minOccurs="0" maxOccurs="1000"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="DeviceFingerprint"> + <xsd:sequence> + <xsd:element name="cookiesEnabled" type="tns:boolean" minOccurs="0"/> + <xsd:element name="flashEnabled" type="tns:boolean" minOccurs="0"/> + <xsd:element name="hash" type="xsd:string" minOccurs="0"/> + <xsd:element name="imagesEnabled" type="tns:boolean" minOccurs="0"/> + <xsd:element name="javascriptEnabled" type="tns:boolean" minOccurs="0"/> + <xsd:element name="proxyIPAddress" type="xsd:string" minOccurs="0"/> + <xsd:element name="proxyIPAddressActivities" type="xsd:string" minOccurs="0"/> + <xsd:element name="proxyIPAddressAttributes" type="xsd:string" minOccurs="0"/> + <xsd:element name="proxyServerType" type="xsd:string" minOccurs="0"/> + <xsd:element name="trueIPAddress" type="xsd:string" minOccurs="0"/> + <xsd:element name="trueIPAddressActivities" type="xsd:string" minOccurs="0"/> + <xsd:element name="trueIPAddressAttributes" type="xsd:string" minOccurs="0"/> + <xsd:element name="trueIPAddressCity" type="xsd:string" minOccurs="0"/> + <xsd:element name="trueIPAddressCountry" type="xsd:string" minOccurs="0"/> + <xsd:element name="smartID" type="xsd:string" minOccurs="0"/> + <xsd:element name="smartIDConfidenceLevel" type="xsd:string" minOccurs="0"/> + <xsd:element name="screenResolution" type="xsd:string" minOccurs="0"/> + <xsd:element name="browserLanguage" type="xsd:string" minOccurs="0"/> + <xsd:element name="agentType" type="xsd:string" minOccurs="0"/> + <xsd:element name="dateTime" type="tns:dateTime" minOccurs="0"/> + <xsd:element name="profileDuration" type="xsd:integer" minOccurs="0"/> + <xsd:element name="profiledURL" type="xsd:string" minOccurs="0"/> + <xsd:element name="timeOnPage" type="xsd:integer" minOccurs="0"/> + <xsd:element name="deviceMatch" type="xsd:string" minOccurs="0"/> + <xsd:element name="firstEncounter" type="xsd:string" minOccurs="0"/> + <xsd:element name="flashOS" type="xsd:string" minOccurs="0"/> + <xsd:element name="flashVersion" type="xsd:string" minOccurs="0"/> + <xsd:element name="deviceLatitude" type="xsd:string" minOccurs="0"/> + <xsd:element name="deviceLongitude" type="xsd:string" minOccurs="0"/> + <xsd:element name="gpsAccuracy" type="xsd:string" minOccurs="0"/> + <xsd:element name="jbRoot" type="xsd:integer" minOccurs="0"/> + <xsd:element name="jbRootReason" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="AFSReply"> + <xsd:sequence> + <xsd:element name="reasonCode" type="xsd:integer"/> + <xsd:element name="afsResult" type="xsd:integer" minOccurs="0"/> + <xsd:element name="hostSeverity" type="xsd:integer" minOccurs="0"/> + <xsd:element name="consumerLocalTime" type="xsd:string" minOccurs="0"/> + <!-- xsd:time --> + <xsd:element name="afsFactorCode" type="xsd:string" minOccurs="0"/> + <xsd:element name="addressInfoCode" type="xsd:string" minOccurs="0"/> + <xsd:element name="hotlistInfoCode" type="xsd:string" minOccurs="0"/> + <xsd:element name="internetInfoCode" type="xsd:string" minOccurs="0"/> + <xsd:element name="phoneInfoCode" type="xsd:string" minOccurs="0"/> + <xsd:element name="suspiciousInfoCode" type="xsd:string" minOccurs="0"/> + <xsd:element name="velocityInfoCode" type="xsd:string" minOccurs="0"/> + <xsd:element name="identityInfoCode" type="xsd:string" minOccurs="0"/> + <xsd:element name="ipCountry" type="xsd:string" minOccurs="0"/> + <xsd:element name="ipState" type="xsd:string" minOccurs="0"/> + <xsd:element name="ipCity" type="xsd:string" minOccurs="0"/> + <xsd:element name="ipRoutingMethod" type="xsd:string" minOccurs="0"/> + <xsd:element name="ipAnonymizerStatus" type="xsd:string" minOccurs="0"/> + <xsd:element name="scoreModelUsed" type="xsd:string" minOccurs="0"/> + <xsd:element name="cardBin" type="xsd:string" minOccurs="0"/> + <xsd:element name="binCountry" type="xsd:string" minOccurs="0"/> + <xsd:element name="cardAccountType" type="xsd:string" minOccurs="0"/> + <xsd:element name="cardScheme" type="xsd:string" minOccurs="0"/> + <xsd:element name="cardIssuer" type="xsd:string" minOccurs="0"/> + <xsd:element name="deviceFingerprint" type="tns:DeviceFingerprint" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="DAVReply"> + <xsd:sequence> + <xsd:element name="reasonCode" type="xsd:integer"/> + <xsd:element name="addressType" type="xsd:string" minOccurs="0"/> + <xsd:element name="apartmentInfo" type="xsd:string" minOccurs="0"/> + <xsd:element name="barCode" type="xsd:string" minOccurs="0"/> + <xsd:element name="barCodeCheckDigit" type="xsd:string" minOccurs="0"/> + <xsd:element name="careOf" type="xsd:string" minOccurs="0"/> + <xsd:element name="cityInfo" type="xsd:string" minOccurs="0"/> + <xsd:element name="countryInfo" type="xsd:string" minOccurs="0"/> + <xsd:element name="directionalInfo" type="xsd:string" minOccurs="0"/> + <xsd:element name="lvrInfo" type="xsd:string" minOccurs="0"/> + <xsd:element name="matchScore" type="xsd:integer" minOccurs="0"/> + <xsd:element name="standardizedAddress1" type="xsd:string" minOccurs="0"/> + <xsd:element name="standardizedAddress2" type="xsd:string" minOccurs="0"/> + <xsd:element name="standardizedAddress3" type="xsd:string" minOccurs="0"/> + <xsd:element name="standardizedAddress4" type="xsd:string" minOccurs="0"/> + <xsd:element name="standardizedAddressNoApt" type="xsd:string" minOccurs="0"/> + <xsd:element name="standardizedCity" type="xsd:string" minOccurs="0"/> + <xsd:element name="standardizedCounty" type="xsd:string" minOccurs="0"/> + <xsd:element name="standardizedCSP" type="xsd:string" minOccurs="0"/> + <xsd:element name="standardizedState" type="xsd:string" minOccurs="0"/> + <xsd:element name="standardizedPostalCode" type="xsd:string" minOccurs="0"/> + <xsd:element name="standardizedCountry" type="xsd:string" minOccurs="0"/> + <xsd:element name="standardizedISOCountry" type="xsd:string" minOccurs="0"/> + <xsd:element name="stateInfo" type="xsd:string" minOccurs="0"/> + <xsd:element name="streetInfo" type="xsd:string" minOccurs="0"/> + <xsd:element name="suffixInfo" type="xsd:string" minOccurs="0"/> + <xsd:element name="postalCodeInfo" type="xsd:string" minOccurs="0"/> + <xsd:element name="overallInfo" type="xsd:string" minOccurs="0"/> + <xsd:element name="usInfo" type="xsd:string" minOccurs="0"/> + <xsd:element name="caInfo" type="xsd:string" minOccurs="0"/> + <xsd:element name="intlInfo" type="xsd:string" minOccurs="0"/> + <xsd:element name="usErrorInfo" type="xsd:string" minOccurs="0"/> + <xsd:element name="caErrorInfo" type="xsd:string" minOccurs="0"/> + <xsd:element name="intlErrorInfo" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="DeniedPartiesMatch"> + <xsd:sequence> + <xsd:element name="list" type="xsd:string" minOccurs="0"/> + <xsd:element name="name" type="xsd:string" minOccurs="0" maxOccurs="100"/> + <xsd:element name="address" type="xsd:string" minOccurs="0" maxOccurs="100"/> + <xsd:element name="program" type="xsd:string" minOccurs="0" maxOccurs="100"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="ExportReply"> + <xsd:sequence> + <xsd:element name="reasonCode" type="xsd:integer"/> + <xsd:element name="ipCountryConfidence" type="xsd:integer" minOccurs="0"/> + <xsd:element name="infoCode" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="FXQuote"> + <xsd:sequence> + <xsd:element name="id" type="xsd:string" minOccurs="0"/> + <xsd:element name="rate" type="xsd:string" minOccurs="0"/> + <xsd:element name="type" type="xsd:string" minOccurs="0"/> + <xsd:element name="expirationDateTime" type="tns:dateTime" minOccurs="0"/> + <xsd:element name="currency" type="xsd:string" minOccurs="0"/> + <xsd:element name="fundingCurrency" type="xsd:string" minOccurs="0"/> + <xsd:element name="receivedDateTime" type="tns:dateTime" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="FXRatesReply"> + <xsd:sequence> + <xsd:element name="reasonCode" type="xsd:integer"/> + <xsd:element name="quote" type="tns:FXQuote" minOccurs="0" maxOccurs="999"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="BankTransferReply"> + <xsd:sequence> + <xsd:element name="reasonCode" type="xsd:integer"/> + <xsd:element name="accountHolder" type="xsd:string" minOccurs="0"/> + <xsd:element name="accountNumber" type="xsd:string" minOccurs="0"/> + <xsd:element name="amount" type="tns:amount" minOccurs="0"/> + <xsd:element name="bankName" type="xsd:string" minOccurs="0"/> + <xsd:element name="bankCity" type="xsd:string" minOccurs="0"/> + <xsd:element name="bankCountry" type="xsd:string" minOccurs="0"/> + <xsd:element name="paymentReference" type="xsd:string" minOccurs="0"/> + <xsd:element name="processorResponse" type="xsd:string" minOccurs="0"/> + <xsd:element name="bankSwiftCode" type="xsd:string" minOccurs="0"/> + <xsd:element name="bankSpecialID" type="xsd:string" minOccurs="0"/> + <xsd:element name="requestDateTime" type="tns:dateTime" minOccurs="0"/> + <xsd:element name="reconciliationID" type="xsd:string" minOccurs="0"/> + <xsd:element name="iban" type="xsd:string" minOccurs="0"/> + <xsd:element name="bankCode" type="xsd:string" minOccurs="0"/> + <xsd:element name="branchCode" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="BankTransferRealTimeReply"> + <xsd:sequence> + <xsd:element name="reasonCode" type="xsd:integer"/> + <xsd:element name="formMethod" type="xsd:string" minOccurs="0"/> + <xsd:element name="formAction" type="xsd:string" minOccurs="0"/> + <xsd:element name="requestDateTime" type="tns:dateTime" minOccurs="0"/> + <xsd:element name="reconciliationID" type="xsd:string" minOccurs="0"/> + <xsd:element name="paymentReference" type="xsd:string" minOccurs="0"/> + <xsd:element name="amount" type="tns:amount" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="DirectDebitMandateReply"> + <xsd:sequence> + <xsd:element name="reasonCode" type="xsd:integer"/> + <xsd:element name="mandateID" type="xsd:string" minOccurs="0"/> + <xsd:element name="mandateMaturationDate" type="xsd:string" minOccurs="0"/> + <xsd:element name="requestDateTime" type="tns:dateTime" minOccurs="0"/> + <xsd:element name="reconciliationID" type="xsd:string" minOccurs="0"/> + <xsd:element name="processorResponse" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="BankTransferRefundReply"> + <xsd:sequence> + <xsd:element name="reasonCode" type="xsd:integer"/> + <xsd:element name="amount" type="tns:amount" minOccurs="0"/> + <xsd:element name="requestDateTime" type="tns:dateTime" minOccurs="0"/> + <xsd:element name="reconciliationID" type="xsd:string" minOccurs="0"/> + <xsd:element name="processorResponse" type="xsd:string" minOccurs="0"/> + <xsd:element name="iban" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="DirectDebitReply"> + <xsd:sequence> + <xsd:element name="reasonCode" type="xsd:integer"/> + <xsd:element name="amount" type="tns:amount" minOccurs="0"/> + <xsd:element name="requestDateTime" type="tns:dateTime" minOccurs="0"/> + <xsd:element name="reconciliationID" type="xsd:string" minOccurs="0"/> + <xsd:element name="processorResponse" type="xsd:string" minOccurs="0"/> + <xsd:element name="processorTransactionID" type="xsd:string" minOccurs="0"/> + <xsd:element name="mandateAuthenticationDate" type="xsd:string" minOccurs="0"/> + <xsd:element name="mandateID" type="xsd:string" minOccurs="0"/> + <xsd:element name="iban" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="DirectDebitValidateReply"> + <xsd:sequence> + <xsd:element name="reasonCode" type="xsd:integer"/> + <xsd:element name="amount" type="tns:amount" minOccurs="0"/> + <xsd:element name="requestDateTime" type="tns:dateTime" minOccurs="0"/> + <xsd:element name="reconciliationID" type="xsd:string" minOccurs="0"/> + <xsd:element name="processorResponse" type="xsd:string" minOccurs="0"/> + <xsd:element name="iban" type="xsd:string" minOccurs="0"/> + <xsd:element name="bankSwiftCode" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="DirectDebitRefundReply"> + <xsd:sequence> + <xsd:element name="reasonCode" type="xsd:integer"/> + <xsd:element name="amount" type="tns:amount" minOccurs="0"/> + <xsd:element name="requestDateTime" type="tns:dateTime" minOccurs="0"/> + <xsd:element name="reconciliationID" type="xsd:string" minOccurs="0"/> + <xsd:element name="processorResponse" type="xsd:string" minOccurs="0"/> + <xsd:element name="processorTransactionID" type="xsd:string" minOccurs="0"/> + <xsd:element name="iban" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="PaySubscriptionCreateReply"> + <xsd:sequence> + <xsd:element name="reasonCode" type="xsd:integer"/> + <xsd:element name="subscriptionID" type="xsd:string"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="PaySubscriptionUpdateReply"> + <xsd:sequence> + <xsd:element name="reasonCode" type="xsd:integer"/> + <xsd:element name="subscriptionID" type="xsd:string"/> + <xsd:element name="subscriptionIDNew" type="xsd:string" minOccurs="0"/> + <xsd:element name="ownerMerchantID" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="PaySubscriptionEventUpdateReply"> + <xsd:sequence> + <xsd:element name="reasonCode" type="xsd:integer"/> + <xsd:element name="ownerMerchantID" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="PaySubscriptionRetrieveReply"> + <xsd:sequence> + <xsd:element name="reasonCode" type="xsd:integer"/> + <xsd:element name="approvalRequired" type="xsd:string" minOccurs="0"/> + <xsd:element name="automaticRenew" type="xsd:string" minOccurs="0"/> + <xsd:element name="cardAccountNumber" type="xsd:string" minOccurs="0"/> + <xsd:element name="cardExpirationMonth" type="xsd:string" minOccurs="0"/> + <xsd:element name="cardExpirationYear" type="xsd:string" minOccurs="0"/> + <xsd:element name="cardIssueNumber" type="xsd:string" minOccurs="0"/> + <xsd:element name="cardStartMonth" type="xsd:string" minOccurs="0"/> + <xsd:element name="cardStartYear" type="xsd:string" minOccurs="0"/> + <xsd:element name="cardType" type="xsd:string" minOccurs="0"/> + <xsd:element name="checkAccountNumber" type="xsd:string" minOccurs="0"/> + <xsd:element name="checkAccountType" type="xsd:string" minOccurs="0"/> + <xsd:element name="checkBankTransitNumber" type="xsd:string" minOccurs="0"/> + <xsd:element name="checkSecCode" type="xsd:string" minOccurs="0"/> + <xsd:element name="checkAuthenticateID" type="xsd:string" minOccurs="0"/> + <xsd:element name="city" type="xsd:string" minOccurs="0"/> + <xsd:element name="comments" type="xsd:string" minOccurs="0"/> + <xsd:element name="companyName" type="xsd:string" minOccurs="0"/> + <xsd:element name="country" type="xsd:string" minOccurs="0"/> + <xsd:element name="currency" type="xsd:string" minOccurs="0"/> + <xsd:element name="customerAccountID" type="xsd:string" minOccurs="0"/> + <xsd:element name="email" type="xsd:string" minOccurs="0"/> + <xsd:element name="endDate" type="xsd:string" minOccurs="0"/> + <xsd:element name="firstName" type="xsd:string" minOccurs="0"/> + <xsd:element name="frequency" type="xsd:string" minOccurs="0"/> + <xsd:element name="lastName" type="xsd:string" minOccurs="0"/> + <xsd:element name="merchantReferenceCode" type="xsd:string" minOccurs="0"/> + <xsd:element name="paymentMethod" type="xsd:string" minOccurs="0"/> + <xsd:element name="paymentsRemaining" type="xsd:string" minOccurs="0"/> + <xsd:element name="phoneNumber" type="xsd:string" minOccurs="0"/> + <xsd:element name="postalCode" type="xsd:string" minOccurs="0"/> + <xsd:element name="recurringAmount" type="xsd:string" minOccurs="0"/> + <xsd:element name="setupAmount" type="xsd:string" minOccurs="0"/> + <xsd:element name="startDate" type="xsd:string" minOccurs="0"/> + <xsd:element name="state" type="xsd:string" minOccurs="0"/> + <xsd:element name="status" type="xsd:string" minOccurs="0"/> + <xsd:element name="street1" type="xsd:string" minOccurs="0"/> + <xsd:element name="street2" type="xsd:string" minOccurs="0"/> + <xsd:element name="subscriptionID" type="xsd:string" minOccurs="0"/> + <xsd:element name="subscriptionIDNew" type="xsd:string"/> + <xsd:element name="title" type="xsd:string" minOccurs="0"/> + <xsd:element name="totalPayments" type="xsd:string" minOccurs="0"/> + <xsd:element name="shipToFirstName" type="xsd:string" minOccurs="0"/> + <xsd:element name="shipToLastName" type="xsd:string" minOccurs="0"/> + <xsd:element name="shipToStreet1" type="xsd:string" minOccurs="0"/> + <xsd:element name="shipToStreet2" type="xsd:string" minOccurs="0"/> + <xsd:element name="shipToCity" type="xsd:string" minOccurs="0"/> + <xsd:element name="shipToState" type="xsd:string" minOccurs="0"/> + <xsd:element name="shipToPostalCode" type="xsd:string" minOccurs="0"/> + <xsd:element name="shipToCompany" type="xsd:string" minOccurs="0"/> + <xsd:element name="shipToCountry" type="xsd:string" minOccurs="0"/> + <xsd:element name="billPayment" type="xsd:string" minOccurs="0"/> + <xsd:element name="merchantDefinedDataField1" type="xsd:string" minOccurs="0"/> + <xsd:element name="merchantDefinedDataField2" type="xsd:string" minOccurs="0"/> + <xsd:element name="merchantDefinedDataField3" type="xsd:string" minOccurs="0"/> + <xsd:element name="merchantDefinedDataField4" type="xsd:string" minOccurs="0"/> + <xsd:element name="merchantSecureDataField1" type="xsd:string" minOccurs="0"/> + <xsd:element name="merchantSecureDataField2" type="xsd:string" minOccurs="0"/> + <xsd:element name="merchantSecureDataField3" type="xsd:string" minOccurs="0"/> + <xsd:element name="merchantSecureDataField4" type="xsd:string" minOccurs="0"/> + <xsd:element name="ownerMerchantID" type="xsd:string" minOccurs="0"/> + <xsd:element name="companyTaxID" type="xsd:string" minOccurs="0"/> + <xsd:element name="driversLicenseNumber" type="xsd:string" minOccurs="0"/> + <xsd:element name="driversLicenseState" type="xsd:string" minOccurs="0"/> + <xsd:element name="dateOfBirth" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="PaySubscriptionDeleteReply"> + <xsd:sequence> + <xsd:element name="reasonCode" type="xsd:integer"/> + <xsd:element name="subscriptionID" type="xsd:string"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="PayPalPaymentReply"> + <xsd:sequence> + <xsd:element name="reasonCode" type="xsd:integer"/> + <xsd:element name="secureData" type="xsd:string" minOccurs="0"/> + <xsd:element name="amount" type="tns:amount" minOccurs="0"/> + <xsd:element name="requestDateTime" type="tns:dateTime" minOccurs="0"/> + <xsd:element name="reconciliationID" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="PayPalCreditReply"> + <xsd:sequence> + <xsd:element name="reasonCode" type="xsd:integer"/> + <xsd:element name="amount" type="tns:amount" minOccurs="0"/> + <xsd:element name="requestDateTime" type="tns:dateTime" minOccurs="0"/> + <xsd:element name="reconciliationID" type="xsd:string" minOccurs="0"/> + <xsd:element name="processorResponse" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="VoidReply"> + <xsd:sequence> + <xsd:element name="reasonCode" type="xsd:integer"/> + <xsd:element name="requestDateTime" type="tns:dateTime" minOccurs="0"/> + <xsd:element name="amount" type="tns:amount" minOccurs="0"/> + <xsd:element name="currency" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="PinlessDebitReply"> + <xsd:sequence> + <xsd:element name="reasonCode" type="xsd:integer"/> + <xsd:element name="amount" type="tns:amount" minOccurs="0"/> + <xsd:element name="authorizationCode" type="xsd:string" minOccurs="0"/> + <xsd:element name="requestDateTime" type="tns:dateTime" minOccurs="0"/> + <!-- dateTime --> + <xsd:element name="processorResponse" type="xsd:string" minOccurs="0"/> + <xsd:element name="receiptNumber" type="xsd:string" minOccurs="0"/> + <xsd:element name="reconciliationID" type="xsd:string" minOccurs="0"/> + <xsd:element name="ownerMerchantID" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="PinlessDebitValidateReply"> + <xsd:sequence> + <xsd:element name="reasonCode" type="xsd:integer"/> + <xsd:element name="status" type="xsd:string" minOccurs="0"/> + <xsd:element name="requestDateTime" type="tns:dateTime" minOccurs="0"/> + <!-- dateTime --> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="PinlessDebitReversalReply"> + <xsd:sequence> + <xsd:element name="reasonCode" type="xsd:integer"/> + <xsd:element name="amount" type="tns:amount" minOccurs="0"/> + <xsd:element name="requestDateTime" type="tns:dateTime" minOccurs="0"/> + <xsd:element name="processorResponse" type="xsd:string" minOccurs="0"/> + <xsd:element name="reconciliationID" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <!-- payPal Upgrade Services --> + <xsd:complexType name="PayPalButtonCreateReply"> + <xsd:sequence> + <xsd:element name="reasonCode" type="xsd:integer"/> + <xsd:element name="encryptedFormData" type="xsd:string" minOccurs="0"/> + <xsd:element name="unencryptedFormData" type="xsd:string" minOccurs="0"/> + <xsd:element name="requestDateTime" type="tns:dateTime" minOccurs="0"/> + <xsd:element name="reconciliationID" type="xsd:string" minOccurs="0"/> + <xsd:element name="buttonType" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="PayPalPreapprovedPaymentReply"> + <xsd:sequence> + <xsd:element name="reasonCode" type="xsd:integer"/> + <xsd:element name="requestDateTime" type="tns:dateTime" minOccurs="0"/> + <xsd:element name="reconciliationID" type="xsd:string" minOccurs="0"/> + <xsd:element name="payerStatus" type="xsd:string" minOccurs="0"/> + <xsd:element name="payerName" type="xsd:string" minOccurs="0"/> + <xsd:element name="transactionType" type="xsd:string" minOccurs="0"/> + <xsd:element name="feeAmount" type="xsd:string" minOccurs="0"/> + <xsd:element name="payerCountry" type="xsd:string" minOccurs="0"/> + <xsd:element name="pendingReason" type="xsd:string" minOccurs="0"/> + <xsd:element name="paymentStatus" type="xsd:string" minOccurs="0"/> + <xsd:element name="mpStatus" type="xsd:string" minOccurs="0"/> + <xsd:element name="payer" type="xsd:string" minOccurs="0"/> + <xsd:element name="payerID" type="xsd:string" minOccurs="0"/> + <xsd:element name="payerBusiness" type="xsd:string" minOccurs="0"/> + <xsd:element name="transactionID" type="xsd:string" minOccurs="0"/> + <xsd:element name="desc" type="xsd:string" minOccurs="0"/> + <xsd:element name="mpMax" type="xsd:string" minOccurs="0"/> + <xsd:element name="paymentType" type="xsd:string" minOccurs="0"/> + <xsd:element name="paymentDate" type="xsd:string" minOccurs="0"/> + <xsd:element name="paymentGrossAmount" type="xsd:string" minOccurs="0"/> + <xsd:element name="settleAmount" type="xsd:string" minOccurs="0"/> + <xsd:element name="taxAmount" type="xsd:string" minOccurs="0"/> + <xsd:element name="exchangeRate" type="xsd:string" minOccurs="0"/> + <xsd:element name="paymentSourceID" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="PayPalPreapprovedUpdateReply"> + <xsd:sequence> + <xsd:element name="reasonCode" type="xsd:integer"/> + <xsd:element name="requestDateTime" type="tns:dateTime" minOccurs="0"/> + <xsd:element name="reconciliationID" type="xsd:string" minOccurs="0"/> + <xsd:element name="payerStatus" type="xsd:string" minOccurs="0"/> + <xsd:element name="payerName" type="xsd:string" minOccurs="0"/> + <xsd:element name="payerCountry" type="xsd:string" minOccurs="0"/> + <xsd:element name="mpStatus" type="xsd:string" minOccurs="0"/> + <xsd:element name="payer" type="xsd:string" minOccurs="0"/> + <xsd:element name="payerID" type="xsd:string" minOccurs="0"/> + <xsd:element name="payerBusiness" type="xsd:string" minOccurs="0"/> + <xsd:element name="desc" type="xsd:string" minOccurs="0"/> + <xsd:element name="mpMax" type="xsd:string" minOccurs="0"/> + <xsd:element name="paymentSourceID" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <!-- PayPalEcSet --> + <xsd:complexType name="PayPalEcSetReply"> + <xsd:sequence> + <xsd:element name="reasonCode" type="xsd:integer"/> + <xsd:element name="paypalToken" type="xsd:string" minOccurs="0"/> + <xsd:element name="amount" type="xsd:string" minOccurs="0"/> + <xsd:element name="currency" type="xsd:string" minOccurs="0"/> + <xsd:element name="correlationID" type="xsd:string" minOccurs="0"/> + <xsd:element name="errorCode" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <!-- end of PayPalEcSet --> + <!-- PayPalEcGetDetails --> + <xsd:complexType name="PayPalEcGetDetailsReply"> + <xsd:sequence> + <xsd:element name="reasonCode" type="xsd:integer"/> + <xsd:element name="paypalToken" type="xsd:string" minOccurs="0"/> + <xsd:element name="payer" type="xsd:string" minOccurs="0"/> + <xsd:element name="payerId" type="xsd:string" minOccurs="0"/> + <xsd:element name="payerStatus" type="xsd:string" minOccurs="0"/> + <xsd:element name="payerSalutation" type="xsd:string" minOccurs="0"/> + <xsd:element name="payerFirstname" type="xsd:string" minOccurs="0"/> + <xsd:element name="payerMiddlename" type="xsd:string" minOccurs="0"/> + <xsd:element name="payerLastname" type="xsd:string" minOccurs="0"/> + <xsd:element name="payerSuffix" type="xsd:string" minOccurs="0"/> + <xsd:element name="payerCountry" type="xsd:string" minOccurs="0"/> + <xsd:element name="payerBusiness" type="xsd:string" minOccurs="0"/> + <xsd:element name="shipToName" type="xsd:string" minOccurs="0"/> + <xsd:element name="shipToAddress1" type="xsd:string" minOccurs="0"/> + <xsd:element name="shipToAddress2" type="xsd:string" minOccurs="0"/> + <xsd:element name="shipToCity" type="xsd:string" minOccurs="0"/> + <xsd:element name="shipToState" type="xsd:string" minOccurs="0"/> + <xsd:element name="shipToCountry" type="xsd:string" minOccurs="0"/> + <xsd:element name="shipToZip" type="xsd:string" minOccurs="0"/> + <xsd:element name="addressStatus" type="xsd:string" minOccurs="0"/> + <xsd:element name="payerPhone" type="xsd:string" minOccurs="0"/> + <xsd:element name="avsCode" type="xsd:string" minOccurs="0"/> + <xsd:element name="correlationID" type="xsd:string" minOccurs="0"/> + <xsd:element name="errorCode" type="xsd:string" minOccurs="0"/> + <xsd:element name="street1" type="xsd:string" minOccurs="0"/> + <xsd:element name="street2" type="xsd:string" minOccurs="0"/> + <xsd:element name="city" type="xsd:string" minOccurs="0"/> + <xsd:element name="state" type="xsd:string" minOccurs="0"/> + <xsd:element name="postalCode" type="xsd:string" minOccurs="0"/> + <xsd:element name="countryCode" type="xsd:string" minOccurs="0"/> + <xsd:element name="countryName" type="xsd:string" minOccurs="0"/> + <xsd:element name="addressID" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalBillingAgreementAcceptedStatus" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalTaxAmount" type="xsd:string" minOccurs="0"/> + <xsd:element name="item" type="tns:Item" minOccurs="0" maxOccurs="1000" /> + </xsd:sequence> + </xsd:complexType> + <!-- end of PayPalEcGetDetails --> + <!-- PayPalEcDoPayment --> + <xsd:complexType name="PayPalEcDoPaymentReply"> + <xsd:sequence> + <xsd:element name="reasonCode" type="xsd:integer"/> + <xsd:element name="paypalToken" type="xsd:string" minOccurs="0"/> + <xsd:element name="transactionId" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalTransactiontype" type="xsd:string" minOccurs="0"/> + <xsd:element name="paymentType" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalOrderTime" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalAmount" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalFeeAmount" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalTaxAmount" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalExchangeRate" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalPaymentStatus" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalPendingReason" type="xsd:string" minOccurs="0"/> + <xsd:element name="orderId" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalReasonCode" type="xsd:string" minOccurs="0"/> + <xsd:element name="amount" type="xsd:string" minOccurs="0"/> + <xsd:element name="currency" type="xsd:string" minOccurs="0"/> + <xsd:element name="correlationID" type="xsd:string" minOccurs="0"/> + <xsd:element name="errorCode" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalBillingAgreementId" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <!-- end of PayPalEcDoPayment --> + <!-- PayPalDoCapture --> + <xsd:complexType name="PayPalDoCaptureReply"> + <xsd:sequence> + <xsd:element name="reasonCode" type="xsd:integer"/> + <xsd:element name="authorizationId" type="xsd:string" minOccurs="0"/> + <xsd:element name="transactionId" type="xsd:string" minOccurs="0"/> + <xsd:element name="parentTransactionId" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalReceiptId" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalTransactiontype" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalPaymentType" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalOrderTime" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalPaymentGrossAmount" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalFeeAmount" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalTaxAmount" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalExchangeRate" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalPaymentStatus" type="xsd:string" minOccurs="0"/> + <xsd:element name="amount" type="xsd:string" minOccurs="0"/> + <xsd:element name="currency" type="xsd:string" minOccurs="0"/> + <xsd:element name="correlationID" type="xsd:string" minOccurs="0"/> + <xsd:element name="errorCode" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalPendingReason" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <!-- end of PayPalDoCapture --> + <!-- PayPalAuthReversal --> + <xsd:complexType name="PayPalAuthReversalReply"> + <xsd:sequence> + <xsd:element name="reasonCode" type="xsd:integer"/> + <xsd:element name="authorizationId" type="xsd:string" minOccurs="0"/> + <xsd:element name="correlationID" type="xsd:string" minOccurs="0"/> + <xsd:element name="errorCode" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <!-- end of PayPalAuthReversal --> + <!-- PayPalRefund --> + <xsd:complexType name="PayPalRefundReply"> + <xsd:sequence> + <xsd:element name="reasonCode" type="xsd:integer"/> + <xsd:element name="transactionId" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalNetRefundAmount" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalFeeRefundAmount" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalGrossRefundAmount" type="xsd:string" minOccurs="0"/> + <xsd:element name="correlationID" type="xsd:string" minOccurs="0"/> + <xsd:element name="errorCode" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <!-- end of PayPalRefund --> + <!-- PayPalEcOrderSetup --> + <xsd:complexType name="PayPalEcOrderSetupReply"> + <xsd:sequence> + <xsd:element name="reasonCode" type="xsd:integer"/> + <xsd:element name="paypalToken" type="xsd:string" minOccurs="0"/> + <xsd:element name="transactionId" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalTransactiontype" type="xsd:string" minOccurs="0"/> + <xsd:element name="paymentType" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalOrderTime" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalAmount" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalFeeAmount" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalTaxAmount" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalExchangeRate" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalPaymentStatus" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalPendingReason" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalReasonCode" type="xsd:string" minOccurs="0"/> + <xsd:element name="amount" type="xsd:string" minOccurs="0"/> + <xsd:element name="currency" type="xsd:string" minOccurs="0"/> + <xsd:element name="correlationID" type="xsd:string" minOccurs="0"/> + <xsd:element name="errorCode" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <!-- end of PayPalEcOrderSetup --> + <!-- PayPalAuthorization--> + <xsd:complexType name="PayPalAuthorizationReply"> + <xsd:sequence> + <xsd:element name="reasonCode" type="xsd:integer"/> + <xsd:element name="transactionId" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalAmount" type="xsd:string" minOccurs="0"/> + <xsd:element name="amount" type="xsd:string" minOccurs="0"/> + <xsd:element name="currency" type="xsd:string" minOccurs="0"/> + <xsd:element name="correlationID" type="xsd:string" minOccurs="0"/> + <xsd:element name="errorCode" type="xsd:string" minOccurs="0"/> + <xsd:element name="protectionEligibility" type="xsd:string" minOccurs="0"/> + <xsd:element name="protectionEligibilityType" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <!-- end of PayPalAuthorization --> + <!-- PayPalUpdateAgreement--> + <xsd:complexType name="PayPalUpdateAgreementReply"> + <xsd:sequence> + <xsd:element name="reasonCode" type="xsd:integer"/> + <xsd:element name="paypalBillingAgreementId" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalBillingAgreementDesc" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalBillingAgreementCustom" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalBillingAgreementStatus" type="xsd:string" minOccurs="0"/> + <xsd:element name="payer" type="xsd:string" minOccurs="0"/> + <xsd:element name="payerId" type="xsd:string" minOccurs="0"/> + <xsd:element name="payerStatus" type="xsd:string" minOccurs="0"/> + <xsd:element name="payerCountry" type="xsd:string" minOccurs="0"/> + <xsd:element name="payerBusiness" type="xsd:string" minOccurs="0"/> + <xsd:element name="payerSalutation" type="xsd:string" minOccurs="0"/> + <xsd:element name="payerFirstname" type="xsd:string" minOccurs="0"/> + <xsd:element name="payerMiddlename" type="xsd:string" minOccurs="0"/> + <xsd:element name="payerLastname" type="xsd:string" minOccurs="0"/> + <xsd:element name="payerSuffix" type="xsd:string" minOccurs="0"/> + <xsd:element name="addressStatus" type="xsd:string" minOccurs="0"/> + <xsd:element name="errorCode" type="xsd:string" minOccurs="0"/> + <xsd:element name="correlationID" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <!-- end of PayPalUpdateAgreement--> + <!-- PayPalCreateAgreement--> + <xsd:complexType name="PayPalCreateAgreementReply"> + <xsd:sequence> + <xsd:element name="reasonCode" type="xsd:integer"/> + <xsd:element name="paypalBillingAgreementId" type="xsd:string" minOccurs="0"/> + <xsd:element name="errorCode" type="xsd:string" minOccurs="0"/> + <xsd:element name="correlationID" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <!-- end of PayPalCreateAgreement--> + <!-- PayPalDoRefTransaction--> + <xsd:complexType name="PayPalDoRefTransactionReply"> + <xsd:sequence> + <xsd:element name="reasonCode" type="xsd:integer"/> + <xsd:element name="paypalBillingAgreementId" type="xsd:string" minOccurs="0"/> + <xsd:element name="transactionId" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalTransactionType" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalPaymentType" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalOrderTime" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalAmount" type="xsd:string" minOccurs="0"/> + <xsd:element name="currency" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalTaxAmount" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalExchangeRate" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalPaymentStatus" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalPendingReason" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalReasonCode" type="xsd:string" minOccurs="0"/> + <xsd:element name="errorCode" type="xsd:string" minOccurs="0"/> + <xsd:element name="correlationID" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <!-- end of PayPalDoRefTransaction--> + <xsd:complexType name="RiskUpdateReply"> + <xsd:sequence> + <xsd:element name="reasonCode" type="xsd:integer"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="FraudUpdateReply"> + <xsd:sequence> + <xsd:element name="reasonCode" type="xsd:integer"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CaseManagementActionReply"> + <xsd:sequence> + <xsd:element name="reasonCode" type="xsd:integer"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="RuleResultItem"> + <xsd:sequence> + <xsd:element name="name" type="xsd:string" minOccurs="0"/> + <xsd:element name="decision" type="xsd:string" minOccurs="0"/> + <xsd:element name="evaluation" type="xsd:string" minOccurs="0"/> + <xsd:element name="ruleID" type="xsd:integer" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="RuleResultItems"> + <xsd:sequence> + <xsd:element name="ruleResultItem" type="tns:RuleResultItem" minOccurs="0" maxOccurs="1000"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="DecisionReply"> + <xsd:sequence> + <xsd:element name="casePriority" type="xsd:integer" minOccurs="0"/> + <xsd:element name="activeProfileReply" type="tns:ProfileReply" minOccurs="0"/> + <xsd:element name="velocityInfoCode" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <!-- DME --> + <xsd:complexType name="AdditionalFields"> + <xsd:sequence> + <xsd:element name="field" type="tns:Field" minOccurs="0" maxOccurs="3000"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="Field"> + <xsd:sequence> + <xsd:element name="provider" type="xsd:string" minOccurs="1" maxOccurs="1"/> + <xsd:element name="name" type="xsd:string" minOccurs="1" maxOccurs="1"/> + <xsd:element name="value" type="xsd:string" minOccurs="1" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="DMEReply"> + <xsd:sequence> + <xsd:element name="eventType" type="xsd:string" minOccurs="0"/> + <xsd:element name="eventInfo" type="xsd:string" minOccurs="0"/> + <xsd:element name="eventHotlistInfo" type="xsd:string" minOccurs="0"/> + <xsd:element name="eventPolicy" type="xsd:string" minOccurs="0"/> + <xsd:element name="additionalFields" type="tns:AdditionalFields" minOccurs="0" maxOccurs="1" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="ProfileReply"> + <xsd:sequence> + <xsd:element name="selectedBy" type="xsd:string" minOccurs="0"/> + <xsd:element name="name" type="xsd:string" minOccurs="0"/> + <xsd:element name="destinationQueue" type="xsd:string" minOccurs="0"/> + <xsd:element name="profileScore" type="xsd:string" minOccurs="0"/> + <xsd:element name="rulesTriggered" type="tns:RuleResultItems" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CCDCCReply"> + <xsd:sequence> + <xsd:element name="reasonCode" type="xsd:integer"/> + <xsd:element name="dccSupported" type="tns:boolean" minOccurs="0"/> + <xsd:element name="validHours" type="xsd:string" minOccurs="0"/> + <xsd:element name="marginRatePercentage" type="xsd:string" minOccurs="0"/> + <xsd:element name="reconciliationID" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CCDCCUpdateReply"> + <xsd:sequence> + <xsd:element name="reasonCode" type="xsd:integer"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="ChinaPaymentReply"> + <xsd:sequence> + <xsd:element name="reasonCode" type="xsd:integer"/> + <xsd:element name="requestDateTime" type="tns:dateTime" minOccurs="0"/> + <xsd:element name="amount" type="tns:amount" minOccurs="0"/> + <xsd:element name="currency" type="xsd:string" minOccurs="0"/> + <xsd:element name="reconciliationID" type="xsd:string" minOccurs="0"/> + <xsd:element name="formData" type="xsd:string" minOccurs="0"/> + <xsd:element name="verifyFailure" type="xsd:string" minOccurs="0"/> + <xsd:element name="verifyInProcess" type="xsd:string" minOccurs="0"/> + <xsd:element name="verifySuccess" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="ChinaRefundReply"> + <xsd:sequence> + <xsd:element name="reasonCode" type="xsd:integer"/> + <xsd:element name="requestDateTime" type="tns:dateTime" minOccurs="0"/> + <xsd:element name="amount" type="tns:amount" minOccurs="0"/> + <xsd:element name="currency" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="BoletoPaymentReply"> + <xsd:sequence> + <xsd:element name="reasonCode" type="xsd:integer"/> + <xsd:element name="requestDateTime" type="tns:dateTime" minOccurs="0"/> + <xsd:element name="amount" type="tns:amount" minOccurs="0"/> + <xsd:element name="reconciliationID" type="xsd:string" minOccurs="0"/> + <xsd:element name="boletoNumber" type="xsd:string" minOccurs="0"/> + <xsd:element name="expirationDate" type="xsd:string" minOccurs="0"/> + <xsd:element name="url" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="APInitiateReply"> + <xsd:sequence> + <xsd:element name="reasonCode" type="xsd:integer"/> + <xsd:element name="merchantURL" type="xsd:string" minOccurs="0"/> + <xsd:element name="reconciliationID" type="xsd:string" minOccurs="0"/> + <xsd:element name="amount" type="tns:amount" minOccurs="0"/> + <xsd:element name="dateTime" type="tns:dateTime" minOccurs="0"/> + <xsd:element name="signature" type="xsd:string" minOccurs="0"/> + <xsd:element name="publicKey" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="APCheckStatusReply"> + <xsd:sequence> + <xsd:element name="reasonCode" type="xsd:integer"/> + <xsd:element name="reconciliationID" type="xsd:string"/> + <xsd:element name="paymentStatus" type="xsd:string" minOccurs="0"/> + <xsd:element name="processorTradeNo" type="xsd:string"/> + <xsd:element name="processorTransactionID" type="xsd:string"/> + </xsd:sequence> + </xsd:complexType> + <!-- Vme Reseller Reply--> + <xsd:complexType name="APReply"> + <xsd:sequence> + <xsd:element name="orderID" type="xsd:string" minOccurs="0"/> + <xsd:element name="cardGroup" type="xsd:string" minOccurs="0"/> + <xsd:element name="cardType" type="xsd:string" minOccurs="0"/> + <xsd:element name="cardNumberSuffix" type="xsd:string" minOccurs="0"/> + <xsd:element name="cardExpirationMonth" type="xsd:string" minOccurs="0"/> + <xsd:element name="cardExpirationYear" type="xsd:string" minOccurs="0"/> + <xsd:element name="avsCodeRaw" type="xsd:string" minOccurs="0"/> + <xsd:element name="purchaseID" type="xsd:string" minOccurs="0"/> + <xsd:element name="productID" type="xsd:string" minOccurs="0"/> + <xsd:element name="productDescription" type="xsd:string" minOccurs="0"/> + <xsd:element name="shippingAmount" type="xsd:string" minOccurs="0"/> + <xsd:element name="handlingAmount" type="xsd:string" minOccurs="0"/> + <xsd:element name="shippingHandlingAmount" type="xsd:string" minOccurs="0"/> + <xsd:element name="additionalAmount" type="xsd:string" minOccurs="0"/> + <xsd:element name="taxAmount" type="xsd:string" minOccurs="0"/> + <xsd:element name="subtotalAmount" type="xsd:string" minOccurs="0"/> + <xsd:element name="totalPurchaseAmount" type="xsd:string" minOccurs="0"/> + <xsd:element name="giftWrapAmount" type="xsd:string" minOccurs="0"/> + <xsd:element name="discountAmount" type="xsd:string" minOccurs="0"/> + <xsd:element name="cardNumberPrefix" type="xsd:string" minOccurs="0"/> + <xsd:element name="riskIndicator" type="xsd:string" minOccurs="0"/> + <xsd:element name="merchantUUID" type="xsd:string" minOccurs="0"/> + <xsd:element name="merchantSiteID" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <!-- AP Auth Service --> + <xsd:complexType name="APAuthReply"> + <xsd:sequence> + <xsd:element name="reasonCode" type="xsd:integer"/> + <xsd:element name="transactionID" type="xsd:string" minOccurs="0"/> + <xsd:element name="status" type="xsd:string" minOccurs="0"/> + <xsd:element name="processorResponse" type="xsd:string" minOccurs="0"/> + <xsd:element name="amount" type="tns:amount" minOccurs="0"/> + <xsd:element name="dateTime" type="tns:dateTime" minOccurs="0"/> + <xsd:element name="providerResponse" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <!-- End of AP Auth Service --> + <!-- AP Auth Reversal Service --> + <xsd:complexType name="APAuthReversalReply"> + <xsd:sequence> + <xsd:element name="reasonCode" type="xsd:integer"/> + <xsd:element name="transactionID" type="xsd:string" minOccurs="0"/> + <xsd:element name="status" type="xsd:string" minOccurs="0"/> + <xsd:element name="processorResponse" type="xsd:string" minOccurs="0"/> + <xsd:element name="amount" type="tns:amount" minOccurs="0"/> + <xsd:element name="dateTime" type="tns:dateTime" minOccurs="0"/> + <xsd:element name="providerResponse" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <!-- End of AP Auth Reversal Service --> + <!-- AP Capture Service --> + <xsd:complexType name="APCaptureReply"> + <xsd:sequence> + <xsd:element name="reasonCode" type="xsd:integer"/> + <xsd:element name="transactionID" type="xsd:string" minOccurs="0"/> + <xsd:element name="status" type="xsd:string" minOccurs="0"/> + <xsd:element name="processorResponse" type="xsd:string" minOccurs="0"/> + <xsd:element name="amount" type="tns:amount" minOccurs="0"/> + <xsd:element name="dateTime" type="tns:dateTime" minOccurs="0"/> + <xsd:element name="reconciliationID" type="xsd:string" minOccurs="0"/> + <xsd:element name="providerResponse" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <!-- End of AP Capture Service --> + <!-- AP Refund Service --> + <xsd:complexType name="APRefundReply"> + <xsd:sequence> + <xsd:element name="reasonCode" type="xsd:integer"/> + <xsd:element name="transactionID" type="xsd:string" minOccurs="0"/> + <xsd:element name="status" type="xsd:string" minOccurs="0"/> + <xsd:element name="processorResponse" type="xsd:string" minOccurs="0"/> + <xsd:element name="amount" type="tns:amount" minOccurs="0"/> + <xsd:element name="dateTime" type="tns:dateTime" minOccurs="0"/> + <xsd:element name="reconciliationID" type="xsd:string" minOccurs="0"/> + <xsd:element name="returnRef" type="xsd:string" minOccurs="0"/> + <xsd:element name="providerResponse" type="xsd:string" minOccurs="0"/> + <xsd:element name="processorTransactionID" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <!-- End of AP Refund Service --> + <!-- AP CheckOutDetailsReply Service --> + <xsd:complexType name="APCheckOutDetailsReply"> + <xsd:sequence> + <xsd:element name="reasonCode" type="xsd:integer"/> + <xsd:element name="status" type="xsd:string" minOccurs="0"/> + <xsd:element name="processorResponse" type="xsd:string" minOccurs="0"/> + <xsd:element name="dateTime" type="tns:dateTime" minOccurs="0"/> + <xsd:element name="providerResponse" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <!-- End of AP CheckOutDetailsReply Service --> + <xsd:complexType name="APTransactionDetailsReply"> + <xsd:sequence> + <xsd:element name="reasonCode" type="xsd:integer"/> + <xsd:element name="transactionID" type="xsd:string" minOccurs="0"/> + <xsd:element name="status" type="xsd:string" minOccurs="0"/> + <xsd:element name="processorResponse" type="xsd:string" minOccurs="0"/> + <xsd:element name="dateTime" type="tns:dateTime" minOccurs="0"/> + <xsd:element name="reconciliationID" type="xsd:string" minOccurs="0"/> + <xsd:element name="providerResponse" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <!-- AP ConfirmPurchase Service --> + <xsd:complexType name="APConfirmPurchaseReply"> + <xsd:sequence> + <xsd:element name="reasonCode" type="xsd:integer"/> + <xsd:element name="status" type="xsd:string" minOccurs="0"/> + <xsd:element name="processorResponse" type="xsd:string" minOccurs="0"/> + <xsd:element name="amount" type="tns:amount" minOccurs="0"/> + <xsd:element name="dateTime" type="tns:dateTime" minOccurs="0"/> + <xsd:element name="providerResponse" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <!-- End of AP ConfirmPurchase Service --> + <xsd:complexType name="ReplyMessage"> + <xsd:sequence> + <xsd:element name="merchantReferenceCode" type="xsd:string" minOccurs="0"/> + <xsd:element name="requestID" type="xsd:string"/> + <xsd:element name="decision" type="xsd:string"/> + <xsd:element name="reasonCode" type="xsd:integer"/> + <xsd:element name="missingField" type="xsd:string" minOccurs="0" maxOccurs="1000"/> + <xsd:element name="invalidField" type="xsd:string" minOccurs="0" maxOccurs="1000"/> + <xsd:element name="requestToken" type="xsd:string"/> + <xsd:element name="purchaseTotals" type="tns:PurchaseTotals" minOccurs="0"/> + <xsd:element name="deniedPartiesMatch" type="tns:DeniedPartiesMatch" minOccurs="0" maxOccurs="100"/> + <xsd:element name="ccAuthReply" type="tns:CCAuthReply" minOccurs="0"/> + <xsd:element name="octReply" type="tns:OCTReply" minOccurs="0"/> + <xsd:element name="ccSaleReply" type="tns:CCSaleReply" minOccurs="0"/> + <xsd:element name="ccSaleCreditReply" type="tns:CCSaleCreditReply" minOccurs="0"/> + <xsd:element name="ccSaleReversalReply" type="tns:CCSaleReversalReply" minOccurs="0"/> + <xsd:element name="ccIncrementalAuthReply" type="tns:CCIncrementalAuthReply" minOccurs="0"/> + <xsd:element name="serviceFeeCalculateReply" type="tns:ServiceFeeCalculateReply" minOccurs="0"/> + <xsd:element name="ccCaptureReply" type="tns:CCCaptureReply" minOccurs="0"/> + <xsd:element name="ccCreditReply" type="tns:CCCreditReply" minOccurs="0"/> + <xsd:element name="ccAuthReversalReply" type="tns:CCAuthReversalReply" minOccurs="0"/> + <xsd:element name="ccAutoAuthReversalReply" type="tns:CCAutoAuthReversalReply" minOccurs="0"/> + <xsd:element name="ccDCCReply" type="tns:CCDCCReply" minOccurs="0"/> + <xsd:element name="ccDCCUpdateReply" type="tns:CCDCCUpdateReply" minOccurs="0"/> + <xsd:element name="ecDebitReply" type="tns:ECDebitReply" minOccurs="0"/> + <xsd:element name="ecCreditReply" type="tns:ECCreditReply" minOccurs="0"/> + <xsd:element name="ecAuthenticateReply" type="tns:ECAuthenticateReply" minOccurs="0"/> + <xsd:element name="payerAuthEnrollReply" type="tns:PayerAuthEnrollReply" minOccurs="0"/> + <xsd:element name="payerAuthValidateReply" type="tns:PayerAuthValidateReply" minOccurs="0"/> + <xsd:element name="taxReply" type="tns:TaxReply" minOccurs="0"/> + <xsd:element name="encryptedPayment" type="tns:EncryptedPayment" minOccurs="0" /> + <xsd:element name="encryptPaymentDataReply" type="tns:EncryptPaymentDataReply" minOccurs="0"/> + <xsd:element name="dmeReply" type="tns:DMEReply" minOccurs="0"/> + <xsd:element name="afsReply" type="tns:AFSReply" minOccurs="0"/> + <xsd:element name="davReply" type="tns:DAVReply" minOccurs="0"/> + <xsd:element name="exportReply" type="tns:ExportReply" minOccurs="0"/> + <xsd:element name="fxRatesReply" type="tns:FXRatesReply" minOccurs="0"/> + <xsd:element name="bankTransferReply" type="tns:BankTransferReply" minOccurs="0"/> + <xsd:element name="bankTransferRefundReply" type="tns:BankTransferRefundReply" minOccurs="0"/> + <xsd:element name="bankTransferRealTimeReply" type="tns:BankTransferRealTimeReply" minOccurs="0"/> + <xsd:element name="directDebitMandateReply" type="tns:DirectDebitMandateReply" minOccurs="0"/> + <xsd:element name="directDebitReply" type="tns:DirectDebitReply" minOccurs="0"/> + <xsd:element name="directDebitValidateReply" type="tns:DirectDebitValidateReply" minOccurs="0"/> + <xsd:element name="directDebitRefundReply" type="tns:DirectDebitRefundReply" minOccurs="0"/> + <xsd:element name="paySubscriptionCreateReply" type="tns:PaySubscriptionCreateReply" minOccurs="0"/> + <xsd:element name="paySubscriptionUpdateReply" type="tns:PaySubscriptionUpdateReply" minOccurs="0"/> + <xsd:element name="paySubscriptionEventUpdateReply" type="tns:PaySubscriptionEventUpdateReply" minOccurs="0"/> + <xsd:element name="paySubscriptionRetrieveReply" type="tns:PaySubscriptionRetrieveReply" minOccurs="0"/> + <xsd:element name="paySubscriptionDeleteReply" type="tns:PaySubscriptionDeleteReply" minOccurs="0"/> + <xsd:element name="payPalPaymentReply" type="tns:PayPalPaymentReply" minOccurs="0"/> + <xsd:element name="payPalCreditReply" type="tns:PayPalCreditReply" minOccurs="0"/> + <xsd:element name="voidReply" type="tns:VoidReply" minOccurs="0"/> + <xsd:element name="pinlessDebitReply" type="tns:PinlessDebitReply" minOccurs="0"/> + <xsd:element name="pinlessDebitValidateReply" type="tns:PinlessDebitValidateReply" minOccurs="0"/> + <xsd:element name="pinlessDebitReversalReply" type="tns:PinlessDebitReversalReply" minOccurs="0"/> + <xsd:element name="payPalButtonCreateReply" type="tns:PayPalButtonCreateReply" minOccurs="0"/> + <xsd:element name="payPalPreapprovedPaymentReply" type="tns:PayPalPreapprovedPaymentReply" minOccurs="0"/> + <xsd:element name="payPalPreapprovedUpdateReply" type="tns:PayPalPreapprovedUpdateReply" minOccurs="0"/> + <xsd:element name="riskUpdateReply" type="tns:RiskUpdateReply" minOccurs="0"/> + <xsd:element name="fraudUpdateReply" type="tns:FraudUpdateReply" minOccurs="0"/> + <xsd:element name="caseManagementActionReply" type="tns:CaseManagementActionReply" minOccurs="0"/> + <xsd:element name="decisionReply" type="tns:DecisionReply" minOccurs="0"/> + <xsd:element name="payPalRefundReply" type="tns:PayPalRefundReply" minOccurs="0"/> + <xsd:element name="payPalAuthReversalReply" type="tns:PayPalAuthReversalReply" minOccurs="0"/> + <xsd:element name="payPalDoCaptureReply" type="tns:PayPalDoCaptureReply" minOccurs="0"/> + <xsd:element name="payPalEcDoPaymentReply" type="tns:PayPalEcDoPaymentReply" minOccurs="0"/> + <xsd:element name="payPalEcGetDetailsReply" type="tns:PayPalEcGetDetailsReply" minOccurs="0"/> + <xsd:element name="payPalEcSetReply" type="tns:PayPalEcSetReply" minOccurs="0"/> + <xsd:element name="payPalAuthorizationReply" type="tns:PayPalAuthorizationReply" minOccurs="0"/> + <xsd:element name="payPalEcOrderSetupReply" type="tns:PayPalEcOrderSetupReply" minOccurs="0"/> + <xsd:element name="payPalUpdateAgreementReply" type="tns:PayPalUpdateAgreementReply" minOccurs="0"/> + <xsd:element name="payPalCreateAgreementReply" type="tns:PayPalCreateAgreementReply" minOccurs="0"/> + <xsd:element name="payPalDoRefTransactionReply" type="tns:PayPalDoRefTransactionReply" minOccurs="0"/> + <xsd:element name="chinaPaymentReply" type="tns:ChinaPaymentReply" minOccurs="0"/> + <xsd:element name="chinaRefundReply" type="tns:ChinaRefundReply" minOccurs="0"/> + <xsd:element name="boletoPaymentReply" type="tns:BoletoPaymentReply" minOccurs="0"/> + <xsd:element name="pinDebitPurchaseReply" type="tns:PinDebitPurchaseReply" minOccurs="0"/> + <xsd:element name="pinDebitCreditReply" type="tns:PinDebitCreditReply" minOccurs="0"/> + <xsd:element name="pinDebitReversalReply" type="tns:PinDebitReversalReply" minOccurs="0"/> + <xsd:element name="apInitiateReply" type="tns:APInitiateReply" minOccurs="0"/> + <xsd:element name="apCheckStatusReply" type="tns:APCheckStatusReply" minOccurs="0"/> + <xsd:element name="receiptNumber" type="xsd:string" minOccurs="0"/> + <xsd:element name="additionalData" type="xsd:string" minOccurs="0"/> + <xsd:element name="solutionProviderTransactionID" type="xsd:string" minOccurs="0"/> + <xsd:element name="apReply" type="tns:APReply" minOccurs="0"/> + <xsd:element name="shipTo" type="tns:ShipTo" minOccurs="0" /> + <xsd:element name="billTo" type="tns:BillTo" minOccurs="0" /> + <xsd:element name="apAuthReply" type="tns:APAuthReply" minOccurs="0"/> + <xsd:element name="apAuthReversalReply" type="tns:APAuthReversalReply" minOccurs="0"/> + <xsd:element name="apCaptureReply" type="tns:APCaptureReply" minOccurs="0"/> + <xsd:element name="apRefundReply" type="tns:APRefundReply" minOccurs="0"/> + <xsd:element name="apCheckoutDetailsReply" type="tns:APCheckOutDetailsReply" minOccurs="0"/> + <xsd:element name="apTransactionDetailsReply" type="tns:APTransactionDetailsReply" minOccurs="0"/> + <xsd:element name="apConfirmPurchaseReply" type="tns:APConfirmPurchaseReply" minOccurs="0"/> + <xsd:element name="promotion" type="tns:Promotion" minOccurs="0"/> + <xsd:element name="promotionGroup" type="tns:PromotionGroupReply" minOccurs="0" maxOccurs="100"/> + <xsd:element name="payPalGetTxnDetailsReply" type="tns:PayPalGetTxnDetailsReply" minOccurs="0"/> + <xsd:element name="payPalTransactionSearchReply" type="tns:PayPalTransactionSearchReply" minOccurs="0"/> + <xsd:element name="emvReply" type="tns:EmvReply" minOccurs="0" /> + <xsd:element name="originalTransaction" type="tns:OriginalTransaction" minOccurs="0" /> + <xsd:element name="hostedDataCreateReply" type="tns:HostedDataCreateReply" minOccurs="0" /> + <xsd:element name="hostedDataRetrieveReply" type="tns:HostedDataRetrieveReply" minOccurs="0" /> + <xsd:element name="salesSlipNumber" type="xsd:string" minOccurs="0" /> + <xsd:element name="additionalProcessorResponse" type="xsd:string" minOccurs="0" /> + <xsd:element name="jpo" type="tns:JPO" minOccurs="0" /> + <xsd:element name="card" type="tns:Card" minOccurs="0" /> + <xsd:element name="paymentNetworkToken" type="tns:PaymentNetworkToken" minOccurs="0"/> + <xsd:element name="vcReply" type="tns:VCReply" minOccurs="0" /> + <xsd:element name="decryptVisaCheckoutDataReply" type="tns:DecryptVisaCheckoutDataReply" minOccurs="0"/> + <xsd:element name="binLookupReply" type="tns:BinLookupReply" minOccurs="0"/> + <xsd:element name="issuerMessage" type="xsd:string" minOccurs="0" /> + <xsd:element name="reserved" type="tns:ReplyReserved" minOccurs="0"/> + <!--ReplyReserved should always be the last element in the xsd, new elements should be added before this--> + </xsd:sequence> + </xsd:complexType> + <xsd:element name="requestMessage" type="tns:RequestMessage"> + <xsd:unique name="unique-item-id"> + <xsd:selector xpath="tns:item"/> + <xsd:field xpath="@id"/> + </xsd:unique> + </xsd:element> + <xsd:element name="replyMessage" type="tns:ReplyMessage"> + <xsd:unique name="unique-tax-item-id"> + <xsd:selector xpath="tns:taxReplyItem"/> + <xsd:field xpath="@id"/> + </xsd:unique> + </xsd:element> + <xsd:element name="nvpRequest" type="xsd:string"/> + <xsd:element name="nvpReply" type="xsd:string"/> + <!-- used in SOAP faults --> + <xsd:complexType name="FaultDetails"> + <xsd:sequence> + <xsd:element name="requestID" type="xsd:string"/> + </xsd:sequence> + </xsd:complexType> + <xsd:element name="faultDetails" type="tns:FaultDetails"/> + <xsd:complexType name="AirlineData"> + <xsd:sequence> + <xsd:element name="agentCode" type="xsd:string" minOccurs="0"/> + <xsd:element name="agentName" type="xsd:string" minOccurs="0"/> + <xsd:element name="ticketIssuerCity" type="xsd:string" minOccurs="0"/> + <xsd:element name="ticketIssuerState" type="xsd:string" minOccurs="0"/> + <xsd:element name="ticketIssuerPostalCode" type="xsd:string" minOccurs="0"/> + <xsd:element name="ticketIssuerCountry" type="xsd:string" minOccurs="0"/> + <xsd:element name="ticketIssuerAddress" type="xsd:string" minOccurs="0"/> + <xsd:element name="ticketIssuerCode" type="xsd:string" minOccurs="0"/> + <xsd:element name="ticketIssuerName" type="xsd:string" minOccurs="0"/> + <xsd:element name="ticketNumber" type="xsd:string" minOccurs="0"/> + <xsd:element name="checkDigit" type="xsd:integer" minOccurs="0"/> + <xsd:element name="restrictedTicketIndicator" type="xsd:integer" minOccurs="0"/> + <xsd:element name="transactionType" type="xsd:string" minOccurs="0"/> + <xsd:element name="extendedPaymentCode" type="xsd:string" minOccurs="0"/> + <xsd:element name="carrierName" type="xsd:string" minOccurs="0"/> + <xsd:element name="passengerName" type="xsd:string" minOccurs="0"/> + <xsd:element name="customerCode" type="xsd:string" minOccurs="0"/> + <xsd:element name="documentType" type="xsd:string" minOccurs="0"/> + <xsd:element name="documentNumber" type="xsd:string" minOccurs="0"/> + <xsd:element name="documentNumberOfParts" type="xsd:string" minOccurs="0"/> + <xsd:element name="invoiceNumber" type="xsd:string" minOccurs="0"/> + <xsd:element name="invoiceDate" type="xsd:string" minOccurs="0"/> + <xsd:element name="chargeDetails" type="xsd:string" minOccurs="0"/> + <xsd:element name="bookingReference" type="xsd:string" minOccurs="0"/> + <xsd:element name="totalFee" type="tns:amount" minOccurs="0"/> + <xsd:element name="clearingSequence" type="xsd:string" minOccurs="0"/> + <xsd:element name="clearingCount" type="xsd:integer" minOccurs="0"/> + <xsd:element name="totalClearingAmount" type="tns:amount" minOccurs="0"/> + <xsd:element name="leg" type="tns:Leg" minOccurs="0" maxOccurs="1000"/> + <xsd:element name="numberOfPassengers" type="xsd:string" minOccurs="0"/> + <xsd:element name="reservationSystem" type="xsd:string" minOccurs="0"/> + <xsd:element name="processIdentifier" type="xsd:string" minOccurs="0"/> + <xsd:element name="iataNumericCode" type="xsd:string" minOccurs="0"/> + <xsd:element name="ticketIssueDate" type="xsd:string" minOccurs="0"/> + <xsd:element name="electronicTicket" type="xsd:string" minOccurs="0"/> + <xsd:element name="originalTicketNumber" type="xsd:string" minOccurs="0"/> + <xsd:element name="purchaseType" type="xsd:string" minOccurs="0"/> + <xsd:element name="creditReasonIndicator" type="xsd:string" minOccurs="0"/> + <xsd:element name="ticketUpdateIndicator" type="xsd:string" minOccurs="0"/> + <xsd:element name="planNumber" type="xsd:string" minOccurs="0"/> + <xsd:element name="arrivalDate" type="xsd:string" minOccurs="0"/> + <xsd:element name="ticketRestrictionText" type="xsd:string" minOccurs="0"/> + <xsd:element name="exchangeTicketAmount" type="tns:amount" minOccurs="0"/> + <xsd:element name="exchangeTicketFee" type="tns:amount" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="Leg"> + <xsd:sequence> + <xsd:element name="carrierCode" type="xsd:string" minOccurs="0"/> + <xsd:element name="flightNumber" type="xsd:string" minOccurs="0"/> + <xsd:element name="originatingAirportCode" type="xsd:string" minOccurs="0"/> + <xsd:element name="class" type="xsd:string" minOccurs="0"/> + <xsd:element name="stopoverCode" type="xsd:string" minOccurs="0"/> + <xsd:element name="departureDate" type="xsd:string" minOccurs="0"/> + <xsd:element name="destination" type="xsd:string" minOccurs="0"/> + <xsd:element name="fareBasis" type="xsd:string" minOccurs="0"/> + <xsd:element name="departTax" type="xsd:string" minOccurs="0"/> + <xsd:element name="conjunctionTicket" type="xsd:string" minOccurs="0"/> + <xsd:element name="exchangeTicket" type="xsd:string" minOccurs="0"/> + <xsd:element name="couponNumber" type="xsd:string" minOccurs="0"/> + <xsd:element name="departureTime" type="xsd:string" minOccurs="0"/> + <xsd:element name="departureTimeSegment" type="xsd:string" minOccurs="0"/> + <xsd:element name="arrivalTime" type="xsd:string" minOccurs="0"/> + <xsd:element name="arrivalTimeSegment" type="xsd:string" minOccurs="0"/> + <xsd:element name="endorsementsRestrictions" type="xsd:string" minOccurs="0"/> + <xsd:element name="fare" type="xsd:string" minOccurs="0"/> + <xsd:element name="fee" type="xsd:string" minOccurs="0"/> + <xsd:element name="tax" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + <xsd:attribute name="id" type="xsd:integer" use="required"/> + </xsd:complexType> + <xsd:complexType name="AncillaryData"> + <xsd:sequence> + <xsd:element name="ticketNumber" type="xsd:string" minOccurs="0"/> + <xsd:element name="passengerName" type="xsd:string" minOccurs="0"/> + <xsd:element name="connectedTicketNumber" type="xsd:string" minOccurs="0"/> + <xsd:element name="creditReasonIndicator" type="xsd:string" minOccurs="0"/> + <xsd:element name="service" type="tns:Service" minOccurs="0" maxOccurs="1000"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="Service"> + <xsd:sequence> + <xsd:element name="categoryCode" type="xsd:string" minOccurs="0"/> + <xsd:element name="subcategoryCode" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + <xsd:attribute name="id" type="xsd:integer" use="required"/> + </xsd:complexType> + <xsd:complexType name="LodgingData"> + <xsd:sequence> + <xsd:element name="checkInDate" type="xsd:string" minOccurs="0"/> + <xsd:element name="checkOutDate" type="xsd:string" minOccurs="0"/> + <xsd:element name="dailyRoomRate1" type="tns:amount" minOccurs="0"/> + <xsd:element name="dailyRoomRate2" type="tns:amount" minOccurs="0"/> + <xsd:element name="dailyRoomRate3" type="tns:amount" minOccurs="0"/> + <xsd:element name="roomNights1" type="xsd:integer" minOccurs="0"/> + <xsd:element name="roomNights2" type="xsd:integer" minOccurs="0"/> + <xsd:element name="roomNights3" type="xsd:integer" minOccurs="0"/> + <xsd:element name="guestSmokingPreference" type="xsd:string" minOccurs="0"/> + <xsd:element name="numberOfRoomsBooked" type="xsd:integer" minOccurs="0"/> + <xsd:element name="numberOfGuests" type="xsd:integer" minOccurs="0"/> + <xsd:element name="roomBedType" type="xsd:string" minOccurs="0"/> + <xsd:element name="roomTaxElements" type="xsd:string" minOccurs="0"/> + <xsd:element name="roomRateType" type="xsd:string" minOccurs="0"/> + <xsd:element name="guestName" type="xsd:string" minOccurs="0"/> + <xsd:element name="customerServicePhoneNumber" type="xsd:string" minOccurs="0"/> + <xsd:element name="corporateClientCode" type="xsd:string" minOccurs="0"/> + <xsd:element name="promotionalCode" type="xsd:string" minOccurs="0"/> + <xsd:element name="additionalCoupon" type="xsd:string" minOccurs="0"/> + <xsd:element name="roomLocation" type="xsd:string" minOccurs="0"/> + <xsd:element name="specialProgramCode" type="xsd:string" minOccurs="0"/> + <xsd:element name="tax" type="tns:amount" minOccurs="0"/> + <xsd:element name="prepaidCost" type="tns:amount" minOccurs="0"/> + <xsd:element name="foodAndBeverageCost" type="tns:amount" minOccurs="0"/> + <xsd:element name="roomTax" type="tns:amount" minOccurs="0"/> + <xsd:element name="adjustmentAmount" type="tns:amount" minOccurs="0"/> + <xsd:element name="phoneCost" type="tns:amount" minOccurs="0"/> + <xsd:element name="restaurantCost" type="tns:amount" minOccurs="0"/> + <xsd:element name="roomServiceCost" type="tns:amount" minOccurs="0"/> + <xsd:element name="miniBarCost" type="tns:amount" minOccurs="0"/> + <xsd:element name="laundryCost" type="tns:amount" minOccurs="0"/> + <xsd:element name="miscellaneousCost" type="tns:amount" minOccurs="0"/> + <xsd:element name="giftShopCost" type="tns:amount" minOccurs="0"/> + <xsd:element name="movieCost" type="tns:amount" minOccurs="0"/> + <xsd:element name="healthClubCost" type="tns:amount" minOccurs="0"/> + <xsd:element name="valetParkingCost" type="tns:amount" minOccurs="0"/> + <xsd:element name="cashDisbursementCost" type="tns:amount" minOccurs="0"/> + <xsd:element name="nonRoomCost" type="tns:amount" minOccurs="0"/> + <xsd:element name="businessCenterCost" type="tns:amount" minOccurs="0"/> + <xsd:element name="loungeBarCost" type="tns:amount" minOccurs="0"/> + <xsd:element name="transportationCost" type="tns:amount" minOccurs="0"/> + <xsd:element name="gratuityCost" type="tns:amount" minOccurs="0"/> + <xsd:element name="conferenceRoomCost" type="tns:amount" minOccurs="0"/> + <xsd:element name="audioVisualCost" type="tns:amount" minOccurs="0"/> + <xsd:element name="banquetCost" type="tns:amount" minOccurs="0"/> + <xsd:element name="internetAccessCost" type="tns:amount" minOccurs="0"/> + <xsd:element name="earlyCheckOutCost" type="tns:amount" minOccurs="0"/> + <xsd:element name="nonRoomTax" type="tns:amount" minOccurs="0"/> + <xsd:element name="travelAgencyCode" type="xsd:string" minOccurs="0"/> + <xsd:element name="travelAgencyName" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="Pos"> + <xsd:sequence> + <xsd:element name="entryMode" type="xsd:string" minOccurs="0"/> + <xsd:element name="cardPresent" type="xsd:string" minOccurs="0"/> + <xsd:element name="terminalCapability" type="xsd:string" minOccurs="0"/> + <xsd:element name="trackData" type="xsd:string" minOccurs="0"/> + <xsd:element name="terminalID" type="xsd:string" minOccurs="0"/> + <xsd:element name="terminalType" type="xsd:string" minOccurs="0"/> + <xsd:element name="terminalLocation" type="xsd:string" minOccurs="0"/> + <xsd:element name="transactionSecurity" type="xsd:string" minOccurs="0"/> + <xsd:element name="catLevel" type="xsd:string" minOccurs="0"/> + <xsd:element name="conditionCode" type="xsd:string" minOccurs="0"/> + <xsd:element name="environment" type="xsd:string" minOccurs="0"/> + <xsd:element name="paymentData" type="xsd:string" minOccurs="0"/> + <xsd:element name="deviceReaderData" type="xsd:string" minOccurs="0"/> + <xsd:element name="encryptionAlgorithm" type="xsd:string" minOccurs="0"/> + <xsd:element name="encodingMethod" type="xsd:string" minOccurs="0"/> + <xsd:element name="deviceID" type="xsd:string" minOccurs="0"/> + <xsd:element name="serviceCode" type="xsd:string" minOccurs="0"/> + <xsd:element name="terminalIDAlternate" type="xsd:string" minOccurs="0" /> + <xsd:element name="terminalCompliance" type="xsd:integer" minOccurs="0" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="EncryptedPayment"> + <xsd:sequence> + <xsd:element name="descriptor" type="xsd:string" minOccurs="0"/> + <xsd:element name="data" type="xsd:string" minOccurs="0"/> + <xsd:element name="encoding" type="xsd:string" minOccurs="0"/> + <xsd:element name="wrappedKey" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + + <xsd:complexType name="Installment"> + <xsd:sequence> + <xsd:element name="sequence" type="xsd:string" minOccurs="0"/> + <xsd:element name="totalCount" type="xsd:string" minOccurs="0"/> + <xsd:element name="totalAmount" type="xsd:string" minOccurs="0"/> + <xsd:element name="frequency" type="xsd:string" minOccurs="0"/> + <xsd:element name="amount" type="xsd:string" minOccurs="0"/> + <xsd:element name="planType" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="MDDField"> + <xsd:simpleContent> + <xsd:extension base="xsd:string"> + <xsd:attribute name="id" type="xsd:integer" use="required"/> + </xsd:extension> + </xsd:simpleContent> + </xsd:complexType> + <xsd:complexType name="MerchantDefinedData"> + <xsd:sequence> + <xsd:element name="field1" type="xsd:string" minOccurs="0"/> + <xsd:element name="field2" type="xsd:string" minOccurs="0"/> + <xsd:element name="field3" type="xsd:string" minOccurs="0"/> + <xsd:element name="field4" type="xsd:string" minOccurs="0"/> + <xsd:element name="field5" type="xsd:string" minOccurs="0"/> + <xsd:element name="field6" type="xsd:string" minOccurs="0"/> + <xsd:element name="field7" type="xsd:string" minOccurs="0"/> + <xsd:element name="field8" type="xsd:string" minOccurs="0"/> + <xsd:element name="field9" type="xsd:string" minOccurs="0"/> + <xsd:element name="field10" type="xsd:string" minOccurs="0"/> + <xsd:element name="field11" type="xsd:string" minOccurs="0"/> + <xsd:element name="field12" type="xsd:string" minOccurs="0"/> + <xsd:element name="field13" type="xsd:string" minOccurs="0"/> + <xsd:element name="field14" type="xsd:string" minOccurs="0"/> + <xsd:element name="field15" type="xsd:string" minOccurs="0"/> + <xsd:element name="field16" type="xsd:string" minOccurs="0"/> + <xsd:element name="field17" type="xsd:string" minOccurs="0"/> + <xsd:element name="field18" type="xsd:string" minOccurs="0"/> + <xsd:element name="field19" type="xsd:string" minOccurs="0"/> + <xsd:element name="field20" type="xsd:string" minOccurs="0"/> + <xsd:element name="mddField" type="tns:MDDField" minOccurs="0" maxOccurs="100"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="MerchantSecureData"> + <xsd:sequence> + <xsd:element name="field1" type="xsd:string" minOccurs="0"/> + <xsd:element name="field2" type="xsd:string" minOccurs="0"/> + <xsd:element name="field3" type="xsd:string" minOccurs="0"/> + <xsd:element name="field4" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="ReplyReserved"> + <xsd:sequence> + <xsd:any processContents="skip" minOccurs="0" maxOccurs="999"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="RequestReserved"> + <xsd:sequence> + <xsd:element name="name" type="xsd:string"/> + <xsd:element name="value" type="xsd:string"/> + </xsd:sequence> + </xsd:complexType> + <!-- PayPalGetTxnDetails --> + <xsd:complexType name="PayPalGetTxnDetailsReply"> + <xsd:sequence> + <xsd:element name="reasonCode" type="xsd:integer"/> + <xsd:element name="payer" type="xsd:string" minOccurs="0"/> + <xsd:element name="payerId" type="xsd:string" minOccurs="0"/> + <xsd:element name="payerStatus" type="xsd:string" minOccurs="0"/> + <xsd:element name="payerCountry" type="xsd:string" minOccurs="0"/> + <xsd:element name="payerBusiness" type="xsd:string" minOccurs="0"/> + <xsd:element name="payerSalutation" type="xsd:string" minOccurs="0"/> + <xsd:element name="payerFirstname" type="xsd:string" minOccurs="0"/> + <xsd:element name="payerMiddlename" type="xsd:string" minOccurs="0"/> + <xsd:element name="payerLastname" type="xsd:string" minOccurs="0"/> + <xsd:element name="payerSuffix" type="xsd:string" minOccurs="0"/> + <xsd:element name="addressID" type="xsd:string" minOccurs="0"/> + <xsd:element name="addressStatus" type="xsd:string" minOccurs="0"/> + <xsd:element name="shipToName" type="xsd:string" minOccurs="0"/> + <xsd:element name="shipToAddress1" type="xsd:string" minOccurs="0"/> + <xsd:element name="shipToAddress2" type="xsd:string" minOccurs="0"/> + <xsd:element name="shipToCity" type="xsd:string" minOccurs="0"/> + <xsd:element name="shipToState" type="xsd:string" minOccurs="0"/> + <xsd:element name="shipToCountry" type="xsd:string" minOccurs="0"/> + <xsd:element name="shipToZip" type="xsd:string" minOccurs="0"/> + <xsd:element name="payerPhone" type="xsd:string" minOccurs="0"/> + <xsd:element name="transactionId" type="xsd:string" minOccurs="0"/> + <xsd:element name="parentTransactionId" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalReceiptId" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalTransactiontype" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalPaymentType" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalOrderTime" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalPaymentGrossAmount" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalFeeAmount" type="xsd:string" minOccurs="0"/> + <xsd:element name="currency" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalSettleAmount" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalTaxAmount" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalExchangeRate" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalPaymentStatus" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalPendingReason" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalReasonCode" type="xsd:string" minOccurs="0"/> + <xsd:element name="protectionEligibility" type="xsd:string" minOccurs="0"/> + <xsd:element name="protectionEligibilityType" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalNote" type="xsd:string" minOccurs="0"/> + <xsd:element name="invoiceNumber" type="xsd:string" minOccurs="0"/> + <xsd:element name="item" type="tns:Item" minOccurs="0" maxOccurs="1000" /> + <xsd:element name="errorCode" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + + <!-- end of PayPalGetTxnDetails --> + + <!-- PayPalTransactionSearchReply --> + <xsd:complexType name="PayPalTransactionSearchReply"> + <xsd:sequence> + <xsd:element name="reasonCode" type="xsd:integer"/> + <xsd:element name="transaction" type="tns:PaypalTransaction" minOccurs="0" maxOccurs="999" /> + <xsd:element name="errorCode" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + + <xsd:complexType name="PaypalTransaction"> + <xsd:sequence> + <xsd:element name="transactionTime" type="tns:dateTime" minOccurs="0"/> + <xsd:element name="transactionTimeZone" type="xsd:string" minOccurs="0"/> + <xsd:element name="transactionType" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalPayerOrPayeeEmail" type="xsd:string" minOccurs="0"/> + <xsd:element name="customerDisplayName" type="xsd:string" minOccurs="0"/> + <xsd:element name="transactionID" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalPaymentStatus" type="xsd:string" minOccurs="0"/> + <xsd:element name="grandTotalAmount" type="xsd:string" minOccurs="0"/> + <xsd:element name="currency" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalFeeAmount" type="xsd:string" minOccurs="0"/> + <xsd:element name="paypalNetAmount" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + <xsd:attribute name="id" type="xsd:integer" use="optional"/> + </xsd:complexType> + <!-- end of PayPalTransactionSearchReply --> + + <xsd:complexType name="CCDCCUpdateService"> + <xsd:sequence> + <xsd:element name="reason" type="xsd:string" minOccurs="0"/> + <xsd:element name="action" type="xsd:string" minOccurs="0"/> + <xsd:element name="dccRequestID" type="xsd:string" minOccurs="0"/> + <xsd:element name="captureRequestID" type="xsd:string" minOccurs="0"/> + <xsd:element name="creditRequestID" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + <xsd:attribute name="run" type="tns:boolean" use="required"/> + </xsd:complexType> + <!-- Merchant Descriptor fields for Service Fee. goes into RequestMessage--> + <xsd:complexType name="ServiceFee"> + <xsd:sequence> + <xsd:element name="merchantDescriptor" type="xsd:string" minOccurs="0"/> + <xsd:element name="merchantDescriptorContact" type="xsd:string" minOccurs="0"/> + <xsd:element name="merchantDescriptorState" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <!-- EMV transaction data request/reply start --> + <xsd:complexType name="EmvRequest"> + <xsd:sequence> + <xsd:element name="combinedTags" type="xsd:string" minOccurs="0"/> + <xsd:element name="cardSequenceNumber" type="xsd:string" minOccurs="0"/> + <xsd:element name="aidAndDFname" type="xsd:string" minOccurs="0"/> + <xsd:element name="fallback" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + + <xsd:complexType name="EmvReply"> + <xsd:sequence> + <xsd:element name="combinedTags" type="xsd:string" minOccurs="0"/> + <xsd:element name="chipValidationResults" type="xsd:string" minOccurs="0"/> + <xsd:element name="chipValidationType" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <!-- EMV transaction data request/reply end --> + <!-- Auth Reversal time out merchant intitated --> + <xsd:complexType name="OriginalTransaction"> + <xsd:sequence> + <xsd:element name="amount" type="tns:amount" minOccurs="0" /> + <xsd:element name="reasonCode" type="xsd:string" minOccurs="0" /> + </xsd:sequence> + </xsd:complexType> + + <xsd:complexType name="HostedDataCreateService"> + <xsd:sequence> + <xsd:element name="profileID" type="xsd:string" minOccurs="0"/> + <xsd:element name="paymentMethod" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + <xsd:attribute name="run" type="tns:boolean" use="required"/> + </xsd:complexType> + <xsd:complexType name="HostedDataRetrieveService"> + <xsd:sequence> + <xsd:element name="profileID" type="xsd:string" minOccurs="0"/> + <xsd:element name="tokenValue" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + <xsd:attribute name="run" type="tns:boolean" use="required"/> + </xsd:complexType> + + <xsd:complexType name="HostedDataCreateReply"> + <xsd:sequence> + <xsd:element name="responseMessage" type="xsd:string" minOccurs="0" /> + <xsd:element name="reasonCode" type="xsd:integer"/> + <xsd:element name="cardAccountNumberToken" type="xsd:string" minOccurs="0" /> + <xsd:element name="customerID" type="xsd:string" minOccurs="0" /> + </xsd:sequence> + </xsd:complexType> + + <xsd:complexType name="HostedDataRetrieveReply"> + <xsd:sequence> + <xsd:element name="responseMessage" type="xsd:string" minOccurs="0" /> + <xsd:element name="reasonCode" type="xsd:integer"/> + <xsd:element name="aggregatorMerchantIdentifier" type="xsd:string" minOccurs="0" /> + <xsd:element name="customerFirstName" type="xsd:string" minOccurs="0" /> + <xsd:element name="customerLastName" type="xsd:string" minOccurs="0" /> + <xsd:element name="customerID" type="xsd:string" minOccurs="0" /> + <xsd:element name="paymentMethod" type="xsd:string" minOccurs="0" /> + <xsd:element name="billToStreet1" type="xsd:string" minOccurs="0"/> + <xsd:element name="billToStreet2" type="xsd:string" minOccurs="0"/> + <xsd:element name="billToEmail" type="xsd:string" minOccurs="0"/> + <xsd:element name="billToState" type="xsd:string" minOccurs="0"/> + <xsd:element name="billToFirstName" type="xsd:string" minOccurs="0"/> + <xsd:element name="billToLastName" type="xsd:string" minOccurs="0"/> + <xsd:element name="billToCity" type="xsd:string" minOccurs="0"/> + <xsd:element name="billToCountry" type="xsd:string" minOccurs="0"/> + <xsd:element name="billToPostalCode" type="xsd:string" minOccurs="0"/> + <xsd:element name="cardAccountNumber" type="xsd:string" minOccurs="0" /> + <xsd:element name="cardType" type="xsd:string" minOccurs="0" /> + <xsd:element name="cardExpirationMonth" type="xsd:string" minOccurs="0" /> + <xsd:element name="cardExpirationYear" type="xsd:string" minOccurs="0" /> + <xsd:element name="cardIssueNumber" type="xsd:string" minOccurs="0" /> + <xsd:element name="cardStartMonth" type="xsd:string" minOccurs="0" /> + <xsd:element name="cardStartYear" type="xsd:string" minOccurs="0" /> + </xsd:sequence> + </xsd:complexType> + + <xsd:complexType name="AutoRentalData"> + <xsd:sequence> + <xsd:element name="adjustmentCost" type="tns:amount" minOccurs="0" /> + <xsd:element name="adjustmentCode" type="xsd:string" minOccurs="0" /> + <xsd:element name="agreementNumber" type="xsd:string" minOccurs="0" /> + <xsd:element name="classCode" type="xsd:string" minOccurs="0" /> + <xsd:element name="customerServicePhoneNumber" type="xsd:string" minOccurs="0" /> + <xsd:element name="dailyRate" type="tns:amount" minOccurs="0" /> + <xsd:element name="mileageCost" type="tns:amount" minOccurs="0" /> + <xsd:element name="gasCost" type="tns:amount" minOccurs="0" /> + <xsd:element name="insuranceCost" type="tns:amount" minOccurs="0" /> + <xsd:element name="lateReturnCost" type="tns:amount" minOccurs="0" /> + <xsd:element name="maximumFreeMiles" type="xsd:integer" minOccurs="0" /> + <xsd:element name="milesTraveled" type="xsd:integer" minOccurs="0" /> + <xsd:element name="oneWayCost" type="tns:amount" minOccurs="0" /> + <xsd:element name="parkingViolationCost" type="tns:amount" minOccurs="0" /> + <xsd:element name="pickUpCity" type="xsd:string" minOccurs="0" /> + <xsd:element name="pickUpCountry" type="xsd:string" minOccurs="0" /> + <xsd:element name="pickUpDate" type="xsd:string" minOccurs="0" /> + <xsd:element name="pickUpState" type="xsd:string" minOccurs="0" /> + <xsd:element name="pickUpTime" type="xsd:integer" minOccurs="0" /> + <xsd:element name="ratePerMile" type="tns:amount" minOccurs="0" /> + <xsd:element name="renterName" type="xsd:string" minOccurs="0" /> + <xsd:element name="returnCity" type="xsd:string" minOccurs="0" /> + <xsd:element name="returnCountry" type="xsd:string" minOccurs="0" /> + <xsd:element name="returnDate" type="xsd:string" minOccurs="0" /> + <xsd:element name="returnLocationID" type="xsd:string" minOccurs="0" /> + <xsd:element name="returnState" type="xsd:string" minOccurs="0" /> + <xsd:element name="returnTime" type="xsd:integer" minOccurs="0" /> + <xsd:element name="specialProgramCode" type="xsd:string" minOccurs="0" /> + </xsd:sequence> + </xsd:complexType> + + <xsd:complexType name="VCReply"> + <xsd:sequence> + <xsd:element name="creationTimeStamp" type="xsd:string" minOccurs="0" /> + <xsd:element name="alternateShippingAddressCountryCode" type="xsd:string" minOccurs="0" /> + <xsd:element name="alternateShippingAddressPostalCode" type="xsd:string" minOccurs="0" /> + <xsd:element name="vcAccountLoginName" type="xsd:string" minOccurs="0" /> + <xsd:element name="vcAccountFirstName" type="xsd:string" minOccurs="0" /> + <xsd:element name="vcAccountLastName" type="xsd:string" minOccurs="0" /> + <xsd:element name="vcAccountEncryptedID" type="xsd:string" minOccurs="0" /> + <xsd:element name="vcAccountEmail" type="xsd:string" minOccurs="0" /> + <xsd:element name="vcAccountMobilePhoneNumber" type="xsd:string" minOccurs="0" /> + <xsd:element name="merchantReferenceID" type="xsd:string" minOccurs="0" /> + <xsd:element name="subtotalAmount" type="xsd:string" minOccurs="0" /> + <xsd:element name="shippingHandlingAmount" type="xsd:string" minOccurs="0" /> + <xsd:element name="taxAmount" type="xsd:string" minOccurs="0" /> + <xsd:element name="discountAmount" type="xsd:string" minOccurs="0" /> + <xsd:element name="giftWrapAmount" type="xsd:string" minOccurs="0" /> + <xsd:element name="uncategorizedAmount" type="xsd:string" minOccurs="0" /> + <xsd:element name="totalPurchaseAmount" type="xsd:string" minOccurs="0" /> + <xsd:element name="walletReferenceID" type="xsd:string" minOccurs="0" /> + <xsd:element name="promotionCode" type="xsd:string" minOccurs="0" /> + <xsd:element name="paymentInstrumentID" type="xsd:string" minOccurs="0" /> + <xsd:element name="cardVerificationStatus" type="xsd:string" minOccurs="0" /> + <xsd:element name="issuerID" type="xsd:string" minOccurs="0" /> + <xsd:element name="paymentInstrumentNickName" type="xsd:string" minOccurs="0" /> + <xsd:element name="nameOnCard" type="xsd:string" minOccurs="0" /> + <xsd:element name="cardType" type="xsd:string" minOccurs="0" /> + <xsd:element name="cardGroup" type="xsd:string" minOccurs="0" /> + <xsd:element name="cardArt" type="tns:VCCardArt" minOccurs="0" /> + <xsd:element name="riskAdvice" type="xsd:string" minOccurs="0" /> + <xsd:element name="riskScore" type="xsd:string" minOccurs="0" /> + <xsd:element name="riskAdditionalData" type="xsd:string" minOccurs="0" /> + <xsd:element name="avsCodeRaw" type="xsd:string" minOccurs="0" /> + <xsd:element name="cvnCodeRaw" type="xsd:string" minOccurs="0" /> + <xsd:element name="eciRaw" type="xsd:string" minOccurs="0" /> + <xsd:element name="eci" type="xsd:string" minOccurs="0" /> + <xsd:element name="cavv" type="xsd:string" minOccurs="0" /> + <xsd:element name="veresEnrolled" type="xsd:string" minOccurs="0" /> + <xsd:element name="veresTimeStamp" type="xsd:string" minOccurs="0" /> + <xsd:element name="paresStatus" type="xsd:string" minOccurs="0" /> + <xsd:element name="paresTimeStamp" type="xsd:string" minOccurs="0" /> + <xsd:element name="xid" type="xsd:string" minOccurs="0" /> + <xsd:element name="customData" type="tns:VCCustomData" minOccurs="0" /> + </xsd:sequence> + </xsd:complexType> + + <xsd:complexType name="VCCardArt"> + <xsd:sequence> + <xsd:element name="fileName" type="xsd:string" minOccurs="0" /> + <xsd:element name="height" type="xsd:string" minOccurs="0" /> + <xsd:element name="width" type="xsd:string" minOccurs="0" /> + </xsd:sequence> + <xsd:attribute name="id" type="xsd:integer" use="optional"/> + </xsd:complexType> + + <xsd:complexType name="VCCustomData"> + <xsd:sequence> + <xsd:element name="name" type="xsd:string" minOccurs="0" /> + <xsd:element name="value" type="xsd:string" minOccurs="0" /> + </xsd:sequence> + <xsd:attribute name="id" type="xsd:integer" use="optional"/> + </xsd:complexType> + + <xsd:complexType name="DecryptVisaCheckoutDataReply"> + <xsd:sequence> + <xsd:element name="reasonCode" type="xsd:integer"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="EncryptPaymentDataReply"> + <xsd:sequence> + <xsd:element name="reasonCode" type="xsd:integer"/> + <xsd:element name="requestDateTime" type="tns:dateTime" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="BinLookupService"> + <xsd:attribute name="run" type="tns:boolean" use="required"/> + </xsd:complexType> + <xsd:complexType name="BinLookupReply"> + <xsd:sequence> + <xsd:element name="reasonCode" type="xsd:integer"/> + <xsd:element name="cardType" type="xsd:string" minOccurs="0" /> + <xsd:element name="cardGroup" type="xsd:string" minOccurs="0" /> + <xsd:element name="issuerName" type="xsd:string" minOccurs="0" /> + <xsd:element name="issuerCountry" type="xsd:string" minOccurs="0" /> + <xsd:element name="issuedCurrency" type="xsd:string" minOccurs="0" /> + <xsd:element name="level2Eligibility" type="xsd:string" minOccurs="0" /> + <xsd:element name="level3Eligibility" type="xsd:string" minOccurs="0" /> + <xsd:element name="cardCategory" type="xsd:string" minOccurs="0" /> + <xsd:element name="crossBorderIndicator" type="xsd:string" minOccurs="0" /> + <xsd:element name="issuerPhoneNumber" type="xsd:string" minOccurs="0" /> + <xsd:element name="billingCurrency" type="xsd:string" minOccurs="0" /> + <xsd:element name="billingCurrencyMinorDigits" type="xsd:string" minOccurs="0" /> + <xsd:element name="fastFundsIndicator" type="xsd:string" minOccurs="0" /> + <xsd:element name="octBlockIndicator" type="xsd:string" minOccurs="0" /> + <xsd:element name="onlineGamblingBlockIndicator" type="xsd:string" minOccurs="0" /> + <xsd:element name="requestDateTime" type="tns:dateTime" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> +</xsd:schema> + diff --git a/test/schema/firstdata_e4/v11.xsd b/test/schema/firstdata_e4/v11.xsd new file mode 100644 index 00000000000..b2bbc2996f6 --- /dev/null +++ b/test/schema/firstdata_e4/v11.xsd @@ -0,0 +1,126 @@ +<?xml version="1.0" encoding="utf-8"?> +<s:schema + elementFormDefault="qualified" + xmlns:s="http://www.w3.org/2001/XMLSchema" + xmlns:s0="http://secure2.e-xact.com/vplug-in/transaction/rpc-enc/encodedTypes" + xmlns="http://secure2.e-xact.com/vplug-in/transaction/rpc-enc/encodedTypes" + targetNamespace="http://secure2.e-xact.com/vplug-in/transaction/rpc-enc/encodedTypes"> + <s:complexType name="SoftDescriptor_Type"> + <s:sequence> + <s:element minOccurs="0" maxOccurs="1" name="DBAName" type="s:string" /> + <s:element minOccurs="0" maxOccurs="1" name="Street" type="s:string" /> + <s:element minOccurs="0" maxOccurs="1" name="City" type="s:string" /> + <s:element minOccurs="0" maxOccurs="1" name="Region" type="s:string" /> + <s:element minOccurs="0" maxOccurs="1" name="PostalCode" type="s:string" /> + <s:element minOccurs="0" maxOccurs="1" name="CountryCode" type="s:string" /> + <s:element minOccurs="0" maxOccurs="1" name="MID" type="s:string" /> + <s:element minOccurs="0" maxOccurs="1" name="MCC" type="s:string" /> + <s:element minOccurs="0" maxOccurs="1" name="MerchantContactInfo" type="s:string" /> + </s:sequence> + </s:complexType> + <s:complexType name="Level3_ShipToAddress_Type"> + <s:sequence> + <s:element minOccurs="0" maxOccurs="1" name="Address1" type="s:string" /> + <s:element minOccurs="0" maxOccurs="1" name="City" type="s:string" /> + <s:element minOccurs="0" maxOccurs="1" name="State" type="s:string" /> + <s:element minOccurs="0" maxOccurs="1" name="Country" type="s:string" /> + <s:element minOccurs="0" maxOccurs="1" name="CustomerNumber" type="s:string" /> + <s:element minOccurs="0" maxOccurs="1" name="Email" type="s:string" /> + <s:element minOccurs="0" maxOccurs="1" name="Phone" type="s:string" /> + <s:element minOccurs="0" maxOccurs="1" name="Name" type="s:string" /> + <s:element minOccurs="0" maxOccurs="1" name="Zip" type="s:string" /> + </s:sequence> + </s:complexType> + <s:complexType name="Level3_LineItem_Type"> + <s:sequence> + <s:element minOccurs="0" maxOccurs="1" name="CommodityCode" type="s:string" /> + <s:element minOccurs="1" maxOccurs="1" name="Description" type="s:string" /> + <s:element minOccurs="0" maxOccurs="1" name="DiscountAmount" type="s:string" /> + <s:element minOccurs="0" maxOccurs="1" name="DiscountIndicator" type="s:boolean" /> + <s:element minOccurs="0" maxOccurs="1" name="GrossNetIndicator" type="s:boolean" /> + <s:element minOccurs="1" maxOccurs="1" name="LineItemTotal" type="s:string" /> + <s:element minOccurs="0" maxOccurs="1" name="ProductCode" type="s:string" /> + <s:element minOccurs="1" maxOccurs="1" name="Quantity" type="s:string" /> + <s:element minOccurs="0" maxOccurs="1" name="TaxAmount" type="s:string" /> + <s:element minOccurs="0" maxOccurs="1" name="TaxRate" type="s:string" /> + <s:element minOccurs="0" maxOccurs="1" name="TaxType" type="s:string" /> + <s:element minOccurs="1" maxOccurs="1" name="UnitCost" type="s:string" /> + <s:element minOccurs="0" maxOccurs="1" name="UnitOfMeasure" type="s:string" /> + </s:sequence> + </s:complexType> + <s:complexType name="Level3_Type"> + <s:sequence> + <s:element minOccurs="0" maxOccurs="1" name="TaxAmount" type="s:string" /> + <s:element minOccurs="0" maxOccurs="1" name="TaxRate" type="s:string" /> + <s:element minOccurs="0" maxOccurs="1" name="AltTaxAmount" type="s:string" /> + <s:element minOccurs="0" maxOccurs="1" name="AltTaxId" type="s:string" /> + <s:element minOccurs="0" maxOccurs="1" name="DutyAmount" type="s:string" /> + <s:element minOccurs="0" maxOccurs="1" name="FreightAmount" type="s:string" /> + <s:element minOccurs="0" maxOccurs="1" name="DiscountAmount" type="s:string" /> + <s:element minOccurs="0" maxOccurs="1" name="ShipFromZip" type="s:string" /> + <s:element minOccurs="1" maxOccurs="1" name="ShipToAddress" type="Level3_ShipToAddress_Type" /> + <s:element minOccurs="1" maxOccurs="98" name="LineItem" type="Level3_LineItem_Type" /> + </s:sequence> + </s:complexType> + <s:complexType name="PaypalTransactionDetails"> + <s:sequence> + <s:element minOccurs="0" maxOccurs="1" name="PayerID" type="s:string" /> + <s:element minOccurs="0" maxOccurs="1" name="GrossAmountCurrencyID" type="s:string" /> + <s:element minOccurs="1" maxOccurs="1" name="Success" type="s:boolean" /> + <s:element minOccurs="0" maxOccurs="1" name="Authorization" type="s:string" /> + <s:element minOccurs="0" maxOccurs="1" name="Message" type="s:string" /> + <s:element minOccurs="0" maxOccurs="1" name="CorrelationID" type="s:string" /> + <s:element minOccurs="0" maxOccurs="1" name="Timestamp" type="s:string" /> + </s:sequence> + </s:complexType> + <s:complexType name="Transaction"> + <s:all> + <s:element minOccurs="1" maxOccurs="1" name="ExactID" type="s:string" /> + <s:element minOccurs="1" maxOccurs="1" name="Password" type="s:string" /> + <s:element minOccurs="1" maxOccurs="1" name="Transaction_Type" type="s:string" /> + <s:element minOccurs="0" maxOccurs="1" name="DollarAmount" type="s:string" /> + <s:element minOccurs="0" maxOccurs="1" name="SurchargeAmount" type="s:string" /> + <s:element minOccurs="0" maxOccurs="1" name="Card_Number" type="s:string" /> + <s:element minOccurs="0" maxOccurs="1" name="Transaction_Tag" type="s:string" /> + <s:element minOccurs="0" maxOccurs="1" name="Track1" type="s:string" /> + <s:element minOccurs="0" maxOccurs="1" name="Track2" type="s:string" /> + <s:element minOccurs="0" maxOccurs="1" name="PAN" type="s:string" /> + <s:element minOccurs="0" maxOccurs="1" name="Authorization_Num" type="s:string" /> + <s:element minOccurs="0" maxOccurs="1" name="Expiry_Date" type="s:string" /> + <s:element minOccurs="0" maxOccurs="1" name="CardHoldersName" type="s:string" /> + <s:element minOccurs="0" maxOccurs="1" name="VerificationStr1" type="s:string" /> + <s:element minOccurs="0" maxOccurs="1" name="VerificationStr2" type="s:string" /> + <s:element minOccurs="0" maxOccurs="1" name="CVD_Presence_Ind" type="s:string" /> + <s:element minOccurs="0" maxOccurs="1" name="ZipCode" type="s:string" /> + <s:element minOccurs="0" maxOccurs="1" name="Tax1Amount" type="s:string" /> + <s:element minOccurs="0" maxOccurs="1" name="Tax1Number" type="s:string" /> + <s:element minOccurs="0" maxOccurs="1" name="Tax2Amount" type="s:string" /> + <s:element minOccurs="0" maxOccurs="1" name="Tax2Number" type="s:string" /> + <s:element minOccurs="0" maxOccurs="1" name="Secure_AuthRequired" type="s:string" /> + <s:element minOccurs="0" maxOccurs="1" name="Secure_AuthResult" type="s:string" /> + <s:element minOccurs="0" maxOccurs="1" name="Ecommerce_Flag" type="s:string" /> + <s:element minOccurs="0" maxOccurs="1" name="XID" type="s:string" /> + <s:element minOccurs="0" maxOccurs="1" name="CAVV" type="s:string" /> + <s:element minOccurs="0" maxOccurs="1" name="CAVV_Algorithm" type="s:string" /> + <s:element minOccurs="0" maxOccurs="1" name="Reference_No" type="s:string" /> + <s:element minOccurs="0" maxOccurs="1" name="Customer_Ref" type="s:string" /> + <s:element minOccurs="0" maxOccurs="1" name="Reference_3" type="s:string" /> + <s:element minOccurs="0" maxOccurs="1" name="Language" type="s:string" /> + <s:element minOccurs="0" maxOccurs="1" name="Client_IP" type="s:string" /> + <s:element minOccurs="0" maxOccurs="1" name="Client_Email" type="s:string" /> + <s:element minOccurs="0" maxOccurs="1" name="User_Name" type="s:string" /> + <s:element minOccurs="0" maxOccurs="1" name="Currency" type="s:string" /> + <s:element minOccurs="0" maxOccurs="1" name="PartialRedemption" type="s:boolean" /> + <s:element minOccurs="0" maxOccurs="1" name="Level3" type="Level3_Type" /> + <s:element minOccurs="0" maxOccurs="1" name="TransarmorToken" type="s:string" /> + <s:element minOccurs="0" maxOccurs="1" name="CardType" type="s:string" /> + <s:element minOccurs="0" maxOccurs="1" name="EAN" type="s:string" /> + <s:element minOccurs="0" maxOccurs="1" name="VirtualCard" type="s:boolean" /> + <s:element minOccurs="0" maxOccurs="1" name="CardCost" type="s:string" /> + <s:element minOccurs="0" maxOccurs="1" name="PaypalResponse" type="PaypalTransactionDetails" /> + <s:element minOccurs="0" maxOccurs="1" name="SoftDescriptor" type="SoftDescriptor_Type" /> + </s:all> + </s:complexType> + + <s:element name="Transaction" type="Transaction" /> +</s:schema> diff --git a/test/schema/firstdata_e4/v27.xsd b/test/schema/firstdata_e4/v27.xsd new file mode 100644 index 00000000000..775018838c6 --- /dev/null +++ b/test/schema/firstdata_e4/v27.xsd @@ -0,0 +1,223 @@ +<?xml version="1.0" encoding="utf-8"?> +<s:schema + elementFormDefault="qualified" + xmlns:s="http://www.w3.org/2001/XMLSchema" + xmlns:s0="http://secure2.e-xact.com/vplug-in/transaction/rpc-enc/encodedTypes" + xmlns="http://secure2.e-xact.com/vplug-in/transaction/rpc-enc/encodedTypes" + targetNamespace="http://secure2.e-xact.com/vplug-in/transaction/rpc-enc/encodedTypes"> + <s:complexType name="SoftDescriptor_Type"> + <s:sequence> + <s:element minOccurs="0" maxOccurs="1" name="DBAName" type="s:string"/> + <s:element minOccurs="0" maxOccurs="1" name="Street" type="s:string"/> + <s:element minOccurs="0" maxOccurs="1" name="City" type="s:string"/> + <s:element minOccurs="0" maxOccurs="1" name="Region" type="s:string"/> + <s:element minOccurs="0" maxOccurs="1" name="PostalCode" type="s:string"/> + <s:element minOccurs="0" maxOccurs="1" name="CountryCode" type="s:string"/> + <s:element minOccurs="0" maxOccurs="1" name="MID" type="s:string"/> + <s:element minOccurs="0" maxOccurs="1" name="MCC" type="s:string"/> + <s:element minOccurs="0" maxOccurs="1" name="MerchantContactInfo" type="s:string"/> + <s:element minOccurs="0" maxOccurs="1" name="MVV_MAID" type="s:string"/> + <s:element minOccurs="0" maxOccurs="1" name="AMEXMerchantPhone" type="s:string"/> + <s:element minOccurs="0" maxOccurs="1" name="AMEXMerchantEmail" type="s:string"/> + <s:element minOccurs="0" maxOccurs="1" name="PFacSubmerchantId" type="s:string"/> + <s:element minOccurs="0" maxOccurs="1" name="PFacName" type="s:string"/> + </s:sequence> + </s:complexType> + <s:complexType name="Level3_ShipToAddress_Type"> + <s:sequence> + <s:element minOccurs="0" maxOccurs="1" name="Address1" type="s:string"/> + <s:element minOccurs="0" maxOccurs="1" name="City" type="s:string"/> + <s:element minOccurs="0" maxOccurs="1" name="State" type="s:string"/> + <s:element minOccurs="0" maxOccurs="1" name="Country" type="s:string"/> + <s:element minOccurs="0" maxOccurs="1" name="CustomerNumber" type="s:string"/> + <s:element minOccurs="0" maxOccurs="1" name="Email" type="s:string"/> + <s:element minOccurs="0" maxOccurs="1" name="Phone" type="s:string"/> + <s:element minOccurs="0" maxOccurs="1" name="Name" type="s:string"/> + <s:element minOccurs="0" maxOccurs="1" name="Zip" type="s:string"/> + </s:sequence> + </s:complexType> + <s:complexType name="Level3_LineItem_Type"> + <s:sequence> + <s:element minOccurs="0" maxOccurs="1" name="CommodityCode" type="s:string"/> + <s:element minOccurs="1" maxOccurs="1" name="Description" type="s:string"/> + <s:element minOccurs="0" maxOccurs="1" name="DiscountAmount" type="s:string"/> + <s:element minOccurs="0" maxOccurs="1" name="DiscountIndicator" type="s:boolean"/> + <s:element minOccurs="0" maxOccurs="1" name="GrossNetIndicator" type="s:boolean"/> + <s:element minOccurs="1" maxOccurs="1" name="LineItemTotal" type="s:string"/> + <s:element minOccurs="0" maxOccurs="1" name="ProductCode" type="s:string"/> + <s:element minOccurs="1" maxOccurs="1" name="Quantity" type="s:string"/> + <s:element minOccurs="0" maxOccurs="1" name="TaxAmount" type="s:string"/> + <s:element minOccurs="0" maxOccurs="1" name="TaxRate" type="s:string"/> + <s:element minOccurs="0" maxOccurs="1" name="TaxType" type="s:string"/> + <s:element minOccurs="1" maxOccurs="1" name="UnitCost" type="s:string"/> + <s:element minOccurs="0" maxOccurs="1" name="UnitOfMeasure" type="s:string"/> + </s:sequence> + </s:complexType> + <s:complexType name="Level3_Type"> + <s:sequence> + <s:element minOccurs="0" maxOccurs="1" name="TaxAmount" type="s:string"/> + <s:element minOccurs="0" maxOccurs="1" name="TaxRate" type="s:string"/> + <s:element minOccurs="0" maxOccurs="1" name="AltTaxAmount" type="s:string"/> + <s:element minOccurs="0" maxOccurs="1" name="AltTaxId" type="s:string"/> + <s:element minOccurs="0" maxOccurs="1" name="DutyAmount" type="s:string"/> + <s:element minOccurs="0" maxOccurs="1" name="FreightAmount" type="s:string"/> + <s:element minOccurs="0" maxOccurs="1" name="DiscountAmount" type="s:string"/> + <s:element minOccurs="0" maxOccurs="1" name="ShipFromZip" type="s:string"/> + <s:element minOccurs="1" maxOccurs="1" name="ShipToAddress" type="Level3_ShipToAddress_Type"/> + <s:element minOccurs="1" maxOccurs="98" name="LineItem" type="Level3_LineItem_Type"/> + </s:sequence> + </s:complexType> + <s:complexType name="PaypalTransactionDetails"> + <s:sequence> + <s:element minOccurs="0" maxOccurs="1" name="PayerID" type="s:string"/> + <s:element minOccurs="0" maxOccurs="1" name="GrossAmountCurrencyID" type="s:string"/> + <s:element minOccurs="1" maxOccurs="1" name="Success" type="s:boolean"/> + <s:element minOccurs="0" maxOccurs="1" name="Authorization" type="s:string"/> + <s:element minOccurs="0" maxOccurs="1" name="Message" type="s:string"/> + <s:element minOccurs="0" maxOccurs="1" name="CorrelationID" type="s:string"/> + <s:element minOccurs="0" maxOccurs="1" name="Timestamp" type="s:string"/> + </s:sequence> + </s:complexType> + <s:complexType name="Address_Type"> + <s:sequence> + <s:element minOccurs="0" maxOccurs="1" name="Address1" type="s:string"/> + <s:element minOccurs="0" maxOccurs="1" name="Address2" type="s:string"/> + <s:element minOccurs="0" maxOccurs="1" name="City" type="s:string"/> + <s:element minOccurs="0" maxOccurs="1" name="State" type="s:string"/> + <s:element minOccurs="0" maxOccurs="1" name="Zip" type="s:string"/> + <s:element minOccurs="0" maxOccurs="1" name="CountryCode" type="s:string"/> + <s:element minOccurs="0" maxOccurs="1" name="PhoneNumber" type="s:string"/> + <s:element minOccurs="0" maxOccurs="1" name="PhoneType" type="s:string"/> + </s:sequence> + </s:complexType> + <s:complexType name="DynamicCurrency"> + <s:sequence> + <s:element minOccurs="1" maxOccurs="1" name="OptedIn" type="s:string"/> + <s:element minOccurs="0" maxOccurs="1" name="RateResponseSignature" type="s:string"/> + </s:sequence> + </s:complexType> + <s:complexType name="DynamicPricing"> + <s:sequence> + <s:element minOccurs="1" maxOccurs="1" name="OptedIn" type="s:string"/> + <s:element minOccurs="0" maxOccurs="1" name="RateResponseSignature" type="s:string"/> + </s:sequence> + </s:complexType> + <s:complexType name="ForeignCurrencyDetails"> + <s:sequence> + <s:element minOccurs="1" maxOccurs="1" name="DCCIndicator" type="s:string"/> + <s:element minOccurs="0" maxOccurs="1" name="ForeignAmount" type="s:string"/> + <s:element minOccurs="0" maxOccurs="1" name="ForeignCurrencyCode" type="s:string"/> + <s:element minOccurs="0" maxOccurs="1" name="ExchangeRate" type="s:string"/> + <s:element minOccurs="0" maxOccurs="1" name="MarginRate" type="s:string"/> + <s:element minOccurs="0" maxOccurs="1" name="RateSource" type="s:string"/> + </s:sequence> + </s:complexType> + <s:complexType name="FraudDetectResult"> + <s:sequence> + <s:element minOccurs="0" maxOccurs="1" name="Score" type="s:integer"/> + <s:element minOccurs="0" maxOccurs="1" name="Recommendation" type="s:string"/> + <s:element minOccurs="0" maxOccurs="5" name="Explanation" type="FraudDetectExplanation_Type"/> + </s:sequence> + </s:complexType> + <s:complexType name="FraudDetectExplanation_Type"> + <s:sequence> + <s:element minOccurs="1" maxOccurs="1" name="type" type="s:integer"/> + <s:element minOccurs="1" maxOccurs="1" name="description" type="s:string"/> + </s:sequence> + </s:complexType> + <s:complexType name="VisaCheckout"> + <s:sequence> + <s:element minOccurs="1" maxOccurs="1" name="CallID" type="s:string"/> + <s:element minOccurs="0" maxOccurs="1" name="PromoCode" type="s:string"/> + </s:sequence> + </s:complexType> + <s:complexType name="MasterPass"> + <s:sequence> + <s:element minOccurs="1" maxOccurs="1" name="TransactionID" type="s:string"/> + <s:element minOccurs="1" maxOccurs="1" name="WalletID" type="s:string"/> + <s:element minOccurs="1" maxOccurs="1" name="Indicator" type="s:string"/> + </s:sequence> + </s:complexType> + <s:complexType name="Transaction"> + <s:all> + <s:element minOccurs="1" maxOccurs="1" name="ExactID" type="s:string"/> + <s:element minOccurs="1" maxOccurs="1" name="Password" type="s:string"/> + <s:element minOccurs="1" maxOccurs="1" name="Transaction_Type" type="s:string"/> + <s:element minOccurs="0" maxOccurs="1" name="DollarAmount" type="s:string"/> + <s:element minOccurs="0" maxOccurs="1" name="SurchargeAmount" type="s:string"/> + <s:element minOccurs="0" maxOccurs="1" name="Card_Number" type="s:string"/> + <s:element minOccurs="0" maxOccurs="1" name="Transaction_Tag" type="s:string"/> + <s:element minOccurs="0" maxOccurs="1" name="SplitTenderID" type="s:string"/> + <s:element minOccurs="0" maxOccurs="1" name="Track1" type="s:string"/> + <s:element minOccurs="0" maxOccurs="1" name="Track2" type="s:string"/> + <s:element minOccurs="0" maxOccurs="1" name="PAN" type="s:string"/> + <s:element minOccurs="0" maxOccurs="1" name="Authorization_Num" type="s:string"/> + <s:element minOccurs="0" maxOccurs="1" name="Expiry_Date" type="s:string"/> + <s:element minOccurs="0" maxOccurs="1" name="CardHoldersName" type="s:string"/> + <s:element minOccurs="0" maxOccurs="1" name="CVDCode" type="s:string"/> + <s:element minOccurs="0" maxOccurs="1" name="CVD_Presence_Ind" type="s:string"/> + <s:element minOccurs="0" maxOccurs="1" name="ZipCode" type="s:string"/> + <s:element minOccurs="0" maxOccurs="1" name="Tax1Amount" type="s:string"/> + <s:element minOccurs="0" maxOccurs="1" name="Tax1Number" type="s:string"/> + <s:element minOccurs="0" maxOccurs="1" name="Tax2Amount" type="s:string"/> + <s:element minOccurs="0" maxOccurs="1" name="Tax2Number" type="s:string"/> + <s:element minOccurs="0" maxOccurs="1" name="Ecommerce_Flag" type="s:string"/> + <s:element minOccurs="0" maxOccurs="1" name="XID" type="s:string"/> + <s:element minOccurs="0" maxOccurs="1" name="CAVV" type="s:string"/> + <s:element minOccurs="0" maxOccurs="1" name="Reference_No" type="s:string"/> + <s:element minOccurs="0" maxOccurs="1" name="Customer_Ref" type="s:string"/> + <s:element minOccurs="0" maxOccurs="1" name="Reference_3" type="s:string"/> + <s:element minOccurs="0" maxOccurs="1" name="Language" type="s:string"/> + <s:element minOccurs="0" maxOccurs="1" name="Client_IP" type="s:string"/> + <s:element minOccurs="0" maxOccurs="1" name="Client_Email" type="s:string"/> + <s:element minOccurs="0" maxOccurs="1" name="User_Name" type="s:string"/> + <s:element minOccurs="0" maxOccurs="1" name="Currency" type="s:string"/> + <s:element minOccurs="0" maxOccurs="1" name="PartialRedemption" type="s:boolean"/> + <s:element minOccurs="0" maxOccurs="1" name="Level3" type="Level3_Type"/> + <s:element minOccurs="0" maxOccurs="1" name="TransarmorToken" type="s:string"/> + <s:element minOccurs="0" maxOccurs="1" name="CardType" type="s:string"/> + <s:element minOccurs="0" maxOccurs="1" name="EAN" type="s:string"/> + <s:element minOccurs="0" maxOccurs="1" name="VirtualCard" type="s:boolean"/> + <s:element minOccurs="0" maxOccurs="1" name="CardCost" type="s:string"/> + <s:element minOccurs="0" maxOccurs="1" name="FraudSuspected" type="s:string"/> + <s:element minOccurs="0" maxOccurs="1" name="PaypalResponse" type="PaypalTransactionDetails"/> + <s:element minOccurs="0" maxOccurs="1" name="SoftDescriptor" type="SoftDescriptor_Type"/> + <s:element minOccurs="0" maxOccurs="1" name="Address" type="Address_Type"/> + <s:element minOccurs="0" maxOccurs="1" name="TPPID" type="s:string"/> + <s:element minOccurs="0" maxOccurs="1" name="SplitShipmentNumber" type="s:string"/> + <s:element minOccurs="0" maxOccurs="1" name="AmexFraud" type="s:string"/> + <s:element minOccurs="0" maxOccurs="1" name="DynamicCurrency" type="DynamicCurrency"/> + <s:element minOccurs="0" maxOccurs="1" name="DynamicPricing" type="DynamicPricing"/> + <s:element minOccurs="0" maxOccurs="1" name="FeeAmount" type="s:string"/> + <s:element minOccurs="0" maxOccurs="1" name="VisaCheckout" type="VisaCheckout"/> + <s:element minOccurs="0" maxOccurs="1" name="PostDate" type="s:string"/> + <s:element minOccurs="0" maxOccurs="1" name="OtherAmount" type="s:string"/> + <s:element minOccurs="0" maxOccurs="1" name="GiftDepositAvailable" type="s:string"/> + <s:element minOccurs="0" maxOccurs="1" name="SpecialPayment" type="s:string"/> + <s:element minOccurs="0" maxOccurs="1" name="WalletProviderID" type="s:string"/> + <s:element minOccurs="0" maxOccurs="1" name="MasterPass" type="MasterPass"/> + <s:element minOccurs="0" maxOccurs="1" name="FraudDetectInAuthTransId" type="s:string"/> + <s:element minOccurs="0" maxOccurs="1" name="SCV" type="s:string"/> + <s:element minOccurs="0" maxOccurs="1" name="StoredCredentials" type="StoredCredentialsType"/> + <s:element minOccurs="0" maxOccurs="1" name="Extra" type="Extra_Type"/> + </s:all> + </s:complexType> + <s:complexType name="StoredCredentialsType"> + <s:sequence> + <s:element minOccurs="0" maxOccurs="1" name="AuthorizationTypeOverride" type="s:string"/> + <s:element minOccurs="0" maxOccurs="1" name="Initiation" type="s:string"/> + <s:element minOccurs="0" maxOccurs="1" name="Indicator" type="s:string"/> + <s:element minOccurs="0" maxOccurs="1" name="Schedule" type="s:string"/> + <s:element minOccurs="0" maxOccurs="1" name="TransactionId" type="s:string"/> + </s:sequence> + </s:complexType> + <s:complexType name="Extra_Type"> + <s:sequence> + <s:element minOccurs="1" maxOccurs="1" name="Field" type="s:string"/> + <s:element minOccurs="1" maxOccurs="1" name="Value" type="s:string"/> + </s:sequence> + </s:complexType> + + <s:element name="Transaction" type="s0:Transaction"/> + +</s:schema> diff --git a/test/support/mercury_helper.rb b/test/support/mercury_helper.rb index e52ad7bb800..a8afafa25e5 100644 --- a/test/support/mercury_helper.rb +++ b/test/support/mercury_helper.rb @@ -2,43 +2,43 @@ module MercuryHelper module BatchClosing def close_batch xml = Builder::XmlMarkup.new - xml.tag! "TStream" do - xml.tag! "Admin" do + xml.tag! 'TStream' do + xml.tag! 'Admin' do xml.tag! 'MerchantID', @options[:login] - xml.tag! 'TranCode', "BatchSummary" + xml.tag! 'TranCode', 'BatchSummary' end end xml = xml.target! - response = commit("BatchSummary", xml) + response = commit('BatchSummary', xml) xml = Builder::XmlMarkup.new - xml.tag! "TStream" do - xml.tag! "Admin" do + xml.tag! 'TStream' do + xml.tag! 'Admin' do xml.tag! 'MerchantID', @options[:login] - xml.tag! 'OperatorID', response.params["operator_id"] - xml.tag! 'TranCode', "BatchClose" - xml.tag! 'BatchNo', response.params["batch_no"] - xml.tag! 'BatchItemCount', response.params["batch_item_count"] - xml.tag! 'NetBatchTotal', response.params["net_batch_total"] - xml.tag! 'CreditPurchaseCount', response.params["credit_purchase_count"] - xml.tag! 'CreditPurchaseAmount', response.params["credit_purchase_amount"] - xml.tag! 'CreditReturnCount', response.params["credit_return_count"] - xml.tag! 'CreditReturnAmount', response.params["credit_return_amount"] - xml.tag! 'DebitPurchaseCount', response.params["debit_purchase_count"] - xml.tag! 'DebitPurchaseAmount', response.params["debit_purchase_amount"] - xml.tag! 'DebitReturnCount', response.params["debit_return_count"] - xml.tag! 'DebitReturnAmount', response.params["debit_return_amount"] + xml.tag! 'OperatorID', response.params['operator_id'] + xml.tag! 'TranCode', 'BatchClose' + xml.tag! 'BatchNo', response.params['batch_no'] + xml.tag! 'BatchItemCount', response.params['batch_item_count'] + xml.tag! 'NetBatchTotal', response.params['net_batch_total'] + xml.tag! 'CreditPurchaseCount', response.params['credit_purchase_count'] + xml.tag! 'CreditPurchaseAmount', response.params['credit_purchase_amount'] + xml.tag! 'CreditReturnCount', response.params['credit_return_count'] + xml.tag! 'CreditReturnAmount', response.params['credit_return_amount'] + xml.tag! 'DebitPurchaseCount', response.params['debit_purchase_count'] + xml.tag! 'DebitPurchaseAmount', response.params['debit_purchase_amount'] + xml.tag! 'DebitReturnCount', response.params['debit_return_count'] + xml.tag! 'DebitReturnAmount', response.params['debit_return_amount'] end end xml = xml.target! - commit("BatchClose", xml) + commit('BatchClose', xml) end def hashify_xml!(xml, response) super doc = REXML::Document.new(xml) - doc.elements.each("//BatchSummary/*") do |node| + doc.elements.each('//BatchSummary/*') do |node| response[node.name.underscore.to_sym] = node.text end end diff --git a/test/test_helper.rb b/test/test_helper.rb index b866558cd96..9666234fea9 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -1,4 +1,3 @@ -#!/usr/bin/env ruby $:.unshift File.expand_path('../../lib', __FILE__) require 'bundler/setup' @@ -86,7 +85,7 @@ def assert_valid(model, message=nil) errors = model.validate clean_backtrace do - assert_equal({}, errors, (message || "Expected to be valid")) + assert_equal({}, errors, (message || 'Expected to be valid')) end errors @@ -96,14 +95,14 @@ def assert_not_valid(model) errors = model.validate clean_backtrace do - assert_not_equal({}, errors, "Expected to not be valid") + assert_not_equal({}, errors, 'Expected to not be valid') end errors end def assert_deprecation_warning(message=nil) - ActiveMerchant.expects(:deprecated).with(message ? message : anything) + ActiveMerchant.expects(:deprecated).with(message || anything) yield end @@ -123,15 +122,16 @@ def assert_no_deprecation_warning def assert_scrubbed(unexpected_value, transcript) regexp = (Regexp === unexpected_value ? unexpected_value : Regexp.new(Regexp.quote(unexpected_value.to_s))) - refute_match regexp, transcript, "Expected the value to be scrubbed out of the transcript" + refute_match regexp, transcript, 'Expected the value to be scrubbed out of the transcript' end private + def clean_backtrace(&block) yield rescue AssertionClass => e path = File.expand_path(__FILE__) - raise AssertionClass, e.message, e.backtrace.reject { |line| File.expand_path(line) =~ /#{path}/ } + raise AssertionClass, e.message, (e.backtrace.reject { |line| File.expand_path(line) =~ /#{path}/ }) end end @@ -141,6 +141,7 @@ module Fixtures DEFAULT_CREDENTIALS = File.join(File.dirname(__FILE__), 'fixtures.yml') unless defined?(DEFAULT_CREDENTIALS) private + def default_expiration_date @default_expiration_date ||= Date.new((Time.now.year + 1), 9, 30) end @@ -164,7 +165,7 @@ def credit_card(number = '4242424242424242', options = {}) end def credit_card_with_track_data(number = '4242424242424242', options = {}) - exp_date = default_expiration_date.strftime("%y%m") + exp_date = default_expiration_date.strftime('%y%m') defaults = { :track_data => "%B#{number}^LONGSEN/L. ^#{exp_date}1200000000000000**123******?", @@ -207,9 +208,9 @@ def apple_pay_payment_token(options = {}) apple_pay_json_raw = '{"version":"EC_v1","data":"","signature":""}' defaults = { payment_data: ActiveSupport::JSON.decode(apple_pay_json_raw), - payment_instrument_name: "Visa 2424", - payment_network: "Visa", - transaction_identifier: "uniqueidentifier123" + payment_instrument_name: 'Visa 2424', + payment_network: 'Visa', + transaction_identifier: 'uniqueidentifier123' }.update(options) ActiveMerchant::Billing::ApplePayPaymentToken.new(defaults[:payment_data], @@ -234,6 +235,16 @@ def address(options = {}) }.update(options) end + def statement_address(options = {}) + { + address1: '456 My Street', + address2: 'Apt 1', + city: 'Ottawa', + state: 'ON', + zip: 'K1C2N6' + }.update(options) + end + def generate_unique_id SecureRandom.hex(16) end @@ -251,7 +262,7 @@ def fixtures(key) def load_fixtures [DEFAULT_CREDENTIALS, LOCAL_CREDENTIALS].inject({}) do |credentials, file_name| if File.exist?(file_name) - yaml_data = YAML.load(File.read(file_name)) + yaml_data = YAML.safe_load(File.read(file_name), [], [], true) credentials.merge!(symbolize_keys(yaml_data)) end credentials @@ -262,7 +273,7 @@ def symbolize_keys(hash) return unless hash.is_a?(Hash) hash.symbolize_keys! - hash.each{|k,v| symbolize_keys(v)} + hash.each { |k, v| symbolize_keys(v) } end end end @@ -286,8 +297,8 @@ def dump_transcript_and_fail(gateway, amount, credit_card, params) gateway.purchase(amount, credit_card, params) end - File.open("transcript.log", "w") { |f| f.write(transcript) } - assert false, "A purchase transcript has been written to transcript.log for you to test scrubbing with." + File.open('transcript.log', 'w') { |f| f.write(transcript) } + assert false, 'A purchase transcript has been written to transcript.log for you to test scrubbing with.' end end @@ -315,25 +326,25 @@ def url_for(options, *parameters_for_method_reference) end protected + def protect_against_forgery? false end end - class MockResponse attr_reader :code, :body, :message attr_accessor :headers - def self.succeeded(body, message="") + def self.succeeded(body, message='') MockResponse.new(200, body, message) end - def self.failed(body, http_status_code=422, message="") + def self.failed(body, http_status_code=422, message='') MockResponse.new(http_status_code, body, message) end - def initialize(code, body, message="", headers={}) + def initialize(code, body, message='', headers={}) @code, @body, @message, @headers = code, body, message, headers end diff --git a/test/unit/check_test.rb b/test/unit/check_test.rb index f828b434bbc..e5908553ab9 100644 --- a/test/unit/check_test.rb +++ b/test/unit/check_test.rb @@ -22,7 +22,7 @@ def test_nil_name check = Check.new(:name => nil) assert_nil check.first_name assert_nil check.last_name - assert_equal "", check.name + assert_equal '', check.name end def test_valid @@ -41,12 +41,12 @@ def test_credit_card? def test_invalid_routing_number errors = assert_not_valid Check.new(:routing_number => INVALID_ABA) - assert_equal ["is invalid"], errors[:routing_number] + assert_equal ['is invalid'], errors[:routing_number] end def test_malformed_routing_number errors = assert_not_valid Check.new(:routing_number => MALFORMED_ABA) - assert_equal ["is invalid"], errors[:routing_number] + assert_equal ['is invalid'], errors[:routing_number] end def test_account_holder_type @@ -73,7 +73,7 @@ def test_account_type assert !c.validate[:account_type] c.account_type = 'moo' - assert_equal ["must be checking or savings"], c.validate[:account_type] + assert_equal ['must be checking or savings'], c.validate[:account_type] c.account_type = nil assert !c.validate[:account_type] diff --git a/test/unit/connection_test.rb b/test/unit/connection_test.rb index 8486ef987d9..ac8c29a4f1d 100644 --- a/test/unit/connection_test.rb +++ b/test/unit/connection_test.rb @@ -22,43 +22,82 @@ def test_connection_endpoint_accepts_uri def test_connection_endpoint_raises_uri_error assert_raises URI::InvalidURIError do - ActiveMerchant::Connection.new("not a URI") + ActiveMerchant::Connection.new('not a URI') end end + def test_connection_passes_env_proxy_by_default + spy = Net::HTTP.new('example.com', 443) + Net::HTTP.expects(:new).with('example.com', 443, :ENV, nil).returns(spy) + spy.expects(:start).returns(true) + spy.expects(:get).with('/tx.php', {'connection' => 'close'}).returns(@ok) + @connection.request(:get, nil, {}) + end + + def test_connection_does_pass_requested_proxy + @connection.proxy_address = 'proxy.example.com' + @connection.proxy_port = 8080 + spy = Net::HTTP.new('example.com', 443) + Net::HTTP.expects(:new).with('example.com', 443, 'proxy.example.com', 8080).returns(spy) + spy.expects(:start).returns(true) + spy.expects(:get).with('/tx.php', {'connection' => 'close'}).returns(@ok) + @connection.request(:get, nil, {}) + end + + def test_connection_does_not_mutate_headers_argument + headers = { 'Content-Type' => 'text/xml' }.freeze + Net::HTTP.any_instance.expects(:get).with('/tx.php', headers.merge({'connection' => 'close'})).returns(@ok) + Net::HTTP.any_instance.expects(:start).returns(true) + @connection.request(:get, nil, headers) + assert_equal({ 'Content-Type' => 'text/xml' }, headers) + end + def test_successful_get_request @connection.logger.expects(:info).twice - Net::HTTP.any_instance.expects(:get).with('/tx.php', {}).returns(@ok) + Net::HTTP.any_instance.expects(:get).with('/tx.php', {'connection' => 'close'}).returns(@ok) + Net::HTTP.any_instance.expects(:start).returns(true) response = @connection.request(:get, nil, {}) assert_equal 'success', response.body end def test_successful_post_request - Net::HTTP.any_instance.expects(:post).with('/tx.php', 'data', ActiveMerchant::Connection::RUBY_184_POST_HEADERS).returns(@ok) + Net::HTTP.any_instance.expects(:post).with('/tx.php', 'data', ActiveMerchant::Connection::RUBY_184_POST_HEADERS.merge({'connection' => 'close'})).returns(@ok) + Net::HTTP.any_instance.expects(:start).returns(true) response = @connection.request(:post, 'data', {}) assert_equal 'success', response.body end def test_successful_put_request - Net::HTTP.any_instance.expects(:put).with('/tx.php', 'data', {}).returns(@ok) + Net::HTTP.any_instance.expects(:put).with('/tx.php', 'data', {'connection' => 'close'}).returns(@ok) + Net::HTTP.any_instance.expects(:start).returns(true) response = @connection.request(:put, 'data', {}) assert_equal 'success', response.body end def test_successful_delete_request - Net::HTTP.any_instance.expects(:delete).with('/tx.php', {}).returns(@ok) + Net::HTTP.any_instance.expects(:delete).with('/tx.php', {'connection' => 'close'}).returns(@ok) + Net::HTTP.any_instance.expects(:start).returns(true) response = @connection.request(:delete, nil, {}) assert_equal 'success', response.body end + def test_successful_delete_with_body_request + Net::HTTP.any_instance.expects(:request).at_most(3).returns(@ok) + Net::HTTP.any_instance.expects(:start).returns(true) + response = @connection.request(:delete, 'data', {}) + assert_equal 'success', response.body + end + def test_get_raises_argument_error_if_passed_data assert_raises(ArgumentError) do + Net::HTTP.any_instance.expects(:start).returns(true) @connection.request(:get, 'data', {}) end end def test_request_raises_when_request_method_not_supported assert_raises(ArgumentError) do + Net::HTTP.any_instance.expects(:start).returns(true) @connection.request(:head, nil, {}) end end @@ -75,6 +114,22 @@ def test_override_ssl_version assert_equal :SSLv3, @connection.ssl_version end + def test_override_min_version + omit_if Net::HTTP.instance_methods.exclude?(:min_version=) + + refute_equal :TLS1_2, @connection.min_version + @connection.min_version = :TLS1_2 + assert_equal :TLS1_2, @connection.min_version + end + + def test_override_max_version + omit_if Net::HTTP.instance_methods.exclude?(:min_version=) + + refute_equal :TLS1_2, @connection.max_version + @connection.max_version = :TLS1_2 + assert_equal :TLS1_2, @connection.max_version + end + def test_default_read_timeout assert_equal ActiveMerchant::Connection::READ_TIMEOUT, @connection.read_timeout end @@ -108,9 +163,9 @@ def test_default_ca_file end def test_override_ca_file - @connection.ca_file = "/bogus" - assert_equal "/bogus", @connection.ca_file - assert_equal "/bogus", @connection.send(:http).ca_file + @connection.ca_file = '/bogus' + assert_equal '/bogus', @connection.ca_file + assert_equal '/bogus', @connection.send(:http).ca_file end def test_default_ca_path @@ -119,14 +174,14 @@ def test_default_ca_path end def test_override_ca_path - @connection.ca_path = "/bogus" - assert_equal "/bogus", @connection.ca_path - assert_equal "/bogus", @connection.send(:http).ca_path + @connection.ca_path = '/bogus' + assert_equal '/bogus', @connection.ca_path + assert_equal '/bogus', @connection.send(:http).ca_path end def test_unrecoverable_exception @connection.logger.expects(:info).once - Net::HTTP.any_instance.expects(:post).raises(EOFError) + Net::HTTP.any_instance.expects(:start).raises(EOFError) assert_raises(ActiveMerchant::ConnectionError) do @connection.request(:post, '') @@ -135,14 +190,15 @@ def test_unrecoverable_exception def test_failure_then_success_with_recoverable_exception @connection.logger.expects(:info).never - Net::HTTP.any_instance.expects(:post).times(2).raises(Errno::ECONNREFUSED).then.returns(@ok) + Net::HTTP.any_instance.expects(:start).times(2).raises(Errno::ECONNREFUSED).then.returns(true) + Net::HTTP.any_instance.expects(:post).returns(@ok) @connection.request(:post, '') end def test_failure_limit_reached @connection.logger.expects(:info).once - Net::HTTP.any_instance.expects(:post).times(ActiveMerchant::Connection::MAX_RETRIES).raises(Errno::ECONNREFUSED) + Net::HTTP.any_instance.expects(:start).times(ActiveMerchant::Connection::MAX_RETRIES).raises(Errno::ECONNREFUSED) assert_raises(ActiveMerchant::ConnectionError) do @connection.request(:post, '') @@ -150,7 +206,8 @@ def test_failure_limit_reached end def test_failure_then_success_with_retry_safe_enabled - Net::HTTP.any_instance.expects(:post).times(2).raises(EOFError).then.returns(@ok) + Net::HTTP.any_instance.expects(:start).times(2).raises(EOFError).then.returns(@ok) + Net::HTTP.any_instance.expects(:post).returns(@ok) @connection.retry_safe = true @@ -158,9 +215,12 @@ def test_failure_then_success_with_retry_safe_enabled end def test_mixture_of_failures_with_retry_safe_enabled - Net::HTTP.any_instance.expects(:post).times(3).raises(Errno::ECONNRESET). - raises(Errno::ECONNREFUSED). - raises(EOFError) + Net::HTTP.any_instance. + expects(:start). + times(3). + raises(Errno::ECONNRESET). + raises(Errno::ECONNREFUSED). + raises(EOFError) @connection.retry_safe = true @@ -171,11 +231,18 @@ def test_mixture_of_failures_with_retry_safe_enabled def test_failure_with_ssl_certificate @connection.logger.expects(:error).once - Net::HTTP.any_instance.expects(:post).raises(OpenSSL::X509::CertificateError) + Net::HTTP.any_instance.expects(:start).raises(OpenSSL::X509::CertificateError) assert_raises(ActiveMerchant::ClientCertificateError) do @connection.request(:post, '') end end + def test_wiredump_service_raises_on_frozen_object + transcript = ''.freeze + assert_raise ArgumentError, "can't wiredump to frozen object" do + @connection.wiredump_device = transcript + end + end + end diff --git a/test/unit/country_code_test.rb b/test/unit/country_code_test.rb index b455d05f3d7..12ee3ae4ab4 100644 --- a/test/unit/country_code_test.rb +++ b/test/unit/country_code_test.rb @@ -26,6 +26,6 @@ def test_numeric_code end def test_invalid_code_format - assert_raises(ActiveMerchant::CountryCodeFormatError){ ActiveMerchant::CountryCode.new('Canada') } + assert_raises(ActiveMerchant::CountryCodeFormatError) { ActiveMerchant::CountryCode.new('Canada') } end end diff --git a/test/unit/country_test.rb b/test/unit/country_test.rb index a48e73fa36f..d9dcae71b07 100644 --- a/test/unit/country_test.rb +++ b/test/unit/country_test.rb @@ -59,6 +59,14 @@ def test_find_united_kingdom assert_equal 'GB', country.code(:alpha2).value end + def test_find_romania + country = ActiveMerchant::Country.find('ROM') + assert_equal 'RO', country.code(:alpha2).value + + country = ActiveMerchant::Country.find('ROU') + assert_equal 'RO', country.code(:alpha2).value + end + def test_raise_on_nil_name assert_raises(ActiveMerchant::InvalidCountryCodeError) do ActiveMerchant::Country.find(nil) @@ -66,7 +74,7 @@ def test_raise_on_nil_name end def test_country_names_are_alphabetized - country_names = ActiveMerchant::Country::COUNTRIES.map { | each | each[:name] } + country_names = ActiveMerchant::Country::COUNTRIES.map { |each| each[:name] } assert_equal(country_names.sort, country_names) end diff --git a/test/unit/credit_card_methods_test.rb b/test/unit/credit_card_methods_test.rb index e910ddfecdd..da6211e1a7f 100644 --- a/test/unit/credit_card_methods_test.rb +++ b/test/unit/credit_card_methods_test.rb @@ -9,9 +9,8 @@ class CreditCard def maestro_card_numbers %w[ - 5000000000000000 5099999999999999 5600000000000000 - 5899999999999999 6000000000000000 6999999999999999 - 6761999999999999 6763000000000000 5038999999999999 + 6390000000000000 6390700000000000 6390990000000000 + 6761999999999999 6763000000000000 6799999999999999 ] end @@ -47,11 +46,11 @@ def test_should_be_able_to_identify_valid_start_years end def test_valid_start_year_can_handle_strings - assert valid_start_year?("2009") + assert valid_start_year?('2009') end def test_valid_month_can_handle_strings - assert valid_month?("1") + assert valid_month?('1') end def test_valid_expiry_year_can_handle_strings @@ -110,14 +109,14 @@ def test_should_detect_maestro_dk_as_maestro end def test_should_detect_maestro_cards - assert_equal 'maestro', CreditCard.brand?('5020100000000000') + assert_equal 'maestro', CreditCard.brand?('675675000000000') maestro_card_numbers.each { |number| assert_equal 'maestro', CreditCard.brand?(number) } non_maestro_card_numbers.each { |number| assert_not_equal 'maestro', CreditCard.brand?(number) } end def test_should_detect_mastercard - assert_equal 'master', CreditCard.brand?('6771890000000000') + assert_equal 'master', CreditCard.brand?('2720890000000000') assert_equal 'master', CreditCard.brand?('5413031000000000') end @@ -125,33 +124,12 @@ def test_should_detect_forbrugsforeningen assert_equal 'forbrugsforeningen', CreditCard.brand?('6007221000000000') end - def test_should_detect_laser_card - # 16 digits - assert_equal 'laser', CreditCard.brand?('6304985028090561') - - # 18 digits - assert_equal 'laser', CreditCard.brand?('630498502809056151') - - # 19 digits - assert_equal 'laser', CreditCard.brand?('6304985028090561515') - - # 17 digits - assert_not_equal 'laser', CreditCard.brand?('63049850280905615') - - # 15 digits - assert_not_equal 'laser', CreditCard.brand?('630498502809056') - - # Alternate format - assert_equal 'laser', CreditCard.brand?('6706950000000000000') - - # Alternate format (16 digits) - assert_equal 'laser', CreditCard.brand?('6706123456789012') - - # New format (16 digits) - assert_equal 'laser', CreditCard.brand?('6709123456789012') + def test_should_detect_sodexo_card + assert_equal 'sodexo', CreditCard.brand?('60606944957644') + end - # Ulster bank (Ireland) with 12 digits - assert_equal 'laser', CreditCard.brand?('677117111234') + def test_should_detect_vr_card + assert_equal 'vr', CreditCard.brand?('63703644957644') end def test_should_detect_when_an_argument_brand_does_not_match_calculated_brand @@ -160,14 +138,14 @@ def test_should_detect_when_an_argument_brand_does_not_match_calculated_brand end def test_detecting_full_range_of_maestro_card_numbers - maestro = '50000000000' + maestro = '63900000000' assert_equal 11, maestro.length assert_not_equal 'maestro', CreditCard.brand?(maestro) while maestro.length < 19 maestro << '0' - assert_equal 'maestro', CreditCard.brand?(maestro) + assert_equal 'maestro', CreditCard.brand?(maestro), "Failed for bin #{maestro}" end assert_equal 19, maestro.length @@ -187,26 +165,40 @@ def test_matching_discover_card end def test_matching_invalid_card - assert_nil CreditCard.brand?("XXXXXXXXXXXX0000") - assert_false CreditCard.valid_number?("XXXXXXXXXXXX0000") + assert_nil CreditCard.brand?('XXXXXXXXXXXX0000') + assert_false CreditCard.valid_number?('XXXXXXXXXXXX0000') + assert_false CreditCard.valid_number?(nil) end def test_16_digit_maestro_uk number = '6759000000000000' assert_equal 16, number.length - assert_equal 'switch', CreditCard.brand?(number) + assert_equal 'maestro', CreditCard.brand?(number) end def test_18_digit_maestro_uk number = '675900000000000000' assert_equal 18, number.length - assert_equal 'switch', CreditCard.brand?(number) + assert_equal 'maestro', CreditCard.brand?(number) end def test_19_digit_maestro_uk number = '6759000000000000000' assert_equal 19, number.length - assert_equal 'switch', CreditCard.brand?(number) + assert_equal 'maestro', CreditCard.brand?(number) + end + + def test_carnet_cards + numbers = [ + '5062280000000000', + '6046220312312312', + '6393889871239871', + '5022751231231231' + ] + numbers.each do |num| + assert_equal 16, num.length + assert_equal 'carnet', CreditCard.brand?(num) + end end def test_electron_cards @@ -222,6 +214,9 @@ def test_electron_cards end end + # nil check + assert_false electron_test.call(nil) + # Visa range assert_false electron_test.call('4245180000000000') assert_false electron_test.call('4918810000000000') diff --git a/test/unit/credit_card_test.rb b/test/unit/credit_card_test.rb index 154e1c72ee6..fed8dea282f 100644 --- a/test/unit/credit_card_test.rb +++ b/test/unit/credit_card_test.rb @@ -3,8 +3,8 @@ class CreditCardTest < Test::Unit::TestCase def setup CreditCard.require_verification_value = false - @visa = credit_card("4779139500118580", :brand => "visa") - @solo = credit_card("676700000000000000", :brand => "solo", :issue_number => '01') + @visa = credit_card('4779139500118580', brand: 'visa') + @maestro = credit_card('676700000000000000', brand: 'maestro', verification_value: '') end def teardown @@ -14,11 +14,11 @@ def teardown def test_constructor_should_properly_assign_values c = credit_card - assert_equal "4242424242424242", c.number + assert_equal '4242424242424242', c.number assert_equal 9, c.month assert_equal Time.now.year + 1, c.year - assert_equal "Longbob Longsen", c.name - assert_equal "visa", c.brand + assert_equal 'Longbob Longsen', c.name + assert_equal 'visa', c.brand assert_valid c end @@ -32,8 +32,8 @@ def test_should_be_a_valid_visa_card assert_valid @visa end - def test_should_be_a_valid_solo_card - assert_valid @solo + def test_should_be_a_valid_maestro_card + assert_valid @maestro end def test_cards_with_empty_names_should_not_be_valid @@ -55,19 +55,19 @@ def test_should_be_able_to_identify_invalid_card_numbers @visa.number = nil assert_not_valid @visa - @visa.number = "11112222333344ff" + @visa.number = '11112222333344ff' errors = assert_not_valid @visa assert !errors[:type] assert !errors[:brand] assert errors[:number] - @visa.number = "111122223333444" + @visa.number = '111122223333444' errors = assert_not_valid @visa assert !errors[:type] assert !errors[:brand] assert errors[:number] - @visa.number = "11112222333344444" + @visa.number = '11112222333344444' errors = assert_not_valid @visa assert !errors[:type] assert !errors[:brand] @@ -80,7 +80,7 @@ def test_should_have_errors_with_invalid_card_brand_for_otherwise_correct_number errors = assert_not_valid @visa assert !errors[:number] assert errors[:brand] - assert_equal ["does not match the card number"], errors[:brand] + assert_equal ['does not match the card number'], errors[:brand] end def test_should_be_invalid_when_brand_cannot_be_detected @@ -93,13 +93,13 @@ def test_should_be_invalid_when_brand_cannot_be_detected assert errors[:number] assert_equal ['is required'], errors[:number] - @visa.number = "11112222333344ff" + @visa.number = '11112222333344ff' errors = assert_not_valid @visa assert !errors[:type] assert !errors[:brand] assert errors[:number] - @visa.number = "11112222333344444" + @visa.number = '11112222333344444' errors = assert_not_valid @visa assert !errors[:brand] assert !errors[:type] @@ -107,7 +107,7 @@ def test_should_be_invalid_when_brand_cannot_be_detected end def test_should_be_a_valid_card_number - @visa.number = "4242424242424242" + @visa.number = '4242424242424242' assert_valid @visa end @@ -167,12 +167,6 @@ def test_expired_card_should_have_one_error_on_year assert_match(/expired/, errors[:year].first) end - def test_should_be_valid_with_start_month_and_year_as_string - @solo.start_month = '2' - @solo.start_year = '2007' - assert_valid @solo - end - def test_should_identify_wrong_card_brand c = credit_card(:brand => 'master') assert_not_valid c @@ -194,7 +188,7 @@ def test_should_correctly_identify_card_brand assert_equal 'visa', CreditCard.brand?('4242424242424242') assert_equal 'american_express', CreditCard.brand?('341111111111111') assert_equal 'master', CreditCard.brand?('5105105105105100') - (222100..272099).each {|bin| assert_equal 'master', CreditCard.brand?(bin.to_s + '1111111111'), "Failed with BIN #{bin}"} + (222100..272099).each { |bin| assert_equal 'master', CreditCard.brand?(bin.to_s + '1111111111'), "Failed with BIN #{bin}" } assert_nil CreditCard.brand?('') end @@ -242,62 +236,34 @@ def test_bogus_cards_are_not_valid_without_verification_value assert_not_valid card end - def test_should_require_valid_start_date_for_solo_or_switch - @solo.start_month = nil - @solo.start_year = nil - @solo.issue_number = nil - - errors = assert_not_valid @solo - assert errors[:start_month] - assert errors[:start_year] - assert errors[:issue_number] - - @solo.start_month = 2 - @solo.start_year = 2007 - assert_valid @solo - end - - def test_should_require_a_valid_issue_number_for_solo_or_switch - @solo.start_month = nil - @solo.start_year = 2005 - @solo.issue_number = nil - - errors = assert_not_valid @solo - assert errors[:start_month] - assert_equal ["cannot be empty"], errors[:issue_number] - - @solo.issue_number = 3 - assert_valid @solo + def test_should_return_last_four_digits_of_card_number + ccn = CreditCard.new(:number => '4779139500118580') + assert_equal '8580', ccn.last_digits end - def test_should_require_a_validate_non_empty_issue_number_for_solo_or_switch - @solo.issue_number = "invalid" - - errors = assert_not_valid @solo - assert_equal ["is invalid"], errors[:issue_number] - - @solo.issue_number = 3 - assert_valid @solo + def test_bogus_last_digits + ccn = CreditCard.new(:number => '1') + assert_equal '1', ccn.last_digits end - def test_should_return_last_four_digits_of_card_number - ccn = CreditCard.new(:number => "4779139500118580") - assert_equal "8580", ccn.last_digits + def test_should_return_empty_string_for_first_digits_of_nil_card_number + ccn = CreditCard.new + assert_equal '', ccn.first_digits end - def test_bogus_last_digits - ccn = CreditCard.new(:number => "1") - assert_equal "1", ccn.last_digits + def test_should_return_empty_string_for_last_digits_of_nil_card_number + ccn = CreditCard.new + assert_equal '', ccn.last_digits end def test_should_return_first_four_digits_of_card_number - ccn = CreditCard.new(:number => "4779139500118580") - assert_equal "477913", ccn.first_digits + ccn = CreditCard.new(:number => '4779139500118580') + assert_equal '477913', ccn.first_digits end def test_should_return_first_bogus_digit_of_card_number - ccn = CreditCard.new(:number => "1") - assert_equal "1", ccn.first_digits + ccn = CreditCard.new(:number => '1') + assert_equal '1', ccn.first_digits end def test_should_be_true_when_credit_card_has_a_first_name @@ -327,42 +293,42 @@ def test_should_test_for_a_full_name def test_should_handle_full_name_when_first_or_last_is_missing c = CreditCard.new(:first_name => 'James') assert c.name? - assert_equal "James", c.name + assert_equal 'James', c.name c = CreditCard.new(:last_name => 'Herdman') assert c.name? - assert_equal "Herdman", c.name + assert_equal 'Herdman', c.name end def test_should_assign_a_full_name - c = CreditCard.new :name => "James Herdman" - assert_equal "James", c.first_name - assert_equal "Herdman", c.last_name + c = CreditCard.new :name => 'James Herdman' + assert_equal 'James', c.first_name + assert_equal 'Herdman', c.last_name - c = CreditCard.new :name => "Rocket J. Squirrel" - assert_equal "Rocket J.", c.first_name - assert_equal "Squirrel", c.last_name + c = CreditCard.new :name => 'Rocket J. Squirrel' + assert_equal 'Rocket J.', c.first_name + assert_equal 'Squirrel', c.last_name - c = CreditCard.new :name => "Twiggy" - assert_equal "", c.first_name - assert_equal "Twiggy", c.last_name - assert_equal "Twiggy", c.name + c = CreditCard.new :name => 'Twiggy' + assert_equal '', c.first_name + assert_equal 'Twiggy', c.last_name + assert_equal 'Twiggy', c.name end def test_should_remove_trailing_whitespace_on_name c = CreditCard.new(:last_name => 'Herdman') - assert_equal "Herdman", c.name + assert_equal 'Herdman', c.name c = CreditCard.new(:last_name => 'Herdman', first_name: '') - assert_equal "Herdman", c.name + assert_equal 'Herdman', c.name end def test_should_remove_leading_whitespace_on_name c = CreditCard.new(:first_name => 'James') - assert_equal "James", c.name + assert_equal 'James', c.name c = CreditCard.new(:last_name => '', first_name: 'James') - assert_equal "James", c.name + assert_equal 'James', c.name end # The following is a regression for a bug that raised an exception when @@ -411,7 +377,7 @@ def test_mask_number def test_strip_non_digit_characters card = credit_card('4242-4242 %%%%%%4242......4242') assert_valid card - assert_equal "4242424242424242", card.number + assert_equal '4242424242424242', card.number end def test_validate_handles_blank_number @@ -433,40 +399,35 @@ def test_rails_methods_are_deprecated end def test_brand_is_aliased_as_type - assert_deprecation_warning("CreditCard#type is deprecated and will be removed from a future release of ActiveMerchant. Please use CreditCard#brand instead.") do + assert_deprecation_warning('CreditCard#type is deprecated and will be removed from a future release of ActiveMerchant. Please use CreditCard#brand instead.') do assert_equal @visa.type, @visa.brand end - assert_deprecation_warning("CreditCard#type is deprecated and will be removed from a future release of ActiveMerchant. Please use CreditCard#brand instead.") do - assert_equal @solo.type, @solo.brand + assert_deprecation_warning('CreditCard#type is deprecated and will be removed from a future release of ActiveMerchant. Please use CreditCard#brand instead.') do + assert_equal @maestro.type, @maestro.brand end end def test_month_and_year_are_immediately_converted_to_integers card = CreditCard.new - card.month = "1" + card.month = '1' assert_equal 1, card.month - card.year = "1" + card.year = '1' assert_equal 1, card.year - card.month = "" + card.month = '' assert_nil card.month - card.year = "" + card.year = '' assert_nil card.year card.month = nil assert_nil card.month card.year = nil assert_nil card.year - - card.start_month = "1" - assert_equal 1, card.start_month - card.start_year = "1" - assert_equal 1, card.start_year end def test_should_report_as_emv_if_icc_data_present - assert CreditCard.new(icc_data: "E480").emv? + assert CreditCard.new(icc_data: 'E480').emv? end def test_should_not_report_as_emv_if_icc_data_not_present diff --git a/test/unit/cvv_result_test.rb b/test/unit/cvv_result_test.rb index 12ed48d1e35..282fc97c8a6 100644 --- a/test/unit/cvv_result_test.rb +++ b/test/unit/cvv_result_test.rb @@ -6,28 +6,28 @@ def test_nil_data assert_nil result.code assert_nil result.message end - + def test_blank_data result = CVVResult.new('') assert_nil result.code assert_nil result.message end - + def test_successful_match result = CVVResult.new('M') assert_equal 'M', result.code assert_equal CVVResult.messages['M'], result.message end - + def test_failed_match result = CVVResult.new('N') assert_equal 'N', result.code assert_equal CVVResult.messages['N'], result.message end - + def test_to_hash result = CVVResult.new('M').to_hash assert_equal 'M', result['code'] assert_equal CVVResult.messages['M'], result['message'] end -end \ No newline at end of file +end diff --git a/test/unit/expiry_date_test.rb b/test/unit/expiry_date_test.rb index 9be4b731afc..07a44b26c15 100644 --- a/test/unit/expiry_date_test.rb +++ b/test/unit/expiry_date_test.rb @@ -6,27 +6,27 @@ def test_should_be_expired date = CreditCard::ExpiryDate.new(last_month.month, last_month.year) assert date.expired? end - + def test_today_should_not_be_expired today = Time.now.utc date = CreditCard::ExpiryDate.new(today.month, today.year) assert_false date.expired? end - + def test_dates_in_the_future_should_not_be_expired next_month = 1.month.from_now date = CreditCard::ExpiryDate.new(next_month.month, next_month.year) assert_false date.expired? end - + def test_invalid_date expiry = CreditCard::ExpiryDate.new(13, 2009) assert_equal Time.at(0).utc, expiry.expiration end - + def test_month_and_year_coerced_to_integer - expiry = CreditCard::ExpiryDate.new("13", "2009") + expiry = CreditCard::ExpiryDate.new('13', '2009') assert_equal 13, expiry.month assert_equal 2009, expiry.year end -end \ No newline at end of file +end diff --git a/test/unit/fixtures_test.rb b/test/unit/fixtures_test.rb index 5f5baa93eb0..b72720d928c 100644 --- a/test/unit/fixtures_test.rb +++ b/test/unit/fixtures_test.rb @@ -2,7 +2,7 @@ class FixturesTest < Test::Unit::TestCase def test_sort - keys = YAML.load(File.read(ActiveMerchant::Fixtures::DEFAULT_CREDENTIALS)).keys + keys = YAML.safe_load(File.read(ActiveMerchant::Fixtures::DEFAULT_CREDENTIALS), [], [], true).keys assert_equal( keys, keys.sort diff --git a/test/unit/gateways/adyen_test.rb b/test/unit/gateways/adyen_test.rb new file mode 100644 index 00000000000..abfdee32e92 --- /dev/null +++ b/test/unit/gateways/adyen_test.rb @@ -0,0 +1,542 @@ +require 'test_helper' + +class AdyenTest < Test::Unit::TestCase + include CommStub + + def setup + @gateway = AdyenGateway.new( + username: 'ws@adyenmerchant.com', + password: 'password', + merchant_account: 'merchantAccount' + ) + + @credit_card = credit_card('4111111111111111', + :month => 8, + :year => 2018, + :first_name => 'Test', + :last_name => 'Card', + :verification_value => '737', + :brand => 'visa' + ) + + @apple_pay_card = network_tokenization_credit_card('4111111111111111', + :payment_cryptogram => 'YwAAAAAABaYcCMX/OhNRQAAAAAA=', + :month => '08', + :year => '2018', + :source => :apple_pay, + :verification_value => nil + ) + + @amount = 100 + + @options = { + billing_address: address(), + shopper_reference: 'John Smith', + order_id: '345123', + installments: 2, + recurring_processing_model: 'CardOnFile' + } + end + + # Subdomains are only valid for production gateways, so the test_url check must be manually bypassed for this test to pass. + # def test_subdomain_specification + # gateway = AdyenGateway.new( + # username: 'ws@adyenmerchant.com', + # password: 'password', + # merchant_account: 'merchantAccount', + # subdomain: '123-subdomain' + # ) + # + # response = stub_comms(gateway) do + # gateway.authorize(@amount, @credit_card, @options) + # end.check_request do |endpoint, data, headers| + # assert_match("https://123-subdomain-pal-live.adyenpayments.com/pal/servlet/Payment/v18/authorise", endpoint) + # end.respond_with(successful_authorize_response) + # + # assert response + # assert_success response + # end + + def test_successful_authorize + @gateway.expects(:ssl_post).returns(successful_authorize_response) + + response = @gateway.authorize(@amount, @credit_card, @options) + assert_success response + + assert_equal '#7914775043909934#', response.authorization + assert_equal 'R', response.avs_result['code'] + assert_equal 'M', response.cvv_result['code'] + assert response.test? + end + + def test_failed_authorize + @gateway.expects(:ssl_post).returns(failed_authorize_response) + + response = @gateway.authorize(@amount, @credit_card, @options) + assert_equal 'Expired Card', response.message + assert_failure response + end + + def test_successful_capture + @gateway.expects(:ssl_post).returns(successful_capture_response) + response = @gateway.capture(@amount, '7914775043909934') + assert_equal '7914775043909934#8814775564188305#', response.authorization + assert_success response + assert response.test? + end + + def test_failed_capture + @gateway.expects(:ssl_post).returns(failed_capture_response) + response = @gateway.capture(nil, '') + assert_nil response.authorization + assert_equal 'Original pspReference required for this operation', response.message + assert_failure response + end + + def test_successful_purchase + response = stub_comms do + @gateway.purchase(@amount, @credit_card, @options) + end.respond_with(successful_authorize_response, successful_capture_response) + assert_success response + assert_equal '7914775043909934#8814775564188305#', response.authorization + assert response.test? + end + + def test_successful_maestro_purchase + response = stub_comms do + @gateway.purchase(@amount, @credit_card, @options.merge({selected_brand: 'maestro', overwrite_brand: 'true'})) + end.check_request do |endpoint, data, headers| + if endpoint =~ /authorise/ + assert_match(/"overwriteBrand":true/, data) + assert_match(/"selectedBrand":"maestro"/, data) + end + end.respond_with(successful_authorize_response, successful_capture_response) + assert_success response + assert_equal '7914775043909934#8814775564188305#', response.authorization + assert response.test? + end + + def test_installments_sent + stub_comms do + @gateway.authorize(@amount, @credit_card, @options) + end.check_request do |endpoint, data, headers| + assert_equal 2, JSON.parse(data)['installments']['value'] + end.respond_with(successful_authorize_response) + end + + def test_custom_routing_sent + stub_comms do + @gateway.authorize(@amount, @credit_card, @options.merge({custom_routing_flag: 'abcdefg'})) + end.check_request do |endpoint, data, headers| + assert_equal 'abcdefg', JSON.parse(data)['additionalData']['customRoutingFlag'] + end.respond_with(successful_authorize_response) + end + + def test_failed_purchase + @gateway.expects(:ssl_post).returns(failed_purchase_response) + + response = @gateway.purchase(@amount, credit_card('400111'), @options) + assert_failure response + + assert_equal AdyenGateway::STANDARD_ERROR_CODE[:incorrect_number], response.error_code + end + + def test_successful_refund + @gateway.expects(:ssl_post).returns(successful_refund_response) + response = @gateway.refund(@amount, '7914775043909934') + assert_equal '7914775043909934#8514775559925128#', response.authorization + assert_equal '[refund-received]', response.message + assert response.test? + end + + def test_successful_refund_with_compound_psp_reference + @gateway.expects(:ssl_post).returns(successful_refund_response) + response = @gateway.refund(@amount, '7914775043909934#8514775559000000') + assert_equal '7914775043909934#8514775559925128#', response.authorization + assert_equal '[refund-received]', response.message + assert response.test? + end + + def test_failed_refund + @gateway.expects(:ssl_post).returns(failed_refund_response) + response = @gateway.refund(@amount, '') + assert_nil response.authorization + assert_equal 'Original pspReference required for this operation', response.message + assert_failure response + end + + def test_successful_void + @gateway.expects(:ssl_post).returns(successful_void_response) + response = @gateway.void('7914775043909934') + assert_equal '7914775043909934#8614775821628806#', response.authorization + assert_equal '[cancel-received]', response.message + assert response.test? + end + + def test_failed_void + @gateway.expects(:ssl_post).returns(failed_void_response) + response = @gateway.void('') + assert_equal 'Original pspReference required for this operation', response.message + assert_failure response + end + + def test_successful_store + response = stub_comms do + @gateway.store(@credit_card, @options) + end.check_request do |endpoint, data, headers| + assert_equal 'CardOnFile', JSON.parse(data)['recurringProcessingModel'] + end.respond_with(successful_store_response) + assert_success response + assert_equal '#8835205392522157#8315202663743702', response.authorization + end + + def test_failed_store + @gateway.expects(:ssl_post).returns(failed_store_response) + response = @gateway.store(@credit_card, @options) + assert_failure response + assert_equal 'Refused', response.message + end + + def test_successful_verify + response = stub_comms do + @gateway.verify(@credit_card, @options) + end.respond_with(successful_verify_response) + assert_success response + assert_equal '#7914776426645103#', response.authorization + assert_equal 'Authorised', response.message + assert response.test? + end + + def test_failed_verify + response = stub_comms do + @gateway.verify(@credit_card, @options) + end.respond_with(failed_verify_response) + assert_failure response + assert_equal '#7914776433387947#', response.authorization + assert_equal 'Refused', response.message + assert response.test? + end + + def test_failed_avs_check_returns_refusal_reason_raw + @gateway.expects(:ssl_post).returns(failed_authorize_avs_response) + + response = @gateway.authorize(@amount, @credit_card, @options) + assert_failure response + assert_equal 'Refused | 05 : Do not honor', response.message + end + + def test_scrub + assert @gateway.supports_scrubbing? + assert_equal @gateway.scrub(pre_scrubbed), post_scrubbed + end + + def test_scrub_network_tokenization_card + assert @gateway.supports_scrubbing? + assert_equal @gateway.scrub(pre_scrubbed), post_scrubbed + end + + def test_add_address + post = {:card => {:billingAddress => {}}} + @options[:billing_address].delete(:address1) + @options[:billing_address].delete(:address2) + @gateway.send(:add_address, post, @options) + assert_equal 'N/A', post[:card][:billingAddress][:street] + assert_equal 'N/A', post[:card][:billingAddress][:houseNumberOrName] + assert_equal @options[:billing_address][:zip], post[:card][:billingAddress][:postalCode] + assert_equal @options[:billing_address][:city], post[:card][:billingAddress][:city] + assert_equal @options[:billing_address][:state], post[:card][:billingAddress][:stateOrProvince] + assert_equal @options[:billing_address][:country], post[:card][:billingAddress][:country] + end + + def test_authorize_with_network_tokenization_credit_card_no_name + @apple_pay_card.first_name = nil + @apple_pay_card.last_name = nil + response = stub_comms do + @gateway.authorize(@amount, @apple_pay_card, @options) + end.check_request do |endpoint, data, headers| + assert_equal 'Not Provided', JSON.parse(data)['card']['holderName'] + end.respond_with(successful_authorize_response) + assert_success response + end + + def test_authorize_with_network_tokenization_credit_card + response = stub_comms do + @gateway.authorize(@amount, @apple_pay_card, @options) + end.check_request do |endpoint, data, headers| + parsed = JSON.parse(data) + assert_equal 'YwAAAAAABaYcCMX/OhNRQAAAAAA=', parsed['mpiData']['cavv'] + assert_equal '07', parsed['mpiData']['eci'] + assert_equal 'applepay', parsed['additionalData']['paymentdatasource.type'] + end.respond_with(successful_authorize_response) + assert_success response + end + + private + + def pre_scrubbed + <<-PRE_SCRUBBED + opening connection to pal-test.adyen.com:443... + opened + starting SSL for pal-test.adyen.com:443... + SSL established + <- "POST /pal/servlet/Payment/v18/authorise HTTP/1.1\r\nContent-Type: application/json\r\nAuthorization: Basic d3NfMTYzMjQ1QENvbXBhbnkuRGFuaWVsYmFra2Vybmw6eXU0aD50ZlxIVEdydSU1PDhxYTVMTkxVUw==\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nAccept: */*\r\nUser-Agent: Ruby\r\nConnection: close\r\nHost: pal-test.adyen.com\r\nContent-Length: 308\r\n\r\n" + <- "{\"merchantAccount\":\"DanielbakkernlNL\",\"reference\":\"345123\",\"amount\":{\"value\":\"100\",\"currency\":\"USD\"},\"card\":{\"expiryMonth\":8,\"expiryYear\":2018,\"holderName\":\"John Smith\",\"number\":\"4111111111111111\",\"cvc\":\"737\"},\"shopperEmail\":\"john.smith@test.com\",\"shopperIP\":\"77.110.174.153\",\"shopperReference\":\"John Smith\"}" + -> "HTTP/1.1 200 OK\r\n" + -> "Date: Thu, 27 Oct 2016 11:37:13 GMT\r\n" + -> "Server: Apache\r\n" + -> "Set-Cookie: JSESSIONID=C0D66C19173B3491D862B8FDBFD72FD7.test3e; Path=/pal/; Secure; HttpOnly\r\n" + -> "pspReference: 8514775682339577\r\n" + -> "Connection: close\r\n" + -> "Transfer-Encoding: chunked\r\n" + -> "Content-Type: application/json;charset=utf-8\r\n" + -> "\r\n" + -> "50\r\n" + reading 80 bytes... + -> "" + -> "{\"pspReference\":\"8514775682339577\",\"resultCode\":\"Authorised\",\"authCode\":\"31845\"}" + read 80 bytes + reading 2 bytes... + -> "" + -> "\r\n" + read 2 bytes + -> "0\r\n" + -> "\r\n" + Conn close + PRE_SCRUBBED + end + + def post_scrubbed + <<-POST_SCRUBBED + opening connection to pal-test.adyen.com:443... + opened + starting SSL for pal-test.adyen.com:443... + SSL established + <- "POST /pal/servlet/Payment/v18/authorise HTTP/1.1\r\nContent-Type: application/json\r\nAuthorization: Basic [FILTERED]==\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nAccept: */*\r\nUser-Agent: Ruby\r\nConnection: close\r\nHost: pal-test.adyen.com\r\nContent-Length: 308\r\n\r\n" + <- "{\"merchantAccount\":\"DanielbakkernlNL\",\"reference\":\"345123\",\"amount\":{\"value\":\"100\",\"currency\":\"USD\"},\"card\":{\"expiryMonth\":8,\"expiryYear\":2018,\"holderName\":\"John Smith\",\"number\":\"[FILTERED]\",\"cvc\":\"[FILTERED]\"},\"shopperEmail\":\"john.smith@test.com\",\"shopperIP\":\"77.110.174.153\",\"shopperReference\":\"John Smith\"}" + -> "HTTP/1.1 200 OK\r\n" + -> "Date: Thu, 27 Oct 2016 11:37:13 GMT\r\n" + -> "Server: Apache\r\n" + -> "Set-Cookie: JSESSIONID=C0D66C19173B3491D862B8FDBFD72FD7.test3e; Path=/pal/; Secure; HttpOnly\r\n" + -> "pspReference: 8514775682339577\r\n" + -> "Connection: close\r\n" + -> "Transfer-Encoding: chunked\r\n" + -> "Content-Type: application/json;charset=utf-8\r\n" + -> "\r\n" + -> "50\r\n" + reading 80 bytes... + -> "" + -> "{\"pspReference\":\"8514775682339577\",\"resultCode\":\"Authorised\",\"authCode\":\"31845\"}" + read 80 bytes + reading 2 bytes... + -> "" + -> "\r\n" + read 2 bytes + -> "0\r\n" + -> "\r\n" + Conn close + POST_SCRUBBED + end + + def pre_scrubbed_network_tokenization_card + <<-PRE_SCRUBBED + opening connection to pal-test.adyen.com:443... + opened + starting SSL for pal-test.adyen.com:443... + SSL established + I, [2018-06-18T11:53:47.394267 #25363] INFO -- : [ActiveMerchant::Billing::AdyenGateway] connection_ssl_version=TLSv1.2 connection_ssl_cipher=ECDHE-RSA-AES128-GCM-SHA256 + D, [2018-06-18T11:53:47.394346 #25363] DEBUG -- : {"merchantAccount":"SpreedlyCOM294","reference":"123","amount":{"value":"100","currency":"USD"},"mpiData":{"authenticationResponse":"Y","cavv":"YwAAAAAABaYcCMX/OhNRQAAAAAA=","directoryResponse":"Y","eci":"07"},"card":{"expiryMonth":8,"expiryYear":2018,"holderName":"Longbob Longsen","number":"4111111111111111","billingAddress":{"street":"456 My Street","houseNumberOrName":"Apt 1","postalCode":"K1C2N6","city":"Ottawa","stateOrProvince":"ON","country":"CA"}},"shopperEmail":"john.smith@test.com","shopperIP":"77.110.174.153","shopperReference":"John Smith","selectedBrand":"applepay","shopperInteraction":"Ecommerce"} + <- "POST /pal/servlet/Payment/v18/authorise HTTP/1.1\r\nContent-Type: application/json\r\nAuthorization: Basic d3NAQ29tcGFueS5TcHJlZWRseTQ3MTo3c3d6U0p2R1VWViUvP3Q0Uy9bOVtoc0hF\r\nConnection: close\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nAccept: */*\r\nUser-Agent: Ruby\r\nHost: pal-test.adyen.com\r\nContent-Length: 618\r\n\r\n" + <- "{\"merchantAccount\":\"SpreedlyCOM294\",\"reference\":\"123\",\"amount\":{\"value\":\"100\",\"currency\":\"USD\"},\"mpiData\":{\"authenticationResponse\":\"Y\",\"cavv\":\"YwAAAAAABaYcCMX/OhNRQAAAAAA=\",\"directoryResponse\":\"Y\",\"eci\":\"07\"},\"card\":{\"expiryMonth\":8,\"expiryYear\":2018,\"holderName\":\"Longbob Longsen\",\"number\":\"4111111111111111\",\"billingAddress\":{\"street\":\"456 My Street\",\"houseNumberOrName\":\"Apt 1\",\"postalCode\":\"K1C2N6\",\"city\":\"Ottawa\",\"stateOrProvince\":\"ON\",\"country\":\"CA\"}},\"shopperEmail\":\"john.smith@test.com\",\"shopperIP\":\"77.110.174.153\",\"shopperReference\":\"John Smith\",\"selectedBrand\":\"applepay\",\"shopperInteraction\":\"Ecommerce\"}" + -> "HTTP/1.1 200 OK\r\n" + -> "Date: Mon, 18 Jun 2018 15:53:47 GMT\r\n" + -> "Server: Apache\r\n" + -> "Set-Cookie: JSESSIONID=06EE78291B761A33ED9E21E46BA54649.test104e; Path=/pal; Secure; HttpOnly\r\n" + -> "pspReference: 8835293372276408\r\n" + -> "Connection: close\r\n" + -> "Transfer-Encoding: chunked\r\n" + -> "Content-Type: application/json;charset=utf-8\r\n" + -> "\r\n" + -> "50\r\n" + reading 80 bytes... + -> "" + -> "{\"pspReference\":\"8835293372276408\",\"resultCode\":\"Authorised\",\"authCode\":\"26056\"}" + read 80 bytes + reading 2 bytes... + -> "" + -> "\r\n" + read 2 bytes + -> "0\r\n" + -> "\r\n" + Conn close + PRE_SCRUBBED + end + + def post_scrubbed_network_tokenization_card + <<-POST_SCRUBBED + opening connection to pal-test.adyen.com:443... + opened + starting SSL for pal-test.adyen.com:443... + SSL established + I, [2018-06-18T11:53:47.394267 #25363] INFO -- : [ActiveMerchant::Billing::AdyenGateway] connection_ssl_version=TLSv1.2 connection_ssl_cipher=ECDHE-RSA-AES128-GCM-SHA256 + D, [2018-06-18T11:53:47.394346 #25363] DEBUG -- : {"merchantAccount":"SpreedlyCOM294","reference":"123","amount":{"value":"100","currency":"USD"},"mpiData":{"authenticationResponse":"Y","cavv":"[FILTERED]","directoryResponse":"Y","eci":"07"},"card":{"expiryMonth":8,"expiryYear":2018,"holderName":"Longbob Longsen","number":"[FILTERED]","billingAddress":{"street":"456 My Street","houseNumberOrName":"Apt 1","postalCode":"K1C2N6","city":"Ottawa","stateOrProvince":"ON","country":"CA"}},"shopperEmail":"john.smith@test.com","shopperIP":"77.110.174.153","shopperReference":"John Smith","selectedBrand":"applepay","shopperInteraction":"Ecommerce"} + <- "POST /pal/servlet/Payment/v18/authorise HTTP/1.1\r\nContent-Type: application/json\r\nAuthorization: Basic [FILTERED]\r\nConnection: close\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nAccept: */*\r\nUser-Agent: Ruby\r\nHost: pal-test.adyen.com\r\nContent-Length: 618\r\n\r\n" + <- "{\"merchantAccount\":\"SpreedlyCOM294\",\"reference\":\"123\",\"amount\":{\"value\":\"100\",\"currency\":\"USD\"},\"mpiData\":{\"authenticationResponse\":\"Y\",\"cavv\":\"[FILTERED]\",\"directoryResponse\":\"Y\",\"eci\":\"07\"},\"card\":{\"expiryMonth\":8,\"expiryYear\":2018,\"holderName\":\"Longbob Longsen\",\"number\":\"[FILTERED]\",\"billingAddress\":{\"street\":\"456 My Street\",\"houseNumberOrName\":\"Apt 1\",\"postalCode\":\"K1C2N6\",\"city\":\"Ottawa\",\"stateOrProvince\":\"ON\",\"country\":\"CA\"}},\"shopperEmail\":\"john.smith@test.com\",\"shopperIP\":\"77.110.174.153\",\"shopperReference\":\"John Smith\",\"selectedBrand\":\"applepay\",\"shopperInteraction\":\"Ecommerce\"}" + -> "HTTP/1.1 200 OK\r\n" + -> "Date: Mon, 18 Jun 2018 15:53:47 GMT\r\n" + -> "Server: Apache\r\n" + -> "Set-Cookie: JSESSIONID=06EE78291B761A33ED9E21E46BA54649.test104e; Path=/pal; Secure; HttpOnly\r\n" + -> "pspReference: 8835293372276408\r\n" + -> "Connection: close\r\n" + -> "Transfer-Encoding: chunked\r\n" + -> "Content-Type: application/json;charset=utf-8\r\n" + -> "\r\n" + -> "50\r\n" + reading 80 bytes... + -> "" + -> "{\"pspReference\":\"8835293372276408\",\"resultCode\":\"Authorised\",\"authCode\":\"26056\"}" + read 80 bytes + reading 2 bytes... + -> "" + -> "\r\n" + read 2 bytes + -> "0\r\n" + -> "\r\n" + Conn close + POST_SCRUBBED + end + + def failed_purchase_response + <<-RESPONSE + { + "status": 422, + "errorCode": "101", + "message": "Invalid card number", + "errorType": "validation", + "pspReference": "8514775645144049" + } + RESPONSE + end + + def successful_authorize_response + <<-RESPONSE + { + "additionalData": { + "cvcResult": "1 Matches", + "avsResult": "0 Unknown", + "cvcResultRaw": "M" + }, + "pspReference":"7914775043909934", + "resultCode":"Authorised", + "authCode":"50055" + } + RESPONSE + end + + def failed_authorize_response + <<-RESPONSE + { + "pspReference": "8514775559925128", + "refusalReason": "Expired Card", + "resultCode": "Refused" + } + RESPONSE + end + + def successful_capture_response + <<-RESPONSE + { + "pspReference": "8814775564188305", + "response": "[capture-received]" + } + RESPONSE + end + + def failed_capture_response + <<-RESPONSE + { + "status": 422, + "errorCode": "167", + "message": "Original pspReference required for this operation", + "errorType": "validation" + } + RESPONSE + end + + def successful_refund_response + <<-RESPONSE + { + "pspReference": "8514775559925128", + "response": "[refund-received]" + } + RESPONSE + end + + def failed_refund_response + <<-RESPONSE + { + "status":422, + "errorCode":"167", + "message":"Original pspReference required for this operation", + "errorType":"validation" + } + RESPONSE + end + + def successful_void_response + <<-RESPONSE + { + "pspReference":"8614775821628806", + "response":"[cancel-received]" + } + RESPONSE + end + + def failed_void_response + <<-RESPONSE + { + "status":422, + "errorCode":"167", + "message":"Original pspReference required for this operation", + "errorType":"validation" + } + RESPONSE + end + + def successful_verify_response + <<-RESPONSE + { + "pspReference":"7914776426645103", + "resultCode":"Authorised", + "authCode":"31265" + } + RESPONSE + end + + def failed_verify_response + <<-RESPONSE + { + "pspReference":"7914776433387947", + "refusalReason":"Refused", + "resultCode":"Refused" + } + RESPONSE + end + + def failed_authorize_avs_response + <<-RESPONSE + {\"additionalData\":{\"cvcResult\":\"0 Unknown\",\"fraudResultType\":\"GREEN\",\"avsResult\":\"3 AVS unavailable\",\"fraudManualReview\":\"false\",\"avsResultRaw\":\"U\",\"refusalReasonRaw\":\"05 : Do not honor\",\"authorisationMid\":\"494619000001174\",\"acquirerCode\":\"AdyenVisa_BR_494619\",\"acquirerReference\":\"802320302458\",\"acquirerAccountCode\":\"AdyenVisa_BR_Cabify\"},\"fraudResult\":{\"accountScore\":0,\"results\":[{\"FraudCheckResult\":{\"accountScore\":0,\"checkId\":46,\"name\":\"DistinctCountryUsageByShopper\"}}]},\"pspReference\":\"1715167376763498\",\"refusalReason\":\"Refused\",\"resultCode\":\"Refused\"} + RESPONSE + end + + def successful_store_response + <<-RESPONSE + {"additionalData":{"recurring.recurringDetailReference":"8315202663743702","recurring.shopperReference":"John Smith"},"pspReference":"8835205392522157","resultCode":"Authorised","authCode":"94571"} + RESPONSE + end + + def failed_store_response + <<-RESPONSE + {"pspReference":"8835205393394754","refusalReason":"Refused","resultCode":"Refused"} + RESPONSE + end +end diff --git a/test/unit/gateways/allied_wallet_test.rb b/test/unit/gateways/allied_wallet_test.rb index ec45ec0f918..fb291c7c4b4 100644 --- a/test/unit/gateways/allied_wallet_test.rb +++ b/test/unit/gateways/allied_wallet_test.rb @@ -3,354 +3,352 @@ class AlliedWalletTest < Test::Unit::TestCase include CommStub - def setup - @gateway = AlliedWalletGateway.new( - site_id: "1234", - merchant_id: "1234", - token: "token" - ) - - @credit_card = credit_card - @amount = 100 - end - - def test_successful_purchase - response = stub_comms do - @gateway.purchase(@amount, @credit_card) - end.respond_with(successful_purchase_response) - - assert_success response - - assert_equal "123456", response.authorization - assert response.test? - end - - def test_failed_purchase - response = stub_comms do - @gateway.purchase(@amount, @credit_card) - end.respond_with(failed_purchase_response) - - assert_failure response - assert_equal "Declined", response.message - assert response.test? - end - - def test_successful_authorize_and_capture - response = stub_comms do - @gateway.authorize(@amount, @credit_card) - end.respond_with(successful_authorize_response) - - assert_success response - assert_equal "123456", response.authorization - - capture = stub_comms do - @gateway.capture(@amount, response.authorization) - end.respond_with(successful_capture_response) - - assert_success capture - end - - def test_failed_authorize - response = stub_comms do - @gateway.authorize(@amount, @credit_card) - end.respond_with(failed_authorize_response) - - assert_failure response - assert_equal "Declined", response.message - assert response.test? - end - - def test_failed_capture - response = stub_comms do - @gateway.capture(100, "") - end.respond_with(failed_capture_response) - - assert_failure response - end - - def test_successful_void - response = stub_comms do - @gateway.purchase(@amount, @credit_card) - end.respond_with(successful_authorize_response) - - assert_success response - assert_equal "123456", response.authorization - - void = stub_comms do - @gateway.void(response.authorization) - end.check_request do |endpoint, data, headers| - assert_match(/123456/, data) - end.respond_with(successful_void_response) - - assert_success void - end - - def test_failed_void - response = stub_comms do - @gateway.void("5d53a33d960c46d00f5dc061947d998c") - end.check_request do |endpoint, data, headers| - assert_match(/5d53a33d960c46d00f5dc061947d998c/, data) - end.respond_with(failed_void_response) - - assert_failure response - end - - def test_successful_refund - response = stub_comms do - @gateway.purchase(@amount, @credit_card) - end.respond_with(successful_purchase_response) - - assert_success response - assert_equal "123456", response.authorization - - refund = stub_comms do - @gateway.refund(@amount, response.authorization) - end.check_request do |endpoint, data, headers| - assert_match(/123456/, data) - end.respond_with(successful_refund_response) - - assert_success refund - end - - def test_failed_refund - response = stub_comms do - @gateway.refund(nil, "") - end.respond_with(failed_refund_response) - - assert_failure response - end - - def test_successful_verify - response = stub_comms do - @gateway.verify(@credit_card) - end.respond_with(successful_authorize_response, failed_void_response) - assert_success response - assert_equal "Succeeded", response.message - end - - def test_failed_verify - response = stub_comms do - @gateway.verify(@credit_card) - end.respond_with(failed_authorize_response, successful_void_response) - assert_failure response - assert_equal "Declined", response.message - end - - def test_empty_response_fails - response = stub_comms do - @gateway.purchase(@amount, @credit_card) - end.respond_with(empty_purchase_response) - - assert_failure response - assert_equal "Error", response.message - end - - def test_invalid_json - response = stub_comms do - @gateway.purchase(@amount, @credit_card) - end.respond_with(invalid_json_response) - - assert_failure response - assert_match %r{Unparsable response}, response.message - end - - def test_transcript_scrubbing - assert_equal scrubbed_transcript, @gateway.scrub(transcript) - end - - def test_nil_cvv_transcript_scrubbing - assert_equal nil_cvv_scrubbed_transcript, @gateway.scrub(nil_cvv_transcript) - end - - def test_empty_string_cvv_transcript_scrubbing - assert_equal empty_string_cvv_scrubbed_transcript, @gateway.scrub(empty_string_cvv_transcript) - end - - private - - def successful_purchase_response - %( - { - "id": "123456", - "message": "Success", - "state": "Sale", - "status": "Successful" - } - ) - end - - def failed_purchase_response - %( - { - "id": "123456", - "message": "Declined", - "state": "Sale", - "status": "Declined" - } - ) - end - - def successful_authorize_response - %( - { - "id": "123456", - "message": "Success", - "state": "Authorize", - "status": "Successful" - } - ) - end - - def failed_authorize_response - %( - { - "id": "123456", - "message": "Declined", - "state": "Authorize", - "status": "Declined" - } - ) - end - - def successful_capture_response - %( - { - "id": "123456", - "message": "Successful", - "state": "Capture", - "status": "Successful" - } - ) - end - - def failed_capture_response - %( - { - "id": "123456", - "message": "Declined", - "state": "Capture", - "status": "Declined" - } - ) - end - - def successful_void_response - %( - { - "id": "123456", - "message": "Success", - "state": "Void", - "status": "Successful" - } - ) - end - - def failed_void_response - %( - { - "id": "123456", - "message": "Error", - "state": "Void", - "status": "Error" - } - ) - end - - def successful_refund_response - %( - { - "id": "123456", - "message": "Success", - "state": "Refund", - "status": "Successful" - } - ) - end - - def failed_refund_response - %( - { - "id": "123456", - "message": "Error", - "state": "Refund", - "status": "Error" - } - ) - end - - - def empty_purchase_response - %( - { - "id": "123456", - "message": "Error", - "state": "Purchase", - "status": "Error" - } - ) - end - - def invalid_json_response - %( - { - "id": "123456", - ) - end - - - def transcript - %( - <- "POST /merchants/10090/SALEtransactions HTTP/1.1\r\nContent-Type: application/json\r\nAuthorization: Bearer AAEAAHwXaLTYs2APKJW_4TpTDwCw_h9oDx9rA58FR78AFuYCX82Izes1nz9qGBXELGUN_EukKcP5T78Th5guDz4Rw5dQ4Gf0suKw7pz9vWrqa1NpZhrD9Lj9T-SFtOJgfodiwVaBBeSgbJLKA7MOzC9q2dv91HBNP69DygL1oX2L2mtt8fWlKSWhQmtG040E1I43jTueX3L3L9YA7iO6pIwO7CGybE5LnjkQ65KB2K4oYKfXRZosF77hgMJIh-KprFy9cYY3EjfupHeLon9im1BGafrda2N5wj_A_LvdMzfLAD1l1dgj82KlvM_gAzNJ4S19gAicRo9zIbsq36Apt-8jFjS0AQAAAAEAAA9Zr_lVLKMmmtKSo6T_9ulzMCRbYs798EpFD2wMlkb1NCQtA65VrNcM20Ka2FjNQfwOcSMWqDl9zFQhPyFl-npsG1Ww2oyyavA6HSe1HLRLtE_1hNBAlTBPQnLJ6hBf8eR_NTiVa-aQdV2l92-eSwCS59CzrOYGGCY1pLdNMDr_r66kg9l-l94154kRoMBRQSCqZV9iM9M-f3adLJqG6Q79zz1oJpGrH-Zv1kuv8eLaJJNOEFYARb0JbnAC5G1l9-aqxGvBrNkd4sAJIe23XrRx2XJCBIABxuGSQ1xJBTINVlXBXq1mvvd8B1uiYiDNia3c_vIGuSGIjZE0VbUN3oJppfCt1joGdePeUaC2Pyb2vuUN00EBEOaD9RF8IBWMLVJaF9cW2OewDOfBQg94MuOKLdXB_IisRx1ed25VQDVyv0f0CxmkAidvoDN0vvRIJZJr-bgBuL5FZM7gETAeYeiGlh7-Mf2Hzgy7236YNxcC9OnWFEcKEU50nlqog1bJnk8wJgoJWNqG0NUEK4DUzYqknmZ98qQv6rYrg5V-Hey-jAQp_KNf3h-vFHVZdP26Yg\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nAccept: */*\r\nUser-Agent: Ruby\r\nConnection: close\r\nHost: api.alliedwallet.com\r\nContent-Length: 464\r\n\r\n" - <- "{\"siteId\":\"10118\",\"amount\":\"1.00\",\"trackingId\":\"82b5f6217fa19daa426e226a231d330a\",\"currency\":\"USD\",\"nameOnCard\":\"Longbob Longsen\",\"cardNumber\":\"4242424242424242\",\"cVVCode\":\"123\",\"expirationYear\":\"2016\",\"expirationMonth\":\"09\",\"email\":\"jim_smith@example.com\",\"iPAddress\":\"127.0.0.1\",\"firstName\":\"Jim\",\"lastName\":\"Smith\",\"addressLine1\":\"456 My Street\",\"addressLine2\":\"Apt 1\",\"city\":\"Ottawa\",\"state\":\"ON\",\"countryId\":\"CA\",\"postalCode\":\"K1C2N6\",\"phone\":\"(555)555-5555\"}" - ) - end - - def scrubbed_transcript - %( - <- "POST /merchants/10090/SALEtransactions HTTP/1.1\r\nContent-Type: application/json\r\nAuthorization: Bearer [FILTERED]\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nAccept: */*\r\nUser-Agent: Ruby\r\nConnection: close\r\nHost: api.alliedwallet.com\r\nContent-Length: 464\r\n\r\n" - <- "{\"siteId\":\"10118\",\"amount\":\"1.00\",\"trackingId\":\"82b5f6217fa19daa426e226a231d330a\",\"currency\":\"USD\",\"nameOnCard\":\"Longbob Longsen\",\"cardNumber\":\"[FILTERED]\",\"cVVCode\":\"[FILTERED]\",\"expirationYear\":\"2016\",\"expirationMonth\":\"09\",\"email\":\"jim_smith@example.com\",\"iPAddress\":\"127.0.0.1\",\"firstName\":\"Jim\",\"lastName\":\"Smith\",\"addressLine1\":\"456 My Street\",\"addressLine2\":\"Apt 1\",\"city\":\"Ottawa\",\"state\":\"ON\",\"countryId\":\"CA\",\"postalCode\":\"K1C2N6\",\"phone\":\"(555)555-5555\"}" - ) - end - - def nil_cvv_transcript - %( - <- "POST /merchants/10090/SALEtransactions HTTP/1.1\r\nContent-Type: application/json\r\nAuthorization: Bearer AAEAAHwXaLTYs2APKJW_4TpTDwCw_h9oDx9rA58FR78AFuYCX82Izes1nz9qGBXELGUN_EukKcP5T78Th5guDz4Rw5dQ4Gf0suKw7pz9vWrqa1NpZhrD9Lj9T-SFtOJgfodiwVaBBeSgbJLKA7MOzC9q2dv91HBNP69DygL1oX2L2mtt8fWlKSWhQmtG040E1I43jTueX3L3L9YA7iO6pIwO7CGybE5LnjkQ65KB2K4oYKfXRZosF77hgMJIh-KprFy9cYY3EjfupHeLon9im1BGafrda2N5wj_A_LvdMzfLAD1l1dgj82KlvM_gAzNJ4S19gAicRo9zIbsq36Apt-8jFjS0AQAAAAEAAA9Zr_lVLKMmmtKSo6T_9ulzMCRbYs798EpFD2wMlkb1NCQtA65VrNcM20Ka2FjNQfwOcSMWqDl9zFQhPyFl-npsG1Ww2oyyavA6HSe1HLRLtE_1hNBAlTBPQnLJ6hBf8eR_NTiVa-aQdV2l92-eSwCS59CzrOYGGCY1pLdNMDr_r66kg9l-l94154kRoMBRQSCqZV9iM9M-f3adLJqG6Q79zz1oJpGrH-Zv1kuv8eLaJJNOEFYARb0JbnAC5G1l9-aqxGvBrNkd4sAJIe23XrRx2XJCBIABxuGSQ1xJBTINVlXBXq1mvvd8B1uiYiDNia3c_vIGuSGIjZE0VbUN3oJppfCt1joGdePeUaC2Pyb2vuUN00EBEOaD9RF8IBWMLVJaF9cW2OewDOfBQg94MuOKLdXB_IisRx1ed25VQDVyv0f0CxmkAidvoDN0vvRIJZJr-bgBuL5FZM7gETAeYeiGlh7-Mf2Hzgy7236YNxcC9OnWFEcKEU50nlqog1bJnk8wJgoJWNqG0NUEK4DUzYqknmZ98qQv6rYrg5V-Hey-jAQp_KNf3h-vFHVZdP26Yg\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nAccept: */*\r\nUser-Agent: Ruby\r\nConnection: close\r\nHost: api.alliedwallet.com\r\nContent-Length: 464\r\n\r\n" - <- "{\"siteId\":\"10118\",\"amount\":\"1.00\",\"trackingId\":\"82b5f6217fa19daa426e226a231d330a\",\"currency\":\"USD\",\"nameOnCard\":\"Longbob Longsen\",\"cardNumber\":\"4242424242424242\",\"cVVCode\":null,\"expirationYear\":\"2016\",\"expirationMonth\":\"09\",\"email\":\"jim_smith@example.com\",\"iPAddress\":\"127.0.0.1\",\"firstName\":\"Jim\",\"lastName\":\"Smith\",\"addressLine1\":\"456 My Street\",\"addressLine2\":\"Apt 1\",\"city\":\"Ottawa\",\"state\":\"ON\",\"countryId\":\"CA\",\"postalCode\":\"K1C2N6\",\"phone\":\"(555)555-5555\"}" - ) - end - - def nil_cvv_scrubbed_transcript - %( - <- "POST /merchants/10090/SALEtransactions HTTP/1.1\r\nContent-Type: application/json\r\nAuthorization: Bearer [FILTERED]\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nAccept: */*\r\nUser-Agent: Ruby\r\nConnection: close\r\nHost: api.alliedwallet.com\r\nContent-Length: 464\r\n\r\n" - <- "{\"siteId\":\"10118\",\"amount\":\"1.00\",\"trackingId\":\"82b5f6217fa19daa426e226a231d330a\",\"currency\":\"USD\",\"nameOnCard\":\"Longbob Longsen\",\"cardNumber\":\"[FILTERED]\",\"cVVCode\":[BLANK],\"expirationYear\":\"2016\",\"expirationMonth\":\"09\",\"email\":\"jim_smith@example.com\",\"iPAddress\":\"127.0.0.1\",\"firstName\":\"Jim\",\"lastName\":\"Smith\",\"addressLine1\":\"456 My Street\",\"addressLine2\":\"Apt 1\",\"city\":\"Ottawa\",\"state\":\"ON\",\"countryId\":\"CA\",\"postalCode\":\"K1C2N6\",\"phone\":\"(555)555-5555\"}" - ) - end - - def empty_string_cvv_transcript - %( - <- "POST /merchants/10090/SALEtransactions HTTP/1.1\r\nContent-Type: application/json\r\nAuthorization: Bearer AAEAAHwXaLTYs2APKJW_4TpTDwCw_h9oDx9rA58FR78AFuYCX82Izes1nz9qGBXELGUN_EukKcP5T78Th5guDz4Rw5dQ4Gf0suKw7pz9vWrqa1NpZhrD9Lj9T-SFtOJgfodiwVaBBeSgbJLKA7MOzC9q2dv91HBNP69DygL1oX2L2mtt8fWlKSWhQmtG040E1I43jTueX3L3L9YA7iO6pIwO7CGybE5LnjkQ65KB2K4oYKfXRZosF77hgMJIh-KprFy9cYY3EjfupHeLon9im1BGafrda2N5wj_A_LvdMzfLAD1l1dgj82KlvM_gAzNJ4S19gAicRo9zIbsq36Apt-8jFjS0AQAAAAEAAA9Zr_lVLKMmmtKSo6T_9ulzMCRbYs798EpFD2wMlkb1NCQtA65VrNcM20Ka2FjNQfwOcSMWqDl9zFQhPyFl-npsG1Ww2oyyavA6HSe1HLRLtE_1hNBAlTBPQnLJ6hBf8eR_NTiVa-aQdV2l92-eSwCS59CzrOYGGCY1pLdNMDr_r66kg9l-l94154kRoMBRQSCqZV9iM9M-f3adLJqG6Q79zz1oJpGrH-Zv1kuv8eLaJJNOEFYARb0JbnAC5G1l9-aqxGvBrNkd4sAJIe23XrRx2XJCBIABxuGSQ1xJBTINVlXBXq1mvvd8B1uiYiDNia3c_vIGuSGIjZE0VbUN3oJppfCt1joGdePeUaC2Pyb2vuUN00EBEOaD9RF8IBWMLVJaF9cW2OewDOfBQg94MuOKLdXB_IisRx1ed25VQDVyv0f0CxmkAidvoDN0vvRIJZJr-bgBuL5FZM7gETAeYeiGlh7-Mf2Hzgy7236YNxcC9OnWFEcKEU50nlqog1bJnk8wJgoJWNqG0NUEK4DUzYqknmZ98qQv6rYrg5V-Hey-jAQp_KNf3h-vFHVZdP26Yg\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nAccept: */*\r\nUser-Agent: Ruby\r\nConnection: close\r\nHost: api.alliedwallet.com\r\nContent-Length: 464\r\n\r\n" - <- "{\"siteId\":\"10118\",\"amount\":\"1.00\",\"trackingId\":\"82b5f6217fa19daa426e226a231d330a\",\"currency\":\"USD\",\"nameOnCard\":\"Longbob Longsen\",\"cardNumber\":\"4242424242424242\",\"cVVCode\":\"\",\"expirationYear\":\"2016\",\"expirationMonth\":\"09\",\"email\":\"jim_smith@example.com\",\"iPAddress\":\"127.0.0.1\",\"firstName\":\"Jim\",\"lastName\":\"Smith\",\"addressLine1\":\"456 My Street\",\"addressLine2\":\"Apt 1\",\"city\":\"Ottawa\",\"state\":\"ON\",\"countryId\":\"CA\",\"postalCode\":\"K1C2N6\",\"phone\":\"(555)555-5555\"}" - ) - end - - def empty_string_cvv_scrubbed_transcript - %( - <- "POST /merchants/10090/SALEtransactions HTTP/1.1\r\nContent-Type: application/json\r\nAuthorization: Bearer [FILTERED]\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nAccept: */*\r\nUser-Agent: Ruby\r\nConnection: close\r\nHost: api.alliedwallet.com\r\nContent-Length: 464\r\n\r\n" - <- "{\"siteId\":\"10118\",\"amount\":\"1.00\",\"trackingId\":\"82b5f6217fa19daa426e226a231d330a\",\"currency\":\"USD\",\"nameOnCard\":\"Longbob Longsen\",\"cardNumber\":\"[FILTERED]\",\"cVVCode\":\"[BLANK]\",\"expirationYear\":\"2016\",\"expirationMonth\":\"09\",\"email\":\"jim_smith@example.com\",\"iPAddress\":\"127.0.0.1\",\"firstName\":\"Jim\",\"lastName\":\"Smith\",\"addressLine1\":\"456 My Street\",\"addressLine2\":\"Apt 1\",\"city\":\"Ottawa\",\"state\":\"ON\",\"countryId\":\"CA\",\"postalCode\":\"K1C2N6\",\"phone\":\"(555)555-5555\"}" - ) - end - - def whitespace_string_cvv_transcript - %( - <- "POST /merchants/10090/SALEtransactions HTTP/1.1\r\nContent-Type: application/json\r\nAuthorization: Bearer AAEAAHwXaLTYs2APKJW_4TpTDwCw_h9oDx9rA58FR78AFuYCX82Izes1nz9qGBXELGUN_EukKcP5T78Th5guDz4Rw5dQ4Gf0suKw7pz9vWrqa1NpZhrD9Lj9T-SFtOJgfodiwVaBBeSgbJLKA7MOzC9q2dv91HBNP69DygL1oX2L2mtt8fWlKSWhQmtG040E1I43jTueX3L3L9YA7iO6pIwO7CGybE5LnjkQ65KB2K4oYKfXRZosF77hgMJIh-KprFy9cYY3EjfupHeLon9im1BGafrda2N5wj_A_LvdMzfLAD1l1dgj82KlvM_gAzNJ4S19gAicRo9zIbsq36Apt-8jFjS0AQAAAAEAAA9Zr_lVLKMmmtKSo6T_9ulzMCRbYs798EpFD2wMlkb1NCQtA65VrNcM20Ka2FjNQfwOcSMWqDl9zFQhPyFl-npsG1Ww2oyyavA6HSe1HLRLtE_1hNBAlTBPQnLJ6hBf8eR_NTiVa-aQdV2l92-eSwCS59CzrOYGGCY1pLdNMDr_r66kg9l-l94154kRoMBRQSCqZV9iM9M-f3adLJqG6Q79zz1oJpGrH-Zv1kuv8eLaJJNOEFYARb0JbnAC5G1l9-aqxGvBrNkd4sAJIe23XrRx2XJCBIABxuGSQ1xJBTINVlXBXq1mvvd8B1uiYiDNia3c_vIGuSGIjZE0VbUN3oJppfCt1joGdePeUaC2Pyb2vuUN00EBEOaD9RF8IBWMLVJaF9cW2OewDOfBQg94MuOKLdXB_IisRx1ed25VQDVyv0f0CxmkAidvoDN0vvRIJZJr-bgBuL5FZM7gETAeYeiGlh7-Mf2Hzgy7236YNxcC9OnWFEcKEU50nlqog1bJnk8wJgoJWNqG0NUEK4DUzYqknmZ98qQv6rYrg5V-Hey-jAQp_KNf3h-vFHVZdP26Yg\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nAccept: */*\r\nUser-Agent: Ruby\r\nConnection: close\r\nHost: api.alliedwallet.com\r\nContent-Length: 464\r\n\r\n" - <- "{\"siteId\":\"10118\",\"amount\":\"1.00\",\"trackingId\":\"82b5f6217fa19daa426e226a231d330a\",\"currency\":\"USD\",\"nameOnCard\":\"Longbob Longsen\",\"cardNumber\":\"4242424242424242\",\"cVVCode\":\" \",\"expirationYear\":\"2016\",\"expirationMonth\":\"09\",\"email\":\"jim_smith@example.com\",\"iPAddress\":\"127.0.0.1\",\"firstName\":\"Jim\",\"lastName\":\"Smith\",\"addressLine1\":\"456 My Street\",\"addressLine2\":\"Apt 1\",\"city\":\"Ottawa\",\"state\":\"ON\",\"countryId\":\"CA\",\"postalCode\":\"K1C2N6\",\"phone\":\"(555)555-5555\"}" - ) - end - - def whitespace_string_cvv_scrubbed_transcript - %( - <- "POST /merchants/10090/SALEtransactions HTTP/1.1\r\nContent-Type: application/json\r\nAuthorization: Bearer [FILTERED]\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nAccept: */*\r\nUser-Agent: Ruby\r\nConnection: close\r\nHost: api.alliedwallet.com\r\nContent-Length: 464\r\n\r\n" - <- "{\"siteId\":\"10118\",\"amount\":\"1.00\",\"trackingId\":\"82b5f6217fa19daa426e226a231d330a\",\"currency\":\"USD\",\"nameOnCard\":\"Longbob Longsen\",\"cardNumber\":\"[FILTERED]\",\"cVVCode\":\"[BLANK]\",\"expirationYear\":\"2016\",\"expirationMonth\":\"09\",\"email\":\"jim_smith@example.com\",\"iPAddress\":\"127.0.0.1\",\"firstName\":\"Jim\",\"lastName\":\"Smith\",\"addressLine1\":\"456 My Street\",\"addressLine2\":\"Apt 1\",\"city\":\"Ottawa\",\"state\":\"ON\",\"countryId\":\"CA\",\"postalCode\":\"K1C2N6\",\"phone\":\"(555)555-5555\"}" - ) - end + def setup + @gateway = AlliedWalletGateway.new( + site_id: '1234', + merchant_id: '1234', + token: 'token' + ) + + @credit_card = credit_card + @amount = 100 + end + + def test_successful_purchase + response = stub_comms do + @gateway.purchase(@amount, @credit_card) + end.respond_with(successful_purchase_response) + + assert_success response + + assert_equal '123456', response.authorization + assert response.test? + end + + def test_failed_purchase + response = stub_comms do + @gateway.purchase(@amount, @credit_card) + end.respond_with(failed_purchase_response) + + assert_failure response + assert_equal 'Declined', response.message + assert response.test? + end + + def test_successful_authorize_and_capture + response = stub_comms do + @gateway.authorize(@amount, @credit_card) + end.respond_with(successful_authorize_response) + + assert_success response + assert_equal '123456', response.authorization + + capture = stub_comms do + @gateway.capture(@amount, response.authorization) + end.respond_with(successful_capture_response) + + assert_success capture + end + + def test_failed_authorize + response = stub_comms do + @gateway.authorize(@amount, @credit_card) + end.respond_with(failed_authorize_response) + + assert_failure response + assert_equal 'Declined', response.message + assert response.test? + end + + def test_failed_capture + response = stub_comms do + @gateway.capture(100, '') + end.respond_with(failed_capture_response) + + assert_failure response + end + + def test_successful_void + response = stub_comms do + @gateway.purchase(@amount, @credit_card) + end.respond_with(successful_authorize_response) + + assert_success response + assert_equal '123456', response.authorization + + void = stub_comms do + @gateway.void(response.authorization) + end.check_request do |endpoint, data, headers| + assert_match(/123456/, data) + end.respond_with(successful_void_response) + + assert_success void + end + + def test_failed_void + response = stub_comms do + @gateway.void('5d53a33d960c46d00f5dc061947d998c') + end.check_request do |endpoint, data, headers| + assert_match(/5d53a33d960c46d00f5dc061947d998c/, data) + end.respond_with(failed_void_response) + + assert_failure response + end + + def test_successful_refund + response = stub_comms do + @gateway.purchase(@amount, @credit_card) + end.respond_with(successful_purchase_response) + + assert_success response + assert_equal '123456', response.authorization + + refund = stub_comms do + @gateway.refund(@amount, response.authorization) + end.check_request do |endpoint, data, headers| + assert_match(/123456/, data) + end.respond_with(successful_refund_response) + + assert_success refund + end + + def test_failed_refund + response = stub_comms do + @gateway.refund(nil, '') + end.respond_with(failed_refund_response) + + assert_failure response + end + + def test_successful_verify + response = stub_comms do + @gateway.verify(@credit_card) + end.respond_with(successful_authorize_response, failed_void_response) + assert_success response + assert_equal 'Succeeded', response.message + end + + def test_failed_verify + response = stub_comms do + @gateway.verify(@credit_card) + end.respond_with(failed_authorize_response, successful_void_response) + assert_failure response + assert_equal 'Declined', response.message + end + + def test_empty_response_fails + response = stub_comms do + @gateway.purchase(@amount, @credit_card) + end.respond_with(empty_purchase_response) + + assert_failure response + assert_equal 'Error', response.message + end + + def test_invalid_json + response = stub_comms do + @gateway.purchase(@amount, @credit_card) + end.respond_with(invalid_json_response) + + assert_failure response + assert_match %r{Unparsable response}, response.message + end + + def test_transcript_scrubbing + assert_equal scrubbed_transcript, @gateway.scrub(transcript) + end + + def test_nil_cvv_transcript_scrubbing + assert_equal nil_cvv_scrubbed_transcript, @gateway.scrub(nil_cvv_transcript) + end + + def test_empty_string_cvv_transcript_scrubbing + assert_equal empty_string_cvv_scrubbed_transcript, @gateway.scrub(empty_string_cvv_transcript) + end + + private + + def successful_purchase_response + %( + { + "id": "123456", + "message": "Success", + "state": "Sale", + "status": "Successful" + } + ) + end + + def failed_purchase_response + %( + { + "id": "123456", + "message": "Declined", + "state": "Sale", + "status": "Declined" + } + ) + end + + def successful_authorize_response + %( + { + "id": "123456", + "message": "Success", + "state": "Authorize", + "status": "Successful" + } + ) + end + + def failed_authorize_response + %( + { + "id": "123456", + "message": "Declined", + "state": "Authorize", + "status": "Declined" + } + ) + end + + def successful_capture_response + %( + { + "id": "123456", + "message": "Successful", + "state": "Capture", + "status": "Successful" + } + ) + end + + def failed_capture_response + %( + { + "id": "123456", + "message": "Declined", + "state": "Capture", + "status": "Declined" + } + ) + end + + def successful_void_response + %( + { + "id": "123456", + "message": "Success", + "state": "Void", + "status": "Successful" + } + ) + end + + def failed_void_response + %( + { + "id": "123456", + "message": "Error", + "state": "Void", + "status": "Error" + } + ) + end + + def successful_refund_response + %( + { + "id": "123456", + "message": "Success", + "state": "Refund", + "status": "Successful" + } + ) + end + + def failed_refund_response + %( + { + "id": "123456", + "message": "Error", + "state": "Refund", + "status": "Error" + } + ) + end + + def empty_purchase_response + %( + { + "id": "123456", + "message": "Error", + "state": "Purchase", + "status": "Error" + } + ) + end + + def invalid_json_response + %( + { + "id": "123456", + ) + end + + def transcript + %( + <- "POST /merchants/10090/SALEtransactions HTTP/1.1\r\nContent-Type: application/json\r\nAuthorization: Bearer AAEAAHwXaLTYs2APKJW_4TpTDwCw_h9oDx9rA58FR78AFuYCX82Izes1nz9qGBXELGUN_EukKcP5T78Th5guDz4Rw5dQ4Gf0suKw7pz9vWrqa1NpZhrD9Lj9T-SFtOJgfodiwVaBBeSgbJLKA7MOzC9q2dv91HBNP69DygL1oX2L2mtt8fWlKSWhQmtG040E1I43jTueX3L3L9YA7iO6pIwO7CGybE5LnjkQ65KB2K4oYKfXRZosF77hgMJIh-KprFy9cYY3EjfupHeLon9im1BGafrda2N5wj_A_LvdMzfLAD1l1dgj82KlvM_gAzNJ4S19gAicRo9zIbsq36Apt-8jFjS0AQAAAAEAAA9Zr_lVLKMmmtKSo6T_9ulzMCRbYs798EpFD2wMlkb1NCQtA65VrNcM20Ka2FjNQfwOcSMWqDl9zFQhPyFl-npsG1Ww2oyyavA6HSe1HLRLtE_1hNBAlTBPQnLJ6hBf8eR_NTiVa-aQdV2l92-eSwCS59CzrOYGGCY1pLdNMDr_r66kg9l-l94154kRoMBRQSCqZV9iM9M-f3adLJqG6Q79zz1oJpGrH-Zv1kuv8eLaJJNOEFYARb0JbnAC5G1l9-aqxGvBrNkd4sAJIe23XrRx2XJCBIABxuGSQ1xJBTINVlXBXq1mvvd8B1uiYiDNia3c_vIGuSGIjZE0VbUN3oJppfCt1joGdePeUaC2Pyb2vuUN00EBEOaD9RF8IBWMLVJaF9cW2OewDOfBQg94MuOKLdXB_IisRx1ed25VQDVyv0f0CxmkAidvoDN0vvRIJZJr-bgBuL5FZM7gETAeYeiGlh7-Mf2Hzgy7236YNxcC9OnWFEcKEU50nlqog1bJnk8wJgoJWNqG0NUEK4DUzYqknmZ98qQv6rYrg5V-Hey-jAQp_KNf3h-vFHVZdP26Yg\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nAccept: */*\r\nUser-Agent: Ruby\r\nConnection: close\r\nHost: api.alliedwallet.com\r\nContent-Length: 464\r\n\r\n" + <- "{\"siteId\":\"10118\",\"amount\":\"1.00\",\"trackingId\":\"82b5f6217fa19daa426e226a231d330a\",\"currency\":\"USD\",\"nameOnCard\":\"Longbob Longsen\",\"cardNumber\":\"4242424242424242\",\"cVVCode\":\"123\",\"expirationYear\":\"2016\",\"expirationMonth\":\"09\",\"email\":\"jim_smith@example.com\",\"iPAddress\":\"127.0.0.1\",\"firstName\":\"Jim\",\"lastName\":\"Smith\",\"addressLine1\":\"456 My Street\",\"addressLine2\":\"Apt 1\",\"city\":\"Ottawa\",\"state\":\"ON\",\"countryId\":\"CA\",\"postalCode\":\"K1C2N6\",\"phone\":\"(555)555-5555\"}" + ) + end + + def scrubbed_transcript + %( + <- "POST /merchants/10090/SALEtransactions HTTP/1.1\r\nContent-Type: application/json\r\nAuthorization: Bearer [FILTERED]\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nAccept: */*\r\nUser-Agent: Ruby\r\nConnection: close\r\nHost: api.alliedwallet.com\r\nContent-Length: 464\r\n\r\n" + <- "{\"siteId\":\"10118\",\"amount\":\"1.00\",\"trackingId\":\"82b5f6217fa19daa426e226a231d330a\",\"currency\":\"USD\",\"nameOnCard\":\"Longbob Longsen\",\"cardNumber\":\"[FILTERED]\",\"cVVCode\":\"[FILTERED]\",\"expirationYear\":\"2016\",\"expirationMonth\":\"09\",\"email\":\"jim_smith@example.com\",\"iPAddress\":\"127.0.0.1\",\"firstName\":\"Jim\",\"lastName\":\"Smith\",\"addressLine1\":\"456 My Street\",\"addressLine2\":\"Apt 1\",\"city\":\"Ottawa\",\"state\":\"ON\",\"countryId\":\"CA\",\"postalCode\":\"K1C2N6\",\"phone\":\"(555)555-5555\"}" + ) + end + + def nil_cvv_transcript + %( + <- "POST /merchants/10090/SALEtransactions HTTP/1.1\r\nContent-Type: application/json\r\nAuthorization: Bearer AAEAAHwXaLTYs2APKJW_4TpTDwCw_h9oDx9rA58FR78AFuYCX82Izes1nz9qGBXELGUN_EukKcP5T78Th5guDz4Rw5dQ4Gf0suKw7pz9vWrqa1NpZhrD9Lj9T-SFtOJgfodiwVaBBeSgbJLKA7MOzC9q2dv91HBNP69DygL1oX2L2mtt8fWlKSWhQmtG040E1I43jTueX3L3L9YA7iO6pIwO7CGybE5LnjkQ65KB2K4oYKfXRZosF77hgMJIh-KprFy9cYY3EjfupHeLon9im1BGafrda2N5wj_A_LvdMzfLAD1l1dgj82KlvM_gAzNJ4S19gAicRo9zIbsq36Apt-8jFjS0AQAAAAEAAA9Zr_lVLKMmmtKSo6T_9ulzMCRbYs798EpFD2wMlkb1NCQtA65VrNcM20Ka2FjNQfwOcSMWqDl9zFQhPyFl-npsG1Ww2oyyavA6HSe1HLRLtE_1hNBAlTBPQnLJ6hBf8eR_NTiVa-aQdV2l92-eSwCS59CzrOYGGCY1pLdNMDr_r66kg9l-l94154kRoMBRQSCqZV9iM9M-f3adLJqG6Q79zz1oJpGrH-Zv1kuv8eLaJJNOEFYARb0JbnAC5G1l9-aqxGvBrNkd4sAJIe23XrRx2XJCBIABxuGSQ1xJBTINVlXBXq1mvvd8B1uiYiDNia3c_vIGuSGIjZE0VbUN3oJppfCt1joGdePeUaC2Pyb2vuUN00EBEOaD9RF8IBWMLVJaF9cW2OewDOfBQg94MuOKLdXB_IisRx1ed25VQDVyv0f0CxmkAidvoDN0vvRIJZJr-bgBuL5FZM7gETAeYeiGlh7-Mf2Hzgy7236YNxcC9OnWFEcKEU50nlqog1bJnk8wJgoJWNqG0NUEK4DUzYqknmZ98qQv6rYrg5V-Hey-jAQp_KNf3h-vFHVZdP26Yg\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nAccept: */*\r\nUser-Agent: Ruby\r\nConnection: close\r\nHost: api.alliedwallet.com\r\nContent-Length: 464\r\n\r\n" + <- "{\"siteId\":\"10118\",\"amount\":\"1.00\",\"trackingId\":\"82b5f6217fa19daa426e226a231d330a\",\"currency\":\"USD\",\"nameOnCard\":\"Longbob Longsen\",\"cardNumber\":\"4242424242424242\",\"cVVCode\":null,\"expirationYear\":\"2016\",\"expirationMonth\":\"09\",\"email\":\"jim_smith@example.com\",\"iPAddress\":\"127.0.0.1\",\"firstName\":\"Jim\",\"lastName\":\"Smith\",\"addressLine1\":\"456 My Street\",\"addressLine2\":\"Apt 1\",\"city\":\"Ottawa\",\"state\":\"ON\",\"countryId\":\"CA\",\"postalCode\":\"K1C2N6\",\"phone\":\"(555)555-5555\"}" + ) + end + + def nil_cvv_scrubbed_transcript + %( + <- "POST /merchants/10090/SALEtransactions HTTP/1.1\r\nContent-Type: application/json\r\nAuthorization: Bearer [FILTERED]\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nAccept: */*\r\nUser-Agent: Ruby\r\nConnection: close\r\nHost: api.alliedwallet.com\r\nContent-Length: 464\r\n\r\n" + <- "{\"siteId\":\"10118\",\"amount\":\"1.00\",\"trackingId\":\"82b5f6217fa19daa426e226a231d330a\",\"currency\":\"USD\",\"nameOnCard\":\"Longbob Longsen\",\"cardNumber\":\"[FILTERED]\",\"cVVCode\":[BLANK],\"expirationYear\":\"2016\",\"expirationMonth\":\"09\",\"email\":\"jim_smith@example.com\",\"iPAddress\":\"127.0.0.1\",\"firstName\":\"Jim\",\"lastName\":\"Smith\",\"addressLine1\":\"456 My Street\",\"addressLine2\":\"Apt 1\",\"city\":\"Ottawa\",\"state\":\"ON\",\"countryId\":\"CA\",\"postalCode\":\"K1C2N6\",\"phone\":\"(555)555-5555\"}" + ) + end + + def empty_string_cvv_transcript + %( + <- "POST /merchants/10090/SALEtransactions HTTP/1.1\r\nContent-Type: application/json\r\nAuthorization: Bearer AAEAAHwXaLTYs2APKJW_4TpTDwCw_h9oDx9rA58FR78AFuYCX82Izes1nz9qGBXELGUN_EukKcP5T78Th5guDz4Rw5dQ4Gf0suKw7pz9vWrqa1NpZhrD9Lj9T-SFtOJgfodiwVaBBeSgbJLKA7MOzC9q2dv91HBNP69DygL1oX2L2mtt8fWlKSWhQmtG040E1I43jTueX3L3L9YA7iO6pIwO7CGybE5LnjkQ65KB2K4oYKfXRZosF77hgMJIh-KprFy9cYY3EjfupHeLon9im1BGafrda2N5wj_A_LvdMzfLAD1l1dgj82KlvM_gAzNJ4S19gAicRo9zIbsq36Apt-8jFjS0AQAAAAEAAA9Zr_lVLKMmmtKSo6T_9ulzMCRbYs798EpFD2wMlkb1NCQtA65VrNcM20Ka2FjNQfwOcSMWqDl9zFQhPyFl-npsG1Ww2oyyavA6HSe1HLRLtE_1hNBAlTBPQnLJ6hBf8eR_NTiVa-aQdV2l92-eSwCS59CzrOYGGCY1pLdNMDr_r66kg9l-l94154kRoMBRQSCqZV9iM9M-f3adLJqG6Q79zz1oJpGrH-Zv1kuv8eLaJJNOEFYARb0JbnAC5G1l9-aqxGvBrNkd4sAJIe23XrRx2XJCBIABxuGSQ1xJBTINVlXBXq1mvvd8B1uiYiDNia3c_vIGuSGIjZE0VbUN3oJppfCt1joGdePeUaC2Pyb2vuUN00EBEOaD9RF8IBWMLVJaF9cW2OewDOfBQg94MuOKLdXB_IisRx1ed25VQDVyv0f0CxmkAidvoDN0vvRIJZJr-bgBuL5FZM7gETAeYeiGlh7-Mf2Hzgy7236YNxcC9OnWFEcKEU50nlqog1bJnk8wJgoJWNqG0NUEK4DUzYqknmZ98qQv6rYrg5V-Hey-jAQp_KNf3h-vFHVZdP26Yg\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nAccept: */*\r\nUser-Agent: Ruby\r\nConnection: close\r\nHost: api.alliedwallet.com\r\nContent-Length: 464\r\n\r\n" + <- "{\"siteId\":\"10118\",\"amount\":\"1.00\",\"trackingId\":\"82b5f6217fa19daa426e226a231d330a\",\"currency\":\"USD\",\"nameOnCard\":\"Longbob Longsen\",\"cardNumber\":\"4242424242424242\",\"cVVCode\":\"\",\"expirationYear\":\"2016\",\"expirationMonth\":\"09\",\"email\":\"jim_smith@example.com\",\"iPAddress\":\"127.0.0.1\",\"firstName\":\"Jim\",\"lastName\":\"Smith\",\"addressLine1\":\"456 My Street\",\"addressLine2\":\"Apt 1\",\"city\":\"Ottawa\",\"state\":\"ON\",\"countryId\":\"CA\",\"postalCode\":\"K1C2N6\",\"phone\":\"(555)555-5555\"}" + ) + end + + def empty_string_cvv_scrubbed_transcript + %( + <- "POST /merchants/10090/SALEtransactions HTTP/1.1\r\nContent-Type: application/json\r\nAuthorization: Bearer [FILTERED]\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nAccept: */*\r\nUser-Agent: Ruby\r\nConnection: close\r\nHost: api.alliedwallet.com\r\nContent-Length: 464\r\n\r\n" + <- "{\"siteId\":\"10118\",\"amount\":\"1.00\",\"trackingId\":\"82b5f6217fa19daa426e226a231d330a\",\"currency\":\"USD\",\"nameOnCard\":\"Longbob Longsen\",\"cardNumber\":\"[FILTERED]\",\"cVVCode\":\"[BLANK]\",\"expirationYear\":\"2016\",\"expirationMonth\":\"09\",\"email\":\"jim_smith@example.com\",\"iPAddress\":\"127.0.0.1\",\"firstName\":\"Jim\",\"lastName\":\"Smith\",\"addressLine1\":\"456 My Street\",\"addressLine2\":\"Apt 1\",\"city\":\"Ottawa\",\"state\":\"ON\",\"countryId\":\"CA\",\"postalCode\":\"K1C2N6\",\"phone\":\"(555)555-5555\"}" + ) + end + + def whitespace_string_cvv_transcript + %( + <- "POST /merchants/10090/SALEtransactions HTTP/1.1\r\nContent-Type: application/json\r\nAuthorization: Bearer AAEAAHwXaLTYs2APKJW_4TpTDwCw_h9oDx9rA58FR78AFuYCX82Izes1nz9qGBXELGUN_EukKcP5T78Th5guDz4Rw5dQ4Gf0suKw7pz9vWrqa1NpZhrD9Lj9T-SFtOJgfodiwVaBBeSgbJLKA7MOzC9q2dv91HBNP69DygL1oX2L2mtt8fWlKSWhQmtG040E1I43jTueX3L3L9YA7iO6pIwO7CGybE5LnjkQ65KB2K4oYKfXRZosF77hgMJIh-KprFy9cYY3EjfupHeLon9im1BGafrda2N5wj_A_LvdMzfLAD1l1dgj82KlvM_gAzNJ4S19gAicRo9zIbsq36Apt-8jFjS0AQAAAAEAAA9Zr_lVLKMmmtKSo6T_9ulzMCRbYs798EpFD2wMlkb1NCQtA65VrNcM20Ka2FjNQfwOcSMWqDl9zFQhPyFl-npsG1Ww2oyyavA6HSe1HLRLtE_1hNBAlTBPQnLJ6hBf8eR_NTiVa-aQdV2l92-eSwCS59CzrOYGGCY1pLdNMDr_r66kg9l-l94154kRoMBRQSCqZV9iM9M-f3adLJqG6Q79zz1oJpGrH-Zv1kuv8eLaJJNOEFYARb0JbnAC5G1l9-aqxGvBrNkd4sAJIe23XrRx2XJCBIABxuGSQ1xJBTINVlXBXq1mvvd8B1uiYiDNia3c_vIGuSGIjZE0VbUN3oJppfCt1joGdePeUaC2Pyb2vuUN00EBEOaD9RF8IBWMLVJaF9cW2OewDOfBQg94MuOKLdXB_IisRx1ed25VQDVyv0f0CxmkAidvoDN0vvRIJZJr-bgBuL5FZM7gETAeYeiGlh7-Mf2Hzgy7236YNxcC9OnWFEcKEU50nlqog1bJnk8wJgoJWNqG0NUEK4DUzYqknmZ98qQv6rYrg5V-Hey-jAQp_KNf3h-vFHVZdP26Yg\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nAccept: */*\r\nUser-Agent: Ruby\r\nConnection: close\r\nHost: api.alliedwallet.com\r\nContent-Length: 464\r\n\r\n" + <- "{\"siteId\":\"10118\",\"amount\":\"1.00\",\"trackingId\":\"82b5f6217fa19daa426e226a231d330a\",\"currency\":\"USD\",\"nameOnCard\":\"Longbob Longsen\",\"cardNumber\":\"4242424242424242\",\"cVVCode\":\" \",\"expirationYear\":\"2016\",\"expirationMonth\":\"09\",\"email\":\"jim_smith@example.com\",\"iPAddress\":\"127.0.0.1\",\"firstName\":\"Jim\",\"lastName\":\"Smith\",\"addressLine1\":\"456 My Street\",\"addressLine2\":\"Apt 1\",\"city\":\"Ottawa\",\"state\":\"ON\",\"countryId\":\"CA\",\"postalCode\":\"K1C2N6\",\"phone\":\"(555)555-5555\"}" + ) + end + + def whitespace_string_cvv_scrubbed_transcript + %( + <- "POST /merchants/10090/SALEtransactions HTTP/1.1\r\nContent-Type: application/json\r\nAuthorization: Bearer [FILTERED]\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nAccept: */*\r\nUser-Agent: Ruby\r\nConnection: close\r\nHost: api.alliedwallet.com\r\nContent-Length: 464\r\n\r\n" + <- "{\"siteId\":\"10118\",\"amount\":\"1.00\",\"trackingId\":\"82b5f6217fa19daa426e226a231d330a\",\"currency\":\"USD\",\"nameOnCard\":\"Longbob Longsen\",\"cardNumber\":\"[FILTERED]\",\"cVVCode\":\"[BLANK]\",\"expirationYear\":\"2016\",\"expirationMonth\":\"09\",\"email\":\"jim_smith@example.com\",\"iPAddress\":\"127.0.0.1\",\"firstName\":\"Jim\",\"lastName\":\"Smith\",\"addressLine1\":\"456 My Street\",\"addressLine2\":\"Apt 1\",\"city\":\"Ottawa\",\"state\":\"ON\",\"countryId\":\"CA\",\"postalCode\":\"K1C2N6\",\"phone\":\"(555)555-5555\"}" + ) + end end diff --git a/test/unit/gateways/authorize_net_arb_test.rb b/test/unit/gateways/authorize_net_arb_test.rb index 8472ba1a138..5c18ff468ff 100644 --- a/test/unit/gateways/authorize_net_arb_test.rb +++ b/test/unit/gateways/authorize_net_arb_test.rb @@ -4,7 +4,7 @@ class AuthorizeNetArbTest < Test::Unit::TestCase include CommStub def setup - ActiveMerchant.expects(:deprecated).with("ARB functionality in ActiveMerchant is deprecated and will be removed in a future version. Please contact the ActiveMerchant maintainers if you have an interest in taking ownership of a separate gem that continues support for it.") + ActiveMerchant.expects(:deprecated).with('ARB functionality in ActiveMerchant is deprecated and will be removed in a future version. Please contact the ActiveMerchant maintainers if you have an interest in taking ownership of a separate gem that continues support for it.') @gateway = AuthorizeNetArbGateway.new( :login => 'X', :password => 'Y' @@ -25,10 +25,10 @@ def test_successful_recurring :unit => :days }, :duration => { - :start_date => Time.now.strftime("%Y-%m-%d"), + :start_date => Time.now.strftime('%Y-%m-%d'), :occurrences => 30 } - ) + ) assert_instance_of Response, response assert response.success? @@ -69,8 +69,8 @@ def test_successful_status_recurring end def test_expdate_formatting - assert_equal '2009-09', @gateway.send(:expdate, credit_card('4111111111111111', :month => "9", :year => "2009")) - assert_equal '2013-11', @gateway.send(:expdate, credit_card('4111111111111111', :month => "11", :year => "2013")) + assert_equal '2009-09', @gateway.send(:expdate, credit_card('4111111111111111', :month => '9', :year => '2009')) + assert_equal '2013-11', @gateway.send(:expdate, credit_card('4111111111111111', :month => '11', :year => '2013')) end private diff --git a/test/unit/gateways/authorize_net_cim_test.rb b/test/unit/gateways/authorize_net_cim_test.rb index 75e41ea4a05..1d9bd462192 100644 --- a/test/unit/gateways/authorize_net_cim_test.rb +++ b/test/unit/gateways/authorize_net_cim_test.rb @@ -46,8 +46,8 @@ def setup end def test_expdate_formatting - assert_equal '2009-09', @gateway.send(:expdate, credit_card('4111111111111111', :month => "9", :year => "2009")) - assert_equal '2013-11', @gateway.send(:expdate, credit_card('4111111111111111', :month => "11", :year => "2013")) + assert_equal '2009-09', @gateway.send(:expdate, credit_card('4111111111111111', :month => '9', :year => '2009')) + assert_equal '2013-11', @gateway.send(:expdate, credit_card('4111111111111111', :month => '11', :year => '2013')) assert_equal 'XXXX', @gateway.send(:expdate, credit_card('XXXX1234', :month => nil, :year => nil)) end @@ -58,7 +58,7 @@ def test_should_create_customer_profile_request assert_instance_of Response, response assert_success response assert_equal @customer_profile_id, response.authorization - assert_equal "Successful.", response.message + assert_equal 'Successful.', response.message end def test_should_create_customer_payment_profile_request @@ -76,7 +76,7 @@ def test_should_create_customer_payment_profile_request assert_instance_of Response, response assert_success response assert_equal @customer_payment_profile_id, response.params['customer_payment_profile_id'] - assert_equal "This output is only present if the ValidationMode input parameter is passed with a value of testMode or liveMode", response.params['validation_direct_response'] + assert_equal 'This output is only present if the ValidationMode input parameter is passed with a value of testMode or liveMode', response.params['validation_direct_response'] end def test_should_create_customer_shipping_address_request @@ -420,15 +420,15 @@ def test_should_update_customer_payment_profile_request end def test_should_update_customer_payment_profile_request_with_last_four_digits - last_four_credit_card = ActiveMerchant::Billing::CreditCard.new(:number => "4242") #Credit card with only last four digits + last_four_credit_card = ActiveMerchant::Billing::CreditCard.new(:number => '4242') # Credit card with only last four digits response = stub_comms do @gateway.update_customer_payment_profile( :customer_profile_id => @customer_profile_id, :payment_profile => { :customer_payment_profile_id => @customer_payment_profile_id, - :bill_to => address(:address1 => "345 Avenue B", - :address2 => "Apt 101"), + :bill_to => address(:address1 => '345 Avenue B', + :address2 => 'Apt 101'), :payment => { :credit_card => last_four_credit_card } @@ -509,6 +509,8 @@ def test_should_create_customer_profile_transaction_auth_capture_and_then_refund # http://www.modernbill.com/support/manual/old/v4/adminhelp/english/Configuration/Payment_Settings/Gateway_API/AuthorizeNet/Module_Authorize.net.htm assert_failure response assert_equal 'The referenced transaction does not meet the criteria for issuing a credit.', response.params['direct_response']['message'] + assert_equal 'The transaction was unsuccessful.', response.message + assert_equal 'E00027', response.error_code return response end @@ -573,8 +575,8 @@ def test_should_create_customer_profile_transaction_for_refund_request assert response = @gateway.create_customer_profile_transaction_for_refund( :transaction => { :trans_id => 1, - :amount => "1.00", - :credit_card_number_masked => "XXXX1234" + :amount => '1.00', + :credit_card_number_masked => 'XXXX1234' } ) assert_instance_of Response, response @@ -583,7 +585,7 @@ def test_should_create_customer_profile_transaction_for_refund_request assert_equal 'This transaction has been approved.', response.params['direct_response']['message'] end - def test_should_create_customer_profile_trasnaction_passing_recurring_flag + def test_should_create_customer_profile_transaction_passing_recurring_flag response = stub_comms do @gateway.create_customer_profile_transaction( :transaction => { @@ -618,6 +620,22 @@ def test_full_or_masked_card_number assert_equal 'XXXX1234', @gateway.send(:full_or_masked_card_number, '1234') end + def test_multiple_errors_when_creating_customer_profile + @gateway.expects(:ssl_post).returns(unsuccessful_create_customer_profile_transaction_response_with_multiple_errors(:refund)) + assert response = @gateway.create_customer_profile_transaction( + :transaction => { + :type => :refund, + :amount => 1, + + :customer_profile_id => @customer_profile_id, + :customer_payment_profile_id => @customer_payment_profile_id, + :trans_id => 1 + } + ) + assert_equal 'The transaction was unsuccessful.', response.message + assert_equal 'E00027', response.error_code + end + private def get_auth_only_response @@ -1056,4 +1074,26 @@ def unsuccessful_create_customer_profile_transaction_response(transaction_type) XML end + def unsuccessful_create_customer_profile_transaction_response_with_multiple_errors(transaction_type) + <<-XML + <?xml version="1.0" encoding="utf-8"?> + <createCustomerProfileTransactionResponse + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns:xsd="http://www.w3.org/2001/XMLSchema" + xmlns="AnetApi/xml/v1/schema/AnetApiSchema.xsd"> + <messages> + <resultCode>Error</resultCode> + <message> + <code>E00027</code> + <text>The transaction was unsuccessful.</text> + </message> + <message> + <code>E00001</code> + <text>An error occurred during processing. Please try again.</text> + </message> + </messages> + <directResponse>#{UNSUCCESSUL_DIRECT_RESPONSE[transaction_type]}</directResponse> + </createCustomerProfileTransactionResponse> + XML + end end diff --git a/test/unit/gateways/authorize_net_test.rb b/test/unit/gateways/authorize_net_test.rb index 0fa604f6e74..2cdfde5abcd 100644 --- a/test/unit/gateways/authorize_net_test.rb +++ b/test/unit/gateways/authorize_net_test.rb @@ -29,21 +29,44 @@ def setup description: 'Store Purchase' } + @level_3_options = { + ship_from_address: { + zip: 'origin27701', + country: 'originUS' + }, + summary_commodity_code: 'CODE' + } + @additional_options = { line_items: [ { - item_id: "1", - name: "mug", - description: "coffee", - quantity: "100", - unit_price: "10" + item_id: '1', + name: 'mug', + description: 'coffee', + quantity: '100', + unit_price: '10' }, { - item_id: "2", - name: "vase", - description: "floral", - quantity: "200", - unit_price: "20" + item_id: '2', + name: 'vase', + description: 'floral', + quantity: '200', + unit_price: '20' + } + ] + } + + @level_3_line_item_options = { + line_items: [ + { + item_id: '1', + name: 'mug', + description: 'coffee', + quantity: '100', + unit_price: '10', + unit_of_measure: 'yards', + total_amount: '1000', + product_code: 'coupon' } ] } @@ -57,7 +80,7 @@ def test_add_swipe_data_with_bad_data parse(data) do |doc| assert_nil doc.at_xpath('//track1') assert_nil doc.at_xpath('//track2') - assert_equal "1.00", doc.at_xpath("//transactionRequest/amount").content + assert_equal '1.00', doc.at_xpath('//transactionRequest/amount').content end end.respond_with(successful_purchase_response) end @@ -70,7 +93,7 @@ def test_add_swipe_data_with_track_1 parse(data) do |doc| assert_equal '%B378282246310005^LONGSON/LONGBOB^1705101130504392?', doc.at_xpath('//track1').content assert_nil doc.at_xpath('//track2') - assert_equal "1.00", doc.at_xpath("//transactionRequest/amount").content + assert_equal '1.00', doc.at_xpath('//transactionRequest/amount').content end end.respond_with(successful_purchase_response) end @@ -83,7 +106,7 @@ def test_add_swipe_data_with_track_2 parse(data) do |doc| assert_nil doc.at_xpath('//track1') assert_equal ';4111111111111111=1803101000020000831?', doc.at_xpath('//track2').content - assert_equal "1.00", doc.at_xpath("//transactionRequest/amount").content + assert_equal '1.00', doc.at_xpath('//transactionRequest/amount').content end end.respond_with(successful_purchase_response) end @@ -107,8 +130,8 @@ def test_retail_market_type_device_type_included_in_swipe_transactions_with_vali end.check_request do |endpoint, data, headers| parse(data) do |doc| assert_not_nil doc.at_xpath('//retail') - assert_equal "2", doc.at_xpath('//retail/marketType').content - assert_equal "7", doc.at_xpath('//retail/deviceType').content + assert_equal '2', doc.at_xpath('//retail/marketType').content + assert_equal '7', doc.at_xpath('//retail/deviceType').content end end.respond_with(successful_purchase_response) end @@ -122,8 +145,8 @@ def test_device_type_used_from_options_if_included_with_valid_track_data end.check_request do |endpoint, data, headers| parse(data) do |doc| assert_not_nil doc.at_xpath('//retail') - assert_equal "2", doc.at_xpath('//retail/marketType').content - assert_equal "1", doc.at_xpath('//retail/deviceType').content + assert_equal '2', doc.at_xpath('//retail/marketType').content + assert_equal '1', doc.at_xpath('//retail/deviceType').content end end.respond_with(successful_purchase_response) end @@ -148,7 +171,7 @@ def test_moto_market_type_included_when_card_is_entered_manually end.check_request do |endpoint, data, headers| parse(data) do |doc| assert_not_nil doc.at_xpath('//retail') - assert_equal "1", doc.at_xpath('//retail/marketType').content + assert_equal '1', doc.at_xpath('//retail/marketType').content end end.respond_with(successful_purchase_response) end @@ -158,7 +181,7 @@ def test_market_type_can_be_specified @gateway.purchase(@amount, @credit_card, market_type: 0) end.check_request do |endpoint, data, headers| parse(data) do |doc| - assert_equal "0", doc.at_xpath('//retail/marketType').content + assert_equal '0', doc.at_xpath('//retail/marketType').content end end.respond_with(successful_purchase_response) end @@ -168,13 +191,13 @@ def test_successful_echeck_authorization @gateway.authorize(@amount, @check) end.check_request do |endpoint, data, headers| parse(data) do |doc| - assert_not_nil doc.at_xpath("//payment/bankAccount") - assert_equal "244183602", doc.at_xpath("//routingNumber").content - assert_equal "15378535", doc.at_xpath("//accountNumber").content - assert_equal "Bank of Elbonia", doc.at_xpath("//bankName").content - assert_equal "Jim Smith", doc.at_xpath("//nameOnAccount").content - assert_equal "1", doc.at_xpath("//checkNumber").content - assert_equal "1.00", doc.at_xpath("//transactionRequest/amount").content + assert_not_nil doc.at_xpath('//payment/bankAccount') + assert_equal '244183602', doc.at_xpath('//routingNumber').content + assert_equal '15378535', doc.at_xpath('//accountNumber').content + assert_equal 'Bank of Elbonia', doc.at_xpath('//bankName').content + assert_equal 'Jim Smith', doc.at_xpath('//nameOnAccount').content + assert_equal '1', doc.at_xpath('//checkNumber').content + assert_equal '1.00', doc.at_xpath('//transactionRequest/amount').content end end.respond_with(successful_authorize_response) @@ -189,13 +212,13 @@ def test_successful_echeck_purchase @gateway.purchase(@amount, @check) end.check_request do |endpoint, data, headers| parse(data) do |doc| - assert_not_nil doc.at_xpath("//payment/bankAccount") - assert_equal "244183602", doc.at_xpath("//routingNumber").content - assert_equal "15378535", doc.at_xpath("//accountNumber").content - assert_equal "Bank of Elbonia", doc.at_xpath("//bankName").content - assert_equal "Jim Smith", doc.at_xpath("//nameOnAccount").content - assert_equal "1", doc.at_xpath("//checkNumber").content - assert_equal "1.00", doc.at_xpath("//transactionRequest/amount").content + assert_not_nil doc.at_xpath('//payment/bankAccount') + assert_equal '244183602', doc.at_xpath('//routingNumber').content + assert_equal '15378535', doc.at_xpath('//accountNumber').content + assert_equal 'Bank of Elbonia', doc.at_xpath('//bankName').content + assert_equal 'Jim Smith', doc.at_xpath('//nameOnAccount').content + assert_equal '1', doc.at_xpath('//checkNumber').content + assert_equal '1.00', doc.at_xpath('//transactionRequest/amount').content end end.respond_with(successful_purchase_response) @@ -209,7 +232,7 @@ def test_echeck_passing_recurring_flag response = stub_comms do @gateway.purchase(@amount, @check, recurring: true) end.check_request do |endpoint, data, headers| - assert_equal settings_from_doc(parse(data))["recurringBilling"], "true" + assert_equal settings_from_doc(parse(data))['recurringBilling'], 'true' end.respond_with(successful_purchase_response) assert_success response @@ -227,8 +250,8 @@ def test_successful_apple_pay_authorization @gateway.authorize(@amount, @apple_pay_payment_token) end.check_request do |endpoint, data, headers| parse(data) do |doc| - assert_equal @gateway.class::APPLE_PAY_DATA_DESCRIPTOR, doc.at_xpath("//opaqueData/dataDescriptor").content - assert_equal Base64.strict_encode64(@apple_pay_payment_token.payment_data.to_json), doc.at_xpath("//opaqueData/dataValue").content + assert_equal @gateway.class::APPLE_PAY_DATA_DESCRIPTOR, doc.at_xpath('//opaqueData/dataDescriptor').content + assert_equal Base64.strict_encode64(@apple_pay_payment_token.payment_data.to_json), doc.at_xpath('//opaqueData/dataValue').content end end.respond_with(successful_authorize_response) @@ -243,8 +266,8 @@ def test_successful_apple_pay_purchase @gateway.purchase(@amount, @apple_pay_payment_token) end.check_request do |endpoint, data, headers| parse(data) do |doc| - assert_equal @gateway.class::APPLE_PAY_DATA_DESCRIPTOR, doc.at_xpath("//opaqueData/dataDescriptor").content - assert_equal Base64.strict_encode64(@apple_pay_payment_token.payment_data.to_json), doc.at_xpath("//opaqueData/dataValue").content + assert_equal @gateway.class::APPLE_PAY_DATA_DESCRIPTOR, doc.at_xpath('//opaqueData/dataDescriptor').content + assert_equal Base64.strict_encode64(@apple_pay_payment_token.payment_data.to_json), doc.at_xpath('//opaqueData/dataValue').content end end.respond_with(successful_purchase_response) @@ -262,6 +285,7 @@ def test_successful_authorization assert_equal 'M', response.cvv_result['code'] assert_equal 'CVV matches', response.cvv_result['message'] + assert_equal 'I00001', response.params['full_response_code'] assert_equal '508141794', response.authorization.split('#')[0] assert response.test? @@ -307,17 +331,38 @@ def test_passes_email_customer assert_match(/<settingName>emailCustomer<\/settingName>/, data) assert_match(/<settingValue>true<\/settingValue>/, data) end.respond_with(successful_purchase_response) + + stub_comms do + @gateway.purchase(@amount, credit_card, email_customer: false) + end.check_request do |endpoint, data, headers| + assert_match(/<settingName>emailCustomer<\/settingName>/, data) + assert_match(/<settingValue>false<\/settingValue>/, data) + end.respond_with(successful_purchase_response) end def test_passes_header_email_receipt stub_comms do - @gateway.purchase(@amount, credit_card, header_email_receipt: "yet another field") + @gateway.purchase(@amount, credit_card, header_email_receipt: 'yet another field') end.check_request do |endpoint, data, headers| assert_match(/<settingName>headerEmailReceipt<\/settingName>/, data) assert_match(/<settingValue>yet another field<\/settingValue>/, data) end.respond_with(successful_purchase_response) end + def test_passes_level_3_options + stub_comms do + @gateway.purchase(@amount, credit_card, @options.merge(@level_3_options)) + end.check_request do |endpoint, data, headers| + assert_match(/<order>/, data) + assert_match(/<summaryCommodityCode>#{@level_3_options[:summary_commodity_code]}<\/summaryCommodityCode>/, data) + assert_match(/<\/order>/, data) + assert_match(/<shipFrom>/, data) + assert_match(/<zip>#{@level_3_options[:ship_from_address][:zip]}<\/zip>/, data) + assert_match(/<country>#{@level_3_options[:ship_from_address][:country]}<\/country>/, data) + assert_match(/<\/shipFrom>/, data) + end.respond_with(successful_purchase_response) + end + def test_passes_line_items stub_comms do @gateway.purchase(@amount, credit_card, @options.merge(@additional_options)) @@ -339,6 +384,24 @@ def test_passes_line_items end.respond_with(successful_purchase_response) end + def test_passes_level_3_line_items + stub_comms do + @gateway.purchase(@amount, credit_card, @options.merge(@level_3_line_item_options)) + end.check_request do |endpoint, data, headers| + assert_match(/<lineItems>/, data) + assert_match(/<lineItem>/, data) + assert_match(/<itemId>#{@level_3_line_item_options[:line_items][0][:item_id]}<\/itemId>/, data) + assert_match(/<name>#{@level_3_line_item_options[:line_items][0][:name]}<\/name>/, data) + assert_match(/<description>#{@level_3_line_item_options[:line_items][0][:description]}<\/description>/, data) + assert_match(/<quantity>#{@level_3_line_item_options[:line_items][0][:quantity]}<\/quantity>/, data) + assert_match(/<unitPrice>#{@level_3_line_item_options[:line_items][0][:unit_price]}<\/unitPrice>/, data) + assert_match(/<unitOfMeasure>#{@level_3_line_item_options[:line_items][0][:unit_of_measure]}<\/unitOfMeasure>/, data) + assert_match(/<totalAmount>#{@level_3_line_item_options[:line_items][0][:total_amount]}<\/totalAmount>/, data) + assert_match(/<productCode>#{@level_3_line_item_options[:line_items][0][:product_code]}<\/productCode>/, data) + assert_match(/<\/lineItems>/, data) + end.respond_with(successful_purchase_response) + end + def test_failed_purchase @gateway.expects(:ssl_post).returns(failed_purchase_response) @@ -366,7 +429,7 @@ def test_live_gateway_cannot_use_test_mode_on_auth_dot_net_server real_gateway.stubs(:ssl_post).returns(successful_purchase_response_test_mode) response = real_gateway.purchase(@amount, @credit_card) assert_failure response - assert_equal "Using a live Authorize.net account in Test Mode is not permitted.", response.message + assert_equal 'Using a live Authorize.net account in Test Mode is not permitted.', response.message end def test_successful_purchase_using_stored_card @@ -386,6 +449,24 @@ def test_successful_purchase_using_stored_card assert_equal 'Street address and 5-digit postal code match.', response.avs_result['message'] end + def test_successful_purchase_using_stored_card_and_custom_delimiter + @gateway.expects(:ssl_post).returns(successful_store_response) + store = @gateway.store(@credit_card, @options) + assert_success store + + @gateway.expects(:ssl_post).returns(successful_purchase_using_stored_card_response_with_pipe_delimiter) + + response = @gateway.purchase(@amount, store.authorization, {delimiter: '|', description: 'description, with, commas'}) + assert_success response + + assert_equal '2235700270#XXXX2224#cim_purchase', response.authorization + assert_equal 'Y', response.avs_result['code'] + assert response.avs_result['street_match'] + assert response.avs_result['postal_match'] + assert_equal 'Street address and 5-digit postal code match.', response.avs_result['message'] + assert_equal 'description, with, commas', response.params['order_description'] + end + def test_failed_purchase_using_stored_card @gateway.expects(:ssl_post).returns(successful_store_response) store = @gateway.store(@credit_card, @options) @@ -395,8 +476,8 @@ def test_failed_purchase_using_stored_card response = @gateway.purchase(@amount, store.authorization) assert_failure response - assert_equal "The credit card number is invalid.", response.message - assert_equal "6", response.params["response_reason_code"] + assert_equal 'The credit card number is invalid.', response.message + assert_equal '6', response.params['response_reason_code'] end def test_failed_authorize @@ -414,13 +495,13 @@ def test_successful_authorize_and_capture_using_stored_card @gateway.expects(:ssl_post).returns(successful_authorize_using_stored_card_response) auth = @gateway.authorize(@amount, store.authorization) assert_success auth - assert_equal "This transaction has been approved.", auth.message + assert_equal 'This transaction has been approved.', auth.message @gateway.expects(:ssl_post).returns(successful_capture_using_stored_card_response) capture = @gateway.capture(@amount, auth.authorization) assert_success capture - assert_equal "This transaction has been approved.", capture.message + assert_equal 'This transaction has been approved.', capture.message end def test_failed_authorize_using_stored_card @@ -430,8 +511,8 @@ def test_failed_authorize_using_stored_card @gateway.expects(:ssl_post).returns(failed_authorize_using_stored_card_response) response = @gateway.authorize(@amount, store.authorization) assert_failure response - assert_equal "The credit card number is invalid.", response.message - assert_equal "6", response.params["response_reason_code"] + assert_equal 'The credit card number is invalid.', response.message + assert_equal '6', response.params['response_reason_code'] end def test_successful_capture @@ -494,7 +575,7 @@ def test_successful_void_using_stored_card @gateway.expects(:ssl_post).returns(successful_void_using_stored_card_response) void = @gateway.void(auth.authorization) assert_success void - assert_equal "This transaction has been approved.", void.message + assert_equal 'This transaction has been approved.', void.message end def test_failed_void_using_stored_card @@ -507,7 +588,7 @@ def test_failed_void_using_stored_card @gateway.expects(:ssl_post).returns(failed_void_using_stored_card_response) void = @gateway.void(auth.authorization) assert_failure void - assert_equal "This transaction has already been voided.", void.message + assert_equal 'This transaction has already been voided.', void.message end def test_successful_verify @@ -546,7 +627,30 @@ def test_failed_refund_using_stored_card @gateway.expects(:ssl_post).returns(failed_refund_using_stored_card_response) refund = @gateway.refund(@amount, purchase.authorization) assert_failure refund - assert_equal "The record cannot be found", refund.message + assert_equal 'The record cannot be found', refund.message + end + + def test_failed_refund_due_to_unsettled_payment + @gateway.expects(:ssl_post).returns(failed_refund_for_unsettled_payment_response) + @gateway.expects(:void).never + + @gateway.refund(36.40, '2214269051#XXXX1234') + end + + def test_failed_full_refund_due_to_unsettled_payment_forces_void + @gateway.expects(:ssl_post).returns(failed_refund_for_unsettled_payment_response) + @gateway.expects(:void).once + + @gateway.refund(36.40, '2214269051#XXXX1234', force_full_refund_if_unsettled: true) + end + + def test_failed_full_refund_returns_failed_response_if_reason_code_is_not_unsettled_error + @gateway.expects(:ssl_post).returns(failed_refund_response) + @gateway.expects(:void).never + + response = @gateway.refund(36.40, '2214269051#XXXX1234', force_full_refund_if_unsettled: true) + assert response.present? + assert_failure response end def test_successful_store @@ -554,9 +658,9 @@ def test_successful_store store = @gateway.store(@credit_card, @options) assert_success store - assert_equal "Successful", store.message - assert_equal "35959426", store.params["customer_profile_id"] - assert_equal "32506918", store.params["customer_payment_profile_id"] + assert_equal 'Successful', store.message + assert_equal '35959426', store.params['customer_profile_id'] + assert_equal '32506918', store.params['customer_payment_profile_id'] end def test_failed_store @@ -565,7 +669,7 @@ def test_failed_store store = @gateway.store(@credit_card, @options) assert_failure store assert_match(/The field length is invalid/, store.message) - assert_equal("15", store.params["message_code"]) + assert_equal('15', store.params['message_code']) end def test_successful_unstore @@ -573,11 +677,11 @@ def test_successful_unstore @gateway.unstore('35959426#32506918#cim_store') end.check_request do |endpoint, data, headers| doc = parse(data) - assert_equal "35959426", doc.at_xpath("//deleteCustomerProfileRequest/customerProfileId").content + assert_equal '35959426', doc.at_xpath('//deleteCustomerProfileRequest/customerProfileId').content end.respond_with(successful_unstore_response) assert_success response - assert_equal "Successful", response.message + assert_equal 'Successful', response.message end def test_failed_unstore @@ -586,7 +690,7 @@ def test_failed_unstore unstore = @gateway.unstore('35959426#32506918#cim_store') assert_failure unstore assert_match(/The record cannot be found/, unstore.message) - assert_equal("40", unstore.params["message_code"]) + assert_equal('40', unstore.params['message_code']) end def test_successful_store_new_payment_profile @@ -594,9 +698,9 @@ def test_successful_store_new_payment_profile store = @gateway.store(@credit_card, @options) assert_success store - assert_equal "Successful", store.message - assert_equal "38392170", store.params["customer_profile_id"] - assert_equal "34896759", store.params["customer_payment_profile_id"] + assert_equal 'Successful', store.message + assert_equal '38392170', store.params['customer_profile_id'] + assert_equal '34896759', store.params['customer_payment_profile_id'] end def test_failed_store_new_payment_profile @@ -604,9 +708,9 @@ def test_failed_store_new_payment_profile store = @gateway.store(@credit_card, @options) assert_failure store - assert_equal "A duplicate customer payment profile already exists", store.message - assert_equal "38392767", store.params["customer_profile_id"] - assert_equal "34897359", store.params["customer_payment_profile_id"] + assert_equal 'A duplicate customer payment profile already exists', store.message + assert_equal '38392767', store.params['customer_profile_id'] + assert_equal '34897359', store.params['customer_payment_profile_id'] end def test_address @@ -614,54 +718,93 @@ def test_address @gateway.authorize(@amount, @credit_card, billing_address: {address1: '164 Waverley Street', country: 'US', state: 'CO', phone: '(555)555-5555', fax: '(555)555-4444'}) end.check_request do |endpoint, data, headers| parse(data) do |doc| - assert_equal "CO", doc.at_xpath("//billTo/state").content, data - assert_equal "164 Waverley Street", doc.at_xpath("//billTo/address").content, data - assert_equal "US", doc.at_xpath("//billTo/country").content, data - assert_equal "(555)555-5555", doc.at_xpath("//billTo/phoneNumber").content - assert_equal "(555)555-4444", doc.at_xpath("//billTo/faxNumber").content + assert_equal 'CO', doc.at_xpath('//billTo/state').content, data + assert_equal '164 Waverley Street', doc.at_xpath('//billTo/address').content, data + assert_equal 'US', doc.at_xpath('//billTo/country').content, data + assert_equal '(555)555-5555', doc.at_xpath('//billTo/phoneNumber').content + assert_equal '(555)555-4444', doc.at_xpath('//billTo/faxNumber').content end end.respond_with(successful_authorize_response) end - def test_address_outsite_north_america + def test_address_with_empty_billing_address stub_comms do - @gateway.authorize(@amount, @credit_card, billing_address: {address1: '164 Waverley Street', country: 'DE', state: ''}) + @gateway.authorize(@amount, @credit_card) end.check_request do |endpoint, data, headers| parse(data) do |doc| - assert_equal "n/a", doc.at_xpath("//billTo/state").content, data - assert_equal "164 Waverley Street", doc.at_xpath("//billTo/address").content, data - assert_equal "DE", doc.at_xpath("//billTo/country").content, data + assert_equal '', doc.at_xpath('//billTo/address').content, data + assert_equal '', doc.at_xpath('//billTo/city').content, data + assert_equal 'n/a', doc.at_xpath('//billTo/state').content, data + assert_equal '', doc.at_xpath('//billTo/zip').content, data + assert_equal '', doc.at_xpath('//billTo/country').content, data end end.respond_with(successful_authorize_response) end - def test_duplicate_window + def test_address_with_address2_present stub_comms do - @gateway.purchase(@amount, @credit_card, duplicate_window: 0) + @gateway.authorize(@amount, @credit_card, billing_address: {address1: '164 Waverley Street', address2: 'Apt 1234', country: 'US', state: 'CO', phone: '(555)555-5555', fax: '(555)555-4444'}) end.check_request do |endpoint, data, headers| - assert_equal settings_from_doc(parse(data))["duplicateWindow"], "0" - end.respond_with(successful_purchase_response) + parse(data) do |doc| + assert_equal 'CO', doc.at_xpath('//billTo/state').content, data + assert_equal '164 Waverley Street Apt 1234', doc.at_xpath('//billTo/address').content, data + assert_equal 'US', doc.at_xpath('//billTo/country').content, data + assert_equal '(555)555-5555', doc.at_xpath('//billTo/phoneNumber').content + assert_equal '(555)555-4444', doc.at_xpath('//billTo/faxNumber').content + end + end.respond_with(successful_authorize_response) end - def test_settings_for_cim_purchase + def test_address_north_america_with_defaults stub_comms do - @store = @gateway.store(@credit_card, @options) - assert_success @store - end.respond_with(successful_store_response) + @gateway.authorize(@amount, @credit_card, billing_address: {address1: '164 Waverley Street', country: 'US'}) + end.check_request do |endpoint, data, headers| + parse(data) do |doc| + assert_equal 'NC', doc.at_xpath('//billTo/state').content, data + assert_equal '164 Waverley Street', doc.at_xpath('//billTo/address').content, data + assert_equal 'US', doc.at_xpath('//billTo/country').content, data + end + end.respond_with(successful_authorize_response) + end + def test_address_outsite_north_america stub_comms do - test_options = {email_customer: true, duplicate_window: 0} - @gateway.purchase(@amount, @store.authorization, test_options) - end.check_request do |_endpoint, data, _headers| - assert_equal settings_from_doc(parse(data))["duplicateWindow"], "0" - assert_equal settings_from_doc(parse(data))["emailCustomer"], "true" - end.respond_with(successful_purchase_using_stored_card_response) + @gateway.authorize(@amount, @credit_card, billing_address: {address1: '164 Waverley Street', country: 'DE'}) + end.check_request do |endpoint, data, headers| + parse(data) do |doc| + assert_equal 'n/a', doc.at_xpath('//billTo/state').content, data + assert_equal '164 Waverley Street', doc.at_xpath('//billTo/address').content, data + assert_equal 'DE', doc.at_xpath('//billTo/country').content, data + end + end.respond_with(successful_authorize_response) + end + + def test_address_outsite_north_america_with_address2_present + stub_comms do + @gateway.authorize(@amount, @credit_card, billing_address: {address1: '164 Waverley Street', address2: 'Apt 1234', country: 'DE'}) + end.check_request do |endpoint, data, headers| + parse(data) do |doc| + assert_equal 'n/a', doc.at_xpath('//billTo/state').content, data + assert_equal '164 Waverley Street Apt 1234', doc.at_xpath('//billTo/address').content, data + assert_equal 'DE', doc.at_xpath('//billTo/country').content, data + end + end.respond_with(successful_authorize_response) + end + + def test_duplicate_window + stub_comms do + @gateway.purchase(@amount, @credit_card, duplicate_window: 0) + end.check_request do |endpoint, data, headers| + assert_equal settings_from_doc(parse(data))['duplicateWindow'], '0' + end.respond_with(successful_purchase_response) end def test_duplicate_window_class_attribute_deprecated @gateway.class.duplicate_window = 0 - assert_deprecation_warning("Using the duplicate_window class_attribute is deprecated. Use the transaction options hash instead.") do - @gateway.purchase(@amount, @credit_card) + assert_deprecation_warning('Using the duplicate_window class_attribute is deprecated. Use the transaction options hash instead.') do + stub_comms do + @gateway.purchase(@amount, @credit_card) + end.respond_with(successful_purchase_response) end ensure @gateway.class.duplicate_window = nil @@ -669,25 +812,57 @@ def test_duplicate_window_class_attribute_deprecated def test_add_cardholder_authentication_value stub_comms do - @gateway.purchase(@amount, @credit_card, cardholder_authentication_value: 'E0Mvq8AAABEiMwARIjNEVWZ3iJk=', authentication_indicator: "2") + @gateway.purchase(@amount, @credit_card, cardholder_authentication_value: 'E0Mvq8AAABEiMwARIjNEVWZ3iJk=', authentication_indicator: '2') + end.check_request do |endpoint, data, headers| + parse(data) do |doc| + assert_equal 'E0Mvq8AAABEiMwARIjNEVWZ3iJk=', doc.at_xpath('//cardholderAuthentication/cardholderAuthenticationValue').content + assert_equal '2', doc.at_xpath('//cardholderAuthentication/authenticationIndicator').content + assert_equal '1.00', doc.at_xpath('//transactionRequest/amount').content + end + end.respond_with(successful_purchase_response) + end + + def test_alternative_three_d_secure_options + three_d_secure_opts = { cavv: 'E0Mvq8AAABEiMwARIjNEVWZ3iJk=', eci: '2' } + stub_comms do + @gateway.purchase(@amount, @credit_card, three_d_secure: three_d_secure_opts) + end.check_request do |endpoint, data, headers| + parse(data) do |doc| + assert_equal 'E0Mvq8AAABEiMwARIjNEVWZ3iJk=', doc.at_xpath('//cardholderAuthentication/cardholderAuthenticationValue').content + assert_equal '2', doc.at_xpath('//cardholderAuthentication/authenticationIndicator').content + assert_equal '1.00', doc.at_xpath('//transactionRequest/amount').content + end + end.respond_with(successful_purchase_response) + end + + def test_prioritize_authentication_value_params + three_d_secure_opts = { cavv: 'fake', eci: 'fake' } + stub_comms do + @gateway.purchase( + @amount, + @credit_card, + cardholder_authentication_value: 'E0Mvq8AAABEiMwARIjNEVWZ3iJk=', + authentication_indicator: '2', + three_d_secure: three_d_secure_opts + ) end.check_request do |endpoint, data, headers| parse(data) do |doc| - assert_equal "E0Mvq8AAABEiMwARIjNEVWZ3iJk=", doc.at_xpath("//cardholderAuthentication/cardholderAuthenticationValue").content - assert_equal "2", doc.at_xpath("//cardholderAuthentication/authenticationIndicator").content - assert_equal "1.00", doc.at_xpath("//transactionRequest/amount").content + assert_equal 'E0Mvq8AAABEiMwARIjNEVWZ3iJk=', doc.at_xpath('//cardholderAuthentication/cardholderAuthenticationValue').content + assert_equal '2', doc.at_xpath('//cardholderAuthentication/authenticationIndicator').content + assert_equal '1.00', doc.at_xpath('//transactionRequest/amount').content end end.respond_with(successful_purchase_response) end def test_capture_passing_extra_info response = stub_comms do - @gateway.capture(50, '123456789', description: "Yo", order_id: "Sweetness") + @gateway.capture(50, '123456789', description: 'Yo', order_id: 'Sweetness') end.check_request do |endpoint, data, headers| parse(data) do |doc| - assert_not_nil doc.at_xpath("//order/description"), data - assert_equal "Yo", doc.at_xpath("//order/description").content, data - assert_equal "Sweetness", doc.at_xpath("//order/invoiceNumber").content, data - assert_equal "0.50", doc.at_xpath("//transactionRequest/amount").content + assert_not_nil doc.at_xpath('//order/description'), data + assert_equal 'Yo', doc.at_xpath('//order/description').content, data + assert_equal 'Sweetness', doc.at_xpath('//order/invoiceNumber').content, data + assert_equal '0.50', doc.at_xpath('//transactionRequest/amount').content end end.respond_with(successful_capture_response) assert_success response @@ -702,17 +877,31 @@ def test_successful_refund assert_equal '2214602071#2224#refund', refund.authorization end + def test_successful_bank_refund + response = stub_comms do + @gateway.refund(50, '12345667', account_type: 'checking', routing_number: '123450987', account_number: '12345667', first_name: 'Louise', last_name: 'Belcher') + end.check_request do |endpoint, data, headers| + parse(data) do |doc| + assert_equal 'checking', doc.at_xpath('//transactionRequest/payment/bankAccount/accountType').content + assert_equal '123450987', doc.at_xpath('//transactionRequest/payment/bankAccount/routingNumber').content + assert_equal '12345667', doc.at_xpath('//transactionRequest/payment/bankAccount/accountNumber').content + assert_equal 'Louise Belcher', doc.at_xpath('//transactionRequest/payment/bankAccount/nameOnAccount').content + end + end.respond_with(successful_refund_response) + assert_success response + end + def test_refund_passing_extra_info response = stub_comms do - @gateway.refund(50, '123456789', card_number: @credit_card.number, first_name: "Bob", last_name: "Smith", zip: "12345", order_id: "1", description: "Refund for order 1") + @gateway.refund(50, '123456789', card_number: @credit_card.number, first_name: 'Bob', last_name: 'Smith', zip: '12345', order_id: '1', description: 'Refund for order 1') end.check_request do |endpoint, data, headers| parse(data) do |doc| - assert_equal "Bob", doc.at_xpath("//billTo/firstName").content, data - assert_equal "Smith", doc.at_xpath("//billTo/lastName").content, data - assert_equal "12345", doc.at_xpath("//billTo/zip").content, data - assert_equal "0.50", doc.at_xpath("//transactionRequest/amount").content - assert_equal "1", doc.at_xpath("//transactionRequest/order/invoiceNumber").content - assert_equal "Refund for order 1", doc.at_xpath("//transactionRequest/order/description").content + assert_equal 'Bob', doc.at_xpath('//billTo/firstName').content, data + assert_equal 'Smith', doc.at_xpath('//billTo/lastName').content, data + assert_equal '12345', doc.at_xpath('//billTo/zip').content, data + assert_equal '0.50', doc.at_xpath('//transactionRequest/amount').content + assert_equal '1', doc.at_xpath('//transactionRequest/order/invoiceNumber').content + assert_equal 'Refund for order 1', doc.at_xpath('//transactionRequest/order/description').content end end.respond_with(successful_purchase_response) assert_success response @@ -734,7 +923,7 @@ def test_successful_credit assert_success response assert_equal '2230004436', response.authorization.split('#')[0] - assert_equal "This transaction has been approved", response.message + assert_equal 'This transaction has been approved', response.message end def test_failed_credit @@ -742,7 +931,7 @@ def test_failed_credit response = @gateway.credit(@amount, @credit_card) assert_failure response - assert_equal "The credit card number is invalid", response.message + assert_equal 'The credit card number is invalid', response.message end def test_supported_countries @@ -757,16 +946,16 @@ def test_failure_without_response_reason_text response = stub_comms do @gateway.purchase(@amount, @credit_card) end.respond_with(no_message_response) - assert_equal "", response.message + assert_equal '', response.message end def test_response_under_review_by_fraud_service @gateway.expects(:ssl_post).returns(fraud_review_response) response = @gateway.purchase(@amount, @credit_card) - assert_failure response + assert_success response assert response.fraud_review? - assert_equal "Thank you! For security reasons your order is currently being reviewed", response.message + assert_equal 'Thank you! For security reasons your order is currently being reviewed', response.message end def test_avs_result @@ -777,7 +966,6 @@ def test_avs_result assert_equal 'Y', response.avs_result['street_match'] assert_equal 'Y', response.avs_result['postal_match'] - @gateway.expects(:ssl_post).returns(address_not_provided_avs_response) response = @gateway.purchase(@amount, @credit_card) @@ -797,17 +985,17 @@ def test_message response = stub_comms do @gateway.purchase(@amount, @credit_card) end.respond_with(no_match_cvv_response) - assert_equal "CVV does not match", response.message + assert_equal 'CVV does not match', response.message response = stub_comms do @gateway.purchase(@amount, @credit_card) end.respond_with(no_match_avs_response) - assert_equal "Street address matches, but 5-digit and 9-digit postal code do not match.", response.message + assert_equal 'Street address matches, but 5-digit and 9-digit postal code do not match.', response.message response = stub_comms do @gateway.purchase(@amount, @credit_card) end.respond_with(failed_purchase_response) - assert_equal "The credit card number is invalid", response.message + assert_equal 'The credit card number is invalid', response.message end def test_solution_id_is_added_to_post_data_parameters @@ -816,8 +1004,8 @@ def test_solution_id_is_added_to_post_data_parameters @gateway.authorize(@amount, @credit_card) end.check_request do |endpoint, data, headers| doc = parse(data) - assert_equal "A1000000", fields_from_doc(doc)["x_solution_id"], data - assert_equal "1.00", doc.at_xpath("//transactionRequest/amount").content + assert_equal 'A1000000', fields_from_doc(doc)['x_solution_id'], data + assert_equal '1.00', doc.at_xpath('//transactionRequest/amount').content end.respond_with(successful_authorize_response) ensure @gateway.class.application_id = nil @@ -826,7 +1014,7 @@ def test_solution_id_is_added_to_post_data_parameters def test_alternate_currency @gateway.expects(:ssl_post).returns(successful_purchase_response) - response = @gateway.purchase(@amount, @credit_card, currency: "GBP") + response = @gateway.purchase(@amount, @credit_card, currency: 'GBP') assert_success response end @@ -835,60 +1023,82 @@ def assert_no_has_customer_id(data) end def test_include_cust_id_for_numeric_values - stub_comms do - @gateway.purchase(@amount, @credit_card, customer: "123") + stub_comms do + @gateway.purchase(@amount, @credit_card, customer: '123') end.check_request do |endpoint, data, headers| parse(data) do |doc| - assert_not_nil doc.at_xpath("//customer/id"), data - assert_equal "123", doc.at_xpath("//customer/id").content, data - assert_equal "1.00", doc.at_xpath("//transactionRequest/amount").content + assert_not_nil doc.at_xpath('//customer/id'), data + assert_equal '123', doc.at_xpath('//customer/id').content, data + assert_equal '1.00', doc.at_xpath('//transactionRequest/amount').content end end.respond_with(successful_authorize_response) end - def test_dont_include_cust_id_for_non_numeric_values - stub_comms do - @gateway.purchase(@amount, @credit_card, customer: "bob@test.com") + def test_include_cust_id_for_word_character_values + stub_comms do + @gateway.purchase(@amount, @credit_card, customer: '4840_TT') + end.check_request do |endpoint, data, headers| + parse(data) do |doc| + assert_not_nil doc.at_xpath('//customer/id'), data + assert_equal '4840_TT', doc.at_xpath('//customer/id').content, data + assert_equal '1.00', doc.at_xpath('//transactionRequest/amount').content + end + end.respond_with(successful_authorize_response) + end + + def test_dont_include_cust_id_for_email_addresses + stub_comms do + @gateway.purchase(@amount, @credit_card, customer: 'bob@test.com') + end.check_request do |endpoint, data, headers| + doc = parse(data) + assert !doc.at_xpath('//customer/id'), data + assert_equal '1.00', doc.at_xpath('//transactionRequest/amount').content + end.respond_with(successful_authorize_response) + end + + def test_dont_include_cust_id_for_phone_numbers + stub_comms do + @gateway.purchase(@amount, @credit_card, customer: '111-123-1231') end.check_request do |endpoint, data, headers| doc = parse(data) - assert !doc.at_xpath("//customer/id"), data - assert_equal "1.00", doc.at_xpath("//transactionRequest/amount").content + assert !doc.at_xpath('//customer/id'), data + assert_equal '1.00', doc.at_xpath('//transactionRequest/amount').content end.respond_with(successful_authorize_response) end def test_includes_shipping_name_when_different_from_billing_name card = credit_card('4242424242424242', - first_name: "billing", - last_name: "name") + first_name: 'billing', + last_name: 'name') options = { - order_id: "a" * 21, - billing_address: address(name: "billing name"), - shipping_address: address(name: "shipping lastname") + order_id: 'a' * 21, + billing_address: address(name: 'billing name'), + shipping_address: address(name: 'shipping lastname') } stub_comms do @gateway.purchase(@amount, card, options) end.check_request do |endpoint, data, headers| parse(data) do |doc| - assert_equal "billing", doc.at_xpath("//billTo/firstName").text - assert_equal "name", doc.at_xpath("//billTo/lastName").text - assert_equal "shipping", doc.at_xpath("//shipTo/firstName").text - assert_equal "lastname", doc.at_xpath("//shipTo/lastName").text + assert_equal 'billing', doc.at_xpath('//billTo/firstName').text + assert_equal 'name', doc.at_xpath('//billTo/lastName').text + assert_equal 'shipping', doc.at_xpath('//shipTo/firstName').text + assert_equal 'lastname', doc.at_xpath('//shipTo/lastName').text end end.respond_with(successful_purchase_response) end def test_includes_shipping_name_when_passed_as_options card = credit_card('4242424242424242', - first_name: "billing", - last_name: "name") + first_name: 'billing', + last_name: 'name') - shipping_address = address(first_name: "shipping", last_name: "lastname") + shipping_address = address(first_name: 'shipping', last_name: 'lastname') shipping_address.delete(:name) options = { - order_id: "a" * 21, - billing_address: address(name: "billing name"), + order_id: 'a' * 21, + billing_address: address(name: 'billing name'), shipping_address: shipping_address } @@ -896,55 +1106,55 @@ def test_includes_shipping_name_when_passed_as_options @gateway.purchase(@amount, card, options) end.check_request do |endpoint, data, headers| parse(data) do |doc| - assert_equal "billing", doc.at_xpath("//billTo/firstName").text - assert_equal "name", doc.at_xpath("//billTo/lastName").text - assert_equal "shipping", doc.at_xpath("//shipTo/firstName").text - assert_equal "lastname", doc.at_xpath("//shipTo/lastName").text + assert_equal 'billing', doc.at_xpath('//billTo/firstName').text + assert_equal 'name', doc.at_xpath('//billTo/lastName').text + assert_equal 'shipping', doc.at_xpath('//shipTo/firstName').text + assert_equal 'lastname', doc.at_xpath('//shipTo/lastName').text end end.respond_with(successful_purchase_response) end def test_truncation card = credit_card('4242424242424242', - first_name: "a" * 51, - last_name: "a" * 51, + first_name: 'a' * 51, + last_name: 'a' * 51 ) options = { - order_id: "a" * 21, - description: "a" * 256, + order_id: 'a' * 21, + description: 'a' * 256, billing_address: address( - company: "a" * 51, - address1: "a" * 61, - city: "a" * 41, - state: "a" * 41, - zip: "a" * 21, - country: "a" * 61, + company: 'a' * 51, + address1: 'a' * 61, + city: 'a' * 41, + state: 'a' * 41, + zip: 'a' * 21, + country: 'a' * 61 ), shipping_address: address( - name: ["a" * 51, "a" * 51].join(" "), - company: "a" * 51, - address1: "a" * 61, - city: "a" * 41, - state: "a" * 41, - zip: "a" * 21, - country: "a" * 61, + name: ['a' * 51, 'a' * 51].join(' '), + company: 'a' * 51, + address1: 'a' * 61, + city: 'a' * 41, + state: 'a' * 41, + zip: 'a' * 21, + country: 'a' * 61 ) } stub_comms do @gateway.purchase(@amount, card, options) end.check_request do |endpoint, data, headers| - assert_truncated(data, 20, "//refId") - assert_truncated(data, 255, "//description") - assert_address_truncated(data, 50, "firstName") - assert_address_truncated(data, 50, "lastName") - assert_address_truncated(data, 50, "company") - assert_address_truncated(data, 60, "address") - assert_address_truncated(data, 40, "city") - assert_address_truncated(data, 40, "state") - assert_address_truncated(data, 20, "zip") - assert_address_truncated(data, 60, "country") + assert_truncated(data, 20, '//refId') + assert_truncated(data, 255, '//description') + assert_address_truncated(data, 50, 'firstName') + assert_address_truncated(data, 50, 'lastName') + assert_address_truncated(data, 50, 'company') + assert_address_truncated(data, 60, 'address') + assert_address_truncated(data, 40, 'city') + assert_address_truncated(data, 40, 'state') + assert_address_truncated(data, 20, 'zip') + assert_address_truncated(data, 60, 'country') end.respond_with(successful_purchase_response) end @@ -981,15 +1191,15 @@ def test_supports_scrubbing? def test_successful_apple_pay_authorization_with_network_tokenization credit_card = network_tokenization_credit_card('4242424242424242', - :payment_cryptogram => "111111111100cryptogram" + :payment_cryptogram => '111111111100cryptogram' ) response = stub_comms do @gateway.authorize(@amount, credit_card) end.check_request do |endpoint, data, headers| parse(data) do |doc| - assert_equal credit_card.payment_cryptogram, doc.at_xpath("//creditCard/cryptogram").content - assert_equal credit_card.number, doc.at_xpath("//creditCard/cardNumber").content + assert_equal credit_card.payment_cryptogram, doc.at_xpath('//creditCard/cryptogram').content + assert_equal credit_card.number, doc.at_xpath('//creditCard/cardNumber').content end end.respond_with(successful_authorize_response) @@ -1001,15 +1211,15 @@ def test_successful_apple_pay_authorization_with_network_tokenization def test_failed_apple_pay_authorization_with_network_tokenization_not_supported credit_card = network_tokenization_credit_card('4242424242424242', - :payment_cryptogram => "111111111100cryptogram" + :payment_cryptogram => '111111111100cryptogram' ) response = stub_comms do @gateway.authorize(@amount, credit_card) end.check_request do |endpoint, data, headers| parse(data) do |doc| - assert_equal credit_card.payment_cryptogram, doc.at_xpath("//creditCard/cryptogram").content - assert_equal credit_card.number, doc.at_xpath("//creditCard/cardNumber").content + assert_equal credit_card.payment_cryptogram, doc.at_xpath('//creditCard/cryptogram').content + assert_equal credit_card.number, doc.at_xpath('//creditCard/cardNumber').content end end.respond_with(network_tokenization_not_supported_response) @@ -1021,10 +1231,10 @@ def test_supports_network_tokenization_true @gateway.supports_network_tokenization? end.check_request do |endpoint, data, headers| parse(data) do |doc| - assert_equal "authOnlyTransaction", doc.at_xpath("//transactionType").content - assert_equal "0.01", doc.at_xpath("//amount").content - assert_equal "EHuWW9PiBkWvqE5juRwDzAUFBAk=", doc.at_xpath("//creditCard/cryptogram").content - assert_equal "4111111111111111", doc.at_xpath("//creditCard/cardNumber").content + assert_equal 'authOnlyTransaction', doc.at_xpath('//transactionType').content + assert_equal '0.01', doc.at_xpath('//amount').content + assert_equal 'EHuWW9PiBkWvqE5juRwDzAUFBAk=', doc.at_xpath('//creditCard/cryptogram').content + assert_equal '4111111111111111', doc.at_xpath('//creditCard/cardNumber').content end end.respond_with(successful_authorize_response) @@ -1036,10 +1246,10 @@ def test_supports_network_tokenization_false @gateway.supports_network_tokenization? end.check_request do |endpoint, data, headers| parse(data) do |doc| - assert_equal "authOnlyTransaction", doc.at_xpath("//transactionType").content - assert_equal "0.01", doc.at_xpath("//amount").content - assert_equal "EHuWW9PiBkWvqE5juRwDzAUFBAk=", doc.at_xpath("//creditCard/cryptogram").content - assert_equal "4111111111111111", doc.at_xpath("//creditCard/cardNumber").content + assert_equal 'authOnlyTransaction', doc.at_xpath('//transactionType').content + assert_equal '0.01', doc.at_xpath('//amount').content + assert_equal 'EHuWW9PiBkWvqE5juRwDzAUFBAk=', doc.at_xpath('//creditCard/cryptogram').content + assert_equal '4111111111111111', doc.at_xpath('//creditCard/cardNumber').content end end.respond_with(network_tokenization_not_supported_response) @@ -1122,23 +1332,23 @@ def parse(data) end def fields_from_doc(doc) - assert_not_nil doc.at_xpath("//userFields/userField/name") - doc.xpath("//userFields/userField").inject({}) do |hash, element| - hash[element.at_xpath("name").content] = element.at_xpath("value").content + assert_not_nil doc.at_xpath('//userFields/userField/name') + doc.xpath('//userFields/userField').inject({}) do |hash, element| + hash[element.at_xpath('name').content] = element.at_xpath('value').content hash end end def settings_from_doc(doc) - assert_not_nil doc.at_xpath("//transactionSettings/setting/settingName") - doc.xpath("//transactionSettings/setting").inject({}) do |hash, element| - hash[element.at_xpath("settingName").content] = element.at_xpath("settingValue").content + assert_not_nil doc.at_xpath('//transactionSettings/setting/settingName') + doc.xpath('//transactionSettings/setting').inject({}) do |hash, element| + hash[element.at_xpath('settingName').content] = element.at_xpath('settingValue').content hash end end def assert_truncated(data, expected_size, field) - assert_equal ("a" * expected_size), parse(data).at_xpath(field).text, data + assert_equal ('a' * expected_size), parse(data).at_xpath(field).text, data end def assert_address_truncated(data, expected_size, field) @@ -1986,6 +2196,23 @@ def successful_purchase_using_stored_card_response eos end + def successful_purchase_using_stored_card_response_with_pipe_delimiter + <<-eos + <?xml version="1.0" encoding="UTF-8"?> + <createCustomerProfileTransactionResponse xmlns="AnetApi/xml/v1/schema/AnetApiSchema.xsd" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> + <refId>1</refId> + <messages> + <resultCode>Ok</resultCode> + <message> + <code>I00001</code> + <text>Successful.</text> + </message> + </messages> + <directResponse>1|1|1|This transaction has been approved.|8HUT72|Y|2235700270|1|description, with, commas|1.01|CC|auth_capture|e385c780422f4bd182c4|Longbob|Longsen||||n/a|||||||||||||||||||4A20EEAF89018FF075899DDB332E9D35||2|||||||||||XXXX2224|Visa||||||||||||||||</directResponse> + </createCustomerProfileTransactionResponse> + eos + end + def failed_purchase_using_stored_card_response <<-eos <?xml version="1.0" encoding="UTF-8"?> @@ -2085,7 +2312,6 @@ def failed_refund_using_stored_card_response </messages> </createCustomerProfileTransactionResponse> eos - end def successful_void_using_stored_card_response @@ -2197,4 +2423,40 @@ def credentials_are_bogus_response </authenticateTestResponse> eos end + + def failed_refund_for_unsettled_payment_response + <<-eos + <?xml version="1.0" encoding="utf-8"?> + <createTransactionResponse xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="AnetApi/xml/v1/schema/AnetApiSchema.xsd"> + <messages> + <resultCode>Error</resultCode> + <message> + <code>E00027</code> + <text>The transaction was unsuccessful.</text> + </message> + </messages> + <transactionResponse> + <responseCode>3</responseCode> + <authCode/> + <avsResultCode>P</avsResultCode> + <cvvResultCode/> + <cavvResultCode/> + <transId>0</transId> + <refTransID/> + <transHash/> + <testRequest>0</testRequest> + <accountNumber>XXXX0001</accountNumber> + <accountType>Visa</accountType> + <errors> + <error> + <errorCode>54</errorCode> + <errorText>The referenced transaction does not meet the criteria for issuing a credit.</errorText> + </error> + </errors> + <userFields/> + <transHashSha2/> + </transactionResponse> + </createTransactionResponse> + eos + end end diff --git a/test/unit/gateways/axcessms_test.rb b/test/unit/gateways/axcessms_test.rb index 62174c6e493..e87a092498b 100644 --- a/test/unit/gateways/axcessms_test.rb +++ b/test/unit/gateways/axcessms_test.rb @@ -10,23 +10,23 @@ def setup @gateway = AxcessmsGateway.new(fixtures(:axcessms)) @amount = 1500 - @credit_card = credit_card("4200000000000000", month: 05, year: 2022) - @declined_card = credit_card("4444444444444444", month: 05, year: 2022) - @mode = "CONNECTOR_TEST" + @credit_card = credit_card('4200000000000000', month: 05, year: 2022) + @declined_card = credit_card('4444444444444444', month: 05, year: 2022) + @mode = 'CONNECTOR_TEST' @options = { order_id: generate_unique_id, - email: "customer@example.com", + email: 'customer@example.com', description: "Order Number #{Time.now.to_f.divmod(2473)[1]}", - ip: "0.0.0.0", + ip: '0.0.0.0', mode: @mode, billing_address: { - :address1 => "10 Marklar St", - :address2 => "Musselburgh", - :city => "Dunedin", - :zip => "9013", - :state => "Otago", - :country => "NZ" + :address1 => '10 Marklar St', + :address2 => 'Musselburgh', + :city => 'Dunedin', + :zip => '9013', + :state => 'Otago', + :country => 'NZ' } } end @@ -71,75 +71,75 @@ def test_successful_capture @gateway.expects(:ssl_post).returns(successful_capture_response) response = @gateway.capture(@amount, TEST_AUTHORIZATION, @options) assert_success response - assert response.params["reference_id"], TEST_AUTHORIZATION + assert response.params['reference_id'], TEST_AUTHORIZATION end def test_successful_refund @gateway.expects(:ssl_post).returns(successful_refund_response) response = @gateway.refund(@amount - 30, TEST_PURCHASE, @options) assert_success response - assert response.params["reference_id"], TEST_PURCHASE + assert response.params['reference_id'], TEST_PURCHASE end def test_successful_void @gateway.expects(:ssl_post).returns(successful_void_response) response = @gateway.void(TEST_AUTHORIZATION, @options) assert_success response - assert response.params["reference_id"], TEST_AUTHORIZATION + assert response.params['reference_id'], TEST_AUTHORIZATION end def test_unauthorized_capture @gateway.expects(:ssl_post).returns(failed_capture_response) - response = @gateway.capture(@amount, "authorization", @options) + response = @gateway.capture(@amount, 'authorization', @options) assert_failure response - assert_equal "Reference Error - capture needs at least one successful transaction of type (PA)", response.message + assert_equal 'Reference Error - capture needs at least one successful transaction of type (PA)', response.message end def test_failed_refund @gateway.expects(:ssl_post).returns(failed_refund_response) - response = @gateway.refund(@amount - 30, "authorization", @options) + response = @gateway.refund(@amount - 30, 'authorization', @options) assert_failure response - assert_equal "Configuration Validation - Invalid payment data. You are not configured for this currency or sub type (country or brand)", response.message + assert_equal 'Configuration Validation - Invalid payment data. You are not configured for this currency or sub type (country or brand)', response.message end def test_failed_void @gateway.expects(:ssl_post).returns(failed_void_response) - response = @gateway.refund(@amount - 30, "authorization", @options) + response = @gateway.refund(@amount - 30, 'authorization', @options) assert_failure response - assert_equal "Reference Error - reversal needs at least one successful transaction of type (CP or DB or RB or PA)", response.message + assert_equal 'Reference Error - reversal needs at least one successful transaction of type (CP or DB or RB or PA)', response.message end def test_authorize_using_reference_sets_proper_elements stub_comms do - @gateway.authorize(@amount, "MY_AUTHORIZE_VALUE", @options) + @gateway.authorize(@amount, 'MY_AUTHORIZE_VALUE', @options) end.check_request do |endpoint, body, headers| - assert_xpath_text(body, "//ReferenceID", "MY_AUTHORIZE_VALUE") + assert_xpath_text(body, '//ReferenceID', 'MY_AUTHORIZE_VALUE') assert_no_match(/<Account>/, body) end.respond_with(successful_authorize_response) end def test_purchase_using_reference_sets_proper_elements stub_comms do - @gateway.purchase(@amount, "MY_AUTHORIZE_VALUE", @options) + @gateway.purchase(@amount, 'MY_AUTHORIZE_VALUE', @options) end.check_request do |endpoint, body, headers| - assert_xpath_text(body, "//ReferenceID", "MY_AUTHORIZE_VALUE") + assert_xpath_text(body, '//ReferenceID', 'MY_AUTHORIZE_VALUE') assert_no_match(/<Account>/, body) end.respond_with(successful_authorize_response) end def test_setting_mode_sets_proper_element stub_comms do - @gateway.purchase(@amount, "MY_AUTHORIZE_VALUE", {mode: "CRAZY_TEST_MODE"}) + @gateway.purchase(@amount, 'MY_AUTHORIZE_VALUE', {mode: 'CRAZY_TEST_MODE'}) end.check_request do |endpoint, body, headers| - assert_xpath_text(body, "//Transaction/@mode", "CRAZY_TEST_MODE") + assert_xpath_text(body, '//Transaction/@mode', 'CRAZY_TEST_MODE') end.respond_with(successful_authorize_response) end def test_defaults_to_integrator_test stub_comms do - @gateway.purchase(@amount, "MY_AUTHORIZE_VALUE", {}) + @gateway.purchase(@amount, 'MY_AUTHORIZE_VALUE', {}) end.check_request do |endpoint, body, headers| - assert_xpath_text(body, "//Transaction/@mode", "INTEGRATOR_TEST") + assert_xpath_text(body, '//Transaction/@mode', 'INTEGRATOR_TEST') end.respond_with(successful_authorize_response) end @@ -167,10 +167,10 @@ def test_failed_verify private def assert_xpath_text(xml, xpath, expected_text) - xml = CGI.unescape(xml.gsub("load=", "")) + xml = CGI.unescape(xml.gsub('load=', '')) root = REXML::Document.new(xml).root element = REXML::XPath.first(root, xpath) - actual_text = xpath.include?("@") ? element.value : element.text + actual_text = xpath.include?('@') ? element.value : element.text assert_equal expected_text, actual_text, %{Expected to find the text "#{expected_text}" within the XML element with path "#{xpath}", but instead found the text "#{actual_text}" in the following XML:\n#{xml}} end diff --git a/test/unit/gateways/balanced_test.rb b/test/unit/gateways/balanced_test.rb index 396af8a95d6..68e98b4f0d4 100644 --- a/test/unit/gateways/balanced_test.rb +++ b/test/unit/gateways/balanced_test.rb @@ -32,9 +32,9 @@ def test_successful_purchase def test_successful_purchase_with_outside_token response = stub_comms(@gateway, :ssl_request) do - @gateway.purchase(@amount, "/cards/CCVOX2d7Ar6Ze5TOxHsebeH", @options) + @gateway.purchase(@amount, '/cards/CCVOX2d7Ar6Ze5TOxHsebeH', @options) end.check_request do |method, endpoint, data, headers| - assert_equal("https://api.balancedpayments.com/cards/CCVOX2d7Ar6Ze5TOxHsebeH/debits", endpoint) + assert_equal('https://api.balancedpayments.com/cards/CCVOX2d7Ar6Ze5TOxHsebeH/debits', endpoint) end.respond_with(debits_response) assert_success response @@ -80,11 +80,11 @@ def test_passing_appears_on_statement ).then.returns( appears_on_response ) - options = @options.merge(appears_on_statement_as: "Homer Electric") + options = @options.merge(appears_on_statement_as: 'Homer Electric') assert response = @gateway.purchase(@amount, @credit_card, options) assert_success response - assert_equal "BAL*Homer Electric", response.params['debits'][0]['appears_on_statement_as'] + assert_equal 'BAL*Homer Electric', response.params['debits'][0]['appears_on_statement_as'] end def test_authorize_and_capture @@ -146,10 +146,10 @@ def test_void_authorization amount = @amount assert auth = @gateway.authorize(amount, @credit_card, @options) assert_success auth - number = auth.params["card_holds"][0]["href"] + number = auth.params['card_holds'][0]['href'] assert void = @gateway.void(number) assert_success void - assert void.params["card_holds"][0]['voided_at'] + assert void.params['card_holds'][0]['voided_at'] end def test_refund_purchase @@ -200,7 +200,7 @@ def test_refund_pending_status assert refund = @gateway.refund(@amount, debit.authorization) assert_success refund - assert_equal "pending", refund.params['refunds'][0]['status'] + assert_equal 'pending', refund.params['refunds'][0]['status'] assert_equal @amount, refund.params['refunds'][0]['amount'] end @@ -222,7 +222,7 @@ def test_successful_purchase_with_legacy_outside_token response = stub_comms(@gateway, :ssl_request) do @gateway.purchase(@amount, legacy_outside_token, @options) end.check_request do |method, endpoint, data, headers| - assert_equal("https://api.balancedpayments.com/cards/CC7m1Mtqk6rVJo5tcD1qitAC/debits", endpoint) + assert_equal('https://api.balancedpayments.com/cards/CC7m1Mtqk6rVJo5tcD1qitAC/debits', endpoint) end.respond_with(debits_response) assert_success response @@ -231,42 +231,42 @@ def test_successful_purchase_with_legacy_outside_token end def test_capturing_legacy_authorizations - v1_authorization = "/v1/marketplaces/TEST-MP73SaFdpQePv9dOaG5wXOGO/holds/HL7dYMhpVBcqAYqxLF5mZtQ5" - v11_authorization = "/card_holds/HL7dYMhpVBcqAYqxLF5mZtQ5/debits||/card_holds/HL7dYMhpVBcqAYqxLF5mZtQ5" + v1_authorization = '/v1/marketplaces/TEST-MP73SaFdpQePv9dOaG5wXOGO/holds/HL7dYMhpVBcqAYqxLF5mZtQ5' + v11_authorization = '/card_holds/HL7dYMhpVBcqAYqxLF5mZtQ5/debits||/card_holds/HL7dYMhpVBcqAYqxLF5mZtQ5' [v1_authorization, v11_authorization].each do |authorization| stub_comms(@gateway, :ssl_request) do @gateway.capture(@amount, authorization) end.check_request do |method, endpoint, data, headers| - assert_equal("https://api.balancedpayments.com/card_holds/HL7dYMhpVBcqAYqxLF5mZtQ5/debits", endpoint) + assert_equal('https://api.balancedpayments.com/card_holds/HL7dYMhpVBcqAYqxLF5mZtQ5/debits', endpoint) end.respond_with(authorized_debits_response) end end def test_voiding_legacy_authorizations - v1_authorization = "/v1/marketplaces/TEST-MP73SaFdpQePv9dOaG5wXOGO/holds/HL7dYMhpVBcqAYqxLF5mZtQ5" - v11_authorization = "/card_holds/HL7dYMhpVBcqAYqxLF5mZtQ5/debits||/card_holds/HL7dYMhpVBcqAYqxLF5mZtQ5" + v1_authorization = '/v1/marketplaces/TEST-MP73SaFdpQePv9dOaG5wXOGO/holds/HL7dYMhpVBcqAYqxLF5mZtQ5' + v11_authorization = '/card_holds/HL7dYMhpVBcqAYqxLF5mZtQ5/debits||/card_holds/HL7dYMhpVBcqAYqxLF5mZtQ5' [v1_authorization, v11_authorization].each do |authorization| stub_comms(@gateway, :ssl_request) do @gateway.void(authorization) end.check_request do |method, endpoint, data, headers| assert_equal :put, method - assert_equal("https://api.balancedpayments.com/card_holds/HL7dYMhpVBcqAYqxLF5mZtQ5", endpoint) + assert_equal('https://api.balancedpayments.com/card_holds/HL7dYMhpVBcqAYqxLF5mZtQ5', endpoint) assert_match %r{\bis_void=true\b}, data end.respond_with(voided_hold_response) end end def test_refunding_legacy_purchases - v1_authorization = "/v1/marketplaces/TEST-MP73SaFdpQePv9dOaG5wXOGO/debits/WD2x6vLS7RzHYEcdymqRyNAO" - v11_authorization = "|/debits/WD2x6vLS7RzHYEcdymqRyNAO/refunds|" + v1_authorization = '/v1/marketplaces/TEST-MP73SaFdpQePv9dOaG5wXOGO/debits/WD2x6vLS7RzHYEcdymqRyNAO' + v11_authorization = '|/debits/WD2x6vLS7RzHYEcdymqRyNAO/refunds|' [v1_authorization, v11_authorization].each do |authorization| stub_comms(@gateway, :ssl_request) do @gateway.refund(nil, authorization) end.check_request do |method, endpoint, data, headers| - assert_equal("https://api.balancedpayments.com/debits/WD2x6vLS7RzHYEcdymqRyNAO/refunds", endpoint) + assert_equal('https://api.balancedpayments.com/debits/WD2x6vLS7RzHYEcdymqRyNAO/refunds', endpoint) end.respond_with(refunds_response) end end @@ -277,7 +277,7 @@ def test_passing_address @gateway.purchase(@amount, @credit_card, address: a) end.check_request do |method, endpoint, data, headers| next if endpoint =~ /debits/ - clean = proc{|s| Regexp.escape(CGI.escape(s))} + clean = proc { |s| Regexp.escape(CGI.escape(s)) } assert_match(%r{address\[line1\]=#{clean[a[:address1]]}}, data) assert_match(%r{address\[line2\]=#{clean[a[:address2]]}}, data) assert_match(%r{address\[city\]=#{clean[a[:city]]}}, data) @@ -302,7 +302,7 @@ def test_passing_address_without_zip def test_passing_address_with_blank_zip response = stub_comms(@gateway, :ssl_request) do - @gateway.purchase(@amount, @credit_card, address: address(zip: " ")) + @gateway.purchase(@amount, @credit_card, address: address(zip: ' ')) end.check_request do |method, endpoint, data, headers| next if endpoint =~ /debits/ assert_no_match(%r{address}, data) @@ -539,7 +539,6 @@ def authorized_partial_debits_response RESPONSE end - def declined_response <<-RESPONSE { diff --git a/test/unit/gateways/bank_frick_test.rb b/test/unit/gateways/bank_frick_test.rb index 8ab20b5e9be..4c49abc68c5 100644 --- a/test/unit/gateways/bank_frick_test.rb +++ b/test/unit/gateways/bank_frick_test.rb @@ -6,7 +6,7 @@ def setup sender: 'sender-uuid', channel: 'channel-uuid', userid: 'user-uuid', - userpwd: 'password', + userpwd: 'password' ) @credit_card = credit_card diff --git a/test/unit/gateways/banwire_test.rb b/test/unit/gateways/banwire_test.rb index f943718a62c..faa341c1f97 100644 --- a/test/unit/gateways/banwire_test.rb +++ b/test/unit/gateways/banwire_test.rb @@ -9,9 +9,9 @@ def setup :currency => 'MXN') @credit_card = credit_card('5204164299999999', - :month => 11, - :year => 2012, - :verification_value => '999') + :month => 11, + :year => 2012, + :verification_value => '999') @amount = 100 @options = { @@ -22,10 +22,10 @@ def setup } @amex_credit_card = credit_card('375932134599999', - :month => 3, - :year => 2017, - :first_name => "Banwire", - :last_name => "Test Card") + :month => 3, + :year => 2017, + :first_name => 'Banwire', + :last_name => 'Test Card') @amex_options = { :order_id => '2', :email => 'test@email.com', @@ -61,7 +61,7 @@ def test_invalid_json assert_match %r{Invalid response received from the Banwire API}, response.message end - #American Express requires address and zipcode + # American Express requires address and zipcode def test_successful_amex_purchase response = stub_comms do @gateway.purchase(@amount, @amex_credit_card, @amex_options) @@ -75,7 +75,7 @@ def test_successful_amex_purchase assert response.test? end - #American Express requires address and zipcode + # American Express requires address and zipcode def test_unsuccessful_amex_request @gateway.expects(:ssl_post).returns(failed_purchase_amex_response) @@ -89,7 +89,6 @@ def test_transcript_scrubbing assert_equal scrubbed_transcript, @gateway.scrub(transcript) end - private def failed_purchase_response diff --git a/test/unit/gateways/barclaycard_smartpay_test.rb b/test/unit/gateways/barclaycard_smartpay_test.rb index 0febeb7ce32..2bb8443b85d 100644 --- a/test/unit/gateways/barclaycard_smartpay_test.rb +++ b/test/unit/gateways/barclaycard_smartpay_test.rb @@ -1,6 +1,8 @@ require 'test_helper' class BarclaycardSmartpayTest < Test::Unit::TestCase + include CommStub + def setup @gateway = BarclaycardSmartpayGateway.new( company: 'company', @@ -9,6 +11,7 @@ def setup ) @credit_card = credit_card + @three_ds_enrolled_card = credit_card('4212345678901237', brand: :visa) @amount = 100 @options = { @@ -17,7 +20,77 @@ def setup description: 'Store Purchase' } - @avs_address = @options + @options_with_alternate_address = { + order_id: '1', + billing_address: { + name: 'PU JOI SO', + address1: '新北市店溪路3579號139樓', + company: 'Widgets Inc', + city: '新北市', + zip: '231509', + country: 'TW', + phone: '(555)555-5555', + fax: '(555)555-6666' + }, + email: 'pujoi@so.com', + customer: 'PU JOI SO', + description: 'Store Purchase' + } + + @options_with_house_number_and_street = { + order_id: '1', + street: 'Top Level Drive', + house_number: '1000', + billing_address: address, + description: 'Store Purchase' + } + + @options_with_shipping_house_number_and_shipping_street = { + order_id: '1', + street: 'Top Level Drive', + house_number: '1000', + billing_address: address, + shipping_house_number: '999', + shipping_street: 'Downtown Loop', + shipping_address: { + name: 'PU JOI SO', + address1: '新北市店溪路3579號139樓', + company: 'Widgets Inc', + city: '新北市', + zip: '231509', + country: 'TW', + phone: '(555)555-5555', + fax: '(555)555-6666' + }, + description: 'Store Purchase' + } + + @options_with_credit_fields = { + order_id: '1', + billing_address: { + name: 'Jim Smith', + address1: '100 Street', + company: 'Widgets Inc', + city: 'Ottawa', + state: 'ON', + zip: 'K1C2N6', + country: 'CA', + phone: '(555)555-5555', + fax: '(555)555-6666'}, + email: 'long@bob.com', + customer: 'Longbob Longsen', + description: 'Store Purchase', + date_of_birth: '1990-10-11', + entity_type: 'NaturalPerson', + nationality: 'US', + shopper_name: { + firstName: 'Longbob', + lastName: 'Longsen', + gender: 'MALE' + } + } + + @avs_address = @options.clone @avs_address.update(billing_address: { name: 'Jim Smith', street: 'Test AVS result', @@ -29,6 +102,72 @@ def setup }) end + def test_successful_purchase + response = stub_comms do + @gateway.purchase(@amount, @credit_card, @options) + end.respond_with(successful_authorize_response, successful_capture_response) + + assert_success response + assert_equal '7914002629995504#8814002632606717', response.authorization + assert response.test? + end + + def test_successful_authorize_with_alternate_address + response = stub_comms do + @gateway.authorize(@amount, @credit_card, @options_with_alternate_address) + end.check_request do |endpoint, data, headers| + assert_match(/billingAddress.houseNumberOrName=%E6%96%B0%E5%8C%97%E5%B8%82%E5%BA%97%E6%BA%AA%E8%B7%AF3579%E8%99%9F139%E6%A8%93/, data) + assert_match(/billingAddress.street=Not\+Provided/, data) + end.respond_with(successful_authorize_response) + + assert_success response + assert_equal '7914002629995504', response.authorization + assert response.test? + end + + def test_successful_authorize_with_house_number_and_street + response = stub_comms do + @gateway.authorize(@amount, + @credit_card, + @options_with_house_number_and_street) + end.check_request do |endpoint, data, headers| + assert_match(/billingAddress.street=Top\+Level\+Drive/, data) + assert_match(/billingAddress.houseNumberOrName=1000/, data) + end.respond_with(successful_authorize_response) + + assert response + assert_success response + assert_equal '7914002629995504', response.authorization + end + + def test_successful_authorize_with_shipping_house_number_and_street + response = stub_comms do + @gateway.authorize(@amount, + @credit_card, + @options_with_shipping_house_number_and_shipping_street) + end.check_request do |endpoint, data, headers| + assert_match(/billingAddress.street=Top\+Level\+Drive/, data) + assert_match(/billingAddress.houseNumberOrName=1000/, data) + assert_match(/deliveryAddress.street=Downtown\+Loop/, data) + assert_match(/deliveryAddress.houseNumberOrName=999/, data) + end.respond_with(successful_authorize_response) + + assert response + assert_success response + assert_equal '7914002629995504', response.authorization + end + + def test_successful_authorize_with_extra_options + response = stub_comms do + @gateway.authorize(@amount, @credit_card, @options.merge(shopper_interaction: 'ContAuth', device_fingerprint: 'abcde123')) + end.check_request do |endpoint, data, headers| + assert_match(/shopperInteraction=ContAuth/, data) + assert_match(/deviceFingerprint=abcde123/, data) + end.respond_with(successful_authorize_response) + + assert_success response + end + def test_successful_authorize @gateway.stubs(:ssl_post).returns(successful_authorize_response) @@ -38,6 +177,18 @@ def test_successful_authorize assert response.test? end + def test_successful_authorize_with_3ds + @gateway.stubs(:ssl_post).returns(successful_authorize_with_3ds_response) + + response = @gateway.authorize(@amount, @three_ds_enrolled_card, @options) + + assert_equal '8815161318854998', response.authorization + refute response.params['issuerUrl'].blank? + refute response.params['md'].blank? + refute response.params['paRequest'].blank? + assert response.test? + end + def test_failed_authorize @gateway.stubs(:ssl_post).returns(failed_authorize_response) @@ -51,31 +202,48 @@ def test_successful_capture response = @gateway.capture(@amount, '7914002629995504', @options) assert_success response + assert_equal '7914002629995504#8814002632606717', response.authorization assert response.test? end def test_failed_capture - @gateway.stubs(:ssl_post).raises(ActiveMerchant::ResponseError.new(stub(:code => '500', :body => failed_capture_response))) + @gateway.stubs(:ssl_post).raises(ActiveMerchant::ResponseError.new(stub(:code => '422', :body => failed_capture_response))) response = @gateway.capture(@amount, '0000000000000000', @options) assert_failure response + assert_equal('167: Original pspReference required for this operation', response.message) assert response.test? end - def test_successful_refund - @gateway.expects(:ssl_post).returns(successful_refund_response) + def test_legacy_capture_psp_reference_passed_for_refund + response = stub_comms do + @gateway.refund(@amount, '8814002632606717', @options) + end.check_request do |endpoint, data, headers| + assert_match(/originalReference=8814002632606717/, data) + end.respond_with(successful_refund_response) - response = @gateway.refund(@amount, '7914002629995504', @options) assert_success response assert response.test? + end + + def test_successful_refund + response = stub_comms do + @gateway.refund(@amount, '7914002629995504#8814002632606717', @options) + end.check_request do |endpoint, data, headers| + assert_match(/originalReference=7914002629995504&/, data) + assert_no_match(/8814002632606717/, data) + end.respond_with(successful_refund_response) + assert_success response + assert response.test? end def test_failed_refund - @gateway.stubs(:ssl_post).raises(ActiveMerchant::ResponseError.new(stub(:code => '500', :body => failed_refund_response))) + @gateway.stubs(:ssl_post).raises(ActiveMerchant::ResponseError.new(stub(:code => '422', :body => failed_refund_response))) response = @gateway.refund(@amount, '0000000000000000', @options) assert_failure response + assert_equal('137: Invalid amount specified', response.message) assert response.test? end @@ -93,6 +261,41 @@ def test_failed_credit assert_failure response end + def test_credit_contains_all_fields + response = stub_comms do + @gateway.credit(@amount, @credit_card, @options_with_credit_fields) + end.check_request do |endpoint, data, headers| + assert_match(%r{/refundWithData}, endpoint) + assert_match(/dateOfBirth=1990-10-11&/, data) + assert_match(/entityType=NaturalPerson&/, data) + assert_match(/nationality=US&/, data) + assert_match(/shopperName.firstName=Longbob&/, data) + end.respond_with(successful_credit_response) + + assert_success response + assert response.test? + end + + def test_successful_third_party_payout + response = stub_comms do + @gateway.credit(@amount, @credit_card, @options_with_credit_fields.merge({third_party_payout: true})) + end.check_request do |endpoint, data, headers| + if /storeDetailAndSubmitThirdParty/ =~ endpoint + assert_match(%r{/storeDetailAndSubmitThirdParty}, endpoint) + assert_match(/dateOfBirth=1990-10-11&/, data) + assert_match(/entityType=NaturalPerson&/, data) + assert_match(/nationality=US&/, data) + assert_match(/shopperName.firstName=Longbob&/, data) + assert_match(/recurring\.contract=PAYOUT/, data) + else + assert_match(/originalReference=/, data) + end + end.respond_with(successful_payout_store_response, successful_payout_confirm_response) + + assert_success response + assert response.test? + end + def test_successful_void @gateway.expects(:ssl_post).returns(successful_void_response) @@ -113,18 +316,29 @@ def test_unsuccessful_verify response = @gateway.verify(@credit_card, @options) assert_failure response - assert_equal "Refused", response.message + assert_equal 'Refused', response.message end - def test_fractional_currency - @gateway.expects(:ssl_post).returns(successful_authorize_response) - @gateway.expects(:post_data).with do |params| - '100' == params['amount.value'] && 'JPY' == params['amount.currency'] - end + def test_authorize_nonfractional_currency + response = stub_comms do + @gateway.authorize(@amount, @credit_card, @options.merge(currency: 'JPY')) + end.check_request do |endpoint, data, headers| + assert_match(/amount.value=1/, data) + assert_match(/amount.currency=JPY/, data) + end.respond_with(successful_authorize_response) + + assert_success response + end - @options[:currency] = 'JPY' + def test_authorize_three_decimal_currency + response = stub_comms do + @gateway.authorize(@amount, @credit_card, @options.merge(currency: 'OMR')) + end.check_request do |endpoint, data, headers| + assert_match(/amount.value=100/, data) + assert_match(/amount.currency=OMR/, data) + end.respond_with(successful_authorize_response) - @gateway.authorize(@amount, @credit_card, @options) + assert_success response end def test_successful_store @@ -146,7 +360,8 @@ def test_avs_result @gateway.expects(:ssl_post).returns(failed_avs_response) response = @gateway.authorize(@amount, @credit_card, @avs_address) - assert_equal "N", response.avs_result['code'] + assert_failure response + assert_equal 'N', response.avs_result['code'] assert response.test? end @@ -154,12 +369,32 @@ def test_transcript_scrubbing assert_equal scrubbed_transcript, @gateway.scrub(transcript) end + def test_proper_error_response_handling + response = stub_comms do + @gateway.purchase(@amount, @credit_card, @options) + end.respond_with(configuration_error_response) + + message = "#{response.params['errorCode']}: #{response.params['message']}" + assert_equal('905: Payment details are not supported', message) + + response2 = stub_comms do + @gateway.purchase(@amount, @credit_card, @options) + end.respond_with(validation_error_response) + + message2 = "#{response2.params['errorCode']}: #{response2.params['message']}" + assert_equal('702: Internal error', message2) + end + private def successful_authorize_response 'pspReference=7914002629995504&authCode=56469&resultCode=Authorised' end + def successful_authorize_with_3ds_response + 'pspReference=8815161318854998&resultCode=RedirectShopper&issuerUrl=https%3A%2F%2Ftest.adyen.com%2Fhpp%2F3d%2Fvalidate.shtml&md=WIFa2sF3CuPyN53Txjt3U%2F%2BDuCsddzywiY5NLgEAdUAXPksHUzXL5E%2BsfvdpolkGWR8b1oh%2FNA3jNaUP9UCgfjhXqRslGFy9OGqcZ1ITMz54HHm%2FlsCKN9bTftKnYA4F7GqvOgcIIrinUZjbMvW9doGifwzSqYLo6ASOm6bARL5n7cIFV8IWtA2yPlO%2FztKSTRJt1glN4s8sMcpE57z4soWKMuycbdXdpp6d4ZRSa%2F1TPF0MnJF0zNaSAAkw9JpXqGMOz5sFF2Smpc38HXJzM%2FV%2B1mmoDhhWmXXOb5YQ0QSCS7DXKIcr8ZtuGuGmFp0QOfZiO41%2B2I2N7VhONVx8xSn%2BLu4m6vaDIg5qsnd9saxaWwbJpl9okKm6pB2MJap9ScuBCcvI496BPCrjQ2LHxvDWhk6M3Exemtv942NQIGlsiPaW0KXoC2dQvBsxWh0K&paRequest=eNpVUtuOgjAQ%2FRXj%2B1KKoIWMTVgxWR%2B8RNkPaMpEycrFUlb8%2B20B190%2BnXPm0pnTQnpRiMkJZauQwxabRpxxkmfLacQYDeiczihjgR%2BGbMrhEB%2FxxuEbVZNXJaeO63hAntSUK3kRpeYg5O19s%2BPUm%2FnBHMhIoUC1SXiKjT4URSxvba5QARlkKEWB%2FFSbgbLr41QIpXFVFUB6HWTVllo9OPNMwyeBVl35Reu6iQi53%2B9OM5Y7sipMVqmF1G9tA8QmAnlNeGgtakzjLs%2F4Pjl3u3TtbdNtZzDdJV%2FBPu7PEojNgExo5J5LmUvpfELDyPcjPwDS6yAKOxFffx4nxhXXrDwIUNt74oFQG%2FgrgLFdYSkfPFwws9WTAXZ1VaLJMPb%2BYiCvoVcf1mSpjW%2B%2BN9i8YKFr0MLa3Qdsl9yYREM37NtYAsSWkvElyfjiBv37CT9ySbE1' + end + def failed_authorize_response 'pspReference=7914002630895750&refusalReason=Refused&resultCode=Refused' end @@ -169,7 +404,7 @@ def successful_capture_response end def failed_capture_response - 'validation 100 No amount specified' + 'errorType=validation&errorCode=167&message=Original+pspReference+required+for+this+operation&status=422' end def successful_refund_response @@ -177,13 +412,21 @@ def successful_refund_response end def failed_refund_response - 'validation 100 No amount specified' + 'errorType=validation&errorCode=137&message=Invalid+amount+specified&status=422' end def successful_credit_response 'fraudResult.accountScore=70&fraudResult.results.0.accountScore=20&fraudResult.results.0.checkId=2&fraudResult.results.0.name=CardChunkUsage&fraudResult.results.1.accountScore=25&fraudResult.results.1.checkId=4&fraudResult.results.1.name=HolderNameUsage&fraudResult.results.2.accountScore=25&fraudResult.results.2.checkId=8&fraudResult.results.2.name=ShopperEmailUsage&fraudResult.results.3.accountScore=0&fraudResult.results.3.checkId=1&fraudResult.results.3.name=PaymentDetailRefCheck&fraudResult.results.4.accountScore=0&fraudResult.results.4.checkId=13&fraudResult.results.4.name=IssuerRefCheck&fraudResult.results.5.accountScore=0&fraudResult.results.5.checkId=15&fraudResult.results.5.name=IssuingCountryReferral&fraudResult.results.6.accountScore=0&fraudResult.results.6.checkId=26&fraudResult.results.6.name=ShopperEmailRefCheck&fraudResult.results.7.accountScore=0&fraudResult.results.7.checkId=27&fraudResult.results.7.name=PmOwnerRefCheck&fraudResult.results.8.accountScore=0&fraudResult.results.8.checkId=56&fraudResult.results.8.name=ShopperReferenceTrustCheck&fraudResult.results.9.accountScore=0&fraudResult.results.9.checkId=10&fraudResult.results.9.name=HolderNameContainsNumber&fraudResult.results.10.accountScore=0&fraudResult.results.10.checkId=11&fraudResult.results.10.name=HolderNameIsOneWord&fraudResult.results.11.accountScore=0&fraudResult.results.11.checkId=21&fraudResult.results.11.name=EmailDomainValidation&pspReference=8514743049239955&resultCode=Received' end + def successful_payout_store_response + 'pspReference=8815391117417347&resultCode=%5Bpayout-submit-received%5D' + end + + def successful_payout_confirm_response + 'pspReference=8815391117421182&response=%5Bpayout-confirm-received%5D' + end + def failed_credit_response 'errorType=validation&errorCode=137&message=Invalid+amount+specified&status=422' end @@ -204,6 +447,14 @@ def failed_avs_response 'additionalData.liabilityShift=false&additionalData.authCode=3115&additionalData.avsResult=2+Neither+postal+code+nor+address+match&additionalData.cardHolderName=Longbob+Longsen&additionalData.threeDOffered=false&additionalData.refusalReasonRaw=AUTHORISED&additionalData.issuerCountry=US&additionalData.cvcResult=1+Matches&additionalData.avsResultRaw=2&additionalData.threeDAuthenticated=false&additionalData.cvcResultRaw=1&additionalData.acquirerCode=SmartPayTestPmmAcquirer&additionalData.acquirerReference=7F50RDN2L06&fraudResult.accountScore=170&fraudResult.results.0.accountScore=20&fraudResult.results.0.checkId=2&fraudResult.results.0.name=CardChunkUsage&fraudResult.results.1.accountScore=25&fraudResult.results.1.checkId=4&fraudResult.results.1.name=HolderNameUsage&fraudResult.results.2.accountScore=25&fraudResult.results.2.checkId=8&fraudResult.results.2.name=ShopperEmailUsage&fraudResult.results.3.accountScore=0&fraudResult.results.3.checkId=1&fraudResult.results.3.name=PaymentDetailRefCheck&fraudResult.results.4.accountScore=0&fraudResult.results.4.checkId=13&fraudResult.results.4.name=IssuerRefCheck&fraudResult.results.5.accountScore=0&fraudResult.results.5.checkId=15&fraudResult.results.5.name=IssuingCountryReferral&fraudResult.results.6.accountScore=0&fraudResult.results.6.checkId=26&fraudResult.results.6.name=ShopperEmailRefCheck&fraudResult.results.7.accountScore=0&fraudResult.results.7.checkId=27&fraudResult.results.7.name=PmOwnerRefCheck&fraudResult.results.8.accountScore=0&fraudResult.results.8.checkId=10&fraudResult.results.8.name=HolderNameContainsNumber&fraudResult.results.9.accountScore=0&fraudResult.results.9.checkId=11&fraudResult.results.9.name=HolderNameIsOneWord&fraudResult.results.10.accountScore=0&fraudResult.results.10.checkId=21&fraudResult.results.10.name=EmailDomainValidation&fraudResult.results.11.accountScore=100&fraudResult.results.11.checkId=20&fraudResult.results.11.name=AVSAuthResultCheck&fraudResult.results.12.accountScore=0&fraudResult.results.12.checkId=25&fraudResult.results.12.name=CVCAuthResultCheck&pspReference=8814591938804745&refusalReason=FRAUD-CANCELLED&resultCode=Cancelled&authCode=3115' end + def validation_error_response + 'errorType=validation&errorCode=702&message=Internal+error&status=500' + end + + def configuration_error_response + 'errorType=configuration&errorCode=905&message=Payment+details+are+not+supported&pspReference=4315391674762857&status=500' + end + def transcript %( opening connection to pal-test.barclaycardsmartpay.com:443... diff --git a/test/unit/gateways/barclays_epdq_extra_plus_test.rb b/test/unit/gateways/barclays_epdq_extra_plus_test.rb index b1f2cb61c61..330bdf13d4d 100644 --- a/test/unit/gateways/barclays_epdq_extra_plus_test.rb +++ b/test/unit/gateways/barclays_epdq_extra_plus_test.rb @@ -9,10 +9,10 @@ def setup :signature_encryptor => 'sha512' } @gateway = BarclaysEpdqExtraPlusGateway.new(@credentials) @credit_card = credit_card - @mastercard = credit_card('5399999999999999', :brand => "mastercard") + @mastercard = credit_card('5399999999999999', :brand => 'mastercard') @amount = 100 - @identification = "3014726" - @billing_id = "myalias" + @identification = '3014726' + @billing_id = 'myalias' @options = { :order_id => '1', :billing_address => address, @@ -31,7 +31,7 @@ def setup @parameters_d3d = { 'FLAG3D' => 'Y', 'WIN3DS' => 'MAINW', - 'HTTP_ACCEPT' => "*/*" + 'HTTP_ACCEPT' => '*/*' } end @@ -133,7 +133,7 @@ def test_successful_authorize_with_3dsecure def test_successful_capture @gateway.expects(:ssl_post).returns(successful_capture_response) - assert response = @gateway.capture(@amount, "3048326") + assert response = @gateway.capture(@amount, '3048326') assert_success response assert_equal '3048326;SAL', response.authorization assert response.test? @@ -141,7 +141,7 @@ def test_successful_capture def test_successful_capture_with_action_option @gateway.expects(:ssl_post).returns(successful_capture_response) - assert response = @gateway.capture(@amount, "3048326", :action => 'SAS') + assert response = @gateway.capture(@amount, '3048326', :action => 'SAS') assert_success response assert_equal '3048326;SAS', response.authorization assert response.test? @@ -149,7 +149,7 @@ def test_successful_capture_with_action_option def test_successful_void @gateway.expects(:ssl_post).returns(successful_void_response) - assert response = @gateway.void("3048606") + assert response = @gateway.void('3048606') assert_success response assert_equal '3048606;DES', response.authorization assert response.test? @@ -158,7 +158,7 @@ def test_successful_void def test_deprecated_credit @gateway.expects(:ssl_post).returns(successful_referenced_credit_response) assert_deprecation_warning(Gateway::CREDIT_DEPRECATION_MESSAGE) do - assert response = @gateway.credit(@amount, "3049652;SAL") + assert response = @gateway.credit(@amount, '3049652;SAL') assert_success response assert_equal '3049652;RFD', response.authorization assert response.test? @@ -169,13 +169,13 @@ def test_successful_unreferenced_credit @gateway.expects(:ssl_post).returns(successful_unreferenced_credit_response) assert response = @gateway.credit(@amount, @credit_card) assert_success response - assert_equal "3049654;RFD", response.authorization + assert_equal '3049654;RFD', response.authorization assert response.test? end def test_successful_refund @gateway.expects(:ssl_post).returns(successful_referenced_credit_response) - assert response = @gateway.refund(@amount, "3049652") + assert response = @gateway.refund(@amount, '3049652') assert_success response assert_equal '3049652;RFD', response.authorization assert response.test? @@ -217,7 +217,7 @@ def test_create_readable_error_message_upon_failure assert_failure response assert response.test? - assert_equal "Unknown order", response.message + assert_equal 'Unknown order', response.message end def test_supported_countries @@ -294,19 +294,19 @@ def test_test_mode def test_format_error_message_with_slash_separator @gateway.expects(:ssl_post).returns('<ncresponse NCERRORPLUS="unknown order/1/i/67.192.100.64" STATUS="0" />') assert response = @gateway.purchase(@amount, @credit_card, @options) - assert_equal "Unknown order", response.message + assert_equal 'Unknown order', response.message end def test_format_error_message_with_pipe_separator @gateway.expects(:ssl_post).returns('<ncresponse NCERRORPLUS=" no card no|no exp date|no brand" STATUS="0" />') assert response = @gateway.purchase(@amount, @credit_card, @options) - assert_equal "No card no, no exp date, no brand", response.message + assert_equal 'No card no, no exp date, no brand', response.message end def test_format_error_message_with_no_separator @gateway.expects(:ssl_post).returns('<ncresponse NCERRORPLUS=" unknown order " STATUS="0" />') assert response = @gateway.purchase(@amount, @credit_card, @options) - assert_equal "Unknown order", response.message + assert_equal 'Unknown order', response.message end def test_without_signature @@ -316,7 +316,7 @@ def test_without_signature gateway.purchase(@amount, @credit_card, @options) end - gateway = BarclaysEpdqExtraPlusGateway.new(@credentials.merge(:signature => nil, :signature_encryptor => "none")) + gateway = BarclaysEpdqExtraPlusGateway.new(@credentials.merge(:signature => nil, :signature_encryptor => 'none')) gateway.expects(:ssl_post).returns(successful_purchase_response) assert_no_deprecation_warning do gateway.purchase(@amount, @credit_card, @options) @@ -326,7 +326,7 @@ def test_without_signature def test_signature_for_accounts_created_before_10_may_20101 gateway = BarclaysEpdqExtraPlusGateway.new(@credentials.merge(:signature_encryptor => nil)) assert signature = gateway.send(:add_signature, @parameters) - assert_equal Digest::SHA1.hexdigest("1100EUR4111111111111111MrPSPIDRES2mynicesig").upcase, signature + assert_equal Digest::SHA1.hexdigest('1100EUR4111111111111111MrPSPIDRES2mynicesig').upcase, signature end def test_signature_for_accounts_with_signature_encryptor_to_sha1 @@ -360,13 +360,13 @@ def test_3dsecure_win_3ds_option gateway = BarclaysEpdqExtraPlusGateway.new(@credentials) gateway.send(:add_d3d, post, { :win_3ds => :pop_up }) - assert 'POPUP', post["WIN3DS"] + assert 'POPUP', post['WIN3DS'] gateway.send(:add_d3d, post, { :win_3ds => :pop_ix }) - assert 'POPIX', post["WIN3DS"] + assert 'POPIX', post['WIN3DS'] gateway.send(:add_d3d, post, { :win_3ds => :invalid }) - assert 'MAINW', post["WIN3DS"] + assert 'MAINW', post['WIN3DS'] end def test_3dsecure_additional_options @@ -374,8 +374,8 @@ def test_3dsecure_additional_options gateway = BarclaysEpdqExtraPlusGateway.new(@credentials) gateway.send(:add_d3d, post, { - :http_accept => "text/html", - :http_user_agent => "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)", + :http_accept => 'text/html', + :http_user_agent => 'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)', :accept_url => 'https://accept_url', :decline_url => 'https://decline_url', :exception_url => 'https://exception_url', @@ -383,8 +383,8 @@ def test_3dsecure_additional_options :complus => 'com_plus', :language => 'fr_FR' }) - assert 'HTTP_ACCEPT', "text/html" - assert 'HTTP_USER_AGENT', "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)" + assert 'HTTP_ACCEPT', 'text/html' + assert 'HTTP_USER_AGENT', 'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)' assert 'ACCEPTURL', 'https://accept_url' assert 'DECLINEURL', 'https://decline_url' assert 'EXCEPTIONURL', 'https://exception_url' @@ -414,16 +414,16 @@ def test_transcript_scrubbing private def string_to_digest - "ALIAS=2mynicesigAMOUNT=100mynicesigCARDNO=4111111111111111mynicesig"+ - "CN=Client NamemynicesigCURRENCY=EURmynicesigOPERATION=RESmynicesig"+ - "ORDERID=1mynicesigPSPID=MrPSPIDmynicesig" + 'ALIAS=2mynicesigAMOUNT=100mynicesigCARDNO=4111111111111111mynicesig'\ + 'CN=Client NamemynicesigCURRENCY=EURmynicesigOPERATION=RESmynicesig'\ + 'ORDERID=1mynicesigPSPID=MrPSPIDmynicesig' end def d3d_string_to_digest - "ALIAS=2mynicesigAMOUNT=100mynicesigCARDNO=4111111111111111mynicesig"+ - "CN=Client NamemynicesigCURRENCY=EURmynicesigFLAG3D=Ymynicesig"+ - "HTTP_ACCEPT=*/*mynicesigOPERATION=RESmynicesigORDERID=1mynicesig"+ - "PSPID=MrPSPIDmynicesigWIN3DS=MAINWmynicesig" + 'ALIAS=2mynicesigAMOUNT=100mynicesigCARDNO=4111111111111111mynicesig'\ + 'CN=Client NamemynicesigCURRENCY=EURmynicesigFLAG3D=Ymynicesig'\ + 'HTTP_ACCEPT=*/*mynicesigOPERATION=RESmynicesigORDERID=1mynicesig'\ + 'PSPID=MrPSPIDmynicesigWIN3DS=MAINWmynicesig' end def successful_authorize_response diff --git a/test/unit/gateways/barclays_epdq_test.rb b/test/unit/gateways/barclays_epdq_test.rb deleted file mode 100644 index 499d877a188..00000000000 --- a/test/unit/gateways/barclays_epdq_test.rb +++ /dev/null @@ -1,450 +0,0 @@ -require 'test_helper' - -class BarclaysEpdqTest < Test::Unit::TestCase - def setup - @gateway = BarclaysEpdqGateway.new( - :login => 'login', - :password => 'password', - :client_id => 'client_id' - ) - - @credit_card = credit_card - @amount = 100 - - @options = { - :billing_address => address - } - end - - def test_successful_purchase - @gateway.expects(:ssl_post).returns(successful_purchase_response) - - assert response = @gateway.purchase(@amount, @credit_card, @options) - assert_success response - - # Replace with authorization number from the successful response - assert_equal "150127237", response.authorization - assert response.test? - end - - def test_failed_purchase - @gateway.expects(:ssl_post).returns(failed_purchase_response) - - assert response = @gateway.purchase(@amount, @credit_card, @options) - assert_failure response - assert response.test? - end - - def test_deprecated_credit - @gateway.expects(:ssl_post).with(anything, regexp_matches(/>asdfasdf</)).returns(successful_credit_response) - assert_deprecation_warning(Gateway::CREDIT_DEPRECATION_MESSAGE) do - assert_success @gateway.credit(@amount, "asdfasdf:jklljkll") - end - end - - def test_credit - @gateway.expects(:ssl_post).with(anything, regexp_matches(/#{@credit_card.number}/)).returns(successful_credit_response) - assert response = @gateway.credit(@amount, @credit_card) - assert_success response - end - - def test_refund - @gateway.expects(:ssl_post).with(anything, regexp_matches(/>asdfasdf</)).returns(successful_credit_response) - assert response = @gateway.refund(@amount, "asdfasdf:jklljkll") - assert_success response - end - - def test_handling_incorrectly_encoded_message - @gateway.expects(:ssl_post).returns(incorrectly_encoded_response) - - assert_nothing_raised { @gateway.purchase(@amount, @credit_card, @options) } - end - - private - - def successful_purchase_response - %(<?xml version="1.0" encoding="UTF-8"?> -<EngineDocList> - <DocVersion DataType="String">1.0</DocVersion> - <EngineDoc> - <ContentType DataType="String">OrderFormDoc</ContentType> - <DocumentId DataType="String">4d45da6a-5e10-3000-002b-00144ff2e45c</DocumentId> - <Instructions> - <Pipeline DataType="String">Payment</Pipeline> - - </Instructions> - <MessageList> - <MaxSev DataType="S32">3</MaxSev> - <Message> - <AdvisedAction DataType="S32">32</AdvisedAction> - <Audience DataType="String">Merchant</Audience> - <Component DataType="String">CcxBarclaysGbpAuth</Component> - <ContextId DataType="String">PaymentNormErrors</ContextId> - <DataState DataType="S32">3</DataState> - <FileLine DataType="S32">121</FileLine> - <FileName DataType="String">CcxBarclaysAuthResponseRedirector.cpp</FileName> - <FileTime DataType="String">10:41:43May 26 2009</FileTime> - <ResourceId DataType="S32">1</ResourceId> - <Sev DataType="S32">3</Sev> - <Text DataType="String">Approved.</Text> - - </Message> - - </MessageList> - <OrderFormDoc> - <Consumer> - <BillTo> - <Location> - <Address> - <City DataType="String">Ottawa</City> - <Country DataType="String"></Country> - <PostalCode DataType="String">K1C2N6</PostalCode> - <StateProv DataType="String">ON</StateProv> - <Street1 DataType="String">1234 My Street</Street1> - <Street2 DataType="String">Apt 1</Street2> - - </Address> - <Id DataType="String">4d45da6a-5e12-3000-002b-00144ff2e45c</Id> - - </Location> - - </BillTo> - <PaymentMech> - <CreditCard> - <Cvv2Indicator DataType="String">1</Cvv2Indicator> - <Cvv2Val DataType="String">123</Cvv2Val> - <Expires DataType="ExpirationDate">09/12</Expires> - <Number DataType="String">4715320629000001</Number> - <Type DataType="S32">1</Type> - - </CreditCard> - <Type DataType="String">CreditCard</Type> - - </PaymentMech> - - </Consumer> - <DateTime DataType="DateTime">1296599280954</DateTime> - <FraudInfo> - <FraudResult DataType="String">None</FraudResult> - <FraudResultCode DataType="S32">0</FraudResultCode> - <OrderScore DataType="Numeric" Precision="0">0</OrderScore> - <StrategyList> - <Strategy> - <FraudAction DataType="String">None</FraudAction> - <StrategyId DataType="S32">1</StrategyId> - <StrategyName DataType="String">My Rules</StrategyName> - <StrategyOwnerId DataType="S32">2974</StrategyOwnerId> - <StrategyScore DataType="Numeric" Precision="0">0</StrategyScore> - - </Strategy> - - </StrategyList> - <TotalScore DataType="Numeric" Precision="0">0</TotalScore> - - </FraudInfo> - <GroupId DataType="String">150127237</GroupId> - <Id DataType="String">150127237</Id> - <Mode DataType="String">P</Mode> - <Transaction> - <AuthCode DataType="String">442130</AuthCode> - <CardProcRequest> - <TerminalId DataType="String">90003750</TerminalId> - - </CardProcRequest> - <CardProcResp> - <AvsDisplay DataType="String">YY</AvsDisplay> - <AvsRespCode DataType="String">EX</AvsRespCode> - <CcErrCode DataType="S32">1</CcErrCode> - <CcReturnMsg DataType="String">Approved.</CcReturnMsg> - <Cvv2Resp DataType="String">2</Cvv2Resp> - <ProcAvsRespCode DataType="String">22</ProcAvsRespCode> - <ProcReturnCode DataType="String">00</ProcReturnCode> - <ProcReturnMsg DataType="String">AUTH CODE:442130</ProcReturnMsg> - <Status DataType="String">1</Status> - - </CardProcResp> - <CardholderPresentCode DataType="S32">7</CardholderPresentCode> - <CurrentTotals> - <Totals> - <Total DataType="Money" Currency="826">3900</Total> - - </Totals> - - </CurrentTotals> - <Id DataType="String">4d45da6a-5e11-3000-002b-00144ff2e45c</Id> - <InputEnvironment DataType="S32">4</InputEnvironment> - <SecurityIndicator DataType="S32">7</SecurityIndicator> - <TerminalInputCapability DataType="S32">1</TerminalInputCapability> - <Type DataType="String">Auth</Type> - - </Transaction> - - </OrderFormDoc> - <User> - <Alias DataType="String">2974</Alias> - <ClientId DataType="S32">2974</ClientId> - <EffectiveAlias DataType="String">2974</EffectiveAlias> - <EffectiveClientId DataType="S32">2974</EffectiveClientId> - <Name DataType="String">spreedlytesting</Name> - <Password DataType="String">XXXXXXX</Password> - - </User> - - </EngineDoc> - <TimeIn DataType="DateTime">1296599280948</TimeIn> - <TimeOut DataType="DateTime">1296599283885</TimeOut> - -</EngineDocList> -) - end - - def failed_purchase_response - %(<?xml version="1.0" encoding="UTF-8"?> -<EngineDocList> - <DocVersion DataType="String">1.0</DocVersion> - <EngineDoc> - <ContentType DataType="String">OrderFormDoc</ContentType> - <DocumentId DataType="String">4d45da6a-5d6b-3000-002b-00144ff2e45c</DocumentId> - <Instructions> - <Pipeline DataType="String">Payment</Pipeline> - - </Instructions> - <MessageList> - <MaxSev DataType="S32">3</MaxSev> - <Message> - <AdvisedAction DataType="S32">32</AdvisedAction> - <Audience DataType="String">Merchant</Audience> - <Component DataType="String">CcxBarclaysGbpAuth</Component> - <ContextId DataType="String">PaymentNormErrors</ContextId> - <DataState DataType="S32">3</DataState> - <FileLine DataType="S32">121</FileLine> - <FileName DataType="String">CcxBarclaysAuthResponseRedirector.cpp</FileName> - <FileTime DataType="String">10:41:43May 26 2009</FileTime> - <ResourceId DataType="S32">50</ResourceId> - <Sev DataType="S32">3</Sev> - <Text DataType="String">Declined (General).</Text> - - </Message> - - </MessageList> - <OrderFormDoc> - <Consumer> - <BillTo> - <Location> - <Address> - <City DataType="String">Ottawa</City> - <Country DataType="String"></Country> - <PostalCode DataType="String">K1C2N6</PostalCode> - <StateProv DataType="String">ON</StateProv> - <Street1 DataType="String">1234 My Street</Street1> - <Street2 DataType="String">Apt 1</Street2> - - </Address> - <Id DataType="String">4d45da6a-5d6d-3000-002b-00144ff2e45c</Id> - - </Location> - - </BillTo> - <PaymentMech> - <CreditCard> - <Cvv2Indicator DataType="String">1</Cvv2Indicator> - <Cvv2Val DataType="String">123</Cvv2Val> - <Expires DataType="ExpirationDate">09/12</Expires> - <Number DataType="String">4715320629000027</Number> - <Type DataType="S32">1</Type> - - </CreditCard> - <Type DataType="String">CreditCard</Type> - - </PaymentMech> - - </Consumer> - <DateTime DataType="DateTime">1296598178436</DateTime> - <FraudInfo> - <FraudResult DataType="String">None</FraudResult> - <FraudResultCode DataType="S32">0</FraudResultCode> - <OrderScore DataType="Numeric" Precision="0">0</OrderScore> - <StrategyList> - <Strategy> - <FraudAction DataType="String">None</FraudAction> - <StrategyId DataType="S32">1</StrategyId> - <StrategyName DataType="String">My Rules</StrategyName> - <StrategyOwnerId DataType="S32">2974</StrategyOwnerId> - <StrategyScore DataType="Numeric" Precision="0">0</StrategyScore> - - </Strategy> - - </StrategyList> - <TotalScore DataType="Numeric" Precision="0">0</TotalScore> - - </FraudInfo> - <GroupId DataType="String">22394792</GroupId> - <Id DataType="String">22394792</Id> - <Mode DataType="String">P</Mode> - <Transaction> - <CardProcRequest> - <TerminalId DataType="String">90003745</TerminalId> - - </CardProcRequest> - <CardProcResp> - <AvsDisplay DataType="String">NY</AvsDisplay> - <AvsRespCode DataType="String">B5</AvsRespCode> - <CcErrCode DataType="S32">50</CcErrCode> - <CcReturnMsg DataType="String">Declined (General).</CcReturnMsg> - <Cvv2Resp DataType="String">2</Cvv2Resp> - <ProcAvsRespCode DataType="String">24</ProcAvsRespCode> - <ProcReturnCode DataType="String">05</ProcReturnCode> - <ProcReturnMsg DataType="String">NOT AUTHORISED</ProcReturnMsg> - <Status DataType="String">1</Status> - - </CardProcResp> - <CardholderPresentCode DataType="S32">7</CardholderPresentCode> - <CurrentTotals> - <Totals> - <Total DataType="Money" Currency="826">4205</Total> - - </Totals> - - </CurrentTotals> - <Id DataType="String">4d45da6a-5d6c-3000-002b-00144ff2e45c</Id> - <InputEnvironment DataType="S32">4</InputEnvironment> - <SecurityIndicator DataType="S32">7</SecurityIndicator> - <TerminalInputCapability DataType="S32">1</TerminalInputCapability> - <Type DataType="String">Auth</Type> - - </Transaction> - - </OrderFormDoc> - <User> - <Alias DataType="String">2974</Alias> - <ClientId DataType="S32">2974</ClientId> - <EffectiveAlias DataType="String">2974</EffectiveAlias> - <EffectiveClientId DataType="S32">2974</EffectiveClientId> - <Name DataType="String">login</Name> - <Password DataType="String">XXXXXXX</Password> - - </User> - - </EngineDoc> - <TimeIn DataType="DateTime">1296598178430</TimeIn> - <TimeOut DataType="DateTime">1296598179756</TimeOut> - -</EngineDocList> -) - end - - def successful_credit_response - %(<?xml version="1.0" encoding="UTF-8"?> -<EngineDocList> - <DocVersion DataType="String">1.0</DocVersion> - <EngineDoc> - <ContentType DataType="String">OrderFormDoc</ContentType> - <DocumentId DataType="String">4d45da6a-8bcd-3000-002b-00144ff2e45c</DocumentId> - <Instructions> - <Pipeline DataType="String">Payment</Pipeline> - - </Instructions> - <MessageList> - - </MessageList> - <OrderFormDoc> - <Consumer> - <BillTo> - <Location> - <Address> - <City DataType="String">Ottawa</City> - <PostalCode DataType="String">K1C2N6</PostalCode> - <StateProv DataType="String">ON</StateProv> - <Street1 DataType="String">1234 My Street</Street1> - <Street2 DataType="String">Apt 1</Street2> - - </Address> - <Id DataType="String">4d45da6a-8bcc-3000-002b-00144ff2e45c</Id> - - </Location> - - </BillTo> - <PaymentMech> - <CreditCard> - <ExchangeType DataType="S32">1</ExchangeType> - <Expires DataType="ExpirationDate">09/12</Expires> - <Number DataType="String">4715320629000001</Number> - - </CreditCard> - <Type DataType="String">CreditCard</Type> - - </PaymentMech> - - </Consumer> - <DateTime DataType="DateTime">1296679499967</DateTime> - <FraudInfo> - <FraudResult DataType="String">None</FraudResult> - <FraudResultCode DataType="S32">0</FraudResultCode> - <OrderScore DataType="Numeric" Precision="0">0</OrderScore> - <StrategyList> - <Strategy> - <FraudAction DataType="String">None</FraudAction> - <StrategyId DataType="S32">1</StrategyId> - <StrategyName DataType="String">My Rules</StrategyName> - <StrategyOwnerId DataType="S32">2974</StrategyOwnerId> - <StrategyScore DataType="Numeric" Precision="0">0</StrategyScore> - - </Strategy> - - </StrategyList> - <TotalScore DataType="Numeric" Precision="0">0</TotalScore> - - </FraudInfo> - <GroupId DataType="String">b92b5bff09d05d771c17e6b6b30531ed</GroupId> - <Id DataType="String">b92b5bff09d05d771c17e6b6b30531ed</Id> - <Mode DataType="String">P</Mode> - <Transaction> - <CardProcResp> - <CcErrCode DataType="S32">1</CcErrCode> - <CcReturnMsg DataType="String">Approved.</CcReturnMsg> - <ProcReturnCode DataType="String">1</ProcReturnCode> - <ProcReturnMsg DataType="String">Approved</ProcReturnMsg> - <Status DataType="String">1</Status> - - </CardProcResp> - <CardholderPresentCode DataType="S32">7</CardholderPresentCode> - <ChargeTypeCode DataType="String">S</ChargeTypeCode> - <CurrentTotals> - <Totals> - <Total DataType="Money" Currency="826">3900</Total> - - </Totals> - - </CurrentTotals> - <Id DataType="String">4d45da6a-8bce-3000-002b-00144ff2e45c</Id> - <InputEnvironment DataType="S32">4</InputEnvironment> - <SecurityIndicator DataType="S32">7</SecurityIndicator> - <TerminalInputCapability DataType="S32">1</TerminalInputCapability> - <Type DataType="String">Credit</Type> - - </Transaction> - - </OrderFormDoc> - <User> - <Alias DataType="String">2974</Alias> - <ClientId DataType="S32">2974</ClientId> - <EffectiveAlias DataType="String">2974</EffectiveAlias> - <EffectiveClientId DataType="S32">2974</EffectiveClientId> - <Name DataType="String">spreedlytesting</Name> - <Password DataType="String">XXXXXXX</Password> - - </User> - - </EngineDoc> - <TimeIn DataType="DateTime">1296679499961</TimeIn> - <TimeOut DataType="DateTime">1296679500312</TimeOut> - -</EngineDocList> - -) - end - - def incorrectly_encoded_response - successful_purchase_response.gsub("Ottawa", "\xD6ttawa") - end -end diff --git a/test/unit/gateways/be2bill_test.rb b/test/unit/gateways/be2bill_test.rb index 26d9625bd02..d83f42e42b5 100644 --- a/test/unit/gateways/be2bill_test.rb +++ b/test/unit/gateways/be2bill_test.rb @@ -41,11 +41,11 @@ def test_unsuccessful_request # Place raw successful response from gateway here def successful_purchase_response - {"OPERATIONTYPE"=>"payment", "TRANSACTIONID"=>"A189063", "EXECCODE"=>"0000", "MESSAGE"=>"The transaction has been accepted.", "ALIAS"=>"A189063", "DESCRIPTOR"=>"RENTABILITEST"}.to_json + {'OPERATIONTYPE'=>'payment', 'TRANSACTIONID'=>'A189063', 'EXECCODE'=>'0000', 'MESSAGE'=>'The transaction has been accepted.', 'ALIAS'=>'A189063', 'DESCRIPTOR'=>'RENTABILITEST'}.to_json end # Place raw failed response from gateway here def failed_purchase_response - {"OPERATIONTYPE"=>"payment", "TRANSACTIONID"=>"A189063", "EXECCODE"=>"1001", "MESSAGE"=>"The parameter \"CARDCODE\" is missing.\n", "DESCRIPTOR"=>"RENTABILITEST"}.to_json + {'OPERATIONTYPE'=>'payment', 'TRANSACTIONID'=>'A189063', 'EXECCODE'=>'1001', 'MESSAGE'=>"The parameter \"CARDCODE\" is missing.\n", 'DESCRIPTOR'=>'RENTABILITEST'}.to_json end end diff --git a/test/unit/gateways/beanstream_interac_test.rb b/test/unit/gateways/beanstream_interac_test.rb index d7659f76326..a0a7bac3862 100644 --- a/test/unit/gateways/beanstream_interac_test.rb +++ b/test/unit/gateways/beanstream_interac_test.rb @@ -8,44 +8,44 @@ def setup ) @amount = 100 - - @options = { + + @options = { :order_id => '1', :billing_address => address, :description => 'Store Purchase' } end - + def test_successful_purchase @gateway.expects(:ssl_post).returns(successful_purchase_response) response = @gateway.purchase(@amount, @options) assert_success response - assert_equal "R", response.params["responseType"] - assert response.params["pageContents"] - assert_equal response.params["pageContents"], response.redirect + assert_equal 'R', response.params['responseType'] + assert response.params['pageContents'] + assert_equal response.params['pageContents'], response.redirect end - + def test_successful_confirmation @gateway.expects(:ssl_post).returns(successful_confirmation_response) response = @gateway.confirm(successful_return_from_interac_online) assert response.success? - assert_equal "Approved", response.message - assert_equal "10000029;5.00;P", response.authorization + assert_equal 'Approved', response.message + assert_equal '10000029;5.00;P', response.authorization end private - + def successful_purchase_response - "responseType=R&pageContents=%3CHTML%3E%3CHEAD%3E%3C%2FHEAD%3E%3CBODY%3E%3CFORM%20action%3D%22https%3A%2F%2Fpayments%2Ebeanstream%2Ecom%2FiOnlineEmulator%2Fgateway%2Easp%22%20method%3DPOST%20id%3DfrmIOnline%20name%3DfrmIOnline%3E%3Cinput%20type%3D%22hidden%22%20name%3D%22IDEBIT%5FMERCHNUM%22%20%20value%3D%2210010162199999%22%3E%3Cinput%20type%3D%22hidden%22%20name%3D%22IDEBIT%5FAMOUNT%22%20%20value%3D%221500%22%3E%3Cinput%20type%3D%22hidden%22%20name%3D%22IDEBIT%5FTERMID%22%20value%3D%2262199999%22%3E%3Cinput%20type%3D%22hidden%22%20name%3D%22IDEBIT%5FCURRENCY%22%20value%3D%22CAD%22%3E%3Cinput%20type%3D%22hidden%22%20name%3D%22IDEBIT%5FINVOICE%22%20value%3D%221be7db7a129b07ac5f7e%22%3E%3Cinput%20type%3D%22hidden%22%20name%3D%22IDEBIT%5FMERCHDATA%22%20value%3D%226CE36AF7%2D5013%2D4B94%2DB740153714A41962%22%3E%3Cinput%20type%3D%22hidden%22%20name%3D%22IDEBIT%5FFUNDEDURL%22%20value%3D%22https%3A%2F%2Fwww%2Ebeanstream%2Ecom%2Fscripts%2Fprocess%5Ftransaction%5Fauth%2Easp%3F%26funded%3D1%22%3E%3Cinput%20type%3D%22hidden%22%20name%3D%22IDEBIT%5FNOTFUNDEDURL%22%20value%3D%22https%3A%2F%2Fwww%2Ebeanstream%2Ecom%2Fscripts%2Fprocess%5Ftransaction%5Fauth%2Easp%3F%26funded%3D0%22%3E%3Cinput%20type%3D%22hidden%22%20name%3D%22merchant%5Fname%22%20value%3D%22Cody%20Fauser%22%3E%3Cinput%20type%3D%22hidden%22%20name%3D%22referHost%22%20value%3D%22https%3A%2F%2Fwww%2Ebeanstream%2Ecom%2Fscripts%2Fprocess%5Ftransaction%2Easp%22%3E%3Cinput%20type%3D%22hidden%22%20name%3D%22referHost2%22%20value%3D%22https%3A%2F%2Fwww%2Ecatnrose%2Ecom%2Fioxml%2Easp%22%3E%3Cinput%20type%3D%22hidden%22%20name%3D%22referHost3%22%20value%3D%22%22%3E%3Cinput%20type%3D%22hidden%22%20name%3D%22IDEBIT%5FMERCHLANG%22%20value%3D%22en%22%3E%3Cinput%20type%3D%22hidden%22%20name%3D%22IDEBIT%5FVERSION%22%20value%3D%221%22%3E%3C%2FFORM%3E%3CSCRIPT%20language%3D%22JavaScript%22%3Edocument%2EfrmIOnline%2Esubmit%28%29%3B%3C%2FSCRIPT%3E%3C%2FBODY%3E%3C%2FHTML%3E" + 'responseType=R&pageContents=%3CHTML%3E%3CHEAD%3E%3C%2FHEAD%3E%3CBODY%3E%3CFORM%20action%3D%22https%3A%2F%2Fpayments%2Ebeanstream%2Ecom%2FiOnlineEmulator%2Fgateway%2Easp%22%20method%3DPOST%20id%3DfrmIOnline%20name%3DfrmIOnline%3E%3Cinput%20type%3D%22hidden%22%20name%3D%22IDEBIT%5FMERCHNUM%22%20%20value%3D%2210010162199999%22%3E%3Cinput%20type%3D%22hidden%22%20name%3D%22IDEBIT%5FAMOUNT%22%20%20value%3D%221500%22%3E%3Cinput%20type%3D%22hidden%22%20name%3D%22IDEBIT%5FTERMID%22%20value%3D%2262199999%22%3E%3Cinput%20type%3D%22hidden%22%20name%3D%22IDEBIT%5FCURRENCY%22%20value%3D%22CAD%22%3E%3Cinput%20type%3D%22hidden%22%20name%3D%22IDEBIT%5FINVOICE%22%20value%3D%221be7db7a129b07ac5f7e%22%3E%3Cinput%20type%3D%22hidden%22%20name%3D%22IDEBIT%5FMERCHDATA%22%20value%3D%226CE36AF7%2D5013%2D4B94%2DB740153714A41962%22%3E%3Cinput%20type%3D%22hidden%22%20name%3D%22IDEBIT%5FFUNDEDURL%22%20value%3D%22https%3A%2F%2Fwww%2Ebeanstream%2Ecom%2Fscripts%2Fprocess%5Ftransaction%5Fauth%2Easp%3F%26funded%3D1%22%3E%3Cinput%20type%3D%22hidden%22%20name%3D%22IDEBIT%5FNOTFUNDEDURL%22%20value%3D%22https%3A%2F%2Fwww%2Ebeanstream%2Ecom%2Fscripts%2Fprocess%5Ftransaction%5Fauth%2Easp%3F%26funded%3D0%22%3E%3Cinput%20type%3D%22hidden%22%20name%3D%22merchant%5Fname%22%20value%3D%22Cody%20Fauser%22%3E%3Cinput%20type%3D%22hidden%22%20name%3D%22referHost%22%20value%3D%22https%3A%2F%2Fwww%2Ebeanstream%2Ecom%2Fscripts%2Fprocess%5Ftransaction%2Easp%22%3E%3Cinput%20type%3D%22hidden%22%20name%3D%22referHost2%22%20value%3D%22https%3A%2F%2Fwww%2Ecatnrose%2Ecom%2Fioxml%2Easp%22%3E%3Cinput%20type%3D%22hidden%22%20name%3D%22referHost3%22%20value%3D%22%22%3E%3Cinput%20type%3D%22hidden%22%20name%3D%22IDEBIT%5FMERCHLANG%22%20value%3D%22en%22%3E%3Cinput%20type%3D%22hidden%22%20name%3D%22IDEBIT%5FVERSION%22%20value%3D%221%22%3E%3C%2FFORM%3E%3CSCRIPT%20language%3D%22JavaScript%22%3Edocument%2EfrmIOnline%2Esubmit%28%29%3B%3C%2FSCRIPT%3E%3C%2FBODY%3E%3C%2FHTML%3E' end - + def successful_return_from_interac_online - "bank_choice=1&merchant_name=Billing+Boss+IO+SB&confirmValue=&headerText=&IDEBIT_MERCHDATA=C4B50A48-6E11-4C21-A31EF4A602BC0099&IDEBIT_INVOICE=18face21593b59c7bb7e&IDEBIT_AMOUNT=1500&IDEBIT_FUNDEDURL=http%3A%2F%2Febay.massapparel.com%3A8000%2Finterac%2Ffunded%3Ffunded%3D1&IDEBIT_NOTFUNDEDURL=http%3A%2F%2Febay.massapparel.com%3A8000%2Finterac%2Fnotfunded%3Ffunded%3D0&IDEBIT_ISSLANG=en&IDEBIT_TRACK2=3728024906540591214%3D12010123456789XYZ&IDEBIT_ISSCONF=CONF%23TEST&IDEBIT_ISSNAME=TestBank1&IDEBIT_VERSION=1&accountType=Chequing" + 'bank_choice=1&merchant_name=Billing+Boss+IO+SB&confirmValue=&headerText=&IDEBIT_MERCHDATA=C4B50A48-6E11-4C21-A31EF4A602BC0099&IDEBIT_INVOICE=18face21593b59c7bb7e&IDEBIT_AMOUNT=1500&IDEBIT_FUNDEDURL=http%3A%2F%2Febay.massapparel.com%3A8000%2Finterac%2Ffunded%3Ffunded%3D1&IDEBIT_NOTFUNDEDURL=http%3A%2F%2Febay.massapparel.com%3A8000%2Finterac%2Fnotfunded%3Ffunded%3D0&IDEBIT_ISSLANG=en&IDEBIT_TRACK2=3728024906540591214%3D12010123456789XYZ&IDEBIT_ISSCONF=CONF%23TEST&IDEBIT_ISSNAME=TestBank1&IDEBIT_VERSION=1&accountType=Chequing' end - + def successful_confirmation_response - "trnApproved=1&trnId=10000029&messageId=1&messageText=Approved&trnOrderNumber=f29d2406b49b239b6dfb5db1f642b2&authCode=TEST&errorType=N&errorFields=&responseType=T&trnAmount=5%2E00&trnDate=6%2F8%2F2008+3%3A17%3A12+PM&avsProcessed=0&avsId=0&avsResult=0&avsAddrMatch=0&avsPostalMatch=0&avsMessage=Address+Verification+not+performed+for+this+transaction%2E&trnType=P&paymentMethod=IO&ioConfCode=CONF%23TEST&ioInstName=TestBank1&ref1=reference+one&ref2=&ref3=&ref4=&ref5=" + 'trnApproved=1&trnId=10000029&messageId=1&messageText=Approved&trnOrderNumber=f29d2406b49b239b6dfb5db1f642b2&authCode=TEST&errorType=N&errorFields=&responseType=T&trnAmount=5%2E00&trnDate=6%2F8%2F2008+3%3A17%3A12+PM&avsProcessed=0&avsId=0&avsResult=0&avsAddrMatch=0&avsPostalMatch=0&avsMessage=Address+Verification+not+performed+for+this+transaction%2E&trnType=P&paymentMethod=IO&ioConfCode=CONF%23TEST&ioInstName=TestBank1&ref1=reference+one&ref2=&ref3=&ref4=&ref5=' end end diff --git a/test/unit/gateways/beanstream_test.rb b/test/unit/gateways/beanstream_test.rb index d57e52afb98..c07adf22c0e 100644 --- a/test/unit/gateways/beanstream_test.rb +++ b/test/unit/gateways/beanstream_test.rb @@ -9,19 +9,20 @@ def setup @gateway = BeanstreamGateway.new( :login => 'merchant id', :user => 'username', - :password => 'password' + :password => 'password', + :api_key => 'api_key' ) @credit_card = credit_card @decrypted_credit_card = ActiveMerchant::Billing::NetworkTokenizationCreditCard.new( - month: "01", - year: "2012", - brand: "visa", - number: "4030000010001234", - payment_cryptogram: "cryptogram goes here", - eci: "an ECI value", - transaction_id: "transaction ID", + month: '01', + year: '2012', + brand: 'visa', + number: '4030000010001234', + payment_cryptogram: 'cryptogram goes here', + eci: 'an ECI value', + transaction_id: 'transaction ID' ) @check = check( @@ -57,13 +58,36 @@ def setup end def test_successful_purchase - @gateway.expects(:ssl_post).returns(successful_purchase_response) + response = stub_comms(@gateway, :ssl_request) do + @gateway.purchase(@amount, @decrypted_credit_card, @options) + end.check_request do |method, endpoint, data, headers| + refute_match(/recurringPayment=true/, data) + end.respond_with(successful_purchase_response) - assert response = @gateway.purchase(@amount, @credit_card, @options) assert_success response assert_equal '10000028;15.00;P', response.authorization end + def test_successful_purchase_with_recurring + response = stub_comms(@gateway, :ssl_request) do + @gateway.purchase(@amount, @decrypted_credit_card, @options.merge(recurring: true)) + end.check_request do |method, endpoint, data, headers| + assert_match(/recurringPayment=1/, data) + end.respond_with(successful_purchase_response) + + assert_success response + end + + def test_successful_authorize_with_recurring + response = stub_comms(@gateway, :ssl_request) do + @gateway.authorize(@amount, @decrypted_credit_card, @options.merge(recurring: true)) + end.check_request do |method, endpoint, data, headers| + assert_match(/recurringPayment=1/, data) + end.respond_with(successful_purchase_response) + + assert_success response + end + def test_successful_test_request_in_production_environment Base.mode = :production @gateway.expects(:ssl_post).returns(successful_test_purchase_response) @@ -115,7 +139,7 @@ def test_successful_purchase_with_check def test_successful_purchase_with_vault @gateway.expects(:ssl_post).returns(successful_purchase_response) - vault = rand(100000)+10001 + vault = rand(10001..110000) assert response = @gateway.purchase(@amount, vault, @options) assert_success response @@ -127,7 +151,7 @@ def test_successful_verify @gateway.verify(@credit_card) end.respond_with(successful_authorize_response, unsuccessful_void_response) assert_success response - assert_equal "Approved", response.message + assert_equal 'Approved', response.message end def test_failed_verify @@ -135,10 +159,9 @@ def test_failed_verify @gateway.verify(@credit_card) end.respond_with(unsuccessful_authorize_response, successful_void_response) assert_failure response - assert_equal "DECLINE", response.message + assert_equal 'DECLINE', response.message end - # Testing Non-American countries def test_german_address_sets_state_to_the_required_dummy_value @@ -187,10 +210,10 @@ def test_successful_update_recurring @gateway.expects(:ssl_post).returns(successful_update_recurring_response) response = assert_deprecation_warning(Gateway::RECURRING_DEPRECATION_MESSAGE) do - @gateway.update_recurring(@amount, @credit_card, @recurring_options.merge(:account_id => response.params["rbAccountId"])) + @gateway.update_recurring(@amount, @credit_card, @recurring_options.merge(:account_id => response.params['rbAccountId'])) end assert_success response - assert_equal "Request successful", response.message + assert_equal 'Request successful', response.message end def test_successful_cancel_recurring @@ -205,18 +228,18 @@ def test_successful_cancel_recurring @gateway.expects(:ssl_post).returns(successful_cancel_recurring_response) response = assert_deprecation_warning(Gateway::RECURRING_DEPRECATION_MESSAGE) do - @gateway.cancel_recurring(:account_id => response.params["rbAccountId"]) + @gateway.cancel_recurring(:account_id => response.params['rbAccountId']) end assert_success response - assert_equal "Request successful", response.message + assert_equal 'Request successful', response.message end def test_ip_is_being_sent @gateway.expects(:ssl_post).with do |url, data| - data =~ /customerIP=123\.123\.123\.123/ + data =~ /customerIp=123\.123\.123\.123/ end.returns(successful_purchase_response) - @options[:ip] = "123.123.123.123" + @options[:ip] = '123.123.123.123' @gateway.purchase(@amount, @credit_card, @options) end @@ -232,44 +255,88 @@ def test_includes_network_tokenization_fields assert_success response end + def test_defaults_state_and_zip_with_country + address = { country: 'AF' } + @options[:billing_address] = address + @options[:shipping_address] = address + response = stub_comms(@gateway, :ssl_request) do + @gateway.purchase(@amount, @decrypted_credit_card, @options) + end.check_request do |method, endpoint, data, headers| + assert_match(/ordProvince=--/, data) + assert_match(/ordPostalCode=000000/, data) + assert_match(/shipProvince=--/, data) + assert_match(/shipPostalCode=000000/, data) + end.respond_with(successful_purchase_response) + + assert_success response + end + + def test_no_state_and_zip_default_with_missing_country + address = { } + @options[:billing_address] = address + @options[:shipping_address] = address + response = stub_comms(@gateway, :ssl_request) do + @gateway.purchase(@amount, @decrypted_credit_card, @options) + end.check_request do |method, endpoint, data, headers| + assert_no_match(/ordProvince=--/, data) + assert_no_match(/ordPostalCode=000000/, data) + assert_no_match(/shipProvince=--/, data) + assert_no_match(/shipPostalCode=000000/, data) + end.respond_with(successful_purchase_response) + + assert_success response + end + + def test_sends_email_without_addresses + @options[:billing_address] = nil + @options[:shipping_address] = nil + @options[:shipping_email] = 'ship@mail.com' + response = stub_comms(@gateway, :ssl_request) do + @gateway.purchase(@amount, @decrypted_credit_card, @options) + end.check_request do |method, endpoint, data, headers| + assert_match(/ordEmailAddress=xiaobozzz%40example.com/, data) + assert_match(/shipEmailAddress=ship%40mail.com/, data) + end.respond_with(successful_purchase_response) + + assert_success response + end def test_transcript_scrubbing assert_equal scrubbed_transcript, @gateway.scrub(transcript) end - private def successful_purchase_response - "cvdId=1&trnType=P&trnApproved=1&trnId=10000028&messageId=1&messageText=Approved&trnOrderNumber=df5e88232a61dc1d0058a20d5b5c0e&authCode=TEST&errorType=N&errorFields=&responseType=T&trnAmount=15%2E00&trnDate=6%2F5%2F2008+5%3A26%3A53+AM&avsProcessed=0&avsId=0&avsResult=0&avsAddrMatch=0&avsPostalMatch=0&avsMessage=Address+Verification+not+performed+f" + 'cvdId=1&trnType=P&trnApproved=1&trnId=10000028&messageId=1&messageText=Approved&trnOrderNumber=df5e88232a61dc1d0058a20d5b5c0e&authCode=TEST&errorType=N&errorFields=&responseType=T&trnAmount=15%2E00&trnDate=6%2F5%2F2008+5%3A26%3A53+AM&avsProcessed=0&avsId=0&avsResult=0&avsAddrMatch=0&avsPostalMatch=0&avsMessage=Address+Verification+not+performed+f' end def successful_test_purchase_response - "merchant_id=100200000&trnId=11011067&authCode=TEST&trnApproved=1&avsId=M&cvdId=1&messageId=1&messageText=Approved&trnOrderNumber=1234" + 'merchant_id=100200000&trnId=11011067&authCode=TEST&trnApproved=1&avsId=M&cvdId=1&messageId=1&messageText=Approved&trnOrderNumber=1234' end def unsuccessful_purchase_response - "merchant_id=100200000&trnId=11011069&authCode=&trnApproved=0&avsId=0&cvdId=6&messageId=16&messageText=Duplicate+transaction&trnOrderNumber=1234" + 'merchant_id=100200000&trnId=11011069&authCode=&trnApproved=0&avsId=0&cvdId=6&messageId=16&messageText=Duplicate+transaction&trnOrderNumber=1234' end def successful_check_purchase_response - "trnApproved=1&trnId=10000072&messageId=1&messageText=Approved&trnOrderNumber=5d9f511363a0f35d37de53b4d74f5b&authCode=&errorType=N&errorFields=&responseType=T&trnAmount=15%2E00&trnDate=6%2F4%2F2008+6%3A33%3A55+PM&avsProcessed=0&avsId=0&avsResult=0&avsAddrMatch=0&avsPostalMatch=0&avsMessage=Address+Verification+not+performed+for+this+transaction%2E&trnType=D&paymentMethod=EFT&ref1=reference+one&ref2=&ref3=&ref4=&ref5=" + 'trnApproved=1&trnId=10000072&messageId=1&messageText=Approved&trnOrderNumber=5d9f511363a0f35d37de53b4d74f5b&authCode=&errorType=N&errorFields=&responseType=T&trnAmount=15%2E00&trnDate=6%2F4%2F2008+6%3A33%3A55+PM&avsProcessed=0&avsId=0&avsResult=0&avsAddrMatch=0&avsPostalMatch=0&avsMessage=Address+Verification+not+performed+for+this+transaction%2E&trnType=D&paymentMethod=EFT&ref1=reference+one&ref2=&ref3=&ref4=&ref5=' end def successful_authorize_response - "trnApproved=1&trnId=10100560&messageId=1&messageText=Approved&trnOrderNumber=0b936c13208677aaa00be509c541e7&authCode=TEST&errorType=N&errorFields=&responseType=T&trnAmount=15%2E00&trnDate=9%2F9%2F2015+10%3A10%3A28+AM&avsProcessed=1&avsId=N&avsResult=0&avsAddrMatch=0&avsPostalMatch=0&avsMessage=Street+address+and+Postal%2FZIP+do+not+match%2E&cvdId=1&cardType=VI&trnType=PA&paymentMethod=CC&ref1=reference+one&ref2=&ref3=&ref4=&ref5=" + 'trnApproved=1&trnId=10100560&messageId=1&messageText=Approved&trnOrderNumber=0b936c13208677aaa00be509c541e7&authCode=TEST&errorType=N&errorFields=&responseType=T&trnAmount=15%2E00&trnDate=9%2F9%2F2015+10%3A10%3A28+AM&avsProcessed=1&avsId=N&avsResult=0&avsAddrMatch=0&avsPostalMatch=0&avsMessage=Street+address+and+Postal%2FZIP+do+not+match%2E&cvdId=1&cardType=VI&trnType=PA&paymentMethod=CC&ref1=reference+one&ref2=&ref3=&ref4=&ref5=' end def unsuccessful_authorize_response - "trnApproved=0&trnId=10100561&messageId=7&messageText=DECLINE&trnOrderNumber=7eef9f25c6f123572f193bee4a1aa0&authCode=&errorType=N&errorFields=&responseType=T&trnAmount=15%2E00&trnDate=9%2F9%2F2015+10%3A11%3A22+AM&avsProcessed=1&avsId=N&avsResult=0&avsAddrMatch=0&avsPostalMatch=0&avsMessage=Street+address+and+Postal%2FZIP+do+not+match%2E&cvdId=2&cardType=AM&trnType=PA&paymentMethod=CC&ref1=reference+one&ref2=&ref3=&ref4=&ref5=" + 'trnApproved=0&trnId=10100561&messageId=7&messageText=DECLINE&trnOrderNumber=7eef9f25c6f123572f193bee4a1aa0&authCode=&errorType=N&errorFields=&responseType=T&trnAmount=15%2E00&trnDate=9%2F9%2F2015+10%3A11%3A22+AM&avsProcessed=1&avsId=N&avsResult=0&avsAddrMatch=0&avsPostalMatch=0&avsMessage=Street+address+and+Postal%2FZIP+do+not+match%2E&cvdId=2&cardType=AM&trnType=PA&paymentMethod=CC&ref1=reference+one&ref2=&ref3=&ref4=&ref5=' end def successful_void_response - "trnApproved=1&trnId=10100563&messageId=1&messageText=Approved&trnOrderNumber=6ca476d1a29da81a5f2d5d2c92ddeb&authCode=TEST&errorType=N&errorFields=&responseType=T&trnAmount=15%2E00&trnDate=9%2F9%2F2015+10%3A13%3A12+AM&avsProcessed=0&avsId=U&avsResult=0&avsAddrMatch=0&avsPostalMatch=0&avsMessage=Address+information+is+unavailable%2E&cvdId=2&cardType=VI&trnType=VP&paymentMethod=CC&ref1=reference+one&ref2=&ref3=&ref4=&ref5=" - end + 'trnApproved=1&trnId=10100563&messageId=1&messageText=Approved&trnOrderNumber=6ca476d1a29da81a5f2d5d2c92ddeb&authCode=TEST&errorType=N&errorFields=&responseType=T&trnAmount=15%2E00&trnDate=9%2F9%2F2015+10%3A13%3A12+AM&avsProcessed=0&avsId=U&avsResult=0&avsAddrMatch=0&avsPostalMatch=0&avsMessage=Address+information+is+unavailable%2E&cvdId=2&cardType=VI&trnType=VP&paymentMethod=CC&ref1=reference+one&ref2=&ref3=&ref4=&ref5=' + end def unsuccessful_void_response - "trnApproved=0&trnId=0&messageId=0&messageText=%3CLI%3EAdjustment+id+must+be+less+than+8+characters%3Cbr%3E&trnOrderNumber=&authCode=&errorType=U&errorFields=adjId&responseType=T&trnAmount=&trnDate=9%2F9%2F2015+10%3A15%3A20+AM&avsProcessed=0&avsId=0&avsResult=0&avsAddrMatch=0&avsPostalMatch=0&avsMessage=Address+Verification+not+performed+for+this+transaction%2E&cardType=&trnType=VP&paymentMethod=CC&ref1=&ref2=&ref3=&ref4=&ref5=" + 'trnApproved=0&trnId=0&messageId=0&messageText=%3CLI%3EAdjustment+id+must+be+less+than+8+characters%3Cbr%3E&trnOrderNumber=&authCode=&errorType=U&errorFields=adjId&responseType=T&trnAmount=&trnDate=9%2F9%2F2015+10%3A15%3A20+AM&avsProcessed=0&avsId=0&avsResult=0&avsAddrMatch=0&avsPostalMatch=0&avsMessage=Address+Verification+not+performed+for+this+transaction%2E&cardType=&trnType=VP&paymentMethod=CC&ref1=&ref2=&ref3=&ref4=&ref5=' end def brazilian_address_params_without_zip_and_state @@ -285,23 +352,23 @@ def next_year end def successful_recurring_response - "trnApproved=1&trnId=10000072&messageId=1&messageText=Approved&trnOrderNumber=5d9f511363a0f35d37de53b4d74f5b&authCode=&errorType=N&errorFields=&responseType=T&trnAmount=15%2E00&trnDate=6%2F4%2F2008+6%3A33%3A55+PM&avsProcessed=0&avsId=0&avsResult=0&avsAddrMatch=0&avsPostalMatch=0&avsMessage=Address+Verification+not+performed+for+this+transaction%2E&trnType=D&paymentMethod=EFT&ref1=reference+one&ref2=&ref3=&ref4=&ref5=" + 'trnApproved=1&trnId=10000072&messageId=1&messageText=Approved&trnOrderNumber=5d9f511363a0f35d37de53b4d74f5b&authCode=&errorType=N&errorFields=&responseType=T&trnAmount=15%2E00&trnDate=6%2F4%2F2008+6%3A33%3A55+PM&avsProcessed=0&avsId=0&avsResult=0&avsAddrMatch=0&avsPostalMatch=0&avsMessage=Address+Verification+not+performed+for+this+transaction%2E&trnType=D&paymentMethod=EFT&ref1=reference+one&ref2=&ref3=&ref4=&ref5=' end def successful_update_recurring_response - "<response><code>1</code><message>Request successful</message></response>" + '<response><code>1</code><message>Request successful</message></response>' end def successful_cancel_recurring_response - "<response><code>1</code><message>Request successful</message></response>" + '<response><code>1</code><message>Request successful</message></response>' end def transcript - "ref1=reference+one&trnCardOwner=Longbob+Longsen&trnCardNumber=4030000010001234&trnExpMonth=09&trnExpYear=16&trnCardCvd=123&ordName=xiaobo+zzz&ordEmailAddress=xiaobozzz%40example.com&username=awesomesauce&password=sp00nz%21%21" + 'ref1=reference+one&trnCardOwner=Longbob+Longsen&trnCardNumber=4030000010001234&trnExpMonth=09&trnExpYear=16&trnCardCvd=123&ordName=xiaobo+zzz&ordEmailAddress=xiaobozzz%40example.com&username=awesomesauce&password=sp00nz%21%21' end def scrubbed_transcript - "ref1=reference+one&trnCardOwner=Longbob+Longsen&trnCardNumber=[FILTERED]&trnExpMonth=09&trnExpYear=16&trnCardCvd=[FILTERED]&ordName=xiaobo+zzz&ordEmailAddress=xiaobozzz%40example.com&username=awesomesauce&password=[FILTERED]" + 'ref1=reference+one&trnCardOwner=Longbob+Longsen&trnCardNumber=[FILTERED]&trnExpMonth=09&trnExpYear=16&trnCardCvd=[FILTERED]&ordName=xiaobo+zzz&ordEmailAddress=xiaobozzz%40example.com&username=awesomesauce&password=[FILTERED]' end end diff --git a/test/unit/gateways/blue_pay_test.rb b/test/unit/gateways/blue_pay_test.rb index 3a13b0fe71b..b4b040f5c43 100644 --- a/test/unit/gateways/blue_pay_test.rb +++ b/test/unit/gateways/blue_pay_test.rb @@ -1,11 +1,11 @@ require 'test_helper' RSP = { - :approved_auth => "AUTH_CODE=XCADZ&PAYMENT_ACCOUNT_MASK=xxxxxxxxxxxx4242&CARD_TYPE=VISA&TRANS_TYPE=AUTH&REBID=&STATUS=1&AVS=_&TRANS_ID=100134203758&CVV2=_&MESSAGE=Approved%20Auth", - :approved_capture => "AUTH_CODE=CHTHX&PAYMENT_ACCOUNT_MASK=xxxxxxxxxxxx4242&CARD_TYPE=VISA&TRANS_TYPE=CAPTURE&REBID=&STATUS=1&AVS=_&TRANS_ID=100134203760&CVV2=_&MESSAGE=Approved%20Capture", - :approved_void => "AUTH_CODE=KTMHB&PAYMENT_ACCOUNT_MASK=xxxxxxxxxxxx4242&CARD_TYPE=VISA&TRANS_TYPE=VOID&REBID=&STATUS=1&AVS=_&TRANS_ID=100134203763&CVV2=_&MESSAGE=Approved%20Void", - :declined => "TRANS_ID=100000000150&STATUS=0&AVS=0&CVV2=7&MESSAGE=Declined&REBID=", - :approved_purchase => "AUTH_CODE=GYRUY&PAYMENT_ACCOUNT_MASK=xxxxxxxxxxxx4242&CARD_TYPE=VISA&TRANS_TYPE=SALE&REBID=&STATUS=1&AVS=_&TRANS_ID=100134203767&CVV2=_&MESSAGE=Approved%20Sale" + :approved_auth => 'AUTH_CODE=XCADZ&PAYMENT_ACCOUNT_MASK=xxxxxxxxxxxx4242&CARD_TYPE=VISA&TRANS_TYPE=AUTH&REBID=&STATUS=1&AVS=_&TRANS_ID=100134203758&CVV2=_&MESSAGE=Approved%20Auth', + :approved_capture => 'AUTH_CODE=CHTHX&PAYMENT_ACCOUNT_MASK=xxxxxxxxxxxx4242&CARD_TYPE=VISA&TRANS_TYPE=CAPTURE&REBID=&STATUS=1&AVS=_&TRANS_ID=100134203760&CVV2=_&MESSAGE=Approved%20Capture', + :approved_void => 'AUTH_CODE=KTMHB&PAYMENT_ACCOUNT_MASK=xxxxxxxxxxxx4242&CARD_TYPE=VISA&TRANS_TYPE=VOID&REBID=&STATUS=1&AVS=_&TRANS_ID=100134203763&CVV2=_&MESSAGE=Approved%20Void', + :declined => 'TRANS_ID=100000000150&STATUS=0&AVS=0&CVV2=7&MESSAGE=Declined&REBID=', + :approved_purchase => 'AUTH_CODE=GYRUY&PAYMENT_ACCOUNT_MASK=xxxxxxxxxxxx4242&CARD_TYPE=VISA&TRANS_TYPE=SALE&REBID=&STATUS=1&AVS=_&TRANS_ID=100134203767&CVV2=_&MESSAGE=Approved%20Sale' } class BluePayTest < Test::Unit::TestCase @@ -23,7 +23,6 @@ def setup end def test_successful_authorization - #@gateway.expects(:ssl_post).returns(successful_authorization_response) @gateway.expects(:ssl_post).returns(RSP[:approved_auth]) assert response = @gateway.authorize(@amount, @credit_card) assert_instance_of Response, response @@ -52,8 +51,8 @@ def test_failed_authorization def test_add_address_outsite_north_america result = {} - @gateway.send(:add_address, result, :billing_address => {:address1 => '123 Test St.', :address2 => '5F', :city => 'Testville', :company => 'Test Company', :country => 'DE', :state => ''} ) - assert_equal ["ADDR1", "ADDR2", "CITY", "COMPANY_NAME", "COUNTRY", "PHONE", "STATE", "ZIP"], result.stringify_keys.keys.sort + @gateway.send(:add_address, result, :billing_address => {:address1 => '123 Test St.', :address2 => '5F', :city => 'Testville', :company => 'Test Company', :country => 'DE', :state => ''}) + assert_equal ['ADDR1', 'ADDR2', 'CITY', 'COMPANY_NAME', 'COUNTRY', 'PHONE', 'STATE', 'ZIP'], result.stringify_keys.keys.sort assert_equal 'n/a', result[:STATE] assert_equal '123 Test St.', result[:ADDR1] assert_equal 'DE', result[:COUNTRY] @@ -62,20 +61,19 @@ def test_add_address_outsite_north_america def test_add_address result = {} - @gateway.send(:add_address, result, :billing_address => {:address1 => '123 Test St.', :address2 => '5F', :city => 'Testville', :company => 'Test Company', :country => 'US', :state => 'AK'} ) + @gateway.send(:add_address, result, :billing_address => {:address1 => '123 Test St.', :address2 => '5F', :city => 'Testville', :company => 'Test Company', :country => 'US', :state => 'AK'}) - assert_equal ["ADDR1", "ADDR2", "CITY", "COMPANY_NAME", "COUNTRY", "PHONE", "STATE", "ZIP"], result.stringify_keys.keys.sort + assert_equal ['ADDR1', 'ADDR2', 'CITY', 'COMPANY_NAME', 'COUNTRY', 'PHONE', 'STATE', 'ZIP'], result.stringify_keys.keys.sort assert_equal 'AK', result[:STATE] assert_equal '123 Test St.', result[:ADDR1] assert_equal 'US', result[:COUNTRY] - end def test_name_comes_from_payment_method result = {} @gateway.send(:add_creditcard, result, @credit_card) - @gateway.send(:add_address, result, :billing_address => {:address1 => '123 Test St.', :address2 => '5F', :city => 'Testville', :company => 'Test Company', :country => 'US', :state => 'AK'} ) + @gateway.send(:add_address, result, :billing_address => {:address1 => '123 Test St.', :address2 => '5F', :city => 'Testville', :company => 'Test Company', :country => 'US', :state => 'AK'}) assert_equal @credit_card.first_name, result[:NAME1] assert_equal @credit_card.last_name, result[:NAME2] @@ -95,7 +93,7 @@ def test_add_description def test_purchase_meets_minimum_requirements params = { - :amount => "1.01", + :amount => '1.01', } @gateway.send(:add_creditcard, params, @credit_card) @@ -115,7 +113,7 @@ def test_successful_refund def test_refund_passing_extra_info response = stub_comms do - @gateway.refund(50, '123456789', :card_number => @credit_card.number, :first_name => "Bob", :last_name => "Smith", :zip => "12345") + @gateway.refund(50, '123456789', :card_number => @credit_card.number, :first_name => 'Bob', :last_name => 'Smith', :zip => '12345') end.check_request do |endpoint, data, headers| assert_match(/NAME1=Bob/, data) assert_match(/NAME2=Smith/, data) @@ -133,7 +131,7 @@ def test_failed_refund def test_deprecated_credit @gateway.expects(:ssl_post).returns(successful_purchase_response) - assert_deprecation_warning("credit should only be used to credit a payment method") do + assert_deprecation_warning('credit should only be used to credit a payment method') do assert response = @gateway.credit(@amount, '123456789', :card_number => @credit_card.number) assert_success response assert_equal 'This transaction has been approved', response.message @@ -150,15 +148,15 @@ def test_supported_card_types def test_parser_extracts_exactly_the_keys_in_gateway_response assert_nothing_raised do - response = @gateway.send(:parse, "NEW_IMPORTANT_FIELD=value_on_fire") + response = @gateway.send(:parse, 'NEW_IMPORTANT_FIELD=value_on_fire') assert_equal response.params.keys, ['NEW_IMPORTANT_FIELD'] - assert_equal response.params['NEW_IMPORTANT_FIELD'], "value_on_fire" + assert_equal response.params['NEW_IMPORTANT_FIELD'], 'value_on_fire' end end def test_failure_without_response_reason_text assert_nothing_raised do - assert_equal '', @gateway.send(:parse, "MESSAGE=").message + assert_equal '', @gateway.send(:parse, 'MESSAGE=').message end end @@ -177,13 +175,9 @@ def test_cvv_result end def test_message_from - - def get_msg(query) - @gateway.send(:parse, query).message - end - assert_equal "CVV does not match", get_msg('STATUS=2&CVV2=N&AVS=A&MESSAGE=FAILURE') - assert_equal "Street address matches, but 5-digit and 9-digit postal code do not match.", - get_msg('STATUS=2&CVV2=M&AVS=A&MESSAGE=FAILURE') + assert_equal 'CVV does not match', @gateway.send(:parse, 'STATUS=2&CVV2=N&AVS=A&MESSAGE=FAILURE').message + assert_equal 'Street address matches, but 5-digit and 9-digit postal code do not match.', + @gateway.send(:parse, 'STATUS=2&CVV2=M&AVS=A&MESSAGE=FAILURE').message end # Recurring Billing Unit Tests @@ -197,7 +191,7 @@ def test_successful_recurring :rebill_expression => '14 DAYS', :rebill_cycles => '24', :rebill_amount => @amount * 4 - ) + ) end assert_instance_of Response, response @@ -245,9 +239,9 @@ def test_successful_status_recurring end def test_solution_id_is_added_to_post_data_parameters - assert !@gateway.send(:post_data, 'AUTH_ONLY').include?("solution_ID=A1000000") + assert !@gateway.send(:post_data, 'AUTH_ONLY').include?('solution_ID=A1000000') ActiveMerchant::Billing::BluePayGateway.application_id = 'A1000000' - assert @gateway.send(:post_data, 'AUTH_ONLY').include?("solution_ID=A1000000") + assert @gateway.send(:post_data, 'AUTH_ONLY').include?('solution_ID=A1000000') ensure ActiveMerchant::Billing::BluePayGateway.application_id = nil end @@ -263,7 +257,7 @@ def minimum_requirements end def successful_refund_response - "AUTH_CODE=GFOCD&PAYMENT_ACCOUNT_MASK=xxxxxxxxxxxx4242&CARD_TYPE=VISA&TRANS_TYPE=CREDIT&REBID=&STATUS=1&AVS=_&TRANS_ID=100134230412&CVV2=_&MESSAGE=Approved%20Credit" + 'AUTH_CODE=GFOCD&PAYMENT_ACCOUNT_MASK=xxxxxxxxxxxx4242&CARD_TYPE=VISA&TRANS_TYPE=CREDIT&REBID=&STATUS=1&AVS=_&TRANS_ID=100134230412&CVV2=_&MESSAGE=Approved%20Credit' end def failed_refund_response @@ -271,15 +265,15 @@ def failed_refund_response end def successful_authorization_response - "AUTH_CODE=RSWUC&PAYMENT_ACCOUNT_MASK=xxxxxxxxxxxx4242&CARD_TYPE=VISA&TRANS_TYPE=AUTH&REBID=&STATUS=1&AVS=_&TRANS_ID=100134229528&CVV2=_&MESSAGE=Approved%20Auth" + 'AUTH_CODE=RSWUC&PAYMENT_ACCOUNT_MASK=xxxxxxxxxxxx4242&CARD_TYPE=VISA&TRANS_TYPE=AUTH&REBID=&STATUS=1&AVS=_&TRANS_ID=100134229528&CVV2=_&MESSAGE=Approved%20Auth' end def successful_purchase_response - "AUTH_CODE=KHJMY&PAYMENT_ACCOUNT_MASK=xxxxxxxxxxxx4242&CARD_TYPE=VISA&TRANS_TYPE=SALE&REBID=&STATUS=1&AVS=_&TRANS_ID=100134229668&CVV2=_&MESSAGE=Approved%20Sale" + 'AUTH_CODE=KHJMY&PAYMENT_ACCOUNT_MASK=xxxxxxxxxxxx4242&CARD_TYPE=VISA&TRANS_TYPE=SALE&REBID=&STATUS=1&AVS=_&TRANS_ID=100134229668&CVV2=_&MESSAGE=Approved%20Sale' end def failed_authorization_response - "AUTH_CODE=&PAYMENT_ACCOUNT_MASK=xxxxxxxxxxxx4242&CARD_TYPE=VISA&TRANS_TYPE=AUTH&REBID=&STATUS=0&AVS=_&TRANS_ID=100134229728&CVV2=_&MESSAGE=Declined%20Auth" + 'AUTH_CODE=&PAYMENT_ACCOUNT_MASK=xxxxxxxxxxxx4242&CARD_TYPE=VISA&TRANS_TYPE=AUTH&REBID=&STATUS=0&AVS=_&TRANS_ID=100134229728&CVV2=_&MESSAGE=Declined%20Auth' end def successful_recurring_response @@ -299,10 +293,10 @@ def successful_status_recurring_response end def transcript - "card_num=4111111111111111&exp_date=1212&MASTER_ID=&PAYMENT_TYPE=CREDIT&PAYMENT_ACCOUNT=4242424242424242&CARD_CVV2=123&CARD_EXPIRE=0916&NAME1=Longbob&NAME2=Longsen&ORDER_ID=78c40687dd55dbdc140df777b0e8ece3&INVOICE_ID=&invoice_num=78c40687dd55dbdc140df777b0e8ece3&EMAIL=&CUSTOM_ID=&DUPLICATE_OVERRIDE=&TRANS_TYPE=SALE&AMOUNT=1.00&MODE=TEST&ACCOUNT_ID=100096218902&TAMPER_PROOF_SEAL=55624458ce3e15fa8e33e6f2d784bbcb" + 'card_num=4111111111111111&exp_date=1212&MASTER_ID=&PAYMENT_TYPE=CREDIT&PAYMENT_ACCOUNT=4242424242424242&CARD_CVV2=123&CARD_EXPIRE=0916&NAME1=Longbob&NAME2=Longsen&ORDER_ID=78c40687dd55dbdc140df777b0e8ece3&INVOICE_ID=&invoice_num=78c40687dd55dbdc140df777b0e8ece3&EMAIL=&CUSTOM_ID=&DUPLICATE_OVERRIDE=&TRANS_TYPE=SALE&AMOUNT=1.00&MODE=TEST&ACCOUNT_ID=100096218902&TAMPER_PROOF_SEAL=55624458ce3e15fa8e33e6f2d784bbcb' end def scrubbed_transcript - "card_num=[FILTERED]&exp_date=1212&MASTER_ID=&PAYMENT_TYPE=CREDIT&PAYMENT_ACCOUNT=[FILTERED]&CARD_CVV2=[FILTERED]&CARD_EXPIRE=0916&NAME1=Longbob&NAME2=Longsen&ORDER_ID=78c40687dd55dbdc140df777b0e8ece3&INVOICE_ID=&invoice_num=78c40687dd55dbdc140df777b0e8ece3&EMAIL=&CUSTOM_ID=&DUPLICATE_OVERRIDE=&TRANS_TYPE=SALE&AMOUNT=1.00&MODE=TEST&ACCOUNT_ID=100096218902&TAMPER_PROOF_SEAL=[FILTERED]" + 'card_num=[FILTERED]&exp_date=1212&MASTER_ID=&PAYMENT_TYPE=CREDIT&PAYMENT_ACCOUNT=[FILTERED]&CARD_CVV2=[FILTERED]&CARD_EXPIRE=0916&NAME1=Longbob&NAME2=Longsen&ORDER_ID=78c40687dd55dbdc140df777b0e8ece3&INVOICE_ID=&invoice_num=78c40687dd55dbdc140df777b0e8ece3&EMAIL=&CUSTOM_ID=&DUPLICATE_OVERRIDE=&TRANS_TYPE=SALE&AMOUNT=1.00&MODE=TEST&ACCOUNT_ID=100096218902&TAMPER_PROOF_SEAL=[FILTERED]' end end diff --git a/test/unit/gateways/blue_snap_test.rb b/test/unit/gateways/blue_snap_test.rb index d115ec290b9..76d230a9853 100644 --- a/test/unit/gateways/blue_snap_test.rb +++ b/test/unit/gateways/blue_snap_test.rb @@ -1,6 +1,8 @@ require 'test_helper' class BlueSnapTest < Test::Unit::TestCase + include CommStub + def setup @gateway = BlueSnapGateway.new(api_username: 'login', api_password: 'password') @credit_card = credit_card @@ -30,13 +32,15 @@ def test_failed_purchase response = @gateway.purchase(@amount, @credit_card, @options) assert_failure response - assert_equal "14002", response.error_code + assert_equal '14002', response.error_code end def test_successful_authorize - @gateway.expects(:raw_ssl_request).returns(successful_authorize_response) - - response = @gateway.authorize(@amount, @credit_card, @options) + response = stub_comms(@gateway, :raw_ssl_request) do + @gateway.authorize(@amount, @credit_card, @options) + end.check_request do |type, endpoint, data, headers| + assert_match '<storeCard>false</storeCard>', data + end.respond_with(successful_authorize_response) assert_success response assert_equal '1012082893', response.authorization end @@ -46,39 +50,45 @@ def test_failed_authorize response = @gateway.authorize(@amount, @credit_card, @options) assert_failure response - assert_equal "14002", response.error_code + assert_equal '14002', response.error_code end def test_successful_capture @gateway.expects(:raw_ssl_request).returns(successful_capture_response) - response = @gateway.capture(@amount, "Authorization") + response = @gateway.capture(@amount, 'Authorization') assert_success response - assert_equal "1012082881", response.authorization + assert_equal '1012082881', response.authorization end def test_failed_capture @gateway.expects(:raw_ssl_request).returns(failed_capture_response) - response = @gateway.capture(@amount, "Authorization") + response = @gateway.capture(@amount, 'Authorization') assert_failure response - assert_equal "20008", response.error_code + assert_equal '20008', response.error_code end def test_successful_refund @gateway.expects(:raw_ssl_request).returns(successful_refund_response) +<<<<<<< HEAD response = @gateway.refund(@amount, "1012082839") assert_success response assert_equal 204, response.params["code"].to_i +======= + response = @gateway.refund(@amount, 'Authorization') + assert_success response + assert_equal '1012082907', response.authorization +>>>>>>> upstream/master end def test_failed_refund @gateway.expects(:raw_ssl_request).returns(failed_refund_response) - response = @gateway.refund(@amount, "Authorization") + response = @gateway.refund(@amount, 'Authorization') assert_failure response - assert_equal "20008", response.error_code + assert_equal '20008', response.error_code end def test_successful_void @@ -86,7 +96,7 @@ def test_successful_void response = @gateway.void("Authorization", credit_card) assert_success response - assert_equal "1012082919", response.authorization + assert_equal '1012082919', response.authorization end def test_failed_void @@ -94,7 +104,7 @@ def test_failed_void response = @gateway.void("Authorization", credit_card) assert_failure response - assert_equal "20008", response.error_code + assert_equal '20008', response.error_code end def test_successful_verify @@ -102,7 +112,7 @@ def test_successful_verify response = @gateway.verify(@credit_card, @options) assert_success response - assert_equal "1012082929", response.authorization + assert_equal '1012082929', response.authorization end def test_failed_verify @@ -110,7 +120,7 @@ def test_failed_verify response = @gateway.verify(@credit_card, @options) assert_failure response - assert_equal "14002", response.error_code + assert_equal '14002', response.error_code end def test_successful_store @@ -118,7 +128,7 @@ def test_successful_store response = @gateway.store(@credit_card, @options) assert_success response - assert_equal "20936441", response.authorization + assert_equal '20936441', response.authorization end def test_failed_store @@ -126,7 +136,15 @@ def test_failed_store response = @gateway.store(@credit_card, @options) assert_failure response - assert_equal "14002", response.error_code + assert_equal '14002', response.error_code + end + + def test_currency_added_correctly + stub_comms(@gateway, :raw_ssl_request) do + @gateway.purchase(@amount, @credit_card, @options.merge(currency: 'CAD')) + end.check_request do |method, url, data| + assert_match(/<currency>CAD<\/currency>/, data) + end.respond_with(successful_purchase_response) end def test_verify_good_credentials @@ -139,6 +157,14 @@ def test_verify_bad_credentials assert !@gateway.verify_credentials end + def test_failed_forbidden_response + @gateway.expects(:raw_ssl_request).returns(forbidden_response) + + response = @gateway.purchase(@amount, @credit_card, @options) + assert_failure response + assert_equal '<xml>You are not authorized to perform this request due to inappropriate role permissions.</xml>', response.message + end + def test_scrub assert @gateway.supports_scrubbing? assert_equal @gateway.scrub(pre_scrubbed), post_scrubbed @@ -493,7 +519,7 @@ def successful_store_response </vaulted-shopper> XML - response.headers = { "content-location" => "https://sandbox.bluesnap.com/services/2/vaulted-shoppers/20936441" } + response.headers = { 'content-location' => 'https://sandbox.bluesnap.com/services/2/vaulted-shoppers/20936441' } response end @@ -511,12 +537,15 @@ def failed_store_response MockResponse.failed(body, 400) end + def forbidden_response + MockResponse.new(403, '<xml>You are not authorized to perform this request due to inappropriate role permissions.</xml>') + end + def credentials_are_legit_response - MockResponse.new(400, "<xml>Server Error</xml>") + MockResponse.new(400, '<xml>Server Error</xml>') end def credentials_are_bogus_response - MockResponse.new(401, %{<!DOCTYPE html><html><head><title>Apache Tomcat/8.0.24 - Error report</title><style type="text/css">H1 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:22px;} H2 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:16px;} H3 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:14px;} BODY {font-family:Tahoma,Arial,sans-serif;color:black;background-color:white;} B {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;} P {font-family:Tahoma,Arial,sans-serif;background:white;color:black;font-size:12px;}A {color : black;}A.name {color : black;}.line {height: 1px; background-color: #525D76; border: none;}</style> </head><body><h1>HTTP Status 401 - Bad credentials</h1><div class="line"></div><p><b>type</b> Status report</p><p><b>message</b> <u>Bad credentials</u></p><p><b>description</b> <u>This request requires HTTP authentication.</u></p><hr class="line"><h3>Apache Tomcat/8.0.24</h3></body></html>}) + MockResponse.new(401, %{<!DOCTYPE html><html lang="en"><head><title>HTTP Status 401 – Unauthorized</title><style type="text/css">h1 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:22px;} h2 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:16px;} h3 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:14px;} body {font-family:Tahoma,Arial,sans-serif;color:black;background-color:white;} b {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;} p {font-family:Tahoma,Arial,sans-serif;background:white;color:black;font-size:12px;} a {color:black;} a.name {color:black;} .line {height:1px;background-color:#525D76;border:none;}</style></head><body><h1>HTTP Status 401 – Unauthorized</h1><hr class="line" /><p><b>Type</b> Status Report</p><p><b>Message</b> Bad credentials</p><p><b>Description</b> The request has not been applied because it lacks valid authentication credentials for the target resource.</p><hr class="line" /><h3>Apache Tomcat Version X</h3></body></html>}) end - end diff --git a/test/unit/gateways/bogus_test.rb b/test/unit/gateways/bogus_test.rb index 25323865538..e6978d828e1 100644 --- a/test/unit/gateways/bogus_test.rb +++ b/test/unit/gateways/bogus_test.rb @@ -14,34 +14,39 @@ def setup @creditcard = credit_card(CC_SUCCESS_PLACEHOLDER) - @response = ActiveMerchant::Billing::Response.new(true, "Transaction successful", :transid => BogusGateway::AUTHORIZATION) + @response = ActiveMerchant::Billing::Response.new(true, 'Transaction successful', :transid => BogusGateway::AUTHORIZATION) end def test_authorize - assert @gateway.authorize(1000, credit_card(CC_SUCCESS_PLACEHOLDER)).success? + assert @gateway.authorize(1000, credit_card(CC_SUCCESS_PLACEHOLDER)).success? response = @gateway.authorize(1000, credit_card(CC_FAILURE_PLACEHOLDER)) refute response.success? assert_equal Gateway::STANDARD_ERROR_CODE[:processing_error], response.error_code e = assert_raises(ActiveMerchant::Billing::Error) do @gateway.authorize(1000, credit_card('123')) end - assert_equal("Bogus Gateway: Use CreditCard number ending in 1 for success, 2 for exception and anything else for error", e.message) + assert_equal('Bogus Gateway: Use CreditCard number ending in 1 for success, 2 for exception and anything else for error', e.message) + end + + def test_authorize_using_credit_card_token + token = @gateway.store(credit_card(CC_SUCCESS_PLACEHOLDER)).authorization + assert @gateway.authorize(1000, token).success? end def test_purchase - assert @gateway.purchase(1000, credit_card(CC_SUCCESS_PLACEHOLDER)).success? + assert @gateway.purchase(1000, credit_card(CC_SUCCESS_PLACEHOLDER)).success? response = @gateway.purchase(1000, credit_card(CC_FAILURE_PLACEHOLDER)) refute response.success? assert_equal Gateway::STANDARD_ERROR_CODE[:processing_error], response.error_code e = assert_raises(ActiveMerchant::Billing::Error) do @gateway.purchase(1000, credit_card('123')) end - assert_equal("Bogus Gateway: Use CreditCard number ending in 1 for success, 2 for exception and anything else for error", e.message) + assert_equal('Bogus Gateway: Use CreditCard number ending in 1 for success, 2 for exception and anything else for error', e.message) end def test_capture assert @gateway.capture(1000, '1337').success? - assert @gateway.capture(1000, @response.params["transid"]).success? + assert @gateway.capture(1000, @response.params['transid']).success? response = @gateway.capture(1000, CC_FAILURE_PLACEHOLDER) refute response.success? assert_equal Gateway::STANDARD_ERROR_CODE[:processing_error], response.error_code @@ -51,19 +56,19 @@ def test_capture end def test_credit - assert @gateway.credit(1000, credit_card(CC_SUCCESS_PLACEHOLDER)).success? + assert @gateway.credit(1000, credit_card(CC_SUCCESS_PLACEHOLDER)).success? response = @gateway.credit(1000, credit_card(CC_FAILURE_PLACEHOLDER)) refute response.success? assert_equal Gateway::STANDARD_ERROR_CODE[:processing_error], response.error_code e = assert_raises(ActiveMerchant::Billing::Error) do @gateway.credit(1000, credit_card('123')) end - assert_equal("Bogus Gateway: Use CreditCard number ending in 1 for success, 2 for exception and anything else for error", e.message) + assert_equal('Bogus Gateway: Use CreditCard number ending in 1 for success, 2 for exception and anything else for error', e.message) end def test_refund assert @gateway.refund(1000, '1337').success? - assert @gateway.refund(1000, @response.params["transid"]).success? + assert @gateway.refund(1000, @response.params['transid']).success? response = @gateway.refund(1000, CC_FAILURE_PLACEHOLDER) refute response.success? assert_equal Gateway::STANDARD_ERROR_CODE[:processing_error], response.error_code @@ -82,7 +87,7 @@ def test_credit_uses_refund def test_void assert @gateway.void('1337').success? - assert @gateway.void(@response.params["transid"]).success? + assert @gateway.void(@response.params['transid']).success? response = @gateway.void(CC_FAILURE_PLACEHOLDER) refute response.success? assert_equal Gateway::STANDARD_ERROR_CODE[:processing_error], response.error_code @@ -92,14 +97,14 @@ def test_void end def test_store - assert @gateway.store(credit_card(CC_SUCCESS_PLACEHOLDER)).success? + assert @gateway.store(credit_card(CC_SUCCESS_PLACEHOLDER)).success? response = @gateway.store(credit_card(CC_FAILURE_PLACEHOLDER)) refute response.success? assert_equal Gateway::STANDARD_ERROR_CODE[:processing_error], response.error_code e = assert_raises(ActiveMerchant::Billing::Error) do @gateway.store(credit_card('123')) end - assert_equal("Bogus Gateway: Use CreditCard number ending in 1 for success, 2 for exception and anything else for error", e.message) + assert_equal('Bogus Gateway: Use CreditCard number ending in 1 for success, 2 for exception and anything else for error', e.message) end def test_unstore @@ -125,7 +130,7 @@ def test_authorize_with_check e = assert_raises(ActiveMerchant::Billing::Error) do @gateway.authorize(1000, check(:account_number => '123', :number => nil)) end - assert_equal("Bogus Gateway: Use bank account number ending in 1 for success, 2 for exception and anything else for error", e.message) + assert_equal('Bogus Gateway: Use bank account number ending in 1 for success, 2 for exception and anything else for error', e.message) end def test_purchase_with_check @@ -138,7 +143,7 @@ def test_purchase_with_check e = assert_raises(ActiveMerchant::Billing::Error) do @gateway.purchase(1000, check(:account_number => '123', :number => nil)) end - assert_equal("Bogus Gateway: Use bank account number ending in 1 for success, 2 for exception and anything else for error", e.message) + assert_equal('Bogus Gateway: Use bank account number ending in 1 for success, 2 for exception and anything else for error', e.message) end def test_store_with_check @@ -147,7 +152,7 @@ def test_store_with_check e = assert_raises(ActiveMerchant::Billing::Error) do @gateway.store(check(:account_number => '123', :number => nil)) end - assert_equal("Bogus Gateway: Use bank account number ending in 1 for success, 2 for exception and anything else for error", e.message) + assert_equal('Bogus Gateway: Use bank account number ending in 1 for success, 2 for exception and anything else for error', e.message) end def test_credit_with_check @@ -156,7 +161,7 @@ def test_credit_with_check e = assert_raises(ActiveMerchant::Billing::Error) do @gateway.credit(1000, check(:account_number => '123', :number => nil)) end - assert_equal("Bogus Gateway: Use bank account number ending in 1 for success, 2 for exception and anything else for error", e.message) + assert_equal('Bogus Gateway: Use bank account number ending in 1 for success, 2 for exception and anything else for error', e.message) end def test_store_then_purchase_with_check @@ -175,17 +180,17 @@ def test_authorize_emv e = assert_raises(ActiveMerchant::Billing::Error) do @gateway.authorize(1001, credit_card('123', {icc_data: 'DEADBEEF'})) end - assert_equal("Bogus Gateway: Use amount ending in 00 for success, 05 for failure and anything else for exception", e.message) + assert_equal('Bogus Gateway: Use amount ending in 00 for success, 05 for failure and anything else for exception', e.message) end def test_purchase_emv - assert @gateway.purchase(1000, credit_card('123', {icc_data: 'DEADBEEF'})).success? + assert @gateway.purchase(1000, credit_card('123', {icc_data: 'DEADBEEF'})).success? response = @gateway.purchase(1005, credit_card('123', {icc_data: 'DEADBEEF'})) refute response.success? assert_equal Gateway::STANDARD_ERROR_CODE[:processing_error], response.error_code e = assert_raises(ActiveMerchant::Billing::Error) do @gateway.purchase(1001, credit_card('123', {icc_data: 'DEADBEEF'})) end - assert_equal("Bogus Gateway: Use amount ending in 00 for success, 05 for failure and anything else for exception", e.message) + assert_equal('Bogus Gateway: Use amount ending in 00 for success, 05 for failure and anything else for exception', e.message) end end diff --git a/test/unit/gateways/borgun_test.rb b/test/unit/gateways/borgun_test.rb index 79d7c635a4d..bd38587664a 100644 --- a/test/unit/gateways/borgun_test.rb +++ b/test/unit/gateways/borgun_test.rb @@ -17,7 +17,8 @@ def setup @options = { order_id: '1', billing_address: address, - description: 'Store Purchase' + description: 'Store Purchase', + terminal_id: '3' } end @@ -27,7 +28,7 @@ def test_successful_purchase response = @gateway.purchase(@amount, @credit_card, @options) assert_success response - assert_equal "140216103700|11|15|WC0000000001|123456|1|000000012300", response.authorization + assert_equal '140216103700|11|15|WC0000000001|123456|1|000000012300|978', response.authorization assert response.test? end @@ -44,7 +45,7 @@ def test_authorize_and_capture end.respond_with(successful_authorize_response) assert_success response - assert_equal "140601083732|11|18|WC0000000001|123456|5|000000012300", response.authorization + assert_equal '140601083732|11|18|WC0000000001|123456|5|000000012300|978', response.authorization capture = stub_comms do @gateway.capture(@amount, response.authorization) @@ -61,7 +62,7 @@ def test_refund end.respond_with(successful_purchase_response) assert_success response - assert_equal "140216103700|11|15|WC0000000001|123456|1|000000012300", response.authorization + assert_equal '140216103700|11|15|WC0000000001|123456|1|000000012300|978', response.authorization refund = stub_comms do @gateway.refund(@amount, response.authorization) @@ -78,7 +79,7 @@ def test_void end.respond_with(successful_purchase_response) assert_success response - assert_equal "140216103700|11|15|WC0000000001|123456|1|000000012300", response.authorization + assert_equal '140216103700|11|15|WC0000000001|123456|1|000000012300|978', response.authorization refund = stub_comms do @gateway.void(response.authorization) @@ -97,6 +98,14 @@ def test_passing_cvv end.respond_with(successful_purchase_response) end + def test_passing_terminal_id + stub_comms do + @gateway.purchase(@amount, @credit_card, { terminal_id: '3' }) + end.check_request do |endpoint, data, headers| + assert_match(/TerminalID&gt;3/, data) + end.respond_with(successful_purchase_response) + end + def test_transcript_scrubbing assert_equal scrubbed_transcript, @gateway.scrub(transcript) end diff --git a/test/unit/gateways/bpoint_test.rb b/test/unit/gateways/bpoint_test.rb index 1c7dafe14c6..384862ab576 100644 --- a/test/unit/gateways/bpoint_test.rb +++ b/test/unit/gateways/bpoint_test.rb @@ -46,7 +46,7 @@ def test_failed_purchase response = @gateway.purchase(@amount, @credit_card, @options) assert_failure response - assert_equal "Declined", response.message + assert_equal 'Declined', response.message end def test_successful_authorize @@ -399,23 +399,23 @@ def failed_void_response end def successful_store_response - %( - <?xml version="1.0" encoding="UTF-8"?> - <soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> - <soap:Body> - <AddTokenResponse xmlns="urn:Eve_1_4_4"> - <AddTokenResult> - <Token>5999992142370790</Token> - <MaskedCardNumber>498765...769</MaskedCardNumber> - <CardType>VC</CardType> - </AddTokenResult> - <response> - <ResponseCode>SUCCESS</ResponseCode> - </response> - </AddTokenResponse> - </soap:Body> - </soap:Envelope> - ) + %( + <?xml version="1.0" encoding="UTF-8"?> + <soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> + <soap:Body> + <AddTokenResponse xmlns="urn:Eve_1_4_4"> + <AddTokenResult> + <Token>5999992142370790</Token> + <MaskedCardNumber>498765...769</MaskedCardNumber> + <CardType>VC</CardType> + </AddTokenResult> + <response> + <ResponseCode>SUCCESS</ResponseCode> + </response> + </AddTokenResponse> + </soap:Body> + </soap:Envelope> + ) end def failed_store_response diff --git a/test/unit/gateways/braintree_blue_test.rb b/test/unit/gateways/braintree_blue_test.rb index fbb95eaa405..0135224cd32 100644 --- a/test/unit/gateways/braintree_blue_test.rb +++ b/test/unit/gateways/braintree_blue_test.rb @@ -7,10 +7,11 @@ def setup @gateway = BraintreeBlueGateway.new( :merchant_id => 'test', :public_key => 'test', - :private_key => 'test' + :private_key => 'test', + :test => true ) - @internal_gateway = @gateway.instance_variable_get( :@braintree_gateway ) + @internal_gateway = @gateway.instance_variable_get(:@braintree_gateway) end def teardown @@ -20,22 +21,22 @@ def teardown def test_refund_legacy_method_signature Braintree::TransactionGateway.any_instance.expects(:refund). with('transaction_id', nil). - returns(braintree_result(:id => "refund_transaction_id")) + returns(braintree_result(:id => 'refund_transaction_id')) response = @gateway.refund('transaction_id', :test => true) - assert_equal "refund_transaction_id", response.authorization + assert_equal 'refund_transaction_id', response.authorization end def test_refund_method_signature Braintree::TransactionGateway.any_instance.expects(:refund). with('transaction_id', '10.00'). - returns(braintree_result(:id => "refund_transaction_id")) + returns(braintree_result(:id => 'refund_transaction_id')) response = @gateway.refund(1000, 'transaction_id', :test => true) - assert_equal "refund_transaction_id", response.authorization + assert_equal 'refund_transaction_id', response.authorization end def test_transaction_uses_customer_id_by_default Braintree::TransactionGateway.any_instance.expects(:sale). - with(has_entries(:customer_id => "present")). + with(has_entries(:customer_id => 'present')). returns(braintree_result) assert response = @gateway.purchase(10, 'present', {}) @@ -45,7 +46,7 @@ def test_transaction_uses_customer_id_by_default def test_transaction_uses_payment_method_token_when_option Braintree::TransactionGateway.any_instance.expects(:sale). - with(has_entries(:payment_method_token => "present")). + with(has_entries(:payment_method_token => 'present')). returns(braintree_result) assert response = @gateway.purchase(10, 'present', { payment_method_token: true }) @@ -55,7 +56,7 @@ def test_transaction_uses_payment_method_token_when_option def test_transaction_uses_payment_method_nonce_when_option Braintree::TransactionGateway.any_instance.expects(:sale). - with(has_entries(:payment_method_nonce => "present")). + with(has_entries(:payment_method_nonce => 'present')). returns(braintree_result) assert response = @gateway.purchase(10, 'present', { payment_method_nonce: true }) @@ -63,13 +64,53 @@ def test_transaction_uses_payment_method_nonce_when_option assert_success response end + def test_authorize_transaction + Braintree::TransactionGateway.any_instance.expects(:sale). + returns(braintree_result) + + response = @gateway.authorize(100, credit_card('41111111111111111111')) + + assert_equal 'transaction_id', response.authorization + assert_equal true, response.test + end + + def test_purchase_transaction + Braintree::TransactionGateway.any_instance.expects(:sale). + returns(braintree_result) + + response = @gateway.purchase(100, credit_card('41111111111111111111')) + + assert_equal 'transaction_id', response.authorization + assert_equal true, response.test + end + + def test_capture_transaction + Braintree::TransactionGateway.any_instance.expects(:submit_for_settlement). + returns(braintree_result(:id => 'capture_transaction_id')) + + response = @gateway.capture(100, 'transaction_id') + + assert_equal 'capture_transaction_id', response.authorization + assert_equal true, response.test + end + + def test_refund_transaction + Braintree::TransactionGateway.any_instance.expects(:refund). + returns(braintree_result(:id => 'refund_transaction_id')) + + response = @gateway.refund(1000, 'transaction_id') + assert_equal 'refund_transaction_id', response.authorization + assert_equal true, response.test + end + def test_void_transaction Braintree::TransactionGateway.any_instance.expects(:void). with('transaction_id'). - returns(braintree_result(:id => "void_transaction_id")) + returns(braintree_result(:id => 'void_transaction_id')) - response = @gateway.void('transaction_id', :test => true) - assert_equal "void_transaction_id", response.authorization + response = @gateway.void('transaction_id') + assert_equal 'void_transaction_id', response.authorization + assert_equal true, response.test end def test_verify_good_credentials @@ -99,10 +140,10 @@ def test_merchant_account_id_present_when_provided_on_gateway_initialization ) Braintree::TransactionGateway.any_instance.expects(:sale). - with(has_entries(:merchant_account_id => "present")). + with(has_entries(:merchant_account_id => 'present')). returns(braintree_result) - @gateway.authorize(100, credit_card("41111111111111111111")) + @gateway.authorize(100, credit_card('41111111111111111111')) end def test_merchant_account_id_on_transaction_takes_precedence @@ -114,26 +155,26 @@ def test_merchant_account_id_on_transaction_takes_precedence ) Braintree::TransactionGateway.any_instance.expects(:sale). - with(has_entries(:merchant_account_id => "account_on_transaction")). + with(has_entries(:merchant_account_id => 'account_on_transaction')). returns(braintree_result) - @gateway.authorize(100, credit_card("41111111111111111111"), :merchant_account_id => "account_on_transaction") + @gateway.authorize(100, credit_card('41111111111111111111'), :merchant_account_id => 'account_on_transaction') end def test_merchant_account_id_present_when_provided Braintree::TransactionGateway.any_instance.expects(:sale). - with(has_entries(:merchant_account_id => "present")). + with(has_entries(:merchant_account_id => 'present')). returns(braintree_result) - @gateway.authorize(100, credit_card("41111111111111111111"), :merchant_account_id => "present") + @gateway.authorize(100, credit_card('41111111111111111111'), :merchant_account_id => 'present') end def test_service_fee_amount_can_be_specified Braintree::TransactionGateway.any_instance.expects(:sale). - with(has_entries(:service_fee_amount => "2.31")). + with(has_entries(:service_fee_amount => '2.31')). returns(braintree_result) - @gateway.authorize(100, credit_card("41111111111111111111"), :service_fee_amount => "2.31") + @gateway.authorize(100, credit_card('41111111111111111111'), :service_fee_amount => '2.31') end def test_hold_in_escrow_can_be_specified @@ -141,7 +182,7 @@ def test_hold_in_escrow_can_be_specified (params[:options][:hold_in_escrow] == true) end.returns(braintree_result) - @gateway.authorize(100, credit_card("41111111111111111111"), :hold_in_escrow => true) + @gateway.authorize(100, credit_card('41111111111111111111'), :hold_in_escrow => true) end def test_merchant_account_id_absent_if_not_provided @@ -149,7 +190,7 @@ def test_merchant_account_id_absent_if_not_provided not params.has_key?(:merchant_account_id) end.returns(braintree_result) - @gateway.authorize(100, credit_card("41111111111111111111")) + @gateway.authorize(100, credit_card('41111111111111111111')) end def test_verification_merchant_account_id_exists_when_verify_card_and_merchant_account_id @@ -162,6 +203,7 @@ def test_verification_merchant_account_id_exists_when_verify_card_and_merchant_a customer = stub( :credit_cards => [stub_everything], :email => 'email', + :phone => '321-654-0987', :first_name => 'John', :last_name => 'Smith' ) @@ -169,7 +211,7 @@ def test_verification_merchant_account_id_exists_when_verify_card_and_merchant_a result = Braintree::SuccessfulResult.new(:customer => customer) Braintree::CustomerGateway.any_instance.expects(:create).with do |params| - 'merchant_account_id' == params[:credit_card][:options][:verification_merchant_account_id] + params[:credit_card][:options][:verification_merchant_account_id] == 'merchant_account_id' end.returns(result) gateway.store(credit_card('41111111111111111111'), :verify_card => true) @@ -185,13 +227,14 @@ def test_merchant_account_id_can_be_set_by_options customer = stub( :credit_cards => [stub_everything], :email => 'email', + :phone => '321-654-0987', :first_name => 'John', :last_name => 'Smith' ) customer.stubs(:id).returns('123') result = Braintree::SuccessfulResult.new(:customer => customer) Braintree::CustomerGateway.any_instance.expects(:create).with do |params| - 'value_from_options' == params[:credit_card][:options][:verification_merchant_account_id] + params[:credit_card][:options][:verification_merchant_account_id] == 'value_from_options' end.returns(result) gateway.store(credit_card('41111111111111111111'), :verify_card => true, :verification_merchant_account_id => 'value_from_options') @@ -201,6 +244,7 @@ def test_store_with_verify_card_true customer = stub( :credit_cards => [stub_everything], :email => 'email', + :phone => '321-654-0987', :first_name => 'John', :last_name => 'Smith' ) @@ -209,30 +253,31 @@ def test_store_with_verify_card_true Braintree::CustomerGateway.any_instance.expects(:create).with do |params| params[:credit_card][:options].has_key?(:verify_card) assert_equal true, params[:credit_card][:options][:verify_card] - assert_equal "Longbob Longsen", params[:credit_card][:cardholder_name] + assert_equal 'Longbob Longsen', params[:credit_card][:cardholder_name] params end.returns(result) - response = @gateway.store(credit_card("41111111111111111111"), :verify_card => true) - assert_equal "123", response.params["customer_vault_id"] - assert_equal response.params["customer_vault_id"], response.authorization + response = @gateway.store(credit_card('41111111111111111111'), :verify_card => true) + assert_equal '123', response.params['customer_vault_id'] + assert_equal response.params['customer_vault_id'], response.authorization end def test_passes_email customer = stub( :credit_cards => [stub_everything], - :email => "bob@example.com", + :email => 'bob@example.com', + :phone => '321-654-0987', :first_name => 'John', :last_name => 'Smith', - id: "123" + id: '123' ) result = Braintree::SuccessfulResult.new(:customer => customer) Braintree::CustomerGateway.any_instance.expects(:create).with do |params| - assert_equal "bob@example.com", params[:email] + assert_equal 'bob@example.com', params[:email] params end.returns(result) - response = @gateway.store(credit_card("41111111111111111111"), :email => "bob@example.com") + response = @gateway.store(credit_card('41111111111111111111'), :email => 'bob@example.com') assert_success response end @@ -240,9 +285,10 @@ def test_scrubs_invalid_email customer = stub( :credit_cards => [stub_everything], :email => nil, + :phone => '321-654-0987', :first_name => 'John', :last_name => 'Smith', - :id => "123" + :id => '123' ) result = Braintree::SuccessfulResult.new(:customer => customer) Braintree::CustomerGateway.any_instance.expects(:create).with do |params| @@ -250,7 +296,7 @@ def test_scrubs_invalid_email params end.returns(result) - response = @gateway.store(credit_card("41111111111111111111"), :email => "bogus") + response = @gateway.store(credit_card('41111111111111111111'), :email => 'bogus') assert_success response end @@ -258,6 +304,7 @@ def test_store_with_verify_card_false customer = stub( :credit_cards => [stub_everything], :email => 'email', + :phone => '321-654-0987', :first_name => 'John', :last_name => 'Smith' ) @@ -269,25 +316,26 @@ def test_store_with_verify_card_false params end.returns(result) - response = @gateway.store(credit_card("41111111111111111111"), :verify_card => false) - assert_equal "123", response.params["customer_vault_id"] - assert_equal response.params["customer_vault_id"], response.authorization + response = @gateway.store(credit_card('41111111111111111111'), :verify_card => false) + assert_equal '123', response.params['customer_vault_id'] + assert_equal response.params['customer_vault_id'], response.authorization end def test_store_with_billing_address_options customer_attributes = { :credit_cards => [stub_everything], :email => 'email', + :phone => '321-654-0987', :first_name => 'John', :last_name => 'Smith' } billing_address = { - :address1 => "1 E Main St", - :address2 => "Suite 403", - :city => "Chicago", - :state => "Illinois", - :zip => "60622", - :country_name => "US" + :address1 => '1 E Main St', + :address2 => 'Suite 403', + :city => 'Chicago', + :state => 'Illinois', + :zip => '60622', + :country_name => 'US' } customer = stub(customer_attributes) customer.stubs(:id).returns('123') @@ -300,95 +348,185 @@ def test_store_with_billing_address_options params end.returns(result) - @gateway.store(credit_card("41111111111111111111"), :billing_address => billing_address) + @gateway.store(credit_card('41111111111111111111'), :billing_address => billing_address) + end + + def test_store_with_phone_only_billing_address_option + customer_attributes = { + :credit_cards => [stub_everything], + :email => 'email', + :first_name => 'John', + :last_name => 'Smith', + :phone => '123-456-7890' + } + billing_address = { + :phone => '123-456-7890' + } + customer = stub(customer_attributes) + customer.stubs(:id).returns('123') + result = Braintree::SuccessfulResult.new(:customer => customer) + Braintree::CustomerGateway.any_instance.expects(:create).with do |params| + assert_nil params[:credit_card][:billing_address] + params + end.returns(result) + + @gateway.store(credit_card('41111111111111111111'), :billing_address => billing_address) + end + + def test_store_with_nil_billing_address_options + customer_attributes = { + :credit_cards => [stub_everything], + :email => 'email', + :first_name => 'John', + :last_name => 'Smith', + :phone => '123-456-7890' + } + billing_address = { + :name => 'John Smith', + :phone => '123-456-7890', + :company => nil, + :address1 => nil, + :address2 => '', + :city => nil, + :state => nil, + :zip => nil, + :country_name => nil + } + customer = stub(customer_attributes) + customer.stubs(:id).returns('123') + result = Braintree::SuccessfulResult.new(:customer => customer) + Braintree::CustomerGateway.any_instance.expects(:create).with do |params| + assert_nil params[:credit_card][:billing_address] + params + end.returns(result) + + @gateway.store(credit_card('41111111111111111111'), :billing_address => billing_address) end def test_store_with_credit_card_token customer = stub( :email => 'email', + :phone => '321-654-0987', :first_name => 'John', :last_name => 'Smith' ) customer.stubs(:id).returns('123') - braintree_credit_card = stub_everything(token: "cctoken") + braintree_credit_card = stub_everything(token: 'cctoken') customer.stubs(:credit_cards).returns([braintree_credit_card]) result = Braintree::SuccessfulResult.new(:customer => customer) Braintree::CustomerGateway.any_instance.expects(:create).with do |params| - assert_equal "cctoken", params[:credit_card][:token] + assert_equal 'cctoken', params[:credit_card][:token] params end.returns(result) - response = @gateway.store(credit_card("41111111111111111111"), :credit_card_token => "cctoken") + response = @gateway.store(credit_card('41111111111111111111'), :credit_card_token => 'cctoken') assert_success response - assert_equal "cctoken", response.params["braintree_customer"]["credit_cards"][0]["token"] - assert_equal "cctoken", response.params["credit_card_token"] + assert_equal 'cctoken', response.params['braintree_customer']['credit_cards'][0]['token'] + assert_equal 'cctoken', response.params['credit_card_token'] end def test_store_with_customer_id customer = stub( :email => 'email', + :phone => '321-654-0987', :first_name => 'John', :last_name => 'Smith', :credit_cards => [stub_everything] ) - customer.stubs(:id).returns("customerid") + customer.stubs(:id).returns('customerid') result = Braintree::SuccessfulResult.new(:customer => customer) Braintree::CustomerGateway.any_instance.expects(:find). - with("customerid"). + with('customerid'). raises(Braintree::NotFoundError) Braintree::CustomerGateway.any_instance.expects(:create).with do |params| - assert_equal "customerid", params[:id] + assert_equal 'customerid', params[:id] params end.returns(result) - response = @gateway.store(credit_card("41111111111111111111"), :customer => "customerid") + response = @gateway.store(credit_card('41111111111111111111'), :customer => 'customerid') assert_success response - assert_equal "customerid", response.params["braintree_customer"]["id"] + assert_equal 'customerid', response.params['braintree_customer']['id'] end def test_store_with_existing_customer_id credit_card = stub( - customer_id: "customerid", - token: "cctoken" + customer_id: 'customerid', + token: 'cctoken' ) result = Braintree::SuccessfulResult.new(credit_card: credit_card) - Braintree::CustomerGateway.any_instance.expects(:find).with("customerid") + Braintree::CustomerGateway.any_instance.expects(:find).with('customerid') Braintree::CreditCardGateway.any_instance.expects(:create).with do |params| - assert_equal "customerid", params[:customer_id] - assert_equal "41111111111111111111", params[:number] - assert_equal "Longbob Longsen", params[:cardholder_name] + assert_equal 'customerid', params[:customer_id] + assert_equal '41111111111111111111', params[:number] + assert_equal 'Longbob Longsen', params[:cardholder_name] params end.returns(result) - response = @gateway.store(credit_card("41111111111111111111"), customer: "customerid") + response = @gateway.store(credit_card('41111111111111111111'), customer: 'customerid') assert_success response - assert_nil response.params["braintree_customer"] - assert_equal "customerid", response.params["customer_vault_id"] - assert_equal "cctoken", response.params["credit_card_token"] + assert_nil response.params['braintree_customer'] + assert_equal 'customerid', response.params['customer_vault_id'] + assert_equal 'cctoken', response.params['credit_card_token'] + end + + def test_store_with_existing_customer_id_and_nil_billing_address_options + credit_card = stub( + customer_id: 'customerid', + token: 'cctoken' + ) + options = { + :customer => 'customerid', + :billing_address => { + :name => 'John Smith', + :phone => '123-456-7890', + :company => nil, + :address1 => nil, + :address2 => nil, + :city => nil, + :state => nil, + :zip => nil, + :country_name => nil + } + } + + result = Braintree::SuccessfulResult.new(credit_card: credit_card) + Braintree::CustomerGateway.any_instance.expects(:find).with('customerid') + Braintree::CreditCardGateway.any_instance.expects(:create).with do |params| + assert_equal 'customerid', params[:customer_id] + assert_equal '41111111111111111111', params[:number] + assert_equal 'Longbob Longsen', params[:cardholder_name] + params + end.returns(result) + + response = @gateway.store(credit_card('41111111111111111111'), options) + assert_success response + assert_nil response.params['braintree_customer'] + assert_equal 'customerid', response.params['customer_vault_id'] + assert_equal 'cctoken', response.params['credit_card_token'] end def test_update_with_cvv - stored_credit_card = mock(:token => "token", :default? => true) + stored_credit_card = mock(:token => 'token', :default? => true) customer = mock(:credit_cards => [stored_credit_card], :id => '123') Braintree::CustomerGateway.any_instance.stubs(:find).with('vault_id').returns(customer) BraintreeBlueGateway.any_instance.stubs(:customer_hash) result = Braintree::SuccessfulResult.new(:customer => customer) Braintree::CustomerGateway.any_instance.expects(:update).with do |vault, params| - assert_equal "567", params[:credit_card][:cvv] - assert_equal "Longbob Longsen", params[:credit_card][:cardholder_name] + assert_equal '567', params[:credit_card][:cvv] + assert_equal 'Longbob Longsen', params[:credit_card][:cardholder_name] [vault, params] end.returns(result) - @gateway.update('vault_id', credit_card("41111111111111111111", :verification_value => "567")) + @gateway.update('vault_id', credit_card('41111111111111111111', :verification_value => '567')) end def test_update_with_verify_card_true - stored_credit_card = stub(:token => "token", :default? => true) + stored_credit_card = stub(:token => 'token', :default? => true) customer = stub(:credit_cards => [stored_credit_card], :id => '123') Braintree::CustomerGateway.any_instance.stubs(:find).with('vault_id').returns(customer) BraintreeBlueGateway.any_instance.stubs(:customer_hash) @@ -399,7 +537,7 @@ def test_update_with_verify_card_true [vault, params] end.returns(result) - @gateway.update('vault_id', credit_card("41111111111111111111"), :verify_card => true) + @gateway.update('vault_id', credit_card('41111111111111111111'), :verify_card => true) end def test_merge_credit_card_options_ignores_bad_option @@ -420,11 +558,11 @@ def test_merge_credit_card_options_handles_nil_credit_card def test_merge_credit_card_options_handles_billing_address billing_address = { - :address1 => "1 E Main St", - :city => "Chicago", - :state => "Illinois", - :zip => "60622", - :country => "US" + :address1 => '1 E Main St', + :city => 'Chicago', + :state => 'Illinois', + :zip => '60622', + :country => 'US' } params = {:first_name => 'John'} options = {:billing_address => billing_address} @@ -432,13 +570,13 @@ def test_merge_credit_card_options_handles_billing_address :first_name => 'John', :credit_card => { :billing_address => { - :street_address => "1 E Main St", + :street_address => '1 E Main St', :extended_address => nil, :company => nil, - :locality => "Chicago", - :region => "Illinois", - :postal_code => "60622", - :country_code_alpha2 => "US" + :locality => 'Chicago', + :region => 'Illinois', + :postal_code => '60622', + :country_code_alpha2 => 'US' }, :options => {} } @@ -460,48 +598,62 @@ def test_merge_credit_card_options_only_includes_billing_address_when_present def test_address_country_handling Braintree::TransactionGateway.any_instance.expects(:sale).with do |params| - (params[:billing][:country_code_alpha2] == "US") + (params[:billing][:country_code_alpha2] == 'US') end.returns(braintree_result) - @gateway.purchase(100, credit_card("41111111111111111111"), :billing_address => {:country => "US"}) + @gateway.purchase(100, credit_card('41111111111111111111'), :billing_address => {:country => 'US'}) Braintree::TransactionGateway.any_instance.expects(:sale).with do |params| - (params[:billing][:country_code_alpha2] == "US") + (params[:billing][:country_code_alpha2] == 'US') end.returns(braintree_result) - @gateway.purchase(100, credit_card("41111111111111111111"), :billing_address => {:country_code_alpha2 => "US"}) + @gateway.purchase(100, credit_card('41111111111111111111'), :billing_address => {:country_code_alpha2 => 'US'}) Braintree::TransactionGateway.any_instance.expects(:sale).with do |params| - (params[:billing][:country_name] == "United States of America") + (params[:billing][:country_name] == 'United States of America') end.returns(braintree_result) - @gateway.purchase(100, credit_card("41111111111111111111"), :billing_address => {:country_name => "United States of America"}) + @gateway.purchase(100, credit_card('41111111111111111111'), :billing_address => {:country_name => 'United States of America'}) Braintree::TransactionGateway.any_instance.expects(:sale).with do |params| - (params[:billing][:country_code_alpha3] == "USA") + (params[:billing][:country_code_alpha3] == 'USA') end.returns(braintree_result) - @gateway.purchase(100, credit_card("41111111111111111111"), :billing_address => {:country_code_alpha3 => "USA"}) + @gateway.purchase(100, credit_card('41111111111111111111'), :billing_address => {:country_code_alpha3 => 'USA'}) Braintree::TransactionGateway.any_instance.expects(:sale).with do |params| (params[:billing][:country_code_numeric] == 840) end.returns(braintree_result) - @gateway.purchase(100, credit_card("41111111111111111111"), :billing_address => {:country_code_numeric => 840}) + @gateway.purchase(100, credit_card('41111111111111111111'), :billing_address => {:country_code_numeric => 840}) end def test_address_zip_handling Braintree::TransactionGateway.any_instance.expects(:sale).with do |params| - (params[:billing][:postal_code] == "12345") + (params[:billing][:postal_code] == '12345') end.returns(braintree_result) - @gateway.purchase(100, credit_card("41111111111111111111"), :billing_address => {:zip => "12345"}) + @gateway.purchase(100, credit_card('41111111111111111111'), :billing_address => {:zip => '12345'}) Braintree::TransactionGateway.any_instance.expects(:sale).with do |params| (params[:billing][:postal_code] == nil) end.returns(braintree_result) - @gateway.purchase(100, credit_card("41111111111111111111"), :billing_address => {:zip => "1234567890"}) + @gateway.purchase(100, credit_card('41111111111111111111'), :billing_address => {:zip => '1234567890'}) end def test_cardholder_name_passing_with_card Braintree::TransactionGateway.any_instance.expects(:sale).with do |params| - (params[:credit_card][:cardholder_name] == "Longbob Longsen") + (params[:credit_card][:cardholder_name] == 'Longbob Longsen') end.returns(braintree_result) - @gateway.purchase(100, credit_card("41111111111111111111"), :customer => {:first_name => "Longbob", :last_name => "Longsen"}) + @gateway.purchase(100, credit_card('41111111111111111111'), :customer => {:first_name => 'Longbob', :last_name => 'Longsen'}) + end + + def test_three_d_secure_pass_thru_handling + Braintree::TransactionGateway. + any_instance. + expects(:sale). + with(has_entries(three_d_secure_pass_thru: { + cavv: 'cavv', + eci_flag: 'eci', + xid: 'xid', + })). + returns(braintree_result) + + @gateway.purchase(100, credit_card('41111111111111111111'), three_d_secure: {cavv: 'cavv', eci: 'eci', xid: 'xid'}) end def test_passes_recurring_flag @@ -516,13 +668,13 @@ def test_passes_recurring_flag with(has_entries(:recurring => true)). returns(braintree_result) - @gateway.purchase(100, credit_card("41111111111111111111"), :recurring => true) + @gateway.purchase(100, credit_card('41111111111111111111'), :recurring => true) Braintree::TransactionGateway.any_instance.expects(:sale). with(Not(has_entries(:recurring => true))). returns(braintree_result) - @gateway.purchase(100, credit_card("41111111111111111111")) + @gateway.purchase(100, credit_card('41111111111111111111')) end def test_configured_logger_has_a_default @@ -574,12 +726,12 @@ def test_that_setting_a_wiredump_device_on_the_gateway_sets_the_braintree_logger end def test_solution_id_is_added_to_create_transaction_parameters - assert_nil @gateway.send(:create_transaction_parameters, 100, credit_card("41111111111111111111"),{})[:channel] + assert_nil @gateway.send(:create_transaction_parameters, 100, credit_card('41111111111111111111'), {})[:channel] ActiveMerchant::Billing::BraintreeBlueGateway.application_id = 'ABC123' - assert_equal @gateway.send(:create_transaction_parameters, 100, credit_card("41111111111111111111"),{})[:channel], "ABC123" + assert_equal @gateway.send(:create_transaction_parameters, 100, credit_card('41111111111111111111'), {})[:channel], 'ABC123' - gateway = BraintreeBlueGateway.new(:merchant_id => 'test', :public_key => 'test', :private_key => 'test', channel: "overidden-channel") - assert_equal gateway.send(:create_transaction_parameters, 100, credit_card("41111111111111111111"),{})[:channel], "overidden-channel" + gateway = BraintreeBlueGateway.new(:merchant_id => 'test', :public_key => 'test', :private_key => 'test', channel: 'overidden-channel') + assert_equal gateway.send(:create_transaction_parameters, 100, credit_card('41111111111111111111'), {})[:channel], 'overidden-channel' ensure ActiveMerchant::Billing::BraintreeBlueGateway.application_id = nil end @@ -590,7 +742,7 @@ def test_successful_purchase_with_descriptor (params[:descriptor][:phone] == '4443331112') && (params[:descriptor][:url] == 'wow.com') end.returns(braintree_result) - @gateway.purchase(100, credit_card("41111111111111111111"), descriptor_name: 'wow*productname', descriptor_phone: '4443331112', descriptor_url: 'wow.com') + @gateway.purchase(100, credit_card('41111111111111111111'), descriptor_name: 'wow*productname', descriptor_phone: '4443331112', descriptor_url: 'wow.com') end def test_apple_pay_card @@ -598,7 +750,8 @@ def test_apple_pay_card with( :amount => '1.00', :order_id => '1', - :customer => {:id => nil, :email => nil, :first_name => 'Longbob', :last_name => 'Longsen'}, + :customer => {:id => nil, :email => nil, :phone => nil, + :first_name => 'Longbob', :last_name => 'Longsen'}, :options => {:store_in_vault => false, :submit_for_settlement => nil, :hold_in_escrow => nil}, :custom_fields => nil, :apple_pay_card => { @@ -606,20 +759,21 @@ def test_apple_pay_card :expiration_month => '09', :expiration_year => (Time.now.year + 1).to_s, :cardholder_name => 'Longbob Longsen', - :cryptogram => '111111111100cryptogram' + :cryptogram => '111111111100cryptogram', + :eci_indicator => '05' } ). - returns(braintree_result(:id => "transaction_id")) + returns(braintree_result(:id => 'transaction_id')) credit_card = network_tokenization_credit_card('4111111111111111', :brand => 'visa', - :transaction_id => "123", - :eci => "05", - :payment_cryptogram => "111111111100cryptogram" + :transaction_id => '123', + :eci => '05', + :payment_cryptogram => '111111111100cryptogram' ) response = @gateway.authorize(100, credit_card, :test => true, :order_id => '1') - assert_equal "transaction_id", response.authorization + assert_equal 'transaction_id', response.authorization end def test_android_pay_card @@ -627,7 +781,8 @@ def test_android_pay_card with( :amount => '1.00', :order_id => '1', - :customer => {:id => nil, :email => nil, :first_name => 'Longbob', :last_name => 'Longsen'}, + :customer => {:id => nil, :email => nil, :phone => nil, + :first_name => 'Longbob', :last_name => 'Longsen'}, :options => {:store_in_vault => false, :submit_for_settlement => nil, :hold_in_escrow => nil}, :custom_fields => nil, :android_pay_card => { @@ -635,22 +790,58 @@ def test_android_pay_card :expiration_month => '09', :expiration_year => (Time.now.year + 1).to_s, :cryptogram => '111111111100cryptogram', - :google_transaction_id => '1234567890' + :google_transaction_id => '1234567890', + :source_card_type => 'visa', + :source_card_last_four => '1111', + :eci_indicator => '05' } ). - returns(braintree_result(:id => "transaction_id")) + returns(braintree_result(:id => 'transaction_id')) credit_card = network_tokenization_credit_card('4111111111111111', :brand => 'visa', - :transaction_id => "123", - :eci => "05", - :payment_cryptogram => "111111111100cryptogram", + :eci => '05', + :payment_cryptogram => '111111111100cryptogram', :source => :android_pay, :transaction_id => '1234567890' ) response = @gateway.authorize(100, credit_card, :test => true, :order_id => '1') - assert_equal "transaction_id", response.authorization + assert_equal 'transaction_id', response.authorization + end + + def test_google_pay_card + Braintree::TransactionGateway.any_instance.expects(:sale). + with( + :amount => '1.00', + :order_id => '1', + :customer => {:id => nil, :email => nil, :phone => nil, + :first_name => 'Longbob', :last_name => 'Longsen'}, + :options => {:store_in_vault => false, :submit_for_settlement => nil, :hold_in_escrow => nil}, + :custom_fields => nil, + :android_pay_card => { + :number => '4111111111111111', + :expiration_month => '09', + :expiration_year => (Time.now.year + 1).to_s, + :cryptogram => '111111111100cryptogram', + :google_transaction_id => '1234567890', + :source_card_type => 'visa', + :source_card_last_four => '1111', + :eci_indicator => '05' + } + ). + returns(braintree_result(:id => 'transaction_id')) + + credit_card = network_tokenization_credit_card('4111111111111111', + :brand => 'visa', + :eci => '05', + :payment_cryptogram => '111111111100cryptogram', + :source => :google_pay, + :transaction_id => '1234567890' + ) + + response = @gateway.authorize(100, credit_card, :test => true, :order_id => '1') + assert_equal 'transaction_id', response.authorization end def test_supports_network_tokenization @@ -659,7 +850,7 @@ def test_supports_network_tokenization def test_unsuccessful_transaction_returns_id_when_available Braintree::TransactionGateway.any_instance.expects(:sale).returns(braintree_error_result(transaction: {id: 'transaction_id'})) - assert response = @gateway.purchase(100, credit_card("41111111111111111111")) + assert response = @gateway.purchase(100, credit_card('41111111111111111111')) refute response.success? assert response.authorization.present? end @@ -668,15 +859,41 @@ def test_unsuccessful_transaction_returns_message_when_available Braintree::TransactionGateway.any_instance. expects(:sale). returns(braintree_error_result(message: 'Some error message')) - assert response = @gateway.purchase(100, credit_card("41111111111111111111")) + assert response = @gateway.purchase(100, credit_card('41111111111111111111')) refute response.success? assert_equal response.message, 'Some error message' end + def test_refund_unsettled_payment + Braintree::TransactionGateway.any_instance. + expects(:refund). + returns(braintree_error_result(message: 'Cannot refund a transaction unless it is settled. (91506)')) + + Braintree::TransactionGateway.any_instance. + expects(:void). + never + + response = @gateway.refund(1.00, 'transaction_id') + refute response.success? + end + + def test_refund_unsettled_payment_forces_void_on_full_refund + Braintree::TransactionGateway.any_instance. + expects(:refund). + returns(braintree_error_result(message: 'Cannot refund a transaction unless it is settled. (91506)')) + + Braintree::TransactionGateway.any_instance. + expects(:void). + returns(braintree_result) + + response = @gateway.refund(1.00, 'transaction_id', force_full_refund_if_unsettled: true) + assert response.success? + end + private def braintree_result(options = {}) - Braintree::SuccessfulResult.new(:transaction => Braintree::Transaction._new(nil, {:id => "transaction_id"}.merge(options))) + Braintree::SuccessfulResult.new(:transaction => Braintree::Transaction._new(nil, {:id => 'transaction_id'}.merge(options))) end def braintree_error_result(options = {}) diff --git a/test/unit/gateways/braintree_orange_test.rb b/test/unit/gateways/braintree_orange_test.rb index 6607ad45d0a..ee4149137bb 100644 --- a/test/unit/gateways/braintree_orange_test.rb +++ b/test/unit/gateways/braintree_orange_test.rb @@ -24,21 +24,31 @@ def test_successful_purchase assert_equal '510695343', response.authorization end + def test_fractional_amounts + response = stub_comms do + @gateway.purchase(100, @credit_card, @options.merge(currency: 'JPY')) + end.check_request do |endpoint, data, headers| + refute_match(/amount=1.00/, data) + end.respond_with(successful_purchase_response) + + assert_success response + end + def test_successful_store @gateway.expects(:ssl_post).returns(successful_store_response) assert response = @gateway.store(@credit_card, @options) assert_instance_of Response, response assert_success response - assert_equal "853162645", response.authorization - assert_equal response.authorization, response.params["customer_vault_id"] + assert_equal '853162645', response.authorization + assert_equal response.authorization, response.params['customer_vault_id'] end def test_add_processor result = {} - @gateway.send(:add_processor, result, {:processor => 'ccprocessorb'} ) - assert_equal ["processor_id"], result.stringify_keys.keys.sort + @gateway.send(:add_processor, result, {:processor => 'ccprocessorb'}) + assert_equal ['processor_id'], result.stringify_keys.keys.sort assert_equal 'ccprocessorb', result[:processor_id] end @@ -76,36 +86,36 @@ def test_unsuccessful_verify def test_add_address result = {} - @gateway.send(:add_address, result, {:address1 => '164 Waverley Street', :country => 'US', :state => 'CO'} ) - assert_equal ["address1", "city", "company", "country", "phone", "state", "zip"], result.stringify_keys.keys.sort - assert_equal 'CO', result["state"] - assert_equal '164 Waverley Street', result["address1"] - assert_equal 'US', result["country"] + @gateway.send(:add_address, result, {:address1 => '164 Waverley Street', :country => 'US', :state => 'CO'}) + assert_equal ['address1', 'city', 'company', 'country', 'phone', 'state', 'zip'], result.stringify_keys.keys.sort + assert_equal 'CO', result['state'] + assert_equal '164 Waverley Street', result['address1'] + assert_equal 'US', result['country'] end def test_add_shipping_address result = {} - @gateway.send(:add_address, result, {:address1 => '164 Waverley Street', :country => 'US', :state => 'CO'},"shipping" ) - assert_equal ["shipping_address1", "shipping_city", "shipping_company", "shipping_country", "shipping_phone", "shipping_state", "shipping_zip"], result.stringify_keys.keys.sort - assert_equal 'CO', result["shipping_state"] - assert_equal '164 Waverley Street', result["shipping_address1"] - assert_equal 'US', result["shipping_country"] + @gateway.send(:add_address, result, {:address1 => '164 Waverley Street', :country => 'US', :state => 'CO'}, 'shipping') + assert_equal ['shipping_address1', 'shipping_city', 'shipping_company', 'shipping_country', 'shipping_phone', 'shipping_state', 'shipping_zip'], result.stringify_keys.keys.sort + assert_equal 'CO', result['shipping_state'] + assert_equal '164 Waverley Street', result['shipping_address1'] + assert_equal 'US', result['shipping_country'] end def test_adding_store_adds_vault_id_flag result = {} @gateway.send(:add_creditcard, result, @credit_card, :store => true) - assert_equal ["ccexp", "ccnumber", "customer_vault", "cvv", "firstname", "lastname"], result.stringify_keys.keys.sort + assert_equal ['ccexp', 'ccnumber', 'customer_vault', 'cvv', 'firstname', 'lastname'], result.stringify_keys.keys.sort assert_equal 'add_customer', result[:customer_vault] end def test_blank_store_doesnt_add_vault_flag result = {} - @gateway.send(:add_creditcard, result, @credit_card, {} ) - assert_equal ["ccexp", "ccnumber", "cvv", "firstname", "lastname"], result.stringify_keys.keys.sort + @gateway.send(:add_creditcard, result, @credit_card, {}) + assert_equal ['ccexp', 'ccnumber', 'cvv', 'firstname', 'lastname'], result.stringify_keys.keys.sort assert_nil result[:customer_vault] end @@ -179,14 +189,14 @@ def failed_void_response end def successful_store_response - "response=1&responsetext=Customer Added&authcode=&transactionid=&avsresponse=&cvvresponse=&orderid=&type=&response_code=100&merchant_defined_field_6=&merchant_defined_field_7=&customer_vault_id=853162645" + 'response=1&responsetext=Customer Added&authcode=&transactionid=&avsresponse=&cvvresponse=&orderid=&type=&response_code=100&merchant_defined_field_6=&merchant_defined_field_7=&customer_vault_id=853162645' end def transcript - "username=demo&password=password&type=sale&orderid=8267b7f890aac7699f6ebc93c7c94d96&ccnumber=4111111111111111&cvv=123&ccexp=0916&firstname=Longbob&lastname=Longsen&address1=456+My+Street&address2=Apt+1&company=Widgets+Inc&phone=%28555%29555-5555&zip=K1C2N6&city=Ottawa&country=CA&state=ON&currency=USD&tax=&amount=77.70" + 'username=demo&password=password&type=sale&orderid=8267b7f890aac7699f6ebc93c7c94d96&ccnumber=4111111111111111&cvv=123&ccexp=0916&firstname=Longbob&lastname=Longsen&address1=456+My+Street&address2=Apt+1&company=Widgets+Inc&phone=%28555%29555-5555&zip=K1C2N6&city=Ottawa&country=CA&state=ON&currency=USD&tax=&amount=77.70' end def scrubbed_transcript - "username=demo&password=password&type=sale&orderid=8267b7f890aac7699f6ebc93c7c94d96&ccnumber=[FILTERED]&cvv=[FILTERED]&ccexp=0916&firstname=Longbob&lastname=Longsen&address1=456+My+Street&address2=Apt+1&company=Widgets+Inc&phone=%28555%29555-5555&zip=K1C2N6&city=Ottawa&country=CA&state=ON&currency=USD&tax=&amount=77.70" + 'username=demo&password=password&type=sale&orderid=8267b7f890aac7699f6ebc93c7c94d96&ccnumber=[FILTERED]&cvv=[FILTERED]&ccexp=0916&firstname=Longbob&lastname=Longsen&address1=456+My+Street&address2=Apt+1&company=Widgets+Inc&phone=%28555%29555-5555&zip=K1C2N6&city=Ottawa&country=CA&state=ON&currency=USD&tax=&amount=77.70' end end diff --git a/test/unit/gateways/braintree_test.rb b/test/unit/gateways/braintree_test.rb index ba1b24e76a2..7cff9f6512f 100644 --- a/test/unit/gateways/braintree_test.rb +++ b/test/unit/gateways/braintree_test.rb @@ -20,18 +20,18 @@ def test_new_with_merchant_id_creates_braintree_blue end def test_should_have_display_name_of_just_braintree - assert_equal "Braintree", BraintreeGateway.display_name + assert_equal 'Braintree', BraintreeGateway.display_name end def test_should_have_homepage_url - assert_equal "http://www.braintreepaymentsolutions.com", BraintreeGateway.homepage_url + assert_equal 'http://www.braintreepaymentsolutions.com', BraintreeGateway.homepage_url end def test_should_have_supported_credit_card_types - assert_equal [:visa, :master, :american_express, :discover, :jcb, :diners_club], BraintreeGateway.supported_cardtypes + assert_equal [:visa, :master, :american_express, :discover, :jcb, :diners_club, :maestro], BraintreeGateway.supported_cardtypes end def test_should_have_default_currency - assert_equal "USD", BraintreeGateway.default_currency + assert_equal 'USD', BraintreeGateway.default_currency end end diff --git a/test/unit/gateways/bridge_pay_test.rb b/test/unit/gateways/bridge_pay_test.rb index 85b9579b9fd..ce60e3e05f9 100644 --- a/test/unit/gateways/bridge_pay_test.rb +++ b/test/unit/gateways/bridge_pay_test.rb @@ -45,13 +45,21 @@ def test_successful_purchase_with_echeck assert response.test? end + def test_failed_purchase_with_bad_echeck + @gateway.expects(:ssl_post).returns(failed_purchase_response) + + @check.account_type = nil + response = @gateway.purchase(@amount, @check) + assert_failure response + end + def test_authorize_and_capture response = stub_comms do @gateway.authorize(@amount, @credit_card) end.respond_with(successful_authorize_response) assert_success response - assert_equal "OK2657|838662", response.authorization + assert_equal 'OK2657|838662', response.authorization capture = stub_comms do @gateway.capture(@amount, response.authorization) @@ -68,7 +76,7 @@ def test_refund end.respond_with(successful_purchase_response) assert_success response - assert_equal "OK9757|837495", response.authorization + assert_equal 'OK9757|837495', response.authorization refund = stub_comms do @gateway.refund(@amount, response.authorization) @@ -85,7 +93,7 @@ def test_void end.respond_with(successful_purchase_response) assert_success response - assert_equal "OK9757|837495", response.authorization + assert_equal 'OK9757|837495', response.authorization refund = stub_comms do @gateway.void(response.authorization) @@ -102,14 +110,14 @@ def test_store_and_purchase_with_token end.respond_with(successful_store_response) assert_success store - assert_equal "Success", store.message + assert_equal 'Success', store.message purchase = stub_comms do @gateway.purchase(@amount, store.authorization) end.respond_with(successful_purchase_response) assert_success purchase - assert_equal "Approved", purchase.message + assert_equal 'Approved', purchase.message end def test_passing_cvv @@ -134,7 +142,7 @@ def test_successful_verify @gateway.verify(@credit_card, @options) end.respond_with(successful_authorize_response, successful_void_response) assert_success response - assert_equal "OK2657", response.params["authcode"] + assert_equal 'OK2657', response.params['authcode'] end def test_successful_verify_with_failed_void @@ -142,7 +150,7 @@ def test_successful_verify_with_failed_void @gateway.verify(@credit_card, @options) end.respond_with(successful_authorize_response, failed_void_response) assert_success response - assert_equal "Approved", response.message + assert_equal 'Approved', response.message end def test_unsuccessful_verify @@ -150,7 +158,7 @@ def test_unsuccessful_verify @gateway.verify(@credit_card, @options) end.respond_with(failed_authorize_response, successful_void_response) assert_failure response - assert_equal "Invalid Account Number", response.message + assert_equal 'Invalid Account Number', response.message end def test_scrub diff --git a/test/unit/gateways/cams_test.rb b/test/unit/gateways/cams_test.rb index d9edc5e56bb..23102e41c39 100644 --- a/test/unit/gateways/cams_test.rb +++ b/test/unit/gateways/cams_test.rb @@ -50,7 +50,7 @@ def test_failed_authorize end def test_successful_capture - authorization = "12345678#54321" + authorization = '12345678#54321' @gateway.expects(:ssl_post).returns(successful_capture_response) assert capture = @gateway.capture(@amount, authorization) @@ -65,7 +65,7 @@ def test_failed_capture end def test_successful_refund - authorization = "12345678#54321" + authorization = '12345678#54321' @gateway.expects(:ssl_post).returns(successful_refund_response) assert refund = @gateway.refund(nil, authorization) @@ -80,7 +80,7 @@ def test_failed_refund end def test_successful_void - authorization = "12345678#54321" + authorization = '12345678#54321' @gateway.expects(:ssl_post).returns(successful_void_response) assert void = @gateway.void(authorization) diff --git a/test/unit/gateways/card_connect_test.rb b/test/unit/gateways/card_connect_test.rb new file mode 100644 index 00000000000..e4a49a1541b --- /dev/null +++ b/test/unit/gateways/card_connect_test.rb @@ -0,0 +1,324 @@ +require 'test_helper' + +class CardConnectTest < Test::Unit::TestCase + include CommStub + def setup + @gateway = CardConnectGateway.new(username: 'username', password: 'password', merchant_id: 'merchand_id') + @credit_card = credit_card('4788250000121443') + @declined_card = credit_card('4387751111111053') + @amount = 100 + @check = check(routing_number: '053000196') + + @options = { + order_id: '1', + billing_address: address, + description: 'Store Purchase' + } + end + + def test_incorrect_domain + assert_raise(ArgumentError) { + CardConnectGateway.new(username: 'username', password: 'password', merchant_id: 'merchand_id', domain: 'www.google.com') + } + end + + def test_successful_purchase + @gateway.expects(:ssl_request).returns(successful_purchase_response) + + response = @gateway.purchase(@amount, @credit_card, @options) + assert_success response + + assert_equal '363652261392', response.authorization + assert response.test? + end + + def test_successful_purchase_with_echeck + @gateway.expects(:ssl_request).returns(successful_echeck_purchase_response) + + response = @gateway.purchase(@amount, @check, @options) + assert_success response + + assert_equal '010136262668', response.authorization + assert response.test? + end + + def test_failed_purchase + @gateway.expects(:ssl_request).returns(failed_purchase_response) + + response = @gateway.purchase(@amount, @declined_card, @options) + assert_failure response + assert_equal Gateway::STANDARD_ERROR_CODE[:card_declined], response.error_code + end + + def test_failed_purchase_with_echeck + @gateway.expects(:ssl_request).returns(failed_echeck_purchase_response) + + response = @gateway.purchase(@amount, check(routing_number: '23433'), @options) + assert_failure response + assert_equal Gateway::STANDARD_ERROR_CODE[:card_declined], response.error_code + end + + def test_successful_authorize + @gateway.expects(:ssl_request).returns(successful_authorize_response) + + response = @gateway.authorize(@amount, @credit_card, @options) + assert_success response + + assert_equal '363168161558', response.authorization + assert response.test? + end + + def test_failed_authorize + @gateway.expects(:ssl_request).returns(failed_authorize_response) + + response = @gateway.authorize(@amount, @declined_card, @options) + assert_failure response + assert_equal Gateway::STANDARD_ERROR_CODE[:card_declined], response.error_code + end + + def test_successful_capture + @gateway.expects(:ssl_request).returns(successful_capture_response) + + response = @gateway.capture(@amount, '363168161558', @options) + assert_success response + + assert_equal '363168161558', response.authorization + assert response.test? + end + + def test_failed_capture + @gateway.expects(:ssl_request).returns(failed_capture_response) + + response = @gateway.capture(@amount, '23221', @options) + assert_failure response + + assert_equal '23221', response.authorization + assert response.test? + + assert_equal Gateway::STANDARD_ERROR_CODE[:processing_error], response.error_code + end + + def test_successful_refund + @gateway.expects(:ssl_request).returns(successful_refund_response) + + response = @gateway.refund(@amount, '36366126178', @options) + assert_success response + + assert_equal '363661261786', response.authorization + assert response.test? + end + + def test_failed_refund + @gateway.expects(:ssl_request).returns(failed_refund_response) + + response = @gateway.refund(@amount, '23221', @options) + assert_failure response + + assert_equal '23221', response.authorization + assert response.test? + + assert_equal Gateway::STANDARD_ERROR_CODE[:processing_error], response.error_code + end + + def test_successful_void + @gateway.expects(:ssl_request).returns(successful_void_response) + + response = @gateway.void('363750268295') + assert_success response + + assert_equal '363664261982', response.authorization + assert response.test? + end + + def test_failed_void + @gateway.expects(:ssl_request).returns(failed_void_response) + + response = @gateway.void('23221') + assert_failure response + + assert response.test? + + assert_equal Gateway::STANDARD_ERROR_CODE[:processing_error], response.error_code + end + + def test_successful_verify + @gateway.expects(:ssl_request).returns(successful_verify_response) + + response = @gateway.verify(@credit_card, @options) + assert_success response + + assert_equal '363272166977', response.authorization + assert response.test? + end + + def test_successful_verify_with_failed_void + response = stub_comms(@gateway, :ssl_request) do + @gateway.verify(@credit_card, @options) + end.respond_with(successful_authorize_response, failed_void_response) + assert_success response + end + + def test_failed_verify + @gateway.expects(:ssl_request).returns(failed_verify_response) + + response = @gateway.verify(@declined_card, @options) + assert_failure response + assert_equal 'Insufficient funds', response.message + end + + def test_successful_store + @gateway.expects(:ssl_request).returns(successful_store_response) + response = @gateway.store(@credit_card, @options) + + assert_success response + assert_equal 'Profile Saved', response.message + assert_equal '1|16700875781344019340', response.authorization + end + + def test_failed_store + @gateway.expects(:ssl_request).returns(failed_store_response) + response = @gateway.store(@credit_card, @options) + + assert_failure response + end + + def test_successful_unstore + stub_comms(@gateway, :ssl_request) do + @gateway.unstore('1|16700875781344019340') + end.check_request do |verb, url, data, headers| + assert_equal :delete, verb + assert_match %r{16700875781344019340/1}, url + end.respond_with(successful_unstore_response) + end + + def test_failed_unstore + end + + def test_scrub + assert @gateway.supports_scrubbing? + assert_equal @gateway.scrub(pre_scrubbed), post_scrubbed + end + + private + + def pre_scrubbed + %q( + opening connection to fts.cardconnect.com:6443... + opened + starting SSL for fts.cardconnect.com:6443... + SSL established + <- "PUT /cardconnect/rest/auth HTTP/1.1\r\nAuthorization: Basic dGVzdGluZzp0ZXN0aW5nMTIz\r\nContent-Type: application/json\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nAccept: */*\r\nUser-Agent: Ruby\r\nConnection: close\r\nHost: fts.cardconnect.com:6443\r\nContent-Length: 298\r\n\r\n" + <- "{\"orderid\":null,\"ecomind\":\"E\",\"amount\":\"1.00\",\"name\":\"Longbob Longsen\",\"account\":\"4000100011112224\",\"expiry\":\"0918\",\"cvv2\":\"123\",\"currency\":\"USD\",\"address\":\"456 My Street\",\"city\":\"Ottawa\",\"region\":\"ON\",\"country\":\"CA\",\"postal\":\"K1C2N6\",\"phone\":\"(555)555-5555\",\"capture\":\"Y\",\"merchid\":\"496160873888\"}" + -> "HTTP/1.1 200 OK\r\n" + -> "X-FRAME-OPTIONS: DENY\r\n" + -> "Content-Type: application/json\r\n" + -> "Content-Length: 281\r\n" + -> "Date: Fri, 29 Dec 2017 23:51:22 GMT\r\n" + -> "Server: CardConnect\r\n" + -> "Connection: close\r\n" + -> "Set-Cookie: BIGipServerphu-smb-vip_8080=!3EyEfCvmvK/UDgCOaMq7McVUJtfXHaj0/1BWyxbacLNntp1E0Upt2onAMTKRSSu6r6mZaKuZm7N9ais=; path=/; Httponly; Secure\r\n" + -> "\r\n" + reading 281 bytes... + -> "{\"amount\":\"1.00\",\"resptext\":\"Approval\",\"commcard\":\" C \",\"cvvresp\":\"M\",\"batchid\":\"1900941444\",\"avsresp\":\" \",\"respcode\":\"00\",\"merchid\":\"496160873888\",\"token\":\"9405701444882224\",\"authcode\":\"PPS568\",\"respproc\":\"FNOR\",\"retref\":\"363743267882\",\"respstat\":\"A\",\"account\":\"9405701444882224\"}" + read 281 bytes + Conn close + ) + end + + def post_scrubbed + %q( + opening connection to fts.cardconnect.com:6443... + opened + starting SSL for fts.cardconnect.com:6443... + SSL established + <- "PUT /cardconnect/rest/auth HTTP/1.1\r\nAuthorization: Basic [FILTERED]\r\nContent-Type: application/json\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nAccept: */*\r\nUser-Agent: Ruby\r\nConnection: close\r\nHost: fts.cardconnect.com:6443\r\nContent-Length: 298\r\n\r\n" + <- "{\"orderid\":null,\"ecomind\":\"E\",\"amount\":\"1.00\",\"name\":\"Longbob Longsen\",\"account\":\"[FILTERED]\",\"expiry\":\"0918\",\"cvv2\":\"[FILTERED]\",\"currency\":\"USD\",\"address\":\"456 My Street\",\"city\":\"Ottawa\",\"region\":\"ON\",\"country\":\"CA\",\"postal\":\"K1C2N6\",\"phone\":\"(555)555-5555\",\"capture\":\"Y\",\"merchid\":\"[FILTERED]\"}" + -> "HTTP/1.1 200 OK\r\n" + -> "X-FRAME-OPTIONS: DENY\r\n" + -> "Content-Type: application/json\r\n" + -> "Content-Length: 281\r\n" + -> "Date: Fri, 29 Dec 2017 23:51:22 GMT\r\n" + -> "Server: CardConnect\r\n" + -> "Connection: close\r\n" + -> "Set-Cookie: BIGipServerphu-smb-vip_8080=!3EyEfCvmvK/UDgCOaMq7McVUJtfXHaj0/1BWyxbacLNntp1E0Upt2onAMTKRSSu6r6mZaKuZm7N9ais=; path=/; Httponly; Secure\r\n" + -> "\r\n" + reading 281 bytes... + -> "{\"amount\":\"1.00\",\"resptext\":\"Approval\",\"commcard\":\" C \",\"cvvresp\":\"M\",\"batchid\":\"1900941444\",\"avsresp\":\" \",\"respcode\":\"00\",\"merchid\":\"[FILTERED]\",\"token\":\"[FILTERED]\",\"authcode\":\"PPS568\",\"respproc\":\"FNOR\",\"retref\":\"363743267882\",\"respstat\":\"A\",\"account\":\"[FILTERED]\"}" + read 281 bytes + Conn close + ) + end + + def successful_purchase_response + '{"amount":"1.00","resptext":"Approval","commcard":" C ","cvvresp":"M","batchid":"1900941444","avsresp":" ","respcode":"00","merchid":"496160873888","token":"9405701444882224","authcode":"PPS500","respproc":"FNOR","retref":"363652261392","respstat":"A","account":"9405701444882224"}' + end + + def successful_echeck_purchase_response + '{"amount":"1.00","resptext":"Success","cvvresp":"U","batchid":"1900940633","avsresp":"U","respcode":"00","merchid":"542041","token":"9051769384108535","authcode":"GF7PBR","respproc":"PSTR","retref":"010136262668","respstat":"A","account":"9051769384108535"}' + end + + def failed_echeck_purchase_response + '{"respproc":"PPS","amount":"0.00","resptext":"Invalid card","cardproc":"PSTR","retref":"010108164081","respstat":"C","respcode":"11","account":"9235405400368535","merchid":"542041","token":"9235405400368535"}' + end + + def failed_purchase_response + '{"respproc":"FNOR","amount":"0.00","resptext":"Insufficient funds","cardproc":"FNOR","commcard":" C ","retref":"005533134378","respstat":"C","respcode":"NU","account":"9435885049491053","merchid":"496160873888","token":"9435885049491053"}' + end + + def successful_authorize_response + '{"amount":"1.00","resptext":"Approval","commcard":" C ","cvvresp":"M","avsresp":" ","respcode":"00","merchid":"496160873888","token":"9405701444882224","authcode":"PPS454","respproc":"FNOR","retref":"363168161558","respstat":"A","account":"9405701444882224"}' + end + + def failed_authorize_response + '{"respproc":"FNOR","amount":"0.00","resptext":"Insufficient funds","cardproc":"FNOR","commcard":" C ","retref":"005737235263","respstat":"C","respcode":"NU","account":"9435885049491053","merchid":"496160873888","token":"9435885049491053"}' + end + + def successful_capture_response + '{"respproc":"FNOR","amount":"1.00","resptext":"Approval","setlstat":"Queued for Capture","commcard":" C ","retref":"363168161558","respstat":"A","respcode":"00","batchid":"1900941444","account":"9405701444882224","merchid":"496160873888","token":"9405701444882224"}' + end + + def failed_capture_response + '{"respproc":"PPS","resptext":"Txn not found","retref":"23221","respstat":"C","respcode":"29","batchid":"-1","account":""}' + end + + def successful_refund_response + '{"respproc":"PPS","amount":"1.00","resptext":"Approval","retref":"363661261786","respstat":"A","respcode":"00","merchid":"496160873888"}' + end + + def failed_refund_response + '{"respproc":"PPS","resptext":"Txn not found","retref":"23221","respcode":"29","respstat":"C"}' + end + + def successful_void_response + '{"authcode":"REVERS","respproc":"FNOR","amount":"0.00","resptext":"Approval","currency":"USD","retref":"363664261982","respstat":"A","respcode":"00","merchid":"496160873888"}' + end + + def failed_void_response + '{"respproc":"PPS","resptext":"Txn not found","retref":"23221","respcode":"29","respstat":"C"}' + end + + def successful_verify_response + '{"amount":"0.00","resptext":"Approval","commcard":" C ","cvvresp":"M","avsresp":" ","respcode":"00","merchid":"496160873888","token":"9405701444882224","authcode":"PPS585","respproc":"FNOR","retref":"363272166977","respstat":"A","account":"9405701444882224"}' + end + + def failed_verify_response + '{"respproc":"FNOR","amount":"0.00","resptext":"Insufficient funds","cardproc":"FNOR","commcard":" C ","retref":"005101240599","respstat":"C","respcode":"NU","account":"9435885049491053","merchid":"496160873888","token":"9435885049491053"}' + end + + def successful_store_response + '{"country":"CA","gsacard":"N","address":"456 My Street Apt 1","resptext":"Profile Saved","city":"Ottawa","acctid":"1","respcode":"09","defaultacct":"Y","accttype":"VISA","token":"9477709629051443","respproc":"PPS","phone":"(555)555-555","profileid":"16700875781344019340","name":"Longbob Longsen","auoptout":"N","postal":"K1C2N6","expiry":"0919","region":"ON","respstat":"A"}' + end + + def successful_unstore_response + '{"respproc":"PPS","resptext":"Profile Deleted","respstat":"A","respcode":"08"}' + end + + def failed_store_response + # Best-guess based on documentation + '{"country":"CA","gsacard":"N","address":"456 My Street Apt 1","resptext":"Profile Saved","city":"Ottawa","acctid":"1","respcode":"09","defaultacct":"Y","accttype":"VISA","token":"9477709629051443","respproc":"PPS","phone":"(555)555-555","profileid":"16700875781344019340","name":"Longbob Longsen","auoptout":"N","postal":"K1C2N6","expiry":"0919","region":"ON","respstat":"C"}' + end + + def failed_unstore_response + '{"respproc":"PPS","resptext":"Profile not found","respstat":"C","respcode":"96"}' + end +end diff --git a/test/unit/gateways/card_save_test.rb b/test/unit/gateways/card_save_test.rb index 8377581dd45..bb19495a1f1 100644 --- a/test/unit/gateways/card_save_test.rb +++ b/test/unit/gateways/card_save_test.rb @@ -59,7 +59,7 @@ def test_successful_authorize def test_successful_capture @gateway.expects(:ssl_post).returns(capture_successful) - assert response = @gateway.capture(1111, "1;110706124418747501702211;702211") + assert response = @gateway.capture(1111, '1;110706124418747501702211;702211') assert_success response assert_equal('110706124418747501702211', response.authorization) assert response.test? diff --git a/test/unit/gateways/card_stream_test.rb b/test/unit/gateways/card_stream_test.rb index c9bd4f98447..e7f225346de 100644 --- a/test/unit/gateways/card_stream_test.rb +++ b/test/unit/gateways/card_stream_test.rb @@ -18,10 +18,10 @@ def setup @visacredit_options = { :billing_address => { - :address1 => "Flat 6, Primrose Rise", - :address2 => "347 Lavender Road", - :city => "", - :state => "Northampton", + :address1 => 'Flat 6, Primrose Rise', + :address2 => '347 Lavender Road', + :city => '', + :state => 'Northampton', :zip => 'NN17 8YG ' }, :order_id => generate_unique_id, @@ -30,10 +30,10 @@ def setup @visacredit_descriptor_options = { :billing_address => { - :address1 => "Flat 6, Primrose Rise", - :address2 => "347 Lavender Road", - :city => "", - :state => "Northampton", + :address1 => 'Flat 6, Primrose Rise', + :address2 => '347 Lavender Road', + :city => '', + :state => 'Northampton', :zip => 'NN17 8YG ' }, :merchant_name => 'merchant', @@ -62,13 +62,13 @@ def test_successful_avs_and_cvv_results assert response = @gateway.authorize(142, @visacreditcard, @visacredit_options) assert_success response assert response.avs_result - assert_equal "M", response.avs_result['code'] - assert_equal "Street address and postal code match.", response.avs_result['message'] - assert_equal "Y", response.avs_result['street_match'] - assert_equal "Y", response.avs_result['postal_match'] + assert_equal 'M', response.avs_result['code'] + assert_equal 'Street address and postal code match.', response.avs_result['message'] + assert_equal 'Y', response.avs_result['street_match'] + assert_equal 'Y', response.avs_result['postal_match'] assert response.cvv_result - assert_equal "M", response.cvv_result['code'] + assert_equal 'M', response.cvv_result['code'] end def test_successful_visacreditcard_capture @@ -80,19 +80,39 @@ def test_successful_visacreditcard_capture assert responseCapture.test? end - def test_successful_visacreditcard_refund + def test_successful_refund @gateway.expects(:ssl_post).returns(successful_refund_response) - assert responseRefund = @gateway.refund(142, "authorization", @visacredit_options) + assert responseRefund = @gateway.refund(142, 'authorization', @visacredit_options) assert_equal 'APPROVED', responseRefund.message assert_success responseRefund assert responseRefund.test? end + def test_successful_refund_due_to_unsettled_payment_forces_void + refund = stub_comms do + @gateway.refund(142, 'authorization', @visacredit_options.merge(force_full_refund_if_unsettled: true)) + end.respond_with(failed_refund_for_unsettled_payment_response, successful_void_response) + + assert refund + assert_success refund + assert_equal 'APPROVED', refund.message + assert refund.test? + end + + def test_failed_refund_due_to_unsettled_payment + @gateway.expects(:ssl_post).returns(failed_refund_for_unsettled_payment_response) + + assert refund = @gateway.refund(142, 'authorization', @visacredit_options) + assert_equal 'Can not REFUND this SALE transaction', refund.message + assert_failure refund + assert refund.test? + end + def test_successful_visacreditcard_void @gateway.expects(:ssl_post).returns(successful_void_response) - assert responseRefund = @gateway.void("authorization", @visacredit_options) + assert responseRefund = @gateway.void('authorization', @visacredit_options) assert_equal 'APPROVED', responseRefund.message assert_success responseRefund assert responseRefund.test? @@ -116,6 +136,22 @@ def test_successful_visacreditcard_purchase_with_descriptors end.respond_with(successful_purchase_response_with_descriptors) end + def test_successful_visacreditcard_purchase_with_default_ip + stub_comms do + @gateway.purchase(284, @visacreditcard, @visacredit_options) + end.check_request do |endpoint, data, headers| + assert_match(/remoteAddress=1\.1\.1\.1/, data) + end.respond_with(successful_purchase_response_with_descriptors) + end + + def test_successful_visacreditcard_purchase_with_default_country + stub_comms do + @gateway.purchase(284, @visacreditcard, @visacredit_options.delete(:billing_address)) + end.check_request do |endpoint, data, headers| + assert_match(/customerCountryCode=GB/, data) + end.respond_with(successful_purchase_response) + end + def test_successful_visacreditcard_purchase_via_reference @gateway.expects(:ssl_post).returns(successful_reference_purchase_response) @@ -148,7 +184,7 @@ def test_successful_verify @gateway.verify(@visacreditcard, @visacredit_options) end.respond_with(successful_authorization_response, failed_void_response) assert_success response - assert_equal "APPROVED", response.message + assert_equal 'APPROVED', response.message end def test_failed_verify @@ -156,11 +192,10 @@ def test_failed_verify @gateway.verify(@declined_card, @visacredit_options) end.respond_with(failed_authorization_response, successful_void_response) assert_failure response - assert_equal "CARD DECLINED", response.message + assert_equal 'CARD DECLINED', response.message end def test_purchase_options - # Default purchase = stub_comms do @gateway.purchase(142, @visacreditcard, @visacredit_options) @@ -179,7 +214,7 @@ def test_purchase_options assert_success purchase purchase = stub_comms do - @gateway.purchase(142, @visacreditcard, @visacredit_options.merge(currency: "PEN")) + @gateway.purchase(142, @visacreditcard, @visacredit_options.merge(currency: 'PEN')) end.check_request do |endpoint, data, headers| assert_match(/currencyCode=604/, data) end.respond_with(successful_purchase_response) @@ -189,7 +224,7 @@ def test_purchase_options def test_successful_purchase_without_street_address @gateway.expects(:ssl_post).returns(successful_purchase_response) - assert response = @gateway.purchase(142, @visacreditcard, billing_address: {state: "Northampton"}) + assert response = @gateway.purchase(142, @visacreditcard, billing_address: {state: 'Northampton'}) assert_equal 'APPROVED', response.message end @@ -200,7 +235,7 @@ def test_successful_purchase_without_any_address end def test_hmac_signature_added_to_post - post_params = "action=SALE&amount=10000&captureDelay=0&cardCVV=356&cardExpiryMonth=12&cardExpiryYear=14&cardNumber=4929421234600821&countryCode=GB&currencyCode=826&customerAddress=Flat+6%2C+Primrose+Rise+347+Lavender+Road&customerName=Longbob+Longsen&customerPostCode=NN17+8YG+&merchantID=login&orderRef=AM+test+purchase&threeDSRequired=N&transactionUnique=#{@visacredit_options[:order_id]}&type=1" + post_params = "action=SALE&amount=10000&captureDelay=0&cardCVV=356&cardExpiryMonth=12&cardExpiryYear=14&cardNumber=4929421234600821&countryCode=GB&currencyCode=826&customerAddress=Flat+6%2C+Primrose+Rise+347+Lavender+Road&customerCountryCode=GB&customerName=Longbob+Longsen&customerPostCode=NN17+8YG+&merchantID=login&orderRef=AM+test+purchase&remoteAddress=1.1.1.1&threeDSRequired=N&transactionUnique=#{@visacredit_options[:order_id]}&type=1" expected_signature = Digest::SHA512.hexdigest("#{post_params}#{@gateway.options[:shared_secret]}") @gateway.expects(:ssl_post).with do |url, data| @@ -218,9 +253,9 @@ def test_3ds_response end.respond_with(successful_purchase_response_with_3dsecure) assert_failure purchase # 3DS required means purchase not _yet_ successful - assert_equal "UDNLRVk6eHJlZj0xNTA4MDYxNVJaMThSSjE1Uko2NFlWWg==", purchase.params["threeDSMD"] - assert_equal "eJxVUttuwjAM/ZWKD2iaQrnJjVQGA7TBGFSTeMxSC8rohTRd2d8vKe0YD5F8jh37\r\n+CQQHiXidIeilMhghUXBD2jFkd/xPNHtCz747EaCdhhsgi1eGHyjLOIsZdR2bBdI\r\nC/VVKY48VQy4uEyWa+YN6LDbA9JASFAup2zk9Tx3pOkbhJQnyHa5FhGdf6wQC2UF\r\nQmRlqizdvc5CDeUPG7p9IC2AUp7ZUam8GBNSVZUtuIwKJZEntsgSAsQUALnr2pQm\r\nKnTDaxyx1TSoHs/BW5/2zlsofCCmAiKukLkO9Zyh07dob0yHYzoAUvPAE6OEzScb\r\ni7q2o9U2DORmUHAD1DWZ/wxoqyWmot2nRYDXPEtRV+gLfzFEWAgWrCxlrMmbFbQG\r\nQwO57/S0MM4LpU1dxM/hrJx9zU8f6/3WuZxGL6/vle+bt6gLzKhYe6h3u80yAIhp\r\nQZpnJs1X0NHDF/kFvj+6mg==", purchase.params["threeDSPaReq"] - assert_equal "https://dropit.3dsecure.net:9443/PIT/ACS", purchase.params["threeDSACSURL"] + assert_equal 'UDNLRVk6eHJlZj0xNTA4MDYxNVJaMThSSjE1Uko2NFlWWg==', purchase.params['threeDSMD'] + assert_equal "eJxVUttuwjAM/ZWKD2iaQrnJjVQGA7TBGFSTeMxSC8rohTRd2d8vKe0YD5F8jh37\r\n+CQQHiXidIeilMhghUXBD2jFkd/xPNHtCz747EaCdhhsgi1eGHyjLOIsZdR2bBdI\r\nC/VVKY48VQy4uEyWa+YN6LDbA9JASFAup2zk9Tx3pOkbhJQnyHa5FhGdf6wQC2UF\r\nQmRlqizdvc5CDeUPG7p9IC2AUp7ZUam8GBNSVZUtuIwKJZEntsgSAsQUALnr2pQm\r\nKnTDaxyx1TSoHs/BW5/2zlsofCCmAiKukLkO9Zyh07dob0yHYzoAUvPAE6OEzScb\r\ni7q2o9U2DORmUHAD1DWZ/wxoqyWmot2nRYDXPEtRV+gLfzFEWAgWrCxlrMmbFbQG\r\nQwO57/S0MM4LpU1dxM/hrJx9zU8f6/3WuZxGL6/vle+bt6gLzKhYe6h3u80yAIhp\r\nQZpnJs1X0NHDF/kFvj+6mg==", purchase.params['threeDSPaReq'] + assert_equal 'https://dropit.3dsecure.net:9443/PIT/ACS', purchase.params['threeDSACSURL'] end def test_deprecated_3ds_required @@ -253,51 +288,55 @@ def test_transcript_scrubbing private def successful_authorization_response - "merchantID=0000000&threeDSEnabled=Y&merchantDescription=General+test+account+with+AVS%2FCV2+checking&amount=142&currencyCode=826&transactionUnique=fadc4985c51fc55ca349c45a79136ade&orderRef=AM+test+purchase&customerName=Longbob+Longsen&customerAddress=Flat+6%2C+Primrose+Rise+347+Lavender+Road&customerPostCode=NN17+8YG+&action=PREAUTH&type=1&countryCode=826&merchantAlias=0000992&remoteAddress=80.229.33.63&responseCode=0&responseMessage=AUTHCODE%3AD24577&xref=13021914RV01VR56LR16FNF&threeDSEnrolled=U&threeDSXID=00000000000004717472&transactionID=4717472&transactionPreviousID=0&timestamp=2013-02-19+14%3A02%3A19&amountReceived=142&avscv2ResponseCode=222100&avscv2ResponseMessage=ALL+MATCH&avscv2AuthEntity=merchant+host&cv2Check=matched&addressCheck=2&postcodeCheck=2&cardNumberMask=%2A%2A%2A%2A%2A%2A%2A%2A%2A%2A%2A%2A0821&cardTypeCode=VC&cardType=Visa+Credit&threeDSErrorCode=-1&threeDSErrorDescription=Error+while+attempting+to+send+the+request+to%3A+https%3A%2F%2F3dstest.universalpaymentgateway.com%3A4343%2FAPI%0A%0DPlease+make+sure+that+ActiveMerchant+server+is+running+and+the+URL+is+valid.+ERROR_INTERNET_CANNOT_CONNECT%3A+The+attempt+to+connect+to+the+server+failed.&threeDSMerchantPref=PROCEED&threeDSVETimestamp=2013-02-19+14%3A01%3A56&currencyExponent=2&responseStatus=0&merchantName=CARDSTREAM+TEST&merchantID2=100001" + 'merchantID=0000000&threeDSEnabled=Y&merchantDescription=General+test+account+with+AVS%2FCV2+checking&amount=142&currencyCode=826&transactionUnique=fadc4985c51fc55ca349c45a79136ade&orderRef=AM+test+purchase&customerName=Longbob+Longsen&customerAddress=Flat+6%2C+Primrose+Rise+347+Lavender+Road&customerPostCode=NN17+8YG+&action=PREAUTH&type=1&countryCode=826&merchantAlias=0000992&remoteAddress=80.229.33.63&responseCode=0&responseMessage=AUTHCODE%3AD24577&xref=13021914RV01VR56LR16FNF&threeDSEnrolled=U&threeDSXID=00000000000004717472&transactionID=4717472&transactionPreviousID=0&timestamp=2013-02-19+14%3A02%3A19&amountReceived=142&avscv2ResponseCode=222100&avscv2ResponseMessage=ALL+MATCH&avscv2AuthEntity=merchant+host&cv2Check=matched&addressCheck=2&postcodeCheck=2&cardNumberMask=%2A%2A%2A%2A%2A%2A%2A%2A%2A%2A%2A%2A0821&cardTypeCode=VC&cardType=Visa+Credit&threeDSErrorCode=-1&threeDSErrorDescription=Error+while+attempting+to+send+the+request+to%3A+https%3A%2F%2F3dstest.universalpaymentgateway.com%3A4343%2FAPI%0A%0DPlease+make+sure+that+ActiveMerchant+server+is+running+and+the+URL+is+valid.+ERROR_INTERNET_CANNOT_CONNECT%3A+The+attempt+to+connect+to+the+server+failed.&threeDSMerchantPref=PROCEED&threeDSVETimestamp=2013-02-19+14%3A01%3A56&currencyExponent=2&responseStatus=0&merchantName=CARDSTREAM+TEST&merchantID2=100001' end def successful_capture_response - "merchantID=0000000&threeDSEnabled=Y&merchantDescription=General+test+account+with+AVS%2FCV2+checking&xref=13021914XW02YJ20MQ37RMT&amount=142&currencyCode=826&action=SALE&type=1&countryCode=826&merchantAlias=0000992&remoteAddress=80.229.33.63&responseCode=0&responseMessage=AUTHCODE%3A39657X&customerName=Longbob+Longsen&customerAddress=Flat+6%2C+Primrose+Rise+347+Lavender+Road&customerPostCode=NN17+8YG+&transactionUnique=fadc4985c51fc55ca349c45a79136ade&orderRef=AM+test+purchase&amountReceived=142&avscv2ResponseCode=422100&avscv2ResponseMessage=ALL+MATCH&avscv2AuthEntity=merchant+host&cv2Check=not+matched&addressCheck=matched&postcodeCheck=matched&threeDSXID=00000000000004717475&threeDSEnrolled=U&threeDSErrorCode=-1&threeDSErrorDescription=Error+while+attempting+to+send+the+request+to%3A+https%3A%2F%2F3dstest.universalpaymentgateway.com%3A4343%2FAPI%0A%0DPlease+make+sure+that+ActiveMerchant+server+is+running+and+the+URL+is+valid.+ERROR_INTERNET_CANNOT_CONNECT%3A+The+attempt+to+connect+to+the+server+failed.&threeDSMerchantPref=PROCEED&threeDSVETimestamp=2013-02-19+14%3A02%3A20&cardTypeCode=VC&cardNumberMask=%2A%2A%2A%2A%2A%2A%2A%2A%2A%2A%2A%2A0821&transactionID=4717475&transactionPreviousID=4717472&timestamp=2013-02-19+14%3A02%3A44&cardType=Visa+Credit&currencyExponent=2&responseStatus=0&merchantName=CARDSTREAM+TEST&merchantID2=100001" + 'merchantID=0000000&threeDSEnabled=Y&merchantDescription=General+test+account+with+AVS%2FCV2+checking&xref=13021914XW02YJ20MQ37RMT&amount=142&currencyCode=826&action=SALE&type=1&countryCode=826&merchantAlias=0000992&remoteAddress=80.229.33.63&responseCode=0&responseMessage=AUTHCODE%3A39657X&customerName=Longbob+Longsen&customerAddress=Flat+6%2C+Primrose+Rise+347+Lavender+Road&customerPostCode=NN17+8YG+&transactionUnique=fadc4985c51fc55ca349c45a79136ade&orderRef=AM+test+purchase&amountReceived=142&avscv2ResponseCode=422100&avscv2ResponseMessage=ALL+MATCH&avscv2AuthEntity=merchant+host&cv2Check=not+matched&addressCheck=matched&postcodeCheck=matched&threeDSXID=00000000000004717475&threeDSEnrolled=U&threeDSErrorCode=-1&threeDSErrorDescription=Error+while+attempting+to+send+the+request+to%3A+https%3A%2F%2F3dstest.universalpaymentgateway.com%3A4343%2FAPI%0A%0DPlease+make+sure+that+ActiveMerchant+server+is+running+and+the+URL+is+valid.+ERROR_INTERNET_CANNOT_CONNECT%3A+The+attempt+to+connect+to+the+server+failed.&threeDSMerchantPref=PROCEED&threeDSVETimestamp=2013-02-19+14%3A02%3A20&cardTypeCode=VC&cardNumberMask=%2A%2A%2A%2A%2A%2A%2A%2A%2A%2A%2A%2A0821&transactionID=4717475&transactionPreviousID=4717472&timestamp=2013-02-19+14%3A02%3A44&cardType=Visa+Credit&currencyExponent=2&responseStatus=0&merchantName=CARDSTREAM+TEST&merchantID2=100001' end def successful_refund_response - "merchantID=0000000&threeDSEnabled=Y&merchantDescription=General+test+account+with+AVS%2FCV2+checking&xref=13021914NT06BM21GJ15VJH&amount=142&currencyCode=826&action=REFUND&type=1&countryCode=826&merchantAlias=0000992&remoteAddress=80.229.33.63&responseCode=0&responseMessage=REFUNDACCEPTED&customerName=Longbob+Longsen&customerAddress=Flat+6%2C+Primrose+Rise+347+Lavender+Road&customerPostCode=NN17+8YG+&transactionUnique=c7981d78d217cf3cfda6559921e31c4a&orderRef=AM+test+purchase&amountReceived=142&avscv2ResponseCode=222100&avscv2ResponseMessage=ALL+MATCH&avscv2AuthEntity=merchant+host&cv2Check=matched&addressCheck=matched&postcodeCheck=matched&threeDSXID=00000000000004717488&threeDSEnrolled=U&threeDSErrorCode=-1&threeDSErrorDescription=Error+while+attempting+to+send+the+request+to%3A+https%3A%2F%2F3dstest.universalpaymentgateway.com%3A4343%2FAPI%0A%0DPlease+make+sure+that+ActiveMerchant+server+is+running+and+the+URL+is+valid.+ERROR_INTERNET_CANNOT_CONNECT%3A+The+attempt+to+connect+to+the+server+failed.&threeDSMerchantPref=PROCEED&threeDSVETimestamp=2013-02-19+14%3A05%3A58&cardTypeCode=VC&cardNumberMask=%2A%2A%2A%2A%2A%2A%2A%2A%2A%2A%2A%2A0821&threeDSRequired=N&transactionID=4717490&transactionPreviousID=4717488&timestamp=2013-02-19+14%3A06%3A21&cardType=Visa+Credit&currencyExponent=2&responseStatus=0&merchantName=CARDSTREAM+TEST&merchantID2=100001" + 'merchantID=0000000&threeDSEnabled=Y&merchantDescription=General+test+account+with+AVS%2FCV2+checking&xref=13021914NT06BM21GJ15VJH&amount=142&currencyCode=826&action=REFUND&type=1&countryCode=826&merchantAlias=0000992&remoteAddress=80.229.33.63&responseCode=0&responseMessage=REFUNDACCEPTED&customerName=Longbob+Longsen&customerAddress=Flat+6%2C+Primrose+Rise+347+Lavender+Road&customerPostCode=NN17+8YG+&transactionUnique=c7981d78d217cf3cfda6559921e31c4a&orderRef=AM+test+purchase&amountReceived=142&avscv2ResponseCode=222100&avscv2ResponseMessage=ALL+MATCH&avscv2AuthEntity=merchant+host&cv2Check=matched&addressCheck=matched&postcodeCheck=matched&threeDSXID=00000000000004717488&threeDSEnrolled=U&threeDSErrorCode=-1&threeDSErrorDescription=Error+while+attempting+to+send+the+request+to%3A+https%3A%2F%2F3dstest.universalpaymentgateway.com%3A4343%2FAPI%0A%0DPlease+make+sure+that+ActiveMerchant+server+is+running+and+the+URL+is+valid.+ERROR_INTERNET_CANNOT_CONNECT%3A+The+attempt+to+connect+to+the+server+failed.&threeDSMerchantPref=PROCEED&threeDSVETimestamp=2013-02-19+14%3A05%3A58&cardTypeCode=VC&cardNumberMask=%2A%2A%2A%2A%2A%2A%2A%2A%2A%2A%2A%2A0821&threeDSRequired=N&transactionID=4717490&transactionPreviousID=4717488&timestamp=2013-02-19+14%3A06%3A21&cardType=Visa+Credit&currencyExponent=2&responseStatus=0&merchantName=CARDSTREAM+TEST&merchantID2=100001' + end + + def failed_refund_for_unsettled_payment_response + 'responseCode=65541&responseMessage=Can+not+REFUND+this+SALE+transaction&responseStatus=2&xref=18032714RP14KM21FX11YHT&amount=142&currencyCode=826&remoteAddress=1.1.1.1&countryCode=GB&merchantID=103191&action=REFUND_SALE&requestID=5aba43ad1481e&state=finished&requestMerchantID=103191&processMerchantID=103191&transactionID=25814232&timestamp=2018-03-27+14%3A14%3A21&vcsResponseCode=0&vcsResponseMessage=Success+-+no+velocity+check+rules+applied&signature=b56640b215510a04ebfaa095b63705cda08cca318a7ccb2b2b48caec75adc187d9cae5082eb1dc71d258813ee9d879721e48af04966a489171f435bfa67b6d92' end def successful_void_response - "merchantID=103191&threeDSEnabled=Y&avscv2CheckEnabled=N&eReceiptsEnabled=N&transactionID=11132605&xref=16050316NZ51LT53FP70BMZ&state=canceled&captureDelay=-1&remoteAddress=107.15.253.186&action=CANCEL%3ASALE&type=1&currencyCode=826&countryCode=826&amount=284&orderRef=AM+test+purchase&transactionUnique=2240526ccaa7d41af63a94aab843e683&cardTypeCode=VC&cardNumberMask=492942%2A%2A%2A%2A%2A%2A0821&cardExpiryDate=1214&cardExpiryMonth=12&cardExpiryYear=14&customerName=Longbob+Longsen&customerAddress=Flat+6%2C+Primrose+Rise+347+Lavender+Road&customerPostcode=NN17+8YG&eReceiptsStoreID=1&customerReceiptsRequired=N&cv2Check=matched&addressCheck=matched&postcodeCheck=matched&avscv2ResponseCode=222100&avscv2ResponseMessage=ALL+MATCH&avscv2AuthEntity=merchant+host&addressCheckPref=not+known%2Cnot+checked%2Cmatched%2Cnot+matched%2Cpartially+matched&postcodeCheckPref=not+known%2Cnot+checked%2Cmatched%2Cnot+matched%2Cpartially+matched&threeDSRequired=N&threeDSCheckPref=authenticated&authorisationCode=084609&amountReceived=0&responseCode=0&responseMessage=Transaction+cancelled.&cardCVVMandatory=N&responseStatus=0&timestamp=2016-05-03+16%3A51%3A54&cardType=Visa+Credit&cardScheme=Visa+&cardSchemeCode=VC&cardIssuer=BARCLAYS+BANK+PLC&cardIssuerCountry=United+Kingdom&cardIssuerCountryCode=GBR&signature=73cf5ec5470f6a1b3abce4e2a4b64adc2da0cb7103e8d362b40ab101d2ff339961a593869f289f7660a286e8c92c22fd5dec4330cf7e7e0ca8651cd8c0a8d966" + 'merchantID=103191&threeDSEnabled=Y&avscv2CheckEnabled=N&eReceiptsEnabled=N&transactionID=11132605&xref=16050316NZ51LT53FP70BMZ&state=canceled&captureDelay=-1&remoteAddress=107.15.253.186&action=CANCEL%3ASALE&type=1&currencyCode=826&countryCode=826&amount=284&orderRef=AM+test+purchase&transactionUnique=2240526ccaa7d41af63a94aab843e683&cardTypeCode=VC&cardNumberMask=492942%2A%2A%2A%2A%2A%2A0821&cardExpiryDate=1214&cardExpiryMonth=12&cardExpiryYear=14&customerName=Longbob+Longsen&customerAddress=Flat+6%2C+Primrose+Rise+347+Lavender+Road&customerPostcode=NN17+8YG&eReceiptsStoreID=1&customerReceiptsRequired=N&cv2Check=matched&addressCheck=matched&postcodeCheck=matched&avscv2ResponseCode=222100&avscv2ResponseMessage=ALL+MATCH&avscv2AuthEntity=merchant+host&addressCheckPref=not+known%2Cnot+checked%2Cmatched%2Cnot+matched%2Cpartially+matched&postcodeCheckPref=not+known%2Cnot+checked%2Cmatched%2Cnot+matched%2Cpartially+matched&threeDSRequired=N&threeDSCheckPref=authenticated&authorisationCode=084609&amountReceived=0&responseCode=0&responseMessage=Transaction+cancelled.&cardCVVMandatory=N&responseStatus=0&timestamp=2016-05-03+16%3A51%3A54&cardType=Visa+Credit&cardScheme=Visa+&cardSchemeCode=VC&cardIssuer=BARCLAYS+BANK+PLC&cardIssuerCountry=United+Kingdom&cardIssuerCountryCode=GBR&signature=73cf5ec5470f6a1b3abce4e2a4b64adc2da0cb7103e8d362b40ab101d2ff339961a593869f289f7660a286e8c92c22fd5dec4330cf7e7e0ca8651cd8c0a8d966' end def successful_purchase_response - "merchantID=0000000&threeDSEnabled=Y&merchantDescription=General+test+account+with+AVS%2FCV2+checking&amount=142&currencyCode=826&transactionUnique=27a594210e27846c8e9102647f210586&orderRef=AM+test+purchase&customerName=Longbob+Longsen&customerAddress=Flat+6%2C+Primrose+Rise+347+Lavender+Road&customerPostCode=NN17+8YG+&action=SALE&type=1&countryCode=826&merchantAlias=0000992&remoteAddress=80.229.33.63&responseCode=0&responseMessage=AUTHCODE%3A635959&xref=13021914LS06DW22NW22LVJ&threeDSEnrolled=U&threeDSXID=00000000000004717491&transactionID=4717491&transactionPreviousID=0&timestamp=2013-02-19+14%3A06%3A44&amountReceived=142&avscv2ResponseCode=222100&avscv2ResponseMessage=ALL+MATCH&avscv2AuthEntity=merchant+host&cv2Check=matched&addressCheck=matched&postcodeCheck=matched&cardNumberMask=%2A%2A%2A%2A%2A%2A%2A%2A%2A%2A%2A%2A0821&cardTypeCode=VC&cardType=Visa+Credit&threeDSErrorCode=-1&threeDSErrorDescription=Error+while+attempting+to+send+the+request+to%3A+https%3A%2F%2F3dstest.universalpaymentgateway.com%3A4343%2FAPI%0A%0DPlease+make+sure+that+ActiveMerchant+server+is+running+and+the+URL+is+valid.+ERROR_INTERNET_CANNOT_CONNECT%3A+The+attempt+to+connect+to+the+server+failed.&threeDSMerchantPref=PROCEED&threeDSVETimestamp=2013-02-19+14%3A06%3A22&currencyExponent=2&responseStatus=0&merchantName=CARDSTREAM+TEST&merchantID2=100001" + 'merchantID=0000000&threeDSEnabled=Y&merchantDescription=General+test+account+with+AVS%2FCV2+checking&amount=142&currencyCode=826&transactionUnique=27a594210e27846c8e9102647f210586&orderRef=AM+test+purchase&customerName=Longbob+Longsen&customerAddress=Flat+6%2C+Primrose+Rise+347+Lavender+Road&customerPostCode=NN17+8YG+&action=SALE&type=1&countryCode=826&merchantAlias=0000992&remoteAddress=80.229.33.63&responseCode=0&responseMessage=AUTHCODE%3A635959&xref=13021914LS06DW22NW22LVJ&threeDSEnrolled=U&threeDSXID=00000000000004717491&transactionID=4717491&transactionPreviousID=0&timestamp=2013-02-19+14%3A06%3A44&amountReceived=142&avscv2ResponseCode=222100&avscv2ResponseMessage=ALL+MATCH&avscv2AuthEntity=merchant+host&cv2Check=matched&addressCheck=matched&postcodeCheck=matched&cardNumberMask=%2A%2A%2A%2A%2A%2A%2A%2A%2A%2A%2A%2A0821&cardTypeCode=VC&cardType=Visa+Credit&threeDSErrorCode=-1&threeDSErrorDescription=Error+while+attempting+to+send+the+request+to%3A+https%3A%2F%2F3dstest.universalpaymentgateway.com%3A4343%2FAPI%0A%0DPlease+make+sure+that+ActiveMerchant+server+is+running+and+the+URL+is+valid.+ERROR_INTERNET_CANNOT_CONNECT%3A+The+attempt+to+connect+to+the+server+failed.&threeDSMerchantPref=PROCEED&threeDSVETimestamp=2013-02-19+14%3A06%3A22&currencyExponent=2&responseStatus=0&merchantName=CARDSTREAM+TEST&merchantID2=100001' end def successful_purchase_response_with_3dsecure - "responseCode=65802&responseMessage=3DS+AUTHENTICATION+REQUIRED&responseStatus=2&merchantID=103191&threeDSEnabled=Y&threeDSCheckPref=not+known%2Cnot+checked%2Cauthenticated%2Cnot+authenticated%2Cattempted+authentication&avscv2CheckEnabled=N&cv2CheckPref=not+known%2Cnot+checked%2Cmatched%2Cnot+matched%2Cpartially+matched&addressCheckPref=not+known%2Cnot+checked%2Cmatched%2Cnot+matched%2Cpartially+matched&postcodeCheckPref=not+known%2Cnot+checked%2Cmatched%2Cnot+matched%2Cpartially+matched&cardCVVMandatory=Y&customerID=1749&eReceiptsEnabled=N&eReceiptsStoreID=1&amount=1202&currencyCode=826&transactionUnique=42e13d06ce4d5f5e3eb4868d29baa8bb&orderRef=AM+test+purchase&threeDSRequired=Y&customerName=Longbob+Longsen&customerAddress=25+The+Larches&customerPostCode=LE10+2RT&action=SALE&type=1&countryCode=826&customerPostcode=LE10+2RT&customerReceiptsRequired=N&state=finished&remoteAddress=45.37.180.92&requestMerchantID=103191&processMerchantID=103191&xref=15080615RZ18RJ15RJ64YVZ&cardExpiryDate=1220&threeDSXID=MDAwMDAwMDAwMDAwMDg5NjY0OTc%3D&threeDSEnrolled=Y&transactionID=8966497&cardNumberMask=%2A%2A%2A%2A%2A%2A%2A%2A%2A%2A%2A%2A1112&cardType=Visa+Credit&cardTypeCode=VC&cardScheme=Visa+&cardSchemeCode=VC&cardIssuer=Unknown&cardIssuerCountry=Unknown&cardIssuerCountryCode=XXX&threeDSPaReq=eJxVUttuwjAM%2FZWKD2iaQrnJjVQGA7TBGFSTeMxSC8rohTRd2d8vKe0YD5F8jh37%0D%0A%2BCQQHiXidIeilMhghUXBD2jFkd%2FxPNHtCz747EaCdhhsgi1eGHyjLOIsZdR2bBdI%0D%0AC%2FVVKY48VQy4uEyWa%2BYN6LDbA9JASFAup2zk9Tx3pOkbhJQnyHa5FhGdf6wQC2UF%0D%0AQmRlqizdvc5CDeUPG7p9IC2AUp7ZUam8GBNSVZUtuIwKJZEntsgSAsQUALnr2pQm%0D%0AKnTDaxyx1TSoHs%2FBW5%2F2zlsofCCmAiKukLkO9Zyh07dob0yHYzoAUvPAE6OEzScb%0D%0Ai7q2o9U2DORmUHAD1DWZ%2FwxoqyWmot2nRYDXPEtRV%2BgLfzFEWAgWrCxlrMmbFbQG%0D%0AQwO57%2FS0MM4LpU1dxM%2FhrJx9zU8f6%2F3WuZxGL6%2Fvle%2Bbt6gLzKhYe6h3u80yAIhp%0D%0AQZpnJs1X0NHDF%2FkFvj%2B6mg%3D%3D&threeDSACSURL=https%3A%2F%2Fdropit.3dsecure.net%3A9443%2FPIT%2FACS&threeDSVETimestamp=2015-08-06+15%3A18%3A15&threeDSCheck=not+checked&vcsResponseCode=0&vcsResponseMessage=Success+-+no+velocity+check+rules+applied&currencyExponent=2&threeDSMD=UDNLRVk6eHJlZj0xNTA4MDYxNVJaMThSSjE1Uko2NFlWWg%3D%3D&timestamp=2015-08-06+15%3A18%3A17&threeDSResponseCode=65802&threeDSResponseMessage=3DS+AUTHENTICATION+REQUIRED&signature=8551e3f1c77b6cfa78e154d99ffb05fdeabbae48a7ce723a3464047731ad98a1c4bfe0b7dfdf46de7ff3dab66b3e2e365025fc9ff3a74d86ae4378c8cc985d88" + 'responseCode=65802&responseMessage=3DS+AUTHENTICATION+REQUIRED&responseStatus=2&merchantID=103191&threeDSEnabled=Y&threeDSCheckPref=not+known%2Cnot+checked%2Cauthenticated%2Cnot+authenticated%2Cattempted+authentication&avscv2CheckEnabled=N&cv2CheckPref=not+known%2Cnot+checked%2Cmatched%2Cnot+matched%2Cpartially+matched&addressCheckPref=not+known%2Cnot+checked%2Cmatched%2Cnot+matched%2Cpartially+matched&postcodeCheckPref=not+known%2Cnot+checked%2Cmatched%2Cnot+matched%2Cpartially+matched&cardCVVMandatory=Y&customerID=1749&eReceiptsEnabled=N&eReceiptsStoreID=1&amount=1202&currencyCode=826&transactionUnique=42e13d06ce4d5f5e3eb4868d29baa8bb&orderRef=AM+test+purchase&threeDSRequired=Y&customerName=Longbob+Longsen&customerAddress=25+The+Larches&customerPostCode=LE10+2RT&action=SALE&type=1&countryCode=826&customerPostcode=LE10+2RT&customerReceiptsRequired=N&state=finished&remoteAddress=45.37.180.92&requestMerchantID=103191&processMerchantID=103191&xref=15080615RZ18RJ15RJ64YVZ&cardExpiryDate=1220&threeDSXID=MDAwMDAwMDAwMDAwMDg5NjY0OTc%3D&threeDSEnrolled=Y&transactionID=8966497&cardNumberMask=%2A%2A%2A%2A%2A%2A%2A%2A%2A%2A%2A%2A1112&cardType=Visa+Credit&cardTypeCode=VC&cardScheme=Visa+&cardSchemeCode=VC&cardIssuer=Unknown&cardIssuerCountry=Unknown&cardIssuerCountryCode=XXX&threeDSPaReq=eJxVUttuwjAM%2FZWKD2iaQrnJjVQGA7TBGFSTeMxSC8rohTRd2d8vKe0YD5F8jh37%0D%0A%2BCQQHiXidIeilMhghUXBD2jFkd%2FxPNHtCz747EaCdhhsgi1eGHyjLOIsZdR2bBdI%0D%0AC%2FVVKY48VQy4uEyWa%2BYN6LDbA9JASFAup2zk9Tx3pOkbhJQnyHa5FhGdf6wQC2UF%0D%0AQmRlqizdvc5CDeUPG7p9IC2AUp7ZUam8GBNSVZUtuIwKJZEntsgSAsQUALnr2pQm%0D%0AKnTDaxyx1TSoHs%2FBW5%2F2zlsofCCmAiKukLkO9Zyh07dob0yHYzoAUvPAE6OEzScb%0D%0Ai7q2o9U2DORmUHAD1DWZ%2FwxoqyWmot2nRYDXPEtRV%2BgLfzFEWAgWrCxlrMmbFbQG%0D%0AQwO57%2FS0MM4LpU1dxM%2FhrJx9zU8f6%2F3WuZxGL6%2Fvle%2Bbt6gLzKhYe6h3u80yAIhp%0D%0AQZpnJs1X0NHDF%2FkFvj%2B6mg%3D%3D&threeDSACSURL=https%3A%2F%2Fdropit.3dsecure.net%3A9443%2FPIT%2FACS&threeDSVETimestamp=2015-08-06+15%3A18%3A15&threeDSCheck=not+checked&vcsResponseCode=0&vcsResponseMessage=Success+-+no+velocity+check+rules+applied&currencyExponent=2&threeDSMD=UDNLRVk6eHJlZj0xNTA4MDYxNVJaMThSSjE1Uko2NFlWWg%3D%3D&timestamp=2015-08-06+15%3A18%3A17&threeDSResponseCode=65802&threeDSResponseMessage=3DS+AUTHENTICATION+REQUIRED&signature=8551e3f1c77b6cfa78e154d99ffb05fdeabbae48a7ce723a3464047731ad98a1c4bfe0b7dfdf46de7ff3dab66b3e2e365025fc9ff3a74d86ae4378c8cc985d88' end def successful_purchase_response_with_descriptors - "merchantID=103191&threeDSEnabled=Y&threeDSCheckPref=authenticated&avscv2CheckEnabled=N&cv2CheckPref=not+known%2Cnot+checked%2Cmatched%2Cnot+matched%2Cpartially+matched&addressCheckPref=not+known%2Cnot+checked%2Cmatched%2Cnot+matched%2Cpartially+matched&postcodeCheckPref=not+known%2Cnot+checked%2Cmatched%2Cnot+matched%2Cpartially+matched&cardCVVMandatory=Y&customerReceiptsRequired=N&eReceiptsEnabled=N&eReceiptsStoreID=1&captureDelay=0&amount=284&currencyCode=826&statementNarrative1=merchant&statementNarrative2=product&type=1&threeDSRequired=N&customerName=Longbob+Longsen&cardExpiryMonth=12&cardExpiryYear=14&customerAddress=Flat+6%2C+Primrose+Rise+347+Lavender+Road&customerPostCode=NN17+8YG&countryCode=826&action=SALE&customerPostcode=NN17+8YG&requestID=586aae8406720&responseCode=0&responseMessage=AUTHCODE%3A684787&state=captured&requestMerchantID=103191&processMerchantID=103191&xref=17010219YV48VW21QH25TKS&paymentMethod=card&cardExpiryDate=1214&authorisationCode=684787&transactionID=13843073&responseStatus=0&timestamp=2017-01-02+19%3A48%3A21&amountReceived=284&avscv2ResponseCode=222100&avscv2ResponseMessage=ALL+MATCH&avscv2AuthEntity=merchant+host&cv2Check=matched&addressCheck=matched&postcodeCheck=matched&cardNumberMask=492942%2A%2A%2A%2A%2A%2A0821&cardType=Visa+Credit&cardTypeCode=VC&cardScheme=Visa+&cardSchemeCode=VC&cardIssuer=BARCLAYS+BANK+PLC&cardIssuerCountry=United+Kingdom&cardIssuerCountryCode=GBR&vcsResponseCode=0&vcsResponseMessage=Success+-+no+velocity+check+rules+applied&currencyExponent=2&signature=d47c9253d2d9ff6e9464a782b798b3fa699f6ed085eb03d5f87c4cf1f0994efab0c3145236df2163ea2b48fc0232bed25626b7ac331f0c98473ef4b551099eef" + 'merchantID=103191&threeDSEnabled=Y&threeDSCheckPref=authenticated&avscv2CheckEnabled=N&cv2CheckPref=not+known%2Cnot+checked%2Cmatched%2Cnot+matched%2Cpartially+matched&addressCheckPref=not+known%2Cnot+checked%2Cmatched%2Cnot+matched%2Cpartially+matched&postcodeCheckPref=not+known%2Cnot+checked%2Cmatched%2Cnot+matched%2Cpartially+matched&cardCVVMandatory=Y&customerReceiptsRequired=N&eReceiptsEnabled=N&eReceiptsStoreID=1&captureDelay=0&amount=284&currencyCode=826&statementNarrative1=merchant&statementNarrative2=product&type=1&threeDSRequired=N&customerName=Longbob+Longsen&cardExpiryMonth=12&cardExpiryYear=14&customerAddress=Flat+6%2C+Primrose+Rise+347+Lavender+Road&customerPostCode=NN17+8YG&countryCode=826&action=SALE&customerPostcode=NN17+8YG&requestID=586aae8406720&responseCode=0&responseMessage=AUTHCODE%3A684787&state=captured&requestMerchantID=103191&processMerchantID=103191&xref=17010219YV48VW21QH25TKS&paymentMethod=card&cardExpiryDate=1214&authorisationCode=684787&transactionID=13843073&responseStatus=0&timestamp=2017-01-02+19%3A48%3A21&amountReceived=284&avscv2ResponseCode=222100&avscv2ResponseMessage=ALL+MATCH&avscv2AuthEntity=merchant+host&cv2Check=matched&addressCheck=matched&postcodeCheck=matched&cardNumberMask=492942%2A%2A%2A%2A%2A%2A0821&cardType=Visa+Credit&cardTypeCode=VC&cardScheme=Visa+&cardSchemeCode=VC&cardIssuer=BARCLAYS+BANK+PLC&cardIssuerCountry=United+Kingdom&cardIssuerCountryCode=GBR&vcsResponseCode=0&vcsResponseMessage=Success+-+no+velocity+check+rules+applied&currencyExponent=2&signature=d47c9253d2d9ff6e9464a782b798b3fa699f6ed085eb03d5f87c4cf1f0994efab0c3145236df2163ea2b48fc0232bed25626b7ac331f0c98473ef4b551099eef' end def failed_purchase_card_declined_response - "merchantID=0000000&threeDSEnabled=Y&merchantDescription=General+test+account+with+AVS%2FCV2+checking&amount=10000&currencyCode=826&transactionUnique=7385df1d9c5484142bb6be1e932cd2df&orderRef=AM+test+purchase&customerName=Longbob+Longsen&customerAddress=25+The+Larches+&customerPostCode=LE10+2RT&action=SALE&type=1&countryCode=826&merchantAlias=0000992&remoteAddress=80.229.33.63&responseCode=5&responseMessage=CARD+DECLINED&xref=13021914RQ07HK55HG29KPH&threeDSEnrolled=U&threeDSXID=00000000000004717495&transactionID=4717495&transactionPreviousID=0&timestamp=2013-02-19+14%3A08%3A18&amountReceived=0&cardNumberMask=%2A%2A%2A%2A%2A%2A%2A%2A%2A%2A%2A%2A0191&cardTypeCode=MC&cardType=Mastercard&threeDSErrorCode=-1&threeDSErrorDescription=Error+while+attempting+to+send+the+request+to%3A+https%3A%2F%2F3dstest.universalpaymentgateway.com%3A4343%2FAPI%0A%0DPlease+make+sure+that+ActiveMerchant+server+is+running+and+the+URL+is+valid.+ERROR_INTERNET_CANNOT_CONNECT%3A+The+attempt+to+connect+to+the+server+failed.&threeDSMerchantPref=PROCEED&threeDSVETimestamp=2013-02-19+14%3A07%3A55&currencyExponent=2&responseStatus=1&merchantName=CARDSTREAM+TEST&merchantID2=100001" + 'merchantID=0000000&threeDSEnabled=Y&merchantDescription=General+test+account+with+AVS%2FCV2+checking&amount=10000&currencyCode=826&transactionUnique=7385df1d9c5484142bb6be1e932cd2df&orderRef=AM+test+purchase&customerName=Longbob+Longsen&customerAddress=25+The+Larches+&customerPostCode=LE10+2RT&action=SALE&type=1&countryCode=826&merchantAlias=0000992&remoteAddress=80.229.33.63&responseCode=5&responseMessage=CARD+DECLINED&xref=13021914RQ07HK55HG29KPH&threeDSEnrolled=U&threeDSXID=00000000000004717495&transactionID=4717495&transactionPreviousID=0&timestamp=2013-02-19+14%3A08%3A18&amountReceived=0&cardNumberMask=%2A%2A%2A%2A%2A%2A%2A%2A%2A%2A%2A%2A0191&cardTypeCode=MC&cardType=Mastercard&threeDSErrorCode=-1&threeDSErrorDescription=Error+while+attempting+to+send+the+request+to%3A+https%3A%2F%2F3dstest.universalpaymentgateway.com%3A4343%2FAPI%0A%0DPlease+make+sure+that+ActiveMerchant+server+is+running+and+the+URL+is+valid.+ERROR_INTERNET_CANNOT_CONNECT%3A+The+attempt+to+connect+to+the+server+failed.&threeDSMerchantPref=PROCEED&threeDSVETimestamp=2013-02-19+14%3A07%3A55&currencyExponent=2&responseStatus=1&merchantName=CARDSTREAM+TEST&merchantID2=100001' end def failed_authorization_response - "merchantID=0000000&threeDSEnabled=Y&merchantDescription=General+test+account+with+AVS%2FCV2+checking&amount=10000&currencyCode=826&transactionUnique=7385df1d9c5484142bb6be1e932cd2df&orderRef=AM+test+purchase&customerName=Longbob+Longsen&customerAddress=25+The+Larches+&customerPostCode=LE10+2RT&action=SALE&type=1&countryCode=826&merchantAlias=0000992&remoteAddress=80.229.33.63&responseCode=5&responseMessage=CARD+DECLINED&xref=13021914RQ07HK55HG29KPH&threeDSEnrolled=U&threeDSXID=00000000000004717495&transactionID=4717495&transactionPreviousID=0&timestamp=2013-02-19+14%3A08%3A18&amountReceived=0&cardNumberMask=%2A%2A%2A%2A%2A%2A%2A%2A%2A%2A%2A%2A0191&cardTypeCode=MC&cardType=Mastercard&threeDSErrorCode=-1&threeDSErrorDescription=Error+while+attempting+to+send+the+request+to%3A+https%3A%2F%2F3dstest.universalpaymentgateway.com%3A4343%2FAPI%0A%0DPlease+make+sure+that+ActiveMerchant+server+is+running+and+the+URL+is+valid.+ERROR_INTERNET_CANNOT_CONNECT%3A+The+attempt+to+connect+to+the+server+failed.&threeDSMerchantPref=PROCEED&threeDSVETimestamp=2013-02-19+14%3A07%3A55&currencyExponent=2&responseStatus=1&merchantName=CARDSTREAM+TEST&merchantID2=100001" + 'merchantID=0000000&threeDSEnabled=Y&merchantDescription=General+test+account+with+AVS%2FCV2+checking&amount=10000&currencyCode=826&transactionUnique=7385df1d9c5484142bb6be1e932cd2df&orderRef=AM+test+purchase&customerName=Longbob+Longsen&customerAddress=25+The+Larches+&customerPostCode=LE10+2RT&action=SALE&type=1&countryCode=826&merchantAlias=0000992&remoteAddress=80.229.33.63&responseCode=5&responseMessage=CARD+DECLINED&xref=13021914RQ07HK55HG29KPH&threeDSEnrolled=U&threeDSXID=00000000000004717495&transactionID=4717495&transactionPreviousID=0&timestamp=2013-02-19+14%3A08%3A18&amountReceived=0&cardNumberMask=%2A%2A%2A%2A%2A%2A%2A%2A%2A%2A%2A%2A0191&cardTypeCode=MC&cardType=Mastercard&threeDSErrorCode=-1&threeDSErrorDescription=Error+while+attempting+to+send+the+request+to%3A+https%3A%2F%2F3dstest.universalpaymentgateway.com%3A4343%2FAPI%0A%0DPlease+make+sure+that+ActiveMerchant+server+is+running+and+the+URL+is+valid.+ERROR_INTERNET_CANNOT_CONNECT%3A+The+attempt+to+connect+to+the+server+failed.&threeDSMerchantPref=PROCEED&threeDSVETimestamp=2013-02-19+14%3A07%3A55&currencyExponent=2&responseStatus=1&merchantName=CARDSTREAM+TEST&merchantID2=100001' end def failed_void_response - "responseCode=65548&responseMessage=DB+ERROR&responseStatus=2&xref=16050317BX02HT10NH49ZRS&merchantID=103191&action=CANCEL&state=finished&remoteAddress=107.15.253.186&requestMerchantID=103191&processMerchantID=103191&timestamp=2016-05-03+17%3A02%3A10&signature=73d3ea59f106208fdf3b0fd1bc09a21c8bb66bbf481a7b6769959b1b3b2cbc18fbce434f2ea7f648a4dbdbf180003b0cc77036410be7f246e827ace0ed459d9b" + 'responseCode=65548&responseMessage=DB+ERROR&responseStatus=2&xref=16050317BX02HT10NH49ZRS&merchantID=103191&action=CANCEL&state=finished&remoteAddress=107.15.253.186&requestMerchantID=103191&processMerchantID=103191&timestamp=2016-05-03+17%3A02%3A10&signature=73d3ea59f106208fdf3b0fd1bc09a21c8bb66bbf481a7b6769959b1b3b2cbc18fbce434f2ea7f648a4dbdbf180003b0cc77036410be7f246e827ace0ed459d9b' end def successful_reference_purchase_response - "merchantID=103191&threeDSEnabled=Y&threeDSCheckPref=authenticated&avscv2CheckEnabled=N&addressCheckPref=not+known%2Cnot+checked%2Cmatched%2Cnot+matched%2Cpartially+matched&postcodeCheckPref=not+known%2Cnot+checked%2Cmatched%2Cnot+matched%2Cpartially+matched&customerReceiptsRequired=N&eReceiptsEnabled=N&eReceiptsStoreID=1&amount=142&currencyCode=826&transactionUnique=1f21b6d2fdf1f13378705707bc7e24bd&orderRef=AM+test+purchase&type=1&threeDSRequired=N&countryCode=826&action=SALE&responseCode=0&responseMessage=AUTHCODE%3A300382&state=captured&remoteAddress=107.15.253.186&requestMerchantID=103191&processMerchantID=103191&cardNumberMask=492942%2A%2A%2A%2A%2A%2A0821&cardExpiryMonth=12&cardExpiryYear=14&customerName=Longbob+Longsen&customerAddress=Flat+6%2C+Primrose+Rise+347+Lavender+Road&customerPostcode=NN17+8YG&previousID=10886746&cardCVVMandatory=N&xref=16040515PS17RG20GT73SBF&cardExpiryDate=1214&authorisationCode=300382&transactionID=10886747&responseStatus=0&timestamp=2016-04-05+15%3A17%3A20&amountReceived=142&avscv2ResponseCode=422100&avscv2ResponseMessage=ADDRESS+MATCH+ONLY&avscv2AuthEntity=merchant+host&cv2Check=not+matched&addressCheck=matched&postcodeCheck=matched&cardType=Visa+Credit&cardTypeCode=VC&cardScheme=Visa+&cardSchemeCode=VC&cardIssuer=BARCLAYS+BANK+PLC&cardIssuerCountry=United+Kingdom&cardIssuerCountryCode=GBR&vcsResponseCode=0&vcsResponseMessage=Success+-+no+velocity+check+rules+applied&currencyExponent=2&signature=9e13f5ffd9cf94215225ab60f80915879a242dcf8c30c7f39a0265acf0f3f7186cbea656d53fcce249e54f522050efd32e677726fc7d5aa1f7b6ee746e040956" + 'merchantID=103191&threeDSEnabled=Y&threeDSCheckPref=authenticated&avscv2CheckEnabled=N&addressCheckPref=not+known%2Cnot+checked%2Cmatched%2Cnot+matched%2Cpartially+matched&postcodeCheckPref=not+known%2Cnot+checked%2Cmatched%2Cnot+matched%2Cpartially+matched&customerReceiptsRequired=N&eReceiptsEnabled=N&eReceiptsStoreID=1&amount=142&currencyCode=826&transactionUnique=1f21b6d2fdf1f13378705707bc7e24bd&orderRef=AM+test+purchase&type=1&threeDSRequired=N&countryCode=826&action=SALE&responseCode=0&responseMessage=AUTHCODE%3A300382&state=captured&remoteAddress=107.15.253.186&requestMerchantID=103191&processMerchantID=103191&cardNumberMask=492942%2A%2A%2A%2A%2A%2A0821&cardExpiryMonth=12&cardExpiryYear=14&customerName=Longbob+Longsen&customerAddress=Flat+6%2C+Primrose+Rise+347+Lavender+Road&customerPostcode=NN17+8YG&previousID=10886746&cardCVVMandatory=N&xref=16040515PS17RG20GT73SBF&cardExpiryDate=1214&authorisationCode=300382&transactionID=10886747&responseStatus=0&timestamp=2016-04-05+15%3A17%3A20&amountReceived=142&avscv2ResponseCode=422100&avscv2ResponseMessage=ADDRESS+MATCH+ONLY&avscv2AuthEntity=merchant+host&cv2Check=not+matched&addressCheck=matched&postcodeCheck=matched&cardType=Visa+Credit&cardTypeCode=VC&cardScheme=Visa+&cardSchemeCode=VC&cardIssuer=BARCLAYS+BANK+PLC&cardIssuerCountry=United+Kingdom&cardIssuerCountryCode=GBR&vcsResponseCode=0&vcsResponseMessage=Success+-+no+velocity+check+rules+applied&currencyExponent=2&signature=9e13f5ffd9cf94215225ab60f80915879a242dcf8c30c7f39a0265acf0f3f7186cbea656d53fcce249e54f522050efd32e677726fc7d5aa1f7b6ee746e040956' end def failed_reference_purchase_response - "responseCode=65548&responseMessage=DB+ERROR&responseStatus=2&amount=142&currencyCode=826&transactionUnique=740290de68c10d18acabe9fb0a52bd92&orderRef=AM+test+purchase&type=1&threeDSRequired=N&xref=16040515NM21GM43SF71MMR&countryCode=GB&merchantID=103191&action=SALE&state=finished&remoteAddress=107.15.253.186&requestMerchantID=103191&processMerchantID=103191&transactionID=10886787&timestamp=2016-04-05+15%3A21%3A43&vcsResponseCode=0&vcsResponseMessage=Success+-+no+velocity+check+rules+applied&signature=311f2bfd94c3807fae4fbeff13801c37d81c3e1082c5d3c5893281f18d7152b96420fa7b45285eb692b09b576b3b85d894ee35ff9e31cd06ace54019b806550f" + 'responseCode=65548&responseMessage=DB+ERROR&responseStatus=2&amount=142&currencyCode=826&transactionUnique=740290de68c10d18acabe9fb0a52bd92&orderRef=AM+test+purchase&type=1&threeDSRequired=N&xref=16040515NM21GM43SF71MMR&countryCode=GB&merchantID=103191&action=SALE&state=finished&remoteAddress=107.15.253.186&requestMerchantID=103191&processMerchantID=103191&transactionID=10886787&timestamp=2016-04-05+15%3A21%3A43&vcsResponseCode=0&vcsResponseMessage=Success+-+no+velocity+check+rules+applied&signature=311f2bfd94c3807fae4fbeff13801c37d81c3e1082c5d3c5893281f18d7152b96420fa7b45285eb692b09b576b3b85d894ee35ff9e31cd06ace54019b806550f' end def transcript @@ -308,7 +347,7 @@ def transcript end def scrubbed_transcript - <<-eos + <<-eos POST /direct/ HTTP/1.1\r\nContent-Type: application/x-www-form-urlencoded\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nAccept: */*\r\nUser-Agent: Ruby\r\nConnection: close\r\nHost: gateway.cardstream.com\r\nContent-Length: 501\r\n\r\n" amount=&currencyCode=826&transactionUnique=a017ca2ac0569188517ad8368c36a06d&orderRef=AM+test+purchase&customerName=Longbob+Longsen&cardNumber=[FILTERED]&cardExpiryMonth=12&cardExpiryYear=14&cardCVV=[FILTERED]&customerAddress=Flat+6%2C+Primrose+Rise+347+Lavender+Road&customerPostCode=NN17+8YG+&merchantID=102922&action=SALE&type=1&countryCode=GB&threeDSRequired=N&signature=970b3fe099a85c9922a79af46c2cb798616b9fbd044a921ac5eb46cd1907a5e89b8c720aae59c7eb1d81a59563f209d5db51aa3c270838199f2bfdcbe2c1149d eos diff --git a/test/unit/gateways/cardknox_test.rb b/test/unit/gateways/cardknox_test.rb index fef7402a53a..bc10d5e0e70 100644 --- a/test/unit/gateways/cardknox_test.rb +++ b/test/unit/gateways/cardknox_test.rb @@ -15,7 +15,7 @@ def setup def test_successful_purchase_passing_extra_info response = stub_comms do - @gateway.purchase(@amount, @credit_card, @options.merge(order_id: "1337", description: "socool")) + @gateway.purchase(@amount, @credit_card, @options.merge(order_id: '1337', description: 'socool')) end.check_request do |endpoint, data, headers| assert_match(/xOrderID=1337/, data) assert_match(/xDescription=socool/, data) @@ -38,10 +38,10 @@ def test_cvv_result end def test_add_track_data_with_creditcard - @credit_card.track_data = "data" + @credit_card.track_data = 'data' @gateway.expects(:ssl_post).with do |_, body| - body.include?("xMagstripe=data") + body.include?('xMagstripe=data') end.returns(successful_purchase_response) assert response = @gateway.purchase(@amount, @credit_card, @options) @@ -49,11 +49,11 @@ def test_add_track_data_with_creditcard end def test_add_track_data_with_empty_data - ["", nil].each do |data| + ['', nil].each do |data| @credit_card.track_data = data @gateway.expects(:ssl_post).with do |_, body| - refute body.include? "xMagstripe=" + refute body.include? 'xMagstripe=' body end.returns(successful_purchase_response) @@ -67,10 +67,8 @@ def test_manual_entry_is_properly_indicated_on_purchase response = stub_comms do @gateway.purchase(@amount, @credit_card, @options) end.check_request do |endpoint, data, headers| - assert_match %r{xCardNum=4242424242424242}, data assert_match %r{xCardPresent=true}, data - end.respond_with(successful_purchase_response) assert_success response @@ -81,7 +79,7 @@ def test_ip_is_being_sent # failed data =~ /xIP=123.123.123.123/ end.returns(successful_purchase_response) - @options[:ip] = "123.123.123.123" + @options[:ip] = '123.123.123.123' @gateway.purchase(@amount, @credit_card, @options) end @@ -203,54 +201,54 @@ def test_scrub private def purchase_request - "xKey=api_key&xVersion=4.5.4&xSoftwareName=Active+Merchant&xSoftwareVersion=1.52.0&xCommand=cc%3Asale&xAmount=1.00&xCardNum=4242424242424242&xCVV=123&xExp=0916&xName=Longbob+Longsen&xBillFirstName=Longbob&xBillLastName=Longsen&xBillCompany=Widgets+Inc&xBillStreet=456+My+Street&xBillStreet2=Apt+1&xBillCity=Ottawa&xBillState=ON&xBillZip=K1C2N6&xBillCountry=CA&xBillPhone=%28555%29555-5555&xShipFirstName=Longbob&xShipLastName=Longsen&xShipCompany=Widgets+Inc&xShipStreet=456+My+Street&xShipStreet2=Apt+1&xShipCity=Ottawa&xShipState=ON&xShipZip=K1C2N6&xShipCountry=CA&xShipPhone=%28555%29555-5555&xStreet=456+My+Street&xZip=K1C2N6" + 'xKey=api_key&xVersion=4.5.4&xSoftwareName=Active+Merchant&xSoftwareVersion=1.52.0&xCommand=cc%3Asale&xAmount=1.00&xCardNum=4242424242424242&xCVV=123&xExp=0916&xName=Longbob+Longsen&xBillFirstName=Longbob&xBillLastName=Longsen&xBillCompany=Widgets+Inc&xBillStreet=456+My+Street&xBillStreet2=Apt+1&xBillCity=Ottawa&xBillState=ON&xBillZip=K1C2N6&xBillCountry=CA&xBillPhone=%28555%29555-5555&xShipFirstName=Longbob&xShipLastName=Longsen&xShipCompany=Widgets+Inc&xShipStreet=456+My+Street&xShipStreet2=Apt+1&xShipCity=Ottawa&xShipState=ON&xShipZip=K1C2N6&xShipCountry=CA&xShipPhone=%28555%29555-5555&xStreet=456+My+Street&xZip=K1C2N6' end def successful_purchase_response # passed avs and cvv - "xResult=A&xStatus=Approved&xError=&xRefNum=16268727&xAuthCode=230809&xBatch=347&xAvsResultCode=YYY&xAvsResult=Address%3a+Match+%26+5+Digit+Zip%3a+Match&xCvvResultCode=M&xCvvResult=Match&xAuthAmount=4.38&xToken=f0b84a5b181749b4b0d77f6291a753ab&xMaskedCardNumber=4xxxxxxxxxxx2224&xName=Longbob+Longsen" + 'xResult=A&xStatus=Approved&xError=&xRefNum=16268727&xAuthCode=230809&xBatch=347&xAvsResultCode=YYY&xAvsResult=Address%3a+Match+%26+5+Digit+Zip%3a+Match&xCvvResultCode=M&xCvvResult=Match&xAuthAmount=4.38&xToken=f0b84a5b181749b4b0d77f6291a753ab&xMaskedCardNumber=4xxxxxxxxxxx2224&xName=Longbob+Longsen' end def failed_purchase_response - "xResult=D&xStatus=Declined&xError=Invalid+CVV&xRefNum=15307128&xAuthCode=&xBatch=&xAvsResultCode=NNN&xAvsResult=Address%3a+No+Match+%26+5+Digit+Zip%3a+No+Match&xCvvResultCode=N&xCvvResult=No+Match&xToken=8138747e41894071a353318541d2ee8c" + 'xResult=D&xStatus=Declined&xError=Invalid+CVV&xRefNum=15307128&xAuthCode=&xBatch=&xAvsResultCode=NNN&xAvsResult=Address%3a+No+Match+%26+5+Digit+Zip%3a+No+Match&xCvvResultCode=N&xCvvResult=No+Match&xToken=8138747e41894071a353318541d2ee8c' end def successful_authorize_response - "xResult=A&xStatus=Approved&xError=&xRefNum=15312316&xAuthCode=630421&xBatch=&xAvsResultCode=NNN&xAvsResult=Address%3a+No+Match+%26+5+Digit+Zip%3a+No+Match&xCvvResultCode=N&xCvvResult=No+Match&xAuthAmount=2.06&xToken=62d4fd9aebd240659d68ffaa156d1788&xMaskedCardNumber=4xxxxxxxxxxx2224&xName=Longbob+Longsen" + 'xResult=A&xStatus=Approved&xError=&xRefNum=15312316&xAuthCode=630421&xBatch=&xAvsResultCode=NNN&xAvsResult=Address%3a+No+Match+%26+5+Digit+Zip%3a+No+Match&xCvvResultCode=N&xCvvResult=No+Match&xAuthAmount=2.06&xToken=62d4fd9aebd240659d68ffaa156d1788&xMaskedCardNumber=4xxxxxxxxxxx2224&xName=Longbob+Longsen' end def failed_authorize_response - "xResult=D&xStatus=Declined&xError=Invalid+CVV&xRefNum=15307290&xAuthCode=&xBatch=&xAvsResultCode=NNN&xAvsResult=Address%3a+No+Match+%26+5+Digit+Zip%3a+No+Match&xCvvResultCode=N&xCvvResult=No+Match&xToken=065751a8a28e468a8d79cb98c04cf350" + 'xResult=D&xStatus=Declined&xError=Invalid+CVV&xRefNum=15307290&xAuthCode=&xBatch=&xAvsResultCode=NNN&xAvsResult=Address%3a+No+Match+%26+5+Digit+Zip%3a+No+Match&xCvvResultCode=N&xCvvResult=No+Match&xToken=065751a8a28e468a8d79cb98c04cf350' end def successful_capture_response - "xResult=A&xStatus=Approved&xError=&xRefNum=15312316&xRefNumCurrent=15312319&xAuthCode=&xBatch=321&xAvsResultCode=&xAvsResult=Unmapped+AVS+response&xCvvResultCode=&xCvvResult=No+CVV+data+available&xAuthAmount=2.06&xToken=f9097326fb1c4976a6da75ccb872f28a&xMaskedCardNumber=4xxxxxxxxxxx2224&xName=Longbob+Longsen" + 'xResult=A&xStatus=Approved&xError=&xRefNum=15312316&xRefNumCurrent=15312319&xAuthCode=&xBatch=321&xAvsResultCode=&xAvsResult=Unmapped+AVS+response&xCvvResultCode=&xCvvResult=No+CVV+data+available&xAuthAmount=2.06&xToken=f9097326fb1c4976a6da75ccb872f28a&xMaskedCardNumber=4xxxxxxxxxxx2224&xName=Longbob+Longsen' end def failed_capture_response - "xResult=E&xStatus=Error&xAuthCode=000000&xError=Original+transaction+not+specified&xRefNum=15307619&xErrorCode=00000" + 'xResult=E&xStatus=Error&xAuthCode=000000&xError=Original+transaction+not+specified&xRefNum=15307619&xErrorCode=00000' end def successful_credit_card_refund_response end def failed_credit_card_refund_response - "xResult=D&xStatus=Declined&xError=UNSUPPORTED+CARD+TYPE&xRefNum=15308026&xAuthCode=&xBatch=&xAvsResultCode=&xAvsResult=Unmapped+AVS+response&xCvvResultCode=&xCvvResult=No+CVV+data+available" + 'xResult=D&xStatus=Declined&xError=UNSUPPORTED+CARD+TYPE&xRefNum=15308026&xAuthCode=&xBatch=&xAvsResultCode=&xAvsResult=Unmapped+AVS+response&xCvvResultCode=&xCvvResult=No+CVV+data+available' end def successful_check_refund_response - "xResult=A&xStatus=Approved&xError=&xRefNum=16274604" + 'xResult=A&xStatus=Approved&xError=&xRefNum=16274604' end def failed_check_refund_response - "xResult=D&xStatus=Declined&xError=&xRefNum=16274604" + 'xResult=D&xStatus=Declined&xError=&xRefNum=16274604' end def successful_void_response - "xResult=A&xStatus=Approved&xError=&xRefNum=15308171&xRefNumCurrent=15308172&xAuthCode=912013&xBatch=&xAvsResultCode=&xAvsResult=Unmapped+AVS+response&xCvvResultCode=&xCvvResult=No+CVV+data+available&xAuthAmount=2.33&xMaskedCardNumber=4xxxxxxxxxxx2224&xName=Longbob+Longsen" + 'xResult=A&xStatus=Approved&xError=&xRefNum=15308171&xRefNumCurrent=15308172&xAuthCode=912013&xBatch=&xAvsResultCode=&xAvsResult=Unmapped+AVS+response&xCvvResultCode=&xCvvResult=No+CVV+data+available&xAuthAmount=2.33&xMaskedCardNumber=4xxxxxxxxxxx2224&xName=Longbob+Longsen' end def failed_void_response - "xResult=E&xStatus=Error&xAuthCode=000000&xError=Original+transaction+not+specified&xRefNum=15308297&xErrorCode=00000" + 'xResult=E&xStatus=Error&xAuthCode=000000&xError=Original+transaction+not+specified&xRefNum=15308297&xErrorCode=00000' end def successful_check_refund_void @@ -258,18 +256,18 @@ def successful_check_refund_void end def successful_verify_response - "xResult=A&xStatus=Approved&xError=&xRefNum=15314566&xAuthCode=608755&xBatch=&xAvsResultCode=NNN&xAvsResult=Address%3a+No+Match+%26+5+Digit+Zip%3a+No+Match&xCvvResultCode=N&xCvvResult=No+Match&xAuthAmount=1.00&xToken=09dc51aceb98440fbf0847cad2941d45&xMaskedCardNumber=4xxxxxxxxxxx2224&xName=Longbob+Longsen" + 'xResult=A&xStatus=Approved&xError=&xRefNum=15314566&xAuthCode=608755&xBatch=&xAvsResultCode=NNN&xAvsResult=Address%3a+No+Match+%26+5+Digit+Zip%3a+No+Match&xCvvResultCode=N&xCvvResult=No+Match&xAuthAmount=1.00&xToken=09dc51aceb98440fbf0847cad2941d45&xMaskedCardNumber=4xxxxxxxxxxx2224&xName=Longbob+Longsen' end def failed_verify_response - "xResult=D&xStatus=Declined&xError=Invalid+CVV&xRefNum=15310681&xAuthCode=&xBatch=&xAvsResultCode=NNN&xAvsResult=Address%3a+No+Match+%26+5+Digit+Zip%3a+No+Match&xCvvResultCode=N&xCvvResult=No+Match&xToken=748df69e22f142d4aab296328d4f2653" + 'xResult=D&xStatus=Declined&xError=Invalid+CVV&xRefNum=15310681&xAuthCode=&xBatch=&xAvsResultCode=NNN&xAvsResult=Address%3a+No+Match+%26+5+Digit+Zip%3a+No+Match&xCvvResultCode=N&xCvvResult=No+Match&xToken=748df69e22f142d4aab296328d4f2653' end def pre_scrubbed - "xKey=api_key&xVersion=4.5.4&xSoftwareName=Active+Merchant&xSoftwareVersion=1.52.0&xCommand=cc%3Asale&xAmount=1.00&xCardNum=4242424242424242&xCVV=123&xExp=0916&xName=Longbob+Longsen&xBillFirstName=Longbob&xBillLastName=Longsen&xBillCompany=Widgets+Inc&xBillStreet=456+My+Street&xBillStreet2=Apt+1&xBillCity=Ottawa&xBillState=ON&xBillZip=K1C2N6&xBillCountry=CA&xBillPhone=%28555%29555-5555&xShipFirstName=Longbob&xShipLastName=Longsen&xShipCompany=Widgets+Inc&xShipStreet=456+My+Street&xShipStreet2=Apt+1&xShipCity=Ottawa&xShipState=ON&xShipZip=K1C2N6&xShipCountry=CA&xShipPhone=%28555%29555-5555&xStreet=456+My+Street&xZip=K1C2N6" + 'xKey=api_key&xVersion=4.5.4&xSoftwareName=Active+Merchant&xSoftwareVersion=1.52.0&xCommand=cc%3Asale&xAmount=1.00&xCardNum=4242424242424242&xCVV=123&xExp=0916&xName=Longbob+Longsen&xBillFirstName=Longbob&xBillLastName=Longsen&xBillCompany=Widgets+Inc&xBillStreet=456+My+Street&xBillStreet2=Apt+1&xBillCity=Ottawa&xBillState=ON&xBillZip=K1C2N6&xBillCountry=CA&xBillPhone=%28555%29555-5555&xShipFirstName=Longbob&xShipLastName=Longsen&xShipCompany=Widgets+Inc&xShipStreet=456+My+Street&xShipStreet2=Apt+1&xShipCity=Ottawa&xShipState=ON&xShipZip=K1C2N6&xShipCountry=CA&xShipPhone=%28555%29555-5555&xStreet=456+My+Street&xZip=K1C2N6' end def post_scrubbed - "xKey=[FILTERED]&xVersion=4.5.4&xSoftwareName=Active+Merchant&xSoftwareVersion=1.52.0&xCommand=cc%3Asale&xAmount=1.00&xCardNum=[FILTERED]&xCVV=[FILTERED]&xExp=0916&xName=Longbob+Longsen&xBillFirstName=Longbob&xBillLastName=Longsen&xBillCompany=Widgets+Inc&xBillStreet=456+My+Street&xBillStreet2=Apt+1&xBillCity=Ottawa&xBillState=ON&xBillZip=K1C2N6&xBillCountry=CA&xBillPhone=%28555%29555-5555&xShipFirstName=Longbob&xShipLastName=Longsen&xShipCompany=Widgets+Inc&xShipStreet=456+My+Street&xShipStreet2=Apt+1&xShipCity=Ottawa&xShipState=ON&xShipZip=K1C2N6&xShipCountry=CA&xShipPhone=%28555%29555-5555&xStreet=456+My+Street&xZip=K1C2N6" + 'xKey=[FILTERED]&xVersion=4.5.4&xSoftwareName=Active+Merchant&xSoftwareVersion=1.52.0&xCommand=cc%3Asale&xAmount=1.00&xCardNum=[FILTERED]&xCVV=[FILTERED]&xExp=0916&xName=Longbob+Longsen&xBillFirstName=Longbob&xBillLastName=Longsen&xBillCompany=Widgets+Inc&xBillStreet=456+My+Street&xBillStreet2=Apt+1&xBillCity=Ottawa&xBillState=ON&xBillZip=K1C2N6&xBillCountry=CA&xBillPhone=%28555%29555-5555&xShipFirstName=Longbob&xShipLastName=Longsen&xShipCompany=Widgets+Inc&xShipStreet=456+My+Street&xShipStreet2=Apt+1&xShipCity=Ottawa&xShipState=ON&xShipZip=K1C2N6&xShipCountry=CA&xShipPhone=%28555%29555-5555&xStreet=456+My+Street&xZip=K1C2N6' end end diff --git a/test/unit/gateways/cardprocess_test.rb b/test/unit/gateways/cardprocess_test.rb new file mode 100644 index 00000000000..5377cd16c73 --- /dev/null +++ b/test/unit/gateways/cardprocess_test.rb @@ -0,0 +1,280 @@ +require 'test_helper' + +class CardprocessTest < Test::Unit::TestCase + def setup + @gateway = CardprocessGateway.new(user_id: 'login', password: 'password', entity_id: '123') + @credit_card = credit_card + @amount = 100 + + @options = { + order_id: '1', + billing_address: address, + description: 'Store Purchase' + } + end + + def test_successful_purchase + @gateway.expects(:ssl_post).returns(successful_purchase_response) + + response = @gateway.purchase(@amount, @credit_card, @options) + assert_success response + + assert_equal '8a8294495fe8084a016002dd17c163fd', response.authorization + assert_equal 'DB', response.params['paymentType'] + assert response.test? + end + + def test_failed_purchase + @gateway.expects(:ssl_post).returns(failed_purchase_response) + + response = @gateway.purchase(@amount, @credit_card, @options) + assert_failure response + assert_equal Gateway::STANDARD_ERROR_CODE[:incorrect_number], response.error_code + end + + def test_successful_authorize + @gateway.expects(:ssl_post).returns(successful_authorize_response) + + response = @gateway.authorize(@amount, @credit_card, @options) + assert_success response + + assert_equal '8a82944a5fe82704016002caa42c14f8', response.authorization + assert_equal 'PA', response.params['paymentType'] + assert response.test? + end + + def test_failed_authorize + @gateway.expects(:ssl_post).returns(failed_authorize_response) + + response = @gateway.authorize(@amount, @credit_card, @options) + assert_failure response + assert_equal 'PA', response.params['paymentType'] + assert response.test? + end + + def test_successful_capture + @gateway.expects(:ssl_post).returns(successful_capture_response) + + response = @gateway.capture(@amount, '123', @options) + assert_success response + + assert_equal '8a82944a5fe82704016002caa7cd1513', response.authorization + assert_equal 'CP', response.params['paymentType'] + assert response.test? + end + + def test_failed_capture + @gateway.expects(:ssl_post).returns(failed_capture_response) + + response = @gateway.capture(@amount, '123', @options) + assert_failure response + assert response.test? + end + + def test_successful_refund + @gateway.expects(:ssl_post).returns(successful_refund_response) + + response = @gateway.refund(@amount, '123', @options) + assert_success response + + assert_equal '8a82944a5fe82704016002cc88f61731', response.authorization + assert_equal 'RF', response.params['paymentType'] + assert response.test? + end + + def test_failed_refund + @gateway.expects(:ssl_post).returns(failed_refund_response) + + response = @gateway.refund(@amount, '123', @options) + assert_failure response + end + + def test_successful_void + @gateway.expects(:ssl_post).returns(successful_void_response) + + response = @gateway.void('123') + assert_success response + + assert_equal '8a8294495fe8084a016002cc489446d6', response.authorization + assert_equal 'RV', response.params['paymentType'] + assert response.test? + end + + def test_failed_void + @gateway.expects(:ssl_post).returns(failed_void_response) + + response = @gateway.void('123') + assert_failure response + end + + def test_successful_verify + @gateway.stubs(:ssl_post).returns(successful_authorize_response, successful_capture_response) + + response = @gateway.verify(@credit_card, @options) + assert_success response + assert response.test? + end + + def test_successful_verify_with_failed_void + @gateway.stubs(:ssl_post).returns(successful_authorize_response, failed_void_response) + + response = @gateway.verify(@credit_card, @options) + assert_failure response + assert response.test? + end + + def test_failed_verify + @gateway.expects(:ssl_post).returns(failed_authorize_response) + + response = @gateway.verify(@credit_card, @options) + assert_failure response + assert response.test? + end + + def test_general_credit + @gateway.expects(:ssl_post).returns(successful_credit_response) + + response = @gateway.credit(@amount, @credit_card, @options) + assert_success response + + assert_equal '8a8294495fe8084a01600332a83d4899', response.authorization + assert_equal 'CD', response.params['paymentType'] + assert response.test? + end + + def test_scrub + assert @gateway.supports_scrubbing? + assert_equal @gateway.scrub(pre_scrubbed), post_scrubbed + end + + def test_error_code_parsing + codes = { + '000.000.000' => nil, + '100.100.101' => :incorrect_number, + '100.100.303' => :expired_card, + '100.100.305' => :invalid_expiry_date, + '100.100.600' => :invalid_cvc, + '200.222.222' => :config_error, + '700.777.777' => :config_error, + '800.800.101' => :card_declined, + '800.800.102' => :incorrect_address, + '800.800.302' => :incorrect_address, + '800.800.150' => :card_declined, + '800.100.151' => :invalid_number, + '800.100.152' => :card_declined, + '800.100.153' => :incorrect_cvc, + '800.100.154' => :card_declined, + '800.800.202' => :invalid_zip + } + codes.each_pair do |code, key| + response = {'result' => {'code' => code}} + assert_equal Gateway::STANDARD_ERROR_CODE[key], @gateway.send(:error_code_from, response), "expecting #{code} => #{key}" + end + end + + private + + def pre_scrubbed + %q( +opening connection to test.vr-pay-ecommerce.de:443... +opened +starting SSL for test.vr-pay-ecommerce.de:443... +SSL established +<- "POST /v1/payments HTTP/1.1\r\nContent-Type: application/x-www-form-urlencoded\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nAccept: */*\r\nUser-Agent: Ruby\r\nConnection: close\r\nHost: test.vr-pay-ecommerce.de\r\nContent-Length: 447\r\n\r\n" +<- "amount=1.00&currency=EUR&paymentBrand=VISA&card.number=4200000000000000&card.holder=Longbob+Longsen&card.expiryMonth=09&card.expiryYear=2018&card.cvv=123&billing.street1=456+My+Street&billing.street2=Apt+1&billing.city=Ottawa&billing.state=ON&billing.postcode=K1C2N6&billing.country=CA&authentication.userId=8a8294174e735d0c014e78beb6c5154f&authentication.password=cTZjAm9c87&authentication.entityId=8a8294174e735d0c014e78beb6b9154b&paymentType=DB" +-> "HTTP/1.1 200 OK\r\n" +-> "Date: Mon, 27 Nov 2017 21:40:52 GMT\r\n" +-> "Server: Apache-Coyote/1.1\r\n" +-> "Strict-Transport-Security: max-age=63072000; includeSubdomains; preload\r\n" +-> "X-Content-Type-Options: nosniff\r\n" +-> "X-XSS-Protection: 1; mode=block\r\n" +-> "Access-Control-Allow-Origin: *\r\n" +-> "Access-Control-Allow-Credentials: true\r\n" +-> "X-Application-WAF-Action: allow\r\n" +-> "Content-Type: application/json;charset=UTF-8\r\n" +-> "Content-Length: 725\r\n" +-> "X-Content-Type-Options: nosniff\r\n" +-> "Connection: close\r\n" +-> "\r\n" +reading 725 bytes... +-> "" +-> "{\"id\":\"8a82944a5fe82704015fff6cf5e572b4\",\"paymentType\":\"DB\",\"paymentBrand\":\"VISA\",\"amount\":\"1.00\",\"currency\":\"EUR\",\"descriptor\":\"5901.3583.3250 OPP_Channel \",\"result\":{\"code\":\"000.100.110\",\"description\":\"Request successfully processed in 'Merchant in Integrator Test Mode'\"},\"card\":{\"bin\":\"420000\",\"last4Digits\":\"0000\",\"holder\":\"Longbob Longsen\",\"expiryMonth\":\"09\",\"expiryYear\":\"2018\"},\"billing\":{\"street1\":\"456 My Street\",\"street2\":\"Apt 1\",\"city\":\"Ottawa\",\"state\":\"ON\",\"postcode\":\"K1C2N6\",\"country\":\"CA\"},\"risk\":{\"score\":\"100\"},\"buildNumber\":\"a89317e58e01406de09ff75de6c962f2365f66e9@2017-11-27 15:38:09 +0000\",\"timestamp\":\"2017-11-27 21:40:51+0000\",\"ndc\":\"8a8294174e735d0c014e78beb6b9154b_24979bbf8c3a424cbd25e59860bb5417\"}" +read 725 bytes +Conn close + ) + end + + def post_scrubbed + %q( +opening connection to test.vr-pay-ecommerce.de:443... +opened +starting SSL for test.vr-pay-ecommerce.de:443... +SSL established +<- "POST /v1/payments HTTP/1.1\r\nContent-Type: application/x-www-form-urlencoded\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nAccept: */*\r\nUser-Agent: Ruby\r\nConnection: close\r\nHost: test.vr-pay-ecommerce.de\r\nContent-Length: 447\r\n\r\n" +<- "amount=1.00&currency=EUR&paymentBrand=VISA&card.number=[FILTERED]&card.holder=Longbob+Longsen&card.expiryMonth=09&card.expiryYear=2018&card.cvv=[FILTERED]&billing.street1=456+My+Street&billing.street2=Apt+1&billing.city=Ottawa&billing.state=ON&billing.postcode=K1C2N6&billing.country=CA&authentication.userId=[FILTERED]&authentication.password=[FILTERED]&authentication.entityId=[FILTERED]&paymentType=DB" +-> "HTTP/1.1 200 OK\r\n" +-> "Date: Mon, 27 Nov 2017 21:40:52 GMT\r\n" +-> "Server: Apache-Coyote/1.1\r\n" +-> "Strict-Transport-Security: max-age=63072000; includeSubdomains; preload\r\n" +-> "X-Content-Type-Options: nosniff\r\n" +-> "X-XSS-Protection: 1; mode=block\r\n" +-> "Access-Control-Allow-Origin: *\r\n" +-> "Access-Control-Allow-Credentials: true\r\n" +-> "X-Application-WAF-Action: allow\r\n" +-> "Content-Type: application/json;charset=UTF-8\r\n" +-> "Content-Length: 725\r\n" +-> "X-Content-Type-Options: nosniff\r\n" +-> "Connection: close\r\n" +-> "\r\n" +reading 725 bytes... +-> "" +-> "{\"id\":\"8a82944a5fe82704015fff6cf5e572b4\",\"paymentType\":\"DB\",\"paymentBrand\":\"VISA\",\"amount\":\"1.00\",\"currency\":\"EUR\",\"descriptor\":\"5901.3583.3250 OPP_Channel \",\"result\":{\"code\":\"000.100.110\",\"description\":\"Request successfully processed in 'Merchant in Integrator Test Mode'\"},\"card\":{\"bin\":\"420000\",\"last4Digits\":\"0000\",\"holder\":\"Longbob Longsen\",\"expiryMonth\":\"09\",\"expiryYear\":\"2018\"},\"billing\":{\"street1\":\"456 My Street\",\"street2\":\"Apt 1\",\"city\":\"Ottawa\",\"state\":\"ON\",\"postcode\":\"K1C2N6\",\"country\":\"CA\"},\"risk\":{\"score\":\"100\"},\"buildNumber\":\"a89317e58e01406de09ff75de6c962f2365f66e9@2017-11-27 15:38:09 +0000\",\"timestamp\":\"2017-11-27 21:40:51+0000\",\"ndc\":\"8a8294174e735d0c014e78beb6b9154b_24979bbf8c3a424cbd25e59860bb5417\"}" +read 725 bytes +Conn close + ) + end + + def successful_purchase_response + "{\"id\":\"8a8294495fe8084a016002dd17c163fd\",\"paymentType\":\"DB\",\"paymentBrand\":\"VISA\",\"amount\":\"1.00\",\"currency\":\"EUR\",\"descriptor\":\"0177.7272.0802 OPP_Channel \",\"result\":{\"code\":\"000.100.110\",\"description\":\"Request successfully processed in 'Merchant in Integrator Test Mode'\"},\"card\":{\"bin\":\"420000\",\"last4Digits\":\"0000\",\"holder\":\"Longbob Longsen\",\"expiryMonth\":\"09\",\"expiryYear\":\"2018\"},\"billing\":{\"street1\":\"456 My Street\",\"street2\":\"Apt 1\",\"city\":\"Ottawa\",\"state\":\"ON\",\"postcode\":\"K1C2N6\",\"country\":\"CA\"},\"risk\":{\"score\":\"100\"},\"buildNumber\":\"a89317e58e01406de09ff75de6c962f2365f66e9@2017-11-27 15:38:09 +0000\",\"timestamp\":\"2017-11-28 13:42:12+0000\",\"ndc\":\"8a8294174e735d0c014e78beb6b9154b_ed9f9af4170942719cf6e3446f823f45\"}" + end + + def failed_purchase_response + '{"id":"8a82944a5fe827040160030a3308412d","paymentType":"DB","paymentBrand":"VISA","result":{"code":"100.100.101","description":"invalid creditcard, bank account number or bank name"},"card":{"bin":"420000","last4Digits":"0001","holder":"Longbob Longsen","expiryMonth":"09","expiryYear":"2018"},"billing":{"street1":"456 My Street","street2":"Apt 1","city":"Ottawa","state":"ON","postcode":"K1C2N6","country":"CA"},"buildNumber":"a89317e58e01406de09ff75de6c962f2365f66e9@2017-11-27 15:38:09 +0000","timestamp":"2017-11-28 14:31:28+0000","ndc":"8a8294174e735d0c014e78beb6b9154b_43d463600f8d429ea6ac09cf25fd9f24"}' + end + + def successful_authorize_response + "{\"id\":\"8a82944a5fe82704016002caa42c14f8\",\"paymentType\":\"PA\",\"paymentBrand\":\"VISA\",\"amount\":\"1.00\",\"currency\":\"EUR\",\"descriptor\":\"8374.4038.5698 OPP_Channel \",\"result\":{\"code\":\"000.100.110\",\"description\":\"Request successfully processed in 'Merchant in Integrator Test Mode'\"},\"card\":{\"bin\":\"420000\",\"last4Digits\":\"0000\",\"holder\":\"Longbob Longsen\",\"expiryMonth\":\"09\",\"expiryYear\":\"2018\"},\"billing\":{\"street1\":\"456 My Street\",\"street2\":\"Apt 1\",\"city\":\"Ottawa\",\"state\":\"ON\",\"postcode\":\"K1C2N6\",\"country\":\"CA\"},\"risk\":{\"score\":\"100\"},\"buildNumber\":\"a89317e58e01406de09ff75de6c962f2365f66e9@2017-11-27 15:38:09 +0000\",\"timestamp\":\"2017-11-28 13:22:03+0000\",\"ndc\":\"8a8294174e735d0c014e78beb6b9154b_fc59650eafc84da29ce10e7171e71a34\"}" + end + + def failed_authorize_response + '{"paymentType":"PA","paymentBrand":"VISA","result":{"code":"800.100.151","description":"transaction declined (invalid card)"},"card":{"bin":"420000","last4Digits":"0000","holder":"Longbob Longsen","expiryMonth":"09","expiryYear":"2018"},"billing":{"street1":"456 My Street","street2":"Apt 1","city":"Ottawa","state":"ON","postcode":"K1C2N6","country":"CA"},"customParameters":{"forceResultCode":"800.100.151"},"buildNumber":"a89317e58e01406de09ff75de6c962f2365f66e9@2017-11-27 15:38:09 +0000","timestamp":"2017-11-28 13:50:31+0000","ndc":"8a8294174e735d0c014e78beb6b9154b_1077c67bc41048ff887da9ab9ee8b89d"}' + end + + def successful_capture_response + "{\"id\":\"8a82944a5fe82704016002caa7cd1513\",\"paymentType\":\"CP\",\"amount\":\"1.00\",\"currency\":\"EUR\",\"descriptor\":\"4938.4300.2018 OPP_Channel\",\"result\":{\"code\":\"000.100.110\",\"description\":\"Request successfully processed in 'Merchant in Integrator Test Mode'\"},\"risk\":{\"score\":\"0\"},\"buildNumber\":\"a89317e58e01406de09ff75de6c962f2365f66e9@2017-11-27 15:38:09 +0000\",\"timestamp\":\"2017-11-28 13:22:03+0000\",\"ndc\":\"8a8294174e735d0c014e78beb6b9154b_fb956c7668a04e18af61519693a1d114\"}" + end + + def failed_capture_response + '{"id":"8a82944a5fe8270401600313d3965bca","paymentType":"CP","result":{"code":"700.400.510","description":"capture needs at least one successful transaction of type (PA)"},"risk":{"score":"0"},"buildNumber":"a89317e58e01406de09ff75de6c962f2365f66e9@2017-11-27 15:38:09 +0000","timestamp":"2017-11-28 14:41:59+0000","ndc":"8a8294174e735d0c014e78beb6b9154b_8abfd898a6cd406f94181d9096607aea"}' + end + + def successful_refund_response + "{\"id\":\"8a82944a5fe82704016002cc88f61731\",\"paymentType\":\"RF\",\"amount\":\"1.00\",\"currency\":\"EUR\",\"descriptor\":\"3478.1411.3954 OPP_Channel\",\"result\":{\"code\":\"000.100.110\",\"description\":\"Request successfully processed in 'Merchant in Integrator Test Mode'\"},\"buildNumber\":\"a89317e58e01406de09ff75de6c962f2365f66e9@2017-11-27 15:38:09 +0000\",\"timestamp\":\"2017-11-28 13:24:07+0000\",\"ndc\":\"8a8294174e735d0c014e78beb6b9154b_99293f4fffe64105870e77b8e18c0c02\"}" + end + + def failed_refund_response + '{"result":{"code":"200.300.404","description":"invalid or missing parameter","parameterErrors":[{"name":"paymentType","value":"RF","message":"must be one of [PA, DB, CD, PA.CP]"},{"name":"paymentBrand","value":null,"message":"card properties must be set"}]},"buildNumber":"a89317e58e01406de09ff75de6c962f2365f66e9@2017-11-27 15:38:09 +0000","timestamp":"2017-11-28 14:33:31+0000","ndc":"8a8294174e735d0c014e78beb6b9154b_febee8f6863b4392b064b23602f3f382"}' + end + + def successful_void_response + "{\"id\":\"8a8294495fe8084a016002cc489446d6\",\"paymentType\":\"RV\",\"amount\":\"1.00\",\"currency\":\"EUR\",\"descriptor\":\"9673.6314.6402 OPP_Channel\",\"result\":{\"code\":\"000.100.110\",\"description\":\"Request successfully processed in 'Merchant in Integrator Test Mode'\"},\"risk\":{\"score\":\"0\"},\"buildNumber\":\"a89317e58e01406de09ff75de6c962f2365f66e9@2017-11-27 15:38:09 +0000\",\"timestamp\":\"2017-11-28 13:23:50+0000\",\"ndc\":\"8a8294174e735d0c014e78beb6b9154b_744a5416960a420da01edc3b3daf6c6f\"}" + end + + def failed_void_response + '{"result":{"code":"200.300.404","description":"invalid or missing parameter","parameterErrors":[{"name":"paymentBrand","value":null,"message":"card properties must be set"},{"name":"paymentType","value":"RV","message":"must be one of [PA, DB, CD, PA.CP]"},{"name":"amount","value":null,"message":"may not be empty"},{"name":"currency","value":null,"message":"may not be empty"}]},"buildNumber":"a89317e58e01406de09ff75de6c962f2365f66e9@2017-11-27 15:38:09 +0000","timestamp":"2017-11-28 14:34:50+0000","ndc":"8a8294174e735d0c014e78beb6b9154b_4a909e0b99214eb9b155b46a2c67df30"}' + end + + def successful_credit_response + "{\"id\":\"8a8294495fe8084a01600332a83d4899\",\"paymentType\":\"CD\",\"paymentBrand\":\"VISA\",\"amount\":\"1.00\",\"currency\":\"EUR\",\"descriptor\":\"2299.3739.4338 OPP_Channel \",\"result\":{\"code\":\"000.100.110\",\"description\":\"Request successfully processed in 'Merchant in Integrator Test Mode'\"},\"card\":{\"bin\":\"420000\",\"last4Digits\":\"0000\",\"holder\":\"Longbob Longsen\",\"expiryMonth\":\"09\",\"expiryYear\":\"2018\"},\"billing\":{\"street1\":\"456 My Street\",\"street2\":\"Apt 1\",\"city\":\"Ottawa\",\"state\":\"ON\",\"postcode\":\"K1C2N6\",\"country\":\"CA\"},\"risk\":{\"score\":\"100\"},\"buildNumber\":\"a89317e58e01406de09ff75de6c962f2365f66e9@2017-11-27 15:38:09 +0000\",\"timestamp\":\"2017-11-28 15:15:39+0000\",\"ndc\":\"8a8294174e735d0c014e78beb6b9154b_691783d2e7834e6eb8ca011f4fee1b74\"}" + end +end diff --git a/test/unit/gateways/cashnet_test.rb b/test/unit/gateways/cashnet_test.rb index 52ba6f8255c..844702eac9a 100644 --- a/test/unit/gateways/cashnet_test.rb +++ b/test/unit/gateways/cashnet_test.rb @@ -76,9 +76,9 @@ def test_add_creditcard def test_add_address result = {} - @gateway.send(:add_address, result, billing_address: {address1: '123 Test St.', address2: '5F', city: 'Testville', zip: '12345', state: 'AK'} ) + @gateway.send(:add_address, result, billing_address: {address1: '123 Test St.', address2: '5F', city: 'Testville', zip: '12345', state: 'AK'}) - assert_equal ["addr_g", "city_g", "state_g", "zip_g"], result.stringify_keys.keys.sort + assert_equal ['addr_g', 'city_g', 'state_g', 'zip_g'], result.stringify_keys.keys.sort assert_equal '123 Test St.,5F', result[:addr_g] assert_equal 'Testville', result[:city_g] assert_equal 'AK', result[:state_g] @@ -93,7 +93,7 @@ def test_add_customer_data def test_action_meets_minimum_requirements params = { - amount: "1.01", + amount: '1.01', } @gateway.send(:add_creditcard, params, @credit_card) @@ -124,7 +124,7 @@ def test_invalid_response end def test_passes_custcode_from_credentials - gateway = CashnetGateway.new(merchant: 'X', operator: 'X', password: 'test123', merchant_gateway_name: 'X', custcode: "TheCustCode") + gateway = CashnetGateway.new(merchant: 'X', operator: 'X', password: 'test123', merchant_gateway_name: 'X', custcode: 'TheCustCode') stub_comms(gateway, :ssl_request) do gateway.purchase(@amount, @credit_card, {}) end.check_request do |method, endpoint, data, headers| @@ -133,15 +133,21 @@ def test_passes_custcode_from_credentials end def test_allows_custcode_override - gateway = CashnetGateway.new(merchant: 'X', operator: 'X', password: 'test123', merchant_gateway_name: 'X', custcode: "TheCustCode") + gateway = CashnetGateway.new(merchant: 'X', operator: 'X', password: 'test123', merchant_gateway_name: 'X', custcode: 'TheCustCode') stub_comms(gateway, :ssl_request) do - gateway.purchase(@amount, @credit_card, custcode: "OveriddenCustCode") + gateway.purchase(@amount, @credit_card, custcode: 'OveriddenCustCode') end.check_request do |method, endpoint, data, headers| assert_match(/custcode=OveriddenCustCode/, data) end.respond_with(successful_purchase_response) end + def test_scrub + assert @gateway.supports_scrubbing? + assert_equal @gateway.scrub(pre_scrubbed), post_scrubbed + end + private + def expected_expiration_date '%02d%02d' % [@credit_card.month, @credit_card.year.to_s[2..4]] end @@ -151,22 +157,148 @@ def minimum_requirements end def successful_refund_response - "<cngateway>result=0&respmessage=Success&tx=1234</cngateway>" + '<cngateway>result=0&respmessage=Success&tx=1234</cngateway>' end def failed_refund_response - "<cngateway>result=305&respmessage=Failed</cngateway>" + '<cngateway>result=305&respmessage=Failed</cngateway>' end def successful_purchase_response - "<cngateway>result=0&respmessage=Success&tx=1234</cngateway>" + '<cngateway>result=0&respmessage=Success&tx=1234</cngateway>' end def failed_purchase_response - "<cngateway>result=7&respmessage=Failed</cngateway>" + '<cngateway>result=7&respmessage=Failed</cngateway>' end def invalid_response - "A String without a cngateway tag" + 'A String without a cngateway tag' + end + + def pre_scrubbed + <<-TRANSCRIPT +opening connection to train.cashnet.com:443... +opened +starting SSL for train.cashnet.com:443... +SSL established +<- "POST /givecorpsgateway HTTP/1.1\r\nContent-Type: application/x-www-form-urlencoded\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nAccept: */*\r\nUser-Agent: Ruby\r\nConnection: close\r\nHost: train.cashnet.com\r\nContent-Length: 364\r\n\r\n" +<- "command=SALE&merchant=GiveCorpGW&operator=givecorp&password=14givecorps&station=WEB&custcode=ActiveMerchant%2F1.76.0&cardno=5454545454545454&cid=123&expdate=1215&card_name_g=Longbob+Longsen&fname=Longbob&lname=Longsen&order_number=c440ec8493f215d21c8a993ceae30129&itemcode=FEE&addr_g=456+My+Street%2CApt+1&city_g=Ottawa&state_g=ON&zip_g=K1C2N6&email_g=&amount=1.00" +-> "HTTP/1.1 302 Found\r\n" +-> "Date: Wed, 03 Jan 2018 17:03:35 GMT\r\n" +-> "Content-Type: text/html; charset=utf-8\r\n" +-> "Transfer-Encoding: chunked\r\n" +-> "Connection: close\r\n" +-> "Set-Cookie: AWSALB=5ISjTg8Mez7jS1kEnzY4j5NkQ5bdlwDDNmfzTyEMBmILpb0Tn3k58pUQTGHBj3NUpciP0uqQs7FaAb42YZvt35ndLERGJA0dPQ03iCfrqbneQ+Wm5BhDzMGo5GUT; Expires=Wed, 10 Jan 2018 17:03:35 GMT; Path=/\r\n" +-> "Set-Cookie: AWSALB=bVhwwfJ2D6cI5zB3eapqNStEzF5yX1pXhaJGUBUCa+DZhEgn/TZGxznxIOYB9qKqzkPF4lq/zxWg/tuMBTiY4JGLRjayyhizvHnj2smrnNvr2DLQN7ZjLSh51BzM; Expires=Wed, 10 Jan 2018 17:03:35 GMT; Path=/\r\n" +-> "Cache-Control: private\r\n" +-> "Location: https://train.cashnet.com/cashneti/Gateway/htmlgw.aspx?client=EMARKETVENDOR_DEMO&command=SALE&merchant=GiveCorpGW&operator=givecorp&password=14givecorps&station=WEB&custcode=ActiveMerchant%2f1.76.0&cardno=5454545454545454&cid=123&expdate=1215&card_name_g=Longbob+Longsen&fname=Longbob&lname=Longsen&order_number=c440ec8493f215d21c8a993ceae30129&itemcode=FEE&addr_g=456+My+Street%2cApt+1&city_g=Ottawa&state_g=ON&zip_g=K1C2N6&email_g=&amount=1.00\r\n" +-> "Set-Cookie: ASP.NET_SessionId=; path=/; HttpOnly\r\n" +-> "P3P: CP=\"NOI DSP COR NID NOR\"\r\n" +-> "Set-Cookie: BNI_persistence=0000000000000000000000004d79da0a00005000; Path=/\r\n" +-> "Strict-Transport-Security: max-age=31536000\r\n" +-> "\r\n" +-> "282\r\n" +reading 642 bytes... +-> "<html><head><title>Object moved</title></head><body>\r\n<h2>Object moved to <a href=\"https://train.cashnet.com/cashneti/Gateway/htmlgw.aspx?client=EMARKETVENDOR_DEMO&amp;command=SALE&amp;merchant=GiveCorpGW&amp;operator=givecorp&amp;password=14givecorps&amp;station=WEB&amp;custcode=ActiveMerchant%2f1.76.0&amp;cardno=5454545454545454&amp;cid=123&amp;expdate=1215&amp;card_name_g=Longbob+Longsen&amp;fname=Longbob&amp;lname=Longsen&amp;order_number=c440ec8493f215d21c8a993ceae30129&amp;itemcode=FEE&amp;addr_g=456+My+Street%2cApt+1&amp;city_g=Ottawa&amp;state_g=ON&amp;zip_g=K1C2N6&amp;email_g=&amp;amount=1.00\">here</a>.</h2>\r\n</body></html>\r\n" +read 642 bytes +reading 2 bytes... +-> "\r\n" +read 2 bytes +-> "0\r\n" +-> "\r\n" +Conn close +opening connection to train.cashnet.com:443... +opened +starting SSL for train.cashnet.com:443... +SSL established +<- "GET /cashneti/Gateway/htmlgw.aspx?client=EMARKETVENDOR_DEMO&command=SALE&merchant=GiveCorpGW&operator=givecorp&password=14givecorps&station=WEB&custcode=ActiveMerchant%2f1.76.0&cardno=5454545454545454&cid=123&expdate=1215&card_name_g=Longbob+Longsen&fname=Longbob&lname=Longsen&order_number=c440ec8493f215d21c8a993ceae30129&itemcode=FEE&addr_g=456+My+Street%2cApt+1&city_g=Ottawa&state_g=ON&zip_g=K1C2N6&email_g=&amount=1.00 HTTP/1.1\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nAccept: */*\r\nUser-Agent: Ruby\r\nConnection: close\r\nHost: train.cashnet.com\r\n\r\n" +-> "HTTP/1.1 200 OK\r\n" +-> "Date: Wed, 03 Jan 2018 17:03:35 GMT\r\n" +-> "Content-Type: text/html; charset=utf-8\r\n" +-> "Transfer-Encoding: chunked\r\n" +-> "Connection: close\r\n" +-> "Set-Cookie: AWSALB=lFPwFYRnXJHRNmE6NCRAIfHtQadwx4bYJoT5xeAL5AuAXPcm1vYWx5F/s5FBr3GcungifktpWlwIgAmWS29K7YRXTCjk4xmcAnhXS86fpVUVQt4ECwPH2xdv8tf2; Expires=Wed, 10 Jan 2018 17:03:35 GMT; Path=/\r\n" +-> "Set-Cookie: AWSALB=mEfysFNBclo1/9+tTuI/XtHrmVkD89Fh6tAJ3Gl0u2EuLCYTW5VwEq+fVqYG1fEkN02dbhKSkIdM22QvyT6cRccDaUBsYAnOKjg2JlVShJlf+li5tfbrsUDk14jG; Expires=Wed, 10 Jan 2018 17:03:35 GMT; Path=/\r\n" +-> "Cache-Control: private\r\n" +-> "Set-Cookie: ASP.NET_SessionId=3ocslggtk4cdz54unbdnm25o; path=/; HttpOnly\r\n" +-> "P3P: CP=\"NOI DSP COR NID NOR\"\r\n" +-> "Set-Cookie: BNI_persistence=0000000000000000000000004d79da0a00005000; Path=/\r\n" +-> "Strict-Transport-Security: max-age=31536000\r\n" +-> "\r\n" +-> "3a\r\n" +reading 58 bytes... +-> "<cngateway>result=0&tx=77972&busdate=7/25/2017</cngateway>" +read 58 bytes +reading 2 bytes... +-> "\r\n" +read 2 bytes +-> "0\r\n" +-> "\r\n" +Conn close +TRANSCRIPT + end + + def post_scrubbed + <<-SCRUBBED +opening connection to train.cashnet.com:443... +opened +starting SSL for train.cashnet.com:443... +SSL established +<- "POST /givecorpsgateway HTTP/1.1\r\nContent-Type: application/x-www-form-urlencoded\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nAccept: */*\r\nUser-Agent: Ruby\r\nConnection: close\r\nHost: train.cashnet.com\r\nContent-Length: 364\r\n\r\n" +<- "command=SALE&merchant=GiveCorpGW&operator=givecorp&password=[FILTERED]&station=WEB&custcode=ActiveMerchant%2F1.76.0&cardno=[FILTERED]&cid=[FILTERED]&expdate=1215&card_name_g=Longbob+Longsen&fname=Longbob&lname=Longsen&order_number=c440ec8493f215d21c8a993ceae30129&itemcode=FEE&addr_g=456+My+Street%2CApt+1&city_g=Ottawa&state_g=ON&zip_g=K1C2N6&email_g=&amount=1.00" +-> "HTTP/1.1 302 Found\r\n" +-> "Date: Wed, 03 Jan 2018 17:03:35 GMT\r\n" +-> "Content-Type: text/html; charset=utf-8\r\n" +-> "Transfer-Encoding: chunked\r\n" +-> "Connection: close\r\n" +-> "Set-Cookie: AWSALB=5ISjTg8Mez7jS1kEnzY4j5NkQ5bdlwDDNmfzTyEMBmILpb0Tn3k58pUQTGHBj3NUpciP0uqQs7FaAb42YZvt35ndLERGJA0dPQ03iCfrqbneQ+Wm5BhDzMGo5GUT; Expires=Wed, 10 Jan 2018 17:03:35 GMT; Path=/\r\n" +-> "Set-Cookie: AWSALB=bVhwwfJ2D6cI5zB3eapqNStEzF5yX1pXhaJGUBUCa+DZhEgn/TZGxznxIOYB9qKqzkPF4lq/zxWg/tuMBTiY4JGLRjayyhizvHnj2smrnNvr2DLQN7ZjLSh51BzM; Expires=Wed, 10 Jan 2018 17:03:35 GMT; Path=/\r\n" +-> "Cache-Control: private\r\n" +-> "Location: https://train.cashnet.com/cashneti/Gateway/htmlgw.aspx?client=EMARKETVENDOR_DEMO&command=SALE&merchant=GiveCorpGW&operator=givecorp&password=[FILTERED]&station=WEB&custcode=ActiveMerchant%2f1.76.0&cardno=[FILTERED]&cid=[FILTERED]&expdate=1215&card_name_g=Longbob+Longsen&fname=Longbob&lname=Longsen&order_number=c440ec8493f215d21c8a993ceae30129&itemcode=FEE&addr_g=456+My+Street%2cApt+1&city_g=Ottawa&state_g=ON&zip_g=K1C2N6&email_g=&amount=1.00\r\n" +-> "Set-Cookie: ASP.NET_SessionId=; path=/; HttpOnly\r\n" +-> "P3P: CP=\"NOI DSP COR NID NOR\"\r\n" +-> "Set-Cookie: BNI_persistence=0000000000000000000000004d79da0a00005000; Path=/\r\n" +-> "Strict-Transport-Security: max-age=31536000\r\n" +-> "\r\n" +-> "282\r\n" +reading 642 bytes... +-> "<html><head><title>Object moved</title></head><body>\r\n<h2>Object moved to <a href=\"https://train.cashnet.com/cashneti/Gateway/htmlgw.aspx?client=EMARKETVENDOR_DEMO&amp;command=SALE&amp;merchant=GiveCorpGW&amp;operator=givecorp&amp;password=[FILTERED]&amp;station=WEB&amp;custcode=ActiveMerchant%2f1.76.0&amp;cardno=[FILTERED]&amp;cid=[FILTERED]&amp;expdate=1215&amp;card_name_g=Longbob+Longsen&amp;fname=Longbob&amp;lname=Longsen&amp;order_number=c440ec8493f215d21c8a993ceae30129&amp;itemcode=FEE&amp;addr_g=456+My+Street%2cApt+1&amp;city_g=Ottawa&amp;state_g=ON&amp;zip_g=K1C2N6&amp;email_g=&amp;amount=1.00\">here</a>.</h2>\r\n</body></html>\r\n" +read 642 bytes +reading 2 bytes... +-> "\r\n" +read 2 bytes +-> "0\r\n" +-> "\r\n" +Conn close +opening connection to train.cashnet.com:443... +opened +starting SSL for train.cashnet.com:443... +SSL established +<- "GET /cashneti/Gateway/htmlgw.aspx?client=EMARKETVENDOR_DEMO&command=SALE&merchant=GiveCorpGW&operator=givecorp&password=[FILTERED]&station=WEB&custcode=ActiveMerchant%2f1.76.0&cardno=[FILTERED]&cid=[FILTERED]&expdate=1215&card_name_g=Longbob+Longsen&fname=Longbob&lname=Longsen&order_number=c440ec8493f215d21c8a993ceae30129&itemcode=FEE&addr_g=456+My+Street%2cApt+1&city_g=Ottawa&state_g=ON&zip_g=K1C2N6&email_g=&amount=1.00 HTTP/1.1\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nAccept: */*\r\nUser-Agent: Ruby\r\nConnection: close\r\nHost: train.cashnet.com\r\n\r\n" +-> "HTTP/1.1 200 OK\r\n" +-> "Date: Wed, 03 Jan 2018 17:03:35 GMT\r\n" +-> "Content-Type: text/html; charset=utf-8\r\n" +-> "Transfer-Encoding: chunked\r\n" +-> "Connection: close\r\n" +-> "Set-Cookie: AWSALB=lFPwFYRnXJHRNmE6NCRAIfHtQadwx4bYJoT5xeAL5AuAXPcm1vYWx5F/s5FBr3GcungifktpWlwIgAmWS29K7YRXTCjk4xmcAnhXS86fpVUVQt4ECwPH2xdv8tf2; Expires=Wed, 10 Jan 2018 17:03:35 GMT; Path=/\r\n" +-> "Set-Cookie: AWSALB=mEfysFNBclo1/9+tTuI/XtHrmVkD89Fh6tAJ3Gl0u2EuLCYTW5VwEq+fVqYG1fEkN02dbhKSkIdM22QvyT6cRccDaUBsYAnOKjg2JlVShJlf+li5tfbrsUDk14jG; Expires=Wed, 10 Jan 2018 17:03:35 GMT; Path=/\r\n" +-> "Cache-Control: private\r\n" +-> "Set-Cookie: ASP.NET_SessionId=3ocslggtk4cdz54unbdnm25o; path=/; HttpOnly\r\n" +-> "P3P: CP=\"NOI DSP COR NID NOR\"\r\n" +-> "Set-Cookie: BNI_persistence=0000000000000000000000004d79da0a00005000; Path=/\r\n" +-> "Strict-Transport-Security: max-age=31536000\r\n" +-> "\r\n" +-> "3a\r\n" +reading 58 bytes... +-> "<cngateway>result=0&tx=77972&busdate=7/25/2017</cngateway>" +read 58 bytes +reading 2 bytes... +-> "\r\n" +read 2 bytes +-> "0\r\n" +-> "\r\n" +Conn close +SCRUBBED end end diff --git a/test/unit/gateways/cecabank_test.rb b/test/unit/gateways/cecabank_test.rb index 3a762329b8d..f58aa10e620 100644 --- a/test/unit/gateways/cecabank_test.rb +++ b/test/unit/gateways/cecabank_test.rb @@ -42,9 +42,9 @@ def test_invalid_xml_response_handling def test_expiration_date_sent_correctly stub_comms do - @gateway.purchase(@amount, credit_card("4242424242424242", month: 1, year: 2014), @options) + @gateway.purchase(@amount, credit_card('4242424242424242', month: 1, year: 2014), @options) end.check_request do |endpoint, data, headers| - assert_match(/Caducidad=201401&/, data, "Expected expiration date format is yyyymm") + assert_match(/Caducidad=201401&/, data, 'Expected expiration date format is yyyymm') end.respond_with(successful_purchase_response) end @@ -59,7 +59,7 @@ def test_unsuccessful_request def test_successful_refund_request @gateway.expects(:ssl_post).returns(successful_refund_response) - assert response = @gateway.refund(@amount, "reference", @options) + assert response = @gateway.refund(@amount, 'reference', @options) assert_instance_of Response, response assert_success response assert response.test? @@ -68,16 +68,15 @@ def test_successful_refund_request def test_unsuccessful_refund_request @gateway.expects(:ssl_post).returns(failed_refund_response) - assert response = @gateway.refund(@amount, "reference", @options) + assert response = @gateway.refund(@amount, 'reference', @options) assert_failure response assert response.test? end - + def test_transcript_scrubbing assert_equal scrubbed_transcript, @gateway.scrub(transcript) end - private def successful_purchase_response diff --git a/test/unit/gateways/cenpos_test.rb b/test/unit/gateways/cenpos_test.rb index 0c9f93643c1..950701578bd 100644 --- a/test/unit/gateways/cenpos_test.rb +++ b/test/unit/gateways/cenpos_test.rb @@ -1,13 +1,13 @@ -require "test_helper" +require 'test_helper' class CenposTest < Test::Unit::TestCase include CommStub def setup @gateway = CenposGateway.new( - :merchant_id => "merchant_id", - :password => "password", - :user_id => "user_id" + :merchant_id => 'merchant_id', + :password => 'password', + :user_id => 'user_id' ) @credit_card = credit_card @@ -21,7 +21,7 @@ def test_successful_purchase assert_success response - assert_equal "1609995363|4242|1.00", response.authorization + assert_equal '1609995363|4242|1.00', response.authorization assert response.test? end @@ -31,7 +31,7 @@ def test_successful_purchase_cvv_result end.respond_with(successful_purchase_response) cvv_result = response.cvv_result - assert_equal "M", cvv_result["code"] + assert_equal 'M', cvv_result['code'] end def test_successful_purchase_avs_result @@ -40,7 +40,7 @@ def test_successful_purchase_avs_result end.respond_with(successful_purchase_response) avs_result = response.avs_result - assert_equal "D", avs_result["code"] + assert_equal 'D', avs_result['code'] end def test_failed_purchase @@ -49,7 +49,7 @@ def test_failed_purchase end.respond_with(failed_purchase_response) assert_failure response - assert_equal "Decline transaction", response.message + assert_equal 'Decline transaction', response.message assert_equal Gateway::STANDARD_ERROR_CODE[:card_declined], response.error_code assert response.test? end @@ -60,7 +60,7 @@ def test_missing_cvv_result end.respond_with(failed_purchase_response) cvv_result = response.cvv_result - assert_equal nil, cvv_result["code"] + assert_equal nil, cvv_result['code'] end def test_failed_purchase_avs_result @@ -69,7 +69,7 @@ def test_failed_purchase_avs_result end.respond_with(failed_purchase_response) avs_result = response.avs_result - assert_equal nil, avs_result["code"] + assert_equal nil, avs_result['code'] end def test_unmatched_cvv_result @@ -78,7 +78,7 @@ def test_unmatched_cvv_result end.respond_with(cvv_no_match_response) cvv_result = response.cvv_result - assert_equal "N", cvv_result["code"] + assert_equal 'N', cvv_result['code'] end def test_avs_result_unmatched_zip @@ -86,7 +86,7 @@ def test_avs_result_unmatched_zip @gateway.purchase(@amount, @credit_card) end.respond_with(avs_zip_no_match_response) - assert_equal "B", response.avs_result["code"] + assert_equal 'B', response.avs_result['code'] end def test_avs_result_unmatched_address @@ -94,7 +94,7 @@ def test_avs_result_unmatched_address @gateway.purchase(@amount, @credit_card) end.respond_with(avs_billing_no_match_response) - assert_equal "P", response.avs_result["code"] + assert_equal 'P', response.avs_result['code'] end def test_avs_result_unmatched_address_and_zip @@ -102,7 +102,7 @@ def test_avs_result_unmatched_address_and_zip @gateway.purchase(@amount, @credit_card) end.respond_with(avs_billing_and_zip_no_match_response) - assert_equal "C", response.avs_result["code"] + assert_equal 'C', response.avs_result['code'] end def test_successful_authorize_and_capture @@ -111,7 +111,7 @@ def test_successful_authorize_and_capture end.respond_with(successful_authorize_response) assert_success response - assert_equal "1760035844|4242|1.00", response.authorization + assert_equal '1760035844|4242|1.00', response.authorization capture = stub_comms do @gateway.capture(@amount, response.authorization) @@ -128,14 +128,14 @@ def test_failed_authorize end.respond_with(failed_authorize_response) assert_failure response - assert_equal "Decline transaction", response.message + assert_equal 'Decline transaction', response.message assert_equal Gateway::STANDARD_ERROR_CODE[:card_declined], response.error_code assert response.test? end def test_failed_capture response = stub_comms do - @gateway.capture(100, "") + @gateway.capture(100, '') end.respond_with(failed_capture_response) assert_failure response @@ -147,7 +147,7 @@ def test_successful_void end.respond_with(successful_authorize_response) assert_success response - assert_equal "1760035844|4242|1.00", response.authorization + assert_equal '1760035844|4242|1.00', response.authorization void = stub_comms do @gateway.void(response.authorization) @@ -160,7 +160,7 @@ def test_successful_void def test_failed_void response = stub_comms do - @gateway.void("1758584451|4242|1.00") + @gateway.void('1758584451|4242|1.00') end.check_request do |endpoint, data, headers| assert_match(/1758584451/, data) end.respond_with(failed_void_response) @@ -174,7 +174,7 @@ def test_successful_refund end.respond_with(successful_purchase_response) assert_success response - assert_equal "1609995363|4242|1.00", response.authorization + assert_equal '1609995363|4242|1.00', response.authorization refund = stub_comms do @gateway.refund(@amount, response.authorization) @@ -187,7 +187,7 @@ def test_successful_refund def test_failed_refund response = stub_comms do - @gateway.refund(nil, "") + @gateway.refund(nil, '') end.respond_with(failed_refund_response) assert_failure response @@ -200,7 +200,7 @@ def test_successful_credit assert_success response - assert_equal "1609996211|4242|1.00", response.authorization + assert_equal '1609996211|4242|1.00', response.authorization assert response.test? end @@ -210,7 +210,7 @@ def test_failed_credit end.respond_with(failed_credit_response) assert_failure response - assert_equal "Invalid card number", response.message + assert_equal 'Invalid card number', response.message assert_equal Gateway::STANDARD_ERROR_CODE[:invalid_number], response.error_code assert response.test? end @@ -220,7 +220,7 @@ def test_successful_verify @gateway.verify(@credit_card) end.respond_with(successful_authorize_response, failed_void_response) assert_success response - assert_equal "Succeeded", response.message + assert_equal 'Succeeded', response.message end def test_failed_verify @@ -228,7 +228,7 @@ def test_failed_verify @gateway.verify(@credit_card) end.respond_with(failed_authorize_response, successful_void_response) assert_failure response - assert_equal "Decline transaction", response.message + assert_equal 'Decline transaction', response.message assert_equal Gateway::STANDARD_ERROR_CODE[:card_declined], response.error_code end @@ -238,7 +238,7 @@ def test_empty_response_fails end.respond_with(empty_purchase_response) assert_failure response - assert_equal "Unable to read error message", response.message + assert_equal 'Unable to read error message', response.message end def test_transcript_scrubbing @@ -307,7 +307,6 @@ def failed_refund_response ) end - def successful_credit_response %( <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"><s:Body><ProcessCreditCardResponse xmlns="http://tempuri.org/"><ProcessCreditCardResult i:type="a:ProcessRecurringSaleResponse" xmlns:a="http://schemas.datacontract.org/2004/07/Acriter.ABI.CenPOS.EPayment.VirtualTerminal.v6.Common" xmlns:i="http://www.w3.org/2001/XMLSchema-instance"><Message xmlns="http://schemas.datacontract.org/2004/07/Acriter.ABI.CenPOS.EPayment.VirtualTerminal.Common">Approved</Message><Result xmlns="http://schemas.datacontract.org/2004/07/Acriter.ABI.CenPOS.EPayment.VirtualTerminal.Common">0</Result><a:AccountBalanceAmount i:nil="true"/><a:Amount>91.13</a:Amount><a:AutorizationNumber i:nil="true"/><a:CardType>VISA</a:CardType><a:Discount>0</a:Discount><a:DiscountAmount>0</a:DiscountAmount><a:EmvData i:nil="true"/><a:OriginalAmount>91.13</a:OriginalAmount><a:ParameterValidationResultList/><a:PartiallyAuthorizedAmount i:nil="true"/><a:ReferenceNumber>1609996211</a:ReferenceNumber><a:Surcharge>0</a:Surcharge><a:SurchargeAmount>0</a:SurchargeAmount><a:TraceNumber i:nil="true"/><a:ProtectedCardNumber i:nil="true"/><a:RecurringSaleTokenId i:nil="true"/></ProcessCreditCardResult></ProcessCreditCardResponse></s:Body></s:Envelope> diff --git a/test/unit/gateways/checkout_test.rb b/test/unit/gateways/checkout_test.rb index ca39016cd0f..ab70056694e 100644 --- a/test/unit/gateways/checkout_test.rb +++ b/test/unit/gateways/checkout_test.rb @@ -55,9 +55,9 @@ def test_unsuccessful_authorize def test_unsuccessful_capture @gateway.expects(:ssl_post).returns(failed_capture_response) - assert response = @gateway.capture(100, '||||' , @options) + assert response = @gateway.capture(100, '||||', @options) assert_failure response - assert_equal 'EGP00173', response.params["error_code_tag"] + assert_equal 'EGP00173', response.params['error_code_tag'] assert response.test? end @@ -73,7 +73,7 @@ def test_unsuccessful_purchase def test_passes_correct_currency stub_comms do @gateway.purchase(100, credit_card, @options.merge( - currency: "EUR" + currency: 'EUR' )) end.check_request do |endpoint, data, headers| assert_match(/<bill_currencycode>EUR<\/bill_currencycode>/, data) @@ -83,8 +83,8 @@ def test_passes_correct_currency def test_passes_descriptors stub_comms do @gateway.purchase(100, credit_card, @options.merge( - descriptor_name: "ZahName", - descriptor_city: "Oakland" + descriptor_name: 'ZahName', + descriptor_city: 'Oakland' )) end.check_request do |endpoint, data, headers| assert_match(/<descriptor_name>ZahName<\/descriptor_name>/, data) @@ -137,7 +137,7 @@ def test_successful_verify @gateway.verify(credit_card, @options) end.respond_with(successful_authorize_response, successful_void_response) assert_success response - assert_equal "33024417", response.params['tranid'] + assert_equal '33024417', response.params['tranid'] end def test_successful_verify_with_failed_void @@ -145,7 +145,7 @@ def test_successful_verify_with_failed_void @gateway.verify(credit_card, @options) end.respond_with(successful_authorize_response, failed_void_response) assert_success response - assert_equal "Successful", response.message + assert_equal 'Successful', response.message end def test_unsuccessful_verify @@ -153,7 +153,7 @@ def test_unsuccessful_verify @gateway.verify(credit_card, @options) end.respond_with(failed_authorize_response, successful_void_response) assert_failure response - assert_equal "Not Successful", response.message + assert_equal 'Not Successful', response.message end private diff --git a/test/unit/gateways/checkout_v2_test.rb b/test/unit/gateways/checkout_v2_test.rb index 2ee60065908..bb3f1eda89a 100644 --- a/test/unit/gateways/checkout_v2_test.rb +++ b/test/unit/gateways/checkout_v2_test.rb @@ -5,7 +5,7 @@ class CheckoutV2Test < Test::Unit::TestCase def setup @gateway = CheckoutV2Gateway.new( - secret_key: '1111111111111', + secret_key: '1111111111111' ) @credit_card = credit_card @@ -18,14 +18,51 @@ def test_successful_purchase end.respond_with(successful_purchase_response) assert_success response - assert_equal 'charge_test_941CA9CE174U76BD29C8', response.authorization assert response.test? end + def test_successful_purchase_includes_avs_result + response = stub_comms do + @gateway.purchase(@amount, @credit_card) + end.respond_with(successful_purchase_response) + + assert_equal 'S', response.avs_result['code'] + assert_equal 'U.S.-issuing bank does not support AVS.', response.avs_result['message'] + assert_equal 'X', response.avs_result['postal_match'] + assert_equal 'X', response.avs_result['street_match'] + end + + def test_successful_purchase_includes_cvv_result + response = stub_comms do + @gateway.purchase(@amount, @credit_card) + end.respond_with(successful_purchase_response) + + assert_equal 'Y', response.cvv_result['code'] + end + + def test_successful_authorize_includes_avs_result + response = stub_comms do + @gateway.authorize(@amount, @credit_card) + end.respond_with(successful_authorize_response) + + assert_equal 'S', response.avs_result['code'] + assert_equal 'U.S.-issuing bank does not support AVS.', response.avs_result['message'] + assert_equal 'X', response.avs_result['postal_match'] + assert_equal 'X', response.avs_result['street_match'] + end + + def test_successful_authorize_includes_cvv_result + response = stub_comms do + @gateway.authorize(@amount, @credit_card) + end.respond_with(successful_authorize_response) + + assert_equal 'Y', response.cvv_result['code'] + end + def test_purchase_with_additional_fields response = stub_comms do - @gateway.purchase(@amount, @credit_card, {descriptor_city: "london", descriptor_name: "sherlock"}) + @gateway.purchase(@amount, @credit_card, {descriptor_city: 'london', descriptor_name: 'sherlock'}) end.check_request do |endpoint, data, headers| assert_match(/"descriptor\":{\"name\":\"sherlock\",\"city\":\"london\"}/, data) end.respond_with(successful_purchase_response) @@ -47,7 +84,31 @@ def test_successful_authorize_and_capture end.respond_with(successful_authorize_response) assert_success response - assert_equal "charge_test_941CA9CE174U76BD29C8", response.authorization + assert_equal 'charge_test_AF1A29AD350Q748C7EA8', response.authorization + + capture = stub_comms do + @gateway.capture(@amount, response.authorization) + end.respond_with(successful_capture_response) + + assert_success capture + end + + def test_successful_authorize_and_capture_with_additional_options + response = stub_comms do + options = { + card_on_file: true, + transaction_indicator: 2, + previous_charge_id: 'charge_123' + } + @gateway.authorize(@amount, @credit_card, options) + end.check_request do |endpoint, data, headers| + assert_match(%r{"cardOnFile":true}, data) + assert_match(%r{"transactionIndicator":2}, data) + assert_match(%r{"previousChargeId":"charge_123"}, data) + end.respond_with(successful_authorize_response) + + assert_success response + assert_equal 'charge_test_AF1A29AD350Q748C7EA8', response.authorization capture = stub_comms do @gateway.capture(@amount, response.authorization) @@ -62,13 +123,13 @@ def test_failed_authorize end.respond_with(failed_authorize_response) assert_failure response - assert_equal "Invalid Card Number", response.message + assert_equal 'Invalid Card Number', response.message assert response.test? end def test_failed_capture response = stub_comms do - @gateway.capture(100, "") + @gateway.capture(100, '') end.respond_with(failed_capture_response) assert_failure response @@ -80,7 +141,7 @@ def test_successful_void end.respond_with(successful_authorize_response) assert_success response - assert_equal "charge_test_941CA9CE174U76BD29C8", response.authorization + assert_equal 'charge_test_AF1A29AD350Q748C7EA8', response.authorization void = stub_comms do @gateway.void(response.authorization) @@ -91,7 +152,7 @@ def test_successful_void def test_failed_void response = stub_comms do - @gateway.void("5d53a33d960c46d00f5dc061947d998c") + @gateway.void('5d53a33d960c46d00f5dc061947d998c') end.respond_with(failed_void_response) assert_failure response @@ -103,7 +164,7 @@ def test_successful_refund end.respond_with(successful_purchase_response) assert_success response - assert_equal "charge_test_941CA9CE174U76BD29C8", response.authorization + assert_equal 'charge_test_941CA9CE174U76BD29C8', response.authorization refund = stub_comms do @gateway.refund(@amount, response.authorization) @@ -114,7 +175,7 @@ def test_successful_refund def test_failed_refund response = stub_comms do - @gateway.refund(nil, "") + @gateway.refund(nil, '') end.respond_with(failed_refund_response) assert_failure response @@ -125,7 +186,7 @@ def test_successful_verify @gateway.verify(@credit_card) end.respond_with(successful_authorize_response, failed_void_response) assert_success response - assert_equal "Succeeded", response.message + assert_equal 'Succeeded', response.message end def test_failed_verify @@ -133,7 +194,7 @@ def test_failed_verify @gateway.verify(@credit_card) end.respond_with(failed_authorize_response, successful_void_response) assert_failure response - assert_equal "Invalid Card Number", response.message + assert_equal 'Invalid Card Number', response.message end def test_transcript_scrubbing @@ -149,6 +210,18 @@ def test_invalid_json assert_match %r{Invalid JSON response}, response.message end + def test_error_code_returned + response = stub_comms do + @gateway.purchase(@amount, @credit_card) + end.respond_with(error_code_response) + + assert_failure response + assert_match(/70000: 70077/, response.error_code) + end + + def test_supported_countries + assert_equal ['AD', 'AE', 'AT', 'BE', 'BG', 'CH', 'CY', 'CZ', 'DE', 'DK', 'EE', 'ES', 'FO', 'FI', 'FR', 'GB', 'GI', 'GL', 'GR', 'HR', 'HU', 'IE', 'IS', 'IL', 'IT', 'LI', 'LT', 'LU', 'LV', 'MC', 'MT', 'NL', 'NO', 'PL', 'PT', 'RO', 'SE', 'SI', 'SM', 'SK', 'SJ', 'TR', 'VA'], @gateway.supported_countries + end private @@ -218,23 +291,68 @@ def failed_purchase_response def successful_authorize_response %( - { - "id":"charge_test_941CA9CE174U76BD29C8", - "liveMode":false, - "created":"2015-05-27T20:45:58Z", - "value":200.0, - "currency":"USD", - "trackId":"1", - "description":null, - "email":"longbob.longsen@gmail.com", - "chargeMode":1, - "transactionIndicator":1, - "customerIp":null, - "responseMessage":"Authorised", - "responseAdvancedInfo":"Authorised", - "responseCode":"10000" - } - ) + { + "id":"charge_test_AF1A29AD350Q748C7EA8", + "liveMode":false, + "created":"2017-11-13T14:05:27Z", + "value":200, + "currency":"USD", + "trackId":"1", + "description":null, + "email":"longbob.longsen@example.com", + "chargeMode":1, + "transactionIndicator":1, + "customerIp":null, + "responseMessage":"Approved", + "responseAdvancedInfo":"Approved", + "responseCode":"10000", + "status":"Authorised", + "authCode":"923189", + "isCascaded":false, + "autoCapture":"N", + "autoCapTime":0.0, + "card":{"customerId": + "cust_12DCEB24-ACEA-48AB-BEF2-35A3C09BE581", + "expiryMonth":"06", + "expiryYear":"2018", + "billingDetails":{ + "addressLine1":"456 My Street", + "addressLine2":"Apt 1", + "postcode":"K1C2N6", + "country":"CA", + "city":"Ottawa", + "state":"ON", + "phone":{"number":"(555)555-5555"} + }, + "id":"card_CFA314F4-388D-4CF4-BE6F-940D894C9E64", + "last4":"4242", + "bin":"424242", + "paymentMethod":"Visa", + "fingerprint":"F639CAB2745BEE4140BF86DF6B6D6E255C5945AAC3788D923FA047EA4C208622", + "name":"Longbob Longsen", + "cvvCheck":"Y", + "avsCheck":"S" + }, + "riskCheck":true, + "customerPaymentPlans":null, + "metadata":{}, + "shippingDetails":{ + "addressLine1":null, + "addressLine2":null, + "postcode":null, + "country":null, + "city":null, + "state":null, + "phone":{} + }, + "products":[], + "udf1":null, + "udf2":null, + "udf3":null, + "udf4":null, + "udf5":null + } + ) end def failed_authorize_response @@ -355,5 +473,11 @@ def invalid_json_response ) end - + def error_code_response + %( + { + "eventId":"1b206f69-b4db-4259-9713-b72dfe0f19da","errorCode":"70000","message":"Validation error","errorMessageCodes":["70077"],"errors":["Expired Card"] + } + ) + end end diff --git a/test/unit/gateways/citrus_pay_test.rb b/test/unit/gateways/citrus_pay_test.rb index 97b2ba02a55..40b126e3782 100644 --- a/test/unit/gateways/citrus_pay_test.rb +++ b/test/unit/gateways/citrus_pay_test.rb @@ -91,7 +91,7 @@ def test_void def test_passing_alpha3_country_code stub_comms(@gateway, :ssl_request) do - @gateway.authorize(@amount, @credit_card, :billing_address => {country: "US"}) + @gateway.authorize(@amount, @credit_card, :billing_address => {country: 'US'}) end.check_request do |method, endpoint, data, headers| assert_match(/USA/, data) end.respond_with(successful_authorize_response) @@ -99,7 +99,7 @@ def test_passing_alpha3_country_code def test_non_existent_country stub_comms(@gateway, :ssl_request) do - @gateway.authorize(@amount, @credit_card, :billing_address => {country: "Blah"}) + @gateway.authorize(@amount, @credit_card, :billing_address => {country: 'Blah'}) end.check_request do |method, endpoint, data, headers| assert_match(/"country":null/, data) end.respond_with(successful_authorize_response) @@ -138,7 +138,7 @@ def test_successful_verify @gateway.verify(@credit_card, @options) end.respond_with(successful_authorize_response, successful_void_response) assert_success response - assert_equal "91debbeb-d88f-42e9-a6ce-9b62c99d656b", response.params['order']['id'] + assert_equal '91debbeb-d88f-42e9-a6ce-9b62c99d656b', response.params['order']['id'] end def test_successful_verify_with_failed_void @@ -146,7 +146,7 @@ def test_successful_verify_with_failed_void @gateway.verify(@credit_card, @options) end.respond_with(successful_authorize_response, failed_void_response) assert_success response - assert_equal "Succeeded", response.message + assert_equal 'Succeeded', response.message end def test_unsuccessful_verify @@ -154,7 +154,7 @@ def test_unsuccessful_verify @gateway.verify(@credit_card, @options) end.respond_with(failed_authorize_response, successful_void_response) assert_failure response - assert_equal "FAILURE - DECLINED", response.message + assert_equal 'FAILURE - DECLINED', response.message end def test_north_america_region_url diff --git a/test/unit/gateways/clearhaus_test.rb b/test/unit/gateways/clearhaus_test.rb index 68741fb1bdf..b877de05e4f 100644 --- a/test/unit/gateways/clearhaus_test.rb +++ b/test/unit/gateways/clearhaus_test.rb @@ -14,7 +14,7 @@ def setup description: 'Store Purchase' } - @test_signing_key = "7e51b92e-ca7e-48e3-8a96-7d66cf1f2da2" + @test_signing_key = '7e51b92e-ca7e-48e3-8a96-7d66cf1f2da2' end def test_successful_purchase @@ -56,7 +56,7 @@ def test_successful_authorize_with_threed assert_success response assert response.test? end.check_request do |endpoint, data, headers| - expr = { threed_secure: { pares: '123' } }.to_query + expr = { card: { pares: '123' } }.to_query assert_match expr, data end.respond_with(successful_authorize_response) end @@ -77,7 +77,7 @@ def test_additional_params def test_successful_authorize_with_card stub_comms do - response = @gateway.authorize(@amount, "4110", @options) + response = @gateway.authorize(@amount, '4110', @options) assert_success response assert_equal '84412a34-fa29-4369-a098-0165a80e8fda', response.authorization @@ -153,7 +153,7 @@ def test_successful_void def test_failed_void @gateway.expects(:ssl_post).returns(failed_void_response) - response = @gateway.void( @credit_card, @options) + response = @gateway.void(@credit_card, @options) assert_failure response assert_equal 40000, response.error_code @@ -223,9 +223,9 @@ def test_signing_request assert_equal '84412a34-fa29-4369-a098-0165a80e8fda', response.authorization assert response.test? end.check_request do |method, endpoint, data, headers| - assert headers["Signature"] - assert_match %r{7e51b92e-ca7e-48e3-8a96-7d66cf1f2da2 RS256-hex}, headers["Signature"] - assert_match %r{02f56ed1f6c60cdefd$}, headers["Signature"] + assert headers['Signature'] + assert_match %r{7e51b92e-ca7e-48e3-8a96-7d66cf1f2da2 RS256-hex}, headers['Signature'] + assert_match %r{25f8283c3cc43911d7$}, headers['Signature'] end.respond_with(successful_authorize_response) end @@ -242,20 +242,20 @@ def test_cleans_whitespace_from_private_key assert_equal '84412a34-fa29-4369-a098-0165a80e8fda', response.authorization assert response.test? end.check_request do |method, endpoint, data, headers| - assert headers["Signature"] - assert_match %r{7e51b92e-ca7e-48e3-8a96-7d66cf1f2da2 RS256-hex}, headers["Signature"] - assert_match %r{02f56ed1f6c60cdefd$}, headers["Signature"] + assert headers['Signature'] + assert_match %r{7e51b92e-ca7e-48e3-8a96-7d66cf1f2da2 RS256-hex}, headers['Signature'] + assert_match %r{25f8283c3cc43911d7$}, headers['Signature'] end.respond_with(successful_authorize_response) end def test_unsuccessful_signing_request_with_invalid_key - gateway = ClearhausGateway.new(api_key: "test_key", signing_key: @test_signing_key, private_key: "foo") + gateway = ClearhausGateway.new(api_key: 'test_key', signing_key: @test_signing_key, private_key: 'foo') # stub actual network access, but this shouldn't be reached gateway.stubs(:ssl_post).returns(nil) - card = credit_card("4111111111111111", month: "06", year: "2018", verification_value: "123") - options = { currency: "EUR", ip: "1.1.1.1" } + card = credit_card('4111111111111111', month: '06', year: '2018', verification_value: '123') + options = { currency: 'EUR', ip: '1.1.1.1' } response = gateway.authorize(2050, card, options) assert_failure response @@ -275,7 +275,7 @@ def pre_scrubbed starting SSL for gateway.test.clearhaus.com:443... SSL established <- "POST /authorizations HTTP/1.1\r\nContent-Type: application/x-www-form-urlencoded\r\nAuthorization: Basic NTI2Y2Y1NjQtMTE5Yy00YmI2LTljZjgtMDAxNWVhYzdlNGY2Og==\r\nUser-Agent: Clearhaus ActiveMerchantBindings/1.54.0\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nAccept: */*\r\nConnection: close\r\nHost: gateway.test.clearhaus.com\r\nContent-Length: 128\r\n\r\n" -<- "amount=100&card%5Bcsc%5D=123&card%5Bexpire_month%5D=09&card%5Bexpire_year%5D=2016&card%5Bnumber%5D=4111111111111111&currency=EUR" +<- "amount=100&card%5Bcsc%5D=123&card%5Bexpire_month%5D=09&card%5Bexpire_year%5D=2016&card%5Bpan%5D=4111111111111111&currency=EUR" -> "HTTP/1.1 201 Created\r\n" -> "Content-Type: application/vnd.clearhaus-gateway.hal+json; version=0.9.0; charset=utf-8\r\n" -> "Date: Wed, 28 Oct 2015 18:56:11 GMT\r\n" @@ -318,7 +318,7 @@ def post_scrubbed starting SSL for gateway.test.clearhaus.com:443... SSL established <- "POST /authorizations HTTP/1.1\r\nContent-Type: application/x-www-form-urlencoded\r\nAuthorization: Basic [FILTERED]\r\nUser-Agent: Clearhaus ActiveMerchantBindings/1.54.0\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nAccept: */*\r\nConnection: close\r\nHost: gateway.test.clearhaus.com\r\nContent-Length: 128\r\n\r\n" -<- "amount=100&card%5Bcsc%5D=[FILTERED]&card%5Bexpire_month%5D=09&card%5Bexpire_year%5D=2016&card%5Bnumber%5D=[FILTERED]&currency=EUR" +<- "amount=100&card%5Bcsc%5D=[FILTERED]&card%5Bexpire_month%5D=09&card%5Bexpire_year%5D=2016&card%5Bpan%5D=[FILTERED]&currency=EUR" -> "HTTP/1.1 201 Created\r\n" -> "Content-Type: application/vnd.clearhaus-gateway.hal+json; version=0.9.0; charset=utf-8\r\n" -> "Date: Wed, 28 Oct 2015 18:56:11 GMT\r\n" @@ -355,7 +355,7 @@ def post_scrubbed end def test_private_key - %Q{-----BEGIN RSA PRIVATE KEY-----\nMIIBOwIBAAJBALYK0zmwuYkH3YWcFNLLddx5cwDxEY7Gi1xITuQqRrU4yD3uSw+J\nWYKknb4Tbndb6iEHY+e6gIGD+49TojnNeIUCAwEAAQJARyuYRRe4kcBHdPL+mSL+\nY0IAGkAlUyKAXYXPghidKD/v/oLrFaZWALGM2clv6UoYYpPnInSgbcud4sTcfeUm\nQQIhAN2JZ2qv0WGcbIopBpwpQ5jDxMGVkmkVVUEWWABGF8+pAiEA0lySxTELZm8b\nGx9UEDRghN+Qv/OuIKFldu1Ba4f8W30CIQCaQFIBtunTTVdF28r+cLzgYW9eWwbW\npEP4TdZ4WlW6AQIhAMDCTUdeUpjxlH/87BXROORozAXocBW8bvJUI486U5ctAiAd\nInviQqJd1KTGRDmWIGrE5YACVmW2JSszD9t5VKxkAA==\n-----END RSA PRIVATE KEY-----} + "-----BEGIN RSA PRIVATE KEY-----\nMIIBOwIBAAJBALYK0zmwuYkH3YWcFNLLddx5cwDxEY7Gi1xITuQqRrU4yD3uSw+J\nWYKknb4Tbndb6iEHY+e6gIGD+49TojnNeIUCAwEAAQJARyuYRRe4kcBHdPL+mSL+\nY0IAGkAlUyKAXYXPghidKD/v/oLrFaZWALGM2clv6UoYYpPnInSgbcud4sTcfeUm\nQQIhAN2JZ2qv0WGcbIopBpwpQ5jDxMGVkmkVVUEWWABGF8+pAiEA0lySxTELZm8b\nGx9UEDRghN+Qv/OuIKFldu1Ba4f8W30CIQCaQFIBtunTTVdF28r+cLzgYW9eWwbW\npEP4TdZ4WlW6AQIhAMDCTUdeUpjxlH/87BXROORozAXocBW8bvJUI486U5ctAiAd\nInviQqJd1KTGRDmWIGrE5YACVmW2JSszD9t5VKxkAA==\n-----END RSA PRIVATE KEY-----" end def failed_purchase_response @@ -364,13 +364,13 @@ def failed_purchase_response def successful_authorize_response { - "id" => "84412a34-fa29-4369-a098-0165a80e8fda", - "status" => { - "code" => 20000 + 'id' => '84412a34-fa29-4369-a098-0165a80e8fda', + 'status' => { + 'code' => 20000 }, - "processed_at" => "2014-07-09T09:53:41+00:00", - "_links" => { - "captures" => { "href" => "/authorizations/84412a34-fa29-4369-a098-0165a80e8fda/captures" } + 'processed_at' => '2014-07-09T09:53:41+00:00', + '_links' => { + 'captures' => { 'href' => '/authorizations/84412a34-fa29-4369-a098-0165a80e8fda/captures' } } }.to_json end @@ -381,18 +381,18 @@ def failed_authorize_response def successful_capture_response { - "id" => "d8e92a70-3030-4d4d-8ad2-684b230c1bed", - "status" => { - "code" => 20000 + 'id' => 'd8e92a70-3030-4d4d-8ad2-684b230c1bed', + 'status' => { + 'code' => 20000 }, - "processed_at" => "2014-07-09T11:47:28+00:00", - "amount" => 1000, - "_links" => { - "authorization" => { - "href" => "/authorizations/84412a34-fa29-4369-a098-0165a80e8fda" + 'processed_at' => '2014-07-09T11:47:28+00:00', + 'amount' => 1000, + '_links' => { + 'authorization' => { + 'href' => '/authorizations/84412a34-fa29-4369-a098-0165a80e8fda' }, - "refunds" => { - "href" => "/authorizations/84412a34-fa29-4369-a098-0165a80e8fda/refunds" + 'refunds' => { + 'href' => '/authorizations/84412a34-fa29-4369-a098-0165a80e8fda/refunds' } } }.to_json @@ -404,14 +404,14 @@ def failed_capture_response def successful_refund_response { - "id" => "f04c0872-47ce-4683-8d8c-e154221bba14", - "status" => { - "code" => 20000 + 'id' => 'f04c0872-47ce-4683-8d8c-e154221bba14', + 'status' => { + 'code' => 20000 }, - "processed_at" => "2014-07-09T11:57:58+00:00", - "amount" => 500, - "_links" => { - "authorization" => { "href" => "/authorizations/84412a34-fa29-4369-a098-0165a80e8fda" } + 'processed_at' => '2014-07-09T11:57:58+00:00', + 'amount' => 500, + '_links' => { + 'authorization' => { 'href' => '/authorizations/84412a34-fa29-4369-a098-0165a80e8fda' } } }.to_json end @@ -422,23 +422,23 @@ def failed_refund_response def successful_void_response { - "id" => "77d08c40-cfa9-42e3-993d-795f772b70a4", - "status" => { - "code" => 20000 + 'id' => '77d08c40-cfa9-42e3-993d-795f772b70a4', + 'status' => { + 'code' => 20000 }, - "processed_at" => "2015-08-21T16:44:48+00:00", - "_links" => { - "self" => { - "href" => "/authorizations/77d08c40-cfa9-42e3-993d-795f772b70a4" + 'processed_at' => '2015-08-21T16:44:48+00:00', + '_links' => { + 'self' => { + 'href' => '/authorizations/77d08c40-cfa9-42e3-993d-795f772b70a4' }, - "card" => { - "href" => "/cards/27127636-0748-4df5-97fe-e58a0c29b618" + 'card' => { + 'href' => '/cards/27127636-0748-4df5-97fe-e58a0c29b618' }, - "captures" => { - "href" => "/authorizations/77d08c40-cfa9-42e3-993d-795f772b70a4/captures" + 'captures' => { + 'href' => '/authorizations/77d08c40-cfa9-42e3-993d-795f772b70a4/captures' }, - "voids" => { "href" => "/authorizations/77d08c40-cfa9-42e3-993d-795f772b70a4/voids"}, - "refunds" => { "href" => "/authorizations/77d08c40-cfa9-42e3-993d-795f772b70a4/refunds"} + 'voids' => { 'href' => '/authorizations/77d08c40-cfa9-42e3-993d-795f772b70a4/voids'}, + 'refunds' => { 'href' => '/authorizations/77d08c40-cfa9-42e3-993d-795f772b70a4/refunds'} } } end @@ -449,16 +449,16 @@ def failed_void_response def successful_store_response { - "id" => "58dabba0-e9ea-4133-8c38-bfa1028c1ed2", - "status" => { - "code"=> 20000 + 'id' => '58dabba0-e9ea-4133-8c38-bfa1028c1ed2', + 'status' => { + 'code'=> 20000 }, - "processed_at" => "2014-07-09T12:14:31+00:00", - "last4" => "0004", - "scheme" => "mastercard", - "_links" => { - "authorizations" => { "href" => "/cards/58dabba0-e9ea-4133-8c38-bfa1028c1ed2/authorizations" }, - "credits"=> { "href" => "/cards/58dabba0-e9ea-4133-8c38-bfa1028c1ed2/credits" } + 'processed_at' => '2014-07-09T12:14:31+00:00', + 'last4' => '0004', + 'scheme' => 'mastercard', + '_links' => { + 'authorizations' => { 'href' => '/cards/58dabba0-e9ea-4133-8c38-bfa1028c1ed2/authorizations' }, + 'credits'=> { 'href' => '/cards/58dabba0-e9ea-4133-8c38-bfa1028c1ed2/credits' } } }.to_json end @@ -468,7 +468,7 @@ def failed_store_response end def failed_ch_response - { "status" => { "code" => 40000, "message" => "General input error" }}.to_json + { 'status' => { 'code' => 40000, 'message' => 'General input error' }}.to_json end end diff --git a/test/unit/gateways/commercegate_test.rb b/test/unit/gateways/commercegate_test.rb index dc2d894741e..eeb2f2e13ea 100644 --- a/test/unit/gateways/commercegate_test.rb +++ b/test/unit/gateways/commercegate_test.rb @@ -24,8 +24,8 @@ def test_successful_authorize assert_instance_of Response, response assert_success response assert_equal '100130291387', response.authorization - assert_equal 'U', response.avs_result["code"] - assert_equal 'S', response.cvv_result["code"] + assert_equal 'U', response.avs_result['code'] + assert_equal 'S', response.cvv_result['code'] end def test_successful_capture @@ -44,8 +44,8 @@ def test_successful_purchase assert_instance_of Response, response assert_success response assert_equal '100130291412', response.authorization - assert_equal 'U', response.avs_result["code"] - assert_equal 'S', response.cvv_result["code"] + assert_equal 'U', response.avs_result['code'] + assert_equal 'S', response.cvv_result['code'] assert_equal 'rdkhkRXjPVCXf5jU2Zz5NCcXBihGuaNz', response.params['token'] end @@ -59,7 +59,6 @@ def test_successful_refund assert_equal 'EUR', response.params['currencyCode'] end - def test_successful_void @gateway.expects(:ssl_post).returns(successful_void_response) assert response = @gateway.void('100130291412', @options) @@ -97,34 +96,34 @@ def test_unsuccessful_capture_trans_id_not_found private def failed_request_response - "returnCode=-125&returnText=Invalid+operation" + 'returnCode=-125&returnText=Invalid+operation' end def successful_purchase_response - "action=SALE&returnCode=0&returnText=Success&authCode=040404&avsCode=U&cvvCode=S&amount=10.00&currencyCode=EUR&transID=100130291412&token=rdkhkRXjPVCXf5jU2Zz5NCcXBihGuaNz" + 'action=SALE&returnCode=0&returnText=Success&authCode=040404&avsCode=U&cvvCode=S&amount=10.00&currencyCode=EUR&transID=100130291412&token=rdkhkRXjPVCXf5jU2Zz5NCcXBihGuaNz' end def successful_authorize_response - "action=AUTH&returnCode=0&returnText=Success&authCode=726293&avsCode=U&cvvCode=S&amount=10.00&currencyCode=EUR&transID=100130291387&token=Hf4lDYcKdJsdX92WJ2CpNlEUdh05utsI" + 'action=AUTH&returnCode=0&returnText=Success&authCode=726293&avsCode=U&cvvCode=S&amount=10.00&currencyCode=EUR&transID=100130291387&token=Hf4lDYcKdJsdX92WJ2CpNlEUdh05utsI' end def failed_authorize_response_invalid_country - "action=AUTH&returnCode=-103&returnText=Invalid+country" + 'action=AUTH&returnCode=-103&returnText=Invalid+country' end def successful_capture_response - "action=CAPTURE&returnCode=0&returnText=Success&amount=10.00&currencyCode=EUR&transID=100130291402" + 'action=CAPTURE&returnCode=0&returnText=Success&amount=10.00&currencyCode=EUR&transID=100130291402' end def failed_capture_response_invalid_trans_id - "action=CAPTURE&returnCode=-121&returnText=Previous+transaction+not+found" + 'action=CAPTURE&returnCode=-121&returnText=Previous+transaction+not+found' end def successful_refund_response - "action=REFUND&returnCode=0&returnText=Success&amount=10.00&currencyCode=EUR&transID=100130291425" + 'action=REFUND&returnCode=0&returnText=Success&amount=10.00&currencyCode=EUR&transID=100130291425' end def successful_void_response - "action=VOID_AUTH&returnCode=0&returnText=Success&amount=10.00&currencyCode=EUR&transID=100130425094" + 'action=VOID_AUTH&returnCode=0&returnText=Success&amount=10.00&currencyCode=EUR&transID=100130425094' end end diff --git a/test/unit/gateways/conekta_test.rb b/test/unit/gateways/conekta_test.rb index e8e04eedd59..215a50b1ba3 100644 --- a/test/unit/gateways/conekta_test.rb +++ b/test/unit/gateways/conekta_test.rb @@ -1,42 +1,44 @@ require 'test_helper' class ConektaTest < Test::Unit::TestCase + include CommStub + def setup - @gateway = ConektaGateway.new(:key => "key_eYvWV7gSDkNYXsmr") + @gateway = ConektaGateway.new(:key => 'key_eYvWV7gSDkNYXsmr') @amount = 300 @credit_card = ActiveMerchant::Billing::CreditCard.new( - :number => "4242424242424242", - :verification_value => "183", - :month => "01", - :year => "2018", - :first_name => "Mario F.", - :last_name => "Moreno Reyes" + :number => '4242424242424242', + :verification_value => '183', + :month => '01', + :year => '2018', + :first_name => 'Mario F.', + :last_name => 'Moreno Reyes' ) @declined_card = ActiveMerchant::Billing::CreditCard.new( - :number => "4000000000000002", - :verification_value => "183", - :month => "01", - :year => "2018", - :first_name => "Mario F.", - :last_name => "Moreno Reyes" + :number => '4000000000000002', + :verification_value => '183', + :month => '01', + :year => '2018', + :first_name => 'Mario F.', + :last_name => 'Moreno Reyes' ) @options = { - :device_fingerprint => "41l9l92hjco6cuekf0c7dq68v4", + :device_fingerprint => '41l9l92hjco6cuekf0c7dq68v4', :description => 'Blue clip', - :success_url => "https://www.example.com/success", - :failure_url => "https://www.example.com/failure", - :address1 => "Rio Missisipi #123", - :address2 => "Paris", - :city => "Guerrero", - :country => "Mexico", - :zip => "5555", - :name => "Mario Reyes", - :phone => "12345678", - :carrier => "Estafeta" + :success_url => 'https://www.example.com/success', + :failure_url => 'https://www.example.com/failure', + :address1 => 'Rio Missisipi #123', + :address2 => 'Paris', + :city => 'Guerrero', + :country => 'Mexico', + :zip => '5555', + :customer => 'Mario Reyes', + :phone => '12345678', + :carrier => 'Estafeta' } end @@ -65,9 +67,20 @@ def test_unsuccessful_purchase assert response.test? end + def test_successful_purchase_with_installments + response = stub_comms(@gateway, :ssl_request) do + @gateway.purchase(@amount, @credit_card, @options.merge({monthly_installments: '3'})) + end.check_request do |method, endpoint, data, headers| + assert_match %r{monthly_installments=3}, data + end.respond_with(successful_purchase_response) + + assert_success response + assert response.test? + end + def test_unsuccessful_refund @gateway.expects(:ssl_request).returns(failed_refund_response) - assert response = @gateway.refund(@amount, "1", @options) + assert response = @gateway.refund(@amount, '1', @options) assert_failure response assert response.test? end @@ -120,7 +133,7 @@ def test_unsuccessful_authorize def test_unsuccessful_capture @gateway.expects(:ssl_request).returns(failed_purchase_response) - assert response = @gateway.capture(@amount, "1", @options) + assert response = @gateway.capture(@amount, '1', @options) assert_failure response assert response.test? end @@ -133,6 +146,26 @@ def test_invalid_key assert response.test? end + def test_adds_application_and_meta_headers + application = { + name: 'app', + version: '1.0', + url: 'https://example.com' + } + + response = stub_comms(@gateway, :ssl_request) do + @gateway.purchase(@amount, 'tok_xxxxxxxxxxxxxxxx', @options.merge(application: application, meta: {its_so_meta: 'even this acronym'})) + end.check_request do |method, endpoint, data, headers| + assert_match(/\"application\"/, headers['X-Conekta-Client-User-Agent']) + assert_match(/\"name\":\"app\"/, headers['X-Conekta-Client-User-Agent']) + assert_match(/\"version\":\"1.0\"/, headers['X-Conekta-Client-User-Agent']) + assert_match(/\"url\":\"https:\/\/example.com\"/, headers['X-Conekta-Client-User-Agent']) + assert_match(/\"its_so_meta\":\"even this acronym\"/, headers['X-Conekta-Client-User-Metadata']) + end.respond_with(successful_purchase_response) + + assert_success response + end + def test_transcript_scrubbing assert_equal scrubbed_transcript, @gateway.scrub(transcript) end @@ -373,10 +406,10 @@ def failed_login_response end def transcript - "card%5Baddress%5D%5Bzip%5D=5555&card%5Bcvc%5D=183&card%5Bexp_month%5D=01&card%5Bexp_year%5D=18&card%5Bname%5D=Mario+F.+Moreno+Reyes&card%5Bnumber%5D=4242424242424242&currency=mxn&description=Blue+clip&details%5Bbilling_address%5D%5Bcity%5D=Guerrero" + 'card%5Baddress%5D%5Bzip%5D=5555&card%5Bcvc%5D=183&card%5Bexp_month%5D=01&card%5Bexp_year%5D=18&card%5Bname%5D=Mario+F.+Moreno+Reyes&card%5Bnumber%5D=4242424242424242&currency=mxn&description=Blue+clip&details%5Bbilling_address%5D%5Bcity%5D=Guerrero' end def scrubbed_transcript - "card%5Baddress%5D%5Bzip%5D=5555&card%5Bcvc%5D=[FILTERED]&card%5Bexp_month%5D=01&card%5Bexp_year%5D=18&card%5Bname%5D=Mario+F.+Moreno+Reyes&card%5Bnumber%5D=[FILTERED]&currency=mxn&description=Blue+clip&details%5Bbilling_address%5D%5Bcity%5D=Guerrero" + 'card%5Baddress%5D%5Bzip%5D=5555&card%5Bcvc%5D=[FILTERED]&card%5Bexp_month%5D=01&card%5Bexp_year%5D=18&card%5Bname%5D=Mario+F.+Moreno+Reyes&card%5Bnumber%5D=[FILTERED]&currency=mxn&description=Blue+clip&details%5Bbilling_address%5D%5Bcity%5D=Guerrero' end end diff --git a/test/unit/gateways/creditcall_test.rb b/test/unit/gateways/creditcall_test.rb index 855fda0056d..146606ff742 100644 --- a/test/unit/gateways/creditcall_test.rb +++ b/test/unit/gateways/creditcall_test.rb @@ -49,42 +49,42 @@ def test_failed_authorize def test_successful_capture @gateway.expects(:ssl_post).returns(successful_capture_response) - response = @gateway.capture(@amount, "bc8e3abe-b842-e511-b302-00505692354f", @options) + response = @gateway.capture(@amount, 'bc8e3abe-b842-e511-b302-00505692354f', @options) assert_success response end def test_failed_capture @gateway.expects(:ssl_post).returns(failed_capture_response) - response = @gateway.capture(@amount, "", @options) + response = @gateway.capture(@amount, '', @options) assert_failure response end def test_successful_refund @gateway.expects(:ssl_post).returns(successful_refund_response) - response = @gateway.refund(@amount, "77e55712-ba42-e511-b302-00505692354f", @options) + response = @gateway.refund(@amount, '77e55712-ba42-e511-b302-00505692354f', @options) assert_success response end def test_failed_refund @gateway.expects(:ssl_post).returns(failed_refund_response) - response = @gateway.refund(@amount, "", @options) + response = @gateway.refund(@amount, '', @options) assert_failure response end def test_successful_void @gateway.expects(:ssl_post).returns(successful_void_response) - response = @gateway.void("e5b1b672-ba42-e511-b302-00505692354f", @options) + response = @gateway.void('e5b1b672-ba42-e511-b302-00505692354f', @options) assert_success response end def test_failed_void @gateway.expects(:ssl_post).returns(failed_void_response) - response = @gateway.void("", @options) + response = @gateway.void('', @options) assert_failure response end @@ -118,7 +118,7 @@ def test_verification_value_sent end def test_verification_value_not_sent - @credit_card.verification_value = " " + @credit_card.verification_value = ' ' stub_comms do @gateway.authorize(@amount, @credit_card, @options) end.check_request do |endpoint, data, headers| @@ -126,6 +126,32 @@ def test_verification_value_not_sent end.respond_with(successful_authorize_response) end + def test_options_add_avs_additional_verification_fields + stub_comms do + @gateway.authorize(@amount, @credit_card, @options) + end.check_request do |endpoint, data, headers| + assert_no_match(/AdditionalVerification/, data) + end.respond_with(successful_authorize_response) + + stub_comms do + @gateway.authorize(@amount, @credit_card, @options.merge(verify_zip: 'false', verify_address: 'false')) + end.check_request do |endpoint, data, headers| + assert_no_match(/AdditionalVerification/, data) + end.respond_with(successful_authorize_response) + + stub_comms do + @gateway.authorize(@amount, @credit_card, @options.merge(verify_zip: 'true', verify_address: 'true')) + end.check_request do |endpoint, data, headers| + assert_match(/<AdditionalVerification>\n <Zip>K1C2N6<\/Zip>\n <Address>/, data) + end.respond_with(successful_authorize_response) + + stub_comms do + @gateway.authorize(@amount, @credit_card, @options.merge(verify_zip: 'true', verify_address: 'false')) + end.check_request do |endpoint, data, headers| + assert_match(/ <AdditionalVerification>\n <Zip>K1C2N6<\/Zip>\n <\/AdditionalVerification>\n/, data) + end.respond_with(successful_authorize_response) + end + def test_scrub assert @gateway.supports_scrubbing? assert_equal @gateway.scrub(pre_scrubbed), post_scrubbed @@ -147,7 +173,7 @@ def post_scrubbed def successful_purchase_response %( - <?xml version=\"1.0\" encoding=\"utf-8\"?><Response type=\"CardEaseXML\" version=\"1.0.0\"><TransactionDetails><CardEaseReference>0999da90-b342-e511-b302-00505692354f</CardEaseReference><LocalDateTime format=\"yyyyMMddHHmmss\">20150814143753</LocalDateTime><UTC format=\"yyyyMMddHHmmss\">20150814183753</UTC></TransactionDetails><Result><LocalResult>0</LocalResult><AuthorisationEntity>Unknown</AuthorisationEntity></Result></Response> + <?xml version=\"1.0\" encoding=\"utf-8\"?><Response type=\"CardEaseXML\" version=\"1.0.0\"><TransactionDetails><CardEaseReference>0999da90-b342-e511-b302-00505692354f</CardEaseReference><LocalDateTime format=\"yyyyMMddHHmmss\">20150814143753</LocalDateTime><UTC format=\"yyyyMMddHHmmss\">20150814183753</UTC></TransactionDetails><Result><LocalResult>0</LocalResult><AuthorisationEntity>Unknown</AuthorisationEntity></Result><CardDetails><CardReference>c2c5fa63-3dd1-da11-8531-01422187e37</CardReference><CardHash>8CtuNPQnryhFt6amPWtp6PLZYXI=</CardHash><PAN>341111xxxxx1002</PAN><ExpiryDate format=”yyMM”>2012</ExpiryDate><CardScheme><Description>AMEX</Description></CardScheme></CardDetails></Response> ) end diff --git a/test/unit/gateways/credorax_test.rb b/test/unit/gateways/credorax_test.rb index 6498d449c14..c93b3987470 100644 --- a/test/unit/gateways/credorax_test.rb +++ b/test/unit/gateways/credorax_test.rb @@ -14,221 +14,281 @@ def setup } end - def test_successful_purchase - response = stub_comms do - @gateway.purchase(@amount, @credit_card) - end.respond_with(successful_purchase_response) - - assert_success response - - assert_equal "8a82944a5351570601535955efeb513c;006596;02617cf5f02ccaed239b6521748298c5;purchase", response.authorization - assert response.test? - end - - def test_failed_purchase - response = stub_comms do - @gateway.purchase(@amount, @credit_card) - end.respond_with(failed_purchase_response) - - assert_failure response - assert_equal "Transaction has been declined.", response.message - assert response.test? - end - - def test_successful_authorize_and_capture - response = stub_comms do - @gateway.authorize(@amount, @credit_card) - end.respond_with(successful_authorize_response) - - assert_success response - assert_equal "8a829449535154bc0153595952a2517a;006597;90f7449d555f7bed0a2c5d780475f0bf;authorize", response.authorization - - capture = stub_comms do - @gateway.capture(@amount, response.authorization) - end.check_request do |endpoint, data, headers| - assert_match(/8a829449535154bc0153595952a2517a/, data) - end.respond_with(successful_capture_response) - - assert_success capture - end - - def test_failed_authorize - response = stub_comms do - @gateway.authorize(@amount, @credit_card) - end.respond_with(failed_authorize_response) - - assert_failure response - assert_equal "Transaction has been declined.", response.message - assert response.test? - end - - def test_failed_capture - response = stub_comms do - @gateway.capture(100, "") - end.respond_with(failed_capture_response) - - assert_failure response - end - - def test_successful_void - response = stub_comms do - @gateway.purchase(@amount, @credit_card) - end.respond_with(successful_authorize_response) - - assert_success response - assert_equal "8a829449535154bc0153595952a2517a;006597;90f7449d555f7bed0a2c5d780475f0bf;purchase", response.authorization - - void = stub_comms do - @gateway.void(response.authorization) - end.check_request do |endpoint, data, headers| - assert_match(/8a829449535154bc0153595952a2517a/, data) - end.respond_with(successful_void_response) - - assert_success void - end - - def test_failed_void - response = stub_comms do - @gateway.void("5d53a33d960c46d00f5dc061947d998c") - end.check_request do |endpoint, data, headers| - assert_match(/5d53a33d960c46d00f5dc061947d998c/, data) - end.respond_with(failed_void_response) - - assert_failure response - end - - def test_successful_refund - response = stub_comms do - @gateway.purchase(@amount, @credit_card) - end.respond_with(successful_purchase_response) - - assert_success response - assert_equal "8a82944a5351570601535955efeb513c;006596;02617cf5f02ccaed239b6521748298c5;purchase", response.authorization - - refund = stub_comms do - @gateway.refund(@amount, response.authorization) - end.check_request do |endpoint, data, headers| - assert_match(/8a82944a5351570601535955efeb513c/, data) - end.respond_with(successful_refund_response) - - assert_success refund - end - - def test_failed_refund - response = stub_comms do - @gateway.refund(nil, "") - end.respond_with(failed_refund_response) - - assert_failure response - end - - def test_successful_credit - response = stub_comms do - @gateway.credit(@amount, @credit_card) - end.respond_with(successful_credit_response) - - assert_success response - - assert_equal "8a82944a53515706015359604c135301;;868f8b942fae639d28e27e8933d575d4;credit", response.authorization - assert response.test? - end - - def test_failed_credit - response = stub_comms do - @gateway.credit(@amount, @credit_card) - end.respond_with(failed_credit_response) - - assert_failure response - assert_equal "Transaction has been declined.", response.message - assert response.test? - end - - def test_successful_verify - response = stub_comms do - @gateway.verify(@credit_card) - end.respond_with(successful_authorize_response, failed_void_response) - assert_success response - assert_equal "Succeeded", response.message - end - - def test_failed_verify - response = stub_comms do - @gateway.verify(@credit_card) - end.respond_with(failed_authorize_response, successful_void_response) - assert_failure response - assert_equal "Transaction has been declined.", response.message - end - - def test_empty_response_fails - response = stub_comms do - @gateway.purchase(@amount, @credit_card) - end.respond_with(empty_purchase_response) - - assert_failure response - assert_equal "Unable to read error message", response.message - end - - def test_transcript_scrubbing - assert_equal scrubbed_transcript, @gateway.scrub(transcript) - end - - private - - def successful_purchase_response - "M=SPREE978&O=1&T=03%2F09%2F2016+03%3A05%3A16&V=413&a1=02617cf5f02ccaed239b6521748298c5&a2=2&a4=100&a9=6&z1=8a82944a5351570601535955efeb513c&z13=606944188282&z14=U&z15=100&z2=0&z3=Transaction+has+been+executed+successfully.&z4=006596&z5=0&z6=00&z9=X&K=057e123af2fba5a37b4df76a7cb5cfb6" - end - - def failed_purchase_response - "M=SPREE978&O=1&T=03%2F09%2F2016+03%3A05%3A47&V=413&a1=92176aca194ceafdb4a679389b77f207&a2=2&a4=100&a9=6&z1=8a82944a535157060153595668fd5162&z13=606944188283&z15=100&z2=05&z3=Transaction+has+been+declined.&z5=0&z6=57&K=2d44820a5a907ff820f928696e460ce1" - end - - def successful_authorize_response - "M=SPREE978&O=2&T=03%2F09%2F2016+03%3A08%3A58&V=413&a1=90f7449d555f7bed0a2c5d780475f0bf&a2=2&a4=100&a9=6&z1=8a829449535154bc0153595952a2517a&z13=606944188284&z14=U&z15=100&z2=0&z3=Transaction+has+been+executed+successfully.&z4=006597&z5=0&z6=00&z9=X&K=00effd2c80ab7ecd45b499c0bbea3d20" - end - - def failed_authorize_response - "M=SPREE978&O=2&T=03%2F09%2F2016+03%3A10%3A02&V=413&a1=9bd85e23639ffcd5206f8e7fe4e3d365&a2=2&a4=100&a9=6&z1=8a829449535154bc0153595a4bb051ac&z13=606944188285&z15=100&z2=05&z3=Transaction+has+been+declined.&z5=0&z6=57&K=2fe3ee6b975d1e4ba542c1e7549056f6" - end - - def successful_capture_response - "M=SPREE978&O=3&T=03%2F09%2F2016+03%3A09%3A03&V=413&a1=2a349969e0ed61fb0db59fc9f32d2fb3&a2=2&a4=100&g2=8a829449535154bc0153595952a2517a&g3=006597&g4=90f7449d555f7bed0a2c5d780475f0bf&z1=8a82944a535157060153595966ba51f9&z13=606944188284&z15=100&z2=0&z3=Transaction+has+been+executed+successfully.&z4=006597&z5=0&z6=00&K=4ad979199490a8d000302735220edfa6" - end - - def failed_capture_response - "M=SPREE978&O=3&T=03%2F09%2F2016+03%3A10%3A33&V=413&a1=eed7c896e1355dc4007c0c8df44d5852&a2=2&a4=100&a5=EUR&b1=-&z1=1A-1&z2=-9&z3=2.+At+least+one+of+input+parameters+is+malformed.%3A+Parameter+%5Bg4%5D+cannot+be+empty.&K=8d1d8f2f9feeb7909aa3e6c428903d57" - end - - def successful_void_response - "M=SPREE978&O=4&T=03%2F09%2F2016+03%3A11%3A11&V=413&a1=&a2=2&a4=100&g2=8a82944a535157060153595b484a524d&g3=006598&g4=0d600bf50198059dbe61979f8c28aab2&z1=8a829449535154bc0153595b57c351d2&z13=606944188287&z15=100&z2=0&z3=Transaction+has+been+executed+successfully.&z4=006598&z5=0&z6=00&K=e643b9e88b35fd69d5421b59c611a6c9" - end - - def failed_void_response - "M=SPREE978&O=4&T=03%2F09%2F2016+03%3A11%3A37&V=413&a1=-&a2=2&a4=-&a5=-&b1=-&z1=1A-1&z2=-9&z3=2.+At+least+one+of+input+parameters+is+malformed.%3A+Parameter+%5Bg4%5D+cannot+be+empty.&K=1e6683cd7b1d01712f12ce7bfc9a5ad2" - end - - def successful_refund_response - "M=SPREE978&O=5&T=03%2F09%2F2016+03%3A15%3A32&V=413&a1=b449bb41af3eb09fd483e7629eb2266f&a2=2&a4=100&g2=8a82944a535157060153595f3ea352c2&g3=006600&g4=78141b277cfadba072a0bcb90745faef&z1=8a82944a535157060153595f553a52de&z13=606944188288&z15=100&z2=0&z3=Transaction+has+been+executed+successfully.&z4=006600&z5=0&z6=00&K=bfdfd8b0dcee974c07c3c85cfea753fe" - end - - def failed_refund_response - "M=SPREE978&O=5&T=03%2F09%2F2016+03%3A16%3A06&V=413&a1=c2b481deffe0e27bdef1439655260092&a2=2&a4=-&a5=EUR&b1=-&z1=1A-1&z2=-9&z3=2.+At+least+one+of+input+parameters+is+malformed.%3A+Parameter+%5Bg4%5D+cannot+be+empty.&K=c2f6112b40c61859d03684ac8e422766" - end - - def successful_credit_response - "M=SPREE978&O=6&T=03%2F09%2F2016+03%3A16%3A35&V=413&a1=868f8b942fae639d28e27e8933d575d4&a2=2&a4=100&z1=8a82944a53515706015359604c135301&z13=606944188289&z15=100&z2=0&z3=Transaction+has+been+executed+successfully.&z5=0&z6=00&K=51ba24f6ef3aa161f86e53c34c9616ac" - end - - def failed_credit_response - "M=SPREE978&O=6&T=03%2F09%2F2016+03%3A16%3A59&V=413&a1=ff28246cfc811b1c686a52d08d075d9c&a2=2&a4=100&z1=8a829449535154bc01535960a962524f&z13=606944188290&z15=100&z2=05&z3=Transaction+has+been+declined.&z5=0&z6=57&K=cf34816d5c25dc007ef3525505c4c610" - end - - def empty_purchase_response - %( - ) - end - - def transcript - %( + def test_successful_purchase + response = stub_comms do + @gateway.purchase(@amount, @credit_card) + end.check_request do |endpoint, data, headers| + assert_no_match(/i8=sample-eci%3Asample-cavv%3Asample-xid/, data) + end.respond_with(successful_purchase_response) + + assert_success response + + assert_equal '8a82944a5351570601535955efeb513c;006596;02617cf5f02ccaed239b6521748298c5;purchase', response.authorization + assert response.test? + end + + def test_failed_purchase + response = stub_comms do + @gateway.purchase(@amount, @credit_card) + end.respond_with(failed_purchase_response) + + assert_failure response + assert_equal 'Transaction not allowed for cardholder', response.message + assert response.test? + end + + def test_successful_authorize_and_capture + response = stub_comms do + @gateway.authorize(@amount, @credit_card) + end.respond_with(successful_authorize_response) + + assert_success response + assert_equal '8a829449535154bc0153595952a2517a;006597;90f7449d555f7bed0a2c5d780475f0bf;authorize', response.authorization + + capture = stub_comms do + @gateway.capture(@amount, response.authorization) + end.check_request do |endpoint, data, headers| + assert_match(/8a829449535154bc0153595952a2517a/, data) + end.respond_with(successful_capture_response) + + assert_success capture + end + + def test_failed_authorize + response = stub_comms do + @gateway.authorize(@amount, @credit_card) + end.respond_with(failed_authorize_response) + + assert_failure response + assert_equal 'Transaction not allowed for cardholder', response.message + assert response.test? + end + + def test_failed_capture + response = stub_comms do + @gateway.capture(100, '') + end.respond_with(failed_capture_response) + + assert_failure response + end + + def test_successful_void + response = stub_comms do + @gateway.purchase(@amount, @credit_card) + end.respond_with(successful_authorize_response) + + assert_success response + assert_equal '8a829449535154bc0153595952a2517a;006597;90f7449d555f7bed0a2c5d780475f0bf;purchase', response.authorization + + void = stub_comms do + @gateway.void(response.authorization) + end.check_request do |endpoint, data, headers| + assert_match(/8a829449535154bc0153595952a2517a/, data) + end.respond_with(successful_void_response) + + assert_success void + end + + def test_failed_void + response = stub_comms do + @gateway.void('5d53a33d960c46d00f5dc061947d998c') + end.check_request do |endpoint, data, headers| + assert_match(/5d53a33d960c46d00f5dc061947d998c/, data) + end.respond_with(failed_void_response) + + assert_failure response + end + + def test_successful_refund + response = stub_comms do + @gateway.purchase(@amount, @credit_card) + end.respond_with(successful_purchase_response) + + assert_success response + assert_equal '8a82944a5351570601535955efeb513c;006596;02617cf5f02ccaed239b6521748298c5;purchase', response.authorization + + refund = stub_comms do + @gateway.refund(@amount, response.authorization) + end.check_request do |endpoint, data, headers| + assert_match(/8a82944a5351570601535955efeb513c/, data) + end.respond_with(successful_refund_response) + + assert_success refund + end + + def test_failed_refund + response = stub_comms do + @gateway.refund(nil, '') + end.respond_with(failed_refund_response) + + assert_failure response + end + + def test_successful_credit + response = stub_comms do + @gateway.credit(@amount, @credit_card) + end.respond_with(successful_credit_response) + + assert_success response + + assert_equal '8a82944a53515706015359604c135301;;868f8b942fae639d28e27e8933d575d4;credit', response.authorization + assert response.test? + end + + def test_failed_credit + response = stub_comms do + @gateway.credit(@amount, @credit_card) + end.respond_with(failed_credit_response) + + assert_failure response + assert_equal 'Transaction not allowed for cardholder', response.message + assert response.test? + end + + def test_successful_verify + response = stub_comms do + @gateway.verify(@credit_card) + end.respond_with(successful_authorize_response, failed_void_response) + assert_success response + assert_equal 'Succeeded', response.message + end + + def test_failed_verify + response = stub_comms do + @gateway.verify(@credit_card) + end.respond_with(failed_authorize_response, successful_void_response) + assert_failure response + assert_equal 'Transaction not allowed for cardholder', response.message + end + + def test_empty_response_fails + response = stub_comms do + @gateway.purchase(@amount, @credit_card) + end.respond_with(empty_purchase_response) + + assert_failure response + assert_equal 'Unable to read error message', response.message + end + + def test_transcript_scrubbing + assert_equal scrubbed_transcript, @gateway.scrub(transcript) + end + + def test_adds_3d_secure_fields + options_with_3ds = @options.merge({eci: 'sample-eci', cavv: 'sample-cavv', xid: 'sample-xid'}) + + response = stub_comms do + @gateway.purchase(@amount, @credit_card, options_with_3ds) + end.check_request do |endpoint, data, headers| + assert_match(/i8=sample-eci%3Asample-cavv%3Asample-xid/, data) + end.respond_with(successful_purchase_response) + + assert_success response + + assert_equal '8a82944a5351570601535955efeb513c;006596;02617cf5f02ccaed239b6521748298c5;purchase', response.authorization + assert response.test? + end + + def test_defaults_3d_secure_cavv_field_to_none_if_not_present + options_with_3ds = @options.merge({eci: 'sample-eci', xid: 'sample-xid'}) + + response = stub_comms do + @gateway.purchase(@amount, @credit_card, options_with_3ds) + end.check_request do |endpoint, data, headers| + assert_match(/i8=sample-eci%3Anone%3Asample-xid/, data) + end.respond_with(successful_purchase_response) + + assert_success response + + assert_equal '8a82944a5351570601535955efeb513c;006596;02617cf5f02ccaed239b6521748298c5;purchase', response.authorization + assert response.test? + end + + def test_adds_a9_field + options_with_3ds = @options.merge({transaction_type: '8'}) + + stub_comms do + @gateway.purchase(@amount, @credit_card, options_with_3ds) + end.check_request do |endpoint, data, headers| + assert_match(/a9=8/, data) + end.respond_with(successful_purchase_response) + end + + def test_adds_submerchant_id + @options[:submerchant_id] = '12345' + stub_comms do + @gateway.purchase(@amount, @credit_card, @options) + end.check_request do |endpoint, data, headers| + assert_match(/h3=12345/, data) + end.respond_with(successful_purchase_response) + end + + def test_supports_billing_descriptor + @options[:billing_descriptor] = 'abcdefghijkl' + stub_comms do + @gateway.purchase(@amount, @credit_card, @options) + end.check_request do |endpoint, data, headers| + assert_match(/i2=abcdefghijkl/, data) + end.respond_with(successful_purchase_response) + end + + private + + def successful_purchase_response + 'M=SPREE978&O=1&T=03%2F09%2F2016+03%3A05%3A16&V=413&a1=02617cf5f02ccaed239b6521748298c5&a2=2&a4=100&a9=6&z1=8a82944a5351570601535955efeb513c&z13=606944188282&z14=U&z15=100&z2=0&z3=Transaction+has+been+executed+successfully.&z4=006596&z5=0&z6=00&z9=X&K=057e123af2fba5a37b4df76a7cb5cfb6' + end + + def failed_purchase_response + 'M=SPREE978&O=1&T=03%2F09%2F2016+03%3A05%3A47&V=413&a1=92176aca194ceafdb4a679389b77f207&a2=2&a4=100&a9=6&z1=8a82944a535157060153595668fd5162&z13=606944188283&z15=100&z2=05&z3=Transaction+has+been+declined.&z5=0&z6=57&K=2d44820a5a907ff820f928696e460ce1' + end + + def successful_authorize_response + 'M=SPREE978&O=2&T=03%2F09%2F2016+03%3A08%3A58&V=413&a1=90f7449d555f7bed0a2c5d780475f0bf&a2=2&a4=100&a9=6&z1=8a829449535154bc0153595952a2517a&z13=606944188284&z14=U&z15=100&z2=0&z3=Transaction+has+been+executed+successfully.&z4=006597&z5=0&z6=00&z9=X&K=00effd2c80ab7ecd45b499c0bbea3d20' + end + + def failed_authorize_response + 'M=SPREE978&O=2&T=03%2F09%2F2016+03%3A10%3A02&V=413&a1=9bd85e23639ffcd5206f8e7fe4e3d365&a2=2&a4=100&a9=6&z1=8a829449535154bc0153595a4bb051ac&z13=606944188285&z15=100&z2=05&z3=Transaction+has+been+declined.&z5=0&z6=57&K=2fe3ee6b975d1e4ba542c1e7549056f6' + end + + def successful_capture_response + 'M=SPREE978&O=3&T=03%2F09%2F2016+03%3A09%3A03&V=413&a1=2a349969e0ed61fb0db59fc9f32d2fb3&a2=2&a4=100&g2=8a829449535154bc0153595952a2517a&g3=006597&g4=90f7449d555f7bed0a2c5d780475f0bf&z1=8a82944a535157060153595966ba51f9&z13=606944188284&z15=100&z2=0&z3=Transaction+has+been+executed+successfully.&z4=006597&z5=0&z6=00&K=4ad979199490a8d000302735220edfa6' + end + + def failed_capture_response + 'M=SPREE978&O=3&T=03%2F09%2F2016+03%3A10%3A33&V=413&a1=eed7c896e1355dc4007c0c8df44d5852&a2=2&a4=100&a5=EUR&b1=-&z1=1A-1&z2=-9&z3=2.+At+least+one+of+input+parameters+is+malformed.%3A+Parameter+%5Bg4%5D+cannot+be+empty.&K=8d1d8f2f9feeb7909aa3e6c428903d57' + end + + def successful_void_response + 'M=SPREE978&O=4&T=03%2F09%2F2016+03%3A11%3A11&V=413&a1=&a2=2&a4=100&g2=8a82944a535157060153595b484a524d&g3=006598&g4=0d600bf50198059dbe61979f8c28aab2&z1=8a829449535154bc0153595b57c351d2&z13=606944188287&z15=100&z2=0&z3=Transaction+has+been+executed+successfully.&z4=006598&z5=0&z6=00&K=e643b9e88b35fd69d5421b59c611a6c9' + end + + def failed_void_response + 'M=SPREE978&O=4&T=03%2F09%2F2016+03%3A11%3A37&V=413&a1=-&a2=2&a4=-&a5=-&b1=-&z1=1A-1&z2=-9&z3=2.+At+least+one+of+input+parameters+is+malformed.%3A+Parameter+%5Bg4%5D+cannot+be+empty.&K=1e6683cd7b1d01712f12ce7bfc9a5ad2' + end + + def successful_refund_response + 'M=SPREE978&O=5&T=03%2F09%2F2016+03%3A15%3A32&V=413&a1=b449bb41af3eb09fd483e7629eb2266f&a2=2&a4=100&g2=8a82944a535157060153595f3ea352c2&g3=006600&g4=78141b277cfadba072a0bcb90745faef&z1=8a82944a535157060153595f553a52de&z13=606944188288&z15=100&z2=0&z3=Transaction+has+been+executed+successfully.&z4=006600&z5=0&z6=00&K=bfdfd8b0dcee974c07c3c85cfea753fe' + end + + def failed_refund_response + 'M=SPREE978&O=5&T=03%2F09%2F2016+03%3A16%3A06&V=413&a1=c2b481deffe0e27bdef1439655260092&a2=2&a4=-&a5=EUR&b1=-&z1=1A-1&z2=-9&z3=2.+At+least+one+of+input+parameters+is+malformed.%3A+Parameter+%5Bg4%5D+cannot+be+empty.&K=c2f6112b40c61859d03684ac8e422766' + end + + def successful_credit_response + 'M=SPREE978&O=6&T=03%2F09%2F2016+03%3A16%3A35&V=413&a1=868f8b942fae639d28e27e8933d575d4&a2=2&a4=100&z1=8a82944a53515706015359604c135301&z13=606944188289&z15=100&z2=0&z3=Transaction+has+been+executed+successfully.&z5=0&z6=00&K=51ba24f6ef3aa161f86e53c34c9616ac' + end + + def failed_credit_response + 'M=SPREE978&O=6&T=03%2F09%2F2016+03%3A16%3A59&V=413&a1=ff28246cfc811b1c686a52d08d075d9c&a2=2&a4=100&z1=8a829449535154bc01535960a962524f&z13=606944188290&z15=100&z2=05&z3=Transaction+has+been+declined.&z5=0&z6=57&K=cf34816d5c25dc007ef3525505c4c610' + end + + def empty_purchase_response + %( + ) + end + + def transcript + %( opening connection to intconsole.credorax.com:443... opened starting SSL for intconsole.credorax.com:443... @@ -245,11 +305,11 @@ def transcript -> "M=SPREE978&O=1&T=03%2F09%2F2016+03%3A03%3A01&V=413&a1=335ebb08c489e6d361108a7eb7d8b92a&a2=2&a4=100&a9=6&z1=8a829449535154bc01535953dd235043&z13=606944188276&z14=U&z15=100&z2=0&z3=Transaction+has+been+executed+successfully.&z4=006592&z5=0&z6=00&z9=X&K=4061e16f39915297827af1586635015a" read 283 bytes Conn close - ) - end + ) + end - def scrubbed_transcript - %( + def scrubbed_transcript + %( opening connection to intconsole.credorax.com:443... opened starting SSL for intconsole.credorax.com:443... @@ -266,6 +326,6 @@ def scrubbed_transcript -> "M=SPREE978&O=1&T=03%2F09%2F2016+03%3A03%3A01&V=413&a1=335ebb08c489e6d361108a7eb7d8b92a&a2=2&a4=100&a9=6&z1=8a829449535154bc01535953dd235043&z13=606944188276&z14=U&z15=100&z2=0&z3=Transaction+has+been+executed+successfully.&z4=006592&z5=0&z6=00&z9=X&K=4061e16f39915297827af1586635015a" read 283 bytes Conn close - ) - end + ) + end end diff --git a/test/unit/gateways/ct_payment_test.rb b/test/unit/gateways/ct_payment_test.rb new file mode 100644 index 00000000000..98da844e37f --- /dev/null +++ b/test/unit/gateways/ct_payment_test.rb @@ -0,0 +1,302 @@ +require 'test_helper' + +class CtPaymentTest < Test::Unit::TestCase + def setup + @gateway = CtPaymentGateway.new(api_key: 'api_key', company_number: 'company number', merchant_number: 'merchant_number') + @credit_card = credit_card + @amount = 100 + + @options = { + order_id: '1', + billing_address: address, + description: 'Store Purchase' + } + end + + def test_successful_purchase + @gateway.expects(:ssl_post).twice.returns(successful_purchase_response, successful_ack_response) + + response = @gateway.purchase(@amount, @credit_card, @options) + assert_success response + + assert_equal '000007708972;443752 ;021efc336262;;', response.authorization + assert response.test? + end + + def test_failed_purchase + @gateway.expects(:ssl_post).returns(failed_purchase_response) + + response = @gateway.purchase(@amount, @credit_card, @options) + assert_failure response + assert_equal Gateway::STANDARD_ERROR_CODE[:card_declined], response.error_code + end + + def test_successful_authorize + @gateway.expects(:ssl_post).twice.returns(successful_authorize_response, successful_ack_response) + + response = @gateway.authorize(@amount, @credit_card, @options) + assert_success response + + assert_equal '000007708990;448572 ;0e7ebe0a804f;;', response.authorization + assert response.test? + end + + def test_failed_authorize + @gateway.expects(:ssl_post).returns(failed_authorize_response) + + response = @gateway.authorize(@amount, @credit_card, @options) + assert_failure response + assert_equal Gateway::STANDARD_ERROR_CODE[:card_declined], response.error_code + end + + def test_successful_capture + @gateway.expects(:ssl_post).twice.returns(successful_capture_response, successful_ack_response) + + response = @gateway.capture(@amount, '000007708990;448572 ;0e7ebe0a804f;', @options) + assert_success response + + assert_equal '000007708991; ;0636aca3dd8e;;', response.authorization + assert response.test? + end + + def test_failed_capture + @gateway.expects(:ssl_post).returns(failed_capture_response) + + response = @gateway.capture(@amount, '0123456789asd;0123456789asdf;12345678', @options) + assert_failure response + assert_equal Gateway::STANDARD_ERROR_CODE[:incorrect_number], response.error_code + end + + def test_successful_refund + @gateway.expects(:ssl_post).twice.returns(successful_refund_response, successful_ack_response) + + response = @gateway.refund(@amount, '000007708990;448572 ;0e7ebe0a804f;', @options) + assert_success response + + assert_equal '000007709004; ;0a08f144b6ea;;', response.authorization + assert response.test? + end + + def test_failed_refund + @gateway.expects(:ssl_post).returns(failed_refund_response) + + response = @gateway.capture(@amount, '0123456789asd;0123456789asdf;12345678', @options) + assert_failure response + assert_equal Gateway::STANDARD_ERROR_CODE[:incorrect_number], response.error_code + end + + def test_successful_void + @gateway.expects(:ssl_post).returns(successful_void_response) + + response = @gateway.void('000007708990;448572 ;0e7ebe0a804f;', @options) + assert_success response + + assert_equal '000007709013; ;0de38871ce96;;', response.authorization + assert response.test? + end + + def test_failed_void + @gateway.expects(:ssl_post).returns(failed_void_response) + + response = @gateway.void('0123456789asd;0123456789asdf;12345678') + assert_failure response + assert_equal Gateway::STANDARD_ERROR_CODE[:incorrect_number], response.error_code + end + + def test_successful_verify + @gateway.expects(:ssl_post).twice.returns(successful_verify_response, successful_ack_response) + + response = @gateway.verify(@credit_card, @options) + assert_success response + + assert_equal '000007709025; ;0b882fe35f69;;', response.authorization + assert response.test? + end + + def test_failed_verify + @gateway.expects(:ssl_post).returns(failed_verify_response) + + response = @gateway.verify(@credit_card, @options) + assert_failure response + assert_equal Gateway::STANDARD_ERROR_CODE[:card_declined], response.error_code + end + + def test_successful_credit + @gateway.expects(:ssl_post).twice.returns(successful_credit_response, successful_ack_response) + + response = @gateway.credit(@amount, @credit_card, @options) + assert_success response + + assert_equal '000007709063; ;054902f2ded0;;', response.authorization + assert response.test? + end + + def test_scrub + assert @gateway.supports_scrubbing? + assert_equal @gateway.scrub(pre_scrubbed), post_scrubbed + end + + private + + def pre_scrubbed + %q( + opening connection to test.ctpaiement.ca:443... + opened + starting SSL for test.ctpaiement.ca:443... + SSL established + <- "POST /v1/purchase HTTP/1.1\r\nContent-Type: application/x-www-form-urlencoded\r\nConnection: close\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nAccept: */*\r\nUser-Agent: Ruby\r\nHost: test.ctpaiement.ca\r\nContent-Length: 528\r\n\r\n" + <- "auth-api-key=R46SNTJ42UCJ3264182Y0T087YHBA50RTK&payload=TWVyY2hhbnRUZXJtaW5hbE51bWJlcj0gICAgICZBbW91bnQ9MDAwMDAwMDAxMDAmT3BlcmF0b3JJRD0wMDAwMDAwMCZDdXJyZW5jeUNvZGU9VVNEJkludm9pY2VOdW1iZXI9MDYzZmI1MmMyOTc2JklucHV0VHlwZT1JJkxhbmd1YWdlQ29kZT1FJkNhcmRUeXBlPVYmQ2FyZE51bWJlcj00NTAxMTYxMTA3MjE3MjE0JkV4cGlyYXRpb25EYXRlPTA3MjAmQ2FyZEhvbGRlckFkZHJlc3M9NDU2IE15IFN0cmVldE90dGF3YSAgICAgICAgICAgICAgICAgIE9OJkNhcmRIb2xkZXJQb3N0YWxDb2RlPSAgIEsxQzJONiZDdXN0b21lck51bWJlcj0wMDAwMDAwMCZDb21wYW55TnVtYmVyPTAwNTg5Jk1lcmNoYW50TnVtYmVyPTUzNDAwMDMw" + -> "HTTP/1.1 200 200\r\n" + -> "Date: Fri, 29 Jun 2018 18:21:07 GMT\r\n" + -> "Server: Apache\r\n" + -> "Strict-Transport-Security: max-age=31536000; includeSubDomains; preload\r\n" + -> "Connection: close\r\n" + -> "Transfer-Encoding: chunked\r\n" + -> "Content-Type: application/json;charset=ISO-8859-1\r\n" + -> "\r\n" + -> "480\r\n" + reading 1152 bytes... + -> "{\"returnCode\":\" 00\",\"errorDescription\":null,\"authorizationNumber\":\"448186 \",\"referenceNumber\":\" \",\"transactionNumber\":\"000007709037\",\"batchNumber\":\"0001\",\"terminalNumber\":\"13366\",\"serverNumber\":\"0001\",\"timeStamp\":\"20180629-14210749\",\"trxCode\":\"00\",\"merchantNumber\":\"53400030\",\"amount\":\"00000000100\",\"invoiceNumber\":\"063fb52c2976\",\"trxType\":\"C\",\"cardType\":\"V\",\"cardNumber\":\"450116XXXXXX7214 \",\"expirationDate\":\"0720\",\"bankTerminalNumber\":\"53400188\",\"trxDate\":\"06292018\",\"trxTime\":\"142107\",\"accountType\":\"0\",\"trxMethod\":\"T@1\",\"languageCode\":\"E\",\"sequenceNumber\":\"000000000028\",\"receiptDisp\":\" APPROVED-THANK YOU \",\"terminalDisp\":\"APPROVED \",\"operatorId\":\"00000000\",\"surchargeAmount\":\"\",\"companyNumber\":\"00589\",\"secureID\":\"\",\"cvv2Cvc2Status\":\" \",\"iopIssuerConfirmationNumber\":null,\"iopIssuerName\":null,\"avsStatus\":null,\"holderName\":null,\"threeDSStatus\":null,\"emvLabel\":null,\"emvAID\":null,\"emvTVR\":null,\"emvTSI\":null,\"emvTC\":null,\"demoMode\":null,\"terminalInvoiceNumber\":null,\"cashbackAmount\":null,\"tipAmount\":null,\"taxAmount\":null,\"cvmResults\":null,\"token\":null,\"customerNumber\":null,\"email\":\"\"}" + read 1152 bytes + reading 2 bytes... + -> "\r\n" + read 2 bytes + -> "0\r\n" + -> "\r\n" + Conn close + opening connection to test.ctpaiement.ca:443... + opened + starting SSL for test.ctpaiement.ca:443... + SSL established + <- "POST /v1/ack HTTP/1.1\r\nContent-Type: application/x-www-form-urlencoded\r\nConnection: close\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nAccept: */*\r\nUser-Agent: Ruby\r\nHost: test.ctpaiement.ca\r\nContent-Length: 156\r\n\r\n" + <- "auth-api-key=R46SNTJ42UCJ3264182Y0T087YHBA50RTK&payload=VHJhbnNhY3Rpb25OdW1iZXI9MDAwMDA3NzA5MDM3JkNvbXBhbnlOdW1iZXI9MDA1ODkmTWVyY2hhbnROdW1iZXI9NTM0MDAwMzA=" + -> "HTTP/1.1 200 200\r\n" + -> "Date: Fri, 29 Jun 2018 18:21:08 GMT\r\n" + -> "Server: Apache\r\n" + -> "Strict-Transport-Security: max-age=31536000; includeSubDomains; preload\r\n" + -> "Connection: close\r\n" + -> "Transfer-Encoding: chunked\r\n" + -> "Content-Type: application/json;charset=ISO-8859-1\r\n" + -> "\r\n" + -> "15\r\n" + reading 21 bytes... + -> "{\"returnCode\":\"true\"}" + read 21 bytes + reading 2 bytes... + -> "\r\n" + read 2 bytes + -> "0\r\n" + -> "\r\n" + Conn close + ) + end + + def post_scrubbed + %q( + opening connection to test.ctpaiement.ca:443... + opened + starting SSL for test.ctpaiement.ca:443... + SSL established + <- "POST /v1/purchase HTTP/1.1\r\nContent-Type: application/x-www-form-urlencoded\r\nConnection: close\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nAccept: */*\r\nUser-Agent: Ruby\r\nHost: test.ctpaiement.ca\r\nContent-Length: 528\r\n\r\n" + <- "auth-api-key=[FILTERED]&payload=[FILTERED]" + -> "HTTP/1.1 200 200\r\n" + -> "Date: Fri, 29 Jun 2018 18:21:07 GMT\r\n" + -> "Server: Apache\r\n" + -> "Strict-Transport-Security: max-age=31536000; includeSubDomains; preload\r\n" + -> "Connection: close\r\n" + -> "Transfer-Encoding: chunked\r\n" + -> "Content-Type: application/json;charset=ISO-8859-1\r\n" + -> "\r\n" + -> "480\r\n" + reading 1152 bytes... + -> "{\"returnCode\":\" 00\",\"errorDescription\":null,\"authorizationNumber\":\"448186 \",\"referenceNumber\":\" \",\"transactionNumber\":\"000007709037\",\"batchNumber\":\"0001\",\"terminalNumber\":\"13366\",\"serverNumber\":\"0001\",\"timeStamp\":\"20180629-14210749\",\"trxCode\":\"00\",\"merchantNumber\":\"53400030\",\"amount\":\"00000000100\",\"invoiceNumber\":\"063fb52c2976\",\"trxType\":\"C\",\"cardType\":\"V\",\"cardNumber\":\"450116XXXXXX7214 \",\"expirationDate\":\"0720\",\"bankTerminalNumber\":\"53400188\",\"trxDate\":\"06292018\",\"trxTime\":\"142107\",\"accountType\":\"0\",\"trxMethod\":\"T@1\",\"languageCode\":\"E\",\"sequenceNumber\":\"000000000028\",\"receiptDisp\":\" APPROVED-THANK YOU \",\"terminalDisp\":\"APPROVED \",\"operatorId\":\"00000000\",\"surchargeAmount\":\"\",\"companyNumber\":\"00589\",\"secureID\":\"\",\"cvv2Cvc2Status\":\" \",\"iopIssuerConfirmationNumber\":null,\"iopIssuerName\":null,\"avsStatus\":null,\"holderName\":null,\"threeDSStatus\":null,\"emvLabel\":null,\"emvAID\":null,\"emvTVR\":null,\"emvTSI\":null,\"emvTC\":null,\"demoMode\":null,\"terminalInvoiceNumber\":null,\"cashbackAmount\":null,\"tipAmount\":null,\"taxAmount\":null,\"cvmResults\":null,\"token\":null,\"customerNumber\":null,\"email\":\"\"}" + read 1152 bytes + reading 2 bytes... + -> "\r\n" + read 2 bytes + -> "0\r\n" + -> "\r\n" + Conn close + opening connection to test.ctpaiement.ca:443... + opened + starting SSL for test.ctpaiement.ca:443... + SSL established + <- "POST /v1/ack HTTP/1.1\r\nContent-Type: application/x-www-form-urlencoded\r\nConnection: close\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nAccept: */*\r\nUser-Agent: Ruby\r\nHost: test.ctpaiement.ca\r\nContent-Length: 156\r\n\r\n" + <- "auth-api-key=[FILTERED]&payload=[FILTERED]" + -> "HTTP/1.1 200 200\r\n" + -> "Date: Fri, 29 Jun 2018 18:21:08 GMT\r\n" + -> "Server: Apache\r\n" + -> "Strict-Transport-Security: max-age=31536000; includeSubDomains; preload\r\n" + -> "Connection: close\r\n" + -> "Transfer-Encoding: chunked\r\n" + -> "Content-Type: application/json;charset=ISO-8859-1\r\n" + -> "\r\n" + -> "15\r\n" + reading 21 bytes... + -> "{\"returnCode\":\"true\"}" + read 21 bytes + reading 2 bytes... + -> "\r\n" + read 2 bytes + -> "0\r\n" + -> "\r\n" + Conn close + ) + end + + def successful_purchase_response + '{"returnCode":" 00","errorDescription":null,"authorizationNumber":"443752 ","referenceNumber":" ","transactionNumber":"000007708972","batchNumber":"0001","terminalNumber":"13366","serverNumber":"0001","timeStamp":"20180629-12110905","trxCode":"00","merchantNumber":"53400030","amount":"00000000100","invoiceNumber":"021efc336262","trxType":"C","cardType":"V","cardNumber":"450116XXXXXX7214 ","expirationDate":"0720","bankTerminalNumber":"53400188","trxDate":"06292018","trxTime":"121109","accountType":"0","trxMethod":"T@1","languageCode":"E","sequenceNumber":"000000000008","receiptDisp":" APPROVED-THANK YOU ","terminalDisp":"APPROVED ","operatorId":"00000000","surchargeAmount":"","companyNumber":"00589","secureID":"","cvv2Cvc2Status":" ","iopIssuerConfirmationNumber":null,"iopIssuerName":null,"avsStatus":null,"holderName":null,"threeDSStatus":null,"emvLabel":null,"emvAID":null,"emvTVR":null,"emvTSI":null,"emvTC":null,"demoMode":null,"terminalInvoiceNumber":null,"cashbackAmount":null,"tipAmount":null,"taxAmount":null,"cvmResults":null,"token":null,"customerNumber":null,"email":""}' + end + + def successful_ack_response + '{"returnCode":"true"}' + end + + def failed_purchase_response + '{"returnCode":" 05","errorDescription":"Transaction declined","authorizationNumber":" ","referenceNumber":" ","transactionNumber":"000007708975","batchNumber":"0000","terminalNumber":"13366","serverNumber":"0001","timeStamp":"20180629-12272768","trxCode":"00","merchantNumber":"53400030","amount":"00000000100","invoiceNumber":"098096b31937","trxType":"C","cardType":"V","cardNumber":"450224XXXXXX1718 ","expirationDate":"0919","bankTerminalNumber":"53400188","trxDate":"06292018","trxTime":"122727","accountType":"0","trxMethod":"T@1","languageCode":"E","sequenceNumber":"000000000009","receiptDisp":" TRANSACTION NOT APPROVED ","terminalDisp":"05-DECLINE ","operatorId":"00000000","surchargeAmount":"","companyNumber":"00589","secureID":"","cvv2Cvc2Status":" ","iopIssuerConfirmationNumber":null,"iopIssuerName":null,"avsStatus":null,"holderName":null,"threeDSStatus":null,"emvLabel":null,"emvAID":null,"emvTVR":null,"emvTSI":null,"emvTC":null,"demoMode":null,"terminalInvoiceNumber":null,"cashbackAmount":null,"tipAmount":null,"taxAmount":null,"cvmResults":null,"token":null,"customerNumber":null,"email":""}' + end + + def successful_authorize_response + '{"returnCode":" 00","errorDescription":null,"authorizationNumber":"448572 ","referenceNumber":" ","transactionNumber":"000007708990","batchNumber":"0001","terminalNumber":"13367","serverNumber":"0001","timeStamp":"20180629-12501747","trxCode":"01","merchantNumber":"53400030","amount":"00000000100","invoiceNumber":"0e7ebe0a804f","trxType":"C","cardType":"V","cardNumber":"450116XXXXXX7214 ","expirationDate":"0720","bankTerminalNumber":"53400189","trxDate":"06292018","trxTime":"125017","accountType":"0","trxMethod":"T@1","languageCode":"E","sequenceNumber":"000000000014","receiptDisp":" APPROVED-THANK YOU ","terminalDisp":"APPROVED ","operatorId":"00000000","surchargeAmount":"","companyNumber":"00589","secureID":"","cvv2Cvc2Status":" ","iopIssuerConfirmationNumber":null,"iopIssuerName":null,"avsStatus":null,"holderName":null,"threeDSStatus":null,"emvLabel":null,"emvAID":null,"emvTVR":null,"emvTSI":null,"emvTC":null,"demoMode":null,"terminalInvoiceNumber":null,"cashbackAmount":null,"tipAmount":null,"taxAmount":null,"cvmResults":null,"token":null,"customerNumber":null,"email":""}' + end + + def failed_authorize_response + '{"returnCode":" 05","errorDescription":"Transaction declined","authorizationNumber":" ","referenceNumber":" ","transactionNumber":"000007708993","batchNumber":"0000","terminalNumber":"13367","serverNumber":"0001","timeStamp":"20180629-13072751","trxCode":"01","merchantNumber":"53400030","amount":"00000000100","invoiceNumber":"02ec22cbb5db","trxType":"C","cardType":"V","cardNumber":"450224XXXXXX1718 ","expirationDate":"0919","bankTerminalNumber":"53400189","trxDate":"06292018","trxTime":"130727","accountType":"0","trxMethod":"T@1","languageCode":"E","sequenceNumber":"000000000015","receiptDisp":" TRANSACTION NOT APPROVED ","terminalDisp":"05-DECLINE ","operatorId":"00000000","surchargeAmount":"","companyNumber":"00589","secureID":"","cvv2Cvc2Status":" ","iopIssuerConfirmationNumber":null,"iopIssuerName":null,"avsStatus":null,"holderName":null,"threeDSStatus":null,"emvLabel":null,"emvAID":null,"emvTVR":null,"emvTSI":null,"emvTC":null,"demoMode":null,"terminalInvoiceNumber":null,"cashbackAmount":null,"tipAmount":null,"taxAmount":null,"cvmResults":null,"token":null,"customerNumber":null,"email":""}' + end + + def successful_capture_response + '{"returnCode":" 00","errorDescription":null,"authorizationNumber":" ","referenceNumber":" ","transactionNumber":"000007708991","batchNumber":"0001","terminalNumber":"13366","serverNumber":"0001","timeStamp":"20180629-12501869","trxCode":"02","merchantNumber":"53400030","amount":"00000000100","invoiceNumber":"0636aca3dd8e","trxType":"C","cardType":"V","cardNumber":"450116XXXXXX7214 ","expirationDate":"0720","bankTerminalNumber":"53400188","trxDate":"06292018","trxTime":"125018","accountType":"0","trxMethod":"T@1","languageCode":"E","sequenceNumber":"000000000015","receiptDisp":" APPROVED-THANK YOU ","terminalDisp":"APPROVED ","operatorId":"00000000","surchargeAmount":"","companyNumber":"00589","secureID":"","cvv2Cvc2Status":" ","iopIssuerConfirmationNumber":null,"iopIssuerName":null,"avsStatus":null,"holderName":null,"threeDSStatus":null,"emvLabel":null,"emvAID":null,"emvTVR":null,"emvTSI":null,"emvTC":null,"demoMode":null,"terminalInvoiceNumber":null,"cashbackAmount":null,"tipAmount":null,"taxAmount":null,"cvmResults":null,"token":null,"customerNumber":null,"email":""}' + end + + def failed_capture_response + '{"returnCode":"9068","errorDescription":"The original transaction number does not match any actual transaction","authorizationNumber":" ","referenceNumber":" ","transactionNumber":"000007708999","batchNumber":" ","terminalNumber":" ","serverNumber":" ","timeStamp":"20180629-13224441","trxCode":" ","merchantNumber":" ","amount":"00000000000","invoiceNumber":" ","trxType":" ","cardType":" ","cardNumber":" ","expirationDate":" ","bankTerminalNumber":" ","trxDate":" ","trxTime":" ","accountType":" ","trxMethod":" ","languageCode":" ","sequenceNumber":" ","receiptDisp":" OPERATION NON COMPLETEE ","terminalDisp":"9068: Contactez support.","operatorId":" ","surchargeAmount":" ","companyNumber":" ","secureID":"","cvv2Cvc2Status":" ","iopIssuerConfirmationNumber":null,"iopIssuerName":null,"avsStatus":null,"holderName":null,"threeDSStatus":null,"emvLabel":null,"emvAID":null,"emvTVR":null,"emvTSI":null,"emvTC":null,"demoMode":null,"terminalInvoiceNumber":null,"cashbackAmount":null,"tipAmount":null,"taxAmount":null,"cvmResults":null,"token":null,"customerNumber":null,"email":""}' + end + + def successful_refund_response + ' {"returnCode":" 00","errorDescription":null,"authorizationNumber":" ","referenceNumber":" ","transactionNumber":"000007709004","batchNumber":"0001","terminalNumber":"13367","serverNumber":"0001","timeStamp":"20180629-13294388","trxCode":"03","merchantNumber":"53400030","amount":"00000000100","invoiceNumber":"0a08f144b6ea","trxType":"C","cardType":"V","cardNumber":"450116XXXXXX7214 ","expirationDate":"0720","bankTerminalNumber":"53400189","trxDate":"06292018","trxTime":"132944","accountType":"0","trxMethod":"T@1","languageCode":"E","sequenceNumber":"000000000019","receiptDisp":" APPROVED-THANK YOU ","terminalDisp":"APPROVED ","operatorId":"00000000","surchargeAmount":"","companyNumber":"00589","secureID":"","cvv2Cvc2Status":" ","iopIssuerConfirmationNumber":null,"iopIssuerName":null,"avsStatus":null,"holderName":null,"threeDSStatus":null,"emvLabel":null,"emvAID":null,"emvTVR":null,"emvTSI":null,"emvTC":null,"demoMode":null,"terminalInvoiceNumber":null,"cashbackAmount":null,"tipAmount":null,"taxAmount":null,"cvmResults":null,"token":null,"customerNumber":null,"email":""}' + end + + def failed_refund_response + '{"returnCode":"9068","errorDescription":"The original transaction number does not match any actual transaction","authorizationNumber":" ","referenceNumber":" ","transactionNumber":"000007709009","batchNumber":" ","terminalNumber":" ","serverNumber":" ","timeStamp":"20180629-13402119","trxCode":" ","merchantNumber":" ","amount":"00000000000","invoiceNumber":" ","trxType":" ","cardType":" ","cardNumber":" ","expirationDate":" ","bankTerminalNumber":" ","trxDate":" ","trxTime":" ","accountType":" ","trxMethod":" ","languageCode":" ","sequenceNumber":" ","receiptDisp":" OPERATION NON COMPLETEE ","terminalDisp":"9068: Contactez support.","operatorId":" ","surchargeAmount":" ","companyNumber":" ","secureID":"","cvv2Cvc2Status":" ","iopIssuerConfirmationNumber":null,"iopIssuerName":null,"avsStatus":null,"holderName":null,"threeDSStatus":null,"emvLabel":null,"emvAID":null,"emvTVR":null,"emvTSI":null,"emvTC":null,"demoMode":null,"terminalInvoiceNumber":null,"cashbackAmount":null,"tipAmount":null,"taxAmount":null,"cvmResults":null,"token":null,"customerNumber":null,"email":""}' + end + + def successful_void_response + '{"returnCode":" 00","errorDescription":null,"authorizationNumber":" ","referenceNumber":" ","transactionNumber":"000007709013","batchNumber":"0001","terminalNumber":"13367","serverNumber":"0001","timeStamp":"20180629-13451840","trxCode":"04","merchantNumber":"53400030","amount":"00000000100","invoiceNumber":"0de38871ce96","trxType":"C","cardType":"V","cardNumber":"450116XXXXXX7214","expirationDate":"0720","bankTerminalNumber":"53400189","trxDate":"06292018","trxTime":"134518","accountType":"0","trxMethod":"T@1","languageCode":"E","sequenceNumber":"000000000023","receiptDisp":" APPROVED-THANK YOU ","terminalDisp":"APPROVED ","operatorId":"00000000","surchargeAmount":" ","companyNumber":" ","secureID":"","cvv2Cvc2Status":" ","iopIssuerConfirmationNumber":null,"iopIssuerName":null,"avsStatus":null,"holderName":null,"threeDSStatus":null,"emvLabel":null,"emvAID":null,"emvTVR":null,"emvTSI":null,"emvTC":null,"demoMode":null,"terminalInvoiceNumber":null,"cashbackAmount":null,"tipAmount":null,"taxAmount":null,"cvmResults":null,"token":null,"customerNumber":null,"email":""}' + end + + def failed_void_response + '{"returnCode":"9068","errorDescription":"The original transaction number does not match any actual transaction","authorizationNumber":" ","referenceNumber":" ","transactionNumber":"0000000000-1","batchNumber":" ","terminalNumber":" ","serverNumber":" ","timeStamp":"20180629-13520693","trxCode":" ","merchantNumber":" ","amount":"00000000000","invoiceNumber":" ","trxType":" ","cardType":" ","cardNumber":" ","expirationDate":" ","bankTerminalNumber":" ","trxDate":" ","trxTime":" ","accountType":" ","trxMethod":" ","languageCode":" ","sequenceNumber":" ","receiptDisp":" OPERATION NOT COMPLETED ","terminalDisp":"9068: Contact support. ","operatorId":" ","surchargeAmount":" ","companyNumber":" ","secureID":"","cvv2Cvc2Status":" ","iopIssuerConfirmationNumber":null,"iopIssuerName":null,"avsStatus":null,"holderName":null,"threeDSStatus":null,"emvLabel":null,"emvAID":null,"emvTVR":null,"emvTSI":null,"emvTC":null,"demoMode":null,"terminalInvoiceNumber":null,"cashbackAmount":null,"tipAmount":null,"taxAmount":null,"cvmResults":null,"token":null,"customerNumber":null,"email":""}' + end + + def successful_verify_response + '{"returnCode":" 00","errorDescription":null,"authorizationNumber":" ","referenceNumber":" ","transactionNumber":"000007709025","batchNumber":"0001","terminalNumber":"13367","serverNumber":"0001","timeStamp":"20180629-14023575","trxCode":"08","merchantNumber":"53400030","amount":"00000000000","invoiceNumber":"0b882fe35f69","trxType":"C","cardType":"V","cardNumber":"450116XXXXXX7214 ","expirationDate":"0720","bankTerminalNumber":"53400189","trxDate":"06292018","trxTime":"140236","accountType":"0","trxMethod":"T@1","languageCode":"E","sequenceNumber":"000000000025","receiptDisp":" APPROVED-THANK YOU ","terminalDisp":"APPROVED ","operatorId":"00000000","surchargeAmount":"","companyNumber":"00589","secureID":"","cvv2Cvc2Status":" ","iopIssuerConfirmationNumber":null,"iopIssuerName":null,"avsStatus":null,"holderName":null,"threeDSStatus":null,"emvLabel":null,"emvAID":null,"emvTVR":null,"emvTSI":null,"emvTC":null,"demoMode":null,"terminalInvoiceNumber":null,"cashbackAmount":null,"tipAmount":null,"taxAmount":null,"cvmResults":null,"token":null,"customerNumber":null,"email":""}' + end + + def failed_verify_response + '{"returnCode":" 05","errorDescription":"Transaction declined","authorizationNumber":" ","referenceNumber":" ","transactionNumber":"000007709029","batchNumber":"0000","terminalNumber":"13367","serverNumber":"0001","timeStamp":"20180629-14104707","trxCode":"08","merchantNumber":"53400030","amount":"00000000000","invoiceNumber":"0c0054d2bb7a","trxType":"C","cardType":"V","cardNumber":"450224XXXXXX1718 ","expirationDate":"0919","bankTerminalNumber":"53400189","trxDate":"06292018","trxTime":"141047","accountType":"0","trxMethod":"T@1","languageCode":"E","sequenceNumber":"000000000026","receiptDisp":" TRANSACTION NOT APPROVED ","terminalDisp":"05-DECLINE ","operatorId":"00000000","surchargeAmount":"","companyNumber":"00589","secureID":"","cvv2Cvc2Status":" ","iopIssuerConfirmationNumber":null,"iopIssuerName":null,"avsStatus":null,"holderName":null,"threeDSStatus":null,"emvLabel":null,"emvAID":null,"emvTVR":null,"emvTSI":null,"emvTC":null,"demoMode":null,"terminalInvoiceNumber":null,"cashbackAmount":null,"tipAmount":null,"taxAmount":null,"cvmResults":null,"token":null,"customerNumber":null,"email":""}' + end + + def successful_credit_response + '{"returnCode":" 00","errorDescription":null,"authorizationNumber":" ","referenceNumber":" ","transactionNumber":"000007709063","batchNumber":"0001","terminalNumber":"13366","serverNumber":"0001","timeStamp":"20180629-14420931","trxCode":"03","merchantNumber":"53400030","amount":"00000000100","invoiceNumber":"054902f2ded0","trxType":"C","cardType":"V","cardNumber":"450116XXXXXX7214 ","expirationDate":"0720","bankTerminalNumber":"53400188","trxDate":"06292018","trxTime":"144209","accountType":"0","trxMethod":"T@1","languageCode":"E","sequenceNumber":"000000000032","receiptDisp":" APPROVED-THANK YOU ","terminalDisp":"APPROVED ","operatorId":"00000000","surchargeAmount":"","companyNumber":"00589","secureID":"","cvv2Cvc2Status":" ","iopIssuerConfirmationNumber":null,"iopIssuerName":null,"avsStatus":null,"holderName":null,"threeDSStatus":null,"emvLabel":null,"emvAID":null,"emvTVR":null,"emvTSI":null,"emvTC":null,"demoMode":null,"terminalInvoiceNumber":null,"cashbackAmount":null,"tipAmount":null,"taxAmount":null,"cvmResults":null,"token":null,"customerNumber":null,"email":""}' + end +end diff --git a/test/unit/gateways/culqi_test.rb b/test/unit/gateways/culqi_test.rb index be13543b0f4..0cd74341733 100644 --- a/test/unit/gateways/culqi_test.rb +++ b/test/unit/gateways/culqi_test.rb @@ -5,7 +5,7 @@ def setup @gateway = CulqiGateway.new(merchant_id: 'merchant', terminal_id: 'terminal', secret_key: 'password') @amount = 1000 - @credit_card = credit_card("4111111111111111") + @credit_card = credit_card('4111111111111111') @options = { order_id: generate_unique_id, @@ -56,7 +56,7 @@ def test_failed_authorize def test_failed_capture @gateway.expects(:ssl_post).returns(failed_capture_response) - response = @gateway.capture(@amount, "0") + response = @gateway.capture(@amount, '0') assert_failure response assert_match %r{Transaction not found}, response.message end @@ -77,7 +77,7 @@ def test_successful_refund def test_failed_refund @gateway.expects(:ssl_post).returns(failed_refund_response) - response = @gateway.refund(@amount, "0") + response = @gateway.refund(@amount, '0') assert_failure response assert_match %r{Transaction not found}, response.message end @@ -98,7 +98,7 @@ def test_successful_void def test_failed_void @gateway.expects(:ssl_post).returns(failed_void_response) - response = @gateway.void("0", @options) + response = @gateway.void('0', @options) assert_failure response assert_match %r{Transaction not found}, response.message end diff --git a/test/unit/gateways/cyber_source_test.rb b/test/unit/gateways/cyber_source_test.rb index 7806b52e9ee..77602767222 100644 --- a/test/unit/gateways/cyber_source_test.rb +++ b/test/unit/gateways/cyber_source_test.rb @@ -1,4 +1,5 @@ require 'test_helper' +require 'nokogiri' class CyberSourceTest < Test::Unit::TestCase include CommStub @@ -18,24 +19,24 @@ def setup @check = check() @options = { - :ip => @customer_ip, - :order_id => '1000', - :line_items => [ - { - :declared_value => @amount, - :quantity => 2, - :code => 'default', - :description => 'Giant Walrus', - :sku => 'WA323232323232323' - }, - { - :declared_value => @amount, - :quantity => 2, - :description => 'Marble Snowcone', - :sku => 'FAKE1232132113123' - } - ], - :currency => 'USD' + :ip => @customer_ip, + :order_id => '1000', + :line_items => [ + { + :declared_value => @amount, + :quantity => 2, + :code => 'default', + :description => 'Giant Walrus', + :sku => 'WA323232323232323' + }, + { + :declared_value => @amount, + :quantity => 2, + :description => 'Marble Snowcone', + :sku => 'FAKE1232132113123' + } + ], + :currency => 'USD' } @subscription_options = { @@ -43,7 +44,7 @@ def setup :credit_card => @credit_card, :setup_fee => 100, :subscription => { - :frequency => "weekly", + :frequency => 'weekly', :start_date => Date.today.next_week, :occurrences => 4, :automatic_renew => true, @@ -58,7 +59,7 @@ def test_successful_credit_card_purchase assert response = @gateway.purchase(@amount, @credit_card, @options) assert_equal 'Successful transaction', response.message assert_success response - assert_equal "#{@options[:order_id]};#{response.params['requestID']};#{response.params['requestToken']};purchase;100;USD", response.authorization + assert_equal "#{@options[:order_id]};#{response.params['requestID']};#{response.params['requestToken']};purchase;100;USD;", response.authorization assert response.test? end @@ -66,14 +67,14 @@ def test_purchase_includes_customer_ip customer_ip_regexp = /<ipAddress>#{@customer_ip}<\// @gateway.expects(:ssl_post). with(anything, regexp_matches(customer_ip_regexp), anything). - returns("") + returns('') @gateway.expects(:parse).returns({}) @gateway.purchase(@amount, @credit_card, @options) end def test_purchase_includes_mdd_fields stub_comms do - @gateway.purchase(100, @credit_card, order_id: "1", mdd_field_2: "CustomValue2", mdd_field_3: "CustomValue3") + @gateway.purchase(100, @credit_card, order_id: '1', mdd_field_2: 'CustomValue2', mdd_field_3: 'CustomValue3') end.check_request do |endpoint, data, headers| assert_match(/field2>CustomValue2.*field3>CustomValue3</m, data) end.respond_with(successful_purchase_response) @@ -81,20 +82,19 @@ def test_purchase_includes_mdd_fields def test_authorize_includes_mdd_fields stub_comms do - @gateway.authorize(100, @credit_card, order_id: "1", mdd_field_2: "CustomValue2", mdd_field_3: "CustomValue3") + @gateway.authorize(100, @credit_card, order_id: '1', mdd_field_2: 'CustomValue2', mdd_field_3: 'CustomValue3') end.check_request do |endpoint, data, headers| assert_match(/field2>CustomValue2.*field3>CustomValue3</m, data) end.respond_with(successful_authorization_response) end - def test_successful_check_purchase @gateway.expects(:ssl_post).returns(successful_purchase_response) assert response = @gateway.purchase(@amount, @check, @options) assert_equal 'Successful transaction', response.message assert_success response - assert_equal "#{@options[:order_id]};#{response.params['requestID']};#{response.params['requestToken']};purchase;100;USD", response.authorization + assert_equal "#{@options[:order_id]};#{response.params['requestID']};#{response.params['requestToken']};purchase;100;USD;", response.authorization assert response.test? end @@ -104,7 +104,7 @@ def test_successful_pinless_debit_card_purchase assert response = @gateway.purchase(@amount, @credit_card, @options.merge(:pinless_debit_card => true)) assert_equal 'Successful transaction', response.message assert_success response - assert_equal "#{@options[:order_id]};#{response.params['requestID']};#{response.params['requestToken']};purchase;100;USD", response.authorization + assert_equal "#{@options[:order_id]};#{response.params['requestID']};#{response.params['requestToken']};purchase;100;USD;", response.authorization assert response.test? end @@ -175,6 +175,17 @@ def test_unsuccessful_authorization @gateway.expects(:ssl_post).returns(unsuccessful_authorization_response) assert response = @gateway.purchase(@amount, @credit_card, @options) + refute_equal 'Successful transaction', response.message + assert_instance_of Response, response + assert_failure response + end + + def test_unsuccessful_authorization_with_reply + @gateway.expects(:ssl_post).returns(unsuccessful_authorization_response_with_reply) + + assert response = @gateway.purchase(@amount, @credit_card, @options) + refute_equal 'Successful transaction', response.message + assert_equal '481', response.params['reasonCode'] assert_instance_of Response, response assert_failure response end @@ -220,7 +231,7 @@ def test_successful_check_purchase_request end def test_requires_error_on_tax_calculation_without_line_items - assert_raise(ArgumentError){ @gateway.calculate_tax(@credit_card, @options.delete_if{|key, val| key == :line_items})} + assert_raise(ArgumentError) { @gateway.calculate_tax(@credit_card, @options.delete_if { |key, val| key == :line_items }) } end def test_default_currency @@ -296,7 +307,7 @@ def test_successful_credit_request def test_successful_void_capture_request @gateway.stubs(:ssl_post).returns(successful_capture_response, successful_auth_reversal_response) - assert response_capture = @gateway.capture(@amount, "1846925324700976124593") + assert response_capture = @gateway.capture(@amount, '1846925324700976124593') assert response_capture.success? assert response_capture.test? assert response_auth_reversal = @gateway.void(response_capture.authorization, @options) @@ -339,37 +350,57 @@ def test_unsuccessful_verify @gateway.verify(@credit_card, @options) end.respond_with(unsuccessful_authorization_response) assert_failure response - assert_equal "Invalid account number", response.message + assert_equal 'Invalid account number', response.message end def test_successful_auth_with_network_tokenization_for_visa - @gateway.expects(:ssl_post).with do |host, request_body| - assert_match %r'<ccAuthService run=\"true\">\n <cavv>111111111100cryptogram</cavv>\n <commerceIndicator>vbv</commerceIndicator>\n <xid>111111111100cryptogram</xid>\n</ccAuthService>\n<paymentNetworkToken>\n <transactionType>1</transactionType>\n</paymentNetworkToken>', request_body - true - end.returns(successful_purchase_response) + credit_card = network_tokenization_credit_card('4111111111111111', + :brand => 'visa', + :transaction_id => '123', + :eci => '05', + :payment_cryptogram => '111111111100cryptogram' + ) + response = stub_comms do + @gateway.authorize(@amount, credit_card, @options) + end.check_request do |_endpoint, body, _headers| + assert_xml_valid_to_xsd(body) + assert_match %r'<ccAuthService run=\"true\">\n <cavv>111111111100cryptogram</cavv>\n <commerceIndicator>vbv</commerceIndicator>\n <xid>111111111100cryptogram</xid>\n</ccAuthService>\n<paymentNetworkToken>\n <transactionType>1</transactionType>\n</paymentNetworkToken>', body + end.respond_with(successful_purchase_response) + + assert_success response + end + + def test_successful_purchase_with_network_tokenization_for_visa credit_card = network_tokenization_credit_card('4111111111111111', :brand => 'visa', - :transaction_id => "123", - :eci => "05", - :payment_cryptogram => "111111111100cryptogram" + :transaction_id => '123', + :eci => '05', + :payment_cryptogram => '111111111100cryptogram' ) - assert response = @gateway.authorize(@amount, credit_card, @options) + response = stub_comms do + @gateway.purchase(@amount, credit_card, @options) + end.check_request do |_endpoint, body, _headers| + assert_xml_valid_to_xsd(body) + assert_match %r'<ccAuthService run="true">.+?<ccCaptureService run="true"/>'m, body + end.respond_with(successful_purchase_response) + assert_success response end def test_successful_auth_with_network_tokenization_for_mastercard @gateway.expects(:ssl_post).with do |host, request_body| + assert_xml_valid_to_xsd(request_body) assert_match %r'<ucaf>\n <authenticationData>111111111100cryptogram</authenticationData>\n <collectionIndicator>2</collectionIndicator>\n</ucaf>\n<ccAuthService run=\"true\">\n <commerceIndicator>spa</commerceIndicator>\n</ccAuthService>\n<paymentNetworkToken>\n <transactionType>1</transactionType>\n</paymentNetworkToken>', request_body true end.returns(successful_purchase_response) credit_card = network_tokenization_credit_card('5555555555554444', :brand => 'mastercard', - :transaction_id => "123", - :eci => "05", - :payment_cryptogram => "111111111100cryptogram" + :transaction_id => '123', + :eci => '05', + :payment_cryptogram => '111111111100cryptogram' ) assert response = @gateway.authorize(@amount, credit_card, @options) @@ -378,15 +409,16 @@ def test_successful_auth_with_network_tokenization_for_mastercard def test_successful_auth_with_network_tokenization_for_amex @gateway.expects(:ssl_post).with do |host, request_body| + assert_xml_valid_to_xsd(request_body) assert_match %r'<ccAuthService run=\"true\">\n <cavv>MTExMTExMTExMTAwY3J5cHRvZ3I=\n</cavv>\n <commerceIndicator>aesk</commerceIndicator>\n <xid>YW0=\n</xid>\n</ccAuthService>\n<paymentNetworkToken>\n <transactionType>1</transactionType>\n</paymentNetworkToken>', request_body true end.returns(successful_purchase_response) credit_card = network_tokenization_credit_card('378282246310005', :brand => 'american_express', - :transaction_id => "123", - :eci => "05", - :payment_cryptogram => Base64.encode64("111111111100cryptogram") + :transaction_id => '123', + :eci => '05', + :payment_cryptogram => Base64.encode64('111111111100cryptogram') ) assert response = @gateway.authorize(@amount, credit_card, @options) @@ -400,10 +432,43 @@ def test_nonfractional_currency_handling true end.returns(successful_nonfractional_authorization_response) - assert response = @gateway.authorize(100, @credit_card, @options.merge(currency: "JPY")) + assert response = @gateway.authorize(100, @credit_card, @options.merge(currency: 'JPY')) assert_success response end + def test_malformed_xml_handling + @gateway.expects(:ssl_post).returns(malformed_xml_response) + + assert response = @gateway.purchase(@amount, @credit_card, @options) + assert_failure response + assert_match %r(Missing end tag for), response.message + assert response.test? + end + + def test_3ds_enroll_response + purchase = stub_comms do + @gateway.purchase(@amount, @credit_card, @options.merge(payer_auth_enroll_service: true)) + end.check_request do |endpoint, data, headers| + assert_match(/\<payerAuthEnrollService run=\"true\"\/\>/, data) + end.respond_with(threedeesecure_purchase_response) + + assert_failure purchase + assert_equal 'YTJycDdLR3RIVnpmMXNFejJyazA=', purchase.params['xid'] + assert_equal 'eNpVUe9PwjAQ/d6/ghA/r2tBYMvRBEUFFEKQEP1Yu1Om7gfdJoy/3nZsgk2a3Lveu757B+utRhw/oyo0CphjlskPbIXBsC25TvuPD/lkc3xn2d2R6y+3LWA5WuFOwA/qLExiwRzX4UAbSEwLrbYyzgVItbuZLkS353HWA1pDAhHq6Vgw3ule9/pAT5BALCMUqnwznZJCKwRaZQiopIhzXYpB1wXaAAKF/hbbPE8zn9L9fu9cUB2VREBtAQF6FrQsbJSZOQ9hIF7Xs1KNg6dVZzXdxGk0f1nc4+eslMfREKitIBDIHAV3WZ+Z2+Ku3/F8bjRXeQIysmrEFeOOa0yoIYHUfjQ6Icbt02XGTFRojbFqRmoQATykSYymxlD+YjPDWfntxBqrcusg8wbmWGcrXNFD4w3z2IkfVkZRy6H13mi9YhP9W/0vhyyqPw==', purchase.params['paReq'] + assert_equal 'https://0eafstag.cardinalcommerce.com/EAFService/jsp/v1/redirect', purchase.params['acsURL'] + end + + def test_3ds_validate_response + validation = stub_comms do + @gateway.purchase(@amount, @credit_card, @options.merge(payer_auth_validate_service: true, pares: 'ABC123')) + end.check_request do |endpoint, data, headers| + assert_match(/\<payerAuthValidateService run=\"true\"\>/, data) + assert_match(/\<signedPARes\>ABC123\<\/signedPARes\>/, data) + end.respond_with(successful_threedeesecure_validate_response) + + assert_success validation + end + def test_scrub assert_equal @gateway.scrub(pre_scrubbed), post_scrubbed end @@ -416,6 +481,16 @@ def test_supports_network_tokenization assert_instance_of TrueClass, @gateway.supports_network_tokenization? end + def test_does_not_throw_on_invalid_xml + raw_response = mock + raw_response.expects(:body).returns(invalid_xml_response) + exception = ActiveMerchant::ResponseError.new(raw_response) + @gateway.expects(:ssl_post).raises(exception) + + assert response = @gateway.purchase(@amount, @credit_card, @options) + assert_failure response + end + private def pre_scrubbed @@ -490,6 +565,64 @@ def unsuccessful_authorization_response XML end + def unsuccessful_authorization_response_with_reply + <<-XML + <?xml version="1.0" encoding="utf-8"?> + <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> + <soap:Header> + <wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"> + <wsu:Timestamp xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="Timestamp-5307043"> + <wsu:Created>2017-05-10T01:15:14.835Z</wsu:Created> + </wsu:Timestamp></wsse:Security> + </soap:Header> + <soap:Body> + <c:replyMessage xmlns:c="urn:schemas-cybersource-com:transaction-data-1.121"> + <c:merchantReferenceCode>TEST11111111111</c:merchantReferenceCode> + <c:requestID>1841784762620176127166</c:requestID> + <c:decision>REJECT</c:decision> + <c:reasonCode>481</c:reasonCode> + <c:requestToken>AMYJY9fl62i+vx2OEQYAx9zv/9UBZAAA5h5D</c:requestToken> + <c:purchaseTotals> + <c:currency>USD</c:currency> + </c:purchaseTotals> + <c:ccAuthReply> + <c:reasonCode>100</c:reasonCode> + <c:amount>1186.43</c:amount> + <c:authorizationCode>123456</c:authorizationCode> + <c:avsCode>N</c:avsCode> + <c:avsCodeRaw>N</c:avsCodeRaw> + <c:cvCode>M</c:cvCode> + <c:cvCodeRaw>M</c:cvCodeRaw> + <c:authorizedDateTime>2017-05-10T01:15:14Z</c:authorizedDateTime> + <c:processorResponse>00</c:processorResponse> + <c:reconciliationID>013445773WW7EWMB0RYI9</c:reconciliationID> + </c:ccAuthReply> + <c:afsReply> + <c:reasonCode>100</c:reasonCode> + <c:afsResult>96</c:afsResult> + <c:hostSeverity>1</c:hostSeverity> + <c:consumerLocalTime>20:15:14</c:consumerLocalTime> + <c:afsFactorCode>C^H</c:afsFactorCode> + <c:internetInfoCode>MM-IPBST</c:internetInfoCode> + <c:suspiciousInfoCode>MUL-EM</c:suspiciousInfoCode> + <c:velocityInfoCode>VEL-ADDR^VEL-CC^VEL-NAME</c:velocityInfoCode> + <c:ipCountry>us</c:ipCountry> + <c:ipState>nv</c:ipState><c:ipCity>las vegas</c:ipCity> + <c:ipRoutingMethod>fixed</c:ipRoutingMethod> + <c:scoreModelUsed>default</c:scoreModelUsed> + <c:cardBin>540510</c:cardBin> + <c:binCountry>US</c:binCountry> + <c:cardAccountType>PURCHASING</c:cardAccountType> + <c:cardScheme>MASTERCARD CREDIT</c:cardScheme> + <c:cardIssuer>werewrewrew.</c:cardIssuer> + </c:afsReply> + <c:decisionReply><c:casePriority>3</c:casePriority><c:activeProfileReply/></c:decisionReply> + </c:replyMessage> + </soap:Body> + </soap:Envelope> + XML + end + def successful_tax_response <<-XML <?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> @@ -583,4 +716,41 @@ def successful_nonfractional_authorization_response <wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"><wsu:Timestamp xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="Timestamp-32551101"><wsu:Created>2007-07-12T18:31:53.838Z</wsu:Created></wsu:Timestamp></wsse:Security></soap:Header><soap:Body><c:replyMessage xmlns:c="urn:schemas-cybersource-com:transaction-data-1.26"><c:merchantReferenceCode>TEST11111111111</c:merchantReferenceCode><c:requestID>1842651133440156177166</c:requestID><c:decision>ACCEPT</c:decision><c:reasonCode>100</c:reasonCode><c:requestToken>AP4JY+Or4xRonEAOERAyMzQzOTEzMEM0MFZaNUZCBgDH3fgJ8AEGAMfd+AnwAwzRpAAA7RT/</c:requestToken><c:purchaseTotals><c:currency>JPY</c:currency></c:purchaseTotals><c:ccAuthReply><c:reasonCode>100</c:reasonCode><c:amount>1</c:amount><c:authorizationCode>004542</c:authorizationCode><c:avsCode>A</c:avsCode><c:avsCodeRaw>I7</c:avsCodeRaw><c:authorizedDateTime>2007-07-12T18:31:53Z</c:authorizedDateTime><c:processorResponse>100</c:processorResponse><c:reconciliationID>23439130C40VZ2FB</c:reconciliationID></c:ccAuthReply></c:replyMessage></soap:Body></soap:Envelope> XML end + + def malformed_xml_response + <<-XML +<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> +<soap:Header> +<wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"><wsu:Timestamp xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="Timestamp-2636690"><wsu:Created>2008-01-15T21:42:03.343Z</wsu:Created></wsu:Timestamp></wsse:Security></soap:Header><soap:Body><c:replyMessage xmlns:c="urn:schemas-cybersource-com:transaction-data-1.26"><c:merchantReferenceCode>b0a6cf9aa07f1a8495f89c364bbd6a9a</c:merchantReferenceCode><c:requestID>2004333231260008401927</c:requestID><c:decision>ACCEPT</c:decision><c:reasonCode>100</c:reasonCode><c:requestToken>Afvvj7Ke2Fmsbq0wHFE2sM6R4GAptYZ0jwPSA+R9PhkyhFTb0KRjoE4+ynthZrG6tMBwjAtT</c:requestToken><c:purchaseTotals><c:currency>USD</c:currency></c:purchaseTotals><c:ccAuthReply><c:reasonCode>100</c:reasonCode><c:amount>1.00</c:amount><c:authorizationCode>123456</c:authorizationCode><c:avsCode>Y</c:avsCode><c:avsCodeRaw>Y</c:avsCodeRaw><c:cvCode>M</c:cvCode><c:cvCodeRaw>M</c:cvCodeRaw><c:authorizedDateTime>2008-01-15T21:42:03Z</c:authorizedDateTime><c:processorResponse>00</c:processorResponse><c:authFactorCode>U</c:authFactorCode><p></c:ccAuthReply></c:replyMessage></soap:Body></soap:Envelope> + XML + end + + def threedeesecure_purchase_response + <<-XML +<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> +<soap:Header> +<wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"><wsu:Timestamp xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="Timestamp-1347906680"><wsu:Created>2017-10-17T20:39:27.392Z</wsu:Created></wsu:Timestamp></wsse:Security></soap:Header><soap:Body><c:replyMessage xmlns:c="urn:schemas-cybersource-com:transaction-data-1.121"><c:merchantReferenceCode>1a5ba4804da54b384c6e8a2d8057ea99</c:merchantReferenceCode><c:requestID>5082727663166909004012</c:requestID><c:decision>REJECT</c:decision><c:reasonCode>475</c:reasonCode><c:requestToken>AhjzbwSTE4kEGDR65zjsGwFLjtwzsJ0gXLJx6Xb0ky3SA7ek8AYA/A17</c:requestToken><c:payerAuthEnrollReply><c:reasonCode>475</c:reasonCode><c:acsURL>https://0eafstag.cardinalcommerce.com/EAFService/jsp/v1/redirect</c:acsURL><c:paReq>eNpVUe9PwjAQ/d6/ghA/r2tBYMvRBEUFFEKQEP1Yu1Om7gfdJoy/3nZsgk2a3Lveu757B+utRhw/oyo0CphjlskPbIXBsC25TvuPD/lkc3xn2d2R6y+3LWA5WuFOwA/qLExiwRzX4UAbSEwLrbYyzgVItbuZLkS353HWA1pDAhHq6Vgw3ule9/pAT5BALCMUqnwznZJCKwRaZQiopIhzXYpB1wXaAAKF/hbbPE8zn9L9fu9cUB2VREBtAQF6FrQsbJSZOQ9hIF7Xs1KNg6dVZzXdxGk0f1nc4+eslMfREKitIBDIHAV3WZ+Z2+Ku3/F8bjRXeQIysmrEFeOOa0yoIYHUfjQ6Icbt02XGTFRojbFqRmoQATykSYymxlD+YjPDWfntxBqrcusg8wbmWGcrXNFD4w3z2IkfVkZRy6H13mi9YhP9W/0vhyyqPw==</c:paReq><c:proxyPAN>1198888</c:proxyPAN><c:xid>YTJycDdLR3RIVnpmMXNFejJyazA=</c:xid><c:proofXML>&lt;AuthProof&gt;&lt;Time&gt;2017 Oct 17 20:39:27&lt;/Time&gt;&lt;DSUrl&gt;https://csrtestcustomer34.cardinalcommerce.com/merchantacsfrontend/vereq.jsp?acqid=CYBS&lt;/DSUrl&gt;&lt;VEReqProof&gt;&lt;Message id="a2rp7KGtHVzf1sEz2rk0"&gt;&lt;VEReq&gt;&lt;version&gt;1.0.2&lt;/version&gt;&lt;pan&gt;XXXXXXXXXXXX0002&lt;/pan&gt;&lt;Merchant&gt;&lt;acqBIN&gt;469216&lt;/acqBIN&gt;&lt;merID&gt;1234567&lt;/merID&gt;&lt;/Merchant&gt;&lt;Browser&gt;&lt;deviceCategory&gt;0&lt;/deviceCategory&gt;&lt;/Browser&gt;&lt;/VEReq&gt;&lt;/Message&gt;&lt;/VEReqProof&gt;&lt;VEResProof&gt;&lt;Message id="a2rp7KGtHVzf1sEz2rk0"&gt;&lt;VERes&gt;&lt;version&gt;1.0.2&lt;/version&gt;&lt;CH&gt;&lt;enrolled&gt;Y&lt;/enrolled&gt;&lt;acctID&gt;1198888&lt;/acctID&gt;&lt;/CH&gt;&lt;url&gt;https://testcustomer34.cardinalcommerce.com/merchantacsfrontend/pareq.jsp?vaa=b&amp;amp;gold=AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA&lt;/url&gt;&lt;protocol&gt;ThreeDSecure&lt;/protocol&gt;&lt;/VERes&gt;&lt;/Message&gt;&lt;/VEResProof&gt;&lt;/AuthProof&gt;</c:proofXML><c:veresEnrolled>Y</c:veresEnrolled><c:authenticationPath>ENROLLED</c:authenticationPath></c:payerAuthEnrollReply></c:replyMessage></soap:Body></soap:Envelope> + XML + end + + def successful_threedeesecure_validate_response + <<-XML +<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> +<soap:Header> +<wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"><wsu:Timestamp xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="Timestamp-635495097"><wsu:Created>2018-05-01T14:28:36.773Z</wsu:Created></wsu:Timestamp></wsse:Security></soap:Header><soap:Body><c:replyMessage xmlns:c="urn:schemas-cybersource-com:transaction-data-1.121"><c:merchantReferenceCode>23751b5aeb076ea5940c5b656284bf6a</c:merchantReferenceCode><c:requestID>5251849164756591904009</c:requestID><c:decision>ACCEPT</c:decision><c:reasonCode>100</c:reasonCode><c:requestToken>Ahj//wSTHLQMXdtQnQUJGxDds0bNnDRoo0+VcdXMBUafKuOrnpAuWT9zDJpJlukB29J4YBpMctAxd21CdBQkwQ3g</c:requestToken><c:purchaseTotals><c:currency>USD</c:currency></c:purchaseTotals><c:ccAuthReply><c:reasonCode>100</c:reasonCode><c:amount>12.02</c:amount><c:authorizationCode>831000</c:authorizationCode><c:avsCode>Y</c:avsCode><c:avsCodeRaw>Y</c:avsCodeRaw><c:authorizedDateTime>2018-05-01T14:28:36Z</c:authorizedDateTime><c:processorResponse>00</c:processorResponse><c:reconciliationID>ZLIU5GM27GBP</c:reconciliationID><c:authRecord>0110322000000E10000200000000000000120205011428360272225A4C495535474D32374742503833313030303030000159004400103232415050524F56414C0022313457303136313530373033383032303934473036340006564943524120</c:authRecord></c:ccAuthReply><c:ccCaptureReply><c:reasonCode>100</c:reasonCode><c:requestDateTime>2018-05-01T14:28:36Z</c:requestDateTime><c:amount>12.02</c:amount><c:reconciliationID>76466844</c:reconciliationID></c:ccCaptureReply><c:payerAuthValidateReply><c:reasonCode>100</c:reasonCode><c:authenticationResult>0</c:authenticationResult><c:authenticationStatusMessage>Success</c:authenticationStatusMessage><c:cavv>AAABAWFlmQAAAABjRWWZEEFgFz+=</c:cavv><c:cavvAlgorithm>2</c:cavvAlgorithm><c:commerceIndicator>vbv</c:commerceIndicator><c:eci>05</c:eci><c:eciRaw>05</c:eciRaw><c:xid>S2R4eGtHbEZqbnozeGhBRHJ6QzA=</c:xid><c:paresStatus>Y</c:paresStatus></c:payerAuthValidateReply></c:replyMessage></soap:Body></soap:Envelope> + XML + end + + def invalid_xml_response + "What's all this then, govna?</p>" + end + + def assert_xml_valid_to_xsd(data, root_element = '//s:Body/*') + schema_file = File.open("#{File.dirname(__FILE__)}/../../schema/cyber_source/CyberSourceTransaction_#{CyberSourceGateway::XSD_VERSION}.xsd") + doc = Nokogiri::XML(data) + root = Nokogiri::XML(doc.xpath(root_element).to_s) + xsd = Nokogiri::XML::Schema(schema_file) + errors = xsd.validate(root) + assert_empty errors, "XSD validation errors in the following XML:\n#{root}" + end end diff --git a/test/unit/gateways/data_cash_test.rb b/test/unit/gateways/data_cash_test.rb index 066b567ed0c..2fb5ac40d10 100644 --- a/test/unit/gateways/data_cash_test.rb +++ b/test/unit/gateways/data_cash_test.rb @@ -48,14 +48,14 @@ def test_credit def test_deprecated_credit @gateway.expects(:ssl_post).with(anything, regexp_matches(/<method>txn_refund<\/method>/)).returns(successful_purchase_response) assert_deprecation_warning(Gateway::CREDIT_DEPRECATION_MESSAGE) do - @gateway.credit(@amount, "transaction_id", @options) + @gateway.credit(@amount, 'transaction_id', @options) end end def test_refund @gateway.expects(:ssl_post).with(anything, regexp_matches(/<method>txn_refund<\/method>/)).returns(successful_purchase_response) - @gateway.refund(@amount, "transaction_id", @options) + @gateway.refund(@amount, 'transaction_id', @options) end def test_unsuccessful_purchase @@ -83,15 +83,15 @@ def test_supported_countries end def test_supported_card_types - assert_equal [ :visa, :master, :american_express, :discover, :diners_club, :jcb, :maestro, :switch, :solo, :laser ], DataCashGateway.supported_cardtypes + assert_equal [ :visa, :master, :american_express, :discover, :diners_club, :jcb, :maestro ], DataCashGateway.supported_cardtypes end def test_purchase_with_missing_order_id_option - assert_raise(ArgumentError){ @gateway.purchase(100, @credit_card, {}) } + assert_raise(ArgumentError) { @gateway.purchase(100, @credit_card, {}) } end def test_authorize_with_missing_order_id_option - assert_raise(ArgumentError){ @gateway.authorize(100, @credit_card, {}) } + assert_raise(ArgumentError) { @gateway.authorize(100, @credit_card, {}) } end def test_purchase_does_not_raise_exception_with_missing_billing_address @@ -101,7 +101,7 @@ def test_purchase_does_not_raise_exception_with_missing_billing_address def test_continuous_authority_purchase_with_missing_continuous_authority_reference assert_raise(ArgumentError) do - @gateway.authorize(100, "a;b;", @options) + @gateway.authorize(100, 'a;b;', @options) end end @@ -122,6 +122,7 @@ def test_capture_method_is_ecomm end private + def failed_purchase_response <<-XML <Response> @@ -188,4 +189,69 @@ def successful_purchase_using_continuous_authority_response </Response> XML end + + def test_transcript_scrubbing + assert @gateway.supports_scrubbing? + assert_equal @gateway.scrub(pre_scrub), post_scrub + end + + def pre_scrub + <<-RAW +opening connection to testserver.datacash.com:443... +opened +starting SSL for testserver.datacash.com:443... +SSL established +<- "POST /Transaction HTTP/1.1\r\nContent-Type: application/x-www-form-urlencoded\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nAccept: */*\r\nUser-Agent: Ruby\r\nConnection: close\r\nHost: testserver.datacash.com\r\nContent-Length: 1067\r\n\r\n" +<- "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Request version=\"2\">\n <Authentication>\n <client>99626800</client>\n <password>9YM3DjUa6</password>\n </Authentication>\n <Transaction>\n <CardTxn>\n <method>auth</method>\n <Card>\n <pan>4539792100000003</pan>\n <expirydate>03/20</expirydate>\n <Cv2Avs>\n <cv2>444</cv2>\n <ExtendedPolicy>\n <cv2_policy notprovided=\"reject\" notchecked=\"reject\" matched=\"accept\" notmatched=\"reject\" partialmatch=\"reject\"/>\n <postcode_policy notprovided=\"accept\" notchecked=\"accept\" matched=\"accept\" notmatched=\"reject\" partialmatch=\"accept\"/>\n <address_policy notprovided=\"accept\" notchecked=\"accept\" matched=\"accept\" notmatched=\"reject\" partialmatch=\"accept\"/>\n </ExtendedPolicy>\n </Cv2Avs>\n </Card>\n </CardTxn>\n <TxnDetails>\n <merchantreference>d36e05ce3604313963854fca858d11</merchantreference>\n <amount currency=\"GBP\">1.98</amount>\n <capturemethod>ecomm</capturemethod>\n </TxnDetails>\n </Transaction>\n</Request>\n" +-> "HTTP/1.1 200 OK\r\n" +-> "Date: Wed, 03 Jan 2018 21:24:38 GMT\r\n" +-> "Server: Apache\r\n" +-> "Connection: close\r\n" +-> "Transfer-Encoding: chunked\r\n" +-> "Content-Type: text/plain; charset=iso-8859-1\r\n" +-> "\r\n" +-> "559\r\n" +reading 1369 bytes... +-> "" +-> "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Response version='2'>\n <CardTxn>\n <Cv2Avs>\n <address_policy matched='accept' notchecked='accept' notmatched='reject' notprovided='accept' partialmatch='accept'></address_policy>\n <address_result numeric='1'>notchecked</address_result>\n <cv2_policy matched='accept' notchecked='reject' notmatched='reject' notprovided='reject' partialmatch='reject'></cv2_policy>\n <cv2_result numeric='2'>matched</cv2_result>\n <cv2avs_status>ACCEPTED</cv2avs_status>\n <postcode_policy matched='accept' notchecked='accept' notmatched='reject' notprovided='accept' partialmatch='accept'></postcode_policy>\n <postcode_result numeric='1'>notchecked</postcode_result>\n </Cv2Avs>\n <authcode>698899</authcode>\n <card_scheme>VISA Debit</card_scheme>\n <country>United Kingdom</country>\n <issuer>Barclays Bank PLC</issuer>\n <response_code>00</response_code>\n <response_code_text>Approved or completed successfully</response_code_text>\n <token>D4B1B0558173CAE56E87293F9E9E899C8002F7B6</token>\n </CardTxn>\n <acquirer>RBS</acquirer>\n <datacash_reference>4700204504678897</datacash_reference>\n <merchantreference>d36e05ce3604313963854fca858d11</merchantreference>\n <mid>99626800</mid>\n <mode>TEST</mode>\n <reason>ACCEPTED</reason>\n <status>1</status>\n <time>1515014679</time>\n</Response>\n\n" +read 1369 bytes +reading 2 bytes... +-> "" +-> "\r\n" +read 2 bytes +-> "0\r\n" +-> "\r\n" +Conn close + RAW + end + + def post_scrub + <<-SCRUBBED +opening connection to testserver.datacash.com:443... +opened +starting SSL for testserver.datacash.com:443... +SSL established +<- "POST /Transaction HTTP/1.1\r\nContent-Type: application/x-www-form-urlencoded\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nAccept: */*\r\nUser-Agent: Ruby\r\nConnection: close\r\nHost: testserver.datacash.com\r\nContent-Length: 1067\r\n\r\n" +<- "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Request version=\"2\">\n <Authentication>\n <client>99626800</client>\n <password>[FILTERED]</password>\n </Authentication>\n <Transaction>\n <CardTxn>\n <method>auth</method>\n <Card>\n <pan>[FILTERED]</pan>\n <expirydate>03/20</expirydate>\n <Cv2Avs>\n <cv2>[FILTERED]</cv2>\n <ExtendedPolicy>\n <cv2_policy notprovided=\"reject\" notchecked=\"reject\" matched=\"accept\" notmatched=\"reject\" partialmatch=\"reject\"/>\n <postcode_policy notprovided=\"accept\" notchecked=\"accept\" matched=\"accept\" notmatched=\"reject\" partialmatch=\"accept\"/>\n <address_policy notprovided=\"accept\" notchecked=\"accept\" matched=\"accept\" notmatched=\"reject\" partialmatch=\"accept\"/>\n </ExtendedPolicy>\n </Cv2Avs>\n </Card>\n </CardTxn>\n <TxnDetails>\n <merchantreference>d36e05ce3604313963854fca858d11</merchantreference>\n <amount currency=\"GBP\">1.98</amount>\n <capturemethod>ecomm</capturemethod>\n </TxnDetails>\n </Transaction>\n</Request>\n" +-> "HTTP/1.1 200 OK\r\n" +-> "Date: Wed, 03 Jan 2018 21:24:38 GMT\r\n" +-> "Server: Apache\r\n" +-> "Connection: close\r\n" +-> "Transfer-Encoding: chunked\r\n" +-> "Content-Type: text/plain; charset=iso-8859-1\r\n" +-> "\r\n" +-> "559\r\n" +reading 1369 bytes... +-> "" +-> "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Response version='2'>\n <CardTxn>\n <Cv2Avs>\n <address_policy matched='accept' notchecked='accept' notmatched='reject' notprovided='accept' partialmatch='accept'></address_policy>\n <address_result numeric='1'>notchecked</address_result>\n <cv2_policy matched='accept' notchecked='reject' notmatched='reject' notprovided='reject' partialmatch='reject'></cv2_policy>\n <cv2_result numeric='2'>matched</cv2_result>\n <cv2avs_status>ACCEPTED</cv2avs_status>\n <postcode_policy matched='accept' notchecked='accept' notmatched='reject' notprovided='accept' partialmatch='accept'></postcode_policy>\n <postcode_result numeric='1'>notchecked</postcode_result>\n </Cv2Avs>\n <authcode>698899</authcode>\n <card_scheme>VISA Debit</card_scheme>\n <country>United Kingdom</country>\n <issuer>Barclays Bank PLC</issuer>\n <response_code>00</response_code>\n <response_code_text>Approved or completed successfully</response_code_text>\n <token>D4B1B0558173CAE56E87293F9E9E899C8002F7B6</token>\n </CardTxn>\n <acquirer>RBS</acquirer>\n <datacash_reference>4700204504678897</datacash_reference>\n <merchantreference>d36e05ce3604313963854fca858d11</merchantreference>\n <mid>99626800</mid>\n <mode>TEST</mode>\n <reason>ACCEPTED</reason>\n <status>1</status>\n <time>1515014679</time>\n</Response>\n\n" +read 1369 bytes +reading 2 bytes... +-> "" +-> "\r\n" +read 2 bytes +-> "0\r\n" +-> "\r\n" +Conn close +SCRUBBED + end end diff --git a/test/unit/gateways/dibs_test.rb b/test/unit/gateways/dibs_test.rb index 65865a7546f..af127ba0be8 100644 --- a/test/unit/gateways/dibs_test.rb +++ b/test/unit/gateways/dibs_test.rb @@ -5,8 +5,8 @@ class DibsTest < Test::Unit::TestCase def setup @gateway = DibsGateway.new( - merchant_id: "merchantId", - secret_key: "secretKey" + merchant_id: 'merchantId', + secret_key: 'secretKey' ) @credit_card = credit_card @@ -20,7 +20,7 @@ def test_successful_purchase assert_success response - assert_equal "1066662996", response.authorization + assert_equal '1066662996', response.authorization assert response.test? end @@ -30,7 +30,7 @@ def test_failed_purchase_due_to_failed_capture end.respond_with(successful_authorize_response, failed_capture_response) assert_failure response - assert_equal "DECLINE: 1", response.message + assert_equal 'DECLINE: 1', response.message assert response.test? end @@ -40,7 +40,7 @@ def test_failed_purchase_due_to_failed_auth end.respond_with(failed_authorize_response) assert_failure response - assert_equal "DECLINE: REJECTED_BY_ACQUIRER", response.message + assert_equal 'DECLINE: REJECTED_BY_ACQUIRER', response.message assert response.test? end @@ -49,7 +49,7 @@ def test_successful_authorize @gateway.authorize(@amount, @credit_card) end.respond_with(successful_authorize_response) assert_success response - assert_equal "1066662996", response.authorization + assert_equal '1066662996', response.authorization end def test_successful_authorize_and_capture @@ -58,7 +58,7 @@ def test_successful_authorize_and_capture end.respond_with(successful_authorize_response) assert_success response - assert_equal "1066662996", response.authorization + assert_equal '1066662996', response.authorization capture = stub_comms do @gateway.capture(@amount, response.authorization) @@ -75,13 +75,13 @@ def test_failed_authorize end.respond_with(failed_authorize_response) assert_failure response - assert_equal "DECLINE: REJECTED_BY_ACQUIRER", response.message + assert_equal 'DECLINE: REJECTED_BY_ACQUIRER', response.message assert response.test? end def test_failed_capture response = stub_comms do - @gateway.capture(100, "") + @gateway.capture(100, '') end.respond_with(failed_capture_response) assert_failure response @@ -93,7 +93,7 @@ def test_successful_void end.respond_with(successful_authorize_response) assert_success response - assert_equal "1066662996", response.authorization + assert_equal '1066662996', response.authorization void = stub_comms do @gateway.void(response.authorization) @@ -106,7 +106,7 @@ def test_successful_void def test_failed_void response = stub_comms do - @gateway.void("5d53a33d960c46d00f5dc061947d998c") + @gateway.void('5d53a33d960c46d00f5dc061947d998c') end.check_request do |endpoint, data, headers| assert_match(/5d53a33d960c46d00f5dc061947d998c/, data) end.respond_with(failed_void_response) @@ -120,7 +120,7 @@ def test_successful_refund end.respond_with(successful_authorize_response, successful_capture_response) assert_success response - assert_equal "1066662996", response.authorization + assert_equal '1066662996', response.authorization refund = stub_comms do @gateway.refund(@amount, response.authorization) @@ -133,7 +133,7 @@ def test_successful_refund def test_failed_refund response = stub_comms do - @gateway.refund(nil, "") + @gateway.refund(nil, '') end.respond_with(failed_refund_response) assert_failure response @@ -144,7 +144,7 @@ def test_successful_verify @gateway.verify(@credit_card) end.respond_with(successful_authorize_response, failed_void_response) assert_success response - assert_equal "Succeeded", response.message + assert_equal 'Succeeded', response.message end def test_failed_verify @@ -152,7 +152,7 @@ def test_failed_verify @gateway.verify(@credit_card) end.respond_with(failed_authorize_response, successful_void_response) assert_failure response - assert_equal "DECLINE: REJECTED_BY_ACQUIRER", response.message + assert_equal 'DECLINE: REJECTED_BY_ACQUIRER', response.message end def test_successful_store @@ -162,7 +162,7 @@ def test_successful_store assert_success response - assert_equal "Succeeded", response.message + assert_equal 'Succeeded', response.message assert response.test? end @@ -172,7 +172,7 @@ def test_failed_store end.respond_with(failed_store_response) assert_failure response - assert_equal "DECLINE: REJECTED_BY_ACQUIRER", response.message + assert_equal 'DECLINE: REJECTED_BY_ACQUIRER', response.message assert response.test? end @@ -232,7 +232,7 @@ def failed_store_response end def invalid_json_response - "{" + '{' end def transcript diff --git a/test/unit/gateways/digitzs_test.rb b/test/unit/gateways/digitzs_test.rb new file mode 100644 index 00000000000..99b57ddc432 --- /dev/null +++ b/test/unit/gateways/digitzs_test.rb @@ -0,0 +1,269 @@ +require 'test_helper' + +class DigitzsTest < Test::Unit::TestCase + include CommStub + + def setup + @gateway = DigitzsGateway.new(api_key: 'api_key', app_key: 'app_key') + @credit_card = credit_card + @amount = 100 + + @options = { + merchant_id: 'spreedly-susanswidg-32268973-2091076-148408385', + order_id: '1', + billing_address: address, + description: 'Store Purchase' + } + + @options_with_split = { + merchant_id: 'spreedly-susanswidg-32268973-2091076-148408385', + billing_address: address, + description: 'Split Purchase', + payment_type: 'card_split', + split_amount: 100, + split_merchant_id: 'spreedly-susanswidg-32270590-2095203-148657924' + } + end + + def test_successful_purchase + @gateway.expects(:ssl_post).times(2).returns(successful_app_token_response, successful_purchase_response) + + response = @gateway.purchase(@amount, @credit_card, @options) + assert_success response + + assert_equal 'spreedly-susanswidg-32268973-2091076-148408385-124-148606421', response.authorization + assert response.test? + end + + def test_successful_card_split_purchase + response = stub_comms do + @gateway.purchase(@amount, @credit_card, @options_with_split) + end.check_request do |endpoint, data, headers| + if data =~ /"cardSplit"/ + assert_match(%r(split), data) + assert_match(%r("merchantId":"spreedly-susanswidg-32270590-2095203-148657924"), data) + end + end.respond_with(successful_app_token_response, successful_purchase_response) + assert_success response + + assert_equal 'spreedly-susanswidg-32268973-2091076-148408385-124-148606421', response.authorization + end + + def test_successful_token_split_purchase + response = stub_comms do + @gateway.purchase(@amount, @credit_card, @options_with_split) + end.check_request do |endpoint, data, headers| + if data =~ /"tokenSplit"/ + assert_match(%r(split), data) + assert_match(%r("merchantId":"spreedly-susanswidg-32270590-2095203-148657924"), data) + end + end.respond_with(successful_app_token_response, successful_purchase_response) + assert_success response + + assert_equal 'spreedly-susanswidg-32268973-2091076-148408385-124-148606421', response.authorization + end + + def test_failed_purchase + @gateway.expects(:ssl_post).times(2).returns(successful_app_token_response, failed_purchase_response) + + response = @gateway.purchase(@amount, @credit_card, @options) + assert_failure response + assert_equal '58', response.error_code + end + + def test_successful_refund + @gateway.expects(:ssl_post).times(2).returns(successful_app_token_response, successful_refund_response) + + response = @gateway.refund(@amount, 'authorization', @options) + assert_success response + + assert_equal 'spreedly-susanswidg-32268973-2091076-148408385-127-148606617', response.authorization + assert response.test? + end + + def test_failed_refund + @gateway.expects(:ssl_post).times(2).returns(successful_app_token_response, failed_refund_response) + + response = @gateway.refund(@amount, '', @options) + assert_failure response + + assert_equal nil, response.authorization + assert response.test? + end + + def test_successful_store + @gateway.expects(:ssl_post).times(3).returns(successful_app_token_response, successful_create_customer_response, successful_token_response) + + response = @gateway.store(@credit_card, @options) + assert_success response + assert_equal 'spreedly-susanswidg-32268973-2091076-148408385-2894006614343495-148710226|c0302d83-a694-4bec-9086-d1886b9eefd9-148710226', response.authorization + end + + def test_successful_store_creates_new_customer + @gateway.expects(:ssl_get).returns(customer_id_exists_response) + @gateway.expects(:ssl_post).times(3).returns(successful_app_token_response, successful_create_customer_response, successful_token_response) + + assert response = @gateway.store(@credit_card, @options.merge({customer_id: 'pre_existing_customer_id'})) + assert_success response + assert_equal 'spreedly-susanswidg-32268973-2091076-148408385-2894006614343495-148710226|c0302d83-a694-4bec-9086-d1886b9eefd9-148710226', response.authorization + end + + def test_scrub + assert @gateway.supports_scrubbing? + assert_equal @gateway.scrub(pre_scrubbed), post_scrubbed + end + + private + + def pre_scrubbed + %q( +opening connection to beta.digitzsapi.com:443... +opened +starting SSL for beta.digitzsapi.com:443... +SSL established +<- "POST /sandbox/auth/token HTTP/1.1\r\nContent-Type: application/json\r\nX-Api-Key: 0HhRdOU2AsWVEu3gRIKi2UpMMmj8Fj48qggBYTo4\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nAccept: */*\r\nUser-Agent: Ruby\r\nConnection: close\r\nHost: beta.digitzsapi.com\r\nContent-Length: 115\r\n\r\n" +<- "{\"data\":{\"attributes\":{\"appKey\":\"tcwtTux8SPZYO44Gf0UHZH74Z1HSutqCxmIV2PFj2jRc9Poroh3Z3R1BBQNRQ98Q\"},\"type\":\"auth\"}}" +-> "HTTP/1.1 201 Created\r\n" +-> "Content-Type: application/json\r\n" +-> "Content-Length: 434\r\n" +-> "Connection: close\r\n" +-> "Date: Fri, 27 Jan 2017 20:47:32 GMT\r\n" +-> "Content-Location: https://beta.digitzsapi.com/sandbox/auth/token\r\n" +-> "x-amzn-RequestId: d3637ff0-e4d1-11e6-a393-3dbd03385fb7\r\n" +-> "X-Amzn-Trace-Id: Root=1-588bb1e4-49acd61c62e319bc67e443d8\r\n" +-> "Via: 1.1 344c0192a2becdfa5c3c6b927653ff8b.cloudfront.net (CloudFront), 1.1 986a2cb4ab6fb48c9a4379a4e9d691c4.cloudfront.net (CloudFront)\r\n" +-> "X-Cache: Miss from cloudfront\r\n" +-> "X-Amz-Cf-Id: NfmaknL15LfaGNXlXtc2mhwFwpzNHMbNExCfsMxORdRF7t3bbc77vA==\r\n" +-> "\r\n" +reading 434 bytes... +-> "{\"links\":{\"self\":\"https://beta.digitzsapi.com/sandbox/auth/token\"},\"data\":{\"type\":\"auth\",\"id\":\"0HhRdOU2AsWVEu3gRIKi2UpMMmj8Fj48qggBYTo4\",\"attributes\":{\"appToken\":\"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJwYXJ0bmVySWQiOiJzcHJlZWRseS0xNDgyMzAxOTEiLCJwYXJ0bmVyUHJlZml4Ijoic3ByZWVkbHkiLCJwcm9wYXlUaWVyIjoiU2V0TGlzdGVyIiwicHJvcGF5TWNjIjoiNTk5OSIsImlhdCI6MTQ4NTU1MDA1MiwiZXhwIjoxNDg1NTUzNjUyfQ.P2gunlNF56IKbAKpnRci7vLgUK0Yd7K1PGPzTtYP3Nc\"}}}" +read 434 bytes +Conn close +opening connection to beta.digitzsapi.com:443... +opened +starting SSL for beta.digitzsapi.com:443... +SSL established +<- "POST /sandbox/payments HTTP/1.1\r\nContent-Type: application/json\r\nX-Api-Key: 0HhRdOU2AsWVEu3gRIKi2UpMMmj8Fj48qggBYTo4\r\nAuthorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJwYXJ0bmVySWQiOiJzcHJlZWRseS0xNDgyMzAxOTEiLCJwYXJ0bmVyUHJlZml4Ijoic3ByZWVkbHkiLCJwcm9wYXlUaWVyIjoiU2V0TGlzdGVyIiwicHJvcGF5TWNjIjoiNTk5OSIsImlhdCI6MTQ4NTU1MDA1MiwiZXhwIjoxNDg1NTUzNjUyfQ.P2gunlNF56IKbAKpnRci7vLgUK0Yd7K1PGPzTtYP3Nc\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nAccept: */*\r\nUser-Agent: Ruby\r\nConnection: close\r\nHost: beta.digitzsapi.com\r\nContent-Length: 430\r\n\r\n" +<- "{\"data\":{\"attributes\":{\"paymentType\":\"card\",\"merchantId\":\"spreedly-susanswidg-32268973-2091076-148408385\",\"card\":{\"holder\":\"Longbob Longsen\",\"number\":\"4747474747474747\",\"expiry\":\"0918\",\"code\":\"999\"},\"transaction\":{\"amount\":\"200\",\"currency\":\"USD\",\"invoice\":\"91bbccdd926ab8effc53bc7be094bd2b\"},\"billingAddress\":{\"line1\":\"456 My Street\",\"line2\":\"Apt 1\",\"city\":\"Ottawa\",\"state\":\"ON\",\"zip\":\"K1C2N6\",\"country\":\"US\"}},\"type\":\"payments\"}}" +-> "HTTP/1.1 201 Created\r\n" +-> "Content-Type: application/json\r\n" +-> "Content-Length: 504\r\n" +-> "Connection: close\r\n" +-> "Date: Fri, 27 Jan 2017 20:47:35 GMT\r\n" +-> "Content-Location: https://beta.digitzsapi.com/sandbox/payments/spreedly-susanswidg-32268973-2091076-148408385-88-148555005\r\n" +-> "x-amzn-RequestId: d3dcf5b4-e4d1-11e6-9d9a-59db6e3f8bc6\r\n" +-> "X-Amzn-Trace-Id: Root=1-588bb1e5-5c6481e9f44a8bd604900914\r\n" +-> "Via: 1.1 b06057d522f80c65400aebb1c06a2d72.cloudfront.net (CloudFront), 1.1 e6cb8f0dccd39d6bf4fcef2d892671bf.cloudfront.net (CloudFront)\r\n" +-> "X-Cache: Miss from cloudfront\r\n" +-> "X-Amz-Cf-Id: Q62cc8eH9XbSUl9No6Mp_xPS10ld0GQ8XN_S5uT4RdxkvUUA97a2kg==\r\n" +-> "\r\n" +reading 504 bytes... +-> "{\"links\":{\"self\":\"https://beta.digitzsapi.com/sandbox/payments/spreedly-susanswidg-32268973-2091076-148408385-88-148555005\"},\"data\":{\"type\":\"payments\",\"id\":\"spreedly-susanswidg-32268973-2091076-148408385-88-148555005\",\"attributes\":{\"paymentType\":\"card\",\"transaction\":{\"code\":\"0\",\"message\":\"Success\",\"amount\":\"200\",\"invoice\":\"91bbccdd926ab8effc53bc7be094bd2b\",\"currency\":\"USD\",\"authCode\":\"A11111\",\"avsResult\":\"T\",\"codeResult\":\"M\",\"gross\":\"200\",\"net\":\"169\",\"grossMinusNet\":\"31\",\"fee\":\"25\",\"rate\":\"2.90\"}}}}" +read 504 bytes +Conn close + ) + end + + def post_scrubbed + %q( +opening connection to beta.digitzsapi.com:443... +opened +starting SSL for beta.digitzsapi.com:443... +SSL established +<- "POST /sandbox/auth/token HTTP/1.1\r\nContent-Type: application/json\r\nX-Api-Key: [FILTERED]\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nAccept: */*\r\nUser-Agent: Ruby\r\nConnection: close\r\nHost: beta.digitzsapi.com\r\nContent-Length: 115\r\n\r\n" +<- "{\"data\":{\"attributes\":{\"appKey\":\"[FILTERED] +-> "HTTP/1.1 201 Created\r\n" +-> "Content-Type: application/json\r\n" +-> "Content-Length: 434\r\n" +-> "Connection: close\r\n" +-> "Date: Fri, 27 Jan 2017 20:47:32 GMT\r\n" +-> "Content-Location: https://beta.digitzsapi.com/sandbox/auth/token\r\n" +-> "x-amzn-RequestId: d3637ff0-e4d1-11e6-a393-3dbd03385fb7\r\n" +-> "X-Amzn-Trace-Id: Root=1-588bb1e4-49acd61c62e319bc67e443d8\r\n" +-> "Via: 1.1 344c0192a2becdfa5c3c6b927653ff8b.cloudfront.net (CloudFront), 1.1 986a2cb4ab6fb48c9a4379a4e9d691c4.cloudfront.net (CloudFront)\r\n" +-> "X-Cache: Miss from cloudfront\r\n" +-> "X-Amz-Cf-Id: NfmaknL15LfaGNXlXtc2mhwFwpzNHMbNExCfsMxORdRF7t3bbc77vA==\r\n" +-> "\r\n" +reading 434 bytes... +-> "{\"links\":{\"self\":\"https://beta.digitzsapi.com/sandbox/auth/token\"},\"data\":{\"type\":\"auth\",\"id\":\"[FILTERED] +read 434 bytes +Conn close +opening connection to beta.digitzsapi.com:443... +opened +starting SSL for beta.digitzsapi.com:443... +SSL established +<- "POST /sandbox/payments HTTP/1.1\r\nContent-Type: application/json\r\nX-Api-Key: [FILTERED]\r\nAuthorization: Bearer [FILTERED] +<- "{\"data\":{\"attributes\":{\"paymentType\":\"card\",\"merchantId\":\"spreedly-susanswidg-32268973-2091076-148408385\",\"card\":{\"holder\":\"Longbob Longsen\",\"number\":\"[FILTERED]\",\"expiry\":\"0918\",\"code\":\"[FILTERED]\"},\"transaction\":{\"amount\":\"200\",\"currency\":\"USD\",\"invoice\":\"91bbccdd926ab8effc53bc7be094bd2b\"},\"billingAddress\":{\"line1\":\"456 My Street\",\"line2\":\"Apt 1\",\"city\":\"Ottawa\",\"state\":\"ON\",\"zip\":\"K1C2N6\",\"country\":\"US\"}},\"type\":\"payments\"}}" +-> "HTTP/1.1 201 Created\r\n" +-> "Content-Type: application/json\r\n" +-> "Content-Length: 504\r\n" +-> "Connection: close\r\n" +-> "Date: Fri, 27 Jan 2017 20:47:35 GMT\r\n" +-> "Content-Location: https://beta.digitzsapi.com/sandbox/payments/spreedly-susanswidg-32268973-2091076-148408385-88-148555005\r\n" +-> "x-amzn-RequestId: d3dcf5b4-e4d1-11e6-9d9a-59db6e3f8bc6\r\n" +-> "X-Amzn-Trace-Id: Root=1-588bb1e5-5c6481e9f44a8bd604900914\r\n" +-> "Via: 1.1 b06057d522f80c65400aebb1c06a2d72.cloudfront.net (CloudFront), 1.1 e6cb8f0dccd39d6bf4fcef2d892671bf.cloudfront.net (CloudFront)\r\n" +-> "X-Cache: Miss from cloudfront\r\n" +-> "X-Amz-Cf-Id: Q62cc8eH9XbSUl9No6Mp_xPS10ld0GQ8XN_S5uT4RdxkvUUA97a2kg==\r\n" +-> "\r\n" +reading 504 bytes... +-> "{\"links\":{\"self\":\"https://beta.digitzsapi.com/sandbox/payments/spreedly-susanswidg-32268973-2091076-148408385-88-148555005\"},\"data\":{\"type\":\"payments\",\"id\":\"[FILTERED] +read 504 bytes +Conn close + ) + end + + def successful_app_token_response + %( + {\"links\":{\"self\":\"https://beta.digitzsapi.com/sandbox/auth/token\"},\"data\":{\"type\":\"auth\",\"id\":\"0HhRdOU2AsWVEu3gRIKi2UpMMmj8Fj48qggBYTo4\",\"attributes\":{\"appToken\":\"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJwYXJ0bmVySWQiOiJzcHJlZWRseS0xNDgyMzAxOTEiLCJwYXJ0bmVyUHJlZml4Ijoic3ByZWVkbHkiLCJwcm9wYXlUaWVyIjoiU2V0TGlzdGVyIiwicHJvcGF5TWNjIjoiNTk5OSIsImlhdCI6MTQ4NjA2NDIxNiwiZXhwIjoxNDg2MDY3ODE2fQ.MaLR3ijeMuIGSHnNYINVILwa9hpxahd4U4Q44HW4jFQ\"}}} + ) + end + + def successful_purchase_response + %( + {\"links\":{\"self\":\"https://beta.digitzsapi.com/sandbox/payments/spreedly-susanswidg-32268973-2091076-148408385-124-148606421\"},\"data\":{\"type\":\"payments\",\"id\":\"spreedly-susanswidg-32268973-2091076-148408385-124-148606421\",\"attributes\":{\"paymentType\":\"card\",\"transaction\":{\"code\":\"0\",\"message\":\"Success\",\"amount\":\"200\",\"invoice\":\"42d7b1d026becf29e2005bae84e8935b\",\"currency\":\"USD\",\"authCode\":\"A11111\",\"avsResult\":\"T\",\"codeResult\":\"M\",\"gross\":\"200\",\"net\":\"169\",\"grossMinusNet\":\"31\",\"fee\":\"25\",\"rate\":\"2.90\"}}}} + ) + end + + def successful_split_purchase_response + %( + {\"links\":{\"self\":\"https://beta.digitzsapi.com/sandbox/payments/spreedly-susanswidg-32268973-2091076-148408385-153-148658575\"},\"data\":{\"type\":\"payments\",\"id\":\"spreedly-susanswidg-32268973-2091076-148408385-153-148658575\",\"attributes\":{\"paymentType\":\"cardSplit\",\"transaction\":{\"code\":\"0\",\"message\":\"Success\",\"amount\":\"500\",\"invoice\":\"88ec8adf6c86762684ae54820423acc8\",\"currency\":\"USD\",\"authCode\":\"A11111\",\"avsResult\":\"T\",\"codeResult\":\"M\"},\"split\":{\"merchantId\":\"spreedly-susanswidg-32270590-2095203-148657924\",\"amount\":\"100\",\"splitId\":\"spreedly-susanswidg-32270590-2095203-148657924-2-148658575\"}}}} + ) + end + + def failed_purchase_response + %( + {\"meta\":{},\"errors\":[{\"status\":\"400\",\"source\":{\"pointer\":\"/payments\"},\"title\":\"Bad Request\",\"detail\":\"Partner error: Credit card declined (transaction element shows reason for decline)\",\"code\":\"58\",\"meta\":{\"debug\":{\"message\":\"Include debug info with support request.\",\"resource\":\"/payments POST\",\"log\":\"2017/02/02/[23]eb325f3ca78b4f7eb2178a0d1e635a0e\",\"request\":\"73c22dc3-e980-11e6-9390-69c24d5ed1f4\"},\"transaction\":{\"code\":\"51\",\"message\":\"Insufficient funds\",\"invoice\":\"3d1f247d9112349e3db252f9f3327047\",\"authCode\":\"A11111\",\"avsResult\":\"T\"}}}]} + ) + end + + def successful_refund_response + %( + {\"links\":{\"self\":\"https://beta.digitzsapi.com/sandbox/payments/spreedly-susanswidg-32268973-2091076-148408385-127-148606617\"},\"data\":{\"type\":\"payments\",\"id\":\"spreedly-susanswidg-32268973-2091076-148408385-127-148606617\",\"attributes\":{\"paymentType\":\"cardRefund\",\"transaction\":{\"code\":\"0\",\"message\":\"Success\",\"amount\":\"200\",\"invoice\":\"f87139e53b5273c12bc32d4be6fff9a8\",\"currency\":\"USD\"}}}} + ) + end + + def failed_refund_response + %( + {\"meta\":{},\"errors\":[{\"status\":\"400\",\"source\":{\"pointer\":\"/data/attributes/originalTransaction/id\"},\"title\":\"Bad Request\",\"detail\":\"\\\"id\\\" is not allowed to be empty\"}]} + ) + end + + def successful_create_customer_response + %( + {\"links\":{\"self\":\"https://beta.digitzsapi.com/sandbox/customers/spreedly-susanswidg-32268973-2091076-148408385-2894006614343495-148710226\"},\"data\":{\"type\":\"customers\",\"id\":\"spreedly-susanswidg-32268973-2091076-148408385-2894006614343495-148710226\",\"attributes\":{\"name\":\"Longbob Longsen\",\"externalId\":\"2b942bae49e9297f60428ee841f30724\"}}} + ) + end + + def successful_token_response + %( + {\"links\":{\"self\":\"https://beta.digitzsapi.com/sandbox/tokens/c0302d83-a694-4bec-9086-d1886b9eefd9-148710226\"},\"data\":{\"type\":\"tokens\",\"id\":\"c0302d83-a694-4bec-9086-d1886b9eefd9-148710226\",\"attributes\":{\"label\":\"Credit Card\",\"customerId\":\"spreedly-susanswidg-32268973-2091076-148408385-2894006614343495-148710226\"}}} + ) + end + + def customer_id_exists_response + %( + {\"links\":{\"self\":\"https://beta.digitzsapi.com/sandbox/customers/spreedly-susanswidg-32268973-2091076-148408385-5980208887457495-148700575\"},\"data\":{\"id\":\"spreedly-susanswidg-32268973-2091076-148408385-5980208887457495-148700575\",\"attributes\":{\"merchantId\":\"spreedly-susanswidg-32268973-2091076-148408385\",\"created\":\"2017-02-13T17:09:12.724Z\",\"name\":\"Jon Doe\",\"externalId\":\"123456\"},\"type\":\"customers\"}} + ) + end +end diff --git a/test/unit/gateways/ebanx_test.rb b/test/unit/gateways/ebanx_test.rb new file mode 100644 index 00000000000..c5e93bc8e13 --- /dev/null +++ b/test/unit/gateways/ebanx_test.rb @@ -0,0 +1,247 @@ +require 'test_helper' + +class EbanxTest < Test::Unit::TestCase + def setup + @gateway = EbanxGateway.new(integration_key: 'key') + @credit_card = credit_card + @amount = 100 + + @options = { + order_id: '1', + billing_address: address, + description: 'Store Purchase' + } + end + + def test_successful_purchase + @gateway.expects(:ssl_request).returns(successful_purchase_response) + + response = @gateway.purchase(@amount, @credit_card, @options) + assert_success response + + assert_equal '592db57ad6933455efbb62a48d1dfa091dd7cd092109db99', response.authorization + assert response.test? + end + + def test_failed_purchase + @gateway.expects(:ssl_request).returns(failed_purchase_response) + + response = @gateway.purchase(@amount, @credit_card, @options) + assert_failure response + assert_equal 'NOK', response.error_code + end + + def test_successful_authorize + @gateway.expects(:ssl_request).returns(successful_authorize_response) + + response = @gateway.authorize(@amount, @credit_card, @options) + assert_success response + + assert_equal '592dc02dbe421478a132bf5c2ecfe52c86ac01b454ae799b', response.authorization + assert response.test? + end + + def test_failed_authorize + @gateway.expects(:ssl_request).returns(failed_authorize_response) + + response = @gateway.purchase(@amount, @credit_card, @options) + assert_failure response + assert_equal 'NOK', response.error_code + end + + def test_successful_capture + @gateway.expects(:ssl_request).returns(successful_capture_response) + + response = @gateway.capture(@amount, 'authorization', @options) + assert_success response + + assert_equal 'Sandbox - Test credit card, transaction captured', response.message + assert response.test? + end + + def test_failed_capture + @gateway.expects(:ssl_request).returns(failed_capture_response) + + response = @gateway.capture(@amount, '', @options) + assert_failure response + assert_equal 'BP-CAP-1', response.error_code + end + + def test_successful_refund + @gateway.expects(:ssl_request).returns(successful_refund_response) + + response = @gateway.refund(@amount, 'authorization', @options) + assert_success response + + assert_equal '59306246f2a0c5f327a15dd6492687e197aca7eda179da08', response.authorization + assert response.test? + end + + def test_failed_refund + @gateway.expects(:ssl_request).returns(failed_refund_response) + + response = @gateway.refund(@amount, '', @options) + assert_failure response + assert_equal 'BP-REF-CAN-2', response.error_code + end + + def test_successful_void + @gateway.expects(:ssl_request).returns(successful_void_response) + + response = @gateway.void('authorization', @options) + assert_success response + + assert_equal '5930629dde0899dc53b3557ea9887aa8f3d264a91d115d40', response.authorization + assert response.test? + end + + def test_failed_void + @gateway.expects(:ssl_request).returns(failed_void_response) + + response = @gateway.void('', @options) + assert_failure response + assert_equal 'BP-CAN-1', response.error_code + end + + def test_successful_verify + @gateway.expects(:ssl_request).times(2).returns(successful_authorize_response, successful_void_response) + + response = @gateway.verify(@credit_card, @options) + assert_success response + assert_equal nil, response.error_code + end + + def test_successful_verify_with_failed_void + @gateway.expects(:ssl_request).times(2).returns(successful_authorize_response, failed_void_response) + + response = @gateway.verify(@credit_card, @options) + assert_success response + assert_equal nil, response.error_code + end + + def test_failed_verify + @gateway.expects(:ssl_request).returns(failed_authorize_response) + + response = @gateway.verify(@credit_card, @options) + assert_failure response + assert_equal 'NOK', response.error_code + end + + def test_successful_store_and_purchase + @gateway.expects(:ssl_request).returns(successful_store_response) + + store = @gateway.store(@credit_card, @options) + assert_success store + assert_equal 'a61a7c98535718801395991b5112f888d359c2d632e2c3bb8afe75aa23f3334d7fd8dc57d7721f8162503773063de59ee85901b5714a92338c6d9c0352aee78c|visa', store.authorization + + @gateway.expects(:ssl_request).returns(successful_purchase_with_stored_card_response) + + response = @gateway.purchase(@amount, store.authorization, @options) + assert_success response + end + + def test_error_response_with_invalid_creds + @gateway.expects(:ssl_request).returns(invalid_cred_response) + + response = @gateway.store(@credit_card, @options) + assert_failure response + assert_equal 'Invalid integration key', response.message + end + + def test_scrub + assert @gateway.supports_scrubbing? + assert_equal @gateway.scrub(pre_scrubbed), post_scrubbed + end + + private + + def pre_scrubbed + %q( + request_body={\"integration_key\":\"1231000\",\"operation\":\"request\",\"payment\":{\"amount_total\":\"1.00\",\"currency_code\":\"USD\",\"merchant_payment_code\":\"2bed75b060e936834e354d944aeaa892\",\"name\":\"Longbob Longsen\",\"email\":\"unspecified@example.com\",\"document\":\"853.513.468-93\",\"payment_type_code\":\"visa\",\"creditcard\":{\"card_number\":\"4111111111111111\",\"card_name\":\"Longbob Longsen\",\"card_due_date\":\"9/2018\",\"card_cvv\":\"123\"},\"address\":\"Rua E\",\"street_number\":\"1040\",\"city\":\"Maracana\u{fa}\",\"state\":\"CE\",\"zipcode\":\"61919-230\",\"country\":\"BR\",\"phone_number\":\"(555)555-5555\"}} + ) + end + + def post_scrubbed + %q( + request_body={\"integration_key\":\"[FILTERED]\",\"operation\":\"request\",\"payment\":{\"amount_total\":\"1.00\",\"currency_code\":\"USD\",\"merchant_payment_code\":\"2bed75b060e936834e354d944aeaa892\",\"name\":\"Longbob Longsen\",\"email\":\"unspecified@example.com\",\"document\":\"853.513.468-93\",\"payment_type_code\":\"visa\",\"creditcard\":{\"card_number\":\"[FILTERED]\",\"card_name\":\"Longbob Longsen\",\"card_due_date\":\"9/2018\",\"card_cvv\":\"[FILTERED]\"},\"address\":\"Rua E\",\"street_number\":\"1040\",\"city\":\"Maracana\u{fa}\",\"state\":\"CE\",\"zipcode\":\"61919-230\",\"country\":\"BR\",\"phone_number\":\"(555)555-5555\"}} + ) + end + + def successful_purchase_response + %( + {"payment":{"hash":"592db57ad6933455efbb62a48d1dfa091dd7cd092109db99","pin":"081043552","merchant_payment_code":"ca2251ed6ac582162b17d77dfd7fb98a","order_number":null,"status":"CO","status_date":"2017-05-30 15:10:01","open_date":"2017-05-30 15:10:01","confirm_date":"2017-05-30 15:10:01","transfer_date":null,"amount_br":"3.31","amount_ext":"1.00","amount_iof":"0.01","currency_rate":"3.3000","currency_ext":"USD","due_date":"2017-06-02","instalments":"1","payment_type_code":"visa","transaction_status":{"acquirer":"EBANX","code":"OK","description":"Sandbox - Test credit card, transaction captured"},"pre_approved":true,"capture_available":false,"customer":{"document":"85351346893","email":"unspecified@example.com","name":"LONGBOB LONGSEN","birth_date":null}},"status":"SUCCESS"} + ) + end + + def failed_purchase_response + %( + {"payment":{"hash":"592dd2f17965cd3d7a17e71a3fe943b8363c72d60caffacc","pin":"655998606","merchant_payment_code":"e71e467805aef9064599bc5a76e98e23","order_number":null,"status":"CA","status_date":"2017-05-30 17:15:45","open_date":"2017-05-30 17:15:45","confirm_date":null,"transfer_date":null,"amount_br":"3.31","amount_ext":"1.00","amount_iof":"0.01","currency_rate":"3.3000","currency_ext":"USD","due_date":"2017-06-02","instalments":"1","payment_type_code":"visa","transaction_status":{"acquirer":"EBANX","code":"NOK","description":"Sandbox - Test credit card, transaction declined reason insufficientFunds"},"pre_approved":false,"capture_available":false,"customer":{"document":"85351346893","email":"unspecified@example.com","name":"LONGBOB LONGSEN","birth_date":null}},"status":"SUCCESS"} + ) + end + + def successful_authorize_response + %( + {"payment":{"hash":"592dc02dbe421478a132bf5c2ecfe52c86ac01b454ae799b","pin":"296389224","merchant_payment_code":"8e5c943c3c93adbed8d8a7347ca333fe","order_number":null,"status":"PE","status_date":null,"open_date":"2017-05-30 15:55:40","confirm_date":null,"transfer_date":null,"amount_br":"3.31","amount_ext":"1.00","amount_iof":"0.01","currency_rate":"3.3000","currency_ext":"USD","due_date":"2017-06-02","instalments":"1","payment_type_code":"visa","transaction_status":{"acquirer":"EBANX","code":"OK","description":"Sandbox - Test credit card, transaction will be approved"},"pre_approved":true,"capture_available":true,"customer":{"document":"85351346893","email":"unspecified@example.com","name":"LONGBOB LONGSEN","birth_date":null}},"status":"SUCCESS"} + ) + end + + def failed_authorize_response + %( + {"payment":{"hash":"592dd2146d5b8a27924daaa0f0248d8c582cb2ce6b67495e","pin":"467618452","merchant_payment_code":"7883bdbbdfa961ce753247fbeb4ff99d","order_number":null,"status":"CA","status_date":"2017-05-30 17:12:03","open_date":"2017-05-30 17:12:03","confirm_date":null,"transfer_date":null,"amount_br":"3.31","amount_ext":"1.00","amount_iof":"0.01","currency_rate":"3.3000","currency_ext":"USD","due_date":"2017-06-02","instalments":"1","payment_type_code":"visa","transaction_status":{"acquirer":"EBANX","code":"NOK","description":"Sandbox - Test credit card, transaction declined reason insufficientFunds"},"pre_approved":false,"capture_available":false,"customer":{"document":"85351346893","email":"unspecified@example.com","name":"LONGBOB LONGSEN","birth_date":null}},"status":"SUCCESS"} + ) + end + + def successful_capture_response + %( + {"payment":{"hash":"592dd65824427e4f5f50564c118f399869637bfb30d54f5b","pin":"081043654","merchant_payment_code":"8424e3000d64d056fbd58639957dc1c4","order_number":null,"status":"CO","status_date":"2017-05-30 17:30:16","open_date":"2017-05-30 17:30:15","confirm_date":"2017-05-30 17:30:16","transfer_date":null,"amount_br":"3.31","amount_ext":"1.00","amount_iof":"0.01","currency_rate":"3.3000","currency_ext":"USD","due_date":"2017-06-02","instalments":"1","payment_type_code":"visa","transaction_status":{"acquirer":"EBANX","code":"OK","description":"Sandbox - Test credit card, transaction captured"},"pre_approved":true,"capture_available":false,"customer":{"document":"85351346893","email":"unspecified@example.com","name":"LONGBOB LONGSEN","birth_date":null}},"status":"SUCCESS"} + ) + end + + def failed_capture_response + %( + {"status":"ERROR","status_code":"BP-CAP-1","status_message":"Parameters hash or merchant_payment_code not informed"} + ) + end + + def successful_refund_response + %( + {"payment":{"hash":"59306246f2a0c5f327a15dd6492687e197aca7eda179da08","pin":"446189033","merchant_payment_code":"b5e1f7298f8fa645e8a903fbdc5ce44a","order_number":null,"status":"CO","status_date":"2017-06-01 15:51:49","open_date":"2017-06-01 15:51:49","confirm_date":"2017-06-01 15:51:49","transfer_date":null,"amount_br":"3.31","amount_ext":"1.00","amount_iof":"0.01","currency_rate":"3.3000","currency_ext":"USD","due_date":"2017-06-04","instalments":"1","payment_type_code":"visa","transaction_status":{"acquirer":"EBANX","code":"OK","description":"Sandbox - Test credit card, transaction captured"},"pre_approved":true,"capture_available":false,"refunds":[{"id":"20739","merchant_refund_code":null,"status":"RE","request_date":"2017-06-01 15:51:50","pending_date":null,"confirm_date":null,"cancel_date":null,"amount_ext":"1.00","description":"full refund"}],"customer":{"document":"85351346893","email":"unspecified@example.com","name":"LONGBOB LONGSEN","birth_date":null}},"refund":{"id":"20739","merchant_refund_code":null,"status":"RE","request_date":"2017-06-01 15:51:50","pending_date":null,"confirm_date":null,"cancel_date":null,"amount_ext":"1.00","description":"full refund"},"operation":"refund","status":"SUCCESS"} + ) + end + + def failed_refund_response + %( + {"status":"ERROR","status_code":"BP-REF-CAN-2","status_message":"Payment not found with this hash: "} + ) + end + + def successful_void_response + %( + {"payment":{"hash":"5930629dde0899dc53b3557ea9887aa8f3d264a91d115d40","pin":"465556618","merchant_payment_code":"8b97c49aecffbb309dadd08c87ccbdd0","order_number":null,"status":"CA","status_date":"2017-06-01 15:53:18","open_date":"2017-06-01 15:53:17","confirm_date":null,"transfer_date":null,"amount_br":"3.31","amount_ext":"1.00","amount_iof":"0.01","currency_rate":"3.3000","currency_ext":"USD","due_date":"2017-06-04","instalments":"1","payment_type_code":"visa","transaction_status":{"acquirer":"EBANX","code":"NOK","description":"Sandbox - Test credit card, transaction cancelled"},"pre_approved":false,"capture_available":false,"customer":{"document":"85351346893","email":"unspecified@example.com","name":"LONGBOB LONGSEN","birth_date":null}},"operation":"cancel","status":"SUCCESS"} + ) + end + + def failed_void_response + %( + {"status":"ERROR","status_code":"BP-CAN-1","status_message":"Parameter hash not informed"} + ) + end + + def successful_store_response + %( + {"status":"SUCCESS","payment_type_code":"visa","token":"a61a7c98535718801395991b5112f888d359c2d632e2c3bb8afe75aa23f3334d7fd8dc57d7721f8162503773063de59ee85901b5714a92338c6d9c0352aee78c","masked_card_number":"411111xxxxxx1111"} + ) + end + + def successful_purchase_with_stored_card_response + %( + {"payment":{"hash":"59d3e2955021c5e2b180e1ea9670e2d9675c15453a2ab346","pin":"252076123","merchant_payment_code":"a942f8a68836e888fa8e8af1e8ca4bf2","order_number":null,"status":"CO","status_date":"2017-10-03 19:18:45","open_date":"2017-10-03 19:18:44","confirm_date":"2017-10-03 19:18:45","transfer_date":null,"amount_br":"3.31","amount_ext":"1.00","amount_iof":"0.01","currency_rate":"3.3000","currency_ext":"USD","due_date":"2017-10-06","instalments":"1","payment_type_code":"visa","details":{"billing_descriptor":""},"transaction_status":{"acquirer":"EBANX","code":"OK","description":"Accepted"},"pre_approved":true,"capture_available":false,"customer":{"document":"85351346893","email":"unspecified@example.com","name":"NOT PROVIDED","birth_date":null}},"status":"SUCCESS"} + ) + end + + def invalid_cred_response + %( + {"status":"ERROR","status_code":"DA-1","status_message":"Invalid integration key"} + ) + end +end diff --git a/test/unit/gateways/efsnet_test.rb b/test/unit/gateways/efsnet_test.rb index efd5cc71ce0..e437e2aa422 100644 --- a/test/unit/gateways/efsnet_test.rb +++ b/test/unit/gateways/efsnet_test.rb @@ -22,7 +22,6 @@ def test_successful_purchase assert response.test? assert_equal '100018347764;1.00', response.authorization assert_equal 'Approved', response.message - end def test_unsuccessful_purchase @@ -36,29 +35,29 @@ def test_unsuccessful_purchase end def test_credit - @gateway.expects(:ssl_post).with(anything, regexp_matches(/AccountNumber>#{@credit_card.number}<\/AccountNumber/), anything).returns("") + @gateway.expects(:ssl_post).with(anything, regexp_matches(/AccountNumber>#{@credit_card.number}<\/AccountNumber/), anything).returns('') @gateway.credit(@amount, @credit_card, :order_id => 5) end def test_deprecated_credit - @gateway.expects(:ssl_post).with(anything, regexp_matches(/<OriginalTransactionID>transaction_id<\/OriginalTransactionID>/), anything).returns("") + @gateway.expects(:ssl_post).with(anything, regexp_matches(/<OriginalTransactionID>transaction_id<\/OriginalTransactionID>/), anything).returns('') assert_deprecation_warning(Gateway::CREDIT_DEPRECATION_MESSAGE) do - @gateway.credit(@amount, "transaction_id", :order_id => 5) + @gateway.credit(@amount, 'transaction_id', :order_id => 5) end end def test_refund - @gateway.expects(:ssl_post).with(anything, regexp_matches(/<OriginalTransactionID>transaction_id<\/OriginalTransactionID>/), anything).returns("") - @gateway.refund(@amount, "transaction_id", :order_id => 5) + @gateway.expects(:ssl_post).with(anything, regexp_matches(/<OriginalTransactionID>transaction_id<\/OriginalTransactionID>/), anything).returns('') + @gateway.refund(@amount, 'transaction_id', :order_id => 5) end def test_authorize_is_valid_xml params = { - :order_id => "order1", - :transaction_amount => "1.01", - :account_number => "4242424242424242", - :expiration_month => "12", - :expiration_year => "2029", + :order_id => 'order1', + :transaction_amount => '1.01', + :account_number => '4242424242424242', + :expiration_month => '12', + :expiration_year => '2029', } assert data = @gateway.send(:post_data, :credit_card_authorize, params) @@ -67,10 +66,10 @@ def test_authorize_is_valid_xml def test_settle_is_valid_xml params = { - :order_id => "order1", - :transaction_amount => "1.01", - :original_transaction_amount => "1.01", - :original_transaction_id => "1", + :order_id => 'order1', + :transaction_amount => '1.01', + :original_transaction_amount => '1.01', + :original_transaction_id => '1', } assert data = @gateway.send(:post_data, :credit_card_settle, params) @@ -92,6 +91,7 @@ def test_cvv_result end private + def successful_purchase_response <<-XML <?xml version="1.0"?> diff --git a/test/unit/gateways/elavon_test.rb b/test/unit/gateways/elavon_test.rb index 26f384dbdf7..cf8557ce0af 100644 --- a/test/unit/gateways/elavon_test.rb +++ b/test/unit/gateways/elavon_test.rb @@ -37,7 +37,7 @@ def test_successful_authorization assert_success response assert_equal '123456;00000000-0000-0000-0000-00000000000', response.authorization - assert_equal "APPROVED", response.message + assert_equal 'APPROVED', response.message assert response.test? end @@ -58,7 +58,7 @@ def test_successful_capture assert_success response assert_equal '123456;00000000-0000-0000-0000-00000000000', response.authorization - assert_equal "APPROVAL", response.message + assert_equal 'APPROVAL', response.message assert response.test? end @@ -71,7 +71,7 @@ def test_successful_capture_with_auth_code assert_success response assert_equal '123456;00000000-0000-0000-0000-00000000000', response.authorization - assert_equal "APPROVAL", response.message + assert_equal 'APPROVAL', response.message assert response.test? end @@ -89,7 +89,7 @@ def test_successful_capture_with_additional_options assert_success response assert_equal '123456;00000000-0000-0000-0000-00000000000', response.authorization - assert_equal "APPROVAL", response.message + assert_equal 'APPROVAL', response.message assert response.test? end @@ -176,7 +176,7 @@ def test_successful_verify_failed_void @gateway.verify(@credit_card, @options) end.respond_with(successful_authorization_response, failed_void_response) assert_success response - assert_equal "APPROVED", response.message + assert_equal 'APPROVED', response.message end def test_unsuccessful_verify @@ -184,7 +184,7 @@ def test_unsuccessful_verify @gateway.verify(@credit_card, @options) end.respond_with(failed_authorization_response, successful_void_response) assert_failure response - assert_equal "The Credit Card Number supplied in the authorization request appears to be invalid.", response.message + assert_equal 'The Credit Card Number supplied in the authorization request appears to be invalid.', response.message end def test_invalid_login @@ -218,7 +218,7 @@ def test_successful_store assert response = @gateway.store(@credit_card, @options) assert_success response - assert_equal '7595301425001111', response.params["token"] + assert_equal '7595301425001111', response.params['token'] assert response.test? end @@ -252,7 +252,7 @@ def test_stripping_non_word_characters_from_zip @options[:billing_address][:zip] = bad_zip - @gateway.expects(:commit).with(anything, anything, has_entries(:avs_zip => stripped_zip)) + @gateway.expects(:commit).with(anything, anything, has_entries(:avs_zip => stripped_zip), anything) @gateway.purchase(@amount, @credit_card, @options) end @@ -260,12 +260,28 @@ def test_stripping_non_word_characters_from_zip def test_zip_codes_with_letters_are_left_intact @options[:billing_address][:zip] = '.K1%Z_5E3-' - @gateway.expects(:commit).with(anything, anything, has_entries(:avs_zip => 'K1Z5E3')) + @gateway.expects(:commit).with(anything, anything, has_entries(:avs_zip => 'K1Z5E3'), anything) @gateway.purchase(@amount, @credit_card, @options) end + def test_custom_fields_in_request + stub_comms do + @gateway.purchase(@amount, @credit_card, @options.merge(:customer_number => '123', :custom_fields => {:a_key => 'a value'})) + end.check_request do |endpoint, data, headers| + assert_match(/customer_number=123/, data) + assert_match(/a_key/, data) + refute_match(/ssl_a_key/, data) + end.respond_with(successful_purchase_response) + end + + def test_transcript_scrubbing + assert @gateway.supports_scrubbing? + assert_equal @gateway.scrub(pre_scrub), post_scrub + end + private + def successful_purchase_response "ssl_card_number=42********4242 ssl_exp_date=0910 @@ -356,7 +372,7 @@ def failed_void_response end def invalid_login_response - <<-RESPONSE + <<-RESPONSE ssl_result=7000\r ssl_result_message=The VirtualMerchant ID and/or User ID supplied in the authorization request is invalid.\r RESPONSE @@ -383,7 +399,7 @@ def failed_authorization_response errorName=Credit Card Number Invalid errorMessage=The Credit Card Number supplied in the authorization request appears to be invalid." end - + def successful_capture_response "ssl_card_number=42********4242 ssl_exp_date=0910 @@ -451,4 +467,78 @@ def failed_update_response errorName=Credit Card Number Invalid errorMessage=The Credit Card Number supplied in the authorization request appears to be invalid." end + + def pre_scrub + %q{ +opening connection to api.demo.convergepay.com:443... +opened +starting SSL for api.demo.convergepay.com:443... +SSL established +<- "POST /VirtualMerchantDemo/process.do HTTP/1.1\r\nContent-Type: application/x-www-form-urlencoded\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nAccept: */*\r\nUser-Agent: Ruby\r\nConnection: close\r\nHost: api.demo.convergepay.com\r\nContent-Length: 616\r\n\r\n" +<- "ssl_merchant_id=000127&ssl_pin=IERAOBEE5V0D6Q3Q6R51TG89XAIVGEQ3LGLKMKCKCVQBGGGAU7FN627GPA54P5HR&ssl_show_form=false&ssl_result_format=ASCII&ssl_user_id=ssltest&ssl_invoice_number=&ssl_description=Test+Transaction&ssl_card_number=4124939999999990&ssl_exp_date=0919&ssl_cvv2cvc2=123&ssl_cvv2cvc2_indicator=1&ssl_first_name=Longbob&ssl_last_name=Longsen&ssl_avs_address=456+My+Street&ssl_address2=Apt+1&ssl_avs_zip=K1C2N6&ssl_city=Ottawa&ssl_state=ON&ssl_company=Widgets+Inc&ssl_phone=%28555%29555-5555&ssl_country=CA&ssl_email=paul%40domain.com&ssl_cardholder_ip=203.0.113.0&ssl_amount=1.00&ssl_transaction_type=CCSALE" +-> "HTTP/1.1 200 OK\r\n" +-> "Date: Wed, 03 Jan 2018 21:40:26 GMT\r\n" +-> "Pragma: no-cache\r\n" +-> "Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0\r\n" +-> "Expires: 0\r\n" +-> "Content-Disposition: inline; filename=response.txt\r\n" +-> "AuthApproved: true\r\n" +-> "AuthResponse: AA\r\n" +-> "Set-Cookie: JSESSIONID=00007wKfJV3-JFME8QiC_RCDjuI:14j4qkv92; HTTPOnly; Path=/; Secure\r\n" +-> "Set-Cookie: JSESSIONID=0000uW6woWZ84eAJunhFLfJz8hS:14j4qkv92; HTTPOnly; Path=/; Secure\r\n" +-> "Connection: close\r\n" +-> "Content-Type: text/plain\r\n" +-> "Content-Language: en-US\r\n" +-> "Content-Encoding: gzip\r\n" +-> "Transfer-Encoding: chunked\r\n" +-> "\r\n" +-> "1A5 \r\n" +reading 421 bytes... +-> "\x1F\x8B\b\x00\x00\x00\x00\x00\x00\x03MR\xEFk\xDB0\x10\xFD\xDE\xBF\xC2\x1F\xB7\x81[\xC9\xB1\x1D\xBB \x98\x7FtP\xD66!+\xDBGs\xB1o\x99\xC0\x96\x84%{q\xFF\xFA\xC9R\x12f\x10\xDC\xBDw\xBEw\xEF8\xAD\xFB\xA6\x85\xB1k\xC44\x1Cqd1\xFDr\xFB\xF2<'w\xDA\x16\xE0Y5\x1D\x18d$\xA7\xB9C`\x90\x930\x8C\xDE\x13_\xA1\xA1Gm\xE0\xCC\\\xC6\xC5,y\x8B\xD7\x9E\x0E\x130\xA0\x8FV9\x1Fu\xA8`4\xD3\x88\xBE\xFB\xDD;WM\xE1;\xFBJ9\xA8\x1E\r\x97\xE2Rp\x05A,\xEC\x17\xEFNht\xF0,Z\x87\xFF\xE6\xA36^\xE6E\x8A\xD3Q\x1E\x1D\xDC\xC3\xFF\xA8F\xE1P\x98u\x03]7\xA2\xD6,N\xD2\xE0u\t~\x98\x11\xD1x\xD63\x11+\x94\t\xA8W\xE5fa;c\xE0/\xB8\xDC\x9A\xB5\x03\xED\xDEn\xDD>\xB8b\xDFi\x15\xBD\xA5\xBE~u1.\xAC*\\\xAA\xFEH\x81\xECS\x92$\x9F\xED\v\xEDK\x1C\x8E\x03\xF0\x9E)\x98\xFA\xAF\x9D\xB4\xB1\xB8\xB7\xF6\x1Cc\a\x98z\xC3\xFCz}\xD2\fv(8!+\xF6\xFB\xC3\xEEg\xF1\xE28s\x16\r\xEF\x18\xD9\x10J\xB3\x82&!\xA9\xD3:O\xF3*|\x8A\xEA2\x8C\xB34\t\xB3o\xDB$,\xD3\xA2,\xB3tC\xB7E\xE9\xFE\x04\xA5F9\xC3:l\x87,\xDEnI\x1C9\xA2\x9D\xE7h\xD5TR\xE8\xCB\xD6W\x8B7\xE4\xE2\xBAu&\x9B#\xF4 Z{\x1C\xD7cX'2\xDCn\x9C\xD0\a\xB2y\x88\b\xCD\x02\x12?\xC6\xE41\xDA\x06\xFBW/\xB1\xDE\x9CY\x14\xB2\xEA\xF0T?\xBFW\xC5\xA1\xFE\aC\x85\x1DS\x8C\x02\x00\x00" +read 421 bytes +reading 2 bytes... +-> "\r\n" +read 2 bytes +-> "0\r\n" +-> "\r\n" +Conn close +}} + end + + def post_scrub + %q{ +opening connection to api.demo.convergepay.com:443... +opened +starting SSL for api.demo.convergepay.com:443... +SSL established +<- "POST /VirtualMerchantDemo/process.do HTTP/1.1\r\nContent-Type: application/x-www-form-urlencoded\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nAccept: */*\r\nUser-Agent: Ruby\r\nConnection: close\r\nHost: api.demo.convergepay.com\r\nContent-Length: 616\r\n\r\n" +<- "ssl_merchant_id=000127&ssl_pin=[FILTERED]&ssl_show_form=false&ssl_result_format=ASCII&ssl_user_id=ssltest&ssl_invoice_number=&ssl_description=Test+Transaction&ssl_card_number=[FILTERED]&ssl_exp_date=0919&ssl_cvv2cvc2=[FILTERED]&ssl_cvv2cvc2_indicator=1&ssl_first_name=Longbob&ssl_last_name=Longsen&ssl_avs_address=456+My+Street&ssl_address2=Apt+1&ssl_avs_zip=K1C2N6&ssl_city=Ottawa&ssl_state=ON&ssl_company=Widgets+Inc&ssl_phone=%28555%29555-5555&ssl_country=CA&ssl_email=paul%40domain.com&ssl_cardholder_ip=203.0.113.0&ssl_amount=1.00&ssl_transaction_type=CCSALE" +-> "HTTP/1.1 200 OK\r\n" +-> "Date: Wed, 03 Jan 2018 21:40:26 GMT\r\n" +-> "Pragma: no-cache\r\n" +-> "Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0\r\n" +-> "Expires: 0\r\n" +-> "Content-Disposition: inline; filename=response.txt\r\n" +-> "AuthApproved: true\r\n" +-> "AuthResponse: AA\r\n" +-> "Set-Cookie: JSESSIONID=00007wKfJV3-JFME8QiC_RCDjuI:14j4qkv92; HTTPOnly; Path=/; Secure\r\n" +-> "Set-Cookie: JSESSIONID=0000uW6woWZ84eAJunhFLfJz8hS:14j4qkv92; HTTPOnly; Path=/; Secure\r\n" +-> "Connection: close\r\n" +-> "Content-Type: text/plain\r\n" +-> "Content-Language: en-US\r\n" +-> "Content-Encoding: gzip\r\n" +-> "Transfer-Encoding: chunked\r\n" +-> "\r\n" +-> "1A5 \r\n" +reading 421 bytes... +-> "\x1F\x8B\b\x00\x00\x00\x00\x00\x00\x03MR\xEFk\xDB0\x10\xFD\xDE\xBF\xC2\x1F\xB7\x81[\xC9\xB1\x1D\xBB \x98\x7FtP\xD66!+\xDBGs\xB1o\x99\xC0\x96\x84%{q\xFF\xFA\xC9R\x12f\x10\xDC\xBDw\xBEw\xEF8\xAD\xFB\xA6\x85\xB1k\xC44\x1Cqd1\xFDr\xFB\xF2<'w\xDA\x16\xE0Y5\x1D\x18d$\xA7\xB9C`\x90\x930\x8C\xDE\x13_\xA1\xA1Gm\xE0\xCC\\\xC6\xC5,y\x8B\xD7\x9E\x0E\x130\xA0\x8FV9\x1Fu\xA8`4\xD3\x88\xBE\xFB\xDD;WM\xE1;\xFBJ9\xA8\x1E\r\x97\xE2Rp\x05A,\xEC\x17\xEFNht\xF0,Z\x87\xFF\xE6\xA36^\xE6E\x8A\xD3Q\x1E\x1D\xDC\xC3\xFF\xA8F\xE1P\x98u\x03]7\xA2\xD6,N\xD2\xE0u\t~\x98\x11\xD1x\xD63\x11+\x94\t\xA8W\xE5fa;c\xE0/\xB8\xDC\x9A\xB5\x03\xED\xDEn\xDD>\xB8b\xDFi\x15\xBD\xA5\xBE~u1.\xAC*\\\xAA\xFEH\x81\xECS\x92$\x9F\xED\v\xEDK\x1C\x8E\x03\xF0\x9E)\x98\xFA\xAF\x9D\xB4\xB1\xB8\xB7\xF6\x1Cc\a\x98z\xC3\xFCz}\xD2\fv(8!+\xF6\xFB\xC3\xEEg\xF1\xE28s\x16\r\xEF\x18\xD9\x10J\xB3\x82&!\xA9\xD3:O\xF3*|\x8A\xEA2\x8C\xB34\t\xB3o\xDB$,\xD3\xA2,\xB3tC\xB7E\xE9\xFE\x04\xA5F9\xC3:l\x87,\xDEnI\x1C9\xA2\x9D\xE7h\xD5TR\xE8\xCB\xD6W\x8B7\xE4\xE2\xBAu&\x9B#\xF4 Z{\x1C\xD7cX'2\xDCn\x9C\xD0\a\xB2y\x88\b\xCD\x02\x12?\xC6\xE41\xDA\x06\xFBW/\xB1\xDE\x9CY\x14\xB2\xEA\xF0T?\xBFW\xC5\xA1\xFE\aC\x85\x1DS\x8C\x02\x00\x00" +read 421 bytes +reading 2 bytes... +-> "\r\n" +read 2 bytes +-> "0\r\n" +-> "\r\n" +Conn close +}} + end end diff --git a/test/unit/gateways/element_test.rb b/test/unit/gateways/element_test.rb index c032c360459..253cfcdccbf 100644 --- a/test/unit/gateways/element_test.rb +++ b/test/unit/gateways/element_test.rb @@ -49,7 +49,7 @@ def test_failed_purchase_with_echeck def test_successful_purchase_with_payment_account_token @gateway.expects(:ssl_post).returns(successful_purchase_with_payment_account_token_response) - response = @gateway.purchase(@amount, "payment-account-token-id", @options) + response = @gateway.purchase(@amount, 'payment-account-token-id', @options) assert_success response assert_equal '2005838405|100', response.authorization @@ -58,9 +58,10 @@ def test_successful_purchase_with_payment_account_token def test_failed_purchase_with_payment_account_token @gateway.expects(:ssl_post).returns(failed_purchase_with_payment_account_token_response) - response = @gateway.purchase(@amount, "bad-payment-account-token-id", @options) + response = @gateway.purchase(@amount, 'bad-payment-account-token-id', @options) assert_failure response end + def test_successful_authorize @gateway.expects(:ssl_post).returns(successful_authorize_response) @@ -81,7 +82,7 @@ def test_failed_authorize def test_successful_capture @gateway.expects(:ssl_post).returns(successful_capture_response) - response = @gateway.capture(@amount, "trans-id") + response = @gateway.capture(@amount, 'trans-id') assert_success response assert_equal 'Success', response.message end @@ -89,7 +90,7 @@ def test_successful_capture def test_failed_capture @gateway.expects(:ssl_post).returns(failed_capture_response) - response = @gateway.capture(@amount, "bad-trans-id") + response = @gateway.capture(@amount, 'bad-trans-id') assert_failure response assert_equal 'TransactionID required', response.message end @@ -97,7 +98,7 @@ def test_failed_capture def test_successful_refund @gateway.expects(:ssl_post).returns(successful_refund_response) - response = @gateway.refund(@amount, "trans-id") + response = @gateway.refund(@amount, 'trans-id') assert_success response assert_equal 'Approved', response.message end @@ -105,7 +106,7 @@ def test_successful_refund def test_failed_refund @gateway.expects(:ssl_post).returns(failed_refund_response) - response = @gateway.refund(@amount, "bad-trans-id") + response = @gateway.refund(@amount, 'bad-trans-id') assert_failure response assert_equal 'TransactionID required', response.message end @@ -113,7 +114,7 @@ def test_failed_refund def test_successful_void @gateway.expects(:ssl_post).returns(successful_void_response) - response = @gateway.void("trans-id") + response = @gateway.void('trans-id') assert_success response assert_equal 'Success', response.message end @@ -121,7 +122,7 @@ def test_successful_void def test_failed_void @gateway.expects(:ssl_post).returns(failed_void_response) - response = @gateway.void("bad-trans-id") + response = @gateway.void('bad-trans-id') assert_failure response assert_equal 'TransactionAmount required', response.message end @@ -151,7 +152,7 @@ def test_handles_error_response @gateway.expects(:ssl_post).returns(error_response) response = @gateway.purchase(@amount, @credit_card, @options) - assert_equal response.message, "TargetNamespace required" + assert_equal response.message, 'TargetNamespace required' assert_failure response end diff --git a/test/unit/gateways/epay_test.rb b/test/unit/gateways/epay_test.rb index 462ecf1cbf4..59becd05499 100644 --- a/test/unit/gateways/epay_test.rb +++ b/test/unit/gateways/epay_test.rb @@ -26,7 +26,7 @@ def test_failed_purchase assert response = @gateway.authorize(100, @credit_card) assert_failure response assert_equal 'The payment was declined. Try again in a moment or try with another credit card.', - response.message + response.message end def test_invalid_characters_in_response @@ -35,11 +35,11 @@ def test_invalid_characters_in_response assert response = @gateway.authorize(100, @credit_card) assert_failure response assert_equal 'The payment was declined of unknown reasons. For more information contact the bank. E.g. try with another credit card.<br />Denied - Call your bank for information', - response.message + response.message end def test_failed_response_on_purchase - @gateway.expects(:raw_ssl_request).returns(Net::HTTPBadRequest.new(1.0, 400,'Bad Request')) + @gateway.expects(:raw_ssl_request).returns(Net::HTTPBadRequest.new(1.0, 400, 'Bad Request')) assert response = @gateway.authorize(100, @credit_card) assert_equal 400, response.params['response_code'] diff --git a/test/unit/gateways/evo_ca_test.rb b/test/unit/gateways/evo_ca_test.rb index e699e1462a1..f2fe062e658 100644 --- a/test/unit/gateways/evo_ca_test.rb +++ b/test/unit/gateways/evo_ca_test.rb @@ -99,7 +99,7 @@ def test_successful_refund def test_add_address result = {} - @gateway.send(:add_address, result, :address => {:address1 => '123 Main Street', :country => 'CA', :state => 'BC'} ) + @gateway.send(:add_address, result, :address => {:address1 => '123 Main Street', :country => 'CA', :state => 'BC'}) assert_equal %w{address1 address2 city company country firstname lastname phone state zip}, result.stringify_keys.keys.sort assert_equal 'BC', result[:state] assert_equal '123 Main Street', result[:address1] @@ -109,7 +109,7 @@ def test_add_address def test_add_shipping_address result = {} - @gateway.send(:add_address, result, :shipping_address => {:address1 => '123 Main Street', :country => 'CA', :state => 'BC'} ) + @gateway.send(:add_address, result, :shipping_address => {:address1 => '123 Main Street', :country => 'CA', :state => 'BC'}) assert_equal %w{shipping_address1 shipping_address2 shipping_city shipping_company shipping_country shipping_firstname shipping_lastname shipping_state shipping_zip}, result.stringify_keys.keys.sort assert_equal 'BC', result[:shipping_state] assert_equal '123 Main Street', result[:shipping_address1] diff --git a/test/unit/gateways/eway_managed_test.rb b/test/unit/gateways/eway_managed_test.rb index 4586f4b9a88..02666e0bc71 100644 --- a/test/unit/gateways/eway_managed_test.rb +++ b/test/unit/gateways/eway_managed_test.rb @@ -14,22 +14,23 @@ def setup @amount = 100 - @options = { :billing_address => { - :address1 => '1234 My Street', - :address2 => 'Apt 1', - :company => 'Widgets Inc', - :city => 'Ottawa', - :state => 'ON', - :zip => 'K1C2N6', - :country => 'au', - :title => 'Mr.', - :phone => '(555)555-5555' - }, - :email => 'someguy1232@fakeemail.net', - :order_id => '1000', - :customer => 'mycustomerref', - :description => 'My Description', - :invoice => 'invoice-4567' + @options = { + :billing_address => { + :address1 => '1234 My Street', + :address2 => 'Apt 1', + :company => 'Widgets Inc', + :city => 'Ottawa', + :state => 'ON', + :zip => 'K1C2N6', + :country => 'au', + :title => 'Mr.', + :phone => '(555)555-5555' + }, + :email => 'someguy1232@fakeemail.net', + :order_id => '1000', + :customer => 'mycustomerref', + :description => 'My Description', + :invoice => 'invoice-4567' } end @@ -76,10 +77,10 @@ def test_successful_purchase assert response = @gateway.purchase(@amount, @valid_customer_id, @options) assert_instance_of EwayManagedGateway::EwayResponse, response - assert_equal "00,Transaction Approved(Test Gateway)", response.message + assert_equal '00,Transaction Approved(Test Gateway)', response.message assert_success response - assert_equal "123456", response.authorization - assert_equal "123456", response.params['transaction_number'] + assert_equal '123456', response.authorization + assert_equal '123456', response.params['transaction_number'] assert response.test? end @@ -125,7 +126,6 @@ def test_purchase_invoice_reference_comes_from_order_id_or_invoice request_hash['Envelope']['Body']['ProcessPayment']['invoiceReference'] == 'order_id' }.returns(successful_purchase_response) @gateway.purchase(@amount, @valid_customer_id, options) - end def test_invalid_customer_id @@ -141,9 +141,9 @@ def test_successful_store assert response = @gateway.store(@credit_card, @options) assert_instance_of EwayManagedGateway::EwayResponse, response - assert_equal "OK", response.message + assert_equal 'OK', response.message assert_success response - assert_equal "1234567", response.token + assert_equal '1234567', response.token assert response.test? end @@ -230,7 +230,7 @@ def test_sucessful_update assert response = @gateway.store(@credit_card, @options) assert_instance_of EwayManagedGateway::EwayResponse, response - assert_equal "OK", response.message + assert_equal 'OK', response.message assert_success response assert response.test? end @@ -240,7 +240,7 @@ def test_successful_retrieve assert response = @gateway.retrieve(@valid_customer_id) assert_instance_of EwayManagedGateway::EwayResponse, response - assert_equal "OK", response.message + assert_equal 'OK', response.message assert_success response assert response.test? end @@ -372,9 +372,9 @@ def expected_store_request XML end - # Documented here: https://www.eway.com.au/gateway/ManagedPaymentService/managedCreditCardPayment.asmx?op=CreateCustomer - def expected_purchase_request - <<-XML + # Documented here: https://www.eway.com.au/gateway/ManagedPaymentService/managedCreditCardPayment.asmx?op=CreateCustomer + def expected_purchase_request + <<-XML <?xml version="1.0" encoding="utf-8"?> <soap12:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap12="http://www.w3.org/2003/05/soap-envelope"> <soap12:Header> @@ -393,10 +393,10 @@ def expected_purchase_request </ProcessPayment> </soap12:Body> </soap12:Envelope> - XML - end + XML + end - # Documented here: https://www.eway.com.au/gateway/ManagedPaymentService/managedCreditCardPayment.asmx?op=QueryCustomer + # Documented here: https://www.eway.com.au/gateway/ManagedPaymentService/managedCreditCardPayment.asmx?op=QueryCustomer def expected_retrieve_request <<-XML <?xml version="1.0" encoding="utf-8"?> @@ -416,5 +416,4 @@ def expected_retrieve_request </soap12:Envelope> XML end - end diff --git a/test/unit/gateways/eway_rapid_test.rb b/test/unit/gateways/eway_rapid_test.rb index 2b2b4534346..15788011e99 100644 --- a/test/unit/gateways/eway_rapid_test.rb +++ b/test/unit/gateways/eway_rapid_test.rb @@ -1,4 +1,4 @@ -require "test_helper" +require 'test_helper' class EwayRapidTest < Test::Unit::TestCase include CommStub @@ -6,8 +6,8 @@ class EwayRapidTest < Test::Unit::TestCase def setup ActiveMerchant::Billing::EwayRapidGateway.partner_id = nil @gateway = EwayRapidGateway.new( - :login => "login", - :password => "password" + :login => 'login', + :password => 'password' ) @credit_card = credit_card @@ -20,7 +20,7 @@ def test_successful_purchase end.respond_with(successful_purchase_response) assert_success response - assert_equal "Transaction Approved Successful", response.message + assert_equal 'Transaction Approved Successful', response.message assert_equal 10440187, response.authorization assert response.test? end @@ -45,7 +45,7 @@ def test_failed_purchase end.respond_with(failed_purchase_response) assert_failure response - assert_equal "Invalid Payment TotalAmount", response.message + assert_equal 'Invalid Payment TotalAmount', response.message assert_nil response.authorization assert response.test? end @@ -56,7 +56,7 @@ def test_failed_purchase_without_message end.respond_with(failed_purchase_response_without_message) assert_failure response - assert_equal "Do Not Honour", response.message + assert_equal 'Do Not Honour', response.message assert_nil response.authorization assert response.test? end @@ -67,7 +67,7 @@ def test_failed_purchase_with_multiple_messages end.respond_with(failed_purchase_response_multiple_messages) assert_failure response - assert_equal "Invalid Customer Phone,Invalid ShippingAddress Phone", response.message + assert_equal 'Invalid Customer Phone,Invalid ShippingAddress Phone', response.message assert_nil response.authorization assert response.test? end @@ -76,40 +76,40 @@ def test_purchase_with_all_options response = stub_comms do @gateway.purchase(200, @credit_card, :transaction_type => 'CustomTransactionType', - :redirect_url => "http://awesomesauce.com", - :ip => "0.0.0.0", - :application_id => "Woohoo", - :partner_id => "SomePartner", - :description => "The Really Long Description More Than Sixty Four Characters Gets Truncated", - :order_id => "orderid1", - :invoice => "I1234", - :currency => "INR", - :email => "jim@example.com", + :redirect_url => 'http://awesomesauce.com', + :ip => '0.0.0.0', + :application_id => 'Woohoo', + :partner_id => 'SomePartner', + :description => 'The Really Long Description More Than Sixty Four Characters Gets Truncated', + :order_id => 'orderid1', + :invoice => 'I1234', + :currency => 'INR', + :email => 'jim@example.com', :billing_address => { - :title => "Mr.", - :name => "Jim Awesome Smith", - :company => "Awesome Co", - :address1 => "1234 My Street", - :address2 => "Apt 1", - :city => "Ottawa", - :state => "ON", - :zip => "K1C2N6", - :country => "CA", - :phone => "(555)555-5555", - :fax => "(555)555-6666" + :title => 'Mr.', + :name => 'Jim Awesome Smith', + :company => 'Awesome Co', + :address1 => '1234 My Street', + :address2 => 'Apt 1', + :city => 'Ottawa', + :state => 'ON', + :zip => 'K1C2N6', + :country => 'CA', + :phone => '(555)555-5555', + :fax => '(555)555-6666' }, :shipping_address => { - :title => "Ms.", - :name => "Baker", - :company => "Elsewhere Inc.", - :address1 => "4321 Their St.", - :address2 => "Apt 2", - :city => "Chicago", - :state => "IL", - :zip => "60625", - :country => "US", - :phone => "1115555555", - :fax => "1115556666" + :title => 'Ms.', + :name => 'Baker', + :company => 'Elsewhere Inc.', + :address1 => '4321 Their St.', + :address2 => 'Apt 2', + :city => 'Chicago', + :state => 'IL', + :zip => '60625', + :country => 'US', + :phone => '1115555555', + :fax => '1115556666' } ) end.check_request do |endpoint, data, headers| @@ -185,11 +185,11 @@ def test_partner_id_is_omitted_when_not_set end def test_partner_id_truncates_to_50_characters - partner_string = "EWay Rapid PartnerID is capped at 50 characters and will truncate if it is too long." + partner_string = 'EWay Rapid PartnerID is capped at 50 characters and will truncate if it is too long.' stub_comms do @gateway.purchase(200, @credit_card, partner_id: partner_string) end.check_request do |endpoint, data, headers| - assert_match(%r{"PartnerID":"#{partner_string.slice(0,50)}"}, data) + assert_match(%r{"PartnerID":"#{partner_string.slice(0, 50)}"}, data) end.respond_with(successful_purchase_response) end @@ -199,17 +199,17 @@ def test_successful_authorize end.respond_with(successful_authorize_response) assert_success response - assert_equal "Transaction Approved Successful", response.message + assert_equal 'Transaction Approved Successful', response.message assert_equal 10774952, response.authorization end def test_successful_capture response = stub_comms do - @gateway.capture(nil, "auth") + @gateway.capture(nil, 'auth') end.respond_with(successful_capture_response) assert_success response - assert_equal "982541", response.message + assert_equal '982541', response.message assert_equal 10774953, response.authorization end @@ -219,61 +219,61 @@ def test_failed_authorize end.respond_with(failed_authorize_response) assert_failure response - assert_equal "Invalid Payment TotalAmount", response.message + assert_equal 'Invalid Payment TotalAmount', response.message assert_nil response.authorization end def test_failed_capture response = stub_comms do - @gateway.capture(@amount, "auth") + @gateway.capture(@amount, 'auth') end.respond_with(failed_capture_response) assert_failure response - assert_equal "Invalid Auth Transaction ID for Capture/Void", response.message + assert_equal 'Invalid Auth Transaction ID for Capture/Void', response.message assert_equal 0, response.authorization end def test_successful_void response = stub_comms do - @gateway.void("auth") + @gateway.void('auth') end.respond_with(successful_void_response) assert_success response - assert_equal "878060", response.message + assert_equal '878060', response.message assert_equal 10775041, response.authorization end def test_failed_void response = stub_comms do - @gateway.void(@amount, "auth") + @gateway.void(@amount, 'auth') end.respond_with(failed_void_response) assert_failure response - assert_equal "Invalid Auth Transaction ID for Capture/Void", response.message + assert_equal 'Invalid Auth Transaction ID for Capture/Void', response.message assert_equal 0, response.authorization end def test_successful_store response = stub_comms do @gateway.store(@credit_card, :billing_address => { - :title => "Mr.", - :name => "Jim Awesome Smith", - :company => "Awesome Co", - :address1 => "1234 My Street", - :address2 => "Apt 1", - :city => "Ottawa", - :state => "ON", - :zip => "K1C2N6", - :country => "CA", - :phone => "(555)555-5555", - :fax => "(555)555-6666" + :title => 'Mr.', + :name => 'Jim Awesome Smith', + :company => 'Awesome Co', + :address1 => '1234 My Street', + :address2 => 'Apt 1', + :city => 'Ottawa', + :state => 'ON', + :zip => 'K1C2N6', + :country => 'CA', + :phone => '(555)555-5555', + :fax => '(555)555-6666' }) end.check_request do |endpoint, data, headers| assert_match '"Method":"CreateTokenCustomer"', data end.respond_with(successful_store_response) assert_success response - assert_equal "Transaction Approved Successful", response.message + assert_equal 'Transaction Approved Successful', response.message assert_equal 917224224772, response.authorization assert response.test? end @@ -284,7 +284,7 @@ def test_failed_store end.respond_with(failed_store_response) assert_failure response - assert_equal "Customer CountryCode Required", response.message + assert_equal 'Customer CountryCode Required', response.message assert_nil response.authorization assert response.test? end @@ -297,7 +297,7 @@ def test_successful_update end.respond_with(successful_update_response) assert_success response - assert_equal "Transaction Approved Successful", response.message + assert_equal 'Transaction Approved Successful', response.message assert_equal 916161208398, response.authorization assert response.test? end @@ -313,7 +313,7 @@ def test_successful_refund end.respond_with(successful_refund_response) assert_success response - assert_equal "Transaction Approved Successful", response.message + assert_equal 'Transaction Approved Successful', response.message assert_equal 10488258, response.authorization assert response.test? end @@ -324,7 +324,7 @@ def test_failed_refund end.respond_with(failed_refund_response) assert_failure response - assert_equal "System Error", response.message + assert_equal 'System Error', response.message assert_nil response.authorization assert response.test? end @@ -338,7 +338,7 @@ def test_successful_stored_card_purchase end.respond_with(successful_store_purchase_response) assert_success response - assert_equal "Transaction Approved Successful", response.message + assert_equal 'Transaction Approved Successful', response.message assert_equal 10440234, response.authorization assert response.test? end @@ -346,27 +346,27 @@ def test_successful_stored_card_purchase def test_verification_results response = stub_comms do @gateway.purchase(100, @credit_card) - end.respond_with(successful_purchase_response(:verification_status => "Valid")) + end.respond_with(successful_purchase_response(:verification_status => 'Valid')) assert_success response - assert_equal "M", response.cvv_result["code"] - assert_equal "M", response.avs_result["code"] + assert_equal 'M', response.cvv_result['code'] + assert_equal 'M', response.avs_result['code'] response = stub_comms do @gateway.purchase(100, @credit_card) - end.respond_with(successful_purchase_response(:verification_status => "Invalid")) + end.respond_with(successful_purchase_response(:verification_status => 'Invalid')) assert_success response - assert_equal "N", response.cvv_result["code"] - assert_equal "N", response.avs_result["code"] + assert_equal 'N', response.cvv_result['code'] + assert_equal 'N', response.avs_result['code'] response = stub_comms do @gateway.purchase(100, @credit_card) - end.respond_with(successful_purchase_response(:verification_status => "Unchecked")) + end.respond_with(successful_purchase_response(:verification_status => 'Unchecked')) assert_success response - assert_equal "P", response.cvv_result["code"] - assert_equal "I", response.avs_result["code"] + assert_equal 'P', response.cvv_result['code'] + assert_equal 'I', response.avs_result['code'] end def test_transcript_scrubbing diff --git a/test/unit/gateways/eway_test.rb b/test/unit/gateways/eway_test.rb index 5dbe984051a..5c1059163e5 100644 --- a/test/unit/gateways/eway_test.rb +++ b/test/unit/gateways/eway_test.rb @@ -70,11 +70,11 @@ def test_failed_refund end def test_amount_style - assert_equal '1034', @gateway.send(:amount, 1034) + assert_equal '1034', @gateway.send(:amount, 1034) - assert_raise(ArgumentError) do - @gateway.send(:amount, '10.34') - end + assert_raise(ArgumentError) do + @gateway.send(:amount, '10.34') + end end def test_ensure_does_not_respond_to_authorize @@ -97,6 +97,7 @@ def test_transcript_scrubbing end private + def successful_purchase_response <<-XML <?xml version="1.0"?> diff --git a/test/unit/gateways/exact_test.rb b/test/unit/gateways/exact_test.rb index be5dbb6ea8f..664f3d27ebf 100644 --- a/test/unit/gateways/exact_test.rb +++ b/test/unit/gateways/exact_test.rb @@ -2,8 +2,8 @@ class ExactTest < Test::Unit::TestCase def setup - @gateway = ExactGateway.new( :login => "A00427-01", - :password => "testus" ) + @gateway = ExactGateway.new(:login => 'A00427-01', + :password => 'testus') @credit_card = credit_card @amount = 100 @@ -22,12 +22,12 @@ def test_successful_purchase assert response.test? assert_equal 'Transaction Normal - VER UNAVAILABLE', response.message - ExactGateway::SENSITIVE_FIELDS.each{ |f| assert !response.params.has_key?(f.to_s) } + ExactGateway::SENSITIVE_FIELDS.each { |f| assert !response.params.has_key?(f.to_s) } end def test_successful_refund @gateway.expects(:ssl_post).returns(successful_refund_response) - assert response = @gateway.refund(@amount, "123") + assert response = @gateway.refund(@amount, '123') assert_success response end @@ -35,7 +35,7 @@ def test_deprecated_credit @gateway.expects(:ssl_post).returns(successful_refund_response) assert_deprecation_warning(Gateway::CREDIT_DEPRECATION_MESSAGE) do - assert response = @gateway.credit(@amount, "123") + assert response = @gateway.credit(@amount, '123') assert_success response end end @@ -48,11 +48,10 @@ def test_failed_purchase assert_failure response end - def test_expdate - assert_equal( "%02d%s" % [ @credit_card.month, - @credit_card.year.to_s[-2..-1] ], - @gateway.send(:expdate, @credit_card) ) + assert_equal('%02d%s' % [ @credit_card.month, + @credit_card.year.to_s[-2..-1] ], + @gateway.send(:expdate, @credit_card)) end def test_soap_fault @@ -85,8 +84,8 @@ def test_cvv_result assert_equal 'M', response.cvv_result['code'] end - private + def successful_purchase_response <<-RESPONSE <?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:tns="http://secure2.e-xact.com/vplug-in/transaction/rpc-enc/" xmlns:types="http://secure2.e-xact.com/vplug-in/transaction/rpc-enc/encodedTypes" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><soap:Body soap:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><q1:SendAndCommitResponse xmlns:q1="http://secure2.e-xact.com/vplug-in/transaction/rpc-enc/Response"><SendAndCommitResult href="#id1" /></q1:SendAndCommitResponse><types:TransactionResult id="id1" xsi:type="types:TransactionResult"><ExactID xsi:type="xsd:string">A00427-01</ExactID><Password xsi:type="xsd:string">#######</Password><Transaction_Type xsi:type="xsd:string">00</Transaction_Type><DollarAmount xsi:type="xsd:string">1</DollarAmount><SurchargeAmount xsi:type="xsd:string">0</SurchargeAmount><Card_Number xsi:type="xsd:string">4242424242424242</Card_Number><Transaction_Tag xsi:type="xsd:string">106625152</Transaction_Tag><Authorization_Num xsi:type="xsd:string">ET1700</Authorization_Num><Expiry_Date xsi:type="xsd:string">0909</Expiry_Date><CardHoldersName xsi:type="xsd:string">Longbob Longsen</CardHoldersName><VerificationStr2 xsi:type="xsd:string">123</VerificationStr2><CVD_Presence_Ind xsi:type="xsd:string">1</CVD_Presence_Ind><Secure_AuthRequired xsi:type="xsd:string">0</Secure_AuthRequired><Secure_AuthResult xsi:type="xsd:string">0</Secure_AuthResult><Ecommerce_Flag xsi:type="xsd:string">0</Ecommerce_Flag><CAVV_Algorithm xsi:type="xsd:string">0</CAVV_Algorithm><Reference_No xsi:type="xsd:string">1</Reference_No><Reference_3 xsi:type="xsd:string">Store Purchase</Reference_3><Language xsi:type="xsd:string">0</Language><LogonMessage xsi:type="xsd:string">Processed by: @@ -122,6 +121,7 @@ def successful_purchase_response </CTR></types:TransactionResult></soap:Body></soap:Envelope> RESPONSE end + def successful_refund_response <<-RESPONSE <?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:tns="http://secure2.e-xact.com/vplug-in/transaction/rpc-enc/" xmlns:types="http://secure2.e-xact.com/vplug-in/transaction/rpc-enc/encodedTypes" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><soap:Body soap:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><q1:SendAndCommitResponse xmlns:q1="http://secure2.e-xact.com/vplug-in/transaction/rpc-enc/Response"><SendAndCommitResult href="#id1" /></q1:SendAndCommitResponse><types:TransactionResult id="id1" xsi:type="types:TransactionResult"><ExactID xsi:type="xsd:string">A00427-01</ExactID><Password xsi:type="xsd:string">#######</Password><Transaction_Type xsi:type="xsd:string">00</Transaction_Type><DollarAmount xsi:type="xsd:string">1</DollarAmount><SurchargeAmount xsi:type="xsd:string">0</SurchargeAmount><Card_Number xsi:type="xsd:string">4242424242424242</Card_Number><Transaction_Tag xsi:type="xsd:string">106625152</Transaction_Tag><Authorization_Num xsi:type="xsd:string">ET1700</Authorization_Num><Expiry_Date xsi:type="xsd:string">0909</Expiry_Date><CardHoldersName xsi:type="xsd:string">Longbob Longsen</CardHoldersName><VerificationStr2 xsi:type="xsd:string">123</VerificationStr2><CVD_Presence_Ind xsi:type="xsd:string">1</CVD_Presence_Ind><Secure_AuthRequired xsi:type="xsd:string">0</Secure_AuthRequired><Secure_AuthResult xsi:type="xsd:string">0</Secure_AuthResult><Ecommerce_Flag xsi:type="xsd:string">0</Ecommerce_Flag><CAVV_Algorithm xsi:type="xsd:string">0</CAVV_Algorithm><Reference_No xsi:type="xsd:string">1</Reference_No><Reference_3 xsi:type="xsd:string">Store Purchase</Reference_3><Language xsi:type="xsd:string">0</Language><LogonMessage xsi:type="xsd:string">Processed by: diff --git a/test/unit/gateways/ezic_test.rb b/test/unit/gateways/ezic_test.rb index 8f379901fac..5fa29b4004b 100644 --- a/test/unit/gateways/ezic_test.rb +++ b/test/unit/gateways/ezic_test.rb @@ -22,8 +22,8 @@ def test_successful_purchase assert_success response assert_equal '120741089764', response.authorization assert response.test? - assert_equal "Street address and 9-digit postal code match.", response.avs_result["message"] - assert_equal "CVV matches", response.cvv_result["message"] + assert_equal 'Street address and 9-digit postal code match.', response.avs_result['message'] + assert_equal 'CVV matches', response.cvv_result['message'] end def test_failed_purchase @@ -31,7 +31,7 @@ def test_failed_purchase response = @gateway.purchase(@amount, @credit_card, @options) assert_failure response - assert_equal "TEST DECLINED", response.message + assert_equal 'TEST DECLINED', response.message end def test_successful_authorize @@ -47,13 +47,13 @@ def test_failed_authorize response = @gateway.authorize(@amount, @credit_card, @options) assert_failure response - assert_equal "TEST DECLINED", response.message + assert_equal 'TEST DECLINED', response.message end def test_successful_capture @gateway.expects(:ssl_post).returns(successful_capture_response) - response = @gateway.capture(@amount, "123312") + response = @gateway.capture(@amount, '123312') assert_success response assert_equal '120762306743', response.authorization end @@ -61,15 +61,15 @@ def test_successful_capture def test_failed_capture @gateway.expects(:raw_ssl_request).returns(failed_capture_response) - response = @gateway.capture(@amount, "2131212") + response = @gateway.capture(@amount, '2131212') assert_failure response - assert_equal "20105: Settlement amount cannot exceed authorized amount", response.message + assert_equal '20105: Settlement amount cannot exceed authorized amount', response.message end def test_successful_refund @gateway.expects(:ssl_post).returns(successful_refund_response) - response = @gateway.refund(@amount, "32432423", @options) + response = @gateway.refund(@amount, '32432423', @options) assert_success response assert_equal '120421340652', response.authorization end @@ -77,17 +77,17 @@ def test_successful_refund def test_failed_refund @gateway.expects(:raw_ssl_request).returns(failed_refund_response) - response = @gateway.refund(@amount, "5511231") + response = @gateway.refund(@amount, '5511231') assert_failure response - assert_equal "20183: Amount of refunds exceed original sale", response.message + assert_equal '20183: Amount of refunds exceed original sale', response.message end def test_failed_void @gateway.expects(:raw_ssl_request).returns(failed_void_response) - response = @gateway.void("5511231") + response = @gateway.void('5511231') assert_failure response - assert_equal "Processor/Network Error", response.message + assert_equal 'Processor/Network Error', response.message end def test_successful_verify @@ -103,7 +103,7 @@ def test_failed_verify @gateway.verify(@credit_card, @options) end.respond_with(failed_authorize_response, failed_void_response) assert_failure response - assert_equal "TEST DECLINED", response.message + assert_equal 'TEST DECLINED', response.message end def test_scrub @@ -128,39 +128,39 @@ def post_scrubbed end def successful_purchase_response - "avs_code=X&cvv2_code=M&status_code=1&processor=TEST&auth_code=999999&settle_amount=1.00&settle_currency=USD&trans_id=120741089764&auth_msg=TEST+APPROVED&auth_date=2015-04-23+15:27:28" + 'avs_code=X&cvv2_code=M&status_code=1&processor=TEST&auth_code=999999&settle_amount=1.00&settle_currency=USD&trans_id=120741089764&auth_msg=TEST+APPROVED&auth_date=2015-04-23+15:27:28' end def failed_purchase_response - "avs_code=Y&cvv2_code=M&status_code=0&processor=TEST&settle_currency=USD&settle_amount=190.88&trans_id=120740287652&auth_msg=TEST+DECLINED&auth_date=2015-04-23+15:31:30" + 'avs_code=Y&cvv2_code=M&status_code=0&processor=TEST&settle_currency=USD&settle_amount=190.88&trans_id=120740287652&auth_msg=TEST+DECLINED&auth_date=2015-04-23+15:31:30' end def successful_authorize_response - "avs_code=X&cvv2_code=M&status_code=T&processor=TEST&auth_code=999999&settle_amount=1.00&settle_currency=USD&trans_id=120762306743&auth_msg=TEST+APPROVED&ticket_code=XXXXXXXXXXXXXXX&auth_date=2015-04-23+17:24:37" + 'avs_code=X&cvv2_code=M&status_code=T&processor=TEST&auth_code=999999&settle_amount=1.00&settle_currency=USD&trans_id=120762306743&auth_msg=TEST+APPROVED&ticket_code=XXXXXXXXXXXXXXX&auth_date=2015-04-23+17:24:37' end def failed_authorize_response - "avs_code=Y&cvv2_code=M&status_code=0&processor=TEST&auth_code=999999&settle_currency=USD&settle_amount=190.88&trans_id=120761061862&auth_msg=TEST+DECLINED&ticket_code=XXXXXXXXXXXXXXX&auth_date=2015-04-23+17:25:35" + 'avs_code=Y&cvv2_code=M&status_code=0&processor=TEST&auth_code=999999&settle_currency=USD&settle_amount=190.88&trans_id=120761061862&auth_msg=TEST+DECLINED&ticket_code=XXXXXXXXXXXXXXX&auth_date=2015-04-23+17:25:35' end def successful_capture_response - "avs_code=X&cvv2_code=M&status_code=1&auth_code=999999&trans_id=120762306743&auth_msg=TEST+CAPTURED&ticket_code=XXXXXXXXXXXXXXX&auth_date=2015-04-23+17:24:37" + 'avs_code=X&cvv2_code=M&status_code=1&auth_code=999999&trans_id=120762306743&auth_msg=TEST+CAPTURED&ticket_code=XXXXXXXXXXXXXXX&auth_date=2015-04-23+17:24:37' end def failed_capture_response - MockResponse.failed("", 611, "20105: Settlement amount cannot exceed authorized amount") + MockResponse.failed('', 611, '20105: Settlement amount cannot exceed authorized amount') end def successful_refund_response - "status_code=1&processor=TEST&auth_code=RRRRRR&settle_amount=-1.00&settle_currency=USD&trans_id=120421340652&auth_msg=TEST+RETURNED&auth_date=2015-04-23+18:26:02" + 'status_code=1&processor=TEST&auth_code=RRRRRR&settle_amount=-1.00&settle_currency=USD&trans_id=120421340652&auth_msg=TEST+RETURNED&auth_date=2015-04-23+18:26:02' end def failed_refund_response - MockResponse.failed("", 611, "20183: Amount of refunds exceed original sale") + MockResponse.failed('', 611, '20183: Amount of refunds exceed original sale') end def failed_void_response - MockResponse.failed("", 611, "Processor/Network Error") + MockResponse.failed('', 611, 'Processor/Network Error') end def successful_authorize_raw_response diff --git a/test/unit/gateways/fat_zebra_test.rb b/test/unit/gateways/fat_zebra_test.rb index 3c62fe2edb9..e802111c648 100644 --- a/test/unit/gateways/fat_zebra_test.rb +++ b/test/unit/gateways/fat_zebra_test.rb @@ -34,7 +34,7 @@ def test_successful_purchase_with_token body.match '"card_token":"e1q7dbj2"' }.returns(successful_purchase_response) - assert response = @gateway.purchase(@amount, "e1q7dbj2", @options) + assert response = @gateway.purchase(@amount, 'e1q7dbj2', @options) assert_success response assert_equal '001-P-12345AA', response.authorization @@ -46,7 +46,7 @@ def test_successful_purchase_with_token_string body.match '"card_token":"e1q7dbj2"' }.returns(successful_purchase_response) - assert response = @gateway.purchase(@amount, "e1q7dbj2", @options) + assert response = @gateway.purchase(@amount, 'e1q7dbj2', @options) assert_success response assert_equal '001-P-12345AA', response.authorization @@ -58,7 +58,7 @@ def test_successful_multi_currency_purchase body.match '"currency":"USD"' }.returns(successful_purchase_response) - assert response = @gateway.purchase(@amount, "e1q7dbj2", @options.merge(:currency => 'USD')) + assert response = @gateway.purchase(@amount, 'e1q7dbj2', @options.merge(:currency => 'USD')) assert_success response assert_equal '001-P-12345AA', response.authorization @@ -79,7 +79,7 @@ def test_successful_purchase_with_descriptor json['extra']['name'] == 'Merchant' && json['extra']['location'] == 'Location' }.returns(successful_purchase_response) - assert response = @gateway.purchase(@amount, "e1q7dbj2", @options.merge(:merchant => 'Merchant', :merchant_location => 'Location')) + assert response = @gateway.purchase(@amount, 'e1q7dbj2', @options.merge(:merchant => 'Merchant', :merchant_location => 'Location')) assert_success response assert_equal '001-P-12345AA', response.authorization @@ -91,7 +91,7 @@ def test_successful_authorization body.match '"capture":false' }.returns(successful_purchase_response) - assert response = @gateway.authorize(@amount, "e1q7dbj2", @options) + assert response = @gateway.authorize(@amount, 'e1q7dbj2', @options) assert_success response assert_equal '001-P-12345AA', response.authorization @@ -103,7 +103,7 @@ def test_successful_capture url =~ %r[purchases/e1q7dbj2/capture\z] }.returns(successful_purchase_response) - response = @gateway.capture(@amount, "e1q7dbj2", @options) + response = @gateway.capture(@amount, 'e1q7dbj2', @options) assert_success response assert_equal '001-P-12345AA', response.authorization assert response.test? @@ -128,7 +128,7 @@ def test_declined_purchase end def test_parse_error - @gateway.expects(:ssl_request).returns("{") # Some invalid JSON + @gateway.expects(:ssl_request).returns('{') # Some invalid JSON assert response = @gateway.purchase(@amount, @credit_card, @options) assert_failure response assert_match %r{Invalid JSON response}, response.message @@ -147,7 +147,7 @@ def test_successful_tokenization assert response = @gateway.store(@credit_card) assert_success response - assert_equal "e1q7dbj2", response.authorization + assert_equal 'e1q7dbj2', response.authorization end def test_unsuccessful_tokenization @@ -160,7 +160,7 @@ def test_unsuccessful_tokenization def test_successful_refund @gateway.expects(:ssl_request).returns(successful_refund_response) - assert response = @gateway.refund(100, "TEST") + assert response = @gateway.refund(100, 'TEST') assert_success response assert_equal '003-R-7MNIUMY6', response.authorization assert response.test? @@ -169,7 +169,7 @@ def test_successful_refund def test_unsuccessful_refund @gateway.expects(:ssl_request).returns(unsuccessful_refund_response) - assert response = @gateway.refund(100, "TEST") + assert response = @gateway.refund(100, 'TEST') assert_failure response assert response.test? end @@ -236,21 +236,22 @@ def post_scrubbed Conn close POST_SCRUBBED end + # Place raw successful response from gateway here def successful_purchase_response { :successful => true, :response => { - :authorization => "55355", - :id => "001-P-12345AA", - :card_number => "XXXXXXXXXXXX1111", - :card_holder => "John Smith", - :card_expiry => "10/2011", - :card_token => "a1bhj98j", + :authorization => '55355', + :id => '001-P-12345AA', + :card_number => 'XXXXXXXXXXXX1111', + :card_holder => 'John Smith', + :card_expiry => '10/2011', + :card_token => 'a1bhj98j', :amount => 349, :successful => true, - :reference => "ABC123", - :message => "Approved", + :reference => 'ABC123', + :message => 'Approved', }, :test => true, :errors => [] @@ -263,13 +264,13 @@ def declined_purchase_response :response => { :authorization_id => nil, :id => nil, - :card_number => "XXXXXXXXXXXX1111", - :card_holder => "John Smith", - :card_expiry => "10/2011", + :card_number => 'XXXXXXXXXXXX1111', + :card_holder => 'John Smith', + :card_expiry => '10/2011', :amount => 100, :authorized => false, - :reference => "ABC123", - :message => "Card Declined - check with issuer", + :reference => 'ABC123', + :message => 'Card Declined - check with issuer', }, :test => true, :errors => [] @@ -280,16 +281,16 @@ def successful_refund_response { :successful => true, :response => { - :authorization => "1339973263", - :id => "003-R-7MNIUMY6", + :authorization => '1339973263', + :id => '003-R-7MNIUMY6', :amount => -10, - :refunded => "Approved", - :message => "08 Approved", - :card_holder => "Harry Smith", - :card_number => "XXXXXXXXXXXX4444", - :card_expiry => "2013-05-31", - :card_type => "MasterCard", - :transaction_id => "003-R-7MNIUMY6", + :refunded => 'Approved', + :message => '08 Approved', + :card_holder => 'Harry Smith', + :card_number => 'XXXXXXXXXXXX4444', + :card_expiry => '2013-05-31', + :card_type => 'MasterCard', + :transaction_id => '003-R-7MNIUMY6', :successful => true }, :errors => [ @@ -308,10 +309,10 @@ def unsuccessful_refund_response :amount => nil, :refunded => nil, :message => nil, - :card_holder => "Matthew Savage", - :card_number => "XXXXXXXXXXXX4444", - :card_expiry => "2013-05-31", - :card_type => "MasterCard", + :card_holder => 'Matthew Savage', + :card_number => 'XXXXXXXXXXXX4444', + :card_expiry => '2013-05-31', + :card_type => 'MasterCard', :transaction_id => nil, :successful => false }, @@ -326,10 +327,10 @@ def successful_tokenize_response { :successful => true, :response => { - :token => "e1q7dbj2", - :card_holder => "Bob Smith", - :card_number => "XXXXXXXXXXXX2346", - :card_expiry => "2013-05-31T23:59:59+10:00", + :token => 'e1q7dbj2', + :card_holder => 'Bob Smith', + :card_number => 'XXXXXXXXXXXX2346', + :card_expiry => '2013-05-31T23:59:59+10:00', :authorized => true, :transaction_count => 0 }, @@ -343,8 +344,8 @@ def failed_tokenize_response :successful => false, :response => { :token => nil, - :card_holder => "Bob ", - :card_number => "512345XXXXXX2346", + :card_holder => 'Bob ', + :card_number => '512345XXXXXX2346', :card_expiry => nil, :authorized => false, :transaction_count => 10 @@ -362,7 +363,7 @@ def failed_purchase_response :successful => false, :response => {}, :test => true, - :errors => ["Invalid Card Number"] + :errors => ['Invalid Card Number'] }.to_json end @@ -371,7 +372,7 @@ def missing_data_response :successful => false, :response => {}, :test => true, - :errors => ["Card Number is required"] + :errors => ['Card Number is required'] }.to_json end end diff --git a/test/unit/gateways/federated_canada_test.rb b/test/unit/gateways/federated_canada_test.rb index bd5c2415124..d3ca5956ae8 100644 --- a/test/unit/gateways/federated_canada_test.rb +++ b/test/unit/gateways/federated_canada_test.rb @@ -11,34 +11,33 @@ def setup @credit_card.verification_value = '999' @amount = 100 - @options = { + @options = { :order_id => '1', :billing_address => address, :description => 'Store Purchase' } end - + def test_successful_authorization @gateway.expects(:ssl_post).returns(successful_authorization_response) - options = {:billing_address => {:address1 => '888', :address2 => "apt 13", :country => 'CA', :state => 'SK', :city => "Big Beaver", :zip => "77777"}} + options = {:billing_address => {:address1 => '888', :address2 => 'apt 13', :country => 'CA', :state => 'SK', :city => 'Big Beaver', :zip => '77777'}} assert response = @gateway.authorize(@amount, @credit_card, options) assert_instance_of Response, response assert_success response assert_equal '1355694937', response.authorization assert_equal 'auth', response.params['type'] end - - + def test_successful_purchase @gateway.expects(:ssl_post).returns(successful_purchase_response) assert response = @gateway.purchase(@amount, @credit_card, @options) assert_instance_of Response, response assert_success response assert_equal '1346648416', response.authorization - assert_equal 'sale', response.params['type'] + assert_equal 'sale', response.params['type'] assert response.test? end - + def test_unsuccessful_request @gateway.expects(:ssl_post).returns(failed_purchase_response) assert response = @gateway.purchase(@amount, @credit_card, @options) @@ -48,21 +47,21 @@ def test_unsuccessful_request def test_add_address result = {} - @gateway.send(:add_address, result, :billing_address => {:address1 => '123 Happy Town Road', :address2 => "apt 13", :country => 'CA', :state => 'SK', :phone => '1234567890'} ) - assert_equal ["address1", "address2", "city", "company", "country", "phone", "state", "zip"], result.stringify_keys.keys.sort + @gateway.send(:add_address, result, :billing_address => {:address1 => '123 Happy Town Road', :address2 => 'apt 13', :country => 'CA', :state => 'SK', :phone => '1234567890'}) + assert_equal ['address1', 'address2', 'city', 'company', 'country', 'phone', 'state', 'zip'], result.stringify_keys.keys.sort assert_equal 'SK', result[:state] assert_equal '123 Happy Town Road', result[:address1] - assert_equal 'apt 13', result[:address2] + assert_equal 'apt 13', result[:address2] assert_equal 'CA', result[:country] end def test_add_invoice result = {} - @gateway.send(:add_invoice, result, :order_id => '#1001', :description => "This is a great order") + @gateway.send(:add_invoice, result, :order_id => '#1001', :description => 'This is a great order') assert_equal '#1001', result[:orderid] assert_equal 'This is a great order', result[:orderdescription] end - + def test_purchase_is_valid_csv params = {:amount => @amount} @gateway.send(:add_creditcard, params, @credit_card) @@ -70,8 +69,7 @@ def test_purchase_is_valid_csv assert data = @gateway.send(:post_data, 'auth', params) assert_equal post_data_fixture.size, data.size end - - + def test_purchase_meets_minimum_requirements params = {:amount => @amount} @gateway.send(:add_creditcard, params, @credit_card) @@ -80,10 +78,10 @@ def test_purchase_meets_minimum_requirements assert_not_nil(data.include?(key)) end end - + def test_expdate_formatting - assert_equal '0909', @gateway.send(:expdate, credit_card('4111111111111111', :month => "9", :year => "2009")) - assert_equal '0711', @gateway.send(:expdate, credit_card('4111111111111111', :month => "7", :year => "2011")) + assert_equal '0909', @gateway.send(:expdate, credit_card('4111111111111111', :month => '9', :year => '2009')) + assert_equal '0711', @gateway.send(:expdate, credit_card('4111111111111111', :month => '7', :year => '2011')) end def test_supported_countries @@ -105,7 +103,7 @@ def test_cvv_result response = @gateway.purchase(@amount, @credit_card) assert_equal 'M', response.cvv_result['code'] end - + def test_amount assert_equal '1.00', @gateway.send(:amount, 100) assert_equal '10.00', @gateway.send(:amount, 1000) @@ -113,29 +111,29 @@ def test_amount @gateway.send(:amount, '10.00') end end - + private - + def post_data_fixture - "password=password&type=auth&ccnumber=4111111111111111&username=demo&ccexp=1111&amount=100&cvv=999" + 'password=password&type=auth&ccnumber=4111111111111111&username=demo&ccexp=1111&amount=100&cvv=999' end - + def minimum_requirements %w{type username password amount ccnumber ccexp} end - + # Raw successful authorization response def successful_authorization_response - "response=1&responsetext=SUCCESS&authcode=123456&transactionid=1355694937&avsresponse=Y&cvvresponse=M&orderid=&type=auth&response_code=100" + 'response=1&responsetext=SUCCESS&authcode=123456&transactionid=1355694937&avsresponse=Y&cvvresponse=M&orderid=&type=auth&response_code=100' end # Raw successful purchase response def successful_purchase_response - "response=1&responsetext=SUCCESS&authcode=123456&transactionid=1346648416&avsresponse=N&cvvresponse=N&orderid=&type=sale&response_code=100" + 'response=1&responsetext=SUCCESS&authcode=123456&transactionid=1346648416&avsresponse=N&cvvresponse=N&orderid=&type=sale&response_code=100' end - + # Raw failed sale response def failed_purchase_response - "response=2&responsetext=DECLINE&authcode=&transactionid=1346648595&avsresponse=N&cvvresponse=N&orderid=&type=sale&response_code=200" + 'response=2&responsetext=DECLINE&authcode=&transactionid=1346648595&avsresponse=N&cvvresponse=N&orderid=&type=sale&response_code=200' end end diff --git a/test/unit/gateways/finansbank_test.rb b/test/unit/gateways/finansbank_test.rb index efdd29845c4..9cb280aac30 100644 --- a/test/unit/gateways/finansbank_test.rb +++ b/test/unit/gateways/finansbank_test.rb @@ -1,13 +1,10 @@ # encoding: utf-8 + require 'test_helper' class FinansbankTest < Test::Unit::TestCase def setup @original_kcode = nil - if RUBY_VERSION < '1.9' && $KCODE == "NONE" - @original_kcode = $KCODE - $KCODE = 'u' - end @gateway = FinansbankGateway.new( :login => 'login', diff --git a/test/unit/gateways/first_giving_test.rb b/test/unit/gateways/first_giving_test.rb index c368b8d3562..1e9b7f0345b 100644 --- a/test/unit/gateways/first_giving_test.rb +++ b/test/unit/gateways/first_giving_test.rb @@ -3,9 +3,9 @@ class FirstGivingTest < Test::Unit::TestCase def setup @gateway = FirstGivingGateway.new( - application_key: "application_key", - security_token: "security_token", - charity_id: "charity_id" + application_key: 'application_key', + security_token: 'security_token', + charity_id: 'charity_id' ) @credit_card = credit_card @@ -20,8 +20,8 @@ def test_successful_purchase response = @gateway.purchase(@amount, @credit_card, @options) assert_success response - assert_equal "a-c71f5e0a25f96e48a3dc54", response.authorization - assert_equal "Success", response.message + assert_equal 'a-c71f5e0a25f96e48a3dc54', response.authorization + assert_equal 'Success', response.message end def test_unsuccessful_purchase @@ -29,7 +29,7 @@ def test_unsuccessful_purchase response = @gateway.purchase(@amount, @credit_card, @options) assert_failure response - assert_equal "Unfortunately, we were unable to perform credit card number validation. The credit card number validator responded with the following message ccNumber failed data validation for the following reasons : creditcardChecksum: 4457010000000000 seems to contain an invalid checksum.", response.message + assert_equal 'Unfortunately, we were unable to perform credit card number validation. The credit card number validator responded with the following message ccNumber failed data validation for the following reasons : creditcardChecksum: 4457010000000000 seems to contain an invalid checksum.', response.message end def test_successful_refund @@ -37,7 +37,7 @@ def test_successful_refund response = @gateway.refund(@amount, @options) assert_success response - assert_equal "a-a09bf64559e5824eb925f5", response.authorization + assert_equal 'a-a09bf64559e5824eb925f5', response.authorization end def test_unsuccessful_refund @@ -45,7 +45,7 @@ def test_unsuccessful_refund response = @gateway.refund(@amount, @options) assert_failure response - assert_equal "Bad JG_APPLICATIONKEY and JG_SECURITYTOKEN.", response.message + assert_equal 'Bad JG_APPLICATIONKEY and JG_SECURITYTOKEN.', response.message end private diff --git a/test/unit/gateways/first_pay_test.rb b/test/unit/gateways/first_pay_test.rb index 5aa676f9faa..b761e884938 100644 --- a/test/unit/gateways/first_pay_test.rb +++ b/test/unit/gateways/first_pay_test.rb @@ -181,6 +181,37 @@ def test_failed_void assert response.message.include?('Void failed') end + def test_recurring_payments + @options[:recurring] = 1 + @options[:recurring_start_date] = '01/01/1900' + @options[:recurring_end_date] = '02/02/1901' + @options[:recurring_type] = 'monthly' + response = stub_comms do + @gateway.purchase(@amount, @credit_card, @options) + end.check_request do |endpoint, data, headers| + assert_match(%r{<FIELD KEY="recurring">1</FIELD>}, data) + assert_match(%r{<FIELD KEY="recurring_start_date">01/01/1900</FIELD>}, data) + assert_match(%r{<FIELD KEY="recurring_end_date">02/02/1901</FIELD>}, data) + assert_match(%r{<FIELD KEY="recurring_type">monthly</FIELD>}, data) + end.respond_with(successful_purchase_response) + + assert response + assert_success response + end + + def test_error_message + @gateway.stubs(:ssl_post).returns(failed_login_response) + response = @gateway.void('1') + + assert_failure response + assert response.error_code.include?('Merchant: 1234 has encountered error #DTO-200-TC.') + end + + def test_scrub + assert @gateway.supports_scrubbing? + assert_equal @gateway.scrub(pre_scrubbed), post_scrubbed + end + private def successful_purchase_response @@ -344,6 +375,67 @@ def failed_void_response <FIELD KEY="reference_number1">1</FIELD> <FIELD KEY="error1" /> </FIELDS> +</RESPONSE>) + end + + def failed_login_response + %(<RESPONSE> + <FIELDS> + <FIELD KEY="status">0</FIELD> + <FIELD KEY="auth_code"></FIELD> + <FIELD KEY="auth_response"></FIELD> + <FIELD KEY="avs_code"></FIELD> + <FIELD KEY="cvv2_code"></FIELD> + <FIELD KEY="reference_number"></FIELD> + <FIELD KEY="order_id">a0d2560dda18631ce325c07dcbda2a9880fd17fb344fd233</FIELD> + <FIELD KEY="error">Merchant: 1234 has encountered error #DTO-200-TC. Please call 888-638-7867 if you feel this is in error.</FIELD> + </FIELDS> +</RESPONSE>) + end + + def pre_scrubbed + %(<RESPONSE> + <FIELDS> + <FIELD KEY="order_id">77b61bfe08510e00852f2f20011e7952d80f9a4be17d27cf</FIELD> + <FIELD KEY="total">1.00</FIELD><FIELD KEY="card_name">visa</FIELD> + <FIELD KEY="card_number">4111111111111111</FIELD> + <FIELD KEY="card_exp">0919</FIELD> + <FIELD KEY="cvv2">789</FIELD> + <FIELD KEY="owner_name">Jim Smith</FIELD> + <FIELD KEY="owner_street">456 My Street</FIELD> + <FIELD KEY="owner_street2">Apt 1</FIELD> + <FIELD KEY="owner_city">Ottawa</FIELD> + <FIELD KEY="owner_state">ON</FIELD> + <FIELD KEY="owner_zip">K1C2N6</FIELD> + <FIELD KEY="owner_country">CA</FIELD> + <FIELD KEY="owner_phone">(555)555-5555</FIELD> + <FIELD KEY="transaction_center_id">1264</FIELD> + <FIELD KEY="gateway_id">a91c38c3-7d7f-4d29-acc7-927b4dca0dbe</FIELD> + <FIELD KEY="operation_type">sale</FIELD> + </FIELDS> +</RESPONSE>) + end + + def post_scrubbed + %(<RESPONSE> + <FIELDS> + <FIELD KEY=\"order_id\">77b61bfe08510e00852f2f20011e7952d80f9a4be17d27cf</FIELD> + <FIELD KEY=\"total\">1.00</FIELD><FIELD KEY=\"card_name\">visa</FIELD> + <FIELD KEY=\"card_number[FILTERED]</FIELD> + <FIELD KEY=\"card_exp\">0919</FIELD> + <FIELD KEY=\"cvv2[FILTERED]</FIELD> + <FIELD KEY=\"owner_name\">Jim Smith</FIELD> + <FIELD KEY=\"owner_street\">456 My Street</FIELD> + <FIELD KEY=\"owner_street2\">Apt 1</FIELD> + <FIELD KEY=\"owner_city\">Ottawa</FIELD> + <FIELD KEY=\"owner_state\">ON</FIELD> + <FIELD KEY=\"owner_zip\">K1C2N6</FIELD> + <FIELD KEY=\"owner_country\">CA</FIELD> + <FIELD KEY=\"owner_phone\">(555)555-5555</FIELD> + <FIELD KEY=\"transaction_center_id\">1264</FIELD> + <FIELD KEY=\"gateway_id[FILTERED]</FIELD> + <FIELD KEY=\"operation_type\">sale</FIELD> + </FIELDS> </RESPONSE>) end end diff --git a/test/unit/gateways/firstdata_e4_test.rb b/test/unit/gateways/firstdata_e4_test.rb index 67739fd4b43..e4aa2511096 100755 --- a/test/unit/gateways/firstdata_e4_test.rb +++ b/test/unit/gateways/firstdata_e4_test.rb @@ -1,4 +1,5 @@ require 'test_helper' +require 'nokogiri' require 'yaml' class FirstdataE4Test < Test::Unit::TestCase @@ -6,8 +7,8 @@ class FirstdataE4Test < Test::Unit::TestCase def setup @gateway = FirstdataE4Gateway.new( - :login => "A00427-01", - :password => "testus" + :login => 'A00427-01', + :password => 'testus' ) @credit_card = credit_card @@ -17,7 +18,7 @@ def setup :billing_address => address, :description => 'Store Purchase' } - @authorization = "ET1700;106625152;4738" + @authorization = 'ET1700;106625152;4738' end def test_invalid_credentials @@ -37,7 +38,7 @@ def test_successful_purchase assert response.test? assert_equal 'Transaction Normal - Approved', response.message - FirstdataE4Gateway::SENSITIVE_FIELDS.each{|f| assert !response.params.has_key?(f.to_s)} + FirstdataE4Gateway::SENSITIVE_FIELDS.each { |f| assert !response.params.has_key?(f.to_s) } end def test_successful_purchase_with_specified_currency @@ -50,7 +51,7 @@ def test_successful_purchase_with_specified_currency assert_equal 'Transaction Normal - Approved', response.message assert_equal 'GBP', response.params['currency'] - FirstdataE4Gateway::SENSITIVE_FIELDS.each{|f| assert !response.params.has_key?(f.to_s)} + FirstdataE4Gateway::SENSITIVE_FIELDS.each { |f| assert !response.params.has_key?(f.to_s) } end def test_successful_purchase_with_token @@ -63,7 +64,7 @@ def test_successful_purchase_with_specified_currency_and_token options_with_specified_currency = @options.merge({currency: 'GBP'}) @gateway.expects(:ssl_post).returns(successful_purchase_with_specified_currency_response) assert response = @gateway.purchase(@amount, '8938737759041111;visa;Longbob;Longsen;9;2014', - options_with_specified_currency) + options_with_specified_currency) assert_success response assert_equal 'GBP', response.params['currency'] end @@ -109,7 +110,7 @@ def test_failed_purchase assert response = @gateway.purchase(@amount, @credit_card, @options) assert_instance_of Response, response assert_failure response - assert_equal response.error_code, "invalid_expiry_date" + assert_equal response.error_code, 'invalid_expiry_date' end def test_successful_verify @@ -121,7 +122,7 @@ def test_successful_verify def test_expdate assert_equal( - "%02d%s" % [@credit_card.month, @credit_card.year.to_s[-2..-1]], + '%02d%s' % [@credit_card.month, @credit_card.year.to_s[-2..-1]], @gateway.send(:expdate, @credit_card) ) end @@ -160,92 +161,137 @@ def test_requests_include_verification_string stub_comms do @gateway.purchase(@amount, @credit_card, @options) end.check_request do |endpoint, data, headers| - assert_match "<VerificationStr1>456 My Street|K1C2N6|Ottawa|ON|CA</VerificationStr1>", data + assert_match '<VerificationStr1>456 My Street|K1C2N6|Ottawa|ON|CA</VerificationStr1>', data end.respond_with(successful_purchase_response) end def test_tax_fields_are_sent stub_comms do - @gateway.purchase(@amount, @credit_card, @options.merge(tax1_amount: 830, tax1_number: "Br59a")) + @gateway.purchase(@amount, @credit_card, @options.merge(tax1_amount: 830, tax1_number: 'Br59a')) end.check_request do |endpoint, data, headers| - assert_match "<Tax1Amount>830", data - assert_match "<Tax1Number>Br59a", data + assert_match '<Tax1Amount>830', data + assert_match '<Tax1Number>Br59a', data end.respond_with(successful_purchase_response) end def test_customer_ref_is_sent stub_comms do - @gateway.purchase(@amount, @credit_card, @options.merge(customer: "932")) + @gateway.purchase(@amount, @credit_card, @options.merge(customer: '932')) end.check_request do |endpoint, data, headers| - assert_match "<Customer_Ref>932", data + assert_match '<Customer_Ref>932', data end.respond_with(successful_purchase_response) end - def test_network_tokenization_requests_with_visa + def test_eci_default_value stub_comms do - credit_card = network_tokenization_credit_card('4111111111111111', - :brand => 'visa', - :transaction_id => "123", - :eci => "05", - :payment_cryptogram => "111111111100cryptogram" - ) + @gateway.purchase(@amount, @credit_card, @options) + end.check_request do |endpoint, data, headers| + assert_match '<Ecommerce_Flag>07</Ecommerce_Flag>', data + end.respond_with(successful_purchase_response) + end - @gateway.purchase(@amount, credit_card, @options) + def test_eci_numeric_padding + @credit_card = network_tokenization_credit_card + @credit_card.eci = '5' + + stub_comms do + @gateway.purchase(@amount, @credit_card, @options) + end.check_request do |endpoint, data, headers| + assert_match '<Ecommerce_Flag>05</Ecommerce_Flag>', data + end.respond_with(successful_purchase_response) + + @credit_card = network_tokenization_credit_card + @credit_card.eci = 5 + + stub_comms do + @gateway.purchase(@amount, @credit_card, @options) + end.check_request do |endpoint, data, headers| + assert_match '<Ecommerce_Flag>05</Ecommerce_Flag>', data + end.respond_with(successful_purchase_response) + end + + def test_eci_option_value + stub_comms do + @gateway.purchase(@amount, @credit_card, @options.merge(eci: '05')) end.check_request do |endpoint, data, headers| - assert_match "<Ecommerce_Flag>05</Ecommerce_Flag>", data - assert_match "<XID>123</XID>", data - assert_match "<CAVV>111111111100cryptogram</CAVV>", data + assert_match '<Ecommerce_Flag>05</Ecommerce_Flag>', data end.respond_with(successful_purchase_response) end - def test_network_tokenization_requests_with_mastercard + def test_network_tokenization_requests_with_amex stub_comms do - credit_card = network_tokenization_credit_card('5555555555554444', - :brand => 'mastercard', - :transaction_id => "123", - :eci => "05", - :payment_cryptogram => "111111111100cryptogram" + credit_card = network_tokenization_credit_card( + '378282246310005', + brand: 'american_express', + transaction_id: '123', + eci: '05', + payment_cryptogram: 'whatever_the_cryptogram_of_at_least_20_characters_is' ) @gateway.purchase(@amount, credit_card, @options) - end.check_request do |endpoint, data, headers| - assert_match "<Ecommerce_Flag>05</Ecommerce_Flag>", data - assert_match "<XID>123</XID>", data - assert_match "<CAVV>111111111100cryptogram</CAVV>", data + end.check_request do |_, data, _| + assert_match '<Ecommerce_Flag>05</Ecommerce_Flag>', data + assert_match "<XID>mrLdtHIWq2nLXq7IrA==\n</XID>", data + assert_match "<CAVV>whateverthecryptogramofatlc=\n</CAVV>", data + assert_xml_valid_to_wsdl(data) end.respond_with(successful_purchase_response) end - def test_network_tokenization_requests_with_amex + def test_network_tokenization_requests_with_discover stub_comms do - credit_card = network_tokenization_credit_card('378282246310005', - :brand => 'american_express', - :transaction_id => "123", - :eci => "05", - :payment_cryptogram => Base64.encode64("111111111100cryptogram") + credit_card = network_tokenization_credit_card( + '6011111111111117', + brand: 'discover', + transaction_id: '123', + eci: '05', + payment_cryptogram: 'whatever_the_cryptogram_is' ) @gateway.purchase(@amount, credit_card, @options) - end.check_request do |endpoint, data, headers| - assert_match "<Ecommerce_Flag>05</Ecommerce_Flag>", data - assert_match "<XID>YW0=\n</XID>", data - assert_match "<CAVV>MTExMTExMTExMTAwY3J5cHRvZ3I=\n</CAVV>", data + end.check_request do |_, data, _| + assert_match '<Ecommerce_Flag>04</Ecommerce_Flag>', data + assert_match '<XID>123</XID>', data + assert_match '<CAVV>whatever_the_cryptogram_is</CAVV>', data + assert_xml_valid_to_wsdl(data) end.respond_with(successful_purchase_response) end + def test_network_tokenization_requests_with_other_brands + %w(visa mastercard other).each do |brand| + stub_comms do + credit_card = network_tokenization_credit_card( + '378282246310005', + brand: brand, + transaction_id: '123', + eci: '05', + payment_cryptogram: 'whatever_the_cryptogram_is' + ) + + @gateway.purchase(@amount, credit_card, @options) + end.check_request do |_, data, _| + assert_match '<Ecommerce_Flag>05</Ecommerce_Flag>', data + assert_match '<XID>123</XID>', data + assert_match '<CAVV>whatever_the_cryptogram_is</CAVV>', data + assert_xml_valid_to_wsdl(data) + end.respond_with(successful_purchase_response) + end + end + def test_requests_include_card_authentication_data authentication_hash = { - eci: "06", - cavv: "SAMPLECAVV", - xid: "SAMPLEXID" + eci: '06', + cavv: 'SAMPLECAVV', + xid: 'SAMPLEXID' } options_with_authentication_data = @options.merge(authentication_hash) stub_comms do @gateway.purchase(@amount, @credit_card, options_with_authentication_data) end.check_request do |endpoint, data, headers| - assert_match "<Ecommerce_Flag>06</Ecommerce_Flag>", data - assert_match "<CAVV>SAMPLECAVV</CAVV>", data - assert_match "<XID>SAMPLEXID</XID>", data + assert_match '<Ecommerce_Flag>06</Ecommerce_Flag>', data + assert_match '<CAVV>SAMPLECAVV</CAVV>', data + assert_match '<XID>SAMPLEXID</XID>', data + assert_xml_valid_to_wsdl(data) end.respond_with(successful_purchase_response) end @@ -259,22 +305,19 @@ def test_card_type end def test_add_swipe_data_with_creditcard - @credit_card.track_data = "Track Data" + @credit_card.track_data = 'Track Data' stub_comms do @gateway.purchase(@amount, @credit_card) end.check_request do |endpoint, data, headers| - assert_match "<Track1>Track Data</Track1>", data - assert_match "<Ecommerce_Flag>R</Ecommerce_Flag>", data + assert_match '<Track1>Track Data</Track1>', data + assert_match '<Ecommerce_Flag>R</Ecommerce_Flag>', data end.respond_with(successful_purchase_response) end - def test_supports_scrubbing? + def test_transcript_scrubbing assert @gateway.supports_scrubbing? - end - - def test_scrub - assert_equal @gateway.scrub(pre_scrubbed), post_scrubbed + assert_equal @gateway.scrub(pre_scrub), post_scrub end def test_supports_network_tokenization @@ -283,14 +326,21 @@ def test_supports_network_tokenization private - def pre_scrubbed + def assert_xml_valid_to_wsdl(data) + xsd = Nokogiri::XML::Schema(File.open("#{File.dirname(__FILE__)}/../../schema/firstdata_e4/v11.xsd")) + doc = Nokogiri::XML(data) + errors = xsd.validate(doc) + assert_empty errors, "XSD validation errors in the following XML:\n#{doc}" + end + + def pre_scrub <<-PRE_SCRUBBED opening connection to api.demo.globalgatewaye4.firstdata.com:443... opened starting SSL for api.demo.globalgatewaye4.firstdata.com:443... SSL established <- "POST /transaction/v11 HTTP/1.1\r\nContent-Type: application/xml\r\nAccepts: application/xml\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nAccept: */*\r\nUser-Agent: Ruby\r\nConnection: close\r\nHost: api.demo.globalgatewaye4.firstdata.com\r\nContent-Length: 593\r\n\r\n" - <- "<?xml version=\"1.0\" encoding=\"UTF-8\"?><Transaction><ExactID>REDACTED</ExactID><Password>REDACTED</Password><Transaction_Type>00</Transaction_Type><DollarAmount>1.00</DollarAmount><Card_Number>4242424242424242</Card_Number><Expiry_Date>0916</Expiry_Date><CardHoldersName>Longbob Longsen</CardHoldersName><CardType>Visa</CardType><VerificationStr1>1234 My Street|K1C2N6|Ottawa|ON|CA</VerificationStr1><CVD_Presence_Ind>1</CVD_Presence_Ind><VerificationStr2>123</VerificationStr2><Reference_No>1</Reference_No><Reference_3>Store Purchase</Reference_3><CAVV/><XID/><Ecommerce_Flag/></Transaction>" + <- "<?xml version=\"1.0\" encoding=\"UTF-8\"?><Transaction><ExactID>REDACTED</ExactID><Password>REDACTED</Password><Transaction_Type>00</Transaction_Type><DollarAmount>1.00</DollarAmount><Card_Number>4242424242424242</Card_Number><Expiry_Date>0916</Expiry_Date><CardHoldersName>Longbob Longsen</CardHoldersName><CardType>Visa</CardType><VerificationStr1>1234 My Street|K1C2N6|Ottawa|ON|CA</VerificationStr1><CVD_Presence_Ind>1</CVD_Presence_Ind><VerificationStr2>123</VerificationStr2><Reference_No>1</Reference_No><Reference_3>Store Purchase</Reference_3><CAVV>lol</CAVV><XID/><Ecommerce_Flag/></Transaction>" -> "HTTP/1.1 201 Created\r\n" -> "Cache-Control: max-age=0, private, must-revalidate\r\n" -> "Content-Type: application/xml; charset=utf-8\r\n" @@ -306,21 +356,21 @@ def pre_scrubbed -> "Connection: Close\r\n" -> "\r\n" reading 2872 bytes... - -> "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<TransactionResult>\n <ExactID>AD2327-05</ExactID>\n <Password></Password>\n <Transaction_Type>00</Transaction_Type>\n <DollarAmount>1.0</DollarAmount>\n <SurchargeAmount></SurchargeAmount>\n <Card_Number>############4242</Card_Number>\n <Transaction_Tag>42930941</Transaction_Tag>\n <Track1></Track1>\n <Track2></Track2>\n <PAN></PAN>\n <Authorization_Num>ET151682</Authorization_Num>\n <Expiry_Date>0916</Expiry_Date>\n <CardHoldersName>Longbob Longsen</CardHoldersName>\n <VerificationStr1>1234 My Street|K1C2N6|Ottawa|ON|CA</VerificationStr1>\n <VerificationStr2>123</VerificationStr2>\n <CVD_Presence_Ind>0</CVD_Presence_Ind>\n <ZipCode></ZipCode>\n <Tax1Amount></Tax1Amount>\n <Tax1Number></Tax1Number>\n <Tax2Amount></Tax2Amount>\n <Tax2Number></Tax2Number>\n <Secure_AuthRequired></Secure_AuthRequired>\n <Secure_AuthResult></Secure_AuthResult>\n <Ecommerce_Flag></Ecommerce_Flag>\n <XID></XID>\n <CAVV></CAVV>\n <CAVV_Algorithm></CAVV_Algorithm>\n <Reference_No>1</Reference_No>\n <Customer_Ref></Customer_Ref>\n <Reference_3>Store Purchase</Reference_3>\n <Language></Language>\n <Client_IP>216.191.105.146</Client_IP>\n <Client_Email></Client_Email>\n <Transaction_Error>false</Transaction_Error>\n <Transaction_Approved>true</Transaction_Approved>\n <EXact_Resp_Code>00</EXact_Resp_Code>\n <EXact_Message>Transaction Normal</EXact_Message>\n <Bank_Resp_Code>100</Bank_Resp_Code>\n <Bank_Message>Approved</Bank_Message>\n <Bank_Resp_Code_2></Bank_Resp_Code_2>\n <SequenceNo>106826</SequenceNo>\n <AVS>1</AVS>\n <CVV2>M</CVV2>\n <Retrieval_Ref_No>0025564</Retrieval_Ref_No>\n <CAVV_Response></CAVV_Response>\n <Currency>USD</Currency>\n <AmountRequested></AmountRequested>\n <PartialRedemption>false</PartialRedemption>\n <MerchantName>Shopify DEMO0678</MerchantName>\n <MerchantAddress>126 York Street</MerchantAddress>\n <MerchantCity>Ottawa</MerchantCity>\n <MerchantProvince>Alabama</MerchantProvince>\n <MerchantCountry>Canada</MerchantCountry>\n <MerchantPostal>K1N 5T5</MerchantPostal>\n <MerchantURL>www.shopify.com</MerchantURL>\n <TransarmorToken></TransarmorToken>\n <CardType>Visa</CardType>\n <CurrentBalance></CurrentBalance>\n <PreviousBalance></PreviousBalance>\n <EAN></EAN>\n <CardCost></CardCost>\n <VirtualCard>false</VirtualCard>\n <CTR>=========== TRANSACTION RECORD ==========\nShopify DEMO0678\n126 York Street\nOttawa, AL K1N 5T5\nCanada\nwww.shopify.com\n\nTY" + -> "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<TransactionResult>\n <ExactID>AD2327-05</ExactID>\n <Password></Password>\n <Transaction_Type>00</Transaction_Type>\n <DollarAmount>1.0</DollarAmount>\n <SurchargeAmount></SurchargeAmount>\n <Card_Number>############4242</Card_Number>\n <Transaction_Tag>42930941</Transaction_Tag>\n <Track1></Track1>\n <Track2></Track2>\n <PAN></PAN>\n <Authorization_Num>ET151682</Authorization_Num>\n <Expiry_Date>0916</Expiry_Date>\n <CardHoldersName>Longbob Longsen</CardHoldersName>\n <VerificationStr1>1234 My Street|K1C2N6|Ottawa|ON|CA</VerificationStr1>\n <VerificationStr2>123</VerificationStr2>\n <CVD_Presence_Ind>0</CVD_Presence_Ind>\n <ZipCode></ZipCode>\n <Tax1Amount></Tax1Amount>\n <Tax1Number></Tax1Number>\n <Tax2Amount></Tax2Amount>\n <Tax2Number></Tax2Number>\n <Secure_AuthRequired></Secure_AuthRequired>\n <Secure_AuthResult></Secure_AuthResult>\n <Ecommerce_Flag></Ecommerce_Flag>\n <XID></XID>\n <CAVV>lol</CAVV>\n <CAVV_Algorithm></CAVV_Algorithm>\n <Reference_No>1</Reference_No>\n <Customer_Ref></Customer_Ref>\n <Reference_3>Store Purchase</Reference_3>\n <Language></Language>\n <Client_IP>216.191.105.146</Client_IP>\n <Client_Email></Client_Email>\n <Transaction_Error>false</Transaction_Error>\n <Transaction_Approved>true</Transaction_Approved>\n <EXact_Resp_Code>00</EXact_Resp_Code>\n <EXact_Message>Transaction Normal</EXact_Message>\n <Bank_Resp_Code>100</Bank_Resp_Code>\n <Bank_Message>Approved</Bank_Message>\n <Bank_Resp_Code_2></Bank_Resp_Code_2>\n <SequenceNo>106826</SequenceNo>\n <AVS>1</AVS>\n <CVV2>M</CVV2>\n <Retrieval_Ref_No>0025564</Retrieval_Ref_No>\n <CAVV_Response></CAVV_Response>\n <Currency>USD</Currency>\n <AmountRequested></AmountRequested>\n <PartialRedemption>false</PartialRedemption>\n <MerchantName>Shopify DEMO0678</MerchantName>\n <MerchantAddress>126 York Street</MerchantAddress>\n <MerchantCity>Ottawa</MerchantCity>\n <MerchantProvince>Alabama</MerchantProvince>\n <MerchantCountry>Canada</MerchantCountry>\n <MerchantPostal>K1N 5T5</MerchantPostal>\n <MerchantURL>www.shopify.com</MerchantURL>\n <TransarmorToken></TransarmorToken>\n <CardType>Visa</CardType>\n <CurrentBalance></CurrentBalance>\n <PreviousBalance></PreviousBalance>\n <EAN></EAN>\n <CardCost></CardCost>\n <VirtualCard>false</VirtualCard>\n <CTR>=========== TRANSACTION RECORD ==========\nShopify DEMO0678\n126 York Street\nOttawa, AL K1N 5T5\nCanada\nwww.shopify.com\n\nTY" -> "PE: Purchase\n\nACCT: Visa $ 1.00 USD\n\nCARDHOLDER NAME : Longbob Longsen\nCARD NUMBER : ############4242\nDATE/TIME : 26 Jan 15 12:11:44\nREFERENCE # : 106826 M\nAUTHOR. # : ET151682\nTRANS. REF. : 1\n\n Approved - Thank You 100\n\n\nPlease retain this copy for your records.\n\nCardholder will pay above amount to card\nissuer pursuant to cardholder agreement.\n=========================================</CTR>\n</TransactionResult>\n" read 2872 bytes Conn close PRE_SCRUBBED end - def post_scrubbed + def post_scrub <<-POST_SCRUBBED opening connection to api.demo.globalgatewaye4.firstdata.com:443... opened starting SSL for api.demo.globalgatewaye4.firstdata.com:443... SSL established <- "POST /transaction/v11 HTTP/1.1\r\nContent-Type: application/xml\r\nAccepts: application/xml\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nAccept: */*\r\nUser-Agent: Ruby\r\nConnection: close\r\nHost: api.demo.globalgatewaye4.firstdata.com\r\nContent-Length: 593\r\n\r\n" - <- "<?xml version=\"1.0\" encoding=\"UTF-8\"?><Transaction><ExactID>REDACTED</ExactID><Password>REDACTED</Password><Transaction_Type>00</Transaction_Type><DollarAmount>1.00</DollarAmount><Card_Number>[FILTERED]</Card_Number><Expiry_Date>0916</Expiry_Date><CardHoldersName>Longbob Longsen</CardHoldersName><CardType>Visa</CardType><VerificationStr1>1234 My Street|K1C2N6|Ottawa|ON|CA</VerificationStr1><CVD_Presence_Ind>1</CVD_Presence_Ind><VerificationStr2>[FILTERED]</VerificationStr2><Reference_No>1</Reference_No><Reference_3>Store Purchase</Reference_3><CAVV/><XID/><Ecommerce_Flag/></Transaction>" + <- "<?xml version=\"1.0\" encoding=\"UTF-8\"?><Transaction><ExactID>REDACTED</ExactID><Password>[FILTERED]</Password><Transaction_Type>00</Transaction_Type><DollarAmount>1.00</DollarAmount><Card_Number>[FILTERED]</Card_Number><Expiry_Date>0916</Expiry_Date><CardHoldersName>Longbob Longsen</CardHoldersName><CardType>Visa</CardType><VerificationStr1>1234 My Street|K1C2N6|Ottawa|ON|CA</VerificationStr1><CVD_Presence_Ind>1</CVD_Presence_Ind><VerificationStr2>[FILTERED]</VerificationStr2><Reference_No>1</Reference_No><Reference_3>Store Purchase</Reference_3><CAVV>[FILTERED]</CAVV><XID/><Ecommerce_Flag/></Transaction>" -> "HTTP/1.1 201 Created\r\n" -> "Cache-Control: max-age=0, private, must-revalidate\r\n" -> "Content-Type: application/xml; charset=utf-8\r\n" @@ -336,7 +386,7 @@ def post_scrubbed -> "Connection: Close\r\n" -> "\r\n" reading 2872 bytes... - -> "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<TransactionResult>\n <ExactID>AD2327-05</ExactID>\n <Password></Password>\n <Transaction_Type>00</Transaction_Type>\n <DollarAmount>1.0</DollarAmount>\n <SurchargeAmount></SurchargeAmount>\n <Card_Number>[FILTERED]</Card_Number>\n <Transaction_Tag>42930941</Transaction_Tag>\n <Track1></Track1>\n <Track2></Track2>\n <PAN></PAN>\n <Authorization_Num>ET151682</Authorization_Num>\n <Expiry_Date>0916</Expiry_Date>\n <CardHoldersName>Longbob Longsen</CardHoldersName>\n <VerificationStr1>1234 My Street|K1C2N6|Ottawa|ON|CA</VerificationStr1>\n <VerificationStr2>[FILTERED]</VerificationStr2>\n <CVD_Presence_Ind>0</CVD_Presence_Ind>\n <ZipCode></ZipCode>\n <Tax1Amount></Tax1Amount>\n <Tax1Number></Tax1Number>\n <Tax2Amount></Tax2Amount>\n <Tax2Number></Tax2Number>\n <Secure_AuthRequired></Secure_AuthRequired>\n <Secure_AuthResult></Secure_AuthResult>\n <Ecommerce_Flag></Ecommerce_Flag>\n <XID></XID>\n <CAVV></CAVV>\n <CAVV_Algorithm></CAVV_Algorithm>\n <Reference_No>1</Reference_No>\n <Customer_Ref></Customer_Ref>\n <Reference_3>Store Purchase</Reference_3>\n <Language></Language>\n <Client_IP>216.191.105.146</Client_IP>\n <Client_Email></Client_Email>\n <Transaction_Error>false</Transaction_Error>\n <Transaction_Approved>true</Transaction_Approved>\n <EXact_Resp_Code>00</EXact_Resp_Code>\n <EXact_Message>Transaction Normal</EXact_Message>\n <Bank_Resp_Code>100</Bank_Resp_Code>\n <Bank_Message>Approved</Bank_Message>\n <Bank_Resp_Code_2></Bank_Resp_Code_2>\n <SequenceNo>106826</SequenceNo>\n <AVS>1</AVS>\n <CVV2>M</CVV2>\n <Retrieval_Ref_No>0025564</Retrieval_Ref_No>\n <CAVV_Response></CAVV_Response>\n <Currency>USD</Currency>\n <AmountRequested></AmountRequested>\n <PartialRedemption>false</PartialRedemption>\n <MerchantName>Shopify DEMO0678</MerchantName>\n <MerchantAddress>126 York Street</MerchantAddress>\n <MerchantCity>Ottawa</MerchantCity>\n <MerchantProvince>Alabama</MerchantProvince>\n <MerchantCountry>Canada</MerchantCountry>\n <MerchantPostal>K1N 5T5</MerchantPostal>\n <MerchantURL>www.shopify.com</MerchantURL>\n <TransarmorToken></TransarmorToken>\n <CardType>Visa</CardType>\n <CurrentBalance></CurrentBalance>\n <PreviousBalance></PreviousBalance>\n <EAN></EAN>\n <CardCost></CardCost>\n <VirtualCard>false</VirtualCard>\n <CTR>=========== TRANSACTION RECORD ==========\nShopify DEMO0678\n126 York Street\nOttawa, AL K1N 5T5\nCanada\nwww.shopify.com\n\nTY" + -> "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<TransactionResult>\n <ExactID>AD2327-05</ExactID>\n <Password></Password>\n <Transaction_Type>00</Transaction_Type>\n <DollarAmount>1.0</DollarAmount>\n <SurchargeAmount></SurchargeAmount>\n <Card_Number>[FILTERED]</Card_Number>\n <Transaction_Tag>42930941</Transaction_Tag>\n <Track1></Track1>\n <Track2></Track2>\n <PAN></PAN>\n <Authorization_Num>ET151682</Authorization_Num>\n <Expiry_Date>0916</Expiry_Date>\n <CardHoldersName>Longbob Longsen</CardHoldersName>\n <VerificationStr1>1234 My Street|K1C2N6|Ottawa|ON|CA</VerificationStr1>\n <VerificationStr2>[FILTERED]</VerificationStr2>\n <CVD_Presence_Ind>0</CVD_Presence_Ind>\n <ZipCode></ZipCode>\n <Tax1Amount></Tax1Amount>\n <Tax1Number></Tax1Number>\n <Tax2Amount></Tax2Amount>\n <Tax2Number></Tax2Number>\n <Secure_AuthRequired></Secure_AuthRequired>\n <Secure_AuthResult></Secure_AuthResult>\n <Ecommerce_Flag></Ecommerce_Flag>\n <XID></XID>\n <CAVV>[FILTERED]</CAVV>\n <CAVV_Algorithm></CAVV_Algorithm>\n <Reference_No>1</Reference_No>\n <Customer_Ref></Customer_Ref>\n <Reference_3>Store Purchase</Reference_3>\n <Language></Language>\n <Client_IP>216.191.105.146</Client_IP>\n <Client_Email></Client_Email>\n <Transaction_Error>false</Transaction_Error>\n <Transaction_Approved>true</Transaction_Approved>\n <EXact_Resp_Code>00</EXact_Resp_Code>\n <EXact_Message>Transaction Normal</EXact_Message>\n <Bank_Resp_Code>100</Bank_Resp_Code>\n <Bank_Message>Approved</Bank_Message>\n <Bank_Resp_Code_2></Bank_Resp_Code_2>\n <SequenceNo>106826</SequenceNo>\n <AVS>1</AVS>\n <CVV2>M</CVV2>\n <Retrieval_Ref_No>0025564</Retrieval_Ref_No>\n <CAVV_Response></CAVV_Response>\n <Currency>USD</Currency>\n <AmountRequested></AmountRequested>\n <PartialRedemption>false</PartialRedemption>\n <MerchantName>Shopify DEMO0678</MerchantName>\n <MerchantAddress>126 York Street</MerchantAddress>\n <MerchantCity>Ottawa</MerchantCity>\n <MerchantProvince>Alabama</MerchantProvince>\n <MerchantCountry>Canada</MerchantCountry>\n <MerchantPostal>K1N 5T5</MerchantPostal>\n <MerchantURL>www.shopify.com</MerchantURL>\n <TransarmorToken></TransarmorToken>\n <CardType>Visa</CardType>\n <CurrentBalance></CurrentBalance>\n <PreviousBalance></PreviousBalance>\n <EAN></EAN>\n <CardCost></CardCost>\n <VirtualCard>false</VirtualCard>\n <CTR>=========== TRANSACTION RECORD ==========\nShopify DEMO0678\n126 York Street\nOttawa, AL K1N 5T5\nCanada\nwww.shopify.com\n\nTY" -> "PE: Purchase\n\nACCT: Visa $ 1.00 USD\n\nCARDHOLDER NAME : Longbob Longsen\nCARD NUMBER : ############4242\nDATE/TIME : 26 Jan 15 12:11:44\nREFERENCE # : 106826 M\nAUTHOR. # : ET151682\nTRANS. REF. : 1\n\n Approved - Thank You 100\n\n\nPlease retain this copy for your records.\n\nCardholder will pay above amount to card\nissuer pursuant to cardholder agreement.\n=========================================</CTR>\n</TransactionResult>\n" read 2872 bytes Conn close @@ -431,6 +481,7 @@ def successful_purchase_response </TransactionResult> RESPONSE end + def successful_purchase_with_specified_currency_response <<-RESPONSE <?xml version="1.0" encoding="UTF-8"?> @@ -519,6 +570,7 @@ def successful_purchase_with_specified_currency_response </TransactionResult> RESPONSE end + def successful_purchase_response_without_transarmor <<-RESPONSE <?xml version="1.0" encoding="UTF-8"?> @@ -607,6 +659,7 @@ def successful_purchase_response_without_transarmor </TransactionResult> RESPONSE end + def successful_refund_response <<-RESPONSE <?xml version="1.0" encoding="UTF-8"?> @@ -987,7 +1040,7 @@ def no_transaction_response read: true socket: RESPONSE - YAML.load(yamlexcep) + YAML.safe_load(yamlexcep, ['Net::HTTPBadRequest', 'ActiveMerchant::ResponseError']) end def bad_credentials_response @@ -1024,7 +1077,7 @@ def bad_credentials_response http_version: '1.1' socket: RESPONSE - YAML.load(yamlexcep) + YAML.safe_load(yamlexcep, ['Net::HTTPUnauthorized', 'ActiveMerchant::ResponseError']) end def successful_void_response diff --git a/test/unit/gateways/firstdata_e4_v27_test.rb b/test/unit/gateways/firstdata_e4_v27_test.rb new file mode 100644 index 00000000000..77c51017ffe --- /dev/null +++ b/test/unit/gateways/firstdata_e4_v27_test.rb @@ -0,0 +1,989 @@ +require 'test_helper' +require 'nokogiri' +require 'yaml' + +class FirstdataE4V27Test < Test::Unit::TestCase + include CommStub + + def setup + @gateway = FirstdataE4V27Gateway.new( + :login => 'A00427-01', + :password => 'testus', + :key_id => '12345', + :hmac_key => 'hexkey' + ) + + @credit_card = credit_card + @amount = 100 + @options = { + :order_id => '1', + :billing_address => address, + :description => 'Store Purchase' + } + @authorization = 'ET1700;106625152;4738' + end + + def test_invalid_credentials + @gateway.expects(:ssl_post).raises(bad_credentials_response) + assert response = @gateway.store(@credit_card, {}) + assert_failure response + assert response.test? + assert_equal '', response.authorization + assert_equal 'Unauthorized Request. Bad or missing credentials.', response.message + end + + def test_successful_purchase + @gateway.expects(:ssl_post).returns(successful_purchase_response) + assert response = @gateway.purchase(@amount, @credit_card, @options) + assert_success response + assert_equal 'ET1700;106625152;4738', response.authorization + assert response.test? + assert_equal 'Transaction Normal - Approved', response.message + + FirstdataE4V27Gateway::SENSITIVE_FIELDS.each { |f| assert !response.params.has_key?(f.to_s) } + end + + def test_successful_purchase_with_token + @gateway.expects(:ssl_post).returns(successful_purchase_response) + assert response = @gateway.purchase(@amount, '8938737759041111;visa;Longbob;Longsen;9;2014') + assert_success response + end + + def test_successful_purchase_with_wallet + response = stub_comms do + @gateway.purchase(@amount, @credit_card, @options.merge!({wallet_provider_id: 4})) + end.check_request do |endpoint, data, headers| + assert_match(/WalletProviderID>4</, data) + end.respond_with(successful_purchase_response) + + assert_success response + end + + def test_successful_void + @gateway.expects(:ssl_post).returns(successful_void_response) + assert response = @gateway.void(@authorization, @options) + assert_success response + end + + def test_successful_refund + @gateway.expects(:ssl_post).returns(successful_refund_response) + assert response = @gateway.refund(@amount, @authorization) + assert_success response + end + + def test_successful_store + @gateway.expects(:ssl_post).returns(successful_purchase_response) + assert response = @gateway.store(@credit_card, @options) + assert_success response + assert_equal '8938737759041111', response.params['transarmor_token'] + assert_equal "8938737759041111;visa;Longbob;Longsen;9;#{@credit_card.year}", response.authorization + end + + def test_failed_store_without_transarmor_support + @gateway.expects(:ssl_post).returns(successful_purchase_response_without_transarmor) + assert_raise StandardError do + @gateway.store(@credit_card, @options) + end + end + + def test_failed_purchase + @gateway.expects(:ssl_post).returns(failed_purchase_response) + + assert response = @gateway.purchase(@amount, @credit_card, @options) + assert_instance_of Response, response + assert_failure response + assert_equal response.error_code, 'invalid_expiry_date' + end + + def test_successful_verify + response = stub_comms do + @gateway.verify(@credit_card) + end.respond_with(successful_verify_response) + assert_success response + end + + def test_expdate + assert_equal( + '%02d%2s' % [@credit_card.month, @credit_card.year.to_s[-2..-1]], + @gateway.send(:expdate, @credit_card) + ) + end + + def test_no_transaction + @gateway.expects(:ssl_post).raises(no_transaction_response()) + assert response = @gateway.purchase(100, @credit_card, {}) + assert_failure response + assert response.test? + assert_equal 'Malformed request: Transaction Type is missing.', response.message + end + + def test_supported_countries + assert_equal ['CA', 'US'], FirstdataE4V27Gateway.supported_countries + end + + def test_supported_cardtypes + assert_equal [:visa, :master, :american_express, :jcb, :discover], FirstdataE4V27Gateway.supported_cardtypes + end + + def test_avs_result + @gateway.expects(:ssl_post).returns(successful_purchase_response) + + response = @gateway.purchase(@amount, @credit_card) + assert_equal 'U', response.avs_result['code'] + end + + def test_cvv_result + @gateway.expects(:ssl_post).returns(successful_purchase_response) + + response = @gateway.purchase(@amount, @credit_card) + assert_equal 'M', response.cvv_result['code'] + end + + def test_request_includes_address + stub_comms do + @gateway.purchase(@amount, @credit_card, @options) + end.check_request do |endpoint, data, headers| + assert_match '<Address><Address1>456 My Street</Address1><Address2>Apt 1</Address2><City>Ottawa</City><State>ON</State><Zip>K1C2N6</Zip><CountryCode>CA</CountryCode></Address>', data + end.respond_with(successful_purchase_response) + end + + def test_tax_fields_are_sent + stub_comms do + @gateway.purchase(@amount, @credit_card, @options.merge(tax1_amount: 830, tax1_number: 'Br59a')) + end.check_request do |endpoint, data, headers| + assert_match '<Tax1Amount>830', data + assert_match '<Tax1Number>Br59a', data + end.respond_with(successful_purchase_response) + end + + def test_customer_ref_is_sent + stub_comms do + @gateway.purchase(@amount, @credit_card, @options.merge(customer: '932')) + end.check_request do |endpoint, data, headers| + assert_match '<Customer_Ref>932', data + end.respond_with(successful_purchase_response) + end + + def test_eci_default_value + stub_comms do + @gateway.purchase(@amount, @credit_card, @options) + end.check_request do |endpoint, data, headers| + assert_match '<Ecommerce_Flag>07</Ecommerce_Flag>', data + end.respond_with(successful_purchase_response) + end + + def test_eci_numeric_padding + @credit_card = network_tokenization_credit_card + @credit_card.eci = '5' + + stub_comms do + @gateway.purchase(@amount, @credit_card, @options) + end.check_request do |endpoint, data, headers| + assert_match '<Ecommerce_Flag>05</Ecommerce_Flag>', data + end.respond_with(successful_purchase_response) + + @credit_card = network_tokenization_credit_card + @credit_card.eci = 5 + + stub_comms do + @gateway.purchase(@amount, @credit_card, @options) + end.check_request do |endpoint, data, headers| + assert_match '<Ecommerce_Flag>05</Ecommerce_Flag>', data + end.respond_with(successful_purchase_response) + end + + def test_eci_option_value + stub_comms do + @gateway.purchase(@amount, @credit_card, @options.merge(eci: '05')) + end.check_request do |endpoint, data, headers| + assert_match '<Ecommerce_Flag>05</Ecommerce_Flag>', data + end.respond_with(successful_purchase_response) + end + + def test_network_tokenization_requests_with_amex + stub_comms do + credit_card = network_tokenization_credit_card( + '378282246310005', + brand: 'american_express', + transaction_id: '123', + eci: '05', + payment_cryptogram: 'whatever_the_cryptogram_of_at_least_20_characters_is' + ) + + @gateway.purchase(@amount, credit_card, @options) + end.check_request do |_, data, _| + assert_match '<Ecommerce_Flag>05</Ecommerce_Flag>', data + assert_match "<XID>mrLdtHIWq2nLXq7IrA==\n</XID>", data + assert_match "<CAVV>whateverthecryptogramofatlc=\n</CAVV>", data + assert_xml_valid_to_wsdl(data) + end.respond_with(successful_purchase_response) + end + + def test_network_tokenization_requests_with_discover + stub_comms do + credit_card = network_tokenization_credit_card( + '6011111111111117', + brand: 'discover', + transaction_id: '123', + eci: '05', + payment_cryptogram: 'whatever_the_cryptogram_is' + ) + + @gateway.purchase(@amount, credit_card, @options) + end.check_request do |_, data, _| + assert_match '<Ecommerce_Flag>04</Ecommerce_Flag>', data + assert_match '<XID>123</XID>', data + assert_match '<CAVV>whatever_the_cryptogram_is</CAVV>', data + assert_xml_valid_to_wsdl(data) + end.respond_with(successful_purchase_response) + end + + def test_network_tokenization_requests_with_other_brands + %w(visa mastercard other).each do |brand| + stub_comms do + credit_card = network_tokenization_credit_card( + '378282246310005', + brand: brand, + transaction_id: '123', + eci: '05', + payment_cryptogram: 'whatever_the_cryptogram_is' + ) + + @gateway.purchase(@amount, credit_card, @options) + end.check_request do |_, data, _| + assert_match '<Ecommerce_Flag>05</Ecommerce_Flag>', data + assert_match '<XID>123</XID>', data + assert_match '<CAVV>whatever_the_cryptogram_is</CAVV>', data + assert_xml_valid_to_wsdl(data) + end.respond_with(successful_purchase_response) + end + end + + def test_requests_include_card_authentication_data + authentication_hash = { + eci: '06', + cavv: 'SAMPLECAVV', + xid: 'SAMPLEXID' + } + options_with_authentication_data = @options.merge(authentication_hash) + + stub_comms do + @gateway.purchase(@amount, @credit_card, options_with_authentication_data) + end.check_request do |endpoint, data, headers| + assert_match '<Ecommerce_Flag>06</Ecommerce_Flag>', data + assert_match '<CAVV>SAMPLECAVV</CAVV>', data + assert_match '<XID>SAMPLEXID</XID>', data + assert_xml_valid_to_wsdl(data) + end.respond_with(successful_purchase_response) + end + + def test_card_type + assert_equal 'Visa', @gateway.send(:card_type, 'visa') + assert_equal 'Mastercard', @gateway.send(:card_type, 'master') + assert_equal 'American Express', @gateway.send(:card_type, 'american_express') + assert_equal 'JCB', @gateway.send(:card_type, 'jcb') + assert_equal 'Discover', @gateway.send(:card_type, 'discover') + end + + def test_add_swipe_data_with_creditcard + @credit_card.track_data = 'Track Data' + + stub_comms do + @gateway.purchase(@amount, @credit_card) + end.check_request do |endpoint, data, headers| + assert_match '<Track1>Track Data</Track1>', data + assert_match '<Ecommerce_Flag>R</Ecommerce_Flag>', data + end.respond_with(successful_purchase_response) + end + + def test_transcript_scrubbing + assert @gateway.supports_scrubbing? + assert_equal @gateway.scrub(pre_scrub), post_scrub + end + + def test_supports_network_tokenization + assert_instance_of TrueClass, @gateway.supports_network_tokenization? + end + + private + + def assert_xml_valid_to_wsdl(data) + xsd = Nokogiri::XML::Schema(File.open("#{File.dirname(__FILE__)}/../../schema/firstdata_e4/v27.xsd")) + doc = Nokogiri::XML(data) + errors = xsd.validate(doc) + assert_empty errors, "XSD validation errors in the following XML:\n#{doc}" + end + + def pre_scrub + <<-PRE_SCRUBBED + opening connection to api.demo.globalgatewaye4.firstdata.com:443... + opened + starting SSL for api.demo.globalgatewaye4.firstdata.com:443... + SSL established + <- "POST /transaction/v27 HTTP/1.1\r\nContent-Type: application/xml\r\nX-Gge4-Date: 2018-07-03T07:35:34Z\r\nX-Gge4-Content-Sha1: 5335f81daf59c493fe5d4c18910d17eba69558d4\r\nAuthorization: GGE4_API 397439:iwaxRr8f3GQIMSucb+dmDeiwoAk=\r\nAccepts: application/xml\r\nConnection: close\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nAccept: */*\r\nUser-Agent: Ruby\r\nHost: api.demo.globalgatewaye4.firstdata.com\r\nContent-Length: 807\r\n\r\n" + <- "<?xml version=\"1.0\" encoding=\"UTF-8\"?><Transaction xmlns=\"http://secure2.e-xact.com/vplug-in/transaction/rpc-enc/encodedTypes\"><ExactID>SD8821-67</ExactID><Password>cBhEc4GENtZ5fnVtpb2qlrhKUDprqtar</Password><Transaction_Type>00</Transaction_Type><DollarAmount>1.00</DollarAmount><Currency>USD</Currency><Card_Number>4242424242424242</Card_Number><Expiry_Date>0919</Expiry_Date><CardHoldersName>Longbob Longsen</CardHoldersName><CardType>Visa</CardType><Ecommerce_Flag>07</Ecommerce_Flag><CVD_Presence_Ind>1</CVD_Presence_Ind><CVDCode>123</CVDCode><CAVV/><XID/><Address><Address1>456 My Street</Address1><Address2>Apt 1</Address2><City>Ottawa</City><State>ON</State><Zip>K1C2N6</Zip><CountryCode>CA</CountryCode></Address><Reference_No>1</Reference_No><Reference_3>Store Purchase</Reference_3></Transaction>" + -> "HTTP/1.1 201 Created\r\n" + -> "Server: nginx\r\n" + -> "Date: Tue, 03 Jul 2018 07:35:34 GMT\r\n" + -> "Content-Type: application/xml; charset=utf-8\r\n" + -> "Transfer-Encoding: chunked\r\n" + -> "Connection: close\r\n" + -> "X-Frame-Options: SAMEORIGIN\r\n" + -> "X-XSS-Protection: 1; mode=block\r\n" + -> "X-Content-Type-Options: nosniff\r\n" + -> "X-GGE4-Date: 2018-07-03T07:35:34Z\r\n" + -> "X-GGE4-CONTENT-SHA1: 87ae8c40ae5afbfd060c7569645f3f6b4045994f\r\n" + -> "Authorization: GGE4_API 397439:dPOI+d2MkNJjBJhHTYUo0ieILw4=\r\n" + -> "Pragma: no-cache\r\n" + -> "Expires: Tue, 03 Jul 2018 06:35:34 GMT\r\n" + -> "Cache-Control: no-store, no-cache\r\n" + -> "X-Request-Id: 0f9ba7k2rd80a2tpch40\r\n" + -> "Location: https://api.demo.globalgatewaye4.firstdata.com/transaction/v27/2264726018\r\n" + -> "Status: 201 Created\r\n" + -> "Strict-Transport-Security: max-age=31536000; includeSubDomains\r\n" + -> "Strict-Transport-Security: max-age=315360000; includeSubdomains\r\n" + -> "\r\n" + -> "2da\r\n" + reading 2944 bytes... + -> "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<TransactionResult>\n <ExactID>SD8821-67</ExactID>\n <Password/>\n <Transaction_Type>00</Transaction_Type>\n <DollarAmount>1.0</DollarAmount>\n <SurchargeAmount/>\n <Card_Number>############4242</Card_Number>\n <Transaction_Tag>2264726018</Transaction_Tag>\n <SplitTenderID/>\n <Track1/>\n <Track2/>\n <PAN/>\n <Authorization_Num>ET121995</Authorization_Num>\n <Expiry_Date>0919</Expiry_Date>\n <CardHoldersName>Longbob Longsen</CardHoldersName>\n <CVD_Presence_Ind>1</CVD_Presence_Ind>\n <ZipCode/>\n <Tax1Amount/>\n <Tax1Number/>\n <Tax2Amount/>\n <Tax2Number/>\n <Secure_AuthRequired/>\n <Secure_AuthResult/>\n <Ecommerce_Flag>7</Ecommerce_Flag>\n <XID/>\n <CAVV/>\n <Reference_No>1</Reference_No>\n <Customer_Ref/>\n <Reference_3>Store Purchase</Reference_3>\n <Language/>\n <Client_IP/>\n <Client_Email/>\n <User_Name/>\n <Transaction_Error>false</Transaction_Error>\n <Transaction_Approved>true</Transaction_Approved>\n <EXact_Resp_Code>00</EXact_Resp_Code>\n <EXact_Message>Transaction Normal</EXact_Message>\n <Bank_Resp_Code>100</Bank_Resp_Code>\n <Bank_Message>Approved</Bank_Message>\n <Bank_Resp_Code_2/>\n <SequenceNo>001157</SequenceNo>\n <AVS>4</AVS>\n <CVV2>M</CVV2>\n <Retrieval_Ref_No>1196543</Retrieval_Ref_No>\n <CAVV_Response/>\n <Currency>USD</Currency>\n <AmountRequested/>\n <PartialRedemption>false</PartialRedemption>\n <MerchantName>Spreedly DEMO0095</MerchantName>\n <MerchantAddress>123 Testing</MerchantAddress>\n <MerchantCity>Durham</MerchantCity>\n <MerchantProvince>North Carolina</MerchantProvince>\n <MerchantCountry>United States</MerchantCountry>\n <MerchantPostal>27701</MerchantPostal>\n <MerchantURL/>\n <TransarmorToken/>\n <CardType>Visa</CardType>\n <CurrentBalance/>\n <PreviousBalance/>\n <EAN/>\n <CardCost/>\n <VirtualCard>false</VirtualCard>\n <CTR>========== TRANSACTION RECORD ==========\nSpreedly DEMO0095\n123 Testing\nDurham, NC 27701\nUnited States\n\n\nTYPE: Purchase\n\nACCT: Visa $ 1.00 USD\n\nCARDHOLDER NAME : Longbob Longsen\nCARD NUMBER : ############4242\nDATE/TIME : 03 Jul 18 03:35:34\nREFERENCE # : 03 001157 M\nAUTHOR. # : ET121995\nTRANS. REF. : 1\n\n Approved - Thank You 100\n\n\nPlease retain this copy for your records.\n\nCardholder will pay above amount to\ncard issuer pursuant to cardholder\nagreement.\n========================================</CTR>\n <FraudSuspected/>\n <Address>\n <Address1>456 My Street</Address1>\n <Address2>Apt 1</Address2>\n <City>Ottawa</City>\n <State>ON</State>\n <Zip>K1C2N6</Zip>\n <CountryCode>CA</CountryCode>\n </Address>\n <CVDCode>123</CVDCode>\n <SplitShipmentNumber/>\n</TransactionResult>\n" + read 2944 bytes + Conn close + PRE_SCRUBBED + end + + def post_scrub + <<-POST_SCRUBBED + opening connection to api.demo.globalgatewaye4.firstdata.com:443... + opened + starting SSL for api.demo.globalgatewaye4.firstdata.com:443... + SSL established + <- "POST /transaction/v27 HTTP/1.1\r\nContent-Type: application/xml\r\nX-Gge4-Date: 2018-07-03T07:35:34Z\r\nX-Gge4-Content-Sha1: 5335f81daf59c493fe5d4c18910d17eba69558d4\r\nAuthorization: GGE4_API 397439:iwaxRr8f3GQIMSucb+dmDeiwoAk=\r\nAccepts: application/xml\r\nConnection: close\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nAccept: */*\r\nUser-Agent: Ruby\r\nHost: api.demo.globalgatewaye4.firstdata.com\r\nContent-Length: 807\r\n\r\n" + <- "<?xml version=\"1.0\" encoding=\"UTF-8\"?><Transaction xmlns=\"http://secure2.e-xact.com/vplug-in/transaction/rpc-enc/encodedTypes\"><ExactID>SD8821-67</ExactID><Password>[FILTERED]</Password><Transaction_Type>00</Transaction_Type><DollarAmount>1.00</DollarAmount><Currency>USD</Currency><Card_Number>[FILTERED]</Card_Number><Expiry_Date>0919</Expiry_Date><CardHoldersName>Longbob Longsen</CardHoldersName><CardType>Visa</CardType><Ecommerce_Flag>07</Ecommerce_Flag><CVD_Presence_Ind>1</CVD_Presence_Ind><CVDCode>[FILTERED]</CVDCode><CAVV/><XID/><Address><Address1>456 My Street</Address1><Address2>Apt 1</Address2><City>Ottawa</City><State>ON</State><Zip>K1C2N6</Zip><CountryCode>CA</CountryCode></Address><Reference_No>1</Reference_No><Reference_3>Store Purchase</Reference_3></Transaction>" + -> "HTTP/1.1 201 Created\r\n" + -> "Server: nginx\r\n" + -> "Date: Tue, 03 Jul 2018 07:35:34 GMT\r\n" + -> "Content-Type: application/xml; charset=utf-8\r\n" + -> "Transfer-Encoding: chunked\r\n" + -> "Connection: close\r\n" + -> "X-Frame-Options: SAMEORIGIN\r\n" + -> "X-XSS-Protection: 1; mode=block\r\n" + -> "X-Content-Type-Options: nosniff\r\n" + -> "X-GGE4-Date: 2018-07-03T07:35:34Z\r\n" + -> "X-GGE4-CONTENT-SHA1: 87ae8c40ae5afbfd060c7569645f3f6b4045994f\r\n" + -> "Authorization: GGE4_API 397439:dPOI+d2MkNJjBJhHTYUo0ieILw4=\r\n" + -> "Pragma: no-cache\r\n" + -> "Expires: Tue, 03 Jul 2018 06:35:34 GMT\r\n" + -> "Cache-Control: no-store, no-cache\r\n" + -> "X-Request-Id: 0f9ba7k2rd80a2tpch40\r\n" + -> "Location: https://api.demo.globalgatewaye4.firstdata.com/transaction/v27/2264726018\r\n" + -> "Status: 201 Created\r\n" + -> "Strict-Transport-Security: max-age=31536000; includeSubDomains\r\n" + -> "Strict-Transport-Security: max-age=315360000; includeSubdomains\r\n" + -> "\r\n" + -> "2da\r\n" + reading 2944 bytes... + -> "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<TransactionResult>\n <ExactID>SD8821-67</ExactID>\n <Password/>\n <Transaction_Type>00</Transaction_Type>\n <DollarAmount>1.0</DollarAmount>\n <SurchargeAmount/>\n <Card_Number>[FILTERED]</Card_Number>\n <Transaction_Tag>2264726018</Transaction_Tag>\n <SplitTenderID/>\n <Track1/>\n <Track2/>\n <PAN/>\n <Authorization_Num>ET121995</Authorization_Num>\n <Expiry_Date>0919</Expiry_Date>\n <CardHoldersName>Longbob Longsen</CardHoldersName>\n <CVD_Presence_Ind>1</CVD_Presence_Ind>\n <ZipCode/>\n <Tax1Amount/>\n <Tax1Number/>\n <Tax2Amount/>\n <Tax2Number/>\n <Secure_AuthRequired/>\n <Secure_AuthResult/>\n <Ecommerce_Flag>7</Ecommerce_Flag>\n <XID/>\n <CAVV/>\n <Reference_No>1</Reference_No>\n <Customer_Ref/>\n <Reference_3>Store Purchase</Reference_3>\n <Language/>\n <Client_IP/>\n <Client_Email/>\n <User_Name/>\n <Transaction_Error>false</Transaction_Error>\n <Transaction_Approved>true</Transaction_Approved>\n <EXact_Resp_Code>00</EXact_Resp_Code>\n <EXact_Message>Transaction Normal</EXact_Message>\n <Bank_Resp_Code>100</Bank_Resp_Code>\n <Bank_Message>Approved</Bank_Message>\n <Bank_Resp_Code_2/>\n <SequenceNo>001157</SequenceNo>\n <AVS>4</AVS>\n <CVV2>M</CVV2>\n <Retrieval_Ref_No>1196543</Retrieval_Ref_No>\n <CAVV_Response/>\n <Currency>USD</Currency>\n <AmountRequested/>\n <PartialRedemption>false</PartialRedemption>\n <MerchantName>Spreedly DEMO0095</MerchantName>\n <MerchantAddress>123 Testing</MerchantAddress>\n <MerchantCity>Durham</MerchantCity>\n <MerchantProvince>North Carolina</MerchantProvince>\n <MerchantCountry>United States</MerchantCountry>\n <MerchantPostal>27701</MerchantPostal>\n <MerchantURL/>\n <TransarmorToken/>\n <CardType>Visa</CardType>\n <CurrentBalance/>\n <PreviousBalance/>\n <EAN/>\n <CardCost/>\n <VirtualCard>false</VirtualCard>\n <CTR>========== TRANSACTION RECORD ==========\nSpreedly DEMO0095\n123 Testing\nDurham, NC 27701\nUnited States\n\n\nTYPE: Purchase\n\nACCT: Visa $ 1.00 USD\n\nCARDHOLDER NAME : Longbob Longsen\nCARD NUMBER : [FILTERED]\nDATE/TIME : 03 Jul 18 03:35:34\nREFERENCE # : 03 001157 M\nAUTHOR. # : ET121995\nTRANS. REF. : 1\n\n Approved - Thank You 100\n\n\nPlease retain this copy for your records.\n\nCardholder will pay above amount to\ncard issuer pursuant to cardholder\nagreement.\n========================================</CTR>\n <FraudSuspected/>\n <Address>\n <Address1>456 My Street</Address1>\n <Address2>Apt 1</Address2>\n <City>Ottawa</City>\n <State>ON</State>\n <Zip>K1C2N6</Zip>\n <CountryCode>CA</CountryCode>\n </Address>\n <CVDCode>[FILTERED]</CVDCode>\n <SplitShipmentNumber/>\n</TransactionResult>\n" + read 2944 bytes + Conn close + POST_SCRUBBED + end + + def successful_purchase_response + <<-RESPONSE + <?xml version="1.0" encoding="UTF-8"?> + <TransactionResult> + <ExactID>AD1234-56</ExactID> + <Password></Password> + <Transaction_Type>00</Transaction_Type> + <DollarAmount>47.38</DollarAmount> + <SurchargeAmount></SurchargeAmount> + <Card_Number>############1111</Card_Number> + <Transaction_Tag>106625152</Transaction_Tag> + <Track1></Track1> + <Track2></Track2> + <PAN></PAN> + <Authorization_Num>ET1700</Authorization_Num> + <Expiry_Date>0913</Expiry_Date> + <CardHoldersName>Fred Burfle</CardHoldersName> + <CVD_Presence_Ind>0</CVD_Presence_Ind> + <ZipCode></ZipCode> + <Tax1Amount></Tax1Amount> + <Tax1Number></Tax1Number> + <Tax2Amount></Tax2Amount> + <Tax2Number></Tax2Number> + <Secure_AuthRequired></Secure_AuthRequired> + <Secure_AuthResult></Secure_AuthResult> + <Ecommerce_Flag></Ecommerce_Flag> + <XID></XID> + <CAVV></CAVV> + <CAVV_Algorithm></CAVV_Algorithm> + <Reference_No>77</Reference_No> + <Customer_Ref></Customer_Ref> + <Reference_3></Reference_3> + <Language></Language> + <Client_IP>1.1.1.10</Client_IP> + <Client_Email></Client_Email> + <Transaction_Error>false</Transaction_Error> + <Transaction_Approved>true</Transaction_Approved> + <EXact_Resp_Code>00</EXact_Resp_Code> + <EXact_Message>Transaction Normal</EXact_Message> + <Bank_Resp_Code>100</Bank_Resp_Code> + <Bank_Message>Approved</Bank_Message> + <Bank_Resp_Code_2></Bank_Resp_Code_2> + <SequenceNo>000040</SequenceNo> + <AVS>U</AVS> + <CVV2>M</CVV2> + <Retrieval_Ref_No>3146117</Retrieval_Ref_No> + <CAVV_Response></CAVV_Response> + <Currency>USD</Currency> + <AmountRequested></AmountRequested> + <PartialRedemption>false</PartialRedemption> + <MerchantName>Friendly Inc DEMO0983</MerchantName> + <MerchantAddress>123 King St</MerchantAddress> + <MerchantCity>Toronto</MerchantCity> + <MerchantProvince>Ontario</MerchantProvince> + <MerchantCountry>Canada</MerchantCountry> + <MerchantPostal>L7Z 3K8</MerchantPostal> + <MerchantURL></MerchantURL> + <TransarmorToken>8938737759041111</TransarmorToken> + <CTR>=========== TRANSACTION RECORD ========== +Friendly Inc DEMO0983 +123 King St +Toronto, ON L7Z 3K8 +Canada + + +TYPE: Purchase + +ACCT: Visa $ 47.38 USD + +CARD NUMBER : ############1111 +DATE/TIME : 28 Sep 12 07:54:48 +REFERENCE # : 000040 M +AUTHOR. # : ET120454 +TRANS. REF. : 77 + + Approved - Thank You 100 + + +Please retain this copy for your records. + +Cardholder will pay above amount to card +issuer pursuant to cardholder agreement. +=========================================</CTR> + <Address> + <Address1>456 My Street</Address1> + <Address2>Apt 1</Address2> + <City>Ottawa</City> + <State>ON</State> + <Zip>K1C2N6</Zip> + <CountryCode>CA</CountryCode> + </Address> + </TransactionResult> + RESPONSE + end + + def successful_purchase_response_without_transarmor + <<-RESPONSE + <?xml version="1.0" encoding="UTF-8"?> + <TransactionResult> + <ExactID>AD1234-56</ExactID> + <Password></Password> + <Transaction_Type>00</Transaction_Type> + <DollarAmount>47.38</DollarAmount> + <SurchargeAmount></SurchargeAmount> + <Card_Number>############1111</Card_Number> + <Transaction_Tag>106625152</Transaction_Tag> + <Track1></Track1> + <Track2></Track2> + <PAN></PAN> + <Authorization_Num>ET1700</Authorization_Num> + <Expiry_Date>0913</Expiry_Date> + <CardHoldersName>Fred Burfle</CardHoldersName> + <CVD_Presence_Ind>0</CVD_Presence_Ind> + <ZipCode></ZipCode> + <Tax1Amount></Tax1Amount> + <Tax1Number></Tax1Number> + <Tax2Amount></Tax2Amount> + <Tax2Number></Tax2Number> + <Secure_AuthRequired></Secure_AuthRequired> + <Secure_AuthResult></Secure_AuthResult> + <Ecommerce_Flag></Ecommerce_Flag> + <XID></XID> + <CAVV></CAVV> + <CAVV_Algorithm></CAVV_Algorithm> + <Reference_No>77</Reference_No> + <Customer_Ref></Customer_Ref> + <Reference_3></Reference_3> + <Language></Language> + <Client_IP>1.1.1.10</Client_IP> + <Client_Email></Client_Email> + <Transaction_Error>false</Transaction_Error> + <Transaction_Approved>true</Transaction_Approved> + <EXact_Resp_Code>00</EXact_Resp_Code> + <EXact_Message>Transaction Normal</EXact_Message> + <Bank_Resp_Code>100</Bank_Resp_Code> + <Bank_Message>Approved</Bank_Message> + <Bank_Resp_Code_2></Bank_Resp_Code_2> + <SequenceNo>000040</SequenceNo> + <AVS>U</AVS> + <CVV2>M</CVV2> + <Retrieval_Ref_No>3146117</Retrieval_Ref_No> + <CAVV_Response></CAVV_Response> + <Currency>USD</Currency> + <AmountRequested></AmountRequested> + <PartialRedemption>false</PartialRedemption> + <MerchantName>Friendly Inc DEMO0983</MerchantName> + <MerchantAddress>123 King St</MerchantAddress> + <MerchantCity>Toronto</MerchantCity> + <MerchantProvince>Ontario</MerchantProvince> + <MerchantCountry>Canada</MerchantCountry> + <MerchantPostal>L7Z 3K8</MerchantPostal> + <MerchantURL></MerchantURL> + <TransarmorToken></TransarmorToken> + <CTR>=========== TRANSACTION RECORD ========== +Friendly Inc DEMO0983 +123 King St +Toronto, ON L7Z 3K8 +Canada + + +TYPE: Purchase + +ACCT: Visa $ 47.38 USD + +CARD NUMBER : ############1111 +DATE/TIME : 28 Sep 12 07:54:48 +REFERENCE # : 000040 M +AUTHOR. # : ET120454 +TRANS. REF. : 77 + + Approved - Thank You 100 + + +Please retain this copy for your records. + +Cardholder will pay above amount to card +issuer pursuant to cardholder agreement. +=========================================</CTR> + </TransactionResult> + RESPONSE + end + + def successful_refund_response + <<-RESPONSE + <?xml version="1.0" encoding="UTF-8"?> + <TransactionResult> + <ExactID>AD1234-56</ExactID> + <Password></Password> + <Transaction_Type>34</Transaction_Type> + <DollarAmount>123</DollarAmount> + <SurchargeAmount></SurchargeAmount> + <Card_Number>############1111</Card_Number> + <Transaction_Tag>888</Transaction_Tag> + <Track1></Track1> + <Track2></Track2> + <PAN></PAN> + <Authorization_Num>ET112216</Authorization_Num> + <Expiry_Date>0913</Expiry_Date> + <CardHoldersName>Fred Burfle</CardHoldersName> + <CVD_Presence_Ind>0</CVD_Presence_Ind> + <ZipCode></ZipCode> + <Tax1Amount></Tax1Amount> + <Tax1Number></Tax1Number> + <Tax2Amount></Tax2Amount> + <Tax2Number></Tax2Number> + <Secure_AuthRequired></Secure_AuthRequired> + <Secure_AuthResult></Secure_AuthResult> + <Ecommerce_Flag></Ecommerce_Flag> + <XID></XID> + <CAVV></CAVV> + <CAVV_Algorithm></CAVV_Algorithm> + <Reference_No></Reference_No> + <Customer_Ref></Customer_Ref> + <Reference_3></Reference_3> + <Language></Language> + <Client_IP>1.1.1.10</Client_IP> + <Client_Email></Client_Email> + <Transaction_Error>false</Transaction_Error> + <Transaction_Approved>true</Transaction_Approved> + <EXact_Resp_Code>00</EXact_Resp_Code> + <EXact_Message>Transaction Normal</EXact_Message> + <Bank_Resp_Code>100</Bank_Resp_Code> + <Bank_Message>Approved</Bank_Message> + <Bank_Resp_Code_2></Bank_Resp_Code_2> + <SequenceNo>000041</SequenceNo> + <AVS></AVS> + <CVV2>I</CVV2> + <Retrieval_Ref_No>9176784</Retrieval_Ref_No> + <CAVV_Response></CAVV_Response> + <Currency>USD</Currency> + <AmountRequested></AmountRequested> + <PartialRedemption>false</PartialRedemption> + <MerchantName>Friendly Inc DEMO0983</MerchantName> + <MerchantAddress>123 King St</MerchantAddress> + <MerchantCity>Toronto</MerchantCity> + <MerchantProvince>Ontario</MerchantProvince> + <MerchantCountry>Canada</MerchantCountry> + <MerchantPostal>L7Z 3K8</MerchantPostal> + <MerchantURL></MerchantURL> + <CTR>=========== TRANSACTION RECORD ========== +Friendly Inc DEMO0983 +123 King St +Toronto, ON L7Z 3K8 +Canada + + +TYPE: Refund + +ACCT: Visa $ 23.69 USD + +CARD NUMBER : ############1111 +DATE/TIME : 28 Sep 12 08:31:23 +REFERENCE # : 000041 M +AUTHOR. # : ET112216 +TRANS. REF. : + + Approved - Thank You 100 + + +Please retain this copy for your records. + +=========================================</CTR> + </TransactionResult> + RESPONSE + end + + def failed_purchase_response + <<-RESPONSE + <?xml version="1.0" encoding="UTF-8"?> + <TransactionResult> + <ExactID>AD1234-56</ExactID> + <Password></Password> + <Transaction_Type>00</Transaction_Type> + <DollarAmount>5013.0</DollarAmount> + <SurchargeAmount></SurchargeAmount> + <Card_Number>############1111</Card_Number> + <Transaction_Tag>555555</Transaction_Tag> + <Track1></Track1> + <Track2></Track2> + <PAN></PAN> + <Authorization_Num></Authorization_Num> + <Expiry_Date>0911</Expiry_Date> + <CardHoldersName>Fred Burfle</CardHoldersName> + <CVD_Presence_Ind>0</CVD_Presence_Ind> + <ZipCode></ZipCode> + <Tax1Amount></Tax1Amount> + <Tax1Number></Tax1Number> + <Tax2Amount></Tax2Amount> + <Tax2Number></Tax2Number> + <Secure_AuthRequired></Secure_AuthRequired> + <Secure_AuthResult></Secure_AuthResult> + <Ecommerce_Flag></Ecommerce_Flag> + <XID></XID> + <CAVV></CAVV> + <CAVV_Algorithm></CAVV_Algorithm> + <Reference_No>77</Reference_No> + <Customer_Ref></Customer_Ref> + <Reference_3></Reference_3> + <Language></Language> + <Client_IP>1.1.1.10</Client_IP> + <Client_Email></Client_Email> + <LogonMessage></LogonMessage> + <Error_Number>0</Error_Number> + <Error_Description> </Error_Description> + <Transaction_Error>false</Transaction_Error> + <Transaction_Approved>false</Transaction_Approved> + <EXact_Resp_Code>00</EXact_Resp_Code> + <EXact_Message>Transaction Normal</EXact_Message> + <Bank_Resp_Code>605</Bank_Resp_Code> + <Bank_Message>Invalid Expiration Date</Bank_Message> + <Bank_Resp_Code_2></Bank_Resp_Code_2> + <SequenceNo>000033</SequenceNo> + <AVS></AVS> + <CVV2></CVV2> + <Retrieval_Ref_No></Retrieval_Ref_No> + <CAVV_Response></CAVV_Response> + <Currency>USD</Currency> + <AmountRequested></AmountRequested> + <PartialRedemption>false</PartialRedemption> + <MerchantName>Friendly Inc DEMO0983</MerchantName> + <MerchantAddress>123 King St</MerchantAddress> + <MerchantCity>Toronto</MerchantCity> + <MerchantProvince>Ontario</MerchantProvince> + <MerchantCountry>Canada</MerchantCountry> + <MerchantPostal>L7Z 3K8</MerchantPostal> + <MerchantURL></MerchantURL> + <CTR>=========== TRANSACTION RECORD ========== +Friendly Inc DEMO0983 +123 King St +Toronto, ON L7Z 3K8 +Canada + + +TYPE: Purchase +ACCT: Visa $ 5,013.00 USD +CARD NUMBER : ############1111 +DATE/TIME : 25 Sep 12 07:27:00 +REFERENCE # : 000033 M +AUTHOR. # : +TRANS. REF. : 77 +Transaction not approved 605 +Please retain this copy for your records. +=========================================</CTR> + </TransactionResult> + RESPONSE + end + + def successful_verify_response + <<-RESPONSE +<?xml version="1.0" encoding="UTF-8"?> +<TransactionResult> + <ExactID>AD2552-05</ExactID> + <Password></Password> + <Transaction_Type>05</Transaction_Type> + <DollarAmount>0.0</DollarAmount> + <SurchargeAmount></SurchargeAmount> + <Card_Number>############4242</Card_Number> + <Transaction_Tag>25101911</Transaction_Tag> + <Track1></Track1> + <Track2></Track2> + <PAN></PAN> + <Authorization_Num>ET184931</Authorization_Num> + <Expiry_Date>0915</Expiry_Date> + <CardHoldersName>Longbob Longsen</CardHoldersName> + <CVD_Presence_Ind>0</CVD_Presence_Ind> + <ZipCode></ZipCode> + <Tax1Amount></Tax1Amount> + <Tax1Number></Tax1Number> + <Tax2Amount></Tax2Amount> + <Tax2Number></Tax2Number> + <Secure_AuthRequired></Secure_AuthRequired> + <Secure_AuthResult></Secure_AuthResult> + <Ecommerce_Flag></Ecommerce_Flag> + <XID></XID> + <CAVV></CAVV> + <CAVV_Algorithm></CAVV_Algorithm> + <Reference_No>1</Reference_No> + <Customer_Ref></Customer_Ref> + <Reference_3>Store Purchase</Reference_3> + <Language></Language> + <Client_IP>75.182.123.244</Client_IP> + <Client_Email></Client_Email> + <Transaction_Error>false</Transaction_Error> + <Transaction_Approved>true</Transaction_Approved> + <EXact_Resp_Code>00</EXact_Resp_Code> + <EXact_Message>Transaction Normal</EXact_Message> + <Bank_Resp_Code>100</Bank_Resp_Code> + <Bank_Message>Approved</Bank_Message> + <Bank_Resp_Code_2></Bank_Resp_Code_2> + <SequenceNo>000040</SequenceNo> + <AVS>1</AVS> + <CVV2>M</CVV2> + <Retrieval_Ref_No>7228838</Retrieval_Ref_No> + <CAVV_Response></CAVV_Response> + <Currency>USD</Currency> + <AmountRequested></AmountRequested> + <PartialRedemption>false</PartialRedemption> + <MerchantName>FriendlyInc</MerchantName> + <MerchantAddress>123 Main Street</MerchantAddress> + <MerchantCity>Durham</MerchantCity> + <MerchantProvince>North Carolina</MerchantProvince> + <MerchantCountry>United States</MerchantCountry> + <MerchantPostal>27592</MerchantPostal> + <MerchantURL></MerchantURL> + <TransarmorToken></TransarmorToken> + <CardType>Visa</CardType> + <CurrentBalance></CurrentBalance> + <PreviousBalance></PreviousBalance> + <EAN></EAN> + <CardCost></CardCost> + <VirtualCard>false</VirtualCard> + <CTR>=========== TRANSACTION RECORD ========== +FriendlyInc DEMO0 +123 Main Street +Durham, NC 27592 +United States + + +TYPE: Auth Only + +ACCT: Visa $ 0.00 USD + +CARDHOLDER NAME : Longbob Longsen +CARD NUMBER : ############4242 +DATE/TIME : 04 Jul 14 14:21:52 +REFERENCE # : 000040 M +AUTHOR. # : ET184931 +TRANS. REF. : 1 + + Approved - Thank You 100 + + +Please retain this copy for your records. + +Cardholder will pay above amount to card +issuer pursuant to cardholder agreement. +=========================================</CTR> +</TransactionResult> + RESPONSE + end + + def no_transaction_response + yamlexcep = <<-RESPONSE +--- !ruby/exception:ActiveMerchant::ResponseError +message: Failed with 400 Bad Request +message: +response: !ruby/object:Net::HTTPBadRequest + body: "Malformed request: Transaction Type is missing." + body_exist: true + code: "400" + header: + connection: + - Close + content-type: + - text/html; charset=utf-8 + server: + - Apache + date: + - Fri, 28 Sep 2012 18:21:37 GMT + content-length: + - "47" + status: + - "400" + cache-control: + - no-cache + http_version: "1.1" + message: Bad Request + read: true + socket: + RESPONSE + YAML.safe_load(yamlexcep, ['Net::HTTPBadRequest', 'ActiveMerchant::ResponseError']) + end + + def bad_credentials_response + yamlexcep = <<-RESPONSE +--- !ruby/exception:ActiveMerchant::ResponseError +message: +response: !ruby/object:Net::HTTPUnauthorized + code: '401' + message: Authorization Required + body: Unauthorized Request. Bad or missing credentials. + read: true + header: + cache-control: + - no-cache + content-type: + - text/html; charset=utf-8 + date: + - Tue, 30 Dec 2014 23:28:32 GMT + server: + - Apache + status: + - '401' + x-rack-cache: + - invalidate, pass + x-request-id: + - 4157e21cc5620a95ead8d2025b55bdf4 + x-ua-compatible: + - IE=Edge,chrome=1 + content-length: + - '49' + connection: + - Close + body_exist: true + http_version: '1.1' + socket: + RESPONSE + YAML.safe_load(yamlexcep, ['Net::HTTPUnauthorized', 'ActiveMerchant::ResponseError']) + end + + def successful_void_response + <<-RESPONSE + <?xml version="1.0" encoding="UTF-8"?> + <TransactionResult> + <ExactID>AD1234-56</ExactID> + <Password></Password> + <Transaction_Type>33</Transaction_Type> + <DollarAmount>11.45</DollarAmount> + <SurchargeAmount></SurchargeAmount> + <Card_Number>############1111</Card_Number> + <Transaction_Tag>987123</Transaction_Tag> + <Track1></Track1> + <Track2></Track2> + <PAN></PAN> + <Authorization_Num>ET112112</Authorization_Num> + <Expiry_Date>0913</Expiry_Date> + <CardHoldersName>Fred Burfle</CardHoldersName> + <CVD_Presence_Ind>0</CVD_Presence_Ind> + <ZipCode></ZipCode> + <Tax1Amount></Tax1Amount> + <Tax1Number></Tax1Number> + <Tax2Amount></Tax2Amount> + <Tax2Number></Tax2Number> + <Secure_AuthRequired></Secure_AuthRequired> + <Secure_AuthResult></Secure_AuthResult> + <Ecommerce_Flag></Ecommerce_Flag> + <XID></XID> + <CAVV></CAVV> + <CAVV_Algorithm></CAVV_Algorithm> + <Reference_No></Reference_No> + <Customer_Ref></Customer_Ref> + <Reference_3></Reference_3> + <Language></Language> + <Client_IP>1.1.1.10</Client_IP> + <Client_Email></Client_Email> + <LogonMessage></LogonMessage> + <Error_Number>0</Error_Number> + <Error_Description> </Error_Description> + <Transaction_Error>false</Transaction_Error> + <Transaction_Approved>true</Transaction_Approved> + <EXact_Resp_Code>00</EXact_Resp_Code> + <EXact_Message>Transaction Normal</EXact_Message> + <Bank_Resp_Code>100</Bank_Resp_Code> + <Bank_Message>Approved</Bank_Message> + <Bank_Resp_Code_2></Bank_Resp_Code_2> + <SequenceNo>000166</SequenceNo> + <AVS></AVS> + <CVV2>I</CVV2> + <Retrieval_Ref_No>2046743</Retrieval_Ref_No> + <CAVV_Response></CAVV_Response> + <Currency>USD</Currency> + <AmountRequested></AmountRequested> + <PartialRedemption>false</PartialRedemption> + <MerchantName>FreshBooks DEMO0785</MerchantName> + <MerchantAddress>35 Golden Ave</MerchantAddress> + <MerchantCity>Toronto</MerchantCity> + <MerchantProvince>Ontario</MerchantProvince> + <MerchantCountry>Canada</MerchantCountry> + <MerchantPostal>M6R 2J5</MerchantPostal> + <MerchantURL></MerchantURL> +<CTR>=========== TRANSACTION RECORD ========== +FreshBooks DEMO0785 +35 Golden Ave +Toronto, ON M6R 2J5 +Canada + + +TYPE: Void + +ACCT: Visa $ 47.38 USD + +CARD NUMBER : ############1111 +DATE/TIME : 15 Nov 12 08:20:36 +REFERENCE # : 000166 M +AUTHOR. # : ET112112 +TRANS. REF. : + +Approved - Thank You 100 + + +Please retain this copy for your records. + +Cardholder will pay above amount to card +issuer pursuant to cardholder agreement. +=========================================</CTR> + </TransactionResult> +RESPONSE + end +end diff --git a/test/unit/gateways/flo2cash_simple_test.rb b/test/unit/gateways/flo2cash_simple_test.rb index 6037368c7f4..627f6782e29 100644 --- a/test/unit/gateways/flo2cash_simple_test.rb +++ b/test/unit/gateways/flo2cash_simple_test.rb @@ -18,14 +18,14 @@ def setup def test_successful_purchase response = stub_comms do - @gateway.purchase(@amount, @credit_card, order_id: "boom") + @gateway.purchase(@amount, @credit_card, order_id: 'boom') end.check_request do |endpoint, data, headers| assert_match(%r{<Reference>boom</Reference>}, data) end.respond_with(successful_purchase_response) assert_success response - assert_equal "P150200005007600", response.authorization + assert_equal 'P150200005007600', response.authorization assert response.test? end @@ -35,7 +35,7 @@ def test_failed_purchase end.respond_with(failed_purchase_response) assert_failure response - assert_equal "Transaction Declined - Bank Error", response.message + assert_equal 'Transaction Declined - Bank Error', response.message assert_equal Gateway::STANDARD_ERROR_CODE[:processing_error], response.error_code assert response.test? end @@ -46,7 +46,7 @@ def test_successful_refund end.respond_with(successful_purchase_response) assert_success response - assert_equal "P150200005007600", response.authorization + assert_equal 'P150200005007600', response.authorization refund = stub_comms do @gateway.refund(@amount, response.authorization) @@ -63,7 +63,7 @@ def test_empty_response_fails end.respond_with(empty_purchase_response) assert_failure response - assert_equal "Unable to read error message", response.message + assert_equal 'Unable to read error message', response.message end def test_transcript_scrubbing diff --git a/test/unit/gateways/flo2cash_test.rb b/test/unit/gateways/flo2cash_test.rb index ca01d04299f..4564114db64 100644 --- a/test/unit/gateways/flo2cash_test.rb +++ b/test/unit/gateways/flo2cash_test.rb @@ -18,14 +18,14 @@ def setup def test_successful_purchase response = stub_comms do - @gateway.purchase(@amount, @credit_card, order_id: "boom") + @gateway.purchase(@amount, @credit_card, order_id: 'boom') end.check_request do |endpoint, data, headers| assert_match(%r{<Reference>boom</Reference>}, data) end.respond_with(successful_authorize_response, successful_capture_response) assert_success response - assert_equal "P150100005006789", response.authorization + assert_equal 'P150100005006789', response.authorization assert response.test? end @@ -35,7 +35,7 @@ def test_failed_purchase end.respond_with(failed_authorize_response) assert_failure response - assert_equal "Transaction Declined - Bank Error", response.message + assert_equal 'Transaction Declined - Bank Error', response.message assert_equal Gateway::STANDARD_ERROR_CODE[:processing_error], response.responses.first.error_code assert response.test? end @@ -46,7 +46,7 @@ def test_successful_authorize_and_capture end.respond_with(successful_authorize_response) assert_success response - assert_equal "P150100005006789", response.authorization + assert_equal 'P150100005006789', response.authorization capture = stub_comms do @gateway.capture(@amount, response.authorization) @@ -63,7 +63,7 @@ def test_failed_authorize end.respond_with(failed_authorize_response) assert_failure response - assert_equal "Transaction Declined - Bank Error", response.message + assert_equal 'Transaction Declined - Bank Error', response.message assert_equal Gateway::STANDARD_ERROR_CODE[:processing_error], response.error_code assert response.test? end @@ -74,7 +74,7 @@ def test_successful_refund end.respond_with(successful_authorize_response, successful_capture_response) assert_success response - assert_equal "P150100005006789", response.authorization + assert_equal 'P150100005006789', response.authorization refund = stub_comms do @gateway.refund(@amount, response.authorization) @@ -91,7 +91,7 @@ def test_empty_response_fails end.respond_with(empty_purchase_response) assert_failure response - assert_equal "Unable to read error message", response.message + assert_equal 'Unable to read error message', response.message end def test_transcript_scrubbing diff --git a/test/unit/gateways/forte_test.rb b/test/unit/gateways/forte_test.rb index d3990377e13..c7ca564cc65 100644 --- a/test/unit/gateways/forte_test.rb +++ b/test/unit/gateways/forte_test.rb @@ -1,6 +1,8 @@ require 'test_helper' class ForteTest < Test::Unit::TestCase + include CommStub + def setup @gateway = ForteGateway.new(location_id: 'location_id', account_id: 'account_id', api_key: 'api_key', secret: 'secret') @credit_card = credit_card @@ -15,9 +17,9 @@ def setup end def test_successful_purchase - @gateway.expects(:handle_resp).returns(successful_purchase_response) - - response = @gateway.purchase(@amount, @credit_card, @options) + response = stub_comms(@gateway, :raw_ssl_request) do + @gateway.purchase(@amount, @credit_card, @options) + end.respond_with(MockedResponse.new(successful_purchase_response)) assert_success response assert_equal 'trn_bb7687a7-3d3a-40c2-8fa9-90727a814249#123456', response.authorization @@ -26,24 +28,25 @@ def test_successful_purchase def test_purchase_passes_options options = { order_id: '1' } - @gateway.expects(:commit).with(anything, has_entries(:order_number => '1')) - @gateway.purchase(@amount, @credit_card, options) + stub_comms(@gateway, :raw_ssl_request) do + @gateway.purchase(@amount, @credit_card, options) + end.respond_with(MockedResponse.new(successful_purchase_response)) end def test_failed_purchase - @gateway.expects(:handle_resp).returns(failed_purchase_response) - - response = @gateway.purchase(@amount, @credit_card, @options) + response = stub_comms(@gateway, :raw_ssl_request) do + @gateway.purchase(@amount, @credit_card, @options) + end.respond_with(MockedResponse.new(failed_purchase_response)) assert_failure response - assert_equal "INVALID TRN", response.message + assert_equal 'INVALID TRN', response.message end def test_successful_purchase_with_echeck - @gateway.expects(:handle_resp).returns(successful_echeck_purchase_response) - - response = @gateway.purchase(@amount, @check, @options) + response = stub_comms(@gateway, :raw_ssl_request) do + @gateway.purchase(@amount, @check, @options) + end.respond_with(MockedResponse.new(successful_echeck_purchase_response)) assert_success response assert_equal 'trn_bb7687a7-3d3a-40c2-8fa9-90727a814249#123456', response.authorization @@ -51,91 +54,115 @@ def test_successful_purchase_with_echeck end def test_failed_purchase_with_echeck - @gateway.expects(:handle_resp).returns(failed_echeck_purchase_response) - - response = @gateway.purchase(@amount, @credit_card, @options) + response = stub_comms(@gateway, :raw_ssl_request) do + @gateway.purchase(@amount, @credit_card, @options) + end.respond_with(MockedResponse.new(failed_echeck_purchase_response)) assert_failure response - assert_equal "INVALID CREDIT CARD NUMBER", response.message + assert_equal 'INVALID CREDIT CARD NUMBER', response.message end def test_successful_authorize - @gateway.expects(:handle_resp).returns(successful_authorize_response) - - response = @gateway.authorize(@amount, @credit_card, @options) + response = stub_comms(@gateway, :raw_ssl_request) do + @gateway.authorize(@amount, @credit_card, @options) + end.respond_with(MockedResponse.new(successful_authorize_response)) assert_success response end def test_failed_authorize - @gateway.expects(:handle_resp).returns(failed_authorize_response) - - response = @gateway.authorize(@amount, @credit_card, @options) + response = stub_comms(@gateway, :raw_ssl_request) do + @gateway.authorize(@amount, @credit_card, @options) + end.respond_with(MockedResponse.new(failed_authorize_response)) assert_failure response - assert_equal "INVALID CREDIT CARD NUMBER", response.message + assert_equal 'INVALID CREDIT CARD NUMBER', response.message end def test_successful_capture - @gateway.expects(:handle_resp).returns(successful_capture_response) - - response = @gateway.capture(@amount, "authcode") + response = stub_comms(@gateway, :raw_ssl_request) do + @gateway.capture(@amount, 'authcode') + end.respond_with(MockedResponse.new(successful_capture_response)) assert_success response end def test_failed_capture - @gateway.expects(:handle_resp).returns(failed_capture_response) - - response = @gateway.capture(@amount, "authcode") + response = stub_comms(@gateway, :raw_ssl_request) do + @gateway.capture(@amount, 'authcode') + end.respond_with(MockedResponse.new(failed_capture_response)) assert_failure response end def test_successful_credit - @gateway.expects(:handle_resp).returns(successful_credit_response) - - response = @gateway.credit(@amount, @credit_card, @options) + response = stub_comms(@gateway, :raw_ssl_request) do + @gateway.credit(@amount, @credit_card, @options) + end.respond_with(MockedResponse.new(successful_credit_response)) assert_success response end def test_failed_credit - @gateway.expects(:handle_resp).returns(failed_credit_response) - - response = @gateway.credit(@amount, @credit_card, @options) + response = stub_comms(@gateway, :raw_ssl_request) do + @gateway.credit(@amount, @credit_card, @options) + end.respond_with(MockedResponse.new(failed_credit_response)) assert_failure response end def test_successful_void - @gateway.expects(:handle_resp).returns(successful_credit_response) - - response = @gateway.void("authcode") + response = stub_comms(@gateway, :raw_ssl_request) do + @gateway.void('authcode') + end.respond_with(MockedResponse.new(successful_credit_response)) assert_success response end def test_failed_void - @gateway.expects(:handle_resp).returns(failed_credit_response) - - response = @gateway.void("authcode") + response = stub_comms(@gateway, :raw_ssl_request) do + @gateway.void('authcode') + end.respond_with(MockedResponse.new(failed_credit_response)) assert_failure response end def test_successful_verify - @gateway.expects(:handle_resp).times(2).returns(successful_authorize_response, successful_void_response) - - response = @gateway.verify(@credit_card, @options) + response = stub_comms(@gateway, :raw_ssl_request) do + @gateway.verify(@credit_card, @options) + end.respond_with(MockedResponse.new(successful_authorize_response), MockedResponse.new(successful_void_response)) assert_success response end def test_successful_verify_with_failed_void - @gateway.expects(:handle_resp).times(2).returns(successful_authorize_response, failed_void_response) - - response = @gateway.verify(@credit_card, @options) + response = stub_comms(@gateway, :raw_ssl_request) do + @gateway.verify(@credit_card, @options) + end.respond_with(MockedResponse.new(successful_authorize_response), MockedResponse.new(failed_void_response)) assert_success response end def test_failed_verify - @gateway.expects(:handle_resp).returns(failed_authorize_response) + response = stub_comms(@gateway, :raw_ssl_request) do + @gateway.verify(@credit_card, @options) + end.respond_with(MockedResponse.new(failed_authorize_response)) + assert_failure response + end - response = @gateway.verify(@credit_card, @options) + def test_successful_refund + response = stub_comms(@gateway, :raw_ssl_request) do + @gateway.refund(@amount, 'authcode') + end.respond_with(MockedResponse.new(successful_refund_response)) + assert_success response + end + + def test_failed_refund + response = stub_comms(@gateway, :raw_ssl_request) do + @gateway.refund(@amount, 'authcode') + end.respond_with(MockedResponse.new(failed_refund_response)) assert_failure response end + def test_handles_improper_padding + @gateway = ForteGateway.new(location_id: ' improperly-padded ', account_id: ' account_id ', api_key: 'api_key', secret: 'secret') + response = stub_comms(@gateway, :raw_ssl_request) do + @gateway.purchase(@amount, @credit_card, @options) + end.check_request do |type, url, parameters, headers| + URI.parse(url) + end.respond_with(MockedResponse.new(successful_purchase_response)) + assert_success response + end + def test_scrub assert @gateway.supports_scrubbing? assert_equal @gateway.scrub(pre_scrubbed), post_scrubbed @@ -143,6 +170,14 @@ def test_scrub private + class MockedResponse + attr :code, :body + def initialize(body, code = 200) + @code = code + @body = body + end + end + def pre_scrubbed %q( <- "POST /api/v2/accounts/act_300111/locations/loc_176008/transactions/ HTTP/1.1\r\nContent-Type: application/json\r\nAuthorization: Basic ZjA4N2E5MGYwMGYwYWU1NzA1MGM5MzdlZDM4MTVjOWY6ZDc5M2Q2NDA2NGUzMTEzYTc0ZmE3MjAzNWNmYzNhMWQ=\r\nX-Forte-Auth-Account-Id: act_300111\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nAccept: */*\r\nUser-Agent: Ruby\r\nConnection: close\r\nHost: sandbox.forte.net\r\nContent-Length: 471\r\n\r\n" @@ -158,7 +193,7 @@ def post_scrubbed end def successful_purchase_response - %q( + ' { "transaction_id":"trn_bb7687a7-3d3a-40c2-8fa9-90727a814249", "account_id":"act_300111", @@ -192,11 +227,11 @@ def successful_purchase_response "settlements":"https://sandbox.forte.net/API/v2/transactions/trn_bb7687a7-3d3a-40c2-8fa9-90727a814249/settlements" } } - ) + ' end def failed_purchase_response - %q( + ' { "transaction_id":"trn_e9ea64c4-5c2c-43dd-9138-f2661b59947c", "account_id":"act_300111", @@ -226,11 +261,11 @@ def failed_purchase_response "settlements":"https://sandbox.forte.net/API/v2/transactions/trn_e9ea64c4-5c2c-43dd-9138-f2661b59947c/settlements" } } - ) + ' end def successful_echeck_purchase_response - %q( + ' { "transaction_id":"trn_bb7687a7-3d3a-40c2-8fa9-90727a814249", "account_id":"act_300111", @@ -271,11 +306,11 @@ def successful_echeck_purchase_response "settlements":"https://sandbox.forte.net/API/v2/transactions/trn_bb7687a7-3d3a-40c2-8fa9-90727a814249/settlements" } } - ) + ' end def failed_echeck_purchase_response - %q( + ' { "transaction_id":"trn_bb7687a7-3d3a-40c2-8fa9-90727a814249", "account_id":"act_300111", @@ -313,11 +348,11 @@ def failed_echeck_purchase_response "settlements":"https://sandbox.forte.net/API/v2/transactions/trn_bb7687a7-3d3a-40c2-8fa9-90727a814249/settlements" } } - ) + ' end def successful_authorize_response - %q( + ' { "transaction_id":"trn_527fdc8a-d3d0-4680-badc-bfa784c63c13", "account_id":"act_300111", @@ -351,11 +386,11 @@ def successful_authorize_response "settlements":"https://sandbox.forte.net/API/v2/transactions/trn_527fdc8a-d3d0-4680-badc-bfa784c63c13/settlements" } } - ) + ' end def failed_authorize_response - %q( + ' { "transaction_id":"trn_7c045645-98b3-4c8a-88d6-e8d686884564", "account_id":"act_300111", @@ -385,11 +420,11 @@ def failed_authorize_response "settlements":"https://sandbox.forte.net/API/v2/transactions/trn_7c045645-98b3-4c8a-88d6-e8d686884564/settlements" } } - ) + ' end def successful_capture_response - %q( + ' { "transaction_id":"trn_94a04a97-c847-4420-820b-fb153a1f0f64", "account_id":"act_300111", @@ -409,11 +444,11 @@ def successful_capture_response "settlements":"https://sandbox.forte.net/API/v2/transactions/trn_94a04a97-c847-4420-820b-fb153a1f0f64/settlements" } } - ) + ' end def failed_capture_response - %q( + ' { "account_id":"act_300111", "location_id":"loc_176008", @@ -424,11 +459,11 @@ def failed_capture_response "response_desc":"The field transaction_id is required." } } - ) + ' end def successful_credit_response - %q( + ' { "transaction_id":"trn_357b284e-1dde-42ba-b0a5-5f66e08c7d9f", "account_id":"act_300111", @@ -462,11 +497,11 @@ def successful_credit_response "settlements":"https://sandbox.forte.net/API/v2/transactions/trn_357b284e-1dde-42ba-b0a5-5f66e08c7d9f/settlements" } } - ) + ' end def failed_credit_response - %q( + ' { "transaction_id":"trn_ce70ce9a-6265-4892-9a83-5825cb869ed5", "account_id":"act_300111", @@ -488,11 +523,11 @@ def failed_credit_response "settlements":"https://sandbox.forte.net/API/v2/transactions/trn_ce70ce9a-6265-4892-9a83-5825cb869ed5/settlements" } } - ) + ' end def successful_void_response - %q( + ' { "transaction_id":"trn_6c9d049e-1971-45fb-a4da-a0c35c4ed274", "account_id":"act_300111", @@ -511,11 +546,11 @@ def successful_void_response "settlements":"https://sandbox.forte.net/API/v2/transactions/trn_6c9d049e-1971-45fb-a4da-a0c35c4ed274/settlements" } } - ) + ' end def failed_void_response - %q( + ' { "account_id":"act_300111", "location_id":"loc_176008", @@ -526,6 +561,56 @@ def failed_void_response "response_desc":"The field transaction_id is required." } } - ) + ' + end + + def successful_refund_response + <<-SUCCESS + { + "transaction_id": "trn_6ad08872-a8c9-44a9-baca-670c31de98a1", + "location_id": "loc_176008", + "original_transaction_id": "trn_cf645bab-72cc-41d5-a9d2-376845333008", + "order_number": "1", + "action": "disburse", + "authorization_amount": 1, + "authorization_code": "123456", + "entered_by": "f087a90f00f0ae57050c937ed3815c9f", + "billing_address": { + "first_name": "Jim", + "last_name": "Smith", + "physical_address": { + "street_line1": "456 My Street", + "street_line2": "Apt 1", + "locality": "Ottawa", + "region": "ON", + "postal_code": "K1C2N6" + } + }, + "response": { + "environment": "sandbox", + "response_type": "A", + "response_code": "A01", + "response_desc": "TEST APPROVAL", + "authorization_code": "123456", + "avs_result": "Y", + "cvv_code": "M" + } + } + SUCCESS + end + + def failed_refund_response + <<-FAILED + { + "location_id": "loc_176008", + "action": "reverse", + "authorization_amount": 1, + "entered_by": "f087a90f00f0ae57050c937ed3815c9f", + "response": { + "environment": "sandbox", + "response_desc": "Error[1]: The field authorization_code is required when performing a reverse action. Error[2]: The field original_transaction_id is required when performing a reverse action." + } + } + FAILED end end diff --git a/test/unit/gateways/garanti_test.rb b/test/unit/gateways/garanti_test.rb index cd1ecf19482..46e7ce79e87 100644 --- a/test/unit/gateways/garanti_test.rb +++ b/test/unit/gateways/garanti_test.rb @@ -5,16 +5,12 @@ class GarantiTest < Test::Unit::TestCase def setup @original_kcode = nil - if RUBY_VERSION < '1.9' && $KCODE == "NONE" - @original_kcode = $KCODE - $KCODE = 'u' - end Base.mode = :test @gateway = GarantiGateway.new(:login => 'a', :password => 'b', :terminal_id => 'c', :merchant_id => 'd') @credit_card = credit_card(4242424242424242) - @amount = 1000 #1000 cents, 10$ + @amount = 1000 # 1000 cents, 10$ @options = { :order_id => 'db4af18c5222503d845180350fbda516', @@ -51,12 +47,9 @@ def test_character_normalization if ActiveSupport::Inflector.method(:transliterate).arity == -2 assert_equal 'ABCCDEFGGHIIJKLMNOOPRSSTUUVYZ', @gateway.send(:normalize, 'ABCÇDEFGĞHIİJKLMNOÖPRSŞTUÜVYZ') assert_equal 'abccdefgghiijklmnooprsstuuvyz', @gateway.send(:normalize, 'abcçdefgğhıijklmnoöprsştuüvyz') - elsif RUBY_VERSION >= '1.9' + else assert_equal 'ABCDEFGHIJKLMNOPRSTUVYZ', @gateway.send(:normalize, 'ABCÇDEFGĞHIİJKLMNOÖPRSŞTUÜVYZ') assert_equal 'abcdefghijklmnoprstuvyz', @gateway.send(:normalize, 'abcçdefgğhıijklmnoöprsştuüvyz') - else - assert_equal 'ABCCDEFGGHIIJKLMNOOPRSSTUUVYZ', @gateway.send(:normalize, 'ABCÇDEFGĞHIİJKLMNOÖPRSŞTUÜVYZ') - assert_equal 'abccdefgghijklmnooprsstuuvyz', @gateway.send(:normalize, 'abcçdefgğhıijklmnoöprsştuüvyz') end end diff --git a/test/unit/gateways/gateway_test.rb b/test/unit/gateways/gateway_test.rb index e2554bf98c5..3372ee5de13 100644 --- a/test/unit/gateways/gateway_test.rb +++ b/test/unit/gateways/gateway_test.rb @@ -11,10 +11,10 @@ def teardown def test_should_detect_if_a_card_is_supported Gateway.supported_cardtypes = [:visa, :bogus] - assert [:visa, :bogus].all? { |supported_cardtype| Gateway.supports?(supported_cardtype) } + assert([:visa, :bogus].all? { |supported_cardtype| Gateway.supports?(supported_cardtype) }) Gateway.supported_cardtypes = [] - assert_false [:visa, :bogus].all? { |invalid_cardtype| Gateway.supports?(invalid_cardtype) } + assert_false([:visa, :bogus].all? { |invalid_cardtype| Gateway.supports?(invalid_cardtype) }) end def test_should_validate_supported_countries @@ -29,7 +29,7 @@ def test_should_validate_supported_countries assert_nothing_raised do Gateway.supported_countries = all_country_codes assert Gateway.supported_countries == all_country_codes, - "List of supported countries not properly set" + 'List of supported countries not properly set' end end @@ -46,26 +46,26 @@ def test_should_be_able_to_look_for_test_mode end def test_amount_style - assert_equal '10.34', @gateway.send(:amount, 1034) + assert_equal '10.34', @gateway.send(:amount, 1034) - assert_raise(ArgumentError) do - @gateway.send(:amount, '10.34') - end + assert_raise(ArgumentError) do + @gateway.send(:amount, '10.34') + end end def test_card_brand - credit_card = stub(:brand => "visa") - assert_equal "visa", Gateway.card_brand(credit_card) + credit_card = stub(:brand => 'visa') + assert_equal 'visa', Gateway.card_brand(credit_card) end def test_card_brand_using_type - credit_card = stub(:type => "String") - assert_equal "string", Gateway.card_brand(credit_card) + credit_card = stub(:type => 'String') + assert_equal 'string', Gateway.card_brand(credit_card) end def test_setting_application_id_outside_the_class_definition assert_equal SimpleTestGateway.application_id, SubclassGateway.application_id - SimpleTestGateway.application_id = "New Application ID" + SimpleTestGateway.application_id = 'New Application ID' assert_equal SimpleTestGateway.application_id, SubclassGateway.application_id end @@ -83,28 +83,39 @@ def test_localized_amount_should_not_modify_for_fractional_currencies def test_localized_amount_should_ignore_money_format_for_non_fractional_currencies Gateway.money_format = :dollars assert_equal '1', @gateway.send(:localized_amount, 100, 'JPY') - assert_equal '12', @gateway.send(:localized_amount, 1234, 'HUF') + assert_equal '12', @gateway.send(:localized_amount, 1234, 'ISK') Gateway.money_format = :cents assert_equal '1', @gateway.send(:localized_amount, 100, 'JPY') - assert_equal '12', @gateway.send(:localized_amount, 1234, 'HUF') + assert_equal '12', @gateway.send(:localized_amount, 1234, 'ISK') + end + + def test_localized_amount_returns_three_decimal_places_for_three_decimal_currencies + @gateway.currencies_with_three_decimal_places = %w(BHD KWD OMR RSD TND) + + Gateway.money_format = :dollars + assert_equal '0.100', @gateway.send(:localized_amount, 100, 'OMR') + assert_equal '1.234', @gateway.send(:localized_amount, 1234, 'BHD') + + Gateway.money_format = :cents + assert_equal '100', @gateway.send(:localized_amount, 100, 'OMR') + assert_equal '1234', @gateway.send(:localized_amount, 1234, 'BHD') end def test_split_names - assert_equal ["Longbob", "Longsen"], @gateway.send(:split_names, "Longbob Longsen") + assert_equal ['Longbob', 'Longsen'], @gateway.send(:split_names, 'Longbob Longsen') end def test_split_names_with_single_name - assert_equal ["", "Prince"], @gateway.send(:split_names, "Prince") + assert_equal ['', 'Prince'], @gateway.send(:split_names, 'Prince') end def test_split_names_with_empty_names - assert_equal [nil, nil], @gateway.send(:split_names, "") + assert_equal [nil, nil], @gateway.send(:split_names, '') assert_equal [nil, nil], @gateway.send(:split_names, nil) - assert_equal [nil, nil], @gateway.send(:split_names, " ") + assert_equal [nil, nil], @gateway.send(:split_names, ' ') end - def test_supports_scrubbing? gateway = Gateway.new refute gateway.supports_scrubbing? @@ -115,7 +126,7 @@ def test_should_not_allow_scrubbing_if_unsupported refute gateway.supports_scrubbing? assert_raise(RuntimeError) do - gateway.scrub("hi") + gateway.scrub('hi') end end diff --git a/test/unit/gateways/global_collect_test.rb b/test/unit/gateways/global_collect_test.rb index 5fd92020abb..318f4ea8e38 100644 --- a/test/unit/gateways/global_collect_test.rb +++ b/test/unit/gateways/global_collect_test.rb @@ -4,9 +4,9 @@ class GlobalCollectTest < Test::Unit::TestCase include CommStub def setup - @gateway = GlobalCollectGateway.new(merchant_id: "1234", - api_key_id: "39u4193urng12", - secret_api_key: "109H/288H*50Y18W4/0G8571F245KA=") + @gateway = GlobalCollectGateway.new(merchant_id: '1234', + api_key_id: '39u4193urng12', + secret_api_key: '109H/288H*50Y18W4/0G8571F245KA=') @credit_card = credit_card('4567350000427977') @declined_card = credit_card('5424180279791732') @@ -24,7 +24,7 @@ def test_successful_authorize_and_capture end.respond_with(successful_authorize_response) assert_success response - assert_equal "000000142800000000920000100001", response.authorization + assert_equal '000000142800000000920000100001', response.authorization capture = stub_comms do @gateway.capture(@accepted_amount, response.authorization) @@ -41,22 +41,81 @@ def test_purchase_does_not_run_capture_if_authorize_auto_captured end.respond_with(successful_capture_response) assert_success response - assert_equal "CAPTURE_REQUESTED", response.params["payment"]["status"] + assert_equal 'CAPTURE_REQUESTED', response.params['payment']['status'] assert_equal 1, response.responses.size end + def test_authorize_with_pre_authorization_flag + response = stub_comms do + @gateway.authorize(@accepted_amount, @credit_card, @options.merge(pre_authorization: true)) + end.check_request do |endpoint, data, headers| + assert_match(/PRE_AUTHORIZATION/, data) + end.respond_with(successful_authorize_response) + + assert_success response + end + + def test_authorize_without_pre_authorization_flag + response = stub_comms do + @gateway.authorize(@accepted_amount, @credit_card, @options) + end.check_request do |endpoint, data, headers| + assert_match(/FINAL_AUTHORIZATION/, data) + end.respond_with(successful_authorize_response) + + assert_success response + end + + def test_successful_authorization_with_extra_options + options = @options.merge( + { + customer: '123987', + email: 'example@example.com', + order_id: '123', + ip: '127.0.0.1', + fraud_fields: + { + 'website' => 'www.example.com', + 'giftMessage' => 'Happy Day!' + } + } + ) + + response = stub_comms do + @gateway.authorize(@accepted_amount, @credit_card, options) + end.check_request do |endpoint, data, headers| + assert_match %r("fraudFields":{"website":"www.example.com","giftMessage":"Happy Day!","customerIpAddress":"127.0.0.1"}), data + assert_match %r("merchantReference":"123"), data + assert_match %r("customer":{"personalInformation":{"name":{"firstName":"Longbob","surname":"Longsen"}},"merchantCustomerId":"123987","contactDetails":{"emailAddress":"example@example.com","phoneNumber":"\(555\)555-5555"},"billingAddress":{"street":"456 My Street","additionalInfo":"Apt 1","zip":"K1C2N6","city":"Ottawa","state":"ON","countryCode":"CA"}}}), data + end.respond_with(successful_authorize_response) + + assert_success response + end + + def test_trucates_first_name_to_15_chars + credit_card = credit_card('4567350000427977', { first_name: 'thisisaverylongfirstname' }) + + response = stub_comms do + @gateway.authorize(@accepted_amount, credit_card, @options) + end.check_request do |endpoint, data, headers| + assert_match(/thisisaverylong/, data) + end.respond_with(successful_authorize_response) + + assert_success response + assert_equal '000000142800000000920000100001', response.authorization + end + def test_failed_authorize response = stub_comms do @gateway.authorize(@rejected_amount, @declined_card, @options) end.respond_with(failed_authorize_response) assert_failure response - assert_equal "Not authorised", response.message + assert_equal 'Not authorised', response.message end def test_failed_capture response = stub_comms do - @gateway.capture(100, "", @options) + @gateway.capture(100, '', @options) end.respond_with(failed_capture_response) assert_failure response @@ -68,7 +127,7 @@ def test_successful_void end.respond_with(successful_capture_response) assert_success response - assert_equal "000000142800000000920000100001", response.authorization + assert_equal '000000142800000000920000100001', response.authorization void = stub_comms do @gateway.void(response.authorization) @@ -81,7 +140,7 @@ def test_successful_void def test_failed_void response = stub_comms do - @gateway.void("5d53a33d960c46d00f5dc061947d998c") + @gateway.void('5d53a33d960c46d00f5dc061947d998c') end.check_request do |endpoint, data, headers| assert_match(/5d53a33d960c46d00f5dc061947d998c/, endpoint) end.respond_with(failed_void_response) @@ -93,7 +152,7 @@ def test_successful_verify response = stub_comms do @gateway.verify(@credit_card, @options) end.respond_with(successful_verify_response) - assert_equal "000000142800000000920000100001", response.authorization + assert_equal '000000142800000000920000100001', response.authorization assert_success response end @@ -102,7 +161,7 @@ def test_failed_verify response = stub_comms do @gateway.verify(@credit_card, @options) end.respond_with(failed_verify_response) - assert_equal "cee09c50-5d9d-41b8-b740-8c7bf06d2c66", response.authorization + assert_equal 'cee09c50-5d9d-41b8-b740-8c7bf06d2c66', response.authorization assert_failure response end @@ -112,7 +171,7 @@ def test_successful_refund @gateway.authorize(@accepted_amount, @credit_card, @options) end.respond_with(successful_authorize_response) - assert_equal "000000142800000000920000100001", response.authorization + assert_equal '000000142800000000920000100001', response.authorization capture = stub_comms do @gateway.capture(@accepted_amount, response.authorization) @@ -137,17 +196,44 @@ def test_refund_passes_currency_code def test_failed_refund response = stub_comms do - @gateway.refund(nil, "") + @gateway.refund(nil, '') end.respond_with(failed_refund_response) assert_failure response end + def test_rejected_refund + response = stub_comms do + @gateway.refund(@accepted_amount, '000000142800000000920000100001') + end.respond_with(rejected_refund_response) + + assert_failure response + assert_equal '1850', response.error_code + assert_equal 'Status: REJECTED', response.message + end + + def test_invalid_raw_response + response = stub_comms do + @gateway.purchase(@accepted_amount, @credit_card, @options) + end.respond_with(invalid_json_response) + + assert_failure response + assert_match %r{^Invalid response received from the Ingenico ePayments}, response.message + end + def test_scrub assert @gateway.supports_scrubbing? assert_equal @gateway.scrub(pre_scrubbed), post_scrubbed end + def test_scrub_invalid_response + response = stub_comms do + @gateway.purchase(@accepted_amount, @credit_card, @options) + end.respond_with(invalid_json_plus_card_data).message + + assert_equal @gateway.scrub(response), scrubbed_invalid_json_plus + end + private def pre_scrubbed @@ -286,6 +372,10 @@ def failed_refund_response %({\n \"errorId\" : \"1bd31e6a-39dd-4214-941a-088a320e0286\",\n \"errors\" : [ {\n \"code\" : \"1002\",\n \"propertyName\" : \"paymentId\",\n \"message\" : \"INVALID_PAYMENT_ID\"\n } ]\n}) end + def rejected_refund_response + %({\n \"id\" : \"00000022184000047564000-100001\",\n \"refundOutput\" : {\n \"amountOfMoney\" : {\n \"amount\" : 627000,\n \"currencyCode\" : \"COP\"\n },\n \"references\" : {\n \"merchantReference\" : \"17091GTgZmcC\",\n \"paymentReference\" : \"0\"\n },\n \"paymentMethod\" : \"card\",\n \"cardRefundMethodSpecificOutput\" : {\n }\n },\n \"status\" : \"REJECTED\",\n \"statusOutput\" : {\n \"isCancellable\" : false,\n \"statusCategory\" : \"UNSUCCESSFUL\",\n \"statusCode\" : 1850,\n \"statusCodeChangeDateTime\" : \"20170313230631\"\n }\n}) + end + def successful_void_response %({\n \"payment\" : {\n \"id\" : \"000000142800000000920000100001\",\n \"paymentOutput\" : {\n \"amountOfMoney\" : {\n \"amount\" : 100,\n \"currencyCode\" : \"USD\"\n },\n \"references\" : {\n \"paymentReference\" : \"0\"\n },\n \"paymentMethod\" : \"card\",\n \"cardPaymentMethodSpecificOutput\" : {\n \"paymentProductId\" : 1,\n \"authorisationCode\" : \"OK1131\",\n \"card\" : {\n \"cardNumber\" : \"************7977\",\n \"expiryDate\" : \"0917\"\n },\n \"fraudResults\" : {\n \"fraudServiceResult\" : \"no-advice\",\n \"avsResult\" : \"0\",\n \"cvvResult\" : \"0\"\n }\n }\n },\n \"status\" : \"CANCELLED\",\n \"statusOutput\" : {\n \"isCancellable\" : false,\n \"statusCode\" : 99999,\n \"statusCodeChangeDateTime\" : \"20160317191526\"\n }\n }\n}) end @@ -301,4 +391,44 @@ def successful_verify_response def failed_verify_response %({\n \"errorId\" : \"cee09c50-5d9d-41b8-b740-8c7bf06d2c66\",\n \"errors\" : [ {\n \"code\" : \"430330\",\n \"message\" : \"Not authorised\"\n } ],\n \"paymentResult\" : {\n \"creationOutput\" : {\n \"additionalReference\" : \"00000014280000000134\",\n \"externalReference\" : \"000000142800000000920000100001\"\n },\n \"payment\" : {\n \"id\" : \"000000142800000000920000100001\",\n \"paymentOutput\" : {\n \"amountOfMoney\" : {\n \"amount\" : 100,\n \"currencyCode\" : \"USD\"\n },\n \"references\" : {\n \"paymentReference\" : \"0\"\n },\n \"paymentMethod\" : \"card\",\n \"cardPaymentMethodSpecificOutput\" : {\n \"paymentProductId\" : 1\n }\n },\n \"status\" : \"REJECTED\",\n \"statusOutput\" : {\n \"errors\" : [ {\n \"code\" : \"430330\",\n \"requestId\" : \"64357\",\n \"message\" : \"Not authorised\"\n } ],\n \"isCancellable\" : false,\n \"statusCode\" : 100,\n \"statusCodeChangeDateTime\" : \"20160318170253\",\n \"isAuthorized\" : false\n }\n }\n }\n}) end + + def invalid_json_response + '<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN"> + <html><head> + <title>502 Proxy Error</title> + </head><body> + <h1>Proxy Error</h1> + <p>The proxy server received an invalid + response from an upstream server.<br /> + The proxy server could not handle the request <em><a href="/v1/9040/payments">POST&nbsp;/v1/9040/payments</a></em>.<p> + Reason: <strong>Error reading from remote server</strong></p></p> + </body></html>' + end + + def invalid_json_plus_card_data + %q(<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN"> + <html><head> + <title>502 Proxy Error</title> + </head></html> + opening connection to api-sandbox.globalcollect.com:443... + opened + starting SSL for api-sandbox.globalcollect.com:443... + SSL established + <- "POST //v1/1428/payments HTTP/1.1\r\nContent-Type: application/json\r\nAuthorization: GCS v1HMAC:96f16a41890565d0:Bqv5QtSXi+SdqXUyoBBeXUDlRvi5DzSm49zWuJTLX9s=\r\nDate: Tue, 15 Mar 2016 14:32:13 GMT\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nAccept: */*\r\nUser-Agent: Ruby\r\nConnection: close\r\nHost: api-sandbox.globalcollect.com\r\nContent-Length: 560\r\n\r\n" + <- "{\"order\":{\"amountOfMoney\":{\"amount\":\"100\",\"currencyCode\":\"USD\"},\"customer\":{\"merchantCustomerId\":null,\"personalInformation\":{\"name\":{\"firstName\":null,\"surname\":null}},\"billingAddress\":{\"street\":\"456 My Street\",\"additionalInfo\":\"Apt 1\",\"zip\":\"K1C2N6\",\"city\":\"Ottawa\",\"state\":\"ON\",\"countryCode\":\"CA\"}},\"contactDetails\":{\"emailAddress\":null}},\"cardPaymentMethodSpecificInput\":{\"paymentProductId\":\"1\",\"skipAuthentication\":\"true\",\"skipFraudService\":\"true\",\"card\":{\"cvv\":\"123\",\"cardNumber\":\"4567350000427977\",\"expiryDate\":\"0917\",\"cardholderName\":\"Longbob Longsen\"}}}" + -> "HTTP/1.1 201 Created\r\n" + -> "Date: Tue, 15 Mar 2016 18:32:14 GMT\r\n" + -> "Server: Apache/2.4.16 (Unix) OpenSSL/1.0.1p\r\n" + -> "Location: https://api-sandbox.globalcollect.com:443/v1/1428/payments/000000142800000000300000100001\r\n" + -> "X-Powered-By: Servlet/3.0 JSP/2.2\r\n" + -> "Connection: close\r\n" + -> "Transfer-Encoding: chunked\r\n" + -> "Content-Type: application/json\r\n" + -> "\r\n" + -> "457\r\n") + end + + def scrubbed_invalid_json_plus + 'Invalid response received from the Ingenico ePayments (formerly GlobalCollect) API. Please contact Ingenico ePayments if you continue to receive this message. (The raw response returned by the API was "<!DOCTYPE HTML PUBLIC \\"-//IETF//DTD HTML 2.0//EN\\">\\n <html><head>\\n <title>502 Proxy Error</title>\\n </head></html>\\n opening connection to api-sandbox.globalcollect.com:443...\\n opened\\n starting SSL for api-sandbox.globalcollect.com:443...\\n SSL established\\n <- \\"POST //v1/1428/payments HTTP/1.1\\\\r\\\\nContent-Type: application/json\\\\r\\\\nAuthorization: [FILTERED]\\\\r\\\\nDate: Tue, 15 Mar 2016 14:32:13 GMT\\\\r\\\\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\\\\r\\\\nAccept: */*\\\\r\\\\nUser-Agent: Ruby\\\\r\\\\nConnection: close\\\\r\\\\nHost: api-sandbox.globalcollect.com\\\\r\\\\nContent-Length: 560\\\\r\\\\n\\\\r\\\\n\\"\\n <- \\"{\\\\\\"order\\\\\\":{\\\\\\"amountOfMoney\\\\\\":{\\\\\\"amount\\\\\\":\\\\\\"100\\\\\\",\\\\\\"currencyCode\\\\\\":\\\\\\"USD\\\\\\"},\\\\\\"customer\\\\\\":{\\\\\\"merchantCustomerId\\\\\\":null,\\\\\\"personalInformation\\\\\\":{\\\\\\"name\\\\\\":{\\\\\\"firstName\\\\\\":null,\\\\\\"surname\\\\\\":null}},\\\\\\"billingAddress\\\\\\":{\\\\\\"street\\\\\\":\\\\\\"456 My Street\\\\\\",\\\\\\"additionalInfo\\\\\\":\\\\\\"Apt 1\\\\\\",\\\\\\"zip\\\\\\":\\\\\\"K1C2N6\\\\\\",\\\\\\"city\\\\\\":\\\\\\"Ottawa\\\\\\",\\\\\\"state\\\\\\":\\\\\\"ON\\\\\\",\\\\\\"countryCode\\\\\\":\\\\\\"CA\\\\\\"}},\\\\\\"contactDetails\\\\\\":{\\\\\\"emailAddress\\\\\\":null}},\\\\\\"cardPaymentMethodSpecificInput\\\\\\":{\\\\\\"paymentProductId\\\\\\":\\\\\\"1\\\\\\",\\\\\\"skipAuthentication\\\\\\":\\\\\\"true\\\\\\",\\\\\\"skipFraudService\\\\\\":\\\\\\"true\\\\\\",\\\\\\"card\\\\\\":{\\\\\\"cvv\\\\\\":\\\\\\"[FILTERED]\\\\\\",\\\\\\"cardNumber\\\\\\":\\\\\\"[FILTERED]\\\\\\",\\\\\\"expiryDate\\\\\\":\\\\\\"0917\\\\\\",\\\\\\"cardholderName\\\\\\":\\\\\\"Longbob Longsen\\\\\\"}}}\\"\\n -> \\"HTTP/1.1 201 Created\\\\r\\\\n\\"\\n -> \\"Date: Tue, 15 Mar 2016 18:32:14 GMT\\\\r\\\\n\\"\\n -> \\"Server: Apache/2.4.16 (Unix) OpenSSL/1.0.1p\\\\r\\\\n\\"\\n -> \\"Location: https://api-sandbox.globalcollect.com:443/v1/1428/payments/000000142800000000300000100001\\\\r\\\\n\\"\\n -> \\"X-Powered-By: Servlet/3.0 JSP/2.2\\\\r\\\\n\\"\\n -> \\"Connection: close\\\\r\\\\n\\"\\n -> \\"Transfer-Encoding: chunked\\\\r\\\\n\\"\\n -> \\"Content-Type: application/json\\\\r\\\\n\\"\\n -> \\"\\\\r\\\\n\\"\\n -> \\"457\\\\r\\\\n\\"")' + end end diff --git a/test/unit/gateways/global_transport_test.rb b/test/unit/gateways/global_transport_test.rb index a5956436d26..b64fd765323 100644 --- a/test/unit/gateways/global_transport_test.rb +++ b/test/unit/gateways/global_transport_test.rb @@ -5,7 +5,7 @@ class GlobalTransportTest < Test::Unit::TestCase def setup Base.mode = :test - @gateway = GlobalTransportGateway.new(global_user_name: 'login', global_password: 'password', term_type: "ABC") + @gateway = GlobalTransportGateway.new(global_user_name: 'login', global_password: 'password', term_type: 'ABC') @options = { order_id: '1', @@ -20,8 +20,8 @@ def test_successful_purchase assert_success response assert_equal '3648838', response.authorization assert response.test? - assert_equal "CVV matches", response.cvv_result["message"] - assert_equal "Street address and postal code do not match.", response.avs_result["message"] + assert_equal 'CVV matches', response.cvv_result['message'] + assert_equal 'Street address and postal code do not match.', response.avs_result['message'] end def test_failed_purchase @@ -31,13 +31,24 @@ def test_failed_purchase assert_failure response end + def test_successful_partial_purchase + @gateway.expects(:ssl_post).returns(successful_partial_purchase_response) + + response = @gateway.purchase(200, credit_card, @options) + assert_success response + assert_equal '8869188', response.authorization + assert_equal 'Partial Approval', response.message + assert_equal '3.54', response.params['balance_due'] + assert_equal '20.00', response.params['approved_amount'] + end + def test_successful_authorize_and_capture response = stub_comms do @gateway.authorize(100, credit_card) end.respond_with(successful_authorize_response) assert_success response - assert_equal "3648890", response.authorization + assert_equal '3648890', response.authorization capture = stub_comms do @gateway.capture(100, response.authorization) @@ -48,6 +59,24 @@ def test_successful_authorize_and_capture assert_success capture end + def test_successful_partial_authorize_and_capture + response = stub_comms do + @gateway.authorize(200, credit_card, @options) + end.respond_with(successful_partial_authorize_response) + + assert_success response + assert_equal '8869269', response.authorization + assert_equal 'Partial Approval', response.message + + capture = stub_comms do + @gateway.capture(150, response.authorization) + end.check_request do |endpoint, data, headers| + assert_match(/PNRef=8869269/, data) + end.respond_with(successful_partial_capture_response) + + assert_success capture + end + def test_failed_authorize @gateway.expects(:ssl_post).returns(failed_authorize_response) @@ -57,7 +86,7 @@ def test_failed_authorize def test_failed_capture capture = stub_comms do - @gateway.capture(100, "Authorization") + @gateway.capture(100, 'Authorization') end.respond_with(failed_capture_response) assert_failure capture @@ -70,7 +99,7 @@ def test_successful_refund end.respond_with(successful_purchase_response) assert_success response - assert_equal "3648838", response.authorization + assert_equal '3648838', response.authorization refund = stub_comms do @gateway.refund(100, response.authorization) @@ -83,7 +112,7 @@ def test_successful_refund def test_failed_refund refund = stub_comms do - @gateway.refund(100, "PurchaseAuth") + @gateway.refund(100, 'PurchaseAuth') end.respond_with(failed_refund_response) assert_failure refund @@ -107,11 +136,11 @@ def test_successful_void def test_failed_void void = stub_comms do - @gateway.void("PurchaseAuth") + @gateway.void('PurchaseAuth') end.respond_with(failed_void_response) assert_failure void - assert_equal "Invalid PNRef", void.message + assert_equal 'Invalid PNRef', void.message end def test_successful_verify @@ -132,14 +161,19 @@ def test_failed_verify def test_truncation stub_comms do - @gateway.purchase(100, credit_card, order_id: "a" * 17) + @gateway.purchase(100, credit_card, order_id: 'a' * 17) end.check_request do |endpoint, data, headers| assert_match(/&InvNum=a{16}&/, data) end.respond_with(successful_purchase_response) end + def test_transcript_scrubbing + assert @gateway.supports_scrubbing? + assert_equal @gateway.scrub(pre_scrub), post_scrub + end private + def successful_purchase_response %( <Response xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="GlobalPayments"> @@ -180,6 +214,66 @@ def failed_purchase_response ) end + def successful_partial_purchase_response + %( + <Response xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="GlobalPayments"> + <Result>200</Result> + <RespMSG>Partial Approval</RespMSG> + <Message>PARTIAL AP</Message> + <AuthCode>VI2000</AuthCode> + <PNRef>8869188</PNRef> + <HostCode>0004</HostCode> + <GetAVSResult>N</GetAVSResult> + <GetAVSResultTXT>No Match</GetAVSResultTXT> + <GetStreetMatchTXT>No Match</GetStreetMatchTXT> + <GetZipMatchTXT>No Match</GetZipMatchTXT> + <GetCVResult>M</GetCVResult> + <GetCVResultTXT>Match</GetCVResultTXT> + <GetCommercialCard>False</GetCommercialCard> + <ExtData>InvNum=1,CardType=Visa,BatchNum=0005&lt;BatchNum&gt;0005&lt;/BatchNum&gt;&lt;ReceiptData&gt;&lt;MID&gt;332518545311149&lt;/MID&gt;&lt;Trans_Id&gt;017198190587855&lt;/Trans_Id&gt;&lt;Val_Code&gt;AABC&lt;/Val_Code&gt;&lt;/ReceiptData&gt;&lt;ApprovedAmount&gt;20.00&lt;/ApprovedAmount&gt;&lt;BalanceDue&gt;3.54&lt;/BalanceDue&gt;</ExtData> + <AcqRefData>aWb017198190587855cAABCd5e10fJj470993170717112415k0057840C000000002354lA m000005</AcqRefData> + </Response> + ) + end + + def successful_partial_authorize_response + %( + <Response xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="GlobalPayments"> + <Result>200</Result> + <RespMSG>Partial Approval</RespMSG> + <Message>PARTIAL AP</Message> + <AuthCode>VI2000</AuthCode> + <PNRef>8869269</PNRef> + <GetAVSResult>N</GetAVSResult> + <GetAVSResultTXT>No Match</GetAVSResultTXT> + <GetStreetMatchTXT>No Match</GetStreetMatchTXT> + <GetZipMatchTXT>No Match</GetZipMatchTXT> + <GetCVResult>M</GetCVResult> + <GetCVResultTXT>Match</GetCVResultTXT> + <GetCommercialCard>False</GetCommercialCard> + <ExtData>InvNum=1,CardType=Visa&lt;ReceiptData&gt;&lt;MID&gt;332518545311149&lt;/MID&gt;&lt;Trans_Id&gt;017198190582649&lt;/Trans_Id&gt;&lt;Val_Code&gt;AABC&lt;/Val_Code&gt;&lt;/ReceiptData&gt;&lt;ApprovedAmount&gt;20.00&lt;/ApprovedAmount&gt;&lt;BalanceDue&gt;3.54&lt;/BalanceDue&gt;</ExtData> + <AcqRefData>aWb017198190582649cAABCd5e10fJj471048170717124409k0057840C000000002354lA m000005</AcqRefData> + </Response> + ) + end + + def successful_partial_capture_response + %( + <Response xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="GlobalPayments"> + <Result>0</Result> + <RespMSG>Approved</RespMSG> + <Message>AP</Message> + <AuthCode>VI2000</AuthCode> + <PNRef>8869275</PNRef> + <HostCode>0034</HostCode> + <GetCVResultTXT>Service Not Requested</GetCVResultTXT> + <GetCommercialCard>False</GetCommercialCard> + <ExtData>InvNum=1,CardType=Visa,BatchNum=0005&lt;ExtReceiptData&gt;&lt;AccountNumber&gt;************1111&lt;/AccountNumber&gt;&lt;Issuer&gt;Visa&lt;/Issuer&gt;&lt;Amount&gt;20.00&lt;/Amount&gt;&lt;AuthAmount&gt;20.00&lt;/AuthAmount&gt;&lt;TicketNumber&gt;1&lt;/TicketNumber&gt;&lt;EntryMode&gt;Manual CNP&lt;/EntryMode&gt;&lt;/ExtReceiptData&gt;&lt;BatchNum&gt;0005&lt;/BatchNum&gt;&lt;ReceiptData&gt;&lt;MID&gt;332518545311149&lt;/MID&gt;&lt;Trans_Id&gt;017198190583609&lt;/Trans_Id&gt;&lt;Val_Code&gt;AABC&lt;/Val_Code&gt;&lt;/ReceiptData&gt;</ExtData> + <AcqRefData>aWb017198190583609cAABCd5e10fJj471054170717130009lA m000005</AcqRefData> + </Response> + ) + end + def successful_authorize_response %( <Response xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="GlobalPayments"> @@ -321,4 +415,62 @@ def failed_verify_response </Response> ) end + + def pre_scrub + %q{ +opening connection to certapia.globalpay.com:443... +opened +starting SSL for certapia.globalpay.com:443... +SSL established +<- "POST /GlobalPay/transact.asmx/ProcessCreditCard HTTP/1.1\r\nContent-Type: application/x-www-form-urlencoded\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nAccept: */*\r\nUser-Agent: Ruby\r\nConnection: close\r\nHost: certapia.globalpay.com\r\nContent-Length: 253\r\n\r\n" +<- "CardNum=4003002345678903&ExpDate=0919&NameOnCard=Longbob+Longsen&Amount=&PNRef=&Zip=K1C2N6&Street=456+My+Street&CVNum=123&MagData=&InvNum=1&ExtData=%3CTermType%3E1BJ%3C%2FTermType%3E&GlobalUserName=spre930948&GlobalPassword=AoaeYX2n3Y7wfr&TransType=Sale" +-> "HTTP/1.1 200 OK\r\n" +-> "Date: Mon, 08 Jan 2018 16:00:33 GMT\r\n" +-> "Content-Type: text/xml; charset=utf-8\r\n" +-> "Content-Length: 559\r\n" +-> "Connection: close\r\n" +-> "Cache-Control: private, no-store, max-age=0\r\n" +-> "Pragma: no-cache\r\n" +-> "X-Frame-Options: SAMEORIGIN\r\n" +-> "Set-Cookie: ASP.NET_SessionId=tawdjune2xixlighniqxcvkm; path=/; HttpOnly\r\n" +-> "X-AspNet-Version: 4.0.30319\r\n" +-> "X-Powered-By: ASP.NET\r\n" +-> "Set-Cookie: TS012462a7=01cf83bd2f409aa8ee6c4cacb355788019f1a8ff3010306e6b8fe1c42e01745058ecc78aeff78d5071c2b7c56c186a470efd7c78f1; Path=/; Secure\r\n" +-> "Set-Cookie: TS012462a7_28=013b80ac89ca00c8b688533fc64e6f7b3fa3424b483ef82651a9f9a1c184ec131cc099732b39bf84f703f9f0754d2a12a53fe3d537; Path=/; Secure\r\n" +-> "\r\n" +reading 559 bytes... +-> "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<Response xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns=\"GlobalPayments\">\r\n <Result>12</Result>\r\n <RespMSG>Declined</RespMSG>\r\n <Message>INVLD AMOUNT</Message>\r\n <PNRef>9169188</PNRef>\r\n <GetCVResultTXT>Service Not Requested</GetCVResultTXT>\r\n <GetCommercialCard>False</GetCommercialCard>\r\n <ExtData>InvNum=1,CardType=Visa&lt;ReceiptData&gt;&lt;MID&gt;332518545311149&lt;/MID&gt;&lt;/ReceiptData&gt;</ExtData>\r\n <AcqRefData>aY</AcqRefData>\r\n</Response>" +read 559 bytes +Conn close + } + end + + def post_scrub + %q{ +opening connection to certapia.globalpay.com:443... +opened +starting SSL for certapia.globalpay.com:443... +SSL established +<- "POST /GlobalPay/transact.asmx/ProcessCreditCard HTTP/1.1\r\nContent-Type: application/x-www-form-urlencoded\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nAccept: */*\r\nUser-Agent: Ruby\r\nConnection: close\r\nHost: certapia.globalpay.com\r\nContent-Length: 253\r\n\r\n" +<- "CardNum=[FILTERED]&ExpDate=0919&NameOnCard=Longbob+Longsen&Amount=&PNRef=&Zip=K1C2N6&Street=456+My+Street&CVNum=[FILTERED]&MagData=&InvNum=1&ExtData=%3CTermType%3E1BJ%3C%2FTermType%3E&GlobalUserName=spre930948&GlobalPassword=[FILTERED]&TransType=Sale" +-> "HTTP/1.1 200 OK\r\n" +-> "Date: Mon, 08 Jan 2018 16:00:33 GMT\r\n" +-> "Content-Type: text/xml; charset=utf-8\r\n" +-> "Content-Length: 559\r\n" +-> "Connection: close\r\n" +-> "Cache-Control: private, no-store, max-age=0\r\n" +-> "Pragma: no-cache\r\n" +-> "X-Frame-Options: SAMEORIGIN\r\n" +-> "Set-Cookie: ASP.NET_SessionId=tawdjune2xixlighniqxcvkm; path=/; HttpOnly\r\n" +-> "X-AspNet-Version: 4.0.30319\r\n" +-> "X-Powered-By: ASP.NET\r\n" +-> "Set-Cookie: TS012462a7=01cf83bd2f409aa8ee6c4cacb355788019f1a8ff3010306e6b8fe1c42e01745058ecc78aeff78d5071c2b7c56c186a470efd7c78f1; Path=/; Secure\r\n" +-> "Set-Cookie: TS012462a7_28=013b80ac89ca00c8b688533fc64e6f7b3fa3424b483ef82651a9f9a1c184ec131cc099732b39bf84f703f9f0754d2a12a53fe3d537; Path=/; Secure\r\n" +-> "\r\n" +reading 559 bytes... +-> "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<Response xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns=\"GlobalPayments\">\r\n <Result>12</Result>\r\n <RespMSG>Declined</RespMSG>\r\n <Message>INVLD AMOUNT</Message>\r\n <PNRef>9169188</PNRef>\r\n <GetCVResultTXT>Service Not Requested</GetCVResultTXT>\r\n <GetCommercialCard>False</GetCommercialCard>\r\n <ExtData>InvNum=1,CardType=Visa&lt;ReceiptData&gt;&lt;MID&gt;332518545311149&lt;/MID&gt;&lt;/ReceiptData&gt;</ExtData>\r\n <AcqRefData>aY</AcqRefData>\r\n</Response>" +read 559 bytes +Conn close + } + end end diff --git a/test/unit/gateways/hdfc_test.rb b/test/unit/gateways/hdfc_test.rb index 9efff29568b..9913adedf19 100644 --- a/test/unit/gateways/hdfc_test.rb +++ b/test/unit/gateways/hdfc_test.rb @@ -22,7 +22,7 @@ def test_successful_purchase assert_success response - assert_equal "849768440022761|Longbob Longsen", response.authorization + assert_equal '849768440022761|Longbob Longsen', response.authorization assert response.test? end @@ -32,8 +32,8 @@ def test_failed_purchase end.respond_with(failed_purchase_response) assert_failure response - assert_equal "Invalid Brand.", response.message - assert_equal "GW00160", response.params["error_code_tag"] + assert_equal 'Invalid Brand.', response.message + assert_equal 'GW00160', response.params['error_code_tag'] assert response.test? end @@ -43,7 +43,7 @@ def test_authorize_and_capture end.respond_with(successful_authorize_response) assert_success response - assert_equal "2441955352022771|Longbob Longsen", response.authorization + assert_equal '2441955352022771|Longbob Longsen', response.authorization capture = stub_comms do @gateway.capture(@amount, response.authorization) @@ -60,7 +60,7 @@ def test_refund end.respond_with(successful_purchase_response) assert_success response - assert_equal "849768440022761|Longbob Longsen", response.authorization + assert_equal '849768440022761|Longbob Longsen', response.authorization refund = stub_comms do @gateway.refund(@amount, response.authorization) @@ -81,7 +81,7 @@ def test_passing_cvv def test_passing_currency stub_comms do - @gateway.purchase(@amount, @credit_card, :currency => "INR") + @gateway.purchase(@amount, @credit_card, :currency => 'INR') end.check_request do |endpoint, data, headers| assert_match(/currencycode>356</, data) end.respond_with(successful_purchase_response) @@ -89,13 +89,13 @@ def test_passing_currency def test_passing_invalid_currency assert_raise(ArgumentError, 'Unsupported currency for HDFC: AOA') do - @gateway.purchase(@amount, @credit_card, :currency => "AOA") + @gateway.purchase(@amount, @credit_card, :currency => 'AOA') end end def test_passing_order_id stub_comms do - @gateway.purchase(@amount, @credit_card, :order_id => "932823723") + @gateway.purchase(@amount, @credit_card, :order_id => '932823723') end.check_request do |endpoint, data, headers| assert_match(/932823723/, data) end.respond_with(successful_purchase_response) @@ -103,7 +103,7 @@ def test_passing_order_id def test_passing_description stub_comms do - @gateway.purchase(@amount, @credit_card, :description => "Awesome Services By Us") + @gateway.purchase(@amount, @credit_card, :description => 'Awesome Services By Us') end.check_request do |endpoint, data, headers| assert_match(/Awesome Services By Us/, data) end.respond_with(successful_purchase_response) @@ -111,7 +111,7 @@ def test_passing_description def test_escaping stub_comms do - @gateway.purchase(@amount, @credit_card, :order_id => "a" * 41, :description => "This has 'Hack Characters' ~`!\#$%^=+|\\:'\",;<>{}[]() and non-Hack Characters -_@.") + @gateway.purchase(@amount, @credit_card, :order_id => 'a' * 41, :description => "This has 'Hack Characters' ~`!\#$%^=+|\\:'\",;<>{}[]() and non-Hack Characters -_@.") end.check_request do |endpoint, data, headers| assert_match(/>This has Hack Characters and non-Hack Characters -_@.</, data) assert_match(/>#{"a" * 40}</, data) @@ -156,7 +156,7 @@ def test_empty_response_fails end.respond_with(empty_purchase_response) assert_failure response - assert_equal "Unable to read error message", response.message + assert_equal 'Unable to read error message', response.message end def test_handling_bad_xml @@ -178,8 +178,8 @@ def test_handling_bad_xml )) assert_success response - assert_equal "&", response.params["unescaped"] - assert_equal "&\"'<>", response.params["escaped"] + assert_equal '&', response.params['unescaped'] + assert_equal "&\"'<>", response.params['escaped'] end private diff --git a/test/unit/gateways/hps_test.rb b/test/unit/gateways/hps_test.rb index 3f964d51ec7..0f85bf5a2cb 100644 --- a/test/unit/gateways/hps_test.rb +++ b/test/unit/gateways/hps_test.rb @@ -90,7 +90,7 @@ def test_failed_capture def test_successful_refund @gateway.expects(:ssl_post).returns(successful_refund_response) - refund = @gateway.refund(@amount,'transaction_id') + refund = @gateway.refund(@amount, 'transaction_id') assert_instance_of Response, refund assert_success refund assert_equal '0', refund.params['GatewayRspCode'] @@ -99,7 +99,7 @@ def test_successful_refund def test_failed_refund @gateway.expects(:ssl_post).returns(failed_refund_response) - refund = @gateway.refund(@amount,'169054') + refund = @gateway.refund(@amount, '169054') assert_instance_of Response, refund assert_failure refund end @@ -124,7 +124,7 @@ def test_successful_purchase_with_swipe_no_encryption @gateway.expects(:ssl_post).returns(successful_swipe_purchase_response) @credit_card.track_data = '%B547888879888877776?;5473500000000014=25121019999888877776?' - response = @gateway.purchase(@amount,@credit_card,@options) + response = @gateway.purchase(@amount, @credit_card, @options) assert_success response assert_equal 'Success', response.message end @@ -133,7 +133,7 @@ def test_failed_purchase_with_swipe_bad_track_data @gateway.expects(:ssl_post).returns(failed_swipe_purchase_response) @credit_card.track_data = '%B547888879888877776?;?' - response = @gateway.purchase(@amount,@credit_card,@options) + response = @gateway.purchase(@amount, @credit_card, @options) assert_failure response assert_equal 'Transaction was rejected because the track data could not be read.', response.message @@ -142,9 +142,9 @@ def test_failed_purchase_with_swipe_bad_track_data def test_successful_purchase_with_swipe_encryption_type_01 @gateway.expects(:ssl_post).returns(successful_swipe_purchase_response) - @options[:encryption_type] = "01" - @credit_card.track_data = "&lt;E1052711%B5473501000000014^MC TEST CARD^251200000000000000000000000000000000?|GVEY/MKaKXuqqjKRRueIdCHPPoj1gMccgNOtHC41ymz7bIvyJJVdD3LW8BbwvwoenI+|+++++++C4cI2zjMp|11;5473501000000014=25120000000000000000?|8XqYkQGMdGeiIsgM0pzdCbEGUDP|+++++++C4cI2zjMp|00|||/wECAQECAoFGAgEH2wYcShV78RZwb3NAc2VjdXJlZXhjaGFuZ2UubmV0PX50qfj4dt0lu9oFBESQQNkpoxEVpCW3ZKmoIV3T93zphPS3XKP4+DiVlM8VIOOmAuRrpzxNi0TN/DWXWSjUC8m/PI2dACGdl/hVJ/imfqIs68wYDnp8j0ZfgvM26MlnDbTVRrSx68Nzj2QAgpBCHcaBb/FZm9T7pfMr2Mlh2YcAt6gGG1i2bJgiEJn8IiSDX5M2ybzqRT86PCbKle/XCTwFFe1X|&gt;" - response = @gateway.purchase(@amount,@credit_card,@options) + @options[:encryption_type] = '01' + @credit_card.track_data = '&lt;E1052711%B5473501000000014^MC TEST CARD^251200000000000000000000000000000000?|GVEY/MKaKXuqqjKRRueIdCHPPoj1gMccgNOtHC41ymz7bIvyJJVdD3LW8BbwvwoenI+|+++++++C4cI2zjMp|11;5473501000000014=25120000000000000000?|8XqYkQGMdGeiIsgM0pzdCbEGUDP|+++++++C4cI2zjMp|00|||/wECAQECAoFGAgEH2wYcShV78RZwb3NAc2VjdXJlZXhjaGFuZ2UubmV0PX50qfj4dt0lu9oFBESQQNkpoxEVpCW3ZKmoIV3T93zphPS3XKP4+DiVlM8VIOOmAuRrpzxNi0TN/DWXWSjUC8m/PI2dACGdl/hVJ/imfqIs68wYDnp8j0ZfgvM26MlnDbTVRrSx68Nzj2QAgpBCHcaBb/FZm9T7pfMr2Mlh2YcAt6gGG1i2bJgiEJn8IiSDX5M2ybzqRT86PCbKle/XCTwFFe1X|&gt;' + response = @gateway.purchase(@amount, @credit_card, @options) assert_success response assert_equal 'Success', response.message @@ -157,7 +157,7 @@ def test_successful_purchase_with_swipe_encryption_type_02 @options[:encrypted_track_number] = 2 @options[:ktb] = '/wECAQECAoFGAgEH3QgVTDT6jRZwb3NAc2VjdXJlZXhjaGFuZ2UubmV0Nkt08KRSPigRYcr1HVgjRFEvtUBy+VcCKlOGA3871r3SOkqDvH2+30insdLHmhTLCc4sC2IhlobvWnutAfylKk2GLspH/pfEnVKPvBv0hBnF4413+QIRlAuGX6+qZjna2aMl0kIsjEY4N6qoVq2j5/e5I+41+a2pbm61blv2PEMAmyuCcAbN3/At/1kRZNwN6LSUg9VmJO83kOglWBe1CbdFtncq' @credit_card.track_data = '7SV2BK6ESQPrq01iig27E74SxMg' - response = @gateway.purchase(@amount,@credit_card,@options) + response = @gateway.purchase(@amount, @credit_card, @options) assert_success response assert_equal 'Success', response.message @@ -190,6 +190,11 @@ def test_test_returns_false assert_false @gateway.send(:test?) end + def test_transcript_scrubbing + assert @gateway.supports_scrubbing? + assert_equal @gateway.scrub(pre_scrub), post_scrub + end + private def successful_charge_response @@ -265,7 +270,7 @@ def failed_charge_response end def successful_authorize_response - <<-RESPONSE + <<-RESPONSE <?xml version="1.0" encoding="UTF-8"?> <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <soap:Body> @@ -604,4 +609,64 @@ def failed_verify_response RESPONSE end + def pre_scrub + %q{ +opening connection to posgateway.cert.secureexchange.net:443... +opened +starting SSL for posgateway.cert.secureexchange.net:443... +SSL established +<- "POST /Hps.Exchange.PosGateway/PosGatewayService.asmx?wsdl HTTP/1.1\r\nContent-Type: text/xml\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nAccept: */*\r\nUser-Agent: Ruby\r\nConnection: close\r\nHost: posgateway.cert.secureexchange.net\r\nContent-Length: 1295\r\n\r\n" +<- "<?xml version=\"1.0\" encoding=\"UTF-8\"?><SOAP:Envelope xmlns:SOAP=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:hps=\"http://Hps.Exchange.PosGateway\"><SOAP:Body><hps:PosRequest><hps:Ver1.0><hps:Header><hps:SecretAPIKey>skapi_cert_MYl2AQAowiQAbLp5JesGKh7QFkcizOP2jcX9BrEMqQ</hps:SecretAPIKey></hps:Header><hps:Transaction><hps:CreditSale><hps:Block1><hps:Amt>1.00</hps:Amt><hps:AllowDup>Y</hps:AllowDup><hps:CardHolderData><hps:CardHolderFirstName>Longbob</hps:CardHolderFirstName><hps:CardHolderLastName>Longsen</hps:CardHolderLastName><hps:CardHolderAddr>456 My Street</hps:CardHolderAddr><hps:CardHolderCity>Ottawa</hps:CardHolderCity><hps:CardHolderState>ON</hps:CardHolderState><hps:CardHolderZip>K1C2N6</hps:CardHolderZip></hps:CardHolderData><hps:AdditionalTxnFields><hps:Description>Store Purchase</hps:Description><hps:InvoiceNbr>1</hps:InvoiceNbr></hps:AdditionalTxnFields><hps:CardData><hps:ManualEntry><hps:CardNbr>4000100011112224</hps:CardNbr><hps:ExpMonth>9</hps:ExpMonth><hps:ExpYear>2019</hps:ExpYear><hps:CVV2>123</hps:CVV2><hps:CardPresent>N</hps:CardPresent><hps:ReaderPresent>N</hps:ReaderPresent></hps:ManualEntry><hps:TokenRequest>N</hps:TokenRequest></hps:CardData></hps:Block1></hps:CreditSale></hps:Transaction></hps:Ver1.0></hps:PosRequest></SOAP:Body></SOAP:Envelope>" +-> "HTTP/1.1 200 OK\r\n" +-> "Cache-Control: private, max-age=0\r\n" +-> "Content-Type: text/xml; charset=utf-8\r\n" +-> "Server: Microsoft-IIS/7.5\r\n" +-> "X-dynaTrace: PT=266421;PA=-1324159421;SP=Gateway Cert;PS=1926692524\r\n" +-> "dynaTrace: PT=266421;PA=-1324159421;SP=Gateway Cert;PS=1926692524\r\n" +-> "X-AspNet-Version: 4.0.30319\r\n" +-> "X-Powered-By: ASP.NET\r\n" +-> "X-Frame-Options: DENY\r\n" +-> "X-Content-Type-Options: nosniff\r\n" +-> "Date: Mon, 08 Jan 2018 16:28:18 GMT\r\n" +-> "Connection: close\r\n" +-> "Content-Length: 1067\r\n" +-> "\r\n" +reading 1067 bytes... +-> "<?xml version=\"1.0\" encoding=\"utf-8\"?><soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"><soap:Body><PosResponse rootUrl=\"https://posgateway.cert.secureexchange.net/Hps.Exchange.PosGateway\" xmlns=\"http://Hps.Exchange.PosGateway\"><Ver1.0><Header><LicenseId>95878</LicenseId><SiteId>95881</SiteId><DeviceId>2409000</DeviceId><GatewayTxnId>1035967766</GatewayTxnId><GatewayRspCode>0</GatewayRspCode><GatewayRspMsg>Success</GatewayRspMsg><RspDT>2018-01-08T10:28:18.5555936</RspDT></Header><Transaction><CreditSale><RspCode>00</RspCode><RspText>APPROVAL</RspText><AuthCode>64349A</AuthCode><AVSRsltCode>0</AVSRsltCode><CVVRsltCode>M</CVVRsltCode><RefNbr>800818231451</RefNbr><AVSResultCodeActi" +-> "on>ACCEPT</AVSResultCodeAction><CVVResultCodeAction>ACCEPT</CVVResultCodeAction><CardType>Visa</CardType><AVSRsltText>AVS Not Requested.</AVSRsltText><CVVRsltText>Match.</CVVRsltText></CreditSale></Transaction></Ver1.0></PosResponse></soap:Body></soap:Envelope>" +read 1067 bytes +Conn close + } + end + + def post_scrub + %q{ +opening connection to posgateway.cert.secureexchange.net:443... +opened +starting SSL for posgateway.cert.secureexchange.net:443... +SSL established +<- "POST /Hps.Exchange.PosGateway/PosGatewayService.asmx?wsdl HTTP/1.1\r\nContent-Type: text/xml\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nAccept: */*\r\nUser-Agent: Ruby\r\nConnection: close\r\nHost: posgateway.cert.secureexchange.net\r\nContent-Length: 1295\r\n\r\n" +<- "<?xml version=\"1.0\" encoding=\"UTF-8\"?><SOAP:Envelope xmlns:SOAP=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:hps=\"http://Hps.Exchange.PosGateway\"><SOAP:Body><hps:PosRequest><hps:Ver1.0><hps:Header><hps:SecretAPIKey>[FILTERED]</hps:SecretAPIKey></hps:Header><hps:Transaction><hps:CreditSale><hps:Block1><hps:Amt>1.00</hps:Amt><hps:AllowDup>Y</hps:AllowDup><hps:CardHolderData><hps:CardHolderFirstName>Longbob</hps:CardHolderFirstName><hps:CardHolderLastName>Longsen</hps:CardHolderLastName><hps:CardHolderAddr>456 My Street</hps:CardHolderAddr><hps:CardHolderCity>Ottawa</hps:CardHolderCity><hps:CardHolderState>ON</hps:CardHolderState><hps:CardHolderZip>K1C2N6</hps:CardHolderZip></hps:CardHolderData><hps:AdditionalTxnFields><hps:Description>Store Purchase</hps:Description><hps:InvoiceNbr>1</hps:InvoiceNbr></hps:AdditionalTxnFields><hps:CardData><hps:ManualEntry><hps:CardNbr>[FILTERED]</hps:CardNbr><hps:ExpMonth>9</hps:ExpMonth><hps:ExpYear>2019</hps:ExpYear><hps:CVV2>[FILTERED]</hps:CVV2><hps:CardPresent>N</hps:CardPresent><hps:ReaderPresent>N</hps:ReaderPresent></hps:ManualEntry><hps:TokenRequest>N</hps:TokenRequest></hps:CardData></hps:Block1></hps:CreditSale></hps:Transaction></hps:Ver1.0></hps:PosRequest></SOAP:Body></SOAP:Envelope>" +-> "HTTP/1.1 200 OK\r\n" +-> "Cache-Control: private, max-age=0\r\n" +-> "Content-Type: text/xml; charset=utf-8\r\n" +-> "Server: Microsoft-IIS/7.5\r\n" +-> "X-dynaTrace: PT=266421;PA=-1324159421;SP=Gateway Cert;PS=1926692524\r\n" +-> "dynaTrace: PT=266421;PA=-1324159421;SP=Gateway Cert;PS=1926692524\r\n" +-> "X-AspNet-Version: 4.0.30319\r\n" +-> "X-Powered-By: ASP.NET\r\n" +-> "X-Frame-Options: DENY\r\n" +-> "X-Content-Type-Options: nosniff\r\n" +-> "Date: Mon, 08 Jan 2018 16:28:18 GMT\r\n" +-> "Connection: close\r\n" +-> "Content-Length: 1067\r\n" +-> "\r\n" +reading 1067 bytes... +-> "<?xml version=\"1.0\" encoding=\"utf-8\"?><soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"><soap:Body><PosResponse rootUrl=\"https://posgateway.cert.secureexchange.net/Hps.Exchange.PosGateway\" xmlns=\"http://Hps.Exchange.PosGateway\"><Ver1.0><Header><LicenseId>95878</LicenseId><SiteId>95881</SiteId><DeviceId>2409000</DeviceId><GatewayTxnId>1035967766</GatewayTxnId><GatewayRspCode>0</GatewayRspCode><GatewayRspMsg>Success</GatewayRspMsg><RspDT>2018-01-08T10:28:18.5555936</RspDT></Header><Transaction><CreditSale><RspCode>00</RspCode><RspText>APPROVAL</RspText><AuthCode>64349A</AuthCode><AVSRsltCode>0</AVSRsltCode><CVVRsltCode>M</CVVRsltCode><RefNbr>800818231451</RefNbr><AVSResultCodeActi" +-> "on>ACCEPT</AVSResultCodeAction><CVVResultCodeAction>ACCEPT</CVVResultCodeAction><CardType>Visa</CardType><AVSRsltText>AVS Not Requested.</AVSRsltText><CVVRsltText>Match.</CVVRsltText></CreditSale></Transaction></Ver1.0></PosResponse></soap:Body></soap:Envelope>" +read 1067 bytes +Conn close + } + end + end diff --git a/test/unit/gateways/iats_payments_test.rb b/test/unit/gateways/iats_payments_test.rb index d13475b1b75..ac94ec90912 100644 --- a/test/unit/gateways/iats_payments_test.rb +++ b/test/unit/gateways/iats_payments_test.rb @@ -119,7 +119,7 @@ def test_successful_refund def test_successful_check_refund response = stub_comms do - @gateway.refund(@amount, "ref|check", @options) + @gateway.refund(@amount, 'ref|check', @options) end.check_request do |endpoint, data, headers| assert_match(/<ProcessACHEFTRefundWithTransactionIdV1/, data) assert_match(/<agentCode>login<\/agentCode>/, data) @@ -140,7 +140,7 @@ def test_successful_check_refund def test_failed_check_refund response = stub_comms do - @gateway.refund(@amount, "ref|check", @options) + @gateway.refund(@amount, 'ref|check', @options) end.respond_with(failed_check_refund_response) assert response @@ -192,7 +192,7 @@ def test_failed_store def test_successful_unstore response = stub_comms do - @gateway.unstore("TheAuthorization", @options) + @gateway.unstore('TheAuthorization', @options) end.check_request do |endpoint, data, headers| assert_match(%r{<customerCode>TheAuthorization</customerCode>}, data) end.respond_with(successful_unstore_response) @@ -225,7 +225,7 @@ def test_region_urls @gateway = IatsPaymentsGateway.new( :agent_code => 'code', :password => 'password', - :region => 'na' #North america + :region => 'na' # North america ) response = stub_comms do @@ -243,6 +243,16 @@ def test_supported_countries end end + def test_failed_connection + response = stub_comms do + @gateway.purchase(@amount, @credit_card, @options) + end.respond_with(failed_connection_response) + + assert response + assert_failure response + assert_match(/Server Error/, response.message) + end + def test_scrub assert_equal @gateway.scrub(pre_scrub), post_scrub end @@ -513,6 +523,26 @@ def successful_unstore_response XML end + def failed_connection_response + <<-XML + <?xml version="1.0" encoding="UTF-8"?> + <soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> + <soap:Body> + <ProcessCreditCardV1Response xmlns="https://www.iatspayments.com/NetGate/"> + <ProcessCreditCardV1Result> + <IATSRESPONSE xmlns=""> + <STATUS>Failure</STATUS> + <ERRORS>Server Error</ERRORS> + <PROCESSRESULT> + </PROCESSRESULT> + </IATSRESPONSE> + </ProcessCreditCardV1Result> + </ProcessCreditCardV1Response> + </soap:Body> + </soap:Envelope> + XML + end + def pre_scrub <<-XML opening connection to www.iatspayments.com:443... diff --git a/test/unit/gateways/ideal_rabobank_test.rb b/test/unit/gateways/ideal_rabobank_test.rb deleted file mode 100644 index fe777decea0..00000000000 --- a/test/unit/gateways/ideal_rabobank_test.rb +++ /dev/null @@ -1,320 +0,0 @@ -# coding: UTF-8 - -require 'test_helper' - -class IdealRabobankTest < Test::Unit::TestCase - - DEFAULT_IDEAL_OPTIONS = { - :login => '123456789', - :pem => 'PEM', - :password => 'PASSWORD' - } - - def setup - @gateway = IdealRabobankGateway.new(DEFAULT_IDEAL_OPTIONS) - - # stub security methods, so we can run tests without PEM files - @stubbed_time_stamp = '2007-07-02T10:03:18.000Z' - @gateway.stubs(:create_fingerprint).returns('TOKEN') - @gateway.stubs(:sign_message).returns('TOKEN_CODE') - @gateway.stubs(:create_time_stamp).returns(@stubbed_time_stamp) - - @transaction_options = { - :issuer_id => '0001', - :expiration_period => 'PT10M', - :return_url => 'http://www.return.url', - :order_id => '1234567890123456', - :currency => 'EUR', - :description => 'A description', - :entrance_code => '1234' - } - end - - def test_build_transaction_request - request = @gateway.send(:build_transaction_request, 100, @transaction_options) - - xml_request = REXML::Document.new(request) - - assert_ideal_message xml_request, 'AcquirerTrxReq' - assert_merchant_elements xml_request - - assert_equal @transaction_options[:issuer_id], xml_request.root.elements['Issuer/issuerID'].text, 'Should map to an issuerID element.' - assert_equal @transaction_options[:return_url], xml_request.root.elements['Merchant/merchantReturnURL'].text, 'Should map to a merchantReturnURL element.' - assert_equal @transaction_options[:order_id], xml_request.root.elements['Transaction/purchaseID'].text, 'Should map to a purchaseID element.' - assert_equal '100', xml_request.root.elements['Transaction/amount'].text, 'Should map to an amount element.' - assert_equal @transaction_options[:currency], xml_request.root.elements['Transaction/currency'].text, 'Should map to a currency element.' - assert_equal @transaction_options[:expiration_period], xml_request.root.elements['Transaction/expirationPeriod'].text, 'Should map to an expirationPeriod element.' - assert_equal 'nl', xml_request.root.elements['Transaction/language'].text, 'Should map to a language element.' - assert_equal @transaction_options[:description], xml_request.root.elements['Transaction/description'].text, 'Should map to a description element.' - assert_equal @transaction_options[:entrance_code], xml_request.root.elements['Transaction/entranceCode'].text, 'Should map to an entranceCode element.' - end - - def test_build_status_request - request = @gateway.send(:build_status_request, :transaction_id => '1234') - xml_request = REXML::Document.new(request) - - assert_ideal_message xml_request, 'AcquirerStatusReq' - assert_merchant_elements xml_request - - assert_equal '1234', xml_request.root.elements['Transaction/transactionID'].text, 'Should map to a transactionID element.' - end - - def test_build_directory_request - request = @gateway.send(:build_directory_request) - xml_request = REXML::Document.new(request) - - assert_ideal_message xml_request, 'DirectoryReq' - assert_merchant_elements xml_request - end - - def assert_ideal_message xml_request, message_name - assert_equal '1.0', xml_request.version, "Should be version 1.0 of the xml specification" - assert_equal 'UTF-8', xml_request.encoding, "Should be UTF-8 encoding" - assert_equal 'http://www.idealdesk.com/Message', xml_request.root.namespace, "Should have a valid namespace" - assert_equal message_name, xml_request.root.name, "Root should match messagename" - assert_equal '1.1.0', xml_request.root.attribute('version', nil).value, "Should have a ideal version number" - assert_equal @stubbed_time_stamp, xml_request.root.elements['createDateTimeStamp'].text, 'Should have a time stamp.' - end - - def assert_merchant_elements xml_request - assert_equal DEFAULT_IDEAL_OPTIONS[:login], xml_request.root.elements['Merchant/merchantID'].text, 'Should map to an merchantID element.' - assert_equal '0', xml_request.root.elements['Merchant/subID'].text, 'Should map to an subID element.' - assert_equal 'SHA1_RSA', xml_request.root.elements['Merchant/authentication'].text, 'Should map to an authentication element.' - assert_equal 'TOKEN', xml_request.root.elements['Merchant/token'].text, 'Should map to a token element.' - assert_equal 'TOKEN_CODE', xml_request.root.elements['Merchant/tokenCode'].text, 'Should map to a tokenCode element.' - end - - # test incoming messages - - def test_setup_purchase_successful - @gateway.expects(:ssl_post).returns(successful_transaction_response) - response = @gateway.setup_purchase(100, @transaction_options) - assert_success response - transaction = response.transaction - assert_equal '0050000002797923', transaction['transactionID'], 'Should map to transaction_id' - assert_equal '9459897270157938', transaction['purchaseID'], 'Should map to purchase_id' - assert_equal '0050', response.params['AcquirerTrxRes']['Acquirer']['acquirerID'], 'Should map to acquirer_id' - assert_equal 'https://issuer.url/action?trxid=0050000002797923', response.service_url, "Response should have an issuer url" - end - - def test_error_response - @gateway.expects(:ssl_post).returns(failed_transaction_response) - response = @gateway.setup_purchase(100, @transaction_options) - assert_failure response - assert_equal 'ErrorRes', response.message, 'Should return error response' - error = response.error - assert_equal "BR1210", error['errorCode'], "Should return an error code" - assert_equal "Field generating error: Parameter \'25.99\' is not a natural(or \'-\') format", error['errorDetail'], "Should return an error detail" - assert_equal "Value contains non-permitted character", error['errorMessage'], "Should return an error message" - assert_equal "Betalen met iDEAL is nu niet mogelijk. Probeer het later nogmaals of betaal op een andere manier.", error['consumerMessage'], "Should return consumer message" - end - - def test_capture - @gateway.expects(:ssl_post).returns(successful_status_response) - @gateway.expects(:verify_message).returns(true) - - response = @gateway.capture('0050000002807474') - assert_success response - transaction = response.transaction - assert_equal '0050000002807474', transaction['transactionID'], 'Should map to transaction_id' - assert_equal 'C M Bröcker-Meijer en M Bröcker', transaction['consumerName'] - assert_equal 'P001234567', transaction['consumerAccountNumber'] - assert_equal 'DEN HAAG', transaction['consumerCity'] - assert_equal 'Success', transaction['status'], 'Should map to status' - end - - # make sure the gateway does not crash if issuer 'forgets' consumerAcountNumber - def test_capture_with_missing_account_number - @gateway.expects(:ssl_post).returns(successful_status_response_with_missing_fields) - @gateway.expects(:verify_message).returns(true) - - response = @gateway.capture('0050000002807474') - assert_success response - transaction = response.transaction - assert_equal '0050000002807474', transaction['transactionID'], 'Should map to transaction_id' - assert_nil transaction['consumerAccountNumber'] - assert_equal 'Success', transaction['status'], 'Should map to status' - end - - def test_payment_cancelled - @gateway.expects(:ssl_post).returns(cancelled_status_response) - @gateway.expects(:verify_message).returns(true) - - response = @gateway.capture('0050000002807474') - assert_failure response - transaction = response.transaction - assert_equal '0050000002807474', transaction['transactionID'], 'Should map to transaction_id' - assert_equal 'Cancelled', transaction['status'], 'Should map to status' - end - - def test_issuers_multiple - @gateway.expects(:ssl_post).returns(directory_request_response) - response = @gateway.issuers - assert_success response - list = response.issuer_list - assert_equal 4, list.size, "Should return multiple issuers" - assert_equal '0031', list[0]['issuerID'], "Should return an issuerID" - end - - def test_issuers_one_issuer - @gateway.expects(:ssl_post).returns(directory_request_response_one_issuer) - response = @gateway.issuers - assert_success response - list = response.issuer_list - assert_equal 1, list.size, "Should return one issuer" - assert_equal '0031', list[0]['issuerID'], "Should return an issuerID" - end - - def successful_transaction_response - <<-RESPONSE -<?xml version='1.0' encoding='UTF-8'?> -<AcquirerTrxRes version='1.1.0' xmlns='http://www.idealdesk.com/Message'> - <createDateTimeStamp>2007-07-02T10:03:18.000Z</createDateTimeStamp> - <Acquirer> - <acquirerID>0050</acquirerID> - </Acquirer> - <Issuer> - <issuerAuthenticationURL>https://issuer.url/action?trxid=0050000002797923</issuerAuthenticationURL> - </Issuer> - <Transaction> - <transactionID>0050000002797923</transactionID> - <purchaseID>9459897270157938</purchaseID> - </Transaction> -</AcquirerTrxRes> - RESPONSE - end - - def failed_transaction_response - <<-RESPONSE -<?xml version='1.0' encoding='UTF-8'?> - <ErrorRes version='1.1.0' xmlns='http://www.idealdesk.com/Message'> - <createDateTimeStamp>2007-07-02T10:03:18.000Z</createDateTimeStamp> - <Error> - <errorCode>BR1210</errorCode> - <errorMessage>Value contains non-permitted character</errorMessage> - <errorDetail>Field generating error: Parameter &apos;25.99&apos; is not a natural(or &apos;-&apos;) format</errorDetail> - <consumerMessage>Betalen met iDEAL is nu niet mogelijk. Probeer het later nogmaals of betaal op een andere manier.</consumerMessage> - </Error> -</ErrorRes> - RESPONSE - end - - def successful_status_response - <<-RESPONSE -?xml version='1.0' encoding='UTF-8'?> -<AcquirerStatusRes version='1.1.0' xmlns='http://www.idealdesk.com/Message'> - <createDateTimeStamp>2007-07-02T10:03:18.000Z</createDateTimeStamp> -<Acquirer> - <acquirerID>0050</acquirerID> -</Acquirer> -<Transaction> - <transactionID>0050000002807474</transactionID> - <status>Success</status> - <consumerName>C M Bröcker-Meijer en M Bröcker</consumerName> - <consumerAccountNumber>P001234567</consumerAccountNumber> - <consumerCity>DEN HAAG</consumerCity> -</Transaction> -<Signature> - <signatureValue>LONGSTRING</signatureValue> - <fingerprint>FINGERPRINT</fingerprint> -</Signature> -</AcquirerStatusRes> - RESPONSE - end - - def successful_status_response_with_missing_fields - <<-RESPONSE -?xml version='1.0' encoding='UTF-8'?> -<AcquirerStatusRes version='1.1.0' xmlns='http://www.idealdesk.com/Message'> - <createDateTimeStamp>2007-07-02T10:03:18.000Z</createDateTimeStamp> -<Acquirer> - <acquirerID>0050</acquirerID> -</Acquirer> -<Transaction> - <transactionID>0050000002807474</transactionID> - <status>Success</status> -</Transaction> -<Signature> - <signatureValue>LONGSTRING</signatureValue> - <fingerprint>FINGERPRINT</fingerprint> -</Signature> -</AcquirerStatusRes> - RESPONSE - end - - def cancelled_status_response - <<-RESPONSE -<?xml version='1.0' encoding='UTF-8'?> -<AcquirerStatusRes version='1.1.0' xmlns='http://www.idealdesk.com/Message'> - <createDateTimeStamp>2007-07-02T10:03:18.000Z</createDateTimeStamp> -<Acquirer> - <acquirerID>0050</acquirerID> -</Acquirer> -<Transaction> - <transactionID>0050000002807474</transactionID> - <status>Cancelled</status> -</Transaction> -<Signature> - <signatureValue>LONGSTRING</signatureValue> - <fingerprint>FINGERPRINT</fingerprint> -</Signature> -</AcquirerStatusRes> - RESPONSE - end - - def directory_request_response - <<-RESPONSE -<?xml version='1.0' encoding='UTF-8'?> -<DirectoryRes version='1.1.0' xmlns='http://www.idealdesk.com/Message'> -<createDateTimeStamp>2007-07-02T10:03:18.000Z</createDateTimeStamp> -<Acquirer> - <acquirerID>0050</acquirerID> -</Acquirer> -<Directory> - <directoryDateTimeStamp>2007-07-02T10:03:18.000Z</directoryDateTimeStamp> - <Issuer> - <issuerID>0031</issuerID> - <issuerName>ABN Amro Bank</issuerName> - <issuerList>Short</issuerList> - </Issuer> - <Issuer> - <issuerID>0721</issuerID> - <issuerName>Postbank</issuerName> - <issuerList>Short</issuerList> - </Issuer> - <Issuer> - <issuerID>0021</issuerID> - <issuerName>Rabobank</issuerName> - <issuerList>Short</issuerList> - </Issuer> - <Issuer> - <issuerID>0751</issuerID> - <issuerName>SNS Bank</issuerName> - <issuerList>Short</issuerList> - </Issuer> -</Directory> -</DirectoryRes> - RESPONSE - end - - def directory_request_response_one_issuer - <<-RESPONSE -<?xml version='1.0' encoding='UTF-8'?> -<DirectoryRes version='1.1.0' xmlns='http://www.idealdesk.com/Message'> -<createDateTimeStamp>2007-07-02T10:03:18.000Z</createDateTimeStamp> -<Acquirer> - <acquirerID>0050</acquirerID> -</Acquirer> -<Directory> - <directoryDateTimeStamp>2007-07-02T10:03:18.000Z</directoryDateTimeStamp> - <Issuer> - <issuerID>0031</issuerID> - <issuerName>ABN Amro Bank</issuerName> - <issuerList>Short</issuerList> - </Issuer> -</Directory> -</DirectoryRes> - RESPONSE - end - -end diff --git a/test/unit/gateways/in_context_paypal_express_test.rb b/test/unit/gateways/in_context_paypal_express_test.rb index 4760bf50e5b..4e92dc3032a 100644 --- a/test/unit/gateways/in_context_paypal_express_test.rb +++ b/test/unit/gateways/in_context_paypal_express_test.rb @@ -40,4 +40,3 @@ def test_test_redirect_url_without_review assert_equal TEST_REDIRECT_URL_WITHOUT_REVIEW, @gateway.redirect_url_for('1234567890', review: false) end end - diff --git a/test/unit/gateways/inspire_test.rb b/test/unit/gateways/inspire_test.rb index 6ce02c05717..b92b13ef34c 100644 --- a/test/unit/gateways/inspire_test.rb +++ b/test/unit/gateways/inspire_test.rb @@ -32,7 +32,7 @@ def test_failed_purchase def test_successful_refund response = stub_comms do - @gateway.refund(nil, "identifier") + @gateway.refund(nil, 'identifier') end.check_request do |_, data, _| assert_match %r{identifier}, data assert_no_match %r{amount}, data @@ -42,7 +42,7 @@ def test_successful_refund def test_partial_refund response = stub_comms do - @gateway.refund(100, "identifier") + @gateway.refund(100, 'identifier') end.check_request do |_, data, _| assert_match %r{identifier}, data assert_match %r{amount}, data @@ -52,7 +52,7 @@ def test_partial_refund def test_failed_refund response = stub_comms do - @gateway.refund(nil, "identifier") + @gateway.refund(nil, 'identifier') end.respond_with(failed_refund_response) assert_failure response end @@ -60,8 +60,8 @@ def test_failed_refund def test_add_address result = {} - @gateway.send(:add_address, result, nil, :billing_address => {:address1 => '164 Waverley Street', :country => 'US', :state => 'CO'} ) - assert_equal ["address1", "city", "company", "country", "phone", "state", "zip"], result.stringify_keys.keys.sort + @gateway.send(:add_address, result, nil, :billing_address => {:address1 => '164 Waverley Street', :country => 'US', :state => 'CO'}) + assert_equal ['address1', 'city', 'company', 'country', 'phone', 'state', 'zip'], result.stringify_keys.keys.sort assert_equal 'CO', result[:state] assert_equal '164 Waverley Street', result[:address1] assert_equal 'US', result[:country] @@ -79,15 +79,15 @@ def test_adding_store_adds_vault_id_flag result = {} @gateway.send(:add_creditcard, result, @credit_card, :store => true) - assert_equal ["ccexp", "ccnumber", "customer_vault", "cvv", "firstname", "lastname"], result.stringify_keys.keys.sort + assert_equal ['ccexp', 'ccnumber', 'customer_vault', 'cvv', 'firstname', 'lastname'], result.stringify_keys.keys.sort assert_equal 'add_customer', result[:customer_vault] end def test_blank_store_doesnt_add_vault_flag result = {} - @gateway.send(:add_creditcard, result, @credit_card, {} ) - assert_equal ["ccexp", "ccnumber", "cvv", "firstname", "lastname"], result.stringify_keys.keys.sort + @gateway.send(:add_creditcard, result, @credit_card, {}) + assert_equal ['ccexp', 'ccnumber', 'cvv', 'firstname', 'lastname'], result.stringify_keys.keys.sort assert_nil result[:customer_vault] end @@ -133,11 +133,10 @@ def failed_purchase_response end def successful_refund_response - "response=1&responsetext=SUCCESS&authcode=&transactionid=2594884528&avsresponse=&cvvresponse=&orderid=&type=refund&response_code=100" + 'response=1&responsetext=SUCCESS&authcode=&transactionid=2594884528&avsresponse=&cvvresponse=&orderid=&type=refund&response_code=100' end def failed_refund_response - "response=3&responsetext=Invalid Transaction ID specified REFID:3150951931&authcode=&transactionid=&avsresponse=&cvvresponse=&orderid=&type=refund&response_code=300" + 'response=3&responsetext=Invalid Transaction ID specified REFID:3150951931&authcode=&transactionid=&avsresponse=&cvvresponse=&orderid=&type=refund&response_code=300' end end - diff --git a/test/unit/gateways/instapay_test.rb b/test/unit/gateways/instapay_test.rb index 1e698357c52..d70c9c52f72 100644 --- a/test/unit/gateways/instapay_test.rb +++ b/test/unit/gateways/instapay_test.rb @@ -11,9 +11,9 @@ def test_successful_purchase @gateway.expects(:ssl_post).returns(successful_purchase_response) assert response = @gateway.purchase(@amount, @credit_card) - assert_instance_of Response, response + assert_instance_of Response, response assert_success response - assert_equal "118583850", response.authorization + assert_equal '118583850', response.authorization end def test_unsuccessful_purchase @@ -29,9 +29,9 @@ def test_successful_auth @gateway.expects(:ssl_post).returns(successful_purchase_response) assert response = @gateway.authorize(@amount, @credit_card) - assert_instance_of Response, response + assert_instance_of Response, response assert_success response - assert_equal "118583850", response.authorization + assert_equal '118583850', response.authorization end def test_unsuccessful_auth @@ -42,33 +42,33 @@ def test_unsuccessful_auth assert_failure response assert_nil response.authorization end - + def test_avs_result @gateway.expects(:ssl_post).returns(successful_purchase_response) - + response = @gateway.purchase(@amount, @credit_card) assert_equal 'X', response.avs_result['code'] end - + def test_cvv_result @gateway.expects(:ssl_post).returns(successful_purchase_response) - + response = @gateway.purchase(@amount, @credit_card) assert_equal 'M', response.cvv_result['code'] end - + def test_successful_capture @gateway.expects(:ssl_post).returns(successful_capture_response) - - response = @gateway.capture(100, "123456") + + response = @gateway.capture(100, '123456') assert_equal InstapayGateway::SUCCESS_MESSAGE, response.message end - + def test_failed_capture @gateway.expects(:ssl_post).returns(failed_capture_response) - - response = @gateway.capture(100, "123456") - assert_equal "Post amount exceeds Auth amount", response.message + + response = @gateway.capture(100, '123456') + assert_equal 'Post amount exceeds Auth amount', response.message end private @@ -82,7 +82,7 @@ def successful_purchase_response def failed_purchase_response "<html><body><plaintext>\r\nDeclined=DECLINED:0720930009:CVV2 MISMATCH:N7\r\nhistoryid=118583848\r\norderid=92886713\r\nACCOUNTNUMBER=************2220\r\nDeclined=DECLINED:0720930009:CVV2 MISMATCH:N7\r\nhistoryid=118583848\r\norderid=92886713\r\nrcode=0720930009\r\nReason=DECLINED:0720930009:CVV2 MISMATCH:N7\r\nrecurid=0\r\nresult=0\r\nStatus=Declined\r\ntransid=80410586\r\n" end - + def successful_auth_response "<html><body><plaintext>\r\nAccepted=AUTH:TEST:::118585994:::\r\nhistoryid=118585994\r\norderid=92888143\r\nAccepted=AUTH:TEST:::118585994:::\r\nACCOUNTNUMBER=************5454\r\nauthcode=TEST\r\nAuthNo=AUTH:TEST:::118585994:::\r\nhistoryid=118585994\r\norderid=92888143\r\nrecurid=0\r\nrefcode=118585994-TEST\r\nresult=1\r\nStatus=Accepted\r\ntransid=0\r\n" end @@ -90,13 +90,12 @@ def successful_auth_response def failed_auth_response "<html><body><plaintext>\r\nDeclined=DECLINED:0720930009:CVV2 MISMATCH:N7\r\nhistoryid=118585991\r\norderid=92888142\r\nACCOUNTNUMBER=************2220\r\nDeclined=DECLINED:0720930009:CVV2 MISMATCH:N7\r\nhistoryid=118585991\r\norderid=92888142\r\nrcode=0720930009\r\nReason=DECLINED:0720930009:CVV2 MISMATCH:N7\r\nrecurid=0\r\nresult=0\r\nStatus=Declined\r\ntransid=80412271\r\n" end - + def successful_capture_response "<html><body><plaintext>\r\nAccepted=AVSAUTH:TEST:::121609962::::DUPLICATE\r\nhistoryid=121609962\r\norderid=95009583\r\nAccepted=AVSAUTH:TEST:::121609962::::DUPLICATE\r\nACCOUNTNUMBER=************5454\r\nauthcode=TEST\r\nAuthNo=AVSAUTH:TEST:::121609962::::DUPLICATE\r\nDUPLICATE=1\r\nhistoryid=121609962\r\norderid=95009583\r\nrecurid=0\r\nrefcode=121609962-TEST\r\nresult=1\r\nStatus=Accepted\r\ntransid=0\r\n" end - + def failed_capture_response "<html><body><plaintext>\r\nDeclined=DECLINED:1101450002:Post amount exceeds Auth amount:\r\nhistoryid=\r\norderid=\r\nDeclined=DECLINED:1101450002:Post amount exceeds Auth amount:\r\nrcode=1101450002\r\nReason=DECLINED:1101450002:Post amount exceeds Auth amount:\r\nresult=0\r\nStatus=Declined\r\ntransid=0\r\n" end end - diff --git a/test/unit/gateways/ipp_test.rb b/test/unit/gateways/ipp_test.rb index 1c8add40662..40b8035b37b 100644 --- a/test/unit/gateways/ipp_test.rb +++ b/test/unit/gateways/ipp_test.rb @@ -6,7 +6,7 @@ class IppTest < Test::Unit::TestCase def setup @gateway = IppGateway.new( username: 'username', - password: 'password', + password: 'password' ) @amount = 100 @@ -31,7 +31,7 @@ def test_successful_purchase end.respond_with(successful_purchase_response) assert_success response - assert_equal "89435577", response.authorization + assert_equal '89435577', response.authorization end def test_failed_purchase @@ -40,9 +40,9 @@ def test_failed_purchase end.respond_with(failed_purchase_response) assert_failure response - assert_equal "Do Not Honour", response.message + assert_equal 'Do Not Honour', response.message assert_equal Gateway::STANDARD_ERROR_CODE[:card_declined], response.error_code - assert_equal "", response.authorization + assert_equal '', response.authorization end def test_successful_authorize @@ -55,12 +55,12 @@ def test_successful_authorize end.respond_with(successful_authorize_response) assert_success response - assert_equal "89435583", response.authorization + assert_equal '89435583', response.authorization end def test_successful_capture response = stub_comms do - @gateway.capture(@amount, "receipt") + @gateway.capture(@amount, 'receipt') end.check_request do |endpoint, data, headers| assert_match(%r{<SubmitSingleCapture }, data) assert_match(%r{<Receipt>receipt<}, data) @@ -72,7 +72,7 @@ def test_successful_capture def test_successful_refund response = stub_comms do - @gateway.refund(@amount, "receipt") + @gateway.refund(@amount, 'receipt') end.check_request do |endpoint, data, headers| assert_match(%r{<SubmitSingleRefund }, data) assert_match(%r{<Receipt>receipt<}, data) diff --git a/test/unit/gateways/iridium_test.rb b/test/unit/gateways/iridium_test.rb index 2c9baab308d..055afb50653 100644 --- a/test/unit/gateways/iridium_test.rb +++ b/test/unit/gateways/iridium_test.rb @@ -36,7 +36,6 @@ def test_unsuccessful_request assert response.test? end - def test_successful_authorize @gateway.expects(:ssl_post).returns(successful_authorize_response) @@ -50,7 +49,7 @@ def test_successful_authorize def test_successful_capture @gateway.expects(:ssl_post).returns(successful_capture_response) - assert response = @gateway.capture(1111, "1;100115172046327701460093;460093") + assert response = @gateway.capture(1111, '1;100115172046327701460093;460093') assert_success response assert_equal('100115172047506301812526', response.authorization) @@ -103,19 +102,17 @@ def test_do_not_depend_on_expiry_date_class def test_use_ducktyping_for_credit_card @gateway.expects(:ssl_post).returns(successful_purchase_response) - credit_card = stub(:number => '4242424242424242', :verification_value => '123', :name => "Hans Tester", :year => 2012, :month => 1) + credit_card = stub(:number => '4242424242424242', :verification_value => '123', :name => 'Hans Tester', :year => 2012, :month => 1) assert_nothing_raised do assert_success @gateway.purchase(@amount, credit_card, @options) end end - def test_transcript_scrubbing assert_equal post_scrubbed, @gateway.scrub(pre_scrubbed) end - private # Place raw successful response from gateway here diff --git a/test/unit/gateways/itransact_test.rb b/test/unit/gateways/itransact_test.rb index e1fe37ef8e3..5f43bfc702f 100644 --- a/test/unit/gateways/itransact_test.rb +++ b/test/unit/gateways/itransact_test.rb @@ -11,8 +11,8 @@ def setup @credit_card = credit_card @check = check @amount = 1014 # = $10.14 - - @options = { + + @options = { :email => 'name@domain.com', :order_id => '1', :billing_address => address, @@ -20,14 +20,14 @@ def setup :email_text => ['line1', 'line2', 'line3'] } end - + def test_successful_card_purchase @gateway.expects(:ssl_post).returns(successful_card_purchase_response) - + assert response = @gateway.purchase(@amount, @credit_card, @options) assert_instance_of Response, response assert_success response - + assert_equal '9999999999', response.authorization assert response.test? end @@ -45,19 +45,19 @@ def test_successful_check_purchase def test_unsuccessful_card_request @gateway.expects(:ssl_post).returns(failed_purchase_response) - + assert response = @gateway.purchase(@amount, @credit_card, @options) assert_failure response assert response.test? end private - + def successful_card_purchase_response "<?xml version=\"1.0\" standalone=\"yes\"?> <GatewayInterface><TransactionResponse><TransactionResult><Status>ok</Status><ErrorCategory></ErrorCategory><ErrorMessage></ErrorMessage><WarningMessage></WarningMessage><AuthCode></AuthCode><AVSCategory></AVSCategory><AVSResponse></AVSResponse><CVV2Response></CVV2Response><TimeStamp>20081216141214</TimeStamp><TestMode>TRUE</TestMode><Total>1.0</Total><XID>9999999999</XID><CustomerData><BillingAddress><Address1>1234 My Street</Address1><City>Ottawa</City><FirstName>Longbob</FirstName><LastName>Longsen</LastName><State>ON</State><Zip>K1C2N6</Zip><Country>CA</Country><Phone>(555)555-5555</Phone></BillingAddress><ShippingAddress><Address1></Address1><City></City><FirstName></FirstName><LastName></LastName><State></State><Zip></Zip><Country></Country><Phone></Phone></ShippingAddress></CustomerData></TransactionResult></TransactionResponse></GatewayInterface>" end - + def failed_purchase_response '<?xml version="1.0" standalone="yes"?> <GatewayInterface><TransactionResponse><TransactionResult><Status>FAILED</Status><ErrorCategory>REQUEST_FORMAT</ErrorCategory><ErrorMessage>Form does not contain xml parameter</ErrorMessage><AuthCode></AuthCode><AVSCategory></AVSCategory><AVSResponse></AVSResponse><CVV2Response></CVV2Response><TimeStamp></TimeStamp><TestMode></TestMode><Total></Total><XID></XID><CustomerData><BillingAddress><Address1 /><City></City><FirstName></FirstName><LastName></LastName><State></State><Zip></Zip><Country></Country><Phone></Phone></BillingAddress><ShippingAddress><Address1></Address1><City></City><FirstName></FirstName><LastName></LastName><State></State><Zip></Zip><Country></Country><Phone></Phone></ShippingAddress></CustomerData></TransactionResult></TransactionResponse></GatewayInterface>' diff --git a/test/unit/gateways/iveri_test.rb b/test/unit/gateways/iveri_test.rb new file mode 100644 index 00000000000..1269cd1ee53 --- /dev/null +++ b/test/unit/gateways/iveri_test.rb @@ -0,0 +1,553 @@ +require 'test_helper' + +class IveriTest < Test::Unit::TestCase + def setup + @gateway = IveriGateway.new(app_id: '123', cert_id: '321') + @credit_card = credit_card('4242424242424242') + @amount = 100 + + @options = { + order_id: generate_unique_id, + billing_address: address, + description: 'Store Purchase', + currency: 'ZAR' + } + end + + def test_successful_purchase + @gateway.expects(:ssl_post).returns(successful_purchase_response) + + response = @gateway.purchase(@amount, @credit_card, @options) + assert_success response + assert_equal '{F0568958-D10B-4093-A3BF-663168B06140}|{5CEF96FD-960E-4EA5-811F-D02CE6E36A96}|48b63446223ce91451fc3c1641a9ec03', response.authorization + assert response.test? + end + + def test_failed_purchase + @gateway.expects(:ssl_post).returns(failed_purchase_response) + + response = @gateway.purchase(@amount, @credit_card, @options) + assert_failure response + assert_equal '4', response.error_code + end + + def test_successful_authorize + @gateway.expects(:ssl_post).returns(successful_authorize_response) + + response = @gateway.authorize(@amount, @credit_card, @options) + assert_success response + assert_equal '{B90D7CDB-C8E8-4477-BDF2-695F28137874}|{EF0DC64E-2D00-4B6C-BDA0-2AD265391317}|23b4125c3b8e2777bffee52e196a863b', response.authorization + assert response.test? + end + + def test_failed_authorize + @gateway.expects(:ssl_post).returns(failed_authorize_response) + + response = @gateway.authorize(@amount, @credit_card, @options) + assert_failure response + assert_equal '4', response.error_code + end + + def test_successful_capture + @gateway.expects(:ssl_post).returns(successful_capture_response) + + response = @gateway.capture(@amount, '{B90D7CDB-C8E8-4477-BDF2-695F28137874}|{EF0DC64E-2D00-4B6C-BDA0-2AD265391317}|23b4125c3b8e2777bffee52e196a863b') + assert_success response + assert_equal '{7C91245F-607D-44AE-8958-C26E447BAEB7}|{EF0DC64E-2D00-4B6C-BDA0-2AD265391317}|23b4125c3b8e2777bffee52e196a863b', response.authorization + assert response.test? + end + + def test_failed_capture + @gateway.expects(:ssl_post).returns(failed_capture_response) + + response = @gateway.capture(@amount, '', @options) + assert_failure response + assert_equal '14', response.error_code + end + + def test_successful_refund + @gateway.expects(:ssl_post).returns(successful_refund_response) + + response = @gateway.refund(@amount, '{33C8274D-6811-409A-BF86-661F24084A2F}|{D50DB1B4-B6EC-4AF1-AFF7-71C2AA4A957B}|5be2c040bd46b7eebc70274659779acf') + assert_success response + assert_equal '{097C55B5-D020-40AD-8949-F9F5E4102F1D}|{D50DB1B4-B6EC-4AF1-AFF7-71C2AA4A957B}|5be2c040bd46b7eebc70274659779acf', response.authorization + assert response.test? + end + + def test_failed_refund + @gateway.expects(:ssl_post).returns(failed_refund_response) + + response = @gateway.refund(@amount, '', @options) + assert_failure response + assert_equal '255', response.error_code + end + + def test_successful_void + @gateway.expects(:ssl_post).returns(successful_void_response) + + response = @gateway.void('{230390C8-4A9E-4426-BDD3-15D072F135FE}|{3CC6E6A8-13E0-41A6-AB1E-71BE1AEEAE58}|1435f1a008137cd8508bf43751e07495') + assert_success response + assert_equal '{0A1A3FFF-C2A3-4B91-85FD-10D1C25B765B}||', response.authorization + assert response.test? + end + + def test_failed_void + @gateway.expects(:ssl_post).returns(failed_void_response) + + response = @gateway.void('', @options) + assert_failure response + assert_equal '255', response.error_code + end + + def test_successful_verify + @gateway.expects(:ssl_post).returns(successful_verify_response) + + response = @gateway.verify(@credit_card, @options) + assert_success response + assert_equal '{F4337D04-B526-4A7E-A400-2A6DEADDCF57}|{5D5F8BF7-2D9D-42C3-AF32-08C5E62CD45E}|c0006d1d739905afc9e70beaf4194ea3', response.authorization + assert response.test? + end + + def test_failed_verify + @gateway.expects(:ssl_post).returns(failed_verify_response) + + response = @gateway.verify(credit_card('2121212121212121'), @options) + assert_failure response + assert_equal '4', response.error_code + end + + def test_successful_verify_credentials + @gateway.expects(:ssl_post).returns(successful_verify_credentials_response) + assert @gateway.verify_credentials + end + + def test_failed_verify_credentials + @gateway.expects(:ssl_post).returns(failed_verify_credentials_response) + assert !@gateway.verify_credentials + end + + def test_scrub + assert @gateway.supports_scrubbing? + assert_equal @gateway.scrub(pre_scrubbed), post_scrubbed + end + + private + + def pre_scrubbed + %q( +opening connection to portal.nedsecure.co.za:443... +opened +starting SSL for portal.nedsecure.co.za:443... +SSL established +<- "POST /iVeriWebService/Service.asmx HTTP/1.1\r\nContent-Type: text/xml; charset=utf-8\r\nContent-Length: 1016\r\nSoapaction: http://iveri.com/Execute\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nAccept: */*\r\nUser-Agent: Ruby\r\nConnection: close\r\nHost: portal.nedsecure.co.za\r\n\r\n" +<- "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">\n <soap:Body>\n <Execute xmlns=\"http://iveri.com/\">\n <validateRequest>true</validateRequest>\n <protocol>V_XML</protocol>\n <protocolVersion>2.0</protocolVersion>\n <request>&lt;V_XML Version=\"2.0\" CertificateID=\"CB69E68D-C7E7-46B9-9B7A-025DCABAD6EF\" Direction=\"Request\"&gt;\n &lt;Transaction ApplicationID=\"D10A603D-4ADE-405B-93F1-826DFC0181E8\" Command=\"Debit\" Mode=\"Test\"&gt;\n &lt;Amount&gt;100&lt;/Amount&gt;\n &lt;Currency&gt;ZAR&lt;/Currency&gt;\n &lt;ExpiryDate&gt;092018&lt;/ExpiryDate&gt;\n &lt;MerchantReference&gt;b3ceea8b93d5611cbde7d162baef1245&lt;/MerchantReference&gt;\n &lt;CardSecurityCode&gt;123&lt;/CardSecurityCode&gt;\n &lt;PAN&gt;4242424242424242&lt;/PAN&gt;\n &lt;/Transaction&gt;\n&lt;/V_XML&gt;</request>\n </Execute>\n </soap:Body>\n</soap:Envelope>\n" +-> "HTTP/1.1 200 OK\r\n" +-> "Cache-Control: private, max-age=0\r\n" +-> "Content-Type: text/xml; charset=utf-8\r\n" +-> "Server: Microsoft-IIS/8.0\r\n" +-> "X-AspNet-Version: 4.0.30319\r\n" +-> "X-Powered-By: ASP.NET\r\n" +-> "Date: Wed, 12 Apr 2017 19:46:44 GMT\r\n" +-> "Connection: close\r\n" +-> "Content-Length: 2377\r\n" +-> "\r\n" +reading 2377 bytes... +-> "<?xml version=\"1.0\" encoding=\"utf-8\"?><soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"><soap:Body><ExecuteResponse xmlns=\"http://iveri.com/\"><ExecuteResult>&lt;V_XML Version=\"2.0\" Direction=\"Response\"&gt;\r\n &lt;Transaction ApplicationID=\"{D10A603D-4ADE-405B-93F1-826DFC0181E8}\" Command=\"Debit\" Mode=\"Test\" RequestID=\"{5485B5EA-2661-4436-BAA9-CD6DD546FA0D}\"&gt;\r\n &lt;Result Status=\"0\" AppServer=\"105IVERIAPPPR02\" DBServer=\"105iveridbpr01\" Gateway=\"Nedbank\" AcquirerCode=\"00\" /&gt;\r\n &lt;Amount&gt;100&lt;/Amount&gt;\r\n &lt;AuthorisationCode&gt;115205&lt;/AuthorisationCode&gt;\r\n &lt;Currency&gt;ZAR&lt;/Currency&gt;\r\n &lt;ExpiryDate&gt;092018&lt;/ExpiryDate&gt;\r\n &lt;MerchantReference&gt;b3ceea8b93d5611cbde7d162baef1245&lt;/MerchantReference&gt;\r\n &lt;Terminal&gt;Default&lt;/Terminal&gt;\r\n &lt;TransactionIndex&gt;{10418186-FE90-44F9-AB7A-FEC11C9027F8}&lt;/TransactionIndex&gt;\r\n &lt;MerchantName&gt;iVeri Payment Technology&lt;/MerchantName&gt;\r\n &lt;MerchantUSN&gt;7771777&lt;/MerchantUSN&gt;\r\n &lt;Acquirer&gt;NBPostilionBICISONBSouthAfrica&lt;/Acquirer&gt;\r\n &lt;AcquirerReference&gt;70412:04077382&lt;/AcquirerReference&gt;\r\n &lt;AcquirerDate&gt;20170412&lt;/AcquirerDate&gt;\r\n &lt;AcquirerTime&gt;214645&lt;/AcquirerTime&gt;\r\n &lt;DisplayAmount&gt;R 1.00&lt;/DisplayAmount&gt;\r\n &lt;BIN&gt;4&lt;/BIN&gt;\r\n &lt;Association&gt;VISA&lt;/Association&gt;\r\n &lt;CardType&gt;Unknown CardType&lt;/CardType&gt;\r\n &lt;Issuer&gt;Unknown&lt;/Issuer&gt;\r\n &lt;Jurisdiction&gt;International&lt;/Jurisdiction&gt;\r\n &lt;PANMode&gt;Keyed,CVV&lt;/PANMode&gt;\r\n &lt;ReconReference&gt;04077382&lt;/ReconReference&gt;\r\n &lt;CardHolderPresence&gt;CardNotPresent&lt;/CardHolderPresence&gt;\r\n &lt;MerchantAddress&gt;MERCHANT ADDRESS&lt;/MerchantAddress&gt;\r\n &lt;MerchantCity&gt;Sandton&lt;/MerchantCity&gt;\r\n &lt;MerchantCountryCode&gt;ZA&lt;/MerchantCountryCode&gt;\r\n &lt;MerchantCountry&gt;South Africa&lt;/MerchantCountry&gt;\r\n &lt;DistributorName&gt;Nedbank&lt;/DistributorName&gt;\r\n &lt;CCNumber&gt;4242........4242&lt;/CCNumber&gt;\r\n &lt;PAN&gt;[4242........4242]&lt;/PAN&gt;\r\n &lt;/Transaction&gt;\r\n&lt;/V_XML&gt;</ExecuteResult></ExecuteResponse></soap:Body></soap:Envelope>" +read 2377 bytes +Conn close +) + end + + def post_scrubbed + %q( +opening connection to portal.nedsecure.co.za:443... +opened +starting SSL for portal.nedsecure.co.za:443... +SSL established +<- "POST /iVeriWebService/Service.asmx HTTP/1.1\r\nContent-Type: text/xml; charset=utf-8\r\nContent-Length: 1016\r\nSoapaction: http://iveri.com/Execute\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nAccept: */*\r\nUser-Agent: Ruby\r\nConnection: close\r\nHost: portal.nedsecure.co.za\r\n\r\n" +<- "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">\n <soap:Body>\n <Execute xmlns=\"http://iveri.com/\">\n <validateRequest>true</validateRequest>\n <protocol>V_XML</protocol>\n <protocolVersion>2.0</protocolVersion>\n <request>&lt;V_XML Version=\"2.0\" CertificateID=\"[FILTERED]\" Direction=\"Request\"&gt;\n &lt;Transaction ApplicationID=\"D10A603D-4ADE-405B-93F1-826DFC0181E8\" Command=\"Debit\" Mode=\"Test\"&gt;\n &lt;Amount&gt;100&lt;/Amount&gt;\n &lt;Currency&gt;ZAR&lt;/Currency&gt;\n &lt;ExpiryDate&gt;092018&lt;/ExpiryDate&gt;\n &lt;MerchantReference&gt;b3ceea8b93d5611cbde7d162baef1245&lt;/MerchantReference&gt;\n &lt;CardSecurityCode&gt;[FILTERED]&lt;/CardSecurityCode&gt;\n &lt;PAN&gt;[FILTERED]&lt;/PAN&gt;\n &lt;/Transaction&gt;\n&lt;/V_XML&gt;</request>\n </Execute>\n </soap:Body>\n</soap:Envelope>\n" +-> "HTTP/1.1 200 OK\r\n" +-> "Cache-Control: private, max-age=0\r\n" +-> "Content-Type: text/xml; charset=utf-8\r\n" +-> "Server: Microsoft-IIS/8.0\r\n" +-> "X-AspNet-Version: 4.0.30319\r\n" +-> "X-Powered-By: ASP.NET\r\n" +-> "Date: Wed, 12 Apr 2017 19:46:44 GMT\r\n" +-> "Connection: close\r\n" +-> "Content-Length: 2377\r\n" +-> "\r\n" +reading 2377 bytes... +-> "<?xml version=\"1.0\" encoding=\"utf-8\"?><soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"><soap:Body><ExecuteResponse xmlns=\"http://iveri.com/\"><ExecuteResult>&lt;V_XML Version=\"2.0\" Direction=\"Response\"&gt;\r\n &lt;Transaction ApplicationID=\"{D10A603D-4ADE-405B-93F1-826DFC0181E8}\" Command=\"Debit\" Mode=\"Test\" RequestID=\"{5485B5EA-2661-4436-BAA9-CD6DD546FA0D}\"&gt;\r\n &lt;Result Status=\"0\" AppServer=\"105IVERIAPPPR02\" DBServer=\"105iveridbpr01\" Gateway=\"Nedbank\" AcquirerCode=\"00\" /&gt;\r\n &lt;Amount&gt;100&lt;/Amount&gt;\r\n &lt;AuthorisationCode&gt;115205&lt;/AuthorisationCode&gt;\r\n &lt;Currency&gt;ZAR&lt;/Currency&gt;\r\n &lt;ExpiryDate&gt;092018&lt;/ExpiryDate&gt;\r\n &lt;MerchantReference&gt;b3ceea8b93d5611cbde7d162baef1245&lt;/MerchantReference&gt;\r\n &lt;Terminal&gt;Default&lt;/Terminal&gt;\r\n &lt;TransactionIndex&gt;{10418186-FE90-44F9-AB7A-FEC11C9027F8}&lt;/TransactionIndex&gt;\r\n &lt;MerchantName&gt;iVeri Payment Technology&lt;/MerchantName&gt;\r\n &lt;MerchantUSN&gt;7771777&lt;/MerchantUSN&gt;\r\n &lt;Acquirer&gt;NBPostilionBICISONBSouthAfrica&lt;/Acquirer&gt;\r\n &lt;AcquirerReference&gt;70412:04077382&lt;/AcquirerReference&gt;\r\n &lt;AcquirerDate&gt;20170412&lt;/AcquirerDate&gt;\r\n &lt;AcquirerTime&gt;214645&lt;/AcquirerTime&gt;\r\n &lt;DisplayAmount&gt;R 1.00&lt;/DisplayAmount&gt;\r\n &lt;BIN&gt;4&lt;/BIN&gt;\r\n &lt;Association&gt;VISA&lt;/Association&gt;\r\n &lt;CardType&gt;Unknown CardType&lt;/CardType&gt;\r\n &lt;Issuer&gt;Unknown&lt;/Issuer&gt;\r\n &lt;Jurisdiction&gt;International&lt;/Jurisdiction&gt;\r\n &lt;PANMode&gt;Keyed,CVV&lt;/PANMode&gt;\r\n &lt;ReconReference&gt;04077382&lt;/ReconReference&gt;\r\n &lt;CardHolderPresence&gt;CardNotPresent&lt;/CardHolderPresence&gt;\r\n &lt;MerchantAddress&gt;MERCHANT ADDRESS&lt;/MerchantAddress&gt;\r\n &lt;MerchantCity&gt;Sandton&lt;/MerchantCity&gt;\r\n &lt;MerchantCountryCode&gt;ZA&lt;/MerchantCountryCode&gt;\r\n &lt;MerchantCountry&gt;South Africa&lt;/MerchantCountry&gt;\r\n &lt;DistributorName&gt;Nedbank&lt;/DistributorName&gt;\r\n &lt;CCNumber&gt;4242........4242&lt;/CCNumber&gt;\r\n &lt;PAN&gt;[FILTERED]&lt;/PAN&gt;\r\n &lt;/Transaction&gt;\r\n&lt;/V_XML&gt;</ExecuteResult></ExecuteResponse></soap:Body></soap:Envelope>" +read 2377 bytes +Conn close +) + end + + def successful_purchase_response + <<-XML +<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><soap:Body><ExecuteResponse xmlns="http://iveri.com/"><ExecuteResult>&lt;V_XML Version="2.0" Direction="Response"&gt; +&lt;Transaction ApplicationID="{D10A603D-4ADE-405B-93F1-826DFC0181E8}" Command="Debit" Mode="Test" RequestID="{F0568958-D10B-4093-A3BF-663168B06140}"&gt; + &lt;Result Status="0" AppServer="105IVERIAPPPR01" DBServer="105IVERIDBPR01" Gateway="Nedbank" AcquirerCode="00" /&gt; + &lt;Amount&gt;100&lt;/Amount&gt; + &lt;AuthorisationCode&gt;537473&lt;/AuthorisationCode&gt; + &lt;Currency&gt;ZAR&lt;/Currency&gt; + &lt;ExpiryDate&gt;092018&lt;/ExpiryDate&gt; + &lt;MerchantReference&gt;48b63446223ce91451fc3c1641a9ec03&lt;/MerchantReference&gt; + &lt;Terminal&gt;Default&lt;/Terminal&gt; + &lt;TransactionIndex&gt;{5CEF96FD-960E-4EA5-811F-D02CE6E36A96}&lt;/TransactionIndex&gt; + &lt;MerchantName&gt;iVeri Payment Technology&lt;/MerchantName&gt; + &lt;MerchantUSN&gt;7771777&lt;/MerchantUSN&gt; + &lt;Acquirer&gt;NBPostilionBICISONBSouthAfrica&lt;/Acquirer&gt; + &lt;AcquirerReference&gt;70417:04077982&lt;/AcquirerReference&gt; + &lt;AcquirerDate&gt;20170417&lt;/AcquirerDate&gt; + &lt;AcquirerTime&gt;190433&lt;/AcquirerTime&gt; + &lt;DisplayAmount&gt;R 1.00&lt;/DisplayAmount&gt; + &lt;BIN&gt;4&lt;/BIN&gt; + &lt;Association&gt;VISA&lt;/Association&gt; + &lt;CardType&gt;Unknown CardType&lt;/CardType&gt; + &lt;Issuer&gt;Unknown&lt;/Issuer&gt; + &lt;Jurisdiction&gt;International&lt;/Jurisdiction&gt; + &lt;PANMode&gt;Keyed,CVV&lt;/PANMode&gt; + &lt;ReconReference&gt;04077982&lt;/ReconReference&gt; + &lt;CardHolderPresence&gt;CardNotPresent&lt;/CardHolderPresence&gt; + &lt;MerchantAddress&gt;MERCHANT ADDRESS&lt;/MerchantAddress&gt; + &lt;MerchantCity&gt;Sandton&lt;/MerchantCity&gt; + &lt;MerchantCountryCode&gt;ZA&lt;/MerchantCountryCode&gt; + &lt;MerchantCountry&gt;South Africa&lt;/MerchantCountry&gt; + &lt;DistributorName&gt;Nedbank&lt;/DistributorName&gt; + &lt;CCNumber&gt;4242........4242&lt;/CCNumber&gt; + &lt;PAN&gt;4242........4242&lt;/PAN&gt; +&lt;/Transaction&gt; +&lt;/V_XML&gt;</ExecuteResult></ExecuteResponse></soap:Body></soap:Envelope> + XML + end + + def failed_purchase_response + <<-XML +<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><soap:Body><ExecuteResponse xmlns="http://iveri.com/"><ExecuteResult>&lt;V_XML Version="2.0" Direction="Response"&gt; + &lt;Transaction ApplicationID="{D10A603D-4ADE-405B-93F1-826DFC0181E8}" Command="Debit" Mode="Test" RequestID="{B14C3834-72B9-4ACA-B362-B3C9EC96E8C0}"&gt; + &lt;Result Status="-1" Code="4" Description="Denied" Source="NBPostilionBICISONBSouthAfrica" AppServer="105IVERIAPPPR01" DBServer="105IVERIDBPR01" Gateway="Nedbank" AcquirerCode="05" AcquirerDescription="Do not Honour" /&gt; + &lt;Amount&gt;100&lt;/Amount&gt; + &lt;Currency&gt;ZAR&lt;/Currency&gt; + &lt;ExpiryDate&gt;092018&lt;/ExpiryDate&gt; + &lt;MerchantReference&gt;435a5d60b5fe874840c34e2e0504626b&lt;/MerchantReference&gt; + &lt;Terminal&gt;Default&lt;/Terminal&gt; + &lt;TransactionIndex&gt;{B35872A9-39C7-4DB8-9774-A5E34FFA519E}&lt;/TransactionIndex&gt; + &lt;MerchantName&gt;iVeri Payment Technology&lt;/MerchantName&gt; + &lt;MerchantUSN&gt;7771777&lt;/MerchantUSN&gt; + &lt;Acquirer&gt;NBPostilionBICISONBSouthAfrica&lt;/Acquirer&gt; + &lt;AcquirerReference&gt;70417:04077988&lt;/AcquirerReference&gt; + &lt;AcquirerDate&gt;20170417&lt;/AcquirerDate&gt; + &lt;AcquirerTime&gt;192038&lt;/AcquirerTime&gt; + &lt;DisplayAmount&gt;R 1.00&lt;/DisplayAmount&gt; + &lt;BIN&gt;2&lt;/BIN&gt; + &lt;Association&gt;Unknown Association&lt;/Association&gt; + &lt;CardType&gt;Unknown CardType&lt;/CardType&gt; + &lt;Issuer&gt;Unknown&lt;/Issuer&gt; + &lt;Jurisdiction&gt;Local&lt;/Jurisdiction&gt; + &lt;PANMode&gt;Keyed,CVV&lt;/PANMode&gt; + &lt;ReconReference&gt;04077988&lt;/ReconReference&gt; + &lt;CardHolderPresence&gt;CardNotPresent&lt;/CardHolderPresence&gt; + &lt;MerchantAddress&gt;MERCHANT ADDRESS&lt;/MerchantAddress&gt; + &lt;MerchantCity&gt;Sandton&lt;/MerchantCity&gt; + &lt;MerchantCountryCode&gt;ZA&lt;/MerchantCountryCode&gt; + &lt;MerchantCountry&gt;South Africa&lt;/MerchantCountry&gt; + &lt;DistributorName&gt;Nedbank&lt;/DistributorName&gt; + &lt;CCNumber&gt;2121........2121&lt;/CCNumber&gt; + &lt;PAN&gt;2121........2121&lt;/PAN&gt; + &lt;/Transaction&gt; +&lt;/V_XML&gt;</ExecuteResult></ExecuteResponse></soap:Body></soap:Envelope> + XML + end + + def successful_authorize_response + <<-XML +<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><soap:Body><ExecuteResponse xmlns="http://iveri.com/"><ExecuteResult>&lt;V_XML Version="2.0" Direction="Response"&gt; + &lt;Transaction ApplicationID="{D10A603D-4ADE-405B-93F1-826DFC0181E8}" Command="Authorisation" Mode="Test" RequestID="{B90D7CDB-C8E8-4477-BDF2-695F28137874}"&gt; + &lt;Result Status="0" AppServer="105IVERIAPPPR01" DBServer="105IVERIDBPR01" Gateway="Nedbank" AcquirerCode="00" /&gt; + &lt;Amount&gt;100&lt;/Amount&gt; + &lt;AuthorisationCode&gt;541267&lt;/AuthorisationCode&gt; + &lt;Currency&gt;ZAR&lt;/Currency&gt; + &lt;ExpiryDate&gt;092018&lt;/ExpiryDate&gt; + &lt;MerchantReference&gt;23b4125c3b8e2777bffee52e196a863b&lt;/MerchantReference&gt; + &lt;Terminal&gt;Default&lt;/Terminal&gt; + &lt;TransactionIndex&gt;{EF0DC64E-2D00-4B6C-BDA0-2AD265391317}&lt;/TransactionIndex&gt; + &lt;MerchantName&gt;iVeri Payment Technology&lt;/MerchantName&gt; + &lt;MerchantUSN&gt;7771777&lt;/MerchantUSN&gt; + &lt;Acquirer&gt;NBPostilionBICISONBSouthAfrica&lt;/Acquirer&gt; + &lt;AcquirerReference&gt;70417:04078057&lt;/AcquirerReference&gt; + &lt;AcquirerDate&gt;20170417&lt;/AcquirerDate&gt; + &lt;AcquirerTime&gt;200747&lt;/AcquirerTime&gt; + &lt;DisplayAmount&gt;R 1.00&lt;/DisplayAmount&gt; + &lt;BIN&gt;4&lt;/BIN&gt; + &lt;Association&gt;VISA&lt;/Association&gt; + &lt;CardType&gt;Unknown CardType&lt;/CardType&gt; + &lt;Issuer&gt;Unknown&lt;/Issuer&gt; + &lt;Jurisdiction&gt;International&lt;/Jurisdiction&gt; + &lt;PANMode&gt;Keyed,CVV&lt;/PANMode&gt; + &lt;ReconReference&gt;04078057&lt;/ReconReference&gt; + &lt;CardHolderPresence&gt;CardNotPresent&lt;/CardHolderPresence&gt; + &lt;MerchantAddress&gt;MERCHANT ADDRESS&lt;/MerchantAddress&gt; + &lt;MerchantCity&gt;Sandton&lt;/MerchantCity&gt; + &lt;MerchantCountryCode&gt;ZA&lt;/MerchantCountryCode&gt; + &lt;MerchantCountry&gt;South Africa&lt;/MerchantCountry&gt; + &lt;DistributorName&gt;Nedbank&lt;/DistributorName&gt; + &lt;CCNumber&gt;4242........4242&lt;/CCNumber&gt; + &lt;PAN&gt;4242........4242&lt;/PAN&gt; + &lt;/Transaction&gt; +&lt;/V_XML&gt;</ExecuteResult></ExecuteResponse></soap:Body></soap:Envelope> + XML + end + + def failed_authorize_response + <<-XML +<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><soap:Body><ExecuteResponse xmlns="http://iveri.com/"><ExecuteResult>&lt;V_XML Version="2.0" Direction="Response"&gt; + &lt;Transaction ApplicationID="{D10A603D-4ADE-405B-93F1-826DFC0181E8}" Command="Authorisation" Mode="Test" RequestID="{3A1A29BE-288F-4FEE-8C15-B3BB8A207544}"&gt; + &lt;Result Status="-1" Code="4" Description="Denied" Source="NBPostilionBICISONBSouthAfrica" AppServer="105IVERIAPPPR01" DBServer="105IVERIDBPR01" Gateway="Nedbank" AcquirerCode="05" AcquirerDescription="Do not Honour" /&gt; + &lt;Amount&gt;100&lt;/Amount&gt; + &lt;Currency&gt;ZAR&lt;/Currency&gt; + &lt;ExpiryDate&gt;092018&lt;/ExpiryDate&gt; + &lt;MerchantReference&gt;3d12442ea042e78fd33057b7b50c76f7&lt;/MerchantReference&gt; + &lt;Terminal&gt;Default&lt;/Terminal&gt; + &lt;TransactionIndex&gt;{8AC33FB1-0D2E-42C7-A0DB-CF8B20279825}&lt;/TransactionIndex&gt; + &lt;MerchantName&gt;iVeri Payment Technology&lt;/MerchantName&gt; + &lt;MerchantUSN&gt;7771777&lt;/MerchantUSN&gt; + &lt;Acquirer&gt;NBPostilionBICISONBSouthAfrica&lt;/Acquirer&gt; + &lt;AcquirerReference&gt;70417:04078062&lt;/AcquirerReference&gt; + &lt;AcquirerDate&gt;20170417&lt;/AcquirerDate&gt; + &lt;AcquirerTime&gt;202648&lt;/AcquirerTime&gt; + &lt;DisplayAmount&gt;R 1.00&lt;/DisplayAmount&gt; + &lt;BIN&gt;2&lt;/BIN&gt; + &lt;Association&gt;Unknown Association&lt;/Association&gt; + &lt;CardType&gt;Unknown CardType&lt;/CardType&gt; + &lt;Issuer&gt;Unknown&lt;/Issuer&gt; + &lt;Jurisdiction&gt;Local&lt;/Jurisdiction&gt; + &lt;PANMode&gt;Keyed,CVV&lt;/PANMode&gt; + &lt;ReconReference&gt;04078062&lt;/ReconReference&gt; + &lt;CardHolderPresence&gt;CardNotPresent&lt;/CardHolderPresence&gt; + &lt;MerchantAddress&gt;MERCHANT ADDRESS&lt;/MerchantAddress&gt; + &lt;MerchantCity&gt;Sandton&lt;/MerchantCity&gt; + &lt;MerchantCountryCode&gt;ZA&lt;/MerchantCountryCode&gt; + &lt;MerchantCountry&gt;South Africa&lt;/MerchantCountry&gt; + &lt;DistributorName&gt;Nedbank&lt;/DistributorName&gt; + &lt;CCNumber&gt;2121........2121&lt;/CCNumber&gt; + &lt;PAN&gt;2121........2121&lt;/PAN&gt; + &lt;/Transaction&gt; +&lt;/V_XML&gt;</ExecuteResult></ExecuteResponse></soap:Body></soap:Envelope> + XML + end + + def successful_capture_response + <<-XML +<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><soap:Body><ExecuteResponse xmlns="http://iveri.com/"><ExecuteResult>&lt;V_XML Version="2.0" Direction="Response"&gt; + &lt;Transaction ApplicationID="{D10A603D-4ADE-405B-93F1-826DFC0181E8}" Command="Debit" Mode="Test" RequestID="{7C91245F-607D-44AE-8958-C26E447BAEB7}"&gt; + &lt;Result Status="0" AppServer="105IVERIAPPPR02" DBServer="105iveridbpr01" Gateway="Nedbank" AcquirerCode="00" /&gt; + &lt;Amount&gt;100&lt;/Amount&gt; + &lt;AuthorisationCode&gt;541268&lt;/AuthorisationCode&gt; + &lt;Currency&gt;ZAR&lt;/Currency&gt; + &lt;ExpiryDate&gt;092018&lt;/ExpiryDate&gt; + &lt;MerchantReference&gt;23b4125c3b8e2777bffee52e196a863b&lt;/MerchantReference&gt; + &lt;Terminal&gt;Default&lt;/Terminal&gt; + &lt;TransactionIndex&gt;{EF0DC64E-2D00-4B6C-BDA0-2AD265391317}&lt;/TransactionIndex&gt; + &lt;MerchantName&gt;iVeri Payment Technology&lt;/MerchantName&gt; + &lt;MerchantUSN&gt;7771777&lt;/MerchantUSN&gt; + &lt;Acquirer&gt;NBPostilionBICISONBSouthAfrica&lt;/Acquirer&gt; + &lt;AcquirerReference&gt;70417:04078057&lt;/AcquirerReference&gt; + &lt;AcquirerDate&gt;20170417&lt;/AcquirerDate&gt; + &lt;AcquirerTime&gt;200748&lt;/AcquirerTime&gt; + &lt;DisplayAmount&gt;R 1.00&lt;/DisplayAmount&gt; + &lt;BIN&gt;4&lt;/BIN&gt; + &lt;Association&gt;VISA&lt;/Association&gt; + &lt;CardType&gt;Unknown CardType&lt;/CardType&gt; + &lt;Issuer&gt;Unknown&lt;/Issuer&gt; + &lt;Jurisdiction&gt;International&lt;/Jurisdiction&gt; + &lt;PANMode&gt;Keyed,CVV&lt;/PANMode&gt; + &lt;ReconReference&gt;04078057&lt;/ReconReference&gt; + &lt;CardHolderPresence&gt;CardNotPresent&lt;/CardHolderPresence&gt; + &lt;MerchantAddress&gt;MERCHANT ADDRESS&lt;/MerchantAddress&gt; + &lt;MerchantCity&gt;Sandton&lt;/MerchantCity&gt; + &lt;MerchantCountryCode&gt;ZA&lt;/MerchantCountryCode&gt; + &lt;MerchantCountry&gt;South Africa&lt;/MerchantCountry&gt; + &lt;DistributorName&gt;Nedbank&lt;/DistributorName&gt; + &lt;CCNumber&gt;4242........4242&lt;/CCNumber&gt; + &lt;PAN&gt;4242........4242&lt;/PAN&gt; + &lt;/Transaction&gt; +&lt;/V_XML&gt;</ExecuteResult></ExecuteResponse></soap:Body></soap:Envelope> + XML + end + + def failed_capture_response + <<-XML +<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><soap:Body><ExecuteResponse xmlns="http://iveri.com/"><ExecuteResult>&lt;V_XML Version="2.0" Direction="Response"&gt; + &lt;Transaction ApplicationID="{D10A603D-4ADE-405B-93F1-826DFC0181E8}" Command="Debit" Mode="Test" RequestID="{9DAAA002-0EF9-46DC-A440-8DCD9E78B36F}"&gt; + &lt;Result Status="-1" Code="14" Description="Missing PAN" Source="NBPostilionBICISONBSouthAfricaTestProvider" AppServer="105IVERIAPPPR02" DBServer="105iveridbpr01" Gateway="Nedbank" AcquirerCode="" AcquirerDescription="" /&gt; + &lt;/Transaction&gt; +&lt;/V_XML&gt;</ExecuteResult></ExecuteResponse></soap:Body></soap:Envelope> + XML + end + + def successful_refund_response + <<-XML +<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><soap:Body><ExecuteResponse xmlns="http://iveri.com/"><ExecuteResult>&lt;V_XML Version="2.0" Direction="Response"&gt; + &lt;Transaction ApplicationID="{D10A603D-4ADE-405B-93F1-826DFC0181E8}" Command="Credit" Mode="Test" RequestID="{097C55B5-D020-40AD-8949-F9F5E4102F1D}"&gt; + &lt;Result Status="0" AppServer="105IVERIAPPPR02" DBServer="105iveridbpr01" Gateway="Nedbank" AcquirerCode="00" /&gt; + &lt;Amount&gt;100&lt;/Amount&gt; + &lt;AuthorisationCode&gt;541996&lt;/AuthorisationCode&gt; + &lt;Currency&gt;ZAR&lt;/Currency&gt; + &lt;ExpiryDate&gt;092018&lt;/ExpiryDate&gt; + &lt;MerchantReference&gt;5be2c040bd46b7eebc70274659779acf&lt;/MerchantReference&gt; + &lt;Terminal&gt;Default&lt;/Terminal&gt; + &lt;TransactionIndex&gt;{D50DB1B4-B6EC-4AF1-AFF7-71C2AA4A957B}&lt;/TransactionIndex&gt; + &lt;MerchantName&gt;iVeri Payment Technology&lt;/MerchantName&gt; + &lt;MerchantUSN&gt;7771777&lt;/MerchantUSN&gt; + &lt;Acquirer&gt;NBPostilionBICISONBSouthAfrica&lt;/Acquirer&gt; + &lt;AcquirerReference&gt;70417:04078059&lt;/AcquirerReference&gt; + &lt;AcquirerDate&gt;20170417&lt;/AcquirerDate&gt; + &lt;AcquirerTime&gt;201956&lt;/AcquirerTime&gt; + &lt;DisplayAmount&gt;R 1.00&lt;/DisplayAmount&gt; + &lt;BIN&gt;4&lt;/BIN&gt; + &lt;Association&gt;VISA&lt;/Association&gt; + &lt;CardType&gt;Unknown CardType&lt;/CardType&gt; + &lt;Issuer&gt;Unknown&lt;/Issuer&gt; + &lt;Jurisdiction&gt;International&lt;/Jurisdiction&gt; + &lt;PANMode /&gt; + &lt;ReconReference&gt;04078059&lt;/ReconReference&gt; + &lt;CardHolderPresence&gt;CardNotPresent&lt;/CardHolderPresence&gt; + &lt;MerchantAddress&gt;MERCHANT ADDRESS&lt;/MerchantAddress&gt; + &lt;MerchantCity&gt;Sandton&lt;/MerchantCity&gt; + &lt;MerchantCountryCode&gt;ZA&lt;/MerchantCountryCode&gt; + &lt;MerchantCountry&gt;South Africa&lt;/MerchantCountry&gt; + &lt;DistributorName&gt;Nedbank&lt;/DistributorName&gt; + &lt;CCNumber&gt;4242........4242&lt;/CCNumber&gt; + &lt;PAN&gt;4242........4242&lt;/PAN&gt; + &lt;/Transaction&gt; +&lt;/V_XML&gt;</ExecuteResult></ExecuteResponse></soap:Body></soap:Envelope> + XML + end + + def failed_refund_response + <<-XML +<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><soap:Body><ExecuteResponse xmlns="http://iveri.com/"><ExecuteResult>&lt;V_XML Version="2.0" Direction="Response"&gt; + &lt;Transaction ApplicationID="{D10A603D-4ADE-405B-93F1-826DFC0181E8}" Command="Credit" Mode="Test" RequestID="{5097A60A-A112-42F1-9490-FA17A859E7A3}"&gt; + &lt;Result Status="-1" Code="255" Description="Credit is not supported for ApplicationID (D10A603D-4ADE-405B-93F1-826DFC0181E8)" Source="PortalService" AppServer="105IVERIAPPPR02" DBServer="105iveridbpr01" Gateway="Nedbank" AcquirerCode="" AcquirerDescription="" /&gt; + &lt;/Transaction&gt; +&lt;/V_XML&gt;</ExecuteResult></ExecuteResponse></soap:Body></soap:Envelope> + XML + end + + def successful_void_response + <<-XML +<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><soap:Body><ExecuteResponse xmlns="http://iveri.com/"><ExecuteResult>&lt;V_XML Version="2.0" Direction="Response"&gt; + &lt;Transaction ApplicationID="{D10A603D-4ADE-405B-93F1-826DFC0181E8}" Command="Void" Mode="Test" RequestID="{0A1A3FFF-C2A3-4B91-85FD-10D1C25B765B}"&gt; + &lt;Result Status="0" AppServer="105IVERIAPPPR02" DBServer="105iveridbpr01" Gateway="Nedbank" /&gt; + &lt;OriginalRequestID&gt;{230390C8-4A9E-4426-BDD3-15D072F135FE}&lt;/OriginalRequestID&gt; + &lt;/Transaction&gt; +&lt;/V_XML&gt;</ExecuteResult></ExecuteResponse></soap:Body></soap:Envelope> + XML + end + + def failed_void_response + <<-XML +<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><soap:Body><ExecuteResponse xmlns="http://iveri.com/"><ExecuteResult>&lt;V_XML Version="2.0" Direction="Response"&gt; + &lt;Transaction ApplicationID="{D10A603D-4ADE-405B-93F1-826DFC0181E8}" Command="Void" Mode="Test" RequestID="{AE97CCE4-0631-4F08-AB47-9C2698ABEC75}"&gt; + &lt;Result Status="-1" Code="255" Description="Missing OriginalMerchantTrace" Source="NBPostilionBICISONBSouthAfricaTestProvider" AppServer="105IVERIAPPPR01" DBServer="105IVERIDBPR01" Gateway="Nedbank" AcquirerCode="" AcquirerDescription="" /&gt; + &lt;/Transaction&gt; +&lt;/V_XML&gt;</ExecuteResult></ExecuteResponse></soap:Body></soap:Envelope> + XML + end + + def successful_verify_response + <<-XML +<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><soap:Body><ExecuteResponse xmlns="http://iveri.com/"><ExecuteResult>&lt;V_XML Version="2.0" Direction="Response"&gt; + &lt;Transaction ApplicationID="{D10A603D-4ADE-405B-93F1-826DFC0181E8}" Command="Authorisation" Mode="Test" RequestID="{F4337D04-B526-4A7E-A400-2A6DEADDCF57}"&gt; + &lt;Result Status="0" AppServer="105IVERIAPPPR01" DBServer="105IVERIDBPR01" Gateway="Nedbank" AcquirerCode="00" /&gt; + &lt;Amount&gt;0&lt;/Amount&gt; + &lt;AuthorisationCode&gt;613755&lt;/AuthorisationCode&gt; + &lt;Currency&gt;ZAR&lt;/Currency&gt; + &lt;ExpiryDate&gt;092018&lt;/ExpiryDate&gt; + &lt;MerchantReference&gt;c0006d1d739905afc9e70beaf4194ea3&lt;/MerchantReference&gt; + &lt;Terminal&gt;Default&lt;/Terminal&gt; + &lt;TransactionIndex&gt;{5D5F8BF7-2D9D-42C3-AF32-08C5E62CD45E}&lt;/TransactionIndex&gt; + &lt;MerchantName&gt;iVeri Payment Technology&lt;/MerchantName&gt; + &lt;MerchantUSN&gt;7771777&lt;/MerchantUSN&gt; + &lt;Acquirer&gt;NBPostilionBICISONBSouthAfrica&lt;/Acquirer&gt; + &lt;AcquirerReference&gt;70418:04078335&lt;/AcquirerReference&gt; + &lt;AcquirerDate&gt;20170418&lt;/AcquirerDate&gt; + &lt;AcquirerTime&gt;161555&lt;/AcquirerTime&gt; + &lt;DisplayAmount&gt;R 0.00&lt;/DisplayAmount&gt; + &lt;BIN&gt;4&lt;/BIN&gt; + &lt;Association&gt;VISA&lt;/Association&gt; + &lt;CardType&gt;Unknown CardType&lt;/CardType&gt; + &lt;Issuer&gt;Unknown&lt;/Issuer&gt; + &lt;Jurisdiction&gt;International&lt;/Jurisdiction&gt; + &lt;PANMode&gt;Keyed,CVV&lt;/PANMode&gt; + &lt;ReconReference&gt;04078335&lt;/ReconReference&gt; + &lt;CardHolderPresence&gt;CardNotPresent&lt;/CardHolderPresence&gt; + &lt;MerchantAddress&gt;MERCHANT ADDRESS&lt;/MerchantAddress&gt; + &lt;MerchantCity&gt;Sandton&lt;/MerchantCity&gt; + &lt;MerchantCountryCode&gt;ZA&lt;/MerchantCountryCode&gt; + &lt;MerchantCountry&gt;South Africa&lt;/MerchantCountry&gt; + &lt;DistributorName&gt;Nedbank&lt;/DistributorName&gt; + &lt;CCNumber&gt;4242........4242&lt;/CCNumber&gt; + &lt;PAN&gt;4242........4242&lt;/PAN&gt; + &lt;/Transaction&gt; +&lt;/V_XML&gt;</ExecuteResult></ExecuteResponse></soap:Body></soap:Envelope> + XML + end + + def failed_verify_response + <<-XML +<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><soap:Body><ExecuteResponse xmlns="http://iveri.com/"><ExecuteResult>&lt;V_XML Version="2.0" Direction="Response"&gt; + &lt;Transaction ApplicationID="{D10A603D-4ADE-405B-93F1-826DFC0181E8}" Command="Authorisation" Mode="Test" RequestID="{A700FAE2-2A76-407D-A540-B41668E2B703}"&gt; + &lt;Result Status="-1" Code="4" Description="Denied" Source="NBPostilionBICISONBSouthAfrica" AppServer="105IVERIAPPPR02" DBServer="105iveridbpr01" Gateway="Nedbank" AcquirerCode="05" AcquirerDescription="Do not Honour" /&gt; + &lt;Amount&gt;0&lt;/Amount&gt; + &lt;Currency&gt;ZAR&lt;/Currency&gt; + &lt;ExpiryDate&gt;092018&lt;/ExpiryDate&gt; + &lt;MerchantReference&gt;e955afb03f224284b09ad6ae7e9b4683&lt;/MerchantReference&gt; + &lt;Terminal&gt;Default&lt;/Terminal&gt; + &lt;TransactionIndex&gt;{2A378547-AEA4-48E1-8A3E-29F9BBEA954D}&lt;/TransactionIndex&gt; + &lt;MerchantName&gt;iVeri Payment Technology&lt;/MerchantName&gt; + &lt;MerchantUSN&gt;7771777&lt;/MerchantUSN&gt; + &lt;Acquirer&gt;NBPostilionBICISONBSouthAfrica&lt;/Acquirer&gt; + &lt;AcquirerReference&gt;70418:04078337&lt;/AcquirerReference&gt; + &lt;AcquirerDate&gt;20170418&lt;/AcquirerDate&gt; + &lt;AcquirerTime&gt;161716&lt;/AcquirerTime&gt; + &lt;DisplayAmount&gt;R 0.00&lt;/DisplayAmount&gt; + &lt;BIN&gt;2&lt;/BIN&gt; + &lt;Association&gt;Unknown Association&lt;/Association&gt; + &lt;CardType&gt;Unknown CardType&lt;/CardType&gt; + &lt;Issuer&gt;Unknown&lt;/Issuer&gt; + &lt;Jurisdiction&gt;Local&lt;/Jurisdiction&gt; + &lt;PANMode&gt;Keyed,CVV&lt;/PANMode&gt; + &lt;ReconReference&gt;04078337&lt;/ReconReference&gt; + &lt;CardHolderPresence&gt;CardNotPresent&lt;/CardHolderPresence&gt; + &lt;MerchantAddress&gt;MERCHANT ADDRESS&lt;/MerchantAddress&gt; + &lt;MerchantCity&gt;Sandton&lt;/MerchantCity&gt; + &lt;MerchantCountryCode&gt;ZA&lt;/MerchantCountryCode&gt; + &lt;MerchantCountry&gt;South Africa&lt;/MerchantCountry&gt; + &lt;DistributorName&gt;Nedbank&lt;/DistributorName&gt; + &lt;CCNumber&gt;2121........2121&lt;/CCNumber&gt; + &lt;PAN&gt;2121........2121&lt;/PAN&gt; + &lt;/Transaction&gt; +&lt;/V_XML&gt;</ExecuteResult></ExecuteResponse></soap:Body></soap:Envelope> + XML + end + + def successful_verify_credentials_response + <<-XML +<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><soap:Body><ExecuteResponse xmlns="http://iveri.com/"><ExecuteResult>&lt;V_XML Version="2.0" Direction="Response"&gt; + &lt;Transaction ApplicationID="{D10A603D-4ADE-405B-93F1-826DFC0181E8}" Command="Void" Mode="Test" RequestID="{5ED922D0-92AD-40DF-9019-320591A4BA59}"&gt; + &lt;Result Status="-1" Code="255" Description="Missing OriginalMerchantTrace" Source="NBPostilionBICISONBSouthAfricaTestProvider" AppServer="105IVERIAPPPR01" DBServer="105IVERIDBPR01" Gateway="Nedbank" AcquirerCode="" AcquirerDescription="" /&gt; + &lt;/Transaction&gt; +&lt;/V_XML&gt;</ExecuteResult></ExecuteResponse></soap:Body></soap:Envelope> + XML + end + + def failed_verify_credentials_response + <<-XML +<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><soap:Body><ExecuteResponse xmlns="http://iveri.com/"><ExecuteResult>&lt;V_XML Version="2.0" Direction="Response"&gt; + &lt;Result Status="-1" Code="255" Description="The ApplicationID {11111111-1111-1111-1111-111111111111} is not valid for the current CertificateID {11111111-1111-1111-1111-111111111111}" Source="RequestHandler" RequestID="{EE6E5B39-63AD-402C-8331-F25082AD8564}" AppServer="105IVERIAPPPR01" DBServer="105IVERIDBPR01" Gateway="Nedbank" AcquirerCode="" AcquirerDescription="" /&gt; +&lt;/V_XML&gt;</ExecuteResult></ExecuteResponse></soap:Body></soap:Envelope> + XML + end +end diff --git a/test/unit/gateways/jetpay_test.rb b/test/unit/gateways/jetpay_test.rb index 279c77434e3..91069432c3e 100644 --- a/test/unit/gateways/jetpay_test.rb +++ b/test/unit/gateways/jetpay_test.rb @@ -28,7 +28,7 @@ def test_successful_purchase assert_success response assert_equal '8afa688fd002821362;TEST97;100;KKLIHOJKKNKKHJKONJHOLHOL', response.authorization - assert_equal('TEST97', response.params["approval"]) + assert_equal('TEST97', response.params['approval']) assert response.test? end @@ -48,18 +48,18 @@ def test_successful_authorize assert_success response assert_equal('cbf902091334a0b1aa;TEST01;100;KKLIHOJKKNKKHJKONOHCLOIO', response.authorization) - assert_equal('TEST01', response.params["approval"]) + assert_equal('TEST01', response.params['approval']) assert response.test? end def test_successful_capture @gateway.expects(:ssl_post).returns(successful_capture_response) - assert response = @gateway.capture(1111, "010327153017T10018;502F7B;1111") + assert response = @gateway.capture(1111, '010327153017T10018;502F7B;1111') assert_success response assert_equal('010327153017T10018;502F6B;1111;', response.authorization) - assert_equal('502F6B', response.params["approval"]) + assert_equal('502F6B', response.params['approval']) assert response.test? end @@ -70,7 +70,7 @@ def test_successful_void assert_success response assert_equal('010327153x17T10418;502F7B;500;', response.authorization) - assert_equal('502F7B', response.params["approval"]) + assert_equal('502F7B', response.params['approval']) assert response.test? end @@ -141,6 +141,7 @@ def test_purchase_sends_order_origin end private + def successful_purchase_response <<-EOF <JetPayResponse> diff --git a/test/unit/gateways/jetpay_v2_test.rb b/test/unit/gateways/jetpay_v2_test.rb new file mode 100644 index 00000000000..8129bf5eb11 --- /dev/null +++ b/test/unit/gateways/jetpay_v2_test.rb @@ -0,0 +1,308 @@ +require 'test_helper' + +class JetpayV2Test < Test::Unit::TestCase + + def setup + @gateway = JetpayV2Gateway.new(:login => 'login') + + @credit_card = credit_card + @amount = 100 + + @options = { + :device => 'spreedly', + :application => 'spreedly', + :developer_id => 'GenkID', + :billing_address => address(:country => 'US'), + :shipping_address => address(:country => 'US'), + :email => 'test@test.com', + :ip => '127.0.0.1', + :order_id => '12345' + } + end + + def test_successful_purchase + @gateway.expects(:ssl_post).returns(successful_purchase_response) + + assert response = @gateway.purchase(@amount, @credit_card, @options) + assert_success response + + assert_equal '8afa688fd002821362;TEST97;100;KKLIHOJKKNKKHJKONJHOLHOL', response.authorization + assert_equal('TEST97', response.params['approval']) + assert response.test? + end + + def test_failed_purchase + @gateway.expects(:ssl_post).returns(failed_purchase_response) + + assert response = @gateway.purchase(@amount, @credit_card, @options) + assert_failure response + assert_equal('7605f7c5d6e8f74deb;;100;', response.authorization) + assert response.test? + end + + def test_successful_authorize + @gateway.expects(:ssl_post).returns(successful_authorize_response) + + assert response = @gateway.authorize(@amount, @credit_card, @options) + assert_success response + + assert_equal('cbf902091334a0b1aa;TEST01;100;KKLIHOJKKNKKHJKONOHCLOIO', response.authorization) + assert_equal('TEST01', response.params['approval']) + assert response.test? + end + + def test_successful_capture + @gateway.expects(:ssl_post).returns(successful_capture_response) + + assert response = @gateway.capture(1111, '010327153017T10018;502F7B;1111', @options) + assert_success response + + assert_equal('010327153017T10018;502F6B;1111;', response.authorization) + assert_equal('502F6B', response.params['approval']) + assert response.test? + end + + def test_failed_capture + @gateway.expects(:ssl_post).returns(failed_capture_response) + + assert response = @gateway.capture(@amount, '7605f7c5d6e8f74deb', @options) + assert_failure response + assert_equal 'Transaction Not Found.', response.message + end + + def test_successful_void + @gateway.expects(:ssl_post).returns(successful_void_response) + + assert response = @gateway.void('010327153x17T10418;502F7B;500', @options) + assert_success response + + assert_equal('010327153x17T10418;502F7B;500;', response.authorization) + assert_equal('502F7B', response.params['approval']) + assert response.test? + end + + def test_failed_void + @gateway.expects(:ssl_post).returns(failed_void_response) + + assert void = @gateway.void('bogus', @options) + assert_failure void + end + + def test_successful_credit + card = credit_card('4242424242424242', :verification_value => nil) + + @gateway.expects(:ssl_post).returns(successful_credit_response) + + assert response = @gateway.credit(@amount, card, @options) + assert_success response + end + + def test_failed_credit + card = credit_card('2424242424242424', :verification_value => nil) + + @gateway.expects(:ssl_post).returns(failed_credit_response) + + assert credit = @gateway.credit(@amount, card, @options) + assert_failure credit + assert_match %r{Invalid card format}, credit.message + end + + def test_successful_refund + @gateway.expects(:ssl_post).returns(successful_credit_response) + + assert response = @gateway.refund(9900, '010327153017T10017', @options) + assert_success response + + assert_equal('010327153017T10017;002F6B;9900;', response.authorization) + assert_equal('002F6B', response.params['approval']) + assert response.test? + end + + def test_failed_refund + @gateway.expects(:ssl_post).returns(failed_void_response) + + assert refund = @gateway.refund(@amount, 'bogus', @options) + assert_failure refund + end + + def test_successful_verify + @gateway.expects(:ssl_post).returns(successful_authorize_response) + + assert verify = @gateway.verify(@credit_card, @options) + assert_success verify + end + + def test_failed_verify + card = credit_card('2424242424242424', :verification_value => nil) + + @gateway.expects(:ssl_post).returns(failed_credit_response) + + assert verify = @gateway.verify(card, @options) + assert_failure verify + assert_match %r{Invalid card format}, verify.message + end + + def test_avs_result + @gateway.expects(:ssl_post).returns(successful_purchase_response) + + response = @gateway.purchase(@amount, @credit_card, @options) + assert_equal 'D', response.avs_result['code'] + end + + def test_cvv_result + @gateway.expects(:ssl_post).returns(successful_purchase_response) + + response = @gateway.purchase(@amount, @credit_card, @options) + assert_equal 'P', response.cvv_result['code'] + end + + def test_transcript_scrubbing + assert @gateway.supports_scrubbing + assert_equal scrubbed_transcript, @gateway.scrub(transcript) + end + + def test_purchase_sends_additional_options + @gateway.expects(:ssl_post). + with(anything, regexp_matches(/<TaxAmount ExemptInd=\"false\">777<\/TaxAmount>/)). + with(anything, regexp_matches(/<UDField1>Value1<\/UDField1>/)). + with(anything, regexp_matches(/<UDField2>Value2<\/UDField2>/)). + with(anything, regexp_matches(/<UDField3>Value3<\/UDField3>/)). + returns(successful_purchase_response) + + @gateway.purchase(@amount, @credit_card, {:tax => '777', :ud_field_1 => 'Value1', :ud_field_2 => 'Value2', :ud_field_3 => 'Value3'}) + end + + private + + def successful_purchase_response + <<-EOF + <JetPayResponse Version="2.2"> + <TransactionID>8afa688fd002821362</TransactionID> + <ActionCode>000</ActionCode> + <Approval>TEST97</Approval> + <CVV2>P</CVV2> + <ResponseText>APPROVED</ResponseText> + <Token>KKLIHOJKKNKKHJKONJHOLHOL</Token> + <AddressMatch>Y</AddressMatch> + <ZipMatch>Y</ZipMatch> + <AVS>D</AVS> + </JetPayResponse> + EOF + end + + def failed_purchase_response + <<-EOF + <JetPayResponse Version="2.2"> + <TransactionID>7605f7c5d6e8f74deb</TransactionID> + <ActionCode>005</ActionCode> + <ResponseText>DECLINED</ResponseText> + </JetPayResponse> + EOF + end + + def successful_authorize_response + <<-EOF + <JetPayResponse Version="2.2"> + <TransactionID>cbf902091334a0b1aa</TransactionID> + <ActionCode>000</ActionCode> + <Approval>TEST01</Approval> + <CVV2>P</CVV2> + <ResponseText>APPROVED</ResponseText> + <Token>KKLIHOJKKNKKHJKONOHCLOIO</Token> + <AddressMatch>Y</AddressMatch> + <ZipMatch>Y</ZipMatch> + <AVS>D</AVS> + </JetPayResponse> + EOF + end + + def successful_capture_response + <<-EOF + <JetPayResponse Version="2.2"> + <TransactionID>010327153017T10018</TransactionID> + <ActionCode>000</ActionCode> + <Approval>502F6B</Approval> + <ResponseText>APPROVED</ResponseText> + </JetPayResponse> + EOF + end + + def failed_capture_response + <<-EOF + <JetPayResponse Version="2.2"> + <TransactionID>010327153017T10018</TransactionID> + <ActionCode>025</ActionCode> + <Approval>REJECT</Approval> + <ResponseText>ED</ResponseText> + </JetPayResponse> + EOF + end + + def successful_void_response + <<-EOF + <JetPayResponse Version="2.2"> + <TransactionID>010327153x17T10418</TransactionID> + <ActionCode>000</ActionCode> + <Approval>502F7B</Approval> + <ResponseText>VOID PROCESSED</ResponseText> + </JetPayResponse> + EOF + end + + def failed_void_response + <<-EOF + <JetPayResponse Version="2.2"> + <TransactionID>010327153x17T10418</TransactionID> + <ActionCode>900</ActionCode> + <ResponseText>INVALID MESSAGE TYPE</ResponseText> + </JetPayResponse> + EOF + end + + def successful_credit_response + <<-EOF + <JetPayResponse Version="2.2"> + <TransactionID>010327153017T10017</TransactionID> + <ActionCode>000</ActionCode> + <Approval>002F6B</Approval> + <ResponseText>APPROVED</ResponseText> + </JetPayResponse> + EOF + end + + def failed_credit_response + <<-EOF + <JetPayResponse Version="2.2"> + <TransactionID>010327153017T10017</TransactionID> + <ActionCode>912</ActionCode> + <ResponseText>INVALID CARD NUMBER</ResponseText> + </JetPayResponse> + EOF + end + + def transcript + <<-EOF + <TerminalID>TESTMCC3136X</TerminalID> + <TransactionType>SALE</TransactionType> + <TransactionID>e23c963a1247fd7aad</TransactionID> + <CardNum>4000300020001000</CardNum> + <CardExpMonth>09</CardExpMonth> + <CardExpYear>16</CardExpYear> + <CardName>Longbob Longsen</CardName> + <CVV2>123</CVV2> + EOF + end + + def scrubbed_transcript + <<-EOF + <TerminalID>TESTMCC3136X</TerminalID> + <TransactionType>SALE</TransactionType> + <TransactionID>e23c963a1247fd7aad</TransactionID> + <CardNum>[FILTERED]</CardNum> + <CardExpMonth>09</CardExpMonth> + <CardExpYear>16</CardExpYear> + <CardName>Longbob Longsen</CardName> + <CVV2>[FILTERED]</CVV2> + EOF + end +end diff --git a/test/unit/gateways/komoju_test.rb b/test/unit/gateways/komoju_test.rb index 5ea948308b4..dc67d18686c 100644 --- a/test/unit/gateways/komoju_test.rb +++ b/test/unit/gateways/komoju_test.rb @@ -10,11 +10,11 @@ def setup @options = { :order_id => '1', :description => 'Store Purchase', - :tax => "10", - :ip => "192.168.0.1", - :email => "valid@email.com", - :browser_language => "en", - :browser_user_agent => "user_agent" + :tax => '10', + :ip => '192.168.0.1', + :email => 'valid@email.com', + :browser_language => 'en', + :browser_user_agent => 'user_agent' } end @@ -25,7 +25,7 @@ def test_successful_credit_card_purchase response = @gateway.purchase(@amount, @credit_card, @options) assert_success response - assert_equal successful_response["id"], response.authorization + assert_equal successful_response['id'], response.authorization assert response.test? end @@ -38,7 +38,7 @@ def test_failed_purchase response = @gateway.purchase(@amount, @credit_card, @options) assert_failure response - assert_equal "missing_parameter", response.error_code + assert_equal 'missing_parameter', response.error_code assert response.test? end @@ -51,7 +51,7 @@ def test_detected_fraud response = @gateway.purchase(@amount, @credit_card, @options) assert_failure response - assert_equal "fraudulent", response.error_code + assert_equal 'fraudulent', response.error_code assert response.test? end @@ -59,10 +59,10 @@ def test_successful_credit_card_refund successful_response = successful_credit_card_refund_response @gateway.expects(:ssl_post).returns(JSON.generate(successful_response)) - response = @gateway.refund(@amount, "7e8c55a54256ce23e387f2838c", @options) + response = @gateway.refund(@amount, '7e8c55a54256ce23e387f2838c', @options) assert_success response - assert_equal successful_response["id"], response.authorization + assert_equal successful_response['id'], response.authorization assert response.test? end @@ -70,76 +70,76 @@ def test_successful_credit_card_refund def successful_credit_card_purchase_response { - "id" => "7e8c55a54256ce23e387f2838c", - "resource" => "payment", - "status" => "captured", - "amount" => 100, - "tax" => 8, - "payment_deadline" => nil, - "payment_details" => { - "type" => "credit_card", - "brand" => "visa", - "last_four_digits" => "2220", - "month" => 9, - "year" => 2016 + 'id' => '7e8c55a54256ce23e387f2838c', + 'resource' => 'payment', + 'status' => 'captured', + 'amount' => 100, + 'tax' => 8, + 'payment_deadline' => nil, + 'payment_details' => { + 'type' => 'credit_card', + 'brand' => 'visa', + 'last_four_digits' => '2220', + 'month' => 9, + 'year' => 2016 }, - "payment_method_fee" => 0, - "total" => 108, - "currency" => "JPY", - "description" => "Store Purchase", - "subscription" => nil, - "captured_at" => "2015-03-20T04:51:48Z", - "metadata" => { - "order_id" => "262f2a92-542c-4b4e-a68b-5b6d54a438a8" + 'payment_method_fee' => 0, + 'total' => 108, + 'currency' => 'JPY', + 'description' => 'Store Purchase', + 'subscription' => nil, + 'captured_at' => '2015-03-20T04:51:48Z', + 'metadata' => { + 'order_id' => '262f2a92-542c-4b4e-a68b-5b6d54a438a8' }, - "created_at" => "2015-03-20T04:51:48Z" + 'created_at' => '2015-03-20T04:51:48Z' } end def successful_credit_card_refund_response { - "id" => "7e8c55a54256ce23e387f2838c", - "resource" => "payment", - "status" => "refunded", - "amount" => 100, - "tax" => 8, - "payment_deadline" => nil, - "payment_details" => { - "type" => "credit_card", - "brand" => "visa", - "last_four_digits" => "2220", - "month" => 9, - "year" => 2016 + 'id' => '7e8c55a54256ce23e387f2838c', + 'resource' => 'payment', + 'status' => 'refunded', + 'amount' => 100, + 'tax' => 8, + 'payment_deadline' => nil, + 'payment_details' => { + 'type' => 'credit_card', + 'brand' => 'visa', + 'last_four_digits' => '2220', + 'month' => 9, + 'year' => 2016 }, - "payment_method_fee" => 0, - "total" => 108, - "currency" => "JPY", - "description" => "Store Purchase", - "subscription" => nil, - "captured_at" => nil, - "metadata" => { - "order_id" => "262f2a92-542c-4b4e-a68b-5b6d54a438a8" + 'payment_method_fee' => 0, + 'total' => 108, + 'currency' => 'JPY', + 'description' => 'Store Purchase', + 'subscription' => nil, + 'captured_at' => nil, + 'metadata' => { + 'order_id' => '262f2a92-542c-4b4e-a68b-5b6d54a438a8' }, - "created_at" => "2015-03-20T04:51:48Z" + 'created_at' => '2015-03-20T04:51:48Z' } end def failed_purchase_response { - "error" => { - "code" => "missing_parameter", - "message" => "A required parameter (currency) is missing", - "param" => "currency" + 'error' => { + 'code' => 'missing_parameter', + 'message' => 'A required parameter (currency) is missing', + 'param' => 'currency' } } end def detected_fraud_response { - "error" => { - "code" => "fraudulent", - "message" => "The payment could not be completed.", - "param" => nil + 'error' => { + 'code' => 'fraudulent', + 'message' => 'The payment could not be completed.', + 'param' => nil } } end diff --git a/test/unit/gateways/kushki_test.rb b/test/unit/gateways/kushki_test.rb index 315497841d1..861d82f8354 100644 --- a/test/unit/gateways/kushki_test.rb +++ b/test/unit/gateways/kushki_test.rb @@ -1,6 +1,8 @@ require 'test_helper' class KushkiTest < Test::Unit::TestCase + include CommStub + def setup @gateway = KushkiGateway.new(public_merchant_id: '_', private_merchant_id: '_') @amount = 100 @@ -20,12 +22,12 @@ def test_successful_purchase def test_successful_purchase_with_options options = { - currency: "USD", + currency: 'USD', amount: { - subtotal_iva_0: "4.95", - subtotal_iva: "10", - iva: "1.54", - ice: "3.50" + subtotal_iva_0: '4.95', + subtotal_iva: '10', + iva: '1.54', + ice: '3.50' } } @@ -46,31 +48,87 @@ def test_successful_purchase_with_options assert response.test? end - def test_failed_purchase + def test_taxes_are_excluded_when_not_provided options = { + currency: 'COP', amount: { - subtotal_iva: "200" + subtotal_iva_0: '4.95', + subtotal_iva: '10', + iva: '1.54', + ice: '3.50' } } - @gateway.expects(:ssl_post).returns(failed_charge_response) - @gateway.expects(:ssl_post).returns(successful_token_response) + amount = 100 * ( + options[:amount][:subtotal_iva_0].to_f + + options[:amount][:subtotal_iva].to_f + + options[:amount][:iva].to_f + + options[:amount][:ice].to_f + ) - response = @gateway.purchase(@amount, @credit_card, options) - assert_failure response - assert_equal 'Monto de la transacción es diferente al monto de la venta inicial', response.message - assert_equal '220', response.error_code + response = stub_comms do + @gateway.purchase(amount, @credit_card, options) + end.check_request do |endpoint, data, headers| + if /charges/ =~ endpoint + assert_no_match %r{extraTaxes}, data + end + end.respond_with(successful_charge_response, successful_token_response) + + assert_success response end - def test_successful_void + def test_partial_taxes_do_not_error + options = { + currency: 'COP', + amount: { + subtotal_iva_0: '4.95', + subtotal_iva: '10', + iva: '1.54', + ice: '3.50', + extra_taxes: { + tasa_aeroportuaria: 0.2, + iac: 0.4 + } + } + } + + amount = 100 * ( + options[:amount][:subtotal_iva_0].to_f + + options[:amount][:subtotal_iva].to_f + + options[:amount][:iva].to_f + + options[:amount][:ice].to_f + ) + + response = stub_comms do + @gateway.purchase(amount, @credit_card, options) + end.check_request do |endpoint, data, headers| + if /charges/ =~ endpoint + assert_match %r{extraTaxes}, data + assert_no_match %r{propina}, data + assert_match %r{iac}, data + end + end.respond_with(successful_charge_response, successful_token_response) + + assert_success response + end + + def test_taxes_are_included_when_provided options = { + currency: 'COP', amount: { - subtotal_iva_0: "4.95", - subtotal_iva: "10", - iva: "1.54", - ice: "3.50" + subtotal_iva_0: '4.95', + subtotal_iva: '10', + iva: '1.54', + ice: '3.50', + extra_taxes: { + propina: 0.1, + tasa_aeroportuaria: 0.2, + agencia_de_viaje: 0.3, + iac: 0.4 + } } } + amount = 100 * ( options[:amount][:subtotal_iva_0].to_f + options[:amount][:subtotal_iva].to_f + @@ -78,32 +136,84 @@ def test_successful_void options[:amount][:ice].to_f ) + response = stub_comms do + @gateway.purchase(amount, @credit_card, options) + end.check_request do |endpoint, data, headers| + if /charges/ =~ endpoint + assert_match %r{extraTaxes}, data + assert_match %r{propina}, data + end + end.respond_with(successful_charge_response, successful_token_response) + + assert_success response + end + + def test_failed_purchase + options = { + amount: { + subtotal_iva: '200' + } + } + + @gateway.expects(:ssl_post).returns(failed_charge_response) + @gateway.expects(:ssl_post).returns(successful_token_response) + + response = @gateway.purchase(@amount, @credit_card, options) + assert_failure response + assert_equal 'Monto de la transacción es diferente al monto de la venta inicial', response.message + assert_equal '220', response.error_code + end + + def test_successful_refund @gateway.expects(:ssl_post).returns(successful_charge_response) @gateway.expects(:ssl_post).returns(successful_token_response) - purchase = @gateway.purchase(amount, @credit_card, options) + purchase = @gateway.purchase(@amount, @credit_card) assert_success purchase - @gateway.expects(:ssl_request).returns(successful_void_response) + @gateway.expects(:ssl_request).returns(successful_refund_response) - assert void = @gateway.void(purchase.authorization, options) - assert_success void - assert_equal 'Succeeded', void.message + assert refund = @gateway.refund(@amount, purchase.authorization) + assert_success refund + assert_equal 'Succeeded', refund.message end - def test_failed_void + def test_failed_refund @gateway.expects(:ssl_post).returns(successful_charge_response) @gateway.expects(:ssl_post).returns(successful_token_response) purchase = @gateway.purchase(@amount, @credit_card) assert_success purchase + @gateway.expects(:ssl_request).returns(failed_refund_response) + + assert refund = @gateway.refund(@amount, purchase.authorization) + assert_failure refund + assert_equal 'Ticket number inválido', refund.message + assert_equal 'K010', refund.error_code + end + + def test_successful_void + @gateway.expects(:ssl_post).returns(successful_charge_response) + @gateway.expects(:ssl_post).returns(successful_token_response) + + purchase = @gateway.purchase(@amount, @credit_card) + assert_success purchase + + @gateway.expects(:ssl_request).returns(successful_void_response) + + assert void = @gateway.void(purchase.authorization) + assert_success void + assert_equal 'Succeeded', void.message + end + + def test_failed_void @gateway.expects(:ssl_request).returns(failed_void_response) - response = @gateway.void(purchase.authorization) + response = @gateway.void('000') assert_failure response - assert_equal 'El monto es zero', response.message - assert_equal '219', response.error_code + assert_equal 'Tipo de moneda no válida', response.message + assert_equal '205', response.error_code end def test_scrub @@ -236,6 +346,24 @@ def failed_charge_response ) end + def successful_refund_response + %( + { + "code": "K000", + "message": "El reembolso solicitado se realizó con éxito." + } + ) + end + + def failed_refund_response + %( + { + "code": "K010", + "message": "Ticket number inválido" + } + ) + end + def successful_void_response %( { @@ -247,8 +375,8 @@ def successful_void_response def failed_void_response %( { - "code":"219", - "message":"El monto es zero" + "code":"205", + "message":"Tipo de moneda no válida" } ) end diff --git a/test/unit/gateways/latitude19_test.rb b/test/unit/gateways/latitude19_test.rb index 0af67308a86..75f7b75cba8 100644 --- a/test/unit/gateways/latitude19_test.rb +++ b/test/unit/gateways/latitude19_test.rb @@ -5,8 +5,8 @@ def setup @gateway = Latitude19Gateway.new(fixtures(:latitude19)) @amount = 100 - @credit_card = credit_card("4000100011112224", verification_value: "747") - @declined_card = credit_card("0000000000000000") + @credit_card = credit_card('4000100011112224', verification_value: '747') + @declined_card = credit_card('0000000000000000') @options = { order_id: generate_unique_id, @@ -21,7 +21,7 @@ def test_successful_purchase response = @gateway.purchase(@amount, @credit_card, @options) assert_success response - assert_equal "Approved", response.message + assert_equal 'Approved', response.message assert response.test? end @@ -35,14 +35,14 @@ def test_successful_authorize_and_capture response = @gateway.authorize(@amount, @credit_card, @options) assert_success response - assert_equal "Approved", response.message + assert_equal 'Approved', response.message assert_match %r(^auth\|\w+$), response.authorization @gateway.expects(:ssl_post).returns(successful_capture_response) capture = @gateway.capture(@amount, response.authorization, @options) assert_success capture - assert_equal "Approved", capture.message + assert_equal 'Approved', capture.message end # def test_failed_authorize @@ -51,11 +51,11 @@ def test_successful_authorize_and_capture def test_failed_capture @gateway.expects(:ssl_post).returns(failed_capture_response) - authorization = "auth" + "|" + SecureRandom.hex(6) + authorization = 'auth' + '|' + SecureRandom.hex(6) response = @gateway.capture(@amount, authorization, @options) assert_failure response - assert_equal "Not submitted", response.message - assert_equal "400", response.error_code + assert_equal 'Not submitted', response.message + assert_equal '400', response.error_code end def test_successful_void @@ -70,7 +70,7 @@ def test_successful_void void = @gateway.void(auth.authorization, @options) assert_success void - assert_equal "Approved", void.message + assert_equal 'Approved', void.message # response = @gateway.authorize(@amount, @credit_card, @options) # assert_success response @@ -95,7 +95,7 @@ def test_successful_void void = @gateway.void(purchase.authorization, @options) assert_success void - assert_equal "Approved", void.message + assert_equal 'Approved', void.message end def test_failed_void @@ -108,12 +108,12 @@ def test_failed_void @gateway.expects(:ssl_post).returns(failed_reversal_response) - authorization = auth.authorization[0..9] + "XX" + authorization = auth.authorization[0..9] + 'XX' response = @gateway.void(authorization, @options) assert_failure response - assert_equal "Not submitted", response.message - assert_equal "400", response.error_code + assert_equal 'Not submitted', response.message + assert_equal '400', response.error_code end def test_successful_credit @@ -123,7 +123,7 @@ def test_successful_credit response = @gateway.credit(@amount, @credit_card, @options) assert_success response - assert_equal "Approved", response.message + assert_equal 'Approved', response.message end # def test_failed_credit @@ -136,7 +136,7 @@ def test_successful_verify response = @gateway.verify(@credit_card, @options) assert_success response - assert_equal "Approved", response.message + assert_equal 'Approved', response.message end # def test_failed_verify @@ -149,13 +149,13 @@ def test_successful_store_and_purchase store = @gateway.store(@credit_card, @options) assert_success store - assert_equal "Approved", store.message + assert_equal 'Approved', store.message @gateway.expects(:ssl_post).returns(successful_purchase_response) purchase = @gateway.purchase(@amount, store.authorization, @options) assert_success purchase - assert_equal "Approved", purchase.message + assert_equal 'Approved', purchase.message end def test_scrub diff --git a/test/unit/gateways/linkpoint_test.rb b/test/unit/gateways/linkpoint_test.rb index 48312215e0a..50639eb460a 100644 --- a/test/unit/gateways/linkpoint_test.rb +++ b/test/unit/gateways/linkpoint_test.rb @@ -39,7 +39,7 @@ def test_successful_authorization def test_successful_capture @gateway.expects(:ssl_post).returns(successful_capture_response) - assert response = @gateway.capture(@amount, "token", @options) + assert response = @gateway.capture(@amount, 'token', @options) assert_instance_of Response, response assert_success response assert_equal '1000', response.authorization @@ -65,7 +65,7 @@ def test_recurring @gateway.expects(:ssl_post).returns(successful_recurring_response) response = assert_deprecation_warning(Gateway::RECURRING_DEPRECATION_MESSAGE) do - @gateway.recurring(2400, @credit_card, :order_id => 1003, :installments => 12, :startdate => "immediate", :periodicity => :monthly) + @gateway.recurring(2400, @credit_card, :order_id => 1003, :installments => 12, :startdate => 'immediate', :periodicity => :monthly) end assert_success response end @@ -79,7 +79,10 @@ def test_amount_style end def test_purchase_is_valid_xml - @gateway.send(:parameters, 1000, @credit_card, :ordertype => "SALE", :order_id => 1004, + @gateway.send( + :parameters, 1000, @credit_card, + :ordertype => 'SALE', + :order_id => 1004, :billing_address => { :address1 => '1313 lucky lane', :city => 'Lost Angeles', @@ -93,7 +96,14 @@ def test_purchase_is_valid_xml end def test_recurring_is_valid_xml - @gateway.send(:parameters, 1000, @credit_card, :ordertype => "SALE", :action => "SUBMIT", :installments => 12, :startdate => "immediate", :periodicity => "monthly", :order_id => 1006, + @gateway.send( + :parameters, 1000, @credit_card, + :ordertype => 'SALE', + :action => 'SUBMIT', + :installments => 12, + :startdate => 'immediate', + :periodicity => 'monthly', + :order_id => 1006, :billing_address => { :address1 => '1313 lucky lane', :city => 'Lost Angeles', @@ -106,17 +116,42 @@ def test_recurring_is_valid_xml end def test_line_items_are_valid_xml - options = {:ordertype => "SALE", :action => "SUBMIT", :installments => 12, :startdate => "immediate", :periodicity => "monthly", :order_id => 1006, + options = { + :ordertype => 'SALE', + :action => 'SUBMIT', + :installments => 12, + :startdate => 'immediate', + :periodicity => 'monthly', + :order_id => 1006, :billing_address => { :address1 => '1313 lucky lane', :city => 'Lost Angeles', :state => 'CA', :zip => '90210' - }, - :line_items => [{:id => '123456', :description => "Logo T-Shirt", :price => - "12.00", :quantity => '1', :options => [{:name => "Color", :value => - "Red"}, {:name => "Size", :value => "XL"}]},{:id => '111', :description => "keychain", :price => "3.00", :quantity => '1'}]} - + }, + :line_items => [ + { + :id => '123456', + :description => 'Logo T-Shirt', + :price => '12.00', + :quantity => '1', + :options => [ + { + :name => 'Color', + :value => 'Red'}, + { + :name => 'Size', + :value => 'XL'} + ] + }, + { + :id => '111', + :description => 'keychain', + :price => '3.00', + :quantity => '1' + } + ] + } assert data = @gateway.send(:post_data, @amount, @credit_card, options) assert REXML::Document.new(data) @@ -125,7 +160,10 @@ def test_line_items_are_valid_xml def test_declined_purchase_is_valid_xml @gateway = LinkpointGateway.new(:login => 123123, :pem => 'PEM') - @gateway.send(:parameters, 1000, @credit_card, :ordertype => "SALE", :order_id => 1005, + @gateway.send( + :parameters, 1000, @credit_card, + :ordertype => 'SALE', + :order_id => 1005, :billing_address => { :address1 => '1313 lucky lane', :city => 'Lost Angeles', @@ -188,6 +226,7 @@ def test_transcript_scrubbing end private + def successful_authorization_response '<r_csp>CSI</r_csp><r_time>Sun Jan 6 21:41:31 2008</r_time><r_ref>0004486182</r_ref><r_error/><r_ordernum>1000</r_ordernum><r_message>APPROVED</r_message><r_code>1234560004486182:NNNM:100018312899:</r_code><r_tdate>1199680890</r_tdate><r_score/><r_authresponse/><r_approved>APPROVED</r_approved><r_avs>NNNM</r_avs>' end diff --git a/test/unit/gateways/litle_test.rb b/test/unit/gateways/litle_test.rb index b3c64744ac1..00538933ec8 100644 --- a/test/unit/gateways/litle_test.rb +++ b/test/unit/gateways/litle_test.rb @@ -17,12 +17,33 @@ def setup { month: '01', year: '2012', - brand: "visa", - number: "44444444400009", - payment_cryptogram: "BwABBJQ1AgAAAAAgJDUCAAAAAAA=" + brand: 'visa', + number: '44444444400009', + payment_cryptogram: 'BwABBJQ1AgAAAAAgJDUCAAAAAAA=' + }) + @decrypted_android_pay = ActiveMerchant::Billing::NetworkTokenizationCreditCard.new( + { + source: :android_pay, + month: '01', + year: '2021', + brand: 'visa', + number: '4457000300000007', + payment_cryptogram: 'BwABBJQ1AgAAAAAgJDUCAAAAAAA=' }) @amount = 100 @options = {} + @check = check( + name: 'Tom Black', + routing_number: '011075150', + account_number: '4099999992', + account_type: 'checking' + ) + @authorize_check = check( + name: 'John Smith', + routing_number: '011075150', + account_number: '1099999999', + account_type: 'checking' + ) end def test_successful_purchase @@ -32,7 +53,18 @@ def test_successful_purchase assert_success response - assert_equal "100000000000000006;sale;100", response.authorization + assert_equal '100000000000000006;sale;100', response.authorization + assert response.test? + end + + def test_successful_purchase_with_echeck + response = stub_comms do + @gateway.purchase(2004, @check) + end.respond_with(successful_purchase_with_echeck_response) + + assert_success response + + assert_equal '621100411297330000;echeckSales;2004', response.authorization assert response.test? end @@ -42,11 +74,26 @@ def test_failed_purchase end.respond_with(failed_purchase_response) assert_failure response - assert_equal "Insufficient Funds", response.message - assert_equal "110", response.params["response"] + assert_equal 'Insufficient Funds', response.message + assert_equal '110', response.params['response'] assert response.test? end + def test_passing_merchant_data + options = @options.merge( + affiliate: 'some-affiliate', + campaign: 'super-awesome-campaign', + merchant_grouping_id: 'brilliant-group' + ) + stub_comms do + @gateway.purchase(@amount, @credit_card, options) + end.check_request do |endpoint, data, headers| + assert_match(%r(<affiliate>some-affiliate</affiliate>), data) + assert_match(%r(<campaign>super-awesome-campaign</campaign>), data) + assert_match(%r(<merchantGroupingId>brilliant-group</merchantGroupingId>), data) + end.respond_with(successful_purchase_response) + end + def test_passing_name_on_card stub_comms do @gateway.purchase(@amount, @credit_card) @@ -57,7 +104,7 @@ def test_passing_name_on_card def test_passing_order_id stub_comms do - @gateway.purchase(@amount, @credit_card, order_id: "774488") + @gateway.purchase(@amount, @credit_card, order_id: '774488') end.check_request do |endpoint, data, headers| assert_match(/774488/, data) end.respond_with(successful_purchase_response) @@ -82,7 +129,7 @@ def test_passing_shipping_address def test_passing_descriptor stub_comms do @gateway.authorize(@amount, @credit_card, { - descriptor_name: "Name", descriptor_phone: "Phone" + descriptor_name: 'Name', descriptor_phone: 'Phone' }) end.check_request do |endpoint, data, headers| assert_match(%r(<customBilling>.*<descriptor>Name<)m, data) @@ -110,10 +157,17 @@ def test_add_applepay_order_source stub_comms do @gateway.purchase(@amount, @decrypted_apple_pay) end.check_request do |endpoint, data, headers| - assert_match "<orderSource>applepay</orderSource>", data + assert_match '<orderSource>applepay</orderSource>', data end.respond_with(successful_purchase_response) end + def test_add_android_pay_order_source + stub_comms do + @gateway.purchase(@amount, @decrypted_android_pay) + end.check_request do |endpoint, data, headers| + assert_match '<orderSource>androidpay</orderSource>', data + end.respond_with(successful_purchase_response) + end def test_successful_authorize_and_capture response = stub_comms do @@ -122,7 +176,7 @@ def test_successful_authorize_and_capture assert_success response - assert_equal "100000000000000001;authorization;100", response.authorization + assert_equal '100000000000000001;authorization;100', response.authorization assert response.test? capture = stub_comms do @@ -140,8 +194,8 @@ def test_failed_authorize end.respond_with(failed_authorize_response) assert_failure response - assert_equal "Insufficient Funds", response.message - assert_equal "110", response.params["response"] + assert_equal 'Insufficient Funds', response.message + assert_equal '110', response.params['response'] end def test_failed_capture @@ -150,8 +204,8 @@ def test_failed_capture end.respond_with(failed_capture_response) assert_failure response - assert_equal "No transaction found with specified litleTxnId", response.message - assert_equal "360", response.params["response"] + assert_equal 'No transaction found with specified litleTxnId', response.message + assert_equal '360', response.params['response'] end def test_successful_refund @@ -159,7 +213,7 @@ def test_successful_refund @gateway.purchase(@amount, @credit_card) end.respond_with(successful_purchase_response) - assert_equal "100000000000000006;sale;100", response.authorization + assert_equal '100000000000000006;sale;100', response.authorization refund = stub_comms do @gateway.refund(@amount, response.authorization) @@ -172,12 +226,12 @@ def test_successful_refund def test_failed_refund response = stub_comms do - @gateway.refund(@amount, "SomeAuthorization") + @gateway.refund(@amount, 'SomeAuthorization') end.respond_with(failed_refund_response) assert_failure response - assert_equal "No transaction found with specified litleTxnId", response.message - assert_equal "360", response.params["response"] + assert_equal 'No transaction found with specified litleTxnId', response.message + assert_equal '360', response.params['response'] end def test_successful_void_of_authorization @@ -186,7 +240,7 @@ def test_successful_void_of_authorization end.respond_with(successful_authorize_response) assert_success response - assert_equal "100000000000000001;authorization;100", response.authorization + assert_equal '100000000000000001;authorization;100', response.authorization void = stub_comms do @gateway.void(response.authorization) @@ -199,10 +253,10 @@ def test_successful_void_of_authorization def test_successful_void_of_other_things refund = stub_comms do - @gateway.refund(@amount, "SomeAuthorization") + @gateway.refund(@amount, 'SomeAuthorization') end.respond_with(successful_refund_response) - assert_equal "100000000000000003;credit;", refund.authorization + assert_equal '100000000000000003;credit;', refund.authorization void = stub_comms do @gateway.void(refund.authorization) @@ -215,22 +269,31 @@ def test_successful_void_of_other_things def test_failed_void_of_authorization response = stub_comms do - @gateway.void("123456789012345360;authorization;100") + @gateway.void('123456789012345360;authorization;100') end.respond_with(failed_void_of_authorization_response) assert_failure response - assert_equal "No transaction found with specified litleTxnId", response.message - assert_equal "360", response.params["response"] + assert_equal 'No transaction found with specified litleTxnId', response.message + assert_equal '360', response.params['response'] end def test_failed_void_of_other_things response = stub_comms do - @gateway.void("123456789012345360;credit;100") + @gateway.void('123456789012345360;credit;100') end.respond_with(failed_void_of_other_things_response) assert_failure response - assert_equal "No transaction found with specified litleTxnId", response.message - assert_equal "360", response.params["response"] + assert_equal 'No transaction found with specified litleTxnId', response.message + assert_equal '360', response.params['response'] + end + + def test_successful_void_of_echeck + response = stub_comms do + @gateway.void('945032206979933000;echeckSales;2004') + end.respond_with(successful_void_of_echeck_response) + + assert_success response + assert_equal '986272331806746000;echeckVoid;', response.authorization end def test_successful_store @@ -241,16 +304,16 @@ def test_successful_store end.respond_with(successful_store_response) assert_success response - assert_equal "1111222233330123", response.authorization + assert_equal '1111222233330123', response.authorization end def test_successful_store_with_paypage_registration_id response = stub_comms do - @gateway.store("cDZJcmd1VjNlYXNaSlRMTGpocVZQY1NNlYE4ZW5UTko4NU9KK3p1L1p1VzE4ZWVPQVlSUHNITG1JN2I0NzlyTg=") + @gateway.store('cDZJcmd1VjNlYXNaSlRMTGpocVZQY1NNlYE4ZW5UTko4NU9KK3p1L1p1VzE4ZWVPQVlSUHNITG1JN2I0NzlyTg=') end.respond_with(successful_store_paypage_response) assert_success response - assert_equal "1111222233334444", response.authorization + assert_equal '1111222233334444', response.authorization end def test_failed_store @@ -259,8 +322,8 @@ def test_failed_store end.respond_with(failed_store_response) assert_failure response - assert_equal "Credit card number was invalid", response.message - assert_equal "820", response.params["response"] + assert_equal 'Credit card number was invalid', response.message + assert_equal '820', response.params['response'] end def test_successful_verify @@ -275,7 +338,7 @@ def test_successful_verify_failed_void @gateway.verify(@credit_card, @options) end.respond_with(successful_authorize_response, failed_void_of_authorization_response) assert_success response - assert_equal "Approved", response.message + assert_equal 'Approved', response.message end def test_unsuccessful_verify @@ -283,17 +346,17 @@ def test_unsuccessful_verify @gateway.verify(@credit_card, @options) end.respond_with(failed_authorize_response, successful_void_of_auth_response) assert_failure response - assert_equal "Insufficient Funds", response.message + assert_equal 'Insufficient Funds', response.message end def test_add_swipe_data_with_creditcard - @credit_card.track_data = "Track Data" + @credit_card.track_data = 'Track Data' stub_comms do @gateway.purchase(@amount, @credit_card) end.check_request do |endpoint, data, headers| - assert_match "<track>Track Data</track>", data - assert_match "<orderSource>retail</orderSource>", data + assert_match '<track>Track Data</track>', data + assert_match '<orderSource>retail</orderSource>', data assert_match %r{<pos>.+<\/pos>}m, data end.respond_with(successful_purchase_response) end @@ -302,16 +365,16 @@ def test_order_source_with_creditcard_no_track_data stub_comms do @gateway.purchase(@amount, @credit_card) end.check_request do |endpoint, data, headers| - assert_match "<orderSource>ecommerce</orderSource>", data + assert_match '<orderSource>ecommerce</orderSource>', data assert %r{<pos>.+<\/pos>}m !~ data end.respond_with(successful_purchase_response) end def test_order_source_override stub_comms do - @gateway.purchase(@amount, @credit_card, order_source: "recurring") + @gateway.purchase(@amount, @credit_card, order_source: 'recurring') end.check_request do |endpoint, data, headers| - assert_match "<orderSource>recurring</orderSource>", data + assert_match '<orderSource>recurring</orderSource>', data end.respond_with(successful_purchase_response) end @@ -322,7 +385,7 @@ def test_unsuccessful_xml_schema_validation assert_failure response assert_match(/^Error validating xml data against the schema/, response.message) - assert_equal "1", response.params["response"] + assert_equal '1', response.params['response'] end def test_scrub @@ -333,7 +396,6 @@ def test_supports_scrubbing? assert @gateway.supports_scrubbing? end - private def successful_purchase_response @@ -355,6 +417,20 @@ def successful_purchase_response ) end + def successful_purchase_with_echeck_response + %( + <litleOnlineResponse version='9.12' response='0' message='Valid Format' xmlns='http://www.litle.com/schema'> + <echeckSalesResponse id='42' reportGroup='Default Report Group' customerId=''> + <litleTxnId>621100411297330000</litleTxnId> + <orderId>42</orderId> + <response>000</response> + <responseTime>2018-01-09T14:02:20</responseTime> + <message>Approved</message> + </echeckSalesResponse> + </litleOnlineResponse> + ) + end + def failed_purchase_response %( <litleOnlineResponse version='8.22' response='0' message='Valid Format' xmlns='http://www.litle.com/schema'> @@ -489,6 +565,20 @@ def successful_void_of_other_things_response ) end + def successful_void_of_echeck_response + %( + <litleOnlineResponse version='9.12' response='0' message='Valid Format' xmlns='http://www.litle.com/schema'> + <echeckVoidResponse id='' reportGroup='Default Report Group' customerId=''> + <litleTxnId>986272331806746000</litleTxnId> + <response>000</response> + <responseTime>2018-01-09T14:20:00</responseTime> + <message>Approved</message> + <postDate>2018-01-09</postDate> + </echeckVoidResponse> + </litleOnlineResponse> + ) + end + def failed_void_of_authorization_response %( <litleOnlineResponse version='8.22' response='0' message='Valid Format' xmlns='http://www.litle.com/schema'> diff --git a/test/unit/gateways/maxipago_test.rb b/test/unit/gateways/maxipago_test.rb index dce65d37260..b437bcda00a 100644 --- a/test/unit/gateways/maxipago_test.rb +++ b/test/unit/gateways/maxipago_test.rb @@ -54,14 +54,14 @@ def test_failed_authorize def test_successful_capture @gateway.expects(:ssl_post).returns(successful_capture_response) - response = @gateway.capture(nil, "authorization", @options) + response = @gateway.capture(nil, 'authorization', @options) assert_success response end def test_failed_capture @gateway.expects(:ssl_post).returns(failed_capture_response) - response = @gateway.capture(nil, "bogus", @options) + response = @gateway.capture(nil, 'bogus', @options) assert_failure response end @@ -73,15 +73,14 @@ def test_successful_void @gateway.expects(:ssl_post).returns(successful_void_response) void = @gateway.void(auth.authorization) assert_success void - assert_equal "VOIDED", void.params["response_message"] - + assert_equal 'VOIDED', void.params['response_message'] end def test_failed_void @gateway.expects(:ssl_post).returns(failed_void_response) - response = @gateway.void("NOAUTH|0000000") + response = @gateway.void('NOAUTH|0000000') assert_failure response - assert_equal "Unable to validate, original void transaction not found", response.message + assert_equal 'Unable to validate, original void transaction not found', response.message end def test_successful_refund @@ -92,7 +91,7 @@ def test_successful_refund @gateway.expects(:ssl_post).returns(successful_refund_response) refund = @gateway.refund(@amount, purchase.authorization, @options) assert_success refund - assert_equal "CAPTURED", refund.message + assert_equal 'CAPTURED', refund.message end def test_failed_refund @@ -104,21 +103,21 @@ def test_failed_refund refund_amount = @amount + 10 refund = @gateway.refund(refund_amount, purchase.authorization, @options) assert_failure refund - assert_equal "The Return amount is greater than the amount that can be returned.", refund.message + assert_equal 'The Return amount is greater than the amount that can be returned.', refund.message end def test_successful_verify @gateway.expects(:ssl_post).times(2).returns(successful_authorize_response).then.returns(successful_void_response) response = @gateway.verify(@credit_card, @options) assert_success response - assert_equal "AUTHORIZED", response.message + assert_equal 'AUTHORIZED', response.message end def test_failed_verify @gateway.expects(:ssl_post).returns(failed_authorize_response) response = @gateway.verify(@credit_card, @options) assert_failure response - assert_equal "The transaction has an expired credit card.", response.message + assert_equal 'The transaction has an expired credit card.', response.message end def test_scrub diff --git a/test/unit/gateways/mercado_pago_test.rb b/test/unit/gateways/mercado_pago_test.rb new file mode 100644 index 00000000000..9139432254c --- /dev/null +++ b/test/unit/gateways/mercado_pago_test.rb @@ -0,0 +1,389 @@ +require 'test_helper' + +class MercadoPagoTest < Test::Unit::TestCase + include CommStub + + def setup + @gateway = MercadoPagoGateway.new(access_token: 'access_token') + @credit_card = credit_card + @amount = 100 + + @options = { + order_id: '1', + billing_address: address, + description: 'Store Purchase' + } + end + + def test_successful_purchase + @gateway.expects(:ssl_post).at_most(2).returns(successful_purchase_response) + + response = @gateway.purchase(@amount, @credit_card, @options) + assert_success response + + assert_equal '4141491|1.0', response.authorization + assert_equal 'accredited', response.message + assert response.test? + end + + def test_failed_purchase + @gateway.expects(:ssl_post).at_most(2).returns(failed_purchase_response) + + response = @gateway.purchase(@amount, @credit_card, @options) + assert_failure response + assert_equal 'rejected', response.error_code + assert_equal 'cc_rejected_other_reason', response.message + end + + def test_successful_authorize + @gateway.expects(:ssl_post).at_most(2).returns(successful_authorize_response) + + response = @gateway.authorize(@amount, @credit_card, @options) + assert_success response + + assert_equal '4261941|1.0', response.authorization + assert_equal 'pending_capture', response.message + assert response.test? + end + + def test_failed_authorize + @gateway.expects(:ssl_post).at_most(2).returns(failed_authorize_response) + + response = @gateway.authorize(@amount, @credit_card, @options) + assert_failure response + assert_equal 'rejected', response.error_code + assert_equal 'cc_rejected_other_reason', response.message + end + + def test_successful_capture + @gateway.expects(:ssl_request).returns(successful_capture_response) + + response = @gateway.capture(@amount, 'authorization|amount') + assert_success response + + assert_equal '4261941|1.0', response.authorization + assert_equal 'accredited', response.message + assert response.test? + end + + def test_failed_capture + @gateway.expects(:ssl_request).returns(failed_capture_response) + + response = @gateway.capture(@amount, '') + assert_failure response + + assert_equal '|1.0', response.authorization + assert_equal 'Method not allowed', response.message + assert response.test? + end + + def test_successful_refund + @gateway.expects(:ssl_post).returns(successful_refund_response) + + response = @gateway.refund(@amount, 'authorization|1.0', @options) + assert_success response + end + + def test_failed_refund + @gateway.expects(:ssl_post).returns(failed_refund_response) + + response = @gateway.refund(@amount, '', @options) + assert_failure response + assert_equal nil, response.error_code + end + + def test_successful_void + @gateway.expects(:ssl_request).returns(successful_void_response) + + response = @gateway.void('authorization|amount') + assert_success response + + assert_equal '4261966|', response.authorization + assert_equal 'by_collector', response.message + assert response.test? + end + + def test_failed_void + @gateway.expects(:ssl_request).returns(failed_void_response) + + response = @gateway.void('') + assert_failure response + + assert_equal '|', response.authorization + assert_equal 'Method not allowed', response.message + assert response.test? + end + + def test_successful_verify + @gateway.expects(:ssl_request).at_most(3).returns(successful_void_response) + + response = @gateway.verify(@credit_card, @options) + assert_success response + + assert_equal 'by_collector', response.message + assert response.test? + end + + def test_successful_verify_with_failed_void + @gateway.expects(:ssl_request).at_most(3).returns(failed_void_response) + + response = @gateway.verify(@credit_card, @options) + assert_failure response + + assert_equal 'Method not allowed', response.message + assert response.test? + end + + def test_failed_verify + @gateway.expects(:ssl_request).at_most(2).returns(failed_authorize_response) + + response = @gateway.verify(@credit_card, @options) + assert_failure response + + assert_equal 'cc_rejected_other_reason', response.message + assert response.test? + end + + def test_scrub + assert @gateway.supports_scrubbing? + assert_equal @gateway.scrub(pre_scrubbed), post_scrubbed + end + + def test_does_not_send_brand + credit_card = credit_card('378282246310005', brand: 'american_express') + + response = stub_comms do + @gateway.purchase(@amount, credit_card, @options) + end.check_request do |endpoint, data, headers| + if endpoint =~ /payments/ + assert_not_match(%r("payment_method_id":"amex"), data) + end + end.respond_with(successful_purchase_response) + + assert_success response + assert_equal '4141491|1.0', response.authorization + end + + def test_sends_payment_method_id + credit_card = credit_card('30569309025904') + + response = stub_comms do + @gateway.purchase(@amount, credit_card, @options.merge(payment_method_id: 'diners')) + end.check_request do |endpoint, data, headers| + if endpoint =~ /payments/ + assert_match(%r("payment_method_id":"diners"), data) + end + end.respond_with(successful_purchase_response) + + assert_success response + assert_equal '4141491|1.0', response.authorization + end + + def test_includes_deviceid_header + @options[:device_id] = '1a2b3c' + @gateway.expects(:ssl_post).with(anything, anything, {'Content-Type' => 'application/json'}).returns(successful_purchase_response) + @gateway.expects(:ssl_post).with(anything, anything, {'Content-Type' => 'application/json', 'X-Device-Session-ID' => '1a2b3c'}).returns(successful_purchase_response) + + response = @gateway.purchase(@amount, @credit_card, @options) + assert_success response + end + + def test_includes_additional_data + @options[:additional_info] = {'foo' => 'bar', 'baz' => 'quux'} + response = stub_comms do + @gateway.purchase(@amount, @credit_card, @options) + end.check_request do |endpoint, data, headers| + if data =~ /payment_method_id/ + assert_match(/"foo":"bar"/, data) + assert_match(/"baz":"quux"/, data) + end + end.respond_with(successful_purchase_response) + + assert_success response + end + + def test_includes_issuer_id + response = stub_comms do + @gateway.purchase(@amount, @credit_card, @options.merge(issuer_id: '1a2b3c4d')) + end.check_request do |endpoint, data, headers| + if endpoint =~ /payments/ + assert_match(%r("issuer_id":"1a2b3c4d"), data) + end + end.respond_with(successful_purchase_response) + + assert_success response + assert_equal '4141491|1.0', response.authorization + end + + private + + def pre_scrubbed + %q( + opening connection to api.mercadopago.com:443... + opened + starting SSL for api.mercadopago.com:443... + SSL established + <- "POST /v1/card_tokens?access_token=TEST-8527269031909288-071213-0fc96cb7cd3633189bfbe29f63722700__LB_LA__-263489584 HTTP/1.1\r\nContent-Type: application/json\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nAccept: */*\r\nUser-Agent: Ruby\r\nConnection: close\r\nHost: api.mercadopago.com\r\nContent-Length: 140\r\n\r\n" + <- "{\"card_number\":\"4509953566233704\",\"security_code\":\"123\",\"expiration_month\":9,\"expiration_year\":2018,\"cardholder\":{\"name\":\"Longbob Longsen\"}}" + -> "HTTP/1.1 201 Created\r\n" + -> "Access-Control-Allow-Origin: *\r\n" + -> "X-Request-Id: eb7a95a0-dccb-4580-9a69-534f6faf0bd6\r\n" + -> "Content-Type: application/json;charset=utf-8\r\n" + -> "Date: Thu, 13 Jul 2017 17:37:58 GMT\r\n" + -> "Connection: close\r\n" + -> "X-XSS-Protection: 1; mode=block\r\n" + -> "X-Content-Type-Options: nosniff\r\n" + -> "Strict-Transport-Security: max-age=16070400\r\n" + -> "Set-Cookie: TS016da221=0119b547a2244bba3789910575ac019d7d44d644026217ca433918a8c8fd9ff83de9d4b3c095adc76ee58870b56cd33041797db9e2; Path=/; Secure; HTTPOnly\r\n" + -> "Vary: Accept-Encoding, User-Agent\r\n" + -> "Content-Encoding: gzip\r\n" + -> "Transfer-Encoding: chunked\r\n" + -> "\r\n" + Conn close + opening connection to api.mercadopago.com:443... + opened + starting SSL for api.mercadopago.com:443... + SSL established + <- "POST /v1/payments?access_token=TEST-8527269031909288-071213-0fc96cb7cd3633189bfbe29f63722700__LB_LA__-263489584 HTTP/1.1\r\nContent-Type: application/json\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nAccept: */*\r\nUser-Agent: Ruby\r\nConnection: close\r\nHost: api.mercadopago.com\r\nContent-Length: 395\r\n\r\n" + <- "{\"transaction_amount\":5.0,\"description\":\"Store Purchase\",\"installments\":1,\"order\":{\"type\":\"mercadopago\",\"id\":2554731505684667137},\"token\":\"02ed9760103508d54361da8741a22a9e\",\"payment_method_id\":\"visa\",\"additional_info\":{\"payer\":{\"address\":{\"zip_code\":\"K1C2N6\",\"street_number\":\"456\",\"street_name\":\"My Street\"}}},\"payer\":{\"email\":\"user+br@example.com\",\"first_name\":\"Longbob\",\"last_name\":\"Longsen\"}}" + -> "HTTP/1.1 201 Created\r\n" + -> "Date: Thu, 13 Jul 2017 17:37:59 GMT\r\n" + -> "Content-Type: application/json;charset=UTF-8\r\n" + -> "Connection: close\r\n" + -> "X-Response-Status: approved/accredited\r\n" + -> "X-Caller-Id: 263489584\r\n" + -> "Vary: Accept,Accept-Encoding, User-Agent\r\n" + -> "Cache-Control: max-age=0\r\n" + -> "ETag: 1deee4b03ae344416c5863ac0d92c13e\r\n" + -> "X-Content-Type-Options: nosniff\r\n" + -> "X-Frame-Options: DENY\r\n" + -> "X-Request-Id: ccb324d1-8365-42dd-8e9a-734488220777\r\n" + -> "X-XSS-Protection: 1; mode=block\r\n" + -> "Strict-Transport-Security: max-age=15724800\r\n" + -> "Access-Control-Allow-Origin: *\r\n" + -> "Access-Control-Allow-Headers: Content-Type\r\n" + -> "Access-Control-Allow-Methods: PUT, GET, POST, DELETE, OPTIONS\r\n" + -> "Access-Control-Max-Age: 86400\r\n" + -> "Set-Cookie: TS016da221=0119b547a287375accd901052e4871cecbc881599be32e9bcb508701e62cabee4424801a25969778d1c93e2c57c2fd0a8a934c9817; Path=/; Secure; HTTPOnly\r\n" + -> "Content-Encoding: gzip\r\n" + -> "Transfer-Encoding: chunked\r\n" + -> "\r\n" + Conn close + ) + end + + def post_scrubbed + %q( + opening connection to api.mercadopago.com:443... + opened + starting SSL for api.mercadopago.com:443... + SSL established + <- "POST /v1/card_tokens?access_token=[FILTERED] HTTP/1.1\r\nContent-Type: application/json\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nAccept: */*\r\nUser-Agent: Ruby\r\nConnection: close\r\nHost: api.mercadopago.com\r\nContent-Length: 140\r\n\r\n" + <- "{\"card_number\":\"[FILTERED]\",\"security_code\":\"[FILTERED]\",\"expiration_month\":9,\"expiration_year\":2018,\"cardholder\":{\"name\":\"Longbob Longsen\"}}" + -> "HTTP/1.1 201 Created\r\n" + -> "Access-Control-Allow-Origin: *\r\n" + -> "X-Request-Id: eb7a95a0-dccb-4580-9a69-534f6faf0bd6\r\n" + -> "Content-Type: application/json;charset=utf-8\r\n" + -> "Date: Thu, 13 Jul 2017 17:37:58 GMT\r\n" + -> "Connection: close\r\n" + -> "X-XSS-Protection: 1; mode=block\r\n" + -> "X-Content-Type-Options: nosniff\r\n" + -> "Strict-Transport-Security: max-age=16070400\r\n" + -> "Set-Cookie: TS016da221=0119b547a2244bba3789910575ac019d7d44d644026217ca433918a8c8fd9ff83de9d4b3c095adc76ee58870b56cd33041797db9e2; Path=/; Secure; HTTPOnly\r\n" + -> "Vary: Accept-Encoding, User-Agent\r\n" + -> "Content-Encoding: gzip\r\n" + -> "Transfer-Encoding: chunked\r\n" + -> "\r\n" + Conn close + opening connection to api.mercadopago.com:443... + opened + starting SSL for api.mercadopago.com:443... + SSL established + <- "POST /v1/payments?access_token=[FILTERED] HTTP/1.1\r\nContent-Type: application/json\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nAccept: */*\r\nUser-Agent: Ruby\r\nConnection: close\r\nHost: api.mercadopago.com\r\nContent-Length: 395\r\n\r\n" + <- "{\"transaction_amount\":5.0,\"description\":\"Store Purchase\",\"installments\":1,\"order\":{\"type\":\"mercadopago\",\"id\":2554731505684667137},\"token\":\"02ed9760103508d54361da8741a22a9e\",\"payment_method_id\":\"visa\",\"additional_info\":{\"payer\":{\"address\":{\"zip_code\":\"K1C2N6\",\"street_number\":\"456\",\"street_name\":\"My Street\"}}},\"payer\":{\"email\":\"user+br@example.com\",\"first_name\":\"Longbob\",\"last_name\":\"Longsen\"}}" + -> "HTTP/1.1 201 Created\r\n" + -> "Date: Thu, 13 Jul 2017 17:37:59 GMT\r\n" + -> "Content-Type: application/json;charset=UTF-8\r\n" + -> "Connection: close\r\n" + -> "X-Response-Status: approved/accredited\r\n" + -> "X-Caller-Id: 263489584\r\n" + -> "Vary: Accept,Accept-Encoding, User-Agent\r\n" + -> "Cache-Control: max-age=0\r\n" + -> "ETag: 1deee4b03ae344416c5863ac0d92c13e\r\n" + -> "X-Content-Type-Options: nosniff\r\n" + -> "X-Frame-Options: DENY\r\n" + -> "X-Request-Id: ccb324d1-8365-42dd-8e9a-734488220777\r\n" + -> "X-XSS-Protection: 1; mode=block\r\n" + -> "Strict-Transport-Security: max-age=15724800\r\n" + -> "Access-Control-Allow-Origin: *\r\n" + -> "Access-Control-Allow-Headers: Content-Type\r\n" + -> "Access-Control-Allow-Methods: PUT, GET, POST, DELETE, OPTIONS\r\n" + -> "Access-Control-Max-Age: 86400\r\n" + -> "Set-Cookie: TS016da221=0119b547a287375accd901052e4871cecbc881599be32e9bcb508701e62cabee4424801a25969778d1c93e2c57c2fd0a8a934c9817; Path=/; Secure; HTTPOnly\r\n" + -> "Content-Encoding: gzip\r\n" + -> "Transfer-Encoding: chunked\r\n" + -> "\r\n" + Conn close + ) + end + + def successful_purchase_response + %( + {"id":4141491,"date_created":"2017-07-06T09:49:35.000-04:00","date_approved":"2017-07-06T09:49:35.000-04:00","date_last_updated":"2017-07-06T09:49:35.000-04:00","date_of_expiration":null,"money_release_date":"2017-07-18T09:49:35.000-04:00","operation_type":"regular_payment","issuer_id":"166","payment_method_id":"visa","payment_type_id":"credit_card","status":"approved","status_detail":"accredited","currency_id":"MXN","description":"Store Purchase","live_mode":false,"sponsor_id":null,"authorization_code":null,"related_exchange_rate":null,"collector_id":261735089,"payer":{"type":"guest","id":null,"email":"user@example.com","identification":{"type":null,"number":null},"phone":{"area_code":null,"number":null,"extension":""},"first_name":"First User","last_name":"User","entity_type":null},"metadata":{},"additional_info":{"payer":{"address":{"zip_code":"K1C2N6","street_name":"My Street","street_number":"456"}}},"order":{"type":"mercadopago","id":"2326513804447055222"},"external_reference":null,"transaction_amount":5,"transaction_amount_refunded":0,"coupon_amount":0,"differential_pricing_id":null,"deduction_schema":null,"transaction_details":{"net_received_amount":0.14,"total_paid_amount":5,"overpaid_amount":0,"external_resource_url":null,"installment_amount":5,"financial_institution":null,"payment_method_reference_id":null,"payable_deferral_period":null,"acquirer_reference":null},"fee_details":[{"type":"mercadopago_fee","amount":4.86,"fee_payer":"collector"}],"captured":true,"binary_mode":false,"call_for_authorize_id":null,"statement_descriptor":"WWW.MERCADOPAGO.COM","installments":1,"card":{"id":null,"first_six_digits":"450995","last_four_digits":"3704","expiration_month":9,"expiration_year":2018,"date_created":"2017-07-06T09:49:35.000-04:00","date_last_updated":"2017-07-06T09:49:35.000-04:00","cardholder":{"name":"Longbob Longsen","identification":{"number":null,"type":null}}},"notification_url":null,"refunds":[],"processing_mode":null,"merchant_account_id":null,"acquirer":null,"merchant_number":null} + ) + end + + def failed_purchase_response + %( + {"id":4142297,"date_created":"2017-07-06T10:13:32.000-04:00","date_approved":null,"date_last_updated":"2017-07-06T10:13:32.000-04:00","date_of_expiration":null,"money_release_date":null,"operation_type":"regular_payment","issuer_id":"166","payment_method_id":"visa","payment_type_id":"credit_card","status":"rejected","status_detail":"cc_rejected_other_reason","currency_id":"MXN","description":"Store Purchase","live_mode":false,"sponsor_id":null,"authorization_code":null,"related_exchange_rate":null,"collector_id":261735089,"payer":{"type":"guest","id":null,"email":"user@example.com","identification":{"type":null,"number":null},"phone":{"area_code":null,"number":null,"extension":""},"first_name":"First User","last_name":"User","entity_type":null},"metadata":{},"additional_info":{"payer":{"address":{"zip_code":"K1C2N6","street_name":"My Street","street_number":"456"}}},"order":{"type":"mercadopago","id":"830943860538524456"},"external_reference":null,"transaction_amount":5,"transaction_amount_refunded":0,"coupon_amount":0,"differential_pricing_id":null,"deduction_schema":null,"transaction_details":{"net_received_amount":0,"total_paid_amount":5,"overpaid_amount":0,"external_resource_url":null,"installment_amount":5,"financial_institution":null,"payment_method_reference_id":null,"payable_deferral_period":null,"acquirer_reference":null},"fee_details":[],"captured":true,"binary_mode":false,"call_for_authorize_id":null,"statement_descriptor":"WWW.MERCADOPAGO.COM","installments":1,"card":{"id":null,"first_six_digits":"400030","last_four_digits":"2220","expiration_month":9,"expiration_year":2018,"date_created":"2017-07-06T10:13:32.000-04:00","date_last_updated":"2017-07-06T10:13:32.000-04:00","cardholder":{"name":"Longbob Longsen","identification":{"number":null,"type":null}}},"notification_url":null,"refunds":[],"processing_mode":null,"merchant_account_id":null,"acquirer":null,"merchant_number":null} + ) + end + + def successful_authorize_response + %( + {"id":4261941,"date_created":"2017-07-13T14:24:46.000-04:00","date_approved":null,"date_last_updated":"2017-07-13T14:24:46.000-04:00","date_of_expiration":null,"money_release_date":null,"operation_type":"regular_payment","issuer_id":"25","payment_method_id":"visa","payment_type_id":"credit_card","status":"authorized","status_detail":"pending_capture","currency_id":"BRL","description":"Store Purchase","live_mode":false,"sponsor_id":null,"authorization_code":null,"related_exchange_rate":null,"collector_id":263489584,"payer":{"type":"guest","id":null,"email":"user+br@example.com","identification":{"type":null,"number":null},"phone":{"area_code":null,"number":null,"extension":null},"first_name":null,"last_name":null,"entity_type":null},"metadata":{},"additional_info":{"payer":{"address":{"zip_code":"K1C2N6","street_name":"My Street","street_number":"456"}}},"order":{"type":"mercadopago","id":"2294029672081601730"},"external_reference":null,"transaction_amount":5,"transaction_amount_refunded":0,"coupon_amount":0,"differential_pricing_id":null,"deduction_schema":null,"transaction_details":{"net_received_amount":0,"total_paid_amount":5,"overpaid_amount":0,"external_resource_url":null,"installment_amount":5,"financial_institution":null,"payment_method_reference_id":null,"payable_deferral_period":null,"acquirer_reference":null},"fee_details":[],"captured":false,"binary_mode":false,"call_for_authorize_id":null,"statement_descriptor":"WWW.MERCADOPAGO.COM","installments":1,"card":{"id":null,"first_six_digits":"450995","last_four_digits":"3704","expiration_month":9,"expiration_year":2018,"date_created":"2017-07-13T14:24:46.000-04:00","date_last_updated":"2017-07-13T14:24:46.000-04:00","cardholder":{"name":"Longbob Longsen","identification":{"number":null,"type":null}}},"notification_url":null,"refunds":[],"processing_mode":"aggregator","merchant_account_id":null,"acquirer":null,"merchant_number":null} + ) + end + + def failed_authorize_response + %( + {"id":4261953,"date_created":"2017-07-13T14:25:33.000-04:00","date_approved":null,"date_last_updated":"2017-07-13T14:25:33.000-04:00","date_of_expiration":null,"money_release_date":null,"operation_type":"regular_payment","issuer_id":"25","payment_method_id":"visa","payment_type_id":"credit_card","status":"rejected","status_detail":"cc_rejected_other_reason","currency_id":"BRL","description":"Store Purchase","live_mode":false,"sponsor_id":null,"authorization_code":null,"related_exchange_rate":null,"collector_id":263489584,"payer":{"type":"guest","id":null,"email":"user+br@example.com","identification":{"type":null,"number":null},"phone":{"area_code":null,"number":null,"extension":null},"first_name":null,"last_name":null,"entity_type":null},"metadata":{},"additional_info":{"payer":{"address":{"zip_code":"K1C2N6","street_name":"My Street","street_number":"456"}}},"order":{"type":"mercadopago","id":"7528376941458928221"},"external_reference":null,"transaction_amount":5,"transaction_amount_refunded":0,"coupon_amount":0,"differential_pricing_id":null,"deduction_schema":null,"transaction_details":{"net_received_amount":0,"total_paid_amount":5,"overpaid_amount":0,"external_resource_url":null,"installment_amount":5,"financial_institution":null,"payment_method_reference_id":null,"payable_deferral_period":null,"acquirer_reference":null},"fee_details":[],"captured":false,"binary_mode":false,"call_for_authorize_id":null,"statement_descriptor":"WWW.MERCADOPAGO.COM","installments":1,"card":{"id":null,"first_six_digits":"400030","last_four_digits":"2220","expiration_month":9,"expiration_year":2018,"date_created":"2017-07-13T14:25:33.000-04:00","date_last_updated":"2017-07-13T14:25:33.000-04:00","cardholder":{"name":"Longbob Longsen","identification":{"number":null,"type":null}}},"notification_url":null,"refunds":[],"processing_mode":"aggregator","merchant_account_id":null,"acquirer":null,"merchant_number":null} + ) + end + + def successful_capture_response + %( + {"id":4261941,"date_created":"2017-07-13T14:24:46.000-04:00","date_approved":"2017-07-13T14:24:47.000-04:00","date_last_updated":"2017-07-13T14:24:47.000-04:00","date_of_expiration":null,"money_release_date":"2017-07-27T14:24:47.000-04:00","operation_type":"regular_payment","issuer_id":"25","payment_method_id":"visa","payment_type_id":"credit_card","status":"approved","status_detail":"accredited","currency_id":"BRL","description":"Store Purchase","live_mode":false,"sponsor_id":null,"authorization_code":null,"related_exchange_rate":null,"collector_id":263489584,"payer":{"type":"guest","id":null,"email":"user+br@example.com","identification":{"type":null,"number":null},"phone":{"area_code":null,"number":null,"extension":null},"first_name":null,"last_name":null,"entity_type":null},"metadata":{},"additional_info":{"payer":{"address":{"zip_code":"K1C2N6","street_name":"My Street","street_number":"456"}}},"order":{"type":"mercadopago","id":"2294029672081601730"},"external_reference":null,"transaction_amount":5,"transaction_amount_refunded":0,"coupon_amount":0,"differential_pricing_id":null,"deduction_schema":null,"transaction_details":{"net_received_amount":4.75,"total_paid_amount":5,"overpaid_amount":0,"external_resource_url":null,"installment_amount":5,"financial_institution":null,"payment_method_reference_id":null,"payable_deferral_period":null,"acquirer_reference":null},"fee_details":[{"type":"mercadopago_fee","amount":0.25,"fee_payer":"collector"}],"captured":true,"binary_mode":false,"call_for_authorize_id":null,"statement_descriptor":"WWW.MERCADOPAGO.COM","installments":1,"card":{"id":null,"first_six_digits":"450995","last_four_digits":"3704","expiration_month":9,"expiration_year":2018,"date_created":"2017-07-13T14:24:46.000-04:00","date_last_updated":"2017-07-13T14:24:46.000-04:00","cardholder":{"name":"Longbob Longsen","identification":{"number":null,"type":null}}},"notification_url":null,"refunds":[],"processing_mode":"aggregator","merchant_account_id":null,"acquirer":null,"merchant_number":null} + ) + end + + def failed_capture_response + %( + {"message":"Method not allowed","error":"method_not_allowed","status":405,"cause":[{"code":"Method not allowed","description":"Method not allowed","data":null}]} + ) + end + + def successful_refund_response + %( + {"id":4247757,"payment_id":4247751,"amount":5,"metadata":{},"source":{"id":"261735089","name":"Spreedly Integrations","type":"collector"},"date_created":"2017-07-12T14:45:08.752-04:00","unique_sequence_number":null} + ) + end + + def failed_refund_response + %( + {"message":"Resource /payments/refunds/ not found.","error":"not_found","status":404,"cause":[]} + ) + end + + def successful_void_response + %( + {"id":4261966,"date_created":"2017-07-13T14:26:56.000-04:00","date_approved":null,"date_last_updated":"2017-07-13T14:26:57.000-04:00","date_of_expiration":null,"money_release_date":null,"operation_type":"regular_payment","issuer_id":"25","payment_method_id":"visa","payment_type_id":"credit_card","status":"cancelled","status_detail":"by_collector","currency_id":"BRL","description":"Store Purchase","live_mode":false,"sponsor_id":null,"authorization_code":null,"related_exchange_rate":null,"collector_id":263489584,"payer":{"type":"guest","id":null,"email":"user+br@example.com","identification":{"type":null,"number":null},"phone":{"area_code":null,"number":null,"extension":null},"first_name":null,"last_name":null,"entity_type":null},"metadata":{},"additional_info":{"payer":{"address":{"zip_code":"K1C2N6","street_name":"My Street","street_number":"456"}}},"order":{"type":"mercadopago","id":"6688620487994029432"},"external_reference":null,"transaction_amount":5,"transaction_amount_refunded":0,"coupon_amount":0,"differential_pricing_id":null,"deduction_schema":null,"transaction_details":{"net_received_amount":0,"total_paid_amount":5,"overpaid_amount":0,"external_resource_url":null,"installment_amount":5,"financial_institution":null,"payment_method_reference_id":null,"payable_deferral_period":null,"acquirer_reference":null},"fee_details":[],"captured":false,"binary_mode":false,"call_for_authorize_id":null,"statement_descriptor":"WWW.MERCADOPAGO.COM","installments":1,"card":{"id":null,"first_six_digits":"450995","last_four_digits":"3704","expiration_month":9,"expiration_year":2018,"date_created":"2017-07-13T14:26:56.000-04:00","date_last_updated":"2017-07-13T14:26:56.000-04:00","cardholder":{"name":"Longbob Longsen","identification":{"number":null,"type":null}}},"notification_url":null,"refunds":[],"processing_mode":"aggregator","merchant_account_id":null,"acquirer":null,"merchant_number":null} + ) + end + + def failed_void_response + %( + {"message":"Method not allowed","error":"method_not_allowed","status":405,"cause":[{"code":"Method not allowed","description":"Method not allowed","data":null}]} + ) + end +end diff --git a/test/unit/gateways/merchant_e_solutions_test.rb b/test/unit/gateways/merchant_e_solutions_test.rb index a213ffde63c..9e073026c41 100644 --- a/test/unit/gateways/merchant_e_solutions_test.rb +++ b/test/unit/gateways/merchant_e_solutions_test.rb @@ -38,11 +38,11 @@ def test_unsuccessful_purchase end def test_purchase_with_long_order_id_truncates_id - options = {order_id: "thisislongerthan17characters"} + options = {order_id: 'thisislongerthan17characters'} @gateway.expects(:ssl_post).with( anything, all_of( - includes("invoice_number=thisislongerthan1"), + includes('invoice_number=thisislongerthan1') ) ).returns(successful_purchase_response) assert response = @gateway.purchase(@amount, @credit_card, options) @@ -103,42 +103,42 @@ def test_unstore def test_successful_avs_check @gateway.expects(:ssl_post).returns(successful_purchase_response + '&avs_result=Y') assert response = @gateway.purchase(@amount, @credit_card, @options) - assert_equal response.avs_result['code'], "Y" - assert_equal response.avs_result['message'], "Street address and 5-digit postal code match." - assert_equal response.avs_result['street_match'], "Y" - assert_equal response.avs_result['postal_match'], "Y" + assert_equal response.avs_result['code'], 'Y' + assert_equal response.avs_result['message'], 'Street address and 5-digit postal code match.' + assert_equal response.avs_result['street_match'], 'Y' + assert_equal response.avs_result['postal_match'], 'Y' end def test_unsuccessful_avs_check_with_bad_street_address @gateway.expects(:ssl_post).returns(successful_purchase_response + '&avs_result=Z') assert response = @gateway.purchase(@amount, @credit_card, @options) - assert_equal response.avs_result['code'], "Z" - assert_equal response.avs_result['message'], "Street address does not match, but 5-digit postal code matches." - assert_equal response.avs_result['street_match'], "N" - assert_equal response.avs_result['postal_match'], "Y" + assert_equal response.avs_result['code'], 'Z' + assert_equal response.avs_result['message'], 'Street address does not match, but 5-digit postal code matches.' + assert_equal response.avs_result['street_match'], 'N' + assert_equal response.avs_result['postal_match'], 'Y' end def test_unsuccessful_avs_check_with_bad_zip @gateway.expects(:ssl_post).returns(successful_purchase_response + '&avs_result=A') assert response = @gateway.purchase(@amount, @credit_card, @options) - assert_equal response.avs_result['code'], "A" - assert_equal response.avs_result['message'], "Street address matches, but 5-digit and 9-digit postal code do not match." - assert_equal response.avs_result['street_match'], "Y" - assert_equal response.avs_result['postal_match'], "N" + assert_equal response.avs_result['code'], 'A' + assert_equal response.avs_result['message'], 'Street address matches, but 5-digit and 9-digit postal code do not match.' + assert_equal response.avs_result['street_match'], 'Y' + assert_equal response.avs_result['postal_match'], 'N' end def test_successful_cvv_check @gateway.expects(:ssl_post).returns(successful_purchase_response + '&cvv2_result=M') assert response = @gateway.purchase(@amount, @credit_card, @options) - assert_equal response.cvv_result['code'], "M" - assert_equal response.cvv_result['message'], "CVV matches" + assert_equal response.cvv_result['code'], 'M' + assert_equal response.cvv_result['message'], 'CVV matches' end def test_unsuccessful_cvv_check @gateway.expects(:ssl_post).returns(failed_purchase_response + '&cvv2_result=N') assert response = @gateway.purchase(@amount, @credit_card, @options) - assert_equal response.cvv_result['code'], "N" - assert_equal response.cvv_result['message'], "CVV does not match" + assert_equal response.cvv_result['code'], 'N' + assert_equal response.cvv_result['message'], 'CVV does not match' end def test_visa_3dsecure_params_submitted @@ -167,6 +167,11 @@ def test_supported_card_types assert_equal [:visa, :master, :american_express, :discover, :jcb], MerchantESolutionsGateway.supported_cardtypes end + def test_scrub + assert @gateway.supports_scrubbing? + assert_equal @gateway.scrub(pre_scrubbed), post_scrubbed + end + private def successful_purchase_response @@ -200,4 +205,18 @@ def successful_unstore_response def failed_purchase_response 'transaction_id=error&error_code=101&auth_response_text=Invalid%20I%20or%20Key%20Incomplete%20Request' end + + def pre_scrubbed + <<-TRANSCRIPT + "profile_id=94100010518900000029&profile_key=YvKeIpxLxpJoKRKkJjMOpqmGkwUCBBEO&transaction_type=D&invoice_number=123&card_number=4111111111111111&cvv2=123&card_exp_date=0919&cardholder_street_address=123%2BState%2BStreet&cardholder_zip=55555&transaction_amount=1.00" + "transaction_id=3dfdc828adf032d589111ff45a7087fc&error_code=000&auth_response_text=Exact Match&avs_result=Y&cvv2_result=M&auth_code=T4797H" + TRANSCRIPT + end + + def post_scrubbed + <<-TRANSCRIPT + "profile_id=94100010518900000029&profile_key=[FILTERED]&transaction_type=D&invoice_number=123&card_number=[FILTERED]&cvv2=[FILTERED]&card_exp_date=0919&cardholder_street_address=123%2BState%2BStreet&cardholder_zip=55555&transaction_amount=1.00" + "transaction_id=3dfdc828adf032d589111ff45a7087fc&error_code=000&auth_response_text=Exact Match&avs_result=Y&cvv2_result=M&auth_code=T4797H" + TRANSCRIPT + end end diff --git a/test/unit/gateways/merchant_one_test.rb b/test/unit/gateways/merchant_one_test.rb index 839fc8ff8c5..16e3b879473 100644 --- a/test/unit/gateways/merchant_one_test.rb +++ b/test/unit/gateways/merchant_one_test.rb @@ -27,7 +27,7 @@ def test_successful_purchase assert response = @gateway.purchase(@amount, @credit_card, @options) assert_instance_of Response, response assert_success response - assert_equal "281719471", response.authorization + assert_equal '281719471', response.authorization assert response.test?, response.test.to_s end @@ -60,10 +60,10 @@ def test_unsuccessful_request private def successful_purchase_response - "response=1&responsetext=SUCCESS&authcode=123456&transactionid=281719471&avsresponse=&cvvresponse=M&orderid=&type=sale&response_code=100" + 'response=1&responsetext=SUCCESS&authcode=123456&transactionid=281719471&avsresponse=&cvvresponse=M&orderid=&type=sale&response_code=100' end def failed_purchase_response - "response=3&responsetext=DECLINE&authcode=123456&transactionid=281719471&avsresponse=&cvvresponse=M&orderid=&type=sale&response_code=300" + 'response=3&responsetext=DECLINE&authcode=123456&transactionid=281719471&avsresponse=&cvvresponse=M&orderid=&type=sale&response_code=300' end end diff --git a/test/unit/gateways/merchant_partners_test.rb b/test/unit/gateways/merchant_partners_test.rb index f1e48b964ba..3307fa37d61 100644 --- a/test/unit/gateways/merchant_partners_test.rb +++ b/test/unit/gateways/merchant_partners_test.rb @@ -1,19 +1,19 @@ -require "test_helper" -require "nokogiri" +require 'test_helper' +require 'nokogiri' class MerchantPartnersTest < Test::Unit::TestCase include CommStub def setup @gateway = MerchantPartnersGateway.new( - account_id: "TEST0", - merchant_pin: "1234567890" + account_id: 'TEST0', + merchant_pin: '1234567890' ) @credit_card = credit_card @amount = 100 - @request_root = "/interface_driver/trans_catalog/transaction/inputs" + @request_root = '/interface_driver/trans_catalog/transaction/inputs' end def test_successful_purchase @@ -22,19 +22,19 @@ def test_successful_purchase end.check_request do |endpoint, data, headers| parse(data) do |doc| assert_not_nil root = doc.at_xpath(@request_root) - assert_equal @gateway.options[:account_id], root.at_xpath("//acctid").content - assert_equal @gateway.options[:merchant_pin], root.at_xpath("//merchantpin").content - assert_equal @credit_card.name, root.at_xpath("//ccname").content - assert_equal @credit_card.number, root.at_xpath("//ccnum").content - assert_equal @credit_card.verification_value, root.at_xpath("//cvv2").content - assert_equal "2", root.at_xpath("//service").content - assert_equal "1.00", root.at_xpath("//amount").content + assert_equal @gateway.options[:account_id], root.at_xpath('//acctid').content + assert_equal @gateway.options[:merchant_pin], root.at_xpath('//merchantpin').content + assert_equal @credit_card.name, root.at_xpath('//ccname').content + assert_equal @credit_card.number, root.at_xpath('//ccnum').content + assert_equal @credit_card.verification_value, root.at_xpath('//cvv2').content + assert_equal '2', root.at_xpath('//service').content + assert_equal '1.00', root.at_xpath('//amount').content end end.respond_with(successful_purchase_response) assert_success response assert response.test? - assert_equal "398182213", response.authorization + assert_equal '398182213', response.authorization end def test_failed_purchase @@ -43,8 +43,8 @@ def test_failed_purchase end.respond_with(failed_purchase_response) assert_failure response - assert_equal "Invalid account number", response.message - assert response.params["result"].start_with?("DECLINED") + assert_equal 'Invalid account number', response.message + assert response.params['result'].start_with?('DECLINED') assert response.test? end @@ -54,36 +54,36 @@ def test_successful_authorize_and_capture end.check_request do |endpoint, data, headers| parse(data) do |doc| assert_not_nil root = doc.at_xpath(@request_root) - assert_equal @gateway.options[:account_id], root.at_xpath("//acctid").content - assert_equal @gateway.options[:merchant_pin], root.at_xpath("//merchantpin").content - assert_equal @credit_card.name, root.at_xpath("//ccname").content - assert_equal @credit_card.number, root.at_xpath("//ccnum").content - assert_equal @credit_card.verification_value, root.at_xpath("//cvv2").content - assert_equal "1", root.at_xpath("//service").content - assert_equal "1.00", root.at_xpath("//amount").content + assert_equal @gateway.options[:account_id], root.at_xpath('//acctid').content + assert_equal @gateway.options[:merchant_pin], root.at_xpath('//merchantpin').content + assert_equal @credit_card.name, root.at_xpath('//ccname').content + assert_equal @credit_card.number, root.at_xpath('//ccnum').content + assert_equal @credit_card.verification_value, root.at_xpath('//cvv2').content + assert_equal '1', root.at_xpath('//service').content + assert_equal '1.00', root.at_xpath('//amount').content end end.respond_with(successful_authorize_response) assert_success response assert response.test? - assert_equal "398047747", response.authorization + assert_equal '398047747', response.authorization capture = stub_comms do @gateway.capture(@amount, response.authorization) end.check_request do |endpoint, data, headers| parse(data) do |doc| assert_not_nil root = doc.at_xpath(@request_root) - assert_equal @gateway.options[:account_id], root.at_xpath("//acctid").content - assert_equal @gateway.options[:merchant_pin], root.at_xpath("//merchantpin").content - assert_equal response.authorization, root.at_xpath("//historykeyid").content - assert_equal "3", root.at_xpath("//service").content - assert_equal "1.00", root.at_xpath("//amount").content + assert_equal @gateway.options[:account_id], root.at_xpath('//acctid').content + assert_equal @gateway.options[:merchant_pin], root.at_xpath('//merchantpin').content + assert_equal response.authorization, root.at_xpath('//historykeyid').content + assert_equal '3', root.at_xpath('//service').content + assert_equal '1.00', root.at_xpath('//amount').content end end.respond_with(successful_capture_response) assert_success capture assert capture.test? - assert_equal "398044113", capture.authorization + assert_equal '398044113', capture.authorization end def test_failed_authorize @@ -92,14 +92,14 @@ def test_failed_authorize end.respond_with(failed_authorize_response) assert_failure response - assert_equal "Invalid account number", response.message - assert response.params["result"].start_with?("DECLINED") + assert_equal 'Invalid account number', response.message + assert response.params['result'].start_with?('DECLINED') assert response.test? end def test_failed_capture response = stub_comms do - @gateway.capture(100, "") + @gateway.capture(100, '') end.respond_with(failed_capture_response) assert_failure response @@ -111,17 +111,17 @@ def test_successful_void end.respond_with(successful_authorize_response) assert_success response - assert_equal "398047747", response.authorization + assert_equal '398047747', response.authorization void = stub_comms do @gateway.void(response.authorization) end.check_request do |endpoint, data, headers| parse(data) do |doc| assert_not_nil root = doc.at_xpath(@request_root) - assert_equal @gateway.options[:account_id], root.at_xpath("//acctid").content - assert_equal @gateway.options[:merchant_pin], root.at_xpath("//merchantpin").content - assert_equal response.authorization, root.at_xpath("//historykeyid").content - assert_equal "5", root.at_xpath("//service").content + assert_equal @gateway.options[:account_id], root.at_xpath('//acctid').content + assert_equal @gateway.options[:merchant_pin], root.at_xpath('//merchantpin').content + assert_equal response.authorization, root.at_xpath('//historykeyid').content + assert_equal '5', root.at_xpath('//service').content end end.respond_with(successful_void_response) @@ -130,7 +130,7 @@ def test_successful_void def test_failed_void response = stub_comms do - @gateway.void("5d53a33d960c46d00f5dc061947d998c") + @gateway.void('5d53a33d960c46d00f5dc061947d998c') end.respond_with(failed_void_response) assert_failure response @@ -148,11 +148,11 @@ def test_successful_refund end.check_request do |endpoint, data, headers| parse(data) do |doc| assert_not_nil root = doc.at_xpath(@request_root) - assert_equal @gateway.options[:account_id], root.at_xpath("//acctid").content - assert_equal @gateway.options[:merchant_pin], root.at_xpath("//merchantpin").content - assert_equal response.authorization, root.at_xpath("//historykeyid").content - assert_equal "4", root.at_xpath("//service").content - assert_equal "1.00", root.at_xpath("//amount").content + assert_equal @gateway.options[:account_id], root.at_xpath('//acctid').content + assert_equal @gateway.options[:merchant_pin], root.at_xpath('//merchantpin').content + assert_equal response.authorization, root.at_xpath('//historykeyid').content + assert_equal '4', root.at_xpath('//service').content + assert_equal '1.00', root.at_xpath('//amount').content end end.respond_with(successful_refund_response) @@ -161,7 +161,7 @@ def test_successful_refund def test_failed_refund response = stub_comms do - @gateway.refund(nil, "") + @gateway.refund(nil, '') end.respond_with(failed_refund_response) assert_failure response @@ -173,13 +173,13 @@ def test_successful_credit end.check_request do |endpoint, data, headers| parse(data) do |doc| assert_not_nil root = doc.at_xpath(@request_root) - assert_equal @gateway.options[:account_id], root.at_xpath("//acctid").content - assert_equal @gateway.options[:merchant_pin], root.at_xpath("//merchantpin").content - assert_equal @credit_card.name, root.at_xpath("//ccname").content - assert_equal @credit_card.number, root.at_xpath("//ccnum").content - assert_equal @credit_card.verification_value, root.at_xpath("//cvv2").content - assert_equal "6", root.at_xpath("//service").content - assert_equal "1.00", root.at_xpath("//amount").content + assert_equal @gateway.options[:account_id], root.at_xpath('//acctid').content + assert_equal @gateway.options[:merchant_pin], root.at_xpath('//merchantpin').content + assert_equal @credit_card.name, root.at_xpath('//ccname').content + assert_equal @credit_card.number, root.at_xpath('//ccnum').content + assert_equal @credit_card.verification_value, root.at_xpath('//cvv2').content + assert_equal '6', root.at_xpath('//service').content + assert_equal '1.00', root.at_xpath('//amount').content end end.respond_with(successful_credit_response) @@ -193,8 +193,8 @@ def test_failed_credit end.respond_with(failed_credit_response) assert_failure response - assert_equal "Invalid account number", response.message - assert response.params["result"].start_with?("DECLINED") + assert_equal 'Invalid account number', response.message + assert response.params['result'].start_with?('DECLINED') assert response.test? end @@ -203,7 +203,7 @@ def test_successful_verify @gateway.verify(@credit_card) end.respond_with(successful_authorize_response, failed_void_response) assert_success response - assert_equal "Succeeded", response.message + assert_equal 'Succeeded', response.message end def test_failed_verify @@ -211,7 +211,7 @@ def test_failed_verify @gateway.verify(@credit_card) end.respond_with(failed_authorize_response, successful_void_response) assert_failure response - assert_equal "Invalid account number", response.message + assert_equal 'Invalid account number', response.message end def test_successful_store @@ -220,18 +220,18 @@ def test_successful_store end.check_request do |endpoint, data, headers| parse(data) do |doc| assert_not_nil root = doc.at_xpath(@request_root) - assert_equal @gateway.options[:account_id], root.at_xpath("//acctid").content - assert_equal @gateway.options[:merchant_pin], root.at_xpath("//merchantpin").content - assert_equal @credit_card.name, root.at_xpath("//ccname").content - assert_equal @credit_card.number, root.at_xpath("//ccnum").content - assert_equal @credit_card.verification_value, root.at_xpath("//cvv2").content - assert_equal "7", root.at_xpath("//service").content + assert_equal @gateway.options[:account_id], root.at_xpath('//acctid').content + assert_equal @gateway.options[:merchant_pin], root.at_xpath('//merchantpin').content + assert_equal @credit_card.name, root.at_xpath('//ccname').content + assert_equal @credit_card.number, root.at_xpath('//ccnum').content + assert_equal @credit_card.verification_value, root.at_xpath('//cvv2').content + assert_equal '7', root.at_xpath('//service').content end end.respond_with(successful_store_response) assert_success response - assert_equal "Succeeded", response.message - assert_equal "17522090|6781", response.authorization + assert_equal 'Succeeded', response.message + assert_equal '17522090|6781', response.authorization assert response.test? end @@ -241,8 +241,8 @@ def test_successful_stored_purchase end.respond_with(successful_store_response) assert_success response - assert_equal "Succeeded", response.message - assert_equal "17522090|6781", response.authorization + assert_equal 'Succeeded', response.message + assert_equal '17522090|6781', response.authorization assert response.test? purchase = stub_comms do @@ -250,12 +250,12 @@ def test_successful_stored_purchase end.check_request do |endpoint, data, headers| parse(data) do |doc| assert_not_nil root = doc.at_xpath(@request_root) - assert_equal @gateway.options[:account_id], root.at_xpath("//acctid").content - assert_equal @gateway.options[:merchant_pin], root.at_xpath("//merchantpin").content - assert_equal response.params["userprofileid"], root.at_xpath("//userprofileid").content - assert_equal response.params["last4digits"], root.at_xpath("//last4digits").content - assert_equal "8", root.at_xpath("//service").content - assert_equal "1.00", root.at_xpath("//amount").content + assert_equal @gateway.options[:account_id], root.at_xpath('//acctid').content + assert_equal @gateway.options[:merchant_pin], root.at_xpath('//merchantpin').content + assert_equal response.params['userprofileid'], root.at_xpath('//userprofileid').content + assert_equal response.params['last4digits'], root.at_xpath('//last4digits').content + assert_equal '8', root.at_xpath('//service').content + assert_equal '1.00', root.at_xpath('//amount').content end end.respond_with(successful_purchase_response) @@ -269,8 +269,8 @@ def test_successful_stored_credit end.respond_with(successful_store_response) assert_success response - assert_equal "Succeeded", response.message - assert_equal "17522090|6781", response.authorization + assert_equal 'Succeeded', response.message + assert_equal '17522090|6781', response.authorization assert response.test? credit = stub_comms do @@ -278,12 +278,12 @@ def test_successful_stored_credit end.check_request do |endpoint, data, headers| parse(data) do |doc| assert_not_nil root = doc.at_xpath(@request_root) - assert_equal @gateway.options[:account_id], root.at_xpath("//acctid").content - assert_equal @gateway.options[:merchant_pin], root.at_xpath("//merchantpin").content - assert_equal response.params["userprofileid"], root.at_xpath("//userprofileid").content - assert_equal response.params["last4digits"], root.at_xpath("//last4digits").content - assert_equal "13", root.at_xpath("//service").content - assert_equal "1.00", root.at_xpath("//amount").content + assert_equal @gateway.options[:account_id], root.at_xpath('//acctid').content + assert_equal @gateway.options[:merchant_pin], root.at_xpath('//merchantpin').content + assert_equal response.params['userprofileid'], root.at_xpath('//userprofileid').content + assert_equal response.params['last4digits'], root.at_xpath('//last4digits').content + assert_equal '13', root.at_xpath('//service').content + assert_equal '1.00', root.at_xpath('//amount').content end end.respond_with(successful_purchase_response) @@ -297,8 +297,8 @@ def test_failed_store end.respond_with(failed_store_response) assert_failure response - assert_equal "Live Transactions Not Allowed", response.message - assert response.params["result"].start_with?("DECLINED") + assert_equal 'Live Transactions Not Allowed', response.message + assert response.params['result'].start_with?('DECLINED') assert response.test? end @@ -628,7 +628,6 @@ def failed_credit_response ) end - def successful_store_response %(<?xml version="1.0"?><interface_driver> <trans_catalog> diff --git a/test/unit/gateways/merchant_ware_test.rb b/test/unit/gateways/merchant_ware_test.rb index 9f19d3d3090..bfaf52f2462 100644 --- a/test/unit/gateways/merchant_ware_test.rb +++ b/test/unit/gateways/merchant_ware_test.rb @@ -27,12 +27,12 @@ def test_successful_authorization assert_success response assert_equal '4706382;1', response.authorization - assert_equal "APPROVED", response.message + assert_equal 'APPROVED', response.message assert response.test? end def test_soap_fault_during_authorization - response_500 = stub(:code => "500", :message => "Internal Server Error", :body => fault_authorization_response) + response_500 = stub(:code => '500', :message => 'Internal Server Error', :body => fault_authorization_response) @gateway.expects(:ssl_post).raises(ActiveMerchant::ResponseError.new(response_500)) assert response = @gateway.authorize(@amount, @credit_card, @options) @@ -41,9 +41,9 @@ def test_soap_fault_during_authorization assert response.test? assert_nil response.authorization - assert_equal "Server was unable to process request. ---> strPAN should be at least 13 to at most 19 characters in size. Parameter name: strPAN", response.message - assert_equal response_500.code, response.params["http_code"] - assert_equal response_500.message, response.params["http_message"] + assert_equal 'Server was unable to process request. ---> strPAN should be at least 13 to at most 19 characters in size. Parameter name: strPAN', response.message + assert_equal response_500.code, response.params['http_code'] + assert_equal response_500.message, response.params['http_message'] end def test_failed_authorization @@ -55,43 +55,43 @@ def test_failed_authorization assert response.test? assert_nil response.authorization - assert_equal "transaction type not supported by version", response.message - assert_equal "FAILED", response.params["status"] - assert_equal "1014", response.params["failure_code"] + assert_equal 'transaction type not supported by version', response.message + assert_equal 'FAILED', response.params['status'] + assert_equal '1014', response.params['failure_code'] end def test_credit - @gateway.expects(:ssl_post).with(anything, regexp_matches(/<strPAN>#{@credit_card.number}<\//), anything).returns("") + @gateway.expects(:ssl_post).with(anything, regexp_matches(/<strPAN>#{@credit_card.number}<\//), anything).returns('') @gateway.expects(:parse).returns({}) @gateway.credit(@amount, @credit_card, @options) end def test_deprecated_credit - @gateway.expects(:ssl_post).with(anything, regexp_matches(/<strReferenceCode>transaction_id<\//), anything).returns("") + @gateway.expects(:ssl_post).with(anything, regexp_matches(/<strReferenceCode>transaction_id<\//), anything).returns('') @gateway.expects(:parse).returns({}) assert_deprecation_warning(Gateway::CREDIT_DEPRECATION_MESSAGE) do - @gateway.credit(@amount, "transaction_id", @options) + @gateway.credit(@amount, 'transaction_id', @options) end end def test_refund - @gateway.expects(:ssl_post).with(anything, regexp_matches(/<strReferenceCode>transaction_id<\//), anything).returns("") + @gateway.expects(:ssl_post).with(anything, regexp_matches(/<strReferenceCode>transaction_id<\//), anything).returns('') @gateway.expects(:parse).returns({}) - @gateway.refund(@amount, "transaction_id", @options) + @gateway.refund(@amount, 'transaction_id', @options) end def test_failed_void @gateway.expects(:ssl_post).returns(failed_void_response) - assert response = @gateway.void("1") + assert response = @gateway.void('1') assert_instance_of Response, response assert_failure response assert response.test? assert_nil response.authorization - assert_equal "decline", response.message - assert_equal "DECLINED", response.params["status"] - assert_equal "1012", response.params["failure_code"] + assert_equal 'decline', response.message + assert_equal 'DECLINED', response.params['status'] + assert_equal '1012', response.params['failure_code'] end def test_avs_result @@ -109,12 +109,12 @@ def test_cvv_result end def test_add_swipe_data_with_creditcard - @credit_card.track_data = "Track Data" + @credit_card.track_data = 'Track Data' options = {:order_id => '1'} stub_comms do @gateway.authorize(@amount, @credit_card, options) end.check_request do |endpoint, data, headers| - assert_match "<trackData>Track Data</trackData>", data + assert_match '<trackData>Track Data</trackData>', data end.respond_with(successful_authorization_response) end diff --git a/test/unit/gateways/merchant_ware_version_four_test.rb b/test/unit/gateways/merchant_ware_version_four_test.rb index f30a7fef0c1..4119f8f63d9 100644 --- a/test/unit/gateways/merchant_ware_version_four_test.rb +++ b/test/unit/gateways/merchant_ware_version_four_test.rb @@ -26,12 +26,12 @@ def test_successful_authorization assert_success response assert_equal '1236564', response.authorization - assert_equal "APPROVED", response.message + assert_equal 'APPROVED', response.message assert response.test? end def test_soap_fault_during_authorization - response_400 = stub(:code => "400", :message => "Bad Request", :body => failed_authorize_response) + response_400 = stub(:code => '400', :message => 'Bad Request', :body => failed_authorize_response) @gateway.expects(:ssl_post).raises(ActiveMerchant::ResponseError.new(response_400)) assert response = @gateway.authorize(@amount, @credit_card, @options) @@ -40,9 +40,9 @@ def test_soap_fault_during_authorization assert response.test? assert_nil response.authorization - assert_equal "amount cannot be null. Parameter name: amount", response.message - assert_equal response_400.code, response.params["http_code"] - assert_equal response_400.message, response.params["http_message"] + assert_equal 'amount cannot be null. Parameter name: amount', response.message + assert_equal response_400.code, response.params['http_code'] + assert_equal response_400.message, response.params['http_message'] end def test_failed_authorization @@ -54,9 +54,9 @@ def test_failed_authorization assert response.test? assert_nil response.authorization - assert_equal "invalid exp date", response.message - assert_equal "DECLINED", response.params["status"] - assert_equal "1024", response.params["failure_code"] + assert_equal 'invalid exp date', response.message + assert_equal 'DECLINED', response.params['status'] + assert_equal '1024', response.params['failure_code'] end def test_failed_authorization_due_to_invalid_credit_card_number @@ -68,29 +68,29 @@ def test_failed_authorization_due_to_invalid_credit_card_number assert response.test? assert_nil response.authorization - assert_equal "Invalid card number.", response.message - assert_nil response.params["status"] - assert_nil response.params["failure_code"] + assert_equal 'Invalid card number.', response.message + assert_nil response.params['status'] + assert_nil response.params['failure_code'] end def test_refund - @gateway.expects(:ssl_post).with(anything, regexp_matches(/<token>transaction_id<\//), anything).returns("") + @gateway.expects(:ssl_post).with(anything, regexp_matches(/<token>transaction_id<\//), anything).returns('') @gateway.expects(:parse).returns({}) - @gateway.refund(@amount, "transaction_id", @options) + @gateway.refund(@amount, 'transaction_id', @options) end def test_failed_void @gateway.expects(:ssl_post).returns(failed_void_response) - assert response = @gateway.void("1") + assert response = @gateway.void('1') assert_instance_of Response, response assert_failure response assert response.test? assert_nil response.authorization - assert_equal "original transaction id not found", response.message - assert_equal "DECLINED", response.params["status"] - assert_equal "1019", response.params["failure_code"] + assert_equal 'original transaction id not found', response.message + assert_equal 'DECLINED', response.params['status'] + assert_equal '1019', response.params['failure_code'] end def test_avs_result @@ -115,7 +115,7 @@ def test_successful_purchase_using_prior_transaction assert_success response assert_equal '1236564', response.authorization - assert_equal "APPROVED", response.message + assert_equal 'APPROVED', response.message assert response.test? end diff --git a/test/unit/gateways/merchant_warrior_test.rb b/test/unit/gateways/merchant_warrior_test.rb index 17e098d5849..2d718e7da74 100644 --- a/test/unit/gateways/merchant_warrior_test.rb +++ b/test/unit/gateways/merchant_warrior_test.rb @@ -28,7 +28,7 @@ def test_successful_purchase assert_success response assert_equal 'Transaction approved', response.message assert response.test? - assert_equal "30-98a79008-dae8-11df-9322-0022198101cd", response.authorization + assert_equal '30-98a79008-dae8-11df-9322-0022198101cd', response.authorization end def test_failed_purchase @@ -38,7 +38,7 @@ def test_failed_purchase assert_failure response assert_equal 'Card has expired', response.message assert response.test? - assert_equal "30-69433444-af1-11df-9322-0022198101cd", response.authorization + assert_equal '30-69433444-af1-11df-9322-0022198101cd', response.authorization end def test_successful_refund @@ -48,7 +48,7 @@ def test_successful_refund assert_success response assert_equal 'Transaction approved', response.message assert response.test? - assert_equal "30-d4d19f4-db17-11df-9322-0022198101cd", response.authorization + assert_equal '30-d4d19f4-db17-11df-9322-0022198101cd', response.authorization end def test_failed_refund @@ -62,8 +62,8 @@ def test_failed_refund end def test_successful_store - @credit_card.month = "2" - @credit_card.year = "2005" + @credit_card.month = '2' + @credit_card.year = '2005' store = stub_comms do @gateway.store(@credit_card, @options) @@ -73,14 +73,14 @@ def test_successful_store end.respond_with(successful_store_response) assert_success store - assert_equal "Operation successful", store.message - assert_match "KOCI10023982", store.authorization + assert_equal 'Operation successful', store.message + assert_match 'KOCI10023982', store.authorization end def test_scrub_name @credit_card.first_name = "Chars; Merchant-Warrior Don't Like" - @credit_card.last_name = "& More. # Here" - @options[:address][:name] = "Ren & Stimpy" + @credit_card.last_name = '& More. # Here' + @options[:address][:name] = 'Ren & Stimpy' stub_comms do @gateway.purchase(@success_amount, @credit_card, @options) @@ -90,14 +90,60 @@ def test_scrub_name end.respond_with(successful_purchase_response) end + def test_address + @options[:address] = { + name: 'Bat Man', + address1: '123 Main', + city: 'Brooklyn', + state: 'NY', + country: 'US', + zip: '11111', + phone: '555-1212', + email: 'user@aol.com', + ip: '1.2.3.4' + } + + stub_comms do + @gateway.purchase(@success_amount, @credit_card, @options) + end.check_request do |endpoint, data, headers| + assert_match(/customerName=Bat\+Man/, data) + assert_match(/customerCountry=US/, data) + assert_match(/customerState=NY/, data) + assert_match(/customerCity=Brooklyn/, data) + assert_match(/customerAddress=123\+Main/, data) + assert_match(/customerPostCode=11111/, data) + assert_match(/customerIP=1.2.3.4/, data) + assert_match(/customerPhone=555-1212/, data) + assert_match(/customerEmail=user%40aol.com/, data) + end.respond_with(successful_purchase_response) + end + + def test_address_without_state + @options[:address] = { + name: 'Bat Man', + state: nil + } + + stub_comms do + @gateway.purchase(@success_amount, @credit_card, @options) + end.check_request do |endpoint, data, headers| + assert_match(/customerState=N%2FA/, data) + end.respond_with(successful_purchase_response) + end + def test_orderid_truncated stub_comms do - @gateway.purchase(@success_amount, @credit_card, order_id: "ThisIsQuiteALongDescriptionWithLotsOfChars") + @gateway.purchase(@success_amount, @credit_card, order_id: 'ThisIsQuiteALongDescriptionWithLotsOfChars') end.check_request do |endpoint, data, headers| assert_match(/transactionProduct=ThisIsQuiteALongDescriptionWithLot&/, data) end.respond_with(successful_purchase_response) end + def test_scrub + assert @gateway.supports_scrubbing? + assert_equal @gateway.scrub(pre_scrubbed), post_scrubbed + end + private def successful_purchase_response @@ -175,4 +221,12 @@ def successful_store_response </mwResponse> XML end + + def pre_scrubbed + 'transactionAmount=1.00&transactionCurrency=AUD&hash=adb50f6ff360f861e6f525e8daae76b5&transactionProduct=98fc25d40a47f3d24da460c0ca307c&customerName=Longbob+Longsen&customerCountry=AU&customerState=Queensland&customerCity=Brisbane&customerAddress=123+test+st&customerPostCode=4000&customerIP=&customerPhone=&customerEmail=&paymentCardNumber=5123456789012346&paymentCardName=Longbob+Longsen&paymentCardExpiry=0520&paymentCardCSC=123&merchantUUID=51f7da294af8f&apiKey=nooudtd0&method=processCard' + end + + def post_scrubbed + 'transactionAmount=1.00&transactionCurrency=AUD&hash=adb50f6ff360f861e6f525e8daae76b5&transactionProduct=98fc25d40a47f3d24da460c0ca307c&customerName=Longbob+Longsen&customerCountry=AU&customerState=Queensland&customerCity=Brisbane&customerAddress=123+test+st&customerPostCode=4000&customerIP=&customerPhone=&customerEmail=&paymentCardNumber=[FILTERED]&paymentCardName=Longbob+Longsen&paymentCardExpiry=0520&paymentCardCSC=[FILTERED]&merchantUUID=51f7da294af8f&apiKey=[FILTERED]&method=processCard' + end end diff --git a/test/unit/gateways/mercury_test.rb b/test/unit/gateways/mercury_test.rb index 5b756f07ee7..e7d298f52b4 100644 --- a/test/unit/gateways/mercury_test.rb +++ b/test/unit/gateways/mercury_test.rb @@ -9,7 +9,7 @@ def setup @gateway = MercuryGateway.new(fixtures(:mercury)) @amount = 100 - @credit_card = credit_card("5499990123456781", :brand => "master") + @credit_card = credit_card('5499990123456781', :brand => 'master') @declined_card = credit_card('4000300011112220') @options = { @@ -64,7 +64,7 @@ def test_successful_refund end def test_card_present_with_track_1_data - track_data = "%B4003000123456781^LONGSEN/L. ^15121200000000000000123?" + track_data = '%B4003000123456781^LONGSEN/L. ^15121200000000000000123?' @credit_card.track_data = track_data response = stub_comms do @gateway.purchase(@amount, @credit_card, @options) @@ -77,8 +77,8 @@ def test_card_present_with_track_1_data end def test_card_present_with_track_2_data - track_data = ";5413330089010608=2512101097750213?" - stripped_track_data = "5413330089010608=2512101097750213" + track_data = ';5413330089010608=2512101097750213?' + stripped_track_data = '5413330089010608=2512101097750213' @credit_card.track_data = track_data response = stub_comms do @gateway.purchase(@amount, @credit_card, @options) @@ -91,8 +91,8 @@ def test_card_present_with_track_2_data end def test_card_present_with_max_length_track_1_data - track_data = "%B373953192351004^CARDUSER/JOHN^200910100000019301000000877000000930001234567?" - stripped_data = "B373953192351004^CARDUSER/JOHN^200910100000019301000000877000000930001234567" + track_data = '%B373953192351004^CARDUSER/JOHN^200910100000019301000000877000000930001234567?' + stripped_data = 'B373953192351004^CARDUSER/JOHN^200910100000019301000000877000000930001234567' @credit_card.track_data = track_data response = stub_comms do @gateway.purchase(@amount, @credit_card, @options) @@ -105,7 +105,7 @@ def test_card_present_with_max_length_track_1_data end def test_card_present_with_invalid_data - track_data = "this is not valid track data" + track_data = 'this is not valid track data' @credit_card.track_data = track_data response = stub_comms do @gateway.purchase(@amount, @credit_card, @options) @@ -117,91 +117,144 @@ def test_card_present_with_invalid_data assert_success response end + def test_transcript_scrubbing + assert @gateway.supports_scrubbing? + assert_equal @gateway.scrub(pre_scrub), post_scrub + end + private def successful_purchase_response <<-RESPONSE -<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><soap:Body><CreditTransactionResponse xmlns="http://www.mercurypay.com"><CreditTransactionResult>&lt;?xml version="1.0"?&gt; -&lt;RStream&gt; - &lt;CmdResponse&gt; - &lt;ResponseOrigin&gt;Processor&lt;/ResponseOrigin&gt; - &lt;DSIXReturnCode&gt;000000&lt;/DSIXReturnCode&gt; - &lt;CmdStatus&gt;Approved&lt;/CmdStatus&gt; - &lt;TextResponse&gt;AP*&lt;/TextResponse&gt; - &lt;UserTraceData&gt;&lt;/UserTraceData&gt; - &lt;/CmdResponse&gt; - &lt;TranResponse&gt; - &lt;MerchantID&gt;595901&lt;/MerchantID&gt; - &lt;AcctNo&gt;5499990123456781&lt;/AcctNo&gt; - &lt;ExpDate&gt;0813&lt;/ExpDate&gt; - &lt;CardType&gt;M/C&lt;/CardType&gt; - &lt;TranCode&gt;Sale&lt;/TranCode&gt; - &lt;AuthCode&gt;000011&lt;/AuthCode&gt; - &lt;CaptureStatus&gt;Captured&lt;/CaptureStatus&gt; - &lt;RefNo&gt;0194&lt;/RefNo&gt; - &lt;InvoiceNo&gt;1&lt;/InvoiceNo&gt; - &lt;AVSResult&gt;Y&lt;/AVSResult&gt; - &lt;CVVResult&gt;M&lt;/CVVResult&gt; - &lt;OperatorID&gt;999&lt;/OperatorID&gt; - &lt;Memo&gt;LM Integration (Ruby)&lt;/Memo&gt; - &lt;Amount&gt; - &lt;Purchase&gt;1.00&lt;/Purchase&gt; - &lt;Authorize&gt;1.00&lt;/Authorize&gt; - &lt;/Amount&gt; - &lt;AcqRefData&gt;KbMCC0742510421 &lt;/AcqRefData&gt; - &lt;ProcessData&gt;|17|410100700000&lt;/ProcessData&gt; - &lt;/TranResponse&gt; -&lt;/RStream&gt; +<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><soap:Body><CreditTransactionResponse xmlns="http://www.mercurypay.com"><CreditTransactionResult><?xml version="1.0"?> +<RStream> + <CmdResponse> + <ResponseOrigin>Processor</ResponseOrigin> + <DSIXReturnCode>000000</DSIXReturnCode> + <CmdStatus>Approved</CmdStatus> + <TextResponse>AP*</TextResponse> + <UserTraceData></UserTraceData> + </CmdResponse> + <TranResponse> + <MerchantID>595901</MerchantID> + <AcctNo>5499990123456781</AcctNo> + <ExpDate>0813</ExpDate> + <CardType>M/C</CardType> + <TranCode>Sale</TranCode> + <AuthCode>000011</AuthCode> + <CaptureStatus>Captured</CaptureStatus> + <RefNo>0194</RefNo> + <InvoiceNo>1</InvoiceNo> + <AVSResult>Y</AVSResult> + <CVVResult>M</CVVResult> + <OperatorID>999</OperatorID> + <Memo>LM Integration (Ruby)</Memo> + <Amount> + <Purchase>1.00</Purchase> + <Authorize>1.00</Authorize> + </Amount> + <AcqRefData>KbMCC0742510421 </AcqRefData> + <ProcessData>|17|410100700000</ProcessData> + </TranResponse> +</RStream> </CreditTransactionResult></CreditTransactionResponse></soap:Body></soap:Envelope> RESPONSE end def failed_purchase_response <<-RESPONSE -<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><soap:Body><CreditTransactionResponse xmlns="http://www.mercurypay.com"><CreditTransactionResult>&lt;?xml version="1.0"?&gt; -&lt;RStream&gt; - &lt;CmdResponse&gt; - &lt;ResponseOrigin&gt;Server&lt;/ResponseOrigin&gt; - &lt;DSIXReturnCode&gt;000000&lt;/DSIXReturnCode&gt; - &lt;CmdStatus&gt;Error&lt;/CmdStatus&gt; - &lt;TextResponse&gt;No Live Cards on Test Merchant ID Allowed.&lt;/TextResponse&gt; - &lt;UserTraceData&gt;&lt;/UserTraceData&gt; - &lt;/CmdResponse&gt; -&lt;/RStream&gt; +<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><soap:Body><CreditTransactionResponse xmlns="http://www.mercurypay.com"><CreditTransactionResult><?xml version="1.0"?> +<RStream> + <CmdResponse> + <ResponseOrigin>Server</ResponseOrigin> + <DSIXReturnCode>000000</DSIXReturnCode> + <CmdStatus>Error</CmdStatus> + <TextResponse>No Live Cards on Test Merchant ID Allowed.</TextResponse> + <UserTraceData></UserTraceData> + </CmdResponse> +</RStream> </CreditTransactionResult></CreditTransactionResponse></soap:Body></soap:Envelope> RESPONSE end def successful_refund_response <<-RESPONSE -<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><soap:Body><CreditTransactionResponse xmlns="http://www.mercurypay.com"><CreditTransactionResult>&lt;?xml version="1.0"?&gt; -&lt;RStream&gt; - &lt;CmdResponse&gt; - &lt;ResponseOrigin&gt;Processor&lt;/ResponseOrigin&gt; - &lt;DSIXReturnCode&gt;000000&lt;/DSIXReturnCode&gt; - &lt;CmdStatus&gt;Approved&lt;/CmdStatus&gt; - &lt;TextResponse&gt;AP&lt;/TextResponse&gt; - &lt;UserTraceData&gt;&lt;/UserTraceData&gt; - &lt;/CmdResponse&gt; - &lt;TranResponse&gt; - &lt;MerchantID&gt;595901&lt;/MerchantID&gt; - &lt;AcctNo&gt;5499990123456781&lt;/AcctNo&gt; - &lt;ExpDate&gt;0813&lt;/ExpDate&gt; - &lt;CardType&gt;M/C&lt;/CardType&gt; - &lt;TranCode&gt;VoidSale&lt;/TranCode&gt; - &lt;AuthCode&gt;VOIDED&lt;/AuthCode&gt; - &lt;CaptureStatus&gt;Captured&lt;/CaptureStatus&gt; - &lt;RefNo&gt;0568&lt;/RefNo&gt; - &lt;InvoiceNo&gt;123&lt;/InvoiceNo&gt; - &lt;OperatorID&gt;999&lt;/OperatorID&gt; - &lt;Amount&gt; - &lt;Purchase&gt;1.00&lt;/Purchase&gt; - &lt;Authorize&gt;1.00&lt;/Authorize&gt; - &lt;/Amount&gt; - &lt;AcqRefData&gt;K&lt;/AcqRefData&gt; - &lt;/TranResponse&gt; -&lt;/RStream&gt; +<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><soap:Body><CreditTransactionResponse xmlns="http://www.mercurypay.com"><CreditTransactionResult><?xml version="1.0"?> +<RStream> + <CmdResponse> + <ResponseOrigin>Processor</ResponseOrigin> + <DSIXReturnCode>000000</DSIXReturnCode> + <CmdStatus>Approved</CmdStatus> + <TextResponse>AP</TextResponse> + <UserTraceData></UserTraceData> + </CmdResponse> + <TranResponse> + <MerchantID>595901</MerchantID> + <AcctNo>5499990123456781</AcctNo> + <ExpDate>0813</ExpDate> + <CardType>M/C</CardType> + <TranCode>VoidSale</TranCode> + <AuthCode>VOIDED</AuthCode> + <CaptureStatus>Captured</CaptureStatus> + <RefNo>0568</RefNo> + <InvoiceNo>123</InvoiceNo> + <OperatorID>999</OperatorID> + <Amount> + <Purchase>1.00</Purchase> + <Authorize>1.00</Authorize> + </Amount> + <AcqRefData>K</AcqRefData> + </TranResponse> +</RStream> </CreditTransactionResult></CreditTransactionResponse></soap:Body></soap:Envelope> RESPONSE end + + def pre_scrub + %q{ +opening connection to w1.mercurycert.net:443... +opened +starting SSL for w1.mercurycert.net:443... +SSL established +<- "POST /ws/ws.asmx HTTP/1.1\r\nContent-Type: text/xml; charset=utf-8\r\nSoapaction: http://www.mercurypay.com/CreditTransaction\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nAccept: */*\r\nUser-Agent: Ruby\r\nConnection: close\r\nHost: w1.mercurycert.net\r\nContent-Length: 823\r\n\r\n" +<- "<?xml version=\"1.0\" encoding=\"UTF-8\"?><soap:Envelope xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"><soap:Body><CreditTransaction xmlns=\"http://www.mercurypay.com\"><tran>\n<![CDATA[\n<TStream><Transaction><TranType>Credit</TranType><TranCode>Sale</TranCode><InvoiceNo>c111111111.1</InvoiceNo><RefNo>c111111111.1</RefNo><Memo>ActiveMerchant</Memo><Frequency>OneTime</Frequency><RecordNo>RecordNumberRequested</RecordNo><MerchantID>089716741701445</MerchantID><Amount><Purchase>1.00</Purchase></Amount><Account><AcctNo>4003000123456781</AcctNo><ExpDate>1218</ExpDate></Account><CardType>VISA</CardType><CVVData>123</CVVData></Transaction></TStream>\n]]>\n</tran><pw>xyz</pw></CreditTransaction></soap:Body></soap:Envelope>" +-> "HTTP/1.1 200 OK\r\n" +-> "Cache-Control: private, max-age=0\r\n" +-> "Content-Type: text/xml; charset=utf-8\r\n" +-> "X-AspNet-Version: 4.0.30319\r\n" +-> "X-Powered-By: ASP.NET\r\n" +-> "Date: Mon, 08 Jan 2018 19:49:31 GMT\r\n" +-> "Connection: close\r\n" +-> "Content-Length: 1648\r\n" +-> "\r\n" +reading 1648 bytes... +-> "<?xml version=\"1.0\" encoding=\"utf-8\"?><soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"><soap:Body><CreditTransactionResponse xmlns=\"http://www.mercurypay.com\"><CreditTransactionResult><?xml version=\"1.0\"?>\r\n<RStream>\r\n\t<CmdResponse>\r\n\t\t<ResponseOrigin>Processor</ResponseOrigin>\r\n\t\t<DSIXReturnCode>000000</DSIXReturnCode>\r\n\t\t<CmdStatus>Approved</CmdStatus>\r\n\t\t<TextResponse>AP*</TextResponse>\r\n\t\t<UserTraceData></UserTraceData>\r\n\t</CmdResponse>\r\n\t<TranResponse>\r\n\t\t<MerchantID>089716741701445</MerchantID>\r\n\t\t<AcctNo>400300XXXXXX6781</AcctNo>\r\n\t\t<ExpDate>XXXX</ExpDate>\r\n\t\t<CardType>VISA</CardType>\r\n\t\t<TranCode>Sale</TranCode>\r\n\t\t<AuthCode>VI0100</AuthCode>\r\n\t\t<CaptureStatus>Captured</CaptureStatus>\r\n\t\t<RefNo>0001</RefNo>\r\n\t\t<InvoiceNo>C111111111.1</InvoiceNo>\r\n\t\t<CVVResult>U</CVVResult>\r\n\t\t<Memo>ActiveMerchant</Memo>\r\n\t\t<Amount>\r\n\t\t\t<Purchase>1.00</Purchase>\r\n\t\t\t<Authorize>1.00</Authorize>\r\n\t\t</Amount>\r\n\t\t<AcqRefData>KaNb018008177003332cABCAd5e00fJlA m000005</AcqRefData>\r\n\t\t<RecordNo>win4rRFHp8+AV/vstAfKvsUvZ5IH+bHblTktfumnY/EiEgUQFyIQGjMM</RecordNo>\r\n\t\t<ProcessData>|00|600550672000</ProcessData>\r\n\t</TranResponse>\r\n</RStream>\r\n</CreditTransactionResult></CreditTransactionResponse></soap:Body></soap:Envelope>" +read 1648 bytes +Conn close + } + end + + def post_scrub + %q{ +opening connection to w1.mercurycert.net:443... +opened +starting SSL for w1.mercurycert.net:443... +SSL established +<- "POST /ws/ws.asmx HTTP/1.1\r\nContent-Type: text/xml; charset=utf-8\r\nSoapaction: http://www.mercurypay.com/CreditTransaction\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nAccept: */*\r\nUser-Agent: Ruby\r\nConnection: close\r\nHost: w1.mercurycert.net\r\nContent-Length: 823\r\n\r\n" +<- "<?xml version=\"1.0\" encoding=\"UTF-8\"?><soap:Envelope xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"><soap:Body><CreditTransaction xmlns=\"http://www.mercurypay.com\"><tran>\n<![CDATA[\n<TStream><Transaction><TranType>Credit</TranType><TranCode>Sale</TranCode><InvoiceNo>c111111111.1</InvoiceNo><RefNo>c111111111.1</RefNo><Memo>ActiveMerchant</Memo><Frequency>OneTime</Frequency><RecordNo>RecordNumberRequested</RecordNo><MerchantID>089716741701445</MerchantID><Amount><Purchase>1.00</Purchase></Amount><Account><AcctNo>[FILTERED]</AcctNo><ExpDate>1218</ExpDate></Account><CardType>VISA</CardType><CVVData>[FILTERED]</CVVData></Transaction></TStream>\n]]>\n</tran><pw>[FILTERED]</pw></CreditTransaction></soap:Body></soap:Envelope>" +-> "HTTP/1.1 200 OK\r\n" +-> "Cache-Control: private, max-age=0\r\n" +-> "Content-Type: text/xml; charset=utf-8\r\n" +-> "X-AspNet-Version: 4.0.30319\r\n" +-> "X-Powered-By: ASP.NET\r\n" +-> "Date: Mon, 08 Jan 2018 19:49:31 GMT\r\n" +-> "Connection: close\r\n" +-> "Content-Length: 1648\r\n" +-> "\r\n" +reading 1648 bytes... +-> "<?xml version=\"1.0\" encoding=\"utf-8\"?><soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"><soap:Body><CreditTransactionResponse xmlns=\"http://www.mercurypay.com\"><CreditTransactionResult><?xml version=\"1.0\"?>\r\n<RStream>\r\n\t<CmdResponse>\r\n\t\t<ResponseOrigin>Processor</ResponseOrigin>\r\n\t\t<DSIXReturnCode>000000</DSIXReturnCode>\r\n\t\t<CmdStatus>Approved</CmdStatus>\r\n\t\t<TextResponse>AP*</TextResponse>\r\n\t\t<UserTraceData></UserTraceData>\r\n\t</CmdResponse>\r\n\t<TranResponse>\r\n\t\t<MerchantID>089716741701445</MerchantID>\r\n\t\t<AcctNo>[FILTERED]</AcctNo>\r\n\t\t<ExpDate>XXXX</ExpDate>\r\n\t\t<CardType>VISA</CardType>\r\n\t\t<TranCode>Sale</TranCode>\r\n\t\t<AuthCode>VI0100</AuthCode>\r\n\t\t<CaptureStatus>Captured</CaptureStatus>\r\n\t\t<RefNo>0001</RefNo>\r\n\t\t<InvoiceNo>C111111111.1</InvoiceNo>\r\n\t\t<CVVResult>U</CVVResult>\r\n\t\t<Memo>ActiveMerchant</Memo>\r\n\t\t<Amount>\r\n\t\t\t<Purchase>1.00</Purchase>\r\n\t\t\t<Authorize>1.00</Authorize>\r\n\t\t</Amount>\r\n\t\t<AcqRefData>KaNb018008177003332cABCAd5e00fJlA m000005</AcqRefData>\r\n\t\t<RecordNo>win4rRFHp8+AV/vstAfKvsUvZ5IH+bHblTktfumnY/EiEgUQFyIQGjMM</RecordNo>\r\n\t\t<ProcessData>|00|600550672000</ProcessData>\r\n\t</TranResponse>\r\n</RStream>\r\n</CreditTransactionResult></CreditTransactionResponse></soap:Body></soap:Envelope>" +read 1648 bytes +Conn close + } + end end diff --git a/test/unit/gateways/metrics_global_test.rb b/test/unit/gateways/metrics_global_test.rb index 04e8d7ed20c..0184ddfbeff 100644 --- a/test/unit/gateways/metrics_global_test.rb +++ b/test/unit/gateways/metrics_global_test.rb @@ -44,9 +44,9 @@ def test_failed_authorization def test_add_address_outsite_north_america result = {} - @gateway.send(:add_address, result, :billing_address => {:address1 => '164 Waverley Street', :country => 'DE', :state => ''} ) + @gateway.send(:add_address, result, :billing_address => {:address1 => '164 Waverley Street', :country => 'DE', :state => ''}) - assert_equal ["address", "city", "company", "country", "phone", "state", "zip"], result.stringify_keys.keys.sort + assert_equal ['address', 'city', 'company', 'country', 'phone', 'state', 'zip'], result.stringify_keys.keys.sort assert_equal 'n/a', result[:state] assert_equal '164 Waverley Street', result[:address] assert_equal 'DE', result[:country] @@ -55,13 +55,12 @@ def test_add_address_outsite_north_america def test_add_address result = {} - @gateway.send(:add_address, result, :billing_address => {:address1 => '164 Waverley Street', :country => 'US', :state => 'CO'} ) + @gateway.send(:add_address, result, :billing_address => {:address1 => '164 Waverley Street', :country => 'US', :state => 'CO'}) - assert_equal ["address", "city", "company", "country", "phone", "state", "zip"], result.stringify_keys.keys.sort + assert_equal ['address', 'city', 'company', 'country', 'phone', 'state', 'zip'], result.stringify_keys.keys.sort assert_equal 'CO', result[:state] assert_equal '164 Waverley Street', result[:address] assert_equal 'US', result[:country] - end def test_add_invoice @@ -91,17 +90,17 @@ def test_add_duplicate_window_with_duplicate_window end def test_purchase_is_valid_csv - params = { :amount => '1.01' } + params = { :amount => '1.01' } - @gateway.send(:add_creditcard, params, @credit_card) + @gateway.send(:add_creditcard, params, @credit_card) - assert data = @gateway.send(:post_data, 'AUTH_ONLY', params) - assert_equal post_data_fixture.size, data.size + assert data = @gateway.send(:post_data, 'AUTH_ONLY', params) + assert_equal post_data_fixture.size, data.size end def test_purchase_meets_minimum_requirements params = { - :amount => "1.01", + :amount => '1.01', } @gateway.send(:add_creditcard, params, @credit_card) @@ -121,7 +120,7 @@ def test_successful_refund def test_refund_passing_extra_info response = stub_comms do - @gateway.refund(50, '123456789', :card_number => @credit_card.number, :first_name => "Bob", :last_name => "Smith", :zip => "12345") + @gateway.refund(50, '123456789', :card_number => @credit_card.number, :first_name => 'Bob', :last_name => 'Smith', :zip => '12345') end.check_request do |endpoint, data, headers| assert_match(/x_first_name=Bob/, data) assert_match(/x_last_name=Smith/, data) @@ -167,7 +166,7 @@ def test_response_under_review_by_fraud_service response = @gateway.purchase(@amount, @credit_card) assert_failure response assert response.fraud_review? - assert_equal "Thank you! For security reasons your order is currently being reviewed", response.message + assert_equal 'Thank you! For security reasons your order is currently being reviewed', response.message end def test_avs_result @@ -195,13 +194,13 @@ def test_message_from :response_reason_code => '27', :response_reason_text => 'Failure.', } - assert_equal "CVV does not match", @gateway.message_from(result) + assert_equal 'CVV does not match', @gateway.message_from(result) result[:card_code] = 'M' - assert_equal "Street address matches, but 5-digit and 9-digit postal code do not match.", @gateway.message_from(result) + assert_equal 'Street address matches, but 5-digit and 9-digit postal code do not match.', @gateway.message_from(result) result[:response_reason_code] = '22' - assert_equal "Failure", @gateway.message_from(result) + assert_equal 'Failure', @gateway.message_from(result) end private @@ -231,6 +230,6 @@ def failed_authorization_response end def fraud_review_response - "$4$,$$,$253$,$Thank you! For security reasons your order is currently being reviewed.$,$$,$X$,$0$,$$,$$,$1.00$,$$,$auth_capture$,$$,$$,$$,$$,$$,$$,$$,$$,$$,$$,$$,$$,$$,$$,$$,$$,$$,$$,$$,$$,$$,$$,$$,$$,$$,$207BCBBF78E85CF174C87AE286B472D2$,$M$,$$,$$,$$,$$,$$,$$,$$,$$,$$,$$,$$,$$,$$,$$,$$,$$,$$,$$,$$,$$,$$,$$,$$,$$,$$,$$,$$,$$,$$" + '$4$,$$,$253$,$Thank you! For security reasons your order is currently being reviewed.$,$$,$X$,$0$,$$,$$,$1.00$,$$,$auth_capture$,$$,$$,$$,$$,$$,$$,$$,$$,$$,$$,$$,$$,$$,$$,$$,$$,$$,$$,$$,$$,$$,$$,$$,$$,$$,$207BCBBF78E85CF174C87AE286B472D2$,$M$,$$,$$,$$,$$,$$,$$,$$,$$,$$,$$,$$,$$,$$,$$,$$,$$,$$,$$,$$,$$,$$,$$,$$,$$,$$,$$,$$,$$,$$' end end diff --git a/test/unit/gateways/micropayment_test.rb b/test/unit/gateways/micropayment_test.rb index 6a5862852fa..5e63d8f0fa3 100644 --- a/test/unit/gateways/micropayment_test.rb +++ b/test/unit/gateways/micropayment_test.rb @@ -5,7 +5,7 @@ class MicropaymentTest < Test::Unit::TestCase def setup @gateway = MicropaymentGateway.new( - access_key: "key" + access_key: 'key' ) @credit_card = credit_card @@ -23,7 +23,7 @@ def test_successful_purchase end.respond_with(successful_purchase_response) assert_success response - assert_equal "CCadc2b593ca98bfd730c383582de00faed995b0|www.spreedly.com-IDhm7nyju168", response.authorization + assert_equal 'CCadc2b593ca98bfd730c383582de00faed995b0|www.spreedly.com-IDhm7nyju168', response.authorization assert response.test? end @@ -33,7 +33,7 @@ def test_failed_purchase end.respond_with(failed_purchase_response) assert_failure response - assert_equal "AS stellt falsches Routing fest", response.message + assert_equal 'AS stellt falsches Routing fest', response.message assert response.test? end @@ -48,7 +48,7 @@ def test_successful_authorize_and_capture end.respond_with(successful_authorize_response) assert_success response - assert_equal "CC747358d9598614c3ba1e9a7b82a28318cd81bc|www.spreedly.com-IDhngtaj81a1", response.authorization + assert_equal 'CC747358d9598614c3ba1e9a7b82a28318cd81bc|www.spreedly.com-IDhngtaj81a1', response.authorization capture = stub_comms do @gateway.capture(@amount, response.authorization) @@ -68,13 +68,13 @@ def test_failed_authorize end.respond_with(failed_authorize_response) assert_failure response - assert_equal "AS stellt falsches Routing fest", response.message + assert_equal 'AS stellt falsches Routing fest', response.message assert response.test? end def test_failed_capture response = stub_comms do - @gateway.capture(100, "") + @gateway.capture(100, '') end.respond_with(failed_capture_response) assert_failure response @@ -100,7 +100,7 @@ def test_successful_void def test_failed_void response = stub_comms do - @gateway.void("") + @gateway.void('') end.respond_with(failed_void_response) assert_failure response @@ -127,7 +127,7 @@ def test_successful_refund def test_failed_refund response = stub_comms do - @gateway.refund(nil, "") + @gateway.refund(nil, '') end.respond_with(failed_refund_response) assert_failure response @@ -138,7 +138,7 @@ def test_successful_verify @gateway.verify(@credit_card) end.respond_with(successful_authorize_response, failed_void_response) assert_success response - assert_equal "Succeeded", response.message + assert_equal 'Succeeded', response.message end def test_failed_verify @@ -146,7 +146,7 @@ def test_failed_verify @gateway.verify(@credit_card) end.respond_with(failed_authorize_response, successful_void_response) assert_failure response - assert_equal "AS stellt falsches Routing fest", response.message + assert_equal 'AS stellt falsches Routing fest', response.message end def test_transcript_scrubbing diff --git a/test/unit/gateways/migs_test.rb b/test/unit/gateways/migs_test.rb index 927c0e07f95..aec54f4bb5e 100644 --- a/test/unit/gateways/migs_test.rb +++ b/test/unit/gateways/migs_test.rb @@ -60,7 +60,6 @@ def test_purchase_offsite_response response_params = "vpc_3DSXID=a1B8UcW%2BKYqkSinLQohGmqQd9uY%3D&vpc_3DSenrolled=U&vpc_AVSResultCode=Unsupported&vpc_AcqAVSRespCode=Unsupported&vpc_AcqCSCRespCode=Unsupported&vpc_AcqResponseCode=00&vpc_Amount=100&vpc_AuthorizeId=367739&vpc_BatchNo=20120421&vpc_CSCResultCode=Unsupported&vpc_Card=MC&vpc_Command=pay&vpc_Locale=en&vpc_MerchTxnRef=9&vpc_Merchant=TESTANZTEST3&vpc_Message=Approved&vpc_OrderInfo=1&vpc_ReceiptNo=120421367739&vpc_SecureHash=20DE2CDEBE40D6F24E3ABC5D74081CB5B341CD447530121AD51A9504A923BBD0&vpc_TransactionNo=2000025183&vpc_TxnResponseCode=0&vpc_VerSecurityLevel=06&vpc_VerStatus=U&vpc_VerType=3DS&vpc_Version=1" response_hash = @gateway.send(:parse, response_params) - response_hash.delete(:SecureHash) calculated_hash = @gateway.send(:calculate_secure_hash, response_hash, @gateway.options[:secure_hash]) assert_equal '20DE2CDEBE40D6F24E3ABC5D74081CB5B341CD447530121AD51A9504A923BBD0', calculated_hash @@ -71,7 +70,12 @@ def test_purchase_offsite_response assert_raise(SecurityError){@gateway.purchase_offsite_response(tampered_response1)} tampered_response2 = response_params.gsub('Locale=en', 'Locale=es') - assert_raise(SecurityError){@gateway.purchase_offsite_response(tampered_response2)} + assert_raise(SecurityError) { @gateway.purchase_offsite_response(tampered_response2) } + end + + def test_scrub + assert @gateway.supports_scrubbing? + assert_equal @gateway.scrub(pre_scrubbed), post_scrubbed end private @@ -93,6 +97,58 @@ def failed_purchase_response end def build_response(options) - options.collect { |key, value| "vpc_#{key}=#{CGI.escape(value.to_s)}"}.join('&') + options.collect { |key, value| "vpc_#{key}=#{CGI.escape(value.to_s)}" }.join('&') + end + + def pre_scrubbed + <<-EOS +opening connection to migs.mastercard.com.au:443... +opened +starting SSL for migs.mastercard.com.au:443... +SSL established +<- "POST /vpcdps HTTP/1.1\r\nContent-Type: application/x-www-form-urlencoded\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nAccept: */*\r\nUser-Agent: Ruby\r\nConnection: close\r\nHost: migs.mastercard.com.au\r\nContent-Length: 354\r\n\r\n" +<- "vpc_Amount=100&vpc_Currency=SAR&vpc_OrderInfo=1&vpc_CardNum=4987654321098769&vpc_CardSecurityCode=123&vpc_CardExp=2105&vpc_Version=1&vpc_Merchant=TESTH-STATION&vpc_AccessCode=F1CE6F32&vpc_Command=pay&vpc_MerchTxnRef=84c1f31ded35dea26ac297fd7ba092da&vpc_SecureHash=CD1B2B8BC325C6C8FC1A041AD6AC90821984277113DF708B16B37809E7B0EC33&vpc_SecureHashType=SHA256&vpc_VerType=3DS&vpc_3DSXID=YzRjZWRjODY4MmY2NGQ3ZTgzNDQ&vpc_VerToken=AAACAgeVABgnAggAQ5UAAAAAAAA&vpc_3DSenrolled=Y&vpc_3DSECI=05&3DSstatus=Y" +-> "HTTP/1.1 200 OK\r\n" +-> "Date: Tue, 13 Feb 2018 19:02:18 GMT\r\n" +-> "Expires: Sun, 15 Jul 1990 00:00:00 GMT\r\n" +-> "Pragma: no-cache\r\n" +-> "Cache-Control: no-cache\r\n" +-> "Content-Length: 595\r\n" +-> "P3P: CP=\"NOI DSP COR CURa ADMa TA1a OUR BUS IND UNI COM NAV INT\"\r\n" +-> "Content-Type: text/plain;charset=iso-8859-1\r\n" +-> "Connection: close\r\n" +-> "Set-Cookie: TS01c4b9ca=01fb8d8de2ba6ffaf7439497dd78d9b3348c82bcf24d4619e65a406161e57276b6b293e77732a293be63bf750213e588797bc86f05; Path=/; Secure; HTTPOnly\r\n" +-> "\r\n" +reading 595 bytes... +-> "vpc_AVSResultCode=Unsupported&vpc_AcqAVSRespCode=Unsupported&vpc_AcqCSCRespCode=Unsupported&vpc_AcqResponseCode=00&vpc_Amount=100&vpc_AuthorizeId=239491&vpc_BatchNo=20180214&vpc_CSCResultCode=Unsupported&vpc_Card=VC&vpc_Command=pay&vpc_Currency=SAR&vpc_Locale=en_SA&vpc_MerchTxnRef=84c1f31ded35dea26ac297fd7ba092da&vpc_Merchant=TESTH-STATION&vpc_Message=Approved&vpc_OrderInfo=1&vpc_ReceiptNo=804506239491&vpc_RiskOverallResult=ACC&vpc_SecureHash=99993E000461810D9F71B1A4FC5EA2D68DF6BA1F7EBA6A9FC544DA035627C03C&vpc_SecureHashType=SHA256&vpc_TransactionNo=372&vpc_TxnResponseCode=0&vpc_Version=1&vpc_VerType=3DS&vpc_3DSXID=YzRjZWRjODY4MmY2NGQ3ZTgzNDQ&vpc_VerToken=AAACAgeVABgnAggAQ5UAAAAAAAA&vpc_3DSenrolled=Y&vpc_3DSECI=05&3DSstatus=Y" +read 595 bytes +Conn close + EOS + end + + def post_scrubbed + <<-EOS +opening connection to migs.mastercard.com.au:443... +opened +starting SSL for migs.mastercard.com.au:443... +SSL established +<- "POST /vpcdps HTTP/1.1\r\nContent-Type: application/x-www-form-urlencoded\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nAccept: */*\r\nUser-Agent: Ruby\r\nConnection: close\r\nHost: migs.mastercard.com.au\r\nContent-Length: 354\r\n\r\n" +<- "vpc_Amount=100&vpc_Currency=SAR&vpc_OrderInfo=1&vpc_CardNum=[FILTERED]&vpc_CardSecurityCode=[FILTERED]&vpc_CardExp=2105&vpc_Version=1&vpc_Merchant=TESTH-STATION&vpc_AccessCode=[FILTERED]&vpc_Command=pay&vpc_MerchTxnRef=84c1f31ded35dea26ac297fd7ba092da&vpc_SecureHash=CD1B2B8BC325C6C8FC1A041AD6AC90821984277113DF708B16B37809E7B0EC33&vpc_SecureHashType=SHA256&vpc_VerType=3DS&vpc_3DSXID=[FILTERED]&vpc_VerToken=[FILTERED]&vpc_3DSenrolled=Y&vpc_3DSECI=05&3DSstatus=Y" +-> "HTTP/1.1 200 OK\r\n" +-> "Date: Tue, 13 Feb 2018 19:02:18 GMT\r\n" +-> "Expires: Sun, 15 Jul 1990 00:00:00 GMT\r\n" +-> "Pragma: no-cache\r\n" +-> "Cache-Control: no-cache\r\n" +-> "Content-Length: 595\r\n" +-> "P3P: CP=\"NOI DSP COR CURa ADMa TA1a OUR BUS IND UNI COM NAV INT\"\r\n" +-> "Content-Type: text/plain;charset=iso-8859-1\r\n" +-> "Connection: close\r\n" +-> "Set-Cookie: TS01c4b9ca=01fb8d8de2ba6ffaf7439497dd78d9b3348c82bcf24d4619e65a406161e57276b6b293e77732a293be63bf750213e588797bc86f05; Path=/; Secure; HTTPOnly\r\n" +-> "\r\n" +reading 595 bytes... +-> "vpc_AVSResultCode=Unsupported&vpc_AcqAVSRespCode=Unsupported&vpc_AcqCSCRespCode=Unsupported&vpc_AcqResponseCode=00&vpc_Amount=100&vpc_AuthorizeId=239491&vpc_BatchNo=20180214&vpc_CSCResultCode=Unsupported&vpc_Card=VC&vpc_Command=pay&vpc_Currency=SAR&vpc_Locale=en_SA&vpc_MerchTxnRef=84c1f31ded35dea26ac297fd7ba092da&vpc_Merchant=TESTH-STATION&vpc_Message=Approved&vpc_OrderInfo=1&vpc_ReceiptNo=804506239491&vpc_RiskOverallResult=ACC&vpc_SecureHash=99993E000461810D9F71B1A4FC5EA2D68DF6BA1F7EBA6A9FC544DA035627C03C&vpc_SecureHashType=SHA256&vpc_TransactionNo=372&vpc_TxnResponseCode=0&vpc_Version=1&vpc_VerType=3DS&vpc_3DSXID=[FILTERED]&vpc_VerToken=[FILTERED]&vpc_3DSenrolled=Y&vpc_3DSECI=05&3DSstatus=Y" +read 595 bytes +Conn close + EOS end end diff --git a/test/unit/gateways/modern_payments_cim_test.rb b/test/unit/gateways/modern_payments_cim_test.rb index 6faaf1ee3b0..0e6aa87a998 100644 --- a/test/unit/gateways/modern_payments_cim_test.rb +++ b/test/unit/gateways/modern_payments_cim_test.rb @@ -26,35 +26,35 @@ def test_create_customer assert_instance_of Response, response assert response.test? assert_success response - assert_equal "6677348", response.params["create_customer_result"] + assert_equal '6677348', response.params['create_customer_result'] end def test_modify_customer_credit_card @gateway.expects(:ssl_post).returns(successful_modify_customer_credit_card_response) - assert response = @gateway.modify_customer_credit_card("10001", @credit_card) + assert response = @gateway.modify_customer_credit_card('10001', @credit_card) assert_instance_of Response, response assert response.test? assert_success response - assert_equal "6677757", response.params["modify_customer_credit_card_result"] + assert_equal '6677757', response.params['modify_customer_credit_card_result'] end def test_successful_credit_card_authorization @gateway.expects(:ssl_post).returns(successful_authorization_response) - assert response = @gateway.authorize_credit_card_payment("10001", @amount) + assert response = @gateway.authorize_credit_card_payment('10001', @amount) assert_instance_of Response, response assert response.test? assert_success response - assert_equal "18713505", response.params["trans_id"] - assert_equal "RESPONSECODE=A\nAUTHCODE=020411\nDECLINEREASON=\nAVSDATA=Z\nTRANSID=C00 17093294", response.params["auth_string"] - assert_equal "Approved", response.params["message_text"] - assert_equal "true", response.params["approved"] - assert_equal "Z", response.params["avs_code"] - assert_equal "020411", response.params["auth_code"] - assert_equal "C00 17093294", response.params["trans_code"] - assert_equal "18713505", response.authorization + assert_equal '18713505', response.params['trans_id'] + assert_equal "RESPONSECODE=A\nAUTHCODE=020411\nDECLINEREASON=\nAVSDATA=Z\nTRANSID=C00 17093294", response.params['auth_string'] + assert_equal 'Approved', response.params['message_text'] + assert_equal 'true', response.params['approved'] + assert_equal 'Z', response.params['avs_code'] + assert_equal '020411', response.params['auth_code'] + assert_equal 'C00 17093294', response.params['trans_code'] + assert_equal '18713505', response.authorization assert_equal ModernPaymentsCimGateway::SUCCESS_MESSAGE, response.message assert_equal 'Z', response.avs_result['code'] end @@ -62,12 +62,12 @@ def test_successful_credit_card_authorization def test_unsuccessful_credit_card_authorization @gateway.expects(:ssl_post).returns(unsuccessful_credit_card_authorization_response) - assert response = @gateway.authorize_credit_card_payment("10001", @amount) + assert response = @gateway.authorize_credit_card_payment('10001', @amount) assert_instance_of Response, response assert response.test? assert_failure response - assert_equal "999", response.authorization - assert_match %r{RESPONSECODE=D}, response.params["message_text"] + assert_equal '999', response.authorization + assert_match %r{RESPONSECODE=D}, response.params['message_text'] end def test_soap_fault_response @@ -77,7 +77,7 @@ def test_soap_fault_response assert_instance_of Response, response assert response.test? assert_failure response - assert_equal "soap:Client", response.params["faultcode"] + assert_equal 'soap:Client', response.params['faultcode'] end private diff --git a/test/unit/gateways/moneris_test.rb b/test/unit/gateways/moneris_test.rb index e9ecd7e34c7..f1cdffd5488 100644 --- a/test/unit/gateways/moneris_test.rb +++ b/test/unit/gateways/moneris_test.rb @@ -7,7 +7,7 @@ def setup Base.mode = :test @gateway = MonerisGateway.new( - :login => 'store1', + :login => 'store3', :password => 'yesguy' ) @@ -18,8 +18,8 @@ def setup def test_default_options assert_equal 7, @gateway.options[:crypt_type] - assert_equal "store1", @gateway.options[:login] - assert_equal "yesguy", @gateway.options[:password] + assert_equal 'store3', @gateway.options[:login] + assert_equal 'yesguy', @gateway.options[:password] end def test_successful_purchase @@ -30,10 +30,69 @@ def test_successful_purchase assert_equal '58-0_3;1026.1', response.authorization end + def test_successful_first_purchase_with_credential_on_file + gateway = MonerisGateway.new( + :login => 'store3', + :password => 'yesguy', + :cof_enabled => true + ) + gateway.expects(:ssl_post).returns(successful_first_cof_purchase_response) + assert response = gateway.purchase( + @amount, + @credit_card, + @options.merge( + issuer_id: '', + payment_indicator: 'C', + payment_information: '0' + ) + ) + assert_success response + assert_equal 'Approved', response.message + assert_false response.authorization.blank? + assert_not_empty response.params['issuer_id'] + end + + def test_successful_subsequent_purchase_with_credential_on_file + gateway = MonerisGateway.new( + :login => 'store3', + :password => 'yesguy', + :cof_enabled => true + ) + gateway.expects(:ssl_post).returns(successful_first_cof_authorize_response) + assert response = gateway.authorize( + @amount, + @credit_card, + @options.merge( + issuer_id: '', + payment_indicator: 'C', + payment_information: '0' + ) + ) + assert_success response + assert_equal 'Approved', response.message + assert_false response.authorization.blank? + + gateway.expects(:ssl_post).returns(successful_subsequent_cof_purchase_response) + + assert response2 = gateway.purchase( + @amount, + @credit_card, + @options.merge( + order_id: response.authorization, + issuer_id: response.params['issuer_id'], + payment_indicator: 'U', + payment_information: '2' + ) + ) + assert_success response2 + assert_equal 'Approved', response2.message + assert_false response2.authorization.blank? + end + def test_successful_purchase_with_network_tokenization @gateway.expects(:ssl_post).returns(successful_purchase_network_tokenization) @credit_card = network_tokenization_credit_card('4242424242424242', - payment_cryptogram: "BwABB4JRdgAAAAAAiFF2AAAAAAA=", + payment_cryptogram: 'BwABB4JRdgAAAAAAiFF2AAAAAAA=', verification_value: nil ) assert response = @gateway.purchase(100, @credit_card, @options) @@ -49,67 +108,67 @@ def test_failed_purchase end def test_deprecated_credit - @gateway.expects(:ssl_post).with(anything, regexp_matches(/txn_number>123<\//), anything).returns("") + @gateway.expects(:ssl_post).with(anything, regexp_matches(/txn_number>123<\//), anything).returns('') @gateway.expects(:parse).returns({}) assert_deprecation_warning(Gateway::CREDIT_DEPRECATION_MESSAGE) do - @gateway.credit(@amount, "123;456", @options) + @gateway.credit(@amount, '123;456', @options) end end def test_refund - @gateway.expects(:ssl_post).with(anything, regexp_matches(/txn_number>123<\//), anything).returns("") + @gateway.expects(:ssl_post).with(anything, regexp_matches(/txn_number>123<\//), anything).returns('') @gateway.expects(:parse).returns({}) - @gateway.refund(@amount, "123;456", @options) + @gateway.refund(@amount, '123;456', @options) end def test_amount_style - assert_equal '10.34', @gateway.send(:amount, 1034) + assert_equal '10.34', @gateway.send(:amount, 1034) - assert_raise(ArgumentError) do - @gateway.send(:amount, '10.34') - end + assert_raise(ArgumentError) do + @gateway.send(:amount, '10.34') + end end def test_preauth_is_valid_xml - params = { - :order_id => "order1", - :amount => "1.01", - :pan => "4242424242424242", - :expdate => "0303", - :crypt_type => 7, - } + params = { + :order_id => 'order1', + :amount => '1.01', + :pan => '4242424242424242', + :expdate => '0303', + :crypt_type => 7, + } - assert data = @gateway.send(:post_data, 'preauth', params) - assert REXML::Document.new(data) - assert_equal xml_capture_fixture.size, data.size + assert data = @gateway.send(:post_data, 'preauth', params) + assert REXML::Document.new(data) + assert_equal xml_capture_fixture.size, data.size end def test_purchase_is_valid_xml - params = { - :order_id => "order1", - :amount => "1.01", - :pan => "4242424242424242", - :expdate => "0303", - :crypt_type => 7, - } + params = { + :order_id => 'order1', + :amount => '1.01', + :pan => '4242424242424242', + :expdate => '0303', + :crypt_type => 7, + } - assert data = @gateway.send(:post_data, 'purchase', params) - assert REXML::Document.new(data) - assert_equal xml_purchase_fixture.size, data.size + assert data = @gateway.send(:post_data, 'purchase', params) + assert REXML::Document.new(data) + assert_equal xml_purchase_fixture.size, data.size end def test_capture_is_valid_xml - params = { - :order_id => "order1", - :amount => "1.01", - :pan => "4242424242424242", - :expdate => "0303", - :crypt_type => 7, - } + params = { + :order_id => 'order1', + :amount => '1.01', + :pan => '4242424242424242', + :expdate => '0303', + :crypt_type => 7, + } - assert data = @gateway.send(:post_data, 'preauth', params) - assert REXML::Document.new(data) - assert_equal xml_capture_fixture.size, data.size + assert data = @gateway.send(:post_data, 'preauth', params) + assert REXML::Document.new(data) + assert_equal xml_capture_fixture.size, data.size end def test_successful_verify @@ -117,7 +176,7 @@ def test_successful_verify @gateway.verify(@credit_card, @options) end.respond_with(successful_authorize_response, failed_void_response) assert_success response - assert_equal "Approved", response.message + assert_equal 'Approved', response.message end def test_supported_countries @@ -138,9 +197,9 @@ def test_successful_store @gateway.expects(:ssl_post).returns(successful_store_response) assert response = @gateway.store(@credit_card) assert_success response - assert_equal "Successfully registered cc details", response.message - assert response.params["data_key"].present? - @data_key = response.params["data_key"] + assert_equal 'Successfully registered cc details', response.message + assert response.params['data_key'].present? + @data_key = response.params['data_key'] end def test_successful_unstore @@ -148,8 +207,8 @@ def test_successful_unstore test_successful_store assert response = @gateway.unstore(@data_key) assert_success response - assert_equal "Successfully deleted cc details", response.message - assert response.params["data_key"].present? + assert_equal 'Successfully deleted cc details', response.message + assert response.params['data_key'].present? end def test_update @@ -157,8 +216,8 @@ def test_update test_successful_store assert response = @gateway.update(@data_key, @credit_card) assert_success response - assert_equal "Successfully updated cc details", response.message - assert response.params["data_key"].present? + assert_equal 'Successfully updated cc details', response.message + assert response.params['data_key'].present? end def test_successful_purchase_with_vault @@ -166,14 +225,14 @@ def test_successful_purchase_with_vault test_successful_store assert response = @gateway.purchase(100, @data_key, {:order_id => generate_unique_id, :customer => generate_unique_id}) assert_success response - assert_equal "Approved", response.message + assert_equal 'Approved', response.message assert response.authorization.present? end def test_successful_authorize_with_network_tokenization @gateway.expects(:ssl_post).returns(successful_authorization_network_tokenization) @credit_card = network_tokenization_credit_card('4242424242424242', - payment_cryptogram: "BwABB4JRdgAAAAAAiFF2AAAAAAA=", + payment_cryptogram: 'BwABB4JRdgAAAAAAiFF2AAAAAAA=', verification_value: nil ) assert response = @gateway.authorize(100, @credit_card, @options) @@ -186,7 +245,7 @@ def test_successful_authorization_with_vault test_successful_store assert response = @gateway.authorize(100, @data_key, {:order_id => generate_unique_id, :customer => generate_unique_id}) assert_success response - assert_equal "Approved", response.message + assert_equal 'Approved', response.message assert response.authorization.present? end @@ -200,7 +259,7 @@ def test_failed_authorization_with_vault def test_cvv_enabled_and_provided gateway = MonerisGateway.new(login: 'store1', password: 'yesguy', cvv_enabled: true) - @credit_card.verification_value = "452" + @credit_card.verification_value = '452' stub_comms(gateway) do gateway.purchase(@amount, @credit_card, @options) end.check_request do |endpoint, data, headers| @@ -212,7 +271,7 @@ def test_cvv_enabled_and_provided def test_cvv_enabled_but_not_provided gateway = MonerisGateway.new(login: 'store1', password: 'yesguy', cvv_enabled: true) - @credit_card.verification_value = "" + @credit_card.verification_value = '' stub_comms(gateway) do gateway.purchase(@amount, @credit_card, @options) end.check_request do |endpoint, data, headers| @@ -222,7 +281,7 @@ def test_cvv_enabled_but_not_provided end def test_cvv_disabled_and_provided - @credit_card.verification_value = "452" + @credit_card.verification_value = '452' stub_comms do @gateway.purchase(@amount, @credit_card, @options) end.check_request do |endpoint, data, headers| @@ -232,7 +291,7 @@ def test_cvv_disabled_and_provided end def test_cvv_disabled_but_not_provided - @credit_card.verification_value = "" + @credit_card.verification_value = '' stub_comms do @gateway.purchase(@amount, @credit_card, @options) end.check_request do |endpoint, data, headers| @@ -244,9 +303,9 @@ def test_cvv_disabled_but_not_provided def test_avs_enabled_and_provided gateway = MonerisGateway.new(login: 'store1', password: 'yesguy', avs_enabled: true) - billing_address = address(address1: "1234 Anystreet", address2: "") + billing_address = address(address1: '1234 Anystreet', address2: '') stub_comms(gateway) do - gateway.purchase(@amount, @credit_card, billing_address: billing_address, order_id: "1") + gateway.purchase(@amount, @credit_card, billing_address: billing_address, order_id: '1') end.check_request do |endpoint, data, headers| assert_match(%r{avs_street_number>1234<}, data) assert_match(%r{avs_street_name>Anystreet<}, data) @@ -267,9 +326,9 @@ def test_avs_enabled_but_not_provided end def test_avs_disabled_and_provided - billing_address = address(address1: "1234 Anystreet", address2: "") + billing_address = address(address1: '1234 Anystreet', address2: '') stub_comms do - @gateway.purchase(@amount, @credit_card, billing_address: billing_address, order_id: "1") + @gateway.purchase(@amount, @credit_card, billing_address: billing_address, order_id: '1') end.check_request do |endpoint, data, headers| assert_no_match(%r{avs_street_number>}, data) assert_no_match(%r{avs_street_name>}, data) @@ -300,7 +359,7 @@ def test_avs_result_valid_with_address def test_customer_can_be_specified stub_comms do - @gateway.purchase(@amount, @credit_card, order_id: "3", customer: "Joe Jones") + @gateway.purchase(@amount, @credit_card, order_id: '3', customer: 'Joe Jones') end.check_request do |endpoint, data, headers| assert_match(%r{cust_id>Joe Jones}, data) end.respond_with(successful_purchase_response) @@ -308,20 +367,20 @@ def test_customer_can_be_specified def test_customer_not_specified_card_name_used stub_comms do - @gateway.purchase(@amount, @credit_card, order_id: "3") + @gateway.purchase(@amount, @credit_card, order_id: '3') end.check_request do |endpoint, data, headers| assert_match(%r{cust_id>Longbob Longsen}, data) end.respond_with(successful_purchase_response) end def test_add_swipe_data_with_creditcard - @credit_card.track_data = "Track Data" + @credit_card.track_data = 'Track Data' stub_comms do @gateway.purchase(@amount, @credit_card, @options) end.check_request do |endpoint, data, headers| - assert_match "<pos_code>00</pos_code>", data - assert_match "<track2>Track Data</track2>", data + assert_match '<pos_code>00</pos_code>', data + assert_match '<track2>Track Data</track2>', data end.respond_with(successful_purchase_response) end @@ -360,6 +419,92 @@ def successful_purchase_response RESPONSE end + def successful_first_cof_purchase_response + <<-RESPONSE +<?xml version=\"1.0\" standalone=\"yes\"?> +<?xml version=“1.0” standalone=“yes”?> +<response> + <receipt> + <ReceiptId>a33ba7edd448b91ef8d2f85fea614b8d</ReceiptId> + <ReferenceNum>660114080015099160</ReferenceNum> + <ResponseCode>027</ResponseCode> + <ISO>01</ISO> + <AuthCode>822665</AuthCode> + <TransTime>07:43:28</TransTime> + <TransDate>2018-11-11</TransDate> + <TransType>00</TransType> + <Complete>true</Complete> + <Message>APPROVED * =</Message> + <TransAmount>1.00</TransAmount> + <CardType>V</CardType> + <TransID>799655-0_11</TransID> + <TimedOut>false</TimedOut> + <BankTotals>null</BankTotals> + <Ticket>null</Ticket> + <IssuerId>355689484440192</IssuerId> + <IsVisaDebit>false</IsVisaDebit> + </receipt> +</response> + RESPONSE + end + + def successful_first_cof_authorize_response + <<-RESPONSE +<?xml version=\"1.0\" standalone=\"yes\"?> +<response> + <receipt> + <ReceiptId>8dbc28468af2007779bbede7ec1bab6c</ReceiptId> + <ReferenceNum>660109300018229130</ReferenceNum> + <ResponseCode>027</ResponseCode> + <ISO>01</ISO> + <AuthCode>718280</AuthCode> + <TransTime>07:50:53</TransTime> + <TransDate>2018-11-11</TransDate> + <TransType>01</TransType> + <Complete>true</Complete> + <Message>APPROVED * =</Message> + <TransAmount>1.00</TransAmount> + <CardType>V</CardType> + <TransID>830724-0_11</TransID> + <TimedOut>false</TimedOut> + <BankTotals>null</BankTotals> + <Ticket>null</Ticket> + <MessageId>1A8315282537312</MessageId> + <IssuerId>550923784451193</IssuerId> + <IsVisaDebit>false</IsVisaDebit> + </receipt> +</response> + RESPONSE + end + + def successful_subsequent_cof_purchase_response + <<-RESPONSE +<?xml version="1.0" standalone="yes"?> +<response> + <receipt> + <ReceiptId>830724-0_11;8dbc28468af2007779bbede7ec1bab6c</ReceiptId> + <ReferenceNum>660109490014038930</ReferenceNum> + <ResponseCode>027</ResponseCode> + <ISO>01</ISO> + <AuthCode>111234</AuthCode> + <TransTime>07:50:54</TransTime> + <TransDate>2018-11-11</TransDate> + <TransType>00</TransType> + <Complete>true</Complete> + <Message>APPROVED * =</Message> + <TransAmount>1.00</TransAmount> + <CardType>V</CardType> + <TransID>455422-0_11</TransID> + <TimedOut>false</TimedOut> + <BankTotals>null</BankTotals> + <Ticket>null</Ticket> + <IssuerId>762097792112819</IssuerId> + <IsVisaDebit>false</IsVisaDebit> + </receipt> +</response> + RESPONSE + end + def successful_purchase_network_tokenization <<-RESPONSE <?xml version="1.0"?> @@ -572,11 +717,11 @@ def failed_void_response end def xml_purchase_fixture - '<request><store_id>store1</store_id><api_token>yesguy</api_token><purchase><amount>1.01</amount><pan>4242424242424242</pan><expdate>0303</expdate><crypt_type>7</crypt_type><order_id>order1</order_id></purchase></request>' + '<request><store_id>store1</store_id><api_token>yesguy</api_token><purchase><amount>1.01</amount><pan>4242424242424242</pan><expdate>0303</expdate><crypt_type>7</crypt_type><order_id>order1</order_id></purchase></request>' end def xml_capture_fixture - '<request><store_id>store1</store_id><api_token>yesguy</api_token><preauth><amount>1.01</amount><pan>4242424242424242</pan><expdate>0303</expdate><crypt_type>7</crypt_type><order_id>order1</order_id></preauth></request>' + '<request><store_id>store1</store_id><api_token>yesguy</api_token><preauth><amount>1.01</amount><pan>4242424242424242</pan><expdate>0303</expdate><crypt_type>7</crypt_type><order_id>order1</order_id></preauth></request>' end def pre_scrub diff --git a/test/unit/gateways/moneris_us_test.rb b/test/unit/gateways/moneris_us_test.rb index 8bc63a9c289..b2bff66d3d1 100644 --- a/test/unit/gateways/moneris_us_test.rb +++ b/test/unit/gateways/moneris_us_test.rb @@ -13,13 +13,18 @@ def setup @amount = 100 @credit_card = credit_card('4242424242424242') + @check = check({ + routing_number: '011000015', + account_number: '1234455', + number: 123 + }) @options = { :order_id => '1', :billing_address => address } end def test_default_options assert_equal 7, @gateway.options[:crypt_type] - assert_equal "monusqa002", @gateway.options[:login] - assert_equal "qatoken", @gateway.options[:password] + assert_equal 'monusqa002', @gateway.options[:login] + assert_equal 'qatoken', @gateway.options[:password] end def test_successful_purchase @@ -37,18 +42,26 @@ def test_failed_purchase assert_failure response end + def test_successful_echeck_purchase + @gateway.expects(:ssl_post).returns(successful_echeck_purchase_response) + + assert response = @gateway.authorize(100, @check, @options) + assert_success response + assert_equal '1522-0_25;cb80f38f44af2168fd9033cdf2d0d4c0', response.authorization + end + def test_deprecated_credit - @gateway.expects(:ssl_post).with(anything, regexp_matches(/txn_number>123<\//), anything).returns("") + @gateway.expects(:ssl_post).with(anything, regexp_matches(/txn_number>123<\//), anything).returns('') @gateway.expects(:parse).returns({}) assert_deprecation_warning(Gateway::CREDIT_DEPRECATION_MESSAGE) do - @gateway.credit(@amount, "123;456", @options) + @gateway.credit(@amount, '123;456', @options) end end def test_refund - @gateway.expects(:ssl_post).with(anything, regexp_matches(/txn_number>123<\//), anything).returns("") + @gateway.expects(:ssl_post).with(anything, regexp_matches(/txn_number>123<\//), anything).returns('') @gateway.expects(:parse).returns({}) - @gateway.refund(@amount, "123;456", @options) + @gateway.refund(@amount, '123;456', @options) end def test_successful_verify @@ -56,7 +69,7 @@ def test_successful_verify @gateway.verify(@credit_card, @options) end.respond_with(successful_authorize_response, successful_capture_response) assert_success response - assert_equal "830337-0_25;d315c7a28623dec77dc136450692d2dd", response.authorization + assert_equal '830337-0_25;d315c7a28623dec77dc136450692d2dd', response.authorization end def test_successful_verify_and_failed_void @@ -64,8 +77,8 @@ def test_successful_verify_and_failed_void @gateway.verify(@credit_card, @options) end.respond_with(successful_authorize_response, failed_capture_response) assert_success response - assert_equal "830337-0_25;d315c7a28623dec77dc136450692d2dd", response.authorization - assert_equal "Approved", response.message + assert_equal '830337-0_25;d315c7a28623dec77dc136450692d2dd', response.authorization + assert_equal 'Approved', response.message end def test_failed_verify @@ -73,60 +86,57 @@ def test_failed_verify @gateway.verify(@credit_card, @options) end.respond_with(failed_authorize_response, successful_capture_response) assert_failure response - assert_equal "Declined", response.message + assert_equal 'Declined', response.message end def test_amount_style - assert_equal '10.34', @gateway.send(:amount, 1034) + assert_equal '10.34', @gateway.send(:amount, 1034) - assert_raise(ArgumentError) do - @gateway.send(:amount, '10.34') - end + assert_raise(ArgumentError) do + @gateway.send(:amount, '10.34') + end end def test_preauth_is_valid_xml + params = { + :order_id => 'order1', + :amount => '1.01', + :pan => '4242424242424242', + :expdate => '0303', + :crypt_type => 7, + } - params = { - :order_id => "order1", - :amount => "1.01", - :pan => "4242424242424242", - :expdate => "0303", - :crypt_type => 7, - } - - assert data = @gateway.send(:post_data, 'us_preauth', params) - assert REXML::Document.new(data) - assert_equal xml_capture_fixture.size, data.size + assert data = @gateway.send(:post_data, 'us_preauth', params) + assert REXML::Document.new(data) + assert_equal xml_capture_fixture.size, data.size end def test_purchase_is_valid_xml + params = { + :order_id => 'order1', + :amount => '1.01', + :pan => '4242424242424242', + :expdate => '0303', + :crypt_type => 7, + } - params = { - :order_id => "order1", - :amount => "1.01", - :pan => "4242424242424242", - :expdate => "0303", - :crypt_type => 7, - } - - assert data = @gateway.send(:post_data, 'us_purchase', params) - assert REXML::Document.new(data) - assert_equal xml_purchase_fixture.size, data.size + assert data = @gateway.send(:post_data, 'us_purchase', params) + assert REXML::Document.new(data) + assert_equal xml_purchase_fixture.size, data.size end def test_capture_is_valid_xml + params = { + :order_id => 'order1', + :amount => '1.01', + :pan => '4242424242424242', + :expdate => '0303', + :crypt_type => 7, + } - params = { - :order_id => "order1", - :amount => "1.01", - :pan => "4242424242424242", - :expdate => "0303", - :crypt_type => 7, - } - - assert data = @gateway.send(:post_data, 'us_preauth', params) - assert REXML::Document.new(data) - assert_equal xml_capture_fixture.size, data.size + assert data = @gateway.send(:post_data, 'us_preauth', params) + assert REXML::Document.new(data) + assert_equal xml_capture_fixture.size, data.size end def test_supported_countries @@ -147,9 +157,9 @@ def test_successful_store @gateway.expects(:ssl_post).returns(successful_store_response) assert response = @gateway.store(@credit_card) assert_success response - assert_equal "Successfully registered cc details", response.message - assert response.params["data_key"].present? - @data_key = response.params["data_key"] + assert_equal 'Successfully registered cc details', response.message + assert response.params['data_key'].present? + @data_key = response.params['data_key'] end def test_successful_unstore @@ -157,8 +167,8 @@ def test_successful_unstore test_successful_store assert response = @gateway.unstore(@data_key) assert_success response - assert_equal "Successfully deleted cc details", response.message - assert response.params["data_key"].present? + assert_equal 'Successfully deleted cc details', response.message + assert response.params['data_key'].present? end def test_update @@ -166,8 +176,8 @@ def test_update test_successful_store assert response = @gateway.update(@data_key, @credit_card) assert_success response - assert_equal "Successfully updated cc details", response.message - assert response.params["data_key"].present? + assert_equal 'Successfully updated cc details', response.message + assert response.params['data_key'].present? end def test_successful_purchase_with_vault @@ -175,7 +185,7 @@ def test_successful_purchase_with_vault test_successful_store assert response = @gateway.purchase(100, @data_key, {:order_id => generate_unique_id, :customer => generate_unique_id}) assert_success response - assert_equal "Approved", response.message + assert_equal 'Approved', response.message assert response.authorization.present? end @@ -184,7 +194,7 @@ def test_successful_authorization_with_vault test_successful_store assert response = @gateway.authorize(100, @data_key, {:order_id => generate_unique_id, :customer => generate_unique_id}) assert_success response - assert_equal "Approved", response.message + assert_equal 'Approved', response.message assert response.authorization.present? end @@ -198,7 +208,7 @@ def test_failed_authorization_with_vault def test_cvv_enabled_and_provided gateway = MonerisGateway.new(login: 'store1', password: 'yesguy', cvv_enabled: true) - @credit_card.verification_value = "452" + @credit_card.verification_value = '452' stub_comms(gateway) do gateway.purchase(@amount, @credit_card, @options) end.check_request do |endpoint, data, headers| @@ -210,7 +220,7 @@ def test_cvv_enabled_and_provided def test_cvv_enabled_but_not_provided gateway = MonerisGateway.new(login: 'store1', password: 'yesguy', cvv_enabled: true) - @credit_card.verification_value = "" + @credit_card.verification_value = '' stub_comms(gateway) do gateway.purchase(@amount, @credit_card, @options) end.check_request do |endpoint, data, headers| @@ -220,7 +230,7 @@ def test_cvv_enabled_but_not_provided end def test_cvv_disabled_and_provided - @credit_card.verification_value = "452" + @credit_card.verification_value = '452' stub_comms do @gateway.purchase(@amount, @credit_card, @options) end.check_request do |endpoint, data, headers| @@ -230,7 +240,7 @@ def test_cvv_disabled_and_provided end def test_cvv_disabled_but_not_provided - @credit_card.verification_value = "" + @credit_card.verification_value = '' stub_comms do @gateway.purchase(@amount, @credit_card, @options) end.check_request do |endpoint, data, headers| @@ -242,9 +252,9 @@ def test_cvv_disabled_but_not_provided def test_avs_enabled_and_provided gateway = MonerisGateway.new(login: 'store1', password: 'yesguy', avs_enabled: true) - billing_address = address(address1: "1234 Anystreet", address2: "") - stub_comms do - gateway.purchase(@amount, @credit_card, billing_address: billing_address, order_id: "1") + billing_address = address(address1: '1234 Anystreet', address2: '') + stub_comms(gateway) do + gateway.purchase(@amount, @credit_card, billing_address: billing_address, order_id: '1') end.check_request do |endpoint, data, headers| assert_match(%r{avs_street_number>1234<}, data) assert_match(%r{avs_street_name>Anystreet<}, data) @@ -255,7 +265,7 @@ def test_avs_enabled_and_provided def test_avs_enabled_but_not_provided gateway = MonerisGateway.new(login: 'store1', password: 'yesguy', avs_enabled: true) - stub_comms do + stub_comms(gateway) do gateway.purchase(@amount, @credit_card, @options.tap { |x| x.delete(:billing_address) }) end.check_request do |endpoint, data, headers| assert_no_match(%r{avs_street_number>}, data) @@ -265,9 +275,9 @@ def test_avs_enabled_but_not_provided end def test_avs_disabled_and_provided - billing_address = address(address1: "1234 Anystreet", address2: "") + billing_address = address(address1: '1234 Anystreet', address2: '') stub_comms do - @gateway.purchase(@amount, @credit_card, billing_address: billing_address, order_id: "1") + @gateway.purchase(@amount, @credit_card, billing_address: billing_address, order_id: '1') end.check_request do |endpoint, data, headers| assert_no_match(%r{avs_street_number>}, data) assert_no_match(%r{avs_street_name>}, data) @@ -298,7 +308,7 @@ def test_avs_result_valid_with_address def test_customer_can_be_specified stub_comms do - @gateway.purchase(@amount, @credit_card, order_id: "3", customer: "Joe Jones") + @gateway.purchase(@amount, @credit_card, order_id: '3', customer: 'Joe Jones') end.check_request do |endpoint, data, headers| assert_match(%r{cust_id>Joe Jones}, data) end.respond_with(successful_purchase_response) @@ -306,12 +316,17 @@ def test_customer_can_be_specified def test_customer_not_specified_card_name_used stub_comms do - @gateway.purchase(@amount, @credit_card, order_id: "3") + @gateway.purchase(@amount, @credit_card, order_id: '3') end.check_request do |endpoint, data, headers| assert_match(%r{cust_id>Longbob Longsen}, data) end.respond_with(successful_purchase_response) end + def test_transcript_scrubbing + assert @gateway.supports_scrubbing? + assert_equal @gateway.scrub(pre_scrub), post_scrub + end + private def successful_purchase_response @@ -546,12 +561,89 @@ def successful_update_response RESPONSE end + def successful_echeck_purchase_response + <<-RESPONSE + <?xml version="1.0"?> + <response> + <receipt> + <ReceiptId>cb80f38f44af2168fd9033cdf2d0d4c0</ReceiptId> + <ReferenceNum>001000040010015220</ReferenceNum> + <ResponseCode>005</ResponseCode> + <ISO>01</ISO> + <AuthCode></AuthCode> + <TransTime>08:23:37</TransTime> + <TransDate>2018-06-18</TransDate> + <TransType>00</TransType> + <Complete>true</Complete> + <Message>REGISTERED * =</Message> + <TransAmount>1.0</TransAmount> + <CardType>CQ</CardType> + <TransID>1522-0_25</TransID> + <TimedOut>false</TimedOut> + <BankTotals>null</BankTotals> + <Ticket>null</Ticket> + <CorporateCard>false</CorporateCard> + <MessageId>null</MessageId> + <RecurSuccess>true</RecurSuccess> + </receipt> + </response> + RESPONSE + end + def xml_purchase_fixture - '<request><store_id>monusqa002</store_id><api_token>qatoken</api_token><us_purchase><amount>1.01</amount><pan>4242424242424242</pan><expdate>0303</expdate><crypt_type>7</crypt_type><order_id>order1</order_id></us_purchase></request>' + '<request><store_id>monusqa002</store_id><api_token>qatoken</api_token><us_purchase><amount>1.01</amount><pan>4242424242424242</pan><expdate>0303</expdate><crypt_type>7</crypt_type><order_id>order1</order_id></us_purchase></request>' end def xml_capture_fixture - '<request><store_id>monusqa002</store_id><api_token>qatoken</api_token><us_preauth><amount>1.01</amount><pan>4242424242424242</pan><expdate>0303</expdate><crypt_type>7</crypt_type><order_id>order1</order_id></us_preauth></request>' + '<request><store_id>monusqa002</store_id><api_token>qatoken</api_token><us_preauth><amount>1.01</amount><pan>4242424242424242</pan><expdate>0303</expdate><crypt_type>7</crypt_type><order_id>order1</order_id></us_preauth></request>' + end + + def pre_scrub + %q{ +opening connection to esplusqa.moneris.com:443... +opened +starting SSL for esplusqa.moneris.com:443... +SSL established +<- "POST /gateway_us/servlet/MpgRequest HTTP/1.1\r\nContent-Type: application/x-www-form-urlencoded\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nAccept: */*\r\nUser-Agent: Ruby\r\nConnection: close\r\nHost: esplusqa.moneris.com\r\nContent-Length: 291\r\n\r\n" +<- "<request><store_id>monusqa002</store_id><api_token>qatoken</api_token><us_purchase><order_id>cec9ca34132f0945446589e36fff9cce</order_id><cust_id>Longbob Longsen</cust_id><amount>1.00</amount><pan>4242424242424242</pan><expdate>1909</expdate><crypt_type>7</crypt_type></us_purchase></request>" +-> "HTTP/1.1 200 OK\r\n" +-> "Date: Mon, 08 Jan 2018 19:20:26 GMT\r\n" +-> "Content-Length: 659\r\n" +-> "X-UA-Compatible: IE=Edge\r\n" +-> "Connection: close\r\n" +-> "Content-Type: text/html; charset=UTF-8\r\n" +-> "Set-Cookie: TS01d02998=01649737b16d4ca54c296a0a369f4e549e4191e85d8d022d01468e559975e945b419002a42; Path=/\r\n" +-> "Set-Cookie: TS01d02998_28=01e24a44e55591744bc115f421ddccd549b1655d75bda586c8ea625670efaa4432f67c8b7e06e7af82c70ef3ac4f46d7435664f2ac; Path=/\r\n" +-> "\r\n" +reading 659 bytes... +-> "<?xml version=\"1.0\" standalone=\"yes\"?><response><receipt><ReceiptId>cec9ca34132f0945446589e36fff9cce</ReceiptId><ReferenceNum>640000030013630190</ReferenceNum><ResponseCode>001</ResponseCode><ISO>00</ISO><AuthCode>827125</AuthCode><TransTime>13:20:24</TransTime><TransDate>2018-01-08</TransDate><TransType>00</TransType><Complete>true</Complete><Message>APPROVED*</Message><TransAmount>1.00</TransAmount><CardType>V</CardType><TransID>113295-0_25</TransID><TimedOut>false</TimedOut><BankTotals>null</BankTotals><Ticket>null</Ticket><CorporateCard>false</CorporateCard><CardLevelResult>A</CardLevelResult><CavvResultCode> </CavvResultCode></receipt></response>" +read 659 bytes +Conn close + } + end + + def post_scrub + %q{ +opening connection to esplusqa.moneris.com:443... +opened +starting SSL for esplusqa.moneris.com:443... +SSL established +<- "POST /gateway_us/servlet/MpgRequest HTTP/1.1\r\nContent-Type: application/x-www-form-urlencoded\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nAccept: */*\r\nUser-Agent: Ruby\r\nConnection: close\r\nHost: esplusqa.moneris.com\r\nContent-Length: 291\r\n\r\n" +<- "<request><store_id>monusqa002</store_id><api_token>[FILTERED]</api_token><us_purchase><order_id>cec9ca34132f0945446589e36fff9cce</order_id><cust_id>Longbob Longsen</cust_id><amount>1.00</amount><pan>[FILTERED]</pan><expdate>1909</expdate><crypt_type>7</crypt_type></us_purchase></request>" +-> "HTTP/1.1 200 OK\r\n" +-> "Date: Mon, 08 Jan 2018 19:20:26 GMT\r\n" +-> "Content-Length: 659\r\n" +-> "X-UA-Compatible: IE=Edge\r\n" +-> "Connection: close\r\n" +-> "Content-Type: text/html; charset=UTF-8\r\n" +-> "Set-Cookie: TS01d02998=01649737b16d4ca54c296a0a369f4e549e4191e85d8d022d01468e559975e945b419002a42; Path=/\r\n" +-> "Set-Cookie: TS01d02998_28=01e24a44e55591744bc115f421ddccd549b1655d75bda586c8ea625670efaa4432f67c8b7e06e7af82c70ef3ac4f46d7435664f2ac; Path=/\r\n" +-> "\r\n" +reading 659 bytes... +-> "<?xml version=\"1.0\" standalone=\"yes\"?><response><receipt><ReceiptId>cec9ca34132f0945446589e36fff9cce</ReceiptId><ReferenceNum>640000030013630190</ReferenceNum><ResponseCode>001</ResponseCode><ISO>00</ISO><AuthCode>827125</AuthCode><TransTime>13:20:24</TransTime><TransDate>2018-01-08</TransDate><TransType>00</TransType><Complete>true</Complete><Message>APPROVED*</Message><TransAmount>1.00</TransAmount><CardType>V</CardType><TransID>113295-0_25</TransID><TimedOut>false</TimedOut><BankTotals>null</BankTotals><Ticket>null</Ticket><CorporateCard>false</CorporateCard><CardLevelResult>A</CardLevelResult><CavvResultCode> </CavvResultCode></receipt></response>" +read 659 bytes +Conn close + } end end diff --git a/test/unit/gateways/money_movers_test.rb b/test/unit/gateways/money_movers_test.rb index db0f48aa591..c5c3b275baf 100644 --- a/test/unit/gateways/money_movers_test.rb +++ b/test/unit/gateways/money_movers_test.rb @@ -44,8 +44,8 @@ def test_unsuccessful_request def test_add_address result = {} - @gateway.send(:add_address, result, :billing_address => {:address1 => '1 Main St.', :address2 => "apt 13", :country => 'US', :state => 'MI', :phone => '1234567890'} ) - assert_equal ["address1", "address2", "city", "company", "country", "phone", "state", "zip"], result.stringify_keys.keys.sort + @gateway.send(:add_address, result, :billing_address => {:address1 => '1 Main St.', :address2 => 'apt 13', :country => 'US', :state => 'MI', :phone => '1234567890'}) + assert_equal ['address1', 'address2', 'city', 'company', 'country', 'phone', 'state', 'zip'], result.stringify_keys.keys.sort assert_equal 'MI', result[:state] assert_equal '1 Main St.', result[:address1] assert_equal 'apt 13', result[:address2] @@ -54,7 +54,7 @@ def test_add_address def test_add_invoice result = {} - @gateway.send(:add_invoice, result, :order_id => '#1001', :description => "This is a great order") + @gateway.send(:add_invoice, result, :order_id => '#1001', :description => 'This is a great order') assert_equal '#1001', result[:orderid] assert_equal 'This is a great order', result[:orderdescription] end @@ -77,8 +77,8 @@ def test_purchase_meets_minimum_requirements end def test_expdate_formatting - assert_equal '0909', @gateway.send(:expdate, credit_card('4111111111111111', :month => "9", :year => "2009")) - assert_equal '0711', @gateway.send(:expdate, credit_card('4111111111111111', :month => "7", :year => "2011")) + assert_equal '0909', @gateway.send(:expdate, credit_card('4111111111111111', :month => '9', :year => '2009')) + assert_equal '0711', @gateway.send(:expdate, credit_card('4111111111111111', :month => '7', :year => '2011')) end def test_supported_countries @@ -112,7 +112,7 @@ def test_amount private def post_data_fixture - "password=password&type=auth&ccnumber=4111111111111111&username=demo&ccexp=1111&amount=100&cvv=999" + 'password=password&type=auth&ccnumber=4111111111111111&username=demo&ccexp=1111&amount=100&cvv=999' end def minimum_requirements @@ -120,14 +120,14 @@ def minimum_requirements end def successful_authorization_response - "response=1&responsetext=SUCCESS&authcode=123456&transactionid=1355694937&avsresponse=Y&cvvresponse=M&orderid=&type=auth&response_code=100" + 'response=1&responsetext=SUCCESS&authcode=123456&transactionid=1355694937&avsresponse=Y&cvvresponse=M&orderid=&type=auth&response_code=100' end def successful_purchase_response - "response=1&responsetext=SUCCESS&authcode=123456&transactionid=1346648416&avsresponse=N&cvvresponse=N&orderid=&type=sale&response_code=100" + 'response=1&responsetext=SUCCESS&authcode=123456&transactionid=1346648416&avsresponse=N&cvvresponse=N&orderid=&type=sale&response_code=100' end def failed_purchase_response - "response=2&responsetext=DECLINE&authcode=&transactionid=1346648595&avsresponse=N&cvvresponse=N&orderid=&type=sale&response_code=200" + 'response=2&responsetext=DECLINE&authcode=&transactionid=1346648595&avsresponse=N&cvvresponse=N&orderid=&type=sale&response_code=200' end end diff --git a/test/unit/gateways/mundipagg_test.rb b/test/unit/gateways/mundipagg_test.rb new file mode 100644 index 00000000000..208ddba3a5d --- /dev/null +++ b/test/unit/gateways/mundipagg_test.rb @@ -0,0 +1,836 @@ +require 'test_helper' + +class MundipaggTest < Test::Unit::TestCase + include CommStub + def setup + @gateway = MundipaggGateway.new(api_key: 'my_api_key') + @credit_card = credit_card + @amount = 100 + + @options = { + order_id: '1', + billing_address: address, + description: 'Store Purchase' + } + end + + def test_successful_purchase + @gateway.expects(:ssl_post).returns(successful_purchase_response) + + response = @gateway.purchase(@amount, @credit_card, @options) + assert_success response + + assert_equal 'ch_90Vjq8TrwfP74XJO', response.authorization + assert response.test? + end + + def test_successful_purchase_with_holder_document + @options[:holder_document] = 'a1b2c3d4' + response = stub_comms do + @gateway.purchase(@amount, @credit_card, @options) + end.check_request do |endpoint, data, headers| + assert_match(/a1b2c3d4/, data) + end.respond_with(successful_purchase_response) + + assert_success response + assert response.test? + end + + def test_billing_not_sent + @options.delete(:billing_address) + stub_comms do + @gateway.purchase(@amount, @credit_card, @options) + end.check_request do |endpoint, data, headers| + refute data['billing_address'] + end.respond_with(successful_purchase_response) + end + + def test_failed_purchase + @gateway.expects(:ssl_post).returns(failed_purchase_response) + + response = @gateway.purchase(@amount, @credit_card, @options) + assert_failure response + assert_equal Gateway::STANDARD_ERROR_CODE[:processing_error], response.error_code + end + + def test_successful_authorize + @gateway.expects(:ssl_post).returns(successful_authorize_response) + + response = @gateway.authorize(@amount, @credit_card, @options) + assert_success response + + assert_equal 'ch_gm5wrlGMI2Fb0x6K', response.authorization + assert response.test? + end + + def test_failed_authorize + @gateway.expects(:ssl_post).returns(failed_authorize_response) + + response = @gateway.authorize(@amount, @credit_card, @options) + assert_failure response + assert_equal Gateway::STANDARD_ERROR_CODE[:processing_error], response.error_code + end + + def test_successful_capture + @gateway.expects(:ssl_post).returns(successful_capture_response) + + response = @gateway.capture(@amount, @credit_card, @options) + assert_success response + + assert_equal 'ch_gm5wrlGMI2Fb0x6K', response.authorization + assert response.test? + end + + def test_failed_capture + @gateway.expects(:ssl_post).returns(failed_capture_response) + + response = @gateway.capture(@amount, @credit_card, @options) + assert_failure response + assert_equal Gateway::STANDARD_ERROR_CODE[:processing_error], response.error_code + end + + def test_successful_refund + @gateway.expects(:ssl_request).returns(successful_refund_response) + + response = @gateway.refund(@amount, 'K1J5B1YFLE') + assert_success response + + assert_equal 'ch_RbPVPWMH2bcGA50z', response.authorization + assert response.test? + end + + def test_failed_refund + @gateway.expects(:ssl_request).returns(failed_refund_response) + + response = @gateway.refund(@amount, 'abc') + assert_failure response + assert_equal Gateway::STANDARD_ERROR_CODE[:processing_error], response.error_code + end + + def test_successful_void + @gateway.expects(:ssl_request).returns(successful_void_response) + + response = @gateway.void('ch_RbPVPWMH2bcGA50z') + assert_success response + + assert_equal 'ch_RbPVPWMH2bcGA50z', response.authorization + assert response.test? + end + + def test_failed_void + @gateway.expects(:ssl_request).returns(failed_void_response) + + response = @gateway.void('abc') + assert_failure response + assert_equal Gateway::STANDARD_ERROR_CODE[:processing_error], response.error_code + end + + def test_successful_verify + @gateway.expects(:ssl_request).returns(successful_authorize_response) + @gateway.expects(:ssl_post).returns(successful_verify_response) + + response = @gateway.verify(@credit_card, @options) + assert_success response + + assert_equal 'ch_G9rB74PI3uoDMxAo', response.authorization + assert response.test? + end + + def test_successful_verify_with_failed_void + response = stub_comms(@gateway, :ssl_request) do + @gateway.verify(@credit_card, @options) + end.respond_with(successful_authorize_response, failed_void_response) + assert_success response + assert_equal 'Simulator|Transação de simulação autorizada com sucesso', response.message + end + + def test_sucessful_store + @gateway.expects(:ssl_post).times(2).returns(successful_create_customer_response, successful_store_response) + + response = @gateway.store(@credit_card, @options) + assert_success response + + assert_equal 'cus_N70xAX6S65cMnokB|card_51ElNwYSVJFpRe0g', response.authorization + assert response.test? + end + + def test_scrub + assert @gateway.supports_scrubbing? + assert_equal @gateway.scrub(pre_scrubbed), post_scrubbed + end + + private + + def pre_scrubbed + %q( + opening connection to api.mundipagg.com:443... + opened + starting SSL for api.mundipagg.com:443... + SSL established + <- "POST /core/v1/charges/ HTTP/1.1\r\nContent-Type: application/json\r\nAuthorization: Basic c2tfdGVzdF9keE1WOE51QnZpajZKNVhuOg==\r\nAccept: application/json\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nUser-Agent: Ruby\r\nConnection: close\r\nHost: api.mundipagg.com\r\nContent-Length: 424\r\n\r\n" + <- "{\"amount\":100,\"currency\":\"USD\",\"customer\":{\"email\":null,\"name\":\"Longbob Longsen\"},\"payment\":{\"payment_method\":\"credit_card\",\"credit_card\":{\"card\":{\"number\":\"4000100011112224\",\"holder_name\":\"Longbob Longsen\",\"exp_month\":9,\"exp_year\":2019,\"cvv\":\"123\",\"billing_address\":{\"street\":\"My Street\",\"number\":\"456\",\"compliment\":\"Apt 1\",\"city\":\"Ottawa\",\"state\":\"ON\",\"country\":\"CA\",\"zip_code\":\"K1C2N6\",\"neighborhood\":\"Sesame Street\"}}}}}" + -> "HTTP/1.1 200 OK\r\n" + -> "Date: Thu, 01 Feb 2018 20:23:19 GMT\r\n" + -> "Content-Type: application/json; charset=utf-8\r\n" + -> "Content-Length: 801\r\n" + -> "Connection: close\r\n" + -> "Cache-Control: no-cache\r\n" + -> "Pragma: no-cache\r\n" + -> "Content-Encoding: gzip\r\n" + -> "Expires: -1\r\n" + -> "Set-Cookie: TS01e8e2cd=0118d560cc62281517c87bb3b52c62fba3f9d13acb485adc69cac121833699beb2a66ca4bfe3e2af65dfe2f67542ec36ff8e41db56; Path=/; Domain=.api.mundipagg.com\r\n" + -> "\r\n" + reading 801 bytes... + -> "\x1F\x8B\b\x00\x00\x00\x00\x00\x04\x00\x95T\xCDn\x9C0\x10\xBEW\xEA; \xCEA2,,lnmRU\xD5\xB6I\x9AM\xAA\xAA\x174k\x9B]\xB7`\x13c\xB2\xD9\xA4\xFB4=\xF4A\xF2b\xB5\xCD\xC2\x82H\x95\xE4\x84\x98\xEF\x9B\xF1\xCC7?\x0Fo\xDF8\x8E\xCB\x88{\xEC\xB8x\x9D\xBE\x17\xBF\xD0\x1C>_G??\xDD\x7F\xBF\xF9\x9A\xBBG\x16\xC7\x82P\xC3\xF8\x18$\x97'\xA7\xC1b6\xDF\x03+Pt\x03\xDB\xB4\t\x004\xC1\x81\x8F#\x8FNH\xE6\x85\x10\x11o\x19\xFB\xB1\x87&\xD3I\x12M!\x0E\t\xEC\x1D\xA1\x105W\xDA\xC9G\xA8\xB1\x94\xC0H:6W\nT]\x99\xE8\x86\xD0\xE6SKI9\xDE\x1A\xF3\xF5\xE2\xD4m#l\v\xCAUZP\xB5\x16ME\x92\x12\xA6R\f\x92\xB8\xFDW\xCC\vn\x80\xFC\xC4C\x81\x87\xFC\xAB\x00\x1D\a\x93c\x7F\xF6\xA3\x8D/\xA9.\xEC\xFF\xC4\xA4%\xD6%y\x19\x11\xD7\x95\x12\x05\x95\x9A\xF6`\f\a\xD1\xEB*\xF5O\xCF/6\xE8j\xB3Y\xD0\xF8\xC3\\$\x8D\x8F\xA6p(\xAC\xEE\x9F\x05_-\xC5\xD21\xDF\x8A\xF2\x0E\xA7\x05\xB0\xDC\x10:\v\xA19\xE375\xB5\"f\x90W\xB4E^Z\xD3+\xAA2z\xAE\x05\xA7\xA6=\x0F;c\xD95\xD5\xE6P\xA9TI\xE0\x15`\xC5\x04\x1FUm\xB0\xF4\xAE\xD8\xC2\xE6v\xC3\xC2\xB3\xEB \x96\xF3\xB2\v\xDA\xF3L\xD5\xB6\xA4O\xB6r4}q\xE0\x87\xD3 \x9Eya\x92\x10/DQ\xE6\xC1\x94\xF8\x1E\xC28\xCE\xA2)\xCEhD;\xD7\xD1\xA0\rF\rC\xA9j\xFD`G\xAFj\x8Cie0%\xEBNR\xC6\xB5K\x9E\x9B\xA13\x90\xDF\x05\xC775\x93T\xA6m\xFF*V\xD49(!\xDD\x11\x05\xB2\x8C\xE5\fl\xAD\xED\x9A\x8DY\xAA)1\fga\x18\x8Da^\xD5\x06\x9E\xA0d\x12=\x01C\xAD\xD6]\xF0Y\x10\xC5\xF1lL*t}\xB0\xB2\x94E\x9B\xEE\xEF+\xDB\x89\xC7\xBF\x8F\x7F\x84C\xA8\xD3\xD4\xD1\xFC\xEA\xA0B\xB2{ \xE0`Q8Z!\x1D@\x8C\xE3J\xAA\xA5<\xD4\x86:\x86(\xA9\x84A\x8Fm\x9E\xC0I\xBA\xD7\xBF\xA3\xDA\xAEw3t\xD8\x1DmN\xEF\xE4\xFC'\x8F.\xD4\xEA\x12\xF3\xFB`\x19\xB7N\x9A\x951\xA9\xE7\xB0bw)a+f{\xE4\x86\b!\x1F\xF5HvV3Q\xCB\x1E\b\x82\xB0GYj\x15\xEC\x83\xDFX\x05=\xFBZ\xE4\xA4\xD7\xE5\xFFl\xA9\xD9\xD3\xBB2-\x04WkM\x9B\r\xCD[\n\xE6\xE8%\xEB\x01\x87I4[pK{\xA1\x9E[\xE3\xD9\x8F\x1E\xF9\xB9E\x1E\x90\x97,\xD7\xB7c\x95\x02!\xB2\x99\xF5No\x9B\x92\xA4\xD4\x86\xF9\xB2u\x16\xCD\xCFQ\x0F\xE7u\xB1\xB4\xE7\xCD\r\xA3\xE9\x00\xB9ge\xD7\xFD\xB9\x7F\x12\x9C\raN\xD9j\xBD\x14r-\x9A\x9B\xBD\xA0\x95\xD6\xF3\xA9'0S\xF6\xE2\x9F+\x05\e\x18@F0\xFB\xC0\xF9\xD9\xD0\xC5l\xB9\xB4^'\xEF\x06\x88.\x95\xA6\xFE>\xDF#\xA7+\xEA\xC8\x19&\xD0\xBA\xEC\x0EB\rO\xD2\x9E\xB1\xEBf\xF5\xC5\rzE{\xBAS\xA7;S\n^\xD1\xC16\xB4\xEA\xEA\bm6\xF6\x18\xBF}\xB3\xFB\aD\t\x1C\xBA\xE0\a\x00\x00" + read 801 bytes + Conn close + ) + end + + def post_scrubbed + %q( + opening connection to api.mundipagg.com:443... + opened + starting SSL for api.mundipagg.com:443... + SSL established + <- "POST /core/v1/charges/ HTTP/1.1\r\nContent-Type: application/json\r\nAuthorization: Basic [FILTERED]==\r\nAccept: application/json\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nUser-Agent: Ruby\r\nConnection: close\r\nHost: api.mundipagg.com\r\nContent-Length: 424\r\n\r\n" + <- "{\"amount\":100,\"currency\":\"USD\",\"customer\":{\"email\":null,\"name\":\"Longbob Longsen\"},\"payment\":{\"payment_method\":\"credit_card\",\"credit_card\":{\"card\":{\"number\":\"[FILTERED]\",\"holder_name\":\"Longbob Longsen\",\"exp_month\":9,\"exp_year\":2019,\"cvv\":\"[FILTERED]\",\"billing_address\":{\"street\":\"My Street\",\"number\":\"456\",\"compliment\":\"Apt 1\",\"city\":\"Ottawa\",\"state\":\"ON\",\"country\":\"CA\",\"zip_code\":\"K1C2N6\",\"neighborhood\":\"Sesame Street\"}}}}}" + -> "HTTP/1.1 200 OK\r\n" + -> "Date: Thu, 01 Feb 2018 20:23:19 GMT\r\n" + -> "Content-Type: application/json; charset=utf-8\r\n" + -> "Content-Length: 801\r\n" + -> "Connection: close\r\n" + -> "Cache-Control: no-cache\r\n" + -> "Pragma: no-cache\r\n" + -> "Content-Encoding: gzip\r\n" + -> "Expires: -1\r\n" + -> "Set-Cookie: TS01e8e2cd=0118d560cc62281517c87bb3b52c62fba3f9d13acb485adc69cac121833699beb2a66ca4bfe3e2af65dfe2f67542ec36ff8e41db56; Path=/; Domain=.api.mundipagg.com\r\n" + -> "\r\n" + reading 801 bytes... + -> "\x1F\x8B\b\x00\x00\x00\x00\x00\x04\x00\x95T\xCDn\x9C0\x10\xBEW\xEA; \xCEA2,,lnmRU\xD5\xB6I\x9AM\xAA\xAA\x174k\x9B]\xB7`\x13c\xB2\xD9\xA4\xFB4=\xF4A\xF2b\xB5\xCD\xC2\x82H\x95\xE4\x84\x98\xEF\x9B\xF1\xCC7?\x0Fo\xDF8\x8E\xCB\x88{\xEC\xB8x\x9D\xBE\x17\xBF\xD0\x1C>_G??\xDD\x7F\xBF\xF9\x9A\xBBG\x16\xC7\x82P\xC3\xF8\x18$\x97'\xA7\xC1b6\xDF\x03+Pt\x03\xDB\xB4\t\x004\xC1\x81\x8F#\x8FNH\xE6\x85\x10\x11o\x19\xFB\xB1\x87&\xD3I\x12M!\x0E\t\xEC\x1D\xA1\x105W\xDA\xC9G\xA8\xB1\x94\xC0H:6W\nT]\x99\xE8\x86\xD0\xE6SKI9\xDE\x1A\xF3\xF5\xE2\xD4m#l\v\xCAUZP\xB5\x16ME\x92\x12\xA6R\f\x92\xB8\xFDW\xCC\vn\x80\xFC\xC4C\x81\x87\xFC\xAB\x00\x1D\a\x93c\x7F\xF6\xA3\x8D/\xA9.\xEC\xFF\xC4\xA4%\xD6%y\x19\x11\xD7\x95\x12\x05\x95\x9A\xF6`\f\a\xD1\xEB*\xF5O\xCF/6\xE8j\xB3Y\xD0\xF8\xC3\\$\x8D\x8F\xA6p(\xAC\xEE\x9F\x05_-\xC5\xD21\xDF\x8A\xF2\x0E\xA7\x05\xB0\xDC\x10:\v\xA19\xE375\xB5\"f\x90W\xB4E^Z\xD3+\xAA2z\xAE\x05\xA7\xA6=\x0F;c\xD95\xD5\xE6P\xA9TI\xE0\x15`\xC5\x04\x1FUm\xB0\xF4\xAE\xD8\xC2\xE6v\xC3\xC2\xB3\xEB \x96\xF3\xB2\v\xDA\xF3L\xD5\xB6\xA4O\xB6r4}q\xE0\x87\xD3 \x9Eya\x92\x10/DQ\xE6\xC1\x94\xF8\x1E\xC28\xCE\xA2)\xCEhD;\xD7\xD1\xA0\rF\rC\xA9j\xFD`G\xAFj\x8Cie0%\xEBNR\xC6\xB5K\x9E\x9B\xA13\x90\xDF\x05\xC775\x93T\xA6m\xFF*V\xD49(!\xDD\x11\x05\xB2\x8C\xE5\fl\xAD\xED\x9A\x8DY\xAA)1\fga\x18\x8Da^\xD5\x06\x9E\xA0d\x12=\x01C\xAD\xD6]\xF0Y\x10\xC5\xF1lL*t}\xB0\xB2\x94E\x9B\xEE\xEF+\xDB\x89\xC7\xBF\x8F\x7F\x84C\xA8\xD3\xD4\xD1\xFC\xEA\xA0B\xB2{ \xE0`Q8Z!\x1D@\x8C\xE3J\xAA\xA5<\xD4\x86:\x86(\xA9\x84A\x8Fm\x9E\xC0I\xBA\xD7\xBF\xA3\xDA\xAEw3t\xD8\x1DmN\xEF\xE4\xFC'\x8F.\xD4\xEA\x12\xF3\xFB`\x19\xB7N\x9A\x951\xA9\xE7\xB0bw)a+f{\xE4\x86\b!\x1F\xF5HvV3Q\xCB\x1E\b\x82\xB0GYj\x15\xEC\x83\xDFX\x05=\xFBZ\xE4\xA4\xD7\xE5\xFFl\xA9\xD9\xD3\xBB2-\x04WkM\x9B\r\xCD[\n\xE6\xE8%\xEB\x01\x87I4[pK{\xA1\x9E[\xE3\xD9\x8F\x1E\xF9\xB9E\x1E\x90\x97,\xD7\xB7c\x95\x02!\xB2\x99\xF5No\x9B\x92\xA4\xD4\x86\xF9\xB2u\x16\xCD\xCFQ\x0F\xE7u\xB1\xB4\xE7\xCD\r\xA3\xE9\x00\xB9ge\xD7\xFD\xB9\x7F\x12\x9C\raN\xD9j\xBD\x14r-\x9A\x9B\xBD\xA0\x95\xD6\xF3\xA9'0S\xF6\xE2\x9F+\x05\e\x18@F0\xFB\xC0\xF9\xD9\xD0\xC5l\xB9\xB4^'\xEF\x06\x88.\x95\xA6\xFE>\xDF#\xA7+\xEA\xC8\x19&\xD0\xBA\xEC\x0EB\rO\xD2\x9E\xB1\xEBf\xF5\xC5\rzE{\xBAS\xA7;S\n^\xD1\xC16\xB4\xEA\xEA\bm6\xF6\x18\xBF}\xB3\xFB\aD\t\x1C\xBA\xE0\a\x00\x00" + read 801 bytes + Conn close + ) + end + + def successful_purchase_response + %( + { + "id": "ch_90Vjq8TrwfP74XJO", + "code": "ME0KIN4A0O", + "gateway_id": "162bead8-23a0-4708-b687-078a69a1aa7c", + "amount": 100, + "paid_amount": 100, + "status": "paid", + "currency": "USD", + "payment_method": "credit_card", + "paid_at": "2018-02-01T18:41:05Z", + "created_at": "2018-02-01T18:41:04Z", + "updated_at": "2018-02-01T18:41:04Z", + "customer": { + "id": "cus_VxJX2NmTqyUnXgL9", + "name": "Longbob Longsen", + "email": "", + "delinquent": false, + "created_at": "2018-02-01T18:41:04Z", + "updated_at": "2018-02-01T18:41:04Z", + "phones": {} + }, + "last_transaction": { + "id": "tran_JNzjzadcVZHlG8K2", + "transaction_type": "credit_card", + "gateway_id": "c579c8fa-53d7-41a8-b4cc-a03c712ebbb7", + "amount": 100, + "status": "captured", + "success": true, + "installments": 1, + "acquirer_name": "simulator", + "acquirer_affiliation_code": "", + "acquirer_tid": "198548", + "acquirer_nsu": "866277", + "acquirer_auth_code": "713736", + "acquirer_message": "Simulator|Transação de simulação autorizada com sucesso", + "acquirer_return_code": "0", + "operation_type": "auth_and_capture", + "card": { + "id": "card_pD02Q6WtOTB7a3kE", + "first_six_digits": "400010", + "last_four_digits": "2224", + "brand": "Visa", + "holder_name": "Longbob Longsen", + "exp_month": 9, + "exp_year": 2019, + "status": "active", + "created_at": "2018-02-01T18:41:04Z", + "updated_at": "2018-02-01T18:41:04Z", + "billing_address": { + "street": "My Street", + "number": "456", + "zip_code": "K1C2N6", + "neighborhood": "Sesame Street", + "city": "Ottawa", + "state": "ON", + "country": "CA", + "line_1": "456, My Street, Sesame Street" + }, + "type": "credit" + }, + "created_at": "2018-02-01T18:41:04Z", + "updated_at": "2018-02-01T18:41:04Z", + "gateway_response": { + "code": "201" + } + } + } + ) + end + + def failed_purchase_response + %( + { + "id": "ch_ykXLG3RfVfNE4dZe", + "code": "3W80HGVS0R", + "gateway_id": "79ae6732-1b60-4008-80f5-0d1be8ec41a7", + "amount": 105200, + "status": "failed", + "currency": "USD", + "payment_method": "credit_card", + "created_at": "2018-02-01T18:42:44Z", + "updated_at": "2018-02-01T18:42:45Z", + "customer": { + "id": "cus_0JnywlzI3hV6ZNe2", + "name": "Longbob Longsen", + "email": "", + "delinquent": false, + "created_at": "2018-02-01T18:42:44Z", + "updated_at": "2018-02-01T18:42:44Z", + "phones": {} + }, + "last_transaction": { + "id": "tran_nVx8730IjhOR8PD2", + "transaction_type": "credit_card", + "gateway_id": "f3993413-73a0-4e8d-a7bc-eb3ed198c770", + "amount": 105200, + "status": "not_authorized", + "success": false, + "installments": 1, + "acquirer_name": "simulator", + "acquirer_affiliation_code": "", + "acquirer_message": "Simulator|Transação de simulada negada por falta de crédito, utilizado para realizar simulação de autorização parcial.", + "acquirer_return_code": "92", + "operation_type": "auth_and_capture", + "card": { + "id": "card_VrxnWlrsOHOpzMj5", + "first_six_digits": "400030", + "last_four_digits": "2220", + "brand": "Visa", + "holder_name": "Longbob Longsen", + "exp_month": 9, + "exp_year": 2019, + "status": "active", + "created_at": "2018-02-01T18:42:44Z", + "updated_at": "2018-02-01T18:42:44Z", + "billing_address": { + "street": "My Street", + "number": "456", + "zip_code": "K1C2N6", + "neighborhood": "Sesame Street", + "city": "Ottawa", + "state": "ON", + "country": "CA", + "line_1": "456, My Street, Sesame Street" + }, + "type": "credit" + }, + "created_at": "2018-02-01T18:42:44Z", + "updated_at": "2018-02-01T18:42:44Z", + "gateway_response": { + "code": "201" + } + } + } + ) + end + + def successful_authorize_response + %( + { + "id": "ch_gm5wrlGMI2Fb0x6K", + "code": "K1J5B1YFLE", + "gateway_id": "3b6c0f72-c4b3-48b2-8eb7-2424321a6c93", + "amount": 100, + "status": "pending", + "currency": "USD", + "payment_method": "credit_card", + "created_at": "2018-02-01T16:43:30Z", + "updated_at": "2018-02-01T16:43:30Z", + "customer": { + "id": "cus_bVWYqeTmpu9VYLd9", + "name": "Longbob Longsen", + "email": "", + "delinquent": false, + "created_at": "2018-02-01T16:43:30Z", + "updated_at": "2018-02-01T16:43:30Z", + "phones": {} + }, + "last_transaction": { + "id": "tran_DWJlEApZI9UL2qR9", + "transaction_type": "credit_card", + "gateway_id": "6dae95a7-6b7f-4431-be33-cb3ecf21287a", + "amount": 100, + "status": "authorized_pending_capture", + "success": true, + "installments": 1, + "acquirer_name": "simulator", + "acquirer_affiliation_code": "", + "acquirer_tid": "25970", + "acquirer_nsu": "506128", + "acquirer_auth_code": "523448", + "acquirer_message": "Simulator|Transação de simulação autorizada com sucesso", + "acquirer_return_code": "0", + "operation_type": "auth_only", + "card": { + "id": "card_J26O3K2hvPc2vOQG", + "first_six_digits": "400010", + "last_four_digits": "2224", + "brand": "Visa", + "holder_name": "Longbob Longsen", + "exp_month": 9, + "exp_year": 2019, + "status": "active", + "created_at": "2018-02-01T16:43:30Z", + "updated_at": "2018-02-01T16:43:30Z", + "billing_address": { + "street": "My Street", + "number": "456", + "zip_code": "K1C2N6", + "neighborhood": "Sesame Street", + "city": "Ottawa", + "state": "ON", + "country": "CA", + "line_1": "456, My Street, Sesame Street" + }, + "type": "credit" + }, + "created_at": "2018-02-01T16:43:31Z", + "updated_at": "2018-02-01T16:43:31Z", + "gateway_response": { + "code": "201" + } + } + } + ) + end + + def failed_authorize_response + %( + { + "id": "ch_O4bW13ukwF5XpmLg", + "code": "2KW1C5VSZO", + "gateway_id": "9bf24ea7-e913-44bc-92ca-50491ffcd7a1", + "amount": 105200, + "status": "failed", + "currency": "USD", + "payment_method": "credit_card", + "created_at": "2018-02-01T18:46:06Z", + "updated_at": "2018-02-01T18:46:06Z", + "customer": { + "id": "cus_7VGAGxqI4OUwZ392", + "name": "Longbob Longsen", + "email": "", + "delinquent": false, + "created_at": "2018-02-01T18:46:06Z", + "updated_at": "2018-02-01T18:46:06Z", + "phones": {} + }, + "last_transaction": { + "id": "tran_g0JYdDXcDesqd36E", + "transaction_type": "credit_card", + "gateway_id": "c0896dd6-0d5c-4e8b-9d92-df5a70e3fb76", + "amount": 105200, + "status": "not_authorized", + "success": false, + "installments": 1, + "acquirer_name": "simulator", + "acquirer_affiliation_code": "", + "acquirer_message": "Simulator|Transação de simulada negada por falta de crédito, utilizado para realizar simulação de autorização parcial.", + "acquirer_return_code": "92", + "operation_type": "auth_only", + "card": { + "id": "card_LR0A1vcVbsmY3wzY", + "first_six_digits": "400030", + "last_four_digits": "2220", + "brand": "Visa", + "holder_name": "Longbob Longsen", + "exp_month": 9, + "exp_year": 2019, + "status": "active", + "created_at": "2018-02-01T18:46:06Z", + "updated_at": "2018-02-01T18:46:06Z", + "billing_address": { + "street": "My Street", + "number": "456", + "zip_code": "K1C2N6", + "neighborhood": "Sesame Street", + "city": "Ottawa", + "state": "ON", + "country": "CA", + "line_1": "456, My Street, Sesame Street" + }, + "type": "credit" + }, + "created_at": "2018-02-01T18:46:06Z", + "updated_at": "2018-02-01T18:46:06Z", + "gateway_response": { + "code": "201" + } + } + } + ) + end + + def successful_capture_response + %( + { + "id": "ch_gm5wrlGMI2Fb0x6K", + "code": "ch_gm5wrlGMI2Fb0x6K", + "gateway_id": "3b6c0f72-c4b3-48b2-8eb7-2424321a6c93", + "amount": 100, + "paid_amount": 100, + "status": "paid", + "currency": "USD", + "payment_method": "credit_card", + "paid_at": "2018-02-01T16:43:33Z", + "created_at": "2018-02-01T16:43:30Z", + "updated_at": "2018-02-01T16:43:33Z", + "customer": { + "id": "cus_bVWYqeTmpu9VYLd9", + "name": "Longbob Longsen", + "email": "", + "delinquent": false, + "created_at": "2018-02-01T16:43:30Z", + "updated_at": "2018-02-01T16:43:30Z", + "phones": {} + }, + "last_transaction": { + "id": "tran_wL9APd6cws19WNJ7", + "transaction_type": "credit_card", + "gateway_id": "6dae95a7-6b7f-4431-be33-cb3ecf21287a", + "amount": 100, + "status": "captured", + "success": true, + "installments": 1, + "acquirer_name": "simulator", + "acquirer_affiliation_code": "", + "acquirer_tid": "299257", + "acquirer_nsu": "894685", + "acquirer_auth_code": "523448", + "acquirer_message": "Simulator|Transação de simulação capturada com sucesso", + "acquirer_return_code": "0", + "operation_type": "capture", + "card": { + "id": "card_J26O3K2hvPc2vOQG", + "first_six_digits": "400010", + "last_four_digits": "2224", + "brand": "Visa", + "holder_name": "Longbob Longsen", + "exp_month": 9, + "exp_year": 2019, + "status": "active", + "created_at": "2018-02-01T16:43:30Z", + "updated_at": "2018-02-01T16:43:30Z", + "billing_address": { + "street": "My Street", + "number": "456", + "zip_code": "K1C2N6", + "neighborhood": "Sesame Street", + "city": "Ottawa", + "state": "ON", + "country": "CA", + "line_1": "456, My Street, Sesame Street" + }, + "type": "credit" + }, + "created_at": "2018-02-01T16:43:33Z", + "updated_at": "2018-02-01T16:43:33Z", + "gateway_response": { + "code": "200" + } + } + } + ) + end + + def failed_capture_response + '{"message": "Charge not found."}' + end + + def successful_refund_response + %( + { + "id": "ch_RbPVPWMH2bcGA50z", + "code": "O5L5A4VCRK", + "gateway_id": "d77c6a32-e1c8-42d4-bd1b-e92b36f054f9", + "amount": 100, + "canceled_amount": 100, + "status": "canceled", + "currency": "USD", + "payment_method": "credit_card", + "canceled_at": "2018-02-01T16:34:07Z", + "created_at": "2018-02-01T16:34:07Z", + "updated_at": "2018-02-01T16:34:07Z", + "customer": { + "id": "cus_odYDGxQirlcp693a", + "name": "Longbob Longsen", + "email": "", + "delinquent": false, + "created_at": "2018-02-01T16:34:07Z", + "updated_at": "2018-02-01T16:34:07Z", + "phones": {} + }, + "last_transaction": { + "id": "tran_m1prZBNTgUmZrGzZ", + "transaction_type": "credit_card", + "gateway_id": "23648dca-07dc-4f31-9b24-26aa702dc7e8", + "amount": 100, + "status": "voided", + "success": true, + "acquirer_name": "simulator", + "acquirer_affiliation_code": "", + "acquirer_tid": "489627", + "acquirer_nsu": "174061", + "acquirer_auth_code": "433589", + "acquirer_return_code": "0", + "operation_type": "cancel", + "card": { + "id": "card_8PaGBMOhXwi9Q24z", + "first_six_digits": "400010", + "last_four_digits": "2224", + "brand": "Visa", + "holder_name": "Longbob Longsen", + "exp_month": 9, + "exp_year": 2019, + "status": "active", + "created_at": "2018-02-01T16:34:07Z", + "updated_at": "2018-02-01T16:34:07Z", + "billing_address": { + "street": "My Street", + "number": "456", + "zip_code": "K1C2N6", + "neighborhood": "Sesame Street", + "city": "Ottawa", + "state": "ON", + "country": "CA", + "line_1": "456, My Street, Sesame Street" + }, + "type": "credit" + }, + "created_at": "2018-02-01T16:34:07Z", + "updated_at": "2018-02-01T16:34:07Z", + "gateway_response": { + "code": "200" + } + } + } + ) + end + + def failed_refund_response + '{"message": "Charge not found."}' + end + + def successful_void_response + %( + { + "id": "ch_RbPVPWMH2bcGA50z", + "code": "O5L5A4VCRK", + "gateway_id": "d77c6a32-e1c8-42d4-bd1b-e92b36f054f9", + "amount": 100, + "canceled_amount": 100, + "status": "canceled", + "currency": "USD", + "payment_method": "credit_card", + "canceled_at": "2018-02-01T16:34:07Z", + "created_at": "2018-02-01T16:34:07Z", + "updated_at": "2018-02-01T16:34:07Z", + "customer": { + "id": "cus_odYDGxQirlcp693a", + "name": "Longbob Longsen", + "email": "", + "delinquent": false, + "created_at": "2018-02-01T16:34:07Z", + "updated_at": "2018-02-01T16:34:07Z", + "phones": {} + }, + "last_transaction": { + "id": "tran_m1prZBNTgUmZrGzZ", + "transaction_type": "credit_card", + "gateway_id": "23648dca-07dc-4f31-9b24-26aa702dc7e8", + "amount": 100, + "status": "voided", + "success": true, + "acquirer_name": "simulator", + "acquirer_affiliation_code": "", + "acquirer_tid": "489627", + "acquirer_nsu": "174061", + "acquirer_auth_code": "433589", + "acquirer_return_code": "0", + "operation_type": "cancel", + "card": { + "id": "card_8PaGBMOhXwi9Q24z", + "first_six_digits": "400010", + "last_four_digits": "2224", + "brand": "Visa", + "holder_name": "Longbob Longsen", + "exp_month": 9, + "exp_year": 2019, + "status": "active", + "created_at": "2018-02-01T16:34:07Z", + "updated_at": "2018-02-01T16:34:07Z", + "billing_address": { + "street": "My Street", + "number": "456", + "zip_code": "K1C2N6", + "neighborhood": "Sesame Street", + "city": "Ottawa", + "state": "ON", + "country": "CA", + "line_1": "456, My Street, Sesame Street" + }, + "type": "credit" + }, + "created_at": "2018-02-01T16:34:07Z", + "updated_at": "2018-02-01T16:34:07Z", + "gateway_response": { + "code": "200" + } + } + } + ) + end + + def failed_void_response + '{"message": "Charge not found."}' + end + + def successful_verify_response + %( + { + "id": "ch_G9rB74PI3uoDMxAo", + "code": "8EXXFEBQDK", + "gateway_id": "4b228be6-6795-416a-9238-204020e7fdd1", + "amount": 100, + "canceled_amount": 100, + "status": "canceled", + "currency": "USD", + "payment_method": "credit_card", + "canceled_at": "2018-02-02T14:25:25Z", + "created_at": "2018-02-02T14:25:24Z", + "updated_at": "2018-02-02T14:25:25Z", + "customer": { + "id": "cus_V2GXxeOunSYpEvOD", + "name": "Longbob Longsen", + "email": "", + "delinquent": false, + "created_at": "2018-02-02T14:25:24Z", + "updated_at": "2018-02-02T14:25:24Z", + "phones": {} + }, + "last_transaction": { + "id": "tran_r50yVePSJbuA3dKb", + "transaction_type": "credit_card", + "gateway_id": "2d1c155a-e89d-4972-9ee1-a3b3f56d6ff8", + "amount": 100, + "status": "voided", + "success": true, + "acquirer_name": "simulator", + "acquirer_affiliation_code": "", + "acquirer_tid": "711106", + "acquirer_nsu": "553868", + "acquirer_auth_code": "271719", + "acquirer_return_code": "0", + "operation_type": "cancel", + "card": { + "id": "card_7WraOEps6FpRLQob", + "first_six_digits": "400010", + "last_four_digits": "2224", + "brand": "Visa", + "holder_name": "Longbob Longsen", + "exp_month": 9, + "exp_year": 2019, + "status": "active", + "created_at": "2018-02-02T14:25:24Z", + "updated_at": "2018-02-02T14:25:24Z", + "billing_address": { + "street": "My Street", + "number": "456", + "zip_code": "K1C2N6", + "neighborhood": "Sesame Street", + "city": "Ottawa", + "state": "ON", + "country": "CA", + "line_1": "456, My Street, Sesame Street" + }, + "type": "credit" + }, + "created_at": "2018-02-02T14:25:25Z", + "updated_at": "2018-02-02T14:25:25Z", + "gateway_response": { + "code": "200" + } + } + } + ) + end + + def successful_create_customer_response + %( + { + "id": "cus_NRL1bw3HpAHLbWPQ", + "name": "Sideshow Bob", + "email": "", + "delinquent": false, + "created_at": "2018-02-05T15:03:39Z", + "updated_at": "2018-02-05T15:03:39Z", + "phones": {} + } + ) + end + + def successful_store_response + %( + { + "id": "card_51ElNwYSVJFpRe0g", + "first_six_digits": "400010", + "last_four_digits": "2224", + "brand": "Visa", + "holder_name": "Longbob Longsen", + "exp_month": 9, + "exp_year": 2019, + "status": "active", + "created_at": "2018-02-05T15:45:01Z", + "updated_at": "2018-02-05T15:45:01Z", + "billing_address": { + "street": "My Street", + "number": "456", + "zip_code": "K1C2N6", + "neighborhood": "Sesame Street", + "city": "Ottawa", + "state": "ON", + "country": "CA", + "line_1": "456, My Street, Sesame Street" + }, + "customer": { + "id": "cus_N70xAX6S65cMnokB", + "name": "Bob Belcher", + "email": "", + "delinquent": false, + "created_at": "2018-02-05T15:45:01Z", + "updated_at": "2018-02-05T15:45:01Z", + "phones": {} + }, + "type": "credit" + } + ) + end +end diff --git a/test/unit/gateways/nab_transact_test.rb b/test/unit/gateways/nab_transact_test.rb index a10e2a44ee6..d02ebadce3a 100644 --- a/test/unit/gateways/nab_transact_test.rb +++ b/test/unit/gateways/nab_transact_test.rb @@ -86,7 +86,7 @@ def test_unsuccessful_purchase assert_instance_of Response, response assert_failure response assert response.test? - assert_equal "Expired Card", response.message + assert_equal 'Expired Card', response.message end def test_failed_login @@ -95,7 +95,7 @@ def test_failed_login response = @gateway.purchase(@amount, @credit_card, @options) assert_instance_of Response, response assert_failure response - assert_equal "Invalid merchant ID", response.message + assert_equal 'Invalid merchant ID', response.message end def test_supported_countries @@ -108,7 +108,7 @@ def test_supported_card_types def test_successful_refund @gateway.expects(:ssl_post).with(&check_transaction_type(:refund)).returns(successful_refund_response) - assert_success @gateway.refund(@amount, "009887", {:order_id => '1'}) + assert_success @gateway.refund(@amount, '009887', {:order_id => '1'}) end def test_successful_refund_with_merchant_descriptor @@ -131,9 +131,9 @@ def test_successful_credit def test_failed_refund @gateway.expects(:ssl_post).with(&check_transaction_type(:refund)).returns(failed_refund_response) - response = @gateway.refund(@amount, "009887", {:order_id => '1'}) + response = @gateway.refund(@amount, '009887', {:order_id => '1'}) assert_failure response - assert_equal "Only $1.00 available for refund", response.message + assert_equal 'Only $1.00 available for refund', response.message end def test_request_timeout_default @@ -153,6 +153,14 @@ def test_override_request_timeout end.respond_with(successful_purchase_response) end + def test_nonfractional_currencies + stub_comms(@gateway, :ssl_request) do + @gateway.authorize(10000, @credit_card, @options.merge(currency: 'JPY')) + end.check_request do |method, endpoint, data, headers| + assert_match(/<amount>100<\/amount>/, data) + end.respond_with(successful_authorize_response) + end + def test_scrub assert @gateway.supports_scrubbing? assert_equal @gateway.scrub(pre_scrubbed), post_scrubbed @@ -214,14 +222,14 @@ def check_transaction_type(type) end def valid_metadata(name, location) - return <<-XML.gsub(/^\s{4}/,'').gsub(/\n/, '') + return <<-XML.gsub(/^\s{4}/, '').gsub(/\n/, '') <metadata><meta name="ca_name" value="#{name}"/><meta name="ca_location" value="#{location}"/></metadata> XML end def assert_metadata(name, location, &block) stub_comms(@gateway, :ssl_request) do - block.call + yield end.check_request do |method, endpoint, data, headers| metadata_matcher = Regexp.escape(valid_metadata(name, location)) assert_match %r{#{metadata_matcher}}, data @@ -233,7 +241,7 @@ def failed_login_response end def successful_purchase_response - <<-XML.gsub(/^\s{4}/,'') + <<-XML.gsub(/^\s{4}/, '') <?xml version="1.0" encoding="UTF-8"?> <NABTransactMessage> <MessageInfo> @@ -276,7 +284,7 @@ def successful_purchase_response end def failed_purchase_response - <<-XML.gsub(/^\s{4}/,'') + <<-XML.gsub(/^\s{4}/, '') <?xml version="1.0" encoding="UTF-8"?> <NABTransactMessage> <MessageInfo> @@ -319,7 +327,7 @@ def failed_purchase_response end def successful_authorize_response - <<-XML.gsub(/^\s{4}/,'') + <<-XML.gsub(/^\s{4}/, '') <?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?> <NABTransactMessage> <MessageInfo> @@ -364,7 +372,7 @@ def successful_authorize_response end def successful_refund_response - <<-XML.gsub(/^\s{4}/,'') + <<-XML.gsub(/^\s{4}/, '') <?xml version="1.0" encoding="UTF-8"?> <NABTransactMessage> <MessageInfo> @@ -407,7 +415,7 @@ def successful_refund_response end def failed_refund_response - <<-XML.gsub(/^\s{4}/,'') + <<-XML.gsub(/^\s{4}/, '') <?xml version="1.0" encoding="UTF-8"?> <NABTransactMessage> <MessageInfo> diff --git a/test/unit/gateways/ncr_secure_pay_test.rb b/test/unit/gateways/ncr_secure_pay_test.rb index f1b8de1eccd..4fabb3b8779 100644 --- a/test/unit/gateways/ncr_secure_pay_test.rb +++ b/test/unit/gateways/ncr_secure_pay_test.rb @@ -16,7 +16,6 @@ def setup end def test_successful_purchase - response = stub_comms do @gateway.purchase(@amount, @credit_card, @options) end.check_request do |endpoint, data, headers| @@ -42,7 +41,6 @@ def test_failed_purchase end def test_successful_authorize - response = stub_comms do @gateway.authorize(@amount, @credit_card, @options) end.check_request do |endpoint, data, headers| @@ -67,7 +65,6 @@ def test_failed_authorize end def test_successful_capture - response = stub_comms do @gateway.capture(@amount, '12345', @options) end.check_request do |endpoint, data, headers| @@ -91,7 +88,6 @@ def test_failed_capture end def test_successful_refund - response = stub_comms do @gateway.refund(@amount, '12345', @options) end.check_request do |endpoint, data, headers| @@ -115,7 +111,6 @@ def test_failed_refund end def test_successful_void - response = stub_comms do @gateway.void('12345', @options) end.check_request do |endpoint, data, headers| @@ -138,7 +133,6 @@ def test_failed_void end def test_successful_verify - response = stub_comms do @gateway.verify(@credit_card, @options) end.respond_with(successful_authorize_response, successful_void_response) @@ -148,7 +142,6 @@ def test_successful_verify end def test_successful_verify_with_failed_void - response = stub_comms do @gateway.verify(@credit_card, @options) end.respond_with(successful_authorize_response, failed_void_response) @@ -158,7 +151,6 @@ def test_successful_verify_with_failed_void end def test_failed_verify - response = stub_comms do @gateway.verify(@credit_card, @options) end.respond_with(failed_authorize_response, failed_void_response) diff --git a/test/unit/gateways/net_registry_test.rb b/test/unit/gateways/net_registry_test.rb index e478e8d6151..0d6c50e2f63 100644 --- a/test/unit/gateways/net_registry_test.rb +++ b/test/unit/gateways/net_registry_test.rb @@ -105,6 +105,7 @@ def test_bad_login end private + def successful_purchase_response <<-RESPONSE approved diff --git a/test/unit/gateways/netaxept_test.rb b/test/unit/gateways/netaxept_test.rb index 2c03745c929..5dddbde3427 100644 --- a/test/unit/gateways/netaxept_test.rb +++ b/test/unit/gateways/netaxept_test.rb @@ -18,7 +18,7 @@ def setup end def test_successful_purchase - s = sequence("request") + s = sequence('request') @gateway.expects(:ssl_get).returns(successful_purchase_response[0]).in_sequence(s) @gateway.expects(:ssl_get).returns(successful_purchase_response[1]).in_sequence(s) @gateway.expects(:ssl_get).returns(successful_purchase_response[2]).in_sequence(s) @@ -32,7 +32,7 @@ def test_successful_purchase end def test_failed_purchase - s = sequence("request") + s = sequence('request') @gateway.expects(:ssl_get).returns(successful_purchase_response[0]).in_sequence(s) @gateway.expects(:ssl_get).returns(successful_purchase_response[1]).in_sequence(s) @gateway.expects(:ssl_get).returns(failed_purchase_response).in_sequence(s) @@ -51,7 +51,7 @@ def test_requires_order_id end def test_handles_currency_with_money - s = sequence("request") + s = sequence('request') @gateway.expects(:ssl_get).with(regexp_matches(/currencyCode=USD/)).returns(successful_purchase_response[0]).in_sequence(s) @gateway.expects(:ssl_get).returns(successful_purchase_response[1]).in_sequence(s) @gateway.expects(:ssl_get).returns(successful_purchase_response[2]).in_sequence(s) @@ -61,7 +61,7 @@ def test_handles_currency_with_money end def test_handles_currency_with_option - s = sequence("request") + s = sequence('request') @gateway.expects(:ssl_get).with(regexp_matches(/currencyCode=USD/)).returns(successful_purchase_response[0]).in_sequence(s) @gateway.expects(:ssl_get).returns(successful_purchase_response[1]).in_sequence(s) @gateway.expects(:ssl_get).returns(successful_purchase_response[2]).in_sequence(s) @@ -80,7 +80,7 @@ def test_handles_setup_transaction_error end def test_handles_query_error - s = sequence("request") + s = sequence('request') @gateway.expects(:ssl_get).returns(successful_purchase_response[0]).in_sequence(s) @gateway.expects(:ssl_get).returns(successful_purchase_response[1]).in_sequence(s) @gateway.expects(:ssl_get).returns(error_purchase_response[2]).in_sequence(s) @@ -93,7 +93,7 @@ def test_handles_query_error def test_url_escape_password @gateway = NetaxeptGateway.new(:login => 'login', :password => '1a=W+Yr2') - s = sequence("request") + s = sequence('request') @gateway.expects(:ssl_get).with(regexp_matches(/token=1a%3DW%2BYr2/)).returns(successful_purchase_response[0]).in_sequence(s) @gateway.expects(:ssl_get).returns(successful_purchase_response[1]).in_sequence(s) @gateway.expects(:ssl_get).returns(successful_purchase_response[2]).in_sequence(s) @@ -103,7 +103,7 @@ def test_url_escape_password end def test_using_credit_card_transaction_service_type - s = sequence("request") + s = sequence('request') @gateway.expects(:ssl_get).with(regexp_matches(/serviceType=M/)).returns(successful_purchase_response[0]).in_sequence(s) @gateway.expects(:ssl_get).returns(successful_purchase_response[1]).in_sequence(s) @gateway.expects(:ssl_get).returns(successful_purchase_response[2]).in_sequence(s) diff --git a/test/unit/gateways/netbanx_test.rb b/test/unit/gateways/netbanx_test.rb index e1130d469b7..a4a424d27f3 100644 --- a/test/unit/gateways/netbanx_test.rb +++ b/test/unit/gateways/netbanx_test.rb @@ -9,7 +9,8 @@ def setup @options = { order_id: '1', billing_address: address, - description: 'Store Purchase' + description: 'Store Purchase', + currency: 'CAD' } end @@ -604,7 +605,32 @@ def successful_store_response RESPONSE end - # just returns a 200 when successful def successful_unstore_response + <<-RESPONSE + { + "id": "2f840ab3-0e71-4387-bad3-4705e6f4b015", + "status": "ACTIVE", + "merchantCustomerId": "5e9d1ab0f847d147ffe872a9faf76d98", + "locale": "en_GB", + "paymentToken": "PJzuA8s6c6pSIs4", + "addresses": [], + "cards": [ + { + "status": "ACTIVE", + "id": "e4a3cd5a-56db-4d9b-97d3-fdd9ab3bd0f4", + "cardBin": "453091", + "lastDigits": "2345", + "cardExpiry": { + "year": 2017, + "month": 9 + }, + "holderName": "Longbob Longsen", + "cardType": "VI", + "paymentToken": "C6gmdUA1xWT8RsC", + "defaultCardIndicator": true + } + ] + } + RESPONSE end end diff --git a/test/unit/gateways/netbilling_test.rb b/test/unit/gateways/netbilling_test.rb index c16b9d23ee3..724e3037542 100644 --- a/test/unit/gateways/netbilling_test.rb +++ b/test/unit/gateways/netbilling_test.rb @@ -114,35 +114,36 @@ def test_transcript_scrubbing end private + def successful_purchase_response - "avs_code=X&cvv2_code=M&status_code=1&auth_code=999999&trans_id=110270311543&auth_msg=TEST+APPROVED&auth_date=2008-01-25+16:43:54" + 'avs_code=X&cvv2_code=M&status_code=1&auth_code=999999&trans_id=110270311543&auth_msg=TEST+APPROVED&auth_date=2008-01-25+16:43:54' end def unsuccessful_purchase_response - "status_code=0&auth_msg=CARD+EXPIRED&trans_id=110492608613&auth_date=2008-01-25+17:47:44" + 'status_code=0&auth_msg=CARD+EXPIRED&trans_id=110492608613&auth_date=2008-01-25+17:47:44' end def successful_repeat_purchase_response - "avs_code=X&cvv2_code=M&status_code=1&processor=TEST&auth_code=999999&settle_amount=1.00&settle_currency=USD&trans_id=112232503575&auth_msg=TEST+APPROVED&auth_date=2014-12-29+18:23:40" + 'avs_code=X&cvv2_code=M&status_code=1&processor=TEST&auth_code=999999&settle_amount=1.00&settle_currency=USD&trans_id=112232503575&auth_msg=TEST+APPROVED&auth_date=2014-12-29+18:23:40' end def unsuccessful_repeat_purchase_invalid_trans_id_response - "No Record Found For Specified ID" + 'No Record Found For Specified ID' end def successful_store_response - "status_code=T&processor=TEST&settle_amount=0.00&settle_currency=USD&trans_id=112235386882&auth_msg=OFFLINE+RECORD&auth_date=2014-12-29+18:23:43" + 'status_code=T&processor=TEST&settle_amount=0.00&settle_currency=USD&trans_id=112235386882&auth_msg=OFFLINE+RECORD&auth_date=2014-12-29+18:23:43' end def unsuccessful_store_invalid_billing_info_response - "20111: Invalid credit card number: 123" + '20111: Invalid credit card number: 123' end def transcript - "amount=1.00&description=Internet+purchase&bill_name1=Longbob&bill_name2=Longsen&card_number=4444111111111119&card_expire=0916&card_cvv2=123&bill_street=1600+Amphitheatre+Parkway&cust_phone=650-253-0001&bill_zip=94043&bill_city=Mountain+View&bill_country=US&bill_state=CA&account_id=104901072025&pay_type=C&tran_type=S" + 'amount=1.00&description=Internet+purchase&bill_name1=Longbob&bill_name2=Longsen&card_number=4444111111111119&card_expire=0916&card_cvv2=123&bill_street=1600+Amphitheatre+Parkway&cust_phone=650-253-0001&bill_zip=94043&bill_city=Mountain+View&bill_country=US&bill_state=CA&account_id=104901072025&pay_type=C&tran_type=S' end def scrubbed_transcript - "amount=1.00&description=Internet+purchase&bill_name1=Longbob&bill_name2=Longsen&card_number=[FILTERED]&card_expire=0916&card_cvv2=[FILTERED]&bill_street=1600+Amphitheatre+Parkway&cust_phone=650-253-0001&bill_zip=94043&bill_city=Mountain+View&bill_country=US&bill_state=CA&account_id=104901072025&pay_type=C&tran_type=S" + 'amount=1.00&description=Internet+purchase&bill_name1=Longbob&bill_name2=Longsen&card_number=[FILTERED]&card_expire=0916&card_cvv2=[FILTERED]&bill_street=1600+Amphitheatre+Parkway&cust_phone=650-253-0001&bill_zip=94043&bill_city=Mountain+View&bill_country=US&bill_state=CA&account_id=104901072025&pay_type=C&tran_type=S' end end diff --git a/test/unit/gateways/netpay_test.rb b/test/unit/gateways/netpay_test.rb index 55ba0dc273f..6b107d2e9f5 100644 --- a/test/unit/gateways/netpay_test.rb +++ b/test/unit/gateways/netpay_test.rb @@ -34,17 +34,17 @@ def test_successful_purchase @gateway.expects(:ssl_post).with( anything, all_of( - includes("StoreId=12345"), - includes("UserName=login"), - includes("Password=password"), - includes("ResourceName=Auth"), - includes("Total=10.00"), + includes('StoreId=12345'), + includes('UserName=login'), + includes('Password=password'), + includes('ResourceName=Auth'), + includes('Total=10.00'), includes("CardNumber=#{@credit_card.number}"), - includes("ExpDate=" + CGI.escape("09/#{@credit_card.year.to_s[-2..-1]}")), + includes('ExpDate=' + CGI.escape("09/#{@credit_card.year.to_s[-2..-1]}")), includes("CustomerName=#{CGI.escape(@credit_card.name)}"), includes("CVV2=#{@credit_card.verification_value}"), includes("Comments=#{CGI.escape(@options[:description])}"), - includes("CurrencyCode=484") + includes('CurrencyCode=484') ) ).returns(successful_response) @@ -76,22 +76,21 @@ def test_unsuccessful_purchase assert response.test? end - def test_successful_authorize @gateway.expects(:ssl_post).with( anything, all_of( - includes("StoreId=12345"), - includes("UserName=login"), - includes("Password=password"), - includes("ResourceName=PreAuth"), - includes("Total=10.00"), + includes('StoreId=12345'), + includes('UserName=login'), + includes('Password=password'), + includes('ResourceName=PreAuth'), + includes('Total=10.00'), includes("CardNumber=#{@credit_card.number}"), - includes("ExpDate=" + CGI.escape("09/#{@credit_card.year.to_s[-2..-1]}")), + includes('ExpDate=' + CGI.escape("09/#{@credit_card.year.to_s[-2..-1]}")), includes("CustomerName=#{CGI.escape(@credit_card.name)}"), includes("CVV2=#{@credit_card.verification_value}"), includes("Comments=#{CGI.escape(@options[:description])}"), - includes("CurrencyCode=484") + includes('CurrencyCode=484') ) ).returns(successful_response) @@ -107,7 +106,7 @@ def test_successful_capture anything, all_of( includes('ResourceName=PostAuth'), - includes("Total=10.00"), + includes('Total=10.00'), includes("OrderId=#{@order_id}") ) ).returns(successful_response) @@ -120,9 +119,9 @@ def test_successful_void anything, all_of( includes('ResourceName=Refund'), - includes("Total=10.00"), + includes('Total=10.00'), includes("OrderId=#{@order_id}"), - includes("CurrencyCode=484") + includes('CurrencyCode=484') ) ).returns(successful_response) assert response = @gateway.void("#{@order_id}|10.00|484") @@ -134,7 +133,7 @@ def test_successful_refund anything, all_of( includes('ResourceName=Credit'), - includes("Total=10.00"), + includes('Total=10.00'), includes("OrderId=#{@order_id}") ) ).returns(successful_response) diff --git a/test/unit/gateways/network_merchants_test.rb b/test/unit/gateways/network_merchants_test.rb index 4baa4903314..57fbb837167 100644 --- a/test/unit/gateways/network_merchants_test.rb +++ b/test/unit/gateways/network_merchants_test.rb @@ -19,10 +19,10 @@ def setup end def test_add_swipe_data_with_creditcard - @credit_card.track_data = "data" + @credit_card.track_data = 'data' @gateway.expects(:ssl_post).with do |_, body| - body.include?("track_1=data") + body.include?('track_1=data') end.returns(successful_purchase_response) assert response = @gateway.purchase(@amount, @credit_card, @options) @@ -63,7 +63,7 @@ def test_purchase_and_store assert response = @gateway.purchase(@amount, @credit_card, @options.merge(:store => true)) assert_success response assert_equal 'SUCCESS', response.message - assert_equal "1378262091", response.params['customer_vault_id'] + assert_equal '1378262091', response.params['customer_vault_id'] end def test_authorize @@ -97,16 +97,16 @@ def test_void assert response = @gateway.void('1869041506', @options) assert_success response - assert_equal "Transaction Void Successful", response.message + assert_equal 'Transaction Void Successful', response.message end def test_refund @gateway.expects(:ssl_post).returns(successful_refund) - assert response = @gateway.refund(50, "1869041506") + assert response = @gateway.refund(50, '1869041506') assert_success response - assert_equal "SUCCESS", response.message - assert_equal "1869043195", response.authorization + assert_equal 'SUCCESS', response.message + assert_equal '1869043195', response.authorization end def test_store @@ -130,7 +130,7 @@ def test_store_check def test_store_failure @gateway.expects(:ssl_post).returns(failed_store) - @credit_card.number = "123" + @credit_card.number = '123' store = @gateway.store(@credit_card, @options) assert_failure store assert store.message.include?('Billing Information missing') @@ -143,7 +143,7 @@ def test_unstore assert unstore = @gateway.unstore('1200085822') assert_success unstore - assert_equal "Customer Deleted", unstore.message + assert_equal 'Customer Deleted', unstore.message end def test_purchase_on_stored_card @@ -151,7 +151,7 @@ def test_purchase_on_stored_card assert purchase = @gateway.purchase(@amount, 1200085822, @options) assert_success purchase - assert_equal "SUCCESS", purchase.message + assert_equal 'SUCCESS', purchase.message assert_equal '1869047279', purchase.authorization end @@ -165,7 +165,7 @@ def test_invalid_login def test_currency_uses_default_when_not_provided @gateway.expects(:ssl_post).with do |_, body| - body.include?("currency=USD") + body.include?('currency=USD') end.returns(successful_purchase_response) @gateway.purchase(@amount, @credit_card, @options) @@ -174,7 +174,7 @@ def test_currency_uses_default_when_not_provided def test_provided_currency_overrides_default @options.update(currency: 'EUR') @gateway.expects(:ssl_post).with do |_, body| - body.include?("currency=EUR") + body.include?('currency=EUR') end.returns(successful_purchase_response) @gateway.purchase(@amount, @credit_card, @options) @@ -184,59 +184,59 @@ def test_provided_currency_overrides_default # Place raw successful response from gateway here def successful_purchase_response - "response=1&responsetext=SUCCESS&authcode=123456&transactionid=1869031575&avsresponse=N&cvvresponse=N&orderid=1&type=auth&response_code=100&merchant_defined_field_6=&merchant_defined_field_7=&customer_vault_id=" + 'response=1&responsetext=SUCCESS&authcode=123456&transactionid=1869031575&avsresponse=N&cvvresponse=N&orderid=1&type=auth&response_code=100&merchant_defined_field_6=&merchant_defined_field_7=&customer_vault_id=' end # Place raw failed response from gateway here def failed_purchase_response - "response=2&responsetext=DECLINE&authcode=&transactionid=1869031793&avsresponse=N&cvvresponse=N&orderid=1&type=sale&response_code=200&merchant_defined_field_6=&merchant_defined_field_7=&customer_vault_id=" + 'response=2&responsetext=DECLINE&authcode=&transactionid=1869031793&avsresponse=N&cvvresponse=N&orderid=1&type=sale&response_code=200&merchant_defined_field_6=&merchant_defined_field_7=&customer_vault_id=' end def successful_check_purchase - "response=1&responsetext=SUCCESS&authcode=123456&transactionid=1869039732&avsresponse=&cvvresponse=&orderid=1&type=sale&response_code=100&merchant_defined_field_6=&merchant_defined_field_7=&customer_vault_id=" + 'response=1&responsetext=SUCCESS&authcode=123456&transactionid=1869039732&avsresponse=&cvvresponse=&orderid=1&type=sale&response_code=100&merchant_defined_field_6=&merchant_defined_field_7=&customer_vault_id=' end def successful_purchase_and_store - "response=1&responsetext=SUCCESS&authcode=123456&transactionid=1869036881&avsresponse=N&cvvresponse=N&orderid=1&type=sale&response_code=100&merchant_defined_field_6=&merchant_defined_field_7=&customer_vault_id=1378262091" + 'response=1&responsetext=SUCCESS&authcode=123456&transactionid=1869036881&avsresponse=N&cvvresponse=N&orderid=1&type=sale&response_code=100&merchant_defined_field_6=&merchant_defined_field_7=&customer_vault_id=1378262091' end def successful_authorize - "response=1&responsetext=SUCCESS&authcode=123456&transactionid=1869041506&avsresponse=N&cvvresponse=N&orderid=1&type=auth&response_code=100&merchant_defined_field_6=&merchant_defined_field_7=&customer_vault_id=" + 'response=1&responsetext=SUCCESS&authcode=123456&transactionid=1869041506&avsresponse=N&cvvresponse=N&orderid=1&type=auth&response_code=100&merchant_defined_field_6=&merchant_defined_field_7=&customer_vault_id=' end def successful_capture - "response=1&responsetext=SUCCESS&authcode=123456&transactionid=1869041506&avsresponse=&cvvresponse=&orderid=1&type=capture&response_code=100&merchant_defined_field_6=&merchant_defined_field_7=&customer_vault_id=" + 'response=1&responsetext=SUCCESS&authcode=123456&transactionid=1869041506&avsresponse=&cvvresponse=&orderid=1&type=capture&response_code=100&merchant_defined_field_6=&merchant_defined_field_7=&customer_vault_id=' end def failed_capture - "response=3&responsetext=Invalid Transaction ID / Object ID specified: REFID:342421573&authcode=&transactionid=&avsresponse=&cvvresponse=&orderid=&type=capture&response_code=300&merchant_defined_field_6=&merchant_defined_field_7=&customer_vault_id=" + 'response=3&responsetext=Invalid Transaction ID / Object ID specified: REFID:342421573&authcode=&transactionid=&avsresponse=&cvvresponse=&orderid=&type=capture&response_code=300&merchant_defined_field_6=&merchant_defined_field_7=&customer_vault_id=' end def successful_void - "response=1&responsetext=Transaction Void Successful&authcode=123456&transactionid=1869042801&avsresponse=&cvvresponse=&orderid=1&type=void&response_code=100&merchant_defined_field_6=&merchant_defined_field_7=&customer_vault_id=" + 'response=1&responsetext=Transaction Void Successful&authcode=123456&transactionid=1869042801&avsresponse=&cvvresponse=&orderid=1&type=void&response_code=100&merchant_defined_field_6=&merchant_defined_field_7=&customer_vault_id=' end def successful_refund - "response=1&responsetext=SUCCESS&authcode=&transactionid=1869043195&avsresponse=&cvvresponse=&orderid=1&type=refund&response_code=100&merchant_defined_field_6=&merchant_defined_field_7=&customer_vault_id=" + 'response=1&responsetext=SUCCESS&authcode=&transactionid=1869043195&avsresponse=&cvvresponse=&orderid=1&type=refund&response_code=100&merchant_defined_field_6=&merchant_defined_field_7=&customer_vault_id=' end def successful_store - "response=1&responsetext=Customer Added&authcode=&transactionid=&avsresponse=&cvvresponse=&orderid=&type=&response_code=100&merchant_defined_field_6=&merchant_defined_field_7=&customer_vault_id=1200085822" + 'response=1&responsetext=Customer Added&authcode=&transactionid=&avsresponse=&cvvresponse=&orderid=&type=&response_code=100&merchant_defined_field_6=&merchant_defined_field_7=&customer_vault_id=1200085822' end def failed_store - "response=3&responsetext=Billing Information missing REFID:342424380&authcode=&transactionid=&avsresponse=&cvvresponse=&orderid=&type=&response_code=300&merchant_defined_field_6=&merchant_defined_field_7=&customer_vault_id=" + 'response=3&responsetext=Billing Information missing REFID:342424380&authcode=&transactionid=&avsresponse=&cvvresponse=&orderid=&type=&response_code=300&merchant_defined_field_6=&merchant_defined_field_7=&customer_vault_id=' end def successful_unstore - "response=1&responsetext=Customer Deleted&authcode=&transactionid=&avsresponse=&cvvresponse=&orderid=&type=&response_code=100&merchant_defined_field_6=&merchant_defined_field_7=&customer_vault_id=" + 'response=1&responsetext=Customer Deleted&authcode=&transactionid=&avsresponse=&cvvresponse=&orderid=&type=&response_code=100&merchant_defined_field_6=&merchant_defined_field_7=&customer_vault_id=' end def successful_purchase_on_stored_card - "response=1&responsetext=SUCCESS&authcode=123456&transactionid=1869047279&avsresponse=N&cvvresponse=&orderid=1&type=sale&response_code=100&merchant_defined_field_6=&merchant_defined_field_7=&customer_vault_id=1138093627" + 'response=1&responsetext=SUCCESS&authcode=123456&transactionid=1869047279&avsresponse=N&cvvresponse=&orderid=1&type=sale&response_code=100&merchant_defined_field_6=&merchant_defined_field_7=&customer_vault_id=1138093627' end def failed_login - "response=3&responsetext=Invalid Username&authcode=&transactionid=0&avsresponse=&cvvresponse=&orderid=1&type=sale&response_code=300" + 'response=3&responsetext=Invalid Username&authcode=&transactionid=0&avsresponse=&cvvresponse=&orderid=1&type=sale&response_code=300' end end diff --git a/test/unit/gateways/nmi_test.rb b/test/unit/gateways/nmi_test.rb index c2d01a04cef..f7f7d3c0030 100644 --- a/test/unit/gateways/nmi_test.rb +++ b/test/unit/gateways/nmi_test.rb @@ -29,15 +29,15 @@ def test_successful_purchase assert_success response assert response.test? - assert_equal "2762757839#creditcard", response.authorization + assert_equal '2762757839#creditcard', response.authorization end def test_purchase_with_options response = stub_comms do @gateway.purchase(@amount, @credit_card, - recurring: true, order_id: "#1001", description: "AM test", - currency: "GBP", dup_seconds: 15, customer: "123", - merchant_defined_field_8: "value8") + recurring: true, order_id: '#1001', description: 'AM test', + currency: 'GBP', dup_seconds: 15, customer: '123', + merchant_defined_field_8: 'value8') end.check_request do |endpoint, data, headers| assert_match(/billing_method=recurring/, data) assert_match(/orderid=#{CGI.escape("#1001")}/, data) @@ -58,7 +58,7 @@ def test_failed_purchase assert_failure response assert response.test? - assert_equal "DECLINE", response.message + assert_equal 'DECLINE', response.message end def test_successful_purchase_with_echeck @@ -70,6 +70,8 @@ def test_successful_purchase_with_echeck assert_match(/type=sale/, data) assert_match(/amount=1.00/, data) assert_match(/payment=check/, data) + assert_match(/firstname=#{@check.first_name}/, data) + assert_match(/lastname=#{@check.last_name}/, data) assert_match(/checkname=#{@check.name}/, CGI.unescape(data)) assert_match(/checkaba=#{@check.routing_number}/, data) assert_match(/checkaccount=#{@check.account_number}/, data) @@ -80,7 +82,7 @@ def test_successful_purchase_with_echeck assert_success response assert response.test? - assert_equal "2762759808#check", response.authorization + assert_equal '2762759808#check', response.authorization end def test_failed_purchase_with_echeck @@ -90,7 +92,7 @@ def test_failed_purchase_with_echeck assert_failure response assert response.test? - assert_equal "FAILED", response.message + assert_equal 'FAILED', response.message end def test_successful_authorize_and_capture @@ -107,7 +109,7 @@ def test_successful_authorize_and_capture end.respond_with(successful_authorization_response) assert_success response - assert_equal "2762787830#creditcard", response.authorization + assert_equal '2762787830#creditcard', response.authorization capture = stub_comms do @gateway.capture(@amount, response.authorization) @@ -128,13 +130,13 @@ def test_failed_authorize end.respond_with(failed_authorization_response) assert_failure response - assert_equal "DECLINE", response.message + assert_equal 'DECLINE', response.message assert response.test? end def test_failed_capture response = stub_comms do - @gateway.capture(100, "") + @gateway.capture(100, '') end.respond_with(failed_capture_response) assert_failure response @@ -146,7 +148,7 @@ def test_successful_void end.respond_with(successful_purchase_response) assert_success response - assert_equal "2762757839#creditcard", response.authorization + assert_equal '2762757839#creditcard', response.authorization void = stub_comms do @gateway.void(response.authorization) @@ -162,7 +164,7 @@ def test_successful_void def test_failed_void response = stub_comms do - @gateway.void("5d53a33d960c46d00f5dc061947d998c") + @gateway.void('5d53a33d960c46d00f5dc061947d998c') end.respond_with(failed_void_response) assert_failure response @@ -174,7 +176,7 @@ def test_successful_refund end.respond_with(successful_purchase_response) assert_success response - assert_equal "2762757839#creditcard", response.authorization + assert_equal '2762757839#creditcard', response.authorization refund = stub_comms do @gateway.refund(@amount, response.authorization) @@ -191,7 +193,7 @@ def test_successful_refund def test_failed_refund response = stub_comms do - @gateway.refund(nil, "") + @gateway.refund(nil, '') end.respond_with(failed_refund_response) assert_failure response @@ -213,7 +215,7 @@ def test_successful_credit assert_success response - assert_equal "2762828010#creditcard", response.authorization + assert_equal '2762828010#creditcard', response.authorization assert response.test? end @@ -224,7 +226,7 @@ def test_failed_credit assert_failure response assert response.test? - assert_match "Invalid Credit Card", response.message + assert_match 'Invalid Credit Card', response.message end def test_successful_verify @@ -241,7 +243,7 @@ def test_successful_verify end.respond_with(successful_validate_response) assert_success response - assert_equal "Succeeded", response.message + assert_equal 'Succeeded', response.message end def test_failed_verify @@ -250,7 +252,7 @@ def test_failed_verify end.respond_with(failed_validate_response) assert_failure response - assert_match "Invalid Credit Card", response.message + assert_match 'Invalid Credit Card', response.message end def test_successful_store @@ -268,8 +270,8 @@ def test_successful_store assert_success response assert response.test? - assert_equal "Succeeded", response.message - assert response.params["customer_vault_id"] + assert_equal 'Succeeded', response.message + assert response.params['customer_vault_id'] end def test_failed_store @@ -279,7 +281,7 @@ def test_failed_store assert_failure response assert response.test? - assert_match "Invalid Credit Card", response.message + assert_match 'Invalid Credit Card', response.message end def test_successful_store_with_echeck @@ -300,8 +302,8 @@ def test_successful_store_with_echeck assert_success response assert response.test? - assert_equal "Succeeded", response.message - assert response.params["customer_vault_id"] + assert_equal 'Succeeded', response.message + assert response.params['customer_vault_id'] end def test_avs_result @@ -340,7 +342,7 @@ def test_blank_cvv_not_sent assert_no_match(%r{cvv}, data) end.respond_with(successful_purchase_response) - @credit_card.verification_value = " " + @credit_card.verification_value = ' ' stub_comms do @gateway.purchase(@amount, @credit_card) end.check_request do |endpoint, data, headers| @@ -442,20 +444,20 @@ def successful_echeck_store_response end def transcript - %q( + ' amount=1.00&orderid=c9f2fb356d2a839d315aa6e8d7ed2404&orderdescription=Store+purchase&currency=USD&payment=creditcard&firstname=Longbob&lastname=Longsen&ccnumber=4111111111111111&cvv=917&ccexp=0916&email=&ipaddress=&company=Widgets+Inc&address1=456+My+Street&address2=Apt+1&city=Ottawa&state=ON&country=CA&zip=K1C2N6&phone=%28555%29555-5555&type=sale&username=demo&password=password response=1&responsetext=SUCCESS&authcode=123456&transactionid=2767466670&avsresponse=N&cvvresponse=N&orderid=c9f2fb356d2a839d315aa6e8d7ed2404&type=sale&response_code=100 amount=1.00&orderid=e88df316d8ba3c8c6b98aa93b78facc0&orderdescription=Store+purchase&currency=USD&payment=check&checkname=Jim+Smith&checkaba=123123123&checkaccount=123123123&account_holder_type=personal&account_type=checking&sec_code=WEB&email=&ipaddress=&company=Widgets+Inc&address1=456+My+Street&address2=Apt+1&city=Ottawa&state=ON&country=CA&zip=K1C2N6&phone=%28555%29555-5555&type=sale&username=demo&password=password response=1&responsetext=SUCCESS&authcode=123456&transactionid=2767467157&avsresponse=&cvvresponse=&orderid=e88df316d8ba3c8c6b98aa93b78facc0&type=sale&response_code=100 - ) + ' end def scrubbed_transcript - %q( + ' amount=1.00&orderid=c9f2fb356d2a839d315aa6e8d7ed2404&orderdescription=Store+purchase&currency=USD&payment=creditcard&firstname=Longbob&lastname=Longsen&ccnumber=[FILTERED]&cvv=[FILTERED]&ccexp=0916&email=&ipaddress=&company=Widgets+Inc&address1=456+My+Street&address2=Apt+1&city=Ottawa&state=ON&country=CA&zip=K1C2N6&phone=%28555%29555-5555&type=sale&username=demo&password=[FILTERED] response=1&responsetext=SUCCESS&authcode=123456&transactionid=2767466670&avsresponse=N&cvvresponse=N&orderid=c9f2fb356d2a839d315aa6e8d7ed2404&type=sale&response_code=100 amount=1.00&orderid=e88df316d8ba3c8c6b98aa93b78facc0&orderdescription=Store+purchase&currency=USD&payment=check&checkname=Jim+Smith&checkaba=[FILTERED]&checkaccount=[FILTERED]&account_holder_type=personal&account_type=checking&sec_code=WEB&email=&ipaddress=&company=Widgets+Inc&address1=456+My+Street&address2=Apt+1&city=Ottawa&state=ON&country=CA&zip=K1C2N6&phone=%28555%29555-5555&type=sale&username=demo&password=[FILTERED] response=1&responsetext=SUCCESS&authcode=123456&transactionid=2767467157&avsresponse=&cvvresponse=&orderid=e88df316d8ba3c8c6b98aa93b78facc0&type=sale&response_code=100 - ) + ' end end diff --git a/test/unit/gateways/ogone_test.rb b/test/unit/gateways/ogone_test.rb index 6bae8080557..8454a030cfd 100644 --- a/test/unit/gateways/ogone_test.rb +++ b/test/unit/gateways/ogone_test.rb @@ -12,10 +12,10 @@ def setup @gateway = OgoneGateway.new(@credentials) @credit_card = credit_card - @mastercard = credit_card('5399999999999999', :brand => "mastercard") + @mastercard = credit_card('5399999999999999', :brand => 'mastercard') @amount = 100 - @identification = "3014726" - @billing_id = "myalias" + @identification = '3014726' + @billing_id = 'myalias' @options = { :order_id => '1', :billing_address => address, @@ -34,7 +34,7 @@ def setup @parameters_d3d = { 'FLAG3D' => 'Y', 'WIN3DS' => 'MAINW', - 'HTTP_ACCEPT' => "*/*" + 'HTTP_ACCEPT' => '*/*' } end @@ -145,7 +145,7 @@ def test_successful_authorize_with_3dsecure def test_successful_capture @gateway.expects(:ssl_post).returns(successful_capture_response) - assert response = @gateway.capture(@amount, "3048326") + assert response = @gateway.capture(@amount, '3048326') assert_success response assert_equal '3048326;SAL', response.authorization assert response.test? @@ -153,7 +153,7 @@ def test_successful_capture def test_successful_capture_with_action_option @gateway.expects(:ssl_post).returns(successful_capture_response) - assert response = @gateway.capture(@amount, "3048326", :action => 'SAS') + assert response = @gateway.capture(@amount, '3048326', :action => 'SAS') assert_success response assert_equal '3048326;SAS', response.authorization assert response.test? @@ -161,7 +161,7 @@ def test_successful_capture_with_action_option def test_successful_void @gateway.expects(:ssl_post).returns(successful_void_response) - assert response = @gateway.void("3048606") + assert response = @gateway.void('3048606') assert_success response assert_equal '3048606;DES', response.authorization assert response.test? @@ -170,7 +170,7 @@ def test_successful_void def test_deprecated_credit @gateway.expects(:ssl_post).returns(successful_referenced_credit_response) assert_deprecation_warning(Gateway::CREDIT_DEPRECATION_MESSAGE) do - assert response = @gateway.credit(@amount, "3049652;SAL") + assert response = @gateway.credit(@amount, '3049652;SAL') assert_success response assert_equal '3049652;RFD', response.authorization assert response.test? @@ -181,13 +181,13 @@ def test_successful_unreferenced_credit @gateway.expects(:ssl_post).returns(successful_unreferenced_credit_response) assert response = @gateway.credit(@amount, @credit_card) assert_success response - assert_equal "3049654;RFD", response.authorization + assert_equal '3049654;RFD', response.authorization assert response.test? end def test_successful_refund @gateway.expects(:ssl_post).returns(successful_referenced_credit_response) - assert response = @gateway.refund(@amount, "3049652") + assert response = @gateway.refund(@amount, '3049652') assert_success response assert_equal '3049652;RFD', response.authorization assert response.test? @@ -197,14 +197,14 @@ def test_successful_verify @gateway.expects(:ssl_post).times(2).returns(successful_authorize_response).then.returns(successful_void_response) assert response = @gateway.verify(@credit_card, @options) assert_success response - assert_equal "The transaction was successful", response.message + assert_equal 'The transaction was successful', response.message end def test_failed_verify @gateway.expects(:ssl_post).returns(failed_authorization_response) assert response = @gateway.verify(@credit_card, @options) assert_failure response - assert_equal "Unknown order", response.message + assert_equal 'Unknown order', response.message end def test_successful_store @@ -251,7 +251,7 @@ def test_create_readable_error_message_upon_failure assert_failure response assert response.test? - assert_equal "Unknown order", response.message + assert_equal 'Unknown order', response.message end def test_supported_countries @@ -328,19 +328,19 @@ def test_test_mode def test_format_error_message_with_slash_separator @gateway.expects(:ssl_post).returns('<ncresponse NCERRORPLUS="unknown order/1/i/67.192.100.64" STATUS="0" />') assert response = @gateway.purchase(@amount, @credit_card, @options) - assert_equal "Unknown order", response.message + assert_equal 'Unknown order', response.message end def test_format_error_message_with_pipe_separator @gateway.expects(:ssl_post).returns('<ncresponse NCERRORPLUS=" no card no|no exp date|no brand" STATUS="0" />') assert response = @gateway.purchase(@amount, @credit_card, @options) - assert_equal "No card no, no exp date, no brand", response.message + assert_equal 'No card no, no exp date, no brand', response.message end def test_format_error_message_with_no_separator @gateway.expects(:ssl_post).returns('<ncresponse NCERRORPLUS=" unknown order " STATUS="0" />') assert response = @gateway.purchase(@amount, @credit_card, @options) - assert_equal "Unknown order", response.message + assert_equal 'Unknown order', response.message end def test_without_signature @@ -350,7 +350,7 @@ def test_without_signature gateway.purchase(@amount, @credit_card, @options) end - gateway = OgoneGateway.new(@credentials.merge(:signature => nil, :signature_encryptor => "none")) + gateway = OgoneGateway.new(@credentials.merge(:signature => nil, :signature_encryptor => 'none')) gateway.expects(:ssl_post).returns(successful_purchase_response) assert_no_deprecation_warning do gateway.purchase(@amount, @credit_card, @options) @@ -360,7 +360,7 @@ def test_without_signature def test_signature_for_accounts_created_before_10_may_20101 gateway = OgoneGateway.new(@credentials.merge(:signature_encryptor => nil)) assert signature = gateway.send(:add_signature, @parameters) - assert_equal Digest::SHA1.hexdigest("1100EUR4111111111111111MrPSPIDRES2mynicesig").upcase, signature + assert_equal Digest::SHA1.hexdigest('1100EUR4111111111111111MrPSPIDRES2mynicesig').upcase, signature end def test_signature_for_accounts_with_signature_encryptor_to_sha1 @@ -394,13 +394,13 @@ def test_3dsecure_win_3ds_option gateway = OgoneGateway.new(@credentials) gateway.send(:add_d3d, post, { :win_3ds => :pop_up }) - assert 'POPUP', post["WIN3DS"] + assert 'POPUP', post['WIN3DS'] gateway.send(:add_d3d, post, { :win_3ds => :pop_ix }) - assert 'POPIX', post["WIN3DS"] + assert 'POPIX', post['WIN3DS'] gateway.send(:add_d3d, post, { :win_3ds => :invalid }) - assert 'MAINW', post["WIN3DS"] + assert 'MAINW', post['WIN3DS'] end def test_3dsecure_additional_options @@ -408,8 +408,8 @@ def test_3dsecure_additional_options gateway = OgoneGateway.new(@credentials) gateway.send(:add_d3d, post, { - :http_accept => "text/html", - :http_user_agent => "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)", + :http_accept => 'text/html', + :http_user_agent => 'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)', :accept_url => 'https://accept_url', :decline_url => 'https://decline_url', :exception_url => 'https://exception_url', @@ -419,8 +419,8 @@ def test_3dsecure_additional_options :complus => 'com_plus', :language => 'fr_FR' }) - assert_equal post['HTTP_ACCEPT'], "text/html" - assert_equal post['HTTP_USER_AGENT'], "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)" + assert_equal post['HTTP_ACCEPT'], 'text/html' + assert_equal post['HTTP_USER_AGENT'], 'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)' assert_equal post['ACCEPTURL'], 'https://accept_url' assert_equal post['DECLINEURL'], 'https://decline_url' assert_equal post['EXCEPTIONURL'], 'https://exception_url' @@ -445,19 +445,24 @@ def test_response_params_is_hash assert_instance_of Hash, response.params end + def test_transcript_scrubbing + assert @gateway.supports_scrubbing? + assert_equal @gateway.scrub(pre_scrub), post_scrub + end + private def string_to_digest - "ALIAS=2mynicesigAMOUNT=100mynicesigCARDNO=4111111111111111mynicesig"+ - "CN=Client NamemynicesigCURRENCY=EURmynicesigOPERATION=RESmynicesig"+ - "ORDERID=1mynicesigPSPID=MrPSPIDmynicesig" + 'ALIAS=2mynicesigAMOUNT=100mynicesigCARDNO=4111111111111111mynicesig'\ + 'CN=Client NamemynicesigCURRENCY=EURmynicesigOPERATION=RESmynicesig'\ + 'ORDERID=1mynicesigPSPID=MrPSPIDmynicesig' end def d3d_string_to_digest - "ALIAS=2mynicesigAMOUNT=100mynicesigCARDNO=4111111111111111mynicesig"+ - "CN=Client NamemynicesigCURRENCY=EURmynicesigFLAG3D=Ymynicesig"+ - "HTTP_ACCEPT=*/*mynicesigOPERATION=RESmynicesigORDERID=1mynicesig"+ - "PSPID=MrPSPIDmynicesigWIN3DS=MAINWmynicesig" + 'ALIAS=2mynicesigAMOUNT=100mynicesigCARDNO=4111111111111111mynicesig'\ + 'CN=Client NamemynicesigCURRENCY=EURmynicesigFLAG3D=Ymynicesig'\ + 'HTTP_ACCEPT=*/*mynicesigOPERATION=RESmynicesigORDERID=1mynicesig'\ + 'PSPID=MrPSPIDmynicesigWIN3DS=MAINWmynicesig' end def successful_authorize_response @@ -754,4 +759,52 @@ def failed_authorization_response END end + def pre_scrub + %q{ +opening connection to secure.ogone.com:443... +opened +starting SSL for secure.ogone.com:443... +SSL established +<- "POST /ncol/test/orderdirect.asp HTTP/1.1\r\nContent-Type: application/x-www-form-urlencoded\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nAccept: */*\r\nUser-Agent: Ruby\r\nConnection: close\r\nHost: secure.ogone.com\r\nContent-Length: 455\r\n\r\n" +<- "CARDNO=4000100011112224&CN=Longbob+Longsen&COM=Store+Purchase&CVC=123&ECI=7&ED=0919&Operation=SAL&OwnerZip=K1C2N6&Owneraddress=456+My+Street&PSPID=spreedlyinc&PSWD=spreedly1test&SHASign=A67038AB141C6E54C51315F993DC83F5C28A9E585C6C8A79346F802E6557C0C8EE233A5FF1352AAD3C6AA5D476CF49F2B0DF512C63BA624F0583B72C1DCABCEF&USERID=spreedlytest&amount=100&currency=EUR&orderID=7de271d36c1c36999a6039d99179b2&ownercty=CA&ownertelno=%28555%29555-5555&ownertown=Ottawa" +-> "HTTP/1.1 200 OK\r\n" +-> "Cache-Control: private, max-age=0\r\n" +-> "Content-Length: 152\r\n" +-> "Content-Type: text/XML; Charset=iso-8859-1\r\n" +-> "Expires: Mon, 08 Jan 2018 18:13:04 GMT\r\n" +-> "Strict-Transport-Security: max-age=31536000;includeSubdomains\r\n" +-> "Date: Mon, 08 Jan 2018 18:14:05 GMT\r\n" +-> "Connection: close\r\n" +-> "\r\n" +reading 152 bytes... +-> "<?xml version=\"1.0\"?><ncresponse\r\norderID=\"7de271d36c1c36999a6039d99179b2\"\r\nPAYID=\"3029762647\"\r\nNCERROR=\"0\"\r\nSTATUS=\"9\"\r\nNCERRORPLUS=\"!\">\r\n</ncresponse>" +read 152 bytes +Conn close + } + end + + def post_scrub + %q{ +opening connection to secure.ogone.com:443... +opened +starting SSL for secure.ogone.com:443... +SSL established +<- "POST /ncol/test/orderdirect.asp HTTP/1.1\r\nContent-Type: application/x-www-form-urlencoded\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nAccept: */*\r\nUser-Agent: Ruby\r\nConnection: close\r\nHost: secure.ogone.com\r\nContent-Length: 455\r\n\r\n" +<- "CARDNO=[FILTERED]&CN=Longbob+Longsen&COM=Store+Purchase&CVC=[FILTERED]&ECI=7&ED=0919&Operation=SAL&OwnerZip=K1C2N6&Owneraddress=456+My+Street&PSPID=spreedlyinc&PSWD=[FILTERED]&SHASign=A67038AB141C6E54C51315F993DC83F5C28A9E585C6C8A79346F802E6557C0C8EE233A5FF1352AAD3C6AA5D476CF49F2B0DF512C63BA624F0583B72C1DCABCEF&USERID=spreedlytest&amount=100&currency=EUR&orderID=7de271d36c1c36999a6039d99179b2&ownercty=CA&ownertelno=%28555%29555-5555&ownertown=Ottawa" +-> "HTTP/1.1 200 OK\r\n" +-> "Cache-Control: private, max-age=0\r\n" +-> "Content-Length: 152\r\n" +-> "Content-Type: text/XML; Charset=iso-8859-1\r\n" +-> "Expires: Mon, 08 Jan 2018 18:13:04 GMT\r\n" +-> "Strict-Transport-Security: max-age=31536000;includeSubdomains\r\n" +-> "Date: Mon, 08 Jan 2018 18:14:05 GMT\r\n" +-> "Connection: close\r\n" +-> "\r\n" +reading 152 bytes... +-> "<?xml version=\"1.0\"?><ncresponse\r\norderID=\"7de271d36c1c36999a6039d99179b2\"\r\nPAYID=\"3029762647\"\r\nNCERROR=\"0\"\r\nSTATUS=\"9\"\r\nNCERRORPLUS=\"!\">\r\n</ncresponse>" +read 152 bytes +Conn close + } + end + end diff --git a/test/unit/gateways/omise_test.rb b/test/unit/gateways/omise_test.rb index fbf75054d7a..5c31855fd64 100644 --- a/test/unit/gateways/omise_test.rb +++ b/test/unit/gateways/omise_test.rb @@ -4,7 +4,7 @@ class OmiseTest < Test::Unit::TestCase def setup @gateway = OmiseGateway.new( public_key: 'pkey_test_abc', - secret_key: 'skey_test_123', + secret_key: 'skey_test_123' ) @credit_card = credit_card @@ -39,8 +39,8 @@ def test_scrub end def test_gateway_url - assert_equal 'https://api.omise.co/', OmiseGateway::API_URL - assert_equal 'https://vault.omise.co/', OmiseGateway::VAULT_URL + assert_equal 'https://api.omise.co/', OmiseGateway::API_URL + assert_equal 'https://vault.omise.co/', OmiseGateway::VAULT_URL end def test_request_headers @@ -51,24 +51,24 @@ def test_request_headers def test_post_data post_data = @gateway.send(:post_data, { card: {number: '4242424242424242'} }) - assert_equal "{\"card\":{\"number\":\"4242424242424242\"}}", post_data + assert_equal '{"card":{"number":"4242424242424242"}}', post_data end def test_parse_response response = @gateway.send(:parse, successful_purchase_response) - assert(response.key?('object'), "expect json response has object key") + assert(response.key?('object'), 'expect json response has object key') end def test_successful_response response = @gateway.send(:parse, successful_purchase_response) success = @gateway.send(:successful?, response) - assert(success, "expect success to be true") + assert(success, 'expect success to be true') end def test_error_response response = @gateway.send(:parse, error_response) success = @gateway.send(:successful?, response) - assert(!success, "expect success to be false") + assert(!success, 'expect success to be false') end def test_error_code_from diff --git a/test/unit/gateways/openpay_test.rb b/test/unit/gateways/openpay_test.rb index e3d55229688..7355647e382 100644 --- a/test/unit/gateways/openpay_test.rb +++ b/test/unit/gateways/openpay_test.rb @@ -178,6 +178,17 @@ def test_passing_device_session_id assert_success response end + def test_passing_payment_installments + response = stub_comms(@gateway, :ssl_request) do + @gateway.purchase(@amount, @credit_card, payments: '6') + end.check_request do |method, endpoint, data, headers| + assert_match(%r{"payments":"6"}, data) + assert_match(%r{"payment_plan":}, data) + end.respond_with(successful_purchase_response) + + assert_success response + end + def test_transcript_scrubbing assert_equal scrubbed_transcript, @gateway.scrub(transcript) end diff --git a/test/unit/gateways/opp_test.rb b/test/unit/gateways/opp_test.rb index 8225e3c7a91..a59885917d5 100644 --- a/test/unit/gateways/opp_test.rb +++ b/test/unit/gateways/opp_test.rb @@ -1,14 +1,16 @@ require 'test_helper' class OppTest < Test::Unit::TestCase + include CommStub + def setup @gateway = OppGateway.new(fixtures(:opp)) @amount = 100 - @valid_card = credit_card("4200000000000000", month: 05, year: 2018, verification_value: '123') - @invalid_card = credit_card("4444444444444444", month: 05, year: 2018, verification_value: '123') + @valid_card = credit_card('4200000000000000', month: 05, year: 2018, verification_value: '123') + @invalid_card = credit_card('4444444444444444', month: 05, year: 2018, verification_value: '123') - request_type = 'complete' # 'minimal' || 'complete' + request_type = 'complete' # 'minimal' || 'complete' time = Time.now.to_i ip = '101.102.103.104' @complete_request_options = { @@ -16,8 +18,8 @@ def setup merchant_transaction_id: "active_merchant_test_complete #{time}", address: address, description: 'Store Purchase - Books', -# risk_workflow: true, -# test_mode: 'EXTERNAL' # or 'INTERNAL', valid only for test system + # risk_workflow: true, + # test_mode: 'EXTERNAL' # or 'INTERNAL', valid only for test system billing_address: { name: 'Billy Billing', @@ -49,27 +51,27 @@ def setup ip: ip, }, } - + @minimal_request_options = { order_id: "Order #{time}", description: 'Store Purchase - Books', } - @complete_request_options['customParameters[SHOPPER_test124TestName009]'] = 'customParameters_test' - @complete_request_options['customParameters[SHOPPER_otherCustomerParameter]'] = 'otherCustomerParameter_test' + @complete_request_options['customParameters[SHOPPER_test124TestName009]'] = 'customParameters_test' + @complete_request_options['customParameters[SHOPPER_otherCustomerParameter]'] = 'otherCustomerParameter_test' + + @test_success_id = '8a82944a4e008ca9014e1273e0696122' + @test_failure_id = '8a8294494e0078a6014e12b371fb6a8e' - @test_success_id = "8a82944a4e008ca9014e1273e0696122" - @test_failure_id = "8a8294494e0078a6014e12b371fb6a8e" - @options = @minimal_request_options if request_type == 'minimal' @options = @complete_request_options if request_type == 'complete' end - -# ****************************************** SUCCESSFUL TESTS ****************************************** + + # ****************************************** SUCCESSFUL TESTS ****************************************** def test_successful_purchase @gateway.expects(:raw_ssl_request).returns(successful_response('DB', @test_success_id)) response = @gateway.purchase(@amount, @valid_card, @options) - assert_success response, "Failed purchase" + assert_success response, 'Failed purchase' assert_equal @test_success_id, response.authorization assert response.test? end @@ -77,7 +79,7 @@ def test_successful_purchase def test_successful_authorize @gateway.expects(:raw_ssl_request).returns(successful_response('PA', @test_success_id)) response = @gateway.authorize(@amount, @valid_card, @options) - assert_success response, "Authorization Failed" + assert_success response, 'Authorization Failed' assert_equal @test_success_id, response.authorization assert response.test? end @@ -85,12 +87,12 @@ def test_successful_authorize def test_successful_capture @gateway.expects(:raw_ssl_request).returns(successful_response('PA', @test_success_id)) auth = @gateway.authorize(@amount, @valid_card, @options) - assert_success auth, "Authorization Failed" + assert_success auth, 'Authorization Failed' assert_equal @test_success_id, auth.authorization assert auth.test? @gateway.expects(:raw_ssl_request).returns(successful_response('CP', @test_success_id)) capt = @gateway.capture(@amount, auth.authorization, @options) - assert_success capt, "Capture failed" + assert_success capt, 'Capture failed' assert_equal @test_success_id, capt.authorization assert capt.test? end @@ -98,11 +100,11 @@ def test_successful_capture def test_successful_refund @gateway.expects(:raw_ssl_request).returns(successful_response('DB', @test_success_id)) purchase = @gateway.purchase(@amount, @valid_card, @options) - assert_success purchase, "Purchase failed" + assert_success purchase, 'Purchase failed' assert purchase.test? @gateway.expects(:raw_ssl_request).returns(successful_response('RF', @test_success_id)) refund = @gateway.refund(@amount, purchase.authorization, @options) - assert_success refund, "Refund failed" + assert_success refund, 'Refund failed' assert_equal @test_success_id, refund.authorization assert refund.test? end @@ -110,49 +112,63 @@ def test_successful_refund def test_successful_void @gateway.expects(:raw_ssl_request).returns(successful_response('DB', @test_success_id)) purchase = @gateway.purchase(@amount, @valid_card, @options) - assert_success purchase, "Purchase failed" + assert_success purchase, 'Purchase failed' assert purchase.test? @gateway.expects(:raw_ssl_request).returns(successful_response('RV', @test_success_id)) void = @gateway.void(purchase.authorization, @options) - assert_success void, "Void failed" + assert_success void, 'Void failed' assert_equal @test_success_id, void.authorization assert void.test? end -# ****************************************** FAILURE TESTS ****************************************** + # ****************************************** FAILURE TESTS ****************************************** def test_failed_purchase @gateway.expects(:raw_ssl_request).returns(failed_response('DB', @test_failure_id)) response = @gateway.purchase(@amount, @invalid_card, @options) assert_failure response - assert_equal Gateway::STANDARD_ERROR_CODE[:incorrect_number], response.error_code + assert_equal '100.100.101', response.error_code end def test_failed_authorize @gateway.expects(:raw_ssl_request).returns(failed_response('PA', @test_failure_id)) response = @gateway.authorize(@amount, @invalid_card, @options) assert_failure response - assert_equal Gateway::STANDARD_ERROR_CODE[:incorrect_number], response.error_code + assert_equal '100.100.101', response.error_code end def test_failed_capture @gateway.expects(:raw_ssl_request).returns(failed_response('CP', @test_failure_id)) response = @gateway.capture(@amount, @invalid_card) assert_failure response - assert_equal Gateway::STANDARD_ERROR_CODE[:incorrect_number], response.error_code + assert_equal '100.100.101', response.error_code end def test_failed_refund @gateway.expects(:raw_ssl_request).returns(failed_response('PF', @test_failure_id)) response = @gateway.refund(@amount, @test_success_id) assert_failure response - assert_equal Gateway::STANDARD_ERROR_CODE[:incorrect_number], response.error_code + assert_equal '100.100.101', response.error_code end def test_failed_void @gateway.expects(:raw_ssl_request).returns(failed_response('RV', @test_failure_id)) response = @gateway.void(@test_success_id, @options) assert_failure response - assert_equal Gateway::STANDARD_ERROR_CODE[:incorrect_number], response.error_code + assert_equal '100.100.101', response.error_code + end + + def test_passes_3d_secure_fields + options = @complete_request_options.merge({eci: 'eci', cavv: 'cavv', xid: 'xid'}) + + response = stub_comms(@gateway, :raw_ssl_request) do + @gateway.purchase(@amount, @valid_card, options) + end.check_request do |method, endpoint, data, headers| + assert_match(/threeDSecure.eci=eci/, data) + assert_match(/threeDSecure.verificationId=cavv/, data) + assert_match(/threeDSecure.xid=xid/, data) + end.respond_with(successful_response('DB', @test_success_id)) + + assert_success response end def test_scrub @@ -163,44 +179,37 @@ def test_scrub private def pre_scrubbed - "paymentType=DB&amount=1.00&currency=EUR&paymentBrand=VISA&card.holder=Longbob+Longsen&card.number=4200000000000000&card.expiryMonth=05&card.expiryYear=2018& card.cvv=123&billing.street1=456+My+Street&billing.street2=Apt+1&billing.city=Ottawa&billing.state=ON&billing.postcode=K1C2N6&billing.country=CA&authentication.entityId=8a8294174b7ecb28014b9699220015ca&authentication.password=sy6KJsT8&authentication.userId=8a8294174b7ecb28014b9699220015cc" + 'paymentType=DB&amount=1.00&currency=EUR&paymentBrand=VISA&card.holder=Longbob+Longsen&card.number=4200000000000000&card.expiryMonth=05&card.expiryYear=2018& card.cvv=123&billing.street1=456+My+Street&billing.street2=Apt+1&billing.city=Ottawa&billing.state=ON&billing.postcode=K1C2N6&billing.country=CA&authentication.entityId=8a8294174b7ecb28014b9699220015ca&authentication.password=sy6KJsT8&authentication.userId=8a8294174b7ecb28014b9699220015cc' end def post_scrubbed - "paymentType=DB&amount=1.00&currency=EUR&paymentBrand=VISA&card.holder=Longbob+Longsen&card.number=[FILTERED]&card.expiryMonth=05&card.expiryYear=2018& card.cvv=[FILTERED]&billing.street1=456+My+Street&billing.street2=Apt+1&billing.city=Ottawa&billing.state=ON&billing.postcode=K1C2N6&billing.country=CA&authentication.entityId=[FILTERED]&authentication.password=[FILTERED]&authentication.userId=[FILTERED]" + 'paymentType=DB&amount=1.00&currency=EUR&paymentBrand=VISA&card.holder=Longbob+Longsen&card.number=[FILTERED]&card.expiryMonth=05&card.expiryYear=2018& card.cvv=[FILTERED]&billing.street1=456+My+Street&billing.street2=Apt+1&billing.city=Ottawa&billing.state=ON&billing.postcode=K1C2N6&billing.country=CA&authentication.entityId=8a8294174b7ecb28014b9699220015ca&authentication.password=[FILTERED]&authentication.userId=8a8294174b7ecb28014b9699220015cc' end def successful_response(type, id) - OppMockResponse.new(200, - JSON.generate({"id" => id,"paymentType" => type,"paymentBrand" => "VISA","amount" => "1.00","currency" => "EUR","des - criptor" => "5410.9959.0306 OPP_Channel ","result" => {"code" => "000.100.110","description" => "Request successfully processed in 'Merchant in Integrator Test Mode'"},"card" => {"bin - " => "420000","last4Digits" => "0000","holder" => "Longbob Longsen","expiryMonth" => "05","expiryYear" => "2018"},"buildNumber" => "20150618-111601.r185004.opp-tags-20150618_stage","time - stamp" => "2015-06-20 19:31:01+0000","ndc" => "8a8294174b7ecb28014b9699220015ca_4453edbc001f405da557c05cb3c3add9"}) + OppMockResponse.new(200, + JSON.generate({'id' => id, 'paymentType' => type, 'paymentBrand' => 'VISA', 'amount' => '1.00', 'currency' => 'EUR', "des + criptor" => '5410.9959.0306 OPP_Channel ', 'result' => {'code' => '000.100.110', 'description' => "Request successfully processed in 'Merchant in Integrator Test Mode'"}, 'card' => {"bin + " => '420000', 'last4Digits' => '0000', 'holder' => 'Longbob Longsen', 'expiryMonth' => '05', 'expiryYear' => '2018'}, 'buildNumber' => '20150618-111601.r185004.opp-tags-20150618_stage', "time + stamp" => '2015-06-20 19:31:01+0000', 'ndc' => '8a8294174b7ecb28014b9699220015ca_4453edbc001f405da557c05cb3c3add9'}) ) end def failed_response(type, id, code='100.100.101') - OppMockResponse.new(400, - JSON.generate({"id" => id,"paymentType" => type,"paymentBrand" => "VISA","result" => {"code" => code,"des - cription" => "invalid creditcard, bank account number or bank name"},"card" => {"bin" => "444444","last4Digits" => "4444","holder" => "Longbob Longsen","expiryMonth" => "05","expiryYear" => "2018"}, - "buildNumber" => "20150618-111601.r185004.opp-tags-20150618_stage","timestamp" => "2015-06-20 20:40:26+0000","ndc" => "8a8294174b7ecb28014b9699220015ca_5200332e7d664412a84ed5f4777b3c7d"}) + OppMockResponse.new(400, + JSON.generate({'id' => id, 'paymentType' => type, 'paymentBrand' => 'VISA', 'result' => {'code' => code, "des + cription" => 'invalid creditcard, bank account number or bank name'}, 'card' => {'bin' => '444444', 'last4Digits' => '4444', 'holder' => 'Longbob Longsen', 'expiryMonth' => '05', 'expiryYear' => '2018'}, + 'buildNumber' => '20150618-111601.r185004.opp-tags-20150618_stage', 'timestamp' => '2015-06-20 20:40:26+0000', 'ndc' => '8a8294174b7ecb28014b9699220015ca_5200332e7d664412a84ed5f4777b3c7d'}) ) end class OppMockResponse - def initialize(code, body) - @code = code - @body = body - end - - def code - @code - end - - def body - @body - end + attr_reader :code, :body + + def initialize(code, body) + @code = code + @body = body + end end end - diff --git a/test/unit/gateways/optimal_payment_test.rb b/test/unit/gateways/optimal_payment_test.rb index 2beade96c86..f8d194e94ad 100644 --- a/test/unit/gateways/optimal_payment_test.rb +++ b/test/unit/gateways/optimal_payment_test.rb @@ -33,7 +33,7 @@ def test_full_request def test_ip_address_is_passed stub_comms do - @gateway.purchase(@amount, @credit_card, @options.merge(ip: "1.2.3.4")) + @gateway.purchase(@amount, @credit_card, @options.merge(ip: '1.2.3.4')) end.check_request do |endpoint, data, headers| assert_match %r{customerIP%3E1.2.3.4%3C}, data end.respond_with(successful_purchase_response) @@ -72,7 +72,7 @@ def test_successful_purchase end def test_purchase_from_canada_includes_state_field - @options[:billing_address][:country] = "CA" + @options[:billing_address][:country] = 'CA' @gateway.expects(:ssl_post).with do |url, data| data =~ /state/ && data !~ /region/ end.returns(successful_purchase_response) @@ -81,7 +81,7 @@ def test_purchase_from_canada_includes_state_field end def test_purchase_from_us_includes_state_field - @options[:billing_address][:country] = "US" + @options[:billing_address][:country] = 'US' @gateway.expects(:ssl_post).with do |url, data| data =~ /state/ && data !~ /region/ end.returns(successful_purchase_response) @@ -90,7 +90,7 @@ def test_purchase_from_us_includes_state_field end def test_purchase_from_any_other_country_includes_region_field - @options[:billing_address][:country] = "GB" + @options[:billing_address][:country] = 'GB' @gateway.expects(:ssl_post).with do |url, data| data =~ /region/ && data !~ /state/ end.returns(successful_purchase_response) @@ -99,11 +99,11 @@ def test_purchase_from_any_other_country_includes_region_field end def test_purchase_with_shipping_address - @options[:shipping_address] = {:country => "CA"} + @options[:shipping_address] = {:country => 'CA'} @gateway.expects(:ssl_post).with do |url, data| - xml = data.split("&").detect{|string| string =~ /txnRequest=/}.gsub("txnRequest=","") + xml = data.split('&').detect { |string| string =~ /txnRequest=/ }.gsub('txnRequest=', '') doc = Nokogiri::XML.parse(CGI.unescape(xml)) - doc.xpath('//xmlns:shippingDetails/xmlns:country').first.text == "CA" && doc.to_s.include?('<shippingDetails>') + doc.xpath('//xmlns:shippingDetails/xmlns:country').first.text == 'CA' && doc.to_s.include?('<shippingDetails>') end.returns(successful_purchase_response) assert @gateway.purchase(@amount, @credit_card, @options) @@ -112,7 +112,7 @@ def test_purchase_with_shipping_address def test_purchase_without_shipping_address @options[:shipping_address] = nil @gateway.expects(:ssl_post).with do |url, data| - xml = data.split("&").detect{|string| string =~ /txnRequest=/}.gsub("txnRequest=","") + xml = data.split('&').detect { |string| string =~ /txnRequest=/ }.gsub('txnRequest=', '') doc = Nokogiri::XML.parse(CGI.unescape(xml)) doc.to_s.include?('<shippingDetails>') == false end.returns(successful_purchase_response) @@ -128,10 +128,33 @@ def test_purchase_without_billing_address assert_success response end + def test_cvd_fields_pass_correctly + stub_comms do + @gateway.purchase(@amount, @credit_card, @options) + end.check_request do |endpoint, data, headers| + assert_match(/cvdIndicator%3E1%3C\/cvdIndicator%3E%0A%20%20%20%20%3Ccvd%3E123%3C\/cvd/, data) + end.respond_with(successful_purchase_response) + + credit_card = CreditCard.new( + :number => '4242424242424242', + :month => 9, + :year => Time.now.year + 1, + :first_name => 'Longbob', + :last_name => 'Longsen', + :brand => 'visa' + ) + + stub_comms do + @gateway.purchase(@amount, credit_card, @options) + end.check_request do |endpoint, data, headers| + assert_match(/cvdIndicator%3E0%3C\/cvdIndicator%3E%0A%20%20%3C\/card/, data) + end.respond_with(failed_purchase_response) + end + def test_successful_void @gateway.expects(:ssl_post).returns(successful_purchase_response) - assert response = @gateway.void("1234567", @options) + assert response = @gateway.void('1234567', @options) assert_instance_of Response, response assert_success response @@ -149,23 +172,21 @@ def test_unsuccessful_request end def test_in_production_with_test_param_sends_request_to_test_server - begin - ActiveMerchant::Billing::Base.mode = :production - @gateway = OptimalPaymentGateway.new( - :account_number => '12345678', - :store_id => 'login', - :password => 'password', - :test => true - ) - @gateway.expects(:ssl_post).with("https://webservices.test.optimalpayments.com/creditcardWS/CreditCardServlet/v1", anything).returns(successful_purchase_response) - - assert response = @gateway.purchase(@amount, @credit_card, @options) - assert_instance_of Response, response - assert_success response - assert response.test? - ensure - ActiveMerchant::Billing::Base.mode = :test - end + ActiveMerchant::Billing::Base.mode = :production + @gateway = OptimalPaymentGateway.new( + :account_number => '12345678', + :store_id => 'login', + :password => 'password', + :test => true + ) + @gateway.expects(:ssl_post).with('https://webservices.test.optimalpayments.com/creditcardWS/CreditCardServlet/v1', anything).returns(successful_purchase_response) + + assert response = @gateway.purchase(@amount, @credit_card, @options) + assert_instance_of Response, response + assert_success response + assert response.test? + ensure + ActiveMerchant::Billing::Base.mode = :test end def test_avs_result_in_response @@ -191,7 +212,6 @@ def test_avs_results_not_in_response end def test_deprecated_options - assert_deprecation_warning("The 'account' option is deprecated in favor of 'account_number' and will be removed in a future version.") do @gateway = OptimalPaymentGateway.new( :account => '12345678', @@ -209,6 +229,11 @@ def test_deprecated_options end end + def test_scrub + assert_equal @gateway.scrub(pre_scrubbed), post_scrubbed + assert_equal @gateway.scrub(pre_scrubbed_double_escaped), post_scrubbed_double_escaped + end + private def full_request @@ -266,6 +291,7 @@ def minimal_request <year>#{Time.now.year + 1}</year> </cardExpiry> <cardType>VI</cardType> + <cvdIndicator>0</cvdIndicator> </card> <billingDetails> <cardPayMethod>WEB</cardPayMethod> @@ -360,4 +386,64 @@ def failed_purchase_response </ccTxnResponseV1> XML end + + def pre_scrubbed + <<-EOS +opening connection to webservices.test.optimalpayments.com:443... +opened +starting SSL for webservices.test.optimalpayments.com:443... +SSL established +<- "POST /creditcardWS/CreditCardServlet/v1 HTTP/1.1\r\nContent-Type: application/x-www-form-urlencoded\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nAccept: */*\r\nUser-Agent: Ruby\r\nConnection: close\r\nHost: webservices.test.optimalpayments.com\r\nContent-Length: 1616\r\n\r\n" +<- "txnMode=ccPurchase&txnRequest=%3CccAuthRequestV1%20xmlns=%22http://www.optimalpayments.com/creditcard/xmlschema/v1%22%20xmlns:xsi=%22http://www.w3.org/2001/XMLSchema-instance%22%20xsi:schemaLocation=%22http://www.optimalpayments.com/creditcard/xmlschema/v1%22%3E%0A%20%20%3CmerchantAccount%3E%0A%20%20%20%20%3CaccountNum%3E1001134550%3C/accountNum%3E%0A%20%20%20%20%3CstoreID%3Etest%3C/storeID%3E%0A%20%20%20%20%3CstorePwd%3Etest%3C/storePwd%3E%0A%20%20%3C/merchantAccount%3E%0A%20%20%3CmerchantRefNum%3E1%3C/merchantRefNum%3E%0A%20%20%3Camount%3E1.0%3C/amount%3E%0A%20%20%3Ccard%3E%0A%20%20%20%20%3CcardNum%3E4387751111011%3C/cardNum%3E%0A%20%20%20%20%3CcardExpiry%3E%0A%20%20%20%20%20%20%3Cmonth%3E9%3C/month%3E%0A%20%20%20%20%20%20%3Cyear%3E2019%3C/year%3E%0A%20%20%20%20%3C/cardExpiry%3E%0A%20%20%20%20%3CcardType%3EVI%3C/cardType%3E%0A%20%20%20%20%3CcvdIndicator%3E1%3C/cvdIndicator%3E%0A%20%20%20%20%3Ccvd%3E123%3C/cvd%3E%0A%20%20%3C/card%3E%0A%20%20%3CbillingDetails%3E%0A%20%20%20%20%3CcardPayMethod%3EWEB%3C/cardPayMethod%3E%0A%20%20%20%20%3CfirstName%3EJim%3C/firstName%3E%0A%20%20%20%20%3ClastName%3ESmith%3C/lastName%3E%0A%20%20%20%20%3Cstreet%3E456%20My%20Street%3C/street%3E%0A%20%20%20%20%3Cstreet2%3EApt%201%3C/street2%3E%0A%20%20%20%20%3Ccity%3EOttawa%3C/city%3E%0A%20%20%20%20%3Cstate%3EON%3C/state%3E%0A%20%20%20%20%3Ccountry%3ECA%3C/country%3E%0A%20%20%20%20%3Czip%3EK1C2N6%3C/zip%3E%0A%20%20%20%20%3Cphone%3E(555)555-5555%3C/phone%3E%0A%20%20%20%20%3Cemail%3Eemail@example.com%3C/email%3E%0A%20%20%3C/billingDetails%3E%0A%20%20%3CcustomerIP%3E1.2.3.4%3C/customerIP%3E%0A%3C/ccAuthRequestV1%3E%0A" +-> "HTTP/1.1 200 OK\r\n" +-> "Server: WebServer32xS10i3\r\n" +-> "Content-Length: 632\r\n" +-> "X-ApplicationUid: GUID=610a301289c34e8254330b7edc724f5b\r\n" +-> "Content-Type: application/xml\r\n" +-> "Date: Mon, 12 Feb 2018 21:57:42 GMT\r\n" +-> "Connection: close\r\n" +-> "\r\n" +reading 632 bytes... +-> "<" +-> "?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ccTxnResponseV1 xmlns=\"http://www.optimalpayments.com/creditcard/xmlschema/v1\"><confirmationNumber>498871860</confirmationNumber><decision>ACCEPTED</decision><code>0</code><description>No Error</description><authCode>369231</authCode><avsResponse>X</avsResponse><cvdResponse>M</cvdResponse><detail><tag>InternalResponseCode</tag><value>0</value></detail><detail><tag>SubErrorCode</tag><value>0</value></detail><detail><tag>InternalResponseDescription</tag><value>no_error</value></detail><txnTime>2018-02-12T16:57:42.289-05:00</txnTime><duplicateFound>false</duplicateFound></ccTxnResponseV1>" +read 632 bytes +Conn close + EOS + end + + def post_scrubbed + <<-EOS +opening connection to webservices.test.optimalpayments.com:443... +opened +starting SSL for webservices.test.optimalpayments.com:443... +SSL established +<- "POST /creditcardWS/CreditCardServlet/v1 HTTP/1.1\r\nContent-Type: application/x-www-form-urlencoded\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nAccept: */*\r\nUser-Agent: Ruby\r\nConnection: close\r\nHost: webservices.test.optimalpayments.com\r\nContent-Length: 1616\r\n\r\n" +<- "txnMode=ccPurchase&txnRequest=%3CccAuthRequestV1%20xmlns=%22http://www.optimalpayments.com/creditcard/xmlschema/v1%22%20xmlns:xsi=%22http://www.w3.org/2001/XMLSchema-instance%22%20xsi:schemaLocation=%22http://www.optimalpayments.com/creditcard/xmlschema/v1%22%3E%0A%20%20%3CmerchantAccount%3E%0A%20%20%20%20%3CaccountNum%3E1001134550%3C/accountNum%3E%0A%20%20%20%20%3CstoreID%3Etest%3C/storeID%3E%0A%20%20%20%20%3CstorePwd%3E[FILTERED]%3C/storePwd%3E%0A%20%20%3C/merchantAccount%3E%0A%20%20%3CmerchantRefNum%3E1%3C/merchantRefNum%3E%0A%20%20%3Camount%3E1.0%3C/amount%3E%0A%20%20%3Ccard%3E%0A%20%20%20%20%3CcardNum%3E[FILTERED]%3C/cardNum%3E%0A%20%20%20%20%3CcardExpiry%3E%0A%20%20%20%20%20%20%3Cmonth%3E9%3C/month%3E%0A%20%20%20%20%20%20%3Cyear%3E2019%3C/year%3E%0A%20%20%20%20%3C/cardExpiry%3E%0A%20%20%20%20%3CcardType%3EVI%3C/cardType%3E%0A%20%20%20%20%3CcvdIndicator%3E1%3C/cvdIndicator%3E%0A%20%20%20%20%3Ccvd%3E[FILTERED]%3C/cvd%3E%0A%20%20%3C/card%3E%0A%20%20%3CbillingDetails%3E%0A%20%20%20%20%3CcardPayMethod%3EWEB%3C/cardPayMethod%3E%0A%20%20%20%20%3CfirstName%3EJim%3C/firstName%3E%0A%20%20%20%20%3ClastName%3ESmith%3C/lastName%3E%0A%20%20%20%20%3Cstreet%3E456%20My%20Street%3C/street%3E%0A%20%20%20%20%3Cstreet2%3EApt%201%3C/street2%3E%0A%20%20%20%20%3Ccity%3EOttawa%3C/city%3E%0A%20%20%20%20%3Cstate%3EON%3C/state%3E%0A%20%20%20%20%3Ccountry%3ECA%3C/country%3E%0A%20%20%20%20%3Czip%3EK1C2N6%3C/zip%3E%0A%20%20%20%20%3Cphone%3E(555)555-5555%3C/phone%3E%0A%20%20%20%20%3Cemail%3Eemail@example.com%3C/email%3E%0A%20%20%3C/billingDetails%3E%0A%20%20%3CcustomerIP%3E1.2.3.4%3C/customerIP%3E%0A%3C/ccAuthRequestV1%3E%0A" +-> "HTTP/1.1 200 OK\r\n" +-> "Server: WebServer32xS10i3\r\n" +-> "Content-Length: 632\r\n" +-> "X-ApplicationUid: GUID=610a301289c34e8254330b7edc724f5b\r\n" +-> "Content-Type: application/xml\r\n" +-> "Date: Mon, 12 Feb 2018 21:57:42 GMT\r\n" +-> "Connection: close\r\n" +-> "\r\n" +reading 632 bytes... +-> "<" +-> "?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ccTxnResponseV1 xmlns=\"http://www.optimalpayments.com/creditcard/xmlschema/v1\"><confirmationNumber>498871860</confirmationNumber><decision>ACCEPTED</decision><code>0</code><description>No Error</description><authCode>369231</authCode><avsResponse>X</avsResponse><cvdResponse>M</cvdResponse><detail><tag>InternalResponseCode</tag><value>0</value></detail><detail><tag>SubErrorCode</tag><value>0</value></detail><detail><tag>InternalResponseDescription</tag><value>no_error</value></detail><txnTime>2018-02-12T16:57:42.289-05:00</txnTime><duplicateFound>false</duplicateFound></ccTxnResponseV1>" +read 632 bytes +Conn close + EOS + end + + def pre_scrubbed_double_escaped + <<-PRE_SCRUBBED + txnMode=ccPurchase&txnRequest=%3CccAuthRequestV1+xmlns%3D%22http%3A%2F%2Fwww.optimalpayments.com%2Fcreditcard%2Fxmlschema%2Fv1%22+xmlns%3Axsi%3D%22http%3A%2F%2Fwww.w3.org%2F2001%2FXMLSchema-instance%22+xsi%3AschemaLocation%3D%22http%3A%2F%2Fwww.optimalpayments.com%2Fcreditcard%2Fxmlschema%2Fv1%22%3E%0A++%3CmerchantAccount%3E%0A++++%3CaccountNum%3E89986098%3C%2FaccountNum%3E%0A++++%3CstoreID%3Etest%3C%2FstoreID%3E%0A++++%3CstorePwd%3Etest%3C%2FstorePwd%3E%0A++%3C%2FmerchantAccount%3E%0A++%3CmerchantRefNum%3E1%3C%2FmerchantRefNum%3E%0A++%3Camount%3E1.0%3C%2Famount%3E%0A++%3Ccard%3E%0A++++%3CcardNum%3E4387751111011%3C%2FcardNum%3E%0A++++%3CcardExpiry%3E%0A++++++%3Cmonth%3E9%3C%2Fmonth%3E%0A++++++%3Cyear%3E2015%3C%2Fyear%3E%0A++++%3C%2FcardExpiry%3E%0A++++%3CcardType%3EVI%3C%2FcardType%3E%0A++++%3CcvdIndicator%3E1%3C%2FcvdIndicator%3E%0A++++%3Ccvd%3E123%3C%2Fcvd%3E%0A++%3C%2Fcard%3E%0A++%3CbillingDetails%3E%0A++++%3CcardPayMethod%3EWEB%3C%2FcardPayMethod%3E%0A++++%3CfirstName%3EJim%3C%2FfirstName%3E%0A++++%3ClastName%3ESmith%3C%2FlastName%3E%0A++++%3Cstreet%3E1234+My+Street%3C%2Fstreet%3E%0A++++%3Cstreet2%3EApt+1%3C%2Fstreet2%3E%0A++++%3Ccity%3EOttawa%3C%2Fcity%3E%0A++++%3Cstate%3EON%3C%2Fstate%3E%0A++++%3Ccountry%3ECA%3C%2Fcountry%3E%0A++++%3Czip%3EK1C2N6%3C%2Fzip%3E%0A++++%3Cphone%3E%28555%29555-5555%3C%2Fphone%3E%0A++++%3Cemail%3Eemail%40example.com%3C%2Femail%3E%0A++%3C%2FbillingDetails%3E%0A++%3CcustomerIP%3E1.2.3.4%3C%2FcustomerIP%3E%0A%3C%2FccAuthRequestV1%3E%0A + PRE_SCRUBBED + end + + def post_scrubbed_double_escaped + <<-POST_SCRUBBED + txnMode=ccPurchase&txnRequest=%3CccAuthRequestV1+xmlns%3D%22http%3A%2F%2Fwww.optimalpayments.com%2Fcreditcard%2Fxmlschema%2Fv1%22+xmlns%3Axsi%3D%22http%3A%2F%2Fwww.w3.org%2F2001%2FXMLSchema-instance%22+xsi%3AschemaLocation%3D%22http%3A%2F%2Fwww.optimalpayments.com%2Fcreditcard%2Fxmlschema%2Fv1%22%3E%0A++%3CmerchantAccount%3E%0A++++%3CaccountNum%3E89986098%3C%2FaccountNum%3E%0A++++%3CstoreID%3Etest%3C%2FstoreID%3E%0A++++%3CstorePwd%3E[FILTERED]%3C%2FstorePwd%3E%0A++%3C%2FmerchantAccount%3E%0A++%3CmerchantRefNum%3E1%3C%2FmerchantRefNum%3E%0A++%3Camount%3E1.0%3C%2Famount%3E%0A++%3Ccard%3E%0A++++%3CcardNum%3E[FILTERED]%3C%2FcardNum%3E%0A++++%3CcardExpiry%3E%0A++++++%3Cmonth%3E9%3C%2Fmonth%3E%0A++++++%3Cyear%3E2015%3C%2Fyear%3E%0A++++%3C%2FcardExpiry%3E%0A++++%3CcardType%3EVI%3C%2FcardType%3E%0A++++%3CcvdIndicator%3E1%3C%2FcvdIndicator%3E%0A++++%3Ccvd%3E[FILTERED]%3C%2Fcvd%3E%0A++%3C%2Fcard%3E%0A++%3CbillingDetails%3E%0A++++%3CcardPayMethod%3EWEB%3C%2FcardPayMethod%3E%0A++++%3CfirstName%3EJim%3C%2FfirstName%3E%0A++++%3ClastName%3ESmith%3C%2FlastName%3E%0A++++%3Cstreet%3E1234+My+Street%3C%2Fstreet%3E%0A++++%3Cstreet2%3EApt+1%3C%2Fstreet2%3E%0A++++%3Ccity%3EOttawa%3C%2Fcity%3E%0A++++%3Cstate%3EON%3C%2Fstate%3E%0A++++%3Ccountry%3ECA%3C%2Fcountry%3E%0A++++%3Czip%3EK1C2N6%3C%2Fzip%3E%0A++++%3Cphone%3E%28555%29555-5555%3C%2Fphone%3E%0A++++%3Cemail%3Eemail%40example.com%3C%2Femail%3E%0A++%3C%2FbillingDetails%3E%0A++%3CcustomerIP%3E1.2.3.4%3C%2FcustomerIP%3E%0A%3C%2FccAuthRequestV1%3E%0A + POST_SCRUBBED + end end diff --git a/test/unit/gateways/orbital_test.rb b/test/unit/gateways/orbital_test.rb index 310a84e2b75..6b913222dcd 100644 --- a/test/unit/gateways/orbital_test.rb +++ b/test/unit/gateways/orbital_test.rb @@ -12,7 +12,23 @@ def setup :password => 'password', :merchant_id => 'merchant_id' ) - @customer_ref_num = "ABC" + @customer_ref_num = 'ABC' + + @level_2 = { + tax_indicator: '1', + tax: '10', + advice_addendum_1: 'taa1 - test', + advice_addendum_2: 'taa2 - test', + advice_addendum_3: 'taa3 - test', + advice_addendum_4: 'taa4 - test', + purchase_order: '123abc', + name: address[:name], + address1: address[:address1], + address2: address[:address2], + city: address[:city], + state: address[:state], + zip: address[:zip], + } @options = { :order_id => '1'} end @@ -26,6 +42,37 @@ def test_successful_purchase assert_equal '4A5398CF9B87744GG84A1D30F2F2321C66249416;1', response.authorization end + def test_level_2_data + stub_comms do + @gateway.purchase(50, credit_card, @options.merge(level_2_data: @level_2)) + end.check_request do |endpoint, data, headers| + assert_match %{<TaxInd>#{@level_2[:tax_indicator].to_i}</TaxInd>}, data + assert_match %{<Tax>#{@level_2[:tax].to_i}</Tax>}, data + assert_match %{<AMEXTranAdvAddn1>#{@level_2[:advice_addendum_1]}</AMEXTranAdvAddn1>}, data + assert_match %{<AMEXTranAdvAddn2>#{@level_2[:advice_addendum_2]}</AMEXTranAdvAddn2>}, data + assert_match %{<AMEXTranAdvAddn3>#{@level_2[:advice_addendum_3]}</AMEXTranAdvAddn3>}, data + assert_match %{<AMEXTranAdvAddn4>#{@level_2[:advice_addendum_4]}</AMEXTranAdvAddn4>}, data + assert_match %{<PCOrderNum>#{@level_2[:purchase_order]}</PCOrderNum>}, data + assert_match %{<PCDestZip>#{@level_2[:zip]}</PCDestZip>}, data + assert_match %{<PCDestName>#{@level_2[:name]}</PCDestName>}, data + assert_match %{<PCDestAddress1>#{@level_2[:address1]}</PCDestAddress1>}, data + assert_match %{<PCDestAddress2>#{@level_2[:address2]}</PCDestAddress2>}, data + assert_match %{<PCDestCity>#{@level_2[:city]}</PCDestCity>}, data + assert_match %{<PCDestState>#{@level_2[:state]}</PCDestState>}, data + end.respond_with(successful_purchase_response) + end + + def test_network_tokenization_credit_card_data + stub_comms do + @gateway.purchase(50, network_tokenization_credit_card(nil, eci: '5', transaction_id: 'BwABB4JRdgAAAAAAiFF2AAAAAAA='), @options) + end.check_request do |endpoint, data, headers| + assert_match %{<AuthenticationECIInd>5</AuthenticationECIInd>}, data + assert_match %{<DPANInd>Y</DPANInd>}, data + assert_match %{DigitalTokenCryptogram}, data + assert_match %{XID}, data + end.respond_with(successful_purchase_response) + end + def test_currency_exponents stub_comms do @gateway.purchase(50, credit_card, :order_id => '1') @@ -52,13 +99,13 @@ def test_unauthenticated_response assert response = @gateway.purchase(101, credit_card, :order_id => '1') assert_instance_of Response, response assert_failure response - assert_equal "AUTH DECLINED 12001", response.message + assert_equal 'AUTH DECLINED 12001', response.message end def test_successful_void @gateway.expects(:ssl_post).returns(successful_void_response) - assert response = @gateway.void("identifier") + assert response = @gateway.void('identifier') assert_instance_of Response, response assert_success response assert_nil response.message @@ -67,8 +114,8 @@ def test_successful_void def test_deprecated_void @gateway.expects(:ssl_post).returns(successful_void_response) - assert_deprecation_warning("Calling the void method with an amount parameter is deprecated and will be removed in a future version.") do - assert response = @gateway.void(50, "identifier") + assert_deprecation_warning('Calling the void method with an amount parameter is deprecated and will be removed in a future version.') do + assert response = @gateway.void(50, 'identifier') assert_instance_of Response, response assert_success response assert_nil response.message @@ -90,7 +137,7 @@ def test_order_id_as_number def test_order_id_format response = stub_comms do - @gateway.purchase(101, credit_card, :order_id => " #101.23,56 $Hi &thére@Friends") + @gateway.purchase(101, credit_card, :order_id => ' #101.23,56 $Hi &thére@Friends') end.check_request do |endpoint, data, headers| assert_match(/<OrderID>101-23,56 \$Hi &amp;thre@Fr<\/OrderID>/, data) end.respond_with(successful_purchase_response) @@ -99,15 +146,30 @@ def test_order_id_format def test_order_id_format_for_capture response = stub_comms do - @gateway.capture(101, "4A5398CF9B87744GG84A1D30F2F2321C66249416;1001.1", :order_id => "#1001.1") + @gateway.capture(101, '4A5398CF9B87744GG84A1D30F2F2321C66249416;1001.1', :order_id => '#1001.1') end.check_request do |endpoint, data, headers| assert_match(/<OrderID>1001-1<\/OrderID>/, data) end.respond_with(successful_purchase_response) assert_success response end + def test_numeric_merchant_id_for_caputre + gateway = ActiveMerchant::Billing::OrbitalGateway.new( + :login => 'login', + :password => 'password', + :merchant_id => 700000123456 + ) + + response = stub_comms(gateway) do + gateway.capture(101, '4A5398CF9B87744GG84A1D30F2F2321C66249416;1', @options) + end.check_request do |endpoint, data, headers| + assert_match(/<MerchantID>700000123456<\/MerchantID>/, data) + end.respond_with(successful_purchase_response) + assert_success response + end + def test_expiry_date - year = (DateTime.now + 1.year).strftime("%y") + year = (DateTime.now + 1.year).strftime('%y') assert_equal "09#{year}", @gateway.send(:expiry_date, credit_card) end @@ -134,8 +196,8 @@ def test_truncates_address def test_truncates_name card = credit_card('4242424242424242', - :first_name => 'John', - :last_name => 'Jacob Jingleheimer Smith-Jones') + :first_name => 'John', + :last_name => 'Jacob Jingleheimer Smith-Jones') response = stub_comms do @gateway.purchase(50, card, :order_id => 1, :billing_address => address) @@ -170,7 +232,7 @@ def test_truncates_phone end def test_truncates_zip - long_zip = '1234567890123' + long_zip = '1234567890123' response = stub_comms do @gateway.purchase(50, credit_card, :order_id => 1, :billing_address => address(:zip => long_zip)) @@ -190,12 +252,12 @@ def test_address_format :dest_address2 => 'L%u%xury S|u^i\\t/e', :dest_city => '/Winn/i%p|e^g\\', :dest_zip => 'A1A 2B2', - :dest_state => '^MB', + :dest_state => '^MB' ) response = stub_comms do @gateway.purchase(50, credit_card, :order_id => 1, - :billing_address => address_with_invalid_chars) + :billing_address => address_with_invalid_chars) end.check_request do |endpoint, data, headers| assert_match(/456 Main Street</, data) assert_match(/Apt. Number One</, data) @@ -223,8 +285,8 @@ def test_address_format def test_truncates_by_byte_length card = credit_card('4242424242424242', - :first_name => 'John', - :last_name => 'Jacob Jingleheimer Smith-Jones') + :first_name => 'John', + :last_name => 'Jacob Jingleheimer Smith-Jones') long_address = address( :address1 => '456 Stréêt Name is Really Long', @@ -242,7 +304,7 @@ def test_truncates_by_byte_length response = stub_comms do @gateway.purchase(50, card, :order_id => 1, - :billing_address => long_address) + :billing_address => long_address) end.check_request do |endpoint, data, headers| assert_match(/456 Stréêt Name is Really Lo</, data) assert_match(/Apårtmeñt 123456789012345678</, data) @@ -303,7 +365,7 @@ def test_dest_address response = stub_comms do @gateway.purchase(50, credit_card, :order_id => 1, - :billing_address => billing_address) + :billing_address => billing_address) end.check_request do |endpoint, data, headers| assert_match(/<AVSDestzip>90001/, data) assert_match(/<AVSDestaddress1>456 Main St./, data) @@ -319,7 +381,7 @@ def test_dest_address # non-AVS country response = stub_comms do @gateway.purchase(50, credit_card, :order_id => 1, - :billing_address => billing_address.merge(:dest_country => 'BR')) + :billing_address => billing_address.merge(:dest_country => 'BR')) end.check_request do |endpoint, data, headers| assert_match(/<AVSDestcountryCode></, data) end.respond_with(successful_purchase_response) @@ -330,7 +392,7 @@ def test_default_managed_billing response = stub_comms do assert_deprecation_warning(Gateway::RECURRING_DEPRECATION_MESSAGE) do assert_deprecation_warning do - @gateway.add_customer_profile(credit_card, :managed_billing => {:start_date => "10-10-2014" }) + @gateway.add_customer_profile(credit_card, :managed_billing => {:start_date => '10-10-2014' }) end end end.check_request do |endpoint, data, headers| @@ -346,10 +408,12 @@ def test_managed_billing response = stub_comms do assert_deprecation_warning(Gateway::RECURRING_DEPRECATION_MESSAGE) do assert_deprecation_warning do - @gateway.add_customer_profile(credit_card, :managed_billing => {:start_date => "10-10-2014", - :end_date => "10-10-2015", - :max_dollar_value => 1500, - :max_transactions => 12}) + @gateway.add_customer_profile(credit_card, + :managed_billing => { + :start_date => '10-10-2014', + :end_date => '10-10-2015', + :max_dollar_value => 1500, + :max_transactions => 12}) end end end.check_request do |endpoint, data, headers| @@ -506,7 +570,7 @@ def test_american_requests_adhere_to_xml_schema schema_file = File.read("#{File.dirname(__FILE__)}/../../schema/orbital/Request_PTI54.xsd") doc = Nokogiri::XML(data) xsd = Nokogiri::XML::Schema(schema_file) - assert xsd.valid?(doc), "Request does not adhere to DTD" + assert xsd.valid?(doc), 'Request does not adhere to DTD' end.respond_with(successful_purchase_response) assert_success response end @@ -518,7 +582,7 @@ def test_german_requests_adhere_to_xml_schema schema_file = File.read("#{File.dirname(__FILE__)}/../../schema/orbital/Request_PTI54.xsd") doc = Nokogiri::XML(data) xsd = Nokogiri::XML::Schema(schema_file) - assert xsd.valid?(doc), "Request does not adhere to DTD" + assert xsd.valid?(doc), 'Request does not adhere to DTD' end.respond_with(successful_purchase_response) assert_success response end @@ -586,7 +650,7 @@ def test_delete_customer_profile end def test_attempts_seconday_url - @gateway.expects(:ssl_post).with(OrbitalGateway.test_url, anything, anything).raises(ActiveMerchant::ConnectionError.new("message", nil)) + @gateway.expects(:ssl_post).with(OrbitalGateway.test_url, anything, anything).raises(ActiveMerchant::ConnectionError.new('message', nil)) @gateway.expects(:ssl_post).with(OrbitalGateway.secondary_test_url, anything, anything).returns(successful_purchase_response) response = @gateway.purchase(50, credit_card, :order_id => '1') @@ -642,7 +706,7 @@ def test_cc_account_num_is_removed_from_response assert_deprecation_warning do response = @gateway.add_customer_profile(credit_card, - :billing_address => address) + :billing_address => address) end assert_instance_of Response, response @@ -656,7 +720,7 @@ def test_successful_verify end.respond_with(successful_purchase_response, successful_purchase_response) assert_success response assert_equal '4A5398CF9B87744GG84A1D30F2F2321C66249416;1', response.authorization - assert_equal "Approved", response.message + assert_equal 'Approved', response.message end def test_successful_verify_and_failed_void @@ -665,7 +729,7 @@ def test_successful_verify_and_failed_void end.respond_with(successful_purchase_response, failed_purchase_response) assert_success response assert_equal '4A5398CF9B87744GG84A1D30F2F2321C66249416;1', response.authorization - assert_equal "Approved", response.message + assert_equal 'Approved', response.message end def test_failed_verify @@ -673,7 +737,25 @@ def test_failed_verify @gateway.verify(credit_card, @options) end.respond_with(failed_purchase_response, failed_purchase_response) assert_failure response - assert_equal "AUTH DECLINED 12001", response.message + assert_equal 'AUTH DECLINED 12001', response.message + end + + def test_cvv_indicator_present_for_visas_with_cvvs + stub_comms do + @gateway.purchase(50, credit_card, @options) + end.check_request do |_endpoint, data, _headers| + assert_match %r{<CardSecValInd>1<\/CardSecValInd>}, data + assert_match %r{<CardSecVal>123<\/CardSecVal>}, data + end.respond_with(successful_purchase_response) + end + + def test_cvv_indicator_absent_for_recurring + stub_comms do + @gateway.purchase(50, credit_card(nil, {verification_value: nil}), @options) + end.check_request do |_endpoint, data, _headers| + assert_no_match %r{<CardSecValInd>}, data + assert_no_match %r{<CardSecVal>}, data + end.respond_with(successful_purchase_response) end def test_scrub @@ -688,15 +770,15 @@ def successful_purchase_response(resp_code = '00') end def failed_purchase_response - %q{<?xml version="1.0" encoding="UTF-8"?><Response><NewOrderResp><IndustryType></IndustryType><MessageType>AC</MessageType><MerchantID>700000000000</MerchantID><TerminalID>001</TerminalID><CardBrand>VI</CardBrand><AccountNum>4000300011112220</AccountNum><OrderID>1</OrderID><TxRefNum>4A5398CF9B87744GG84A1D30F2F2321C66249416</TxRefNum><TxRefIdx>0</TxRefIdx><ProcStatus>0</ProcStatus><ApprovalStatus>0</ApprovalStatus><RespCode>05</RespCode><AVSRespCode>G </AVSRespCode><CVV2RespCode>N</CVV2RespCode><AuthCode></AuthCode><RecurringAdviceCd></RecurringAdviceCd><CAVVRespCode></CAVVRespCode><StatusMsg>Do Not Honor</StatusMsg><RespMsg>AUTH DECLINED 12001</RespMsg><HostRespCode>05</HostRespCode><HostAVSRespCode>N</HostAVSRespCode><HostCVV2RespCode>N</HostCVV2RespCode><CustomerRefNum></CustomerRefNum><CustomerName></CustomerName><ProfileProcStatus></ProfileProcStatus><CustomerProfileMessage></CustomerProfileMessage><RespTime>150214</RespTime></NewOrderResp></Response>} + '<?xml version="1.0" encoding="UTF-8"?><Response><NewOrderResp><IndustryType></IndustryType><MessageType>AC</MessageType><MerchantID>700000000000</MerchantID><TerminalID>001</TerminalID><CardBrand>VI</CardBrand><AccountNum>4000300011112220</AccountNum><OrderID>1</OrderID><TxRefNum>4A5398CF9B87744GG84A1D30F2F2321C66249416</TxRefNum><TxRefIdx>0</TxRefIdx><ProcStatus>0</ProcStatus><ApprovalStatus>0</ApprovalStatus><RespCode>05</RespCode><AVSRespCode>G </AVSRespCode><CVV2RespCode>N</CVV2RespCode><AuthCode></AuthCode><RecurringAdviceCd></RecurringAdviceCd><CAVVRespCode></CAVVRespCode><StatusMsg>Do Not Honor</StatusMsg><RespMsg>AUTH DECLINED 12001</RespMsg><HostRespCode>05</HostRespCode><HostAVSRespCode>N</HostAVSRespCode><HostCVV2RespCode>N</HostCVV2RespCode><CustomerRefNum></CustomerRefNum><CustomerName></CustomerName><ProfileProcStatus></ProfileProcStatus><CustomerProfileMessage></CustomerProfileMessage><RespTime>150214</RespTime></NewOrderResp></Response>' end def successful_profile_response - %q{<?xml version="1.0" encoding="UTF-8"?><Response><ProfileResp><CustomerBin>000001</CustomerBin><CustomerMerchantID>700000000000</CustomerMerchantID><CustomerName>Longbob Longsen</CustomerName><CustomerRefNum>ABC</CustomerRefNum><CustomerProfileAction>CREATE</CustomerProfileAction><ProfileProcStatus>0</ProfileProcStatus><CustomerProfileMessage>Profile Request Processed</CustomerProfileMessage><CustomerAccountType>CC</CustomerAccountType><Status>A</Status><CCAccountNum>4111111111111111</CCAccountNum><RespTime/></ProfileResp></Response>} + '<?xml version="1.0" encoding="UTF-8"?><Response><ProfileResp><CustomerBin>000001</CustomerBin><CustomerMerchantID>700000000000</CustomerMerchantID><CustomerName>Longbob Longsen</CustomerName><CustomerRefNum>ABC</CustomerRefNum><CustomerProfileAction>CREATE</CustomerProfileAction><ProfileProcStatus>0</ProfileProcStatus><CustomerProfileMessage>Profile Request Processed</CustomerProfileMessage><CustomerAccountType>CC</CustomerAccountType><Status>A</Status><CCAccountNum>4111111111111111</CCAccountNum><RespTime/></ProfileResp></Response>' end def successful_void_response - %q{<?xml version="1.0" encoding="UTF-8"?><Response><ReversalResp><MerchantID>700000208761</MerchantID><TerminalID>001</TerminalID><OrderID>2</OrderID><TxRefNum>50FB1C41FEC9D016FF0BEBAD0884B174AD0853B0</TxRefNum><TxRefIdx>1</TxRefIdx><OutstandingAmt>0</OutstandingAmt><ProcStatus>0</ProcStatus><StatusMsg></StatusMsg><RespTime>01192013172049</RespTime></ReversalResp></Response>} + '<?xml version="1.0" encoding="UTF-8"?><Response><ReversalResp><MerchantID>700000208761</MerchantID><TerminalID>001</TerminalID><OrderID>2</OrderID><TxRefNum>50FB1C41FEC9D016FF0BEBAD0884B174AD0853B0</TxRefNum><TxRefIdx>1</TxRefIdx><OutstandingAmt>0</OutstandingAmt><ProcStatus>0</ProcStatus><StatusMsg></StatusMsg><RespTime>01192013172049</RespTime></ReversalResp></Response>' end def pre_scrubbed @@ -705,7 +787,7 @@ def pre_scrubbed opened starting SSL for orbitalvar1.paymentech.net:443... SSL established -<- "POST /authorize HTTP/1.1\r\nContent-Type: application/PTI56\r\nMime-Version: 1.1\r\nContent-Transfer-Encoding: text\r\nRequest-Number: 1\r\nDocument-Type: Request\r\nInterface-Version: Ruby|ActiveMerchant|Proprietary Gateway\r\nContent-Length: 964\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nAccept: */*\r\nUser-Agent: Ruby\r\nConnection: close\r\nHost: orbitalvar1.paymentech.net\r\n\r\n" +<- "POST /authorize HTTP/1.1\r\nContent-Type: application/PTI71\r\nMime-Version: 1.1\r\nContent-Transfer-Encoding: text\r\nRequest-Number: 1\r\nDocument-Type: Request\r\nInterface-Version: Ruby|ActiveMerchant|Proprietary Gateway\r\nContent-Length: 964\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nAccept: */*\r\nUser-Agent: Ruby\r\nConnection: close\r\nHost: orbitalvar1.paymentech.net\r\n\r\n" <- "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Request>\n <NewOrder>\n <OrbitalConnectionUsername>T16WAYSACT</OrbitalConnectionUsername>\n <OrbitalConnectionPassword>zbp8X1ykGZ</OrbitalConnectionPassword>\n <IndustryType>EC</IndustryType>\n <MessageType>AC</MessageType>\n <BIN>000001</BIN>\n <MerchantID>041756</MerchantID>\n <TerminalID>001</TerminalID>\n <AccountNum>4112344112344113</AccountNum>\n <Exp>0917</Exp>\n <CurrencyCode>840</CurrencyCode>\n <CurrencyExponent>2</CurrencyExponent>\n <CardSecValInd>1</CardSecValInd>\n <CardSecVal>123</CardSecVal>\n <AVSzip>K1C2N6</AVSzip>\n <AVSaddress1>456 My Street</AVSaddress1>\n <AVSaddress2>Apt 1</AVSaddress2>\n <AVScity>Ottawa</AVScity>\n <AVSstate>ON</AVSstate>\n <AVSphoneNum>5555555555</AVSphoneNum>\n <AVSname>Longbob Longsen</AVSname>\n <AVScountryCode>CA</AVScountryCode>\n <OrderID>b141cf3ce2a442732e1906</OrderID>\n <Amount>100</Amount>\n </NewOrder>\n</Request>\n" -> "HTTP/1.1 200 OK\r\n" -> "Date: Thu, 02 Jun 2016 07:04:44 GMT\r\n" @@ -729,7 +811,7 @@ def post_scrubbed opened starting SSL for orbitalvar1.paymentech.net:443... SSL established -<- "POST /authorize HTTP/1.1\r\nContent-Type: application/PTI56\r\nMime-Version: 1.1\r\nContent-Transfer-Encoding: text\r\nRequest-Number: 1\r\nDocument-Type: Request\r\nInterface-Version: Ruby|ActiveMerchant|Proprietary Gateway\r\nContent-Length: 964\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nAccept: */*\r\nUser-Agent: Ruby\r\nConnection: close\r\nHost: orbitalvar1.paymentech.net\r\n\r\n" +<- "POST /authorize HTTP/1.1\r\nContent-Type: application/PTI71\r\nMime-Version: 1.1\r\nContent-Transfer-Encoding: text\r\nRequest-Number: 1\r\nDocument-Type: Request\r\nInterface-Version: Ruby|ActiveMerchant|Proprietary Gateway\r\nContent-Length: 964\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nAccept: */*\r\nUser-Agent: Ruby\r\nConnection: close\r\nHost: orbitalvar1.paymentech.net\r\n\r\n" <- "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Request>\n <NewOrder>\n <OrbitalConnectionUsername>[FILTERED]</OrbitalConnectionUsername>\n <OrbitalConnectionPassword>[FILTERED]</OrbitalConnectionPassword>\n <IndustryType>EC</IndustryType>\n <MessageType>AC</MessageType>\n <BIN>000001</BIN>\n <MerchantID>[FILTERED]</MerchantID>\n <TerminalID>001</TerminalID>\n <AccountNum>[FILTERED]</AccountNum>\n <Exp>0917</Exp>\n <CurrencyCode>840</CurrencyCode>\n <CurrencyExponent>2</CurrencyExponent>\n <CardSecValInd>1</CardSecValInd>\n <CardSecVal>[FILTERED]</CardSecVal>\n <AVSzip>K1C2N6</AVSzip>\n <AVSaddress1>456 My Street</AVSaddress1>\n <AVSaddress2>Apt 1</AVSaddress2>\n <AVScity>Ottawa</AVScity>\n <AVSstate>ON</AVSstate>\n <AVSphoneNum>5555555555</AVSphoneNum>\n <AVSname>Longbob Longsen</AVSname>\n <AVScountryCode>CA</AVScountryCode>\n <OrderID>b141cf3ce2a442732e1906</OrderID>\n <Amount>100</Amount>\n </NewOrder>\n</Request>\n" -> "HTTP/1.1 200 OK\r\n" -> "Date: Thu, 02 Jun 2016 07:04:44 GMT\r\n" @@ -746,4 +828,16 @@ def post_scrubbed Conn close EOS end + + def pre_scrubbed_profile + <<-EOS +<?xml version="1.0" encoding="UTF-8"?><Response><ProfileResp><CustomerBin>000001</CustomerBin><CustomerMerchantID>253997</CustomerMerchantID><CustomerName>LONGBOB LONGSEN</CustomerName><CustomerRefNum>109273631</CustomerRefNum><CustomerProfileAction>CREATE</CustomerProfileAction><ProfileProcStatus>0</ProfileProcStatus><CustomerProfileMessage>Profile Request Processed</CustomerProfileMessage><CustomerAddress1>456 MY STREET</CustomerAddress1><CustomerAddress2>APT 1</CustomerAddress2><CustomerCity>OTTAWA</CustomerCity><CustomerState>ON</CustomerState><CustomerZIP>K1C2N6</CustomerZIP><CustomerEmail></CustomerEmail><CustomerPhone>5555555555</CustomerPhone><CustomerCountryCode>CA</CustomerCountryCode><CustomerProfileOrderOverrideInd>NO</CustomerProfileOrderOverrideInd><OrderDefaultDescription></OrderDefaultDescription><OrderDefaultAmount></OrderDefaultAmount><CustomerAccountType>CC</CustomerAccountType><Status>A</Status><CCAccountNum>4112344112344113</CCAccountNum><CCExpireDate>0919</CCExpireDate><ECPAccountDDA></ECPAccountDDA><ECPAccountType></ECPAccountType><ECPAccountRT></ECPAccountRT><ECPBankPmtDlv></ECPBankPmtDlv><SwitchSoloStartDate></SwitchSoloStartDate><SwitchSoloIssueNum></SwitchSoloIssueNum><RespTime></RespTime></ProfileResp></Response> + EOS + end + + def post_scrubbed_profile + <<-EOS +<?xml version="1.0" encoding="UTF-8"?><Response><ProfileResp><CustomerBin>000001</CustomerBin><CustomerMerchantID>[FILTERED]</CustomerMerchantID><CustomerName>LONGBOB LONGSEN</CustomerName><CustomerRefNum>109273631</CustomerRefNum><CustomerProfileAction>CREATE</CustomerProfileAction><ProfileProcStatus>0</ProfileProcStatus><CustomerProfileMessage>Profile Request Processed</CustomerProfileMessage><CustomerAddress1>456 MY STREET</CustomerAddress1><CustomerAddress2>APT 1</CustomerAddress2><CustomerCity>OTTAWA</CustomerCity><CustomerState>ON</CustomerState><CustomerZIP>K1C2N6</CustomerZIP><CustomerEmail></CustomerEmail><CustomerPhone>5555555555</CustomerPhone><CustomerCountryCode>CA</CustomerCountryCode><CustomerProfileOrderOverrideInd>NO</CustomerProfileOrderOverrideInd><OrderDefaultDescription></OrderDefaultDescription><OrderDefaultAmount></OrderDefaultAmount><CustomerAccountType>CC</CustomerAccountType><Status>A</Status><CCAccountNum>[FILTERED]</CCAccountNum><CCExpireDate>0919</CCExpireDate><ECPAccountDDA></ECPAccountDDA><ECPAccountType></ECPAccountType><ECPAccountRT></ECPAccountRT><ECPBankPmtDlv></ECPBankPmtDlv><SwitchSoloStartDate></SwitchSoloStartDate><SwitchSoloIssueNum></SwitchSoloIssueNum><RespTime></RespTime></ProfileResp></Response> + EOS + end end diff --git a/test/unit/gateways/pac_net_raven_test.rb b/test/unit/gateways/pac_net_raven_test.rb index a3fd01cbab3..79530834e28 100644 --- a/test/unit/gateways/pac_net_raven_test.rb +++ b/test/unit/gateways/pac_net_raven_test.rb @@ -30,14 +30,14 @@ def test_invalid_credit_card_authorization @gateway.expects(:ssl_post).returns(invalid_credit_card_response) assert response = @gateway.authorize(@amount, @credit_card, @options) assert_failure response - assert_equal "Error processing transaction because CardNumber is not between 12 and 19 in length", response.message + assert_equal 'Error processing transaction because CardNumber is not between 12 and 19 in length', response.message end def test_expired_credit_card_authorization @gateway.expects(:ssl_post).returns(expired_credit_card_response) assert response = @gateway.authorize(@amount, @credit_card, @options) assert_failure response - assert_equal "Invalid because the card expiry date is not a date in the future", response.message + assert_equal 'Invalid because the card expiry date is not a date in the future', response.message end def test_declined_authorization @@ -87,14 +87,14 @@ def test_invalid_credit_card_number_purchese @gateway.expects(:ssl_post).returns(invalid_credit_card_response) assert response = @gateway.purchase(@amount, @credit_card, @options) assert_failure response - assert_equal "Error processing transaction because CardNumber is not between 12 and 19 in length", response.message + assert_equal 'Error processing transaction because CardNumber is not between 12 and 19 in length', response.message end def test_expired_credit_card_purchese @gateway.expects(:ssl_post).returns(expired_credit_card_response) assert response = @gateway.purchase(@amount, @credit_card, @options) assert_failure response - assert_equal "Invalid because the card expiry date is not a date in the future", response.message + assert_equal 'Invalid because the card expiry date is not a date in the future', response.message end def test_declined_purchese @@ -146,32 +146,32 @@ def test_successful_void @gateway.expects(:ssl_post).returns(successful_void_response) assert response = @gateway.void('123456789') assert_success response - assert_equal "This transaction has been voided", response.message + assert_equal 'This transaction has been voided', response.message end def test_failed_void @gateway.expects(:ssl_post).returns(failed_void_response) assert response = @gateway.void('123456789') assert_failure response - assert_equal "Error processing transaction because the payment may not be voided", response.message + assert_equal 'Error processing transaction because the payment may not be voided', response.message end def test_argument_error_prn - exception = assert_raises(ArgumentError){ + exception = assert_raises(ArgumentError) { PacNetRavenGateway.new(:user => 'user', :secret => 'secret') } assert_equal 'Missing required parameter: prn', exception.message end def test_argument_error_user - exception = assert_raises(ArgumentError){ + exception = assert_raises(ArgumentError) { PacNetRavenGateway.new(:secret => 'secret', :prn => 123456) } assert_equal 'Missing required parameter: user', exception.message end def test_argument_error_secret - exception = assert_raises(ArgumentError){ + exception = assert_raises(ArgumentError) { PacNetRavenGateway.new(:user => 'user', :prn => 123456) } assert_equal 'Missing required parameter: secret', exception.message @@ -179,8 +179,8 @@ def test_argument_error_secret def test_add_address result = {} - @gateway.send(:add_address, result, :billing_address => {:address1 => 'Address 1', :address2 => 'Address 2', :zip => 'ZIP'} ) - assert_equal ["BillingPostalCode", "BillingStreetAddressLineFour", "BillingStreetAddressLineOne"], result.stringify_keys.keys.sort + @gateway.send(:add_address, result, :billing_address => {:address1 => 'Address 1', :address2 => 'Address 2', :zip => 'ZIP'}) + assert_equal ['BillingPostalCode', 'BillingStreetAddressLineFour', 'BillingStreetAddressLineOne'], result.stringify_keys.keys.sort assert_equal 'ZIP', result['BillingPostalCode'] assert_equal 'Address 2', result['BillingStreetAddressLineFour'] assert_equal 'Address 1', result['BillingStreetAddressLineOne'] @@ -189,7 +189,7 @@ def test_add_address def test_add_creditcard result = {} @gateway.send(:add_creditcard, result, @credit_card) - assert_equal ["CVV2", "CardNumber", "Expiry"], result.stringify_keys.keys.sort + assert_equal ['CVV2', 'CardNumber', 'Expiry'], result.stringify_keys.keys.sort assert_equal @credit_card.number, result['CardNumber'] assert_equal @gateway.send(:expdate, @credit_card), result['Expiry'] assert_equal @credit_card.verification_value, result['CVV2'] @@ -208,7 +208,7 @@ def test_add_currency_code_from_options end def test_parse - result = @gateway.send(:parse, "key1=value1&key2=value2") + result = @gateway.send(:parse, 'key1=value1&key2=value2') h = {'key1' => 'value1', 'key2' => 'value2'} assert_equal h, result end @@ -306,36 +306,36 @@ def test_success end def test_message_from_approved - assert_equal "This transaction has been approved", @gateway.send(:message_from, { + assert_equal 'This transaction has been approved', @gateway.send(:message_from, { 'Status' => 'Approved', 'Message'=> nil }) end def test_message_from_declined - assert_equal "This transaction has been declined", @gateway.send(:message_from, { + assert_equal 'This transaction has been declined', @gateway.send(:message_from, { 'Status' => 'Declined', 'Message'=> nil }) end def test_message_from_voided - assert_equal "This transaction has been voided", @gateway.send(:message_from, { + assert_equal 'This transaction has been voided', @gateway.send(:message_from, { 'Status' => 'Voided', 'Message'=> nil }) end def test_message_from_status - assert_equal "This is the message", @gateway.send(:message_from, { + assert_equal 'This is the message', @gateway.send(:message_from, { 'Status' => 'SomeStatus', - 'Message'=> "This is the message" + 'Message'=> 'This is the message' }) end def test_post_data - @gateway.stubs(:request_id => "wouykiikdvqbwwxueppby") - @gateway.stubs(:timestamp => "2013-10-08T14:31:54.Z") + @gateway.stubs(:request_id => 'wouykiikdvqbwwxueppby') + @gateway.stubs(:timestamp => '2013-10-08T14:31:54.Z') assert_equal "PymtType=cc_preauth&RAPIVersion=2&UserName=user&Timestamp=2013-10-08T14%3A31%3A54.Z&RequestID=wouykiikdvqbwwxueppby&Signature=7794efc8c0d39f0983edc10f778e6143ba13531d&CardNumber=4242424242424242&Expiry=09#{@credit_card.year.to_s[-2..-1]}&CVV2=123&Currency=USD&BillingStreetAddressLineOne=Address+1&BillingStreetAddressLineFour=Address+2&BillingPostalCode=ZIP123", @gateway.send(:post_data, 'cc_preauth', { @@ -416,7 +416,7 @@ def test_signature_for_void_action def test_expdate @credit_card.year = 2015 @credit_card.month = 9 - assert_equal "0915", @gateway.send(:expdate, @credit_card) + assert_equal '0915', @gateway.send(:expdate, @credit_card) end private diff --git a/test/unit/gateways/pagarme_test.rb b/test/unit/gateways/pagarme_test.rb index c874d7ccd37..3944a780cd2 100644 --- a/test/unit/gateways/pagarme_test.rb +++ b/test/unit/gateways/pagarme_test.rb @@ -31,14 +31,14 @@ def test_successful_purchase assert_success response assert_equal 427312, response.authorization - assert_equal @amount, response.params["amount"] + assert_equal @amount, response.params['amount'] - assert_equal @credit_card.name, response.params["card"]["holder_name"] - assert_equal @credit_card.last_digits, response.params["card"]["last_digits"] - assert_equal @credit_card.brand, response.params["card"]["brand"] + assert_equal @credit_card.name, response.params['card']['holder_name'] + assert_equal @credit_card.last_digits, response.params['card']['last_digits'] + assert_equal @credit_card.brand, response.params['card']['brand'] - assert_equal 'credit_card', response.params["payment_method"] - assert_equal 'paid', response.params["status"] + assert_equal 'credit_card', response.params['payment_method'] + assert_equal 'paid', response.params['status'] assert_equal 'Transação aprovada', response.message assert response.test? end @@ -50,7 +50,7 @@ def test_failed_purchase assert_failure response assert_equal Gateway::STANDARD_ERROR_CODE[:card_declined], response.error_code - assert_equal 'refused', response.params["status"] + assert_equal 'refused', response.params['status'] assert_equal 'Transação recusada', response.message end @@ -62,14 +62,14 @@ def test_successful_authorize assert_success response assert_equal 429356, response.authorization - assert_equal @amount, response.params["amount"] + assert_equal @amount, response.params['amount'] - assert_equal @credit_card.name, response.params["card"]["holder_name"] - assert_equal @credit_card.last_digits, response.params["card"]["last_digits"] - assert_equal @credit_card.brand, response.params["card"]["brand"] + assert_equal @credit_card.name, response.params['card']['holder_name'] + assert_equal @credit_card.last_digits, response.params['card']['last_digits'] + assert_equal @credit_card.brand, response.params['card']['brand'] - assert_equal 'credit_card', response.params["payment_method"] - assert_equal 'authorized', response.params["status"] + assert_equal 'credit_card', response.params['payment_method'] + assert_equal 'authorized', response.params['status'] assert_equal 'Transação autorizada', response.message assert response.test? end @@ -81,7 +81,7 @@ def test_failed_authorize assert_failure response assert_equal Gateway::STANDARD_ERROR_CODE[:card_declined], response.error_code - assert_equal 'refused', response.params["status"] + assert_equal 'refused', response.params['status'] assert_equal 'Transação recusada', response.message end @@ -93,14 +93,14 @@ def test_successful_capture assert_success response assert_equal 429356, response.authorization - assert_equal @amount, response.params["amount"] + assert_equal @amount, response.params['amount'] - assert_equal @credit_card.name, response.params["card"]["holder_name"] - assert_equal @credit_card.last_digits, response.params["card"]["last_digits"] - assert_equal @credit_card.brand, response.params["card"]["brand"] + assert_equal @credit_card.name, response.params['card']['holder_name'] + assert_equal @credit_card.last_digits, response.params['card']['last_digits'] + assert_equal @credit_card.brand, response.params['card']['brand'] - assert_equal 'credit_card', response.params["payment_method"] - assert_equal 'paid', response.params["status"] + assert_equal 'credit_card', response.params['payment_method'] + assert_equal 'paid', response.params['status'] assert_equal 'Transação aprovada', response.message assert response.test? end @@ -124,8 +124,8 @@ def test_successful_refund assert_equal 429356, response.authorization - assert_equal 'credit_card', response.params["payment_method"] - assert_equal 'refunded', response.params["status"] + assert_equal 'credit_card', response.params['payment_method'] + assert_equal 'refunded', response.params['status'] assert_equal 'Transação estornada', response.message assert response.test? end @@ -149,8 +149,8 @@ def test_successful_void assert_equal 472218, response.authorization - assert_equal 'credit_card', response.params["payment_method"] - assert_equal 'refunded', response.params["status"] + assert_equal 'credit_card', response.params['payment_method'] + assert_equal 'refunded', response.params['status'] assert_equal 'Transação estornada', response.message assert response.test? end @@ -166,7 +166,7 @@ def test_failed_void end def test_successful_verify - s = sequence("request") + s = sequence('request') @gateway.expects(:ssl_request).returns(successful_verify_response).in_sequence(s) @gateway.expects(:ssl_request).returns(successful_verify_void_response).in_sequence(s) @@ -174,25 +174,25 @@ def test_successful_verify assert_instance_of MultiResponse, response assert_success response - assert_equal 127, response.params["amount"] + assert_equal 127, response.params['amount'] - assert_equal @credit_card.name, response.params["card"]["holder_name"] - assert_equal @credit_card.last_digits, response.params["card"]["last_digits"] - assert_equal @credit_card.brand, response.params["card"]["brand"] + assert_equal @credit_card.name, response.params['card']['holder_name'] + assert_equal @credit_card.last_digits, response.params['card']['last_digits'] + assert_equal @credit_card.brand, response.params['card']['brand'] - assert_equal 'credit_card', response.params["payment_method"] - assert_equal 'authorized', response.params["status"] + assert_equal 'credit_card', response.params['payment_method'] + assert_equal 'authorized', response.params['status'] assert_equal 'Transação autorizada', response.message assert_success response.responses[1] - assert_equal 'refunded', response.responses[1].params["status"] + assert_equal 'refunded', response.responses[1].params['status'] assert_equal 'Transação estornada', response.responses[1].message assert response.test? end def test_successful_verify_with_failed_void - s = sequence("request") + s = sequence('request') @gateway.expects(:ssl_request).returns(successful_verify_response).in_sequence(s) @gateway.expects(:ssl_request).returns(failed_void_response).in_sequence(s) @@ -200,14 +200,14 @@ def test_successful_verify_with_failed_void assert_instance_of MultiResponse, response assert_success response - assert_equal 127, response.params["amount"] + assert_equal 127, response.params['amount'] - assert_equal @credit_card.name, response.params["card"]["holder_name"] - assert_equal @credit_card.last_digits, response.params["card"]["last_digits"] - assert_equal @credit_card.brand, response.params["card"]["brand"] + assert_equal @credit_card.name, response.params['card']['holder_name'] + assert_equal @credit_card.last_digits, response.params['card']['last_digits'] + assert_equal @credit_card.brand, response.params['card']['brand'] - assert_equal 'credit_card', response.params["payment_method"] - assert_equal 'authorized', response.params["status"] + assert_equal 'credit_card', response.params['payment_method'] + assert_equal 'authorized', response.params['status'] assert_equal 'Transação autorizada', response.message assert_failure response.responses[1] @@ -222,8 +222,8 @@ def test_failed_verify assert_failure response assert_equal Gateway::STANDARD_ERROR_CODE[:card_declined], response.error_code - assert_equal 127, response.params["amount"] - assert_equal 'refused', response.params["status"] + assert_equal 127, response.params['amount'] + assert_equal 'refused', response.params['status'] assert_equal 'Transação recusada', response.message end @@ -243,7 +243,7 @@ def test_failed_json_body assert_failure response assert_equal Gateway::STANDARD_ERROR_CODE[:processing_error], response.error_code - assert response.message.start_with?("Resposta inválida") + assert response.message.start_with?('Resposta inválida') end def test_scrub @@ -614,7 +614,7 @@ def successful_capture_response end def failed_capture_response - <<-FAILED_RESPONSE + <<-FAILED_RESPONSE { "errors": [ { @@ -630,7 +630,7 @@ def failed_capture_response end def successful_refund_response - <<-SUCCESS_RESPONSE + <<-SUCCESS_RESPONSE { "acquirer_name": "development", "acquirer_response_code": "00", @@ -688,7 +688,7 @@ def successful_refund_response end def failed_refund_response - <<-FAILED_RESPONSE + <<-FAILED_RESPONSE { "errors": [ { @@ -704,7 +704,7 @@ def failed_refund_response end def successful_void_response - <<-SUCCESS_RESPONSE + <<-SUCCESS_RESPONSE { "acquirer_name": "pagarme", "acquirer_response_code": "00", @@ -762,7 +762,7 @@ def successful_void_response end def failed_void_response - <<-FAILED_RESPONSE + <<-FAILED_RESPONSE { "errors": [ { @@ -778,7 +778,7 @@ def failed_void_response end def successful_verify_response - <<-SUCCESS_RESPONSE + <<-SUCCESS_RESPONSE { "acquirer_name": "pagarme", "acquirer_response_code": "00", @@ -836,7 +836,7 @@ def successful_verify_response end def successful_verify_void_response - <<-SUCCESS_RESPONSE + <<-SUCCESS_RESPONSE { "acquirer_name": "pagarme", "acquirer_response_code": "00", @@ -894,7 +894,7 @@ def successful_verify_void_response end def failed_verify_response - <<-FAILED_RESPONSE + <<-FAILED_RESPONSE { "acquirer_name": "pagarme", "acquirer_response_code": "88", @@ -968,7 +968,7 @@ def failed_error_response end def failed_json_response - <<-SUCCESS_RESPONSE + <<-SUCCESS_RESPONSE { foo: bar } diff --git a/test/unit/gateways/pago_facil_test.rb b/test/unit/gateways/pago_facil_test.rb index 539a8434717..cb75a847402 100644 --- a/test/unit/gateways/pago_facil_test.rb +++ b/test/unit/gateways/pago_facil_test.rb @@ -36,8 +36,8 @@ def test_successful_purchase response = @gateway.purchase(@amount, @credit_card, @options) assert_success response - assert_equal "305638", response.authorization - assert_equal "Transaction has been successful!-Approved", response.message + assert_equal '305638', response.authorization + assert_equal 'Transaction has been successful!-Approved', response.message assert response.test? end @@ -46,8 +46,8 @@ def test_successful_purchase_amex response = @gateway.purchase(@amount, @credit_card, @options) assert_success response - assert_equal "305638", response.authorization - assert_equal "Transaction has been successful!-Approved", response.message + assert_equal '305638', response.authorization + assert_equal 'Transaction has been successful!-Approved', response.message assert response.test? end @@ -70,156 +70,156 @@ def test_invalid_json private def successful_purchase_response - {"WebServices_Transacciones"=> - {"transaccion"=> - {"autorizado"=>"1", - "autorizacion"=>"305638", - "transaccion"=>"S-PFE12S12I12568", - "texto"=>"Transaction has been successful!-Approved", - "mode"=>"R", - "empresa"=>"Usuario Invitado", - "TransIni"=>"15:33:18 pm 25/02/2014", - "TransFin"=>"15:33:27 pm 25/02/2014", - "param1"=>"", - "param2"=>"", - "param3"=>"", - "param4"=>"", - "param5"=>"", - "TipoTC"=>"Visa", - "data"=> - {"anyoExpiracion"=>"(2) **", - "apellidos"=>"Reyes Garza", - "calleyNumero"=>"Anatole France 311", - "celular"=>"5550123456", - "colonia"=>"Polanco", - "cp"=>"11560", - "cvt"=>"(3) ***", - "email"=>"comprador@correo.com", - "estado"=>"Distrito Federal", - "idPedido"=>"1", - "idServicio"=>"3", - "idSucursal"=>"60f961360ca187d533d5adba7d969d6334771370", - "idUsuario"=>"62ad6f592ecf2faa87ef2437ed85a4d175e73c58", - "mesExpiracion"=>"(2) **", - "monto"=>"1.00", - "municipio"=>"Miguel Hidalgo", - "nombre"=>"Juan", - "numeroTarjeta"=>"(16) **** **** ****1111", - "pais"=>"Mexico", - "telefono"=>"5550220910", - "transFechaHora"=>"1393363998", - "bin"=>"(6) ***1"}, - "dataVal"=> - {"idSucursal"=>"12", - "cp"=>"11560", - "nombre"=>"Juan", - "apellidos"=>"Reyes Garza", - "numeroTarjeta"=>"(16) **** **** ****1111", - "cvt"=>"(3) ***", - "monto"=>"1.00", - "mesExpiracion"=>"(2) **", - "anyoExpiracion"=>"(2) **", - "idUsuario"=>"14", - "source"=>"1", - "idServicio"=>"3", - "recurrente"=>"0", - "plan"=>"NOR", - "diferenciado"=>"00", - "mensualidades"=>"00", - "ip"=>"187.162.238.170", - "httpUserAgent"=>"Ruby", - "idPedido"=>"1", - "tipoTarjeta"=>"Visa", - "hashKeyCC"=>"e5be0afe08f125ec4f6f1251141c60df88d65eae", - "idEmpresa"=>"12", - "nombre_comercial"=>"Usuario Invitado", - "transFechaHora"=>"1393363998", - "noProcess"=>"", - "noMail"=>"", - "notaMail"=>"", - "settingsTransaction"=> - {"noMontoMes"=>"0.00", - "noTransaccionesDia"=>"0", - "minTransaccionTc"=>"5", - "tiempoDevolucion"=>"30", - "sendPdfTransCliente"=>"1", - "noMontoDia"=>"0.00", - "noTransaccionesMes"=>"0"}, - "email"=>"comprador@correo.com", - "telefono"=>"5550220910", - "celular"=>"5550123456", - "calleyNumero"=>"Anatole France 311", - "colonia"=>"Polanco", - "municipio"=>"Miguel Hidalgo", - "estado"=>"Distrito Federal", - "pais"=>"Mexico", - "idCaja"=>"", - "paisDetectedIP"=>"MX", - "qa"=>"1", - "https"=>"on"}, - "status"=>"success" + {'WebServices_Transacciones'=> + {'transaccion'=> + {'autorizado'=>'1', + 'autorizacion'=>'305638', + 'transaccion'=>'S-PFE12S12I12568', + 'texto'=>'Transaction has been successful!-Approved', + 'mode'=>'R', + 'empresa'=>'Usuario Invitado', + 'TransIni'=>'15:33:18 pm 25/02/2014', + 'TransFin'=>'15:33:27 pm 25/02/2014', + 'param1'=>'', + 'param2'=>'', + 'param3'=>'', + 'param4'=>'', + 'param5'=>'', + 'TipoTC'=>'Visa', + 'data'=> + {'anyoExpiracion'=>'(2) **', + 'apellidos'=>'Reyes Garza', + 'calleyNumero'=>'Anatole France 311', + 'celular'=>'5550123456', + 'colonia'=>'Polanco', + 'cp'=>'11560', + 'cvt'=>'(3) ***', + 'email'=>'comprador@correo.com', + 'estado'=>'Distrito Federal', + 'idPedido'=>'1', + 'idServicio'=>'3', + 'idSucursal'=>'60f961360ca187d533d5adba7d969d6334771370', + 'idUsuario'=>'62ad6f592ecf2faa87ef2437ed85a4d175e73c58', + 'mesExpiracion'=>'(2) **', + 'monto'=>'1.00', + 'municipio'=>'Miguel Hidalgo', + 'nombre'=>'Juan', + 'numeroTarjeta'=>'(16) **** **** ****1111', + 'pais'=>'Mexico', + 'telefono'=>'5550220910', + 'transFechaHora'=>'1393363998', + 'bin'=>'(6) ***1'}, + 'dataVal'=> + {'idSucursal'=>'12', + 'cp'=>'11560', + 'nombre'=>'Juan', + 'apellidos'=>'Reyes Garza', + 'numeroTarjeta'=>'(16) **** **** ****1111', + 'cvt'=>'(3) ***', + 'monto'=>'1.00', + 'mesExpiracion'=>'(2) **', + 'anyoExpiracion'=>'(2) **', + 'idUsuario'=>'14', + 'source'=>'1', + 'idServicio'=>'3', + 'recurrente'=>'0', + 'plan'=>'NOR', + 'diferenciado'=>'00', + 'mensualidades'=>'00', + 'ip'=>'187.162.238.170', + 'httpUserAgent'=>'Ruby', + 'idPedido'=>'1', + 'tipoTarjeta'=>'Visa', + 'hashKeyCC'=>'e5be0afe08f125ec4f6f1251141c60df88d65eae', + 'idEmpresa'=>'12', + 'nombre_comercial'=>'Usuario Invitado', + 'transFechaHora'=>'1393363998', + 'noProcess'=>'', + 'noMail'=>'', + 'notaMail'=>'', + 'settingsTransaction'=> + {'noMontoMes'=>'0.00', + 'noTransaccionesDia'=>'0', + 'minTransaccionTc'=>'5', + 'tiempoDevolucion'=>'30', + 'sendPdfTransCliente'=>'1', + 'noMontoDia'=>'0.00', + 'noTransaccionesMes'=>'0'}, + 'email'=>'comprador@correo.com', + 'telefono'=>'5550220910', + 'celular'=>'5550123456', + 'calleyNumero'=>'Anatole France 311', + 'colonia'=>'Polanco', + 'municipio'=>'Miguel Hidalgo', + 'estado'=>'Distrito Federal', + 'pais'=>'Mexico', + 'idCaja'=>'', + 'paisDetectedIP'=>'MX', + 'qa'=>'1', + 'https'=>'on'}, + 'status'=>'success' } } }.to_json end def failed_purchase_response - {"WebServices_Transacciones"=> - {"transaccion"=> - {"autorizado"=>"0", - "transaccion"=>"n/a", - "autorizacion"=>"n/a", - "texto"=>"Errores en los datos de entrada Validaciones", - "error"=> - {"numeroTarjeta"=>"'1111111111111111' no es de una institucion permitida"}, - "empresa"=>"Sin determinar", - "TransIni"=>"16:10:20 pm 25/02/2014", - "TransFin"=>"16:10:20 pm 25/02/2014", - "param1"=>"", - "param2"=>"", - "param3"=>"", - "param4"=>"", - "param5"=>"", - "TipoTC"=>"", - "data"=> - {"anyoExpiracion"=>"(2) **", - "apellidos"=>"Reyes Garza", - "calleyNumero"=>"Anatole France 311", - "celular"=>"5550123456", - "colonia"=>"Polanco", - "cp"=>"11560", - "cvt"=>"(3) ***", - "email"=>"comprador@correo.com", - "estado"=>"Distrito Federal", - "idPedido"=>"1", - "idServicio"=>"3", - "idSucursal"=>"60f961360ca187d533d5adba7d969d6334771370", - "idUsuario"=>"62ad6f592ecf2faa87ef2437ed85a4d175e73c58", - "mesExpiracion"=>"(2) **", - "monto"=>"1.00", - "municipio"=>"Miguel Hidalgo", - "nombre"=>"Juan", - "numeroTarjeta"=>"(16) **** **** ****1111", - "pais"=>"Mexico", - "telefono"=>"5550220910", - "transFechaHora"=>"1393366220", - "bin"=>"(6) ***1"}, - "dataVal"=> - {"email"=>"comprador@correo.com", - "telefono"=>"5550220910", - "celular"=>"5550123456", - "calleyNumero"=>"Anatole France 311", - "colonia"=>"Polanco", - "municipio"=>"Miguel Hidalgo", - "estado"=>"Distrito Federal", - "pais"=>"Mexico", - "idCaja"=>"", - "numeroTarjeta"=>"", - "cvt"=>"", - "anyoExpiracion"=>"", - "mesExpiracion"=>"", - "https"=>"on"}, - "status"=>"success" + {'WebServices_Transacciones'=> + {'transaccion'=> + {'autorizado'=>'0', + 'transaccion'=>'n/a', + 'autorizacion'=>'n/a', + 'texto'=>'Errores en los datos de entrada Validaciones', + 'error'=> + {'numeroTarjeta'=>"'1111111111111111' no es de una institucion permitida"}, + 'empresa'=>'Sin determinar', + 'TransIni'=>'16:10:20 pm 25/02/2014', + 'TransFin'=>'16:10:20 pm 25/02/2014', + 'param1'=>'', + 'param2'=>'', + 'param3'=>'', + 'param4'=>'', + 'param5'=>'', + 'TipoTC'=>'', + 'data'=> + {'anyoExpiracion'=>'(2) **', + 'apellidos'=>'Reyes Garza', + 'calleyNumero'=>'Anatole France 311', + 'celular'=>'5550123456', + 'colonia'=>'Polanco', + 'cp'=>'11560', + 'cvt'=>'(3) ***', + 'email'=>'comprador@correo.com', + 'estado'=>'Distrito Federal', + 'idPedido'=>'1', + 'idServicio'=>'3', + 'idSucursal'=>'60f961360ca187d533d5adba7d969d6334771370', + 'idUsuario'=>'62ad6f592ecf2faa87ef2437ed85a4d175e73c58', + 'mesExpiracion'=>'(2) **', + 'monto'=>'1.00', + 'municipio'=>'Miguel Hidalgo', + 'nombre'=>'Juan', + 'numeroTarjeta'=>'(16) **** **** ****1111', + 'pais'=>'Mexico', + 'telefono'=>'5550220910', + 'transFechaHora'=>'1393366220', + 'bin'=>'(6) ***1'}, + 'dataVal'=> + {'email'=>'comprador@correo.com', + 'telefono'=>'5550220910', + 'celular'=>'5550123456', + 'calleyNumero'=>'Anatole France 311', + 'colonia'=>'Polanco', + 'municipio'=>'Miguel Hidalgo', + 'estado'=>'Distrito Federal', + 'pais'=>'Mexico', + 'idCaja'=>'', + 'numeroTarjeta'=>'', + 'cvt'=>'', + 'anyoExpiracion'=>'', + 'mesExpiracion'=>'', + 'https'=>'on'}, + 'status'=>'success' } } }.to_json @@ -232,8 +232,8 @@ def invalid_json_response def successful_purchase_response_amex response = JSON.parse(successful_purchase_response) response. - fetch("WebServices_Transacciones"). - fetch("transaccion")["autorizado"] = true + fetch('WebServices_Transacciones'). + fetch('transaccion')['autorizado'] = true response.to_json end end diff --git a/test/unit/gateways/pay_conex_test.rb b/test/unit/gateways/pay_conex_test.rb index fd4a43b6648..0269f29396d 100644 --- a/test/unit/gateways/pay_conex_test.rb +++ b/test/unit/gateways/pay_conex_test.rb @@ -21,7 +21,7 @@ def test_successful_purchase @gateway.expects(:ssl_post).returns(successful_purchase_response) response = @gateway.purchase(@amount, @credit_card, @options) assert_success response - assert_equal "000000001681", response.authorization + assert_equal '000000001681', response.authorization assert response.test? end @@ -30,19 +30,19 @@ def test_failed_purchase response = @gateway.purchase(@amount, @credit_card, @options) assert_failure response - assert_equal 30002, response.params["error_code"] + assert_equal 30002, response.params['error_code'] end def test_successful_authorize_and_capture @gateway.expects(:ssl_post).returns(successful_authorize_response) response = @gateway.authorize(@amount, @credit_card, @options) assert_success response - assert_equal "000000001721", response.authorization + assert_equal '000000001721', response.authorization @gateway.expects(:ssl_post).returns(successful_capture_response) response = @gateway.capture(@amount, response.authorization) assert_success response - assert_equal "CAPTURED", response.message + assert_equal 'CAPTURED', response.message end def test_failed_authorize @@ -50,66 +50,66 @@ def test_failed_authorize response = @gateway.authorize(@amount, @credit_card, @options) assert_failure response - assert_equal 30002, response.params["error_code"] - assert_equal "DECLINED", response.message + assert_equal 30002, response.params['error_code'] + assert_equal 'DECLINED', response.message end def test_failed_capture @gateway.expects(:ssl_post).returns(failed_capture_response) - response = @gateway.capture(@amount, "Authorization") + response = @gateway.capture(@amount, 'Authorization') assert_failure response - assert_equal 20006, response.params["error_code"] - assert_equal "Invalid token_id", response.message + assert_equal 20006, response.params['error_code'] + assert_equal 'Invalid token_id', response.message end def test_successful_refund @gateway.expects(:ssl_post).returns(successful_refund_response) - response = @gateway.refund(@amount, "Authorization") + response = @gateway.refund(@amount, 'Authorization') assert_success response - assert_equal "000000001801", response.authorization - assert_equal "VOID", response.message + assert_equal '000000001801', response.authorization + assert_equal 'VOID', response.message end def test_failed_refund @gateway.expects(:ssl_post).returns(failed_refund_response) - response = @gateway.refund(@amount, "Authorization") + response = @gateway.refund(@amount, 'Authorization') assert_failure response - assert_equal 20017, response.params["error_code"] - assert_equal "INVALID REFUND AMOUNT", response.message + assert_equal 20017, response.params['error_code'] + assert_equal 'INVALID REFUND AMOUNT', response.message end def test_successful_void @gateway.expects(:ssl_post).returns(successful_void_response) - response = @gateway.void("Authorization") + response = @gateway.void('Authorization') assert_success response - assert_equal "000000001881", response.authorization - assert_equal "APPROVED", response.message + assert_equal '000000001881', response.authorization + assert_equal 'APPROVED', response.message end def test_failed_void @gateway.expects(:ssl_post).returns(failed_void_response) - response = @gateway.refund(@amount, "Authorization") + response = @gateway.refund(@amount, 'Authorization') assert_failure response - assert_equal 20687, response.params["error_code"] - assert_equal "TRANSACTION ID ALREADY REVERSED", response.message + assert_equal 20687, response.params['error_code'] + assert_equal 'TRANSACTION ID ALREADY REVERSED', response.message end def test_successful_verify @gateway.expects(:ssl_post).returns(successful_verify_response) response = @gateway.verify(@credit_card) assert_success response - assert_equal "000000001981", response.authorization - assert_equal "APPROVED", response.message + assert_equal '000000001981', response.authorization + assert_equal 'APPROVED', response.message end def test_successful_credit @gateway.expects(:ssl_post).returns(successful_credit_response) response = @gateway.credit(@amount, @credit_card) assert_success response - assert_equal "000000002061", response.authorization + assert_equal '000000002061', response.authorization end def test_failed_credit @@ -117,15 +117,15 @@ def test_failed_credit response = @gateway.authorize(@amount, @credit_card) assert_failure response - assert_equal "30370", response.params["error_code"] - assert_equal "CARD DATA UNREADABLE", response.message + assert_equal '30370', response.params['error_code'] + assert_equal 'CARD DATA UNREADABLE', response.message end def test_successful_store @gateway.expects(:ssl_post).returns(successful_store_response) response = @gateway.store(@credit_card) assert_success response - assert_equal "000000002101", response.authorization + assert_equal '000000002101', response.authorization end def test_failed_store @@ -133,8 +133,8 @@ def test_failed_store response = @gateway.store(@credit_card) assert_failure response - assert_equal "30370", response.params["error_code"] - assert_equal "CARD DATA UNREADABLE", response.message + assert_equal '30370', response.params['error_code'] + assert_equal 'CARD DATA UNREADABLE', response.message end def test_card_present_purchase_passes_track_data @@ -147,23 +147,23 @@ def test_card_present_purchase_passes_track_data def test_successful_purchase_using_token @gateway.expects(:ssl_post).returns(successful_purchase_using_token_response) - response = @gateway.purchase(@amount, "TheToken", @options) + response = @gateway.purchase(@amount, 'TheToken', @options) assert_success response - assert_equal "000000004561", response.authorization + assert_equal '000000004561', response.authorization end def test_successful_purchase_using_echeck @gateway.expects(:ssl_post).returns(successful_purchase_using_echeck_response) response = @gateway.purchase(@amount, check, @options) assert_success response - assert_equal "000000007161", response.authorization + assert_equal '000000007161', response.authorization end def test_failed_purchase_using_echeck @gateway.expects(:ssl_post).returns(failed_purchase_using_echeck_response) response = @gateway.purchase(@amount, check, @options) assert_failure response - assert_equal "Invalid bank_routing_number", response.message + assert_equal 'Invalid bank_routing_number', response.message end def test_scrub diff --git a/test/unit/gateways/pay_gate_xml_test.rb b/test/unit/gateways/pay_gate_xml_test.rb index c8ee14c5e70..157cd2bd89b 100644 --- a/test/unit/gateways/pay_gate_xml_test.rb +++ b/test/unit/gateways/pay_gate_xml_test.rb @@ -30,7 +30,6 @@ def test_successful_authorization assert response.test? end - def test_successful_settlement @gateway.expects(:ssl_post).returns(successful_settlement_response) @@ -103,5 +102,4 @@ def successful_refund_response ENDOFXML end - end diff --git a/test/unit/gateways/pay_hub_test.rb b/test/unit/gateways/pay_hub_test.rb index 1666bce5bf5..0226cea3ec0 100644 --- a/test/unit/gateways/pay_hub_test.rb +++ b/test/unit/gateways/pay_hub_test.rb @@ -3,9 +3,9 @@ class PayHubTest < Test::Unit::TestCase def setup @gateway = PayHubGateway.new( - orgid: "123456", - username: "abc123DEF", - password: "abc123DEF", + orgid: '123456', + username: 'abc123DEF', + password: 'abc123DEF', tid: '123' ) @credit_card = credit_card @@ -31,7 +31,7 @@ def test_successful_purchase response = @gateway.purchase(@amount, @credit_card, @options) assert_success response assert response.test? - assert_equal "SUCCESS", response.message + assert_equal 'SUCCESS', response.message end def test_successful_purchase_without_options @@ -39,7 +39,7 @@ def test_successful_purchase_without_options response = @gateway.purchase(@amount, @credit_card) assert_success response - assert_equal "SUCCESS", response.message + assert_equal 'SUCCESS', response.message end def test_successful_authorize @@ -47,7 +47,7 @@ def test_successful_authorize response = @gateway.authorize(@amount, @credit_card, @options) assert_success response - assert_equal "SUCCESS", response.message + assert_equal 'SUCCESS', response.message end def test_successful_capture @@ -56,7 +56,7 @@ def test_successful_capture response = @gateway.capture(@amount, 123) assert_success response - assert_equal "TRANSACTION CAPTURED SUCCESSFULLY", response.message + assert_equal 'TRANSACTION CAPTURED SUCCESSFULLY', response.message end def test_unsuccessful_capture @@ -65,7 +65,7 @@ def test_unsuccessful_capture response = @gateway.capture(amount, 123) assert_failure response - assert_equal "UNABLE TO CAPTURE", response.message + assert_equal 'UNABLE TO CAPTURE', response.message end def test_successful_settled_refund @@ -74,7 +74,7 @@ def test_successful_settled_refund response = @gateway.refund(@amount, 123) assert_success response - assert_equal "SUCCESS", response.message + assert_equal 'SUCCESS', response.message end def test_successful_unsettled_refund @@ -83,7 +83,7 @@ def test_successful_unsettled_refund response = @gateway.refund(@amount, 123) assert_success response - assert_equal "SUCCESS", response.message + assert_equal 'SUCCESS', response.message end def test_unsuccessful_refund @@ -92,7 +92,7 @@ def test_unsuccessful_refund assert response = @gateway.refund(@amount, 123) assert_failure response - assert_equal "Unable to refund the previous transaction.", response.message + assert_equal 'Unable to refund the previous transaction.', response.message end def test_invalid_raw_response diff --git a/test/unit/gateways/pay_junction_test.rb b/test/unit/gateways/pay_junction_test.rb index be3c9713169..16a3139be79 100644 --- a/test/unit/gateways/pay_junction_test.rb +++ b/test/unit/gateways/pay_junction_test.rb @@ -8,8 +8,8 @@ def setup Base.mode = :test @gateway = PayJunctionGateway.new( - :login => "pj-ql-01", - :password => "pj-ql-01p" + :login => 'pj-ql-01', + :password => 'pj-ql-01p' ) @credit_card = credit_card @@ -20,19 +20,18 @@ def setup @amount = 100 end - def test_detect_test_credentials_when_in_production Base.mode = :production live_gw = PayJunctionGateway.new( - :login => "l", - :password => "p" + :login => 'l', + :password => 'p' ) assert_false live_gw.test? test_gw = PayJunctionGateway.new( - :login => "pj-ql-01", - :password => "pj-ql-01p" + :login => 'pj-ql-01', + :password => 'pj-ql-01p' ) assert test_gw.test? end @@ -53,7 +52,7 @@ def test_failed_authorization def test_successful_refund @gateway.expects(:ssl_post).returns(successful_refund_response) - response = @gateway.refund(@amount, "123") + response = @gateway.refund(@amount, '123') assert_success response assert_equal PayJunctionGateway::SUCCESS_MESSAGE, response.message end @@ -61,7 +60,7 @@ def test_successful_refund def test_successful_deprecated_credit @gateway.expects(:ssl_post).returns(successful_refund_response) assert_deprecation_warning(Gateway::CREDIT_DEPRECATION_MESSAGE) do - response = @gateway.credit(@amount, "123") + response = @gateway.credit(@amount, '123') assert_success response assert_equal PayJunctionGateway::SUCCESS_MESSAGE, response.message end @@ -82,11 +81,11 @@ def test_cvv_result_not_supported end def test_add_creditcard_with_track_data - @credit_card.track_data = "Tracking data" + @credit_card.track_data = 'Tracking data' stub_comms do @gateway.authorize(@amount, @credit_card, @options) end.check_request do |endpoint, data, headers| - assert_match "dc_track=Tracking+data", data + assert_match 'dc_track=Tracking+data', data assert_no_match(/dc_name=/, data) assert_no_match(/dc_number=/, data) assert_no_match(/dc_expiration_month=/, data) @@ -95,8 +94,8 @@ def test_add_creditcard_with_track_data end.respond_with(successful_authorization_response) end - private + def successful_authorization_response <<-RESPONSE dc_merchant_name=PayJunction - (demo)dc_merchant_address=3 W. Carrillodc_merchant_city=Santa Barbaradc_merchant_state=CAdc_merchant_zip=93101dc_merchant_phone=800-601-0230dc_device_id=1174dc_transaction_date=2007-11-28 19:22:33.791634dc_transaction_action=chargedc_approval_code=TAS193dc_response_code=00dc_response_message=APPROVAL TAS193 dc_transaction_id=3144302dc_posture=holddc_invoice_number=9f76c4e4bd66a36dc5aeb4bd7b3a02fadc_notes=--START QUICK-LINK DEBUG-- diff --git a/test/unit/gateways/pay_junction_v2_test.rb b/test/unit/gateways/pay_junction_v2_test.rb index b6231e6a178..99a40a808ec 100644 --- a/test/unit/gateways/pay_junction_v2_test.rb +++ b/test/unit/gateways/pay_junction_v2_test.rb @@ -102,7 +102,7 @@ def test_successful_credit response = @gateway.credit(@amount, @credit_card, @options) assert_success response - assert_equal "Approved", response.message + assert_equal 'Approved', response.message end def test_failed_credit @@ -115,7 +115,7 @@ def test_failed_credit amount = 0 response = @gateway.credit(amount, @credit_card, @options) assert_failure response - assert_equal "Amount Base must be greater than 0.|", response.message + assert_equal 'Amount Base must be greater than 0.|', response.message end def test_successful_void @@ -148,7 +148,7 @@ def test_successful_verify response = @gateway.verify(@credit_card, @options) assert_success response - assert_equal "Approved", response.message + assert_equal 'Approved', response.message end def test_successful_verify_with_failed_void @@ -161,7 +161,7 @@ def test_successful_verify_with_failed_void response = @gateway.verify(@credit_card, @options) assert_success response - assert_equal "Approved", response.message + assert_equal 'Approved', response.message end def test_failed_verify @@ -185,7 +185,7 @@ def test_successful_store_and_purchase response = @gateway.store(@credit_card, @options) assert_success response assert response.authorization - assert_equal "Approved", response.message + assert_equal 'Approved', response.message response = @gateway.purchase(@amount, response.authorization, @options) assert_success response diff --git a/test/unit/gateways/pay_secure_test.rb b/test/unit/gateways/pay_secure_test.rb index 78ea5b7b56f..a49bf1a60f0 100644 --- a/test/unit/gateways/pay_secure_test.rb +++ b/test/unit/gateways/pay_secure_test.rb @@ -1,7 +1,7 @@ require 'test_helper' class PaySecureTest < Test::Unit::TestCase - + def setup @gateway = PaySecureGateway.new( :login => 'login', @@ -9,14 +9,14 @@ def setup ) @credit_card = credit_card - @options = { + @options = { :order_id => '1000', :billing_address => address, :description => 'Test purchase' } @amount = 100 end - + def test_successful_purchase @gateway.expects(:ssl_post).returns(successful_purchase_response) assert response = @gateway.purchase(@amount, @credit_card, @options) @@ -25,7 +25,7 @@ def test_successful_purchase assert_equal '2778;SimProxy 54041670', response.authorization assert response.test? end - + def test_failed_purchase @gateway.expects(:ssl_post).returns(failure_response) assert response = @gateway.purchase(@amount, @credit_card, @options) @@ -33,22 +33,23 @@ def test_failed_purchase assert_equal "Field value '8f796cb29a1be32af5ce12d4ca7425c2' does not match required format.", response.message assert_failure response end - + def test_avs_result_not_supported @gateway.expects(:ssl_post).returns(successful_purchase_response) - - response = @gateway.purchase(@amount, @credit_card, @options) + + response = @gateway.purchase(@amount, @credit_card, @options) assert_nil response.avs_result['code'] end - + def test_cvv_result_not_supported @gateway.expects(:ssl_post).returns(successful_purchase_response) - + response = @gateway.purchase(@amount, @credit_card, @options) assert_nil response.cvv_result['code'] end - + private + def successful_purchase_response <<-RESPONSE Status: Accepted @@ -60,7 +61,7 @@ def successful_purchase_response TransID: SimProxy 54041670 RESPONSE end - + def failure_response <<-RESPONSE Status: Declined diff --git a/test/unit/gateways/paybox_direct_test.rb b/test/unit/gateways/paybox_direct_test.rb index 5ff7e8817b3..e6e29d1ad93 100644 --- a/test/unit/gateways/paybox_direct_test.rb +++ b/test/unit/gateways/paybox_direct_test.rb @@ -10,8 +10,8 @@ def setup ) @credit_card = credit_card('1111222233334444', - :brand => 'visa' - ) + :brand => 'visa' + ) @amount = 100 @options = { @@ -32,7 +32,7 @@ def test_successful_purchase # Replace with authorization number from the successful response assert_equal response.params['numappel'].to_s + response.params['numtrans'], response.authorization assert_equal 'XXXXXX', response.params['autorisation'] - assert_equal "The transaction was approved", response.message + assert_equal 'The transaction was approved', response.message assert response.test? end @@ -55,10 +55,10 @@ def test_purchase_with_set_currency end def test_deprecated_credit - @gateway.expects(:ssl_post).with(anything, regexp_matches(/NUMAPPEL=transid/), anything).returns("") + @gateway.expects(:ssl_post).with(anything, regexp_matches(/NUMAPPEL=transid/), anything).returns('') @gateway.expects(:parse).returns({}) assert_deprecation_warning(Gateway::CREDIT_DEPRECATION_MESSAGE) do - @gateway.credit(@amount, "transid", @options) + @gateway.credit(@amount, 'transid', @options) end end @@ -66,10 +66,10 @@ def test_refund @gateway.expects(:ssl_post).with(anything) do |_, body| body.include?('NUMAPPEL=transid') body.include?('MONTANT=0000000100&DEVISE=97') - end.returns("") + end.returns('') @gateway.expects(:parse).returns({}) - @gateway.refund(@amount, "transid", @options) + @gateway.refund(@amount, 'transid', @options) end def test_unsuccessful_request @@ -77,12 +77,12 @@ def test_unsuccessful_request assert response = @gateway.purchase(@amount, @credit_card, @options) assert_failure response - assert_equal "Demande trait?e avec succ?s ✔漢", response.message + assert_equal 'Demande trait?e avec succ?s ✔漢', response.message assert response.test? end def test_keep_the_card_code_not_considered_fraudulent - @gateway.expects(:ssl_post).returns(purchase_response("00104")) + @gateway.expects(:ssl_post).returns(purchase_response('00104')) assert response = @gateway.purchase(@amount, @credit_card, @options) assert_failure response @@ -90,7 +90,7 @@ def test_keep_the_card_code_not_considered_fraudulent end def test_do_not_honour_code_not_considered_fraudulent - @gateway.expects(:ssl_post).returns(purchase_response("00105")) + @gateway.expects(:ssl_post).returns(purchase_response('00105')) assert response = @gateway.purchase(@amount, @credit_card, @options) assert_failure response @@ -98,7 +98,7 @@ def test_do_not_honour_code_not_considered_fraudulent end def test_card_absent_from_file_code_not_considered_fraudulent - @gateway.expects(:ssl_post).returns(purchase_response("00156")) + @gateway.expects(:ssl_post).returns(purchase_response('00156')) assert response = @gateway.purchase(@amount, @credit_card, @options) assert_failure response @@ -113,7 +113,7 @@ def test_version private # Place raw successful response from gateway here - def purchase_response(code="00000") + def purchase_response(code='00000') "NUMTRANS=0720248861&NUMAPPEL=0713790302&NUMQUESTION=0000790217&SITE=1999888&RANG=99&AUTORISATION=XXXXXX&CODEREPONSE=#{code}&COMMENTAIRE=Demande trait?e avec succ?s ✔漢" end diff --git a/test/unit/gateways/payeezy_test.rb b/test/unit/gateways/payeezy_test.rb index 131f3b4d33d..6d95954c196 100644 --- a/test/unit/gateways/payeezy_test.rb +++ b/test/unit/gateways/payeezy_test.rb @@ -5,19 +5,18 @@ class PayeezyGateway < Test::Unit::TestCase include CommStub def setup - @gateway = PayeezyGateway.new( - apikey: "45234543524353", - apisecret: "4235423325", - token: "rewrt-23543543542353542" - ) + @gateway = PayeezyGateway.new(fixtures(:payeezy)) @credit_card = credit_card + @bad_credit_card = credit_card('4111111111111113') @check = check @amount = 100 @options = { - :billing_address => address + :billing_address => address, + :ta_token => '123' } - @authorization = "ET1700|106625152|credit_card|4738" + @authorization = 'ET1700|106625152|credit_card|4738' + @reversal_id = SecureRandom.random_number(1000000).to_s end def test_invalid_credentials @@ -26,7 +25,7 @@ def test_invalid_credentials assert response = @gateway.authorize(100, @credit_card, {}) assert_failure response assert response.test? - assert_equal '||credit_card|', response.authorization + assert response.authorization assert_equal 'HMAC validation Failure', response.message end @@ -36,7 +35,7 @@ def test_invalid_token assert response = @gateway.authorize(100, @credit_card, {}) assert_failure response assert response.test? - assert_equal '||credit_card|', response.authorization + assert response.authorization assert_equal 'Access denied', response.message end @@ -46,7 +45,7 @@ def test_invalid_token_on_integration assert response = @gateway.authorize(100, @credit_card, {}) assert_failure response assert response.test? - assert_equal '||credit_card|', response.authorization + assert response.authorization assert_equal 'Invalid ApiKey for given resource', response.message end @@ -59,6 +58,40 @@ def test_successful_purchase assert_equal 'Transaction Normal - Approved', response.message end + def test_successful_store + response = stub_comms(@gateway, :ssl_request) do + @gateway.store(@credit_card, @options.merge(js_security_key: 'js-f4c4b54f08d6c44c8cad3ea80bbf92c4f4c4b54f08d6c44c')) + end.respond_with(successful_store_response) + + assert_success response + assert_equal 'Token successfully created.', response.message + assert response.test? + end + + def test_successful_store_and_purchase + response = stub_comms(@gateway, :ssl_request) do + @gateway.store(@credit_card, @options.merge(js_security_key: 'js-f4c4b54f08d6c44c8cad3ea80bbf92c4f4c4b54f08d6c44c')) + end.respond_with(successful_store_response) + + assert_success response + assert_match %r{Token successfully created}, response.message + + @gateway.expects(:ssl_post).returns(successful_purchase_response) + + purchase = @gateway.purchase(@amount, response.authorization, @options) + assert_success purchase + end + + def test_failed_store + response = stub_comms(@gateway, :ssl_request) do + @gateway.store(@bad_credit_card, @options.merge(js_security_key: 'js-f4c4b54f08d6c44c8cad3ea80bbf92c4f4c4b54f08d6c44c')) + end.respond_with(failed_store_response) + + assert_failure response + assert_equal 'The credit card number check failed', response.message + assert response.test? + end + def test_successful_purchase_with_echeck @gateway.expects(:ssl_post).returns(successful_purchase_echeck_response) assert response = @gateway.purchase(@amount, @check, @options) @@ -68,17 +101,32 @@ def test_successful_purchase_with_echeck assert_equal 'Transaction Normal - Approved', response.message end + def test_successful_purchase_defaulting_check_number + check_without_number = check(number: nil) + + response = stub_comms do + @gateway.purchase(@amount, check_without_number, @options) + end.check_request do |endpoint, data, headers| + assert_match(/001/, data) + end.respond_with(successful_purchase_echeck_response) + + assert_success response + assert_equal 'ET133078|69864362|tele_check|100', response.authorization + assert response.test? + assert_equal 'Transaction Normal - Approved', response.message + end + def test_failed_purchase @gateway.expects(:ssl_post).raises(failed_purchase_response) assert response = @gateway.purchase(@amount, @credit_card, @options) assert_instance_of Response, response assert_failure response - assert_equal response.error_code, "card_expired" + assert_equal response.error_code, 'card_expired' end def test_successful_authorize @gateway.expects(:ssl_post).returns(successful_authorize_response) - assert response = @gateway.purchase(@amount, @credit_card, @options) + assert response = @gateway.authorize(@amount, @credit_card, @options) assert_success response assert_equal 'ET156862|69601979|credit_card|100', response.authorization assert response.test? @@ -94,7 +142,7 @@ def test_failed_authorize def test_successful_capture @gateway.expects(:ssl_post).returns(successful_capture_response) - assert response = @gateway.capture(@amount, "ET156862|69601979|credit_card|100") + assert response = @gateway.capture(@amount, 'ET156862|69601979|credit_card|100') assert_success response assert_equal 'ET176427|69601874|credit_card|100', response.authorization assert response.test? @@ -103,7 +151,7 @@ def test_successful_capture def test_failed_capture @gateway.expects(:ssl_post).raises(failed_capture_response) - assert response = @gateway.capture(@amount, "") + assert response = @gateway.capture(@amount, '') assert_instance_of Response, response assert_failure response end @@ -127,11 +175,25 @@ def test_failed_refund end def test_successful_void - @gateway.expects(:ssl_post).returns(successful_void_response) - assert response = @gateway.void(@authorization, @options) + response = stub_comms do + @gateway.void(@authorization, @options) + end.check_request do |endpoint, data, headers| + json = '{"transaction_type":"void","method":"credit_card","transaction_tag":"106625152","currency_code":"USD","amount":"4738"}' + assert_match json, data + end.respond_with(successful_void_response) + assert_success response end + def test_successful_void_with_reversal_id + stub_comms do + @gateway.void(@authorization, @options.merge(reversal_id: @reversal_id)) + end.check_request do |endpoint, data, headers| + json = "{\"transaction_type\":\"void\",\"method\":\"credit_card\",\"reversal_id\":\"#{@reversal_id}\",\"currency_code\":\"USD\",\"amount\":\"4738\"}" + assert_match json, data + end.respond_with(successful_void_response) + end + def test_failed_void @gateway.expects(:ssl_post).raises(failed_void_response) assert response = @gateway.void(@authorization, @options) @@ -158,8 +220,8 @@ def test_invalid_transaction_tag assert response = @gateway.capture(@amount, @authorization) assert_instance_of Response, response assert_failure response - assert_equal response.error_code, "server_error" - assert_equal response.message, "ProcessedBad Request (69) - Invalid Transaction Tag" + assert_equal response.error_code, 'server_error' + assert_equal response.message, 'ProcessedBad Request (69) - Invalid Transaction Tag' end def test_supported_countries @@ -193,6 +255,13 @@ def test_requests_include_verification_string end.respond_with(successful_purchase_response) end + def test_gateway_message_surfaces + @gateway.expects(:ssl_post).returns(below_minimum_response) + assert response = @gateway.authorize(@amount, @credit_card, @options) + assert_failure response + assert_equal 'Below Minimum Sale', response.message + end + def test_card_type assert_equal 'Visa', PayeezyGateway::CREDIT_CARD_BRAND['visa'] assert_equal 'Mastercard', PayeezyGateway::CREDIT_CARD_BRAND['master'] @@ -206,6 +275,10 @@ def test_scrub assert_equal @gateway.scrub(pre_scrubbed), post_scrubbed end + def test_scrub_store + assert_equal @gateway.scrub(pre_scrubbed_store), post_scrubbed_store + end + def test_scrub_echeck assert @gateway.supports_scrubbing? assert_equal @gateway.scrub(pre_scrubbed_echeck), post_scrubbed_echeck @@ -253,7 +326,7 @@ def post_scrubbed opened starting SSL for api-cert.payeezy.com:443... SSL established - <- "POST /v1/transactions HTTP/1.1\r\nContent-Type: application/json\r\nApikey: oKB61AAxbN3xwC6gVAH3dp58FmioHSAT\r\nToken: [FILTERED]\r\nNonce: 5803993876.636232\r\nTimestamp: 1449523748359\r\nAuthorization: NGRlZjJkMWNlMDc5NGI5OTVlYTQxZDRkOGQ4NjRhNmZhNDgwZmIyNTZkMWJhN2M3MDdkNDI0ZWI1OGUwMGExMA==\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nAccept: */*\r\nUser-Agent: Ruby\r\nConnection: close\r\nHost: api-cert.payeezy.com\r\nContent-Length: 365\r\n\r\n" + <- "POST /v1/transactions HTTP/1.1\r\nContent-Type: application/json\r\nApikey: [FILTERED]\r\nToken: [FILTERED]\r\nNonce: 5803993876.636232\r\nTimestamp: 1449523748359\r\nAuthorization: NGRlZjJkMWNlMDc5NGI5OTVlYTQxZDRkOGQ4NjRhNmZhNDgwZmIyNTZkMWJhN2M3MDdkNDI0ZWI1OGUwMGExMA==\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nAccept: */*\r\nUser-Agent: Ruby\r\nConnection: close\r\nHost: api-cert.payeezy.com\r\nContent-Length: 365\r\n\r\n" <- "{\"transaction_type\":\"purchase\",\"merchant_ref\":null,\"method\":\"credit_card\",\"credit_card\":{\"type\":\"Visa\",\"cardholder_name\":\"Longbob Longsen\",\"card_number\":\"[FILTERED]\",\"exp_date\":\"0916\",\"cvv\":\"[FILTERED]\"},\"billing_address\":{\"street\":\"456 My Street\",\"city\":\"Ottawa\",\"state_province\":\"ON\",\"zip_postal_code\":\"K1C2N6\",\"country\":\"CA\"},\"currency_code\":\"USD\",\"amount\":\"100\"}" -> "HTTP/1.1 201 Created\r\n" -> "Access-Control-Allow-Headers: Content-Type, apikey, token\r\n" @@ -335,6 +408,62 @@ def post_scrubbed_echeck TRANSCRIPT end + def pre_scrubbed_store + <<-TRANSCRIPT + opening connection to api-cert.payeezy.com:443... + opened + starting SSL for api-cert.payeezy.com:443... + SSL established + <- "GET /v1/securitytokens?apikey=UyDMTXx6TD9WErF6ynw7xeEfCAn8fcGs&js_security_key=js-f4c4b54f08d6c44c8cad3ea80bbf92c4f4c4b54f08d6c44c&ta_token=120&callback=Payeezy.callback&type=FDToken&credit_card.type=Visa&credit_card.cardholder_name=Longbob+Longsen&credit_card.card_number=4242424242424242&credit_card.exp_date=0919&credit_card.cvv=123 HTTP/1.1\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nAccept: */*\r\nUser-Agent: Ruby\r\nConnection: close\r\nHost: api-cert.payeezy.com\r\n\r\n" + -> "HTTP/1.1 200 Success\r\n" + -> "Content-Language: en-US\r\n" + -> "Content-Type: application/json\r\n" + -> "correlation_id: 228.1574930196886\r\n" + -> "Date: Fri, 12 Jan 2018 09:28:22 GMT\r\n" + -> "statuscode: 201\r\n" + -> "X-Archived-Client-IP: 10.180.205.250\r\n" + -> "X-Backside-Transport: OK OK,OK OK\r\n" + -> "X-Client-IP: 10.180.205.250,54.218.45.37\r\n" + -> "X-Global-Transaction-ID: 463881989\r\n" + -> "X-Powered-By: Servlet/3.0\r\n" + -> "Content-Length: 266\r\n" + -> "Connection: Close\r\n" + -> "\r\n" + reading 266 bytes... + -> "\n Payeezy.callback({\n \t\"status\":201,\n \t\"results\":{\"correlation_id\":\"228.1574930196886\",\"status\":\"success\",\"type\":\"FDToken\",\"token\":{\"type\":\"Visa\",\"cardholder_name\":\"Longbob Longsen\",\"exp_date\":\"0919\",\"value\":\"2158545373614242\"}}\n })\n " + read 266 bytes + Conn close + TRANSCRIPT + end + + def post_scrubbed_store + <<-TRANSCRIPT + opening connection to api-cert.payeezy.com:443... + opened + starting SSL for api-cert.payeezy.com:443... + SSL established + <- "GET /v1/securitytokens?apikey=[FILTERED]js_security_key=js-f4c4b54f08d6c44c8cad3ea80bbf92c4f4c4b54f08d6c44c&ta_token=120&callback=Payeezy.callback&type=FDToken&credit_card.type=Visa&credit_card.cardholder_name=Longbob+Longsen&credit_card.card_number=[FILTERED]credit_card.exp_date=0919&credit_card.cvv=[FILTERED] HTTP/1.1\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nAccept: */*\r\nUser-Agent: Ruby\r\nConnection: close\r\nHost: api-cert.payeezy.com\r\n\r\n" + -> "HTTP/1.1 200 Success\r\n" + -> "Content-Language: en-US\r\n" + -> "Content-Type: application/json\r\n" + -> "correlation_id: 228.1574930196886\r\n" + -> "Date: Fri, 12 Jan 2018 09:28:22 GMT\r\n" + -> "statuscode: 201\r\n" + -> "X-Archived-Client-IP: 10.180.205.250\r\n" + -> "X-Backside-Transport: OK OK,OK OK\r\n" + -> "X-Client-IP: 10.180.205.250,54.218.45.37\r\n" + -> "X-Global-Transaction-ID: 463881989\r\n" + -> "X-Powered-By: Servlet/3.0\r\n" + -> "Content-Length: 266\r\n" + -> "Connection: Close\r\n" + -> "\r\n" + reading 266 bytes... + -> "\n Payeezy.callback({\n \t\"status\":201,\n \t\"results\":{\"correlation_id\":\"228.1574930196886\",\"status\":\"success\",\"type\":\"FDToken\",\"token\":{\"type\":\"Visa\",\"cardholder_name\":\"Longbob Longsen\",\"exp_date\":\"0919\",\"value\":\"2158545373614242\"}}\n })\n " + read 266 bytes + Conn close + TRANSCRIPT + end + def successful_purchase_response <<-RESPONSE {\"method\":\"credit_card\",\"amount\":\"1\",\"currency\":\"USD\",\"avs\":\"4\",\"card\":{\"type\":\"Visa\",\"cardholder_name\":\"Bobsen 995\",\"card_number\":\"4242\",\"exp_date\":\"0816\"},\"token\":{\"token_type\":\"transarmor\",\"token_data\":{\"value\":\"0152552999534242\"}},\"transaction_status\":\"approved\",\"validation_status\":\"success\",\"transaction_type\":\"purchase\",\"transaction_id\":\"ET114541\",\"transaction_tag\":\"55083431\",\"bank_resp_code\":\"100\",\"bank_message\":\"Approved\",\"gateway_resp_code\":\"00\",\"gateway_message\":\"Transaction Normal\",\"correlation_id\":\"124.1433862672836\"} @@ -347,6 +476,18 @@ def successful_purchase_echeck_response RESPONSE end + def successful_store_response + <<-RESPONSE + {\"correlation_id\":\"124.1792879391754\",\"status\":\"success\",\"type\":\"FDToken\",\"token\":{\"type\":\"Visa\",\"cardholder_name\":\"Longbob Longsen\",\"exp_date\":\"0919\",\"value\":\"9045348309244242\"}} + RESPONSE + end + + def failed_store_response + <<-RESPONSE + {\"correlation_id\":\"124.1792940806770\",\"status\":\"failed\",\"Error\":{\"messages\":[{\"code\":\"invalid_card_number\",\"description\":\"The credit card number check failed\"}]},\"type\":\"FDToken\"} + RESPONSE + end + def failed_purchase_response yamlexcep = <<-RESPONSE --- !ruby/exception:ActiveMerchant::ResponseError @@ -385,7 +526,7 @@ def failed_purchase_response body_exist: true message: RESPONSE - YAML.load(yamlexcep) + YAML.safe_load(yamlexcep, ['Net::HTTPBadRequest', 'ActiveMerchant::ResponseError']) end def successful_authorize_response @@ -418,6 +559,12 @@ def successful_refund_echeck_response RESPONSE end + def below_minimum_response + <<-RESPONSE + {\"correlation_id\":\"123.1234678982\",\"transaction_status\":\"declined\",\"validation_status\":\"success\",\"transaction_type\":\"authorize\",\"transaction_tag\":\"92384753\",\"method\":\"credit_card\",\"amount\":\"250\",\"currency\":\"USD\",\"card\":{\"type\":\"Mastercard\",\"cardholder_name\":\"Omri Test\",\"card_number\":\"[FILTERED]\",\"exp_date\":\"0123\"},\"gateway_resp_code\":\"36\",\"gateway_message\":\"Below Minimum Sale\"} + RESPONSE + end + def failed_refund_response yamlexcep = <<-RESPONSE --- !ruby/exception:ActiveMerchant::ResponseError @@ -454,7 +601,7 @@ def failed_refund_response body_exist: true message: RESPONSE - YAML.load(yamlexcep) + YAML.safe_load(yamlexcep, ['Net::HTTPBadRequest', 'ActiveMerchant::ResponseError']) end def successful_void_response @@ -499,7 +646,7 @@ def failed_void_response body_exist: true message: RESPONSE - YAML.load(yamlexcep) + YAML.safe_load(yamlexcep, ['Net::HTTPBadRequest', 'ActiveMerchant::ResponseError']) end def failed_capture_response @@ -539,7 +686,7 @@ def failed_capture_response body_exist: true message: RESPONSE - YAML.load(yamlexcep) + YAML.safe_load(yamlexcep, ['Net::HTTPBadRequest', 'ActiveMerchant::ResponseError']) end def invalid_token_response @@ -578,7 +725,7 @@ def invalid_token_response body_exist: true message: RESPONSE - YAML.load(yamlexcep) + YAML.safe_load(yamlexcep, ['Net::HTTPUnauthorized', 'ActiveMerchant::ResponseError']) end def invalid_token_response_integration @@ -603,7 +750,7 @@ def invalid_token_response_integration body_exist: true message: RESPONSE - YAML.load(yamlexcep) + YAML.safe_load(yamlexcep, ['Net::HTTPUnauthorized', 'ActiveMerchant::ResponseError']) end def bad_credentials_response @@ -628,6 +775,6 @@ def bad_credentials_response body_exist: true message: RESPONSE - YAML.load(yamlexcep) + YAML.safe_load(yamlexcep, ['Net::HTTPForbidden', 'ActiveMerchant::ResponseError']) end end diff --git a/test/unit/gateways/payex_test.rb b/test/unit/gateways/payex_test.rb index deafad22def..a567c1a08c1 100644 --- a/test/unit/gateways/payex_test.rb +++ b/test/unit/gateways/payex_test.rb @@ -72,7 +72,7 @@ def test_successful_void def test_unsuccessful_void @gateway.expects(:ssl_post).returns(unsuccessful_void_response) - assert response = @gateway.void("1") + assert response = @gateway.void('1') assert_failure response assert_not_equal 'OK', response.message assert_match %r{1}, response.message @@ -89,7 +89,7 @@ def test_successful_refund def test_unsuccessful_refund @gateway.expects(:ssl_post).returns(unsuccessful_refund_response) - assert response = @gateway.refund(@amount, "1", order_id: '123') + assert response = @gateway.refund(@amount, '1', order_id: '123') assert_failure response assert_not_equal 'OK', response.message assert_match %r{1}, response.message @@ -125,7 +125,7 @@ def test_successful_purchase_with_stored_card private def successful_initialize_response - %q{<?xml version="1.0" encoding="utf-8"?> + '<?xml version="1.0" encoding="utf-8"?> <soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <soap:Body> <Initialize8Response xmlns="http://external.payex.com/PxOrder/"> @@ -133,12 +133,12 @@ def successful_initialize_response </Initialize8Response> </soap:Body> </soap:Envelope> - } + ' end # Place raw successful response from gateway here def successful_purchase_response - %q{<?xml version="1.0" encoding="utf-8"?> + '<?xml version="1.0" encoding="utf-8"?> <soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <soap:Body> <PurchaseCCResponse xmlns="http://confined.payex.com/PxOrder/"> @@ -146,11 +146,11 @@ def successful_purchase_response </PurchaseCCResponse> </soap:Body> </soap:Envelope> - } + ' end def failed_purchase_response - %q{<?xml version="1.0" encoding="utf-8"?> + '<?xml version="1.0" encoding="utf-8"?> <soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <soap:Body> <PurchaseCCResponse xmlns="http://confined.payex.com/PxOrder/"> @@ -159,11 +159,11 @@ def failed_purchase_response </PurchaseCCResponse> </soap:Body> </soap:Envelope> - } + ' end def successful_authorize_response - %q{<?xml version="1.0" encoding="utf-8"?> + '<?xml version="1.0" encoding="utf-8"?> <soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <soap:Body> <PurchaseCCResponse xmlns="http://confined.payex.com/PxOrder/"> @@ -171,11 +171,11 @@ def successful_authorize_response </PurchaseCCResponse> </soap:Body> </soap:Envelope> - } + ' end def successful_capture_response - %q{<?xml version="1.0" encoding="utf-8"?> + '<?xml version="1.0" encoding="utf-8"?> <soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <soap:Body> <Capture5Response xmlns="http://external.payex.com/PxOrder/"> @@ -183,11 +183,11 @@ def successful_capture_response </Capture5Response> </soap:Body> </soap:Envelope> - } + ' end def failed_capture_response - %q{<?xml version="1.0" encoding="utf-8"?> + '<?xml version="1.0" encoding="utf-8"?> <soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <soap:Body> <Capture5Response xmlns="http://external.payex.com/PxOrder/"> @@ -195,11 +195,11 @@ def failed_capture_response </Capture5Response> </soap:Body> </soap:Envelope> - } + ' end def successful_void_response - %q{<?xml version="1.0" encoding="utf-8"?> + '<?xml version="1.0" encoding="utf-8"?> <soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <soap:Body> <Cancel2Response xmlns="http://external.payex.com/PxOrder/"> @@ -207,11 +207,11 @@ def successful_void_response </Cancel2Response> </soap:Body> </soap:Envelope> - } + ' end def unsuccessful_void_response - %q{<?xml version="1.0" encoding="utf-8"?> + '<?xml version="1.0" encoding="utf-8"?> <soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <soap:Body> <Cancel2Response xmlns="http://external.payex.com/PxOrder/"> @@ -219,11 +219,11 @@ def unsuccessful_void_response </Cancel2Response> </soap:Body> </soap:Envelope> - } + ' end def successful_refund_response - %q{<?xml version="1.0" encoding="utf-8"?> + '<?xml version="1.0" encoding="utf-8"?> <soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <soap:Body> <Credit5Response xmlns="http://external.payex.com/PxOrder/"> @@ -231,11 +231,11 @@ def successful_refund_response </Credit5Response> </soap:Body> </soap:Envelope> - } + ' end def unsuccessful_refund_response - %q{<?xml version="1.0" encoding="utf-8"?> + '<?xml version="1.0" encoding="utf-8"?> <soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <soap:Body> <Credit5Response xmlns="http://external.payex.com/PxOrder/"> @@ -243,11 +243,11 @@ def unsuccessful_refund_response </Credit5Response> </soap:Body> </soap:Envelope> - } + ' end def successful_store_response - %q{<?xml version="1.0" encoding="utf-8"?> + '<?xml version="1.0" encoding="utf-8"?> <soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <soap:Body> <CreateAgreement3Response xmlns="http://external.payex.com/PxAgreement/"> @@ -255,11 +255,11 @@ def successful_store_response </CreateAgreement3Response> </soap:Body> </soap:Envelope> - } + ' end def successful_unstore_response - %q{<?xml version="1.0" encoding="utf-8"?> + '<?xml version="1.0" encoding="utf-8"?> <soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <soap:Body> <DeleteAgreementResponse xmlns="http://external.payex.com/PxAgreement/"> @@ -267,11 +267,11 @@ def successful_unstore_response </DeleteAgreementResponse> </soap:Body> </soap:Envelope> - } + ' end def successful_autopay_response - %q{<?xml version="1.0" encoding="utf-8"?> + '<?xml version="1.0" encoding="utf-8"?> <soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <soap:Body> <AutoPay3Response xmlns="http://external.payex.com/PxAgreement/"> @@ -279,6 +279,6 @@ def successful_autopay_response </AutoPay3Response> </soap:Body> </soap:Envelope> - } + ' end end diff --git a/test/unit/gateways/payflow_express_test.rb b/test/unit/gateways/payflow_express_test.rb index 2486752caf1..ef8fab1fcb4 100644 --- a/test/unit/gateways/payflow_express_test.rb +++ b/test/unit/gateways/payflow_express_test.rb @@ -5,15 +5,15 @@ class PayflowExpressTest < Test::Unit::TestCase TEST_REDIRECT_URL_MOBILE = 'https://www.sandbox.paypal.com/cgi-bin/webscr?cmd=_express-checkout-mobile&token=1234567890' LIVE_REDIRECT_URL = 'https://www.paypal.com/cgi-bin/webscr?cmd=_express-checkout&token=1234567890' LIVE_REDIRECT_URL_MOBILE = 'https://www.paypal.com/cgi-bin/webscr?cmd=_express-checkout-mobile&token=1234567890' - + TEST_REDIRECT_URL_WITHOUT_REVIEW = "#{TEST_REDIRECT_URL}&useraction=commit" LIVE_REDIRECT_URL_WITHOUT_REVIEW = "#{LIVE_REDIRECT_URL}&useraction=commit" TEST_REDIRECT_URL_MOBILE_WITHOUT_REVIEW = "#{TEST_REDIRECT_URL_MOBILE}&useraction=commit" LIVE_REDIRECT_URL_MOBILE_WITHOUT_REVIEW = "#{LIVE_REDIRECT_URL_MOBILE}&useraction=commit" - + def setup Base.mode = :test - + @gateway = PayflowExpressGateway.new( :login => 'LOGIN', :password => 'PASSWORD' @@ -29,61 +29,61 @@ def setup :phone => '(555)555-5555' } end - + def teardown Base.mode = :test end - + def test_using_test_mode assert @gateway.test? end - + def test_overriding_test_mode Base.mode = :production - + gateway = PayflowExpressGateway.new( :login => 'LOGIN', :password => 'PASSWORD', :test => true ) - + assert gateway.test? end - + def test_using_production_mode Base.mode = :production - + gateway = PayflowExpressGateway.new( :login => 'LOGIN', :password => 'PASSWORD' ) - + assert !gateway.test? end - + def test_live_redirect_url Base.mode = :production assert_equal LIVE_REDIRECT_URL, @gateway.redirect_url_for('1234567890') assert_equal LIVE_REDIRECT_URL_MOBILE, @gateway.redirect_url_for('1234567890', :mobile => true) end - + def test_test_redirect_url assert_equal TEST_REDIRECT_URL, @gateway.redirect_url_for('1234567890') assert_equal TEST_REDIRECT_URL_MOBILE, @gateway.redirect_url_for('1234567890', :mobile => true) end - + def test_live_redirect_url_without_review Base.mode = :production assert_equal LIVE_REDIRECT_URL_WITHOUT_REVIEW, @gateway.redirect_url_for('1234567890', :review => false) assert_equal LIVE_REDIRECT_URL_MOBILE_WITHOUT_REVIEW, @gateway.redirect_url_for('1234567890', :review => false, :mobile => true) end - + def test_test_redirect_url_without_review assert_equal :test, Base.mode assert_equal TEST_REDIRECT_URL_WITHOUT_REVIEW, @gateway.redirect_url_for('1234567890', :review => false) assert_equal TEST_REDIRECT_URL_MOBILE_WITHOUT_REVIEW, @gateway.redirect_url_for('1234567890', :review => false, :mobile => true) end - + def test_invalid_get_express_details_request @gateway.expects(:ssl_post).returns(invalid_get_express_details_response) response = @gateway.details_for('EC-2OPN7UJGFWK9OYFV') @@ -91,20 +91,20 @@ def test_invalid_get_express_details_request assert response.test? assert_equal 'Field format error: Invalid Token', response.message end - + def test_get_express_details @gateway.expects(:ssl_post).returns(successful_get_express_details_response) response = @gateway.details_for('EC-2OPN7UJGFWK9OYFV') assert_instance_of PayflowExpressResponse, response assert_success response assert response.test? - + assert_equal 'EC-2OPN7UJGFWK9OYFV', response.token assert_equal '12345678901234567', response.payer_id assert_equal 'Buyer1@paypal.com', response.email assert_equal 'Joe Smith', response.full_name assert_equal 'US', response.payer_country - + assert address = response.address assert_equal 'Joe Smith', address['name'] assert_nil address['company'] @@ -114,11 +114,36 @@ def test_get_express_details assert_equal 'CA', address['state'] assert_equal '95100', address['zip'] assert_equal 'US', address['country'] - assert_nil address['phone'] + assert_equal '555-555-5555', address['phone'] + end + + def test_get_express_details_with_ship_to_name + @gateway.expects(:ssl_post).returns(successful_get_express_details_response_with_ship_to_name) + response = @gateway.details_for('EC-2OPN7UJGFWK9OYFV') + assert_instance_of PayflowExpressResponse, response + assert_success response + assert response.test? + + assert_equal 'EC-2OPN7UJGFWK9OYFV', response.token + assert_equal '12345678901234567', response.payer_id + assert_equal 'Buyer1@paypal.com', response.email + assert_equal 'Joe Smith', response.full_name + assert_equal 'US', response.payer_country + + assert address = response.address + assert_equal 'John Joseph', address['name'] + assert_nil address['company'] + assert_equal '111 Main St.', address['address1'] + assert_nil address['address2'] + assert_equal 'San Jose', address['city'] + assert_equal 'CA', address['state'] + assert_equal '95100', address['zip'] + assert_equal 'US', address['country'] + assert_equal '555-555-5555', address['phone'] end def test_get_express_details_with_invalid_xml - @gateway.expects(:ssl_post).returns(successful_get_express_details_response(:street => "Main & Magic")) + @gateway.expects(:ssl_post).returns(successful_get_express_details_response(:street => 'Main & Magic')) response = @gateway.details_for('EC-2OPN7UJGFWK9OYFV') assert_instance_of PayflowExpressResponse, response assert_success response @@ -134,10 +159,10 @@ def test_button_source xml_doc = REXML::Document.new(xml.target!) assert_nil REXML::XPath.first(xml_doc, '/PayPal/ButtonSource') end - + private - - def successful_get_express_details_response(options={:street => "111 Main St."}) + + def successful_get_express_details_response(options={:street => '111 Main St.'}) <<-RESPONSE <XMLPayResponse xmlns='http://www.verisign.com/XMLPay'> <ResponseData> @@ -154,6 +179,7 @@ def successful_get_express_details_response(options={:street => "111 Main St."}) <FeeAmount>0</FeeAmount> <PayerStatus>verified</PayerStatus> <Name>Joe</Name> + <Phone>555-555-5555</Phone> <ShipTo> <Address> <Street>#{options[:street]}</Street> @@ -172,7 +198,45 @@ def successful_get_express_details_response(options={:street => "111 Main St."}) </XMLPayResponse> RESPONSE end - + + def successful_get_express_details_response_with_ship_to_name + <<-RESPONSE +<XMLPayResponse xmlns='http://www.verisign.com/XMLPay'> + <ResponseData> + <Vendor>TEST</Vendor> + <Partner>verisign</Partner> + <TransactionResults> + <TransactionResult> + <Result>0</Result> + <Message>Approved</Message> + <PayPalResult> + <EMail>Buyer1@paypal.com</EMail> + <PayerID>12345678901234567</PayerID> + <Token>EC-2OPN7UJGFWK9OYFV</Token> + <FeeAmount>0</FeeAmount> + <PayerStatus>verified</PayerStatus> + <Name>Joe</Name> + <Phone>555-555-5555</Phone> + <ShipTo> + <Address> + <Street>111 Main St.</Street> + <City>San Jose</City> + <State>CA</State> + <Zip>95100</Zip> + <Country>US</Country> + </Address> + </ShipTo> + <CorrelationID>9c3706997455e</CorrelationID> + </PayPalResult> + <ExtData Name='LASTNAME' Value='Smith'/> + <ExtData Name='SHIPTONAME' Value='John Joseph'/> + </TransactionResult> + </TransactionResults> + </ResponseData> + </XMLPayResponse> + RESPONSE + end + def invalid_get_express_details_response <<-RESPONSE <XMLPayResponse xmlns='http://www.verisign.com/XMLPay'> @@ -186,7 +250,7 @@ def invalid_get_express_details_response </TransactionResult> </TransactionResults> </ResponseData> -</XMLPayResponse> +</XMLPayResponse> RESPONSE end end diff --git a/test/unit/gateways/payflow_express_uk_test.rb b/test/unit/gateways/payflow_express_uk_test.rb index 25f88820b1e..60a18a88be8 100644 --- a/test/unit/gateways/payflow_express_uk_test.rb +++ b/test/unit/gateways/payflow_express_uk_test.rb @@ -37,7 +37,33 @@ def test_get_express_details assert_nil address['phone'] end + def test_get_express_details_with_ship_to_name + @gateway.expects(:ssl_post).returns(successful_get_express_details_response_with_ship_to_name) + response = @gateway.details_for('EC-2OPN7UJGFWK9OYFV') + assert_instance_of PayflowExpressResponse, response + assert_success response + assert response.test? + + assert_equal 'EC-2OPN7UJGFWK9OYFV', response.token + assert_equal 'LYWCMEN4FA7ZQ', response.payer_id + assert_equal 'paul@test.com', response.email + assert_equal 'paul smith', response.full_name + assert_equal 'GB', response.payer_country + + assert address = response.address + assert_equal 'John Joseph', address['name'] + assert_nil address['company'] + assert_equal '10 keyworth avenue', address['address1'] + assert_equal 'grangetown', address['address2'] + assert_equal 'hinterland', address['city'] + assert_equal 'Tyne and Wear', address['state'] + assert_equal 'sr5 2uh', address['zip'] + assert_equal 'GB', address['country'] + assert_nil address['phone'] + end + private + def successful_get_express_details_response <<-RESPONSE <?xml version="1.0"?> @@ -73,7 +99,52 @@ def successful_get_express_details_response </PayPalResult> <ExtData Name="LASTNAME" Value="smith"/> <ExtData Name="SHIPTOSTREET2" Value="grangetown"/> - <ExtData Name="SHIPTONAME" Value="paul smith"/> + <ExtData Name="STREET2" Value="ALLAWAY AVENUE"/> + <ExtData Name="COUNTRYCODE" Value="GB"/> + <ExtData Name="ADDRESSSTATUS" Value="Y"/> + </TransactionResult> + </TransactionResults> + </ResponseData> +</XMLPayResponse> + RESPONSE + end + + def successful_get_express_details_response_with_ship_to_name + <<-RESPONSE +<?xml version="1.0"?> +<XMLPayResponse xmlns="http://www.paypal.com/XMLPay"> + <ResponseData> + <Vendor>markcoop</Vendor> + <Partner>paypaluk</Partner> + <TransactionResults> + <TransactionResult> + <Result>0</Result> + <AVSResult> + <StreetMatch>Match</StreetMatch> + <ZipMatch>Match</ZipMatch> + </AVSResult> + <Message>Approved</Message> + <PayPalResult> + <EMail>paul@test.com</EMail> + <PayerID>LYWCMEN4FA7ZQ</PayerID> + <Token>EC-2OPN7UJGFWK9OYFV</Token> + <FeeAmount>0</FeeAmount> + <PayerStatus>unverified</PayerStatus> + <Name>paul</Name> + <ShipTo> + <Address> + <Street>10 keyworth avenue</Street> + <City>hinterland</City> + <State>Tyne and Wear</State> + <Zip>sr5 2uh</Zip> + <Country>GB</Country> + </Address> + </ShipTo> + <CorrelationID>1ea22ef3873ba</CorrelationID> + </PayPalResult> + <ExtData Name="LASTNAME" Value="smith"/> + <ExtData Name="SHIPTOSTREET2" Value="grangetown"/> + <ExtData Name="SHIPTONAME" Value="John Joseph"/> <ExtData Name="STREET2" Value="ALLAWAY AVENUE"/> <ExtData Name="COUNTRYCODE" Value="GB"/> <ExtData Name="ADDRESSSTATUS" Value="Y"/> diff --git a/test/unit/gateways/payflow_test.rb b/test/unit/gateways/payflow_test.rb index bed9c171ebd..01a4ed9cb0b 100644 --- a/test/unit/gateways/payflow_test.rb +++ b/test/unit/gateways/payflow_test.rb @@ -13,18 +13,18 @@ def setup @amount = 100 @credit_card = credit_card('4242424242424242') - @options = { :billing_address => address.merge(:first_name => "Longbob", :last_name => "Longsen") } - @check = check( :name => 'Jim Smith' ) + @options = { :billing_address => address.merge(:first_name => 'Longbob', :last_name => 'Longsen') } + @check = check(:name => 'Jim Smith') end def test_successful_authorization @gateway.stubs(:ssl_post).returns(successful_authorization_response) assert response = @gateway.authorize(@amount, @credit_card, @options) - assert_equal "Approved", response.message + assert_equal 'Approved', response.message assert_success response assert response.test? - assert_equal "VUJN1A6E11D9", response.authorization + assert_equal 'VUJN1A6E11D9', response.authorization refute response.fraud_review? end @@ -32,7 +32,7 @@ def test_failed_authorization @gateway.stubs(:ssl_post).returns(failed_authorization_response) assert response = @gateway.authorize(@amount, @credit_card, @options) - assert_equal "Declined", response.message + assert_equal 'Declined', response.message assert_failure response assert response.test? end @@ -43,10 +43,37 @@ def test_authorization_with_three_d_secure_option end.check_request do |endpoint, data, headers| assert_three_d_secure REXML::Document.new(data), authorize_buyer_auth_result_path end.respond_with(successful_authorization_response) - assert_equal "Approved", response.message + assert_equal 'Approved', response.message assert_success response assert response.test? - assert_equal "VUJN1A6E11D9", response.authorization + assert_equal 'VUJN1A6E11D9', response.authorization + refute response.fraud_review? + end + + def test_successful_authorization_with_more_options + options = @options.merge( + { + order_id: '123', + description: 'Description string', + order_desc: 'OrderDesc string', + comment: 'Comment string', + comment2: 'Comment2 string' + } + ) + + response = stub_comms do + @gateway.authorize(@amount, @credit_card, options) + end.check_request do |endpoint, data, headers| + assert_match %r(<InvNum>123</InvNum>), data + assert_match %r(<Description>Description string</Description>), data + assert_match %r(<OrderDesc>OrderDesc string</OrderDesc>), data + assert_match %r(<Comment>Comment string</Comment>), data + assert_match %r(<ExtData Name=\"COMMENT2\" Value=\"Comment2 string\"/>), data + end.respond_with(successful_authorization_response) + assert_equal 'Approved', response.message + assert_success response + assert response.test? + assert_equal 'VUJN1A6E11D9', response.authorization refute response.fraud_review? end @@ -55,7 +82,7 @@ def test_successful_purchase_with_fraud_review assert response = @gateway.purchase(@amount, @credit_card, @options) assert_success response - assert_equal "126", response.params["result"] + assert_equal '126', response.params['result'] assert response.fraud_review? end @@ -66,28 +93,28 @@ def test_successful_purchase_with_three_d_secure_option assert_three_d_secure REXML::Document.new(data), purchase_buyer_auth_result_path end.respond_with(successful_purchase_with_fraud_review_response) assert_success response - assert_equal "126", response.params["result"] + assert_equal '126', response.params['result'] assert response.fraud_review? end def test_credit - @gateway.expects(:ssl_post).with(anything, regexp_matches(/<CardNum>#{@credit_card.number}<\//), anything).returns("") + @gateway.expects(:ssl_post).with(anything, regexp_matches(/<CardNum>#{@credit_card.number}<\//), anything).returns('') @gateway.expects(:parse).returns({}) @gateway.credit(@amount, @credit_card, @options) end def test_deprecated_credit - @gateway.expects(:ssl_post).with(anything, regexp_matches(/<PNRef>transaction_id<\//), anything).returns("") + @gateway.expects(:ssl_post).with(anything, regexp_matches(/<PNRef>transaction_id<\//), anything).returns('') @gateway.expects(:parse).returns({}) assert_deprecation_warning(Gateway::CREDIT_DEPRECATION_MESSAGE) do - @gateway.credit(@amount, "transaction_id", @options) + @gateway.credit(@amount, 'transaction_id', @options) end end def test_refund - @gateway.expects(:ssl_post).with(anything, regexp_matches(/<PNRef>transaction_id<\//), anything).returns("") + @gateway.expects(:ssl_post).with(anything, regexp_matches(/<PNRef>transaction_id<\//), anything).returns('') @gateway.expects(:parse).returns({}) - @gateway.refund(@amount, "transaction_id", @options) + @gateway.refund(@amount, 'transaction_id', @options) end def test_avs_result @@ -116,13 +143,13 @@ def test_cvv_result end def test_ach_purchase - @gateway.expects(:ssl_post).with(anything, regexp_matches(/<AcctNum>#{@check.account_number}<\//), anything).returns("") + @gateway.expects(:ssl_post).with(anything, regexp_matches(/<AcctNum>#{@check.account_number}<\//), anything).returns('') @gateway.expects(:parse).returns({}) @gateway.purchase(@amount, @check) end def test_ach_credit - @gateway.expects(:ssl_post).with(anything, regexp_matches(/<AcctNum>#{@check.account_number}<\//), anything).returns("") + @gateway.expects(:ssl_post).with(anything, regexp_matches(/<AcctNum>#{@check.account_number}<\//), anything).returns('') @gateway.expects(:parse).returns({}) @gateway.credit(@amount, @check) end @@ -208,7 +235,7 @@ def test_unsuccessful_verify @gateway.verify(@credit_card, @options) end.respond_with(failed_authorization_response) assert_failure response - assert_equal "Declined", response.message + assert_equal 'Declined', response.message end def test_initial_recurring_transaction_missing_parameters @@ -260,42 +287,42 @@ def test_successful_recurring_action assert_success response assert_equal 'RT0000000009', response.profile_id assert response.test? - assert_equal "R7960E739F80", response.authorization + assert_equal 'R7960E739F80', response.authorization end def test_successful_recurring_modify_action @gateway.stubs(:ssl_post).returns(successful_recurring_response) response = assert_deprecation_warning(Gateway::RECURRING_DEPRECATION_MESSAGE) do - @gateway.recurring(@amount, nil, :profile_id => "RT0000000009", :periodicity => :monthly) + @gateway.recurring(@amount, nil, :profile_id => 'RT0000000009', :periodicity => :monthly) end assert_instance_of PayflowResponse, response assert_success response assert_equal 'RT0000000009', response.profile_id assert response.test? - assert_equal "R7960E739F80", response.authorization + assert_equal 'R7960E739F80', response.authorization end def test_successful_recurring_modify_action_with_retry_num_days @gateway.stubs(:ssl_post).returns(successful_recurring_response) response = assert_deprecation_warning(Gateway::RECURRING_DEPRECATION_MESSAGE) do - @gateway.recurring(@amount, nil, :profile_id => "RT0000000009", :retry_num_days => 3, :periodicity => :monthly) + @gateway.recurring(@amount, nil, :profile_id => 'RT0000000009', :retry_num_days => 3, :periodicity => :monthly) end assert_instance_of PayflowResponse, response assert_success response assert_equal 'RT0000000009', response.profile_id assert response.test? - assert_equal "R7960E739F80", response.authorization + assert_equal 'R7960E739F80', response.authorization end def test_falied_recurring_modify_action_with_starting_at_in_the_past @gateway.stubs(:ssl_post).returns(start_date_error_recurring_response) response = assert_deprecation_warning(Gateway::RECURRING_DEPRECATION_MESSAGE) do - @gateway.recurring(@amount, nil, :profile_id => "RT0000000009", :starting_at => Date.yesterday, :periodicity => :monthly) + @gateway.recurring(@amount, nil, :profile_id => 'RT0000000009', :starting_at => Date.yesterday, :periodicity => :monthly) end assert_instance_of PayflowResponse, response @@ -303,14 +330,14 @@ def test_falied_recurring_modify_action_with_starting_at_in_the_past assert_equal 'RT0000000009', response.profile_id assert_equal 'Field format error: START or NEXTPAYMENTDATE older than last payment date', response.message assert response.test? - assert_equal "R7960E739F80", response.authorization + assert_equal 'R7960E739F80', response.authorization end def test_falied_recurring_modify_action_with_starting_at_missing_and_changed_periodicity @gateway.stubs(:ssl_post).returns(start_date_missing_recurring_response) response = assert_deprecation_warning(Gateway::RECURRING_DEPRECATION_MESSAGE) do - @gateway.recurring(@amount, nil, :profile_id => "RT0000000009", :periodicity => :yearly) + @gateway.recurring(@amount, nil, :profile_id => 'RT0000000009', :periodicity => :yearly) end assert_instance_of PayflowResponse, response @@ -318,7 +345,7 @@ def test_falied_recurring_modify_action_with_starting_at_missing_and_changed_per assert_equal 'RT0000000009', response.profile_id assert_equal 'Field format error: START field missing', response.message assert response.test? - assert_equal "R7960E739F80", response.authorization + assert_equal 'R7960E739F80', response.authorization end def test_recurring_profile_payment_history_inquiry @@ -333,28 +360,15 @@ def test_recurring_profile_payment_history_inquiry end def test_recurring_profile_payment_history_inquiry_contains_the_proper_xml - request = @gateway.send( :build_recurring_request, :inquiry, nil, :profile_id => 'RT0000000009', :history => true) + request = @gateway.send(:build_recurring_request, :inquiry, nil, :profile_id => 'RT0000000009', :history => true) assert_match %r(<PaymentHistory>Y</PaymentHistory), request end - def test_format_issue_number - xml = Builder::XmlMarkup.new - credit_card = credit_card("5641820000000005", - :brand => "switch", - :issue_number => 1 - ) - - @gateway.send(:add_credit_card, xml, credit_card) - doc = REXML::Document.new(xml.target!) - node = REXML::XPath.first(doc, '/Card/ExtData') - assert_equal '01', node.attributes['Value'] - end - def test_add_credit_card_with_three_d_secure xml = Builder::XmlMarkup.new - credit_card = credit_card("5641820000000005", - :brand => "switch", - :issue_number => 1 + credit_card = credit_card( + '5641820000000005', + :brand => 'maestro' ) @gateway.send(:add_credit_card, xml, credit_card, @options.merge(three_d_secure_option)) @@ -401,7 +415,117 @@ def test_passed_in_verbosity assert_equal '2014-06-25 09:33:41', response.params['transaction_time'] end + def test_paypal_nvp_option_sends_header + headers = @gateway.send(:build_headers, 1) + assert_not_include headers, 'PAYPAL-NVP' + + old_use_paypal_nvp = PayflowGateway.use_paypal_nvp + PayflowGateway.use_paypal_nvp = true + headers = @gateway.send(:build_headers, 1) + assert_equal 'Y', headers['PAYPAL-NVP'] + PayflowGateway.use_paypal_nvp = old_use_paypal_nvp + end + + def test_scrub + assert @gateway.supports_scrubbing? + assert_equal @gateway.scrub(pre_scrubbed), post_scrubbed + assert_equal @gateway.scrub(pre_scrubbed_check), post_scrubbed_check + end + private + + def pre_scrubbed + <<-EOS +opening connection to pilot-payflowpro.paypal.com:443... +opened +starting SSL for pilot-payflowpro.paypal.com:443... +SSL established +<- "POST / HTTP/1.1\r\nContent-Type: text/xml\r\nContent-Length: 1017\r\nX-Vps-Client-Timeout: 60\r\nX-Vps-Vit-Integration-Product: ActiveMerchant\r\nX-Vps-Vit-Runtime-Version: 2.1.7\r\nX-Vps-Request-Id: 3b2f9831949b48b4b0b89a33a60f9b0c\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nAccept: */*\r\nUser-Agent: Ruby\r\nConnection: close\r\nHost: pilot-payflowpro.paypal.com\r\n\r\n" +<- "<?xml version=\"1.0\" encoding=\"UTF-8\"?><XMLPayRequest Timeout=\"60\" version=\"2.1\" xmlns=\"http://www.paypal.com/XMLPay\"><RequestData><Vendor>spreedlyIntegrations</Vendor><Partner>PayPal</Partner><Transactions><Transaction CustRef=\"codyexample\"><Verbosity>MEDIUM</Verbosity><Sale><PayData><Invoice><EMail>cody@example.com</EMail><BillTo><Name>Jim Smith</Name><EMail>cody@example.com</EMail><Phone>(555)555-5555</Phone><CustCode>codyexample</CustCode><Address><Street>456 My Street</Street><City>Ottawa</City><State>ON</State><Country>CA</Country><Zip>K1C2N6</Zip></Address></BillTo><TotalAmt Currency=\"USD\"/></Invoice><Tender><Card><CardType>MasterCard</CardType><CardNum>5105105105105100</CardNum><ExpDate>201909</ExpDate><NameOnCard>Longbob</NameOnCard><CVNum>123</CVNum><ExtData Name=\"LASTNAME\" Value=\"Longsen\"/></Card></Tender></PayData></Sale></Transaction></Transactions></RequestData><RequestAuth><UserPass><User>spreedlyIntegrations</User><Password>L9DjqEKjXCkU</Password></UserPass></RequestAuth></XMLPayRequest>" +-> "HTTP/1.1 200 OK\r\n" +-> "Connection: close\r\n" +-> "Server: VPS-3.033.00\r\n" +-> "X-VPS-Request-ID: 3b2f9831949b48b4b0b89a33a60f9b0c\r\n" +-> "Date: Thu, 01 Mar 2018 15:42:15 GMT\r\n" +-> "Content-type: text/xml\r\n" +-> "Content-length: 267\r\n" +-> "\r\n" +reading 267 bytes... +-> "<XMLPayResponse xmlns=\"http://www.paypal.com/XMLPay\"><ResponseData><Vendor></Vendor><Partner></Partner><TransactionResults><TransactionResult><Result>4</Result><Message>Invalid amount</Message></TransactionResult></TransactionResults></ResponseData></XMLPayResponse>" +read 267 bytes +Conn close + EOS + end + + def post_scrubbed + <<-EOS +opening connection to pilot-payflowpro.paypal.com:443... +opened +starting SSL for pilot-payflowpro.paypal.com:443... +SSL established +<- "POST / HTTP/1.1\r\nContent-Type: text/xml\r\nContent-Length: 1017\r\nX-Vps-Client-Timeout: 60\r\nX-Vps-Vit-Integration-Product: ActiveMerchant\r\nX-Vps-Vit-Runtime-Version: 2.1.7\r\nX-Vps-Request-Id: 3b2f9831949b48b4b0b89a33a60f9b0c\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nAccept: */*\r\nUser-Agent: Ruby\r\nConnection: close\r\nHost: pilot-payflowpro.paypal.com\r\n\r\n" +<- "<?xml version=\"1.0\" encoding=\"UTF-8\"?><XMLPayRequest Timeout=\"60\" version=\"2.1\" xmlns=\"http://www.paypal.com/XMLPay\"><RequestData><Vendor>spreedlyIntegrations</Vendor><Partner>PayPal</Partner><Transactions><Transaction CustRef=\"codyexample\"><Verbosity>MEDIUM</Verbosity><Sale><PayData><Invoice><EMail>cody@example.com</EMail><BillTo><Name>Jim Smith</Name><EMail>cody@example.com</EMail><Phone>(555)555-5555</Phone><CustCode>codyexample</CustCode><Address><Street>456 My Street</Street><City>Ottawa</City><State>ON</State><Country>CA</Country><Zip>K1C2N6</Zip></Address></BillTo><TotalAmt Currency=\"USD\"/></Invoice><Tender><Card><CardType>MasterCard</CardType><CardNum>[FILTERED]</CardNum><ExpDate>201909</ExpDate><NameOnCard>Longbob</NameOnCard><CVNum>[FILTERED]</CVNum><ExtData Name=\"LASTNAME\" Value=\"Longsen\"/></Card></Tender></PayData></Sale></Transaction></Transactions></RequestData><RequestAuth><UserPass><User>spreedlyIntegrations</User><Password>[FILTERED]</Password></UserPass></RequestAuth></XMLPayRequest>" +-> "HTTP/1.1 200 OK\r\n" +-> "Connection: close\r\n" +-> "Server: VPS-3.033.00\r\n" +-> "X-VPS-Request-ID: 3b2f9831949b48b4b0b89a33a60f9b0c\r\n" +-> "Date: Thu, 01 Mar 2018 15:42:15 GMT\r\n" +-> "Content-type: text/xml\r\n" +-> "Content-length: 267\r\n" +-> "\r\n" +reading 267 bytes... +-> "<XMLPayResponse xmlns=\"http://www.paypal.com/XMLPay\"><ResponseData><Vendor></Vendor><Partner></Partner><TransactionResults><TransactionResult><Result>4</Result><Message>Invalid amount</Message></TransactionResult></TransactionResults></ResponseData></XMLPayResponse>" +read 267 bytes +Conn close + EOS + end + + def pre_scrubbed_check + <<-EOS +opening connection to pilot-payflowpro.paypal.com:443... +opened +starting SSL for pilot-payflowpro.paypal.com:443... +SSL established +<- "POST / HTTP/1.1\r\nContent-Type: text/xml\r\nContent-Length: 658\r\nX-Vps-Client-Timeout: 60\r\nX-Vps-Vit-Integration-Product: ActiveMerchant\r\nX-Vps-Vit-Runtime-Version: 2.1.7\r\nX-Vps-Request-Id: 863021e6890a0660238ef22d0a21c5f2\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nAccept: */*\r\nUser-Agent: Ruby\r\nConnection: close\r\nHost: pilot-payflowpro.paypal.com\r\n\r\n" +<- "<?xml version=\"1.0\" encoding=\"UTF-8\"?><XMLPayRequest Timeout=\"60\" version=\"2.1\" xmlns=\"http://www.paypal.com/XMLPay\"><RequestData><Vendor>spreedlyIntegrations</Vendor><Partner>PayPal</Partner><Transactions><Transaction CustRef=\"codyexample\"><Verbosity>MEDIUM</Verbosity><Sale><PayData><Invoice><BillTo><Name>Jim Smith</Name></BillTo><TotalAmt Currency=\"USD\"/></Invoice><Tender><ACH><AcctType>C</AcctType><AcctNum>1234567801</AcctNum><ABA>111111118</ABA></ACH></Tender></PayData></Sale></Transaction></Transactions></RequestData><RequestAuth><UserPass><User>spreedlyIntegrations</User><Password>L9DjqEKjXCkU</Password></UserPass></RequestAuth></XMLPayRequest>" +-> "HTTP/1.1 200 OK\r\n" +-> "Connection: close\r\n" +-> "Server: VPS-3.033.00\r\n" +-> "X-VPS-Request-ID: 863021e6890a0660238ef22d0a21c5f2\r\n" +-> "Date: Thu, 01 Mar 2018 15:45:59 GMT\r\n" +-> "Content-type: text/xml\r\n" +-> "Content-length: 267\r\n" +-> "\r\n" +reading 267 bytes... +-> "<XMLPayResponse xmlns=\"http://www.paypal.com/XMLPay\"><ResponseData><Vendor></Vendor><Partner></Partner><TransactionResults><TransactionResult><Result>4</Result><Message>Invalid amount</Message></TransactionResult></TransactionResults></ResponseData></XMLPayResponse>" +read 267 bytes +Conn close + EOS + end + + def post_scrubbed_check + <<-EOS +opening connection to pilot-payflowpro.paypal.com:443... +opened +starting SSL for pilot-payflowpro.paypal.com:443... +SSL established +<- "POST / HTTP/1.1\r\nContent-Type: text/xml\r\nContent-Length: 658\r\nX-Vps-Client-Timeout: 60\r\nX-Vps-Vit-Integration-Product: ActiveMerchant\r\nX-Vps-Vit-Runtime-Version: 2.1.7\r\nX-Vps-Request-Id: 863021e6890a0660238ef22d0a21c5f2\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nAccept: */*\r\nUser-Agent: Ruby\r\nConnection: close\r\nHost: pilot-payflowpro.paypal.com\r\n\r\n" +<- "<?xml version=\"1.0\" encoding=\"UTF-8\"?><XMLPayRequest Timeout=\"60\" version=\"2.1\" xmlns=\"http://www.paypal.com/XMLPay\"><RequestData><Vendor>spreedlyIntegrations</Vendor><Partner>PayPal</Partner><Transactions><Transaction CustRef=\"codyexample\"><Verbosity>MEDIUM</Verbosity><Sale><PayData><Invoice><BillTo><Name>Jim Smith</Name></BillTo><TotalAmt Currency=\"USD\"/></Invoice><Tender><ACH><AcctType>C</AcctType><AcctNum>[FILTERED]</AcctNum><ABA>111111118</ABA></ACH></Tender></PayData></Sale></Transaction></Transactions></RequestData><RequestAuth><UserPass><User>spreedlyIntegrations</User><Password>[FILTERED]</Password></UserPass></RequestAuth></XMLPayRequest>" +-> "HTTP/1.1 200 OK\r\n" +-> "Connection: close\r\n" +-> "Server: VPS-3.033.00\r\n" +-> "X-VPS-Request-ID: 863021e6890a0660238ef22d0a21c5f2\r\n" +-> "Date: Thu, 01 Mar 2018 15:45:59 GMT\r\n" +-> "Content-type: text/xml\r\n" +-> "Content-length: 267\r\n" +-> "\r\n" +reading 267 bytes... +-> "<XMLPayResponse xmlns=\"http://www.paypal.com/XMLPay\"><ResponseData><Vendor></Vendor><Partner></Partner><TransactionResults><TransactionResult><Result>4</Result><Message>Invalid amount</Message></TransactionResult></TransactionResults></ResponseData></XMLPayResponse>" +read 267 bytes +Conn close + EOS + end + def successful_recurring_response <<-XML <ResponseData> @@ -416,7 +540,7 @@ def successful_recurring_response end def start_date_error_recurring_response - <<-XML + <<-XML <ResponseData> <Result>0</Result> <Message>Field format error: START or NEXTPAYMENTDATE older than last payment date</Message> @@ -429,7 +553,7 @@ def start_date_error_recurring_response end def start_date_missing_recurring_response - <<-XML + <<-XML <ResponseData> <Result>0</Result> <Message>Field format error: START field missing</Message> diff --git a/test/unit/gateways/payflow_uk_test.rb b/test/unit/gateways/payflow_uk_test.rb index 53c41fcfd20..9d50c599edd 100644 --- a/test/unit/gateways/payflow_uk_test.rb +++ b/test/unit/gateways/payflow_uk_test.rb @@ -11,20 +11,20 @@ def setup def test_default_currency assert_equal 'GBP', PayflowUkGateway.default_currency end - + def test_express_instance assert_instance_of PayflowExpressUkGateway, @gateway.express end - + def test_default_partner assert_equal 'PayPalUk', PayflowUkGateway.partner end - + def test_supported_countries assert_equal ['GB'], PayflowUkGateway.supported_countries end - + def test_supported_card_types - assert_equal [:visa, :master, :american_express, :discover, :solo, :switch], PayflowUkGateway.supported_cardtypes + assert_equal [:visa, :master, :american_express, :discover], PayflowUkGateway.supported_cardtypes end end diff --git a/test/unit/gateways/payment_express_test.rb b/test/unit/gateways/payment_express_test.rb index d97343b8ea6..54489838560 100644 --- a/test/unit/gateways/payment_express_test.rb +++ b/test/unit/gateways/payment_express_test.rb @@ -11,7 +11,7 @@ def setup @visa = credit_card - @solo = credit_card("6334900000000005", :brand => "solo", :issue_number => '01') + @solo = credit_card('6334900000000005', :brand => 'maestro') @options = { :order_id => generate_unique_id, @@ -74,9 +74,9 @@ def test_successful_card_store end def test_successful_card_store_with_custom_billing_id - @gateway.expects(:ssl_post).returns(successful_store_response(:billing_id => "my-custom-id")) + @gateway.expects(:ssl_post).returns(successful_store_response(:billing_id => 'my-custom-id')) - assert response = @gateway.store(@visa, :billing_id => "my-custom-id") + assert response = @gateway.store(@visa, :billing_id => 'my-custom-id') assert_success response assert response.test? assert_equal 'my-custom-id', response.token @@ -158,9 +158,9 @@ def test_expect_no_optional_fields_by_default def test_pass_optional_txn_data options = { - :txn_data1 => "Transaction Data 1", - :txn_data2 => "Transaction Data 2", - :txn_data3 => "Transaction Data 3" + :txn_data1 => 'Transaction Data 1', + :txn_data2 => 'Transaction Data 2', + :txn_data3 => 'Transaction Data 3' } perform_each_transaction_type_with_request_body_assertions(options) do |body| @@ -172,12 +172,12 @@ def test_pass_optional_txn_data def test_pass_optional_txn_data_truncated_to_255_chars options = { - :txn_data1 => "Transaction Data 1-01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345-EXTRA", - :txn_data2 => "Transaction Data 2-01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345-EXTRA", - :txn_data3 => "Transaction Data 3-01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345-EXTRA" + :txn_data1 => 'Transaction Data 1-01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345-EXTRA', + :txn_data2 => 'Transaction Data 2-01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345-EXTRA', + :txn_data3 => 'Transaction Data 3-01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345-EXTRA' } - truncated_addendum = "01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345" + truncated_addendum = '01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345' perform_each_transaction_type_with_request_body_assertions(options) do |body| assert_match(/<TxnData1>Transaction Data 1-#{truncated_addendum}<\/TxnData1>/, body) @@ -244,7 +244,7 @@ def test_pass_client_type_as_symbol_for_unknown_type_omits_element def test_purchase_truncates_order_id_to_16_chars stub_comms do - @gateway.purchase(@amount, @visa, {:order_id => "16chars---------EXTRA"}) + @gateway.purchase(@amount, @visa, {:order_id => '16chars---------EXTRA'}) end.check_request do |endpoint, data, headers| assert_match(/<TxnId>16chars---------<\/TxnId>/, data) end.respond_with(successful_authorization_response) @@ -252,7 +252,7 @@ def test_purchase_truncates_order_id_to_16_chars def test_authorize_truncates_order_id_to_16_chars stub_comms do - @gateway.authorize(@amount, @visa, {:order_id => "16chars---------EXTRA"}) + @gateway.authorize(@amount, @visa, {:order_id => '16chars---------EXTRA'}) end.check_request do |endpoint, data, headers| assert_match(/<TxnId>16chars---------<\/TxnId>/, data) end.respond_with(successful_authorization_response) @@ -260,7 +260,7 @@ def test_authorize_truncates_order_id_to_16_chars def test_capture_truncates_order_id_to_16_chars stub_comms do - @gateway.capture(@amount, 'identification', {:order_id => "16chars---------EXTRA"}) + @gateway.capture(@amount, 'identification', {:order_id => '16chars---------EXTRA'}) end.check_request do |endpoint, data, headers| assert_match(/<TxnId>16chars---------<\/TxnId>/, data) end.respond_with(successful_authorization_response) @@ -268,7 +268,7 @@ def test_capture_truncates_order_id_to_16_chars def test_refund_truncates_order_id_to_16_chars stub_comms do - @gateway.refund(@amount, 'identification', {:description => 'refund', :order_id => "16chars---------EXTRA"}) + @gateway.refund(@amount, 'identification', {:description => 'refund', :order_id => '16chars---------EXTRA'}) end.check_request do |endpoint, data, headers| assert_match(/<TxnId>16chars---------<\/TxnId>/, data) end.respond_with(successful_authorization_response) @@ -276,7 +276,7 @@ def test_refund_truncates_order_id_to_16_chars def test_purchase_truncates_description_to_50_chars stub_comms do - @gateway.purchase(@amount, @visa, {:description => "50chars-------------------------------------------EXTRA"}) + @gateway.purchase(@amount, @visa, {:description => '50chars-------------------------------------------EXTRA'}) end.check_request do |endpoint, data, headers| assert_match(/<MerchantReference>50chars-------------------------------------------<\/MerchantReference>/, data) end.respond_with(successful_authorization_response) @@ -284,7 +284,7 @@ def test_purchase_truncates_description_to_50_chars def test_authorize_truncates_description_to_50_chars stub_comms do - @gateway.authorize(@amount, @visa, {:description => "50chars-------------------------------------------EXTRA"}) + @gateway.authorize(@amount, @visa, {:description => '50chars-------------------------------------------EXTRA'}) end.check_request do |endpoint, data, headers| assert_match(/<MerchantReference>50chars-------------------------------------------<\/MerchantReference>/, data) end.respond_with(successful_authorization_response) @@ -292,7 +292,7 @@ def test_authorize_truncates_description_to_50_chars def test_capture_truncates_description_to_50_chars stub_comms do - @gateway.capture(@amount, 'identification', {:description => "50chars-------------------------------------------EXTRA"}) + @gateway.capture(@amount, 'identification', {:description => '50chars-------------------------------------------EXTRA'}) end.check_request do |endpoint, data, headers| assert_match(/<MerchantReference>50chars-------------------------------------------<\/MerchantReference>/, data) end.respond_with(successful_authorization_response) @@ -300,7 +300,7 @@ def test_capture_truncates_description_to_50_chars def test_refund_truncates_description_to_50_chars stub_comms do - @gateway.capture(@amount, 'identification', {:description => "50chars-------------------------------------------EXTRA"}) + @gateway.capture(@amount, 'identification', {:description => '50chars-------------------------------------------EXTRA'}) end.check_request do |endpoint, data, headers| assert_match(/<MerchantReference>50chars-------------------------------------------<\/MerchantReference>/, data) end.respond_with(successful_authorization_response) @@ -336,7 +336,7 @@ def perform_each_transaction_type_with_request_body_assertions(options = {}) # refund stub_comms do - @gateway.refund(@amount, 'identification', {:description => "description"}.merge(options)) + @gateway.refund(@amount, 'identification', {:description => 'description'}.merge(options)) end.check_request do |endpoint, data, headers| yield data end.respond_with(successful_authorization_response) @@ -433,6 +433,6 @@ def transcript end def scrubbed_transcript - %(<Txn><CardHolderName>Longbob Longsen</CardHolderName><CardNumber>[FILTERED]</CardNumber><DateExpiry>0916</DateExpiry><Cvc2>[FILTERED]</Cvc2><Cvc2Presence>1</Cvc2Presence><Amount>1.00</Amount><InputCurrency>NZD</InputCurrency><TxnId>59956b468905bde7</TxnId><MerchantReference>Store purchase</MerchantReference><EnableAvsData>1</EnableAvsData><AvsAction>1</AvsAction><AvsStreetAddress>456 My Street</AvsStreetAddress><AvsPostCode>K1C2N6</AvsPostCode><PostUsername>WaysactDev</PostUsername><PostPassword>kvr52dw9</PostPassword><TxnType>Purchase</TxnType></Txn>) + %(<Txn><CardHolderName>Longbob Longsen</CardHolderName><CardNumber>[FILTERED]</CardNumber><DateExpiry>0916</DateExpiry><Cvc2>[FILTERED]</Cvc2><Cvc2Presence>1</Cvc2Presence><Amount>1.00</Amount><InputCurrency>NZD</InputCurrency><TxnId>59956b468905bde7</TxnId><MerchantReference>Store purchase</MerchantReference><EnableAvsData>1</EnableAvsData><AvsAction>1</AvsAction><AvsStreetAddress>456 My Street</AvsStreetAddress><AvsPostCode>K1C2N6</AvsPostCode><PostUsername>WaysactDev</PostUsername><PostPassword>[FILTERED]</PostPassword><TxnType>Purchase</TxnType></Txn>) end end diff --git a/test/unit/gateways/paymentez_test.rb b/test/unit/gateways/paymentez_test.rb new file mode 100644 index 00000000000..331c283b417 --- /dev/null +++ b/test/unit/gateways/paymentez_test.rb @@ -0,0 +1,456 @@ +require 'test_helper' + +class PaymentezTest < Test::Unit::TestCase + include CommStub + + def setup + @gateway = PaymentezGateway.new(application_code: 'foo', app_key: 'bar') + @credit_card = credit_card + @amount = 100 + + @options = { + order_id: '1', + user_id: '123', + billing_address: address, + description: 'Store Purchase', + email: 'a@b.com' + } + end + + def test_successful_purchase + @gateway.expects(:ssl_post).returns(successful_purchase_response) + + response = @gateway.purchase(@amount, @credit_card, @options) + assert_success response + + assert_equal 'PR-926', response.authorization + assert response.test? + end + + def test_successful_purchase_with_token + @gateway.expects(:ssl_post).returns(successful_purchase_response) + + response = @gateway.purchase(@amount, '123456789012345678901234567890', @options) + assert_success response + + assert_equal 'PR-926', response.authorization + assert response.test? + end + + def test_failed_purchase + @gateway.expects(:ssl_post).returns(failed_purchase_response) + + response = @gateway.purchase(@amount, @credit_card, @options) + assert_failure response + assert_equal Gateway::STANDARD_ERROR_CODE[:card_declined], response.error_code + end + + def test_expired_card + @gateway.expects(:ssl_post).returns(expired_card_response) + + response = @gateway.purchase(@amount, @credit_card, @options) + assert_failure response + assert_equal Gateway::STANDARD_ERROR_CODE[:card_declined], response.error_code + assert_equal 'Expired card', response.message + end + + def test_successful_authorize + @gateway.stubs(:ssl_post).returns(successful_authorize_response) + + response = @gateway.authorize(@amount, @credit_card, @options) + assert_success response + assert_equal 'CI-635', response.authorization + assert response.test? + end + + def test_successful_authorize_with_token + @gateway.stubs(:ssl_post).returns(successful_authorize_response) + + response = @gateway.authorize(@amount, '123456789012345678901234567890', @options) + assert_success response + assert_equal 'CI-635', response.authorization + assert response.test? + end + + def test_failed_authorize + @gateway.expects(:ssl_post).returns(failed_authorize_response) + + response = @gateway.authorize(@amount, @credit_card, @options) + assert_failure response + assert response.test? + end + + def test_successful_capture + @gateway.expects(:ssl_post).returns(successful_capture_response) + + response = @gateway.capture(nil, '1234', @options) + assert_success response + assert_equal 'CI-635', response.authorization + assert response.test? + end + + def test_successful_capture_with_amount + @gateway.expects(:ssl_post).returns(successful_capture_response) + + response = @gateway.capture(@amount + 1, '1234', @options) + assert_success response + assert_equal 'CI-635', response.authorization + assert response.test? + end + + def test_failed_capture + @gateway.expects(:ssl_post).returns(failed_capture_response) + + response = @gateway.capture(@amount, '1234', @options) + assert_failure response + assert response.test? + end + + def test_successful_refund + @gateway.expects(:ssl_post).returns(successful_refund_response) + + response = @gateway.refund(nil, '1234', @options) + assert_success response + assert response.test? + end + + def test_partial_refund + response = stub_comms do + @gateway.refund(@amount, '1234', @options) + end.check_request do |_endpoint, data, _headers| + assert_match(/"amount":1.0/, data) + end.respond_with(successful_refund_response) + assert_success response + assert response.test? + end + + def test_failed_refund + @gateway.expects(:ssl_post).returns(failed_refund_response) + + response = @gateway.refund(@amount, '1234', @options) + assert_failure response + assert response.test? + end + + def test_successful_void + @gateway.expects(:ssl_post).returns(successful_void_response) + + response = @gateway.void('1234', @options) + assert_success response + assert response.test? + end + + def test_failed_void + @gateway.expects(:ssl_post).returns(failed_void_response) + + response = @gateway.void('1234', @options) + assert_failure response + end + + def test_simple_store + @gateway.expects(:ssl_post).returns(successful_store_response) + + response = @gateway.store(@credit_card, @options) + assert_success response + assert_equal '14436664108567261211', response.authorization + end + + def test_complex_store + @gateway.stubs(:ssl_post).returns(already_stored_response, successful_unstore_response, successful_store_response) + + response = @gateway.store(@credit_card, @options) + assert_success response + end + + def test_paymentez_crashes_fail + @gateway.stubs(:ssl_post).returns(crash_response) + + response = @gateway.purchase(@amount, @credit_card, @options) + assert_failure response + assert_equal Gateway::STANDARD_ERROR_CODE[:processing_error], response.error_code + end + + def test_scrub + assert @gateway.supports_scrubbing? + assert_equal @gateway.scrub(pre_scrubbed), post_scrubbed + end + + private + + def pre_scrubbed + %q( +opening connection to ccapi-stg.paymentez.com:443... +opened +starting SSL for ccapi-stg.paymentez.com:443... +SSL established +<- "POST /v2/transaction/debit_cc HTTP/1.1\r\nContent-Type: application/json\r\nAuth-Token: U1BETFktTVgtU0VSVkVSOzE1MTM3MDU5OTc7M8I1MjQ1NT5yMWNlZWU0ZjFlYTdiZDBlOGE1MWIxZjBkYzBjZTMyYjZmN2RmNjE4ZGQ5MmNiODhjMTM5MWIyNg==\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nAccept: */*\r\nUser-Agent: Ruby\r\nConnection: close\r\nHost: ccapi-stg.paymentez.com\r\nContent-Length: 264\r\n\r\n" +<- "{\"order\":{\"amount\":1.0,\"vat\":0,\"dev_reference\":\"Testing\",\"description\":\"Store Purchase\"},\"card\":{\"number\":\"4111111111111111\",\"holder_name\":\"Longbob Longsen\",\"expiry_month\":9,\"expiry_year\":2018,\"cvc\":\"123\",\"type\":\"vi\"},\"user\":{\"id\":\"123\",\"email\":\"joe@example.com\"}}" +-> "HTTP/1.1 200 OK\r\n" +-> "Server: nginx/1.12.1\r\n" +-> "Date: Tue, 19 Dec 2017 17:51:42 GMT\r\n" +-> "Content-Type: application/json\r\n" +-> "Content-Length: 402\r\n" +-> "Connection: close\r\n" +-> "Vary: Accept-Language, Cookie\r\n" +-> "Content-Language: es\r\n" +-> "\r\n" +reading 402 bytes... +-> "{\"transaction\": {\"status\": \"success\", \"payment_date\": \"2017-12-19T17:51:39.985\", \"amount\": 1.0, \"authorization_code\": \"123456\", \"installments\": 1, \"dev_reference\": \"Testing\", \"message\": \"Response by mock\", \"carrier_code\": \"00\", \"id\": \"PR-871\", \"status_detail\": 3}, \"card\": {\"bin\": \"411111\", \"expiry_year\": \"2018\", \"expiry_month\": \"9\", \"transaction_reference\": \"PR-871\", \"type\": \"vi\", \"number\": \"1111\"}}" +read 402 bytes +Conn close + ) + end + + def post_scrubbed + %q( +opening connection to ccapi-stg.paymentez.com:443... +opened +starting SSL for ccapi-stg.paymentez.com:443... +SSL established +<- "POST /v2/transaction/debit_cc HTTP/1.1\r\nContent-Type: application/json\r\nAuth-Token: [FILTERED]\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nAccept: */*\r\nUser-Agent: Ruby\r\nConnection: close\r\nHost: ccapi-stg.paymentez.com\r\nContent-Length: 264\r\n\r\n" +<- "{\"order\":{\"amount\":1.0,\"vat\":0,\"dev_reference\":\"Testing\",\"description\":\"Store Purchase\"},\"card\":{\"number\":[FILTERED],\"holder_name\":\"Longbob Longsen\",\"expiry_month\":9,\"expiry_year\":2018,\"cvc\":[FILTERED],\"type\":\"vi\"},\"user\":{\"id\":\"123\",\"email\":\"joe@example.com\"}}" +-> "HTTP/1.1 200 OK\r\n" +-> "Server: nginx/1.12.1\r\n" +-> "Date: Tue, 19 Dec 2017 17:51:42 GMT\r\n" +-> "Content-Type: application/json\r\n" +-> "Content-Length: 402\r\n" +-> "Connection: close\r\n" +-> "Vary: Accept-Language, Cookie\r\n" +-> "Content-Language: es\r\n" +-> "\r\n" +reading 402 bytes... +-> "{\"transaction\": {\"status\": \"success\", \"payment_date\": \"2017-12-19T17:51:39.985\", \"amount\": 1.0, \"authorization_code\": \"123456\", \"installments\": 1, \"dev_reference\": \"Testing\", \"message\": \"Response by mock\", \"carrier_code\": \"00\", \"id\": \"PR-871\", \"status_detail\": 3}, \"card\": {\"bin\": \"411111\", \"expiry_year\": \"2018\", \"expiry_month\": \"9\", \"transaction_reference\": \"PR-871\", \"type\": \"vi\", \"number\": \"1111\"}}" +read 402 bytes +Conn close + ) + end + + def successful_purchase_response + ' + { + "transaction": { + "status": "success", + "payment_date": "2017-12-19T20:29:12.715", + "amount": 1, + "authorization_code": "123456", + "installments": 1, + "dev_reference": "Testing", + "message": "Response by mock", + "carrier_code": "00", + "id": "PR-926", + "status_detail": 3 + }, + "card": { + "bin": "411111", + "expiry_year": "2018", + "expiry_month": "9", + "transaction_reference": "PR-926", + "type": "vi", + "number": "1111" + } + } + ' + end + + def failed_purchase_response + ' + { + "transaction": { + "status": "failure", + "payment_date": null, + "amount": 1, + "authorization_code": null, + "installments": 1, + "dev_reference": "Testing", + "message": "Response by mock", + "carrier_code": "3", + "id": "PR-945", + "status_detail": 9 + }, + "card": { + "bin": "424242", + "expiry_year": "2018", + "expiry_month": "9", + "transaction_reference": "PR-945", + "type": "vi", + "number": "4242" + } + } + ' + end + + def successful_authorize_response + ' + { + "transaction": { + "status": "success", + "payment_date": "2017-12-21T18:04:42", + "amount": 1, + "authorization_code": "487897", + "installments": 1, + "dev_reference": "Testing", + "message": "Operation Successful", + "carrier_code": "4", + "id": "CI-635", + "status_detail": 0 + }, + "card": { + "bin": "411111", + "status": "valid", + "token": "12032069702317830187", + "expiry_year": "2018", + "expiry_month": "9", + "transaction_reference": "CI-635", + "type": "vi", + "number": "1111" + } + } + ' + end + + def failed_authorize_response + ' + { + "transaction": { + "status": "failure", + "payment_date": null, + "amount": 1.0, + "authorization_code": null, + "installments": 1, + "dev_reference": "Testing", + "message": null, + "carrier_code": "3", + "id": "CI-1223", + "status_detail": 9 + }, + "card": { + "bin": "424242", + "status": null, + "token": "6461587429110733892", + "expiry_year": "2019", + "expiry_month": "9", + "transaction_reference": "CI-1223", + "type": "vi", + "number": "4242", + "origin": "Paymentez" + } + } + ' + end + + def successful_capture_response + ' + { + "transaction": { + "status": "success", + "payment_date": "2017-12-21T18:04:42", + "amount": 1, + "authorization_code": "487897", + "installments": 1, + "dev_reference": "Testing", + "message": "Operation Successful", + "carrier_code": "6", + "id": "CI-635", + "status_detail": 3 + }, + "card": { + "bin": "411111", + "status": "valid", + "token": "12032069702317830187", + "expiry_year": "2018", + "expiry_month": "9", + "transaction_reference": "CI-635", + "type": "vi", + "number": "1111" + } + } + ' + end + + def failed_capture_response + '{"error": {"type": "Carrier not supported", "help": "", "description": "{}"}}' + end + + def successful_void_response + '{"status": "success", "detail": "Completed"}' + end + + def failed_void_response + '{"error": {"type": "Carrier not supported", "help": "", "description": "{}"}}' + end + + alias_method :successful_refund_response, :successful_void_response + alias_method :failed_refund_response, :failed_void_response + + def already_stored_response + '{"error": {"type": "Card already added: 14436664108567261211", "help": "If you want to update the card, first delete it", "description": "{}"}}' + end + + def successful_unstore_response + '{"message": "card deleted"}' + end + + def successful_store_response + '{"card": {"bin": "411111", "status": "valid", "token": "14436664108567261211", "message": "", "expiry_year": "2018", "expiry_month": "9", "transaction_reference": "PR-959", "type": "vi", "number": "1111"}}' + end + + def failed_store_response + ' + { + "card": { + "bin": "424242", + "status": "rejected", + "token": "2026849624512750545", + "message": "Not Authorized", + "expiry_year": "2018", + "expiry_month": "9", + "transaction_reference": "CI-606", + "type": "vi", + "number": "4242" + } + } + ' + end + + def expired_card_response + ' + { + "transaction":{ + "status":"failure", + "payment_date":null, + "amount":1.0, + "authorization_code":null, + "installments":1, + "dev_reference":"ci123", + "message":"Expired card", + "carrier_code":"54", + "id":"PR-25", + "status_detail":9 + }, + "card":{ + "bin":"528851", + "expiry_year":"2024", + "expiry_month":"4", + "transaction_reference":"PR-25", + "type":"mc", + "number":"9794", + "origin":"Paymentez" + } + } + ' + end + + def crash_response + ' + <html> + <head> + <title>Internal Server Error</title> + </head> + <body> + <h1><p>Internal Server Error</p></h1> + + </body> + </html> + ' + end +end diff --git a/test/unit/gateways/paymill_test.rb b/test/unit/gateways/paymill_test.rb index 7db94b84ab4..546a98b9125 100644 --- a/test/unit/gateways/paymill_test.rb +++ b/test/unit/gateways/paymill_test.rb @@ -13,13 +13,13 @@ def test_successful_purchase assert response = @gateway.purchase(@amount, @credit_card) assert_success response - assert_equal "tran_c94ba7df2dae8fd55028df41173c;", response.authorization - assert_equal "Operation successful", response.message + assert_equal 'tran_c94ba7df2dae8fd55028df41173c;', response.authorization + assert_equal 'Operation successful', response.message assert_equal 20000, response.params['data']['response_code'] assert_equal 'pay_b8e6a28fc5e5e1601cdbefbaeb8a', response.params['data']['payment']['id'] assert_equal '5100', response.params['data']['payment']['last4'] - assert_nil response.cvv_result["message"] - assert_nil response.avs_result["message"] + assert_nil response.cvv_result['message'] + assert_nil response.avs_result['message'] assert response.test? end @@ -81,19 +81,19 @@ def test_successful_authorize_and_capture assert_success response assert response.test? - assert_equal "tran_4c612d5293e26d56d986eb89648c;preauth_fdf916cab73b97c4a139", response.authorization - assert_equal "Operation successful", response.message + assert_equal 'tran_4c612d5293e26d56d986eb89648c;preauth_fdf916cab73b97c4a139', response.authorization + assert_equal 'Operation successful', response.message assert_equal '0004', response.params['data']['payment']['last4'] assert_equal 20000, response.params['data']['response_code'] - assert_nil response.avs_result["message"] - assert_nil response.cvv_result["message"] + assert_nil response.avs_result['message'] + assert_nil response.cvv_result['message'] @gateway.expects(:raw_ssl_request).returns(successful_capture_response) response = @gateway.capture(@amount, response.authorization) assert_success response assert response.test? assert_equal 20000, response.params['data']['response_code'] - assert_equal "Operation successful", response.message + assert_equal 'Operation successful', response.message end def test_failed_authorize @@ -114,7 +114,7 @@ def test_successful_authorize_and_void response = @gateway.void(response.authorization) assert_success response assert response.test? - assert_equal "Transaction approved.", response.message + assert_equal 'Transaction approved.', response.message end def test_failed_capture @@ -176,7 +176,7 @@ def test_successful_store assert response = @gateway.store(@credit_card) assert_success response - assert_equal "tok_4f9a571b39bd8d0b4db5", response.authorization + assert_equal 'tok_4f9a571b39bd8d0b4db5', response.authorization assert_equal "Request successfully processed in 'Merchant in Connector Test Mode'", response.message assert response.test? end @@ -192,31 +192,31 @@ def test_failed_store_with_invalid_credit_card def test_successful_purchase_with_token @gateway.stubs(:raw_ssl_request).returns(successful_purchase_response) - assert response = @gateway.purchase(@amount, "token") + assert response = @gateway.purchase(@amount, 'token') assert_success response - assert_equal "tran_c94ba7df2dae8fd55028df41173c;", response.authorization - assert_equal "Operation successful", response.message + assert_equal 'tran_c94ba7df2dae8fd55028df41173c;', response.authorization + assert_equal 'Operation successful', response.message assert_equal 20000, response.params['data']['response_code'] assert_equal 'pay_b8e6a28fc5e5e1601cdbefbaeb8a', response.params['data']['payment']['id'] assert_equal '5100', response.params['data']['payment']['last4'] - assert_nil response.cvv_result["message"] - assert_nil response.avs_result["message"] + assert_nil response.cvv_result['message'] + assert_nil response.avs_result['message'] assert response.test? end def test_successful_authorize_with_token @gateway.stubs(:raw_ssl_request).returns(successful_authorize_response) - assert response = @gateway.authorize(@amount, "token") + assert response = @gateway.authorize(@amount, 'token') assert_success response assert response.test? - assert_equal "tran_4c612d5293e26d56d986eb89648c;preauth_fdf916cab73b97c4a139", response.authorization - assert_equal "Operation successful", response.message + assert_equal 'tran_4c612d5293e26d56d986eb89648c;preauth_fdf916cab73b97c4a139', response.authorization + assert_equal 'Operation successful', response.message assert_equal '0004', response.params['data']['payment']['last4'] assert_equal 20000, response.params['data']['response_code'] - assert_nil response.avs_result["message"] - assert_nil response.cvv_result["message"] + assert_nil response.avs_result['message'] + assert_nil response.cvv_result['message'] end def test_transcript_scrubbing @@ -224,6 +224,7 @@ def test_transcript_scrubbing end private + def successful_store_response MockResponse.new 200, %[jsonPFunction({"transaction":{"mode":"CONNECTOR_TEST","channel":"57313835619696ac361dc591bc973626","response":"SYNC","payment":{"code":"CC.DB"},"processing":{"code":"CC.DB.90.00","reason":{"code":"00","message":"Successful Processing"},"result":"ACK","return":{"code":"000.100.112","message":"Request successfully processed in 'Merchant in Connector Test Mode'"},"timestamp":"2013-02-12 21:33:43"},"identification":{"shortId":"1998.1832.1612","uniqueId":"tok_4f9a571b39bd8d0b4db5"}}})] end @@ -751,11 +752,11 @@ def failed_capture_response end def transcript - "connection_uri=https://test-token.paymill.com?account.number=5500000000000004&account.expiry.month=09&account.expiry.year=2016&account.verification=123" + 'connection_uri=https://test-token.paymill.com?account.number=5500000000000004&account.expiry.month=09&account.expiry.year=2016&account.verification=123' end def scrubbed_transcript - "connection_uri=https://test-token.paymill.com?account.number=[FILTERED]&account.expiry.month=09&account.expiry.year=2016&account.verification=[FILTERED]" + 'connection_uri=https://test-token.paymill.com?account.number=[FILTERED]&account.expiry.month=09&account.expiry.year=2016&account.verification=[FILTERED]' end end diff --git a/test/unit/gateways/paypal/paypal_common_api_test.rb b/test/unit/gateways/paypal/paypal_common_api_test.rb index 7428848a955..49751604ab9 100644 --- a/test/unit/gateways/paypal/paypal_common_api_test.rb +++ b/test/unit/gateways/paypal/paypal_common_api_test.rb @@ -6,7 +6,9 @@ class CommonPaypalGateway < ActiveMerchant::Billing::Gateway include ActiveMerchant::Billing::PaypalCommonAPI def currency(code); 'USD'; end + def localized_amount(num, code); num; end + def commit(a, b); end end @@ -21,15 +23,16 @@ def setup :pem => 'PEM' ) - @address = { :address1 => '1234 My Street', - :address2 => 'Apt 1', - :company => 'Widgets Inc', - :city => 'Ottawa', - :state => 'ON', - :zip => 'K1C2N6', - :country => 'Canada', - :phone => '(555)555-5555' - } + @address = { + :address1 => '1234 My Street', + :address2 => 'Apt 1', + :company => 'Widgets Inc', + :city => 'Ottawa', + :state => 'ON', + :zip => 'K1C2N6', + :country => 'Canada', + :phone => '(555)555-5555' + } end def xml_builder @@ -83,7 +86,7 @@ def test_build_request_wrapper_plain def test_build_request_wrapper_with_request_details result = @gateway.send(:build_request_wrapper, 'Action', :request_details => true) do |xml| - xml.tag! 'n2:TransactionID', 'baz' + xml.tag! 'n2:TransactionID', 'baz' end assert_equal 'baz', REXML::XPath.first(REXML::Document.new(result), '//ActionReq/ActionRequest/n2:ActionRequestDetails/n2:TransactionID').text end @@ -115,14 +118,13 @@ def test_balance_cleans_up_currencies_values_like_0 end def test_build_do_authorize_request - request = REXML::Document.new(@gateway.send(:build_do_authorize,123, 100, :currency => 'USD')) + request = REXML::Document.new(@gateway.send(:build_do_authorize, 123, 100, :currency => 'USD')) assert_equal '123', REXML::XPath.first(request, '//DoAuthorizationReq/DoAuthorizationRequest/TransactionID').text assert_equal '1.00', REXML::XPath.first(request, '//DoAuthorizationReq/DoAuthorizationRequest/Amount').text end - def test_build_manage_pending_transaction_status_request - request = REXML::Document.new(@gateway.send(:build_manage_pending_transaction_status,123, 'Accept')) + request = REXML::Document.new(@gateway.send(:build_manage_pending_transaction_status, 123, 'Accept')) assert_equal '123', REXML::XPath.first(request, '//ManagePendingTransactionStatusReq/ManagePendingTransactionStatusRequest/TransactionID').text assert_equal 'Accept', REXML::XPath.first(request, '//ManagePendingTransactionStatusReq/ManagePendingTransactionStatusRequest/Action').text end @@ -134,10 +136,12 @@ def test_transaction_search_requires end def test_build_transaction_search_request - options = {:start_date => DateTime.new(2012, 2, 21, 0), + options = { + :start_date => DateTime.new(2012, 2, 21, 0), :end_date => DateTime.new(2012, 3, 21, 0), :receiver => 'foo@example.com', - :first_name => 'Robert'} + :first_name => 'Robert' + } request = REXML::Document.new(@gateway.send(:build_transaction_search, options)) assert_match %r{^2012-02-21T\d{2}:00:00Z$}, REXML::XPath.first(request, '//TransactionSearchReq/TransactionSearchRequest/StartDate').text assert_match %r{^2012-03-21T\d{2}:00:00Z$}, REXML::XPath.first(request, '//TransactionSearchReq/TransactionSearchRequest/EndDate').text @@ -153,9 +157,9 @@ def test_build_reference_transaction_request def test_build_reference_transaction_gets_ip request = REXML::Document.new(@gateway.send(:build_reference_transaction_request, - 100, - :reference_id => 'id', - :ip => '127.0.0.1')) + 100, + :reference_id => 'id', + :ip => '127.0.0.1')) assert_equal '100', REXML::XPath.first(request, '//n2:PaymentDetails/n2:OrderTotal').text assert_equal 'id', REXML::XPath.first(request, '//DoReferenceTransactionReq/DoReferenceTransactionRequest/n2:DoReferenceTransactionRequestDetails/n2:ReferenceID').text assert_equal '127.0.0.1', REXML::XPath.first(request, '//DoReferenceTransactionReq/DoReferenceTransactionRequest/n2:DoReferenceTransactionRequestDetails/n2:IPAddress').text diff --git a/test/unit/gateways/paypal_digital_goods_test.rb b/test/unit/gateways/paypal_digital_goods_test.rb index 65b1e291f55..4b433f38843 100644 --- a/test/unit/gateways/paypal_digital_goods_test.rb +++ b/test/unit/gateways/paypal_digital_goods_test.rb @@ -33,94 +33,90 @@ def test_test_redirect_url end def test_setup_request_invalid_requests - assert_raise ArgumentError do - @gateway.setup_purchase(100, - :ip => "127.0.0.1", - :description => "Test Title", - :return_url => "http://return.url", - :cancel_return_url => "http://cancel.url") - end - - assert_raise ArgumentError do - @gateway.setup_purchase(100, - :ip => "127.0.0.1", - :description => "Test Title", - :return_url => "http://return.url", - :cancel_return_url => "http://cancel.url", - :items => [ ]) - end - - assert_raise ArgumentError do - @gateway.setup_purchase(100, - :ip => "127.0.0.1", - :description => "Test Title", - :return_url => "http://return.url", - :cancel_return_url => "http://cancel.url", - :items => [ Hash.new ] ) - end - - assert_raise ArgumentError do - @gateway.setup_purchase(100, - :ip => "127.0.0.1", - :description => "Test Title", - :return_url => "http://return.url", - :cancel_return_url => "http://cancel.url", - :items => [ { :name => "Charge", - :number => "1", - :quantity => "1", - :amount => 100, - :description => "Description", - :category => "Physical" } ] ) - end + assert_raise ArgumentError do + @gateway.setup_purchase(100, + :ip => '127.0.0.1', + :description => 'Test Title', + :return_url => 'http://return.url', + :cancel_return_url => 'http://cancel.url') + end + + assert_raise ArgumentError do + @gateway.setup_purchase(100, + :ip => '127.0.0.1', + :description => 'Test Title', + :return_url => 'http://return.url', + :cancel_return_url => 'http://cancel.url', + :items => [ ]) + end + + assert_raise ArgumentError do + @gateway.setup_purchase(100, + :ip => '127.0.0.1', + :description => 'Test Title', + :return_url => 'http://return.url', + :cancel_return_url => 'http://cancel.url', + :items => [ Hash.new ]) + end + + assert_raise ArgumentError do + @gateway.setup_purchase(100, + :ip => '127.0.0.1', + :description => 'Test Title', + :return_url => 'http://return.url', + :cancel_return_url => 'http://cancel.url', + :items => [ { :name => 'Charge', + :number => '1', + :quantity => '1', + :amount => 100, + :description => 'Description', + :category => 'Physical' } ]) + end end - def test_build_setup_request_valid @gateway.expects(:ssl_post).returns(successful_setup_response) @gateway.setup_purchase(100, - :ip => "127.0.0.1", - :description => "Test Title", - :return_url => "http://return.url", - :cancel_return_url => "http://cancel.url", - :items => [ { :name => "Charge", - :number => "1", - :quantity => "1", + :ip => '127.0.0.1', + :description => 'Test Title', + :return_url => 'http://return.url', + :cancel_return_url => 'http://cancel.url', + :items => [ { :name => 'Charge', + :number => '1', + :quantity => '1', :amount => 100, - :description => "Description", - :category => "Digital" } ] ) - + :description => 'Description', + :category => 'Digital' } ]) end - private def successful_setup_response -"<?xml version=\"1.0\" encoding=\"UTF-8\"?> -<SOAP-ENV:Envelope xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:SOAP-ENC=\"http://schemas.xmlsoap.org/soap/encoding/\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:xs=\"http://www.w3.org/2001/XMLSchema\" xmlns:cc=\"urn:ebay:apis:CoreComponentTypes\" xmlns:wsu=\"http://schemas.xmlsoap.org/ws/2002/07/utility\" xmlns:saml=\"urn:oasis:names:tc:SAML:1.0:assertion\" xmlns:ds=\"http://www.w3.org/2000/09/xmldsig#\" xmlns:wsse=\"http://schemas.xmlsoap.org/ws/2002/12/secext\" xmlns:ed=\"urn:ebay:apis:EnhancedDataTypes\" xmlns:ebl=\"urn:ebay:apis:eBLBaseComponents\" xmlns:ns=\"urn:ebay:api:PayPalAPI\"> - <SOAP-ENV:Header> - <Security xmlns=\"http://schemas.xmlsoap.org/ws/2002/12/secext\" xsi:type=\"wsse:SecurityType\"></Security> - <RequesterCredentials xmlns=\"urn:ebay:api:PayPalAPI\" xsi:type=\"ebl:CustomSecurityHeaderType\"> - <Credentials xmlns=\"urn:ebay:apis:eBLBaseComponents\" xsi:type=\"ebl:UserIdPasswordType\"> - <Username xsi:type=\"xs:string\"></Username> - <Password xsi:type=\"xs:string\"></Password> - <Signature xsi:type=\"xs:string\">OMGOMGOMGOMGOMG</Signature> - <Subject xsi:type=\"xs:string\"></Subject> - </Credentials> - </RequesterCredentials> - </SOAP-ENV:Header> - <SOAP-ENV:Body id=\"_0\"> - <SetExpressCheckoutResponse xmlns=\"urn:ebay:api:PayPalAPI\"> - <Timestamp xmlns=\"urn:ebay:apis:eBLBaseComponents\">2011-05-19T20:13:30Z</Timestamp> - <Ack xmlns=\"urn:ebay:apis:eBLBaseComponents\">Success</Ack> - <CorrelationID xmlns=\"urn:ebay:apis:eBLBaseComponents\">da0ed6bc90ef1</CorrelationID> - <Version xmlns=\"urn:ebay:apis:eBLBaseComponents\">72</Version> - <Build xmlns=\"urn:ebay:apis:eBLBaseComponents\">1882144</Build> - <Token xsi:type=\"ebl:ExpressCheckoutTokenType\">EC-0XOMGOMGOMG</Token> - </SetExpressCheckoutResponse> - </SOAP-ENV:Body> - </SOAP-ENV:Envelope>" + "<?xml version=\"1.0\" encoding=\"UTF-8\"?> + <SOAP-ENV:Envelope xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:SOAP-ENC=\"http://schemas.xmlsoap.org/soap/encoding/\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:xs=\"http://www.w3.org/2001/XMLSchema\" xmlns:cc=\"urn:ebay:apis:CoreComponentTypes\" xmlns:wsu=\"http://schemas.xmlsoap.org/ws/2002/07/utility\" xmlns:saml=\"urn:oasis:names:tc:SAML:1.0:assertion\" xmlns:ds=\"http://www.w3.org/2000/09/xmldsig#\" xmlns:wsse=\"http://schemas.xmlsoap.org/ws/2002/12/secext\" xmlns:ed=\"urn:ebay:apis:EnhancedDataTypes\" xmlns:ebl=\"urn:ebay:apis:eBLBaseComponents\" xmlns:ns=\"urn:ebay:api:PayPalAPI\"> + <SOAP-ENV:Header> + <Security xmlns=\"http://schemas.xmlsoap.org/ws/2002/12/secext\" xsi:type=\"wsse:SecurityType\"></Security> + <RequesterCredentials xmlns=\"urn:ebay:api:PayPalAPI\" xsi:type=\"ebl:CustomSecurityHeaderType\"> + <Credentials xmlns=\"urn:ebay:apis:eBLBaseComponents\" xsi:type=\"ebl:UserIdPasswordType\"> + <Username xsi:type=\"xs:string\"></Username> + <Password xsi:type=\"xs:string\"></Password> + <Signature xsi:type=\"xs:string\">OMGOMGOMGOMGOMG</Signature> + <Subject xsi:type=\"xs:string\"></Subject> + </Credentials> + </RequesterCredentials> + </SOAP-ENV:Header> + <SOAP-ENV:Body id=\"_0\"> + <SetExpressCheckoutResponse xmlns=\"urn:ebay:api:PayPalAPI\"> + <Timestamp xmlns=\"urn:ebay:apis:eBLBaseComponents\">2011-05-19T20:13:30Z</Timestamp> + <Ack xmlns=\"urn:ebay:apis:eBLBaseComponents\">Success</Ack> + <CorrelationID xmlns=\"urn:ebay:apis:eBLBaseComponents\">da0ed6bc90ef1</CorrelationID> + <Version xmlns=\"urn:ebay:apis:eBLBaseComponents\">72</Version> + <Build xmlns=\"urn:ebay:apis:eBLBaseComponents\">1882144</Build> + <Token xsi:type=\"ebl:ExpressCheckoutTokenType\">EC-0XOMGOMGOMG</Token> + </SetExpressCheckoutResponse> + </SOAP-ENV:Body> + </SOAP-ENV:Envelope>" end end - diff --git a/test/unit/gateways/paypal_express_test.rb b/test/unit/gateways/paypal_express_test.rb index bb75a181311..61c506558a1 100644 --- a/test/unit/gateways/paypal_express_test.rb +++ b/test/unit/gateways/paypal_express_test.rb @@ -19,15 +19,16 @@ def setup :pem => 'PEM' ) - @address = { :address1 => '1234 My Street', - :address2 => 'Apt 1', - :company => 'Widgets Inc', - :city => 'Ottawa', - :state => 'ON', - :zip => 'K1C2N6', - :country => 'Canada', - :phone => '(555)555-5555' - } + @address = { + :address1 => '1234 My Street', + :address2 => 'Apt 1', + :company => 'Widgets Inc', + :city => 'Ottawa', + :state => 'ON', + :zip => 'K1C2N6', + :country => 'Canada', + :phone => '(555)555-5555' + } Base.mode = :test end @@ -104,7 +105,7 @@ def test_get_express_details end def test_express_response_missing_address - response = PaypalExpressResponse.new(true, "ok") + response = PaypalExpressResponse.new(true, 'ok') assert_nil response.address['address1'] end @@ -165,10 +166,24 @@ def test_does_not_include_items_if_not_specified end def test_items_are_included_if_specified_in_build_setup_request - xml = REXML::Document.new(@gateway.send(:build_setup_request, 'SetExpressCheckout', 0, {:currency => 'GBP', :items => [ - {:name => 'item one', :description => 'item one description', :amount => 10000, :number => 1, :quantity => 3}, - {:name => 'item two', :description => 'item two description', :amount => 20000, :number => 2, :quantity => 4} - ]})) + xml = REXML::Document.new(@gateway.send(:build_setup_request, 'SetExpressCheckout', 0, { + :currency => 'GBP', + :items => [ + { + :name => 'item one', + :description => 'item one description', + :amount => 10000, + :number => 1, + :quantity => 3 + }, + { :name => 'item two', + :description => 'item two description', + :amount => 20000, + :number => 2, + :quantity => 4 + } + ] + })) assert_equal 'item one', REXML::XPath.first(xml, '//n2:PaymentDetails/n2:PaymentDetailsItem/n2:Name').text assert_equal 'item one description', REXML::XPath.first(xml, '//n2:PaymentDetails/n2:PaymentDetailsItem/n2:Description').text @@ -192,7 +207,7 @@ def test_does_not_include_callback_url_if_not_specified end def test_callback_url_is_included_if_specified_in_build_setup_request - xml = REXML::Document.new(@gateway.send(:build_setup_request, 'SetExpressCheckout', 0, {:callback_url => "http://example.com/update_callback"})) + xml = REXML::Document.new(@gateway.send(:build_setup_request, 'SetExpressCheckout', 0, {:callback_url => 'http://example.com/update_callback'})) assert_equal 'http://example.com/update_callback', REXML::XPath.first(xml, '//n2:CallbackURL').text end @@ -228,16 +243,22 @@ def test_does_not_include_flatrate_shipping_options_if_not_specified end def test_flatrate_shipping_options_are_included_if_specified_in_build_setup_request - xml = REXML::Document.new(@gateway.send(:build_setup_request, 'SetExpressCheckout', 0, {:currency => 'AUD', :shipping_options => [ - {:default => true, - :name => "first one", + xml = REXML::Document.new(@gateway.send(:build_setup_request, 'SetExpressCheckout', 0, + { + :currency => 'AUD', + :shipping_options => [ + { + :default => true, + :name => 'first one', :amount => 1000 - }, - {:default => false, - :name => "second one", - :amount => 2000 - } - ]})) + }, + { + :default => false, + :name => 'second one', + :amount => 2000 + } + ] + })) assert_equal 'true', REXML::XPath.first(xml, '//n2:FlatRateShippingOptions/n2:ShippingOptionIsDefault').text assert_equal 'first one', REXML::XPath.first(xml, '//n2:FlatRateShippingOptions/n2:ShippingOptionName').text @@ -251,14 +272,18 @@ def test_flatrate_shipping_options_are_included_if_specified_in_build_setup_requ end def test_address_is_included_if_specified - xml = REXML::Document.new(@gateway.send(:build_setup_request, 'Sale', 0, {:currency => 'GBP', :address => { - :name => "John Doe", - :address1 => "123 somewhere", - :city => "Townville", - :country => "Canada", - :zip => "k1l4p2", - :phone => "1231231231" - }})) + xml = REXML::Document.new(@gateway.send(:build_setup_request, 'Sale', 0, + { + :currency => 'GBP', + :address => { + :name => 'John Doe', + :address1 => '123 somewhere', + :city => 'Townville', + :country => 'Canada', + :zip => 'k1l4p2', + :phone => '1231231231' + } + })) assert_equal 'John Doe', REXML::XPath.first(xml, '//n2:PaymentDetails/n2:ShipToAddress/n2:Name').text assert_equal '123 somewhere', REXML::XPath.first(xml, '//n2:PaymentDetails/n2:ShipToAddress/n2:Street1').text @@ -287,10 +312,30 @@ def test_removes_fractional_amounts_with_twd_currency end def test_fractional_discounts_are_correctly_calculated_with_jpy_currency - xml = REXML::Document.new(@gateway.send(:build_setup_request, 'SetExpressCheckout', 14250, { :items => - [{:name => 'item one', :description => 'description', :amount => 15000, :number => 1, :quantity => 1}, - {:name => 'Discount', :description => 'Discount', :amount => -750, :number => 2, :quantity => 1}], - :subtotal => 14250, :currency => 'JPY', :shipping => 0, :handling => 0, :tax => 0 })) + xml = REXML::Document.new(@gateway.send(:build_setup_request, 'SetExpressCheckout', 14250, + { + :items => [ + { + :name => 'item one', + :description => 'description', + :amount => 15000, + :number => 1, + :quantity => 1 + }, + { + :name => 'Discount', + :description => 'Discount', + :amount => -750, + :number => 2, + :quantity => 1 + } + ], + :subtotal => 14250, + :currency => 'JPY', + :shipping => 0, + :handling => 0, + :tax => 0 + })) assert_equal '142', REXML::XPath.first(xml, '//n2:OrderTotal').text assert_equal '142', REXML::XPath.first(xml, '//n2:ItemTotal').text @@ -300,10 +345,30 @@ def test_fractional_discounts_are_correctly_calculated_with_jpy_currency end def test_non_fractional_discounts_are_correctly_calculated_with_jpy_currency - xml = REXML::Document.new(@gateway.send(:build_setup_request, 'SetExpressCheckout', 14300, { :items => - [{:name => 'item one', :description => 'description', :amount => 15000, :number => 1, :quantity => 1}, - {:name => 'Discount', :description => 'Discount', :amount => -700, :number => 2, :quantity => 1}], - :subtotal => 14300, :currency => 'JPY', :shipping => 0, :handling => 0, :tax => 0 })) + xml = REXML::Document.new(@gateway.send(:build_setup_request, 'SetExpressCheckout', 14300, + { + :items => [ + { + :name => 'item one', + :description => 'description', + :amount => 15000, + :number => 1, + :quantity => 1 + }, + { + :name => 'Discount', + :description => 'Discount', + :amount => -700, + :number => 2, + :quantity => 1 + } + ], + :subtotal => 14300, + :currency => 'JPY', + :shipping => 0, + :handling => 0, + :tax => 0 + })) assert_equal '143', REXML::XPath.first(xml, '//n2:OrderTotal').text assert_equal '143', REXML::XPath.first(xml, '//n2:ItemTotal').text @@ -313,10 +378,30 @@ def test_non_fractional_discounts_are_correctly_calculated_with_jpy_currency end def test_fractional_discounts_are_correctly_calculated_with_usd_currency - xml = REXML::Document.new(@gateway.send(:build_setup_request, 'SetExpressCheckout', 14250, { :items => - [{:name => 'item one', :description => 'description', :amount => 15000, :number => 1, :quantity => 1}, - {:name => 'Discount', :description => 'Discount', :amount => -750, :number => 2, :quantity => 1}], - :subtotal => 14250, :currency => 'USD', :shipping => 0, :handling => 0, :tax => 0 })) + xml = REXML::Document.new(@gateway.send(:build_setup_request, 'SetExpressCheckout', 14250, + { + :items => [ + { + :name => 'item one', + :description => 'description', + :amount => 15000, + :number => 1, + :quantity => 1 + }, + { + :name => 'Discount', + :description => 'Discount', + :amount => -750, + :number => 2, + :quantity => 1 + } + ], + :subtotal => 14250, + :currency => 'USD', + :shipping => 0, + :handling => 0, + :tax => 0 + })) assert_equal '142.50', REXML::XPath.first(xml, '//n2:OrderTotal').text assert_equal '142.50', REXML::XPath.first(xml, '//n2:ItemTotal').text @@ -369,11 +454,25 @@ def test_button_source end def test_items_are_included_if_specified_in_build_sale_or_authorization_request - xml = REXML::Document.new(@gateway.send(:build_sale_or_authorization_request, 'Sale', 100, {:items => [ - {:name => 'item one', :description => 'item one description', :amount => 10000, :number => 1, :quantity => 3}, - {:name => 'item two', :description => 'item two description', :amount => 20000, :number => 2, :quantity => 4} - ]})) - + xml = REXML::Document.new(@gateway.send(:build_sale_or_authorization_request, 'Sale', 100, + { + :items => [ + { + :name => 'item one', + :description => 'item one description', + :amount => 10000, + :number => 1, + :quantity => 3 + }, + { + :name => 'item two', + :description => 'item two description', + :amount => 20000, + :number => 2, + :quantity => 4 + } + ] + })) assert_equal 'item one', REXML::XPath.first(xml, '//n2:PaymentDetails/n2:PaymentDetailsItem/n2:Name').text assert_equal 'item one description', REXML::XPath.first(xml, '//n2:PaymentDetails/n2:PaymentDetailsItem/n2:Description').text @@ -390,7 +489,7 @@ def test_items_are_included_if_specified_in_build_sale_or_authorization_request def test_build_create_billing_agreement PaypalExpressGateway.application_id = 'ActiveMerchant_FOO' - xml = REXML::Document.new(@gateway.send(:build_create_billing_agreement_request, "ref_id")) + xml = REXML::Document.new(@gateway.send(:build_create_billing_agreement_request, 'ref_id')) assert_equal 'ref_id', REXML::XPath.first(xml, '//CreateBillingAgreementReq/CreateBillingAgreementRequest/Token').text end @@ -398,64 +497,65 @@ def test_build_create_billing_agreement def test_store @gateway.expects(:ssl_post).returns(successful_create_billing_agreement_response) - response = @gateway.store("ref_id") + response = @gateway.store('ref_id') - assert_equal "Success", response.params['ack'] - assert_equal "Success", response.message - assert_equal "B-3R788221G4476823M", response.params["billing_agreement_id"] + assert_equal 'Success', response.params['ack'] + assert_equal 'Success', response.message + assert_equal 'B-3R788221G4476823M', response.params['billing_agreement_id'] end def test_unstore_successful @gateway.expects(:ssl_post).returns(successful_cancel_billing_agreement_response) - response = @gateway.unstore("B-3RU433629T663020S") + response = @gateway.unstore('B-3RU433629T663020S') assert response.success? - assert_equal "Success", response.params['ack'] - assert_equal "Success", response.message - assert_equal "B-3RU433629T663020S", response.params["billing_agreement_id"] - assert_equal "Canceled", response.params["billing_agreement_status"] + assert_equal 'Success', response.params['ack'] + assert_equal 'Success', response.message + assert_equal 'B-3RU433629T663020S', response.params['billing_agreement_id'] + assert_equal 'Canceled', response.params['billing_agreement_status'] end def test_unstore_failed @gateway.expects(:ssl_post).returns(failed_cancel_billing_agreement_response) - response = @gateway.unstore("B-3RU433629T663020S") + response = @gateway.unstore('B-3RU433629T663020S') assert !response.success? - assert_equal "Failure", response.params['ack'] - assert_equal "Billing Agreement was cancelled", response.message - assert_equal "10201", response.params["error_codes"] + assert_equal 'Failure', response.params['ack'] + assert_equal 'Billing Agreement was cancelled', response.message + assert_equal '10201', response.params['error_codes'] end def test_agreement_details_successful @gateway.expects(:ssl_post).returns(successful_billing_agreement_details_response) - response = @gateway.agreement_details("B-6VE21702A47915521") + response = @gateway.agreement_details('B-6VE21702A47915521') assert response.success? - assert_equal "Success", response.params['ack'] - assert_equal "Success", response.message - assert_equal "B-6VE21702A47915521", response.params["billing_agreement_id"] - assert_equal "Active", response.params["billing_agreement_status"] + assert_equal 'Success', response.params['ack'] + assert_equal 'Success', response.message + assert_equal 'B-6VE21702A47915521', response.params['billing_agreement_id'] + assert_equal 'Active', response.params['billing_agreement_status'] end def test_agreement_details_failure @gateway.expects(:ssl_post).returns(failure_billing_agreement_details_response) - response = @gateway.agreement_details("bad_reference_id") + response = @gateway.agreement_details('bad_reference_id') assert !response.success? - assert_equal "Failure", response.params['ack'] - assert_equal "Billing Agreement Id or transaction Id is not valid", response.message - assert_equal "11451", response.params["error_codes"] + assert_equal 'Failure', response.params['ack'] + assert_equal 'Billing Agreement Id or transaction Id is not valid', response.message + assert_equal '11451', response.params['error_codes'] end - def test_build_reference_transaction_test PaypalExpressGateway.application_id = 'ActiveMerchant_FOO' - xml = REXML::Document.new(@gateway.send(:build_reference_transaction_request, 'Sale', 2000, { - :reference_id => "ref_id", - :payment_type => 'Any', - :invoice_id => 'invoice_id', - :description => 'Description', - :ip => '127.0.0.1' })) + xml = REXML::Document.new(@gateway.send(:build_reference_transaction_request, 'Sale', 2000, + { + :reference_id => 'ref_id', + :payment_type => 'Any', + :invoice_id => 'invoice_id', + :description => 'Description', + :ip => '127.0.0.1' + })) assert_equal '124', REXML::XPath.first(xml, '//DoReferenceTransactionReq/DoReferenceTransactionRequest/n2:Version').text assert_equal 'ref_id', REXML::XPath.first(xml, '//DoReferenceTransactionReq/DoReferenceTransactionRequest/n2:DoReferenceTransactionRequestDetails/n2:ReferenceID').text @@ -477,26 +577,27 @@ def test_build_details_billing_agreement_request_test def test_authorize_reference_transaction @gateway.expects(:ssl_post).returns(successful_authorize_reference_transaction_response) - response = @gateway.authorize_reference_transaction(2000, { - :reference_id => "ref_id", - :payment_type => 'Any', - :invoice_id => 'invoice_id', - :description => 'Description', - :ip => '127.0.0.1' }) + response = @gateway.authorize_reference_transaction(2000, + { + :reference_id => 'ref_id', + :payment_type => 'Any', + :invoice_id => 'invoice_id', + :description => 'Description', + :ip => '127.0.0.1' }) - assert_equal "Success", response.params['ack'] - assert_equal "Success", response.message - assert_equal "9R43552341412482K", response.authorization + assert_equal 'Success', response.params['ack'] + assert_equal 'Success', response.message + assert_equal '9R43552341412482K', response.authorization end def test_reference_transaction @gateway.expects(:ssl_post).returns(successful_reference_transaction_response) - response = @gateway.reference_transaction(2000, { :reference_id => "ref_id" }) + response = @gateway.reference_transaction(2000, { :reference_id => 'ref_id' }) - assert_equal "Success", response.params['ack'] - assert_equal "Success", response.message - assert_equal "9R43552341412482K", response.authorization + assert_equal 'Success', response.params['ack'] + assert_equal 'Success', response.message + assert_equal '9R43552341412482K', response.authorization end def test_reference_transaction_requires_fields @@ -508,30 +609,30 @@ def test_reference_transaction_requires_fields def test_error_code_for_single_error @gateway.expects(:ssl_post).returns(response_with_error) response = @gateway.setup_authorization(100, - :return_url => 'http://example.com', - :cancel_return_url => 'http://example.com' - ) - assert_equal "10736", response.params['error_codes'] + :return_url => 'http://example.com', + :cancel_return_url => 'http://example.com' + ) + assert_equal '10736', response.params['error_codes'] end def test_ensure_only_unique_error_codes @gateway.expects(:ssl_post).returns(response_with_duplicate_errors) response = @gateway.setup_authorization(100, - :return_url => 'http://example.com', - :cancel_return_url => 'http://example.com' - ) + :return_url => 'http://example.com', + :cancel_return_url => 'http://example.com' + ) - assert_equal "10736" , response.params['error_codes'] + assert_equal '10736', response.params['error_codes'] end def test_error_codes_for_multiple_errors @gateway.expects(:ssl_post).returns(response_with_errors) response = @gateway.setup_authorization(100, - :return_url => 'http://example.com', - :cancel_return_url => 'http://example.com' - ) + :return_url => 'http://example.com', + :cancel_return_url => 'http://example.com' + ) - assert_equal ["10736", "10002"] , response.params['error_codes'].split(',') + assert_equal ['10736', '10002'], response.params['error_codes'].split(',') end def test_allow_guest_checkout @@ -600,31 +701,42 @@ def test_structure_correct :handling => 0, :tax => 5, :total_type => 'EstimatedTotal', - :items => [{:name => 'item one', - :number => 'number 1', - :quantity => 3, - :amount => 35, - :description => 'one description', - :url => 'http://example.com/number_1'}], - :address => {:name => 'John Doe', - :address1 => 'Apartment 1', - :address2 => '1 Road St', - :city => 'First City', - :state => 'NSW', - :country => 'AU', - :zip => '2000', - :phone => '555 5555'}, - :callback_url => "http://example.com/update_callback", + :items => [ + { + :name => 'item one', + :number => 'number 1', + :quantity => 3, + :amount => 35, + :description => 'one description', + :url => 'http://example.com/number_1' + } + ], + :address => + { + :name => 'John Doe', + :address1 => 'Apartment 1', + :address2 => '1 Road St', + :city => 'First City', + :state => 'NSW', + :country => 'AU', + :zip => '2000', + :phone => '555 5555' + }, + :callback_url => 'http://example.com/update_callback', :callback_timeout => 2, :callback_version => '53.0', :funding_sources => {:source => 'BML'}, - :shipping_options => [{:default => true, - :name => "first one", - :amount => 10}] + :shipping_options => [ + { + :default => true, + :name => 'first one', + :amount => 10 + } + ] } doc = Nokogiri::XML(@gateway.send(:build_setup_request, 'Sale', 10, all_options_enabled)) - #Strip back to the SetExpressCheckoutRequestDetails element - this is where the base component xsd starts + # Strip back to the SetExpressCheckoutRequestDetails element - this is where the base component xsd starts xml = doc.xpath('//base:SetExpressCheckoutRequestDetails', 'base' => 'urn:ebay:apis:eBLBaseComponents').first sub_doc = Nokogiri::XML::Document.new sub_doc.root = xml @@ -666,9 +778,8 @@ def successful_create_billing_agreement_response RESPONSE end - def successful_authorize_reference_transaction_response - <<-RESPONSE + <<-RESPONSE <?xml version="1.0" encoding="UTF-8"?> <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:cc="urn:ebay:apis:CoreComponentTypes" xmlns:wsu="http://schemas.xmlsoap.org/ws/2002/07/utility" xmlns:saml="urn:oasis:names:tc:SAML:1.0:assertion" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:wsse="http://schemas.xmlsoap.org/ws/2002/12/secext" xmlns:ed="urn:ebay:apis:EnhancedDataTypes" xmlns:ebl="urn:ebay:apis:eBLBaseComponents" xmlns:ns="urn:ebay:api:PayPalAPI"> <SOAP-ENV:Header> @@ -763,7 +874,6 @@ def successful_reference_transaction_response RESPONSE end - def successful_details_response <<-RESPONSE <?xml version="1.0" encoding="UTF-8"?> @@ -946,8 +1056,8 @@ def response_with_error RESPONSE end - def response_with_errors - <<-RESPONSE + def response_with_errors + <<-RESPONSE <?xml version="1.0" encoding="UTF-8"?> <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:cc="urn:ebay:apis:CoreComponentTypes" xmlns:wsu="http://schemas.xmlsoap.org/ws/2002/07/utility" xmlns:saml="urn:oasis:names:tc:SAML:1.0:assertion" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:market="urn:ebay:apis:Market" xmlns:auction="urn:ebay:apis:Auction" xmlns:sizeship="urn:ebay:api:PayPalAPI/sizeship.xsd" xmlns:ship="urn:ebay:apis:ship" xmlns:skype="urn:ebay:apis:skype" xmlns:wsse="http://schemas.xmlsoap.org/ws/2002/12/secext" xmlns:ebl="urn:ebay:apis:eBLBaseComponents" xmlns:ns="urn:ebay:api:PayPalAPI"> <SOAP-ENV:Header> @@ -983,10 +1093,10 @@ def response_with_errors </SOAP-ENV:Body> </SOAP-ENV:Envelope> RESPONSE - end + end - def response_with_duplicate_errors - <<-RESPONSE + def response_with_duplicate_errors + <<-RESPONSE <?xml version="1.0" encoding="UTF-8"?> <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:cc="urn:ebay:apis:CoreComponentTypes" xmlns:wsu="http://schemas.xmlsoap.org/ws/2002/07/utility" xmlns:saml="urn:oasis:names:tc:SAML:1.0:assertion" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:market="urn:ebay:apis:Market" xmlns:auction="urn:ebay:apis:Auction" xmlns:sizeship="urn:ebay:api:PayPalAPI/sizeship.xsd" xmlns:ship="urn:ebay:apis:ship" xmlns:skype="urn:ebay:apis:skype" xmlns:wsse="http://schemas.xmlsoap.org/ws/2002/12/secext" xmlns:ebl="urn:ebay:apis:eBLBaseComponents" xmlns:ns="urn:ebay:api:PayPalAPI"> <SOAP-ENV:Header> @@ -1022,10 +1132,10 @@ def response_with_duplicate_errors </SOAP-ENV:Body> </SOAP-ENV:Envelope> RESPONSE - end + end - def successful_cancel_billing_agreement_response - <<-RESPONSE + def successful_cancel_billing_agreement_response + <<-RESPONSE <?xml version="1.0" encoding="UTF-8"?><SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:cc="urn:ebay:apis:CoreComponentTypes" xmlns:wsu="http://schemas.xmlsoap.org/ws/2002/07/utility" xmlns:saml="urn:oasis:names:tc:SAML:1.0:assertion" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" @@ -1049,10 +1159,10 @@ def successful_cancel_billing_agreement_response xsi:type="xs:string"></ExternalAddressID><AddressStatus xsi:type="ebl:AddressStatusCodeType">None</AddressStatus></Address></PayerInfo></BAUpdateResponseDetails></BAUpdateResponse></SOAP-ENV:Body></SOAP-ENV:Envelope> RESPONSE - end + end - def failed_cancel_billing_agreement_response - <<-RESPONSE + def failed_cancel_billing_agreement_response + <<-RESPONSE <?xml version="1.0" encoding="UTF-8"?><SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:cc="urn:ebay:apis:CoreComponentTypes" xmlns:wsu="http://schemas.xmlsoap.org/ws/2002/07/utility" xmlns:saml="urn:oasis:names:tc:SAML:1.0:assertion" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" @@ -1075,10 +1185,10 @@ def failed_cancel_billing_agreement_response xsi:type="xs:string"></AddressID><AddressOwner xsi:type="ebl:AddressOwnerCodeType">PayPal</AddressOwner><ExternalAddressID xsi:type="xs:string"></ExternalAddressID><AddressStatus xsi:type="ebl:AddressStatusCodeType">None</AddressStatus></Address></PayerInfo></BAUpdateResponseDetails></BAUpdateResponse></SOAP-ENV:Body></SOAP-ENV:Envelope> RESPONSE - end + end - def successful_billing_agreement_details_response - <<-RESPONSE + def successful_billing_agreement_details_response + <<-RESPONSE <?xml version="1.0" encoding="UTF-8"?><SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:cc="urn:ebay:apis:CoreComponentTypes" @@ -1108,10 +1218,10 @@ def successful_billing_agreement_details_response <ExternalAddressID xsi:type="xs:string"></ExternalAddressID><AddressStatus xsi:type="ebl:AddressStatusCodeType">None</AddressStatus> </Address></PayerInfo></BAUpdateResponseDetails></BAUpdateResponse></SOAP-ENV:Body></SOAP-ENV:Envelope> RESPONSE - end + end - def failure_billing_agreement_details_response - <<-RESPONSE + def failure_billing_agreement_details_response + <<-RESPONSE <?xml version="1.0" encoding="UTF-8"?><SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:cc="urn:ebay:apis:CoreComponentTypes" @@ -1140,5 +1250,57 @@ def failure_billing_agreement_details_response <ExternalAddressID xsi:type="xs:string"></ExternalAddressID><AddressStatus xsi:type="ebl:AddressStatusCodeType">None</AddressStatus></Address> </PayerInfo></BAUpdateResponseDetails></BAUpdateResponse></SOAP-ENV:Body></SOAP-ENV:Envelope> RESPONSE - end + end + + def pre_scrubbed + <<-TRANSCRIPT +<?xml version=\"1.0\" encoding=\"UTF-8\"?><env:Envelope xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:env=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"><env:Header><RequesterCredentials xmlns=\"urn:ebay:api:PayPalAPI\" xmlns:n1=\"urn:ebay:apis:eBLBaseComponents\" env:mustUnderstand=\"0\"><n1:Credentials><n1:Username>activemerchant-cert-test_api1.example.com</n1:Username><n1:Password>ERDD3JRFU5H5DQXS</n1:Password><n1:Subject/></n1:Credentials></RequesterCredentials></env:Header><env:Body><SetExpressCheckoutReq xmlns=\"urn:ebay:api:PayPalAPI\"> + <SetExpressCheckoutRequest xmlns:n2=\"urn:ebay:apis:eBLBaseComponents\"> + <n2:Version>124</n2:Version> + <n2:SetExpressCheckoutRequestDetails> + <n2:ReturnURL>http://example.com/return</n2:ReturnURL> + <n2:CancelURL>http://example.com/cancel</n2:CancelURL> + <n2:ReqBillingAddress>0</n2:ReqBillingAddress> + <n2:NoShipping>0</n2:NoShipping> + <n2:AddressOverride>0</n2:AddressOverride> + <n2:BuyerEmail>buyer@jadedpallet.com</n2:BuyerEmail> + <n2:PaymentDetails> + <n2:OrderTotal currencyID=\"USD\">5.00</n2:OrderTotal> + <n2:OrderDescription>Stuff that you purchased, yo!</n2:OrderDescription> + <n2:InvoiceID>230000</n2:InvoiceID> + <n2:PaymentAction>Authorization</n2:PaymentAction> + </n2:PaymentDetails> + </n2:SetExpressCheckoutRequestDetails> + </SetExpressCheckoutRequest> +</SetExpressCheckoutReq> +</env:Body></env:Envelope> +<?xml version=\"1.0\" encoding=\"UTF-8\"?><SOAP-ENV:Envelope xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:SOAP-ENC=\"http://schemas.xmlsoap.org/soap/encoding/\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:xs=\"http://www.w3.org/2001/XMLSchema\" xmlns:cc=\"urn:ebay:apis:CoreComponentTypes\" xmlns:wsu=\"http://schemas.xmlsoap.org/ws/2002/07/utility\" xmlns:saml=\"urn:oasis:names:tc:SAML:1.0:assertion\" xmlns:ds=\"http://www.w3.org/2000/09/xmldsig#\" xmlns:wsse=\"http://schemas.xmlsoap.org/ws/2002/12/secext\" xmlns:ed=\"urn:ebay:apis:EnhancedDataTypes\" xmlns:ebl=\"urn:ebay:apis:eBLBaseComponents\" xmlns:ns=\"urn:ebay:api:PayPalAPI\"><SOAP-ENV:Header><Security xmlns=\"http://schemas.xmlsoap.org/ws/2002/12/secext\" xsi:type=\"wsse:SecurityType\"></Security><RequesterCredentials xmlns=\"urn:ebay:api:PayPalAPI\" xsi:type=\"ebl:CustomSecurityHeaderType\"><Credentials xmlns=\"urn:ebay:apis:eBLBaseComponents\" xsi:type=\"ebl:UserIdPasswordType\"><Username xsi:type=\"xs:string\"></Username><Password xsi:type=\"xs:string\"></Password><Signature xsi:type=\"xs:string\"></Signature><Subject xsi:type=\"xs:string\"></Subject></Credentials></RequesterCredentials></SOAP-ENV:Header><SOAP-ENV:Body id=\"_0\"><SetExpressCheckoutResponse xmlns=\"urn:ebay:api:PayPalAPI\"><Timestamp xmlns=\"urn:ebay:apis:eBLBaseComponents\">2018-05-24T20:23:54Z</Timestamp><Ack xmlns=\"urn:ebay:apis:eBLBaseComponents\">Success</Ack><CorrelationID xmlns=\"urn:ebay:apis:eBLBaseComponents\">b6dd2a043921b</CorrelationID><Version xmlns=\"urn:ebay:apis:eBLBaseComponents\">124</Version><Build xmlns=\"urn:ebay:apis:eBLBaseComponents\">46549960</Build><Token xsi:type=\"ebl:ExpressCheckoutTokenType\">EC-7KR85820NC734104L</Token></SetExpressCheckoutResponse></SOAP-ENV:Body></SOAP-ENV:Envelope> + TRANSCRIPT + end + + def post_scrubbed + <<-TRANSCRIPT +<?xml version=\"1.0\" encoding=\"UTF-8\"?><env:Envelope xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:env=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"><env:Header><RequesterCredentials xmlns=\"urn:ebay:api:PayPalAPI\" xmlns:n1=\"urn:ebay:apis:eBLBaseComponents\" env:mustUnderstand=\"0\"><n1:Credentials><n1:Username>[FILTERED]</n1:Username><n1:Password>[FILTERED]</n1:Password><n1:Subject/></n1:Credentials></RequesterCredentials></env:Header><env:Body><SetExpressCheckoutReq xmlns=\"urn:ebay:api:PayPalAPI\"> + <SetExpressCheckoutRequest xmlns:n2=\"urn:ebay:apis:eBLBaseComponents\"> + <n2:Version>124</n2:Version> + <n2:SetExpressCheckoutRequestDetails> + <n2:ReturnURL>http://example.com/return</n2:ReturnURL> + <n2:CancelURL>http://example.com/cancel</n2:CancelURL> + <n2:ReqBillingAddress>0</n2:ReqBillingAddress> + <n2:NoShipping>0</n2:NoShipping> + <n2:AddressOverride>0</n2:AddressOverride> + <n2:BuyerEmail>buyer@jadedpallet.com</n2:BuyerEmail> + <n2:PaymentDetails> + <n2:OrderTotal currencyID=\"USD\">5.00</n2:OrderTotal> + <n2:OrderDescription>Stuff that you purchased, yo!</n2:OrderDescription> + <n2:InvoiceID>230000</n2:InvoiceID> + <n2:PaymentAction>Authorization</n2:PaymentAction> + </n2:PaymentDetails> + </n2:SetExpressCheckoutRequestDetails> + </SetExpressCheckoutRequest> +</SetExpressCheckoutReq> +</env:Body></env:Envelope> +<?xml version=\"1.0\" encoding=\"UTF-8\"?><SOAP-ENV:Envelope xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:SOAP-ENC=\"http://schemas.xmlsoap.org/soap/encoding/\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:xs=\"http://www.w3.org/2001/XMLSchema\" xmlns:cc=\"urn:ebay:apis:CoreComponentTypes\" xmlns:wsu=\"http://schemas.xmlsoap.org/ws/2002/07/utility\" xmlns:saml=\"urn:oasis:names:tc:SAML:1.0:assertion\" xmlns:ds=\"http://www.w3.org/2000/09/xmldsig#\" xmlns:wsse=\"http://schemas.xmlsoap.org/ws/2002/12/secext\" xmlns:ed=\"urn:ebay:apis:EnhancedDataTypes\" xmlns:ebl=\"urn:ebay:apis:eBLBaseComponents\" xmlns:ns=\"urn:ebay:api:PayPalAPI\"><SOAP-ENV:Header><Security xmlns=\"http://schemas.xmlsoap.org/ws/2002/12/secext\" xsi:type=\"wsse:SecurityType\"></Security><RequesterCredentials xmlns=\"urn:ebay:api:PayPalAPI\" xsi:type=\"ebl:CustomSecurityHeaderType\"><Credentials xmlns=\"urn:ebay:apis:eBLBaseComponents\" xsi:type=\"ebl:UserIdPasswordType\"><Username xsi:type=\"xs:string\"></Username><Password xsi:type=\"xs:string\"></Password><Signature xsi:type=\"xs:string\"></Signature><Subject xsi:type=\"xs:string\"></Subject></Credentials></RequesterCredentials></SOAP-ENV:Header><SOAP-ENV:Body id=\"_0\"><SetExpressCheckoutResponse xmlns=\"urn:ebay:api:PayPalAPI\"><Timestamp xmlns=\"urn:ebay:apis:eBLBaseComponents\">2018-05-24T20:23:54Z</Timestamp><Ack xmlns=\"urn:ebay:apis:eBLBaseComponents\">Success</Ack><CorrelationID xmlns=\"urn:ebay:apis:eBLBaseComponents\">b6dd2a043921b</CorrelationID><Version xmlns=\"urn:ebay:apis:eBLBaseComponents\">124</Version><Build xmlns=\"urn:ebay:apis:eBLBaseComponents\">46549960</Build><Token xsi:type=\"ebl:ExpressCheckoutTokenType\">EC-7KR85820NC734104L</Token></SetExpressCheckoutResponse></SOAP-ENV:Body></SOAP-ENV:Envelope> + TRANSCRIPT + end end diff --git a/test/unit/gateways/paypal_test.rb b/test/unit/gateways/paypal_test.rb index 55aaf10d732..a9ae07cbfc4 100644 --- a/test/unit/gateways/paypal_test.rb +++ b/test/unit/gateways/paypal_test.rb @@ -156,7 +156,7 @@ def test_failed_purchase def test_descriptors_passed stub_comms do - @gateway.purchase(@amount, @credit_card, @options.merge(soft_descriptor: "Eggcellent", soft_descriptor_city: "New York")) + @gateway.purchase(@amount, @credit_card, @options.merge(soft_descriptor: 'Eggcellent', soft_descriptor_city: 'New York')) end.check_request do |endpoint, data, headers| assert_match(%r{<n2:SoftDescriptor>Eggcellent}, data) assert_match(%r{<n2:SoftDescriptorCity>New York}, data) @@ -190,10 +190,10 @@ def test_amount_style def test_paypal_timeout_error @gateway.stubs(:ssl_post).returns(paypal_timeout_error_response) response = @gateway.purchase(@amount, @credit_card, @options) - assert_equal "SOAP-ENV:Server", response.params['faultcode'] - assert_equal "Internal error", response.params['faultstring'] - assert_equal "Timeout processing request", response.params['detail'] - assert_equal "SOAP-ENV:Server: Internal error - Timeout processing request", response.message + assert_equal 'SOAP-ENV:Server', response.params['faultcode'] + assert_equal 'Internal error', response.params['faultstring'] + assert_equal 'Timeout processing request', response.params['detail'] + assert_equal 'SOAP-ENV:Server: Internal error - Timeout processing request', response.message end def test_pem_file_accessor @@ -239,7 +239,7 @@ def test_button_source_via_credentials login: 'cody', password: 'test', pem: 'PEM', - button_source: "WOOHOO" + button_source: 'WOOHOO' ) xml = REXML::Document.new(gateway.send(:build_sale_or_authorization_request, 'Test', @amount, @credit_card, {})) @@ -252,7 +252,7 @@ def test_button_source_via_credentials_with_no_application_id login: 'cody', password: 'test', pem: 'PEM', - button_source: "WOOHOO" + button_source: 'WOOHOO' ) xml = REXML::Document.new(gateway.send(:build_sale_or_authorization_request, 'Test', @amount, @credit_card, {})) @@ -348,8 +348,8 @@ def test_fraud_review response = @gateway.purchase(@amount, @credit_card, @options) assert_success response - assert_equal "SuccessWithWarning", response.params["ack"] - assert_equal "Payment Pending your review in Fraud Management Filters", response.message + assert_equal 'SuccessWithWarning', response.params['ack'] + assert_equal 'Payment Pending your review in Fraud Management Filters', response.message assert response.fraud_review? end @@ -358,7 +358,7 @@ def test_failed_capture_due_to_pending_fraud_review response = @gateway.capture(@amount, 'authorization') assert_failure response - assert_equal "Transaction must be accepted in Fraud Management Filters before capture.", response.message + assert_equal 'Transaction must be accepted in Fraud Management Filters before capture.', response.message end # This occurs when sufficient 3rd party API permissions are not present to make the call for the user @@ -366,8 +366,8 @@ def test_authentication_failed_response @gateway.expects(:ssl_post).returns(authentication_failed_response) response = @gateway.purchase(@amount, @credit_card, @options) assert_failure response - assert_equal "10002", response.params["error_codes"] - assert_equal "You do not have permissions to make this API call", response.message + assert_equal '10002', response.params['error_codes'] + assert_equal 'You do not have permissions to make this API call', response.message end def test_amount_format_for_jpy_currency @@ -379,7 +379,7 @@ def test_amount_format_for_jpy_currency def test_successful_create_profile @gateway.expects(:ssl_post).returns(successful_create_profile_paypal_response) response = assert_deprecation_warning(Gateway::RECURRING_DEPRECATION_MESSAGE) do - @gateway.recurring(@amount, @credit_card, :description => "some description", :start_date => Time.now, :frequency => 12, :period => 'Month') + @gateway.recurring(@amount, @credit_card, :description => 'some description', :start_date => Time.now, :frequency => 12, :period => 'Month') end assert_instance_of Response, response assert response.success? @@ -391,7 +391,7 @@ def test_successful_create_profile def test_failed_create_profile @gateway.expects(:ssl_post).returns(failed_create_profile_paypal_response) response = assert_deprecation_warning(Gateway::RECURRING_DEPRECATION_MESSAGE) do - @gateway.recurring(@amount, @credit_card, :description => "some description", :start_date => Time.now, :frequency => 12, :period => 'Month') + @gateway.recurring(@amount, @credit_card, :description => 'some description', :start_date => Time.now, :frequency => 12, :period => 'Month') end assert_instance_of Response, response assert !response.success? @@ -474,21 +474,21 @@ def test_bill_outstanding_amoung_response end def test_mass_pay_transfer_recipient_types - response = stub_comms do + stub_comms do @gateway.transfer 1000, 'fred@example.com' end.check_request do |endpoint, data, headers| assert_no_match %r{ReceiverType}, data end.respond_with(successful_purchase_response) - response = stub_comms do - @gateway.transfer 1000, 'fred@example.com', :receiver_type => "EmailAddress" + stub_comms do + @gateway.transfer 1000, 'fred@example.com', :receiver_type => 'EmailAddress' end.check_request do |endpoint, data, headers| assert_match %r{<ReceiverType>EmailAddress</ReceiverType>}, data assert_match %r{<ReceiverEmail>fred@example\.com</ReceiverEmail>}, data end.respond_with(successful_purchase_response) - response = stub_comms do - @gateway.transfer 1000, 'fred@example.com', :receiver_type => "UserID" + stub_comms do + @gateway.transfer 1000, 'fred@example.com', :receiver_type => 'UserID' end.check_request do |endpoint, data, headers| assert_match %r{<ReceiverType>UserID</ReceiverType>}, data assert_match %r{<ReceiverID>fred@example\.com</ReceiverID>}, data @@ -500,8 +500,8 @@ def test_successful_verify @gateway.verify(@credit_card, @options) end.respond_with(successful_zero_dollar_auth_response) assert_success response - assert_equal "This card authorization verification is not a payment transaction.", response.message - assert_equal "0.00", response.params["amount"] + assert_equal 'This card authorization verification is not a payment transaction.', response.message + assert_equal '0.00', response.params['amount'] end def test_failed_verify @@ -518,8 +518,8 @@ def test_successful_verify_non_visa_mc @gateway.verify(amex_card, @options) end.respond_with(successful_one_dollar_auth_response, successful_void_response) assert_success response - assert_equal "Success", response.message - assert_equal "1.00", response.params["amount"] + assert_equal 'Success', response.message + assert_equal '1.00', response.params['amount'] end def test_successful_verify_non_visa_mc_failed_void @@ -528,8 +528,8 @@ def test_successful_verify_non_visa_mc_failed_void @gateway.verify(amex_card, @options) end.respond_with(successful_one_dollar_auth_response, failed_void_response) assert_success response - assert_equal "Success", response.message - assert_equal "1.00", response.params["amount"] + assert_equal 'Success', response.message + assert_equal '1.00', response.params['amount'] end def test_failed_verify_non_visa_mc @@ -539,7 +539,7 @@ def test_failed_verify_non_visa_mc end.respond_with(failed_one_dollar_auth_response, successful_void_response) assert_failure response assert_match %r{This transaction cannot be processed}, response.message - assert_equal "1.00", response.params["amount"] + assert_equal '1.00', response.params['amount'] end def test_scrub @@ -566,7 +566,7 @@ def test_blank_cvv_not_sent assert_no_match(%r{CVV2}, data) end.respond_with(successful_purchase_response) - @credit_card.verification_value = " " + @credit_card.verification_value = ' ' stub_comms do @gateway.purchase(@amount, @credit_card, @options) end.check_request do |endpoint, data, headers| @@ -575,7 +575,7 @@ def test_blank_cvv_not_sent end def test_card_declined - ["15005", "10754", "10752", "10759", "10761", "15002", "11084"].each do |error_code| + ['15005', '10754', '10752', '10759', '10761', '15002', '11084'].each do |error_code| @gateway.expects(:ssl_request).returns(response_with_error_code(error_code)) response = @gateway.purchase(@amount, @credit_card, @options) @@ -585,7 +585,7 @@ def test_card_declined end def test_incorrect_cvc - ["15004"].each do |error_code| + ['15004'].each do |error_code| @gateway.expects(:ssl_request).returns(response_with_error_code(error_code)) response = @gateway.purchase(@amount, @credit_card, @options) @@ -595,7 +595,7 @@ def test_incorrect_cvc end def test_invalid_cvc - ["10762"].each do |error_code| + ['10762'].each do |error_code| @gateway.expects(:ssl_request).returns(response_with_error_code(error_code)) response = @gateway.purchase(@amount, @credit_card, @options) @@ -605,7 +605,7 @@ def test_invalid_cvc end def test_error_code_with_no_mapping_returns_standardized_processing_error - @gateway.expects(:ssl_request).returns(response_with_error_code("999999")) + @gateway.expects(:ssl_request).returns(response_with_error_code('999999')) response = @gateway.purchase(@amount, @credit_card, @options) assert_equal(:processing_error, response.error_code) @@ -642,7 +642,7 @@ def post_scrubbed starting SSL for api-3t.sandbox.paypal.com:443... SSL established <- "POST /2.0/ HTTP/1.1\r\nContent-Type: application/x-www-form-urlencoded\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nAccept: */*\r\nUser-Agent: Ruby\r\nConnection: close\r\nHost: api-3t.sandbox.paypal.com\r\nContent-Length: 2229\r\n\r\n" - <- "<?xml version=\"1.0\" encoding=\"UTF-8\"?><env:Envelope xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:env=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"><env:Header><RequesterCredentials xmlns=\"urn:ebay:api:PayPalAPI\" xmlns:n1=\"urn:ebay:apis:eBLBaseComponents\" env:mustUnderstand=\"0\"><n1:Credentials><n1:Username>[FILTERED]</n1:Username><n1:Password>[FILTERED]</n1:Password><n1:Subject/><n1:Signature>AFcWxV21C7fd0v3bYYYRCpSSRl31AC-11AKBL8FFO9tjImL311y8a0hx</n1:Signature></n1:Credentials></RequesterCredentials></env:Header><env:Body><DoDirectPaymentReq xmlns=\"urn:ebay:api:PayPalAPI\">\n <DoDirectPaymentRequest xmlns:n2=\"urn:ebay:apis:eBLBaseComponents\">\n <n2:Version>72</n2:Version>\n <n2:DoDirectPaymentRequestDetails>\n <n2:PaymentAction>Sale</n2:PaymentAction>\n <n2:PaymentDetails>\n <n2:OrderTotal currencyID=\"USD\">1.00</n2:OrderTotal>\n <n2:OrderDescription>Stuff that you purchased, yo!</n2:OrderDescription>\n <n2:InvoiceID>70e472b155c61d27fe19555a96d51127</n2:InvoiceID>\n <n2:ButtonSource>ActiveMerchant</n2:ButtonSource>\n </n2:PaymentDetails>\n <n2:CreditCard>\n <n2:CreditCardType>Visa</n2:CreditCardType>\n <n2:CreditCardNumber>[FILTERED]</n2:CreditCardNumber>\n <n2:ExpMonth>09</n2:ExpMonth>\n <n2:ExpYear>2015</n2:ExpYear>\n <n2:CVV2>[FILTERED]</n2:CVV2>\n <n2:CardOwner>\n <n2:PayerName>\n <n2:FirstName>Longbob</n2:FirstName>\n <n2:LastName>Longsen</n2:LastName>\n </n2:PayerName>\n <n2:Payer>buyer@jadedpallet.com</n2:Payer>\n <n2:Address>\n <n2:Name>Longbob Longsen</n2:Name>\n <n2:Street1>1234 Penny Lane</n2:Street1>\n <n2:Street2/>\n <n2:CityName>Jonsetown</n2:CityName>\n <n2:StateOrProvince>NC</n2:StateOrProvince>\n <n2:Country>US</n2:Country>\n <n2:PostalCode>23456</n2:PostalCode>\n </n2:Address>\n </n2:CardOwner>\n </n2:CreditCard>\n <n2:IPAddress>10.0.0.1</n2:IPAddress>\n </n2:DoDirectPaymentRequestDetails>\n </DoDirectPaymentRequest>\n</DoDirectPaymentReq>\n</env:Body></env:Envelope>" + <- "<?xml version=\"1.0\" encoding=\"UTF-8\"?><env:Envelope xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:env=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"><env:Header><RequesterCredentials xmlns=\"urn:ebay:api:PayPalAPI\" xmlns:n1=\"urn:ebay:apis:eBLBaseComponents\" env:mustUnderstand=\"0\"><n1:Credentials><n1:Username>[FILTERED]</n1:Username><n1:Password>[FILTERED]</n1:Password><n1:Subject/><n1:Signature>[FILTERED]</n1:Signature></n1:Credentials></RequesterCredentials></env:Header><env:Body><DoDirectPaymentReq xmlns=\"urn:ebay:api:PayPalAPI\">\n <DoDirectPaymentRequest xmlns:n2=\"urn:ebay:apis:eBLBaseComponents\">\n <n2:Version>72</n2:Version>\n <n2:DoDirectPaymentRequestDetails>\n <n2:PaymentAction>Sale</n2:PaymentAction>\n <n2:PaymentDetails>\n <n2:OrderTotal currencyID=\"USD\">1.00</n2:OrderTotal>\n <n2:OrderDescription>Stuff that you purchased, yo!</n2:OrderDescription>\n <n2:InvoiceID>70e472b155c61d27fe19555a96d51127</n2:InvoiceID>\n <n2:ButtonSource>ActiveMerchant</n2:ButtonSource>\n </n2:PaymentDetails>\n <n2:CreditCard>\n <n2:CreditCardType>Visa</n2:CreditCardType>\n <n2:CreditCardNumber>[FILTERED]</n2:CreditCardNumber>\n <n2:ExpMonth>09</n2:ExpMonth>\n <n2:ExpYear>2015</n2:ExpYear>\n <n2:CVV2>[FILTERED]</n2:CVV2>\n <n2:CardOwner>\n <n2:PayerName>\n <n2:FirstName>Longbob</n2:FirstName>\n <n2:LastName>Longsen</n2:LastName>\n </n2:PayerName>\n <n2:Payer>buyer@jadedpallet.com</n2:Payer>\n <n2:Address>\n <n2:Name>Longbob Longsen</n2:Name>\n <n2:Street1>1234 Penny Lane</n2:Street1>\n <n2:Street2/>\n <n2:CityName>Jonsetown</n2:CityName>\n <n2:StateOrProvince>NC</n2:StateOrProvince>\n <n2:Country>US</n2:Country>\n <n2:PostalCode>23456</n2:PostalCode>\n </n2:Address>\n </n2:CardOwner>\n </n2:CreditCard>\n <n2:IPAddress>10.0.0.1</n2:IPAddress>\n </n2:DoDirectPaymentRequestDetails>\n </DoDirectPaymentRequest>\n</DoDirectPaymentReq>\n</env:Body></env:Envelope>" -> "HTTP/1.1 200 OK\r\n" -> "Date: Tue, 02 Dec 2014 18:44:21 GMT\r\n" -> "Server: Apache\r\n" @@ -1380,7 +1380,6 @@ def successful_details_response RESPONSE end - def successful_update_recurring_payment_profile_response <<-RESPONSE <?xml version=\"1.0\" encoding=\"UTF-8\"?><SOAP-ENV:Envelope xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:SOAP-ENC=\"http://schemas.xmlsoap.org/soap/encoding/\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:xs=\"http://www.w3.org/2001/XMLSchema\" xmlns:cc=\"urn:ebay:apis:CoreComponentTypes\" xmlns:wsu=\"http://schemas.xmlsoap.org/ws/2002/07/utility\" xmlns:saml=\"urn:oasis:names:tc:SAML:1.0:assertion\" xmlns:ds=\"http://www.w3.org/2000/09/xmldsig#\" xmlns:wsse=\"http://schemas.xmlsoap.org/ws/2002/12/secext\" xmlns:ed=\"urn:ebay:apis:EnhancedDataTypes\" xmlns:ebl=\"urn:ebay:apis:eBLBaseComponents\" xmlns:ns=\"urn:ebay:api:PayPalAPI\"><SOAP-ENV:Header><Security xmlns=\"http://schemas.xmlsoap.org/ws/2002/12/secext\" xsi:type=\"wsse:SecurityType\"></Security><RequesterCredentials xmlns=\"urn:ebay:api:PayPalAPI\" xsi:type=\"ebl:CustomSecurityHeaderType\"><Credentials xmlns=\"urn:ebay:apis:eBLBaseComponents\" xsi:type=\"ebl:UserIdPasswordType\"><Username xsi:type=\"xs:string\"></Username><Password xsi:type=\"xs:string\"></Password><Signature xsi:type=\"xs:string\"></Signature><Subject xsi:type=\"xs:string\"></Subject></Credentials></RequesterCredentials></SOAP-ENV:Header><SOAP-ENV:Body id=\"_0\"> diff --git a/test/unit/gateways/payscout_test.rb b/test/unit/gateways/payscout_test.rb index 0781da14568..f5cb64b3a3f 100644 --- a/test/unit/gateways/payscout_test.rb +++ b/test/unit/gateways/payscout_test.rb @@ -118,7 +118,7 @@ def test_approved_refund assert refund = @gateway.refund(@amount, '1234567890') assert_success refund - assert_equal "The transaction has been approved", refund.message + assert_equal 'The transaction has been approved', refund.message end def test_not_found_transaction_id_refund @@ -126,7 +126,7 @@ def test_not_found_transaction_id_refund assert refund = @gateway.refund(@amount, '1234567890') assert_failure refund - assert_match "Transaction+not+found", refund.message + assert_match 'Transaction+not+found', refund.message end def test_invalid_transaction_id_refund @@ -134,7 +134,7 @@ def test_invalid_transaction_id_refund assert refund = @gateway.refund(@amount, '') assert_failure refund - assert_match "Invalid+Transaction+ID", refund.message + assert_match 'Invalid+Transaction+ID', refund.message end def test_invalid_amount_refund @@ -142,7 +142,7 @@ def test_invalid_amount_refund assert refund = @gateway.refund(200, '1234567890') assert_failure refund - assert_match "Refund+amount+may+not+exceed+the+transaction+balance", refund.message + assert_match 'Refund+amount+may+not+exceed+the+transaction+balance', refund.message end # Void @@ -152,7 +152,7 @@ def test_approved_void_purchase assert void = @gateway.void('1234567890') assert_success void - assert_equal "The transaction has been approved", void.message + assert_equal 'The transaction has been approved', void.message end def test_approved_void_authorization @@ -160,7 +160,7 @@ def test_approved_void_authorization assert void = @gateway.void('1234567890') assert_success void - assert_equal "The transaction has been approved", void.message + assert_equal 'The transaction has been approved', void.message end def test_invalid_transaction_id_void @@ -168,7 +168,7 @@ def test_invalid_transaction_id_void assert void = @gateway.void('') assert_failure void - assert_match "Invalid+Transaction+ID", void.message + assert_match 'Invalid+Transaction+ID', void.message end def test_not_found_transaction_id_void @@ -176,7 +176,7 @@ def test_not_found_transaction_id_void assert void = @gateway.void('1234567890') assert_failure void - assert_match "Transaction+not+found", void.message + assert_match 'Transaction+not+found', void.message end # Methods @@ -214,7 +214,6 @@ def test_shipping_address assert_equal address[:email], post[:shipping_email] end - def test_add_currency_from_options post = {} @gateway.send(:add_currency, post, 100, { currency: 'CAD' }) @@ -243,7 +242,7 @@ def test_expdate @credit_card.year = 2015 @credit_card.month = 8 - assert_equal "0815", @gateway.send(:expdate, @credit_card) + assert_equal '0815', @gateway.send(:expdate, @credit_card) end def test_add_creditcard @@ -260,15 +259,15 @@ def test_add_creditcard def test_parse data = @gateway.send(:parse, approved_authorization_response) - assert data.keys.include?('response') - assert data.keys.include?('responsetext') - assert data.keys.include?('authcode') - assert data.keys.include?('transactionid') - assert data.keys.include?('avsresponse') - assert data.keys.include?('cvvresponse') - assert data.keys.include?('orderid') - assert data.keys.include?('type') - assert data.keys.include?('response_code') + assert data.key?('response') + assert data.key?('responsetext') + assert data.key?('authcode') + assert data.key?('transactionid') + assert data.key?('avsresponse') + assert data.key?('cvvresponse') + assert data.key?('orderid') + assert data.key?('type') + assert data.key?('response_code') assert_equal '1', data['response'] assert_equal 'SUCCESS', data['responsetext'] @@ -303,11 +302,11 @@ def test_post_data parameters = {param1: 'value1', param2: 'value2'} result = @gateway.send(:post_data, 'auth', parameters) - assert_match "username=xxx", result - assert_match "password=xxx", result - assert_match "type=auth", result - assert_match "param1=value1", result - assert_match "param2=value2", result + assert_match 'username=xxx', result + assert_match 'password=xxx', result + assert_match 'type=auth', result + assert_match 'param1=value1', result + assert_match 'param2=value2', result end private diff --git a/test/unit/gateways/paystation_test.rb b/test/unit/gateways/paystation_test.rb index 4e4337b14d9..c32716c1383 100644 --- a/test/unit/gateways/paystation_test.rb +++ b/test/unit/gateways/paystation_test.rb @@ -3,7 +3,6 @@ class PaystationTest < Test::Unit::TestCase include CommStub def setup - @gateway = PaystationGateway.new( :paystation_id => 'some_id_number', :gateway_id => 'another_id_number' @@ -27,7 +26,7 @@ def test_successful_purchase assert_equal '0008813023-01', response.authorization - assert_equal 'Store Purchase', response.params["merchant_reference"] + assert_equal 'Store Purchase', response.params['merchant_reference'] assert response.test? end @@ -42,24 +41,24 @@ def test_unsuccessful_request def test_successful_store @gateway.expects(:ssl_post).returns(successful_store_response) - assert response = @gateway.store(@credit_card, @options.merge(:token => "justatest1310263135")) + assert response = @gateway.store(@credit_card, @options.merge(:token => 'justatest1310263135')) assert_success response assert response.test? - assert_equal "justatest1310263135", response.token + assert_equal 'justatest1310263135', response.token end def test_successful_purchase_from_token @gateway.expects(:ssl_post).returns(successful_stored_purchase_response) - token = "u09fxli14afpnd6022x0z82317beqe9e2w048l9it8286k6lpvz9x27hdal9bl95" + token = 'u09fxli14afpnd6022x0z82317beqe9e2w048l9it8286k6lpvz9x27hdal9bl95' assert response = @gateway.purchase(@amount, token, @options) assert_success response assert_equal '0009062149-01', response.authorization - assert_equal 'Store Purchase', response.params["merchant_reference"] + assert_equal 'Store Purchase', response.params['merchant_reference'] assert response.test? end @@ -75,19 +74,18 @@ def test_successful_authorization def test_successful_capture @gateway.expects(:ssl_post).returns(successful_capture_response) - assert response = @gateway.capture(@amount, "0009062250-01", @options.merge(:credit_card_verification => 123)) + assert response = @gateway.capture(@amount, '0009062250-01', @options.merge(:credit_card_verification => 123)) assert_success response end def test_successful_refund - response = stub_comms do @gateway.purchase(@amount, @credit_card, @options) end.respond_with(successful_purchase_response) assert_success response assert_equal '0008813023-01', response.authorization - assert_equal 'Store Purchase', response.params["merchant_reference"] + assert_equal 'Store Purchase', response.params['merchant_reference'] refund = stub_comms do @gateway.refund(@amount, response.authorization, @options) @@ -100,312 +98,332 @@ def test_successful_refund def test_failed_refund response = stub_comms do - @gateway.refund(nil, "", @options) + @gateway.refund(nil, '', @options) end.respond_with(failed_refund_response) assert_failure response end + def test_successful_verify + @gateway.expects(:ssl_post).returns(successful_authorization_response) + + assert response = @gateway.verify(@credit_card, @options) + assert_success response + end + + def test_scrub + assert @gateway.supports_scrubbing? + assert_equal @gateway.scrub(pre_scrubbed), post_scrubbed + end + private - def successful_purchase_response - %(<?xml version="1.0" standalone="yes"?> - <response> - <ec>0</ec> - <em>Transaction successful</em> - <ti>0006713018-01</ti> - <ct>mastercard</ct> - <merchant_ref>Store Purchase</merchant_ref> - <tm>T</tm> - <MerchantSession>1</MerchantSession> - <UsedAcquirerMerchantID>123456</UsedAcquirerMerchantID> - <TransactionID>0008813023-01</TransactionID> - <PurchaseAmount>10000</PurchaseAmount> - <Locale/> - <ReturnReceiptNumber>8813023</ReturnReceiptNumber> - <ShoppingTransactionNumber/> - <AcqResponseCode>00</AcqResponseCode> - <QSIResponseCode>0</QSIResponseCode> - <CSCResultCode/> - <AVSResultCode/> - <TransactionTime>2011-06-22 00:05:52</TransactionTime> - <PaystationErrorCode>0</PaystationErrorCode> - <PaystationErrorMessage>Transaction successful</PaystationErrorMessage> - <MerchantReference>Store Purchase</MerchantReference> - <TransactionMode>T</TransactionMode> - <BatchNumber>0622</BatchNumber> - <AuthorizeID/> - <Cardtype>MC</Cardtype> - <Username>12345</Username> - <RequestIP>192.168.0.1</RequestIP> - <RequestUserAgent/> - <RequestHttpReferrer/> - <PaymentRequestTime>2011-06-22 00:05:52</PaymentRequestTime> - <DigitalOrderTime/> - <DigitalReceiptTime>2011-06-22 00:05:52</DigitalReceiptTime> - <PaystationTransactionID>0008813023-01</PaystationTransactionID> - <IssuerName>unknown</IssuerName> - <IssuerCountry>unknown</IssuerCountry> - </response>) - end - - def failed_purchase_response - %(<?xml version="1.0" standalone="yes"?> - <response> - <ec>5</ec> - <em>Insufficient Funds</em> - <ti>0006713018-01</ti> - <ct>mastercard</ct> - <merchant_ref>Store Purchase</merchant_ref> - <tm>T</tm> - <MerchantSession>1</MerchantSession> - <UsedAcquirerMerchantID>123456</UsedAcquirerMerchantID> - <TransactionID>0008813018-01</TransactionID> - <PurchaseAmount>10051</PurchaseAmount> - <Locale/> - <ReturnReceiptNumber>8813018</ReturnReceiptNumber> - <ShoppingTransactionNumber/> - <AcqResponseCode>51</AcqResponseCode> - <QSIResponseCode>5</QSIResponseCode> - <CSCResultCode/> - <AVSResultCode/> - <TransactionTime>2011-06-22 00:05:46</TransactionTime> - <PaystationErrorCode>5</PaystationErrorCode> - <PaystationErrorMessage>Insufficient Funds</PaystationErrorMessage> - <MerchantReference>Store Purchase</MerchantReference> - <TransactionMode>T</TransactionMode> - <BatchNumber>0622</BatchNumber> - <AuthorizeID/> - <Cardtype>MC</Cardtype> - <Username>123456</Username> - <RequestIP>192.168.0.1</RequestIP> - <RequestUserAgent/> - <RequestHttpReferrer/> - <PaymentRequestTime>2011-06-22 00:05:46</PaymentRequestTime> - <DigitalOrderTime/> - <DigitalReceiptTime>2011-06-22 00:05:46</DigitalReceiptTime> - <PaystationTransactionID>0008813018-01</PaystationTransactionID> - <IssuerName>unknown</IssuerName> - <IssuerCountry>unknown</IssuerCountry> - </response>) - end - - def successful_store_response - %(<?xml version="1.0" standalone="yes"?> - <PaystationFuturePaymentResponse> - <ec>34</ec> - <em>Future Payment Saved Ok</em> - <ti/> - <ct/> - <merchant_ref>Store Purchase</merchant_ref> - <tm>T</tm> - <MerchantSession>3e48fa9a6b0fe36177adf7269db7a3c4</MerchantSession> - <UsedAcquirerMerchantID/> - <TransactionID/> - <PurchaseAmount>0</PurchaseAmount> - <Locale/> - <ReturnReceiptNumber/> - <ShoppingTransactionNumber/> - <AcqResponseCode/> - <QSIResponseCode/> - <CSCResultCode/> - <AVSResultCode/> - <TransactionTime>2011-07-10 13:58:55</TransactionTime> - <PaystationErrorCode>34</PaystationErrorCode> - <PaystationErrorMessage>Future Payment Saved Ok</PaystationErrorMessage> - <MerchantReference>Store Purchase</MerchantReference> - <TransactionMode>T</TransactionMode> - <BatchNumber/> - <AuthorizeID/> - <Cardtype/> - <Username>123456</Username> - <RequestIP>192.168.0.1</RequestIP> - <RequestUserAgent/> - <RequestHttpReferrer/> - <PaymentRequestTime>2011-07-10 13:58:55</PaymentRequestTime> - <DigitalOrderTime/> - <DigitalReceiptTime>2011-07-10 13:58:55</DigitalReceiptTime> - <PaystationTransactionID>0009062177-01</PaystationTransactionID> - <FuturePaymentToken>justatest1310263135</FuturePaymentToken> - <IssuerName>unknown</IssuerName> - <IssuerCountry>unknown</IssuerCountry> - </PaystationFuturePaymentResponse>) - end - - def successful_stored_purchase_response - %(<?xml version="1.0" standalone="yes"?> - <PaystationFuturePaymentResponse> - <ec>0</ec> - <em>Transaction successful</em> - <ti>0006713018-01</ti> - <ct>visa</ct> - <merchant_ref>Store Purchase</merchant_ref> - <tm>T</tm> - <MerchantSession>0fc70a577f19ae63f651f53c7044640a</MerchantSession> - <UsedAcquirerMerchantID>123456</UsedAcquirerMerchantID> - <TransactionID>0009062149-01</TransactionID> - <PurchaseAmount>10000</PurchaseAmount> - <Locale/> - <ReturnReceiptNumber>9062149</ReturnReceiptNumber> - <ShoppingTransactionNumber/> - <AcqResponseCode>00</AcqResponseCode> - <QSIResponseCode>0</QSIResponseCode> - <CSCResultCode/> - <AVSResultCode/> - <TransactionTime>2011-07-10 13:55:00</TransactionTime> - <PaystationErrorCode>0</PaystationErrorCode> - <PaystationErrorMessage>Transaction successful</PaystationErrorMessage> - <MerchantReference>Store Purchase</MerchantReference> - <TransactionMode>T</TransactionMode> - <BatchNumber>0710</BatchNumber> - <AuthorizeID/> - <Cardtype>VC</Cardtype> - <Username>123456</Username> - <RequestIP>192.168.0.1</RequestIP> - <RequestUserAgent/> - <RequestHttpReferrer/> - <PaymentRequestTime>2011-07-10 13:55:00</PaymentRequestTime> - <DigitalOrderTime/> - <DigitalReceiptTime>2011-07-10 13:55:00</DigitalReceiptTime> - <PaystationTransactionID>0009062149-01</PaystationTransactionID> - <FuturePaymentToken>u09fxli14afpnd6022x0z82317beqe9e2w048l9it8286k6lpvz9x27hdal9bl95</FuturePaymentToken> - <IssuerName>unknown</IssuerName> - <IssuerCountry>unknown</IssuerCountry> - </PaystationFuturePaymentResponse>) - end - - def successful_authorization_response - %(<?xml version="1.0" standalone="yes"?> - <response> - <ec>0</ec> - <em>Transaction successful</em> - <ti>0009062250-01</ti> - <ct>visa</ct> - <merchant_ref>Store Purchase</merchant_ref> - <tm>T</tm> - <MerchantSession>b2168af96076522466af4e3d61e5ba0c</MerchantSession> - <UsedAcquirerMerchantID>123456</UsedAcquirerMerchantID> - <TransactionID>0009062250-01</TransactionID> - <PurchaseAmount>10000</PurchaseAmount> - <Locale/> - <ReturnReceiptNumber>9062250</ReturnReceiptNumber> - <ShoppingTransactionNumber/> - <AcqResponseCode>00</AcqResponseCode> - <QSIResponseCode>0</QSIResponseCode> - <CSCResultCode/> - <AVSResultCode/> - <TransactionTime>2011-07-10 14:11:00</TransactionTime> - <PaystationErrorCode>0</PaystationErrorCode> - <PaystationErrorMessage>Transaction successful</PaystationErrorMessage> - <MerchantReference>Store Purchase</MerchantReference> - <TransactionMode>T</TransactionMode> - <BatchNumber>0710</BatchNumber> - <AuthorizeID/> - <Cardtype>VC</Cardtype> - <Username>123456</Username> - <RequestIP>192.168.0.1</RequestIP> - <RequestUserAgent/> - <RequestHttpReferrer/> - <PaymentRequestTime>2011-07-10 14:11:00</PaymentRequestTime> - <DigitalOrderTime/> - <DigitalReceiptTime>2011-07-10 14:11:00</DigitalReceiptTime> - <PaystationTransactionID>0009062250-01</PaystationTransactionID> - <IssuerName>unknown</IssuerName> - <IssuerCountry>unknown</IssuerCountry> - </response>) - end - - def successful_capture_response - %(<?xml version="1.0" standalone="yes"?> - <PaystationCaptureResponse> - <ec>0</ec> - <em>Transaction successful</em> - <ti>0009062289-01</ti> - <ct/> - <merchant_ref>Store Purchase</merchant_ref> - <tm>T</tm> - <MerchantSession>485fdedc81dc83848dd799cd10a869db</MerchantSession> - <UsedAcquirerMerchantID>123456</UsedAcquirerMerchantID> - <TransactionID>0009062289-01</TransactionID> - <CaptureAmount>10000</CaptureAmount> - <Locale/> - <ReturnReceiptNumber>9062289</ReturnReceiptNumber> - <ShoppingTransactionNumber/> - <AcqResponseCode>00</AcqResponseCode> - <QSIResponseCode>0</QSIResponseCode> - <CSCResultCode/> - <AVSResultCode/> - <TransactionTime>2011-07-10 14:17:36</TransactionTime> - <PaystationErrorCode>0</PaystationErrorCode> - <PaystationErrorMessage>Transaction successful</PaystationErrorMessage> - <MerchantReference>Store Purchase</MerchantReference> - <TransactionMode>T</TransactionMode> - <BatchNumber>0710</BatchNumber> - <AuthorizeID/> - <Cardtype/> - <Username>123456</Username> - <RequestIP>192.168.0.1</RequestIP> - <RequestUserAgent/> - <RequestHttpReferrer/> - <PaymentRequestTime>2011-07-10 14:17:36</PaymentRequestTime> - <DigitalOrderTime>2011-07-10 14:17:36</DigitalOrderTime> - <DigitalReceiptTime>2011-07-10 14:17:36</DigitalReceiptTime> - <PaystationTransactionID/> - <RefundedAmount/> - <CapturedAmount>10000</CapturedAmount> - <AuthorisedAmount/> - </PaystationCaptureResponse>) - end - - def successful_refund_response - %(<?xml version="1.0" standalone="yes"?> - <PaystationRefundResponse> - <ec>0</ec> - <em>Transaction successful</em> - <ti>0008813023-01</ti> - <ct>mastercard</ct> - <merchant_ref>Store Purchase</merchant_ref> - <tm>T</tm> - <MerchantSession>70ceae1b3f069e41ca7f4350a1180cb1</MerchantSession> - <UsedAcquirerMerchantID>924518</UsedAcquirerMerchantID> - <TransactionID>0008813023-01</TransactionID> - <RefundAmount>10000</RefundAmount> - <SurchargeAmount/> - <Locale>en</Locale> - <ReturnReceiptNumber>58160420</ReturnReceiptNumber> - <ShoppingTransactionNumber/> - <AcqResponseCode>00</AcqResponseCode> - <QSIResponseCode>0</QSIResponseCode> - <CSCResultCode/> - <AVSResultCode/> - <TransactionTime>2015-06-25 03:23:24</TransactionTime> - <PaystationErrorCode>0</PaystationErrorCode> - <PaystationErrorMessage>Transaction successful</PaystationErrorMessage> - <PaystationExtendedErrorMessage/> - <MerchantReference>Store Purchase</MerchantReference> - <CardNo>512345XXXXXXX346</CardNo> - <CardExpiry>1305</CardExpiry> - <TransactionProcess>refund</TransactionProcess> - <TransactionMode>T</TransactionMode> - <BatchNumber>0625</BatchNumber> - <AuthorizeID/> - <Cardtype>MC</Cardtype> - <Username>609035</Username> - <RequestIP>173.95.131.239</RequestIP> - <RequestUserAgent>Ruby</RequestUserAgent> - <RequestHttpReferrer/> - <PaymentRequestTime>2015-06-25 03:23:24</PaymentRequestTime> - <DigitalOrderTime>2015-06-25 03:23:24</DigitalOrderTime> - <DigitalReceiptTime/> - <PaystationTransactionID/> - <RefundedAmount>10000</RefundedAmount> - <CapturedAmount/> - </PaystationRefundResponse>) - end - - def failed_refund_response - %(<?xml version="1.0" standalone="yes"?> - <FONT FACE="Arial" SIZE="2"><strong>Error 11:</strong> Not enough input parameters.</FONT>) - end + def successful_purchase_response + %(<?xml version="1.0" standalone="yes"?> + <response> + <ec>0</ec> + <em>Transaction successful</em> + <ti>0006713018-01</ti> + <ct>mastercard</ct> + <merchant_ref>Store Purchase</merchant_ref> + <tm>T</tm> + <MerchantSession>1</MerchantSession> + <UsedAcquirerMerchantID>123456</UsedAcquirerMerchantID> + <TransactionID>0008813023-01</TransactionID> + <PurchaseAmount>10000</PurchaseAmount> + <Locale/> + <ReturnReceiptNumber>8813023</ReturnReceiptNumber> + <ShoppingTransactionNumber/> + <AcqResponseCode>00</AcqResponseCode> + <QSIResponseCode>0</QSIResponseCode> + <CSCResultCode/> + <AVSResultCode/> + <TransactionTime>2011-06-22 00:05:52</TransactionTime> + <PaystationErrorCode>0</PaystationErrorCode> + <PaystationErrorMessage>Transaction successful</PaystationErrorMessage> + <MerchantReference>Store Purchase</MerchantReference> + <TransactionMode>T</TransactionMode> + <BatchNumber>0622</BatchNumber> + <AuthorizeID/> + <Cardtype>MC</Cardtype> + <Username>12345</Username> + <RequestIP>192.168.0.1</RequestIP> + <RequestUserAgent/> + <RequestHttpReferrer/> + <PaymentRequestTime>2011-06-22 00:05:52</PaymentRequestTime> + <DigitalOrderTime/> + <DigitalReceiptTime>2011-06-22 00:05:52</DigitalReceiptTime> + <PaystationTransactionID>0008813023-01</PaystationTransactionID> + <IssuerName>unknown</IssuerName> + <IssuerCountry>unknown</IssuerCountry> + </response>) + end + + def failed_purchase_response + %(<?xml version="1.0" standalone="yes"?> + <response> + <ec>5</ec> + <em>Insufficient Funds</em> + <ti>0006713018-01</ti> + <ct>mastercard</ct> + <merchant_ref>Store Purchase</merchant_ref> + <tm>T</tm> + <MerchantSession>1</MerchantSession> + <UsedAcquirerMerchantID>123456</UsedAcquirerMerchantID> + <TransactionID>0008813018-01</TransactionID> + <PurchaseAmount>10051</PurchaseAmount> + <Locale/> + <ReturnReceiptNumber>8813018</ReturnReceiptNumber> + <ShoppingTransactionNumber/> + <AcqResponseCode>51</AcqResponseCode> + <QSIResponseCode>5</QSIResponseCode> + <CSCResultCode/> + <AVSResultCode/> + <TransactionTime>2011-06-22 00:05:46</TransactionTime> + <PaystationErrorCode>5</PaystationErrorCode> + <PaystationErrorMessage>Insufficient Funds</PaystationErrorMessage> + <MerchantReference>Store Purchase</MerchantReference> + <TransactionMode>T</TransactionMode> + <BatchNumber>0622</BatchNumber> + <AuthorizeID/> + <Cardtype>MC</Cardtype> + <Username>123456</Username> + <RequestIP>192.168.0.1</RequestIP> + <RequestUserAgent/> + <RequestHttpReferrer/> + <PaymentRequestTime>2011-06-22 00:05:46</PaymentRequestTime> + <DigitalOrderTime/> + <DigitalReceiptTime>2011-06-22 00:05:46</DigitalReceiptTime> + <PaystationTransactionID>0008813018-01</PaystationTransactionID> + <IssuerName>unknown</IssuerName> + <IssuerCountry>unknown</IssuerCountry> + </response>) + end + + def successful_store_response + %(<?xml version="1.0" standalone="yes"?> + <PaystationFuturePaymentResponse> + <ec>34</ec> + <em>Future Payment Saved Ok</em> + <ti/> + <ct/> + <merchant_ref>Store Purchase</merchant_ref> + <tm>T</tm> + <MerchantSession>3e48fa9a6b0fe36177adf7269db7a3c4</MerchantSession> + <UsedAcquirerMerchantID/> + <TransactionID/> + <PurchaseAmount>0</PurchaseAmount> + <Locale/> + <ReturnReceiptNumber/> + <ShoppingTransactionNumber/> + <AcqResponseCode/> + <QSIResponseCode/> + <CSCResultCode/> + <AVSResultCode/> + <TransactionTime>2011-07-10 13:58:55</TransactionTime> + <PaystationErrorCode>34</PaystationErrorCode> + <PaystationErrorMessage>Future Payment Saved Ok</PaystationErrorMessage> + <MerchantReference>Store Purchase</MerchantReference> + <TransactionMode>T</TransactionMode> + <BatchNumber/> + <AuthorizeID/> + <Cardtype/> + <Username>123456</Username> + <RequestIP>192.168.0.1</RequestIP> + <RequestUserAgent/> + <RequestHttpReferrer/> + <PaymentRequestTime>2011-07-10 13:58:55</PaymentRequestTime> + <DigitalOrderTime/> + <DigitalReceiptTime>2011-07-10 13:58:55</DigitalReceiptTime> + <PaystationTransactionID>0009062177-01</PaystationTransactionID> + <FuturePaymentToken>justatest1310263135</FuturePaymentToken> + <IssuerName>unknown</IssuerName> + <IssuerCountry>unknown</IssuerCountry> + </PaystationFuturePaymentResponse>) + end + + def successful_stored_purchase_response + %(<?xml version="1.0" standalone="yes"?> + <PaystationFuturePaymentResponse> + <ec>0</ec> + <em>Transaction successful</em> + <ti>0006713018-01</ti> + <ct>visa</ct> + <merchant_ref>Store Purchase</merchant_ref> + <tm>T</tm> + <MerchantSession>0fc70a577f19ae63f651f53c7044640a</MerchantSession> + <UsedAcquirerMerchantID>123456</UsedAcquirerMerchantID> + <TransactionID>0009062149-01</TransactionID> + <PurchaseAmount>10000</PurchaseAmount> + <Locale/> + <ReturnReceiptNumber>9062149</ReturnReceiptNumber> + <ShoppingTransactionNumber/> + <AcqResponseCode>00</AcqResponseCode> + <QSIResponseCode>0</QSIResponseCode> + <CSCResultCode/> + <AVSResultCode/> + <TransactionTime>2011-07-10 13:55:00</TransactionTime> + <PaystationErrorCode>0</PaystationErrorCode> + <PaystationErrorMessage>Transaction successful</PaystationErrorMessage> + <MerchantReference>Store Purchase</MerchantReference> + <TransactionMode>T</TransactionMode> + <BatchNumber>0710</BatchNumber> + <AuthorizeID/> + <Cardtype>VC</Cardtype> + <Username>123456</Username> + <RequestIP>192.168.0.1</RequestIP> + <RequestUserAgent/> + <RequestHttpReferrer/> + <PaymentRequestTime>2011-07-10 13:55:00</PaymentRequestTime> + <DigitalOrderTime/> + <DigitalReceiptTime>2011-07-10 13:55:00</DigitalReceiptTime> + <PaystationTransactionID>0009062149-01</PaystationTransactionID> + <FuturePaymentToken>u09fxli14afpnd6022x0z82317beqe9e2w048l9it8286k6lpvz9x27hdal9bl95</FuturePaymentToken> + <IssuerName>unknown</IssuerName> + <IssuerCountry>unknown</IssuerCountry> + </PaystationFuturePaymentResponse>) + end + + def successful_authorization_response + %(<?xml version="1.0" standalone="yes"?> + <response> + <ec>0</ec> + <em>Transaction successful</em> + <ti>0009062250-01</ti> + <ct>visa</ct> + <merchant_ref>Store Purchase</merchant_ref> + <tm>T</tm> + <MerchantSession>b2168af96076522466af4e3d61e5ba0c</MerchantSession> + <UsedAcquirerMerchantID>123456</UsedAcquirerMerchantID> + <TransactionID>0009062250-01</TransactionID> + <PurchaseAmount>10000</PurchaseAmount> + <Locale/> + <ReturnReceiptNumber>9062250</ReturnReceiptNumber> + <ShoppingTransactionNumber/> + <AcqResponseCode>00</AcqResponseCode> + <QSIResponseCode>0</QSIResponseCode> + <CSCResultCode/> + <AVSResultCode/> + <TransactionTime>2011-07-10 14:11:00</TransactionTime> + <PaystationErrorCode>0</PaystationErrorCode> + <PaystationErrorMessage>Transaction successful</PaystationErrorMessage> + <MerchantReference>Store Purchase</MerchantReference> + <TransactionMode>T</TransactionMode> + <BatchNumber>0710</BatchNumber> + <AuthorizeID/> + <Cardtype>VC</Cardtype> + <Username>123456</Username> + <RequestIP>192.168.0.1</RequestIP> + <RequestUserAgent/> + <RequestHttpReferrer/> + <PaymentRequestTime>2011-07-10 14:11:00</PaymentRequestTime> + <DigitalOrderTime/> + <DigitalReceiptTime>2011-07-10 14:11:00</DigitalReceiptTime> + <PaystationTransactionID>0009062250-01</PaystationTransactionID> + <IssuerName>unknown</IssuerName> + <IssuerCountry>unknown</IssuerCountry> + </response>) + end + + def successful_capture_response + %(<?xml version="1.0" standalone="yes"?> + <PaystationCaptureResponse> + <ec>0</ec> + <em>Transaction successful</em> + <ti>0009062289-01</ti> + <ct/> + <merchant_ref>Store Purchase</merchant_ref> + <tm>T</tm> + <MerchantSession>485fdedc81dc83848dd799cd10a869db</MerchantSession> + <UsedAcquirerMerchantID>123456</UsedAcquirerMerchantID> + <TransactionID>0009062289-01</TransactionID> + <CaptureAmount>10000</CaptureAmount> + <Locale/> + <ReturnReceiptNumber>9062289</ReturnReceiptNumber> + <ShoppingTransactionNumber/> + <AcqResponseCode>00</AcqResponseCode> + <QSIResponseCode>0</QSIResponseCode> + <CSCResultCode/> + <AVSResultCode/> + <TransactionTime>2011-07-10 14:17:36</TransactionTime> + <PaystationErrorCode>0</PaystationErrorCode> + <PaystationErrorMessage>Transaction successful</PaystationErrorMessage> + <MerchantReference>Store Purchase</MerchantReference> + <TransactionMode>T</TransactionMode> + <BatchNumber>0710</BatchNumber> + <AuthorizeID/> + <Cardtype/> + <Username>123456</Username> + <RequestIP>192.168.0.1</RequestIP> + <RequestUserAgent/> + <RequestHttpReferrer/> + <PaymentRequestTime>2011-07-10 14:17:36</PaymentRequestTime> + <DigitalOrderTime>2011-07-10 14:17:36</DigitalOrderTime> + <DigitalReceiptTime>2011-07-10 14:17:36</DigitalReceiptTime> + <PaystationTransactionID/> + <RefundedAmount/> + <CapturedAmount>10000</CapturedAmount> + <AuthorisedAmount/> + </PaystationCaptureResponse>) + end + + def successful_refund_response + %(<?xml version="1.0" standalone="yes"?> + <PaystationRefundResponse> + <ec>0</ec> + <em>Transaction successful</em> + <ti>0008813023-01</ti> + <ct>mastercard</ct> + <merchant_ref>Store Purchase</merchant_ref> + <tm>T</tm> + <MerchantSession>70ceae1b3f069e41ca7f4350a1180cb1</MerchantSession> + <UsedAcquirerMerchantID>924518</UsedAcquirerMerchantID> + <TransactionID>0008813023-01</TransactionID> + <RefundAmount>10000</RefundAmount> + <SurchargeAmount/> + <Locale>en</Locale> + <ReturnReceiptNumber>58160420</ReturnReceiptNumber> + <ShoppingTransactionNumber/> + <AcqResponseCode>00</AcqResponseCode> + <QSIResponseCode>0</QSIResponseCode> + <CSCResultCode/> + <AVSResultCode/> + <TransactionTime>2015-06-25 03:23:24</TransactionTime> + <PaystationErrorCode>0</PaystationErrorCode> + <PaystationErrorMessage>Transaction successful</PaystationErrorMessage> + <PaystationExtendedErrorMessage/> + <MerchantReference>Store Purchase</MerchantReference> + <CardNo>512345XXXXXXX346</CardNo> + <CardExpiry>1305</CardExpiry> + <TransactionProcess>refund</TransactionProcess> + <TransactionMode>T</TransactionMode> + <BatchNumber>0625</BatchNumber> + <AuthorizeID/> + <Cardtype>MC</Cardtype> + <Username>609035</Username> + <RequestIP>173.95.131.239</RequestIP> + <RequestUserAgent>Ruby</RequestUserAgent> + <RequestHttpReferrer/> + <PaymentRequestTime>2015-06-25 03:23:24</PaymentRequestTime> + <DigitalOrderTime>2015-06-25 03:23:24</DigitalOrderTime> + <DigitalReceiptTime/> + <PaystationTransactionID/> + <RefundedAmount>10000</RefundedAmount> + <CapturedAmount/> + </PaystationRefundResponse>) + end + + def failed_refund_response + %(<?xml version="1.0" standalone="yes"?> + <FONT FACE="Arial" SIZE="2"><strong>Error 11:</strong> Not enough input parameters.</FONT>) + end + + def pre_scrubbed + 'pstn_pi=609035&pstn_gi=PUSHPAY&pstn_2p=t&pstn_nr=t&pstn_df=yymm&pstn_ms=a755b9c84a530aee91dc3077f57294b0&pstn_mo=Store+Purchase&pstn_mr=&pstn_am=&pstn_cu=NZD&pstn_cn=5123456789012346&pstn_ct=visa&pstn_ex=1305&pstn_cc=123&pstn_tm=T&paystation=_empty' + end + + def post_scrubbed + 'pstn_pi=609035&pstn_gi=PUSHPAY&pstn_2p=t&pstn_nr=t&pstn_df=yymm&pstn_ms=a755b9c84a530aee91dc3077f57294b0&pstn_mo=Store+Purchase&pstn_mr=&pstn_am=&pstn_cu=NZD&pstn_cn=[FILTERED]&pstn_ct=visa&pstn_ex=1305&pstn_cc=[FILTERED]&pstn_tm=T&paystation=_empty' + end end diff --git a/test/unit/gateways/payu_in_test.rb b/test/unit/gateways/payu_in_test.rb index 8a366f1fb6e..876bae34162 100644 --- a/test/unit/gateways/payu_in_test.rb +++ b/test/unit/gateways/payu_in_test.rb @@ -1,24 +1,24 @@ -require "test_helper" +require 'test_helper' class PayuInTest < Test::Unit::TestCase include CommStub def setup @gateway = PayuInGateway.new( - key: "key", - salt: "salt" + key: 'key', + salt: 'salt' ) @credit_card = credit_card @options = { - order_id: "1" + order_id: '1' } end def assert_parameter(parameter, expected_value, data, options={}) assert (data =~ %r{(?:^|&)#{parameter}=([^&]*)(?:&|$)}), "Unable to find #{parameter} in #{data}" - value = CGI.unescape($1 || "") + value = CGI.unescape($1 || '') case expected_value when Regexp assert_match expected_value, value, "#{parameter} value does not match expected" @@ -34,41 +34,41 @@ def test_successful_purchase response = stub_comms do @gateway.purchase(100, @credit_card, @options) end.check_request do |endpoint, data, headers| - assert_equal "identity", headers["Accept-Encoding"] + assert_equal 'identity', headers['Accept-Encoding'] case endpoint when /_payment/ - assert_parameter("amount", "1.00", data) - assert_parameter("txnid", "1", data) - assert_parameter("productinfo", "Purchase", data) - assert_parameter("surl", "http://example.com", data) - assert_parameter("furl", "http://example.com", data) - assert_parameter("pg", "CC", data) - assert_parameter("firstname", @credit_card.first_name, data) - assert_parameter("bankcode", @credit_card.brand.upcase, data) - assert_parameter("ccnum", @credit_card.number, data) - assert_parameter("ccvv", @credit_card.verification_value, data) - assert_parameter("ccname", @credit_card.name, data) - assert_parameter("ccexpmon", "%02d" % @credit_card.month.to_i, data) - assert_parameter("ccexpyr", @credit_card.year, data) - assert_parameter("email", "unknown@example.com", data) - assert_parameter("phone", "11111111111", data) - assert_parameter("key", "key", data) - assert_parameter("txn_s2s_flow", "1", data) - assert_parameter("hash", "5199c0735c21d647f287a2781024743d35fabfd640bc20f2ae7b5277e3d7d06fa315fcdda266cfa64920517944244c632e5f38768481626b22e2b0d70c806d60", data) + assert_parameter('amount', '1.00', data) + assert_parameter('txnid', '1', data) + assert_parameter('productinfo', 'Purchase', data) + assert_parameter('surl', 'http://example.com', data) + assert_parameter('furl', 'http://example.com', data) + assert_parameter('pg', 'CC', data) + assert_parameter('firstname', @credit_card.first_name, data) + assert_parameter('bankcode', @credit_card.brand.upcase, data) + assert_parameter('ccnum', @credit_card.number, data) + assert_parameter('ccvv', @credit_card.verification_value, data) + assert_parameter('ccname', @credit_card.name, data) + assert_parameter('ccexpmon', '%02d' % @credit_card.month.to_i, data) + assert_parameter('ccexpyr', @credit_card.year, data) + assert_parameter('email', 'unknown@example.com', data) + assert_parameter('phone', '11111111111', data) + assert_parameter('key', 'key', data) + assert_parameter('txn_s2s_flow', '1', data) + assert_parameter('hash', '5199c0735c21d647f287a2781024743d35fabfd640bc20f2ae7b5277e3d7d06fa315fcdda266cfa64920517944244c632e5f38768481626b22e2b0d70c806d60', data) when /hdfc_not_enrolled/ - assert_parameter("transactionId", "6e7e62723683934e6c5507675df11bdd86197c5c935878ff72e344205f3c8a1d", data) - assert_parameter("pgId", "8", data) - assert_parameter("eci", "7", data) - assert_parameter("nonEnrolled", "1", data) - assert_parameter("nonDomestic", "0", data) - assert_parameter("bank", "VISA", data) - assert_parameter("cccat", "creditcard", data) - assert_parameter("ccnum", "4b5c9002295c6cd8e5289e2f9c312dc737810a747b84e71665cf077c78fe245a", data) - assert_parameter("ccname", "53ab689fdb1b025c7e9c53c6b4a6e27f51e0d627579e7c12af2cb6cbc4944cc0", data) - assert_parameter("ccvv", "cc8d6cfb6b03f94e2a64b490ae10c261c10747f543b1fba09d7f56f9ef6aac04", data) - assert_parameter("ccexpmon", "5ddf3702e74f473ec89762f6efece025737c2ab999e695cf10496e6fa3946079", data) - assert_parameter("ccexpyr", "5da83563fcaa945063dc4c2094c48e800badf7c8246c9d13b43757fe99d63e6d", data) - assert_parameter("is_seamless", "1", data) + assert_parameter('transactionId', '6e7e62723683934e6c5507675df11bdd86197c5c935878ff72e344205f3c8a1d', data) + assert_parameter('pgId', '8', data) + assert_parameter('eci', '7', data) + assert_parameter('nonEnrolled', '1', data) + assert_parameter('nonDomestic', '0', data) + assert_parameter('bank', 'VISA', data) + assert_parameter('cccat', 'creditcard', data) + assert_parameter('ccnum', '4b5c9002295c6cd8e5289e2f9c312dc737810a747b84e71665cf077c78fe245a', data) + assert_parameter('ccname', '53ab689fdb1b025c7e9c53c6b4a6e27f51e0d627579e7c12af2cb6cbc4944cc0', data) + assert_parameter('ccvv', 'cc8d6cfb6b03f94e2a64b490ae10c261c10747f543b1fba09d7f56f9ef6aac04', data) + assert_parameter('ccexpmon', '5ddf3702e74f473ec89762f6efece025737c2ab999e695cf10496e6fa3946079', data) + assert_parameter('ccexpyr', '5da83563fcaa945063dc4c2094c48e800badf7c8246c9d13b43757fe99d63e6d', data) + assert_parameter('is_seamless', '1', data) else flunk "Unknown endpoint #{endpoint}" end @@ -76,8 +76,8 @@ def test_successful_purchase assert_success response - assert_equal "403993715512145540", response.authorization - assert_equal "No Error", response.message + assert_equal '403993715512145540', response.authorization + assert_equal 'No Error', response.message assert response.test? end @@ -85,83 +85,83 @@ def test_successful_purchase_with_full_options response = stub_comms do @gateway.purchase( 100, - credit_card("4242424242424242", name: "Bobby Jimbob", verification_value: "678", month: "4", year: "2015"), - order_id: "99", - description: "Awesome!", - email: "jim@example.com", + credit_card('4242424242424242', name: 'Bobby Jimbob', verification_value: '678', month: '4', year: '2015'), + order_id: '99', + description: 'Awesome!', + email: 'jim@example.com', billing_address: { - name: "Jim Smith", - address1: "123 Road", - address2: "Suite 123", - city: "Somewhere", - state: "ZZ", - country: "US", - zip: "12345", - phone: "12223334444" + name: 'Jim Smith', + address1: '123 Road', + address2: 'Suite 123', + city: 'Somewhere', + state: 'ZZ', + country: 'US', + zip: '12345', + phone: '12223334444' }, shipping_address: { - name: "Joe Bob", - address1: "987 Street", - address2: "Suite 987", - city: "Anyplace", - state: "AA", - country: "IN", - zip: "98765", - phone: "98887776666" + name: 'Joe Bob', + address1: '987 Street', + address2: 'Suite 987', + city: 'Anyplace', + state: 'AA', + country: 'IN', + zip: '98765', + phone: '98887776666' } ) end.check_request do |endpoint, data, headers| - assert_equal "identity", headers["Accept-Encoding"] + assert_equal 'identity', headers['Accept-Encoding'] case endpoint when /_payment/ - assert_parameter("amount", "1.00", data) - assert_parameter("txnid", "99", data) - assert_parameter("productinfo", "Awesome!", data) - assert_parameter("surl", "http://example.com", data) - assert_parameter("furl", "http://example.com", data) - assert_parameter("pg", "CC", data) - assert_parameter("firstname", "Bobby", data) - assert_parameter("lastname", "Jimbob", data) - assert_parameter("bankcode", "VISA", data) - assert_parameter("ccnum", "4242424242424242", data) - assert_parameter("ccvv", "678", data) - assert_parameter("ccname", "Bobby Jimbob", data) - assert_parameter("ccexpmon", "04", data) - assert_parameter("ccexpyr", "2015", data) - assert_parameter("email", "jim@example.com", data) - assert_parameter("phone", "12223334444", data) - assert_parameter("key", "key", data) - assert_parameter("txn_s2s_flow", "1", data) - assert_parameter("hash", "1ee17ee9615b55fdee4cd92cee4f28bd88e0c7ff16bd7525cb7b0a792728502f71ffba37606b1b77504d1d0b9d520d39cb1829fffd1aa5eef27dfa4c4a887f61", data) - assert_parameter("address1", "123 Road", data) - assert_parameter("address2", "Suite 123", data) - assert_parameter("city", "Somewhere", data) - assert_parameter("state", "ZZ", data) - assert_parameter("country", "US", data) - assert_parameter("zipcode", "12345", data) - assert_parameter("shipping_firstname", "Joe", data) - assert_parameter("shipping_lastname", "Bob", data) - assert_parameter("shipping_address1", "987 Street", data) - assert_parameter("shipping_address2", "Suite 987", data) - assert_parameter("shipping_city", "Anyplace", data) - assert_parameter("shipping_state", "AA", data) - assert_parameter("shipping_country", "IN", data) - assert_parameter("shipping_zipcode", "98765", data) - assert_parameter("shipping_phone", "98887776666", data) + assert_parameter('amount', '1.00', data) + assert_parameter('txnid', '99', data) + assert_parameter('productinfo', 'Awesome!', data) + assert_parameter('surl', 'http://example.com', data) + assert_parameter('furl', 'http://example.com', data) + assert_parameter('pg', 'CC', data) + assert_parameter('firstname', 'Bobby', data) + assert_parameter('lastname', 'Jimbob', data) + assert_parameter('bankcode', 'VISA', data) + assert_parameter('ccnum', '4242424242424242', data) + assert_parameter('ccvv', '678', data) + assert_parameter('ccname', 'Bobby Jimbob', data) + assert_parameter('ccexpmon', '04', data) + assert_parameter('ccexpyr', '2015', data) + assert_parameter('email', 'jim@example.com', data) + assert_parameter('phone', '12223334444', data) + assert_parameter('key', 'key', data) + assert_parameter('txn_s2s_flow', '1', data) + assert_parameter('hash', '1ee17ee9615b55fdee4cd92cee4f28bd88e0c7ff16bd7525cb7b0a792728502f71ffba37606b1b77504d1d0b9d520d39cb1829fffd1aa5eef27dfa4c4a887f61', data) + assert_parameter('address1', '123 Road', data) + assert_parameter('address2', 'Suite 123', data) + assert_parameter('city', 'Somewhere', data) + assert_parameter('state', 'ZZ', data) + assert_parameter('country', 'US', data) + assert_parameter('zipcode', '12345', data) + assert_parameter('shipping_firstname', 'Joe', data) + assert_parameter('shipping_lastname', 'Bob', data) + assert_parameter('shipping_address1', '987 Street', data) + assert_parameter('shipping_address2', 'Suite 987', data) + assert_parameter('shipping_city', 'Anyplace', data) + assert_parameter('shipping_state', 'AA', data) + assert_parameter('shipping_country', 'IN', data) + assert_parameter('shipping_zipcode', '98765', data) + assert_parameter('shipping_phone', '98887776666', data) when /hdfc_not_enrolled/ - assert_parameter("transactionId", "6e7e62723683934e6c5507675df11bdd86197c5c935878ff72e344205f3c8a1d", data) - assert_parameter("pgId", "8", data) - assert_parameter("eci", "7", data) - assert_parameter("nonEnrolled", "1", data) - assert_parameter("nonDomestic", "0", data) - assert_parameter("bank", "VISA", data) - assert_parameter("cccat", "creditcard", data) - assert_parameter("ccnum", "4b5c9002295c6cd8e5289e2f9c312dc737810a747b84e71665cf077c78fe245a", data) - assert_parameter("ccname", "53ab689fdb1b025c7e9c53c6b4a6e27f51e0d627579e7c12af2cb6cbc4944cc0", data) - assert_parameter("ccvv", "cc8d6cfb6b03f94e2a64b490ae10c261c10747f543b1fba09d7f56f9ef6aac04", data) - assert_parameter("ccexpmon", "5ddf3702e74f473ec89762f6efece025737c2ab999e695cf10496e6fa3946079", data) - assert_parameter("ccexpyr", "5da83563fcaa945063dc4c2094c48e800badf7c8246c9d13b43757fe99d63e6d", data) - assert_parameter("is_seamless", "1", data) + assert_parameter('transactionId', '6e7e62723683934e6c5507675df11bdd86197c5c935878ff72e344205f3c8a1d', data) + assert_parameter('pgId', '8', data) + assert_parameter('eci', '7', data) + assert_parameter('nonEnrolled', '1', data) + assert_parameter('nonDomestic', '0', data) + assert_parameter('bank', 'VISA', data) + assert_parameter('cccat', 'creditcard', data) + assert_parameter('ccnum', '4b5c9002295c6cd8e5289e2f9c312dc737810a747b84e71665cf077c78fe245a', data) + assert_parameter('ccname', '53ab689fdb1b025c7e9c53c6b4a6e27f51e0d627579e7c12af2cb6cbc4944cc0', data) + assert_parameter('ccvv', 'cc8d6cfb6b03f94e2a64b490ae10c261c10747f543b1fba09d7f56f9ef6aac04', data) + assert_parameter('ccexpmon', '5ddf3702e74f473ec89762f6efece025737c2ab999e695cf10496e6fa3946079', data) + assert_parameter('ccexpyr', '5da83563fcaa945063dc4c2094c48e800badf7c8246c9d13b43757fe99d63e6d', data) + assert_parameter('is_seamless', '1', data) else flunk "Unknown endpoint #{endpoint}" end @@ -175,60 +175,60 @@ def test_input_constraint_cleanup @gateway.purchase( 100, credit_card( - "4242424242424242", - first_name: ("3" + ("a" * 61)), - last_name: ("3" + ("a" * 21)), - month: "4", - year: "2015" + '4242424242424242', + first_name: ('3' + ('a' * 61)), + last_name: ('3' + ('a' * 21)), + month: '4', + year: '2015' ), - order_id: ("!@#" + ("a" * 31)), - description: ("a" * 101), - email: ("c" * 51), + order_id: ('!@#' + ('a' * 31)), + description: ('a' * 101), + email: ('c' * 51), billing_address: { - name: "Jim Smith", - address1: ("!#$%^&'\"()" + "Aa0@-_/ ." + ("a" * 101)), - address2: ("!#$%^&'\"()" + "Aa0@-_/ ." + ("a" * 101)), - city: ("!#$%^&'\"()" + "Aa0@-_/ ." + ("a" * 51)), - state: ("!#$%^&'\"()" + "Aa0@-_/ ." + ("a" * 51)), - country: ("!#$%^&'\"()" + "Aa0@-_/ ." + ("a" * 51)), - zip: ("a-" + ("1" * 21)), - phone: ("a-" + ("1" * 51)) + name: 'Jim Smith', + address1: ("!#$%^&'\"()" + 'Aa0@-_/ .' + ('a' * 101)), + address2: ("!#$%^&'\"()" + 'Aa0@-_/ .' + ('a' * 101)), + city: ("!#$%^&'\"()" + 'Aa0@-_/ .' + ('a' * 51)), + state: ("!#$%^&'\"()" + 'Aa0@-_/ .' + ('a' * 51)), + country: ("!#$%^&'\"()" + 'Aa0@-_/ .' + ('a' * 51)), + zip: ('a-' + ('1' * 21)), + phone: ('a-' + ('1' * 51)) }, shipping_address: { - name: (("3" + ("a" * 61)) + " " + ("3" + ("a" * 21))), - address1: ("!#$%^&'\"()" + "Aa0@-_/ ." + ("a" * 101)), - address2: ("!#$%^&'\"()" + "Aa0@-_/ ." + ("a" * 101)), - city: ("!#$%^&'\"()" + "Aa0@-_/ ." + ("a" * 51)), - state: ("!#$%^&'\"()" + "Aa0@-_/ ." + ("a" * 51)), - country: ("!#$%^&'\"()" + "Aa0@-_/ ." + ("a" * 51)), - zip: ("a-" + ("1" * 21)), - phone: ("a-" + ("1" * 51)) + name: (('3' + ('a' * 61)) + ' ' + ('3' + ('a' * 21))), + address1: ("!#$%^&'\"()" + 'Aa0@-_/ .' + ('a' * 101)), + address2: ("!#$%^&'\"()" + 'Aa0@-_/ .' + ('a' * 101)), + city: ("!#$%^&'\"()" + 'Aa0@-_/ .' + ('a' * 51)), + state: ("!#$%^&'\"()" + 'Aa0@-_/ .' + ('a' * 51)), + country: ("!#$%^&'\"()" + 'Aa0@-_/ .' + ('a' * 51)), + zip: ('a-' + ('1' * 21)), + phone: ('a-' + ('1' * 51)) } ) end.check_request do |endpoint, data, headers| case endpoint when /_payment/ - assert_parameter("txnid", /^a/, data, length: 30) - assert_parameter("productinfo", /^a/, data, length: 100) - assert_parameter("firstname", /^a/, data, length: 60) - assert_parameter("lastname", /^a/, data, length: 20) - assert_parameter("email", /^c/, data, length: 50) - assert_parameter("phone", /^\d/, data, length: 50) - assert_parameter("address1", /^Aa0@-_\/ \.a/, data, length: 100) - assert_parameter("address2", /^Aa0@-_\/ \.a/, data, length: 100) - assert_parameter("city", /^Aa0@-_\/ \.a/, data, length: 50) - assert_parameter("state", /^Aa0@-_\/ \.a/, data, length: 50) - assert_parameter("country", /^Aa0@-_\/ \.a/, data, length: 50) - assert_parameter("zipcode", /^1/, data, length: 20) - assert_parameter("shipping_firstname", /^a/, data, length: 60) - assert_parameter("shipping_lastname", /^a/, data, length: 20) - assert_parameter("shipping_address1", /^Aa0@-_\/ \.a/, data, length: 100) - assert_parameter("shipping_address2", /^Aa0@-_\/ \.a/, data, length: 100) - assert_parameter("shipping_city", /^Aa0@-_\/ \.a/, data, length: 50) - assert_parameter("shipping_state", /^Aa0@-_\/ \.a/, data, length: 50) - assert_parameter("shipping_country", /^Aa0@-_\/ \.a/, data, length: 50) - assert_parameter("shipping_zipcode", /^1/, data, length: 20) - assert_parameter("shipping_phone", /^\d/, data, length: 50) + assert_parameter('txnid', /^a/, data, length: 30) + assert_parameter('productinfo', /^a/, data, length: 100) + assert_parameter('firstname', /^a/, data, length: 60) + assert_parameter('lastname', /^a/, data, length: 20) + assert_parameter('email', /^c/, data, length: 50) + assert_parameter('phone', /^\d/, data, length: 50) + assert_parameter('address1', /^Aa0@-_\/ \.a/, data, length: 100) + assert_parameter('address2', /^Aa0@-_\/ \.a/, data, length: 100) + assert_parameter('city', /^Aa0@-_\/ \.a/, data, length: 50) + assert_parameter('state', /^Aa0@-_\/ \.a/, data, length: 50) + assert_parameter('country', /^Aa0@-_\/ \.a/, data, length: 50) + assert_parameter('zipcode', /^1/, data, length: 20) + assert_parameter('shipping_firstname', /^a/, data, length: 60) + assert_parameter('shipping_lastname', /^a/, data, length: 20) + assert_parameter('shipping_address1', /^Aa0@-_\/ \.a/, data, length: 100) + assert_parameter('shipping_address2', /^Aa0@-_\/ \.a/, data, length: 100) + assert_parameter('shipping_city', /^Aa0@-_\/ \.a/, data, length: 50) + assert_parameter('shipping_state', /^Aa0@-_\/ \.a/, data, length: 50) + assert_parameter('shipping_country', /^Aa0@-_\/ \.a/, data, length: 50) + assert_parameter('shipping_zipcode', /^1/, data, length: 20) + assert_parameter('shipping_phone', /^\d/, data, length: 50) end end.respond_with(successful_purchase_setup_response, successful_purchase_response) @@ -237,47 +237,47 @@ def test_input_constraint_cleanup def test_brand_mappings stub_comms do - @gateway.purchase(100, credit_card("4242424242424242", brand: :visa), @options) + @gateway.purchase(100, credit_card('4242424242424242', brand: :visa), @options) end.check_request do |endpoint, data, _| case endpoint when /_payment/ - assert_parameter("bankcode", "VISA", data) + assert_parameter('bankcode', 'VISA', data) end end.respond_with(successful_purchase_response) stub_comms do - @gateway.purchase(100, credit_card("4242424242424242", brand: :master), @options) + @gateway.purchase(100, credit_card('4242424242424242', brand: :master), @options) end.check_request do |endpoint, data, _| case endpoint when /_payment/ - assert_parameter("bankcode", "MAST", data) + assert_parameter('bankcode', 'MAST', data) end end.respond_with(successful_purchase_response) stub_comms do - @gateway.purchase(100, credit_card("4242424242424242", brand: :american_express), @options) + @gateway.purchase(100, credit_card('4242424242424242', brand: :american_express), @options) end.check_request do |endpoint, data, _| case endpoint when /_payment/ - assert_parameter("bankcode", "AMEX", data) + assert_parameter('bankcode', 'AMEX', data) end end.respond_with(successful_purchase_response) stub_comms do - @gateway.purchase(100, credit_card("4242424242424242", brand: :diners_club), @options) + @gateway.purchase(100, credit_card('4242424242424242', brand: :diners_club), @options) end.check_request do |endpoint, data, _| case endpoint when /_payment/ - assert_parameter("bankcode", "DINR", data) + assert_parameter('bankcode', 'DINR', data) end end.respond_with(successful_purchase_response) stub_comms do - @gateway.purchase(100, credit_card("4242424242424242", brand: :maestro), @options) + @gateway.purchase(100, credit_card('4242424242424242', brand: :maestro), @options) end.check_request do |endpoint, data, _| case endpoint when /_payment/ - assert_parameter("bankcode", "MAES", data) + assert_parameter('bankcode', 'MAES', data) end end.respond_with(successful_purchase_response) end @@ -287,37 +287,37 @@ def test_failed_purchase response = @gateway.purchase(100, @credit_card, @options) assert_failure response - assert_equal "Invalid amount @~@ ExceptionConstant : INVALID_AMOUNT", response.message + assert_equal 'Invalid amount @~@ ExceptionConstant : INVALID_AMOUNT', response.message end def test_successful_refund response = stub_comms do - @gateway.refund(100, "abc") + @gateway.refund(100, 'abc') end.check_request do |endpoint, data, headers| - assert_parameter("command", "cancel_refund_transaction", data) - assert_parameter("var1", "abc", data) - assert_parameter("var2", /./, data) - assert_parameter("var3", "1.00", data) - assert_parameter("key", "key", data) - assert_parameter("txn_s2s_flow", "1", data) - assert_parameter("hash", "06ee55774af4e3eee3f946d4079d34efca243453199b0d4a1328f248b93428ed5c6342c6d73010c0b86d19afc04ae7a1c62c68c472cc0811d00a9a10ecf28791", data) + assert_parameter('command', 'cancel_refund_transaction', data) + assert_parameter('var1', 'abc', data) + assert_parameter('var2', /./, data) + assert_parameter('var3', '1.00', data) + assert_parameter('key', 'key', data) + assert_parameter('txn_s2s_flow', '1', data) + assert_parameter('hash', '06ee55774af4e3eee3f946d4079d34efca243453199b0d4a1328f248b93428ed5c6342c6d73010c0b86d19afc04ae7a1c62c68c472cc0811d00a9a10ecf28791', data) end.respond_with(successful_refund_response) assert_success response - assert_equal "Refund Request Queued", response.message + assert_equal 'Refund Request Queued', response.message end def test_failed_refund @gateway.expects(:ssl_post).returns(failed_refund_response) - response = @gateway.refund(100, "abc") + response = @gateway.refund(100, 'abc') assert_failure response - assert_equal "Invalid payuid", response.message + assert_equal 'Invalid payuid', response.message end def test_refund_without_amount assert_raise ArgumentError do - @gateway.refund(nil, "abc") + @gateway.refund(nil, 'abc') end end @@ -326,7 +326,7 @@ def test_3dsecure_cards_fail response = @gateway.purchase(100, @credit_card, @options) assert_failure response - assert_equal "3D-secure enrolled cards are not supported.", response.message + assert_equal '3D-secure enrolled cards are not supported.', response.message end def test_scrub diff --git a/test/unit/gateways/payu_latam_test.rb b/test/unit/gateways/payu_latam_test.rb index 800e7fa36ad..68e76b9ef2e 100644 --- a/test/unit/gateways/payu_latam_test.rb +++ b/test/unit/gateways/payu_latam_test.rb @@ -1,29 +1,40 @@ require 'test_helper' class PayuLatamTest < Test::Unit::TestCase + include CommStub + def setup - @gateway = PayuLatamGateway.new(merchant_id: 'merchant_id', account_id: 'account_id', api_login: 'api_login', api_key: 'api_key') + @gateway = PayuLatamGateway.new(merchant_id: 'merchant_id', account_id: 'account_id', api_login: 'api_login', api_key: 'api_key', payment_country: 'AR') @amount = 4000 - @credit_card = credit_card("4097440000000004", verification_value: "444", first_name: "APPROVED", last_name: "") - @declined_card = credit_card("4097440000000004", verification_value: "333", first_name: "REJECTED", last_name: "") - @pending_card = credit_card("4097440000000004", verification_value: "222", first_name: "PENDING", last_name: "") - @no_cvv_visa_card = credit_card("4097440000000004", verification_value: " ") - @no_cvv_amex_card = credit_card("4097440000000004", verification_value: " ", brand: "american_express") + @credit_card = credit_card('4097440000000004', verification_value: '444', first_name: 'APPROVED', last_name: '') + @declined_card = credit_card('4097440000000004', verification_value: '333', first_name: 'REJECTED', last_name: '') + @pending_card = credit_card('4097440000000004', verification_value: '222', first_name: 'PENDING', last_name: '') + @no_cvv_visa_card = credit_card('4097440000000004', verification_value: ' ') + @no_cvv_amex_card = credit_card('4097440000000004', verification_value: ' ', brand: 'american_express') @options = { - currency: "ARS", + dni_number: '5415668464654', + dni_type: 'TI', + currency: 'ARS', order_id: generate_unique_id, - description: "Active Merchant Transaction", + description: 'Active Merchant Transaction', installments_number: 1, + tax: 0, + tax_return_base: 0, + email: 'username@domain.com', + ip: '127.0.0.1', + device_session_id: 'vghs6tvkcle931686k1900o6e1', + cookie: 'pt1t38347bs6jc9ruv2ecpv7o2', + user_agent: 'Mozilla/5.0 (Windows NT 5.1; rv:18.0) Gecko/20100101 Firefox/18.0', billing_address: address( - address1: "Viamonte", - address2: "1366", - city: "Plata", - state: "Buenos Aires", - country: "AR", - zip: "64000", - phone: "7563126" + address1: 'Viamonte', + address2: '1366', + city: 'Plata', + state: 'Buenos Aires', + country: 'AR', + zip: '64000', + phone: '7563126' ) } end @@ -33,17 +44,25 @@ def test_successful_purchase response = @gateway.purchase(@amount, @credit_card, @options) assert_success response - assert_equal "APPROVED", response.message + assert_equal 'APPROVED', response.message assert response.test? end + def test_successful_purchase_with_specified_language + stub_comms do + @gateway.purchase(@amount, @credit_card, @options.merge(language: 'es')) + end.check_request do |endpoint, data, headers| + assert_match(/"language":"es"/, data) + end.respond_with(successful_purchase_response) + end + def test_failed_purchase @gateway.expects(:ssl_post).returns(failed_purchase_response) response = @gateway.purchase(@amount, @credit_card, @options) assert_failure response - assert_equal "ANTIFRAUD_REJECTED", response.message - assert_equal "DECLINED", response.params["transactionResponse"]["state"] + assert_equal 'ANTIFRAUD_REJECTED', response.message + assert_equal 'DECLINED', response.params['transactionResponse']['state'] end def test_successful_authorize @@ -51,49 +70,81 @@ def test_successful_authorize response = @gateway.authorize(@amount, @credit_card, @options) assert_success response - assert_equal "APPROVED", response.message + assert_equal 'APPROVED', response.message assert_match %r(^\d+\|(\w|-)+$), response.authorization end + def test_successful_authorize_with_specified_language + stub_comms do + @gateway.authorize(@amount, @credit_card, @options.merge(language: 'es')) + end.check_request do |endpoint, data, headers| + assert_match(/"language":"es"/, data) + end.respond_with(successful_purchase_response) + end + def test_failed_authorize @gateway.expects(:ssl_post).returns(pending_authorize_response) response = @gateway.authorize(@amount, @pending_card, @options) assert_failure response - assert_equal "PENDING_TRANSACTION_REVIEW", response.message - assert_equal "PENDING", response.params["transactionResponse"]["state"] + assert_equal 'PENDING_TRANSACTION_REVIEW', response.message + assert_equal 'PENDING', response.params['transactionResponse']['state'] end def test_pending_refund @gateway.expects(:ssl_post).returns(pending_refund_response) - response = @gateway.refund(@amount, "7edbaf68-8f3a-4ae7-b9c7-d1e27e314999") + response = @gateway.refund(@amount, '7edbaf68-8f3a-4ae7-b9c7-d1e27e314999') assert_success response - assert_equal "PENDING", response.params["transactionResponse"]["state"] + assert_equal 'PENDING', response.params['transactionResponse']['state'] + end + + def test_pending_refund_with_specified_language + stub_comms do + @gateway.refund(@amount, '7edbaf68-8f3a-4ae7-b9c7-d1e27e314999', @options.merge(language: 'es')) + end.check_request do |endpoint, data, headers| + assert_match(/"language":"es"/, data) + end.respond_with(pending_refund_response) end def test_failed_refund @gateway.expects(:ssl_post).returns(failed_refund_response) - response = @gateway.refund(@amount, "") + response = @gateway.refund(@amount, '') assert_failure response - assert_equal "property: order.id, message: must not be null property: parentTransactionId, message: must not be null", response.message + assert_equal 'property: order.id, message: must not be null property: parentTransactionId, message: must not be null', response.message end def test_successful_void @gateway.expects(:ssl_post).returns(successful_void_response) - response = @gateway.void("7edbaf68-8f3a-4ae7-b9c7-d1e27e314999", @options) + response = @gateway.void('7edbaf68-8f3a-4ae7-b9c7-d1e27e314999', @options) assert_success response - assert_equal "APPROVED", response.message + assert_equal 'PENDING_REVIEW', response.message + end + + def test_successful_void_with_specified_language + stub_comms do + @gateway.void('7edbaf68-8f3a-4ae7-b9c7-d1e27e314999', @options.merge(language: 'es')) + end.check_request do |endpoint, data, headers| + assert_match(/"language":"es"/, data) + end.respond_with(successful_void_response) end def test_failed_void @gateway.expects(:ssl_post).returns(failed_void_response) - response = @gateway.void("") + response = @gateway.void('') assert_failure response - assert_equal "property: order.id, message: must not be null property: parentTransactionId, message: must not be null", response.message + assert_equal 'property: order.id, message: must not be null property: parentTransactionId, message: must not be null', response.message + end + + def test_successful_purchase_with_dni_number + stub_comms do + @gateway.purchase(@amount, @credit_card, @options) + end.check_request do |endpoint, data, headers| + assert_match(/"dniNumber":"5415668464654"/, data) + end.respond_with(successful_purchase_response) end def test_verify_good_credentials @@ -113,7 +164,7 @@ def test_request_using_visa_card_with_no_cvv }.returns(successful_purchase_response) response = @gateway.purchase(@amount, @no_cvv_visa_card, @options) assert_success response - assert_equal "APPROVED", response.message + assert_equal 'APPROVED', response.message assert response.test? end @@ -124,7 +175,7 @@ def test_request_using_amex_card_with_no_cvv }.returns(successful_purchase_response) response = @gateway.purchase(@amount, @no_cvv_amex_card, @options) assert_success response - assert_equal "APPROVED", response.message + assert_equal 'APPROVED', response.message assert response.test? end @@ -133,13 +184,180 @@ def test_request_passes_cvv_option body.match '"securityCode":"777"' !body.match '"processWithoutCvv2"' }.returns(successful_purchase_response) - options = @options.merge(cvv: "777") + options = @options.merge(cvv: '777') response = @gateway.purchase(@amount, @no_cvv_visa_card, options) assert_success response - assert_equal "APPROVED", response.message + assert_equal 'APPROVED', response.message assert response.test? end + def test_successful_capture + @gateway.expects(:ssl_post).returns(successful_capture_response) + + response = @gateway.capture(@amount, '4000|authorization', @options) + assert_success response + assert_equal 'APPROVED', response.message + end + + def test_successful_capture_with_specified_language + stub_comms do + @gateway.capture(@amount, '4000|authorization', @options.merge(language: 'es')) + end.check_request do |endpoint, data, headers| + assert_match(/"language":"es"/, data) + end.respond_with(successful_purchase_response) + end + + def test_successful_partial_capture + stub_comms do + @gateway.capture(@amount - 1, '4000|authorization', @options) + end.check_request do |endpoint, data, headers| + assert_equal '39.99', JSON.parse(data)['transaction']['additionalValues']['TX_VALUE']['value'] + end.respond_with(successful_purchase_response) + end + + def test_failed_capture + @gateway.expects(:ssl_post).returns(failed_void_response) + + response = @gateway.capture(@amount, '') + assert_failure response + assert_equal 'property: order.id, message: must not be null property: parentTransactionId, message: must not be null', response.message + end + + def test_partial_buyer_hash_info + options_buyer = { + shipping_address: address( + address1: 'Calle 200', + address2: 'N107', + city: 'Sao Paulo', + state: 'SP', + country: 'BR', + zip: '01019-030', + phone: '(11)756312345' + ), + buyer: { + name: 'Jorge Borges', + dni_number: '5415668464456', + email: 'axaxaxas@mlo.org' + } + } + + stub_comms do + @gateway.purchase(@amount, @credit_card, @options.update(options_buyer)) + end.check_request do |endpoint, data, headers| + assert_match(/\"buyer\":{\"fullName\":\"Jorge Borges\",\"dniNumber\":\"5415668464456\",\"dniType\":null,\"emailAddress\":\"axaxaxas@mlo.org\",\"contactPhone\":\"7563126\",\"shippingAddress\":{\"street1\":\"Calle 200\",\"street2\":\"N107\",\"city\":\"Sao Paulo\",\"state\":\"SP\",\"country\":\"BR\",\"postalCode\":\"01019-030\",\"phone\":\"\(11\)756312345\"}}/, data) + end.respond_with(successful_purchase_response) + end + + def test_buyer_fields_default_to_payer + stub_comms do + @gateway.purchase(@amount, @credit_card, @options) + end.check_request do |endpoint, data, headers| + assert_match(/\"buyer\":{\"fullName\":\"APPROVED\",\"dniNumber\":\"5415668464654\",\"dniType\":\"TI\",\"emailAddress\":\"username@domain.com\",\"contactPhone\":\"7563126\"/, data) + end.respond_with(successful_purchase_response) + end + + def test_brazil_required_fields + gateway = PayuLatamGateway.new(merchant_id: 'merchant_id', account_id: 'account_id', api_login: 'api_login', api_key: 'api_key', payment_country: 'BR') + + options_brazil = { + currency: 'BRL', + billing_address: address( + address1: 'Calle 100', + address2: 'BL4', + city: 'Sao Paulo', + state: 'SP', + country: 'BR', + zip: '09210710', + phone: '(11)756312633' + ), + shipping_address: address( + address1: 'Calle 200', + address2: 'N107', + city: 'Sao Paulo', + state: 'SP', + country: 'BR', + zip: '01019-030', + phone: '(11)756312633' + ), + buyer: { + cnpj: '32593371000110' + } + } + + stub_comms(gateway) do + gateway.purchase(@amount, @credit_card, @options.update(options_brazil)) + end.check_request do |endpoint, data, headers| + assert_match(/\"cnpj\":\"32593371000110\"/, data) + end.respond_with(successful_purchase_response) + end + + def test_colombia_required_fields + gateway = PayuLatamGateway.new(merchant_id: 'merchant_id', account_id: 'account_id', api_login: 'api_login', api_key: 'api_key', payment_country: 'CO') + + options_colombia = { + currency: 'COP', + billing_address: address( + address1: 'Calle 100', + address2: 'BL4', + city: 'Bogota', + state: 'Bogota DC', + country: 'CO', + zip: '09210710', + phone: '(11)756312633' + ), + shipping_address: address( + address1: 'Calle 200', + address2: 'N107', + city: 'Bogota', + state: 'Bogota DC', + country: 'CO', + zip: '01019-030', + phone: '(11)756312633' + ), + tx_tax: '3193', + tx_tax_return_base: '16806' + } + + stub_comms(gateway) do + gateway.purchase(@amount, @credit_card, @options.update(options_colombia)) + end.check_request do |endpoint, data, headers| + assert_match(/\"additionalValues\":{\"TX_VALUE\":{\"value\":\"40.00\",\"currency\":\"COP\"},\"TX_TAX\":{\"value\":0,\"currency\":\"COP\"},\"TX_TAX_RETURN_BASE\":{\"value\":0,\"currency\":\"COP\"}}/, data) + end.respond_with(successful_purchase_response) + end + + def test_mexico_required_fields + gateway = PayuLatamGateway.new(merchant_id: 'merchant_id', account_id: 'account_id', api_login: 'api_login', api_key: 'api_key', payment_country: 'MX') + + options_mexico = { + currency: 'MXN', + billing_address: address( + address1: 'Calle 100', + address2: 'BL4', + city: 'Guadalajara', + state: 'Jalisco', + country: 'MX', + zip: '09210710', + phone: '(11)756312633' + ), + shipping_address: address( + address1: 'Calle 200', + address2: 'N107', + city: 'Guadalajara', + state: 'Jalisco', + country: 'MX', + zip: '01019-030', + phone: '(11)756312633' + ), + birth_date: '1985-05-25' + } + + stub_comms(gateway) do + gateway.purchase(@amount, @credit_card, @options.update(options_mexico)) + end.check_request do |endpoint, data, headers| + assert_match(/\"birthdate\":\"1985-05-25\"/, data) + end.respond_with(successful_purchase_response) + end + def test_scrub assert @gateway.supports_scrubbing? assert_equal @gateway.scrub(pre_scrubbed), post_scrubbed @@ -360,15 +578,15 @@ def successful_void_response "transactionResponse": { "orderId": 840434914, "transactionId": "e66fd9aa-f485-4f10-b1d6-be8e9e354b63", - "state": "APPROVED", + "state": "PENDING", "paymentNetworkResponseCode": "0", "paymentNetworkResponseErrorMessage": null, "trazabilityCode": "49263990", "authorizationCode": "NPS-011111", - "pendingReason": null, - "responseCode": "APPROVED", + "pendingReason": "PENDING_REVIEW", + "responseCode": null, "errorCode": null, - "responseMessage": "APROBADA - Autorizada", + "responseMessage": null, "transactionDate": null, "transactionTime": null, "operationDate": 1486655230074, @@ -390,6 +608,42 @@ def failed_void_response RESPONSE end + def successful_capture_response + <<-RESPONSE + { + "code": "SUCCESS", + "error": null, + "transactionResponse": { + "orderId": 272601, + "transactionId": "66c7bff2-c423-42ed-800a-8be11531e7a1", + "state": "APPROVED", + "paymentNetworkResponseCode": null, + "paymentNetworkResponseErrorMessage": null, + "trazabilityCode": "00000000", + "authorizationCode": "00000000", + "pendingReason": null, + "responseCode": "APPROVED", + "errorCode": null, + "responseMessage": null, + "transactionDate": null, + "transactionTime": null, + "operationDate": 1314012754, + "extraParameters": null + } + } + RESPONSE + end + + def failed_capture_response + <<-RESPONSE + { + "code":"ERROR", + "error":"property: order.id, message: must not be null property: parentTransactionId, message: must not be null", + "transactionResponse": null + } + RESPONSE + end + def credentials_are_legit_response <<-RESPONSE { diff --git a/test/unit/gateways/payway_test.rb b/test/unit/gateways/payway_test.rb index 416f1c6bb0f..42a1aa25321 100644 --- a/test/unit/gateways/payway_test.rb +++ b/test/unit/gateways/payway_test.rb @@ -50,7 +50,6 @@ def test_succesful_purchase_visa_from_register_user assert_match '0', response.params['summary_code'] assert_match '08', response.params['response_code'] assert_match 'VISA', response.params['card_scheme_name'] - end def test_successful_purchase_master_card @@ -220,40 +219,40 @@ def test_store private - def successful_response_store - "response.responseCode=00" - end + def successful_response_store + 'response.responseCode=00' + end - def successful_response_visa - "response.summaryCode=0&response.responseCode=08&response.cardSchemeName=VISA" - end + def successful_response_visa + 'response.summaryCode=0&response.responseCode=08&response.cardSchemeName=VISA' + end - def successful_response_master_card - "response.summaryCode=0&response.responseCode=08&response.cardSchemeName=MASTERCARD" - end + def successful_response_master_card + 'response.summaryCode=0&response.responseCode=08&response.cardSchemeName=MASTERCARD' + end - def purchase_with_invalid_credit_card_response - "response.summaryCode=1&response.responseCode=14" - end + def purchase_with_invalid_credit_card_response + 'response.summaryCode=1&response.responseCode=14' + end - def purchase_with_expired_credit_card_response - "response.summaryCode=1&response.responseCode=54" - end + def purchase_with_expired_credit_card_response + 'response.summaryCode=1&response.responseCode=54' + end - def purchase_with_invalid_month_response - "response.summaryCode=3&response.responseCode=QA" - end + def purchase_with_invalid_month_response + 'response.summaryCode=3&response.responseCode=QA' + end - def bad_login_response - "response.summaryCode=3&response.responseCode=QH" - end + def bad_login_response + 'response.summaryCode=3&response.responseCode=QH' + end - def bad_merchant_response - "response.summaryCode=3&response.responseCode=QK" - end + def bad_merchant_response + 'response.summaryCode=3&response.responseCode=QK' + end - def certificate - '------BEGIN CERTIFICATE----- + def certificate + '------BEGIN CERTIFICATE----- -MIIDeDCCAmCgAwIBAgIBATANBgkqhkiG9w0BAQUFADBBMRMwEQYDVQQDDApjb2R5 -ZmF1c2VyMRUwEwYKCZImiZPyLGQBGRYFZ21haWwxEzARBgoJkiaJk/IsZAEZFgNj -b20wHhcNMTMxMTEzMTk1NjE2WhcNMTQxMTEzMTk1NjE2WjBBMRMwEQYDVQQDDApj @@ -274,5 +273,5 @@ def certificate -ZJB9YPQZG+vWBdDSca3sUMtvFxpLUFwdKF5APSPOVnhbFJ3vSXY1ulP/R6XW9vnw -6kkQi2fHhU20ugMzp881Eixr+TjC0RvUerLG7g== ------END CERTIFICATE-----' - end + end end diff --git a/test/unit/gateways/pin_test.rb b/test/unit/gateways/pin_test.rb index e7b9241bbba..33a27b55a56 100644 --- a/test/unit/gateways/pin_test.rb +++ b/test/unit/gateways/pin_test.rb @@ -80,12 +80,12 @@ def test_unsuccessful_request assert response = @gateway.purchase(@amount, @credit_card, @options) assert_failure response - assert_equal "The current resource was deemed invalid.", response.message + assert_equal 'The current resource was deemed invalid.', response.message assert response.test? end def test_unparsable_body_of_successful_response - @gateway.stubs(:raw_ssl_request).returns(MockResponse.succeeded("This is not [ JSON")) + @gateway.stubs(:raw_ssl_request).returns(MockResponse.succeeded('This is not [ JSON')) assert response = @gateway.purchase(@amount, @credit_card, @options) assert_failure response @@ -93,7 +93,7 @@ def test_unparsable_body_of_successful_response end def test_unparsable_body_of_failed_response - @gateway.stubs(:raw_ssl_request).returns(MockResponse.failed("This is not [ JSON")) + @gateway.stubs(:raw_ssl_request).returns(MockResponse.failed('This is not [ JSON')) assert response = @gateway.purchase(@amount, @credit_card, @options) assert_failure response @@ -114,7 +114,7 @@ def test_unsuccessful_store assert response = @gateway.store(@credit_card, @options) assert_failure response - assert_equal "The current resource was deemed invalid.", response.message + assert_equal 'The current resource was deemed invalid.', response.message assert response.test? end @@ -144,7 +144,7 @@ def test_unsuccessful_refund assert response = @gateway.refund(100, token) assert_failure response - assert_equal "The current resource was deemed invalid.", response.message + assert_equal 'The current resource was deemed invalid.', response.message assert response.test? end @@ -299,18 +299,18 @@ def test_post_data def test_headers expected_headers = { - "Content-Type" => "application/json", - "Authorization" => "Basic #{Base64.strict_encode64('I_THISISNOTAREALAPIKEY:').strip}" + 'Content-Type' => 'application/json', + 'Authorization' => "Basic #{Base64.strict_encode64('I_THISISNOTAREALAPIKEY:').strip}" } @gateway.expects(:ssl_request).with(:post, anything, anything, expected_headers).returns(successful_purchase_response) - assert response = @gateway.purchase(@amount, @credit_card, {}) + assert @gateway.purchase(@amount, @credit_card, {}) expected_headers['X-Partner-Key'] = 'MyPartnerKey' expected_headers['X-Safe-Card'] = '1' @gateway.expects(:ssl_request).with(:post, anything, anything, expected_headers).returns(successful_purchase_response) - assert response = @gateway.purchase(@amount, @credit_card, :partner_key => 'MyPartnerKey', :safe_card => '1') + assert @gateway.purchase(@amount, @credit_card, :partner_key => 'MyPartnerKey', :safe_card => '1') end def test_transcript_scrubbing diff --git a/test/unit/gateways/plugnpay_test.rb b/test/unit/gateways/plugnpay_test.rb index 0ee24e4d241..4760eada3f6 100644 --- a/test/unit/gateways/plugnpay_test.rb +++ b/test/unit/gateways/plugnpay_test.rb @@ -36,41 +36,41 @@ def test_purchase_error end def test_capture_partial_amount - @gateway.expects(:ssl_post).with(anything, all_of(regexp_matches(/mode=mark/), regexp_matches(/card_amount=0.99/)), anything).returns("") + @gateway.expects(:ssl_post).with(anything, all_of(regexp_matches(/mode=mark/), regexp_matches(/card_amount=0.99/)), anything).returns('') @gateway.expects(:parse).returns({}) @gateway.capture(@amount - 1, @credit_card, @options) end def test_capture_full_amount - @gateway.expects(:ssl_post).with(anything, all_of(regexp_matches(/mode=mark/), regexp_matches(/card_amount=1.00/)), anything).returns("") + @gateway.expects(:ssl_post).with(anything, all_of(regexp_matches(/mode=mark/), regexp_matches(/card_amount=1.00/)), anything).returns('') @gateway.expects(:parse).returns({'auth_msg' => 'Blah blah blah Transaction may not be reauthorized'}, {}) @gateway.capture(@amount, @credit_card, @options) end def test_credit - @gateway.expects(:ssl_post).with(anything, regexp_matches(/card_number=#{@credit_card.number}/), anything).returns("") + @gateway.expects(:ssl_post).with(anything, regexp_matches(/card_number=#{@credit_card.number}/), anything).returns('') @gateway.expects(:parse).returns({}) @gateway.credit(@amount, @credit_card, @options) end def test_deprecated_credit - @gateway.expects(:ssl_post).with(anything, regexp_matches(/orderID=transaction_id/), anything).returns("") + @gateway.expects(:ssl_post).with(anything, regexp_matches(/orderID=transaction_id/), anything).returns('') @gateway.expects(:parse).returns({}) assert_deprecation_warning(Gateway::CREDIT_DEPRECATION_MESSAGE) do - @gateway.credit(@amount, "transaction_id", @options) + @gateway.credit(@amount, 'transaction_id', @options) end end def test_refund - @gateway.expects(:ssl_post).with(anything, regexp_matches(/orderID=transaction_id/), anything).returns("") + @gateway.expects(:ssl_post).with(anything, regexp_matches(/orderID=transaction_id/), anything).returns('') @gateway.expects(:parse).returns({}) - @gateway.refund(@amount, "transaction_id", @options) + @gateway.refund(@amount, 'transaction_id', @options) end def test_add_address_outsite_north_america result = PlugnpayGateway::PlugnpayPostData.new - @gateway.send(:add_addresses, result, :billing_address => {:address1 => '164 Waverley Street', :country => 'DE', :state => 'Dortmund'} ) + @gateway.send(:add_addresses, result, :billing_address => {:address1 => '164 Waverley Street', :country => 'DE', :state => 'Dortmund'}) assert_equal result[:state], 'ZZ' assert_equal result[:province], 'Dortmund' @@ -80,13 +80,12 @@ def test_add_address_outsite_north_america assert_equal result[:card_address1], '164 Waverley Street' assert_equal result[:card_country], 'DE' - end def test_add_address result = PlugnpayGateway::PlugnpayPostData.new - @gateway.send(:add_addresses, result, :billing_address => {:address1 => '164 Waverley Street', :country => 'US', :state => 'CO'} ) + @gateway.send(:add_addresses, result, :billing_address => {:address1 => '164 Waverley Street', :country => 'US', :state => 'CO'}) assert_equal result[:card_state], 'CO' assert_equal result[:card_address1], '164 Waverley Street' @@ -108,6 +107,7 @@ def test_cvv_result end private + def successful_purchase_response "FinalStatus=success&IPaddress=72%2e138%2e32%2e216&MStatus=success&User_Agent=&acct_code3=newcard&address1=1234%20My%20Street&address2=Apt%201&app_level=5&auth_code=TSTAUT&auth_date=20080125&auth_msg=%20&authtype=authpostauth&avs_code=X&card_address1=1234%20My%20Street&card_amount=1%2e00&card_city=Ottawa&card_country=CA&card_name=Longbob%20Longsen&card_state=ON&card_type=VISA&card_zip=K1C2N6&city=Ottawa&convert=underscores&country=CA&currency=usd&cvvresp=M&dontsndmail=yes&easycart=0&merchant=pnpdemo2&merchfraudlev=&mode=auth&orderID=2008012522252119738&phone=555%2d555%2d5555&publisher_email=trash%40plugnpay%2ecom&publisher_name=pnpdemo2&publisher_password=pnpdemo222&resp_code=00&shipinfo=0&shipname=Jim%20Smith&sresp=A&state=ON&success=yes&zip=K1C2N6&a=b\n" end diff --git a/test/unit/gateways/pro_pay_test.rb b/test/unit/gateways/pro_pay_test.rb new file mode 100644 index 00000000000..b6704553ff2 --- /dev/null +++ b/test/unit/gateways/pro_pay_test.rb @@ -0,0 +1,291 @@ +require 'test_helper' + +class ProPayTest < Test::Unit::TestCase + include CommStub + + def setup + @gateway = ProPayGateway.new(cert_str: 'certStr') + @credit_card = credit_card + @amount = 100 + + @options = { + order_id: '1', + billing_address: address, + description: 'Store Purchase' + } + end + + def test_successful_purchase + @gateway.expects(:ssl_post).returns(successful_purchase_response) + + response = @gateway.purchase(@amount, @credit_card, @options) + assert_success response + + assert_equal '16', response.authorization + assert_equal 'Success', response.message + end + + def test_failed_purchase + @gateway.expects(:ssl_post).returns(failed_purchase_response) + + response = @gateway.purchase(@amount, @credit_card, @options) + assert_failure response + assert_equal '58', response.error_code + assert_equal 'Credit card declined - Insufficient funds', response.message + end + + def test_successful_authorize + @gateway.expects(:ssl_post).returns(successful_authorize_response) + + response = @gateway.authorize(@amount, @credit_card, @options) + assert_success response + + assert_equal '24', response.authorization + assert_equal 'Success', response.message + end + + def test_failed_authorize + @gateway.expects(:ssl_post).returns(failed_authorize_response) + + response = @gateway.authorize(@amount, @credit_card, @options) + assert_failure response + assert_equal '58', response.error_code + assert_equal 'Credit card declined - Insufficient funds', response.message + end + + def test_successful_capture + @gateway.expects(:ssl_post).returns(successful_capture_response) + + response = @gateway.capture(@amount, 'auth', @options) + assert_success response + + assert_equal '24', response.authorization + assert_equal 'Success', response.message + end + + def test_failed_capture + @gateway.expects(:ssl_post).returns(failed_capture_response) + + response = @gateway.capture(@amount, 'invalid-auth', @options) + assert_failure response + assert_equal '51', response.error_code + assert_equal 'Invalid transNum and/or Unable to act perform actions on transNum due to funding', response.message + end + + def test_successful_refund + @gateway.expects(:ssl_post).returns(successful_refund_response) + + response = @gateway.refund(@amount, 'auth', @options) + assert_success response + end + + def test_failed_refund + @gateway.expects(:ssl_post).returns(failed_refund_response) + + response = @gateway.refund(@amount, 'invalid-auth', @options) + assert_failure response + assert_equal 'Invalid transNum and/or Unable to act perform actions on transNum due to funding', response.message + end + + def test_successful_void + response = stub_comms do + @gateway.void('auth', @options) + end.check_request do |endpoint, data, headers| + assert_match(%r(<transType>07</transType>), data) + end.respond_with(successful_void_response) + + assert_success response + end + + def test_failed_void + response = stub_comms do + @gateway.void('invalid-auth', @options) + end.check_request do |endpoint, data, headers| + assert_match(%r(<transType>07</transType>), data) + end.respond_with(failed_void_response) + + assert_failure response + end + + def test_successful_verify + @gateway.expects(:ssl_post).times(2).returns(successful_authorize_response, successful_void_response) + + response = @gateway.verify(@credit_card, @options) + assert_success response + assert_equal 'Success', response.message + end + + def test_successful_verify_with_failed_void + @gateway.expects(:ssl_post).times(2).returns(successful_authorize_response, failed_void_response) + + response = @gateway.verify(@credit_card, @options) + assert_success response + end + + def test_successful_credit + @gateway.expects(:ssl_post).returns(successful_credit_response) + + response = @gateway.credit(@amount, @credit_card, @options) + assert_success response + + assert_equal '103', response.authorization + assert_equal 'Success', response.message + end + + def test_failed_credit + @gateway.expects(:ssl_post).returns(failed_credit_response) + + response = @gateway.credit(@amount, @credit_card, @options) + assert_failure response + assert_equal 'Invalid ccNum', response.message + end + + def test_failed_verify + @gateway.expects(:ssl_post).returns(failed_authorize_response) + + response = @gateway.verify(@credit_card, @options) + assert_failure response + assert_equal '58', response.error_code + end + + def test_scrub + assert @gateway.supports_scrubbing? + assert_equal @gateway.scrub(pre_scrubbed), post_scrubbed + end + + private + + def pre_scrubbed + <<-RESPONSE +opening connection to xmltest.propay.com:443... +opened +starting SSL for xmltest.propay.com:443... +SSL established +<- "POST /API/PropayAPI.aspx HTTP/1.1\r\nContent-Type: application/x-www-form-urlencoded\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nAccept: */*\r\nUser-Agent: Ruby\r\nConnection: close\r\nHost: xmltest.propay.com\r\nContent-Length: 547\r\n\r\n" +<- "<?xml version=\"1.0\"?>\n<XMLRequest>\n <certStr>5ab9cddef2e4911b77e0c4ffb70f03</certStr>\n <class>partner</class>\n <XMLTrans>\n <amount>100</amount>\n <currencyCode>USD</currencyCode>\n <ccNum>4747474747474747</ccNum>\n <expDate>0918</expDate>\n <CVV2>999</CVV2>\n <cardholderName>Longbob Longsen</cardholderName>\n <addr>456 My Street</addr>\n <aptNum>Apt 1</aptNum>\n <city>Ottawa</city>\n <state>ON</state>\n <zip>K1C2N6</zip>\n <accountNum>32287391</accountNum>\n <transType>04</transType>\n </XMLTrans>\n</XMLRequest>\n" +-> "HTTP/1.1 200 OK\r\n" +-> "Cache-Control: max-age=0,no-cache,no-store,must-revalidate\r\n" +-> "Pragma: no-cache\r\n" +-> "Content-Type: text/xml; charset=utf-8\r\n" +-> "Content-Encoding: gzip\r\n" +-> "Expires: Thu, 01 Jan 1970 00:00:00 GMT\r\n" +-> "Vary: Accept-Encoding\r\n" +-> "Server: Microsoft-IIS/7.5\r\n" +-> "Set-Cookie: ASP.NET_SessionId=hn1orxwu31yeoym5fkdhac4o; path=/; secure; HttpOnly\r\n" +-> "Set-Cookie: sessionValidation=1a1d69b6-6e53-408b-b054-602593da00e7; path=/; secure; HttpOnly\r\n" +-> "X-Powered-By: ASP.NET\r\n" +-> "X-Frame-Options: SAMEORIGIN\r\n" +-> "Date: Tue, 25 Apr 2017 19:44:03 GMT\r\n" +-> "Connection: close\r\n" +-> "Content-Length: 343\r\n" +-> "\r\n" +reading 343 bytes... +-> "" +read 343 bytes +Conn close + RESPONSE + end + + def post_scrubbed + <<-POST_SCRUBBED +opening connection to xmltest.propay.com:443... +opened +starting SSL for xmltest.propay.com:443... +SSL established +<- "POST /API/PropayAPI.aspx HTTP/1.1\r\nContent-Type: application/x-www-form-urlencoded\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nAccept: */*\r\nUser-Agent: Ruby\r\nConnection: close\r\nHost: xmltest.propay.com\r\nContent-Length: 547\r\n\r\n" +<- "<?xml version=\"1.0\"?>\n<XMLRequest>\n <certStr>[FILTERED]</certStr>\n <class>partner</class>\n <XMLTrans>\n <amount>100</amount>\n <currencyCode>USD</currencyCode>\n <ccNum>[FILTERED]</ccNum>\n <expDate>0918</expDate>\n <CVV2>[FILTERED]</CVV2>\n <cardholderName>Longbob Longsen</cardholderName>\n <addr>456 My Street</addr>\n <aptNum>Apt 1</aptNum>\n <city>Ottawa</city>\n <state>ON</state>\n <zip>K1C2N6</zip>\n <accountNum>32287391</accountNum>\n <transType>04</transType>\n </XMLTrans>\n</XMLRequest>\n" +-> "HTTP/1.1 200 OK\r\n" +-> "Cache-Control: max-age=0,no-cache,no-store,must-revalidate\r\n" +-> "Pragma: no-cache\r\n" +-> "Content-Type: text/xml; charset=utf-8\r\n" +-> "Content-Encoding: gzip\r\n" +-> "Expires: Thu, 01 Jan 1970 00:00:00 GMT\r\n" +-> "Vary: Accept-Encoding\r\n" +-> "Server: Microsoft-IIS/7.5\r\n" +-> "Set-Cookie: ASP.NET_SessionId=hn1orxwu31yeoym5fkdhac4o; path=/; secure; HttpOnly\r\n" +-> "Set-Cookie: sessionValidation=1a1d69b6-6e53-408b-b054-602593da00e7; path=/; secure; HttpOnly\r\n" +-> "X-Powered-By: ASP.NET\r\n" +-> "X-Frame-Options: SAMEORIGIN\r\n" +-> "Date: Tue, 25 Apr 2017 19:44:03 GMT\r\n" +-> "Connection: close\r\n" +-> "Content-Length: 343\r\n" +-> "\r\n" +reading 343 bytes... +-> "" +read 343 bytes +Conn close + POST_SCRUBBED + end + + def successful_purchase_response + %( + <?xml version="1.0"?><XMLResponse><XMLTrans><transType>04</transType><status>00</status><accountNum>32287391</accountNum><transNum>16</transNum><authCode>A11111</authCode><AVS>T</AVS><CVV2Resp>M</CVV2Resp><responseCode>0</responseCode><NetAmt>67</NetAmt><GrossAmt>100</GrossAmt><GrossAmtLessNetAmt>33</GrossAmtLessNetAmt><PerTransFee>30</PerTransFee><Rate>3.25</Rate></XMLTrans></XMLResponse> + ) + end + + def failed_purchase_response + %( + <?xml version="1.0"?><XMLResponse><XMLTrans><transType>04</transType><status>58</status><accountNum>32287391</accountNum><transNum>22</transNum><authCode>A11111</authCode><AVS>T</AVS><responseCode>51</responseCode></XMLTrans></XMLResponse> + ) + end + + def successful_authorize_response + %( + <?xml version="1.0"?><XMLResponse><XMLTrans><transType>05</transType><status>00</status><accountNum>32287391</accountNum><transNum>24</transNum><authCode>A11111</authCode><AVS>T</AVS><CVV2Resp>M</CVV2Resp><responseCode>0</responseCode><NetAmt>0</NetAmt><GrossAmt>100</GrossAmt><GrossAmtLessNetAmt>100</GrossAmtLessNetAmt><PerTransFee>0</PerTransFee><Rate>0.00</Rate></XMLTrans></XMLResponse> + ) + end + + def failed_authorize_response + %( + <?xml version="1.0"?><XMLResponse><XMLTrans><transType>05</transType><status>58</status><accountNum>32287391</accountNum><transNum>26</transNum><authCode>A11111</authCode><AVS>T</AVS><responseCode>51</responseCode></XMLTrans></XMLResponse> + ) + end + + def successful_capture_response + %( + <?xml version="1.0"?><XMLResponse><XMLTrans><transType>06</transType><status>00</status><accountNum>32287391</accountNum><transNum>24</transNum><NetAmt>67</NetAmt><GrossAmt>100</GrossAmt><GrossAmtLessNetAmt>33</GrossAmtLessNetAmt><PerTransFee>30</PerTransFee><Rate>3.25</Rate></XMLTrans></XMLResponse> + ) + end + + def failed_capture_response + %( + <?xml version="1.0"?><XMLResponse><XMLTrans><transType>06</transType><status>51</status><accountNum>32287391</accountNum></XMLTrans></XMLResponse> + ) + end + + def successful_refund_response + %( + <?xml version="1.0"?><XMLResponse><XMLTrans><transType>07</transType><status>00</status><accountNum>32287391</accountNum><transNum>5</transNum></XMLTrans></XMLResponse> + ) + end + + def failed_refund_response + %( + <?xml version="1.0"?><XMLResponse><XMLTrans><transType>07</transType><status>51</status><accountNum>32287391</accountNum></XMLTrans></XMLResponse> + ) + end + + def successful_void_response + %( + <?xml version="1.0"?><XMLResponse><XMLTrans><transType>07</transType><status>00</status><accountNum>32287391</accountNum><transNum>44</transNum></XMLTrans></XMLResponse> + ) + end + + def failed_void_response + %( + <?xml version="1.0"?><XMLResponse><XMLTrans><transType>07</transType><status>51</status><accountNum>32287391</accountNum></XMLTrans></XMLResponse> + ) + end + + def successful_credit_response + %( + <?xml version="1.0"?><XMLResponse><XMLTrans><transType>35</transType><status>00</status><accountNum>32287391</accountNum><transNum>103</transNum></XMLTrans></XMLResponse> + ) + end + + def failed_credit_response + %( + <?xml version="1.0"?><XMLResponse><XMLTrans><transType>35</transType><status>48</status><accountNum>32287391</accountNum></XMLTrans></XMLResponse> + ) + end +end diff --git a/test/unit/gateways/psigate_test.rb b/test/unit/gateways/psigate_test.rb index 92e85e08ab2..1bcb49689fb 100644 --- a/test/unit/gateways/psigate_test.rb +++ b/test/unit/gateways/psigate_test.rb @@ -9,7 +9,7 @@ def setup @amount = 100 @credit_card = credit_card('4111111111111111') - @options = { :order_id => "1", :billing_address => address } + @options = { :order_id => '1', :billing_address => address } end def test_successful_authorization @@ -38,23 +38,23 @@ def test_failed_purchase end def test_deprecated_credit - @gateway.expects(:ssl_post).with(anything, regexp_matches(/<OrderID>transaction_id<\//), anything).returns("") + @gateway.expects(:ssl_post).with(anything, regexp_matches(/<OrderID>transaction_id<\//), anything).returns('') @gateway.expects(:parse).returns({}) assert_deprecation_warning(Gateway::CREDIT_DEPRECATION_MESSAGE) do - @gateway.credit(@amount, "transaction_id", @options) + @gateway.credit(@amount, 'transaction_id', @options) end end def test_refund - @gateway.expects(:ssl_post).with(anything, regexp_matches(/<OrderID>transaction_id<\//), anything).returns("") + @gateway.expects(:ssl_post).with(anything, regexp_matches(/<OrderID>transaction_id<\//), anything).returns('') @gateway.expects(:parse).returns({}) - @gateway.refund(@amount, "transaction_id", @options) + @gateway.refund(@amount, 'transaction_id', @options) end def test_void - @gateway.expects(:ssl_post).with(anything, regexp_matches(/<OrderID>transaction_id<\//), anything).returns("") + @gateway.expects(:ssl_post).with(anything, regexp_matches(/<OrderID>transaction_id<\//), anything).returns('') @gateway.expects(:parse).returns({}) - @gateway.void("transaction_id;1", @options) + @gateway.void('transaction_id;1', @options) end def test_amount_style @@ -87,6 +87,11 @@ def test_cvv_result assert_equal 'M', response.cvv_result['code'] end + def test_scrub + assert @gateway.supports_scrubbing? + assert_equal @gateway.scrub(pre_scrubbed), post_scrubbed + end + private def successful_authorization_response @@ -186,4 +191,18 @@ def xml_purchase_fixture def xml_capture_fixture '<?xml version="1.0"?><Order><OrderID>1004</OrderID><CardAction>2</CardAction><StoreID>teststore</StoreID><PaymentType>CC</PaymentType><SubTotal>20.00</SubTotal><Passphrase>psigate1234</Passphrase></Order>' end + + def pre_scrubbed + <<-PRE_SCRUBBED + <?xml version='1.0'?><Order><StoreID>teststore</StoreID><Passphrase>psigate1234</Passphrase><OrderID>1b7b4b36bf61e972a9e6a6be8fff15d8</OrderID><Email>jack@example.com</Email><PaymentType>CC</PaymentType><CardAction>0</CardAction><SubTotal>24.00</SubTotal><CardNumber>4242424242424242</CardNumber><CardExpMonth>09</CardExpMonth><CardExpYear>14</CardExpYear><CardIDCode>1</CardIDCode><CardIDNumber>123</CardIDNumber><Bname>Jim Smith</Bname><Baddress1>1234 My Street</Baddress1><Baddress2>Apt 1</Baddress2><Bcity>Ottawa</Bcity><Bprovince>ON</Bprovince><Bpostalcode>K1C2N6</Bpostalcode><Bcountry>CA</Bcountry><Bcompany>Widgets Inc</Bcompany></Order> + <CardNumber>......4242</CardNumber> + PRE_SCRUBBED + end + + def post_scrubbed + <<-POST_SCRUBBED + <?xml version='1.0'?><Order><StoreID>teststore</StoreID><Passphrase>[FILTERED]</Passphrase><OrderID>1b7b4b36bf61e972a9e6a6be8fff15d8</OrderID><Email>jack@example.com</Email><PaymentType>CC</PaymentType><CardAction>0</CardAction><SubTotal>24.00</SubTotal><CardNumber>[FILTERED]</CardNumber><CardExpMonth>09</CardExpMonth><CardExpYear>14</CardExpYear><CardIDCode>1</CardIDCode><CardIDNumber>[FILTERED]</CardIDNumber><Bname>Jim Smith</Bname><Baddress1>1234 My Street</Baddress1><Baddress2>Apt 1</Baddress2><Bcity>Ottawa</Bcity><Bprovince>ON</Bprovince><Bpostalcode>K1C2N6</Bpostalcode><Bcountry>CA</Bcountry><Bcompany>Widgets Inc</Bcompany></Order> + <CardNumber>[FILTERED]</CardNumber> + POST_SCRUBBED + end end diff --git a/test/unit/gateways/psl_card_test.rb b/test/unit/gateways/psl_card_test.rb index 9c6aca35b82..6a971d1815e 100644 --- a/test/unit/gateways/psl_card_test.rb +++ b/test/unit/gateways/psl_card_test.rb @@ -8,14 +8,14 @@ def setup :password => 'PASSWORD' ) - @credit_card = credit_card + @credit_card = credit_card @options = { :billing_address => address, :description => 'Store purchase' } @amount = 100 end - + def test_successful_authorization @gateway.expects(:ssl_post).returns(successful_purchase_response) assert response = @gateway.authorize(@amount, @credit_card, @options) @@ -34,15 +34,15 @@ def test_unsuccessful_request def test_supported_countries assert_equal ['GB'], PslCardGateway.supported_countries end - + def test_supported_card_types - assert_equal [ :visa, :master, :american_express, :diners_club, :jcb, :switch, :solo, :maestro ], PslCardGateway.supported_cardtypes + assert_equal [ :visa, :master, :american_express, :diners_club, :jcb, :maestro ], PslCardGateway.supported_cardtypes end - + def test_avs_result @gateway.expects(:ssl_post).returns(successful_purchase_response) - response = @gateway.purchase(@amount, @credit_card, @options) + response = @gateway.purchase(@amount, @credit_card, @options) assert_equal 'Y', response.avs_result['code'] end @@ -52,13 +52,14 @@ def test_cvv_result response = @gateway.purchase(@amount, @credit_card, @options) assert_equal 'M', response.cvv_result['code'] end - + private + def successful_purchase_response - "ResponseCode=00&Message=AUTHCODE:01256&CrossReference=08012522454901256086&First4=4543&Last4=9982&ExpMonth=12&ExpYear=2010&AVSCV2Check=ALL MATCH&Amount=1000&QAAddress=76 Roseby Avenue Manchester&QAPostcode=M63X 7TH&MerchantName=Merchant Name&QAName=John Smith" + 'ResponseCode=00&Message=AUTHCODE:01256&CrossReference=08012522454901256086&First4=4543&Last4=9982&ExpMonth=12&ExpYear=2010&AVSCV2Check=ALL MATCH&Amount=1000&QAAddress=76 Roseby Avenue Manchester&QAPostcode=M63X 7TH&MerchantName=Merchant Name&QAName=John Smith' end - + def unsuccessful_purchase_response - "ResponseCode=05&Message=CARD DECLINED&QAAddress=The Parkway Larches Approach Hull North Humberside&QAPostcode=HU7 9OP&MerchantName=Merchant Name&QAName=" + 'ResponseCode=05&Message=CARD DECLINED&QAAddress=The Parkway Larches Approach Hull North Humberside&QAPostcode=HU7 9OP&MerchantName=Merchant Name&QAName=' end -end \ No newline at end of file +end diff --git a/test/unit/gateways/qbms_test.rb b/test/unit/gateways/qbms_test.rb index 1ea30acd0ad..894a3e0571d 100644 --- a/test/unit/gateways/qbms_test.rb +++ b/test/unit/gateways/qbms_test.rb @@ -5,8 +5,8 @@ def setup Base.mode = :test @gateway = QbmsGateway.new( - :login => "test", - :ticket => "abc123", + :login => 'test', + :ticket => 'abc123', :pem => 'PEM') @amount = 100 @@ -45,7 +45,7 @@ def test_truncated_address_is_sent with(anything, regexp_matches(/12345 Ridiculously Lengthy Roa\<.*445566778\</), anything). returns(charge_response) - options = { :billing_address => address.update(:address1 => "12345 Ridiculously Lengthy Road Name", :zip => '4455667788') } + options = { :billing_address => address.update(:address1 => '12345 Ridiculously Lengthy Road Name', :zip => '4455667788') } assert response = @gateway.purchase(@amount, @card, options) assert_success response end @@ -61,7 +61,7 @@ def test_partial_address_is_ok def test_successful_void @gateway.expects(:ssl_post).returns(void_response) - assert response = @gateway.void("x") + assert response = @gateway.void('x') assert_instance_of Response, response assert_success response end @@ -70,7 +70,7 @@ def test_successful_deprecated_credit @gateway.expects(:ssl_post).returns(credit_response) assert_deprecation_warning(Gateway::CREDIT_DEPRECATION_MESSAGE) do - assert response = @gateway.credit(@amount, "x") + assert response = @gateway.credit(@amount, 'x') assert_instance_of Response, response assert_success response end @@ -79,7 +79,7 @@ def test_successful_deprecated_credit def test_successful_refund @gateway.expects(:ssl_post).returns(credit_response) - assert response = @gateway.refund(@amount, "x") + assert response = @gateway.refund(@amount, 'x') assert_instance_of Response, response assert_success response end @@ -90,17 +90,17 @@ def test_avs_result assert_equal 'Y', response.avs_result['street_match'] assert_equal 'Y', response.avs_result['postal_match'] - @gateway.expects(:ssl_post).returns(authorization_response(:avs_street => "Fail")) + @gateway.expects(:ssl_post).returns(authorization_response(:avs_street => 'Fail')) assert response = @gateway.authorize(@amount, @card) assert_equal 'N', response.avs_result['street_match'] assert_equal 'Y', response.avs_result['postal_match'] - @gateway.expects(:ssl_post).returns(authorization_response(:avs_zip => "Fail")) + @gateway.expects(:ssl_post).returns(authorization_response(:avs_zip => 'Fail')) assert response = @gateway.authorize(@amount, @card) assert_equal 'Y', response.avs_result['street_match'] assert_equal 'N', response.avs_result['postal_match'] - @gateway.expects(:ssl_post).returns(authorization_response(:avs_street => "Fail", :avs_zip => "Fail")) + @gateway.expects(:ssl_post).returns(authorization_response(:avs_street => 'Fail', :avs_zip => 'Fail')) assert response = @gateway.authorize(@amount, @card) assert_equal 'N', response.avs_result['street_match'] assert_equal 'N', response.avs_result['postal_match'] @@ -111,11 +111,11 @@ def test_cvv_result assert response = @gateway.authorize(@amount, @card) assert_equal 'M', response.cvv_result['code'] - @gateway.expects(:ssl_post).returns(authorization_response(:card_security_code_match => "Fail")) + @gateway.expects(:ssl_post).returns(authorization_response(:card_security_code_match => 'Fail')) assert response = @gateway.authorize(@amount, @card) assert_equal 'N', response.cvv_result['code'] - @gateway.expects(:ssl_post).returns(authorization_response(:card_security_code_match => "NotAvailable")) + @gateway.expects(:ssl_post).returns(authorization_response(:card_security_code_match => 'NotAvailable')) assert response = @gateway.authorize(@amount, @card) assert_equal 'P', response.cvv_result['code'] end @@ -147,7 +147,7 @@ def test_failed_authorization def test_use_test_url_when_overwriting_with_test_option ActiveMerchant::Billing::Base.mode = :production - @gateway = QbmsGateway.new(:login => "test", :ticket => "abc123", :test => true) + @gateway = QbmsGateway.new(:login => 'test', :ticket => 'abc123', :test => true) @gateway.stubs(:parse).returns({}) @gateway.expects(:ssl_post).with(QbmsGateway.test_url, anything, anything).returns(authorization_response) @gateway.authorize(@amount, @card) @@ -155,10 +155,15 @@ def test_use_test_url_when_overwriting_with_test_option ActiveMerchant::Billing::Base.mode = :test end + def test_scrub + assert @gateway.supports_scrubbing? + assert_equal @gateway.scrub(pre_scrubbed), post_scrubbed + end + # helper methods start here def query_response(opts = {}) - wrap "MerchantAccountQuery", opts, <<-"XML" + wrap 'MerchantAccountQuery', opts, <<-"XML" <ConvenienceFees>0.0</ConvenienceFees> <CreditCardType>Visa</CreditCardType> <CreditCardType>MasterCard</CreditCardType> @@ -168,12 +173,12 @@ def query_response(opts = {}) def authorization_response(opts = {}) opts = { - :avs_street => "Pass", - :avs_zip => "Pass", - :card_security_code_match => "Pass", + :avs_street => 'Pass', + :avs_zip => 'Pass', + :card_security_code_match => 'Pass', }.merge(opts) - wrap "CustomerCreditCardAuth", opts, <<-"XML" + wrap 'CustomerCreditCardAuth', opts, <<-"XML" <CreditCardTransID>1000</CreditCardTransID> <AuthorizationCode>STRTYPE</AuthorizationCode> <AVSStreet>#{opts[:avs_street]}</AVSStreet> @@ -184,7 +189,7 @@ def authorization_response(opts = {}) end def capture_response(opts = {}) - wrap "CustomerCreditCardCapture", opts, <<-"XML" + wrap 'CustomerCreditCardCapture', opts, <<-"XML" <CreditCardTransID>1000</CreditCardTransID> <AuthorizationCode>STRTYPE</AuthorizationCode> <MerchantAccountNumber>STRTYPE</MerchantAccountNumber> @@ -195,12 +200,12 @@ def capture_response(opts = {}) def charge_response(opts = {}) opts = { - :avs_street => "Pass", - :avs_zip => "Pass", - :card_security_code_match => "Pass", + :avs_street => 'Pass', + :avs_zip => 'Pass', + :card_security_code_match => 'Pass', }.merge(opts) - wrap "CustomerCreditCardCharge", opts, <<-"XML" + wrap 'CustomerCreditCardCharge', opts, <<-"XML" <CreditCardTransID>1000</CreditCardTransID> <AuthorizationCode>STRTYPE</AuthorizationCode> <AVSStreet>#{opts[:avs_street]}</AVSStreet> @@ -213,14 +218,14 @@ def charge_response(opts = {}) end def void_response(opts = {}) - wrap "CustomerCreditCardTxnVoid", opts, <<-"XML" + wrap 'CustomerCreditCardTxnVoid', opts, <<-"XML" <CreditCardTransID>1000</CreditCardTransID> <ClientTransID>STRTYPE</ClientTransID> XML end def credit_response(opts = {}) - wrap "CustomerCreditCardTxnVoidOrRefund", opts, <<-"XML" + wrap 'CustomerCreditCardTxnVoidOrRefund', opts, <<-"XML" <CreditCardTransID>1000</CreditCardTransID> <VoidOrRefundTxnType>STRTYPE</VoidOrRefundTxnType> <MerchantAccountNumber>STRTYPE</MerchantAccountNumber> @@ -232,7 +237,7 @@ def credit_response(opts = {}) def wrap(type, opts, xml) opts = { :signon_status_code => 0, - :request_id => "x", + :request_id => 'x', :status_code => 0, }.merge(opts) @@ -254,4 +259,66 @@ def wrap(type, opts, xml) </QBMSXML> XML end + + def pre_scrubbed + <<-PRE_SCRUBBED + <?xml version="1.0" encoding="utf-8"?><?qbmsxml version="4.0"?><QBMSXML><SignonMsgsRq><SignonDesktopRq><ClientDateTime>2012-07-06T11:48:30-07:00</ClientDateTime><ApplicationLogin>subscriptions-test.spreedly.com</ApplicationLogin><ConnectionTicket>TGT-135-0exSkgC_I9tvKAxCwOE$Eg</ConnectionTicket></SignonDesktopRq></SignonMsgsRq><QBMSXMLMsgsRq><CustomerCreditCardChargeRq><TransRequestID>859e649c87f9ac698536</TransRequestID><CreditCardNumber>4111111111111111</CreditCardNumber><ExpirationMonth>9</ExpirationMonth><ExpirationYear>2013</ExpirationYear><IsECommerce>true</IsECommerce><Amount>1.00</Amount><NameOnCard>Longbob Longsen</NameOnCard><CreditCardAddress>1234 My Street</CreditCardAddress><CreditCardPostalCode>K1C2N6</CreditCardPostalCode><CardSecurityCode>123</CardSecurityCode></CustomerCreditCardChargeRq></QBMSXMLMsgsRq></QBMSXML> + <!DOCTYPE QBMSXML PUBLIC "-//INTUIT//DTD QBMSXML QBMS 4.0//EN" "http://webmerchantaccount.ptc.quickbooks.com/dtds/qbmsxml40.dtd"> + <QBMSXML> + <SignonMsgsRs> + <SignonDesktopRs statusCode="0" statusSeverity="INFO"> + <ServerDateTime>2012-07-06T18:48:31</ServerDateTime> + <SessionTicket>V1-110-Q31341600511142d1e4131:133159303</SessionTicket> + </SignonDesktopRs> + </SignonMsgsRs> + <QBMSXMLMsgsRs> + <CustomerCreditCardChargeRs statusCode="0" statusMessage="Status OK" statusSeverity="INFO"> + <CreditCardTransID>YY1002519111</CreditCardTransID> + <AuthorizationCode>135927</AuthorizationCode> + <AVSStreet>Pass</AVSStreet> + <AVSZip>Pass</AVSZip> + <CardSecurityCodeMatch>Pass</CardSecurityCodeMatch> + <MerchantAccountNumber>5247711053184054</MerchantAccountNumber> + <ReconBatchID>420120706 1Q11485247711053184054AUTO04</ReconBatchID> + <PaymentGroupingCode>5</PaymentGroupingCode> + <PaymentStatus>Completed</PaymentStatus> + <TxnAuthorizationTime>2012-07-06T18:48:31</TxnAuthorizationTime> + <TxnAuthorizationStamp>1341600511</TxnAuthorizationStamp> + <ClientTransID>q0b539f2</ClientTransID> + </CustomerCreditCardChargeRs> + </QBMSXMLMsgsRs> + </QBMSXML> + PRE_SCRUBBED + end + + def post_scrubbed + <<-POST_SCRUBBED + <?xml version="1.0" encoding="utf-8"?><?qbmsxml version="4.0"?><QBMSXML><SignonMsgsRq><SignonDesktopRq><ClientDateTime>2012-07-06T11:48:30-07:00</ClientDateTime><ApplicationLogin>subscriptions-test.spreedly.com</ApplicationLogin><ConnectionTicket>[FILTERED]</ConnectionTicket></SignonDesktopRq></SignonMsgsRq><QBMSXMLMsgsRq><CustomerCreditCardChargeRq><TransRequestID>859e649c87f9ac698536</TransRequestID><CreditCardNumber>[FILTERED]</CreditCardNumber><ExpirationMonth>9</ExpirationMonth><ExpirationYear>2013</ExpirationYear><IsECommerce>true</IsECommerce><Amount>1.00</Amount><NameOnCard>Longbob Longsen</NameOnCard><CreditCardAddress>1234 My Street</CreditCardAddress><CreditCardPostalCode>K1C2N6</CreditCardPostalCode><CardSecurityCode>[FILTERED]</CardSecurityCode></CustomerCreditCardChargeRq></QBMSXMLMsgsRq></QBMSXML> + <!DOCTYPE QBMSXML PUBLIC "-//INTUIT//DTD QBMSXML QBMS 4.0//EN" "http://webmerchantaccount.ptc.quickbooks.com/dtds/qbmsxml40.dtd"> + <QBMSXML> + <SignonMsgsRs> + <SignonDesktopRs statusCode="0" statusSeverity="INFO"> + <ServerDateTime>2012-07-06T18:48:31</ServerDateTime> + <SessionTicket>V1-110-Q31341600511142d1e4131:133159303</SessionTicket> + </SignonDesktopRs> + </SignonMsgsRs> + <QBMSXMLMsgsRs> + <CustomerCreditCardChargeRs statusCode="0" statusMessage="Status OK" statusSeverity="INFO"> + <CreditCardTransID>YY1002519111</CreditCardTransID> + <AuthorizationCode>135927</AuthorizationCode> + <AVSStreet>Pass</AVSStreet> + <AVSZip>Pass</AVSZip> + <CardSecurityCodeMatch>Pass</CardSecurityCodeMatch> + <MerchantAccountNumber>5247711053184054</MerchantAccountNumber> + <ReconBatchID>420120706 1Q11485247711053184054AUTO04</ReconBatchID> + <PaymentGroupingCode>5</PaymentGroupingCode> + <PaymentStatus>Completed</PaymentStatus> + <TxnAuthorizationTime>2012-07-06T18:48:31</TxnAuthorizationTime> + <TxnAuthorizationStamp>1341600511</TxnAuthorizationStamp> + <ClientTransID>q0b539f2</ClientTransID> + </CustomerCreditCardChargeRs> + </QBMSXMLMsgsRs> + </QBMSXML> + POST_SCRUBBED + end end diff --git a/test/unit/gateways/quantum_test.rb b/test/unit/gateways/quantum_test.rb index a1d771cd8b0..10bb11ccaf4 100644 --- a/test/unit/gateways/quantum_test.rb +++ b/test/unit/gateways/quantum_test.rb @@ -9,19 +9,19 @@ def setup @credit_card = credit_card @amount = 100 - - @options = { + + @options = { :billing_address => address, :description => 'Store Purchase' } end - + def test_successful_purchase @gateway.expects(:ssl_post).returns(successful_purchase_response) - + assert response = @gateway.purchase(@amount, @credit_card, @options) assert_success response - + # Replace with authorization number from the successful response assert_equal '2983691;2224', response.authorization assert response.test? @@ -29,14 +29,14 @@ def test_successful_purchase def test_unsuccessful_request @gateway.expects(:ssl_post).returns(failed_purchase_response) - + assert response = @gateway.purchase(@amount, @credit_card, @options) assert_failure response assert response.test? end - + private - + # Place raw successful response from gateway here def successful_purchase_response %(<QGWRequest> @@ -74,7 +74,7 @@ def successful_purchase_response </Result> </QGWRequest>) end - + # Place raw failed response from gateway here def failed_purchase_response %(<QGWRequest> diff --git a/test/unit/gateways/quickbooks_test.rb b/test/unit/gateways/quickbooks_test.rb index c264c0354b1..7d59f157ba5 100644 --- a/test/unit/gateways/quickbooks_test.rb +++ b/test/unit/gateways/quickbooks_test.rb @@ -9,7 +9,7 @@ def setup consumer_secret: 'consumer_secret', access_token: 'access_token', token_secret: 'token_secret', - realm: 'realm_ID', + realm: 'realm_ID' ) @credit_card = credit_card @@ -21,7 +21,7 @@ def setup description: 'Store Purchase' } - @authorization = "ECZ7U0SO423E" + @authorization = 'ECZ7U0SO423E' end def test_successful_purchase @@ -29,7 +29,7 @@ def test_successful_purchase response = @gateway.purchase(@amount, @credit_card, @options) assert_success response - assert_equal "EF1IQ9GGXS2D", response.authorization + assert_equal 'EF1IQ9GGXS2D', response.authorization assert response.test? end @@ -112,6 +112,16 @@ def test_scrub_with_small_json assert_equal @gateway.scrub(pre_scrubbed_small_json), post_scrubbed_small_json end + def test_default_context + stub_comms do + @gateway.purchase(@amount, @credit_card, @options) + end.check_request do |_endpoint, data, _headers| + json = JSON.parse(data) + refute json.fetch('context').fetch('mobile') + assert json.fetch('context').fetch('isEcommerce') + end.respond_with(successful_purchase_response) + end + private def pre_scrubbed_small_json diff --git a/test/unit/gateways/quickpay_test.rb b/test/unit/gateways/quickpay_test.rb index 4eb99dcf7ed..f9f2e2d28cd 100644 --- a/test/unit/gateways/quickpay_test.rb +++ b/test/unit/gateways/quickpay_test.rb @@ -1,23 +1,21 @@ - require 'test_helper' class QuickpayTest < Test::Unit::TestCase - + def test_error_without_login_option assert_raise ArgumentError do QuickpayGateway.new end end - + def test_v4to7 - gateway = QuickpayGateway.new(:login => 50000000, :password => 'secret') + gateway = QuickpayGateway.new(:login => 50000000, :password => 'secret') assert_instance_of QuickpayV4to7Gateway, gateway end - + def test_v10 - gateway = QuickpayGateway.new(:login => 100, :api_key => 'APIKEY') + gateway = QuickpayGateway.new(:login => 100, :api_key => 'APIKEY') assert_instance_of QuickpayV10Gateway, gateway end - -end +end diff --git a/test/unit/gateways/quickpay_v10_test.rb b/test/unit/gateways/quickpay_v10_test.rb index e87ba7f3b0e..61bec826b5d 100644 --- a/test/unit/gateways/quickpay_v10_test.rb +++ b/test/unit/gateways/quickpay_v10_test.rb @@ -10,7 +10,7 @@ def setup @options = { :order_id => '1', :billing_address => address, :customer_ip => '1.1.1.1' } end - def parse body + def parse(body) JSON.parse(body) end @@ -26,7 +26,7 @@ def test_successful_purchase response = @gateway.purchase(@amount, @credit_card, @options) assert response assert_success response - assert_equal 1145, response.authorization + assert_equal '1145', response.authorization assert response.test? end.check_request do |endpoint, data, headers| parsed = parse(data) @@ -45,13 +45,13 @@ def test_successful_authorization stub_comms do assert response = @gateway.authorize(@amount, @credit_card, @options) assert_success response - assert_equal 1145, response.authorization + assert_equal '1145', response.authorization assert response.test? end.check_request do |endpoint, data, headers| parsed_data = parse(data) if parsed_data['order_id'] assert_match %r{/payments}, endpoint - assert_match "1.1.1.1", @options[:customer_ip] + assert_match '1.1.1.1', @options[:customer_ip] else assert_match %r{/payments/\d+/authorize}, endpoint end @@ -111,7 +111,7 @@ def test_successful_verify @gateway.verify(@credit_card, @options) end.respond_with(successful_authorization_response) assert_success response - assert_equal "OK", response.message + assert_equal 'OK', response.message end def test_failed_verify @@ -119,7 +119,7 @@ def test_failed_verify @gateway.verify(@credit_card, @options) end.respond_with(failed_authorization_response, {'id' => 1145}.to_json) assert_failure response - assert_equal "Validation error", response.message + assert_equal 'Validation error', response.message end def test_supported_countries @@ -129,7 +129,7 @@ def test_supported_countries def test_supported_card_types klass = @gateway.class - assert_equal [:dankort, :forbrugsforeningen, :visa, :master, :american_express, :diners_club, :jcb, :maestro ], klass.supported_cardtypes + assert_equal [:dankort, :forbrugsforeningen, :visa, :master, :american_express, :diners_club, :jcb, :maestro ], klass.supported_cardtypes end def test_successful_capture @@ -146,108 +146,108 @@ def test_transcript_scrubbing def successful_payment_response { - "id" =>1145, - "order_id" =>"310f59c57a", - "accepted" =>false, - "test_mode" =>false, - "branding_id" =>nil, - "variables" =>{}, - "acquirer" =>nil, - "operations" =>[], - "metadata" =>{}, - "created_at" =>"2015-03-30T16:56:17Z", - "balance" =>0, - "currency" =>"DKK" + 'id' =>1145, + 'order_id' =>'310f59c57a', + 'accepted' =>false, + 'test_mode' =>false, + 'branding_id' =>nil, + 'variables' =>{}, + 'acquirer' =>nil, + 'operations' =>[], + 'metadata' =>{}, + 'created_at' =>'2015-03-30T16:56:17Z', + 'balance' =>0, + 'currency' =>'DKK' }.to_json end def successful_authorization_response { - "id" => 1145, - "order_id" => "310f59c57a", - "accepted" => false, - "test_mode" => true, - "branding_id" => nil, - "variables" => {}, - "acquirer" => "clearhaus", - "operations" => [], - "metadata" => { - "type" =>"card", - "brand" =>"quickpay-test-card", - "last4" =>"0008", - "exp_month" =>9, - "exp_year" =>2016, - "country" =>"DK", - "is_3d_secure" =>false, - "customer_ip" =>nil, - "customer_country" =>nil + 'id' => 1145, + 'order_id' => '310f59c57a', + 'accepted' => false, + 'test_mode' => true, + 'branding_id' => nil, + 'variables' => {}, + 'acquirer' => 'clearhaus', + 'operations' => [], + 'metadata' => { + 'type' =>'card', + 'brand' =>'quickpay-test-card', + 'last4' =>'0008', + 'exp_month' =>9, + 'exp_year' =>2016, + 'country' =>'DK', + 'is_3d_secure' =>false, + 'customer_ip' =>nil, + 'customer_country' =>nil }, - "created_at" => "2015-03-30T16:56:17Z", - "balance" => 0, - "currency" => "DKK" + 'created_at' => '2015-03-30T16:56:17Z', + 'balance' => 0, + 'currency' => 'DKK' }.to_json end def successful_capture_response { - "id" =>1145, - "order_id" =>"310f59c57a", - "accepted" =>true, - "test_mode" =>true, - "branding_id" =>nil, - "variables" =>{}, - "acquirer" =>"clearhaus", - "operations" =>[], - "metadata" =>{"type"=>"card", "brand"=>"quickpay-test-card", "last4"=>"0008", "exp_month"=>9, "exp_year"=>2016, "country"=>"DK", "is_3d_secure"=>false, "customer_ip"=>nil, "customer_country"=>nil}, - "created_at" =>"2015-03-30T16:56:17Z", - "balance" =>0, - "currency" =>"DKK" + 'id' =>1145, + 'order_id' =>'310f59c57a', + 'accepted' =>true, + 'test_mode' =>true, + 'branding_id' =>nil, + 'variables' =>{}, + 'acquirer' =>'clearhaus', + 'operations' =>[], + 'metadata' =>{'type'=>'card', 'brand'=>'quickpay-test-card', 'last4'=>'0008', 'exp_month'=>9, 'exp_year'=>2016, 'country'=>'DK', 'is_3d_secure'=>false, 'customer_ip'=>nil, 'customer_country'=>nil}, + 'created_at' =>'2015-03-30T16:56:17Z', + 'balance' =>0, + 'currency' =>'DKK' }.to_json end def succesful_refund_response { - "id" =>1145, - "order_id" =>"310f59c57a", - "accepted" =>true, - "test_mode" =>true, - "branding_id" =>nil, - "variables" =>{}, - "acquirer" =>"clearhaus", - "operations" =>[], - "metadata"=>{ - "type" =>"card", - "brand" =>"quickpay-test-card", - "last4" =>"0008", - "exp_month" =>9, - "exp_year" =>2016, - "country" =>"DK", - "is_3d_secure" =>false, - "customer_ip" =>nil, - "customer_country" =>nil + 'id' =>1145, + 'order_id' =>'310f59c57a', + 'accepted' =>true, + 'test_mode' =>true, + 'branding_id' =>nil, + 'variables' =>{}, + 'acquirer' =>'clearhaus', + 'operations' =>[], + 'metadata'=>{ + 'type' =>'card', + 'brand' =>'quickpay-test-card', + 'last4' =>'0008', + 'exp_month' =>9, + 'exp_year' =>2016, + 'country' =>'DK', + 'is_3d_secure' =>false, + 'customer_ip' =>nil, + 'customer_country' =>nil }, - "created_at" =>"2015-03-30T16:56:17Z", - "balance" =>100, - "currency" =>"DKK" + 'created_at' =>'2015-03-30T16:56:17Z', + 'balance' =>100, + 'currency' =>'DKK' }.to_json end def failed_authorization_response { - 'message' => "Validation error", - "errors" => { - "id" => ["is not valid"] + 'message' => 'Validation error', + 'errors' => { + 'id' => ['is not valid'] } }.to_json end def failed_payment_response { - "message" => "Validation error", - "errors" => { - "currency" => ["must be three uppercase letters"] + 'message' => 'Validation error', + 'errors' => { + 'currency' => ['must be three uppercase letters'] }, - "error_code" => nil + 'error_code' => nil }.to_json end diff --git a/test/unit/gateways/quickpay_v4to7_test.rb b/test/unit/gateways/quickpay_v4to7_test.rb index fd14e56b563..74e395980ca 100644 --- a/test/unit/gateways/quickpay_v4to7_test.rb +++ b/test/unit/gateways/quickpay_v4to7_test.rb @@ -2,11 +2,11 @@ class QuickpayV4to7Test < Test::Unit::TestCase include CommStub - + def merchant_id - "80000000000" + '80000000000' end - + def setup @gateway = QuickpayGateway.new( :login => merchant_id, @@ -129,11 +129,11 @@ def test_supported_countries def test_supported_card_types klass = @gateway.class - assert_equal [ :dankort, :forbrugsforeningen, :visa, :master, :american_express, :diners_club, :jcb, :maestro ], klass.supported_cardtypes + assert_equal [ :dankort, :forbrugsforeningen, :visa, :master, :american_express, :diners_club, :jcb, :maestro ], klass.supported_cardtypes end def test_add_testmode_does_not_add_testmode_if_transaction_id_present - post_hash = {:transaction => "12345"} + post_hash = {:transaction => '12345'} @gateway.send(:add_testmode, post_hash) assert_equal nil, post_hash[:testmode] end @@ -146,7 +146,7 @@ def test_add_testmode_adds_a_testmode_param_if_transaction_id_not_present def test_finalize_is_disabled_by_default stub_comms(@gateway, :ssl_request) do - @gateway.capture(@amount, "12345") + @gateway.capture(@amount, '12345') end.check_request do |method, endpoint, data, headers| assert data =~ /finalize=0/ end.respond_with(successful_capture_response) @@ -154,7 +154,7 @@ def test_finalize_is_disabled_by_default def test_finalize_is_enabled stub_comms(@gateway, :ssl_request) do - @gateway.capture(@amount, "12345", finalize: true) + @gateway.capture(@amount, '12345', finalize: true) end.check_request do |method, endpoint, data, headers| assert data =~ /finalize=1/ end.respond_with(successful_capture_response) @@ -192,33 +192,33 @@ def failed_authorization_response def expected_store_parameters_v6 { - "cardnumber"=>["4242424242424242"], - "cvd"=>["123"], - "expirationdate"=>[expected_expiration_date], - "ordernumber"=>["fa73664073e23597bbdd"], - "description"=>["Storing Card"], - "testmode"=>["1"], - "protocol"=>["6"], - "msgtype"=>["subscribe"], - "merchant"=>[merchant_id], - "md5check"=>[mock_md5_hash] + 'cardnumber'=>['4242424242424242'], + 'cvd'=>['123'], + 'expirationdate'=>[expected_expiration_date], + 'ordernumber'=>['fa73664073e23597bbdd'], + 'description'=>['Storing Card'], + 'testmode'=>['1'], + 'protocol'=>['6'], + 'msgtype'=>['subscribe'], + 'merchant'=>[merchant_id], + 'md5check'=>[mock_md5_hash] } end def expected_store_parameters_v7 { - "amount"=>["0"], - "currency"=>["DKK"], - "cardnumber"=>["4242424242424242"], - "cvd"=>["123"], - "expirationdate"=>[expected_expiration_date], - "ordernumber"=>["ed7546cb4ceb8f017ea4"], - "description"=>["Storing Card"], - "testmode"=>["1"], - "protocol"=>["7"], - "msgtype"=>["subscribe"], - "merchant"=>[merchant_id], - "md5check"=>[mock_md5_hash] + 'amount'=>['0'], + 'currency'=>['DKK'], + 'cardnumber'=>['4242424242424242'], + 'cvd'=>['123'], + 'expirationdate'=>[expected_expiration_date], + 'ordernumber'=>['ed7546cb4ceb8f017ea4'], + 'description'=>['Storing Card'], + 'testmode'=>['1'], + 'protocol'=>['7'], + 'msgtype'=>['subscribe'], + 'merchant'=>[merchant_id], + 'md5check'=>[mock_md5_hash] } end @@ -227,6 +227,6 @@ def expected_expiration_date end def mock_md5_hash - "mock_hash" + 'mock_hash' end end diff --git a/test/unit/gateways/qvalent_test.rb b/test/unit/gateways/qvalent_test.rb index 5c3ff6d6155..f7fa337755a 100644 --- a/test/unit/gateways/qvalent_test.rb +++ b/test/unit/gateways/qvalent_test.rb @@ -1,13 +1,15 @@ -require "test_helper" +require 'test_helper' class QvalentTest < Test::Unit::TestCase include CommStub def setup @gateway = QvalentGateway.new( - username: "username", - password: "password", - merchant: "merchant" + username: 'username', + password: 'password', + merchant: 'merchant', + pem: 'pem', + pem_password: 'pempassword' ) @credit_card = credit_card @@ -21,7 +23,7 @@ def test_successful_purchase assert_success response - assert_equal "5d53a33d960c46d00f5dc061947d998c", response.authorization + assert_equal '5d53a33d960c46d00f5dc061947d998c', response.authorization assert response.test? end @@ -31,18 +33,60 @@ def test_failed_purchase end.respond_with(failed_purchase_response) assert_failure response - assert_equal "Invalid card number (no such number)", response.message + assert_equal 'Invalid card number (no such number)', response.message assert_equal Gateway::STANDARD_ERROR_CODE[:invalid_number], response.error_code assert response.test? end + def test_successful_authorize + response = stub_comms do + @gateway.authorize(@amount, @credit_card) + end.respond_with(successful_authorize_response) + + assert_success response + + assert_equal '21c74c8f08bca415b5373022e6194f74', response.authorization + assert response.test? + end + + def test_failed_authorize + response = stub_comms do + @gateway.authorize(@amount, @credit_card) + end.respond_with(failed_authorize_response) + + assert_failure response + assert_equal 'Expired card', response.message + assert response.test? + end + + def test_successful_capture + response = stub_comms do + @gateway.capture(@amount, 'auth') + end.respond_with(successful_capture_response) + + assert_success response + + assert_equal 'fedf9ea13afa46872592d62e8cdcb0a3', response.authorization + assert response.test? + end + + def test_failed_capture + response = stub_comms do + @gateway.capture(@amount, '') + end.respond_with(failed_capture_response) + + assert_failure response + assert_equal 'Invalid Parameters - order.authId: Required field', response.message + assert response.test? + end + def test_successful_refund response = stub_comms do @gateway.purchase(@amount, @credit_card) end.respond_with(successful_purchase_response) assert_success response - assert_equal "5d53a33d960c46d00f5dc061947d998c", response.authorization + assert_equal '5d53a33d960c46d00f5dc061947d998c', response.authorization refund = stub_comms do @gateway.refund(@amount, response.authorization) @@ -55,12 +99,49 @@ def test_successful_refund def test_failed_refund response = stub_comms do - @gateway.refund(nil, "") + @gateway.refund(nil, '') end.respond_with(failed_refund_response) assert_failure response end + def test_successful_credit + response = stub_comms do + @gateway.credit(@amount, @credit_card) + end.respond_with(successful_credit_response) + + assert_success response + end + + def test_failed_credit + response = stub_comms do + @gateway.credit(@amount, @credit_card) + end.respond_with(failed_credit_response) + + assert_failure response + end + + def test_successful_void + response = stub_comms do + @gateway.void('auth') + end.respond_with(successful_void_response) + + assert_success response + + assert_equal '67686b64b544335815002fd85704c8a1', response.authorization + assert response.test? + end + + def test_failed_void + response = stub_comms do + @gateway.void('') + end.respond_with(failed_void_response) + + assert_failure response + assert_equal 'Invalid Parameters - customer.originalOrderNumber: Required field', response.message + assert response.test? + end + def test_successful_store response = stub_comms do @gateway.store(@credit_card) @@ -68,8 +149,8 @@ def test_successful_store assert_success response - assert_equal "RSL-20887450", response.authorization - assert_equal "Succeeded", response.message + assert_equal 'RSL-20887450', response.authorization + assert_equal 'Succeeded', response.message assert response.test? end @@ -79,7 +160,7 @@ def test_failed_store end.respond_with(failed_store_response) assert_failure response - assert_equal "Invalid card number (no such number)", response.message + assert_equal 'Invalid card number (no such number)', response.message assert_equal Gateway::STANDARD_ERROR_CODE[:invalid_number], response.error_code assert response.test? end @@ -90,7 +171,19 @@ def test_empty_response_fails end.respond_with(empty_purchase_response) assert_failure response - assert_equal "Unable to read error message", response.message + assert_equal 'Unable to read error message', response.message + end + + def test_3d_secure_fields + response = stub_comms(@gateway, :ssl_request) do + @gateway.purchase(@amount, @credit_card, {xid: '123', cavv: '456', eci: '5'}) + end.check_request do |method, endpoint, data, headers| + assert_match(/xid=123/, data) + assert_match(/cavv=456/, data) + assert_match(/ECI=5/, data) + end.respond_with(successful_purchase_response) + + assert_success response end def test_transcript_scrubbing @@ -111,6 +204,42 @@ def failed_purchase_response ) end + def successful_authorize_response + %( + response.summaryCode=0\r\nresponse.responseCode=08\r\nresponse.text=Honour with identification\r\nresponse.referenceNo=731560096\r\nresponse.orderNumber=21c74c8f08bca415b5373022e6194f74\r\nresponse.RRN=731560096 \r\nresponse.settlementDate=20170314\r\nresponse.transactionDate=14-MAR-2017 05:41:44\r\nresponse.cardSchemeName=VISA\r\nresponse.creditGroup=VI/BC/MC\r\nresponse.previousTxn=0\r\nresponse.authId=C3JVDS\r\nresponse.end\r\n + ) + end + + def failed_authorize_response + %( + response.summaryCode=1\r\nresponse.responseCode=54\r\nresponse.text=Expired card\r\nresponse.referenceNo=731560142\r\nresponse.orderNumber=d48cb6104266ed1a51647576d8948c57\r\nresponse.RRN=731560142 \r\nresponse.settlementDate=20170314\r\nresponse.transactionDate=14-MAR-2017 05:45:18\r\nresponse.cardSchemeName=VISA\r\nresponse.creditGroup=VI/BC/MC\r\nresponse.previousTxn=0\r\nresponse.end\r\n + ) + end + + def successful_capture_response + %( + response.summaryCode=0\r\nresponse.responseCode=00\r\nresponse.text=Approved or completed successfully\r\nresponse.referenceNo=731560097\r\nresponse.orderNumber=fedf9ea13afa46872592d62e8cdcb0a3\r\nresponse.RRN=731560097\r\nresponse.settlementDate=20170314\r\nresponse.transactionDate=14-MAR-2017 05:45:52\r\nresponse.cardSchemeName=VISA\r\nresponse.creditGroup=VI/BC/MC\r\nresponse.previousTxn=0\r\nresponse.end\r\n + ) + end + + def failed_capture_response + %( + response.summaryCode=3\r\nresponse.responseCode=QA\r\nresponse.text=Invalid Parameters - order.authId: Required field\r\nresponse.previousTxn=0\r\nresponse.end\r\n + ) + end + + def successful_void_response + %( + response.summaryCode=0\r\nresponse.responseCode=00\r\nresponse.text=Approved or completed successfully\r\nresponse.referenceNo=731560098\r\nresponse.orderNumber=67686b64b544335815002fd85704c8a1\r\nresponse.settlementDate=20170314\r\nresponse.cardSchemeName=VISA\r\nresponse.creditGroup=VI/BC/MC\r\nresponse.previousTxn=0\r\nresponse.end\r\n + ) + end + + def failed_void_response + %( + response.summaryCode=3\r\nresponse.responseCode=QA\r\nresponse.text=Invalid Parameters - customer.originalOrderNumber: Required field\r\nresponse.previousTxn=0\r\nresponse.end\r\n + ) + end + def successful_refund_response %( response.summaryCode=0\r\nresponse.responseCode=08\r\nresponse.text=Honour with identification\r\nresponse.referenceNo=723907127\r\nresponse.orderNumber=f1a65bfe-f95b-4e06-b800-6d3b3a771238\r\nresponse.RRN=723907127 \r\nresponse.settlementDate=20150228\r\nresponse.transactionDate=28-FEB-2015 09:37:20\r\nresponse.cardSchemeName=VISA\r\nresponse.creditGroup=VI/BC/MC\r\nresponse.previousTxn=0\r\nresponse.end\r\n @@ -123,6 +252,18 @@ def failed_refund_response ) end + def successful_credit_response + %( + response.summaryCode=0\r\nresponse.responseCode=08\r\nresponse.text=Honour with identification\r\nresponse.referenceNo=732344591\r\nresponse.orderNumber=f365d21f7f5a1a5fe0eb994f144858e2\r\nresponse.RRN=732344591 \r\nresponse.settlementDate=20170817\r\nresponse.transactionDate=17-AUG-2017 01:19:34\r\nresponse.cardSchemeName=VISA\r\nresponse.creditGroup=VI/BC/MC\r\nresponse.previousTxn=0\r\nresponse.traceCode=799500\r\nresponse.end\r\n + ) + end + + def failed_credit_response + %( + response.summaryCode=1\r\nresponse.responseCode=14\r\nresponse.text=Invalid card number (no such number)\r\nresponse.referenceNo=732344705\r\nresponse.orderNumber=3baab91d5642a34292375a8932cde85f\r\nresponse.settlementDate=20170817\r\nresponse.cardSchemeName=VISA\r\nresponse.creditGroup=VI/BC/MC\r\nresponse.previousTxn=0\r\nresponse.end\r\n + ) + end + def successful_store_response %( response.summaryCode=0\r\nresponse.responseCode=00\r\nresponse.text=Approved or completed successfully\r\nresponse.cardSchemeName=VISA\r\nresponse.creditGroup=VI/BC/MC\r\nresponse.accountAlias=400010...224\r\nresponse.preregistrationCode=RSL-20887450\r\nresponse.customerReferenceNumber=RSL-20887450\r\nresponse.previousTxn=0\r\nresponse.end\r\n diff --git a/test/unit/gateways/realex_test.rb b/test/unit/gateways/realex_test.rb index 69ced65ae8d..b0b5e92859b 100644 --- a/test/unit/gateways/realex_test.rb +++ b/test/unit/gateways/realex_test.rb @@ -3,7 +3,8 @@ class RealexTest < Test::Unit::TestCase class ActiveMerchant::Billing::RealexGateway # For the purposes of testing, lets redefine some protected methods as public. - public :build_purchase_or_authorization_request, :build_refund_request, :build_void_request, :build_capture_request + public :build_purchase_or_authorization_request, :build_refund_request, :build_void_request, + :build_capture_request, :build_verify_request end def setup @@ -95,11 +96,11 @@ def test_deprecated_credit end def test_supported_countries - assert_equal ['IE', 'GB', "FR", "BE", "NL", "LU", "IT"], RealexGateway.supported_countries + assert_equal ['IE', 'GB', 'FR', 'BE', 'NL', 'LU', 'IT', 'US', 'CA', 'ES'], RealexGateway.supported_countries end def test_supported_card_types - assert_equal [ :visa, :master, :american_express, :diners_club, :switch, :solo, :laser ], RealexGateway.supported_cardtypes + assert_equal [ :visa, :master, :american_express, :diners_club ], RealexGateway.supported_cardtypes end def test_avs_result_not_supported @@ -133,14 +134,15 @@ def test_capture_xml <request timestamp="20090824160201" type="settle"> <merchantid>your_merchant_id</merchantid> <account>your_account</account> + <amount>100</amount> <orderid>1</orderid> <pasref>4321</pasref> <authcode>1234</authcode> - <sha1hash>4132600f1dc70333b943fc292bd0ca7d8e722f6e</sha1hash> + <sha1hash>ef0a6c485452f3f94aff336fa90c6c62993056ca</sha1hash> </request> SRC - assert_xml_equal valid_capture_xml, @gateway.build_capture_request('1;4321;1234', {}) + assert_xml_equal valid_capture_xml, @gateway.build_capture_request(@amount, '1;4321;1234', {}) end def test_purchase_xml @@ -192,6 +194,35 @@ def test_void_xml assert_xml_equal valid_void_request_xml, @gateway.build_void_request('1;4321;1234', {}) end + def test_verify_xml + options = { + :order_id => '1' + } + @gateway.expects(:new_timestamp).returns('20181026114304') + + valid_verify_request_xml = <<-SRC +<request timestamp="20181026114304" type="otb"> + <merchantid>your_merchant_id</merchantid> + <account>your_account</account> + <orderid>1</orderid> + <card> + <number>4263971921001307</number> + <expdate>0808</expdate> + <chname>Longbob Longsen</chname> + <type>VISA</type> + <issueno></issueno> + <cvn> + <number></number> + <presind></presind> + </cvn> + </card> + <sha1hash>d53aebf1eaee4c3ff4c30f83f27b80ce99ba5644</sha1hash> +</request> +SRC + + assert_xml_equal valid_verify_request_xml, @gateway.build_verify_request(@credit_card, options) + end + def test_auth_xml options = { :order_id => '1' @@ -241,7 +272,6 @@ def test_refund_xml SRC assert_xml_equal valid_refund_request_xml, @gateway.build_refund_request(@amount, '1;4321;1234', {}) - end def test_refund_with_rebate_secret_xml @@ -264,7 +294,6 @@ def test_refund_with_rebate_secret_xml SRC assert_xml_equal valid_refund_request_xml, gateway.build_refund_request(@amount, '1;4321;1234', {}) - end def test_auth_with_address @@ -282,7 +311,6 @@ def test_auth_with_address assert_instance_of Response, response assert_success response assert response.test? - end def test_zip_in_shipping_address @@ -512,6 +540,6 @@ def assert_xml_equal_recursive(a, b) assert_equal a1.name, b1.name assert_equal a1.value, b1.value end - a.children.zip(b.children).all?{|a1, b1| assert_xml_equal_recursive(a1, b1)} + a.children.zip(b.children).all? { |a1, b1| assert_xml_equal_recursive(a1, b1) } end end diff --git a/test/unit/gateways/redsys_sha256_test.rb b/test/unit/gateways/redsys_sha256_test.rb index 67e093762ba..f1fbac3c70f 100644 --- a/test/unit/gateways/redsys_sha256_test.rb +++ b/test/unit/gateways/redsys_sha256_test.rb @@ -7,8 +7,8 @@ def setup Base.mode = :test @credentials = { :login => '091952713', - :secret_key => "QIK77hYl6UFcoCYFKcj+ZjJg8Q6I93Dx", - :signature_algorithm => "sha256" + :secret_key => 'QIK77hYl6UFcoCYFKcj+ZjJg8Q6I93Dx', + :signature_algorithm => 'sha256' } @gateway = RedsysGateway.new(@credentials) @credit_card = credit_card('4548812049400004') @@ -34,18 +34,18 @@ def test_successful_purchase @gateway.expects(:ssl_post).returns(successful_purchase_response) res = @gateway.purchase(100, credit_card, :order_id => '144742736014') assert_success res - assert_equal "Transaction Approved", res.message - assert_equal "144742736014|100|978", res.authorization + assert_equal 'Transaction Approved', res.message + assert_equal '144742736014|100|978', res.authorization assert_equal '144742736014', res.params['ds_order'] end # This one is being werid... def test_successful_purchase_requesting_credit_card_token @gateway.expects(:ssl_post).returns(successful_purchase_response_with_credit_card_token) - res = @gateway.purchase(100, "e55e1d0ef338e281baf1d0b5b68be433260ddea0", :order_id => '144742955848') + res = @gateway.purchase(100, 'e55e1d0ef338e281baf1d0b5b68be433260ddea0', :order_id => '144742955848') assert_success res - assert_equal "Transaction Approved", res.message - assert_equal "144742955848|100|978", res.authorization + assert_equal 'Transaction Approved', res.message + assert_equal '144742955848|100|978', res.authorization assert_equal '144742955848', res.params['ds_order'] assert_equal 'e55e1d0ef338e281baf1d0b5b68be433260ddea0', res.params['ds_merchant_identifier'] end @@ -54,7 +54,7 @@ def test_failed_purchase @gateway.expects(:ssl_post).returns(failed_purchase_response) res = @gateway.purchase(100, credit_card, :order_id => '144743314659') assert_failure res - assert_equal "SIS0093 ERROR", res.message + assert_equal 'SIS0093 ERROR', res.message end def test_purchase_without_order_id @@ -65,9 +65,9 @@ def test_purchase_without_order_id def test_error_purchase @gateway.expects(:ssl_post).returns(error_purchase_response) - res = @gateway.purchase(100, credit_card, :order_id => "123") + res = @gateway.purchase(100, credit_card, :order_id => '123') assert_failure res - assert_equal "SIS0051 ERROR", res.message + assert_equal 'SIS0051 ERROR', res.message end def test_refund_request @@ -77,18 +77,18 @@ def test_refund_request def test_successful_refund @gateway.expects(:ssl_post).returns(successful_refund_response) - res = @gateway.refund(100, "1001") + res = @gateway.refund(100, '1001') assert_success res - assert_equal "Refund / Confirmation approved", res.message - assert_equal "144743427234|100|978", res.authorization - assert_equal "144743427234", res.params['ds_order'] + assert_equal 'Refund / Confirmation approved', res.message + assert_equal '144743427234|100|978', res.authorization + assert_equal '144743427234', res.params['ds_order'] end def test_error_refund @gateway.expects(:ssl_post).returns(error_refund_response) - res = @gateway.refund(100, "1001") + res = @gateway.refund(100, '1001') assert_failure res - assert_equal "SIS0057 ERROR", res.message + assert_equal 'SIS0057 ERROR', res.message end # Remaining methods a pretty much the same, so we just test that @@ -98,13 +98,13 @@ def test_authorize @gateway.expects(:ssl_post).with( anything, all_of( - includes(CGI.escape("<DS_MERCHANT_TRANSACTIONTYPE>1</DS_MERCHANT_TRANSACTIONTYPE>")), - includes(CGI.escape("<DS_MERCHANT_PAN>4242424242424242</DS_MERCHANT_PAN>")), - includes(CGI.escape("<DS_MERCHANT_AMOUNT>100</DS_MERCHANT_AMOUNT>")) + includes(CGI.escape('<DS_MERCHANT_TRANSACTIONTYPE>1</DS_MERCHANT_TRANSACTIONTYPE>')), + includes(CGI.escape('<DS_MERCHANT_PAN>4242424242424242</DS_MERCHANT_PAN>')), + includes(CGI.escape('<DS_MERCHANT_AMOUNT>100</DS_MERCHANT_AMOUNT>')) ), anything ).returns(successful_authorize_response) - response = @gateway.authorize(100, credit_card, :order_id => "144743367273") + response = @gateway.authorize(100, credit_card, :order_id => '144743367273') assert_success response end @@ -116,7 +116,7 @@ def test_authorize_without_order_id def test_bad_order_id_format stub_comms(@gateway, :ssl_request) do - @gateway.authorize(100, credit_card, order_id: "Una#cce-ptable44Format") + @gateway.authorize(100, credit_card, order_id: 'Una#cce-ptable44Format') end.check_request do |method, endpoint, data, headers| assert_match(/MERCHANT_ORDER%3E\d\d\d\dUnaccept%3C/, data) end.respond_with(successful_authorize_response) @@ -124,7 +124,7 @@ def test_bad_order_id_format def test_order_id_numeric_start_but_too_long stub_comms(@gateway, :ssl_request) do - @gateway.authorize(100, credit_card, order_id: "1234ThisIs]FineButTooLong") + @gateway.authorize(100, credit_card, order_id: '1234ThisIs]FineButTooLong') end.check_request do |method, endpoint, data, headers| assert_match(/MERCHANT_ORDER%3E1234ThisIsFi%3C/, data) end.respond_with(successful_authorize_response) @@ -134,9 +134,9 @@ def test_capture @gateway.expects(:ssl_post).with( anything, all_of( - includes(CGI.escape("<DS_MERCHANT_TRANSACTIONTYPE>2</DS_MERCHANT_TRANSACTIONTYPE>")), - includes(CGI.escape("<DS_MERCHANT_ORDER>144743367273</DS_MERCHANT_ORDER>")), - includes(CGI.escape("<DS_MERCHANT_AMOUNT>100</DS_MERCHANT_AMOUNT>")) + includes(CGI.escape('<DS_MERCHANT_TRANSACTIONTYPE>2</DS_MERCHANT_TRANSACTIONTYPE>')), + includes(CGI.escape('<DS_MERCHANT_ORDER>144743367273</DS_MERCHANT_ORDER>')), + includes(CGI.escape('<DS_MERCHANT_AMOUNT>100</DS_MERCHANT_AMOUNT>')) ), anything ).returns(successful_capture_response) @@ -147,10 +147,10 @@ def test_void @gateway.expects(:ssl_post).with( anything, all_of( - includes(CGI.escape("<DS_MERCHANT_TRANSACTIONTYPE>9</DS_MERCHANT_TRANSACTIONTYPE>")), - includes(CGI.escape("<DS_MERCHANT_ORDER>144743389043</DS_MERCHANT_ORDER>")), - includes(CGI.escape("<DS_MERCHANT_AMOUNT>100</DS_MERCHANT_AMOUNT>")), - includes(CGI.escape("<DS_MERCHANT_CURRENCY>978</DS_MERCHANT_CURRENCY>")) + includes(CGI.escape('<DS_MERCHANT_TRANSACTIONTYPE>9</DS_MERCHANT_TRANSACTIONTYPE>')), + includes(CGI.escape('<DS_MERCHANT_ORDER>144743389043</DS_MERCHANT_ORDER>')), + includes(CGI.escape('<DS_MERCHANT_AMOUNT>100</DS_MERCHANT_AMOUNT>')), + includes(CGI.escape('<DS_MERCHANT_CURRENCY>978</DS_MERCHANT_CURRENCY>')) ), anything ).returns(successful_void_response) @@ -160,7 +160,7 @@ def test_void def test_override_currency @gateway.expects(:ssl_post).with( anything, - includes(CGI.escape("<DS_MERCHANT_CURRENCY>840</DS_MERCHANT_CURRENCY>")), + includes(CGI.escape('<DS_MERCHANT_CURRENCY>840</DS_MERCHANT_CURRENCY>')), anything ).returns(successful_purchase_response) @gateway.authorize(100, credit_card, :order_id => '1001', :currency => 'USD') @@ -176,19 +176,19 @@ def test_successful_verify_with_failed_void @gateway.expects(:ssl_post).times(2).returns(successful_authorize_response).then.returns(failed_void_response) response = @gateway.verify(credit_card, :order_id => '144743367273') assert_success response - assert_equal "Transaction Approved", response.message + assert_equal 'Transaction Approved', response.message end def test_unsuccessful_verify @gateway.expects(:ssl_post).returns(failed_authorize_response) - response = @gateway.verify(credit_card, :order_id => "141278225678") + response = @gateway.verify(credit_card, :order_id => '141278225678') assert_failure response - assert_equal "SIS0093 ERROR", response.message + assert_equal 'SIS0093 ERROR', response.message end def test_unknown_currency assert_raise ArgumentError do - @gateway.purchase(100, credit_card, @options.merge(currency: "HUH WUT")) + @gateway.purchase(100, credit_card, @options.merge(currency: 'HUH WUT')) end end @@ -262,11 +262,11 @@ def generate_order_id # one with card and another without. def purchase_request - "entrada=%3C%3Fxml+version%3D%221.0%22+encoding%3D%22UTF-8%22%3F%3E%3CREQUEST%3E%3CDATOSENTRADA%3E%3CDS_Version%3E0.1%3C%2FDS_Version%3E%3CDS_MERCHANT_CURRENCY%3E978%3C%2FDS_MERCHANT_CURRENCY%3E%3CDS_MERCHANT_AMOUNT%3E100%3C%2FDS_MERCHANT_AMOUNT%3E%3CDS_MERCHANT_ORDER%3E144742736014%3C%2FDS_MERCHANT_ORDER%3E%3CDS_MERCHANT_TRANSACTIONTYPE%3EA%3C%2FDS_MERCHANT_TRANSACTIONTYPE%3E%3CDS_MERCHANT_PRODUCTDESCRIPTION%2F%3E%3CDS_MERCHANT_TERMINAL%3E1%3C%2FDS_MERCHANT_TERMINAL%3E%3CDS_MERCHANT_MERCHANTCODE%3E091952713%3C%2FDS_MERCHANT_MERCHANTCODE%3E%3CDS_MERCHANT_TITULAR%3ELongbob+Longsen%3C%2FDS_MERCHANT_TITULAR%3E%3CDS_MERCHANT_PAN%3E4548812049400004%3C%2FDS_MERCHANT_PAN%3E%3CDS_MERCHANT_EXPIRYDATE%3E1709%3C%2FDS_MERCHANT_EXPIRYDATE%3E%3CDS_MERCHANT_CVV2%3E123%3C%2FDS_MERCHANT_CVV2%3E%3C%2FDATOSENTRADA%3E%3CDS_SIGNATUREVERSION%3EHMAC_SHA256_V1%3C%2FDS_SIGNATUREVERSION%3E%3CDS_SIGNATURE%3Eq9QH2P%2B4qm8w%2FS85KRPVaepWOrOT2RXlEmyPUce5XRM%3D%3C%2FDS_SIGNATURE%3E%3C%2FREQUEST%3E" + 'entrada=%3C%3Fxml+version%3D%221.0%22+encoding%3D%22UTF-8%22%3F%3E%3CREQUEST%3E%3CDATOSENTRADA%3E%3CDS_Version%3E0.1%3C%2FDS_Version%3E%3CDS_MERCHANT_CURRENCY%3E978%3C%2FDS_MERCHANT_CURRENCY%3E%3CDS_MERCHANT_AMOUNT%3E100%3C%2FDS_MERCHANT_AMOUNT%3E%3CDS_MERCHANT_ORDER%3E144742736014%3C%2FDS_MERCHANT_ORDER%3E%3CDS_MERCHANT_TRANSACTIONTYPE%3EA%3C%2FDS_MERCHANT_TRANSACTIONTYPE%3E%3CDS_MERCHANT_PRODUCTDESCRIPTION%2F%3E%3CDS_MERCHANT_TERMINAL%3E1%3C%2FDS_MERCHANT_TERMINAL%3E%3CDS_MERCHANT_MERCHANTCODE%3E091952713%3C%2FDS_MERCHANT_MERCHANTCODE%3E%3CDS_MERCHANT_TITULAR%3ELongbob+Longsen%3C%2FDS_MERCHANT_TITULAR%3E%3CDS_MERCHANT_PAN%3E4548812049400004%3C%2FDS_MERCHANT_PAN%3E%3CDS_MERCHANT_EXPIRYDATE%3E1709%3C%2FDS_MERCHANT_EXPIRYDATE%3E%3CDS_MERCHANT_CVV2%3E123%3C%2FDS_MERCHANT_CVV2%3E%3C%2FDATOSENTRADA%3E%3CDS_SIGNATUREVERSION%3EHMAC_SHA256_V1%3C%2FDS_SIGNATUREVERSION%3E%3CDS_SIGNATURE%3Eq9QH2P%2B4qm8w%2FS85KRPVaepWOrOT2RXlEmyPUce5XRM%3D%3C%2FDS_SIGNATURE%3E%3C%2FREQUEST%3E' end def purchase_request_with_credit_card_token - "entrada=%3C%3Fxml+version%3D%221.0%22+encoding%3D%22UTF-8%22%3F%3E%3CREQUEST%3E%3CDATOSENTRADA%3E%3CDS_Version%3E0.1%3C%2FDS_Version%3E%3CDS_MERCHANT_CURRENCY%3E978%3C%2FDS_MERCHANT_CURRENCY%3E%3CDS_MERCHANT_AMOUNT%3E100%3C%2FDS_MERCHANT_AMOUNT%3E%3CDS_MERCHANT_ORDER%3E144742884282%3C%2FDS_MERCHANT_ORDER%3E%3CDS_MERCHANT_TRANSACTIONTYPE%3EA%3C%2FDS_MERCHANT_TRANSACTIONTYPE%3E%3CDS_MERCHANT_PRODUCTDESCRIPTION%2F%3E%3CDS_MERCHANT_TERMINAL%3E1%3C%2FDS_MERCHANT_TERMINAL%3E%3CDS_MERCHANT_MERCHANTCODE%3E091952713%3C%2FDS_MERCHANT_MERCHANTCODE%3E%3CDS_MERCHANT_IDENTIFIER%3E3126bb8b80a79e66eb1ecc39e305288b60075f86%3C%2FDS_MERCHANT_IDENTIFIER%3E%3C%2FDATOSENTRADA%3E%3CDS_SIGNATUREVERSION%3EHMAC_SHA256_V1%3C%2FDS_SIGNATUREVERSION%3E%3CDS_SIGNATURE%3EFFiY%2B5BTlw1zGwSHySBKWJw4DN7SbgVNSgWMTX8sll0%3D%3C%2FDS_SIGNATURE%3E%3C%2FREQUEST%3E" + 'entrada=%3C%3Fxml+version%3D%221.0%22+encoding%3D%22UTF-8%22%3F%3E%3CREQUEST%3E%3CDATOSENTRADA%3E%3CDS_Version%3E0.1%3C%2FDS_Version%3E%3CDS_MERCHANT_CURRENCY%3E978%3C%2FDS_MERCHANT_CURRENCY%3E%3CDS_MERCHANT_AMOUNT%3E100%3C%2FDS_MERCHANT_AMOUNT%3E%3CDS_MERCHANT_ORDER%3E144742884282%3C%2FDS_MERCHANT_ORDER%3E%3CDS_MERCHANT_TRANSACTIONTYPE%3EA%3C%2FDS_MERCHANT_TRANSACTIONTYPE%3E%3CDS_MERCHANT_PRODUCTDESCRIPTION%2F%3E%3CDS_MERCHANT_TERMINAL%3E1%3C%2FDS_MERCHANT_TERMINAL%3E%3CDS_MERCHANT_MERCHANTCODE%3E091952713%3C%2FDS_MERCHANT_MERCHANTCODE%3E%3CDS_MERCHANT_IDENTIFIER%3E3126bb8b80a79e66eb1ecc39e305288b60075f86%3C%2FDS_MERCHANT_IDENTIFIER%3E%3CDS_MERCHANT_DIRECTPAYMENT%3Etrue%3C%2FDS_MERCHANT_DIRECTPAYMENT%3E%3C%2FDATOSENTRADA%3E%3CDS_SIGNATUREVERSION%3EHMAC_SHA256_V1%3C%2FDS_SIGNATUREVERSION%3E%3CDS_SIGNATURE%3EN0tYMrHGf1PmmJ7WIiRONdqbIGmyhaV%2BhP4acTyfJYE%3D%3C%2FDS_SIGNATURE%3E%3C%2FREQUEST%3E' end def successful_purchase_response @@ -294,7 +294,7 @@ def failed_authorize_response end def refund_request - "entrada=%3C%3Fxml+version%3D%221.0%22+encoding%3D%22UTF-8%22%3F%3E%3CREQUEST%3E%3CDATOSENTRADA%3E%3CDS_Version%3E0.1%3C%2FDS_Version%3E%3CDS_MERCHANT_CURRENCY%3E978%3C%2FDS_MERCHANT_CURRENCY%3E%3CDS_MERCHANT_AMOUNT%3E100%3C%2FDS_MERCHANT_AMOUNT%3E%3CDS_MERCHANT_ORDER%3E144743427234%3C%2FDS_MERCHANT_ORDER%3E%3CDS_MERCHANT_TRANSACTIONTYPE%3E3%3C%2FDS_MERCHANT_TRANSACTIONTYPE%3E%3CDS_MERCHANT_PRODUCTDESCRIPTION%2F%3E%3CDS_MERCHANT_TERMINAL%3E1%3C%2FDS_MERCHANT_TERMINAL%3E%3CDS_MERCHANT_MERCHANTCODE%3E091952713%3C%2FDS_MERCHANT_MERCHANTCODE%3E%3C%2FDATOSENTRADA%3E%3CDS_SIGNATUREVERSION%3EHMAC_SHA256_V1%3C%2FDS_SIGNATUREVERSION%3E%3CDS_SIGNATURE%3EQhNVtjoee6s%2Bvo%2B5bJVM4esT58bz7zkY1Xe7qjdmxA0%3D%3C%2FDS_SIGNATURE%3E%3C%2FREQUEST%3E" + 'entrada=%3C%3Fxml+version%3D%221.0%22+encoding%3D%22UTF-8%22%3F%3E%3CREQUEST%3E%3CDATOSENTRADA%3E%3CDS_Version%3E0.1%3C%2FDS_Version%3E%3CDS_MERCHANT_CURRENCY%3E978%3C%2FDS_MERCHANT_CURRENCY%3E%3CDS_MERCHANT_AMOUNT%3E100%3C%2FDS_MERCHANT_AMOUNT%3E%3CDS_MERCHANT_ORDER%3E144743427234%3C%2FDS_MERCHANT_ORDER%3E%3CDS_MERCHANT_TRANSACTIONTYPE%3E3%3C%2FDS_MERCHANT_TRANSACTIONTYPE%3E%3CDS_MERCHANT_PRODUCTDESCRIPTION%2F%3E%3CDS_MERCHANT_TERMINAL%3E1%3C%2FDS_MERCHANT_TERMINAL%3E%3CDS_MERCHANT_MERCHANTCODE%3E091952713%3C%2FDS_MERCHANT_MERCHANTCODE%3E%3C%2FDATOSENTRADA%3E%3CDS_SIGNATUREVERSION%3EHMAC_SHA256_V1%3C%2FDS_SIGNATUREVERSION%3E%3CDS_SIGNATURE%3EQhNVtjoee6s%2Bvo%2B5bJVM4esT58bz7zkY1Xe7qjdmxA0%3D%3C%2FDS_SIGNATURE%3E%3C%2FREQUEST%3E' end def successful_refund_response diff --git a/test/unit/gateways/redsys_test.rb b/test/unit/gateways/redsys_test.rb index c955ad3b67a..741b5ae9eed 100644 --- a/test/unit/gateways/redsys_test.rb +++ b/test/unit/gateways/redsys_test.rb @@ -7,7 +7,7 @@ def setup Base.mode = :test @credentials = { :login => '091952713', - :secret_key => "qwertyasdf0123456789", + :secret_key => 'qwertyasdf0123456789', :terminal => '1', } @gateway = RedsysGateway.new(@credentials) @@ -32,8 +32,8 @@ def test_successful_purchase @gateway.expects(:ssl_post).returns(successful_purchase_response) res = @gateway.purchase(123, credit_card, @options) assert_success res - assert_equal "Transaction Approved", res.message - assert_equal "1001|123|978", res.authorization + assert_equal 'Transaction Approved', res.message + assert_equal '1001|123|978', res.authorization assert_equal '1001', res.params['ds_order'] end @@ -41,8 +41,8 @@ def test_successful_purchase_requesting_credit_card_token @gateway.expects(:ssl_post).returns(successful_purchase_response_with_credit_card_token) res = @gateway.purchase(123, credit_card, @options) assert_success res - assert_equal "Transaction Approved", res.message - assert_equal "141661632759|100|978", res.authorization + assert_equal 'Transaction Approved', res.message + assert_equal '141661632759|100|978', res.authorization assert_equal '141661632759', res.params['ds_order'] assert_equal '77bff3a969d6f97b2ec815448cdcff453971f573', res.params['ds_merchant_identifier'] end @@ -51,7 +51,7 @@ def test_failed_purchase @gateway.expects(:ssl_post).returns(failed_purchase_response) res = @gateway.purchase(123, credit_card, @options) assert_failure res - assert_equal "Refusal with no specific reason", res.message + assert_equal 'Refusal with no specific reason', res.message assert_equal '1002', res.params['ds_order'] end @@ -65,7 +65,7 @@ def test_error_purchase @gateway.expects(:ssl_post).returns(error_purchase_response) res = @gateway.purchase(123, credit_card, @options) assert_failure res - assert_equal "SIS0051 ERROR", res.message + assert_equal 'SIS0051 ERROR', res.message end def test_refund_request @@ -75,18 +75,18 @@ def test_refund_request def test_successful_refund @gateway.expects(:ssl_post).returns(successful_refund_response) - res = @gateway.refund(123, "1001") + res = @gateway.refund(123, '1001') assert_success res - assert_equal "Refund / Confirmation approved", res.message - assert_equal "1001|123|978", res.authorization - assert_equal "1001", res.params['ds_order'] + assert_equal 'Refund / Confirmation approved', res.message + assert_equal '1001|123|978', res.authorization + assert_equal '1001', res.params['ds_order'] end def test_error_refund @gateway.expects(:ssl_post).returns(error_refund_response) - res = @gateway.refund(123, "1001") + res = @gateway.refund(123, '1001') assert_failure res - assert_equal "SIS0057 ERROR", res.message + assert_equal 'SIS0057 ERROR', res.message end # Remaining methods a pretty much the same, so we just test that @@ -96,9 +96,9 @@ def test_authorize @gateway.expects(:ssl_post).with( anything, all_of( - includes(CGI.escape("<DS_MERCHANT_TRANSACTIONTYPE>1</DS_MERCHANT_TRANSACTIONTYPE>")), - includes(CGI.escape("<DS_MERCHANT_PAN>4242424242424242</DS_MERCHANT_PAN>")), - includes(CGI.escape("<DS_MERCHANT_AMOUNT>123</DS_MERCHANT_AMOUNT>")) + includes(CGI.escape('<DS_MERCHANT_TRANSACTIONTYPE>1</DS_MERCHANT_TRANSACTIONTYPE>')), + includes(CGI.escape('<DS_MERCHANT_PAN>4242424242424242</DS_MERCHANT_PAN>')), + includes(CGI.escape('<DS_MERCHANT_AMOUNT>123</DS_MERCHANT_AMOUNT>')) ), anything ).returns(successful_authorize_response) @@ -114,7 +114,7 @@ def test_authorize_without_order_id def test_bad_order_id_format stub_comms(@gateway, :ssl_request) do - @gateway.authorize(123, credit_card, order_id: "Una#cce-ptable44Format") + @gateway.authorize(123, credit_card, order_id: 'Una#cce-ptable44Format') end.check_request do |method, endpoint, data, headers| assert_match(/MERCHANT_ORDER%3E\d\d\d\dUnaccept%3C/, data) end.respond_with(successful_authorize_response) @@ -122,7 +122,7 @@ def test_bad_order_id_format def test_order_id_numeric_start_but_too_long stub_comms(@gateway, :ssl_request) do - @gateway.authorize(123, credit_card, order_id: "1234ThisIs]FineButTooLong") + @gateway.authorize(123, credit_card, order_id: '1234ThisIs]FineButTooLong') end.check_request do |method, endpoint, data, headers| assert_match(/MERCHANT_ORDER%3E1234ThisIsFi%3C/, data) end.respond_with(successful_authorize_response) @@ -132,9 +132,9 @@ def test_capture @gateway.expects(:ssl_post).with( anything, all_of( - includes(CGI.escape("<DS_MERCHANT_TRANSACTIONTYPE>2</DS_MERCHANT_TRANSACTIONTYPE>")), - includes(CGI.escape("<DS_MERCHANT_ORDER>1001</DS_MERCHANT_ORDER>")), - includes(CGI.escape("<DS_MERCHANT_AMOUNT>123</DS_MERCHANT_AMOUNT>")) + includes(CGI.escape('<DS_MERCHANT_TRANSACTIONTYPE>2</DS_MERCHANT_TRANSACTIONTYPE>')), + includes(CGI.escape('<DS_MERCHANT_ORDER>1001</DS_MERCHANT_ORDER>')), + includes(CGI.escape('<DS_MERCHANT_AMOUNT>123</DS_MERCHANT_AMOUNT>')) ), anything ).returns(successful_capture_response) @@ -145,10 +145,10 @@ def test_void @gateway.expects(:ssl_post).with( anything, all_of( - includes(CGI.escape("<DS_MERCHANT_TRANSACTIONTYPE>9</DS_MERCHANT_TRANSACTIONTYPE>")), - includes(CGI.escape("<DS_MERCHANT_ORDER>1001</DS_MERCHANT_ORDER>")), - includes(CGI.escape("<DS_MERCHANT_AMOUNT>123</DS_MERCHANT_AMOUNT>")), - includes(CGI.escape("<DS_MERCHANT_CURRENCY>978</DS_MERCHANT_CURRENCY>")) + includes(CGI.escape('<DS_MERCHANT_TRANSACTIONTYPE>9</DS_MERCHANT_TRANSACTIONTYPE>')), + includes(CGI.escape('<DS_MERCHANT_ORDER>1001</DS_MERCHANT_ORDER>')), + includes(CGI.escape('<DS_MERCHANT_AMOUNT>123</DS_MERCHANT_AMOUNT>')), + includes(CGI.escape('<DS_MERCHANT_CURRENCY>978</DS_MERCHANT_CURRENCY>')) ), anything ).returns(successful_void_response) @@ -158,7 +158,7 @@ def test_void def test_override_currency @gateway.expects(:ssl_post).with( anything, - includes(CGI.escape("<DS_MERCHANT_CURRENCY>840</DS_MERCHANT_CURRENCY>")), + includes(CGI.escape('<DS_MERCHANT_CURRENCY>840</DS_MERCHANT_CURRENCY>')), anything ).returns(successful_purchase_response) @gateway.authorize(123, credit_card, :order_id => '1001', :currency => 'USD') @@ -174,19 +174,19 @@ def test_successful_verify_with_failed_void @gateway.expects(:ssl_post).times(2).returns(successful_authorize_response).then.returns(failed_void_response) response = @gateway.verify(credit_card, @options) assert_success response - assert_equal "Transaction Approved", response.message + assert_equal 'Transaction Approved', response.message end def test_unsuccessful_verify @gateway.expects(:ssl_post).returns(failed_authorize_response) response = @gateway.verify(credit_card, @options) assert_failure response - assert_equal "SIS0093 ERROR", response.message + assert_equal 'SIS0093 ERROR', response.message end def test_unknown_currency assert_raise ArgumentError do - @gateway.purchase(123, credit_card, @options.merge(currency: "HUH WUT")) + @gateway.purchase(123, credit_card, @options.merge(currency: 'HUH WUT')) end end @@ -256,11 +256,11 @@ def test_whitespace_string_cvv_transcript_scrubbing # one with card and another without. def purchase_request - "entrada=%3CDATOSENTRADA%3E%0A++%3CDS_Version%3E0.1%3C%2FDS_Version%3E%0A++%3CDS_MERCHANT_CURRENCY%3E978%3C%2FDS_MERCHANT_CURRENCY%3E%0A++%3CDS_MERCHANT_AMOUNT%3E123%3C%2FDS_MERCHANT_AMOUNT%3E%0A++%3CDS_MERCHANT_ORDER%3E1001%3C%2FDS_MERCHANT_ORDER%3E%0A++%3CDS_MERCHANT_TRANSACTIONTYPE%3EA%3C%2FDS_MERCHANT_TRANSACTIONTYPE%3E%0A++%3CDS_MERCHANT_PRODUCTDESCRIPTION%2F%3E%0A++%3CDS_MERCHANT_TERMINAL%3E1%3C%2FDS_MERCHANT_TERMINAL%3E%0A++%3CDS_MERCHANT_MERCHANTCODE%3E091952713%3C%2FDS_MERCHANT_MERCHANTCODE%3E%0A++%3CDS_MERCHANT_MERCHANTSIGNATURE%3Eb98b606a6a588d8c45c239f244160efbbe30b4a8%3C%2FDS_MERCHANT_MERCHANTSIGNATURE%3E%0A++%3CDS_MERCHANT_TITULAR%3ELongbob+Longsen%3C%2FDS_MERCHANT_TITULAR%3E%0A++%3CDS_MERCHANT_PAN%3E4242424242424242%3C%2FDS_MERCHANT_PAN%3E%0A++%3CDS_MERCHANT_EXPIRYDATE%3E#{(Time.now.year + 1).to_s.slice(2,2)}09%3C%2FDS_MERCHANT_EXPIRYDATE%3E%0A++%3CDS_MERCHANT_CVV2%3E123%3C%2FDS_MERCHANT_CVV2%3E%0A%3C%2FDATOSENTRADA%3E%0A" + "entrada=%3CDATOSENTRADA%3E%0A++%3CDS_Version%3E0.1%3C%2FDS_Version%3E%0A++%3CDS_MERCHANT_CURRENCY%3E978%3C%2FDS_MERCHANT_CURRENCY%3E%0A++%3CDS_MERCHANT_AMOUNT%3E123%3C%2FDS_MERCHANT_AMOUNT%3E%0A++%3CDS_MERCHANT_ORDER%3E1001%3C%2FDS_MERCHANT_ORDER%3E%0A++%3CDS_MERCHANT_TRANSACTIONTYPE%3EA%3C%2FDS_MERCHANT_TRANSACTIONTYPE%3E%0A++%3CDS_MERCHANT_PRODUCTDESCRIPTION%2F%3E%0A++%3CDS_MERCHANT_TERMINAL%3E1%3C%2FDS_MERCHANT_TERMINAL%3E%0A++%3CDS_MERCHANT_MERCHANTCODE%3E091952713%3C%2FDS_MERCHANT_MERCHANTCODE%3E%0A++%3CDS_MERCHANT_MERCHANTSIGNATURE%3Eb98b606a6a588d8c45c239f244160efbbe30b4a8%3C%2FDS_MERCHANT_MERCHANTSIGNATURE%3E%0A++%3CDS_MERCHANT_TITULAR%3ELongbob+Longsen%3C%2FDS_MERCHANT_TITULAR%3E%0A++%3CDS_MERCHANT_PAN%3E4242424242424242%3C%2FDS_MERCHANT_PAN%3E%0A++%3CDS_MERCHANT_EXPIRYDATE%3E#{(Time.now.year + 1).to_s.slice(2, 2)}09%3C%2FDS_MERCHANT_EXPIRYDATE%3E%0A++%3CDS_MERCHANT_CVV2%3E123%3C%2FDS_MERCHANT_CVV2%3E%0A%3C%2FDATOSENTRADA%3E%0A" end def purchase_request_with_credit_card_token - "entrada=%3CDATOSENTRADA%3E%0A++%3CDS_Version%3E0.1%3C%2FDS_Version%3E%0A++%3CDS_MERCHANT_CURRENCY%3E978%3C%2FDS_MERCHANT_CURRENCY%3E%0A++%3CDS_MERCHANT_AMOUNT%3E123%3C%2FDS_MERCHANT_AMOUNT%3E%0A++%3CDS_MERCHANT_ORDER%3E1001%3C%2FDS_MERCHANT_ORDER%3E%0A++%3CDS_MERCHANT_TRANSACTIONTYPE%3EA%3C%2FDS_MERCHANT_TRANSACTIONTYPE%3E%0A++%3CDS_MERCHANT_PRODUCTDESCRIPTION%2F%3E%0A++%3CDS_MERCHANT_TERMINAL%3E1%3C%2FDS_MERCHANT_TERMINAL%3E%0A++%3CDS_MERCHANT_MERCHANTCODE%3E091952713%3C%2FDS_MERCHANT_MERCHANTCODE%3E%0A++%3CDS_MERCHANT_MERCHANTSIGNATURE%3Ecbcc0dee5724cd3fff08bbd4371946a0599c7fb9%3C%2FDS_MERCHANT_MERCHANTSIGNATURE%3E%0A++%3CDS_MERCHANT_IDENTIFIER%3E77bff3a969d6f97b2ec815448cdcff453971f573%3C%2FDS_MERCHANT_IDENTIFIER%3E%0A%3C%2FDATOSENTRADA%3E%0A" + 'entrada=%3CDATOSENTRADA%3E%0A++%3CDS_Version%3E0.1%3C%2FDS_Version%3E%0A++%3CDS_MERCHANT_CURRENCY%3E978%3C%2FDS_MERCHANT_CURRENCY%3E%0A++%3CDS_MERCHANT_AMOUNT%3E123%3C%2FDS_MERCHANT_AMOUNT%3E%0A++%3CDS_MERCHANT_ORDER%3E1001%3C%2FDS_MERCHANT_ORDER%3E%0A++%3CDS_MERCHANT_TRANSACTIONTYPE%3EA%3C%2FDS_MERCHANT_TRANSACTIONTYPE%3E%0A++%3CDS_MERCHANT_PRODUCTDESCRIPTION%2F%3E%0A++%3CDS_MERCHANT_TERMINAL%3E1%3C%2FDS_MERCHANT_TERMINAL%3E%0A++%3CDS_MERCHANT_MERCHANTCODE%3E091952713%3C%2FDS_MERCHANT_MERCHANTCODE%3E%0A++%3CDS_MERCHANT_MERCHANTSIGNATURE%3Ecbcc0dee5724cd3fff08bbd4371946a0599c7fb9%3C%2FDS_MERCHANT_MERCHANTSIGNATURE%3E%0A++%3CDS_MERCHANT_IDENTIFIER%3E77bff3a969d6f97b2ec815448cdcff453971f573%3C%2FDS_MERCHANT_IDENTIFIER%3E%0A++%3CDS_MERCHANT_DIRECTPAYMENT%3Etrue%3C%2FDS_MERCHANT_DIRECTPAYMENT%3E%0A%3C%2FDATOSENTRADA%3E%0A' end def successful_purchase_response diff --git a/test/unit/gateways/safe_charge_test.rb b/test/unit/gateways/safe_charge_test.rb new file mode 100644 index 00000000000..94d310907c6 --- /dev/null +++ b/test/unit/gateways/safe_charge_test.rb @@ -0,0 +1,363 @@ +require 'test_helper' + +class SafeChargeTest < Test::Unit::TestCase + include CommStub + + def setup + @gateway = SafeChargeGateway.new(client_login_id: 'login', client_password: 'password') + @credit_card = credit_card + @three_ds_enrolled_card = credit_card('4012 0010 3749 0014') + @amount = 100 + + @options = { + order_id: '1', + billing_address: address, + description: 'Store Purchase' + } + @merchant_options = @options.merge( + merchant_descriptor: 'Test Descriptor', + merchant_phone_number: '(555)555-5555', + merchant_name: 'Test Merchant' + ) + @three_ds_options = @options.merge(three_d_secure: true) + end + + def test_successful_purchase + @gateway.expects(:ssl_post).returns(successful_purchase_response) + + response = @gateway.purchase(@amount, @credit_card, @options) + assert_success response + + assert_equal '111951|101508189567|ZQBpAFAASABGAHAAVgBPAFUAMABiADMAewBtAGsAd' \ + 'AAvAFIAQQBrAGoAYwBxACoAXABHAEEAOgA3ACsAMgA4AD0AOABDAG4AbQAzAF' \ + 'UAbQBYAFIAMwA=|%02d|%d|1.00|USD' % [@credit_card.month, @credit_card.year.to_s[-2..-1]], response.authorization + assert response.test? + end + + def test_successful_purchase_with_merchant_options + purchase = stub_comms do + @gateway.purchase(@amount, @credit_card, @merchant_options) + end.check_request do |endpoint, data, headers| + assert_match(/sg_Descriptor/, data) + assert_match(/sg_MerchantPhoneNumber/, data) + assert_match(/sg_MerchantName/, data) + end.respond_with(successful_purchase_response) + + assert_success purchase + assert_equal '111951|101508189567|ZQBpAFAASABGAHAAVgBPAFUAMABiADMAewBtAGsAd' \ + 'AAvAFIAQQBrAGoAYwBxACoAXABHAEEAOgA3ACsAMgA4AD0AOABDAG4AbQAzAF' \ + 'UAbQBYAFIAMwA=|%02d|%d|1.00|USD' % [@credit_card.month, @credit_card.year.to_s[-2..-1]], purchase.authorization + assert purchase.test? + end + + def test_successful_purchase_with_truthy_stored_credential_mode + purchase = stub_comms do + @gateway.purchase(@amount, @credit_card, @options.merge(stored_credential_mode: true)) + end.check_request do |endpoint, data, headers| + assert_match(/sg_StoredCredentialMode=1/, data) + end.respond_with(successful_purchase_response) + + assert_success purchase + assert_equal '111951|101508189567|ZQBpAFAASABGAHAAVgBPAFUAMABiADMAewBtAGsAd' \ + 'AAvAFIAQQBrAGoAYwBxACoAXABHAEEAOgA3ACsAMgA4AD0AOABDAG4AbQAzAF' \ + 'UAbQBYAFIAMwA=|%02d|%d|1.00|USD' % [@credit_card.month, @credit_card.year.to_s[-2..-1]], purchase.authorization + assert purchase.test? + end + + def test_successful_purchase_with_falsey_stored_credential_mode + purchase = stub_comms do + @gateway.purchase(@amount, @credit_card, @options.merge(stored_credential_mode: false)) + end.check_request do |endpoint, data, headers| + assert_match(/sg_StoredCredentialMode=0/, data) + end.respond_with(successful_purchase_response) + + assert_success purchase + assert_equal '111951|101508189567|ZQBpAFAASABGAHAAVgBPAFUAMABiADMAewBtAGsAd' \ + 'AAvAFIAQQBrAGoAYwBxACoAXABHAEEAOgA3ACsAMgA4AD0AOABDAG4AbQAzAF' \ + 'UAbQBYAFIAMwA=|%02d|%d|1.00|USD' % [@credit_card.month, @credit_card.year.to_s[-2..-1]], purchase.authorization + assert purchase.test? + end + + def test_failed_purchase + @gateway.expects(:ssl_post).returns(failed_purchase_response) + + response = @gateway.purchase(@amount, @credit_card, @options) + assert_failure response + assert_equal '0', response.error_code + end + + def test_successful_authorize + @gateway.expects(:ssl_post).returns(successful_authorize_response) + + response = @gateway.authorize(@amount, @credit_card, @options) + assert_success response + + assert_equal '111534|101508189855|MQBVAG4ASABkAEgAagB3AEsAbgAtACoAWgAzAFwAW' \ + 'wBNAF8ATQBUAD0AegBQAGwAQAAtAD0AXAB5AFkALwBtAFAALABaAHoAOgBFAE' \ + 'wAUAA1AFUAMwA=|%02d|%d|1.00|USD' % [@credit_card.month, @credit_card.year.to_s[-2..-1]], response.authorization + assert response.test? + end + + def test_failed_authorize + @gateway.expects(:ssl_post).returns(failed_authorize_response) + + response = @gateway.authorize(@amount, @credit_card, @options) + assert_failure response + assert_equal '0', response.error_code + end + + def test_successful_capture + @gateway.expects(:ssl_post).returns(successful_capture_response) + + response = @gateway.capture(@amount, 'auth|transaction_id|token|month|year|amount|currency') + assert_success response + + assert_equal '111301|101508190200|RwA1AGQAMgAwAEkAWABKADkAcABjAHYAQQA4AC8AZ' \ + 'AAlAHMAfABoADEALAA8ADQAewB8ADsAewBiADsANQBoACwAeAA/AGQAXQAjAF' \ + 'EAYgBVAHIAMwA=|month|year|1.00|currency', response.authorization + assert response.test? + end + + def test_failed_capture + @gateway.expects(:ssl_post).returns(failed_capture_response) + + response = @gateway.capture(@amount, '', @options) + assert_failure response + assert_equal '1163', response.error_code + end + + def test_successful_refund + @gateway.expects(:ssl_post).returns(successful_refund_response) + + response = @gateway.refund(@amount, 'authorization', @options) + assert_success response + assert_equal 'Success', response.message + end + + def test_failed_refund + @gateway.expects(:ssl_post).returns(failed_refund_response) + + response = @gateway.refund(@amount, '', @options) + assert_failure response + assert_equal '1163', response.error_code + end + + def test_successful_credit + @gateway.expects(:ssl_post).returns(successful_credit_response) + + response = @gateway.credit(@amount, @credit_card, @options) + assert_success response + assert_equal 'Success', response.message + end + + def test_failed_credit + @gateway.expects(:ssl_post).returns(failed_credit_response) + + response = @gateway.credit(@amount, @credit_card, @options) + assert_failure response + assert_equal 'Decline', response.message + end + + def test_successful_void + @gateway.expects(:ssl_post).returns(successful_void_response) + + response = @gateway.void('auth|transaction_id|token|month|year|amount|currency') + assert_success response + + assert_equal '111171|101508208625|ZQBpAFAAZgBuAHEATgBUAHcASAAwADUAcwBHAHQAV' \ + 'QBLAHAAbgB6AGwAJAA1AEMAfAB2AGYASwBrAHEAeQBOAEwAOwBZAGIAewB4AG' \ + 'wAYwBUAE0AMwA=|month|year|0.00|currency', response.authorization + assert response.test? + end + + def test_failed_void + @gateway.expects(:ssl_post).returns(failed_void_response) + + response = @gateway.void('') + assert_failure response + assert_equal 'Invalid Amount', response.message + assert response.test? + end + + def test_successful_verify + @gateway.expects(:ssl_post).times(2).returns(successful_authorize_response, successful_void_response) + + response = @gateway.verify(@credit_card, @options) + assert_success response + + assert_equal '111534|101508189855|MQBVAG4ASABkAEgAagB3AEsAbgAtACoAWgAzAFwAW' \ + 'wBNAF8ATQBUAD0AegBQAGwAQAAtAD0AXAB5AFkALwBtAFAALABaAHoAOgBFAE' \ + 'wAUAA1AFUAMwA=|%02d|%d|1.00|USD' % [@credit_card.month, @credit_card.year.to_s[-2..-1]], response.authorization + assert response.test? + end + + def test_successful_verify_with_failed_void + @gateway.expects(:ssl_post).times(2).returns(successful_authorize_response, failed_void_response) + + response = @gateway.verify(@credit_card, @options) + assert_success response + end + + def test_failed_verify + @gateway.expects(:ssl_post).returns(failed_authorize_response) + + response = @gateway.verify(@credit_card, @options) + assert_failure response + assert_equal '0', response.error_code + end + + def test_scrub + assert @gateway.supports_scrubbing? + assert_equal @gateway.scrub(pre_scrubbed), post_scrubbed + end + + def test_3ds_response + purchase = stub_comms do + @gateway.purchase(@amount, @three_ds_enrolled_card, @three_ds_options) + end.check_request do |endpoint, data, headers| + assert_match(/Sale3D/, data) + assert_match(/sg_APIType/, data) + end.respond_with(successful_3ds_purchase_response) + + assert_success purchase + assert_equal 'MDAwMDAwMDAwMDE1MTAxMDgzMTA=', purchase.params['xid'] + assert_equal 'eJxVUdtuwjAM/ZWK95GYgijIjVTWaUNTGdqQ4DUKFq2gF9J0A75+SVcuixTF59g+sY5xlWqi+ItUo0lgQnUtd+Rl27BXyScYAQce+MB7ApfRJx0FfpOus7IQ0Of9AbIrtK1apbIwAqU6zuYLMQSY8ABZBzEnPY8FfzhjGCH7o7GQOYlIq9J4K6qNd5VD1mZQlU1h9FkEQ47sCrDRB5EaU00ZO5RKHtKyth2ORXYfaNm4qLYqp2wrkjj6ud8XSFbRKYl3F/uGyFwFbqUhMeAwBvC5B6Opz6c+IGt5lLn73hlgR+kAVu6PqMu4xCOB1l1NhTqLydg6ckNIp6osyFZYJ28xsvvAz2/OT2WsRa+bdf2+X6cXtd9oHxZNPks+ojB0DrcFTi2zrkDAJ62cA8icBOuWx7oF2+jf4n8B', purchase.params['pareq'] + assert_equal 'https://pit.3dsecure.net/VbVTestSuiteService/pit1/acsService/paReq?summary=MjRlZGYwY2EtZTk5Zi00NDJjLTljOTAtNWUxZmRhMjEwODg3', purchase.params['acsurl'] + end + + private + + def pre_scrubbed + %q( +opening connection to process.sandbox.safecharge.com:443... +opened +starting SSL for process.sandbox.safecharge.com:443... +SSL established +<- "POST /service.asmx/Process HTTP/1.1\r\nContent-Type: application/x-www-form-urlencoded\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nAccept: */*\r\nUser-Agent: Ruby\r\nConnection: close\r\nHost: process.sandbox.safecharge.com\r\nContent-Length: 249\r\n\r\n" +<- "sg_TransType=Sale&sg_Currency=USD&sg_Amount=1.00&sg_ClientLoginID=SpreedlyTestTRX&sg_ClientPassword=5Jp5xKmgqY&sg_ResponseFormat=4&sg_Version=4.1.0&sg_NameOnCard=Longbob+Longsen&sg_CardNumber=4000100011112224&sg_ExpMonth=09&sg_ExpYear=18&sg_CVV2=123" +-> "HTTP/1.1 200 OK\r\n" +-> "Cache-Control: private, max-age=0\r\n" +-> "Content-Type: text/xml; charset=utf-8\r\n" +-> "Content-Encoding: gzip\r\n" +-> "Vary: Accept-Encoding\r\n" +-> "Server: Microsoft-IIS/8.5\r\n" +-> "X-AspNet-Version: 4.0.30319\r\n" +-> "X-Powered-By: ASP.NET\r\n" +-> "Date: Wed, 29 Mar 2017 18:28:17 GMT\r\n" +-> "Connection: close\r\n" +-> "Content-Length: 727\r\n" +-> "Set-Cookie: visid_incap_847807=oQqFyASiS0y3sQoZ55M7TsH821gAAAAAQUIPAAAAAAA/rRn9PSjQ7LsSqhb2S1AZ; expires=Thu, 29 Mar 2018 13:12:58 GMT; path=/; Domain=.sandbox.safecharge.com\r\n" +-> "Set-Cookie: incap_ses_225_847807=H1/pC1tNgzhTmiAXOl0fA8H821gAAAAAFE9hBYJtG83f0yrtcxrGsg==; path=/; Domain=.sandbox.safecharge.com\r\n" +-> "X-Iinfo: 9-132035054-132035081 NNNN CT(207 413 0) RT(1490812095742 212) q(0 0 6 -1) r(14 14) U5\r\n" +-> "X-CDN: Incapsula\r\n" +-> "\r\n" +reading 727 bytes... + ) + end + + def post_scrubbed + %q( +opening connection to process.sandbox.safecharge.com:443... +opened +starting SSL for process.sandbox.safecharge.com:443... +SSL established +<- "POST /service.asmx/Process HTTP/1.1\r\nContent-Type: application/x-www-form-urlencoded\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nAccept: */*\r\nUser-Agent: Ruby\r\nConnection: close\r\nHost: process.sandbox.safecharge.com\r\nContent-Length: 249\r\n\r\n" +<- "sg_TransType=Sale&sg_Currency=USD&sg_Amount=1.00&sg_ClientLoginID=SpreedlyTestTRX&sg_ClientPassword=[FILTERED]&sg_ResponseFormat=4&sg_Version=4.1.0&sg_NameOnCard=Longbob+Longsen&sg_CardNumber=[FILTERED]&sg_ExpMonth=09&sg_ExpYear=18&sg_CVV2=[FILTERED]" +-> "HTTP/1.1 200 OK\r\n" +-> "Cache-Control: private, max-age=0\r\n" +-> "Content-Type: text/xml; charset=utf-8\r\n" +-> "Content-Encoding: gzip\r\n" +-> "Vary: Accept-Encoding\r\n" +-> "Server: Microsoft-IIS/8.5\r\n" +-> "X-AspNet-Version: 4.0.30319\r\n" +-> "X-Powered-By: ASP.NET\r\n" +-> "Date: Wed, 29 Mar 2017 18:28:17 GMT\r\n" +-> "Connection: close\r\n" +-> "Content-Length: 727\r\n" +-> "Set-Cookie: visid_incap_847807=oQqFyASiS0y3sQoZ55M7TsH821gAAAAAQUIPAAAAAAA/rRn9PSjQ7LsSqhb2S1AZ; expires=Thu, 29 Mar 2018 13:12:58 GMT; path=/; Domain=.sandbox.safecharge.com\r\n" +-> "Set-Cookie: incap_ses_225_847807=H1/pC1tNgzhTmiAXOl0fA8H821gAAAAAFE9hBYJtG83f0yrtcxrGsg==; path=/; Domain=.sandbox.safecharge.com\r\n" +-> "X-Iinfo: 9-132035054-132035081 NNNN CT(207 413 0) RT(1490812095742 212) q(0 0 6 -1) r(14 14) U5\r\n" +-> "X-CDN: Incapsula\r\n" +-> "\r\n" +reading 727 bytes... + ) + end + + def successful_purchase_response + %( + <Response><Version>4.1.0</Version><ClientLoginID>SpreedlyTestTRX</ClientLoginID><ClientUniqueID></ClientUniqueID><TransactionID>101508189567</TransactionID><Status>APPROVED</Status><AuthCode>111951</AuthCode><AVSCode></AVSCode><CVV2Reply></CVV2Reply><ReasonCodes><Reason code="0"></Reason></ReasonCodes><ErrCode>0</ErrCode><ExErrCode>0</ExErrCode><Token>ZQBpAFAASABGAHAAVgBPAFUAMABiADMAewBtAGsAdAAvAFIAQQBrAGoAYwBxACoAXABHAEEAOgA3ACsAMgA4AD0AOABDAG4AbQAzAFUAbQBYAFIAMwA=</Token><CustomData></CustomData><AcquirerID>19</AcquirerID><IssuerBankName>University First Federal Credit Union</IssuerBankName><IssuerBankCountry>us</IssuerBankCountry><Reference></Reference><AGVCode></AGVCode><AGVError></AGVError><UniqueCC>SuiMHP60FrDKfyaJs47hqqrR/JU=</UniqueCC><CustomData2></CustomData2><CreditCardInfo><IsPrepaid>0</IsPrepaid><CardType>Credit</CardType><CardProgram></CardProgram><CardProduct></CardProduct></CreditCardInfo><FraudResponse><FinalDecision>Accept</FinalDecision><Recommendations /><Rule /></FraudResponse></Response> + ) + end + + def failed_purchase_response + %( + <Response><Version>4.1.0</Version><ClientLoginID>SpreedlyTestTRX</ClientLoginID><ClientUniqueID></ClientUniqueID><TransactionID>101508189637</TransactionID><Status>DECLINED</Status><AuthCode></AuthCode><AVSCode></AVSCode><CVV2Reply></CVV2Reply><ReasonCodes><Reason code="0">Decline</Reason></ReasonCodes><ErrCode>-1</ErrCode><ExErrCode>0</ExErrCode><Token>bwBVAEYAUgBuAGcAbABSAFYASgB5AEAAMgA/ACsAUQBIAC4AbgB1AHgAdABAAE8ARgBRAGoAbwApACQAWwBKAFwATwAxAEcAMwBZAG4AdwBmACgAMwA=</Token><CustomData></CustomData><AcquirerID>19</AcquirerID><IssuerBankName></IssuerBankName><IssuerBankCountry></IssuerBankCountry><Reference></Reference><AGVCode></AGVCode><AGVError></AGVError><UniqueCC>GyueFkuQqW+UL38d57fuA5/RqfQ=</UniqueCC><CustomData2></CustomData2><CreditCardInfo><IsPrepaid>0</IsPrepaid><CardType></CardType><CardProgram></CardProgram><CardProduct></CardProduct></CreditCardInfo><FraudResponse><FinalDecision>Accept</FinalDecision><Recommendations /><Rule /></FraudResponse></Response> + ) + end + + def successful_authorize_response + %( + <Response><Version>4.1.0</Version><ClientLoginID>SpreedlyTestTRX</ClientLoginID><ClientUniqueID></ClientUniqueID><TransactionID>101508189855</TransactionID><Status>APPROVED</Status><AuthCode>111534</AuthCode><AVSCode></AVSCode><CVV2Reply></CVV2Reply><ReasonCodes><Reason code="0"></Reason></ReasonCodes><ErrCode>0</ErrCode><ExErrCode>0</ExErrCode><Token>MQBVAG4ASABkAEgAagB3AEsAbgAtACoAWgAzAFwAWwBNAF8ATQBUAD0AegBQAGwAQAAtAD0AXAB5AFkALwBtAFAALABaAHoAOgBFAEwAUAA1AFUAMwA=</Token><CustomData></CustomData><AcquirerID>19</AcquirerID><IssuerBankName>University First Federal Credit Union</IssuerBankName><IssuerBankCountry>us</IssuerBankCountry><Reference></Reference><AGVCode></AGVCode><AGVError></AGVError><UniqueCC>SuiMHP60FrDKfyaJs47hqqrR/JU=</UniqueCC><CustomData2></CustomData2><CreditCardInfo><IsPrepaid>0</IsPrepaid><CardType>Credit</CardType><CardProgram></CardProgram><CardProduct></CardProduct></CreditCardInfo><FraudResponse><FinalDecision>Accept</FinalDecision><Recommendations /><Rule /></FraudResponse></Response> + ) + end + + def failed_authorize_response + %( + <Response><Version>4.1.0</Version><ClientLoginID>SpreedlyTestTRX</ClientLoginID><ClientUniqueID></ClientUniqueID><TransactionID>101508190604</TransactionID><Status>DECLINED</Status><AuthCode></AuthCode><AVSCode></AVSCode><CVV2Reply></CVV2Reply><ReasonCodes><Reason code="0">Decline</Reason></ReasonCodes><ErrCode>-1</ErrCode><ExErrCode>0</ExErrCode><Token>MQBLAG4AMgAwADMAOABmAFYANABbAGYAcwA+ACMAVgBXAD0AUQBQAEoANQBrAHQAWABsAFEAeABQAF8ARwA6ACsALgBHADUALwBTAEAARwBIACgAMwA=</Token><CustomData></CustomData><AcquirerID>19</AcquirerID><IssuerBankName></IssuerBankName><IssuerBankCountry></IssuerBankCountry><Reference></Reference><AGVCode></AGVCode><AGVError></AGVError><UniqueCC>GyueFkuQqW+UL38d57fuA5/RqfQ=</UniqueCC><CustomData2></CustomData2><CreditCardInfo><IsPrepaid>0</IsPrepaid><CardType></CardType><CardProgram></CardProgram><CardProduct></CardProduct></CreditCardInfo><FraudResponse><FinalDecision>Accept</FinalDecision><Recommendations /><Rule /></FraudResponse></Response> + ) + end + + def successful_capture_response + %( + <Response><Version>4.1.0</Version><ClientLoginID>SpreedlyTestTRX</ClientLoginID><ClientUniqueID></ClientUniqueID><TransactionID>101508190200</TransactionID><Status>APPROVED</Status><AuthCode>111301</AuthCode><AVSCode></AVSCode><CVV2Reply></CVV2Reply><ReasonCodes><Reason code="0"></Reason></ReasonCodes><ErrCode>0</ErrCode><ExErrCode>0</ExErrCode><Token>RwA1AGQAMgAwAEkAWABKADkAcABjAHYAQQA4AC8AZAAlAHMAfABoADEALAA8ADQAewB8ADsAewBiADsANQBoACwAeAA/AGQAXQAjAFEAYgBVAHIAMwA=</Token><CustomData></CustomData><AcquirerID>19</AcquirerID><IssuerBankName>University First Federal Credit Union</IssuerBankName><IssuerBankCountry>us</IssuerBankCountry><Reference></Reference><AGVCode></AGVCode><AGVError></AGVError><UniqueCC>SuiMHP60FrDKfyaJs47hqqrR/JU=</UniqueCC><CustomData2></CustomData2><CreditCardInfo><IsPrepaid>0</IsPrepaid><CardType>Credit</CardType><CardProgram></CardProgram><CardProduct></CardProduct></CreditCardInfo><FraudResponse /></Response> + ) + end + + def failed_capture_response + %( + <Response><Version>4.1.0</Version><ClientLoginID>SpreedlyTestTRX</ClientLoginID><ClientUniqueID></ClientUniqueID><TransactionID>101508190627</TransactionID><Status>ERROR</Status><AuthCode></AuthCode><AVSCode></AVSCode><CVV2Reply></CVV2Reply><Reason>Transaction must contain a Card/Token/Account</Reason><ErrCode>-1100</ErrCode><ExErrCode>1163</ExErrCode><CustomData></CustomData><AcquirerID>-1</AcquirerID><IssuerBankName></IssuerBankName><IssuerBankCountry></IssuerBankCountry><Reference></Reference><AGVCode></AGVCode><AGVError></AGVError><UniqueCC>2jmj7l5rSw0yVb/vlWAYkK/YBwk=</UniqueCC><CustomData2></CustomData2><CreditCardInfo><IsPrepaid>0</IsPrepaid><CardType></CardType><CardProgram></CardProgram><CardProduct></CardProduct></CreditCardInfo></Response> + ) + end + + def successful_refund_response + %( + <Response><Version>4.1.0</Version><ClientLoginID>SpreedlyTestTRX</ClientLoginID><ClientUniqueID></ClientUniqueID><TransactionID>101508440432</TransactionID><Status>APPROVED</Status><AuthCode>111207</AuthCode><AVSCode></AVSCode><CVV2Reply></CVV2Reply><ReasonCodes><Reason code="0"></Reason></ReasonCodes><ErrCode>0</ErrCode><ExErrCode>0</ExErrCode><Token>MQBVAG4AUgAwAFcAaABxAGoASABdAE4ALABvAGYANAAmAE8AcQA/AEgAawAkAHYASQBKAFMAegBiACoAcQBBAC8AVABlAD4AKwBkAC0AKwA8ACcAMwA=</Token><CustomData></CustomData><AcquirerID>19</AcquirerID><IssuerBankName></IssuerBankName><IssuerBankCountry></IssuerBankCountry><Reference></Reference><AGVCode></AGVCode><AGVError></AGVError><UniqueCC>SuiMHP60FrDKfyaJs47hqqrR/JU=</UniqueCC><CustomData2></CustomData2><CreditCardInfo><IsPrepaid>0</IsPrepaid><CardType></CardType><CardProgram></CardProgram><CardProduct></CardProduct></CreditCardInfo><FraudResponse /></Response> + ) + end + + def failed_refund_response + %( + <Response><Version>4.1.0</Version><ClientLoginID>SpreedlyTestTRX</ClientLoginID><ClientUniqueID></ClientUniqueID><TransactionID>101508208595</TransactionID><Status>ERROR</Status><AuthCode></AuthCode><AVSCode></AVSCode><CVV2Reply></CVV2Reply><Reason>Transaction must contain a Card/Token/Account</Reason><ErrCode>-1100</ErrCode><ExErrCode>1163</ExErrCode><CustomData></CustomData><AcquirerID>-1</AcquirerID><IssuerBankName></IssuerBankName><IssuerBankCountry></IssuerBankCountry><Reference></Reference><AGVCode></AGVCode><AGVError></AGVError><UniqueCC>2jmj7l5rSw0yVb/vlWAYkK/YBwk=</UniqueCC><CustomData2></CustomData2><CreditCardInfo><IsPrepaid>0</IsPrepaid><CardType></CardType><CardProgram></CardProgram><CardProduct></CardProduct></CreditCardInfo></Response> + ) + end + + def successful_credit_response + %( + <Response><Version>4.1.0</Version><ClientLoginID>SpreedlyTestTRX</ClientLoginID><ClientUniqueID></ClientUniqueID><TransactionID>101508440421</TransactionID><Status>APPROVED</Status><AuthCode>111644</AuthCode><AVSCode></AVSCode><CVV2Reply></CVV2Reply><ReasonCodes><Reason code="0"></Reason></ReasonCodes><ErrCode>0</ErrCode><ExErrCode>0</ExErrCode><Token>bwA1ADAAcAAwAHUAVABJAFYAUQAlAGcAfAB8AFQAbwBkAHAAbwAjAG4AaABDAHsAUABdACoAYwBaAEsAMQBHAEUAMQBuAHQAdwBXAFUAVABZACMAMwA=</Token><CustomData></CustomData><AcquirerID>19</AcquirerID><IssuerBankName></IssuerBankName><IssuerBankCountry></IssuerBankCountry><Reference></Reference><AGVCode></AGVCode><AGVError></AGVError><UniqueCC>SuiMHP60FrDKfyaJs47hqqrR/JU=</UniqueCC><CustomData2></CustomData2><CreditCardInfo><IsPrepaid>0</IsPrepaid><CardType></CardType><CardProgram></CardProgram><CardProduct></CardProduct></CreditCardInfo><FraudResponse /></Response> + ) + end + + def failed_credit_response + %( + <Response><Version>4.1.0</Version><ClientLoginID>SpreedlyTestTRX</ClientLoginID><ClientUniqueID></ClientUniqueID><TransactionID>101508440424</TransactionID><Status>DECLINED</Status><AuthCode></AuthCode><AVSCode></AVSCode><CVV2Reply></CVV2Reply><ReasonCodes><Reason code="0">Decline</Reason></ReasonCodes><ErrCode>-1</ErrCode><ExErrCode>0</ExErrCode><Token>RwBVAGQAZgAwAFMAbABwAEwASgBNAFMAXABJAGAAeAAsAHsALAA7ADUAOgBUAEMAZwBNAG4AbABQAC4AQAAvAC0APwBpAEAAWQBoACMAdwBvAGEAMwA=</Token><CustomData></CustomData><AcquirerID>19</AcquirerID><IssuerBankName></IssuerBankName><IssuerBankCountry></IssuerBankCountry><Reference></Reference><AGVCode></AGVCode><AGVError></AGVError><UniqueCC>GyueFkuQqW+UL38d57fuA5/RqfQ=</UniqueCC><CustomData2></CustomData2><CreditCardInfo><IsPrepaid>0</IsPrepaid><CardType></CardType><CardProgram></CardProgram><CardProduct></CardProduct></CreditCardInfo><FraudResponse /></Response> + ) + end + + def successful_void_response + %( + <Response><Version>4.1.0</Version><ClientLoginID>SpreedlyTestTRX</ClientLoginID><ClientUniqueID></ClientUniqueID><TransactionID>101508208625</TransactionID><Status>APPROVED</Status><AuthCode>111171</AuthCode><AVSCode></AVSCode><CVV2Reply></CVV2Reply><ReasonCodes><Reason code="0"></Reason></ReasonCodes><ErrCode>0</ErrCode><ExErrCode>0</ExErrCode><Token>ZQBpAFAAZgBuAHEATgBUAHcASAAwADUAcwBHAHQAVQBLAHAAbgB6AGwAJAA1AEMAfAB2AGYASwBrAHEAeQBOAEwAOwBZAGIAewB4AGwAYwBUAE0AMwA=</Token><CustomData></CustomData><AcquirerID>19</AcquirerID><IssuerBankName>University First Federal Credit Union</IssuerBankName><IssuerBankCountry>us</IssuerBankCountry><Reference></Reference><AGVCode></AGVCode><AGVError></AGVError><UniqueCC>SuiMHP60FrDKfyaJs47hqqrR/JU=</UniqueCC><CustomData2></CustomData2><CreditCardInfo><IsPrepaid>0</IsPrepaid><CardType>Credit</CardType><CardProgram></CardProgram><CardProduct></CardProduct></CreditCardInfo><FraudResponse /></Response> + ) + end + + def failed_void_response + %( + <Response><Version>4.1.0</Version><ClientLoginID>SpreedlyTestTRX</ClientLoginID><ClientUniqueID></ClientUniqueID><TransactionID>101508208633</TransactionID><Status>ERROR</Status><AuthCode></AuthCode><AVSCode></AVSCode><CVV2Reply></CVV2Reply><Reason>Invalid Amount</Reason><ErrCode>-1100</ErrCode><ExErrCode>1201</ExErrCode><CustomData></CustomData><AcquirerID>-1</AcquirerID><IssuerBankName></IssuerBankName><IssuerBankCountry></IssuerBankCountry><Reference></Reference><AGVCode></AGVCode><AGVError></AGVError><UniqueCC>2jmj7l5rSw0yVb/vlWAYkK/YBwk=</UniqueCC><CustomData2></CustomData2><CreditCardInfo><IsPrepaid>0</IsPrepaid><CardType></CardType><CardProgram></CardProgram><CardProduct></CardProduct></CreditCardInfo></Response> + ) + end + + def successful_3ds_purchase_response + %( + <Response><Version>4.1.0</Version><ClientLoginID>SpreedlyManTestTRX</ClientLoginID><ClientUniqueID>98bd80c8c9534088311153ad6a67d108</ClientUniqueID><TransactionID>101510108310</TransactionID><Status>APPROVED</Status><AuthCode></AuthCode><AVSCode></AVSCode><CVV2Reply></CVV2Reply><ReasonCodes><Reason code="0"></Reason></ReasonCodes><ErrCode>0</ErrCode><ExErrCode>0</ExErrCode><Token>ZQBpAFAAMwBTAEcAMQBZAHcASQA4ADoAPQBlACQAZAB3ACMAWwAyAFoAWQBLAFUAPwBTAHYAKQAnAHQAUAA2AHYAYwAoAG0ARgBNAEEAcAAlAGEAMwA=</Token><CustomData></CustomData><ThreeDResponse><Auth3DResponse><Result>Y</Result><PaReq>eJxVUdtuwjAM/ZWK95GYgijIjVTWaUNTGdqQ4DUKFq2gF9J0A75+SVcuixTF59g+sY5xlWqi+ItUo0lgQnUtd+Rl27BXyScYAQce+MB7ApfRJx0FfpOus7IQ0Of9AbIrtK1apbIwAqU6zuYLMQSY8ABZBzEnPY8FfzhjGCH7o7GQOYlIq9J4K6qNd5VD1mZQlU1h9FkEQ47sCrDRB5EaU00ZO5RKHtKyth2ORXYfaNm4qLYqp2wrkjj6ud8XSFbRKYl3F/uGyFwFbqUhMeAwBvC5B6Opz6c+IGt5lLn73hlgR+kAVu6PqMu4xCOB1l1NhTqLydg6ckNIp6osyFZYJ28xsvvAz2/OT2WsRa+bdf2+X6cXtd9oHxZNPks+ojB0DrcFTi2zrkDAJ62cA8icBOuWx7oF2+jf4n8B</PaReq><MerchantID>000000000000715</MerchantID><ACSurl>https://pit.3dsecure.net/VbVTestSuiteService/pit1/acsService/paReq?summary=MjRlZGYwY2EtZTk5Zi00NDJjLTljOTAtNWUxZmRhMjEwODg3</ACSurl><XID>MDAwMDAwMDAwMDE1MTAxMDgzMTA=</XID><ThreeDReason></ThreeDReason></Auth3DResponse></ThreeDResponse><AcquirerID>19</AcquirerID><IssuerBankName>Visa Production Support Client Bid 1</IssuerBankName><IssuerBankCountry>us</IssuerBankCountry><Reference></Reference><AGVCode></AGVCode><AGVError></AGVError><UniqueCC>rDNDlh6XR8R6CVdGQyqDkZzdqE0=</UniqueCC><CustomData2></CustomData2><ThreeDFlow>1</ThreeDFlow><CreditCardInfo><IsPrepaid>0</IsPrepaid><CardType>Debit</CardType><CardProgram></CardProgram><CardProduct></CardProduct></CreditCardInfo><IsPartialApproval>0</IsPartialApproval><AmountInfo><RequestedAmount>1</RequestedAmount><RequestedCurrency>EUR</RequestedCurrency><ProcessedAmount>1</ProcessedAmount><ProcessedCurrency>EUR</ProcessedCurrency></AmountInfo><RRN></RRN><ICC></ICC><CVVReply></CVVReply></Response> + ) + end +end diff --git a/test/unit/gateways/sage_pay_test.rb b/test/unit/gateways/sage_pay_test.rb index 439b1483577..034d563e448 100644 --- a/test/unit/gateways/sage_pay_test.rb +++ b/test/unit/gateways/sage_pay_test.rb @@ -13,7 +13,7 @@ def setup :name => 'Tekin Suleyman', :address1 => 'Flat 10 Lapwing Court', :address2 => 'West Didsbury', - :city => "Manchester", + :city => 'Manchester', :county => 'Greater Manchester', :country => 'GB', :zip => 'M20 2PS' @@ -31,7 +31,7 @@ def test_successful_purchase @gateway.expects(:ssl_post).returns(successful_purchase_response) assert response = @gateway.purchase(@amount, @credit_card, @options) - assert_equal "1;B8AE1CF6-9DEF-C876-1BB4-9B382E6CE520;4193753;OHMETD7DFK;purchase", response.authorization + assert_equal '1;B8AE1CF6-9DEF-C876-1BB4-9B382E6CE520;4193753;OHMETD7DFK;purchase', response.authorization assert_success response end @@ -57,20 +57,39 @@ def test_capture_url assert_equal 'https://test.sagepay.com/gateway/service/release.vsp', @gateway.send(:url_for, :capture) end - def test_avs_result + def test_matched_avs_result + @gateway.expects(:ssl_post).returns(unsuccessful_purchase_response) + + response = @gateway.purchase(@amount, @credit_card, @options) + + assert_equal 'Y', response.avs_result['postal_match'] + assert_equal 'Y', response.avs_result['street_match'] + end + + def test_partially_matched_avs_result @gateway.expects(:ssl_post).returns(successful_purchase_response) response = @gateway.purchase(@amount, @credit_card, @options) + assert_equal 'Y', response.avs_result['postal_match'] assert_equal 'N', response.avs_result['street_match'] end - def test_cvv_result - @gateway.expects(:ssl_post).returns(successful_purchase_response) + def test_matched_cvv_result + @gateway.expects(:ssl_post).returns(unsuccessful_purchase_response) + + response = @gateway.purchase(@amount, @credit_card, @options) + + assert_equal 'M', response.cvv_result['code'] + end + + def test_not_matched_cvv_result + @gateway.expects(:ssl_post).returns(successful_purchase_response) + + response = @gateway.purchase(@amount, @credit_card, @options) - response = @gateway.purchase(@amount, @credit_card, @options) - assert_equal 'N', response.cvv_result['code'] - end + assert_equal 'N', response.cvv_result['code'] + end def test_dont_send_fractional_amount_for_chinese_yen @amount = 100_00 # 100 YEN @@ -204,8 +223,8 @@ def test_website_is_submitted def test_FIxxxx_optional_fields_are_submitted stub_comms(@gateway, :ssl_request) do purchase_with_options(recipient_account_number: '1234567890', - recipient_surname: 'Withnail', recipient_postcode: 'AB11AB', - recipient_dob: '19701223') + recipient_surname: 'Withnail', recipient_postcode: 'AB11AB', + recipient_dob: '19701223') end.check_request do |method, endpoint, data, headers| assert_match(/FIRecipientAcctNumber=1234567890/, data) assert_match(/FIRecipientSurname=Withnail/, data) @@ -215,7 +234,7 @@ def test_FIxxxx_optional_fields_are_submitted end def test_description_is_truncated - huge_description = "SagePay transactions fail if the déscription is more than 100 characters. Therefore, we truncate it to 100 characters." + " Lots more text " * 1000 + huge_description = 'SagePay transactions fail if the déscription is more than 100 characters. Therefore, we truncate it to 100 characters.' + ' Lots more text ' * 1000 stub_comms(@gateway, :ssl_request) do purchase_with_options(description: huge_description) end.check_request do |method, endpoint, data, headers| @@ -224,7 +243,7 @@ def test_description_is_truncated end def test_protocol_version_is_honoured - gateway = SagePayGateway.new(protocol_version: '2.23', login: "X") + gateway = SagePayGateway.new(protocol_version: '2.23', login: 'X') stub_comms(gateway, :ssl_request) do gateway.purchase(@amount, @credit_card, @options) @@ -238,7 +257,7 @@ def test_referrer_id_is_added_to_post_data_parameters stub_comms(@gateway, :ssl_request) do @gateway.purchase(@amount, @credit_card, @options) end.check_request do |method, endpoint, data, headers| - assert data.include?("ReferrerID=00000000-0000-0000-0000-000000000001") + assert data.include?('ReferrerID=00000000-0000-0000-0000-000000000001') end.respond_with(successful_purchase_response) ensure ActiveMerchant::Billing::SagePayGateway.application_id = nil @@ -281,8 +300,37 @@ def test_transcript_scrubbing def test_truncate_accounts_for_url_encoding assert_nil @gateway.send(:truncate, nil, 3) - assert_equal "Wow", @gateway.send(:truncate, "WowAmaze", 3) - assert_equal "Joikam Lomström", @gateway.send(:truncate, "Joikam Lomström Rate", 20) + assert_equal 'Wow', @gateway.send(:truncate, 'WowAmaze', 3) + assert_equal 'Joikam Lomström', @gateway.send(:truncate, 'Joikam Lomström Rate', 20) + end + + def test_successful_authorization_and_capture_and_refund + auth = stub_comms do + @gateway.authorize(@amount, @credit_card, @options) + end.respond_with(successful_authorize_response) + assert_success auth + + capture = stub_comms do + @gateway.capture(@amount, auth.authorization) + end.respond_with(successful_capture_response) + assert_success capture + + refund = stub_comms do + @gateway.refund(@amount, capture.authorization, + order_id: generate_unique_id, + description: 'Refund txn' + ) + end.respond_with(successful_refund_response) + assert_success refund + end + + def test_repeat_purchase_with_reference_token + stub_comms(@gateway, :ssl_request) do + @gateway.purchase(@amount, '1455548a8d178beecd88fe6a285f50ff;{0D2ACAF0-FA64-6DFF-3869-7ADDDC1E0474};15353766;BS231FNE14;purchase', @options) + end.check_request do |method, endpoint, data, headers| + assert_match(/RelatedVPSTxId=%7B0D2ACAF0-FA64-6DFF-3869-7ADDDC1E0474%/, data) + assert_match(/TxType=REPEAT/, data) + end.respond_with(successful_purchase_response) end private @@ -339,6 +387,25 @@ def successful_authorize_response RESP end + def successful_refund_response + <<-RESP +VPSProtocol=3.00 +Status=OK +StatusDetail=0000 : The Authorisation was Successful. +SecurityKey=KUMJBP02HM +TxAuthNo=15282432 +VPSTxId={08C870A9-1E53-3852-BA44-CBC91612CBCA} + RESP + end + + def successful_capture_response + <<-RESP +VPSProtocol=3.00 +Status=OK +StatusDetail=2004 : The Release was Successful. + RESP + end + def unsuccessful_authorize_response <<-RESP VPSProtocol=2.23 @@ -403,7 +470,6 @@ def transcript ExpiryDate=0616 BankAuthCode=999777 TRANSCRIPT - end def scrubbed_transcript @@ -425,6 +491,5 @@ def scrubbed_transcript ExpiryDate=0616 BankAuthCode=999777 TRANSCRIPT - end end diff --git a/test/unit/gateways/sage_test.rb b/test/unit/gateways/sage_test.rb index 0c805fb4b2f..b6faa1761c6 100644 --- a/test/unit/gateways/sage_test.rb +++ b/test/unit/gateways/sage_test.rb @@ -38,19 +38,19 @@ def test_successful_authorization assert_instance_of Response, response assert_success response - assert_equal "APPROVED", response.message - assert_equal "1234567890;bankcard", response.authorization + assert_equal 'APPROVED', response.message + assert_equal '1234567890;bankcard', response.authorization - assert_equal "A", response.params["success"] - assert_equal "911911", response.params["code"] - assert_equal "APPROVED", response.params["message"] - assert_equal "00", response.params["front_end"] - assert_equal "M", response.params["cvv_result"] - assert_equal "X", response.params["avs_result"] - assert_equal "00", response.params["risk"] - assert_equal "1234567890", response.params["reference"] - assert_equal "1000", response.params["order_number"] - assert_equal "0", response.params["recurring"] + assert_equal 'A', response.params['success'] + assert_equal '911911', response.params['code'] + assert_equal 'APPROVED', response.params['message'] + assert_equal '00', response.params['front_end'] + assert_equal 'M', response.params['cvv_result'] + assert_equal 'X', response.params['avs_result'] + assert_equal '00', response.params['risk'] + assert_equal '1234567890', response.params['reference'] + assert_equal '1000', response.params['order_number'] + assert_equal '0', response.params['recurring'] end def test_successful_purchase @@ -60,19 +60,19 @@ def test_successful_purchase assert_instance_of Response, response assert_success response - assert_equal "APPROVED 000001", response.message - assert_equal "B5O89VPdf0;bankcard", response.authorization + assert_equal 'APPROVED 000001', response.message + assert_equal 'B5O89VPdf0;bankcard', response.authorization - assert_equal "A", response.params["success"] - assert_equal "000001", response.params["code"] - assert_equal "APPROVED 000001", response.params["message"] - assert_equal "10", response.params["front_end"] - assert_equal "M", response.params["cvv_result"] - assert_equal "", response.params["avs_result"] - assert_equal "00", response.params["risk"] - assert_equal "B5O89VPdf0", response.params["reference"] - assert_equal "e81cab9e6144a160da82", response.params["order_number"] - assert_equal "0", response.params["recurring"] + assert_equal 'A', response.params['success'] + assert_equal '000001', response.params['code'] + assert_equal 'APPROVED 000001', response.params['message'] + assert_equal '10', response.params['front_end'] + assert_equal 'M', response.params['cvv_result'] + assert_equal '', response.params['avs_result'] + assert_equal '00', response.params['risk'] + assert_equal 'B5O89VPdf0', response.params['reference'] + assert_equal 'e81cab9e6144a160da82', response.params['order_number'] + assert_equal '0', response.params['recurring'] end def test_declined_purchase @@ -81,57 +81,57 @@ def test_declined_purchase assert response = @gateway.purchase(@amount, @credit_card, @options) assert_failure response assert response.test? - assert_equal "DECLINED", response.message - assert_equal "A5O89kkix0;bankcard", response.authorization + assert_equal 'DECLINED', response.message + assert_equal 'A5O89kkix0;bankcard', response.authorization - assert_equal "E", response.params["success"] - assert_equal "000002", response.params["code"] - assert_equal "DECLINED", response.params["message"] - assert_equal "10", response.params["front_end"] - assert_equal "N", response.params["cvv_result"] - assert_equal "", response.params["avs_result"] - assert_equal "00", response.params["risk"] - assert_equal "A5O89kkix0", response.params["reference"] - assert_equal "3443d6426188f8256b8f", response.params["order_number"] - assert_equal "0", response.params["recurring"] + assert_equal 'E', response.params['success'] + assert_equal '000002', response.params['code'] + assert_equal 'DECLINED', response.params['message'] + assert_equal '10', response.params['front_end'] + assert_equal 'N', response.params['cvv_result'] + assert_equal '', response.params['avs_result'] + assert_equal '00', response.params['risk'] + assert_equal 'A5O89kkix0', response.params['reference'] + assert_equal '3443d6426188f8256b8f', response.params['order_number'] + assert_equal '0', response.params['recurring'] end def test_successful_capture @gateway.expects(:ssl_post).returns(successful_capture_response) - assert response = @gateway.capture(@amount, "A5O89kkix0") + assert response = @gateway.capture(@amount, 'A5O89kkix0') assert_instance_of Response, response assert_success response - assert_equal "APPROVED 000001", response.message - assert_equal "B5O8AdFhu0;bankcard", response.authorization + assert_equal 'APPROVED 000001', response.message + assert_equal 'B5O8AdFhu0;bankcard', response.authorization - assert_equal "A", response.params["success"] - assert_equal "000001", response.params["code"] - assert_equal "APPROVED 000001", response.params["message"] - assert_equal "10", response.params["front_end"] - assert_equal "P", response.params["cvv_result"] - assert_equal "", response.params["avs_result"] - assert_equal "00", response.params["risk"] - assert_equal "B5O8AdFhu0", response.params["reference"] - assert_equal "ID5O8AdFhw", response.params["order_number"] - assert_equal "0", response.params["recurring"] + assert_equal 'A', response.params['success'] + assert_equal '000001', response.params['code'] + assert_equal 'APPROVED 000001', response.params['message'] + assert_equal '10', response.params['front_end'] + assert_equal 'P', response.params['cvv_result'] + assert_equal '', response.params['avs_result'] + assert_equal '00', response.params['risk'] + assert_equal 'B5O8AdFhu0', response.params['reference'] + assert_equal 'ID5O8AdFhw', response.params['order_number'] + assert_equal '0', response.params['recurring'] end def test_successful_refund @gateway.expects(:ssl_post).returns(successful_refund_response) - response = @gateway.refund(@amount, "Authorization") + response = @gateway.refund(@amount, 'Authorization') assert_success response - assert_equal "G68FCU2c60;bankcard", response.authorization - assert_equal "APPROVED", response.message + assert_equal 'G68FCU2c60;bankcard', response.authorization + assert_equal 'APPROVED', response.message end def test_failed_refund @gateway.expects(:ssl_post).returns(failed_refund_response) - response = @gateway.refund(@amount, "Authorization") + response = @gateway.refund(@amount, 'Authorization') assert_failure response - assert_equal "INVALID T_REFERENCE", response.message + assert_equal 'INVALID T_REFERENCE', response.message end def test_invalid_login @@ -140,24 +140,24 @@ def test_invalid_login assert response = @gateway.purchase(@amount, @credit_card, @options) assert_failure response assert response.test? - assert_equal "SECURITY VIOLATION", response.message - assert_equal "0000000000;bankcard", response.authorization + assert_equal 'SECURITY VIOLATION', response.message + assert_equal '0000000000;bankcard', response.authorization - assert_equal "X", response.params["success"] - assert_equal "911911", response.params["code"] - assert_equal "SECURITY VIOLATION", response.params["message"] - assert_equal "00", response.params["front_end"] - assert_equal "P", response.params["cvv_result"] - assert_equal "", response.params["avs_result"] - assert_equal "00", response.params["risk"] - assert_equal "0000000000", response.params["reference"] - assert_equal "", response.params["order_number"] - assert_equal "0", response.params["recurring"] + assert_equal 'X', response.params['success'] + assert_equal '911911', response.params['code'] + assert_equal 'SECURITY VIOLATION', response.params['message'] + assert_equal '00', response.params['front_end'] + assert_equal 'P', response.params['cvv_result'] + assert_equal '', response.params['avs_result'] + assert_equal '00', response.params['risk'] + assert_equal '0000000000', response.params['reference'] + assert_equal '', response.params['order_number'] + assert_equal '0', response.params['recurring'] end def test_include_customer_number_for_numeric_values stub_comms do - @gateway.purchase(@amount, @credit_card, @options.merge({:customer => "123"})) + @gateway.purchase(@amount, @credit_card, @options.merge({:customer => '123'})) end.check_request do |method, data| assert data =~ /T_customer_number=123/ end.respond_with(successful_authorization_response) @@ -165,7 +165,7 @@ def test_include_customer_number_for_numeric_values def test_dont_include_customer_number_for_numeric_values stub_comms do - @gateway.purchase(@amount, @credit_card, @options.merge({:customer => "bob@test.com"})) + @gateway.purchase(@amount, @credit_card, @options.merge({:customer => 'bob@test.com'})) end.check_request do |method, data| assert data !~ /T_customer_number/ end.respond_with(successful_authorization_response) @@ -185,26 +185,26 @@ def test_cvv_result assert_equal 'M', response.cvv_result['code'] end - def test_us_address_with_state + def test_address_with_state post = {} options = { - :billing_address => { :country => "US", :state => "CA"} + :billing_address => { :country => 'US', :state => 'CA'} } @gateway.send(:add_addresses, post, options) - assert_equal "US", post[:C_country] - assert_equal "CA", post[:C_state] + assert_equal 'US', post[:C_country] + assert_equal 'CA', post[:C_state] end - def test_us_address_without_state + def test_address_without_state post = {} options = { - :billing_address => { :country => "US", :state => ""} + :billing_address => { :country => 'NZ', :state => ''} } @gateway.send(:add_addresses, post, options) - assert_equal "US", post[:C_country] - assert_equal "", post[:C_state] + assert_equal 'NZ', post[:C_country] + assert_equal 'Outside of US', post[:C_state] end def test_successful_check_purchase @@ -214,17 +214,17 @@ def test_successful_check_purchase assert_instance_of Response, response assert_success response - assert_equal "ACCEPTED", response.message - assert_equal "C5O8NUdNt0;virtual_check", response.authorization + assert_equal 'ACCEPTED', response.message + assert_equal 'C5O8NUdNt0;virtual_check', response.authorization - assert_equal "A", response.params["success"] - assert_equal "", response.params["code"] - assert_equal "ACCEPTED", response.params["message"] - assert_equal "00", response.params["risk"] - assert_equal "C5O8NUdNt0", response.params["reference"] - assert_equal "89be635e663b05eca587", response.params["order_number"] - assert_equal "0", response.params["authentication_indicator"] - assert_equal "NONE", response.params["authentication_disclosure"] + assert_equal 'A', response.params['success'] + assert_equal '', response.params['code'] + assert_equal 'ACCEPTED', response.params['message'] + assert_equal '00', response.params['risk'] + assert_equal 'C5O8NUdNt0', response.params['reference'] + assert_equal '89be635e663b05eca587', response.params['order_number'] + assert_equal '0', response.params['authentication_indicator'] + assert_equal 'NONE', response.params['authentication_disclosure'] end def test_declined_check_purchase @@ -233,17 +233,17 @@ def test_declined_check_purchase response = @gateway.purchase(@amount, @check, @check_options) assert_failure response assert response.test? - assert_equal "INVALID C_RTE", response.message - assert_equal "C5O8NR6Nr0;virtual_check", response.authorization + assert_equal 'INVALID C_RTE', response.message + assert_equal 'C5O8NR6Nr0;virtual_check', response.authorization - assert_equal "X", response.params["success"] - assert_equal "900016", response.params["code"] - assert_equal "INVALID C_RTE", response.params["message"] - assert_equal "00", response.params["risk"] - assert_equal "C5O8NR6Nr0", response.params["reference"] - assert_equal "d98cf50f7a2430fe04ad", response.params["order_number"] - assert_equal "0", response.params["authentication_indicator"] - assert_equal nil, response.params["authentication_disclosure"] + assert_equal 'X', response.params['success'] + assert_equal '900016', response.params['code'] + assert_equal 'INVALID C_RTE', response.params['message'] + assert_equal '00', response.params['risk'] + assert_equal 'C5O8NR6Nr0', response.params['reference'] + assert_equal 'd98cf50f7a2430fe04ad', response.params['order_number'] + assert_equal '0', response.params['authentication_indicator'] + assert_equal nil, response.params['authentication_disclosure'] end def test_successful_store @@ -316,6 +316,7 @@ def test_failed_unstore def test_scrub assert_equal @gateway.scrub(pre_scrubbed), post_scrubbed + assert_equal @gateway.scrub(pre_scrubbed_echeck), post_scrubbed_echeck end def test_supports_scrubbing? @@ -323,6 +324,7 @@ def test_supports_scrubbing? end private + def successful_authorization_response "\002A911911APPROVED 00MX001234567890\0341000\0340\034\003" end @@ -488,4 +490,51 @@ def post_scrubbed Conn close POST_SCRUBBED end + + def pre_scrubbed_echeck + <<-PRE_SCRUBBED +opening connection to www.sagepayments.net:443... +opened +starting SSL for www.sagepayments.net:443... +SSL established +<- "POST /cgi-bin/eftVirtualCheck.dll?transaction HTTP/1.1\r\nContent-Type: application/x-www-form-urlencoded\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nAccept: */*\r\nUser-Agent: Ruby\r\nConnection: close\r\nHost: www.sagepayments.net\r\nContent-Length: 562\r\n\r\n" +<- "C_first_name=Jim&C_last_name=Smith&C_rte=244183602&C_acct=15378535&C_check_number=1&C_acct_type=DDA&C_customer_type=WEB&C_originator_id=&T_addenda=&C_ssn=&C_dl_state_code=&C_dl_number=&C_dob=&T_amt=1.00&T_ordernum=0ac6fd1f74a98de94bf9&C_address=456+My+Street&C_city=Ottawa&C_state=ON&C_zip=K1C2N6&C_country=CA&C_telephone=%28555%29555-5555&C_fax=%28555%29555-6666&C_email=longbob%40example.com&C_ship_name=Jim+Smith&C_ship_address=456+My+Street&C_ship_city=Ottawa&C_ship_state=ON&C_ship_zip=K1C2N6&C_ship_country=CA&M_id=562313162894&M_key=J6U9B3G2F6L3&T_code=01" +-> "HTTP/1.1 200 OK\r\n" +-> "Cache-Control: no-cache\r\n" +-> "Pragma: no-cache\r\n" +-> "Transfer-Encoding: chunked\r\n" +-> "Content-Type: text/html; charset=us-ascii\r\n" +-> "Content-Encoding: gzip\r\n" +-> "Expires: -1\r\n" +-> "Vary: Accept-Encoding\r\n" +-> "Server: Microsoft-IIS/7.5\r\n" +-> "X-Powered-By: ASP.NET\r\n" +-> "Date: Thu, 02 Nov 2017 13:26:30 GMT\r\n" +-> "Connection: close\r\n" +-> "\r\n" +-> "ac\r\n" +reading 172 bytes... +-> "\x1F\x8B\b\x00\x00\x00\x00\x00\x04\x00\xED\xBD\a`\x1CI\x96%&/m\xCA{\x7FJ\xF5J\xD7\xE0t\xA1\b\x80`\x13$\xD8\x90@\x10\xEC\xC1\x88\xCD\xE6\x92\xEC\x1DiG#)\xAB*\x81\xCAeVe]f\x16@\xCC\xED\x9D\xBC\xF7\xDE{\xEF\xBD\xF7\xDE{\xEF\xBD\xF7\xBA;\x9DN'\xF7\xDF\xFF?\\fd\x01l\xF6\xCEJ\xDA\xC9\x9E!\x80\xAA\xC8\x1F?~|\x1F?\"~\xAD\xE3\x94\x9F\xE3\x93\x93\xD3\x97oN\x9F\xD2\xAF\xD1gg\xE7\xD9\x93\xBDo?\xFC\x89\xAF\x16\xF7v~\xA7\x9Dl\xFA\xE9\xF9l\xF7\xFC\xC1~\xF6\xF0`\x96?\xDC\x9F\x9C?\xFC\x9Dv~\xA7\x17_\xBE8\xA5\x1F\xBF" +read 172 bytes +reading 2 bytes... +-> "\r\n" +read 2 bytes +-> "b\r\n" +reading 11 bytes... +-> "\xF6\xFF\x03\x90\xEB\x1E T\x00\x00\x00" +read 11 bytes +reading 2 bytes... +-> "\r\n" +read 2 bytes +-> "0\r\n" +-> "\r\n" +Conn close + PRE_SCRUBBED + end + + def post_scrubbed_echeck + <<-POST_SCRUBBED +opening connection to www.sagepayments.net:443...\nopened\nstarting SSL for www.sagepayments.net:443...\nSSL established\n<- \"POST /cgi-bin/eftVirtualCheck.dll?transaction HTTP/1.1\r\nContent-Type: application/x-www-form-urlencoded\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nAccept: */*\r\nUser-Agent: Ruby\r\nConnection: close\r\nHost: www.sagepayments.net\r\nContent-Length: 562\r\n\r\n\"\n<- \"C_first_name=Jim&C_last_name=Smith&C_rte=[FILTERED]&C_acct=[FILTERED]&C_check_number=1&C_acct_type=DDA&C_customer_type=WEB&C_originator_id=&T_addenda=&C_ssn=[FILTERED]&C_dl_state_code=&C_dl_number=&C_dob=&T_amt=1.00&T_ordernum=0ac6fd1f74a98de94bf9&C_address=456+My+Street&C_city=Ottawa&C_state=ON&C_zip=K1C2N6&C_country=CA&C_telephone=%28555%29555-5555&C_fax=%28555%29555-6666&C_email=longbob%40example.com&C_ship_name=Jim+Smith&C_ship_address=456+My+Street&C_ship_city=Ottawa&C_ship_state=ON&C_ship_zip=K1C2N6&C_ship_country=CA&M_id=[FILTERED]&M_key=[FILTERED]&T_code=01\"\n-> \"HTTP/1.1 200 OK\r\n\"\n-> \"Cache-Control: no-cache\r\n\"\n-> \"Pragma: no-cache\r\n\"\n-> \"Transfer-Encoding: chunked\r\n\"\n-> \"Content-Type: text/html; charset=us-ascii\r\n\"\n-> \"Content-Encoding: gzip\r\n\"\n-> \"Expires: -1\r\n\"\n-> \"Vary: Accept-Encoding\r\n\"\n-> \"Server: Microsoft-IIS/7.5\r\n\"\n-> \"X-Powered-By: ASP.NET\r\n\"\n-> \"Date: Thu, 02 Nov 2017 13:26:30 GMT\r\n\"\n-> \"Connection: close\r\n\"\n-> \"\r\n\"\n-> \"ac\r\n\"\nreading 172 bytes...\n-> \"\u001F?\b\u0000\u0000\u0000\u0000\u0000\u0004\u0000??\a`\u001CI?%&/m?{\u007FJ?J??t?\b?`\u0013$?@\u0010??????\u001DiG#)?*??eVe]f\u0016@????{???{???;?N'????\\fd\u0001l??J??!???\u001F?~|\u001F?\"~????oN???gg???o????\u0016?v~??l???l???~??`???????v~?\u0017_?8?\u001F?\"\nread 172 bytes\nreading 2 bytes...\n-> \"\r\n\"\nread 2 bytes\n-> \"b\r\n\"\nreading 11 bytes...\n-> \"??\u0003??\u001E T\u0000\u0000\u0000\"\nread 11 bytes\nreading 2 bytes...\n-> \"\r\n\"\nread 2 bytes\n-> \"0\r\n\"\n-> \"\r\n\"\nConn close + POST_SCRUBBED + end end diff --git a/test/unit/gateways/sallie_mae_test.rb b/test/unit/gateways/sallie_mae_test.rb index e8779111f22..40194a47164 100644 --- a/test/unit/gateways/sallie_mae_test.rb +++ b/test/unit/gateways/sallie_mae_test.rb @@ -35,7 +35,7 @@ def test_non_test_account end def test_test_account - gateway = SallieMaeGateway.new(:login => "TEST0") + gateway = SallieMaeGateway.new(:login => 'TEST0') assert gateway.test? end @@ -43,11 +43,11 @@ def test_test_account # Place raw successful response from gateway here def successful_purchase_response - "Status=Accepted" + 'Status=Accepted' end # Place raw failed response from gateway here def failed_purchase_response - "Status=Declined" + 'Status=Declined' end end diff --git a/test/unit/gateways/secure_net_test.rb b/test/unit/gateways/secure_net_test.rb index 495a733ea27..01c9b55c70d 100644 --- a/test/unit/gateways/secure_net_test.rb +++ b/test/unit/gateways/secure_net_test.rb @@ -130,7 +130,7 @@ def test_failure_without_response_reason_text end def test_passes_optional_fields - options = { description: "Good Stuff", invoice_description: "Sweet Invoice", invoice_number: "48" } + options = { description: 'Good Stuff', invoice_description: 'Sweet Invoice', invoice_number: '48' } stub_comms do @gateway.purchase(@amount, @credit_card, options) end.check_request do |endpoint, data, headers| @@ -182,6 +182,11 @@ def test_passes_without_test_mode end.respond_with(successful_purchase_response) end + def test_scrub + assert @gateway.supports_scrubbing? + assert_equal @gateway.scrub(pre_scrubbed), post_scrubbed + end + private # Place raw successful response from gateway here @@ -225,4 +230,49 @@ def failed_refund_response '<GATEWAYRESPONSE xmlns="http://gateway.securenet.com/API/Contracts" xmlns:i="http://www.w3.org/2001/XMLSchema-instance"><ASPREPONSE i:nil="true"/><TRANSACTIONRESPONSE><RESPONSE_CODE>3</RESPONSE_CODE><RESPONSE_REASON_CODE>01R3</RESPONSE_REASON_CODE><RESPONSE_REASON_TEXT>CREDIT CANNOT BE COMPLETED ON AN UNSETTLED TRANSACTION</RESPONSE_REASON_TEXT><RESPONSE_SUBCODE/><ADDITIONALAMOUNT>0</ADDITIONALAMOUNT><ADDITIONALDATA1 i:nil="true"/><ADDITIONALDATA2 i:nil="true"/><ADDITIONALDATA3 i:nil="true"/><ADDITIONALDATA4 i:nil="true"/><ADDITIONALDATA5 i:nil="true"/><AUTHCODE/><AUTHORIZEDAMOUNT>0</AUTHORIZEDAMOUNT><AVS_RESULT_CODE/><BANK_ACCOUNTNAME i:nil="true"/><BANK_ACCOUNTTYPE i:nil="true"/><BATCHID i:nil="true"/><CARDHOLDER_FIRSTNAME i:nil="true"/><CARDHOLDER_LASTNAME i:nil="true"/><CARDLEVEL_RESULTS i:nil="true"/><CARDTYPE i:nil="true"/><CARD_CODE_RESPONSE_CODE/><CASHBACK_AMOUNT>0</CASHBACK_AMOUNT><CAVV_RESPONSE_CODE/><CHECKNUM i:nil="true"/><CODE>0500</CODE><CUSTOMERID/><CUSTOMER_BILL><ADDRESS/><CITY/><COMPANY/><COUNTRY/><EMAIL/><EMAILRECEIPT>FALSE</EMAILRECEIPT><FIRSTNAME/><LASTNAME/><PHONE/><STATE/><ZIP/></CUSTOMER_BILL><EXPIRYDATE i:nil="true"/><GRATUITY>0</GRATUITY><INDUSTRYSPECIFICDATA i:nil="true"/><LAST4DIGITS i:nil="true"/><LEVEL2_VALID>FALSE</LEVEL2_VALID><LEVEL3_VALID>FALSE</LEVEL3_VALID><MARKETSPECIFICDATA i:nil="true"/><METHOD>CC</METHOD><NETWORKCODE i:nil="true"/><NETWORKID i:nil="true"/><ORDERID>1285171984419000</ORDERID><PAYMENTID i:nil="true"/><RETREFERENCENUM i:nil="true"/><SECURENETID>1002550</SECURENETID><SETTLEMENTAMOUNT>0</SETTLEMENTAMOUNT><SETTLEMENTDATETIME i:nil="true"/><SYSTEM_TRACENUM i:nil="true"/><TRACKTYPE i:nil="true"/><TRANSACTIONAMOUNT>1.00</TRANSACTIONAMOUNT><TRANSACTIONDATETIME i:nil="true"/><TRANSACTIONID>0</TRANSACTIONID></TRANSACTIONRESPONSE><VAULTACCOUNTRESPONSE i:nil="true"/><VAULTCUSTOMERRESPONSE i:nil="true"/></GATEWAYRESPONSE>' end + def pre_scrubbed + <<-EOS +opening connection to certify.securenet.com:443... +opened +starting SSL for certify.securenet.com:443... +SSL established +<- "POST /API/gateway.svc/webHttp/ProcessTransaction HTTP/1.1\r\nContent-Type: text/xml\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nAccept: */*\r\nUser-Agent: Ruby\r\nConnection: close\r\nHost: certify.securenet.com\r\nContent-Length: 1044\r\n\r\n" +<- "<?xml version=\"1.0\" encoding=\"UTF-8\"?><TRANSACTION xmlns=\"http://gateway.securenet.com/API/Contracts\" xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\"><AMOUNT>1.00</AMOUNT><CARD><CARDCODE>123</CARDCODE><CARDNUMBER>4000100011112224</CARDNUMBER><EXPDATE>0919</EXPDATE></CARD><CODE>0100</CODE><CUSTOMER_BILL><ADDRESS>456 My Street</ADDRESS><CITY>Ottawa</CITY><COMPANY>Widgets Inc</COMPANY><COUNTRY>CA</COUNTRY><FIRSTNAME>Longbob</FIRSTNAME><LASTNAME>Longsen</LASTNAME><PHONE>(555)555-5555</PHONE><STATE>ON</STATE><ZIP>K1C2N6</ZIP></CUSTOMER_BILL><CUSTOMER_SHIP i:nil=\"true\"></CUSTOMER_SHIP><DCI>0</DCI><INSTALLMENT_SEQUENCENUM>1</INSTALLMENT_SEQUENCENUM><MERCHANT_KEY><GROUPID>0</GROUPID><SECUREKEY>BI8gL8HO1dKP</SECUREKEY><SECURENETID>7001218</SECURENETID></MERCHANT_KEY><METHOD>CC</METHOD><NOTE>Store Purchase</NOTE><ORDERID>1519921868962609</ORDERID><OVERRIDE_FROM>0</OVERRIDE_FROM><RETAIL_LANENUM>0</RETAIL_LANENUM><TEST>TRUE</TEST><TOTAL_INSTALLMENTCOUNT>0</TOTAL_INSTALLMENTCOUNT><TRANSACTION_SERVICE>0</TRANSACTION_SERVICE></TRANSACTION>" +-> "HTTP/1.1 200 OK\r\n" +-> "Content-Length: 2547\r\n" +-> "Content-Type: application/xml; charset=utf-8\r\n" +-> "X-Powered-By: ASP.NET\r\n" +-> "Date: Thu, 01 Mar 2018 16:31:01 GMT\r\n" +-> "Connection: close\r\n" +-> "Set-Cookie: TS01e56b0e=010bfb2c76b6671aabf6f176a4e5aefd8e7a6ce7f697d82dfcfd424edede4ae7d4dba7557a4a7a13a539cfc1c5c061e08d5040811a; Path=/\r\n" +-> "\r\n" +reading 2547 bytes... +-> "<GATEWAYRESPONSE xmlns=\"http://gateway.securenet.com/API/Contracts\" xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\"><ABRESPONSE i:nil=\"true\"/><TRANSACTIONRESPONSE><RESPONSE_CODE>1</RESPONSE_CODE><RESPONSE_REASON_CODE>0000</RESPONSE_REASON_CODE><RESPONSE_REASON_TEXT>Approved</RESPONSE_REASON_TEXT><RESPONSE_SUBCODE/><ADDITIONALAMOUNT>0</ADDITIONALAMOUNT><ADDITIONALDATA1/><ADDITIONALDATA2/><ADDITIONALDATA3/><ADDITIONALDATA4/><ADDITIONALDATA5/><AUTHCODE>JUJQLQ</AUTHCODE><AUTHORIZATIONMODE i:nil=\"true\"/><AUTHORIZEDAMOUNT>1.00</AUTHORIZEDAMOUNT><AVS_RESULT_CODE>Y</AVS_RESULT_CODE><BANK_ACCOUNTNAME/><BANK_ACCOUNTTYPE/><BATCHID>0</BATCHID><CALLID/><CARDENTRYMODE i:nil=\"true\"/><CARDHOLDERVERIFICATION i:nil=\"true\"/><CARDHOLDER_FIRSTNAME>Longbob</CARDHOLDER_FIRSTNAME><CARDHOLDER_LASTNAME>Longsen</CARDHOLDER_LASTNAME><CARDLEVEL_RESULTS/><CARDTYPE>VI</CARDTYPE><CARD_CODE_RESPONSE_CODE>M</CARD_CODE_RESPONSE_CODE><CASHBACK_AMOUNT>0</CASHBACK_AMOUNT><CATINDICATOR>0</CATINDICATOR><CAVV_RESPONSE_CODE/><CHECKNUM i:nil=\"true\"/><CODE>0100</CODE><CUSTOMERID/><CUSTOMER_BILL><ADDRESS>456 My Street</ADDRESS><CITY>Ottawa</CITY><COMPANY>Widgets Inc</COMPANY><COUNTRY>CA</COUNTRY><EMAIL/><EMAILRECEIPT>FALSE</EMAILRECEIPT><FIRSTNAME>Longbob</FIRSTNAME><LASTNAME>Longsen</LASTNAME><PHONE>(555)555-5555</PHONE><STATE>ON</STATE><ZIP>K1C2N6</ZIP></CUSTOMER_BILL><DYNAMICMCC i:nil=\"true\"/><EMVRESPONSE><ISSUERAUTHENTICATIONDATA i:nil=\"true\"/><ISSUERSCRIPTTEMPLATE1 i:nil=\"true\"/><ISSUERSCRIPTTEMPLATE2 i:nil=\"true\"/></EMVRESPONSE><EXPIRYDATE>0919</EXPIRYDATE><GRATUITY>0</GRATUITY><INDUSTRYSPECIFICDATA>P</INDUSTRYSPECIFICDATA><INVOICEDESCRIPTION i:nil=\"true\"/><LAST4DIGITS>2224</LAST4DIGITS><LEVEL2_VALID>FALSE</LEVEL2_VALID><LEVEL3_VALID>FALSE</LEVEL3_VALID><MARKETSPECIFICDATA/><METHOD>CC</METHOD><NETWORKCODE/><NETWORKID/><NOTES>Store Purchase</NOTES><ORDERID>1519921868962609</ORDERID><PAYMENTID/><RETREFERENCENUM/><RISK_CATEGORY i:nil=\"true\"/><RISK_REASON1 i:nil=\"true\"/><RISK_REASON2 i:nil=\"true\"/><RISK_REASON3 i:nil=\"true\"/><RISK_REASON4 i:nil=\"true\"/><RISK_REASON5 i:nil=\"true\"/><SECURENETID>7001218</SECURENETID><SETTLEMENTAMOUNT>1.00</SETTLEMENTAMOUNT><SETTLEMENTDATETIME>03012018113101</SETTLEMENTDATETIME><SOFTDESCRIPTOR/><SYSTEM_TRACENUM/><TRACKTYPE>0</TRACKTYPE><TRANSACTIONAMOUNT>1.00</TRANSACTIONAMOUNT><TRANSACTIONDATETIME>03012018113101</TRANSACTIONDATETIME><TRANSACTIONID>116186071</TRANSACTIONID><USERDEFINED i:nil=\"true\"/></TRANSACTIONRESPONSE><VAULTACCOUNTRESPONSE i:nil=\"true\"/><VAULTCUSTOMERRESPONSE i:nil=\"true\"/></GATEWAYRESPONSE>" +read 2547 bytes +Conn close + EOS + end + + def post_scrubbed + <<-EOS +opening connection to certify.securenet.com:443... +opened +starting SSL for certify.securenet.com:443... +SSL established +<- "POST /API/gateway.svc/webHttp/ProcessTransaction HTTP/1.1\r\nContent-Type: text/xml\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nAccept: */*\r\nUser-Agent: Ruby\r\nConnection: close\r\nHost: certify.securenet.com\r\nContent-Length: 1044\r\n\r\n" +<- "<?xml version=\"1.0\" encoding=\"UTF-8\"?><TRANSACTION xmlns=\"http://gateway.securenet.com/API/Contracts\" xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\"><AMOUNT>1.00</AMOUNT><CARD><CARDCODE>[FILTERED]</CARDCODE><CARDNUMBER>[FILTERED]</CARDNUMBER><EXPDATE>0919</EXPDATE></CARD><CODE>0100</CODE><CUSTOMER_BILL><ADDRESS>456 My Street</ADDRESS><CITY>Ottawa</CITY><COMPANY>Widgets Inc</COMPANY><COUNTRY>CA</COUNTRY><FIRSTNAME>Longbob</FIRSTNAME><LASTNAME>Longsen</LASTNAME><PHONE>(555)555-5555</PHONE><STATE>ON</STATE><ZIP>K1C2N6</ZIP></CUSTOMER_BILL><CUSTOMER_SHIP i:nil=\"true\"></CUSTOMER_SHIP><DCI>0</DCI><INSTALLMENT_SEQUENCENUM>1</INSTALLMENT_SEQUENCENUM><MERCHANT_KEY><GROUPID>0</GROUPID><SECUREKEY>[FILTERED]</SECUREKEY><SECURENETID>7001218</SECURENETID></MERCHANT_KEY><METHOD>CC</METHOD><NOTE>Store Purchase</NOTE><ORDERID>1519921868962609</ORDERID><OVERRIDE_FROM>0</OVERRIDE_FROM><RETAIL_LANENUM>0</RETAIL_LANENUM><TEST>TRUE</TEST><TOTAL_INSTALLMENTCOUNT>0</TOTAL_INSTALLMENTCOUNT><TRANSACTION_SERVICE>0</TRANSACTION_SERVICE></TRANSACTION>" +-> "HTTP/1.1 200 OK\r\n" +-> "Content-Length: 2547\r\n" +-> "Content-Type: application/xml; charset=utf-8\r\n" +-> "X-Powered-By: ASP.NET\r\n" +-> "Date: Thu, 01 Mar 2018 16:31:01 GMT\r\n" +-> "Connection: close\r\n" +-> "Set-Cookie: TS01e56b0e=010bfb2c76b6671aabf6f176a4e5aefd8e7a6ce7f697d82dfcfd424edede4ae7d4dba7557a4a7a13a539cfc1c5c061e08d5040811a; Path=/\r\n" +-> "\r\n" +reading 2547 bytes... +-> "<GATEWAYRESPONSE xmlns=\"http://gateway.securenet.com/API/Contracts\" xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\"><ABRESPONSE i:nil=\"true\"/><TRANSACTIONRESPONSE><RESPONSE_CODE>1</RESPONSE_CODE><RESPONSE_REASON_CODE>0000</RESPONSE_REASON_CODE><RESPONSE_REASON_TEXT>Approved</RESPONSE_REASON_TEXT><RESPONSE_SUBCODE/><ADDITIONALAMOUNT>0</ADDITIONALAMOUNT><ADDITIONALDATA1/><ADDITIONALDATA2/><ADDITIONALDATA3/><ADDITIONALDATA4/><ADDITIONALDATA5/><AUTHCODE>JUJQLQ</AUTHCODE><AUTHORIZATIONMODE i:nil=\"true\"/><AUTHORIZEDAMOUNT>1.00</AUTHORIZEDAMOUNT><AVS_RESULT_CODE>Y</AVS_RESULT_CODE><BANK_ACCOUNTNAME/><BANK_ACCOUNTTYPE/><BATCHID>0</BATCHID><CALLID/><CARDENTRYMODE i:nil=\"true\"/><CARDHOLDERVERIFICATION i:nil=\"true\"/><CARDHOLDER_FIRSTNAME>Longbob</CARDHOLDER_FIRSTNAME><CARDHOLDER_LASTNAME>Longsen</CARDHOLDER_LASTNAME><CARDLEVEL_RESULTS/><CARDTYPE>VI</CARDTYPE><CARD_CODE_RESPONSE_CODE>M</CARD_CODE_RESPONSE_CODE><CASHBACK_AMOUNT>0</CASHBACK_AMOUNT><CATINDICATOR>0</CATINDICATOR><CAVV_RESPONSE_CODE/><CHECKNUM i:nil=\"true\"/><CODE>0100</CODE><CUSTOMERID/><CUSTOMER_BILL><ADDRESS>456 My Street</ADDRESS><CITY>Ottawa</CITY><COMPANY>Widgets Inc</COMPANY><COUNTRY>CA</COUNTRY><EMAIL/><EMAILRECEIPT>FALSE</EMAILRECEIPT><FIRSTNAME>Longbob</FIRSTNAME><LASTNAME>Longsen</LASTNAME><PHONE>(555)555-5555</PHONE><STATE>ON</STATE><ZIP>K1C2N6</ZIP></CUSTOMER_BILL><DYNAMICMCC i:nil=\"true\"/><EMVRESPONSE><ISSUERAUTHENTICATIONDATA i:nil=\"true\"/><ISSUERSCRIPTTEMPLATE1 i:nil=\"true\"/><ISSUERSCRIPTTEMPLATE2 i:nil=\"true\"/></EMVRESPONSE><EXPIRYDATE>0919</EXPIRYDATE><GRATUITY>0</GRATUITY><INDUSTRYSPECIFICDATA>P</INDUSTRYSPECIFICDATA><INVOICEDESCRIPTION i:nil=\"true\"/><LAST4DIGITS>2224</LAST4DIGITS><LEVEL2_VALID>FALSE</LEVEL2_VALID><LEVEL3_VALID>FALSE</LEVEL3_VALID><MARKETSPECIFICDATA/><METHOD>CC</METHOD><NETWORKCODE/><NETWORKID/><NOTES>Store Purchase</NOTES><ORDERID>1519921868962609</ORDERID><PAYMENTID/><RETREFERENCENUM/><RISK_CATEGORY i:nil=\"true\"/><RISK_REASON1 i:nil=\"true\"/><RISK_REASON2 i:nil=\"true\"/><RISK_REASON3 i:nil=\"true\"/><RISK_REASON4 i:nil=\"true\"/><RISK_REASON5 i:nil=\"true\"/><SECURENETID>7001218</SECURENETID><SETTLEMENTAMOUNT>1.00</SETTLEMENTAMOUNT><SETTLEMENTDATETIME>03012018113101</SETTLEMENTDATETIME><SOFTDESCRIPTOR/><SYSTEM_TRACENUM/><TRACKTYPE>0</TRACKTYPE><TRANSACTIONAMOUNT>1.00</TRANSACTIONAMOUNT><TRANSACTIONDATETIME>03012018113101</TRANSACTIONDATETIME><TRANSACTIONID>116186071</TRANSACTIONID><USERDEFINED i:nil=\"true\"/></TRANSACTIONRESPONSE><VAULTACCOUNTRESPONSE i:nil=\"true\"/><VAULTCUSTOMERRESPONSE i:nil=\"true\"/></GATEWAYRESPONSE>" +read 2547 bytes +Conn close + EOS + end end diff --git a/test/unit/gateways/secure_pay_au_test.rb b/test/unit/gateways/secure_pay_au_test.rb index af937c7910a..5d995aab6f8 100644 --- a/test/unit/gateways/secure_pay_au_test.rb +++ b/test/unit/gateways/secure_pay_au_test.rb @@ -27,7 +27,6 @@ def test_supported_card_types assert_equal [:visa, :master, :american_express, :diners_club, :jcb], SecurePayAuGateway.supported_cardtypes end - def test_successful_purchase_with_live_data @gateway.expects(:ssl_post).returns(successful_live_purchase_response) @@ -71,13 +70,13 @@ def test_failed_purchase assert_instance_of Response, response assert_failure response assert response.test? - assert_equal "CARD EXPIRED", response.message + assert_equal 'CARD EXPIRED', response.message end def test_purchase_with_stored_id_calls_commit_periodic @gateway.expects(:commit_periodic) - @gateway.purchase(@amount, "123", @options) + @gateway.purchase(@amount, '123', @options) end def test_purchase_with_creditcard_calls_commit_with_purchase @@ -100,59 +99,59 @@ def test_failed_authorization assert response = @gateway.authorize(@amount, @credit_card, @options) assert_failure response - assert_equal "Insufficient Funds", response.message + assert_equal 'Insufficient Funds', response.message end def test_successful_capture @gateway.expects(:ssl_post).returns(successful_capture_response) - assert response = @gateway.capture(@amount, "crazy*reference*thingy*100", {}) + assert response = @gateway.capture(@amount, 'crazy*reference*thingy*100', {}) assert_success response - assert_equal "Approved", response.message + assert_equal 'Approved', response.message end def test_failed_capture @gateway.expects(:ssl_post).returns(failed_capture_response) - assert response = @gateway.capture(@amount, "crazy*reference*thingy*100") + assert response = @gateway.capture(@amount, 'crazy*reference*thingy*100') assert_failure response - assert_equal "Preauth was done for smaller amount", response.message + assert_equal 'Preauth was done for smaller amount', response.message end def test_successful_refund @gateway.expects(:ssl_post).returns(successful_refund_response) - assert_success @gateway.refund(@amount, "crazy*reference*thingy*100", {}) + assert_success @gateway.refund(@amount, 'crazy*reference*thingy*100', {}) end def test_failed_refund @gateway.expects(:ssl_post).returns(failed_refund_response) - assert response = @gateway.refund(@amount, "crazy*reference*thingy*100") + assert response = @gateway.refund(@amount, 'crazy*reference*thingy*100') assert_failure response - assert_equal "Only $1.00 available for refund", response.message + assert_equal 'Only $1.00 available for refund', response.message end def test_deprecated_credit @gateway.expects(:ssl_post).returns(successful_refund_response) assert_deprecation_warning(Gateway::CREDIT_DEPRECATION_MESSAGE) do - assert_success @gateway.credit(@amount, "crazy*reference*thingy*100", {}) + assert_success @gateway.credit(@amount, 'crazy*reference*thingy*100', {}) end end def test_successful_void @gateway.expects(:ssl_post).returns(successful_void_response) - assert response = @gateway.void("crazy*reference*thingy*100", {}) + assert response = @gateway.void('crazy*reference*thingy*100', {}) assert_success response end def test_failed_void @gateway.expects(:ssl_post).returns(failed_void_response) - assert response = @gateway.void("crazy*reference*thingy*100") + assert response = @gateway.void('crazy*reference*thingy*100') assert_failure response - assert_equal "Transaction was done for different amount", response.message + assert_equal 'Transaction was done for different amount', response.message end def test_failed_login @@ -161,7 +160,7 @@ def test_failed_login assert response = @gateway.purchase(@amount, @credit_card, @options) assert_instance_of Response, response assert_failure response - assert_equal "Invalid merchant ID", response.message + assert_equal 'Invalid merchant ID', response.message end def test_successful_store @@ -169,7 +168,7 @@ def test_successful_store assert response = @gateway.store(@credit_card, {:billing_id => 'test3', :amount => 123}) assert_instance_of Response, response - assert_equal "Successful", response.message + assert_equal 'Successful', response.message assert_equal 'test3', response.params['client_id'] end @@ -178,7 +177,7 @@ def test_successful_unstore assert response = @gateway.unstore('test2') assert_instance_of Response, response - assert_equal "Successful", response.message + assert_equal 'Successful', response.message assert_equal 'test2', response.params['client_id'] end @@ -187,7 +186,7 @@ def test_successful_triggered_payment assert response = @gateway.purchase(@amount, 'test3', @options) assert_instance_of Response, response - assert_equal "Approved", response.message + assert_equal 'Approved', response.message assert_equal 'test3', response.params['client_id'] end @@ -202,7 +201,7 @@ def test_supports_scrubbing? private def successful_store_response - <<-XML.gsub(/^\s{4}/,'') + <<-XML.gsub(/^\s{4}/, '') <?xml version="1.0" encoding="UTF-8"?> <SecurePayMessage> <MessageInfo> @@ -241,7 +240,7 @@ def successful_store_response end def successful_unstore_response - <<-XML.gsub(/^\s{4}/,'') + <<-XML.gsub(/^\s{4}/, '') <?xml version="1.0" encoding="UTF-8"?> <SecurePayMessage> <MessageInfo> @@ -273,7 +272,7 @@ def successful_unstore_response end def successful_triggered_payment_response - <<-XML.gsub(/^\s{4}/,'') + <<-XML.gsub(/^\s{4}/, '') <?xml version="1.0" encoding="UTF-8"?> <SecurePayMessage> <MessageInfo> @@ -319,7 +318,7 @@ def failed_login_response end def successful_purchase_response - <<-XML.gsub(/^\s{4}/,'') + <<-XML.gsub(/^\s{4}/, '') <?xml version="1.0" encoding="UTF-8"?> <SecurePayMessage> <MessageInfo> @@ -366,7 +365,7 @@ def successful_purchase_response end def failed_purchase_response - <<-XML.gsub(/^\s{4}/,'') + <<-XML.gsub(/^\s{4}/, '') <?xml version="1.0" encoding="UTF-8"?> <SecurePayMessage> <MessageInfo> @@ -413,7 +412,7 @@ def failed_purchase_response end def successful_live_purchase_response - <<-XML.gsub(/^\s{4}/,'') + <<-XML.gsub(/^\s{4}/, '') <?xml version="1.0" encoding="UTF-8"?> <SecurePayMessage> <MessageInfo> diff --git a/test/unit/gateways/secure_pay_tech_test.rb b/test/unit/gateways/secure_pay_tech_test.rb index 008f447cbc7..87293a7f817 100644 --- a/test/unit/gateways/secure_pay_tech_test.rb +++ b/test/unit/gateways/secure_pay_tech_test.rb @@ -13,31 +13,32 @@ def setup :billing_address => address } end - + def test_successful_purchase @gateway.expects(:ssl_post).returns(successful_purchase_response) - + assert response = @gateway.purchase(@amount, @credit_card, @options) assert_instance_of Response, response assert_success response assert response.test? assert_equal '4--120119220646821', response.authorization end - + def test_unsuccessful_purchase @gateway.expects(:ssl_post).returns(unsuccessful_purchase_response) - + assert response = @gateway.purchase(@amount, @credit_card, @options) assert_instance_of Response, response assert_failure response assert response.test? end - + private + def successful_purchase_response "1,4--120119220646821,000000014511,23284,014511,20080125\r\n" end - + def unsuccessful_purchase_response "4,4--120119180936527,000000014510,23283,014510,20080125\r\n" end diff --git a/test/unit/gateways/secure_pay_test.rb b/test/unit/gateways/secure_pay_test.rb index 2a897b6a2fd..0fdc3b08493 100644 --- a/test/unit/gateways/secure_pay_test.rb +++ b/test/unit/gateways/secure_pay_test.rb @@ -48,7 +48,6 @@ def test_successful_purchase assert response.authorization end - def test_avs_result @gateway.expects(:ssl_post).returns(successful_purchase_response) diff --git a/test/unit/gateways/securion_pay_test.rb b/test/unit/gateways/securion_pay_test.rb index 829976987da..06fbe0ff622 100644 --- a/test/unit/gateways/securion_pay_test.rb +++ b/test/unit/gateways/securion_pay_test.rb @@ -5,7 +5,7 @@ class SecurionPayTest < Test::Unit::TestCase def setup @gateway = SecurionPayGateway.new( - secret_key: 'pr_test_SyMyCpIJosFIAESEsZUd3TgN', + secret_key: 'pr_test_SyMyCpIJosFIAESEsZUd3TgN' ) @credit_card = credit_card @@ -28,9 +28,9 @@ def test_successful_store response = @gateway.store(@credit_card, @options) assert_success response assert_match %r(^cust_\w+$), response.authorization - assert_equal "customer", response.params["objectType"] - assert_match %r(^card_\w+$), response.params["cards"][0]["id"] - assert_equal "card", response.params["cards"][0]["objectType"] + assert_equal 'customer', response.params['objectType'] + assert_match %r(^card_\w+$), response.params['cards'][0]['id'] + assert_equal 'card', response.params['cards'][0]['objectType'] @gateway.expects(:ssl_post).returns(successful_authorize_response) @gateway.expects(:ssl_post).returns(successful_void_response) @@ -38,18 +38,18 @@ def test_successful_store @options[:customer_id] = response.authorization response = @gateway.store(@new_credit_card, @options) assert_success response - assert_match %r(^card_\w+$), response.params["card"]["id"] - assert_equal @options[:customer_id], response.params["card"]["customerId"] + assert_match %r(^card_\w+$), response.params['card']['id'] + assert_equal @options[:customer_id], response.params['card']['customerId'] @gateway.expects(:ssl_request).returns(successful_customer_update_response) response = @gateway.customer(@options) assert_success response - assert_equal @options[:customer_id], response.params["id"] - assert_equal "401288", response.params["cards"][0]["first6"] - assert_equal "1881", response.params["cards"][0]["last4"] - assert_equal "424242", response.params["cards"][1]["first6"] - assert_equal "4242", response.params["cards"][1]["last4"] + assert_equal @options[:customer_id], response.params['id'] + assert_equal '401288', response.params['cards'][0]['first6'] + assert_equal '1881', response.params['cards'][0]['last4'] + assert_equal '424242', response.params['cards'][1]['first6'] + assert_equal '4242', response.params['cards'][1]['last4'] end def test_successful_purchase @@ -65,7 +65,7 @@ def test_successful_purchase def test_successful_purchase_with_token response = stub_comms(@gateway, :ssl_request) do - @gateway.purchase(@amount, "tok_xxx") + @gateway.purchase(@amount, 'tok_xxx') end.check_request do |method, endpoint, data, headers| assert_match(/card=tok_xxx/, data) refute_match(/card\[number\]/, data) @@ -86,8 +86,8 @@ def test_invalid_raw_response def test_client_data_submitted_with_purchase stub_comms(@gateway, :ssl_request) do - updated_options = @options.merge({ description: "test charge", ip: "127.127.127.127", user_agent: "browser XXX", referrer: "http://www.foobar.com", email: "foo@bar.com" }) - @gateway.purchase(@amount,@credit_card,updated_options) + updated_options = @options.merge({ description: 'test charge', ip: '127.127.127.127', user_agent: 'browser XXX', referrer: 'http://www.foobar.com', email: 'foo@bar.com' }) + @gateway.purchase(@amount, @credit_card, updated_options) end.check_request do |method, endpoint, data, headers| assert_match(/description=test\+charge/, data) assert_match(/ip=127\.127\.127\.127/, data) @@ -99,8 +99,8 @@ def test_client_data_submitted_with_purchase def test_client_data_submitted_with_purchase_without_email_or_order stub_comms(@gateway, :ssl_request) do - updated_options = @options.merge({ description: "test charge", ip: "127.127.127.127", user_agent: "browser XXX", referrer: "http://www.foobar.com" }) - @gateway.purchase(@amount,@credit_card,updated_options) + updated_options = @options.merge({ description: 'test charge', ip: '127.127.127.127', user_agent: 'browser XXX', referrer: 'http://www.foobar.com' }) + @gateway.purchase(@amount, @credit_card, updated_options) end.check_request do |method, endpoint, data, headers| assert_match(/description=test\+charge/, data) assert_match(/ip=127\.127\.127\.127/, data) @@ -177,7 +177,7 @@ def test_failed_authorize def test_successful_capture @gateway.expects(:ssl_request).returns(successful_capture_response) - response = @gateway.capture(@amount, "char_CqH9rftszMnaMYBrgtVI49LM", @options) + response = @gateway.capture(@amount, 'char_CqH9rftszMnaMYBrgtVI49LM', @options) assert_instance_of Response, response assert_success response assert response.test? @@ -186,7 +186,7 @@ def test_successful_capture def test_failed_capture @gateway.expects(:ssl_request).returns(failed_capture_response) - response = @gateway.capture(@amount, "invalid_authorization_token", @options) + response = @gateway.capture(@amount, 'invalid_authorization_token', @options) assert_failure response assert_match(/^Requested Charge does not exist/, response.message) assert_nil response.authorization @@ -199,10 +199,10 @@ def test_successful_full_refund response = @gateway.refund(@amount, 'char_DQca5ZjbewP2Oe0lIsNe4EXP', @options) assert_instance_of Response, response assert_success response - assert response.params["refunded"] - assert_equal 0, response.params["amount"] - assert_equal 1, response.params["refunds"].size - assert_equal @amount, response.params["refunds"].map{|r| r["amount"]}.sum + assert response.params['refunded'] + assert_equal 0, response.params['amount'] + assert_equal 1, response.params['refunds'].size + assert_equal @amount, response.params['refunds'].map { |r| r['amount'] }.sum assert_equal 'char_DQca5ZjbewP2Oe0lIsNe4EXP', response.authorization assert response.test? end @@ -213,9 +213,9 @@ def test_successful_partially_refund response = @gateway.refund(@refund_amount, 'char_oVnJ1j6fZqOvnopBBvlnpEuX', @options) assert_instance_of Response, response assert_success response - assert response.params["refunded"] - assert_equal @amount - @refund_amount, response.params["amount"] - assert_equal @refund_amount, response.params["refunds"].map{|r| r["amount"]}.sum + assert response.params['refunded'] + assert_equal @amount - @refund_amount, response.params['amount'] + assert_equal @refund_amount, response.params['refunds'].map { |r| r['amount'] }.sum assert_equal 'char_oVnJ1j6fZqOvnopBBvlnpEuX', response.authorization assert response.test? end @@ -252,7 +252,7 @@ def test_failed_authorization_void response = @gateway.void('invalid_authorization_token', @options) assert_failure response - assert_equal "Requested Charge does not exist", response.message + assert_equal 'Requested Charge does not exist', response.message assert_nil response.authorization end @@ -268,7 +268,7 @@ def test_successful_verify_with_failed_void @gateway.verify(@credit_card, @options) end.respond_with(successful_authorize_response, failed_void_response) assert_success response - assert_equal "Transaction approved", response.message + assert_equal 'Transaction approved', response.message end def test_failed_verify @@ -276,7 +276,7 @@ def test_failed_verify @gateway.verify(@declined_card, @options) end.respond_with(failed_authorize_response, successful_void_response) assert_failure response - assert_equal "The card was declined for other reason.", response.message + assert_equal 'The card was declined for other reason.', response.message end def test_scrub diff --git a/test/unit/gateways/skip_jack_test.rb b/test/unit/gateways/skip_jack_test.rb index 273508220ee..6df67c6a94e 100644 --- a/test/unit/gateways/skip_jack_test.rb +++ b/test/unit/gateways/skip_jack_test.rb @@ -60,7 +60,7 @@ def test_purchase_success response = @gateway.purchase(@amount, @credit_card, @options) assert_success response - assert_equal "9802853155172.022", response.authorization + assert_equal '9802853155172.022', response.authorization end def test_purchase_failure @@ -131,49 +131,49 @@ def test_cvv_result def test_basic_test_url @gateway.stubs(:test?).returns(true) @gateway.stubs(:advanced?).returns(false) - assert_equal "https://developer.skipjackic.com/scripts/evolvcc.dll?AuthorizeAPI", @gateway.send(:url_for, :authorization) + assert_equal 'https://developer.skipjackic.com/scripts/evolvcc.dll?AuthorizeAPI', @gateway.send(:url_for, :authorization) end def test_basic_test_url_non_authorization @gateway.stubs(:test?).returns(true) @gateway.stubs(:advanced?).returns(false) - assert_equal "https://developer.skipjackic.com/scripts/evolvcc.dll?SJAPI_TransactionChangeStatusRequest", @gateway.send(:url_for, :change_status) + assert_equal 'https://developer.skipjackic.com/scripts/evolvcc.dll?SJAPI_TransactionChangeStatusRequest', @gateway.send(:url_for, :change_status) end def test_advanced_test_url @gateway.stubs(:test?).returns(true) @gateway.stubs(:advanced?).returns(true) - assert_equal "https://developer.skipjackic.com/evolvcc/evolvcc.aspx?AuthorizeAPI", @gateway.send(:url_for, :authorization) + assert_equal 'https://developer.skipjackic.com/evolvcc/evolvcc.aspx?AuthorizeAPI', @gateway.send(:url_for, :authorization) end def test_advanced_test_url_non_authorization @gateway.stubs(:test?).returns(true) @gateway.stubs(:advanced?).returns(true) - assert_equal "https://developer.skipjackic.com/scripts/evolvcc.dll?SJAPI_TransactionChangeStatusRequest", @gateway.send(:url_for, :change_status) + assert_equal 'https://developer.skipjackic.com/scripts/evolvcc.dll?SJAPI_TransactionChangeStatusRequest', @gateway.send(:url_for, :change_status) end def test_basic_live_url @gateway.stubs(:test?).returns(false) @gateway.stubs(:advanced?).returns(false) - assert_equal "https://www.skipjackic.com/scripts/evolvcc.dll?AuthorizeAPI", @gateway.send(:url_for, :authorization) + assert_equal 'https://www.skipjackic.com/scripts/evolvcc.dll?AuthorizeAPI', @gateway.send(:url_for, :authorization) end def test_basic_live_url_non_authorization @gateway.stubs(:test?).returns(false) @gateway.stubs(:advanced?).returns(false) - assert_equal "https://www.skipjackic.com/scripts/evolvcc.dll?SJAPI_TransactionChangeStatusRequest", @gateway.send(:url_for, :change_status) + assert_equal 'https://www.skipjackic.com/scripts/evolvcc.dll?SJAPI_TransactionChangeStatusRequest', @gateway.send(:url_for, :change_status) end def test_advanced_live_url @gateway.stubs(:test?).returns(false) @gateway.stubs(:advanced?).returns(true) - assert_equal "https://www.skipjackic.com/evolvcc/evolvcc.aspx?AuthorizeAPI", @gateway.send(:url_for, :authorization) + assert_equal 'https://www.skipjackic.com/evolvcc/evolvcc.aspx?AuthorizeAPI', @gateway.send(:url_for, :authorization) end def test_advanced_live_url_non_authorization @gateway.stubs(:test?).returns(false) @gateway.stubs(:advanced?).returns(true) - assert_equal "https://www.skipjackic.com/scripts/evolvcc.dll?SJAPI_TransactionChangeStatusRequest", @gateway.send(:url_for, :change_status) + assert_equal 'https://www.skipjackic.com/scripts/evolvcc.dll?SJAPI_TransactionChangeStatusRequest', @gateway.send(:url_for, :change_status) end def test_paymentech_authorization_success @@ -193,9 +193,10 @@ def test_paymentech_authorization_failure assert_failure response end - def test_serial_number_is_added_before_developer_serial_number_for_authorization - @gateway.expects(:ssl_post).with('https://developer.skipjackic.com/scripts/evolvcc.dll?AuthorizeAPI', "Year=#{Time.now.year + 1}&TransactionAmount=1.00&ShipToPhone=&SerialNumber=X&SJName=Longbob+Longsen&OrderString=1%7ENone%7E0.00%7E0%7EN%7E%7C%7C&OrderNumber=1&OrderDescription=&Month=9&InvoiceNumber=&Email=cody%40example.com&DeveloperSerialNumber=Y&CustomerCode=&CVV2=123&AccountNumber=4242424242424242").returns(successful_authorization_response) + expected ="Year=#{Time.now.year + 1}&TransactionAmount=1.00&ShipToPhone=&SerialNumber=X&SJName=Longbob+Longsen&OrderString=1~None~0.00~0~N~%7C%7C&OrderNumber=1&OrderDescription=&Month=9&InvoiceNumber=&Email=cody%40example.com&DeveloperSerialNumber=Y&CustomerCode=&CVV2=123&AccountNumber=4242424242424242" + expected = expected.gsub('~', '%7E') if RUBY_VERSION < '2.5.0' + @gateway.expects(:ssl_post).with('https://developer.skipjackic.com/scripts/evolvcc.dll?AuthorizeAPI', expected).returns(successful_authorization_response) @gateway.authorize(@amount, @credit_card, @options) end @@ -205,7 +206,7 @@ def test_serial_number_is_added_before_developer_serial_number_for_capture response = @gateway.authorize(@amount, @credit_card, @options) @gateway.expects(:ssl_post).with('https://developer.skipjackic.com/scripts/evolvcc.dll?SJAPI_TransactionChangeStatusRequest', "szTransactionId=#{response.authorization}&szSerialNumber=X&szForceSettlement=0&szDeveloperSerialNumber=Y&szDesiredStatus=SETTLE&szAmount=1.00").returns(successful_capture_response) - response = @gateway.capture(@amount, response.authorization) + @gateway.capture(@amount, response.authorization) end def test_successful_partial_capture @@ -215,7 +216,7 @@ def test_successful_partial_capture @gateway.expects(:ssl_post).with('https://developer.skipjackic.com/scripts/evolvcc.dll?SJAPI_TransactionChangeStatusRequest', "szTransactionId=#{response.authorization}&szSerialNumber=X&szForceSettlement=0&szDeveloperSerialNumber=Y&szDesiredStatus=SETTLE&szAmount=1.00").returns(successful_capture_response) response = @gateway.capture(@amount/2, response.authorization) - assert_equal "1.0000", response.params["TransactionAmount"] + assert_equal '1.0000', response.params['TransactionAmount'] end def test_dont_send_blank_state @@ -233,6 +234,7 @@ def test_dont_send_blank_state end private + def successful_authorization_response <<-CSV "AUTHCODE","szSerialNumber","szTransactionAmount","szAuthorizationDeclinedMessage","szAVSResponseCode","szAVSResponseMessage","szOrderNumber","szAuthorizationResponseCode","szIsApproved","szCVV2ResponseCode","szCVV2ResponseMessage","szReturnCode","szTransactionFileName","szCAVVResponseCode" @@ -274,4 +276,3 @@ def successful_paymentech_authorization_response CSV end end - diff --git a/test/unit/gateways/so_easy_pay_test.rb b/test/unit/gateways/so_easy_pay_test.rb index daa8a9f9d35..94a7f913a80 100644 --- a/test/unit/gateways/so_easy_pay_test.rb +++ b/test/unit/gateways/so_easy_pay_test.rb @@ -52,7 +52,7 @@ def test_successful_authorize def test_successful_capture @gateway.expects(:ssl_post).returns(successful_capture_response) - assert response = @gateway.capture(1111, "1708980") + assert response = @gateway.capture(1111, '1708980') assert_instance_of Response, response assert_success response @@ -87,7 +87,7 @@ def test_do_not_depend_on_expiry_date_class def test_use_ducktyping_for_credit_card @gateway.expects(:ssl_post).returns(successful_purchase_response) - credit_card = stub(:number => '4242424242424242', :verification_value => '123', :name => "Hans Tester", :year => 2012, :month => 1) + credit_card = stub(:number => '4242424242424242', :verification_value => '123', :name => 'Hans Tester', :year => 2012, :month => 1) assert_nothing_raised do assert_success @gateway.purchase(@amount, credit_card, @options) @@ -222,4 +222,3 @@ def failed_credit_response end end - diff --git a/test/unit/gateways/spreedly_core_test.rb b/test/unit/gateways/spreedly_core_test.rb index 0ae7a5725d8..afc5d4dd961 100644 --- a/test/unit/gateways/spreedly_core_test.rb +++ b/test/unit/gateways/spreedly_core_test.rb @@ -8,6 +8,8 @@ def setup @credit_card = credit_card @amount = 103 + @existing_transaction = 'LKA3RchoqYO0njAfhHVw60ohjrC' + @not_found_transaction = 'AdyQXaG0SVpSoMPdmFlvd3aA3uz' end def test_successful_purchase_with_payment_method_token @@ -18,10 +20,10 @@ def test_successful_purchase_with_payment_method_token assert_success response assert !response.test? - assert_equal "K1CRcdN0jK32UyrnZGPOXLRjqJl", response.authorization - assert_equal "Succeeded!", response.message - assert_equal "Non-U.S. issuing bank does not support AVS.", response.avs_result["message"] - assert_equal "CVV failed data validation check", response.cvv_result["message"] + assert_equal 'K1CRcdN0jK32UyrnZGPOXLRjqJl', response.authorization + assert_equal 'Succeeded!', response.message + assert_equal 'Non-U.S. issuing bank does not support AVS.', response.avs_result['message'] + assert_equal 'CVV failed data validation check', response.cvv_result['message'] end def test_failed_purchase_with_payment_method_token @@ -31,8 +33,8 @@ def test_failed_purchase_with_payment_method_token assert_failure response assert !response.test? - assert_equal "Xh0T15CfYQeUqYV9Ixm8YV283Ds", response.authorization - assert_equal "This transaction cannot be processed.", response.message + assert_equal 'Xh0T15CfYQeUqYV9Ixm8YV283Ds', response.authorization + assert_equal 'This transaction cannot be processed.', response.message assert_equal '10762', response.params['response_error_code'] assert_nil response.avs_result['message'] assert_nil response.cvv_result['message'] @@ -45,10 +47,10 @@ def test_successful_purchase_with_credit_card assert_success response assert !response.test? - assert_equal "K1CRcdN0jK32UyrnZGPOXLRjqJl", response.authorization - assert_equal "Succeeded!", response.message - assert_equal "Non-U.S. issuing bank does not support AVS.", response.avs_result["message"] - assert_equal "CVV failed data validation check", response.cvv_result["message"] + assert_equal 'K1CRcdN0jK32UyrnZGPOXLRjqJl', response.authorization + assert_equal 'Succeeded!', response.message + assert_equal 'Non-U.S. issuing bank does not support AVS.', response.avs_result['message'] + assert_equal 'CVV failed data validation check', response.cvv_result['message'] assert_equal 'Purchase', response.params['transaction_type'] assert_equal '5WxC03VQ0LmmkYvIHl7XsPKIpUb', response.params['payment_method_token'] assert_equal '6644', response.params['payment_method_last_four_digits'] @@ -67,8 +69,8 @@ def test_failed_purchase_with_credit_card response = @gateway.purchase(@amount, @credit_card) assert_failure response - assert_equal "Xh0T15CfYQeUqYV9Ixm8YV283Ds", response.authorization - assert_equal "This transaction cannot be processed.", response.message + assert_equal 'Xh0T15CfYQeUqYV9Ixm8YV283Ds', response.authorization + assert_equal 'This transaction cannot be processed.', response.message assert_equal '10762', response.params['response_error_code'] assert_nil response.avs_result['message'] assert_nil response.cvv_result['message'] @@ -76,12 +78,12 @@ def test_failed_purchase_with_credit_card end def test_purchase_without_gateway_token_option - @gateway.expects(:commit).with("gateways/token/purchase.xml", anything) + @gateway.expects(:commit).with('gateways/token/purchase.xml', anything) @gateway.purchase(@amount, @payment_method_token) end def test_purchase_with_gateway_token_option - @gateway.expects(:commit).with("gateways/mynewtoken/purchase.xml", anything) + @gateway.expects(:commit).with('gateways/mynewtoken/purchase.xml', anything) @gateway.purchase(@amount, @payment_method_token, gateway_token: 'mynewtoken') end @@ -92,18 +94,18 @@ def test_successful_authorize_with_token_and_capture assert_success response assert !response.test? - assert_equal "NKz5SO6jrsRDc0UyaujwayXJZ1a", response.authorization - assert_equal "Succeeded!", response.message - assert_equal "Non-U.S. issuing bank does not support AVS.", response.avs_result["message"] - assert_equal "CVV failed data validation check", response.cvv_result["message"] + assert_equal 'NKz5SO6jrsRDc0UyaujwayXJZ1a', response.authorization + assert_equal 'Succeeded!', response.message + assert_equal 'Non-U.S. issuing bank does not support AVS.', response.avs_result['message'] + assert_equal 'CVV failed data validation check', response.cvv_result['message'] @gateway.expects(:raw_ssl_request).returns(successful_capture_response) response = @gateway.capture(@amount, response.authorization) assert_success response assert !response.test? - assert_equal "Bd1ZeztpPyjfXzfUa14BQGfaLmg", response.authorization - assert_equal "Succeeded!", response.message + assert_equal 'Bd1ZeztpPyjfXzfUa14BQGfaLmg', response.authorization + assert_equal 'Succeeded!', response.message assert_nil response.avs_result['message'] assert_nil response.cvv_result['message'] end @@ -112,7 +114,7 @@ def test_failed_authorize_with_token @gateway.expects(:raw_ssl_request).returns(failed_authorize_response) response = @gateway.authorize(@amount, @payment_method_token) assert_failure response - assert_equal "This transaction cannot be processed.", response.message + assert_equal 'This transaction cannot be processed.', response.message assert_equal '10762', response.params['response_error_code'] assert_nil response.avs_result['message'] assert_nil response.cvv_result['message'] @@ -125,10 +127,10 @@ def test_successful_authorize_with_credit_card_and_capture assert_success response assert !response.test? - assert_equal "NKz5SO6jrsRDc0UyaujwayXJZ1a", response.authorization - assert_equal "Succeeded!", response.message - assert_equal "Non-U.S. issuing bank does not support AVS.", response.avs_result["message"] - assert_equal "CVV failed data validation check", response.cvv_result["message"] + assert_equal 'NKz5SO6jrsRDc0UyaujwayXJZ1a', response.authorization + assert_equal 'Succeeded!', response.message + assert_equal 'Non-U.S. issuing bank does not support AVS.', response.avs_result['message'] + assert_equal 'CVV failed data validation check', response.cvv_result['message'] assert_equal 'Authorization', response.params['transaction_type'] assert_equal '5WxC03VQ0LmmkYvIHl7XsPKIpUb', response.params['payment_method_token'] assert_equal '6644', response.params['payment_method_last_four_digits'] @@ -137,15 +139,15 @@ def test_successful_authorize_with_credit_card_and_capture @gateway.expects(:raw_ssl_request).returns(successful_capture_response) response = @gateway.capture(@amount, response.authorization) assert_success response - assert_equal "Bd1ZeztpPyjfXzfUa14BQGfaLmg", response.authorization - assert_equal "Succeeded!", response.message + assert_equal 'Bd1ZeztpPyjfXzfUa14BQGfaLmg', response.authorization + assert_equal 'Succeeded!', response.message end def test_failed_authorize_with_credit_card @gateway.stubs(:raw_ssl_request).returns(successful_store_response, failed_authorize_response) response = @gateway.authorize(@amount, @credit_card) assert_failure response - assert_equal "This transaction cannot be processed.", response.message + assert_equal 'This transaction cannot be processed.', response.message assert_equal '10762', response.params['response_error_code'] end @@ -164,7 +166,7 @@ def test_failed_capture @gateway.expects(:raw_ssl_request).returns(failed_capture_response) response = @gateway.capture(@amount + 20, response.authorization) assert_failure response - assert_equal "Amount specified exceeds allowable limit.", response.message + assert_equal 'Amount specified exceeds allowable limit.', response.message end def test_successful_refund @@ -175,8 +177,8 @@ def test_successful_refund @gateway.expects(:raw_ssl_request).returns(successful_refund_response) response = @gateway.refund(@amount, response.authorization) assert_success response - assert_equal "Succeeded!", response.message - assert_equal "Credit", response.params["transaction_type"] + assert_equal 'Succeeded!', response.message + assert_equal 'Credit', response.params['transaction_type'] end def test_failed_refund @@ -187,7 +189,7 @@ def test_failed_refund @gateway.expects(:raw_ssl_request).returns(failed_refund_response) response = @gateway.refund(@amount + 20, response.authorization) assert_failure response - assert_equal "The partial refund amount must be less than or equal to the original transaction amount", response.message + assert_equal 'The partial refund amount must be less than or equal to the original transaction amount', response.message assert_equal '10009', response.params['response_error_code'] end @@ -199,7 +201,7 @@ def test_successful_void @gateway.expects(:raw_ssl_request).returns(successful_void_response) response = @gateway.void(response.authorization) assert_success response - assert_equal "Succeeded!", response.message + assert_equal 'Succeeded!', response.message end def test_failed_void @@ -210,17 +212,35 @@ def test_failed_void @gateway.expects(:raw_ssl_request).returns(failed_void_response) response = @gateway.void(response.authorization) assert_failure response - assert_equal "Authorization is voided.", response.message + assert_equal 'Authorization is voided.', response.message assert_equal '10600', response.params['response_error_code'] end + def test_successful_verify + @gateway.expects(:raw_ssl_request).returns(successful_verify_response) + response = @gateway.verify(@payment_method_token) + assert_success response + + assert_equal 'Succeeded!', response.message + assert_equal 'Verification', response.params['transaction_type'] + end + + def test_failed_verify + @gateway.expects(:raw_ssl_request).returns(failed_verify_response) + response = @gateway.verify(@payment_method_token) + assert_failure response + + assert_equal 'Unable to process the verify transaction.', response.message + assert_empty response.params['response_error_code'] + end + def test_successful_store @gateway.expects(:raw_ssl_request).returns(successful_store_response) response = @gateway.store(@credit_card) assert_success response - assert_equal "Succeeded!", response.message - assert_equal "Bml92ojQgsTf7bQ7z7WlwQVIdjr", response.authorization - assert_equal "true", response.params["retained"] + assert_equal 'Succeeded!', response.message + assert_equal 'Bml92ojQgsTf7bQ7z7WlwQVIdjr', response.authorization + assert_equal 'true', response.params['retained'] end def test_failed_store @@ -238,11 +258,34 @@ def test_successful_unstore @gateway.expects(:raw_ssl_request).returns(successful_unstore_response) response = @gateway.unstore(response.authorization) assert_success response - assert_equal "Succeeded!", response.message + assert_equal 'Succeeded!', response.message + end + + def test_successful_find + @gateway.expects(:raw_ssl_request).returns(successful_find_response) + response = @gateway.find(@existing_transaction) + assert_success response + + assert_equal 'Succeeded!', response.message + assert_equal 'LKA3RchoqYO0njAfhHVw60ohjrC', response.authorization + end + + def test_failed_find + @gateway.expects(:raw_ssl_request).returns(failed_find_response) + response = @gateway.find(@not_found_transaction) + assert_failure response + + assert_match %r(Unable to find the transaction), response.message + assert_match %r(#{@not_found_transaction}), response.message end + def test_scrubbing + assert @gateway.supports_scrubbing? + assert_equal @gateway.scrub(pre_scrubbed), post_scrubbed + end private + def successful_purchase_response MockResponse.succeeded <<-XML <transaction> @@ -799,4 +842,319 @@ def successful_unstore_response XML end + def pre_scrubbed + <<-EOS + opening connection to core.spreedly.com:443... + opened + starting SSL for core.spreedly.com:443... + SSL established + <- "POST /v1/payment_methods.xml HTTP/1.1\r\nContent-Type: text/xml\r\nAuthorization: Basic NFk5YlZrT0NwWWVzUFFPZkRpN1RYUXlVdzUwOlkyaTdBamdVMDNTVWp3WTR4bk9QcXpkc3Y0ZE1iUERDUXpvckFrOEJjb3kwVThFSVZFNGlubkdqdW9NUXY3TU4=\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nAccept: */*\r\nUser-Agent: Ruby\r\nConnection: close\r\nHost: core.spreedly.com\r\nContent-Length: 404\r\n\r\n" + <- "<?xml version=\"1.0\"?>\n<payment_method>\n <credit_card>\n <number>5555555555554444</number>\n <verification_value>123</verification_value>\n <first_name>Longbob</first_name>\n <last_name>Longsen</last_name>\n <month>9</month>\n <year>2019</year>\n <email/>\n <address1/>\n <address2/>\n <city/>\n <state/>\n <zip/>\n <country/>\n </credit_card>\n <data></data>\n</payment_method>\n" + -> "HTTP/1.1 201 Created\r\n" + -> "Date: Sat, 10 Mar 2018 22:04:06 GMT\r\n" + -> "Content-Type: application/xml; charset=utf-8\r\n" + -> "Content-Length: 1875\r\n" + -> "Connection: close\r\n" + -> "X-Frame-Options: SAMEORIGIN\r\n" + -> "X-XSS-Protection: 1; mode=block\r\n" + -> "X-Content-Type-Options: nosniff\r\n" + -> "ETag: W/\"c4ef6dfc389a5514d6b6ffd8bac8786c\"\r\n" + -> "Cache-Control: max-age=0, private, must-revalidate\r\n" + -> "X-Request-Id: b227ok4du2hrj7mrtt10.core_dcaa82760687b3ef\r\n" + -> "Server: nginx\r\n" + -> "Strict-Transport-Security: max-age=31536000; includeSubdomains;\r\n" + -> "\r\n" + reading 1875 bytes... + -> "<transaction>\n <token>NRBpydUCWn658GHV8h2kVlUzB0i</token>\n <created_at type=\"dateTime\">2018-03-10T22:04:06Z</created_at>\n <updated_at type=\"dateTime\">2018-03-10T22:04:06Z</updated_at>\n <succeeded type=\"boolean\">true</succeeded>\n <transaction_type>AddPaymentMethod</transaction_type>\n <retained type=\"boolean\">false</retained>\n <state>succeeded</state>\n <message key=\"messages.transaction_succeeded\">Succeeded!</message>\n <payment_method>\n <token>Wd25UIrH1uopTkZZ4UDdb5XmSDd</token>\n <created_at type=\"dateTime\">2018-03-10T22:04:06Z</created_at>\n <updated_at type=\"dateTime\">2018-03-10T22:04:06Z</updated_at>\n <email nil=\"true\"/>\n <data nil=\"true\"/>\n <storage_state>cached</storage_state>\n <test type=\"boolean\">true</test>\n <last_four_digits>4444</last_four_digits>\n <first_six_digits>555555</first_six_digits>\n <card_type>master</card_type>\n <first_name>Longbob</first_name>\n <last_name>Longsen</last_name>\n <month type=\"integer\">9</month>\n <year type=\"integer\">2019</year>\n <address1 nil=\"true\"/>\n <address2 nil=\"true\"/>\n <city nil=\"true\"/>\n <state nil=\"true\"/>\n <zip nil=\"true\"/>\n <country nil=\"true\"/>\n <phone_number nil=\"true\"/>\n <company nil=\"true\"/>\n <full_name>Longbob Longsen</full_name>\n <eligible_for_card_updater type=\"boolean\">true</eligible_for_card_updater>\n <shipping_address1 nil=\"true\"/>\n <shipping_address2 nil=\"true\"/>\n <shipping_city nil=\"true\"/>\n <shipping_state nil=\"true\"/>\n <shipping_zip nil=\"true\"/>\n <shipping_country nil=\"true\"/>\n <shipping_phone_number nil=\"true\"/>\n <payment_method_type>credit_card</payment_method_type>\n <errors>\n </errors>\n <verification_value>XXX</verification_value>\n <number>XXXX-XXXX-XXXX-4444</number>\n <fingerprint>125370bb396dff6fed4f581f85a91a9e5317</fingerprint>\n </payment_method>\n</transaction>\n" + read 1875 bytes + Conn close + EOS + end + + def post_scrubbed + <<-EOS + opening connection to core.spreedly.com:443... + opened + starting SSL for core.spreedly.com:443... + SSL established + <- "POST /v1/payment_methods.xml HTTP/1.1\r\nContent-Type: text/xml\r\nAuthorization: Basic [FILTERED]=\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nAccept: */*\r\nUser-Agent: Ruby\r\nConnection: close\r\nHost: core.spreedly.com\r\nContent-Length: 404\r\n\r\n" + <- "<?xml version=\"1.0\"?>\n<payment_method>\n <credit_card>\n <number>[FILTERED]</number>\n <verification_value>[FILTERED]</verification_value>\n <first_name>Longbob</first_name>\n <last_name>Longsen</last_name>\n <month>9</month>\n <year>2019</year>\n <email/>\n <address1/>\n <address2/>\n <city/>\n <state/>\n <zip/>\n <country/>\n </credit_card>\n <data></data>\n</payment_method>\n" + -> "HTTP/1.1 201 Created\r\n" + -> "Date: Sat, 10 Mar 2018 22:04:06 GMT\r\n" + -> "Content-Type: application/xml; charset=utf-8\r\n" + -> "Content-Length: 1875\r\n" + -> "Connection: close\r\n" + -> "X-Frame-Options: SAMEORIGIN\r\n" + -> "X-XSS-Protection: 1; mode=block\r\n" + -> "X-Content-Type-Options: nosniff\r\n" + -> "ETag: W/\"c4ef6dfc389a5514d6b6ffd8bac8786c\"\r\n" + -> "Cache-Control: max-age=0, private, must-revalidate\r\n" + -> "X-Request-Id: b227ok4du2hrj7mrtt10.core_dcaa82760687b3ef\r\n" + -> "Server: nginx\r\n" + -> "Strict-Transport-Security: max-age=31536000; includeSubdomains;\r\n" + -> "\r\n" + reading 1875 bytes... + -> "<transaction>\n <token>NRBpydUCWn658GHV8h2kVlUzB0i</token>\n <created_at type=\"dateTime\">2018-03-10T22:04:06Z</created_at>\n <updated_at type=\"dateTime\">2018-03-10T22:04:06Z</updated_at>\n <succeeded type=\"boolean\">true</succeeded>\n <transaction_type>AddPaymentMethod</transaction_type>\n <retained type=\"boolean\">false</retained>\n <state>succeeded</state>\n <message key=\"messages.transaction_succeeded\">Succeeded!</message>\n <payment_method>\n <token>Wd25UIrH1uopTkZZ4UDdb5XmSDd</token>\n <created_at type=\"dateTime\">2018-03-10T22:04:06Z</created_at>\n <updated_at type=\"dateTime\">2018-03-10T22:04:06Z</updated_at>\n <email nil=\"true\"/>\n <data nil=\"true\"/>\n <storage_state>cached</storage_state>\n <test type=\"boolean\">true</test>\n <last_four_digits>4444</last_four_digits>\n <first_six_digits>555555</first_six_digits>\n <card_type>master</card_type>\n <first_name>Longbob</first_name>\n <last_name>Longsen</last_name>\n <month type=\"integer\">9</month>\n <year type=\"integer\">2019</year>\n <address1 nil=\"true\"/>\n <address2 nil=\"true\"/>\n <city nil=\"true\"/>\n <state nil=\"true\"/>\n <zip nil=\"true\"/>\n <country nil=\"true\"/>\n <phone_number nil=\"true\"/>\n <company nil=\"true\"/>\n <full_name>Longbob Longsen</full_name>\n <eligible_for_card_updater type=\"boolean\">true</eligible_for_card_updater>\n <shipping_address1 nil=\"true\"/>\n <shipping_address2 nil=\"true\"/>\n <shipping_city nil=\"true\"/>\n <shipping_state nil=\"true\"/>\n <shipping_zip nil=\"true\"/>\n <shipping_country nil=\"true\"/>\n <shipping_phone_number nil=\"true\"/>\n <payment_method_type>credit_card</payment_method_type>\n <errors>\n </errors>\n <verification_value>[FILTERED]</verification_value>\n <number>[FILTERED]</number>\n <fingerprint>125370bb396dff6fed4f581f85a91a9e5317</fingerprint>\n </payment_method>\n</transaction>\n" + read 1875 bytes + Conn close + EOS + end + + def successful_verify_response + MockResponse.succeeded <<-XML + <transaction> + <on_test_gateway type="boolean">true</on_test_gateway> + <created_at type="dateTime">2018-02-24T00:47:56Z</created_at> + <updated_at type="dateTime">2018-02-24T00:47:56Z</updated_at> + <succeeded type="boolean">true</succeeded> + <state>succeeded</state> + <token>891hWyHKmfCggQQ7Q35sGVcEC01</token> + <transaction_type>Verification</transaction_type> + <order_id nil="true"/> + <ip nil="true"/> + <description nil="true"/> + <email nil="true"/> + <merchant_name_descriptor nil="true"/> + <merchant_location_descriptor nil="true"/> + <gateway_specific_fields nil="true"/> + <gateway_specific_response_fields> + </gateway_specific_response_fields> + <gateway_transaction_id>67</gateway_transaction_id> + <gateway_latency_ms type="integer">27</gateway_latency_ms> + <currency_code>USD</currency_code> + <retain_on_success type="boolean">false</retain_on_success> + <payment_method_added type="boolean">false</payment_method_added> + <message key="messages.transaction_succeeded">Succeeded!</message> + <gateway_token>3gLeg4726V5P0HK7cq7QzHsL0a6</gateway_token> + <gateway_type>test</gateway_type> + <shipping_address> + <name>Jim TesterDude</name> + <address1 nil="true"/> + <address2 nil="true"/> + <city nil="true"/> + <state nil="true"/> + <zip nil="true"/> + <country nil="true"/> + <phone_number nil="true"/> + </shipping_address> + <response> + <success type="boolean">true</success> + <message>Successful verify</message> + <avs_code nil="true"/> + <avs_message nil="true"/> + <cvv_code nil="true"/> + <cvv_message nil="true"/> + <pending type="boolean">false</pending> + <result_unknown type="boolean">false</result_unknown> + <error_code></error_code> + <error_detail nil="true"/> + <cancelled type="boolean">false</cancelled> + <fraud_review nil="true"/> + <created_at type="dateTime">2018-02-24T00:47:56Z</created_at> + <updated_at type="dateTime">2018-02-24T00:47:56Z</updated_at> + </response> + <payment_method> + <token>9AjLflWs7SOKuqJLveOZya9bixa</token> + <created_at type="dateTime">2012-12-07T19:08:15Z</created_at> + <updated_at type="dateTime">2018-02-24T00:35:45Z</updated_at> + <email nil="true"/> + <data> + <how_many>2</how_many> + </data> + <storage_state>retained</storage_state> + <test type="boolean">true</test> + <last_four_digits>4444</last_four_digits> + <first_six_digits>555555</first_six_digits> + <card_type>master</card_type> + <first_name>Jim</first_name> + <last_name>TesterDude</last_name> + <month type="integer">9</month> + <year type="integer">2022</year> + <address1 nil="true"/> + <address2 nil="true"/> + <city nil="true"/> + <state nil="true"/> + <zip nil="true"/> + <country nil="true"/> + <phone_number nil="true"/> + <company nil="true"/> + <full_name>Jim TesterDude</full_name> + <eligible_for_card_updater nil="true"/> + <shipping_address1 nil="true"/> + <shipping_address2 nil="true"/> + <shipping_city nil="true"/> + <shipping_state nil="true"/> + <shipping_zip nil="true"/> + <shipping_country nil="true"/> + <shipping_phone_number nil="true"/> + <payment_method_type>credit_card</payment_method_type> + <errors> + </errors> + <verification_value></verification_value> + <number>XXXX-XXXX-XXXX-4444</number> + <fingerprint>125370bb396dff6fed4f581f85a91a9e5317</fingerprint> + </payment_method> + </transaction> + XML + end + + def failed_verify_response + MockResponse.failed <<-XML + <transaction> + <on_test_gateway type="boolean">true</on_test_gateway> + <created_at type="dateTime">2018-02-24T00:53:58Z</created_at> + <updated_at type="dateTime">2018-02-24T00:53:58Z</updated_at> + <succeeded type="boolean">false</succeeded> + <state>gateway_processing_failed</state> + <token>RwmpyTCRmCpji1YtSD5f5fQDpkS</token> + <transaction_type>Verification</transaction_type> + <order_id nil="true"/> + <ip nil="true"/> + <description nil="true"/> + <email nil="true"/> + <merchant_name_descriptor nil="true"/> + <merchant_location_descriptor nil="true"/> + <gateway_specific_fields nil="true"/> + <gateway_specific_response_fields> + </gateway_specific_response_fields> + <gateway_transaction_id nil="true"/> + <gateway_latency_ms type="integer">24</gateway_latency_ms> + <currency_code>USD</currency_code> + <retain_on_success type="boolean">false</retain_on_success> + <payment_method_added type="boolean">false</payment_method_added> + <message>Unable to process the verify transaction.</message> + <gateway_token>3gLeg4726V5P0HK7cq7QzHsL0a6</gateway_token> + <gateway_type>test</gateway_type> + <shipping_address> + <name>Longbob Longsen</name> + <address1 nil="true"/> + <address2 nil="true"/> + <city nil="true"/> + <state nil="true"/> + <zip nil="true"/> + <country nil="true"/> + <phone_number nil="true"/> + </shipping_address> + <response> + <success type="boolean">false</success> + <message>Unable to process the verify transaction.</message> + <avs_code nil="true"/> + <avs_message nil="true"/> + <cvv_code nil="true"/> + <cvv_message nil="true"/> + <pending type="boolean">false</pending> + <result_unknown type="boolean">false</result_unknown> + <error_code></error_code> + <error_detail nil="true"/> + <cancelled type="boolean">false</cancelled> + <fraud_review nil="true"/> + <created_at type="dateTime">2018-02-24T00:53:58Z</created_at> + <updated_at type="dateTime">2018-02-24T00:53:58Z</updated_at> + </response> + <payment_method> + <token>UzUKWHwI7GtZe3gz1UU5FiZ6DxH</token> + <created_at type="dateTime">2018-02-24T00:53:56Z</created_at> + <updated_at type="dateTime">2018-02-24T00:53:56Z</updated_at> + <email nil="true"/> + <data nil="true"/> + <storage_state>cached</storage_state> + <test type="boolean">true</test> + <last_four_digits>1881</last_four_digits> + <first_six_digits>401288</first_six_digits> + <card_type>visa</card_type> + <first_name>Longbob</first_name> + <last_name>Longsen</last_name> + <month type="integer">9</month> + <year type="integer">2019</year> + <address1 nil="true"/> + <address2 nil="true"/> + <city nil="true"/> + <state nil="true"/> + <zip nil="true"/> + <country nil="true"/> + <phone_number nil="true"/> + <company nil="true"/> + <full_name>Longbob Longsen</full_name> + <eligible_for_card_updater nil="true"/> + <shipping_address1 nil="true"/> + <shipping_address2 nil="true"/> + <shipping_city nil="true"/> + <shipping_state nil="true"/> + <shipping_zip nil="true"/> + <shipping_country nil="true"/> + <shipping_phone_number nil="true"/> + <payment_method_type>credit_card</payment_method_type> + <errors> + </errors> + <verification_value>XXX</verification_value> + <number>XXXX-XXXX-XXXX-1881</number> + <fingerprint>db33a42fcf2908a3795bd4ea881de2e0f015</fingerprint> + </payment_method> + </transaction> + XML + end + + def successful_find_response + MockResponse.succeeded <<-XML + <transaction> + <token>LKA3RchoqYO0njAfhHVw60ohjrC</token> + <created_at type="dateTime">2012-12-07T19:03:50Z</created_at> + <updated_at type="dateTime">2012-12-07T19:03:50Z</updated_at> + <succeeded type="boolean">true</succeeded> + <transaction_type>AddPaymentMethod</transaction_type> + <retained type="boolean">false</retained> + <state>succeeded</state> + <message key="messages.transaction_succeeded">Succeeded!</message> + <payment_method> + <token>67KlSyyvBAt9VUMJg3lUeWbBaWX</token> + <created_at type="dateTime">2012-12-07T19:03:50Z</created_at> + <updated_at type="dateTime">2017-07-29T23:25:21Z</updated_at> + <email nil="true"/> + <data> + <how_many>2</how_many> + </data> + <storage_state>redacted</storage_state> + <test type="boolean">false</test> + <last_four_digits>4444</last_four_digits> + <first_six_digits nil="true"/> + <card_type>master</card_type> + <first_name>Jim</first_name> + <last_name>TesterDude</last_name> + <month type="integer">9</month> + <year type="integer">2022</year> + <address1 nil="true"/> + <address2 nil="true"/> + <city nil="true"/> + <state nil="true"/> + <zip nil="true"/> + <country nil="true"/> + <phone_number nil="true"/> + <company nil="true"/> + <full_name>Jim TesterDude</full_name> + <eligible_for_card_updater type="boolean">true</eligible_for_card_updater> + <shipping_address1 nil="true"/> + <shipping_address2 nil="true"/> + <shipping_city nil="true"/> + <shipping_state nil="true"/> + <shipping_zip nil="true"/> + <shipping_country nil="true"/> + <shipping_phone_number nil="true"/> + <payment_method_type>credit_card</payment_method_type> + <errors> + </errors> + <verification_value></verification_value> + <number></number> + <fingerprint nil="true"/> + </payment_method> + </transaction> + XML + end + + def failed_find_response + MockResponse.failed <<-XML + <errors> + <error key="errors.transaction_not_found">Unable to find the transaction AdyQXaG0SVpSoMPdmFlvd3aA3uz.</error> + </errors> + XML + end end diff --git a/test/unit/gateways/stripe_test.rb b/test/unit/gateways/stripe_test.rb index 8c0182a3ee6..aa68953ee16 100644 --- a/test/unit/gateways/stripe_test.rb +++ b/test/unit/gateways/stripe_test.rb @@ -12,18 +12,19 @@ def setup @options = { :billing_address => address(), + :statement_address => statement_address(), :description => 'Test Purchase' } @apple_pay_payment_token = apple_pay_payment_token @emv_credit_card = credit_card_with_icc_data @payment_token = StripeGateway::StripePaymentToken.new(token_params) - @token_string = @payment_token.payment_data["id"] + @token_string = @payment_token.payment_data['id'] @check = check({ - bank_name: "STRIPE TEST BANK", - account_number: "000123456789", - routing_number: "110000000", + bank_name: 'STRIPE TEST BANK', + account_number: '000123456789', + routing_number: '110000000', }) end @@ -288,7 +289,7 @@ def test_passing_validate_false_on_store def test_empty_values_not_sent response = stub_comms(@gateway, :ssl_request) do - @gateway.purchase(@amount, @credit_card, referrer: "") + @gateway.purchase(@amount, @credit_card, referrer: '') end.check_request do |method, endpoint, data, headers| refute_match(/referrer/, data) end.respond_with(successful_purchase_response) @@ -352,7 +353,7 @@ def test_successful_authorization_with_emv_credit_card assert_success response assert_equal 'ch_test_emv_charge', response.authorization - assert response.emv_authorization, "Response should include emv_authorization containing the EMV ARPC" + assert response.emv_authorization, 'Response should include emv_authorization containing the EMV ARPC' end def test_declined_authorization_with_emv_credit_card @@ -363,13 +364,13 @@ def test_declined_authorization_with_emv_credit_card assert_failure response assert_equal 'ch_declined_auth', response.authorization - assert response.emv_authorization, "Response should include emv_auth_data containing the EMV ARC" + assert response.emv_authorization, 'Response should include emv_auth_data containing the EMV ARC' end def test_successful_capture @gateway.expects(:ssl_request).returns(successful_capture_response) - assert response = @gateway.capture(@amount, "ch_test_charge") + assert response = @gateway.capture(@amount, 'ch_test_charge') assert_success response assert response.test? end @@ -377,9 +378,9 @@ def test_successful_capture def test_successful_capture_with_emv_credit_card_tc @gateway.expects(:ssl_request).returns(successful_capture_response_with_icc_data) - assert response = @gateway.capture(@amount, "ch_test_emv_charge") + assert response = @gateway.capture(@amount, 'ch_test_emv_charge') assert_success response - assert response.emv_authorization, "Response should include emv_authorization containing the EMV TC" + assert response.emv_authorization, 'Response should include emv_authorization containing the EMV TC' end def test_successful_purchase @@ -428,10 +429,50 @@ def test_successful_purchase_with_apple_pay_token_exchange assert response.test? end + def test_successful_purchase_with_level3_data + @gateway.expects(:add_creditcard) + + @options[:merchant_reference] = 123 + @options[:customer_reference] = 456 + @options[:shipping_address_zip] = 98765 + @options[:shipping_from_zip] = 54321 + @options[:shipping_amount] = 40 + @options[:line_items] = [ + { + 'product_code' => 1234, + 'product_description' => 'An item', + 'unit_cost' => 60, + 'quantity' => 7, + 'tax_amount' => 0 + }, + { + 'product_code' => 999, + 'tax_amount' => 888 + } + ] + + response = stub_comms(@gateway, :ssl_request) do + @gateway.purchase(@amount, @credit_card, @options) + end.check_request do |_method, endpoint, data, _headers| + if %r{/charges} =~ endpoint + assert_match('level3[merchant_reference]=123', data) + assert_match('level3[customer_reference]=456', data) + assert_match('level3[shipping_address_zip]=98765', data) + assert_match('level3[shipping_amount]=40', data) + assert_match('level3[shipping_from_zip]=54321', data) + assert_match('level3[line_items][0][product_description]=An+item', data) + assert_match('level3[line_items][1][product_code]=999', data) + end + end.respond_with(successful_purchase_response) + + assert_success response + assert response.test? + end + def test_amount_localization @gateway.expects(:ssl_request).returns(successful_purchase_response(true)) @gateway.expects(:post_data).with do |params| - '4' == params[:amount] + params[:amount] == '4' end @options[:currency] = 'JPY' @@ -439,9 +480,28 @@ def test_amount_localization @gateway.purchase(@amount, @credit_card, @options) end + def test_adds_application_to_x_stripe_client_user_agent_header + application = { + name: 'app', + version: '1.0', + url: 'https://example.com' + } + + response = stub_comms(@gateway, :ssl_request) do + @gateway.purchase(@amount, 'cus_xxx|card_xxx', @options.merge({application: application})) + end.check_request do |method, endpoint, data, headers| + assert_match(/\"application\"/, headers['X-Stripe-Client-User-Agent']) + assert_match(/\"name\":\"app\"/, headers['X-Stripe-Client-User-Agent']) + assert_match(/\"version\":\"1.0\"/, headers['X-Stripe-Client-User-Agent']) + assert_match(/\"url\":\"https:\/\/example.com\"/, headers['X-Stripe-Client-User-Agent']) + end.respond_with(successful_purchase_response) + + assert_success response + end + def test_successful_purchase_with_token_including_customer response = stub_comms(@gateway, :ssl_request) do - @gateway.purchase(@amount, "cus_xxx|card_xxx") + @gateway.purchase(@amount, 'cus_xxx|card_xxx') end.check_request do |method, endpoint, data, headers| assert_match(/customer=cus_xxx/, data) assert_match(/card=card_xxx/, data) @@ -452,7 +512,7 @@ def test_successful_purchase_with_token_including_customer def test_successful_purchase_with_token response = stub_comms(@gateway, :ssl_request) do - @gateway.purchase(@amount, "card_xxx") + @gateway.purchase(@amount, 'card_xxx') end.check_request do |method, endpoint, data, headers| assert_match(/card=card_xxx/, data) end.respond_with(successful_purchase_response) @@ -481,7 +541,7 @@ def test_successful_void def test_void_contains_charge_expand @gateway.expects(:ssl_request).with do |_, _, post, _| - post.include?("expand[]=charge") + post.include?('expand[0]=charge') end.returns(successful_purchase_response(true)) assert response = @gateway.void('ch_test_charge') @@ -491,7 +551,8 @@ def test_void_contains_charge_expand def test_void_with_additional_expand_contains_two_expands @gateway.expects(:ssl_request).with do |_, _, post, _| parsed = CGI.parse(post) - parsed['expand[]'].sort == ['balance_transaction', 'charge'].sort + parsed['expand[0]'] = 'balance_transaction' + parsed['expand[1]'] = 'charge' end.returns(successful_purchase_response(true)) assert response = @gateway.void('ch_test_charge', expand: :balance_transaction) @@ -501,7 +562,7 @@ def test_void_with_additional_expand_contains_two_expands def test_void_with_expand_charge_only_sends_one_charge_expand @gateway.expects(:ssl_request).with do |_, _, post, _| parsed = CGI.parse(post) - parsed["expand[]"] == ['charge'] + parsed['expand[0]'] == ['charge'] end.returns(successful_purchase_response(true)) assert response = @gateway.void('ch_test_charge', expand: ['charge']) @@ -510,13 +571,22 @@ def test_void_with_expand_charge_only_sends_one_charge_expand def test_successful_void_with_metadata @gateway.expects(:ssl_request).with do |_, _, post, _| - post.include?("metadata[first_value]=true") + post.include?('metadata[first_value]=true') end.returns(successful_purchase_response(true)) assert response = @gateway.void('ch_test_charge', {metadata: {first_value: true}}) assert_success response end + def test_successful_void_with_reason + @gateway.expects(:ssl_request).with do |_, _, post, _| + post.include?('reason=fraudulent') + end.returns(successful_purchase_response(true)) + + assert response = @gateway.void('ch_test_charge', {reason: 'fraudulent'}) + assert_success response + end + def test_successful_refund @gateway.expects(:ssl_request).returns(successful_partially_refunded_response) @@ -526,6 +596,15 @@ def test_successful_refund assert_equal 're_test_refund', response.authorization end + def test_successful_refund_with_reason + @gateway.expects(:ssl_request).returns(successful_partially_refunded_response) + + assert response = @gateway.refund(@refund_amount, 'ch_test_charge', reason: 'fraudulent') + assert_success response + + assert_equal 're_test_refund', response.authorization + end + def test_unsuccessful_refund @gateway.expects(:ssl_request).returns(generic_error_response) @@ -535,7 +614,7 @@ def test_unsuccessful_refund def test_successful_refund_with_refund_application_fee @gateway.expects(:ssl_request).with do |method, url, post, headers| - post.include?("refund_application_fee=true") + post.include?('refund_application_fee=true') end.returns(successful_partially_refunded_response) assert response = @gateway.refund(@refund_amount, 'ch_test_charge', :refund_application_fee => true) @@ -544,7 +623,7 @@ def test_successful_refund_with_refund_application_fee def test_refund_contains_charge_expand @gateway.expects(:ssl_request).with do |_, _, post, _| - post.include?("expand[]=charge") + post.include?('expand[0]=charge') end.returns(successful_partially_refunded_response) assert response = @gateway.refund(@refund_amount, 'ch_test_charge') @@ -554,7 +633,8 @@ def test_refund_contains_charge_expand def test_refund_with_additional_expand_contains_two_expands @gateway.expects(:ssl_request).with do |_, _, post, _| parsed = CGI.parse(post) - parsed['expand[]'].sort == ['balance_transaction', 'charge'].sort + parsed['expand[0]'] = 'balance_transaction' + parsed['expand[1]'] = 'charge' end.returns(successful_partially_refunded_response) assert response = @gateway.refund(@refund_amount, 'ch_test_charge', expand: :balance_transaction) @@ -564,7 +644,7 @@ def test_refund_with_additional_expand_contains_two_expands def test_refund_with_expand_charge_only_sends_one_charge_expand @gateway.expects(:ssl_request).with do |_, _, post, _| parsed = CGI.parse(post) - parsed["expand[]"] == ['charge'] + parsed['expand[0]'] == ['charge'] end.returns(successful_partially_refunded_response) assert response = @gateway.refund(@refund_amount, 'ch_test_charge', expand: ['charge']) @@ -573,7 +653,7 @@ def test_refund_with_expand_charge_only_sends_one_charge_expand def test_successful_refund_with_metadata @gateway.expects(:ssl_request).with do |method, url, post, headers| - post.include?("metadata[first_value]=true") + post.include?('metadata[first_value]=true') end.returns(successful_partially_refunded_response) assert response = @gateway.refund(@refund_amount, 'ch_test_charge', {metadata: {first_value: true}}) @@ -582,27 +662,28 @@ def test_successful_refund_with_metadata def test_successful_refund_with_reverse_transfer stub_comms(@gateway, :ssl_request) do - @gateway.refund(@amount, "auth", reverse_transfer: true) + @gateway.refund(@amount, 'auth', reverse_transfer: true) end.check_request do |method, endpoint, data, headers| assert_match(/reverse_transfer=true/, data) end.respond_with(successful_partially_refunded_response) end def test_successful_refund_with_refund_fee_amount - s = sequence("request") + s = sequence('request') @gateway.expects(:ssl_request).returns(successful_partially_refunded_response).in_sequence(s) - @gateway.expects(:ssl_request).returns(successful_application_fee_list_response).in_sequence(s) - @gateway.expects(:ssl_request).returns(successful_refunded_application_fee_response).in_sequence(s) + @gateway.expects(:ssl_request).returns(successful_fetch_application_fee_response).in_sequence(s) + @gateway.expects(:ssl_request).returns(successful_partially_refunded_application_fee_response).in_sequence(s) assert response = @gateway.refund(@refund_amount, 'ch_test_charge', :refund_fee_amount => 100) assert_success response end + # What is the significance of this??? it's to test that the first response is used as primary. so identical to above with an extra assertion def test_refund_with_fee_response_gives_a_charge_authorization - s = sequence("request") + s = sequence('request') @gateway.expects(:ssl_request).returns(successful_partially_refunded_response).in_sequence(s) - @gateway.expects(:ssl_request).returns(successful_application_fee_list_response).in_sequence(s) - @gateway.expects(:ssl_request).returns(successful_refunded_application_fee_response).in_sequence(s) + @gateway.expects(:ssl_request).returns(successful_fetch_application_fee_response).in_sequence(s) + @gateway.expects(:ssl_request).returns(successful_partially_refunded_application_fee_response).in_sequence(s) assert response = @gateway.refund(@refund_amount, 'ch_test_charge', :refund_fee_amount => 100) assert_success response @@ -610,19 +691,19 @@ def test_refund_with_fee_response_gives_a_charge_authorization end def test_unsuccessful_refund_with_refund_fee_amount_when_application_fee_id_not_found - s = sequence("request") + s = sequence('request') @gateway.expects(:ssl_request).returns(successful_partially_refunded_response).in_sequence(s) - @gateway.expects(:ssl_request).returns(unsuccessful_application_fee_list_response).in_sequence(s) + @gateway.expects(:ssl_request).returns(unsuccessful_fetch_application_fee_response).in_sequence(s) assert response = @gateway.refund(@refund_amount, 'ch_test_charge', :refund_fee_amount => 100) assert_failure response - assert_match(/^Application fee id could not be found/, response.message) + assert_match(/^Application fee id could not be retrieved/, response.message) end def test_unsuccessful_refund_with_refund_fee_amount_when_refunding_application_fee - s = sequence("request") + s = sequence('request') @gateway.expects(:ssl_request).returns(successful_partially_refunded_response).in_sequence(s) - @gateway.expects(:ssl_request).returns(successful_application_fee_list_response).in_sequence(s) + @gateway.expects(:ssl_request).returns(successful_fetch_application_fee_response).in_sequence(s) @gateway.expects(:ssl_request).returns(generic_error_response).in_sequence(s) assert response = @gateway.refund(@refund_amount, 'ch_test_charge', :refund_fee_amount => 100) @@ -641,7 +722,7 @@ def test_successful_verify_with_failed_void @gateway.verify(@credit_card, @options) end.respond_with(successful_authorization_response, failed_void_response) assert_success response - assert_equal "Transaction approved", response.message + assert_equal 'Transaction approved', response.message end def test_unsuccessful_verify @@ -649,11 +730,11 @@ def test_unsuccessful_verify @gateway.verify(@credit_card, @options) end.respond_with(declined_authorization_response, successful_void_response) assert_failure response - assert_equal "Your card was declined.", response.message + assert_equal 'Your card was declined.', response.message end def test_successful_request_always_uses_live_mode_to_determine_test_request - @gateway.expects(:ssl_request).returns(successful_partially_refunded_response(:livemode => true)) + @gateway.expects(:ssl_request).returns(successful_partially_refunded_response) assert response = @gateway.refund(@refund_amount, 'ch_test_charge') assert_success response @@ -692,6 +773,17 @@ def test_declined_request_advanced_decline_codes assert_equal 'ch_test_charge', response.authorization end + def test_declined_request_advanced_pickup_card_code + @gateway.expects(:ssl_request).returns(declined_pickup_card_purchase_response) + + assert response = @gateway.purchase(@amount, @credit_card, @options) + assert_failure response + + assert_equal Gateway::STANDARD_ERROR_CODE[:pickup_card], response.error_code + refute response.test? # unsuccessful request defaults to live + assert_equal 'ch_test_charge', response.authorization + end + def test_declined_request_advanced_decline_code_not_in_standard_mapping @gateway.expects(:ssl_request).returns(declined_generic_decline_purchase_response) @@ -723,11 +815,39 @@ def test_add_creditcard_with_credit_card def test_add_creditcard_with_track_data post = {} - @credit_card.stubs(:track_data).returns("Tracking data") - @credit_card.stubs(:contactless_magstripe).returns(true) + @credit_card.stubs(:track_data).returns('Swipe data') + @credit_card.stubs(:read_method).returns('contactless_magstripe') @gateway.send(:add_creditcard, post, @credit_card, {}) assert_equal @credit_card.track_data, post[:card][:swipe_data] - assert_equal "contactless_magstripe_mode", post[:card][:read_method] + assert_equal 'contactless_magstripe_mode', post[:card][:read_method] + assert_nil post[:card][:number] + assert_nil post[:card][:exp_year] + assert_nil post[:card][:exp_month] + assert_nil post[:card][:cvc] + assert_nil post[:card][:name] + end + + def test_add_creditcard_with_fallback_no_chip + post = {} + @credit_card.stubs(:track_data).returns('Swipe data') + @credit_card.stubs(:read_method).returns('fallback_no_chip') + @gateway.send(:add_creditcard, post, @credit_card, {}) + assert_equal @credit_card.track_data, post[:card][:swipe_data] + assert_equal 'no_chip', post[:card][:fallback_reason] + assert_nil post[:card][:number] + assert_nil post[:card][:exp_year] + assert_nil post[:card][:exp_month] + assert_nil post[:card][:cvc] + assert_nil post[:card][:name] + end + + def test_add_creditcard_with_fallback_chip_error + post = {} + @credit_card.stubs(:track_data).returns('Swipe data') + @credit_card.stubs(:read_method).returns('fallback_chip_error') + @gateway.send(:add_creditcard, post, @credit_card, {}) + assert_equal @credit_card.track_data, post[:card][:swipe_data] + assert_equal 'chip_error', post[:card][:fallback_reason] assert_nil post[:card][:number] assert_nil post[:card][:exp_year] assert_nil post[:card][:exp_month] @@ -737,24 +857,24 @@ def test_add_creditcard_with_track_data def test_add_creditcard_with_card_token post = {} - credit_card_token = "card_2iD4AezYnNNzkW" + credit_card_token = 'card_2iD4AezYnNNzkW' @gateway.send(:add_creditcard, post, credit_card_token, {}) - assert_equal "card_2iD4AezYnNNzkW", post[:card] + assert_equal 'card_2iD4AezYnNNzkW', post[:card] end def test_add_creditcard_with_card_token_and_customer post = {} - credit_card_token = "cus_3sgheFxeBgTQ3M|card_2iD4AezYnNNzkW" + credit_card_token = 'cus_3sgheFxeBgTQ3M|card_2iD4AezYnNNzkW' @gateway.send(:add_creditcard, post, credit_card_token, {}) - assert_equal "cus_3sgheFxeBgTQ3M", post[:customer] - assert_equal "card_2iD4AezYnNNzkW", post[:card] + assert_equal 'cus_3sgheFxeBgTQ3M', post[:customer] + assert_equal 'card_2iD4AezYnNNzkW', post[:card] end def test_add_creditcard_with_card_token_and_track_data post = {} - credit_card_token = "card_2iD4AezYnNNzkW" - @gateway.send(:add_creditcard, post, credit_card_token, :track_data => "Tracking data") - assert_equal "Tracking data", post[:card][:swipe_data] + credit_card_token = 'card_2iD4AezYnNNzkW' + @gateway.send(:add_creditcard, post, credit_card_token, :track_data => 'Tracking data') + assert_equal 'Tracking data', post[:card][:swipe_data] end def test_add_creditcard_with_emv_credit_card @@ -767,14 +887,14 @@ def test_add_creditcard_with_emv_credit_card def test_add_creditcard_pads_eci_value post = {} credit_card = network_tokenization_credit_card('4242424242424242', - payment_cryptogram: "111111111100cryptogram", + payment_cryptogram: '111111111100cryptogram', verification_value: nil, - eci: "7" + eci: '7' ) @gateway.send(:add_creditcard, post, credit_card, {}) - assert_equal "07", post[:card][:eci] + assert_equal '07', post[:card][:eci] end def test_application_fee_is_submitted_for_purchase @@ -787,24 +907,48 @@ def test_application_fee_is_submitted_for_purchase def test_application_fee_is_submitted_for_capture stub_comms(@gateway, :ssl_request) do - @gateway.capture(@amount, "ch_test_charge", @options.merge({:application_fee => 144})) + @gateway.capture(@amount, 'ch_test_charge', @options.merge({:application_fee => 144})) end.check_request do |method, endpoint, data, headers| assert_match(/application_fee=144/, data) end.respond_with(successful_capture_response) end + def test_exchange_rate_is_submitted_for_purchase + stub_comms(@gateway, :ssl_request) do + @gateway.purchase(@amount, @credit_card, @options.merge({:exchange_rate => 0.96251})) + end.check_request do |method, endpoint, data, headers| + assert_match(/exchange_rate=0.96251/, data) + end.respond_with(successful_purchase_response) + end + + def test_exchange_rate_is_submitted_for_capture + stub_comms(@gateway, :ssl_request) do + @gateway.capture(@amount, 'ch_test_charge', @options.merge({:exchange_rate => 0.96251})) + end.check_request do |method, endpoint, data, headers| + assert_match(/exchange_rate=0.96251/, data) + end.respond_with(successful_capture_response) + end + def test_destination_is_submitted_for_purchase stub_comms(@gateway, :ssl_request) do @gateway.purchase(@amount, @credit_card, @options.merge({:destination => 'subaccountid'})) end.check_request do |method, endpoint, data, headers| - assert_match(/destination=subaccountid/, data) + assert_match(/destination\[account\]=subaccountid/, data) + end.respond_with(successful_purchase_response) + end + + def test_destination_amount_is_submitted_for_purchase + stub_comms(@gateway, :ssl_request) do + @gateway.purchase(@amount, @credit_card, @options.merge({:destination => 'subaccountid', :destination_amount => @amount - 20})) + end.check_request do |method, endpoint, data, headers| + assert_match(/destination\[amount\]=#{@amount - 20}/, data) end.respond_with(successful_purchase_response) end def test_client_data_submitted_with_purchase stub_comms(@gateway, :ssl_request) do - updated_options = @options.merge({:description => "a test customer",:ip => "127.127.127.127", :user_agent => "some browser", :order_id => "42", :email => "foo@wonderfullyfakedomain.com", :receipt_email => "receipt-receiver@wonderfullyfakedomain.com", :referrer =>"http://www.shopify.com"}) - @gateway.purchase(@amount,@credit_card,updated_options) + updated_options = @options.merge({:description => 'a test customer', :ip => '127.127.127.127', :user_agent => 'some browser', :order_id => '42', :email => 'foo@wonderfullyfakedomain.com', :receipt_email => 'receipt-receiver@wonderfullyfakedomain.com', :referrer =>'http://www.shopify.com'}) + @gateway.purchase(@amount, @credit_card, updated_options) end.check_request do |method, endpoint, data, headers| assert_match(/description=a\+test\+customer/, data) assert_match(/ip=127\.127\.127\.127/, data) @@ -820,8 +964,8 @@ def test_client_data_submitted_with_purchase def test_client_data_submitted_with_purchase_without_email_or_order stub_comms(@gateway, :ssl_request) do - updated_options = @options.merge({:description => "a test customer",:ip => "127.127.127.127", :user_agent => "some browser", :referrer =>"http://www.shopify.com"}) - @gateway.purchase(@amount,@credit_card,updated_options) + updated_options = @options.merge({:description => 'a test customer', :ip => '127.127.127.127', :user_agent => 'some browser', :referrer =>'http://www.shopify.com'}) + @gateway.purchase(@amount, @credit_card, updated_options) end.check_request do |method, endpoint, data, headers| assert_match(/description=a\+test\+customer/, data) assert_match(/ip=127\.127\.127\.127/, data) @@ -834,8 +978,8 @@ def test_client_data_submitted_with_purchase_without_email_or_order def test_client_data_submitted_with_metadata_in_options stub_comms(@gateway, :ssl_request) do - updated_options = @options.merge({:metadata => {:this_is_a_random_key_name => 'with a random value', :i_made_up_this_key_too => 'canyoutell'}, :order_id => "42", :email => "foo@wonderfullyfakedomain.com"}) - @gateway.purchase(@amount,@credit_card,updated_options) + updated_options = @options.merge({:metadata => {:this_is_a_random_key_name => 'with a random value', :i_made_up_this_key_too => 'canyoutell'}, :order_id => '42', :email => 'foo@wonderfullyfakedomain.com'}) + @gateway.purchase(@amount, @credit_card, updated_options) end.check_request do |method, endpoint, data, headers| assert_match(/metadata\[this_is_a_random_key_name\]=with\+a\+random\+value/, data) assert_match(/metadata\[i_made_up_this_key_too\]=canyoutell/, data) @@ -846,25 +990,45 @@ def test_client_data_submitted_with_metadata_in_options def test_client_data_submitted_with_metadata_in_options_with_emv_credit_card_purchase stub_comms(@gateway, :ssl_request) do - updated_options = @options.merge({:metadata => {:this_is_a_random_key_name => 'with a random value', :i_made_up_this_key_too => 'canyoutell'}, :order_id => "42", :email => "foo@wonderfullyfakedomain.com"}) + updated_options = @options.merge({:metadata => {:this_is_a_random_key_name => 'with a random value', :i_made_up_this_key_too => 'canyoutell'}, :order_id => '42', :email => 'foo@wonderfullyfakedomain.com'}) @gateway.purchase(@amount, @emv_credit_card, updated_options) end.check_request do |method, endpoint, data, headers| assert_match(/metadata\[this_is_a_random_key_name\]=with\+a\+random\+value/, data) assert_match(/metadata\[i_made_up_this_key_too\]=canyoutell/, data) assert_match(/metadata\[email\]=foo\%40wonderfullyfakedomain\.com/, data) assert_match(/metadata\[order_id\]=42/, data) + assert_match(/metadata\[card_read_method\]=contact/, data) end.respond_with(successful_purchase_response) end def test_client_data_submitted_with_metadata_in_options_with_emv_credit_card_authorize stub_comms(@gateway, :ssl_request) do - updated_options = @options.merge({:metadata => {:this_is_a_random_key_name => 'with a random value', :i_made_up_this_key_too => 'canyoutell'}, :order_id => "42", :email => "foo@wonderfullyfakedomain.com"}) + updated_options = @options.merge({:metadata => {:this_is_a_random_key_name => 'with a random value', :i_made_up_this_key_too => 'canyoutell'}, :order_id => '42', :email => 'foo@wonderfullyfakedomain.com'}) @gateway.authorize(@amount, @emv_credit_card, updated_options) end.check_request do |method, endpoint, data, headers| assert_match(/metadata\[this_is_a_random_key_name\]=with\+a\+random\+value/, data) assert_match(/metadata\[i_made_up_this_key_too\]=canyoutell/, data) assert_match(/metadata\[email\]=foo\%40wonderfullyfakedomain\.com/, data) assert_match(/metadata\[order_id\]=42/, data) + assert_match(/metadata\[card_read_method\]=contact/, data) + end.respond_with(successful_purchase_response) + end + + def test_quickchip_is_set_on_purchase + stub_comms(@gateway, :ssl_request) do + @emv_credit_card.read_method = 'contact_quickchip' + @gateway.purchase(@amount, @emv_credit_card, @options) + end.check_request do |method, endpoint, data, headers| + assert_match(/card\[processing_method\]=quick_chip/, data) + end.respond_with(successful_purchase_response) + end + + def test_quickchip_is_not_set_on_authorize + stub_comms(@gateway, :ssl_request) do + @emv_credit_card.read_method = 'contact_quickchip' + @gateway.authorize(@amount, @emv_credit_card, @options) + end.check_request do |method, endpoint, data, headers| + refute_match(/card\[processing_method\]=quick_chip/, data) end.respond_with(successful_purchase_response) end @@ -879,6 +1043,32 @@ def test_add_address assert_equal @options[:billing_address][:city], post[:card][:address_city] end + def test_add_statement_address + post = {} + + @gateway.send(:add_statement_address, post, @options) + + assert_equal @options[:statement_address][:zip], post[:statement_address][:postal_code] + assert_equal @options[:statement_address][:state], post[:statement_address][:state] + assert_equal @options[:statement_address][:address1], post[:statement_address][:line1] + assert_equal @options[:statement_address][:address2], post[:statement_address][:line2] + assert_equal @options[:statement_address][:country], post[:statement_address][:country] + assert_equal @options[:statement_address][:city], post[:statement_address][:city] + end + + def test_add_statement_address_returns_nil_if_required_fields_missing + post = {} + [:address1, :city, :zip, :state].each do |required_key| + missing_required = @options.tap do |options| + options[:statement_address].delete_if { |k| k == required_key } + end + + @gateway.send(:add_statement_address, post, missing_required) + + assert_equal nil, post[:statement_address] + end + end + def test_ensure_does_not_respond_to_credit assert !@gateway.respond_to?(:credit) end @@ -890,7 +1080,7 @@ def test_gateway_without_credentials end def test_metadata_header - @gateway.expects(:ssl_request).once.with {|method, url, post, headers| + @gateway.expects(:ssl_request).once.with { |method, url, post, headers| headers && headers['X-Stripe-Client-User-Metadata'] == {:ip => '1.1.1.1'}.to_json }.returns(successful_purchase_response) @@ -898,7 +1088,7 @@ def test_metadata_header end def test_optional_version_header - @gateway.expects(:ssl_request).once.with {|method, url, post, headers| + @gateway.expects(:ssl_request).once.with { |method, url, post, headers| headers && headers['Stripe-Version'] == '2013-10-29' }.returns(successful_purchase_response) @@ -906,7 +1096,7 @@ def test_optional_version_header end def test_optional_idempotency_key_header - @gateway.expects(:ssl_request).once.with {|method, url, post, headers| + @gateway.expects(:ssl_request).once.with { |method, url, post, headers| headers && headers['Idempotency-Key'] == 'test123' }.returns(successful_purchase_response) @@ -915,7 +1105,7 @@ def test_optional_idempotency_key_header end def test_optional_idempotency_on_void - @gateway.expects(:ssl_request).once.with {|method, url, post, headers| + @gateway.expects(:ssl_request).once.with { |method, url, post, headers| headers && headers['Idempotency-Key'] == 'test123' }.returns(successful_purchase_response(true)) @@ -938,7 +1128,7 @@ def test_optional_idempotency_on_verify def test_initialize_gateway_with_version @gateway = StripeGateway.new(:login => 'login', :version => '2013-12-03') - @gateway.expects(:ssl_request).once.with {|method, url, post, headers| + @gateway.expects(:ssl_request).once.with { |method, url, post, headers| headers && headers['Stripe-Version'] == '2013-12-03' }.returns(successful_purchase_response) @@ -970,21 +1160,21 @@ def test_address_is_included_with_card_data end.respond_with(successful_purchase_response) end - def test_contactless_emv_flag_is_included_with_emv_card_data + def test_contactless_flag_is_included_with_emv_card_data stub_comms(@gateway, :ssl_request) do - @emv_credit_card.contactless_emv = true + @emv_credit_card.read_method = 'contactless' @gateway.purchase(@amount, @emv_credit_card, @options) end.check_request do |method, endpoint, data, headers| - data =~ /card\[read_method\]=contactless/ + assert data =~ /card\[read_method\]=contactless/ end.respond_with(successful_purchase_response) end def test_contactless_magstripe_flag_is_included_with_emv_card_data stub_comms(@gateway, :ssl_request) do - @emv_credit_card.contactless_magstripe = true + @emv_credit_card.read_method = 'contactless_magstripe' @gateway.purchase(@amount, @emv_credit_card, @options) end.check_request do |method, endpoint, data, headers| - data =~ /card\[read_method\]=contactless_magstripe_mode/ + assert data =~ /card\[read_method\]=contactless_magstripe_mode/ end.respond_with(successful_purchase_response) end @@ -992,14 +1182,14 @@ def test_contactless_flag_is_not_included_with_emv_card_data_by_default stub_comms(@gateway, :ssl_request) do @gateway.purchase(@amount, @emv_credit_card, @options) end.check_request do |method, endpoint, data, headers| - data !~ /card\[read_method\]=contactless/ && data !~ /card\[read_method\]=contactless_magstripe_mode/ + assert data !~ /card\[read_method\]=contactless/ && data !~ /card\[read_method\]=contactless_magstripe_mode/ end.respond_with(successful_purchase_response) end def test_encrypted_pin_is_included_with_emv_card_data stub_comms(@gateway, :ssl_request) do - @emv_credit_card.encrypted_pin_cryptogram = "8b68af72199529b8" - @emv_credit_card.encrypted_pin_ksn = "ffff0102628d12000001" + @emv_credit_card.encrypted_pin_cryptogram = '8b68af72199529b8' + @emv_credit_card.encrypted_pin_ksn = 'ffff0102628d12000001' @gateway.purchase(@amount, @emv_credit_card, @options) end.check_request do |method, endpoint, data, headers| assert data =~ /card\[encrypted_pin\]=8b68af72199529b8/ @@ -1013,27 +1203,27 @@ def generate_options_should_allow_key def test_passing_expand_parameters @gateway.expects(:ssl_request).with do |method, url, post, headers| - post.include?("expand[]=balance_transaction") + post.include?('expand[0]=balance_transaction') end.returns(successful_authorization_response) - @options.merge!(:expand => :balance_transaction) + @options[:expand] = :balance_transaction @gateway.authorize(@amount, @credit_card, @options) end def test_passing_expand_parameters_as_array @gateway.expects(:ssl_request).with do |method, url, post, headers| - post.include?("expand[]=balance_transaction&expand[]=customer") + post.include?('expand[0]=balance_transaction&expand[1]=customer') end.returns(successful_authorization_response) - @options.merge!(:expand => [:balance_transaction, :customer]) + @options[:expand] = [:balance_transaction, :customer] @gateway.authorize(@amount, @credit_card, @options) end def test_recurring_flag_not_set_by_default @gateway.expects(:ssl_request).with do |method, url, post, headers| - !post.include?("recurring") + !post.include?('recurring') end.returns(successful_authorization_response) @gateway.authorize(@amount, @credit_card, @options) @@ -1041,50 +1231,50 @@ def test_recurring_flag_not_set_by_default def test_passing_recurring_eci_sets_recurring_flag @gateway.expects(:ssl_request).with do |method, url, post, headers| - post.include?("recurring=true") + post.include?('recurring=true') end.returns(successful_authorization_response) - @options.merge!(eci: 'recurring') + @options[:eci] = 'recurring' @gateway.authorize(@amount, @credit_card, @options) end def test_passing_unknown_eci_does_not_set_recurring_flag @gateway.expects(:ssl_request).with do |method, url, post, headers| - !post.include?("recurring") + !post.include?('recurring') end.returns(successful_authorization_response) - @options.merge!(eci: 'installment') + @options[:eci] = 'installment' @gateway.authorize(@amount, @credit_card, @options) end def test_passing_recurring_true_option_sets_recurring_flag @gateway.expects(:ssl_request).with do |method, url, post, headers| - post.include?("recurring=true") + post.include?('recurring=true') end.returns(successful_authorization_response) - @options.merge!(recurring: true) + @options[:recurring] = true @gateway.authorize(@amount, @credit_card, @options) end def test_passing_recurring_false_option_does_not_set_recurring_flag @gateway.expects(:ssl_request).with do |method, url, post, headers| - !post.include?("recurring") + !post.include?('recurring') end.returns(successful_authorization_response) - @options.merge!(recurring: false) + @options[:recurring] = false @gateway.authorize(@amount, @credit_card, @options) end def test_new_attributes_are_included_in_update stub_comms(@gateway, :ssl_request) do - @gateway.send(:update, "cus_3sgheFxeBgTQ3M", "card_483etw4er9fg4vF3sQdrt3FG", { :name => "John Smith", :exp_year => 2021, :exp_month => 6 }) + @gateway.send(:update, 'cus_3sgheFxeBgTQ3M', 'card_483etw4er9fg4vF3sQdrt3FG', { :name => 'John Smith', :exp_year => 2021, :exp_month => 6 }) end.check_request do |method, endpoint, data, headers| - assert data == "name=John+Smith&exp_year=2021&exp_month=6" - assert endpoint.include? "/customers/cus_3sgheFxeBgTQ3M/cards/card_483etw4er9fg4vF3sQdrt3FG" + assert data == 'name=John+Smith&exp_year=2021&exp_month=6' + assert endpoint.include? '/customers/cus_3sgheFxeBgTQ3M/cards/card_483etw4er9fg4vF3sQdrt3FG' end.respond_with(successful_update_credit_card_response) end @@ -1112,7 +1302,7 @@ def test_successful_auth_with_network_tokenization_apple_pay end.returns(successful_authorization_response) credit_card = network_tokenization_credit_card('4242424242424242', - payment_cryptogram: "111111111100cryptogram", + payment_cryptogram: '111111111100cryptogram', verification_value: nil, eci: '05' ) @@ -1133,7 +1323,7 @@ def test_successful_auth_with_network_tokenization_android_pay end.returns(successful_authorization_response) credit_card = network_tokenization_credit_card('4242424242424242', - payment_cryptogram: "111111111100cryptogram", + payment_cryptogram: '111111111100cryptogram', verification_value: nil, eci: '05', source: :android_pay @@ -1155,7 +1345,7 @@ def test_successful_purchase_with_network_tokenization_apple_pay end.returns(successful_authorization_response) credit_card = network_tokenization_credit_card('4242424242424242', - payment_cryptogram: "111111111100cryptogram", + payment_cryptogram: '111111111100cryptogram', verification_value: nil, eci: '05' ) @@ -1176,7 +1366,7 @@ def test_successful_purchase_with_network_tokenization_android_pay end.returns(successful_authorization_response) credit_card = network_tokenization_credit_card('4242424242424242', - payment_cryptogram: "111111111100cryptogram", + payment_cryptogram: '111111111100cryptogram', verification_value: nil, eci: '05', source: :android_pay @@ -1196,9 +1386,9 @@ def test_supports_network_tokenization def test_emv_capture_application_fee_ignored response = stub_comms(@gateway, :ssl_request) do - @gateway.capture(@amount, "ch_test_charge", application_fee: 100, icc_data: @emv_credit_card.icc_data) + @gateway.capture(@amount, 'ch_test_charge', application_fee: 100, icc_data: @emv_credit_card.icc_data) end.check_request do |method, endpoint, data, headers| - assert data !~ /application_fee/, "request should not include application_fee" + assert data !~ /application_fee/, 'request should not include application_fee' end.respond_with(successful_capture_response_with_icc_data) assert_success response @@ -1206,21 +1396,20 @@ def test_emv_capture_application_fee_ignored def test_authorization_with_emv_payment_application_fee_included response = stub_comms(@gateway, :ssl_request) do - @gateway.authorize(@amount, "ch_test_charge", application_fee: 100, icc_data: @emv_credit_card.icc_data) + @gateway.authorize(@amount, 'ch_test_charge', application_fee: 100, icc_data: @emv_credit_card.icc_data) end.check_request do |method, endpoint, data, headers| - assert data =~ /application_fee/, "request should include application_fee" + assert data =~ /application_fee/, 'request should include application_fee' end.respond_with(successful_capture_response_with_icc_data) assert_success response end - def test_passing_stripe_account_header @gateway.expects(:ssl_request).with do |method, url, post, headers| - headers.include?("Stripe-Account") + headers.include?('Stripe-Account') end.returns(successful_authorization_response) - @options.merge!(stripe_account: fixtures(:stripe_destination)[:stripe_user_id]) + @options[:stripe_account] = fixtures(:stripe_destination)[:stripe_user_id] @gateway.purchase(@amount, @credit_card, @options) end @@ -1235,12 +1424,22 @@ def test_verify_bad_credentials assert !@gateway.verify_credentials end + def test_stripe_internal_error_fails + @gateway.expects(:add_creditcard) + @gateway.expects(:ssl_request).returns(stripe_internal_error_response) + + assert response = @gateway.purchase(@amount, @credit_card, @options) + assert_failure response + assert_equal response.message, 'No error details' + assert response.test? + end + private # this mock is only useful with unit tests, as cryptograms generated by an EMV terminal # are specific to the target acquirer, so remote tests using this mock will fail elsewhere. def credit_card_with_icc_data - ActiveMerchant::Billing::CreditCard.new(icc_data: '500B56495341204352454449545F201A56495341204143515549524552205445535420434152442030315F24031512315F280208405F2A0208265F300202015F34010182025C008407A0000000031010950502000080009A031408259B02E8009C01009F02060000000734499F03060000000000009F0607A00000000310109F0902008C9F100706010A03A080009F120F4352454449544F20444520564953419F1A0208269F1C0831373030303437309F1E0831373030303437309F2608EB2EC0F472BEA0A49F2701809F3303E0B8C89F34031E03009F3501229F360200C39F37040A27296F9F4104000001319F4502DAC5DFAE5711476173FFFFFF0119D15122011758989389DFAE5A08476173FFFFFF011957114761739001010119D151220117589893895A084761739001010119') + ActiveMerchant::Billing::CreditCard.new(read_method: 'contact', icc_data: '500B56495341204352454449545F201A56495341204143515549524552205445535420434152442030315F24031512315F280208405F2A0208265F300202015F34010182025C008407A0000000031010950502000080009A031408259B02E8009C01009F02060000000734499F03060000000000009F0607A00000000310109F0902008C9F100706010A03A080009F120F4352454449544F20444520564953419F1A0208269F1C0831373030303437309F1E0831373030303437309F2608EB2EC0F472BEA0A49F2701809F3303E0B8C89F34031E03009F3501229F360200C39F37040A27296F9F4104000001319F4502DAC5DFAE5711476173FFFFFF0119D15122011758989389DFAE5A08476173FFFFFF011957114761739001010119D151220117589893895A084761739001010119') end def pre_scrubbed @@ -1799,8 +1998,7 @@ def successful_purchase_response(refunded=false) RESPONSE end - def successful_partially_refunded_response(options = {}) - options = {:livemode=>false}.merge!(options) + def successful_partially_refunded_response <<-RESPONSE { "id": "re_test_refund", @@ -1845,52 +2043,55 @@ def failed_void_response RESPONSE end - def successful_refunded_application_fee_response + def successful_partially_refunded_application_fee_response <<-RESPONSE { - "id": "fee_id", - "object": "application_fee", - "created": 1375375417, - "livemode": false, + "id": "fr_C8qmJKrZVMTjjF", + "object": "fee_refund", "amount": 10, + "balance_transaction": "txn_1BkZ4uAWOtgoysognvusG5N5", + "created": 1516027008, "currency": "usd", - "user": "acct_id", - "user_email": "acct_id", - "application": "ca_application", - "charge": "ch_test_charge", - "refunded": false, - "amount_refunded": 10 + "fee": "fee_1BkZ4rIPBJTitsenGWcxYWCZ", + "metadata": {} } RESPONSE end - def successful_application_fee_list_response + def successful_fetch_application_fee_response <<-RESPONSE { - "object": "list", - "count": 2, - "url": "/v1/application_fees", - "data": [ - { - "object": "application_fee", - "id": "application_fee_id" - }, - { - "object": "another_fee", - "id": "another_fee_id" - } - ] + "id": "ch_1Bja3MIPBJTitsenv28Gy6iN", + "object": "charge", + "amount": 100, + "amount_refunded": 100, + "application": "ca_6E9gvTfZGEMknxpoHhC8xoeyMit55FAV", + "application_fee": "fee_1Bja3MIPBJTitsenKqV8Hc6R", + "balance_transaction": "txn_1Bja3OIPBJTitsenJ5amtW58", + "captured": true, + "created": 1515792428, + "currency": "usd", + "customer": null, + "description": "ActiveMerchant Test Purchase", + "destination": null, + "dispute": null, + "failure_code": null, + "failure_message": null, + "fraud_details": {}, + "invoice": null, + "livemode": false } RESPONSE end - def unsuccessful_application_fee_list_response + def unsuccessful_fetch_application_fee_response <<-RESPONSE { - "object": "list", - "count": 0, - "url": "/v1/application_fees", - "data": [] + "error": { + "type": "invalid_request_error", + "message": "No such charge: bad_auth", + "param": "id" + } } RESPONSE end @@ -1935,6 +2136,20 @@ def declined_call_issuer_purchase_response RESPONSE end + def declined_pickup_card_purchase_response + <<-RESPONSE + { + "error": { + "message": "Your card was declined.", + "type": "card_error", + "code": "card_declined", + "decline_code": "pickup_card", + "charge": "ch_test_charge" + } + } + RESPONSE + end + def declined_generic_decline_purchase_response <<-RESPONSE { @@ -2081,39 +2296,123 @@ def credentials_are_bogus_response MockResponse.new(401, body) end + def stripe_internal_error_response + <<-RESPONSE + { + "id": "ch_1CSa8KL6Z03PTOVWo9B3qYCI", + "object": "charge", + "amount": 900, + "amount_refunded": 0, + "application": null, + "application_fee": null, + "balance_transaction": null, + "captured": false, + "created": 1526517494, + "currency": "usd", + "customer": null, + "description": null, + "destination": null, + "dispute": null, + "failure_code": null, + "failure_message": null, + "fraud_details": {}, + "invoice": null, + "livemode": true, + "metadata": { + "product_name": "1 month", + "vendor_id": "12345", + "connect_agent": "Spreedly", + "email": "someone@example.com", + "order_id": "3193747-1568289" + }, + "on_behalf_of": null, + "order": null, + "outcome": { + "network_status": "approved_by_network", + "reason": null, + "seller_message": "Payment complete.", + "type": "authorized" + }, + "paid": false, + "receipt_email": null, + "receipt_number": null, + "refunded": false, + "refunds": { + "object": "list", + "data": [], + "has_more": false, + "total_count": 0, + "url": "/v1/charges/ch_1CSa8KL6Z03PTOVWo9B3qYCI/refunds" + }, + "review": null, + "shipping": null, + "source": { + "id": "card_1a2b3c4d5e6f7g8h9j", + "object": "card", + "address_city": null, + "address_country": null, + "address_line1": null, + "address_line1_check": null, + "address_line2": null, + "address_state": null, + "address_zip": null, + "address_zip_check": null, + "brand": "Visa", + "country": "MX", + "customer": null, + "cvc_check": null, + "dynamic_last4": null, + "exp_month": 11, + "exp_year": 2021, + "fingerprint": "ABCDEFGHIJKLMNO", + "funding": "credit", + "last4": "0123", + "metadata": {}, + "name": null, + "tokenization_method": null + }, + "source_transfer": null, + "statement_descriptor": "MAGIC*TEST*STUFF", + "status": "failed", + "transfer_group": null, + "livemode": false + } + RESPONSE + end + def token_params { - "id" => "tok_14uq3k2gKyKnHxtYUAZZZlH3", - "object" => "token", - "card" => { - "id" => "card_189f8n2eZvKYlo2CgvOd3Vtn", - "object" => "card", - "address_city" => nil, - "address_country" => nil, - "address_line1" => nil, - "address_line1_check" => nil, - "address_line2" => nil, - "address_state" => nil, - "address_zip" => nil, - "address_zip_check" => nil, - "brand" => "Visa", - "country" => "US", - "cvc_check" => nil, - "dynamic_last4" => nil, - "exp_month" => 8, - "exp_year" => 2017, - "funding" => "credit", - "last4" => "4242", - "metadata" => { + 'id' => 'tok_14uq3k2gKyKnHxtYUAZZZlH3', + 'object' => 'token', + 'card' => { + 'id' => 'card_189f8n2eZvKYlo2CgvOd3Vtn', + 'object' => 'card', + 'address_city' => nil, + 'address_country' => nil, + 'address_line1' => nil, + 'address_line1_check' => nil, + 'address_line2' => nil, + 'address_state' => nil, + 'address_zip' => nil, + 'address_zip_check' => nil, + 'brand' => 'Visa', + 'country' => 'US', + 'cvc_check' => nil, + 'dynamic_last4' => nil, + 'exp_month' => 8, + 'exp_year' => 2017, + 'funding' => 'credit', + 'last4' => '4242', + 'metadata' => { }, - "name" => nil, - "tokenization_method" => nil + 'name' => nil, + 'tokenization_method' => nil }, - "client_ip" => nil, - "created" => 1462903169, - "livemode" => false, - "type" => "card", - "used" => false + 'client_ip' => nil, + 'created' => 1462903169, + 'livemode' => false, + 'type' => 'card', + 'used' => false } end end diff --git a/test/unit/gateways/telr_test.rb b/test/unit/gateways/telr_test.rb index 19730ded31d..8e3ac5766bd 100644 --- a/test/unit/gateways/telr_test.rb +++ b/test/unit/gateways/telr_test.rb @@ -1,12 +1,12 @@ -require "test_helper" +require 'test_helper' class TelrTest < Test::Unit::TestCase include CommStub def setup @gateway = TelrGateway.new( - merchant_id: "login", - api_key: "password" + merchant_id: 'login', + api_key: 'password' ) @credit_card = credit_card @@ -20,7 +20,7 @@ def test_successful_purchase assert_success response - assert_equal "029724176180|100|AED", response.authorization + assert_equal '029724176180|100|AED', response.authorization assert response.test? end @@ -30,7 +30,7 @@ def test_failed_purchase end.respond_with(failed_purchase_response) assert_failure response - assert_equal "Not authorised", response.message + assert_equal 'Not authorised', response.message end def test_successful_authorize_and_capture @@ -56,12 +56,12 @@ def test_failed_authorize end.respond_with(failed_authorize_response) assert_failure response - assert_equal "Not authorised", response.message + assert_equal 'Not authorised', response.message end def test_failed_capture response = stub_comms do - @gateway.capture(100, "") + @gateway.capture(100, '') end.respond_with(failed_capture_response) assert_failure response @@ -73,7 +73,7 @@ def test_successful_void end.respond_with(successful_authorize_response) assert_success response - assert_equal "029894296182|100|AED", response.authorization + assert_equal '029894296182|100|AED', response.authorization void = stub_comms do @gateway.void(response.authorization) @@ -86,7 +86,7 @@ def test_successful_void def test_failed_void response = stub_comms do - @gateway.void("5d53a33d960c46d00f5dc061947d998c") + @gateway.void('5d53a33d960c46d00f5dc061947d998c') end.check_request do |endpoint, data, headers| assert_match(/5d53a33d960c46d00f5dc061947d998c/, data) end.respond_with(failed_void_response) @@ -100,7 +100,7 @@ def test_successful_refund end.respond_with(successful_purchase_response) assert_success response - assert_equal "029724176180|100|AED", response.authorization + assert_equal '029724176180|100|AED', response.authorization refund = stub_comms do @gateway.refund(@amount, response.authorization) @@ -113,7 +113,7 @@ def test_successful_refund def test_failed_refund response = stub_comms do - @gateway.refund(nil, "") + @gateway.refund(nil, '') end.respond_with(failed_refund_response) assert_failure response @@ -124,7 +124,7 @@ def test_successful_verify @gateway.verify(@credit_card) end.respond_with(successful_authorize_response, failed_void_response) assert_success response - assert_equal "Succeeded", response.message + assert_equal 'Succeeded', response.message end def test_failed_verify @@ -132,7 +132,7 @@ def test_failed_verify @gateway.verify(@credit_card) end.respond_with(failed_authorize_response, successful_void_response) assert_failure response - assert_equal "Not authorised", response.message + assert_equal 'Not authorised', response.message end def test_successful_reference_purchase diff --git a/test/unit/gateways/tns_test.rb b/test/unit/gateways/tns_test.rb index b8a5052f2c3..f97a0e6e242 100644 --- a/test/unit/gateways/tns_test.rb +++ b/test/unit/gateways/tns_test.rb @@ -91,7 +91,7 @@ def test_void def test_passing_alpha3_country_code stub_comms(@gateway, :ssl_request) do - @gateway.authorize(@amount, @credit_card, :billing_address => {country: "US"}) + @gateway.authorize(@amount, @credit_card, :billing_address => {country: 'US'}) end.check_request do |method, endpoint, data, headers| assert_match(/USA/, data) end.respond_with(successful_authorize_response) @@ -99,7 +99,7 @@ def test_passing_alpha3_country_code def test_non_existent_country stub_comms(@gateway, :ssl_request) do - @gateway.authorize(@amount, @credit_card, :billing_address => {country: "Blah"}) + @gateway.authorize(@amount, @credit_card, :billing_address => {country: 'Blah'}) end.check_request do |method, endpoint, data, headers| assert_match(/"country":null/, data) end.respond_with(successful_authorize_response) @@ -138,7 +138,7 @@ def test_successful_verify @gateway.verify(@credit_card, @options) end.respond_with(successful_authorize_response, successful_void_response) assert_success response - assert_equal "91debbeb-d88f-42e9-a6ce-9b62c99d656b", response.params['order']['id'] + assert_equal '91debbeb-d88f-42e9-a6ce-9b62c99d656b', response.params['order']['id'] end def test_successful_verify_with_failed_void @@ -146,7 +146,7 @@ def test_successful_verify_with_failed_void @gateway.verify(@credit_card, @options) end.respond_with(successful_authorize_response, failed_void_response) assert_success response - assert_equal "Succeeded", response.message + assert_equal 'Succeeded', response.message end def test_unsuccessful_verify @@ -154,7 +154,7 @@ def test_unsuccessful_verify @gateway.verify(@credit_card, @options) end.respond_with(failed_authorize_response, successful_void_response) assert_failure response - assert_equal "FAILURE - DECLINED", response.message + assert_equal 'FAILURE - DECLINED', response.message end def test_north_america_region_url diff --git a/test/unit/gateways/trans_first_test.rb b/test/unit/gateways/trans_first_test.rb index c9f10c3f810..34f04f9a75c 100644 --- a/test/unit/gateways/trans_first_test.rb +++ b/test/unit/gateways/trans_first_test.rb @@ -65,15 +65,30 @@ def test_failed_purchase_with_echeck def test_successful_refund @gateway.stubs(:ssl_post).returns(successful_refund_response) - response = @gateway.refund(@amount, "TransID") + response = @gateway.refund(@amount, 'TransID') assert_success response assert_equal '207686608|creditcard', response.authorization + assert_equal @amount, response.params['amount'].to_i*100 end def test_failed_refund @gateway.stubs(:ssl_post).returns(failed_refund_response) - response = @gateway.refund(@amount, "TransID") + response = @gateway.refund(@amount, 'TransID') + assert_failure response + end + + def test_successful_void + @gateway.stubs(:ssl_post).returns(successful_void_response) + + response = @gateway.void('TransID') + assert_success response + end + + def test_failed_void + @gateway.stubs(:ssl_post).returns(failed_void_response) + + response = @gateway.void('TransID') assert_failure response end @@ -320,4 +335,36 @@ def failed_refund_response </BankCardRefundStatus> XML end + + def successful_void_response + <<-XML + <?xml version="1.0" encoding="utf-8" ?> + <BankCardRefundStatus xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://www.paymentresources.com/webservices/"> + <TransID>0</TransID> + <TransID>207616632</TransID> + <CreditID>0</CreditID> + <RefID>123</RefID> + <PostedDate>2010-08-09T12:25:00</PostedDate> <SettledDate>0001-01-01T00:00:00</SettledDate> + <Amount>1.3100</Amount> + <AuthCode>012921</AuthCode> + <Status>Voided</Status> + <AVSCode>N</AVSCode> + <CVV2Code /> + </BankCardRefundStatus> + XML + end + + def failed_void_response + <<-XML + <?xml version="1.0" encoding="utf-8" ?> + <BankCardRefundStatus xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://www.paymentresources.com/webservices/"> + <TransID>0</TransID> + <CreditID>0</CreditID> + <PostedDate>0001-01-01T00:00:00</PostedDate> <SettledDate>0001-01-01T00:00:00</SettledDate> + <Amount>0</Amount> + <Status>Canceled</Status> + <Message>Transaction Is Not Allowed To Void or Refund</Message> + </BankCardRefundStatus> + XML + end end diff --git a/test/unit/gateways/trans_first_transaction_express_test.rb b/test/unit/gateways/trans_first_transaction_express_test.rb index 938c94a71a5..1bbfdf81f88 100644 --- a/test/unit/gateways/trans_first_transaction_express_test.rb +++ b/test/unit/gateways/trans_first_transaction_express_test.rb @@ -1,18 +1,18 @@ -require "test_helper" +require 'test_helper' class TransFirstTransactionExpressTest < Test::Unit::TestCase include CommStub def setup @gateway = TransFirstTransactionExpressGateway.new( - gateway_id: "gateway_id", - reg_key: "reg_key" + gateway_id: 'gateway_id', + reg_key: 'reg_key' ) @credit_card = credit_card + @check = check @amount = 100 @declined_amount = 21 - @partial_amount = 1110 end def test_successful_purchase @@ -22,17 +22,7 @@ def test_successful_purchase assert_success response - assert_equal "purchase|000015212561", response.authorization - assert response.test? - end - - def test_partial_purchase - response = stub_comms do - @gateway.purchase(@partial_amount, @credit_card) - end.respond_with(partial_purchase_response) - - assert_success response - assert_equal "000000000555", response.params["amt"] + assert_equal 'purchase|000015212561', response.authorization assert response.test? end @@ -42,18 +32,34 @@ def test_failed_purchase end.respond_with(failed_purchase_response) assert_failure response - assert_equal "Not sufficient funds", response.message - assert_equal "51", response.error_code + assert_equal 'Not sufficient funds', response.message + assert_equal '51', response.error_code assert response.test? end + def test_successful_purchase_with_echeck + @gateway.stubs(:ssl_post).returns(successful_purchase_echeck_response) + response = @gateway.purchase(@amount, @check) + + assert_success response + assert_equal 'purchase_echeck|000028705491', response.authorization + end + + def test_failed_purchase_with_echeck + @gateway.stubs(:ssl_post).returns(failed_purchase_echeck_response) + response = @gateway.purchase(@amount, @check) + + assert_failure response + assert_equal 'Error. Bank routing number validation negative (ABA).', response.message + end + def test_successful_authorize_and_capture response = stub_comms do @gateway.authorize(@amount, @credit_card) end.respond_with(successful_authorize_response) assert_success response - assert_equal "authorize|000015377801", response.authorization + assert_equal 'authorize|000015377801', response.authorization capture = stub_comms do @gateway.capture(@amount, response.authorization) @@ -70,14 +76,14 @@ def test_failed_authorize end.respond_with(failed_authorize_response) assert_failure response - assert_equal "Not sufficient funds", response.message - assert_equal "51", response.error_code + assert_equal 'Not sufficient funds', response.message + assert_equal '51', response.error_code assert response.test? end def test_failed_capture response = stub_comms do - @gateway.capture(100, "") + @gateway.capture(100, '') end.respond_with(failed_capture_response) assert_failure response @@ -89,7 +95,7 @@ def test_successful_void end.respond_with(successful_purchase_response) assert_success response - assert_equal "purchase|000015212561", response.authorization + assert_equal 'purchase|000015212561', response.authorization void = stub_comms do @gateway.void(response.authorization) @@ -102,13 +108,13 @@ def test_successful_void def test_failed_void response = stub_comms do - @gateway.void("purchase|5d53a33d960c46d00f5dc061947d998c") + @gateway.void('purchase|5d53a33d960c46d00f5dc061947d998c') end.check_request do |endpoint, data, headers| assert_match(/5d53a33d960c46d00f5dc061947d998c/, data) end.respond_with(failed_void_response) assert_failure response - assert_equal "50011", response.error_code + assert_equal '50011', response.error_code end def test_successful_refund @@ -117,7 +123,7 @@ def test_successful_refund end.respond_with(successful_purchase_response) assert_success response - assert_equal "purchase|000015212561", response.authorization + assert_equal 'purchase|000015212561', response.authorization refund = stub_comms do @gateway.refund(@amount, response.authorization) @@ -130,11 +136,37 @@ def test_successful_refund def test_failed_refund response = stub_comms do - @gateway.refund(nil, "") + @gateway.refund(nil, '') end.respond_with(failed_refund_response) assert_failure response - assert_equal "50011", response.error_code + assert_equal '50011', response.error_code + end + + def test_successful_refund_with_echeck + response = stub_comms do + @gateway.purchase(@amount, @check) + end.respond_with(successful_purchase_echeck_response) + + assert_success response + assert_equal 'purchase_echeck|000028705491', response.authorization + + refund = stub_comms do + @gateway.refund(@amount, response.authorization) + end.check_request do |endpoint, data, headers| + assert_match(/000028705491/, data) + end.respond_with(successful_refund_echeck_response) + + assert_success refund + end + + def test_failed_refund_with_echeck + response = stub_comms do + @gateway.refund(@amount, 'purchase_echeck|000028706091') + end.respond_with(failed_refund_response) + + assert_failure response + assert_equal '50011', response.error_code end def test_successful_credit @@ -144,7 +176,7 @@ def test_successful_credit assert_success response - assert_equal "credit|000001677461", response.authorization + assert_equal 'credit|000001677461', response.authorization assert response.test? end @@ -154,8 +186,8 @@ def test_failed_credit end.respond_with(failed_credit_response) assert_failure response - assert_equal "Validation Error", response.message - assert_equal "51334", response.error_code + assert_equal 'Validation Error', response.message + assert_equal '51334', response.error_code assert response.test? end @@ -164,7 +196,7 @@ def test_successful_verify @gateway.verify(@credit_card) end.respond_with(successful_authorize_response, failed_void_response) assert_success response - assert_equal "Succeeded", response.message + assert_equal 'Succeeded', response.message end def test_failed_verify @@ -172,7 +204,7 @@ def test_failed_verify @gateway.verify(@credit_card) end.respond_with(failed_authorize_response, successful_void_response) assert_failure response - assert_equal "Not sufficient funds", response.message + assert_equal 'Not sufficient funds', response.message end def test_successful_store @@ -182,8 +214,8 @@ def test_successful_store assert_success response - assert_equal "Succeeded", response.message - assert_equal "store|1453495229881170023", response.authorization + assert_equal 'Succeeded', response.message + assert_equal 'store|1453495229881170023', response.authorization assert response.test? end @@ -193,7 +225,7 @@ def test_failed_store end.respond_with(failed_store_response) assert_failure response - assert_equal "Validation Failure", response.message + assert_equal 'Validation Failure', response.message assert response.test? end @@ -216,10 +248,6 @@ def successful_purchase_response %(<?xml version='1.0' encoding='UTF-8'?><S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"><S:Body><ns2:SendTranResponse xmlns="http://postilion/realtime/portal/soa/xsd/Faults/2009/01" xmlns:ns2="http://postilion/realtime/merchantframework/xsd/v1/"><ns2:rspCode>00</ns2:rspCode><ns2:authRsp><ns2:aci>Y</ns2:aci></ns2:authRsp><ns2:tranData><ns2:swchKey>0A1009331525B2A2DBFAF771E2E62B</ns2:swchKey><ns2:tranNr>000015212561</ns2:tranNr><ns2:dtTm>2016-01-19T10:33:57.000-08:00</ns2:dtTm><ns2:amt>000000000100</ns2:amt><ns2:stan>305156</ns2:stan><ns2:auth>Lexc05</ns2:auth></ns2:tranData><ns2:cardType>0</ns2:cardType><ns2:mapCaid>300979940268000</ns2:mapCaid></ns2:SendTranResponse></S:Body></S:Envelope>) end - def partial_purchase_response - %(<?xml version='1.0' encoding='UTF-8'?><S:Envelope xmlns:S=\"http://schemas.xmlsoap.org/soap/envelope/\"><S:Body><ns2:SendTranResponse xmlns=\"http://postilion/realtime/portal/soa/xsd/Faults/2009/01\" xmlns:ns2=\"http://postilion/realtime/merchantframework/xsd/v1/\"><ns2:rspCode>10</ns2:rspCode><ns2:authRsp><ns2:secRslt>M</ns2:secRslt><ns2:avsRslt>Z</ns2:avsRslt><ns2:aci>Y</ns2:aci></ns2:authRsp><ns2:tranData><ns2:swchKey>0A10092D15279AD062097039A74A15</ns2:swchKey><ns2:tranNr>000015526161</ns2:tranNr><ns2:dtTm>2016-01-25T08:45:28.000-08:00</ns2:dtTm><ns2:amt>000000000555</ns2:amt><ns2:stan>332604</ns2:stan><ns2:auth>Lexc05</ns2:auth></ns2:tranData><ns2:cardType>0</ns2:cardType><ns2:mapCaid>300979940268000</ns2:mapCaid><ns2:additionalAmount><ns2:accountType>00</ns2:accountType><ns2:amountType>57</ns2:amountType><ns2:currencyCode>840</ns2:currencyCode><ns2:amountSign>C</ns2:amountSign><ns2:amount>000000001110</ns2:amount></ns2:additionalAmount></ns2:SendTranResponse></S:Body></S:Envelope>) - end - def failed_purchase_response %(<?xml version='1.0' encoding='UTF-8'?><S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"><S:Body><ns2:SendTranResponse xmlns="http://postilion/realtime/portal/soa/xsd/Faults/2009/01" xmlns:ns2="http://postilion/realtime/merchantframework/xsd/v1/"><ns2:rspCode>51</ns2:rspCode><ns2:authRsp><ns2:aci>Y</ns2:aci></ns2:authRsp><ns2:tranData><ns2:swchKey>0A1009331525BA8F333FC15F59AB32</ns2:swchKey><ns2:tranNr>000015220671</ns2:tranNr><ns2:dtTm>2016-01-19T12:52:25.000-08:00</ns2:dtTm><ns2:amt>000000000021</ns2:amt><ns2:stan>305918</ns2:stan><ns2:auth>Lexc05</ns2:auth></ns2:tranData><ns2:cardType>0</ns2:cardType><ns2:mapCaid>300979940268000</ns2:mapCaid></ns2:SendTranResponse></S:Body></S:Envelope>) end @@ -272,6 +300,22 @@ def failed_store_response %(<?xml version='1.0' encoding='UTF-8'?><S:Envelope xmlns:S=\"http://schemas.xmlsoap.org/soap/envelope/\"><S:Body><S:Fault xmlns:ns4=\"http://www.w3.org/2003/05/soap-envelope\"><faultcode>S:Server</faultcode><faultstring>Validation Failure</faultstring><detail><SystemFault:SystemFault xmlns:SystemFault=\"http://postilion/realtime/portal/soa/xsd/Faults/2009/01\" xmlns=\"http://postilion/realtime/portal/soa/xsd/Faults/2009/01\" xmlns:ns2=\"http://postilion/realtime/merchantframework/xsd/v1/\"><name>Validation Fault</name><message>cvc-type.3.1.3: The value '123' of element 'v1:pan' is not valid.</message><errorCode>50011</errorCode></SystemFault:SystemFault></detail></S:Fault></S:Body></S:Envelope>) end + def successful_purchase_echeck_response + %(<?xml version='1.0' encoding='UTF-8'?><S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"><S:Body><ns2:SendTranResponse xmlns="http://postilion/realtime/portal/soa/xsd/Faults/2009/01" xmlns:ns2="http://postilion/realtime/merchantframework/xsd/v1/"><ns2:rspCode>00</ns2:rspCode><ns2:authRsp><ns2:gwyTranId>43550871</ns2:gwyTranId></ns2:authRsp><ns2:tranData><ns2:swchKey>0A09071615AD2403F804EFDA26EA76</ns2:swchKey><ns2:tranNr>000028705491</ns2:tranNr><ns2:dtTm>2017-03-15T06:55:10-07:00</ns2:dtTm><ns2:amt>000000000100</ns2:amt><ns2:stan>386950</ns2:stan></ns2:tranData><ns2:achResponse><ns2:Message>Transaction processed.</ns2:Message><ns2:Note>PrevPay: nil +0</ns2:Note><ns2:Note>Score: 100/100</ns2:Note></ns2:achResponse></ns2:SendTranResponse></S:Body></S:Envelope>) + end + + def failed_purchase_echeck_response + %(<?xml version='1.0' encoding='UTF-8'?><S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"><S:Body><ns2:SendTranResponse xmlns="http://postilion/realtime/portal/soa/xsd/Faults/2009/01" xmlns:ns2="http://postilion/realtime/merchantframework/xsd/v1/"><ns2:rspCode>06</ns2:rspCode><ns2:authRsp/><ns2:tranData><ns2:swchKey>0A09071715AD2654A6814EE9ADC0EF</ns2:swchKey><ns2:tranNr>000028705711</ns2:tranNr><ns2:dtTm>2017-03-15T07:35:38-07:00</ns2:dtTm><ns2:amt>000000000100</ns2:amt><ns2:stan>386972</ns2:stan></ns2:tranData><ns2:achResponse><ns2:Message>Bank routing number validation negative (ABA).</ns2:Message></ns2:achResponse></ns2:SendTranResponse></S:Body></S:Envelope>) + end + + def successful_refund_echeck_response + %( <?xml version='1.0' encoding='UTF-8'?><S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"><S:Body><ns2:SendTranResponse xmlns="http://postilion/realtime/portal/soa/xsd/Faults/2009/01" xmlns:ns2="http://postilion/realtime/merchantframework/xsd/v1/"><ns2:rspCode>00</ns2:rspCode><ns2:authRsp><ns2:gwyTranId>43550889</ns2:gwyTranId></ns2:authRsp><ns2:tranData><ns2:swchKey>0A09071715AD2786821E2F357D7E52</ns2:swchKey><ns2:tranNr>000028706091</ns2:tranNr><ns2:dtTm>2017-03-15T07:56:31-07:00</ns2:dtTm><ns2:amt>000000000100</ns2:amt><ns2:stan>387010</ns2:stan></ns2:tranData><ns2:achResponse><ns2:Message>Transaction Cancelled.</ns2:Message><ns2:Note>PrevPay: nil +0</ns2:Note><ns2:Note>Score: 100/100</ns2:Note><ns2:Note>Cancellation Notes: RefNumber:28706091</ns2:Note></ns2:achResponse></ns2:SendTranResponse></S:Body></S:Envelope>) + end + + def failed_refund_echeck_response + %(<?xml version='1.0' encoding='UTF-8'?><S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"><S:Body><ns2:SendTranResponse xmlns="http://postilion/realtime/portal/soa/xsd/Faults/2009/01" xmlns:ns2="http://postilion/realtime/merchantframework/xsd/v1/"><ns2:rspCode>12</ns2:rspCode><ns2:extRspCode>B40F</ns2:extRspCode><ns2:authRsp><ns2:gwyTranId>43550889</ns2:gwyTranId></ns2:authRsp><ns2:tranData><ns2:swchKey>0A09071615AD285C3E4E0AE3A42CF3</ns2:swchKey><ns2:tranNr>000028706091</ns2:tranNr><ns2:dtTm>2017-03-15T08:11:06-07:00</ns2:dtTm><ns2:amt>000000000100</ns2:amt></ns2:tranData></ns2:SendTranResponse></S:Body></S:Envelope>) + end + def empty_purchase_response %() end diff --git a/test/unit/gateways/transact_pro_test.rb b/test/unit/gateways/transact_pro_test.rb index a394e91431d..6323dc78536 100644 --- a/test/unit/gateways/transact_pro_test.rb +++ b/test/unit/gateways/transact_pro_test.rb @@ -5,7 +5,7 @@ def setup @gateway = TransactProGateway.new( guid: 'login', password: 'password', - terminal: 'terminal', + terminal: 'terminal' ) @credit_card = credit_card @@ -84,7 +84,7 @@ def test_failed_capture capture = @gateway.capture(nil, '3d25ab044075924479d3836f549b015481d15d74|100') assert_failure capture - assert_equal "4dd02f79f428470bbd794590834dfbf38b5721ac|100", capture.authorization + assert_equal '4dd02f79f428470bbd794590834dfbf38b5721ac|100', capture.authorization assert_equal 'Failed', capture.message end @@ -154,31 +154,31 @@ def test_failed_verify private def successful_purchase_response - "ID:a27891dedd57e875df653144c518b8fb646b2351~Status:Success~MerchantID:1410896668~Terminal:Rietumu - non3D~ResultCode:000~ApprovalCode:646391~CardIssuerCountry:XX" + 'ID:a27891dedd57e875df653144c518b8fb646b2351~Status:Success~MerchantID:1410896668~Terminal:Rietumu - non3D~ResultCode:000~ApprovalCode:646391~CardIssuerCountry:XX' end def failed_purchase_response - "ID:fed54b10b610bb760816aad42721672e8fd19327~Status:Failed~MerchantID:1410965369~Terminal:Rietumu - non3D~ResultCode:908~ApprovalCode:-3~CardIssuerCountry:XX" + 'ID:fed54b10b610bb760816aad42721672e8fd19327~Status:Failed~MerchantID:1410965369~Terminal:Rietumu - non3D~ResultCode:908~ApprovalCode:-3~CardIssuerCountry:XX' end def successful_authorize_response - "ID:3d25ab044075924479d3836f549b015481d15d74~Status:HoldOk~MerchantID:1410974273~Terminal:Rietumu - non3D~ResultCode:000~ApprovalCode:524282~CardIssuerCountry:XX" + 'ID:3d25ab044075924479d3836f549b015481d15d74~Status:HoldOk~MerchantID:1410974273~Terminal:Rietumu - non3D~ResultCode:000~ApprovalCode:524282~CardIssuerCountry:XX' end def failed_authorize_response - "ID:c9c789a575ba8556e2c5f56174d859c23ac56e09~Status:Failed~MerchantID:1410974976~Terminal:Rietumu - non3D~ResultCode:908~ApprovalCode:-3~CardIssuerCountry:XX" + 'ID:c9c789a575ba8556e2c5f56174d859c23ac56e09~Status:Failed~MerchantID:1410974976~Terminal:Rietumu - non3D~ResultCode:908~ApprovalCode:-3~CardIssuerCountry:XX' end def successful_capture_response - "ID:3d25ab044075924479d3836f549b015481d15d74~Status:Success~MerchantID:1410974273~Terminal:Rietumu - non3D~ResultCode:000~ApprovalCode:524282~CardIssuerCountry:XX" + 'ID:3d25ab044075924479d3836f549b015481d15d74~Status:Success~MerchantID:1410974273~Terminal:Rietumu - non3D~ResultCode:000~ApprovalCode:524282~CardIssuerCountry:XX' end def failed_capture_response - "ID:4dd02f79f428470bbd794590834dfbf38b5721ac~Status:Failed~MerchantID:1325788706~Terminal:TerminalName~ResultCode:000~ApprovalCode:804958" + 'ID:4dd02f79f428470bbd794590834dfbf38b5721ac~Status:Failed~MerchantID:1325788706~Terminal:TerminalName~ResultCode:000~ApprovalCode:804958' end def successful_refund_response - "Refund Success" + 'Refund Success' end def failed_refund_response @@ -186,14 +186,14 @@ def failed_refund_response end def successful_void_response - "DMS canceled OK" + 'DMS canceled OK' end def failed_void_response - "DMS Cancel failed" + 'DMS Cancel failed' end def successful_init_response - "OK:a27891dedd57e875df653144c518b8fb646b2351" + 'OK:a27891dedd57e875df653144c518b8fb646b2351' end end diff --git a/test/unit/gateways/trexle_test.rb b/test/unit/gateways/trexle_test.rb new file mode 100644 index 00000000000..a1ee4295ccc --- /dev/null +++ b/test/unit/gateways/trexle_test.rb @@ -0,0 +1,444 @@ +require 'test_helper' + +class TrexleTest < Test::Unit::TestCase + def setup + @gateway = TrexleGateway.new(api_key: 'THIS_IS_NOT_A_REAL_API_KEY') + + @credit_card = credit_card + @amount = 100 + + @options = { + email: 'john@trexle.com', + billing_address: address, + description: 'Store Purchase', + ip: '127.0.0.1' + } + end + + def test_required_api_key_on_initialization + assert_raises ArgumentError do + TrexleGateway.new + end + end + + def test_default_currency + assert_equal 'USD', TrexleGateway.default_currency + end + + def test_money_format + assert_equal :cents, TrexleGateway.money_format + end + + def test_url + assert_equal 'https://core.trexle.com/api/v1', TrexleGateway.test_url + end + + def test_live_url + assert_equal 'https://core.trexle.com/api/v1', TrexleGateway.live_url + end + + def test_supported_countries + expected_supported_countries = %w(AD AE AT AU BD BE BG BN CA CH CY CZ DE DK EE EG ES FI FR GB + GI GR HK HU ID IE IL IM IN IS IT JO KW LB LI LK LT LU LV MC + MT MU MV MX MY NL NO NZ OM PH PL PT QA RO SA SE SG SI SK SM + TR TT UM US VA VN ZA) + assert_equal expected_supported_countries, TrexleGateway.supported_countries + end + + def test_supported_cardtypes + assert_equal [:visa, :master, :american_express], TrexleGateway.supported_cardtypes + end + + def test_display_name + assert_equal 'Trexle', TrexleGateway.display_name + end + + def test_setup_purchase_parameters + @gateway.expects(:add_amount).with(instance_of(Hash), @amount, @options) + @gateway.expects(:add_customer_data).with(instance_of(Hash), @options) + @gateway.expects(:add_invoice).with(instance_of(Hash), @options) + @gateway.expects(:add_creditcard).with(instance_of(Hash), @credit_card) + @gateway.expects(:add_address).with(instance_of(Hash), @credit_card, @options) + + @gateway.stubs(:ssl_request).returns(successful_purchase_response) + assert_success @gateway.purchase(@amount, @credit_card, @options) + end + + def test_successful_purchase + post_data = {} + headers = {} + @gateway.stubs(:headers).returns(headers) + @gateway.stubs(:post_data).returns(post_data) + @gateway.expects(:ssl_request).with(:post, 'https://core.trexle.com/api/v1/charges', post_data, headers).returns(successful_purchase_response) + + assert response = @gateway.purchase(@amount, @credit_card, @options) + assert_success response + assert_equal 'charge_0cfad7ee5ffe75f58222bff214bfa5cc7ad7c367', response.authorization + assert_equal JSON.parse(successful_purchase_response), response.params + assert response.test? + end + + def test_unsuccessful_request + @gateway.expects(:ssl_request).returns(failed_purchase_response) + + assert response = @gateway.purchase(@amount, @credit_card, @options) + assert_failure response + assert_equal 'Invalid response.', response.message + end + + def test_unparsable_body_of_successful_response + @gateway.stubs(:raw_ssl_request).returns(MockResponse.succeeded('not-json')) + + assert response = @gateway.purchase(@amount, @credit_card, @options) + assert_failure response + assert_match(/Invalid JSON response received/, response.message) + end + + def test_successful_store + @gateway.expects(:ssl_request).returns(successful_store_response) + assert response = @gateway.store(@credit_card, @options) + assert_success response + assert_equal 'token_2cb443cf26b6ecdadd8144d1fac8240710aa41f1', response.authorization + assert_equal JSON.parse(successful_store_response), response.params + assert response.test? + end + + def test_unsuccessful_store + @gateway.expects(:ssl_request).returns(failed_store_response) + + assert response = @gateway.store(@credit_card, @options) + assert_failure response + assert_equal 'Invalid response.', response.message + end + + def test_successful_update + token = 'token_940ade441a23d53e04017f53af6c3a1eae9978ae' + @gateway.expects(:ssl_request).with(:put, "https://core.trexle.com/api/v1/customers/#{token}", instance_of(String), instance_of(Hash)).returns(successful_customer_store_response) + assert response = @gateway.update('token_940ade441a23d53e04017f53af6c3a1eae9978ae', @credit_card, @options) + assert_success response + assert_equal 'token_940ade441a23d53e04017f53af6c3a1eae9978ae', response.authorization + assert_equal JSON.parse(successful_customer_store_response), response.params + assert response.test? + end + + def test_successful_refund + token = 'charge_0cfad7ee5ffe75f58222bff214bfa5cc7ad7c367' + @gateway.expects(:ssl_request).with(:post, "https://core.trexle.com/api/v1/charges/#{token}/refunds", {amount: '100'}.to_json, instance_of(Hash)).returns(successful_refund_response) + + assert response = @gateway.refund(100, token) + assert_equal 'refund_7f696a86f9cb136520c51ea90c17f687b8df40b0', response.authorization + assert_success response + assert response.test? + end + + def test_unsuccessful_refund + token = 'charge_0cfad7ee5ffe75f58222bff214bfa5cc7ad7c367' + @gateway.expects(:ssl_request).with(:post, "https://core.trexle.com/api/v1/charges/#{token}/refunds", {amount: '100'}.to_json, instance_of(Hash)).returns(failed_refund_response) + + assert response = @gateway.refund(100, token) + assert_failure response + assert_equal 'Invalid response.', response.message + end + + def test_successful_authorize + post_data = {} + headers = {} + @gateway.stubs(:headers).returns(headers) + @gateway.stubs(:post_data).returns(post_data) + @gateway.expects(:ssl_request).with(:post, 'https://core.trexle.com/api/v1/charges', post_data, headers).returns(successful_purchase_response) + + assert response = @gateway.authorize(@amount, @credit_card, @options) + assert_success response + assert_equal 'charge_0cfad7ee5ffe75f58222bff214bfa5cc7ad7c367', response.authorization + assert_equal JSON.parse(successful_purchase_response), response.params + assert response.test? + end + + def test_successful_capture + post_data = {} + headers = {} + token = 'charge_6e47a330dca67ec7f696e8b650db22fe69bb8499' + @gateway.stubs(:headers).returns(headers) + @gateway.stubs(:post_data).returns(post_data) + @gateway.expects(:ssl_request).with(:put, "https://core.trexle.com/api/v1/charges/#{token}/capture", post_data, headers).returns(successful_capture_response) + + assert response = @gateway.capture(100, token) + assert_success response + assert_equal token, response.authorization + assert response.test? + end + + def test_store_parameters + @gateway.expects(:add_creditcard).with(instance_of(Hash), @credit_card) + @gateway.expects(:add_address).with(instance_of(Hash), @credit_card, @options) + @gateway.expects(:ssl_request).returns(successful_store_response) + assert_success @gateway.store(@credit_card, @options) + end + + def test_update_parameters + @gateway.expects(:add_creditcard).with(instance_of(Hash), @credit_card) + @gateway.expects(:add_address).with(instance_of(Hash), @credit_card, @options) + @gateway.expects(:ssl_request).returns(successful_store_response) + assert_success @gateway.update('token_6b5d89f723d1aeee8ff0c588fd4ccbaae223b9aa', @credit_card, @options) + end + + def test_add_amount + @gateway.expects(:amount).with(100).returns('100') + post = {} + @gateway.send(:add_amount, post, 100, @options) + assert_equal '100', post[:amount] + end + + def test_set_default_currency + @gateway.expects(:currency).with(100).returns('USD') + post = {} + @gateway.send(:add_amount, post, 100, @options) + assert_equal 'USD', post[:currency] + end + + def test_set_currency + @gateway.expects(:currency).never + post = {} + @options[:currency] = 'USD' + @gateway.send(:add_amount, post, 100, @options) + assert_equal 'USD', post[:currency] + end + + def test_set_currency_case + @gateway.expects(:currency).never + post = {} + @options[:currency] = 'usd' + @gateway.send(:add_amount, post, 100, @options) + assert_equal 'USD', post[:currency] + end + + def test_add_customer_data + post = {} + + @gateway.send(:add_customer_data, post, @options) + + assert_equal 'john@trexle.com', post[:email] + assert_equal '127.0.0.1', post[:ip_address] + end + + def test_add_address + post = {} + + @gateway.send(:add_address, post, @credit_card, @options) + + assert_equal @options[:billing_address][:address1], post[:card][:address_line1] + assert_equal @options[:billing_address][:city], post[:card][:address_city] + assert_equal @options[:billing_address][:zip], post[:card][:address_postcode] + assert_equal @options[:billing_address][:state], post[:card][:address_state] + assert_equal @options[:billing_address][:country], post[:card][:address_country] + end + + def test_add_address_with_card_token + post = {} + + @gateway.send(:add_address, post, 'somecreditcardtoken', @options) + + assert_equal false, post.has_key?(:card) + end + + def test_add_invoice + post = {} + @gateway.send(:add_invoice, post, @options) + + assert_equal @options[:description], post[:description] + end + + def test_add_creditcard + post = {} + @gateway.send(:add_creditcard, post, @credit_card) + + assert_equal @credit_card.number, post[:card][:number] + assert_equal @credit_card.month, post[:card][:expiry_month] + assert_equal @credit_card.year, post[:card][:expiry_year] + assert_equal @credit_card.verification_value, post[:card][:cvc] + assert_equal @credit_card.name, post[:card][:name] + end + + def test_add_creditcard_with_card_token + post = {} + @gateway.send(:add_creditcard, post, 'token_f974687e4e866d6cca534e1cd42236817d315b3a') + assert_equal 'token_f974687e4e866d6cca534e1cd42236817d315b3a', post[:card_token] + assert_false post.has_key?(:card) + end + + def test_add_creditcard_with_customer_token + post = {} + @gateway.send(:add_creditcard, post, 'token_2cb443cf26b6ecdadd8144d1fac8240710aa41f1') + assert_equal 'token_2cb443cf26b6ecdadd8144d1fac8240710aa41f1', post[:card_token] + assert_false post.has_key?(:card) + end + + def test_post_data + post = {} + @gateway.send(:add_creditcard, post, @credit_card) + assert_equal post.to_json, @gateway.send(:post_data, post) + end + + def test_headers + expected_headers = { + 'Content-Type' => 'application/json', + 'Authorization' => "Basic #{Base64.strict_encode64('THIS_IS_NOT_A_REAL_API_KEY:').strip}" + } + + @gateway.expects(:ssl_request).with(:post, anything, anything, expected_headers).returns(successful_purchase_response) + assert @gateway.purchase(@amount, @credit_card, {}) + + expected_headers['X-Partner-Key'] = 'MyPartnerKey' + expected_headers['X-Safe-Card'] = '1' + + @gateway.expects(:ssl_request).with(:post, anything, anything, expected_headers).returns(successful_purchase_response) + assert @gateway.purchase(@amount, @credit_card, partner_key: 'MyPartnerKey', safe_card: '1') + end + + def test_transcript_scrubbing + assert_equal scrubbed_transcript, @gateway.scrub(transcript) + end + + private + + def successful_purchase_response + '{ + "response":{ + "token":"charge_0cfad7ee5ffe75f58222bff214bfa5cc7ad7c367", + "success":true, + "captured":true + } + }' + end + + def failed_purchase_response + '{ + "error":"Payment failed", + "detail":"An error occurred while processing your card. Try again in a little bit." + }' + end + + def successful_store_response + '{ + "response":{ + "token":"token_2cb443cf26b6ecdadd8144d1fac8240710aa41f1", + "card":{ + "token":"token_f974687e4e866d6cca534e1cd42236817d315b3a", + "primary":true + } + } + }' + end + + def failed_store_response + '{ + "error":"an error has occured", + "detail":"invalid token" + }' + end + + def successful_customer_store_response + '{ + "response":{ + "token":"token_940ade441a23d53e04017f53af6c3a1eae9978ae", + "card":{ + "token":"token_9a3f559962cbf6828e2cc38a02023565b0294548", + "scheme":"master", + "display_number":"XXXX-XXXX-XXXX-4444", + "expiry_year":2019, + "expiry_month":9, + "cvc":123, + "name":"Longbob Longsen", + "address_line1":"456 My Street", + "address_line2":null, + "address_city":"Ottawa", + "address_state":"ON", + "address_postcode":"K1C2N6", + "address_country":"CA", + "primary":true + } + } + }' + end + + def failed_customer_store_response + '{ + "error":"an error has occured", + "detail":"invalid token" + }' + end + + def successful_refund_response + '{ + "response":{ + "token":"refund_7f696a86f9cb136520c51ea90c17f687b8df40b0", + "success":true, + "amount":100, + "charge":"charge_ee4542e9f4d2c50f7fea55b694423a53991a323a", + "status_message":"Transaction approved" + } + }' + end + + def failed_refund_response + '{ + "error":"Refund failed", + "detail":"invalid token" + }' + end + + def successful_capture_response + '{ + "response":{ + "token":"charge_6e47a330dca67ec7f696e8b650db22fe69bb8499", + "success":true, + "captured":true + } + }' + end + + def transcript + '{ + "amount":"100", + "currency":"USD", + "email":"john@trexle.com", + "ip_address":"66.249.79.118", + "description":"Store Purchase 1437598192", + "card":{ + "number":"5555555555554444", + "expiry_month":9, + "expiry_year":2017, + "cvc":"123", + "name":"Longbob Longsen", + "address_line1":"456 My Street", + "address_city":"Ottawa", + "address_postcode":"K1C2N6", + "address_state":"ON", + "address_country":"CA" + } + }' + end + + def scrubbed_transcript + '{ + "amount":"100", + "currency":"USD", + "email":"john@trexle.com", + "ip_address":"66.249.79.118", + "description":"Store Purchase 1437598192", + "card":{ + "number":"[FILTERED]", + "expiry_month":9, + "expiry_year":2017, + "cvc":"[FILTERED]", + "name":"Longbob Longsen", + "address_line1":"456 My Street", + "address_city":"Ottawa", + "address_postcode":"K1C2N6", + "address_state":"ON", + "address_country":"CA" + } + }' + end + +end diff --git a/test/unit/gateways/trust_commerce_test.rb b/test/unit/gateways/trust_commerce_test.rb index fbba691fece..e94146db360 100644 --- a/test/unit/gateways/trust_commerce_test.rb +++ b/test/unit/gateways/trust_commerce_test.rb @@ -1,15 +1,18 @@ require 'test_helper' class TrustCommerceTest < Test::Unit::TestCase + include CommStub def setup @gateway = TrustCommerceGateway.new( :login => 'TestMerchant', - :password => 'password' + :password => 'password', + :aggregator_id => 'abc123' ) # Force SSL post @gateway.stubs(:tclink?).returns(false) @amount = 100 + @check = check @credit_card = credit_card('4111111111111111') end @@ -28,12 +31,20 @@ def test_unsuccessful_purchase assert_failure response end + def test_succesful_purchase_with_check + stub_comms do + @gateway.purchase(@amount, @check) + end.check_request do |endpoint, data, headers| + assert_match(%r{aggregator1}, data) + end.respond_with(successful_purchase_response) + end + def test_amount_style - assert_equal '1034', @gateway.send(:amount, 1034) + assert_equal '1034', @gateway.send(:amount, 1034) - assert_raise(ArgumentError) do - @gateway.send(:amount, '10.34') - end + assert_raise(ArgumentError) do + @gateway.send(:amount, '10.34') + end end def test_avs_result @@ -100,7 +111,7 @@ def transcript def scrubbed_transcript <<-TRANSCRIPT -action=sale&demo=y&password=password&custid=TestMerchant&shipto_zip=90001&shipto_state=CA&shipto_city=Somewhere&shipto_address1=123+Test+St.&avs=n&zip=90001&state=CA&city=Somewhere&address1=123+Test+St.&cvv=[FILTERED]&exp=0916&cc=[FILTERED]&name=Longbob+Longsen&media=cc&ip=10.10.10.10&email=cody%40example.com&ticket=%231000.1&amount=100 +action=sale&demo=y&password=[FILTERED]&custid=TestMerchant&shipto_zip=90001&shipto_state=CA&shipto_city=Somewhere&shipto_address1=123+Test+St.&avs=n&zip=90001&state=CA&city=Somewhere&address1=123+Test+St.&cvv=[FILTERED]&exp=0916&cc=[FILTERED]&name=Longbob+Longsen&media=cc&ip=10.10.10.10&email=cody%40example.com&ticket=%231000.1&amount=100 TRANSCRIPT end end diff --git a/test/unit/gateways/usa_epay_advanced_test.rb b/test/unit/gateways/usa_epay_advanced_test.rb index 91c6d13e2b4..7c22b87d841 100644 --- a/test/unit/gateways/usa_epay_advanced_test.rb +++ b/test/unit/gateways/usa_epay_advanced_test.rb @@ -1,4 +1,5 @@ # encoding: utf-8 + require 'test_helper' require 'logger' @@ -26,40 +27,40 @@ def setup :year => 12, :brand => 'visa', :verification_value => '123', - :first_name => "Fred", - :last_name => "Flintstone" + :first_name => 'Fred', + :last_name => 'Flintstone' ) @check = ActiveMerchant::Billing::Check.new( :account_number => '123456789012', :routing_number => '123456789', :account_type => 'checking', - :first_name => "Fred", - :last_name => "Flintstone" + :first_name => 'Fred', + :last_name => 'Flintstone' ) payment_methods = [ { - :name => "My Visa", # optional + :name => 'My Visa', # optional :sort => 2, # optional :method => @credit_card }, { - :name => "My Checking", + :name => 'My Checking', :method => @check } ] payment_method = { - :name => "My new Visa", # optional + :name => 'My new Visa', # optional :method => @credit_card } @customer_options = { :id => 1, # optional: merchant assigned id, usually db id - :notes => "Note about customer", # optional - :data => "Some Data", # optional - :url => "awesomesite.com", # optional + :notes => 'Note about customer', # optional + :data => 'Some Data', # optional + :url => 'awesomesite.com', # optional :payment_methods => payment_methods # optional } @@ -78,7 +79,7 @@ def setup @standard_transaction_options = { :method_id => 0, :command => 'Sale', - :amount => 2000 #20.00 + :amount => 2000 # 20.00 } @get_payment_options = { @@ -199,6 +200,18 @@ def test_successful_update_customer assert_nil response.authorization end + def test_successful_quick_update_customer + @gateway.expects(:ssl_post).returns(successful_customer_response('quickUpdateCustomer')) + + assert response = @gateway.quick_update_customer({customer_number: @options[:customer_number], update_data: @customer_options}) + assert_instance_of Response, response + assert response.test? + assert_success response + assert_equal 'true', response.params['quick_update_customer_return'] + assert_equal 'true', response.message + assert_nil response.authorization + end + def test_successful_enable_customer @options.merge!(@standard_transaction_options) @gateway.expects(:ssl_post).returns(successful_customer_response('enableCustomer')) @@ -277,7 +290,7 @@ def test_successful_get_customer_payment_methods end def test_successful_update_customer_payment_method - @options.merge!(@payment_options).merge!(:method_id => 1) + @options.merge!(@payment_options)[:method_id] = 1 @gateway.expects(:ssl_post).returns(successful_update_customer_payment_method_response) assert response = @gateway.update_customer_payment_method(@options) @@ -408,7 +421,7 @@ def test_successful_run_check_credit end # TODO get post_auth response - #def test_successful_post_auth + # def test_successful_post_auth # @options.merge!(:authorization_code => 'bogus') # @gateway.expects(:ssl_post).returns(successful_post_auth_response) @@ -420,7 +433,7 @@ def test_successful_run_check_credit # #assert_equal '47568732', response.authorization # puts response.inspect - #end + # end def test_successful_run_quick_sale @options.merge!(@transaction_options) @@ -482,7 +495,7 @@ def test_successful_refund_transaction end # TODO get override_transaction response - #def test_successful_override_transaction + # def test_successful_override_transaction # @gateway.expects(:ssl_post).returns(successful_override_transaction_response) # assert response = @gateway.override_transaction(@options) @@ -491,7 +504,7 @@ def test_successful_refund_transaction # assert response.test? # puts response.inspect - #end + # end # Transaction Status ================================================ diff --git a/test/unit/gateways/usa_epay_transaction_test.rb b/test/unit/gateways/usa_epay_transaction_test.rb index fda1226a1c8..260195409da 100644 --- a/test/unit/gateways/usa_epay_transaction_test.rb +++ b/test/unit/gateways/usa_epay_transaction_test.rb @@ -7,6 +7,7 @@ def setup @gateway = UsaEpayTransactionGateway.new(:login => 'LOGIN') @credit_card = credit_card('4242424242424242') + @check = check @options = { :billing_address => address, :shipping_address => address @@ -43,6 +44,29 @@ def test_successful_request assert response.test? end + def test_successful_request_with_echeck + @gateway.expects(:ssl_post).returns(successful_purchase_response_echeck) + + response = @gateway.purchase(@amount, @check, @options) + assert_success response + assert_equal '133134803', response.authorization + assert response.test? + end + + def test_successful_purchase_with_echeck_and_extra_options + response = stub_comms do + @gateway.purchase(@amount, @check, @options.merge(check_format: 'ARC', account_type: 'savings')) + end.check_request do |endpoint, data, headers| + assert_match(/UMcheckformat=ARC/, data) + assert_match(/UMaccounttype=savings/, data) + end.respond_with(successful_purchase_response_echeck) + + assert_equal 'Success', response.message + assert_equal '133134803', response.authorization + assert_success response + assert response.test? + end + def test_unsuccessful_request @gateway.expects(:ssl_post).returns(unsuccessful_purchase_response) @@ -54,7 +78,7 @@ def test_unsuccessful_request def test_successful_purchase_passing_extra_info response = stub_comms do - @gateway.purchase(@amount, @credit_card, @options.merge(:order_id => "1337", :description => "socool")) + @gateway.purchase(@amount, @credit_card, @options.merge(:order_id => '1337', :description => 'socool')) end.check_request do |endpoint, data, headers| assert_match(/UMinvoice=1337/, data) assert_match(/UMdescription=socool/, data) @@ -72,6 +96,17 @@ def test_successful_purchase_passing_extra_test_mode assert_success response end + def test_successful_purchase_email_receipt + response = stub_comms do + @gateway.purchase(@amount, @credit_card, @options.merge(:email => 'bobby@hill.com', :cust_receipt => 'Yes', :cust_receipt_name => 'socool')) + end.check_request do |endpoint, data, headers| + assert_match(/UMcustreceipt=Yes/, data) + assert_match(/UMcustreceiptname=socool/, data) + assert_match(/UMtestmode=0/, data) + end.respond_with(successful_purchase_response) + assert_success response + end + def test_successful_purchase_split_payment response = stub_comms do @gateway.purchase(@amount, @credit_card, @options.merge( @@ -108,6 +143,69 @@ def test_successful_purchase_split_payment_with_custom_on_error assert_success response end + def test_successful_purchase_recurring_fields + response = stub_comms do + @gateway.purchase(@amount, @credit_card, @options.merge( + :recurring_fields => { + add_customer: true, + schedule: 'quarterly', + bill_source_key: 'bill source key', + bill_amount: 123, + num_left: 5, + start: '20501212', + recurring_receipt: true + } + )) + end.check_request do |endpoint, data, headers| + assert_match %r{UMaddcustomer=yes}, data + assert_match %r{UMschedule=quarterly}, data + assert_match %r{UMbillsourcekey=bill\+source\+key}, data + assert_match %r{UMbillamount=1.23}, data + assert_match %r{UMnumleft=5}, data + assert_match %r{UMstart=20501212}, data + assert_match %r{UMrecurringreceipt=yes}, data + end.respond_with(successful_purchase_response) + assert_success response + end + + def test_successful_purchase_custom_fields + response = stub_comms do + @gateway.purchase(@amount, @credit_card, @options.merge( + :custom_fields => { + 1 => 'diablo', + 2 => 'mephisto', + 3 => 'baal' + } + )) + end.check_request do |endpoint, data, headers| + assert_match %r{UMcustom1=diablo}, data + assert_match %r{UMcustom2=mephisto}, data + assert_match %r{UMcustom3=baal}, data + end.respond_with(successful_purchase_response) + assert_success response + end + + def test_successful_purchase_line_items + response = stub_comms do + @gateway.purchase(@amount, @credit_card, @options.merge( + :line_items => [ + { :sku=> 'abc123', :cost => 119, :quantity => 1 }, + { :sku => 'def456', :cost => 200, :quantity => 2, :name => 'an item' }, + ] + )) + end.check_request do |endpoint, data, headers| + assert_match %r{UMline0sku=abc123}, data + assert_match %r{UMline0cost=1.19}, data + assert_match %r{UMline0qty=1}, data + + assert_match %r{UMline1sku=def456}, data + assert_match %r{UMline1cost=2.00}, data + assert_match %r{UMline1qty=2}, data + assert_match %r{UMline1name=an\+item}, data + end.respond_with(successful_purchase_response) + assert_success response + end + def test_successful_authorize_request @gateway.expects(:ssl_post).returns(successful_authorize_response) @@ -119,7 +217,7 @@ def test_successful_authorize_request def test_successful_authorize_passing_extra_info response = stub_comms do - @gateway.authorize(@amount, @credit_card, @options.merge(:order_id => "1337", :description => "socool")) + @gateway.authorize(@amount, @credit_card, @options.merge(:order_id => '1337', :description => 'socool')) end.check_request do |endpoint, data, headers| assert_match(/UMinvoice=1337/, data) assert_match(/UMdescription=socool/, data) @@ -174,6 +272,15 @@ def test_successful_refund_request assert response.test? end + def test_successful_refund_request_with_echeck + @gateway.expects(:ssl_post).returns(successful_refund_response_echeck) + + response = @gateway.refund(@amount, '65074409', @options) + assert_success response + assert_equal '133134926', response.authorization + assert response.test? + end + def test_successful_refund_passing_extra_info response = stub_comms do @gateway.refund(@amount, '65074409', @options) @@ -202,6 +309,15 @@ def test_successful_void_request assert response.test? end + def test_successful_void_request_with_echeck + @gateway.expects(:ssl_post).returns(successful_void_response_echeck) + + response = @gateway.void('65074409', @options) + assert_success response + assert_equal '133134971', response.authorization + assert response.test? + end + def test_successful_void_passing_extra_info response = stub_comms do @gateway.void('65074409', @options.merge(:no_release => true)) @@ -296,11 +412,11 @@ def test_add_test_mode_with_false_test_mode_option end def test_amount_style - assert_equal '10.34', @gateway.send(:amount, 1034) + assert_equal '10.34', @gateway.send(:amount, 1034) - assert_raise(ArgumentError) do - @gateway.send(:amount, '10.34') - end + assert_raise(ArgumentError) do + @gateway.send(:amount, '10.34') + end end def test_supported_countries @@ -328,10 +444,10 @@ def test_cvv_result end def test_add_track_data_with_creditcard - @credit_card.track_data = "data" + @credit_card.track_data = 'data' @gateway.expects(:ssl_post).with do |_, body| - body.include?("UMmagstripe=data") + body.include?('UMmagstripe=data') end.returns(successful_purchase_response) assert response = @gateway.purchase(@amount, @credit_card, @options) @@ -339,11 +455,11 @@ def test_add_track_data_with_creditcard end def test_add_track_data_with_empty_data - ["", nil].each do |data| + ['', nil].each do |data| @credit_card.track_data = data @gateway.expects(:ssl_post).with do |_, body| - refute body.include? "UMmagstripe=" + refute body.include? 'UMmagstripe=' body end.returns(successful_purchase_response) @@ -357,24 +473,29 @@ def test_manual_entry_is_properly_indicated_on_purchase response = stub_comms do @gateway.purchase(@amount, @credit_card, @options) end.check_request do |endpoint, data, headers| - assert_match %r{UMcard=4242424242424242}, data assert_match %r{UMcardpresent=true}, data - end.respond_with(successful_purchase_response) assert_success response end def test_does_not_raise_error_on_missing_values - @gateway.expects(:ssl_post).returns("status") + @gateway.expects(:ssl_post).returns('status') assert_nothing_raised do response = @gateway.purchase(@amount, @credit_card, @options) assert_failure response end end -private + def test_scrub + assert @gateway.supports_scrubbing? + assert_equal @gateway.scrub(pre_scrubbed), post_scrubbed + assert_equal @gateway.scrub(pre_scrubbed_track_data), post_scrubbed_track_data + assert_equal @gateway.scrub(pre_scrubbed_echeck), post_scrubbed_echeck + end + + private def assert_address(type, post, expected_first_name = nil, expected_last_name = nil) prefix = key_prefix(type) @@ -414,26 +535,182 @@ def purchase_request end def successful_purchase_response - "UMversion=2.9&UMstatus=Approved&UMauthCode=001716&UMrefNum=55074409&UMavsResult=Address%3A%20Match%20%26%205%20Digit%20Zip%3A%20Match&UMavsResultCode=Y&UMcvv2Result=Match&UMcvv2ResultCode=M&UMresult=A&UMvpasResultCode=&UMerror=Approved&UMerrorcode=00000&UMcustnum=&UMbatch=596&UMisDuplicate=N&UMconvertedAmount=&UMconvertedAmountCurrency=840&UMconversionRate=&UMcustReceiptResult=No%20Receipt%20Sent&UMfiller=filled" + 'UMversion=2.9&UMstatus=Approved&UMauthCode=001716&UMrefNum=55074409&UMavsResult=Address%3A%20Match%20%26%205%20Digit%20Zip%3A%20Match&UMavsResultCode=Y&UMcvv2Result=Match&UMcvv2ResultCode=M&UMresult=A&UMvpasResultCode=&UMerror=Approved&UMerrorcode=00000&UMcustnum=&UMbatch=596&UMisDuplicate=N&UMconvertedAmount=&UMconvertedAmountCurrency=840&UMconversionRate=&UMcustReceiptResult=No%20Receipt%20Sent&UMfiller=filled' end def unsuccessful_purchase_response - "UMversion=2.9&UMstatus=Declined&UMauthCode=000000&UMrefNum=55076060&UMavsResult=Address%3A%20Match%20%26%205%20Digit%20Zip%3A%20Match&UMavsResultCode=Y&UMcvv2Result=Not%20Processed&UMcvv2ResultCode=P&UMvpasResultCode=&UMresult=D&UMerror=Card%20Declined&UMerrorcode=10127&UMbatch=596&UMfiller=filled" + 'UMversion=2.9&UMstatus=Declined&UMauthCode=000000&UMrefNum=55076060&UMavsResult=Address%3A%20Match%20%26%205%20Digit%20Zip%3A%20Match&UMavsResultCode=Y&UMcvv2Result=Not%20Processed&UMcvv2ResultCode=P&UMvpasResultCode=&UMresult=D&UMerror=Card%20Declined&UMerrorcode=10127&UMbatch=596&UMfiller=filled' end def successful_authorize_response - "UMversion=2.9&UMstatus=Approved&UMauthCode=101716&UMrefNum=65074409&UMavsResult=Address%3A%20Match%20%26%205%20Digit%20Zip%3A%20Match&UMavsResultCode=Y&UMcvv2Result=Match&UMcvv2ResultCode=M&UMresult=A&UMvpasResultCode=&UMerror=Approved&UMerrorcode=00000&UMcustnum=&UMbatch=596&UMisDuplicate=N&UMconvertedAmount=&UMconvertedAmountCurrency=840&UMconversionRate=&UMcustReceiptResult=No%20Receipt%20Sent&UMfiller=filled" + 'UMversion=2.9&UMstatus=Approved&UMauthCode=101716&UMrefNum=65074409&UMavsResult=Address%3A%20Match%20%26%205%20Digit%20Zip%3A%20Match&UMavsResultCode=Y&UMcvv2Result=Match&UMcvv2ResultCode=M&UMresult=A&UMvpasResultCode=&UMerror=Approved&UMerrorcode=00000&UMcustnum=&UMbatch=596&UMisDuplicate=N&UMconvertedAmount=&UMconvertedAmountCurrency=840&UMconversionRate=&UMcustReceiptResult=No%20Receipt%20Sent&UMfiller=filled' end def successful_capture_response - "UMversion=2.9&UMstatus=Approved&UMauthCode=101716&UMrefNum=65074409&UMavsResult=No%20AVS%20response%20%28Typically%20no%20AVS%20data%20sent%20or%20swiped%20transaction%29&UMavsResultCode=&UMcvv2Result=No%20CVV2%2FCVC%20data%20available%20for%20transaction.&UMcvv2ResultCode=&UMresult=A&UMvpasResultCode=&UMerror=Approved&UMerrorcode=00000&UMcustnum=&UMbatch=&UMbatchRefNum=&UMisDuplicate=N&UMconvertedAmount=&UMconvertedAmountCurrency=840&UMconversionRate=&UMcustReceiptResult=No%20Receipt%20Sent&UMprocRefNum=&UMcardLevelResult=&UMauthAmount=&UMfiller=filled" + 'UMversion=2.9&UMstatus=Approved&UMauthCode=101716&UMrefNum=65074409&UMavsResult=No%20AVS%20response%20%28Typically%20no%20AVS%20data%20sent%20or%20swiped%20transaction%29&UMavsResultCode=&UMcvv2Result=No%20CVV2%2FCVC%20data%20available%20for%20transaction.&UMcvv2ResultCode=&UMresult=A&UMvpasResultCode=&UMerror=Approved&UMerrorcode=00000&UMcustnum=&UMbatch=&UMbatchRefNum=&UMisDuplicate=N&UMconvertedAmount=&UMconvertedAmountCurrency=840&UMconversionRate=&UMcustReceiptResult=No%20Receipt%20Sent&UMprocRefNum=&UMcardLevelResult=&UMauthAmount=&UMfiller=filled' end def successful_refund_response - "UMversion=2.9&UMstatus=Approved&UMauthCode=101716&UMrefNum=63813138&UMavsResult=Unmapped%20AVS%20response%20%28%20%20%20%29&UMavsResultCode=%20%20%20&UMcvv2Result=No%20CVV2%2FCVC%20data%20available%20for%20transaction.&UMcvv2ResultCode=&UMresult=A&UMvpasResultCode=&UMerror=&UMerrorcode=00000&UMcustnum=&UMbatch=&UMbatchRefNum=&UMisDuplicate=N&UMconvertedAmount=1.00&UMconvertedAmountCurrency=840&UMconversionRate=&UMcustReceiptResult=No%20Receipt%20Sent&UMprocRefNum=&UMcardLevelResult=&UMauthAmount=&UMfiller=filled" + 'UMversion=2.9&UMstatus=Approved&UMauthCode=101716&UMrefNum=63813138&UMavsResult=Unmapped%20AVS%20response%20%28%20%20%20%29&UMavsResultCode=%20%20%20&UMcvv2Result=No%20CVV2%2FCVC%20data%20available%20for%20transaction.&UMcvv2ResultCode=&UMresult=A&UMvpasResultCode=&UMerror=&UMerrorcode=00000&UMcustnum=&UMbatch=&UMbatchRefNum=&UMisDuplicate=N&UMconvertedAmount=1.00&UMconvertedAmountCurrency=840&UMconversionRate=&UMcustReceiptResult=No%20Receipt%20Sent&UMprocRefNum=&UMcardLevelResult=&UMauthAmount=&UMfiller=filled' end def successful_void_response - "UMversion=2.9&UMstatus=Approved&UMauthCode=&UMrefNum=63812270&UMavsResult=No%20AVS%20response%20%28Typically%20no%20AVS%20data%20sent%20or%20swiped%20transaction%29&UMavsResultCode=&UMcvv2Result=No%20CVV2%2FCVC%20data%20available%20for%20transaction.&UMcvv2ResultCode=&UMresult=A&UMvpasResultCode=&UMerror=Transaction%20Voided%20Successfully&UMerrorcode=00000&UMcustnum=&UMbatch=&UMbatchRefNum=&UMisDuplicate=N&UMconvertedAmount=&UMconvertedAmountCurrency=840&UMconversionRate=&UMcustReceiptResult=No%20Receipt%20Sent&UMprocRefNum=&UMcardLevelResult=&UMauthAmount=&UMfiller=filled" + 'UMversion=2.9&UMstatus=Approved&UMauthCode=&UMrefNum=63812270&UMavsResult=No%20AVS%20response%20%28Typically%20no%20AVS%20data%20sent%20or%20swiped%20transaction%29&UMavsResultCode=&UMcvv2Result=No%20CVV2%2FCVC%20data%20available%20for%20transaction.&UMcvv2ResultCode=&UMresult=A&UMvpasResultCode=&UMerror=Transaction%20Voided%20Successfully&UMerrorcode=00000&UMcustnum=&UMbatch=&UMbatchRefNum=&UMisDuplicate=N&UMconvertedAmount=&UMconvertedAmountCurrency=840&UMconversionRate=&UMcustReceiptResult=No%20Receipt%20Sent&UMprocRefNum=&UMcardLevelResult=&UMauthAmount=&UMfiller=filled' + end + + def successful_purchase_response_echeck + 'UMversion=2.9&UMstatus=Approved&UMauthCode=TMEC4D&UMrefNum=133134803&UMavsResult=No%20AVS%20response%20%28Typically%20no%20AVS%20data%20sent%20or%20swiped%20transaction%29&UMavsResultCode=&UMcvv2Result=No%20CVV2%2FCVC%20data%20available%20for%20transaction.&UMcvv2ResultCode=&UMresult=A&UMvpasResultCode=&UMerror=&UMerrorcode=00000&UMcustnum=&UMbatch=180316&UMbatchRefNum=&UMisDuplicate=N&UMconvertedAmount=&UMconvertedAmountCurrency=840&UMconversionRate=&UMcustReceiptResult=No%20Receipt%20Sent&UMprocRefNum=18031621233065&UMcardLevelResult=&UMauthAmount=&UMfiller=filled' + end + + def successful_refund_response_echeck + 'UMversion=2.9&UMstatus=Approved&UMauthCode=TM1E74&UMrefNum=133134926&UMavsResult=No%20AVS%20response%20%28Typically%20no%20AVS%20data%20sent%20or%20swiped%20transaction%29&UMavsResultCode=&UMcvv2Result=No%20CVV2%2FCVC%20data%20available%20for%20transaction.&UMcvv2ResultCode=&UMresult=A&UMvpasResultCode=&UMerror=&UMerrorcode=00000&UMcustnum=&UMbatch=&UMbatchRefNum=&UMisDuplicate=N&UMconvertedAmount=&UMconvertedAmountCurrency=840&UMconversionRate=&UMcustReceiptResult=No%20Receipt%20Sent&UMprocRefNum=&UMcardLevelResult=&UMauthAmount=&UMfiller=filled' + end + + def successful_void_response_echeck + 'UMversion=2.9&UMstatus=Approved&UMauthCode=TM80A5&UMrefNum=133134971&UMavsResult=No%20AVS%20response%20%28Typically%20no%20AVS%20data%20sent%20or%20swiped%20transaction%29&UMavsResultCode=&UMcvv2Result=No%20CVV2%2FCVC%20data%20available%20for%20transaction.&UMcvv2ResultCode=&UMresult=A&UMvpasResultCode=&UMerror=&UMerrorcode=00000&UMcustnum=&UMbatch=&UMbatchRefNum=&UMisDuplicate=N&UMconvertedAmount=&UMconvertedAmountCurrency=840&UMconversionRate=&UMcustReceiptResult=No%20Receipt%20Sent&UMprocRefNum=&UMcardLevelResult=&UMauthAmount=&UMfiller=filled' + end + + def pre_scrubbed + <<-EOS +opening connection to sandbox.usaepay.com:443... +opened +starting SSL for sandbox.usaepay.com:443... +SSL established +<- "POST /gate HTTP/1.1\r\nContent-Type: application/x-www-form-urlencoded\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nAccept: */*\r\nUser-Agent: Ruby\r\nConnection: close\r\nHost: sandbox.usaepay.com\r\nContent-Length: 774\r\n\r\n" +<- "UMamount=1.00&UMinvoice=&UMdescription=&UMcard=4000100011112224&UMcvv2=123&UMexpir=0919&UMname=Longbob+Longsen&UMbillfname=Jim&UMbilllname=Smith&UMbillcompany=Widgets+Inc&UMbillstreet=456+My+Street&UMbillstreet2=Apt+1&UMbillcity=Ottawa&UMbillstate=NC&UMbillzip=27614&UMbillcountry=CA&UMbillphone=%28555%29555-5555&UMshipfname=Jim&UMshiplname=Smith&UMshipcompany=Widgets+Inc&UMshipstreet=456+My+Street&UMshipstreet2=Apt+1&UMshipcity=Ottawa&UMshipstate=ON&UMshipzip=K1C2N6&UMshipcountry=CA&UMshipphone=%28555%29555-5555&UMstreet=456+My+Street&UMzip=27614&UMcommand=cc%3Asale&UMkey=4EoZ5U2Q55j976W7eplC71i6b7kn4pcV&UMsoftware=Active+Merchant&UMtestmode=0&UMhash=s%2F5268F91058BC9F9FA944693D799F324B2497B7247850A51E53226309FB2540F0%2F7b4c4f6a4e775141cc0e4e10c0388d9adeb47fd1%2Fn" +-> "HTTP/1.1 200 OK\r\n" +-> "Server: http\r\n" +-> "Date: Tue, 13 Feb 2018 18:17:20 GMT\r\n" +-> "Content-Type: text/html\r\n" +-> "Content-Length: 485\r\n" +-> "Connection: close\r\n" +-> "P3P: policyref=\"http://www.usaepay.com/w3c/p3p.xml\", CP=\"NON TAIa IVAa IVDa OUR NOR PHY ONL UNI FIN INT DEM\"\r\n" +-> "Strict-Transport-Security: max-age=15768000\r\n" +-> "\r\n" +reading 485 bytes... +-> "UMversion=2.9&UMstatus=Approved&UMauthCode=042366&UMrefNum=132020588&UMavsResult=Address%3A%20Match%20%26%205%20Digit%20Zip%3A%20Match&UMavsResultCode=YYY&UMcvv2Result=Match&UMcvv2ResultCode=M&UMresult=A&UMvpasResultCode=&UMerror=Approved&UMerrorcode=00000&UMcustnum=&UMbatch=120&UMbatchRefNum=848&UMisDuplicate=N&UMconvertedAmount=&UMconvertedAmountCurrency=840&UMconversionRate=&UMcustReceiptResult=No%20Receipt%20Sent&UMprocRefNum=&UMcardLevelResult=A&UMauthAmount=1&UMfiller=filled" +read 485 bytes +Conn close + EOS + end + + def post_scrubbed + <<-EOS +opening connection to sandbox.usaepay.com:443... +opened +starting SSL for sandbox.usaepay.com:443... +SSL established +<- "POST /gate HTTP/1.1\r\nContent-Type: application/x-www-form-urlencoded\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nAccept: */*\r\nUser-Agent: Ruby\r\nConnection: close\r\nHost: sandbox.usaepay.com\r\nContent-Length: 774\r\n\r\n" +<- "UMamount=1.00&UMinvoice=&UMdescription=&UMcard=[FILTERED]&UMcvv2=[FILTERED]&UMexpir=0919&UMname=Longbob+Longsen&UMbillfname=Jim&UMbilllname=Smith&UMbillcompany=Widgets+Inc&UMbillstreet=456+My+Street&UMbillstreet2=Apt+1&UMbillcity=Ottawa&UMbillstate=NC&UMbillzip=27614&UMbillcountry=CA&UMbillphone=%28555%29555-5555&UMshipfname=Jim&UMshiplname=Smith&UMshipcompany=Widgets+Inc&UMshipstreet=456+My+Street&UMshipstreet2=Apt+1&UMshipcity=Ottawa&UMshipstate=ON&UMshipzip=K1C2N6&UMshipcountry=CA&UMshipphone=%28555%29555-5555&UMstreet=456+My+Street&UMzip=27614&UMcommand=cc%3Asale&UMkey=[FILTERED]&UMsoftware=Active+Merchant&UMtestmode=0&UMhash=s%2F5268F91058BC9F9FA944693D799F324B2497B7247850A51E53226309FB2540F0%2F7b4c4f6a4e775141cc0e4e10c0388d9adeb47fd1%2Fn" +-> "HTTP/1.1 200 OK\r\n" +-> "Server: http\r\n" +-> "Date: Tue, 13 Feb 2018 18:17:20 GMT\r\n" +-> "Content-Type: text/html\r\n" +-> "Content-Length: 485\r\n" +-> "Connection: close\r\n" +-> "P3P: policyref=\"http://www.usaepay.com/w3c/p3p.xml\", CP=\"NON TAIa IVAa IVDa OUR NOR PHY ONL UNI FIN INT DEM\"\r\n" +-> "Strict-Transport-Security: max-age=15768000\r\n" +-> "\r\n" +reading 485 bytes... +-> "UMversion=2.9&UMstatus=Approved&UMauthCode=042366&UMrefNum=132020588&UMavsResult=Address%3A%20Match%20%26%205%20Digit%20Zip%3A%20Match&UMavsResultCode=YYY&UMcvv2Result=Match&UMcvv2ResultCode=M&UMresult=A&UMvpasResultCode=&UMerror=Approved&UMerrorcode=00000&UMcustnum=&UMbatch=120&UMbatchRefNum=848&UMisDuplicate=N&UMconvertedAmount=&UMconvertedAmountCurrency=840&UMconversionRate=&UMcustReceiptResult=No%20Receipt%20Sent&UMprocRefNum=&UMcardLevelResult=A&UMauthAmount=1&UMfiller=filled" +read 485 bytes +Conn close + EOS + end + + def pre_scrubbed_track_data + <<-EOS +opening connection to sandbox.usaepay.com:443... +opened +starting SSL for sandbox.usaepay.com:443... +SSL established +<- "POST /gate HTTP/1.1\r\nContent-Type: application/x-www-form-urlencoded\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nAccept: */*\r\nUser-Agent: Ruby\r\nConnection: close\r\nHost: sandbox.usaepay.com\r\nContent-Length: 382\r\n\r\n" +<- "UMamount=1.00&UMinvoice=&UMdescription=&UMmagstripe=%25B4000100011112224%5ELONGSEN%2FL.+%5E19091200000000000000%2A%2A123%2A%2A%2A%2A%2A%2A%3F&UMcardpresent=true&UMcommand=cc%3Asale&UMkey=4EoZ5U2Q55j976W7eplC71i6b7kn4pcV&UMsoftware=Active+Merchant&UMtestmode=0&UMhash=s%2FE27734F076643B23131E5432C1E225EFF982A73D350179EFC2F191CA499B59A4%2F13391bd14ab6e61058cc9a1b78f259a4c26aa8e1%2Fn" +-> "HTTP/1.1 200 OK\r\n" +-> "Server: http\r\n" +-> "Date: Tue, 13 Feb 2018 18:13:11 GMT\r\n" +-> "Content-Type: text/html\r\n" +-> "Content-Length: 485\r\n" +-> "Connection: close\r\n" +-> "P3P: policyref=\"http://www.usaepay.com/w3c/p3p.xml\", CP=\"NON TAIa IVAa IVDa OUR NOR PHY ONL UNI FIN INT DEM\"\r\n" +-> "Strict-Transport-Security: max-age=15768000\r\n" +-> "\r\n" +reading 485 bytes... +-> "UMversion=2.9&UMstatus=Approved&UMauthCode=042087&UMrefNum=132020522&UMavsResult=Address%3A%20Match%20%26%205%20Digit%20Zip%3A%20Match&UMavsResultCode=YYY&UMcvv2Result=Match&UMcvv2ResultCode=M&UMresult=A&UMvpasResultCode=&UMerror=Approved&UMerrorcode=00000&UMcustnum=&UMbatch=120&UMbatchRefNum=848&UMisDuplicate=N&UMconvertedAmount=&UMconvertedAmountCurrency=840&UMconversionRate=&UMcustReceiptResult=No%20Receipt%20Sent&UMprocRefNum=&UMcardLevelResult=A&UMauthAmount=1&UMfiller=filled" +read 485 bytes +Conn close + EOS + end + + def post_scrubbed_track_data + <<-EOS +opening connection to sandbox.usaepay.com:443... +opened +starting SSL for sandbox.usaepay.com:443... +SSL established +<- "POST /gate HTTP/1.1\r\nContent-Type: application/x-www-form-urlencoded\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nAccept: */*\r\nUser-Agent: Ruby\r\nConnection: close\r\nHost: sandbox.usaepay.com\r\nContent-Length: 382\r\n\r\n" +<- "UMamount=1.00&UMinvoice=&UMdescription=&UMmagstripe=[FILTERED]&UMcardpresent=true&UMcommand=cc%3Asale&UMkey=[FILTERED]&UMsoftware=Active+Merchant&UMtestmode=0&UMhash=s%2FE27734F076643B23131E5432C1E225EFF982A73D350179EFC2F191CA499B59A4%2F13391bd14ab6e61058cc9a1b78f259a4c26aa8e1%2Fn" +-> "HTTP/1.1 200 OK\r\n" +-> "Server: http\r\n" +-> "Date: Tue, 13 Feb 2018 18:13:11 GMT\r\n" +-> "Content-Type: text/html\r\n" +-> "Content-Length: 485\r\n" +-> "Connection: close\r\n" +-> "P3P: policyref=\"http://www.usaepay.com/w3c/p3p.xml\", CP=\"NON TAIa IVAa IVDa OUR NOR PHY ONL UNI FIN INT DEM\"\r\n" +-> "Strict-Transport-Security: max-age=15768000\r\n" +-> "\r\n" +reading 485 bytes... +-> "UMversion=2.9&UMstatus=Approved&UMauthCode=042087&UMrefNum=132020522&UMavsResult=Address%3A%20Match%20%26%205%20Digit%20Zip%3A%20Match&UMavsResultCode=YYY&UMcvv2Result=Match&UMcvv2ResultCode=M&UMresult=A&UMvpasResultCode=&UMerror=Approved&UMerrorcode=00000&UMcustnum=&UMbatch=120&UMbatchRefNum=848&UMisDuplicate=N&UMconvertedAmount=&UMconvertedAmountCurrency=840&UMconversionRate=&UMcustReceiptResult=No%20Receipt%20Sent&UMprocRefNum=&UMcardLevelResult=A&UMauthAmount=1&UMfiller=filled" +read 485 bytes +Conn close + EOS + end + + def pre_scrubbed_echeck + <<-EOS +opening connection to sandbox.usaepay.com:443... +opened +starting SSL for sandbox.usaepay.com:443... +SSL established +<- "POST /gate HTTP/1.1\r\nContent-Type: application/x-www-form-urlencoded\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nAccept: */*\r\nUser-Agent: Ruby\r\nConnection: close\r\nHost: sandbox.usaepay.com\r\nContent-Length: 762\r\n\r\n" +<- "UMamount=1.00&UMinvoice=&UMdescription=&UMaccount=15378535&UMrouting=244183602&UMname=Jim+Smith&UMbillfname=Jim&UMbilllname=Smith&UMbillcompany=Widgets+Inc&UMbillstreet=456+My+Street&UMbillstreet2=Apt+1&UMbillcity=Ottawa&UMbillstate=NC&UMbillzip=27614&UMbillcountry=CA&UMbillphone=%28555%29555-5555&UMshipfname=Jim&UMshiplname=Smith&UMshipcompany=Widgets+Inc&UMshipstreet=456+My+Street&UMshipstreet2=Apt+1&UMshipcity=Ottawa&UMshipstate=ON&UMshipzip=K1C2N6&UMshipcountry=CA&UMshipphone=%28555%29555-5555&UMstreet=456+My+Street&UMzip=27614&UMcommand=check%3Asale&UMkey=4EoZ5U2Q55j976W7eplC71i6b7kn4pcV&UMsoftware=Active+Merchant&UMtestmode=0&UMhash=s%2F7F71E7DCB851901EA1D4E2CA1C60D2A7E8BAB99FA10F6220E821BD8B8331114B%2F85f1a7ab01b725c4eed80a12c78ef65d3fa367e6%2Fn" +-> "HTTP/1.1 200 OK\r\n" +-> "Server: http\r\n" +-> "Date: Fri, 16 Mar 2018 20:54:49 GMT\r\n" +-> "Content-Type: text/html\r\n" +-> "Content-Length: 572\r\n" +-> "Connection: close\r\n" +-> "P3P: policyref=\"http://www.usaepay.com/w3c/p3p.xml\", CP=\"NON TAIa IVAa IVDa OUR NOR PHY ONL UNI FIN INT DEM\"\r\n" +-> "Strict-Transport-Security: max-age=15768000\r\n" +-> "\r\n" +reading 572 bytes... +-> "UMversion=2.9&UMstatus=Approved&UMauthCode=TMEAAF&UMrefNum=133135121&UMavsResult=No%20AVS%20response%20%28Typically%20no%20AVS%20data%20sent%20or%20swiped%20transaction%29&UMavsResultCode=&UMcvv2Result=No%20CVV2%2FCVC%20data%20available%20for%20transaction.&UMcvv2ResultCode=&UMresult=A&UMvpasResultCode=&UMerror=&UMerrorcode=00000&UMcustnum=&UMbatch=180316&UMbatchRefNum=&UMisDuplicate=N&UMconvertedAmount=&UMconvertedAmountCurrency=840&UMconversionRate=&UMcustReceiptResult=No%20Receipt%20Sent&UMprocRefNum=18031621233689&UMcardLevelResult=&UMauthAmount=&UMfiller=filled" +read 572 bytes +Conn close + EOS + end + + def post_scrubbed_echeck + <<-EOS +opening connection to sandbox.usaepay.com:443... +opened +starting SSL for sandbox.usaepay.com:443... +SSL established +<- "POST /gate HTTP/1.1\r\nContent-Type: application/x-www-form-urlencoded\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nAccept: */*\r\nUser-Agent: Ruby\r\nConnection: close\r\nHost: sandbox.usaepay.com\r\nContent-Length: 762\r\n\r\n" +<- "UMamount=1.00&UMinvoice=&UMdescription=&UMaccount=[FILTERED]&UMrouting=244183602&UMname=Jim+Smith&UMbillfname=Jim&UMbilllname=Smith&UMbillcompany=Widgets+Inc&UMbillstreet=456+My+Street&UMbillstreet2=Apt+1&UMbillcity=Ottawa&UMbillstate=NC&UMbillzip=27614&UMbillcountry=CA&UMbillphone=%28555%29555-5555&UMshipfname=Jim&UMshiplname=Smith&UMshipcompany=Widgets+Inc&UMshipstreet=456+My+Street&UMshipstreet2=Apt+1&UMshipcity=Ottawa&UMshipstate=ON&UMshipzip=K1C2N6&UMshipcountry=CA&UMshipphone=%28555%29555-5555&UMstreet=456+My+Street&UMzip=27614&UMcommand=check%3Asale&UMkey=[FILTERED]&UMsoftware=Active+Merchant&UMtestmode=0&UMhash=s%2F7F71E7DCB851901EA1D4E2CA1C60D2A7E8BAB99FA10F6220E821BD8B8331114B%2F85f1a7ab01b725c4eed80a12c78ef65d3fa367e6%2Fn" +-> "HTTP/1.1 200 OK\r\n" +-> "Server: http\r\n" +-> "Date: Fri, 16 Mar 2018 20:54:49 GMT\r\n" +-> "Content-Type: text/html\r\n" +-> "Content-Length: 572\r\n" +-> "Connection: close\r\n" +-> "P3P: policyref=\"http://www.usaepay.com/w3c/p3p.xml\", CP=\"NON TAIa IVAa IVDa OUR NOR PHY ONL UNI FIN INT DEM\"\r\n" +-> "Strict-Transport-Security: max-age=15768000\r\n" +-> "\r\n" +reading 572 bytes... +-> "UMversion=2.9&UMstatus=Approved&UMauthCode=TMEAAF&UMrefNum=133135121&UMavsResult=No%20AVS%20response%20%28Typically%20no%20AVS%20data%20sent%20or%20swiped%20transaction%29&UMavsResultCode=&UMcvv2Result=No%20CVV2%2FCVC%20data%20available%20for%20transaction.&UMcvv2ResultCode=&UMresult=A&UMvpasResultCode=&UMerror=&UMerrorcode=00000&UMcustnum=&UMbatch=180316&UMbatchRefNum=&UMisDuplicate=N&UMconvertedAmount=&UMconvertedAmountCurrency=840&UMconversionRate=&UMcustReceiptResult=No%20Receipt%20Sent&UMprocRefNum=18031621233689&UMcardLevelResult=&UMauthAmount=&UMfiller=filled" +read 572 bytes +Conn close + EOS end end diff --git a/test/unit/gateways/vanco_test.rb b/test/unit/gateways/vanco_test.rb index 9b6faa66f2e..449cd696448 100644 --- a/test/unit/gateways/vanco_test.rb +++ b/test/unit/gateways/vanco_test.rb @@ -22,13 +22,13 @@ def test_successful_purchase assert_success response assert_equal '14949117|15756594|16136938', response.authorization - assert_equal "Success", response.message + assert_equal 'Success', response.message assert response.test? end def test_successful_purchase_with_fund_id response = stub_comms do - @gateway.purchase(@amount, @credit_card, @options.merge(fund_id: "MyEggcellentFund")) + @gateway.purchase(@amount, @credit_card, @options.merge(fund_id: 'MyEggcellentFund')) end.check_request do |endpoint, data, headers| if data =~ /<RequestType>EFTAdd/ assert_match(%r(<FundID>MyEggcellentFund<\/FundID>), data) @@ -37,12 +37,12 @@ def test_successful_purchase_with_fund_id assert_success response assert_equal '14949117|15756594|16137331', response.authorization - assert_equal "Success", response.message + assert_equal 'Success', response.message end def test_successful_purchase_with_ip_address response = stub_comms do - @gateway.purchase(@amount, @credit_card, @options.merge(ip: "192.168.0.1")) + @gateway.purchase(@amount, @credit_card, @options.merge(ip: '192.168.0.1')) end.check_request do |endpoint, data, headers| if data =~ /<RequestType>EFTAdd/ assert_match(%r(<CustomerIPAddress>192), data) @@ -57,7 +57,7 @@ def test_failed_purchase end.respond_with(successful_login_response, failed_purchase_response) assert_failure response - assert_equal "286", response.params["error_codes"] + assert_equal '286', response.params['error_codes'] end def test_failed_purchase_multiple_errors @@ -66,8 +66,8 @@ def test_failed_purchase_multiple_errors end.respond_with(successful_login_response, failed_purchase_multiple_errors_response) assert_failure response - assert_equal "Client not set up for International Credit Card Processing. Another Error.", response.message - assert_equal "286, 331", response.params["error_codes"] + assert_equal 'Client not set up for International Credit Card Processing. Another Error.', response.message + assert_equal '286, 331', response.params['error_codes'] end def test_successful_purchase_echeck @@ -77,7 +77,7 @@ def test_successful_purchase_echeck assert_success response assert_equal '14949514|15757035|16138421', response.authorization - assert_equal "Success", response.message + assert_equal 'Success', response.message assert response.test? end @@ -87,25 +87,25 @@ def test_failed_purchase_echeck end.respond_with(successful_login_response, failed_purchase_echeck_response) assert_failure response - assert_equal "178", response.params["error_codes"] + assert_equal '178', response.params['error_codes'] end def test_successful_refund response = stub_comms do - @gateway.refund(@amount, "authoriziation") + @gateway.refund(@amount, 'authoriziation') end.respond_with(successful_login_response, successful_refund_response) assert_success response - assert_equal "Success", response.message + assert_equal 'Success', response.message end def test_failed_refund response = stub_comms do - @gateway.refund(@amount, "authorization") + @gateway.refund(@amount, 'authorization') end.respond_with(successful_login_response, failed_refund_response) assert_failure response - assert_equal "575", response.params["error_codes"] + assert_equal '575', response.params['error_codes'] end def test_scrub diff --git a/test/unit/gateways/verifi_test.rb b/test/unit/gateways/verifi_test.rb index b9dae02ce2a..404556b2d6c 100644 --- a/test/unit/gateways/verifi_test.rb +++ b/test/unit/gateways/verifi_test.rb @@ -13,7 +13,7 @@ def setup @options = { :order_id => '37', - :email => "paul@example.com", + :email => 'paul@example.com', :billing_address => address } @@ -38,30 +38,30 @@ def test_unsuccessful_request end def test_credit - @gateway.expects(:ssl_post).with(anything, regexp_matches(/ccnumber=#{@credit_card.number}/), anything).returns("") + @gateway.expects(:ssl_post).with(anything, regexp_matches(/ccnumber=#{@credit_card.number}/), anything).returns('') @gateway.expects(:parse).returns({}) @gateway.credit(@amount, @credit_card, @options) end def test_deprecated_credit - @gateway.expects(:ssl_post).with(anything, regexp_matches(/transactionid=transaction_id/), anything).returns("") + @gateway.expects(:ssl_post).with(anything, regexp_matches(/transactionid=transaction_id/), anything).returns('') @gateway.expects(:parse).returns({}) assert_deprecation_warning(Gateway::CREDIT_DEPRECATION_MESSAGE) do - @gateway.credit(@amount, "transaction_id", @options) + @gateway.credit(@amount, 'transaction_id', @options) end end def test_refund - @gateway.expects(:ssl_post).with(anything, regexp_matches(/transactionid=transaction_id/), anything).returns("") + @gateway.expects(:ssl_post).with(anything, regexp_matches(/transactionid=transaction_id/), anything).returns('') @gateway.expects(:parse).returns({}) - @gateway.refund(@amount, "transaction_id", @options) + @gateway.refund(@amount, 'transaction_id', @options) end def test_amount_style assert_equal '10.34', @gateway.send(:amount, 1034) assert_raise(ArgumentError) do - @gateway.send(:amount, '10.34') + @gateway.send(:amount, '10.34') end end @@ -69,12 +69,11 @@ def test_add_description result = {} @gateway.send(:add_invoice_data, result, :description => 'My Purchase is great') assert_equal 'My Purchase is great', result[:orderdescription] - end def test_purchase_meets_minimum_requirements post = VerifiGateway::VerifiPostData.new - post[:amount] = "1.01" + post[:amount] = '1.01' @gateway.send(:add_credit_card, post, @credit_card) @@ -83,7 +82,6 @@ def test_purchase_meets_minimum_requirements minimum_requirements.each do |key| assert_not_nil(data =~ /#{key}=/) end - end def test_avs_result @@ -107,10 +105,10 @@ def minimum_requirements end def successful_purchase_response - "response=1&responsetext=SUCCESS&authcode=123456&transactionid=546061538&avsresponse=N&cvvresponse=N&orderid=37&type=sale&response_code=100" + 'response=1&responsetext=SUCCESS&authcode=123456&transactionid=546061538&avsresponse=N&cvvresponse=N&orderid=37&type=sale&response_code=100' end def unsuccessful_purchase_response - "response=3&responsetext=Field required: ccnumber REFID:12109909&authcode=&transactionid=0&avsresponse=&cvvresponse=&orderid=37&type=sale&response_code=300" + 'response=3&responsetext=Field required: ccnumber REFID:12109909&authcode=&transactionid=0&avsresponse=&cvvresponse=&orderid=37&type=sale&response_code=300' end end diff --git a/test/unit/gateways/viaklix_test.rb b/test/unit/gateways/viaklix_test.rb index 8625f01ad5d..ef288b6b652 100644 --- a/test/unit/gateways/viaklix_test.rb +++ b/test/unit/gateways/viaklix_test.rb @@ -7,20 +7,20 @@ def setup :login => 'LOGIN', :password => 'PIN' ) - - @credit_card = credit_card + + @credit_card = credit_card @options = { :order_id => '37', - :email => "paul@domain.com", + :email => 'paul@domain.com', :description => 'Test Transaction', :billing_address => address } @amount = 100 end - - def test_purchase_success + + def test_purchase_success @gateway.expects(:ssl_post).returns(successful_purchase_response) - + assert response = @gateway.purchase(@amount, @credit_card, @options) assert_instance_of Response, response assert_success response @@ -29,50 +29,50 @@ def test_purchase_success def test_purchase_error @gateway.expects(:ssl_post).returns(unsuccessful_purchase_response) - + assert response = @gateway.purchase(@amount, @credit_card, @options) assert_instance_of Response, response assert_failure response end - + def test_invalid_login @gateway.expects(:ssl_post).returns(invalid_login_response) - + assert response = @gateway.purchase(@amount, @credit_card, @options) - + assert_equal '7000', response.params['result'] assert_equal 'The viaKLIX ID and/or User ID supplied in the authorization request is invalid.', response.params['result_message'] assert_failure response end - + def test_avs_result @gateway.expects(:ssl_post).returns(successful_purchase_response) - + response = @gateway.purchase(@amount, @credit_card) assert_equal 'Y', response.avs_result['code'] end - + def test_cvv_result @gateway.expects(:ssl_post).returns(successful_purchase_response) - + response = @gateway.purchase(@amount, @credit_card) assert_equal 'M', response.cvv_result['code'] end - + private - + def successful_purchase_response "ssl_result=0\r\nssl_company=;\r\nssl_city=Herndon\r\nssl_avs_zip=90201\r\nssl_address2=\r\nssl_ship_to_last_name=Jacobs\r\nssl_ship_to_city=Herndon\r\nssl_approval_code=05737D\r\nssl_avs_response=Y\r\nssl_salestax=\r\nssl_ship_to_phone=\r\ncustomer_code=jacobsr1@cox.net\r\nship_to_country=US\r\ncountry=US\r\nssl_txn_id=7E2419F7-2354-4766-BF5C-19C75A1F379A\r\nssl_transaction_type=SALE\r\nssl_invoice_number=#1158.1\r\nssl_amount=243.95\r\nssl_card_number=43*******6820\r\nssl_description=\r\nssl_phone=703-404-9270\r\nssl_ship_to_avs_address=\r\nssl_first_name=Cody\r\nssl_avs_address=12213 Jonathons Glen Way\r\nssl_result_message=APPROVED\r\nssl_exp_date=1109\r\nssl_last_name=Fauser\r\nssl_ship_to_first_name=Robert\r\nssl_ship_to_address2=\r\nssl_ship_to_state=VA\r\nssl_ship_to_avs_zip=\r\nssl_cvv2_response=M\r\nssl_state=VA\r\nssl_email=cody@example.com\r\nssl_ship_to_company=\r\n" end - + def unsuccessful_purchase_response "ssl_result=1\r\nssl_result_message=This transaction request has not been approved. You may elect to use another form of payment to complete this transaction or contact customer service for additional options." end - + def invalid_login_response <<-RESPONSE ssl_result=7000\r ssl_result_message=The viaKLIX ID and/or User ID supplied in the authorization request is invalid.\r RESPONSE end -end \ No newline at end of file +end diff --git a/test/unit/gateways/visanet_peru_test.rb b/test/unit/gateways/visanet_peru_test.rb index 08fe953fa59..49b7a78951b 100644 --- a/test/unit/gateways/visanet_peru_test.rb +++ b/test/unit/gateways/visanet_peru_test.rb @@ -5,46 +5,46 @@ def setup @gateway = VisanetPeruGateway.new(fixtures(:visanet_peru)) @amount = 100 - @credit_card = credit_card("4500340090000016", verification_value: "377") - @declined_card = credit_card("4111111111111111") + @credit_card = credit_card('4500340090000016', verification_value: '377') + @declined_card = credit_card('4111111111111111') @options = { billing_address: address, order_id: generate_unique_id, - email: "visanetperutest@mailinator.com" + email: 'visanetperutest@mailinator.com' } end def test_successful_purchase - @gateway.expects(:ssl_request).returns(successful_authorize_response) - @gateway.expects(:ssl_request).returns(successful_capture_response) + @gateway.expects(:ssl_request).with(:post, any_parameters).returns(successful_authorize_response) + @gateway.expects(:ssl_request).with(:put, any_parameters).returns(successful_capture_response) response = @gateway.purchase(@amount, @credit_card, @options) assert_success response - assert_equal "OK", response.message + assert_equal 'OK', response.message - assert_match %r([0-9]{9}$), response.authorization - assert_equal @options[:order_id], response.params["externalTransactionId"] + assert_match %r([0-9]{9}|$), response.authorization + assert_equal 'de9dc65c094fb4f1defddc562731af81', response.params['externalTransactionId'] assert response.test? end def test_failed_purchase - @gateway.expects(:ssl_request).returns(failed_authorize_response_bad_card) + @gateway.expects(:ssl_request).with(:post, any_parameters).returns(failed_authorize_response_bad_card) response = @gateway.purchase(@amount, @declined_card, @options) assert_failure response assert_equal 400, response.error_code - assert_equal "Operacion Denegada.", response.message + assert_equal 'Operacion Denegada.', response.message end def test_successful_authorize @gateway.expects(:ssl_request).returns(successful_authorize_response) response = @gateway.authorize(@amount, @credit_card, @options) assert_success response - assert_equal "OK", response.message - assert_match %r(^[0-9]{9}$), response.authorization - assert_equal @options[:order_id], response.params["externalTransactionId"] - assert_equal "1.00", response.params["data"]["IMP_AUTORIZADO"] + assert_equal 'OK', response.message + assert_match %r(^[0-9]{9}|$), response.authorization + assert_equal @options[:order_id], response.params['externalTransactionId'] + assert_equal '1.00', response.params['data']['IMP_AUTORIZADO'] assert response.test? end @@ -53,34 +53,34 @@ def test_failed_authorize response = @gateway.authorize(@amount, @declined_card, @options) assert_failure response assert_equal 400, response.error_code - assert_equal "Operacion Denegada.", response.message + assert_equal 'Operacion Denegada.', response.message @gateway.expects(:ssl_request).returns(failed_authorize_response_bad_email) - @options[:email] = "cybersource@reject.com" + @options[:email] = 'cybersource@reject.com' response = @gateway.authorize(@amount, @credit_card, @options) assert_failure response assert_equal 400, response.error_code - assert_equal "El pedido ha sido rechazado por Decision Manager", response.message + assert_equal 'REJECT', response.message end def test_successful_capture - @gateway.expects(:ssl_request).returns(successful_authorize_response) - @gateway.expects(:ssl_request).returns(successful_capture_response) + @gateway.expects(:ssl_request).with(:post, any_parameters).returns(successful_authorize_response) + @gateway.expects(:ssl_request).with(:put, any_parameters).returns(successful_capture_response) response = @gateway.authorize(@amount, @credit_card, @options) capture = @gateway.capture(response.authorization, @options) assert_success capture - assert_equal "OK", capture.message - assert_match %r(^[0-9]{9}$), capture.authorization - assert_equal @options[:order_id], capture.params["externalTransactionId"] + assert_equal 'OK', capture.message + assert_match %r(^[0-9]{9}|$), capture.authorization + assert_equal 'de9dc65c094fb4f1defddc562731af81', capture.params['externalTransactionId'] assert capture.test? end def test_failed_capture @gateway.expects(:ssl_request).returns(failed_capture_response) - invalid_purchase_number = "122333444" - response = @gateway.capture("authorize" + "|" + invalid_purchase_number) + invalid_purchase_number = '900000044' + response = @gateway.capture(invalid_purchase_number) assert_failure response - assert_equal "[ 'NUMORDEN 12233344 no se encuentra registrado', 'No se realizo el deposito' ]", response.message + assert_equal '[ "NUMORDEN 900000044 no se encuentra registrado", "No se realizo el deposito" ]', response.message assert_equal 400, response.error_code end @@ -90,15 +90,15 @@ def test_successful_refund response = @gateway.purchase(@amount, @credit_card, @options) assert_success response - @gateway.expects(:ssl_request).returns(successful_refund_response) + @gateway.expects(:ssl_request).with(:put, any_parameters).returns(successful_refund_response) refund = @gateway.refund(@amount, response.authorization) assert_success refund - assert_equal "OK", refund.message + assert_equal 'OK', refund.message end def test_failed_refund - @gateway.expects(:ssl_request).returns(failed_refund_response) - response = @gateway.refund(@amount, "122333444") + @gateway.expects(:ssl_request).with(:put, any_parameters).returns(failed_refund_response) + response = @gateway.refund(@amount, '122333444') assert_failure response assert_match(/No se realizo la anulacion del deposito/, response.message) assert_equal 400, response.error_code @@ -112,12 +112,12 @@ def test_successful_void @gateway.expects(:ssl_request).returns(successful_void_response) void = @gateway.void(response.authorization) assert_success void - assert_equal "OK", void.message + assert_equal 'OK', void.message end def test_failed_void @gateway.expects(:ssl_request).returns(failed_void_response) - response = @gateway.void("122333444") + response = @gateway.void('122333444') assert_failure response assert_match(/No se ha realizado la anulacion del pedido/, response.message) assert_equal 400, response.error_code @@ -128,8 +128,8 @@ def test_successful_verify @gateway.expects(:ssl_request).returns(successful_verify_response) response = @gateway.verify(@credit_card, @options) assert_success response - assert_equal "OK", response.message - assert_equal @options[:order_id], response.params["externalTransactionId"] + assert_equal 'OK', response.message + assert_equal @options[:order_id], response.params['externalTransactionId'] end def test_failed_verify @@ -137,7 +137,7 @@ def test_failed_verify response = @gateway.verify(@declined_card, @options) assert_failure response assert_equal 400, response.error_code - assert_equal "Operacion Denegada.", response.message + assert_equal 'Operacion Denegada.', response.message end def test_scrub @@ -256,32 +256,58 @@ def failed_authorize_response_bad_card end def failed_authorize_response_bad_email - <<-RESPONSE - { - "errorCode": 400, - "errorMessage": "El pedido ha sido rechazado por Decision Manager" - } - RESPONSE + %q( + { + "errorCode": 400, + "errorMessage": "REJECT", + "millis": 513, + "transactionUUID": "e2f0f73d-2f44-4f05-9e13-dad3bf378c57", + "transactionDate": 1519932476254, + "data": { + "FECHAYHORA_TX": "01\/03\/2018 21:26", + "RES_CVV2": null, + "CSIMENSAJE": null, + "ID_UNICO": null, + "ETICKET": null, + "DECISIONCS": "REJECT", + "CSIPORCENTAJEDESCUENTO": null, + "NROCUOTA": null, + "CSIIMPORTECOMERCIO": null, + "CSICODIGOPROGRAMA": null, + "DSC_ECI": null, + "ECI": "00", + "DSC_COD_ACCION": "Operacion denegada", + "NOM_EMISOR": null, + "IMPCUOTAAPROX": null, + "CSITIPOCOBRO": null, + "NUMREFERENCIA": null, + "RESPUESTA": "2", + "NUMORDEN": "376876217", + "CODACCION": "670", + "IMP_AUTORIZADO": "0.00", + "COD_AUTORIZA": null, + "CODTIENDA": "vndp", + "PAN": null, + "reviewTransaction": "false", + "ORI_TARJETA": null + }, + "transactionLog": { + + } + } + ) end def successful_capture_response - <<-RESPONSE - { - "errorCode": 0, - "errorMessage": "OK", - "externalTransactionId": "#{@options[:order_id]}", - "merchantId": "101266802" - } - RESPONSE + '{"errorCode":0,"errorMessage":"OK","transactionUUID":"8517cf68-4820-4224-959b-01c8117385e0","externalTransactionId":"de9dc65c094fb4f1defddc562731af81","transactionDateTime":1519937673906,"transactionDuration":0,"merchantId":"543025501","userTokenId":null,"aliasName":null,"data":{"FECHAYHORA_TX":null,"DSC_ECI":null,"DSC_COD_ACCION":null,"NOM_EMISOR":null,"ESTADO":"Depositado","RESPUESTA":"1","ID_UNICO":null,"NUMORDEN":null,"CODACCION":null,"ETICKET":null,"IMP_AUTORIZADO":null,"DECISIONCS":null,"COD_AUTORIZA":null,"CODTIENDA":"543025501","PAN":null,"ORI_TARJETA":null}}' end def failed_capture_response - <<-RESPONSE + %q( { - "errorCode": 400, - "errorMessage": "[ 'NUMORDEN 12233344 no se encuentra registrado', 'No se realizo el deposito' ]" + "errorCode":400,"errorMessage":"[ \"NUMORDEN 900000044 no se encuentra registrado\", \"No se realizo el deposito\" ]","millis":513,"transactionUUID":"e2f0f73d-2f44-4f05-9e13-dad3bf378c57","transactionDate":1519932476254,"data":{"FECHAYHORA_TX":null,"DSC_ECI":null,"DSC_COD_ACCION":null,"NOM_EMISOR":null,"ESTADO":"","RESPUESTA":"2","ID_UNICO":null,"NUMORDEN":null,"CODACCION":null,"ETICKET":null,"IMP_AUTORIZADO":null,"DECISIONCS":null,"COD_AUTORIZA":null,"CODTIENDA":"543025501","PAN":null,"ORI_TARJETA":null},"transactionLog":{} } - RESPONSE + ) end def successful_verify_response @@ -290,7 +316,27 @@ def successful_verify_response "errorCode": 0, "errorMessage": "OK", "externalTransactionId": "#{@options[:order_id]}", - "merchantId": "101266802" + "merchantId": "101266802", + "userTokenId": null, + "aliasName": null, + "data": { + "FECHAYHORA_TX": null, + "DSC_ECI": null, + "DSC_COD_ACCION": null, + "NOM_EMISOR": null, + "ESTADO": "Anulado", + "RESPUESTA": "1", + "ID_UNICO": null, + "NUMORDEN": null, + "CODACCION": null, + "ETICKET": null, + "IMP_AUTORIZADO": null, + "DECISIONCS": null, + "COD_AUTORIZA": null, + "CODTIENDA": "543025501", + "PAN": null, + "ORI_TARJETA": null + } } RESPONSE end @@ -313,7 +359,27 @@ def successful_void_response "errorCode": 0, "errorMessage": "OK", "externalTransactionId": "987654321", - "merchantId": "101266802" + "merchantId": "101266802", + "userTokenId": null, + "aliasName": null, + "data": { + "FECHAYHORA_TX": null, + "DSC_ECI": null, + "DSC_COD_ACCION": null, + "NOM_EMISOR": null, + "ESTADO": "Anulado", + "RESPUESTA": "1", + "ID_UNICO": null, + "NUMORDEN": null, + "CODACCION": null, + "ETICKET": null, + "IMP_AUTORIZADO": null, + "DECISIONCS": null, + "COD_AUTORIZA": null, + "CODTIENDA": "543025501", + "PAN": null, + "ORI_TARJETA": null + } } RESPONSE end @@ -322,7 +388,28 @@ def failed_void_response <<-RESPONSE { "errorCode": 400, - "errorMessage": "[ 'NUMORDEN no se encuentra registrado.', 'No se ha realizado la anulacion del pedido' ]" + "errorMessage": "[ 'NUMORDEN no se encuentra registrado.', 'No se ha realizado la anulacion del pedido' ]", + "data": { + "FECHAYHORA_TX": null, + "DSC_ECI": null, + "DSC_COD_ACCION": null, + "NOM_EMISOR": null, + "ESTADO": " ", + "RESPUESTA": "2", + "ID_UNICO": null, + "NUMORDEN": null, + "CODACCION": null, + "ETICKET": null, + "IMP_AUTORIZADO": null, + "DECISIONCS": null, + "COD_AUTORIZA": null, + "CODTIENDA": "543025501", + "PAN": null, + "ORI_TARJETA": null + }, + "transactionLog": { + + } } RESPONSE end @@ -348,7 +435,14 @@ def failed_refund_response <<-RESPONSE { "errorCode": 400, - "errorMessage": "[ 'NUMORDEN 122333444 no se encuentra registrado', 'No se realizo la anulacion del deposito' ]" + "errorMessage": "[ 'NUMORDEN 122333444 no se encuentra registrado', 'No se realizo la anulacion del deposito' ]", + "data": { + "ESTADO": "", + "RESPUESTA": "2" + }, + "transactionLog": { + + } } RESPONSE end diff --git a/test/unit/gateways/webpay_test.rb b/test/unit/gateways/webpay_test.rb index 476a5d514c4..25123a5623b 100644 --- a/test/unit/gateways/webpay_test.rb +++ b/test/unit/gateways/webpay_test.rb @@ -30,7 +30,7 @@ def test_successful_authorization def test_successful_capture @gateway.expects(:ssl_request).returns(successful_capture_response) - assert response = @gateway.capture(@amount, "ch_test_charge") + assert response = @gateway.capture(@amount, 'ch_test_charge') assert_success response assert response.test? end @@ -54,12 +54,12 @@ def test_appropriate_purchase_amount assert_instance_of Response, response assert_success response - assert_equal @amount / 100, response.params["amount"] + assert_equal @amount / 100, response.params['amount'] end def test_successful_purchase_with_token response = stub_comms(@gateway, :ssl_request) do - @gateway.purchase(@amount, "cus_xxx|card_xxx") + @gateway.purchase(@amount, 'cus_xxx|card_xxx') end.check_request do |method, endpoint, data, headers| assert_match(/customer=cus_xxx/, data) assert_match(/card=card_xxx/, data) @@ -121,20 +121,20 @@ def test_invalid_raw_response def test_add_customer post = {} - @gateway.send(:add_customer, post, 'card_token', {:customer => "test_customer"}) - assert_equal "test_customer", post[:customer] + @gateway.send(:add_customer, post, 'card_token', {:customer => 'test_customer'}) + assert_equal 'test_customer', post[:customer] end def test_doesnt_add_customer_if_card post = {} - @gateway.send(:add_customer, post, @credit_card, {:customer => "test_customer"}) + @gateway.send(:add_customer, post, @credit_card, {:customer => 'test_customer'}) assert !post[:customer] end def test_add_customer_data post = {} - @gateway.send(:add_customer_data, post, {:description => "a test customer"}) - assert_equal "a test customer", post[:description] + @gateway.send(:add_customer_data, post, {:description => 'a test customer'}) + assert_equal 'a test customer', post[:description] end def test_add_address @@ -158,7 +158,7 @@ def test_gateway_without_credentials end def test_metadata_header - @gateway.expects(:ssl_request).once.with {|method, url, post, headers| + @gateway.expects(:ssl_request).once.with { |method, url, post, headers| headers && headers['X-Webpay-Client-User-Metadata'] == {:ip => '1.1.1.1'}.to_json }.returns(successful_purchase_response) diff --git a/test/unit/gateways/wepay_test.rb b/test/unit/gateways/wepay_test.rb index 61c59b22c59..9f749e27916 100644 --- a/test/unit/gateways/wepay_test.rb +++ b/test/unit/gateways/wepay_test.rb @@ -1,6 +1,8 @@ require 'test_helper' class WepayTest < Test::Unit::TestCase + include CommStub + def setup @gateway = WepayGateway.new( client_id: 'client_id', @@ -12,7 +14,7 @@ def setup @amount = 20000 @options = { - email: "test@example.com" + email: 'test@example.com' } end @@ -22,7 +24,7 @@ def test_successful_purchase response = @gateway.purchase(@amount, @credit_card, @options) assert_success response - assert_equal "1181910285|20.00", response.authorization + assert_equal '1181910285|20.00', response.authorization end def test_failed_purchase @@ -35,16 +37,16 @@ def test_failed_purchase def test_successful_purchase_with_token @gateway.expects(:ssl_post).at_most(2).returns(successful_capture_response) - response = @gateway.purchase(@amount, "1422891921", @options) + response = @gateway.purchase(@amount, '1422891921', @options) assert_success response - assert_equal "1181910285|20.00", response.authorization + assert_equal '1181910285|20.00', response.authorization end def test_failed_purchase_with_token @gateway.expects(:ssl_post).at_most(2).returns(failed_capture_response) - response = @gateway.purchase(@amount, "1422891921", @options) + response = @gateway.purchase(@amount, '1422891921', @options) assert_failure response end @@ -60,7 +62,7 @@ def test_failed_refund response = @gateway.refund(@amount, @credit_card, @options) assert_failure response - assert_equal "refund_reason parameter is required", response.message + assert_equal 'refund_reason parameter is required', response.message end def test_successful_authorize @@ -75,35 +77,35 @@ def test_failed_authorize response = @gateway.authorize(@amount, @credit_card, @options) assert_failure response - assert_equal "Invalid credit card number", response.message + assert_equal 'Invalid credit card number', response.message end def test_successful_authorize_with_token @gateway.expects(:ssl_post).at_most(2).returns(successful_authorize_response) - response = @gateway.authorize(@amount, "1422891921", @options) + response = @gateway.authorize(@amount, '1422891921', @options) assert_success response end def test_failed_authorize_with_token @gateway.expects(:ssl_post).at_most(2).returns(failed_authorize_response) - response = @gateway.authorize(@amount, "1422891921", @options) + response = @gateway.authorize(@amount, '1422891921', @options) assert_failure response - assert_equal "Invalid credit card number", response.message + assert_equal 'Invalid credit card number', response.message end def test_successful_capture @gateway.expects(:ssl_post).at_most(2).returns(successful_capture_response) - response = @gateway.capture(@amount, "auth|amount", @options) + response = @gateway.capture(@amount, 'auth|amount', @options) assert_success response end def test_failed_capture @gateway.expects(:ssl_post).at_most(3).returns(failed_capture_response) - response = @gateway.capture(@amount, "auth|200.00", @options) + response = @gateway.capture(@amount, 'auth|200.00', @options) assert_failure response assert_equal "Checkout object must be in state 'Reserved' to capture. Currently it is in state captured", response.message end @@ -111,24 +113,32 @@ def test_failed_capture def test_successful_void @gateway.expects(:ssl_post).returns(successful_void_response) - response = @gateway.void("auth|amount", @options) + response = @gateway.void('auth|amount', @options) assert_success response end def test_failed_void @gateway.expects(:ssl_post).returns(failed_void_response) - response = @gateway.void("auth|amount", @options) + response = @gateway.void('auth|amount', @options) assert_failure response - assert_equal "this checkout has already been cancelled", response.message + assert_equal 'this checkout has already been cancelled', response.message end - def test_successful_store + def test_successful_store_via_create @gateway.expects(:ssl_post).returns(successful_store_response) response = @gateway.store(@credit_card, @options) assert_success response - assert_equal "3322208138", response.authorization + assert_equal '3322208138', response.authorization + end + + def test_successful_store_via_transfer + @gateway.expects(:ssl_post).returns(successful_store_response) + + response = @gateway.store(@credit_card, @options.merge(recurring: true)) + assert_success response + assert_equal '3322208138', response.authorization end def test_failed_store @@ -136,7 +146,7 @@ def test_failed_store response = @gateway.store(@credit_card, @options) assert_failure response - assert_equal "Invalid credit card number", response.message + assert_equal 'Invalid credit card number', response.message end def test_invalid_json_response @@ -147,8 +157,231 @@ def test_invalid_json_response assert_match(/Invalid JSON response received from WePay/, response.message) end + def test_no_version_by_default + stub_comms do + @gateway.purchase(@amount, @credit_card, @options) + end.check_request do |endpoint, data, headers| + assert_no_match(/Api-Version/, headers.to_s) + end.respond_with(successful_authorize_response) + end + + def test_version_override + stub_comms do + @gateway.purchase(@amount, @credit_card, @options.merge(version: '2017-05-31')) + end.check_request do |endpoint, data, headers| + assert_match(/"Api-Version\"=>\"2017-05-31\"/, headers.to_s) + end.respond_with(successful_authorize_response) + end + + def test_scrub + assert @gateway.supports_scrubbing? + assert_equal @gateway.scrub(pre_scrubbed), post_scrubbed + end + private + def pre_scrubbed + %q( + opening connection to stage.wepayapi.com:443... + opened + starting SSL for stage.wepayapi.com:443... + SSL established + <- "POST /v2/credit_card/create HTTP/1.1\r\nContent-Type: application/json\r\nUser-Agent: ActiveMerchantBindings/1.65.0\r\nAuthorization: Bearer STAGE_c91882b0bed3584b8aed0f7f515f2f05a1d40924ee6f394ce82d91018cb0f2d3\r\nApi-Version: 2017-02-01\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nAccept: */*\r\nConnection: close\r\nHost: stage.wepayapi.com\r\nContent-Length: 272\r\n\r\n" + <- "{\"client_id\":\"44716\",\"user_name\":\"Longbob Longsen\",\"email\":\"test@example.com\",\"cc_number\":\"5496198584584769\",\"cvv\":\"123\",\"expiration_month\":9,\"expiration_year\":2018,\"address\":{\"address1\":\"456 My Street\",\"city\":\"Ottawa\",\"country\":\"CA\",\"region\":\"ON\",\"postal_code\":\"K1C2N6\"}}" + -> "HTTP/1.1 200 OK\r\n" + -> "Server: nginx\r\n" + -> "Content-Type: application/json\r\n" + -> "X-Content-Type-Options: nosniff\r\n" + -> "Strict-Transport-Security: max-age=31536000; preload\r\n" + -> "Transfer-Encoding: chunked\r\n" + -> "Accept-Ranges: bytes\r\n" + -> "Date: Wed, 26 Apr 2017 18:27:33 GMT\r\n" + -> "Via: 1.1 varnish\r\n" + -> "Connection: close\r\n" + -> "X-Served-By: cache-fra1231-FRA\r\n" + -> "X-Cache: MISS\r\n" + -> "X-Cache-Hits: 0\r\n" + -> "X-Timer: S1493231252.436069,VS0,VE1258\r\n" + -> "Vary: Authorization\r\n" + -> "\r\n" + -> "2b\r\n" + reading 43 bytes... + -> "{\"credit_card_id\":2559797807,\"state\":\"new\"}" + read 43 bytes + reading 2 bytes... + -> "\r\n" + read 2 bytes + -> "0\r\n" + -> "\r\n" + Conn close + opening connection to stage.wepayapi.com:443... + opened + starting SSL for stage.wepayapi.com:443... + SSL established + <- "POST /v2/checkout/create HTTP/1.1\r\nContent-Type: application/json\r\nUser-Agent: ActiveMerchantBindings/1.65.0\r\nAuthorization: Bearer STAGE_c91882b0bed3584b8aed0f7f515f2f05a1d40924ee6f394ce82d91018cb0f2d3\r\nApi-Version: 2017-02-01\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nAccept: */*\r\nConnection: close\r\nHost: stage.wepayapi.com\r\nContent-Length: 202\r\n\r\n" + <- "{\"payment_method\":{\"type\":\"credit_card\",\"credit_card\":{\"id\":\"2559797807\",\"auto_capture\":false}},\"account_id\":\"2080478981\",\"amount\":\"20.00\",\"short_description\":\"Purchase\",\"type\":\"goods\",\"currency\":\"USD\"}" + -> "HTTP/1.1 200 OK\r\n" + -> "Server: nginx\r\n" + -> "Content-Type: application/json\r\n" + -> "X-Content-Type-Options: nosniff\r\n" + -> "Strict-Transport-Security: max-age=31536000; preload\r\n" + -> "Transfer-Encoding: chunked\r\n" + -> "Accept-Ranges: bytes\r\n" + -> "Date: Wed, 26 Apr 2017 18:27:36 GMT\r\n" + -> "Via: 1.1 varnish\r\n" + -> "Connection: close\r\n" + -> "X-Served-By: cache-fra1247-FRA\r\n" + -> "X-Cache: MISS\r\n" + -> "X-Cache-Hits: 0\r\n" + -> "X-Timer: S1493231255.546126,VS0,VE1713\r\n" + -> "Vary: Authorization\r\n" + -> "\r\n" + -> "324\r\n" + reading 804 bytes... + -> "{\"checkout_id\":1709862829,\"account_id\":2080478981,\"type\":\"goods\",\"short_description\":\"Purchase\",\"currency\":\"USD\",\"amount\":20,\"state\":\"authorized\",\"soft_descriptor\":\"WPY*Spreedly\",\"create_time\":1493231254,\"gross\":20.88,\"reference_id\":null,\"callback_uri\":null,\"long_description\":null,\"delivery_type\":null,\"fee\":{\"app_fee\":0,\"processing_fee\":0.88,\"fee_payer\":\"payer\"},\"chargeback\":{\"amount_charged_back\":0,\"dispute_uri\":null},\"refund\":{\"amount_refunded\":0,\"refund_reason\":null},\"payment_method\":{\"type\":\"credit_card\",\"credit_card\":{\"id\":2559797807,\"data\":{\"emv_receipt\":null,\"signature_url\":null},\"auto_capture\":false}},\"hosted_checkout\":null,\"payer\":{\"email\":\"test@example.com\",\"name\":\"Longbob Longsen\",\"home_address\":null},\"npo_information\":null,\"payment_error\":null,\"in_review\":false,\"auto_release\":true}" + read 804 bytes + reading 2 bytes... + -> "\r\n" + read 2 bytes + -> "0\r\n" + -> "\r\n" + Conn close + opening connection to stage.wepayapi.com:443... + opened + starting SSL for stage.wepayapi.com:443... + SSL established + <- "POST /v2/checkout/capture HTTP/1.1\r\nContent-Type: application/json\r\nUser-Agent: ActiveMerchantBindings/1.65.0\r\nAuthorization: Bearer STAGE_c91882b0bed3584b8aed0f7f515f2f05a1d40924ee6f394ce82d91018cb0f2d3\r\nApi-Version: 2017-02-01\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nAccept: */*\r\nConnection: close\r\nHost: stage.wepayapi.com\r\nContent-Length: 28\r\n\r\n" + <- "{\"checkout_id\":\"1709862829\"}" + -> "HTTP/1.1 200 OK\r\n" + -> "Server: nginx\r\n" + -> "Content-Type: application/json\r\n" + -> "X-Content-Type-Options: nosniff\r\n" + -> "Strict-Transport-Security: max-age=31536000; preload\r\n" + -> "Transfer-Encoding: chunked\r\n" + -> "Accept-Ranges: bytes\r\n" + -> "Date: Wed, 26 Apr 2017 18:27:38 GMT\r\n" + -> "Via: 1.1 varnish\r\n" + -> "Connection: close\r\n" + -> "X-Served-By: cache-fra1239-FRA\r\n" + -> "X-Cache: MISS\r\n" + -> "X-Cache-Hits: 0\r\n" + -> "X-Timer: S1493231257.113609,VS0,VE1136\r\n" + -> "Vary: Authorization\r\n" + -> "\r\n" + -> "324\r\n" + reading 804 bytes... + -> "{\"checkout_id\":1709862829,\"account_id\":2080478981,\"type\":\"goods\",\"short_description\":\"Purchase\",\"currency\":\"USD\",\"amount\":20,\"state\":\"authorized\",\"soft_descriptor\":\"WPY*Spreedly\",\"create_time\":1493231254,\"gross\":20.88,\"reference_id\":null,\"callback_uri\":null,\"long_description\":null,\"delivery_type\":null,\"fee\":{\"app_fee\":0,\"processing_fee\":0.88,\"fee_payer\":\"payer\"},\"chargeback\":{\"amount_charged_back\":0,\"dispute_uri\":null},\"refund\":{\"amount_refunded\":0,\"refund_reason\":null},\"payment_method\":{\"type\":\"credit_card\",\"credit_card\":{\"id\":2559797807,\"data\":{\"emv_receipt\":null,\"signature_url\":null},\"auto_capture\":false}},\"hosted_checkout\":null,\"payer\":{\"email\":\"test@example.com\",\"name\":\"Longbob Longsen\",\"home_address\":null},\"npo_information\":null,\"payment_error\":null,\"in_review\":false,\"auto_release\":true}" + read 804 bytes + reading 2 bytes... + -> "\r\n" + read 2 bytes + -> "0\r\n" + -> "\r\n" + Conn close + ) + end + + def post_scrubbed + %q( + opening connection to stage.wepayapi.com:443... + opened + starting SSL for stage.wepayapi.com:443... + SSL established + <- "POST /v2/credit_card/create HTTP/1.1\r\nContent-Type: application/json\r\nUser-Agent: ActiveMerchantBindings/1.65.0\r\nAuthorization: Bearer [FILTERED]\r\nApi-Version: 2017-02-01\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nAccept: */*\r\nConnection: close\r\nHost: stage.wepayapi.com\r\nContent-Length: 272\r\n\r\n" + <- "{\"client_id\":\"44716\",\"user_name\":\"Longbob Longsen\",\"email\":\"test@example.com\",\"cc_number\":\"[FILTERED]\",\"cvv\":\"[FILTERED]\",\"expiration_month\":9,\"expiration_year\":2018,\"address\":{\"address1\":\"456 My Street\",\"city\":\"Ottawa\",\"country\":\"CA\",\"region\":\"ON\",\"postal_code\":\"K1C2N6\"}}" + -> "HTTP/1.1 200 OK\r\n" + -> "Server: nginx\r\n" + -> "Content-Type: application/json\r\n" + -> "X-Content-Type-Options: nosniff\r\n" + -> "Strict-Transport-Security: max-age=31536000; preload\r\n" + -> "Transfer-Encoding: chunked\r\n" + -> "Accept-Ranges: bytes\r\n" + -> "Date: Wed, 26 Apr 2017 18:27:33 GMT\r\n" + -> "Via: 1.1 varnish\r\n" + -> "Connection: close\r\n" + -> "X-Served-By: cache-fra1231-FRA\r\n" + -> "X-Cache: MISS\r\n" + -> "X-Cache-Hits: 0\r\n" + -> "X-Timer: S1493231252.436069,VS0,VE1258\r\n" + -> "Vary: Authorization\r\n" + -> "\r\n" + -> "2b\r\n" + reading 43 bytes... + -> "{\"credit_card_id\":2559797807,\"state\":\"new\"}" + read 43 bytes + reading 2 bytes... + -> "\r\n" + read 2 bytes + -> "0\r\n" + -> "\r\n" + Conn close + opening connection to stage.wepayapi.com:443... + opened + starting SSL for stage.wepayapi.com:443... + SSL established + <- "POST /v2/checkout/create HTTP/1.1\r\nContent-Type: application/json\r\nUser-Agent: ActiveMerchantBindings/1.65.0\r\nAuthorization: Bearer [FILTERED]\r\nApi-Version: 2017-02-01\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nAccept: */*\r\nConnection: close\r\nHost: stage.wepayapi.com\r\nContent-Length: 202\r\n\r\n" + <- "{\"payment_method\":{\"type\":\"credit_card\",\"credit_card\":{\"id\":\"2559797807\",\"auto_capture\":false}},\"account_id\":\"2080478981\",\"amount\":\"20.00\",\"short_description\":\"Purchase\",\"type\":\"goods\",\"currency\":\"USD\"}" + -> "HTTP/1.1 200 OK\r\n" + -> "Server: nginx\r\n" + -> "Content-Type: application/json\r\n" + -> "X-Content-Type-Options: nosniff\r\n" + -> "Strict-Transport-Security: max-age=31536000; preload\r\n" + -> "Transfer-Encoding: chunked\r\n" + -> "Accept-Ranges: bytes\r\n" + -> "Date: Wed, 26 Apr 2017 18:27:36 GMT\r\n" + -> "Via: 1.1 varnish\r\n" + -> "Connection: close\r\n" + -> "X-Served-By: cache-fra1247-FRA\r\n" + -> "X-Cache: MISS\r\n" + -> "X-Cache-Hits: 0\r\n" + -> "X-Timer: S1493231255.546126,VS0,VE1713\r\n" + -> "Vary: Authorization\r\n" + -> "\r\n" + -> "324\r\n" + reading 804 bytes... + -> "{\"checkout_id\":1709862829,\"account_id\":2080478981,\"type\":\"goods\",\"short_description\":\"Purchase\",\"currency\":\"USD\",\"amount\":20,\"state\":\"authorized\",\"soft_descriptor\":\"WPY*Spreedly\",\"create_time\":1493231254,\"gross\":20.88,\"reference_id\":null,\"callback_uri\":null,\"long_description\":null,\"delivery_type\":null,\"fee\":{\"app_fee\":0,\"processing_fee\":0.88,\"fee_payer\":\"payer\"},\"chargeback\":{\"amount_charged_back\":0,\"dispute_uri\":null},\"refund\":{\"amount_refunded\":0,\"refund_reason\":null},\"payment_method\":{\"type\":\"credit_card\",\"credit_card\":{\"id\":2559797807,\"data\":{\"emv_receipt\":null,\"signature_url\":null},\"auto_capture\":false}},\"hosted_checkout\":null,\"payer\":{\"email\":\"test@example.com\",\"name\":\"Longbob Longsen\",\"home_address\":null},\"npo_information\":null,\"payment_error\":null,\"in_review\":false,\"auto_release\":true}" + read 804 bytes + reading 2 bytes... + -> "\r\n" + read 2 bytes + -> "0\r\n" + -> "\r\n" + Conn close + opening connection to stage.wepayapi.com:443... + opened + starting SSL for stage.wepayapi.com:443... + SSL established + <- "POST /v2/checkout/capture HTTP/1.1\r\nContent-Type: application/json\r\nUser-Agent: ActiveMerchantBindings/1.65.0\r\nAuthorization: Bearer [FILTERED]\r\nApi-Version: 2017-02-01\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nAccept: */*\r\nConnection: close\r\nHost: stage.wepayapi.com\r\nContent-Length: 28\r\n\r\n" + <- "{\"checkout_id\":\"1709862829\"}" + -> "HTTP/1.1 200 OK\r\n" + -> "Server: nginx\r\n" + -> "Content-Type: application/json\r\n" + -> "X-Content-Type-Options: nosniff\r\n" + -> "Strict-Transport-Security: max-age=31536000; preload\r\n" + -> "Transfer-Encoding: chunked\r\n" + -> "Accept-Ranges: bytes\r\n" + -> "Date: Wed, 26 Apr 2017 18:27:38 GMT\r\n" + -> "Via: 1.1 varnish\r\n" + -> "Connection: close\r\n" + -> "X-Served-By: cache-fra1239-FRA\r\n" + -> "X-Cache: MISS\r\n" + -> "X-Cache-Hits: 0\r\n" + -> "X-Timer: S1493231257.113609,VS0,VE1136\r\n" + -> "Vary: Authorization\r\n" + -> "\r\n" + -> "324\r\n" + reading 804 bytes... + -> "{\"checkout_id\":1709862829,\"account_id\":2080478981,\"type\":\"goods\",\"short_description\":\"Purchase\",\"currency\":\"USD\",\"amount\":20,\"state\":\"authorized\",\"soft_descriptor\":\"WPY*Spreedly\",\"create_time\":1493231254,\"gross\":20.88,\"reference_id\":null,\"callback_uri\":null,\"long_description\":null,\"delivery_type\":null,\"fee\":{\"app_fee\":0,\"processing_fee\":0.88,\"fee_payer\":\"payer\"},\"chargeback\":{\"amount_charged_back\":0,\"dispute_uri\":null},\"refund\":{\"amount_refunded\":0,\"refund_reason\":null},\"payment_method\":{\"type\":\"credit_card\",\"credit_card\":{\"id\":2559797807,\"data\":{\"emv_receipt\":null,\"signature_url\":null},\"auto_capture\":false}},\"hosted_checkout\":null,\"payer\":{\"email\":\"test@example.com\",\"name\":\"Longbob Longsen\",\"home_address\":null},\"npo_information\":null,\"payment_error\":null,\"in_review\":false,\"auto_release\":true}" + read 804 bytes + reading 2 bytes... + -> "\r\n" + read 2 bytes + -> "0\r\n" + -> "\r\n" + Conn close + ) + end + def successful_store_response %({"credit_card_id": 3322208138,"state": "new"}) end diff --git a/test/unit/gateways/wirecard_test.rb b/test/unit/gateways/wirecard_test.rb index d073f2eecd7..f8f3e2d2b90 100644 --- a/test/unit/gateways/wirecard_test.rb +++ b/test/unit/gateways/wirecard_test.rb @@ -1,4 +1,5 @@ # encoding: UTF-8 + require 'test_helper' class WirecardTest < Test::Unit::TestCase @@ -13,7 +14,7 @@ def setup @credit_card = credit_card('4200000000000000') @declined_card = credit_card('4000300011112220') @unsupported_card = credit_card('4200000000000000', brand: :maestro) - @amex_card = credit_card('370000000000000', brand: "american_express") + @amex_card = credit_card('370000000000000', brand: 'american_express') @amount = 111 @@ -149,23 +150,23 @@ def test_successful_authorization_and_partial_capture def test_unauthorized_capture @gateway.expects(:ssl_post).returns(unauthorized_capture_response) - assert response = @gateway.capture(@amount, "1234567890123456789012", @options) + assert response = @gateway.capture(@amount, '1234567890123456789012', @options) assert_failure response assert_equal TEST_CAPTURE_GUWID, response.authorization - assert response.message["Could not find referenced transaction for GuWID 1234567890123456789012."] + assert response.message['Could not find referenced transaction for GuWID 1234567890123456789012.'] end def test_failed_refund @gateway.expects(:ssl_post).returns(failed_refund_response) - assert response = @gateway.refund(@amount - 30, "TheIdentifcation", @options) + assert response = @gateway.refund(@amount - 30, 'TheIdentifcation', @options) assert_failure response assert_match %r{Not prudent}, response.message end def test_failed_void @gateway.expects(:ssl_post).returns(failed_void_response) - assert response = @gateway.refund(@amount - 30, "TheIdentifcation", @options) + assert response = @gateway.refund(@amount - 30, 'TheIdentifcation', @options) assert_failure response assert_match %r{Not gonna do it}, response.message end @@ -187,7 +188,7 @@ def test_no_error_if_no_address_provided end def test_description_trucated_to_32_chars_in_authorize - options = { description: "32chars-------------------------EXTRA" } + options = { description: '32chars-------------------------EXTRA' } stub_comms do @gateway.authorize(@amount, @credit_card, options) @@ -197,7 +198,7 @@ def test_description_trucated_to_32_chars_in_authorize end def test_description_trucated_to_32_chars_in_purchase - options = { description: "32chars-------------------------EXTRA" } + options = { description: '32chars-------------------------EXTRA' } stub_comms do @gateway.purchase(@amount, @credit_card, options) @@ -207,7 +208,7 @@ def test_description_trucated_to_32_chars_in_purchase end def test_description_is_ascii_encoded_since_wirecard_does_not_like_utf_8 - options = { description: "¿Dónde está la estación?" } + options = { description: '¿Dónde está la estación?' } stub_comms do @gateway.purchase(@amount, @credit_card, options) @@ -220,18 +221,18 @@ def test_failed_avs_response_message options = @options.merge(billing_address: @address_avs) @gateway.expects(:ssl_post).returns(failed_avs_response) response = @gateway.purchase(@amount, @credit_card, options) - assert_match %r{A}, response.avs_result["code"] + assert_match %r{A}, response.avs_result['code'] end def test_failed_amex_avs_response_code options = @options.merge(billing_address: @address_avs) @gateway.expects(:ssl_post).returns(failed_avs_response) response = @gateway.purchase(@amount, @amex_card, options) - assert_match %r{B}, response.avs_result["code"] + assert_match %r{B}, response.avs_result['code'] end def test_commerce_type_option - options = { commerce_type: "MOTO" } + options = { commerce_type: 'MOTO' } stub_comms do @gateway.purchase(@amount, @credit_card, options) @@ -244,7 +245,7 @@ def test_store_sets_recurring_transaction_type_to_initial stub_comms do @gateway.store(@credit_card) end.check_request do |endpoint, body, headers| - assert_xml_element_text(body, "//RECURRING_TRANSACTION/Type", "Initial") + assert_xml_element_text(body, '//RECURRING_TRANSACTION/Type', 'Initial') end.respond_with(successful_authorization_response) end @@ -252,7 +253,7 @@ def test_store_sets_amount_to_100_by_default stub_comms do @gateway.store(@credit_card) end.check_request do |endpoint, body, headers| - assert_xml_element_text(body, "//CC_TRANSACTION/Amount", "100") + assert_xml_element_text(body, '//CC_TRANSACTION/Amount', '100') end.respond_with(successful_authorization_response) end @@ -260,7 +261,7 @@ def test_store_sets_amount_to_amount_from_options stub_comms do @gateway.store(@credit_card, :amount => 120) end.check_request do |endpoint, body, headers| - assert_xml_element_text(body, "//CC_TRANSACTION/Amount", "120") + assert_xml_element_text(body, '//CC_TRANSACTION/Amount', '120') end.respond_with(successful_authorization_response) end @@ -268,7 +269,7 @@ def test_authorization_using_reference_sets_proper_elements stub_comms do @gateway.authorize(@amount, '45678', @options) end.check_request do |endpoint, body, headers| - assert_xml_element_text(body, "//GuWID", '45678') + assert_xml_element_text(body, '//GuWID', '45678') assert_no_match(/<CREDIT_CARD_DATA>/, body) end.respond_with(successful_authorization_response) end @@ -277,24 +278,24 @@ def test_purchase_using_reference_sets_proper_elements stub_comms do @gateway.purchase(@amount, '87654', @options) end.check_request do |endpoint, body, headers| - assert_xml_element_text(body, "//GuWID", '87654') + assert_xml_element_text(body, '//GuWID', '87654') assert_no_match(/<CREDIT_CARD_DATA>/, body) end.respond_with(successful_authorization_response) end def test_authorization_with_recurring_transaction_type_initial stub_comms do - @gateway.authorize(@amount, @credit_card, @options.merge(:recurring => "Initial")) + @gateway.authorize(@amount, @credit_card, @options.merge(:recurring => 'Initial')) end.check_request do |endpoint, body, headers| - assert_xml_element_text(body, "//RECURRING_TRANSACTION/Type", 'Initial') + assert_xml_element_text(body, '//RECURRING_TRANSACTION/Type', 'Initial') end.respond_with(successful_authorization_response) end def test_purchase_using_with_recurring_transaction_type_initial stub_comms do - @gateway.purchase(@amount, @credit_card, @options.merge(:recurring => "Initial")) + @gateway.purchase(@amount, @credit_card, @options.merge(:recurring => 'Initial')) end.check_request do |endpoint, body, headers| - assert_xml_element_text(body, "//RECURRING_TRANSACTION/Type", 'Initial') + assert_xml_element_text(body, '//RECURRING_TRANSACTION/Type', 'Initial') end.respond_with(successful_authorization_response) end @@ -310,8 +311,8 @@ def test_system_error_response_without_job assert response = @gateway.purchase(@amount, @credit_card, @options) assert_failure response - assert_equal "Job Refused", response.params["Message"] - assert_equal "10003", response.params["ErrorCode"] + assert_equal 'Job Refused', response.params['Message'] + assert_equal '10003', response.params['ErrorCode'] end def test_transcript_scrubbing @@ -367,10 +368,11 @@ def wrong_creditcard_authorization_response XML result_node = '</FunctionResult>' auth = 'AuthorizationCode' - successful_authorization_response.gsub('ACK', 'NOK') \ - .gsub(result_node, result_node + error) \ - .gsub(/<#{auth}>\w+<\/#{auth}>/, "<#{auth}><\/#{auth}>") \ - .gsub(/<Info>.+<\/Info>/, '') + successful_authorization_response. + gsub('ACK', 'NOK'). + gsub(result_node, result_node + error). + gsub(/<#{auth}>\w+<\/#{auth}>/, "<#{auth}><\/#{auth}>"). + gsub(/<Info>.+<\/Info>/, '') end # Capture success @@ -577,7 +579,6 @@ def failed_void_response XML end - # Purchase failure def wrong_creditcard_purchase_response <<-XML diff --git a/test/unit/gateways/world_net_test.rb b/test/unit/gateways/world_net_test.rb index d668b615cf6..c32728f69b9 100644 --- a/test/unit/gateways/world_net_test.rb +++ b/test/unit/gateways/world_net_test.rb @@ -191,70 +191,70 @@ def post_scrubbed end def successful_purchase_response - %q(<?xml version="1.0" encoding="UTF-8"?> -<PAYMENTRESPONSE><UNIQUEREF>GZG6IG6VXI</UNIQUEREF><RESPONSECODE>A</RESPONSECODE><RESPONSETEXT>APPROVAL</RESPONSETEXT><APPROVALCODE>475318</APPROVALCODE><DATETIME>2015-09-14T21:22:12</DATETIME><AVSRESPONSE>X</AVSRESPONSE><CVVRESPONSE>M</CVVRESPONSE><HASH>f8642d613c56628371a579443ce8d895</HASH></PAYMENTRESPONSE>) + '<?xml version="1.0" encoding="UTF-8"?> +<PAYMENTRESPONSE><UNIQUEREF>GZG6IG6VXI</UNIQUEREF><RESPONSECODE>A</RESPONSECODE><RESPONSETEXT>APPROVAL</RESPONSETEXT><APPROVALCODE>475318</APPROVALCODE><DATETIME>2015-09-14T21:22:12</DATETIME><AVSRESPONSE>X</AVSRESPONSE><CVVRESPONSE>M</CVVRESPONSE><HASH>f8642d613c56628371a579443ce8d895</HASH></PAYMENTRESPONSE>' end def failed_purchase_response - %q(<?xml version="1.0" encoding="UTF-8"?> -<PAYMENTRESPONSE><UNIQUEREF>JQU1810S4E</UNIQUEREF><RESPONSECODE>D</RESPONSECODE><RESPONSETEXT>DECLINED</RESPONSETEXT><APPROVALCODE></APPROVALCODE><DATETIME>2015-09-14T21:40:07</DATETIME><AVSRESPONSE></AVSRESPONSE><CVVRESPONSE></CVVRESPONSE><HASH>c0ba33a10a6388b12c8fad79a107f2b5</HASH></PAYMENTRESPONSE>) + '<?xml version="1.0" encoding="UTF-8"?> +<PAYMENTRESPONSE><UNIQUEREF>JQU1810S4E</UNIQUEREF><RESPONSECODE>D</RESPONSECODE><RESPONSETEXT>DECLINED</RESPONSETEXT><APPROVALCODE></APPROVALCODE><DATETIME>2015-09-14T21:40:07</DATETIME><AVSRESPONSE></AVSRESPONSE><CVVRESPONSE></CVVRESPONSE><HASH>c0ba33a10a6388b12c8fad79a107f2b5</HASH></PAYMENTRESPONSE>' end def successful_authorize_response - %q(<?xml version="1.0" encoding="UTF-8"?> -<PREAUTHRESPONSE><UNIQUEREF>BF4CNN6WXP</UNIQUEREF><RESPONSECODE>A</RESPONSECODE><RESPONSETEXT>APPROVAL</RESPONSETEXT><APPROVALCODE>450848</APPROVALCODE><DATETIME>2015-09-14T21:53:10</DATETIME><AVSRESPONSE></AVSRESPONSE><CVVRESPONSE></CVVRESPONSE><HASH>e80c52476af1dd969f3bf89ed02fe16f</HASH></PREAUTHRESPONSE>) + '<?xml version="1.0" encoding="UTF-8"?> +<PREAUTHRESPONSE><UNIQUEREF>BF4CNN6WXP</UNIQUEREF><RESPONSECODE>A</RESPONSECODE><RESPONSETEXT>APPROVAL</RESPONSETEXT><APPROVALCODE>450848</APPROVALCODE><DATETIME>2015-09-14T21:53:10</DATETIME><AVSRESPONSE></AVSRESPONSE><CVVRESPONSE></CVVRESPONSE><HASH>e80c52476af1dd969f3bf89ed02fe16f</HASH></PREAUTHRESPONSE>' end def failed_authorize_response - %q(<?xml version="1.0" encoding="UTF-8"?> -<PREAUTHRESPONSE><UNIQUEREF>IP0PUDDXG5</UNIQUEREF><RESPONSECODE>D</RESPONSECODE><RESPONSETEXT>DECLINED</RESPONSETEXT><APPROVALCODE></APPROVALCODE><DATETIME>2015-09-15T14:21:37</DATETIME><AVSRESPONSE></AVSRESPONSE><CVVRESPONSE></CVVRESPONSE><HASH>05dfa85163ee8d8afa8711019f64acb3</HASH></PREAUTHRESPONSE>) + '<?xml version="1.0" encoding="UTF-8"?> +<PREAUTHRESPONSE><UNIQUEREF>IP0PUDDXG5</UNIQUEREF><RESPONSECODE>D</RESPONSECODE><RESPONSETEXT>DECLINED</RESPONSETEXT><APPROVALCODE></APPROVALCODE><DATETIME>2015-09-15T14:21:37</DATETIME><AVSRESPONSE></AVSRESPONSE><CVVRESPONSE></CVVRESPONSE><HASH>05dfa85163ee8d8afa8711019f64acb3</HASH></PREAUTHRESPONSE>' end def successful_capture_response - %q(<?xml version="1.0" encoding="UTF-8"?> -<PREAUTHCOMPLETIONRESPONSE><UNIQUEREF>BF4CNN6WXP</UNIQUEREF><RESPONSECODE>A</RESPONSECODE><RESPONSETEXT>APPROVAL</RESPONSETEXT><APPROVALCODE>450848</APPROVALCODE><DATETIME>2015-09-14T21:53:10</DATETIME><AVSRESPONSE></AVSRESPONSE><CVVRESPONSE></CVVRESPONSE><HASH>e80c52476af1dd969f3bf89ed02fe16f</HASH></PREAUTHCOMPLETIONRESPONSE>) + '<?xml version="1.0" encoding="UTF-8"?> +<PREAUTHCOMPLETIONRESPONSE><UNIQUEREF>BF4CNN6WXP</UNIQUEREF><RESPONSECODE>A</RESPONSECODE><RESPONSETEXT>APPROVAL</RESPONSETEXT><APPROVALCODE>450848</APPROVALCODE><DATETIME>2015-09-14T21:53:10</DATETIME><AVSRESPONSE></AVSRESPONSE><CVVRESPONSE></CVVRESPONSE><HASH>e80c52476af1dd969f3bf89ed02fe16f</HASH></PREAUTHCOMPLETIONRESPONSE>' end def failed_capture_response - %q(<?xml version="1.0" encoding="UTF-8"?> -<ERROR><ERRORSTRING>cvc-minLength-valid: Value &apos;&apos; with length = &apos;0&apos; is not facet-valid with respect to minLength &apos;10&apos; for type &apos;UID&apos;.</ERRORSTRING></ERROR>) + '<?xml version="1.0" encoding="UTF-8"?> +<ERROR><ERRORSTRING>cvc-minLength-valid: Value &apos;&apos; with length = &apos;0&apos; is not facet-valid with respect to minLength &apos;10&apos; for type &apos;UID&apos;.</ERRORSTRING></ERROR>' end def successful_refund_response - %q(<?xml version="1.0" encoding="UTF-8"?> -<REFUNDRESPONSE><RESPONSECODE>A</RESPONSECODE><RESPONSETEXT>SUCCESS</RESPONSETEXT><UNIQUEREF>GIOH10II2J</UNIQUEREF><DATETIME>15-09-2015:14:44:17:999</DATETIME><HASH>aebd69e9db6e4b0db7ecbae79a2970a0</HASH></REFUNDRESPONSE>) + '<?xml version="1.0" encoding="UTF-8"?> +<REFUNDRESPONSE><RESPONSECODE>A</RESPONSECODE><RESPONSETEXT>SUCCESS</RESPONSETEXT><UNIQUEREF>GIOH10II2J</UNIQUEREF><DATETIME>15-09-2015:14:44:17:999</DATETIME><HASH>aebd69e9db6e4b0db7ecbae79a2970a0</HASH></REFUNDRESPONSE>' end def failed_refund_response - %q(<?xml version="1.0" encoding="UTF-8"?> -<ERROR><ERRORSTRING>cvc-minLength-valid: Value &apos;&apos; with length = &apos;0&apos; is not facet-valid with respect to minLength &apos;10&apos; for type &apos;UID&apos;.</ERRORSTRING></ERROR>) + '<?xml version="1.0" encoding="UTF-8"?> +<ERROR><ERRORSTRING>cvc-minLength-valid: Value &apos;&apos; with length = &apos;0&apos; is not facet-valid with respect to minLength &apos;10&apos; for type &apos;UID&apos;.</ERRORSTRING></ERROR>' end def successful_void_response end def successful_store_response - %q(<?xml version="1.0" encoding="UTF-8"?> -<SECURECARDREGISTRATIONRESPONSE><MERCHANTREF>146304412401</MERCHANTREF><CARDREFERENCE>2967530956419033</CARDREFERENCE><DATETIME>12-05-2016:10:08:46:269</DATETIME><HASH>b2e497d14014ad9f4770edbf7716435e</HASH></SECURECARDREGISTRATIONRESPONSE>) + '<?xml version="1.0" encoding="UTF-8"?> +<SECURECARDREGISTRATIONRESPONSE><MERCHANTREF>146304412401</MERCHANTREF><CARDREFERENCE>2967530956419033</CARDREFERENCE><DATETIME>12-05-2016:10:08:46:269</DATETIME><HASH>b2e497d14014ad9f4770edbf7716435e</HASH></SECURECARDREGISTRATIONRESPONSE>' end def failed_store_response - %q(<?xml version="1.0" encoding="UTF-8"?> -<ERROR><ERRORCODE>E11</ERRORCODE><ERRORSTRING>INVALID CARDEXPIRY</ERRORSTRING></ERROR>) + '<?xml version="1.0" encoding="UTF-8"?> +<ERROR><ERRORCODE>E11</ERRORCODE><ERRORSTRING>INVALID CARDEXPIRY</ERRORSTRING></ERROR>' end def successful_unstore_response - %q(<?xml version="1.0" encoding="UTF-8"?> -<SECURECARDREMOVALRESPONSE><MERCHANTREF>146304412401</MERCHANTREF><DATETIME>12-05-2016:10:08:48:399</DATETIME><HASH>7f755e185be8066a535699755f709646</HASH></SECURECARDREMOVALRESPONSE>) + '<?xml version="1.0" encoding="UTF-8"?> +<SECURECARDREMOVALRESPONSE><MERCHANTREF>146304412401</MERCHANTREF><DATETIME>12-05-2016:10:08:48:399</DATETIME><HASH>7f755e185be8066a535699755f709646</HASH></SECURECARDREMOVALRESPONSE>' end def failed_unstore_response - %q(<?xml version="1.0" encoding="UTF-8"?> -<ERROR><ERRORCODE>E04</ERRORCODE><ERRORSTRING>INVALID REFERENCE DETAILS</ERRORSTRING></ERROR>) + '<?xml version="1.0" encoding="UTF-8"?> +<ERROR><ERRORCODE>E04</ERRORCODE><ERRORSTRING>INVALID REFERENCE DETAILS</ERRORSTRING></ERROR>' end def failed_void_response - %q(<?xml version="1.0" encoding="UTF-8"?> -<ERROR><ERRORSTRING>cvc-elt.1: Cannot find the declaration of element &apos;VOID&apos;.</ERRORSTRING></ERROR>) + '<?xml version="1.0" encoding="UTF-8"?> +<ERROR><ERRORSTRING>cvc-elt.1: Cannot find the declaration of element &apos;VOID&apos;.</ERRORSTRING></ERROR>' end end diff --git a/test/unit/gateways/worldpay_online_payments_test.rb b/test/unit/gateways/worldpay_online_payments_test.rb index 1ab94e025a2..697ac11aba0 100644 --- a/test/unit/gateways/worldpay_online_payments_test.rb +++ b/test/unit/gateways/worldpay_online_payments_test.rb @@ -14,11 +14,11 @@ def setup description: 'Test Purchase' } - @token = "TEST_RU_8fcc4f2f-8c0d-483d-a0a3-eaad7356623e" - @intoken = "_TEST_RU_8fcc4f2f-8c0d-483d-a0a3-eaad7356623e_" + @token = 'TEST_RU_8fcc4f2f-8c0d-483d-a0a3-eaad7356623e' + @intoken = '_TEST_RU_8fcc4f2f-8c0d-483d-a0a3-eaad7356623e_' - @orderCode = "e69b5445-2a46-4f2c-b67d-7e1e95bd00a5" - @inorderCode = "_e69b5445-2a46-4f2c-b67d-7e1e95bd00a5_" + @orderCode = 'e69b5445-2a46-4f2c-b67d-7e1e95bd00a5' + @inorderCode = '_e69b5445-2a46-4f2c-b67d-7e1e95bd00a5_' end def test_successful_purchase @@ -184,8 +184,8 @@ def test_failed_verify def test_invalid_login badgateway = WorldpayOnlinePaymentsGateway.new( - client_key: "T_C_NOT_VALID", - service_key: "T_S_NOT_VALID" + client_key: 'T_C_NOT_VALID', + service_key: 'T_S_NOT_VALID' ) badgateway.expects(:ssl_request).returns(failed_login_response) @@ -198,9 +198,11 @@ def test_invalid_login def successful_token_response %({"token": "TEST_RU_8fcc4f2f-8c0d-483d-a0a3-eaad7356623e","paymentMethod": {"type": "ObfuscatedCard","name": "Longbob Longsen","expiryMonth": 10,"expiryYear": 2016,"cardType": "VISA","maskedCardNumber": "**** **** **** 1111"},"reusable": true}) end + def successful_authorize_response %({"orderCode": "a46502d0-80ba-425b-a6db-2c57e9de91da","token": "TEST_RU_8fcc4f2f-8c0d-483d-a0a3-eaad7356623e","orderDescription": "Test Purchase","amount": 0,"currencyCode": "GBP","authorizeOnly": true,"paymentStatus": "AUTHORIZED","paymentResponse": {"type": "ObfuscatedCard","name": "Longbob Longsen","expiryMonth": 10,"expiryYear": 2016,"cardType": "VISA_CREDIT","maskedCardNumber": "**** **** **** 1111"},"environment": "TEST","authorizedAmount": 1000}) end + def failed_authorize_response %({"httpStatusCode":400,"customCode":"BAD_REQUEST","message":"CVC can't be null/empty","description":"Some of request parameters are invalid, please check your request. For more information please refer to Json schema.","errorHelpUrl":null,"originalRequest":"{'reusable':false,'paymentMethod':{'type':'Card','name':'Example Name','expiryMonth':'**','expiryYear':'****','cardNumber':'**** **** **** 1111','cvc':''},'clientKey':'T_C_845d39f4-f33c-430c-8fca-ad89bf1e5810'}"} ) end diff --git a/test/unit/gateways/worldpay_test.rb b/test/unit/gateways/worldpay_test.rb index 51d574cb868..36e2ba8783d 100644 --- a/test/unit/gateways/worldpay_test.rb +++ b/test/unit/gateways/worldpay_test.rb @@ -4,10 +4,10 @@ class WorldpayTest < Test::Unit::TestCase include CommStub def setup - @gateway = WorldpayGateway.new( - :login => 'testlogin', - :password => 'testpassword' - ) + @gateway = WorldpayGateway.new( + :login => 'testlogin', + :password => 'testpassword' + ) @amount = 100 @credit_card = credit_card('4242424242424242') @@ -53,6 +53,21 @@ def test_authorize_passes_ip_and_session_id assert_success response end + def test_authorize_passes_stored_credential_options + options = @options.merge( + stored_credential_usage: 'USED', + stored_credential_initiated_reason: 'UNSCHEDULED', + stored_credential_transaction_id: '000000000000020005060720116005060' + ) + response = stub_comms do + @gateway.authorize(@amount, @credit_card, options) + end.check_request do |endpoint, data, headers| + assert_match(/<storedCredentials usage\=\"USED\" merchantInitiatedReason\=\"UNSCHEDULED\"\>/, data) + assert_match(/<schemeTransactionIdentifier\>000000000000020005060720116005060\<\/schemeTransactionIdentifier\>/, data) + end.respond_with(successful_authorize_response) + assert_success response + end + def test_failed_authorize response = stub_comms do @gateway.authorize(@amount, @credit_card, @options) @@ -97,7 +112,7 @@ def test_purchase_does_not_run_inquiry end.respond_with(successful_capture_response) assert_success response - assert_equal %w(authorize capture), response.responses.collect{|e| e.params["action"]} + assert_equal(%w(authorize capture), response.responses.collect { |e| e.params['action'] }) end def test_successful_void @@ -105,8 +120,8 @@ def test_successful_void @gateway.void(@options[:order_id], @options) end.respond_with(successful_void_inquiry_response, successful_void_response) assert_success response - assert_equal "SUCCESS", response.message - assert_equal "924e810350efc21a989e0ac7727ce43b", response.params["cancel_received_order_code"] + assert_equal 'SUCCESS', response.message + assert_equal '924e810350efc21a989e0ac7727ce43b', response.params['cancel_received_order_code'] end def test_void_fails_unless_status_is_authorized @@ -129,7 +144,15 @@ def test_successful_refund_for_settled_payment @gateway.refund(@amount, @options[:order_id], @options) end.respond_with(successful_refund_inquiry_response('SETTLED'), successful_refund_response) assert_success response - assert_equal "05d9f8c622553b1df1fe3a145ce91ccf", response.params['refund_received_order_code'] + assert_equal '05d9f8c622553b1df1fe3a145ce91ccf', response.params['refund_received_order_code'] + end + + def test_successful_refund_for_settled_by_merchant_payment + response = stub_comms do + @gateway.refund(@amount, @options[:order_id], @options) + end.respond_with(successful_refund_inquiry_response('SETTLED_BY_MERCHANT'), successful_refund_response) + assert_success response + assert_equal '05d9f8c622553b1df1fe3a145ce91ccf', response.params['refund_received_order_code'] end def test_refund_fails_unless_status_is_captured @@ -140,6 +163,14 @@ def test_refund_fails_unless_status_is_captured assert_equal "A transaction status of 'CAPTURED' or 'SETTLED' or 'SETTLED_BY_MERCHANT' is required.", response.message end + def test_full_refund_for_unsettled_payment_forces_void + response = stub_comms do + @gateway.refund(@amount, @options[:order_id], @options.merge(force_full_refund_if_unsettled: true)) + end.respond_with(failed_refund_inquiry_response, failed_refund_inquiry_response, successful_void_response) + assert_success response + assert 'cancel', response.responses.last.params['action'] + end + def test_capture response = stub_comms do response = @gateway.authorize(@amount, @credit_card, @options) @@ -148,6 +179,26 @@ def test_capture assert_success response end + def test_successful_visa_credit + response = stub_comms do + @gateway.credit(@amount, @credit_card, @options) + end.check_request do |endpoint, data, headers| + assert_match(/<paymentDetails action="REFUND">/, data) + end.respond_with(successful_visa_credit_response) + assert_success response + assert_equal '3d4187536044bd39ad6a289c4339c41c', response.authorization + end + + def test_successful_mastercard_credit + response = stub_comms do + @gateway.credit(@amount, @credit_card, @options) + end.check_request do |endpoint, data, headers| + assert_match(/<paymentDetails action="REFUND">/, data) + end.respond_with(successful_mastercard_credit_response) + assert_success response + assert_equal 'f25257d251b81fb1fd9c210973c941ff', response.authorization + end + def test_description stub_comms do @gateway.authorize(@amount, @credit_card, @options) @@ -156,7 +207,7 @@ def test_description end.respond_with(successful_authorize_response) stub_comms do - @gateway.authorize(@amount, @credit_card, @options.merge(description: "Something cool.")) + @gateway.authorize(@amount, @credit_card, @options.merge(description: 'Something cool.')) end.check_request do |endpoint, data, headers| assert_match %r(<description>Something cool.</description>), data end.respond_with(successful_authorize_response) @@ -183,7 +234,7 @@ def test_capture_time if data =~ /capture/ t = Time.now assert_tag_with_attributes 'date', - {'dayOfMonth' => t.day.to_s, 'month' => t.month.to_s, 'year' => t.year.to_s}, + {'dayOfMonth' => t.day.to_s, 'month' => t.month.to_s, 'year' => t.year.to_s}, data end end.respond_with(successful_inquiry_response, successful_capture_response) @@ -194,7 +245,7 @@ def test_amount_handling @gateway.authorize(100, @credit_card, @options) end.check_request do |endpoint, data, headers| assert_tag_with_attributes 'amount', - {'value' => '100', 'exponent' => '2', 'currencyCode' => 'GBP'}, + {'value' => '100', 'exponent' => '2', 'currencyCode' => 'GBP'}, data end.respond_with(successful_authorize_response) end @@ -204,7 +255,15 @@ def test_currency_exponent_handling @gateway.authorize(10000, @credit_card, @options.merge(currency: :JPY)) end.check_request do |endpoint, data, headers| assert_tag_with_attributes 'amount', - {'value' => '100', 'exponent' => '0', 'currencyCode' => 'JPY'}, + {'value' => '100', 'exponent' => '0', 'currencyCode' => 'JPY'}, + data + end.respond_with(successful_authorize_response) + + stub_comms do + @gateway.authorize(10000, @credit_card, @options.merge(currency: :OMR)) + end.check_request do |endpoint, data, headers| + assert_tag_with_attributes 'amount', + {'value' => '10000', 'exponent' => '3', 'currencyCode' => 'OMR'}, data end.respond_with(successful_authorize_response) end @@ -253,7 +312,7 @@ def test_address_handling end.respond_with(successful_authorize_response) stub_comms do - @gateway.authorize(100, @credit_card, @options.merge(billing_address: { phone: "555-3323" })) + @gateway.authorize(100, @credit_card, @options.merge(billing_address: { phone: '555-3323' })) end.check_request do |endpoint, data, headers| assert_no_match %r(firstName), data assert_no_match %r(lastName), data @@ -306,7 +365,7 @@ def test_address_with_parts_unspecified def test_email stub_comms do - @gateway.authorize(100, @credit_card, @options.merge(email: "eggcellent@example.com")) + @gateway.authorize(100, @credit_card, @options.merge(email: 'eggcellent@example.com')) end.check_request do |endpoint, data, headers| assert_match %r(<shopperEmailAddress>eggcellent@example.com</shopperEmailAddress>), data end.respond_with(successful_authorize_response) @@ -318,9 +377,29 @@ def test_email end.respond_with(successful_authorize_response) end + def test_instalments + stub_comms do + @gateway.purchase(100, @credit_card, @options.merge(instalments: 3)) + end.check_request do |endpoint, data, headers| + unless /<capture>/ =~ data + assert_match %r(<instalments>3</instalments>), data + assert_no_match %r(cpf), data + end + end.respond_with(successful_authorize_response, successful_capture_response) + + stub_comms do + @gateway.purchase(100, @credit_card, @options.merge(instalments: 3, cpf: 12341234)) + end.check_request do |endpoint, data, headers| + unless /<capture>/ =~ data + assert_match %r(<instalments>3</instalments>), data + assert_match %r(<cpf>12341234</cpf>), data + end + end.respond_with(successful_authorize_response, successful_capture_response) + end + def test_ip stub_comms do - @gateway.authorize(100, @credit_card, @options.merge(ip: "192.137.11.44")) + @gateway.authorize(100, @credit_card, @options.merge(ip: '192.137.11.44')) end.check_request do |endpoint, data, headers| assert_match %r(<session shopperIPAddress="192.137.11.44"/>), data end.respond_with(successful_authorize_response) @@ -334,30 +413,30 @@ def test_ip def test_parsing response = stub_comms do - @gateway.authorize(100, @credit_card, @options.merge(address: {address1: "123 Anystreet", country: "US"})) + @gateway.authorize(100, @credit_card, @options.merge(address: {address1: '123 Anystreet', country: 'US'})) end.respond_with(successful_authorize_response) assert_equal({ - "action"=>"authorize", - "amount_currency_code"=>"HKD", - "amount_debit_credit_indicator"=>"credit", - "amount_exponent"=>"2", - "amount_value"=>"15000", - "avs_result_code_description"=>"UNKNOWN", - "balance"=>true, - "balance_account_type"=>"IN_PROCESS_AUTHORISED", - "card_number"=>"4111********1111", - "cvc_result_code_description"=>"UNKNOWN", - "last_event"=>"AUTHORISED", - "order_status"=>true, - "order_status_order_code"=>"R50704213207145707", - "payment"=>true, - "payment_method"=>"VISA-SSL", - "payment_service"=>true, - "payment_service_merchant_code"=>"XXXXXXXXXXXXXXX", - "payment_service_version"=>"1.4", - "reply"=>true, - "risk_score_value"=>"1", + 'action'=>'authorize', + 'amount_currency_code'=>'HKD', + 'amount_debit_credit_indicator'=>'credit', + 'amount_exponent'=>'2', + 'amount_value'=>'15000', + 'avs_result_code_description'=>'UNKNOWN', + 'balance'=>true, + 'balance_account_type'=>'IN_PROCESS_AUTHORISED', + 'card_number'=>'4111********1111', + 'cvc_result_code_description'=>'UNKNOWN', + 'last_event'=>'AUTHORISED', + 'order_status'=>true, + 'order_status_order_code'=>'R50704213207145707', + 'payment'=>true, + 'payment_method'=>'VISA-SSL', + 'payment_service'=>true, + 'payment_service_merchant_code'=>'XXXXXXXXXXXXXXX', + 'payment_service_version'=>'1.4', + 'reply'=>true, + 'risk_score_value'=>'1', }, response.params) end @@ -365,7 +444,7 @@ def test_auth stub_comms do @gateway.authorize(100, @credit_card, @options) end.check_request do |endpoint, data, headers| - assert_equal "Basic dGVzdGxvZ2luOnRlc3RwYXNzd29yZA==", headers['Authorization'] + assert_equal 'Basic dGVzdGxvZ2luOnRlc3RwYXNzd29yZA==', headers['Authorization'] end.respond_with(successful_authorize_response) end @@ -383,7 +462,6 @@ def test_request_respects_test_mode_on_gateway_instance end.check_request do |endpoint, data, headers| assert_equal WorldpayGateway.test_url, endpoint end.respond_with(successful_authorize_response, successful_capture_response) - ensure ActiveMerchant::Billing::Base.mode = :test end @@ -408,7 +486,7 @@ def assert_tag_with_attributes(tag, attributes, string) end def test_successful_verify - @gateway.expects(:ssl_post).times(3).returns(successful_authorize_response, successful_void_response) + @gateway.expects(:ssl_post).times(2).returns(successful_authorize_response, successful_void_response) response = @gateway.verify(@credit_card, @options) assert_success response @@ -428,6 +506,18 @@ def test_failed_verify assert_failure response end + def test_3ds_name_coersion + @options[:execute_threed] = true + response = stub_comms do + @gateway.purchase(@amount, @credit_card, @options) + end.check_request do |endpoint, data, headers| + if /<submit>/ =~ data + assert_match %r{<cardHolderName>3D</cardHolderName>}, data + end + end.respond_with(successful_authorize_response, successful_capture_response) + assert_success response + end + def test_transcript_scrubbing assert_equal scrubbed_transcript, @gateway.scrub(transcript) end @@ -591,7 +681,7 @@ def failed_void_inquiry_response RESPONSE end - def successful_refund_inquiry_response(last_event="CAPTURED") + def successful_refund_inquiry_response(last_event='CAPTURED') <<-RESPONSE <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE paymentService PUBLIC "-//Bibit//DTD Bibit PaymentService v1//EN" @@ -602,7 +692,7 @@ def successful_refund_inquiry_response(last_event="CAPTURED") <payment> <paymentMethod>VISA-SSL</paymentMethod> <amount value="100" currencyCode="GBP" exponent="2" debitCreditIndicator="credit"/> - <lastEvent>#{ last_event }</lastEvent> + <lastEvent>#{last_event}</lastEvent> <CVCResultCode description="UNKNOWN"/> <AVSResultCode description="NOT SUPPLIED BY SHOPPER"/> <balance accountType="IN_PROCESS_AUTHORISED"> @@ -680,6 +770,46 @@ def failed_void_response REQUEST end + def successful_visa_credit_response + <<-RESPONSE + <?xml version="1.0" encoding="UTF-8"?> + <!DOCTYPE paymentService PUBLIC "-//WorldPay//DTD WorldPay PaymentService v1//EN" + "http://dtd.worldpay.com/paymentService_v1.dtd"> + <paymentService version="1.4" merchantCode="SPREEDLYCFT"> + <reply> + <ok> + <refundReceived orderCode="3d4187536044bd39ad6a289c4339c41c"> + <amount value="100" currencyCode="GBP" exponent="2" debitCreditIndicator="credit"/> + </refundReceived> + </ok> + </reply> + </paymentService> + RESPONSE + end + + def successful_mastercard_credit_response + <<~RESPONSE + <?xml version="1.0" encoding="UTF-8"?> + <!DOCTYPE paymentService PUBLIC "-//WorldPay//DTD WorldPay PaymentService v1//EN" + "http://dtd.worldpay.com/paymentService_v1.dtd"> + <paymentService version="1.4" merchantCode="YOUR_MERCHANT_CODE"> + <reply> + <orderStatus orderCode="f25257d251b81fb1fd9c210973c941ff\"> + <payment> + <paymentMethod>ECMC_DEBIT-SSL</paymentMethod> + <amount value="1110" currencyCode="GBP" exponent="2" debitCreditIndicator="credit"/> + <lastEvent>SENT_FOR_REFUND</lastEvent> + <AuthorisationId id="987654"/> + <balance accountType="IN_PROCESS_CAPTURED"> + <amount value="1110" currencyCode="GBP" exponent="2" debitCreditIndicator="debit"/> + </balance> + </payment> + </orderStatus> + </reply> + </paymentService> + RESPONSE + end + def sample_authorization_request <<-REQUEST <?xml version="1.0" encoding="UTF-8"?> diff --git a/test/unit/gateways/worldpay_us_test.rb b/test/unit/gateways/worldpay_us_test.rb index 63b0ea6ab8c..ee576daa591 100644 --- a/test/unit/gateways/worldpay_us_test.rb +++ b/test/unit/gateways/worldpay_us_test.rb @@ -28,7 +28,7 @@ def test_successful_purchase assert_success response - assert_equal "353583515|252889136", response.authorization + assert_equal '353583515|252889136', response.authorization assert response.test? end @@ -46,7 +46,7 @@ def test_successful_echeck_purchase assert_success response - assert_equal "421414035|306588394", response.authorization + assert_equal '421414035|306588394', response.authorization assert response.test? end @@ -63,7 +63,7 @@ def test_authorize_and_capture end.respond_with(successful_authorize_response) assert_success response - assert_equal "354275517|253394390", response.authorization + assert_equal '354275517|253394390', response.authorization capture = stub_comms do @gateway.capture(@amount, response.authorization) @@ -80,7 +80,7 @@ def test_refund end.respond_with(successful_purchase_response) assert_success response - assert_equal "353583515|252889136", response.authorization + assert_equal '353583515|252889136', response.authorization refund = stub_comms do @gateway.refund(@amount, response.authorization) @@ -98,7 +98,7 @@ def test_void end.respond_with(successful_purchase_response) assert_success response - assert_equal "353583515|252889136", response.authorization + assert_equal '353583515|252889136', response.authorization refund = stub_comms do @gateway.void(response.authorization) @@ -122,7 +122,7 @@ def test_successful_verify_failed_void @gateway.verify(@credit_card, @options) end.respond_with(successful_authorize_response, failed_void_response) assert_success response - assert_equal "Succeeded", response.message + assert_equal 'Succeeded', response.message end def test_unsuccessful_verify @@ -172,7 +172,22 @@ def test_empty_response_fails end.respond_with(empty_purchase_response) assert_failure response - assert_equal "Unable to read error message", response.message + assert_equal 'Unable to read error message', response.message + end + + def test_backup_url + response = stub_comms(@gateway) do + @gateway.purchase(@amount, @credit_card, use_backup_url: true) + end.check_request do |endpoint, data, headers| + assert_equal WorldpayUsGateway.backup_url, endpoint + end.respond_with(successful_purchase_response) + assert_success response + end + + def test_scrub + assert @gateway.supports_scrubbing? + assert_equal @gateway.scrub(pre_scrubbed), post_scrubbed + assert_equal @gateway.scrub(pre_scrubbed_check), post_scrubbed_check end private @@ -419,4 +434,96 @@ def failed_void_response transid=0 ) end + + def pre_scrubbed + <<-EOS +opening connection to trans.worldpay.us:443... +opened +starting SSL for trans.worldpay.us:443... +SSL established +<- "POST /cgi-bin/process.cgi HTTP/1.1\r\nContent-Type: application/x-www-form-urlencoded\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nAccept: */*\r\nUser-Agent: Ruby\r\nConnection: close\r\nHost: trans.worldpay.us\r\nContent-Length: 425\r\n\r\n" +<- "acctid=MPNAB&action=ns_quicksale_cc&amount=1.00&ccname=Longbob+Longsen&ccnum=4446661234567892&ci_billaddr1=456+My+Street&ci_billaddr2=Apt+1&ci_billcity=Ottawa&ci_billcountry=CA&ci_billstate=ON&ci_billzip=K1C2N6&ci_companyname=Widgets+Inc&ci_email=&ci_ipaddress=&ci_phone=%28555%29555-5555&currencycode=USD&cvv2=987&expmon=09&expyear=2019&merchantordernumber=67f4f20082e79684f036f25dafe96304&merchantpin=1234567890&subid=SPREE" +-> "HTTP/1.1 200 OK\r\n" +-> "Date: Tue, 13 Feb 2018 19:28:27 GMT\r\n" +-> "Server: Apache\r\n" +-> "X-Frame-Options: SAMEORIGIN\r\n" +-> "Content-Type: text/html;charset=ISO-8859-1\r\n" +-> "Content-Length: 962\r\n" +-> "Connection: close\r\n" +-> "\r\n" +reading 962 bytes... +-> "<html><body><plaintext>\r\nAccepted=SALE:036586:477::919067116:N::N\r\nhistoryid=919067116\r\norderid=722189706\r\nAccepted=SALE:036586:477::919067116:N::N\r\nACCOUNTNUMBER=************7892\r\nACCTID=MPNAB\r\nauthcode=036586\r\nAuthNo=SALE:036586:477::919067116:N::N\r\nAVS_RESULT=N\r\nBATCHNUMBER=\r\nCVV2_RESULT=N\r\nDEBIT_TRACE_NUMBER=\r\nENTRYMETHOD=M\r\nhistoryid=919067116\r\nMERCHANT_DBA_ADDR=11121 Willows Road NE\r\nMERCHANT_DBA_CITY=Redmond\r\nMERCHANT_DBA_NAME=Merchant Partners\r\nMERCHANT_DBA_PHONE=4254979909\r\nMERCHANT_DBA_STATE=WA\r\nMERCHANTID=542929804946788\r\nMERCHANTORDERNUMBER=67f4f20082e79684f036f25dafe96304\r\norderid=722189706\r\nPAYTYPE=Visa\r\nPRODUCT_DESCRIPTION=\r\nReason=\r\nRECEIPT_FOOTER=Thank You\r\nrecurid=0\r\nrefcode=919067116-036586\r\nresult=1\r\nSEQUENCE_NUMBER=370609730\r\nStatus=Accepted\r\nSUBID=SPREE\r\nSYSTEMAUDITTRACENUMBER=477\r\nTERMINALID=160551\r\nTRANSGUID=d5701d57-9147-4ded-b596-6805581f081c:266\r\ntransid=370609730\r\ntransresult=APPROVED\r\nVISATRANSACTIONID=088044000036586\r\n" +read 962 bytes +Conn close + EOS + end + + def post_scrubbed + <<-EOS +opening connection to trans.worldpay.us:443... +opened +starting SSL for trans.worldpay.us:443... +SSL established +<- "POST /cgi-bin/process.cgi HTTP/1.1\r\nContent-Type: application/x-www-form-urlencoded\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nAccept: */*\r\nUser-Agent: Ruby\r\nConnection: close\r\nHost: trans.worldpay.us\r\nContent-Length: 425\r\n\r\n" +<- "acctid=MPNAB&action=ns_quicksale_cc&amount=1.00&ccname=Longbob+Longsen&ccnum=[FILTERED]&ci_billaddr1=456+My+Street&ci_billaddr2=Apt+1&ci_billcity=Ottawa&ci_billcountry=CA&ci_billstate=ON&ci_billzip=K1C2N6&ci_companyname=Widgets+Inc&ci_email=&ci_ipaddress=&ci_phone=%28555%29555-5555&currencycode=USD&cvv2=[FILTERED]&expmon=09&expyear=2019&merchantordernumber=67f4f20082e79684f036f25dafe96304&merchantpin=[FILTERED]&subid=SPREE" +-> "HTTP/1.1 200 OK\r\n" +-> "Date: Tue, 13 Feb 2018 19:28:27 GMT\r\n" +-> "Server: Apache\r\n" +-> "X-Frame-Options: SAMEORIGIN\r\n" +-> "Content-Type: text/html;charset=ISO-8859-1\r\n" +-> "Content-Length: 962\r\n" +-> "Connection: close\r\n" +-> "\r\n" +reading 962 bytes... +-> "<html><body><plaintext>\r\nAccepted=SALE:036586:477::919067116:N::N\r\nhistoryid=919067116\r\norderid=722189706\r\nAccepted=SALE:036586:477::919067116:N::N\r\nACCOUNTNUMBER=************7892\r\nACCTID=MPNAB\r\nauthcode=036586\r\nAuthNo=SALE:036586:477::919067116:N::N\r\nAVS_RESULT=N\r\nBATCHNUMBER=\r\nCVV2_RESULT=N\r\nDEBIT_TRACE_NUMBER=\r\nENTRYMETHOD=M\r\nhistoryid=919067116\r\nMERCHANT_DBA_ADDR=11121 Willows Road NE\r\nMERCHANT_DBA_CITY=Redmond\r\nMERCHANT_DBA_NAME=Merchant Partners\r\nMERCHANT_DBA_PHONE=4254979909\r\nMERCHANT_DBA_STATE=WA\r\nMERCHANTID=542929804946788\r\nMERCHANTORDERNUMBER=67f4f20082e79684f036f25dafe96304\r\norderid=722189706\r\nPAYTYPE=Visa\r\nPRODUCT_DESCRIPTION=\r\nReason=\r\nRECEIPT_FOOTER=Thank You\r\nrecurid=0\r\nrefcode=919067116-036586\r\nresult=1\r\nSEQUENCE_NUMBER=370609730\r\nStatus=Accepted\r\nSUBID=SPREE\r\nSYSTEMAUDITTRACENUMBER=477\r\nTERMINALID=160551\r\nTRANSGUID=d5701d57-9147-4ded-b596-6805581f081c:266\r\ntransid=370609730\r\ntransresult=APPROVED\r\nVISATRANSACTIONID=088044000036586\r\n" +read 962 bytes +Conn close + EOS + end + + def pre_scrubbed_check + <<-EOS +opening connection to trans.worldpay.us:443... +opened +starting SSL for trans.worldpay.us:443... +SSL established +<- "POST /cgi-bin/process.cgi HTTP/1.1\r\nContent-Type: application/x-www-form-urlencoded\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nAccept: */*\r\nUser-Agent: Ruby\r\nConnection: close\r\nHost: trans.worldpay.us\r\nContent-Length: 412\r\n\r\n" +<- "acctid=MPNAB&action=ns_quicksale_check&amount=1.00&ci_billaddr1=456+My+Street&ci_billaddr2=Apt+1&ci_billcity=Ottawa&ci_billcountry=CA&ci_billstate=ON&ci_billzip=K1C2N6&ci_companyname=Widgets+Inc&ci_email=&ci_ipaddress=&ci_phone=%28555%29555-5555&ckaba=244183602&ckacct=15378535&ckaccttype=1&ckno=12345654321&currencycode=USD&merchantordernumber=5ec80ff8210dc9d24248ac2777d6b4f3&merchantpin=1234567890&subid=SPREE" +-> "HTTP/1.1 200 OK\r\n" +-> "Date: Tue, 13 Feb 2018 19:29:38 GMT\r\n" +-> "Server: Apache\r\n" +-> "X-Frame-Options: SAMEORIGIN\r\n" +-> "Content-Type: text/html;charset=ISO-8859-1\r\n" +-> "Content-Length: 414\r\n" +-> "Connection: close\r\n" +-> "\r\n" +reading 414 bytes... +-> "<html><body><plaintext>\r\nDeclined=DECLINED:1103180001:Invalid Bank:\r\nhistoryid=919060608\r\norderid=722196666\r\nACCOUNTNUMBER=****8535\r\nDeclined=DECLINED:1103180001:Invalid Bank:\r\nENTRYMETHOD=KEYED\r\nhistoryid=919060608\r\nMERCHANTORDERNUMBER=5ec80ff8210dc9d24248ac2777d6b4f3\r\norderid=722196666\r\nPAYTYPE=Check\r\nrcode=1103180001\r\nReason=DECLINED:1103180001:Invalid Bank:\r\nrecurid=0\r\nresult=0\r\nStatus=Declined\r\ntransid=0\r\n" +read 414 bytes +Conn close + EOS + end + + def post_scrubbed_check + <<-EOS +opening connection to trans.worldpay.us:443... +opened +starting SSL for trans.worldpay.us:443... +SSL established +<- "POST /cgi-bin/process.cgi HTTP/1.1\r\nContent-Type: application/x-www-form-urlencoded\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nAccept: */*\r\nUser-Agent: Ruby\r\nConnection: close\r\nHost: trans.worldpay.us\r\nContent-Length: 412\r\n\r\n" +<- "acctid=MPNAB&action=ns_quicksale_check&amount=1.00&ci_billaddr1=456+My+Street&ci_billaddr2=Apt+1&ci_billcity=Ottawa&ci_billcountry=CA&ci_billstate=ON&ci_billzip=K1C2N6&ci_companyname=Widgets+Inc&ci_email=&ci_ipaddress=&ci_phone=%28555%29555-5555&ckaba=244183602&ckacct=[FILTERED]&ckaccttype=1&ckno=12345654321&currencycode=USD&merchantordernumber=5ec80ff8210dc9d24248ac2777d6b4f3&merchantpin=[FILTERED]&subid=SPREE" +-> "HTTP/1.1 200 OK\r\n" +-> "Date: Tue, 13 Feb 2018 19:29:38 GMT\r\n" +-> "Server: Apache\r\n" +-> "X-Frame-Options: SAMEORIGIN\r\n" +-> "Content-Type: text/html;charset=ISO-8859-1\r\n" +-> "Content-Length: 414\r\n" +-> "Connection: close\r\n" +-> "\r\n" +reading 414 bytes... +-> "<html><body><plaintext>\r\nDeclined=DECLINED:1103180001:Invalid Bank:\r\nhistoryid=919060608\r\norderid=722196666\r\nACCOUNTNUMBER=****8535\r\nDeclined=DECLINED:1103180001:Invalid Bank:\r\nENTRYMETHOD=KEYED\r\nhistoryid=919060608\r\nMERCHANTORDERNUMBER=5ec80ff8210dc9d24248ac2777d6b4f3\r\norderid=722196666\r\nPAYTYPE=Check\r\nrcode=1103180001\r\nReason=DECLINED:1103180001:Invalid Bank:\r\nrecurid=0\r\nresult=0\r\nStatus=Declined\r\ntransid=0\r\n" +read 414 bytes +Conn close + EOS + end end diff --git a/test/unit/multi_response_test.rb b/test/unit/multi_response_test.rb index a07de6fa243..a60062d0003 100644 --- a/test/unit/multi_response_test.rb +++ b/test/unit/multi_response_test.rb @@ -9,21 +9,21 @@ def test_initial_state end def test_processes_sub_requests - r1 = Response.new(true, "1", {}) - r2 = Response.new(true, "2", {}) + r1 = Response.new(true, '1', {}) + r2 = Response.new(true, '2', {}) m = MultiResponse.run do |r| - r.process{r1} - r.process{r2} + r.process { r1 } + r.process { r2 } end assert_equal [r1, r2], m.responses end def test_run_convenience_method - r1 = Response.new(true, "1", {}) - r2 = Response.new(true, "2", {}) + r1 = Response.new(true, '1', {}) + r2 = Response.new(true, '2', {}) m = MultiResponse.run do |r| - r.process{r1} - r.process{r2} + r.process { r1 } + r.process { r2 } end assert_equal [r1, r2], m.responses end @@ -33,43 +33,43 @@ def test_proxies_last_request r1 = Response.new( true, - "1", - {"one" => 1}, + '1', + {'one' => 1}, :test => true, - :authorization => "auth1", - :avs_result => {:code => "AVS1"}, - :cvv_result => "CVV1", + :authorization => 'auth1', + :avs_result => {:code => 'AVS1'}, + :cvv_result => 'CVV1', :error_code => :card_declined, :fraud_review => true ) - m.process{r1} - assert_equal({"one" => 1}, m.params) - assert_equal "1", m.message + m.process { r1 } + assert_equal({'one' => 1}, m.params) + assert_equal '1', m.message assert m.test - assert_equal "auth1", m.authorization - assert_equal "AVS1", m.avs_result["code"] - assert_equal "CVV1", m.cvv_result["code"] + assert_equal 'auth1', m.authorization + assert_equal 'AVS1', m.avs_result['code'] + assert_equal 'CVV1', m.cvv_result['code'] assert_equal :card_declined, m.error_code assert m.test? assert m.fraud_review? r2 = Response.new( true, - "2", - {"two" => 2}, + '2', + {'two' => 2}, :test => false, - :authorization => "auth2", - :avs_result => {:code => "AVS2"}, - :cvv_result => "CVV2", + :authorization => 'auth2', + :avs_result => {:code => 'AVS2'}, + :cvv_result => 'CVV2', :fraud_review => false ) - m.process{r2} - assert_equal({"two" => 2}, m.params) - assert_equal "2", m.message + m.process { r2 } + assert_equal({'two' => 2}, m.params) + assert_equal '2', m.message assert !m.test - assert_equal "auth2", m.authorization - assert_equal "AVS2", m.avs_result["code"] - assert_equal "CVV2", m.cvv_result["code"] + assert_equal 'auth2', m.authorization + assert_equal 'AVS2', m.avs_result['code'] + assert_equal 'CVV2', m.cvv_result['code'] assert !m.test? assert !m.fraud_review? end @@ -79,41 +79,41 @@ def test_proxies_first_request_if_marked r1 = Response.new( true, - "1", - {"one" => 1}, + '1', + {'one' => 1}, :test => true, - :authorization => "auth1", - :avs_result => {:code => "AVS1"}, - :cvv_result => "CVV1", + :authorization => 'auth1', + :avs_result => {:code => 'AVS1'}, + :cvv_result => 'CVV1', :fraud_review => true ) - m.process{r1} - assert_equal({"one" => 1}, m.params) - assert_equal "1", m.message + m.process { r1 } + assert_equal({'one' => 1}, m.params) + assert_equal '1', m.message assert m.test - assert_equal "auth1", m.authorization - assert_equal "AVS1", m.avs_result["code"] - assert_equal "CVV1", m.cvv_result["code"] + assert_equal 'auth1', m.authorization + assert_equal 'AVS1', m.avs_result['code'] + assert_equal 'CVV1', m.cvv_result['code'] assert m.test? assert m.fraud_review? r2 = Response.new( true, - "2", - {"two" => 2}, + '2', + {'two' => 2}, :test => false, - :authorization => "auth2", - :avs_result => {:code => "AVS2"}, - :cvv_result => "CVV2", + :authorization => 'auth2', + :avs_result => {:code => 'AVS2'}, + :cvv_result => 'CVV2', :fraud_review => false ) - m.process{r2} - assert_equal({"one" => 1}, m.params) - assert_equal "1", m.message + m.process { r2 } + assert_equal({'one' => 1}, m.params) + assert_equal '1', m.message assert m.test - assert_equal "auth1", m.authorization - assert_equal "AVS1", m.avs_result["code"] - assert_equal "CVV1", m.cvv_result["code"] + assert_equal 'auth1', m.authorization + assert_equal 'AVS1', m.avs_result['code'] + assert_equal 'CVV1', m.cvv_result['code'] assert m.test? assert m.fraud_review? end @@ -121,38 +121,38 @@ def test_proxies_first_request_if_marked def test_primary_response_always_returns_the_last_response_on_failure m = MultiResponse.new(:use_first_response) - r1 = Response.new(true, "1", {}, {}) - r2 = Response.new(false, "2", {}, {}) - r3 = Response.new(false, "3", {}, {}) - m.process{r1} - m.process{r2} - m.process{r3} + r1 = Response.new(true, '1', {}, {}) + r2 = Response.new(false, '2', {}, {}) + r3 = Response.new(false, '3', {}, {}) + m.process { r1 } + m.process { r2 } + m.process { r3 } assert_equal r2, m.primary_response assert_equal '2', m.message end def test_stops_processing_upon_failure - r1 = Response.new(false, "1", {}) - r2 = Response.new(true, "2", {}) + r1 = Response.new(false, '1', {}) + r2 = Response.new(true, '2', {}) m = MultiResponse.run do |r| - r.process{r1} - r.process{r2} + r.process { r1 } + r.process { r2 } end assert !m.success? assert_equal [r1], m.responses end def test_merges_sub_multi_responses - r1 = Response.new(true, "1", {}) - r2 = Response.new(true, "2", {}) - r3 = Response.new(true, "3", {}) + r1 = Response.new(true, '1', {}) + r2 = Response.new(true, '2', {}) + r3 = Response.new(true, '3', {}) m1 = MultiResponse.run do |r| - r.process{r1} - r.process{r2} + r.process { r1 } + r.process { r2 } end m = MultiResponse.run do |r| - r.process{m1} - r.process{r3} + r.process { m1 } + r.process { r3 } end assert_equal [r1, r2, r3], m.responses end @@ -160,14 +160,14 @@ def test_merges_sub_multi_responses def test_handles_ignores_optional_request_result m = MultiResponse.new - r1 = Response.new(true, "1") - m.process{r1} - assert_equal "1", m.message + r1 = Response.new(true, '1') + m.process { r1 } + assert_equal '1', m.message assert_equal [r1], m.responses - r2 = Response.new(false, "2") - m.process(:ignore_result){r2} - assert_equal "1", m.message + r2 = Response.new(false, '2') + m.process(:ignore_result) { r2 } + assert_equal '1', m.message assert_equal [r1, r2], m.responses assert m.success? diff --git a/test/unit/network_connection_retries_test.rb b/test/unit/network_connection_retries_test.rb index 44afcf0fb2d..49ce4b3d8e6 100644 --- a/test/unit/network_connection_retries_test.rb +++ b/test/unit/network_connection_retries_test.rb @@ -19,7 +19,7 @@ def test_eoferror_raises_correctly end end - assert_equal "The remote server dropped the connection", raised.message + assert_equal 'The remote server dropped the connection', raised.message end def test_econnreset_raises_correctly @@ -28,14 +28,11 @@ def test_econnreset_raises_correctly raise Errno::ECONNRESET end end - assert_equal "The remote server reset the connection", raised.message + assert_equal 'The remote server reset the connection', raised.message end def test_timeout_errors_raise_correctly - exceptions = [Timeout::Error, Errno::ETIMEDOUT] - if RUBY_VERSION >= '2.0.0' - exceptions += [Net::ReadTimeout, Net::OpenTimeout] - end + exceptions = [Timeout::Error, Errno::ETIMEDOUT, Net::ReadTimeout, Net::OpenTimeout] exceptions.each do |exception| raised = assert_raises(ActiveMerchant::ConnectionError) do @@ -43,7 +40,7 @@ def test_timeout_errors_raise_correctly raise exception end end - assert_equal "The connection to the remote server timed out", raised.message + assert_equal 'The connection to the remote server timed out', raised.message end end @@ -53,14 +50,12 @@ def test_socket_error_raises_correctly raise SocketError end end - assert_equal "The connection to the remote server could not be established", raised.message + assert_equal 'The connection to the remote server could not be established', raised.message end def test_ssl_errors_raise_correctly - exceptions = [OpenSSL::SSL::SSLError] - if RUBY_VERSION >= '2.1.0' - exceptions += [OpenSSL::SSL::SSLErrorWaitWritable, OpenSSL::SSL::SSLErrorWaitReadable] - end + exceptions = [OpenSSL::SSL::SSLError, OpenSSL::SSL::SSLErrorWaitWritable, + OpenSSL::SSL::SSLErrorWaitReadable] exceptions.each do |exception| raised = assert_raises(ActiveMerchant::ConnectionError) do @@ -68,11 +63,10 @@ def test_ssl_errors_raise_correctly raise exception end end - assert_equal "The SSL connection to the remote server could not be established", raised.message + assert_equal 'The SSL connection to the remote server could not be established', raised.message end end - def test_invalid_response_error assert_raises(ActiveMerchant::InvalidResponseError) do retry_exceptions do @@ -138,9 +132,12 @@ def test_failure_then_success_logs_success end def test_mixture_of_failures_with_retry_safe_enabled - @requester.expects(:post).times(3).raises(Errno::ECONNRESET). - raises(Errno::ECONNREFUSED). - raises(EOFError) + @requester. + expects(:post). + times(3). + raises(Errno::ECONNRESET). + raises(Errno::ECONNREFUSED). + raises(EOFError) assert_raises(ActiveMerchant::ConnectionError) do retry_exceptions :retry_safe => true do @@ -174,7 +171,7 @@ def test_failure_with_additional_exceptions_specified @requester.expects(:post).raises(MyNewError) assert_raises(ActiveMerchant::ConnectionError) do - retry_exceptions :connection_exceptions => {MyNewError => "my message"} do + retry_exceptions :connection_exceptions => {MyNewError => 'my message'} do @requester.post end end diff --git a/test/unit/network_tokenization_credit_card_test.rb b/test/unit/network_tokenization_credit_card_test.rb index 30a6ec95557..a5ac80e822d 100644 --- a/test/unit/network_tokenization_credit_card_test.rb +++ b/test/unit/network_tokenization_credit_card_test.rb @@ -4,9 +4,9 @@ class NetworkTokenizationCreditCardTest < Test::Unit::TestCase def setup @tokenized_card = ActiveMerchant::Billing::NetworkTokenizationCreditCard.new({ - number: "4242424242424242", :brand => "visa", + number: '4242424242424242', :brand => 'visa', month: default_expiration_date.month, year: default_expiration_date.year, - payment_cryptogram: "EHuWW9PiBkWvqE5juRwDzAUFBAk=", eci: "05" + payment_cryptogram: 'EHuWW9PiBkWvqE5juRwDzAUFBAk=', eci: '05' }) @tokenized_apple_pay_card = ActiveMerchant::Billing::NetworkTokenizationCreditCard.new({ source: :apple_pay @@ -14,30 +14,35 @@ def setup @tokenized_android_pay_card = ActiveMerchant::Billing::NetworkTokenizationCreditCard.new({ source: :android_pay }) + @tokenized_google_pay_card = ActiveMerchant::Billing::NetworkTokenizationCreditCard.new({ + source: :google_pay + }) @tokenized_bogus_pay_card = ActiveMerchant::Billing::NetworkTokenizationCreditCard.new({ source: :bogus_pay }) end def test_type - assert_equal "network_tokenization", @tokenized_card.type + assert_equal 'network_tokenization', @tokenized_card.type end def test_credit_card? assert @tokenized_card.credit_card? assert @tokenized_apple_pay_card.credit_card? assert @tokenized_android_pay_card.credit_card? + assert @tokenized_google_pay_card.credit_card? assert @tokenized_bogus_pay_card.credit_card? end def test_optional_validations - assert_valid @tokenized_card, "Network tokenization card should not require name or verification value" + assert_valid @tokenized_card, 'Network tokenization card should not require name or verification value' end def test_source assert_equal @tokenized_card.source, :apple_pay assert_equal @tokenized_apple_pay_card.source, :apple_pay assert_equal @tokenized_android_pay_card.source, :android_pay + assert_equal @tokenized_google_pay_card.source, :google_pay assert_equal @tokenized_bogus_pay_card.source, :apple_pay end end diff --git a/test/unit/posts_data_test.rb b/test/unit/posts_data_test.rb index d41aecf4d85..960992cd0d4 100644 --- a/test/unit/posts_data_test.rb +++ b/test/unit/posts_data_test.rb @@ -42,6 +42,14 @@ def test_successful_raw_request assert_equal @ok, @gateway.raw_ssl_request(:post, @url, '') end + def test_raw_ssl_request_does_not_mutate_headers_argument + ActiveMerchant::Connection.any_instance.expects(:request).returns(@ok) + + headers = { 'Content-Type' => 'text/xml' }.freeze + @gateway.raw_ssl_request(:post, @url, '', headers) + assert_equal({ 'Content-Type' => 'text/xml' }, headers) + end + def test_setting_ssl_strict_outside_class_definition assert_equal SimpleTestGateway.ssl_strict, SubclassGateway.ssl_strict SimpleTestGateway.ssl_strict = !SimpleTestGateway.ssl_strict diff --git a/test/unit/rails_compatibility_test.rb b/test/unit/rails_compatibility_test.rb index 696c7c92bd5..addcb3ec701 100644 --- a/test/unit/rails_compatibility_test.rb +++ b/test/unit/rails_compatibility_test.rb @@ -1,14 +1,14 @@ -require "test_helper" +require 'test_helper' class RailsCompatibilityTest < Test::Unit::TestCase def test_should_be_able_to_access_errors_indifferently - cc = credit_card("4779139500118580", :first_name => "") + cc = credit_card('4779139500118580', :first_name => '') silence_deprecation_warnings do assert !cc.valid? assert cc.errors.on(:first_name) - assert cc.errors.on("first_name") - assert_equal "cannot be empty", cc.errors.on(:first_name) + assert cc.errors.on('first_name') + assert_equal 'cannot be empty', cc.errors.on(:first_name) end end end