Skip to content

Commit

Permalink
HiPay: Scrub/Refund/Void (#4995)
Browse files Browse the repository at this point in the history
Ser-720
SER-721
----
Summary:
----
Adding to the HiPay gateway support for scrub, refund, and void.

HiPay allows partial capture and partial refunds, this commit include the amount to use it.

Tests
----
Remote Test:
Finished in 6.627757 seconds.
15 tests, 62 assertions, 0 failures, 0 errors, 0 pendings, 0 omissions, 0 notifications
100% passed

Unit Tests:
21 tests, 61 assertions, 0 failures, 0 errors, 0 pendings, 0 omissions, 0 notifications
100% passed

RuboCop:
787 files inspected, no offenses detected

Co-authored-by: Gustavo Sanmartin <gsanmartin@EN2010363.local>
  • Loading branch information
gasb150 and Gustavo Sanmartin committed Jan 4, 2024
1 parent 4fa780b commit e0ecef2
Show file tree
Hide file tree
Showing 4 changed files with 261 additions and 24 deletions.
1 change: 1 addition & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@
* SagePay: Add support for v4 [aenand] #4990
* Braintree: Send merchant_account_id when generating client token [almalee24] #4991
* CheckoutV2: Update reponse message for 3DS transactions [almalee24] #4975
* HiPay: Scrub/Refund/Void [gasb150] #4995

== Version 1.135.0 (August 24, 2023)
* PaymentExpress: Correct endpoints [steveh] #4827
Expand Down
39 changes: 31 additions & 8 deletions lib/active_merchant/billing/gateways/hi_pay.rb
Original file line number Diff line number Diff line change
Expand Up @@ -51,23 +51,42 @@ def authorize(money, payment_method, options = {})
end

def capture(money, authorization, options)
post = {}
post[:operation] = 'capture'
post[:currency] = (options[:currency] || currency(money))
transaction_ref, _card_token, _payment_product = authorization.split('|')
commit('capture', post, { transaction_reference: transaction_ref })
reference_operation(money, authorization, options.merge({ operation: 'capture' }))
end

def store(payment_method, options = {})
tokenize(payment_method, options.merge({ multiuse: '1' }))
end

def scrub(transcrip)
# code
def refund(money, authorization, options)
reference_operation(money, authorization, options.merge({ operation: 'refund' }))
end

def void(authorization, options)
reference_operation(nil, authorization, options.merge({ operation: 'cancel' }))
end

def supports_scrubbing?
true
end

def scrub(transcript)
transcript.
gsub(%r((Authorization: Basic )[\w =]+), '\1[FILTERED]').
gsub(%r((card_number=)\w+), '\1[FILTERED]\2').
gsub(%r((cvc=)\w+), '\1[FILTERED]\2')
end

private

def reference_operation(money, authorization, options)
post = {}
post[:operation] = options[:operation]
post[:currency] = (options[:currency] || currency(money))
post[:amount] = amount(money) if options[:operation] == 'refund' || options[:operation] == 'capture'
commit(options[:operation], post, { transaction_reference: authorization.split('|').first })
end

def add_product_data(post, options)
post[:orderid] = options[:order_id] if options[:order_id]
post[:description] = options[:description]
Expand Down Expand Up @@ -143,6 +162,10 @@ def success_from(action, response)
response['state'] == 'completed'
when 'capture'
response['status'] == '118' && response['message'] == 'Captured'
when 'refund'
response['status'] == '124' && response['message'] == 'Refund Requested'
when 'cancel'
response['status'] == '175' && response['message'] == 'Authorization Cancellation requested'
when 'store'
response.include? 'token'
else
Expand Down Expand Up @@ -170,7 +193,7 @@ def url(action, options = {})
case action
when 'store'
"#{token_url}/create"
when 'capture'
when 'capture', 'refund', 'cancel'
endpoint = "maintenance/transaction/#{options[:transaction_reference]}"
base_url(endpoint)
else
Expand Down
77 changes: 70 additions & 7 deletions test/remote/gateways/remote_hi_pay_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -70,13 +70,11 @@ def test_successful_purchase_with_billing_address
response = @gateway.purchase(@amount, @credit_card, @options.merge({ billing_address: @billing_address }))

assert_success response
assert_equal response.message, 'Captured'
end

def test_successful_capture
authorize_response = @gateway.authorize(@amount, @credit_card, @options)
assert_success authorize_response
assert_include 'Authorized', authorize_response.message

response = @gateway.capture(@amount, authorize_response.authorization, @options)
assert_success response
Expand All @@ -92,23 +90,88 @@ def test_successful_authorize_with_store

response = @gateway.authorize(@amount, store_response.authorization, @options)
assert_success response
assert_include 'Authorized', response.message
end

def test_successful_multiple_purchases_with_single_store
store_response = @gateway.store(@credit_card, @options)
assert_nil store_response.message
assert_success store_response
assert_not_empty store_response.authorization

response1 = @gateway.purchase(@amount, store_response.authorization, @options)
assert_success response1
assert_include 'Captured', response1.message

@options[:order_id] = "Sp_ORDER_2_#{SecureRandom.random_number(1000000000)}"

response2 = @gateway.purchase(@amount, store_response.authorization, @options)
assert_success response2
assert_include 'Captured', response2.message
end

def test_successful_refund
purchase_response = @gateway.purchase(@amount, @credit_card, @options)
assert_success purchase_response

response = @gateway.refund(@amount, purchase_response.authorization, @options)
assert_success response
assert_include 'Refund Requested', response.message
assert_include response.params['authorizedAmount'], '5.00'
assert_include response.params['capturedAmount'], '5.00'
assert_include response.params['refundedAmount'], '5.00'
end

def test_successful_partial_capture_refund
authorize_response = @gateway.authorize(@amount, @credit_card, @options)
assert_success authorize_response
assert_include authorize_response.params['authorizedAmount'], '5.00'
assert_include authorize_response.params['capturedAmount'], '0.00'
assert_equal authorize_response.params['refundedAmount'], '0.00'

capture_response = @gateway.capture(@amount - 100, authorize_response.authorization, @options)
assert_success capture_response
assert_equal authorize_response.authorization, capture_response.authorization
assert_include capture_response.params['authorizedAmount'], '5.00'
assert_include capture_response.params['capturedAmount'], '4.00'
assert_equal capture_response.params['refundedAmount'], '0.00'

response = @gateway.refund(@amount - 200, capture_response.authorization, @options)
assert_success response
assert_include response.params['authorizedAmount'], '5.00'
assert_include response.params['capturedAmount'], '4.00'
assert_include response.params['refundedAmount'], '3.00'
end

def test_failed_refund_because_auth_no_captured
authorize_response = @gateway.authorize(@amount, @credit_card, @options)
assert_success authorize_response

response = @gateway.refund(@amount, authorize_response.authorization, @options)
assert_failure response
assert_include 'Operation Not Permitted : transaction not captured', response.message
end

def test_successful_void
authorize_response = @gateway.authorize(@amount, @credit_card, @options)
assert_success authorize_response

response = @gateway.void(authorize_response.authorization, @options)
assert_success response
assert_include 'Authorization Cancellation requested', response.message
end

def test_failed_void_because_captured_transaction
purchase_response = @gateway.purchase(@amount, @credit_card, @options)
assert_success purchase_response

response = @gateway.void(purchase_response.authorization, @options)
assert_failure response
assert_include 'Action denied : Wrong transaction status', 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
Loading

0 comments on commit e0ecef2

Please sign in to comment.