Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Elavon: Update Stored Credential behavior #5031

Merged
merged 1 commit into from
Feb 28, 2024

Conversation

curiousepic
Copy link
Contributor

To satisfy new Elavon API requirements, including recurring_flag, approval_code for non-tokenized PMs, installment_count and _number, and situational par_value and association_token_data fields.

This also now allows Authorize transactions with a token/stored card.

Remote (Same 5 Failures on Master):
39 tests, 162 assertions, 5 failures, 0 errors, 0 pendings, 0 omissions, 0 notifications 87.1795% passed

Unit:
53 tests, 298 assertions, 0 failures, 0 errors, 0 pendings, 0 omissions, 0 notifications 100% passed

@curiousepic curiousepic requested a review from a team January 30, 2024 21:21
@@ -46,7 +46,7 @@ def purchase(money, payment_method, options = {})
if payment_method.is_a?(String)
add_token(xml, payment_method)
else
add_creditcard(xml, payment_method)
add_creditcard(xml, payment_method) unless options[:ssl_token]
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Elavon indicated that card number should not be added in addition to a token.

add_token(xml, payment_method)
else
add_creditcard(xml, payment_method) unless options[:ssl_token]
end
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adds support for Authorize transctions with a token. I'm not sure why this wasn't added originally.

return options[:entry_mode] if options[:entry_mode]
return 12 if options[:stored_credential]
return if payment_method.is_a?(String)
return 12 if options.dig(:stored_credential, :reason_type) == 'unscheduled'
Copy link
Contributor Author

@curiousepic curiousepic Jan 30, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Elavon indicated that this should only be 12 for unscheduled reason types. It's also only needed for pass-in cards, not tokens. But we retain the ability to override it with an option param.

xml.ssl_oar_data oar_data unless oar_data.nil? || oar_data.empty?
xml.ssl_ps2000_data ps2000_data unless ps2000_data.nil? || ps2000_data.empty?
xml.ssl_oar_data oar_data unless oar_data.nil? || oar_data.empty? || payment_method.is_a?(String)
xml.ssl_ps2000_data ps2000_data unless ps2000_data.nil? || ps2000_data.empty? || payment_method.is_a?(String)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This prevents this data from being added for tokens, if it is also present.

xml.ssl_recurring_flag recurring_flag(options) if recurring_flag(options)
xml.ssl_approval_code options[:approval_code] if options[:approval_code] && !payment_method.is_a?(String)
xml.ssl_par_value options[:par_value] if options[:par_value]
xml.ssl_association_token_data options[:association_token_data] if options[:association_token_data]
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two new values that may be present on an initial transaction that should be passed in subsequent COF transactions.

def recurring_flag(options)
return unless reason = options.dig(:stored_credential, :reason_type)
return 1 if reason == 'recurring'
return 2 if reason == 'installment'
Copy link
Contributor Author

@curiousepic curiousepic Jan 30, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the primary new requirement for indicating recurring txns.

end

def merchant_initiated_unscheduled(options)
return options[:merchant_initiated_unscheduled] if options[:merchant_initiated_unscheduled]
return 'Y' if options.dig(:stored_credential, :initiator) == 'merchant' && options.dig(:stored_credential, :reason_type) == 'unscheduled' || options.dig(:stored_credential, :reason_type) == 'recurring'
return 'Y' if options.dig(:stored_credential, :initiator) == 'merchant' && options.dig(:stored_credential, :reason_type) == 'unscheduled'
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should only be present for reason type unscheduled, not recurring.

@almalee24
Copy link
Contributor

If you haven't already please don't forget to run bundle exec rubocop

@curiousepic
Copy link
Contributor Author

If you haven't already please don't forget to run bundle exec rubocop

Yes, fixing those now!

@curiousepic curiousepic force-pushed the ecs_3295_elavon_stored_cred_updates branch from 01a89b6 to 2cfc40f Compare January 30, 2024 22:02
@curiousepic
Copy link
Contributor Author

Updated with Rubocop fixes.

@curiousepic curiousepic force-pushed the ecs_3295_elavon_stored_cred_updates branch 3 times, most recently from f1730e3 to 952c79d Compare January 31, 2024 15:00
@curiousepic
Copy link
Contributor Author

Added tests for the combination of stored cred fields and using a manual token instead of a stored card authorization string.

end
xml.ssl_recurring_flag recurring_flag(options) if recurring_flag(options)
xml.ssl_approval_code options[:approval_code] if options[:approval_code] && !payment_method.is_a?(String) && !options[:ssl_token]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we make this into a variable so it can also be used above? Where we check for payment_method.is_a?(String) in ssl_oar_data and ssl_ps2000_data. Maybe the the new variable could be called used_payment_token

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good suggestion, I've done some refactoring of this method to clean it up in general which should help.

@curiousepic curiousepic force-pushed the ecs_3295_elavon_stored_cred_updates branch from 952c79d to 9fb65d7 Compare January 31, 2024 16:19
xml.ssl_par_value options[:par_value] if options[:par_value]
xml.ssl_association_token_data options[:association_token_data] if options[:association_token_data]

if !payment_method.is_a?(String) && !options[:ssl_token].present?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could this to be unless instead of if

Copy link
Contributor

@almalee24 almalee24 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks great! Thanks for all the hard work you put in!

@curiousepic curiousepic force-pushed the ecs_3295_elavon_stored_cred_updates branch from 9fb65d7 to 0079e93 Compare January 31, 2024 22:13
@curiousepic curiousepic force-pushed the ecs_3295_elavon_stored_cred_updates branch from 0079e93 to 645d5b3 Compare February 9, 2024 20:09
@curiousepic
Copy link
Contributor Author

curiousepic commented Feb 9, 2024

@almalee24 Made some changes after feedback from Elavon - notably to make sure we don't send cvv on non-initial stored cred txns, and ensuring a blank ps2000 data field was not passed in some situations, as well as being able to invoke real respones for the new par_value and association_token_data fields.

@@ -234,8 +239,11 @@ def add_token(xml, token)
xml.ssl_token token
Copy link
Contributor

@almalee24 almalee24 Feb 12, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We probably need to update this method to either pass down options to grab token from there if payment is a credit card but has options[:ssl_token] or to return unless token.is_a?(String)

Copy link
Contributor Author

@curiousepic curiousepic Feb 13, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch... I thought I'd added enough test variations to cover that situation 😓

Oh wait, I think it didn't catch them because we have another place where we're adding ssl_token in add_auth_purchase_params 😅
I'll see if I can unify those cases to prevent duplication and confusion.

@curiousepic curiousepic force-pushed the ecs_3295_elavon_stored_cred_updates branch 2 times, most recently from ac0a73a to 1954c69 Compare February 13, 2024 17:26
@curiousepic
Copy link
Contributor Author

Refactored all instances of adding card or token into a single helper method (update action needs both so adds them manually). Would appreciate another look at the diff.

@@ -352,30 +353,48 @@ def add_line_items(xml, level_3_data)
}
end

def add_stored_credential(xml, options)
def add_stored_credential(xml, payment_method, options)
return unless options[:stored_credential]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not necessary since you already did if options[:stored_credential] when calling the method

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

True, though I'd lean toward overeager guard clauses than less; if it gets used in the future it's already there.

@almalee24
Copy link
Contributor

Looks good to me!

To satisfy new Elavon API requirements, including recurring_flag,
approval_code for non-tokenized PMs, installment_count and _number, and
situational par_value and association_token_data fields.

This also now allows Authorize transactions with a token/stored card.

Remote (Same 5 Failures on Master):
39 tests, 162 assertions, 5 failures, 0 errors, 0 pendings, 0 omissions, 0 notifications
87.1795% passed

Unit:
53 tests, 298 assertions, 0 failures, 0 errors, 0 pendings, 0 omissions, 0 notifications
100% passed
@bradbroge bradbroge force-pushed the ecs_3295_elavon_stored_cred_updates branch from 1954c69 to f39602f Compare February 28, 2024 18:56
@bradbroge bradbroge merged commit ebcb303 into master Feb 28, 2024
0 of 5 checks passed
@bradbroge bradbroge deleted the ecs_3295_elavon_stored_cred_updates branch February 28, 2024 20:01
@almalee24 almalee24 restored the ecs_3295_elavon_stored_cred_updates branch July 10, 2024 18:42
@almalee24 almalee24 deleted the ecs_3295_elavon_stored_cred_updates branch July 10, 2024 18:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants