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

Add gift support #7

Merged
merged 61 commits into from
Mar 31, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
61 commits
Select commit Hold shift + click to select a range
0cb1d75
Merge pull request #3 from slogsdon/add-refund-reversal-support
MSmedal Feb 13, 2020
2c5054c
decline-messages-work
MSmedal Feb 17, 2020
a6eab21
change-decline-handling
MSmedal Feb 17, 2020
b571f89
++ default decline methods
MSmedal Mar 10, 2020
c34af2b
Merge pull request #4 from slogsdon/show-decline-reason
MSmedal Mar 10, 2020
c38c04c
gc_fields_show;gc_sends_to_backend;minor_fixes
MSmedal Apr 18, 2020
01381d4
solution-pure_jank
MSmedal May 23, 2020
16b9d3d
refactoring-decreasing_the_jank
MSmedal May 26, 2020
de602f4
refactoring-decreasing_the_jank_2
MSmedal May 27, 2020
82c7b97
handle_GC_declines_at_checkout
MSmedal Jun 12, 2020
3f12e70
refactoring-decreasing_the_jank_3
MSmedal Jun 13, 2020
7e8382f
composer require SDK v2.1
MSmedal Nov 23, 2020
47d7e56
HMS works
MSmedal Nov 24, 2020
ba9d816
update Heartland details
MSmedal Dec 7, 2020
e116f92
support SDK 2.1^
MSmedal Dec 14, 2020
5637d55
fix partial gift payments
MSmedal Dec 14, 2020
e7d09bb
1-7-21 notes
MSmedal Jan 7, 2021
a067288
1-7-21
MSmedal Jan 7, 2021
3f77a8e
1-7-21
MSmedal Jan 7, 2021
f4a33d2
1-8-21
MSmedal Jan 8, 2021
0e1892d
transit: correct checkout issue when getting cvv
slogsdon Jan 8, 2021
eb74d68
prevent fields from being rendered more than once
slogsdon Jan 8, 2021
87fa843
ensure submit is shown when needed on first render
slogsdon Jan 8, 2021
33e148a
only save token when needed
slogsdon Jan 8, 2021
0ecc936
TransIT is ready
MSmedal Jan 11, 2021
7b6f88d
fix TransIT admin refunds
MSmedal Jan 12, 2021
bdbf634
added Transit devID
MSmedal Jan 25, 2021
68bf03a
auto-reversal on partial-auth
MSmedal Mar 8, 2021
c05a641
fix MUT w/TransIT
MSmedal Mar 8, 2021
7804678
correction to token saving
MSmedal Mar 8, 2021
3ac8a11
++ order note for admin refund
MSmedal Mar 12, 2021
15afea2
improve admin refund notes
MSmedal Mar 12, 2021
46a5915
++ capture auth support
MSmedal Mar 15, 2021
21fdb9a
++ todo notes
MSmedal Mar 15, 2021
f359d8b
handle capture auth errors
MSmedal Mar 16, 2021
c9b12e2
send stored cred info on transactions
MSmedal Mar 16, 2021
b1e3a1c
fix add_payment_method() error handling w/Transit
MSmedal Mar 17, 2021
6328517
supplement to: send stored cred info on trans
MSmedal Mar 17, 2021
762b443
" "
MSmedal Mar 17, 2021
e8bd324
++ card type handling comment
MSmedal Mar 17, 2021
15c2587
TR-92: add GP-API gateway
apetrovici Mar 24, 2021
451e122
TR-92: add access token request
apetrovici Mar 24, 2021
c5181f8
TR-92: check for invalid key
apetrovici Mar 24, 2021
29dc4b0
TR-92: add more validation errors
apetrovici Mar 24, 2021
89f2711
TR-92: update sdk client
apetrovici Mar 24, 2021
4d98c61
TR-92: check for invalid key
apetrovici Mar 24, 2021
2a4fca8
TR-92: set payment complete only for paid orders
apetrovici Mar 24, 2021
6560bf2
TR-92: fix spacing
apetrovici Mar 24, 2021
976917f
TR-92: fix spacing
apetrovici Mar 24, 2021
8a3cf36
TR-92: remove unused spaces
apetrovici Mar 25, 2021
c154810
TR-92: change envs to constants
apetrovici Mar 25, 2021
f84a6e0
TR-92: map response code
apetrovici Mar 25, 2021
b48652e
TR-92: revert order status for authorize
apetrovici Mar 25, 2021
0ce2294
TR-92: update support email
apetrovici Mar 25, 2021
c5222d0
Merge pull request #5 from apetrovici/feature/tr-92-gpapi-integration
slogsdon Mar 29, 2021
c7c6fa3
use TSEP device ID on front-end
MSmedal Mar 29, 2021
3f1a82c
display TSEP error alert
MSmedal Mar 29, 2021
27b72f0
cleanup
MSmedal Mar 29, 2021
c505fd1
Merge branch 'add-gift-support' of https://github.com/slogsdon/global…
MSmedal Mar 30, 2021
cd8bffe
fix TSEP on TransIT
MSmedal Mar 30, 2021
3fefa10
clean
MSmedal Mar 31, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 75 additions & 0 deletions assets/frontend/HeartlandGiftFields.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
<?php

defined( 'ABSPATH' ) || exit;

?>

<fieldset>
<div class="securesubmit-content gift-card-content">
<div class="form-row form-row-wide" id="gift-card-row">
<label id="gift-card-label" for="gift-card-number"><?php _e('Use a gift card', 'wc_securesubmit'); ?></label>
<div id="gift-card-input">
<input type="tel" placeholder="Gift card" id="gift-card-number" value="" class="input-text">
<input type="tel" placeholder="PIN" id="gift-card-pin" value="" class="input-text">
<p id="gift-card-error"></p>
<p id="gift-card-success"></p>
</div>
<button id="apply-gift-card" class="button"><?php _e('Apply', 'wc_securesubmit'); ?></button>

<?php
$html = '<script data-cfasync="false" type="text/javascript">';
$html .= 'if( typeof ajaxurl === "undefined") { ';
$html .= 'var ajaxurl = "' . admin_url('admin-ajax.php') . '";';
$html .= '}';
$html .= '</script>';

echo $html;
?>

<script data-cfasync="false">

jQuery("#apply-gift-card").on('click', function (event) {
event.preventDefault();
applyGiftCard();
});

function applyGiftCard () {
var httpRequest = new XMLHttpRequest();

var gift_card_number = document.getElementById('gift-card-number').value;
var gift_card_pin = document.getElementById('gift-card-pin').value;

var post_string = 'action=use_gift_card&gift_card_number=' + gift_card_number + '&gift_card_pin=' + gift_card_pin;

httpRequest.open('POST', ajaxurl, false);
httpRequest.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
httpRequest.send(post_string);

jQuery('body').trigger('update_checkout');
};

jQuery(document).on( 'click', '.securesubmit-remove-gift-card', function (event) {
event.preventDefault();

var removedCardID = jQuery(this).attr('id');

jQuery.ajax({
url: ajaxurl,
type: "POST",
data: {
action: 'remove_gift_card',
securesubmit_card_id: removedCardID
}
}).done(function () {
jQuery('body').trigger('update_checkout');
jQuery(".button[name='update_cart']")
.prop("disabled", false)
.trigger("click");
});
});

</script>
</div>
<div class="clear"></div>
</div>
</fieldset>
27 changes: 27 additions & 0 deletions assets/frontend/css/heartland-gift-cards.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#gift-card-label {
display: table-row;
text-transform: uppercase;
font-size: 13px;
letter-spacing: 1px;
white-space: nowrap;
}

#gift-card-input {
display: table-cell;
position: relative;
width: 100%;
}

#apply-gift-card {
display: table-cell;
white-space: nowrap;
margin-left: 1em;
}

#gift-card-number {
width: 70%;
}

#gift-card-pin {
width: 26%;
}
111 changes: 90 additions & 21 deletions assets/frontend/js/globalpayments-secure-payment-fields.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,14 @@
* @param {object} options
*/
function GlobalPaymentsWooCommerce(options) {

/**
* Card form instance
*
* @type {any}
*/
this.cardForm = {};

/**
* Payment gateway id
*
Expand Down Expand Up @@ -101,6 +109,10 @@
* @returns
*/
renderPaymentFields: function () {
if ( $( '#' + this.id + '-' + this.fieldOptions['card-number-field'].class ).children().length > 0 ) {
return;
}

if ( ! GlobalPayments.configure ) {
console.log( 'Warning! Payment fields cannot be loaded' );
return;
Expand All @@ -114,18 +126,23 @@

GlobalPayments.configure( this.gatewayOptions );

var cardForm = GlobalPayments.ui.form(
this.cardForm = GlobalPayments.ui.form(
{
fields: this.getFieldConfiguration(),
styles: this.getStyleConfiguration()
}
);

cardForm.on( 'submit', 'click', this.blockOnSubmit.bind( this ) );
cardForm.on( 'token-success', this.handleResponse.bind( this ) );
cardForm.on( 'token-error', this.handleErrors.bind( this ) );
cardForm.on( 'error', this.handleErrors.bind( this ) );
this.cardForm.on( 'submit', 'click', this.blockOnSubmit.bind( this ) );
this.cardForm.on( 'token-success', this.handleResponse.bind( this ) );
this.cardForm.on( 'token-error', this.handleErrors.bind( this ) );
this.cardForm.on( 'error', this.handleErrors.bind( this ) );
GlobalPayments.on( 'error', this.handleErrors.bind( this ) );

// match the visibility of our payment form
this.cardForm.ready( function () {
this.toggleSubmitButtons();
} );
},

/**
Expand All @@ -138,7 +155,7 @@
el.id = this.getSubmitButtonTargetSelector().replace( '#', '' );
el.className = 'globalpayments ' + this.id + ' card-submit';
$( this.getPlaceOrderButtonSelector() ).after( el );
// match the visibilit of our payment form
// match the visibility of our payment form
this.toggleSubmitButtons();
},

Expand All @@ -150,7 +167,7 @@
*/
toggleSubmitButtons: function () {
var paymentGatewaySelected = $( this.getPaymentMethodRadioSelector() ).is( ':checked' );
var savedCardsAvailable = $( this.getStoredPaymentMethodsRadioSelector() ).length > 0;
var savedCardsAvailable = $( this.getStoredPaymentMethodsRadioSelector() + '[value!="new"]' ).length > 0;
var newSavedCardSelected = 'new' === $( this.getStoredPaymentMethodsRadioSelector() + ':checked' ).val();

var shouldBeVisible = (paymentGatewaySelected && ! savedCardsAvailable) || (savedCardsAvailable && newSavedCardSelected);
Expand Down Expand Up @@ -181,23 +198,38 @@
return;
}

var tokenResponseElement =
console.log(response);

var that = this;

this.cardForm.frames["card-cvv"].getCvv().then(function (c) {

/**
* Get hidden
* CVV; needed for TransIT gateway processing only
*
* @type {HTMLInputElement}
* @type {string}
*/
(document.getElementById( this.id + '-token_response' ));
if ( ! tokenResponseElement) {
tokenResponseElement = document.createElement( 'input' );
tokenResponseElement.id = this.id + '-token_response';
tokenResponseElement.name = this.id + '[token_response]';
tokenResponseElement.type = 'hidden';
this.getForm().appendChild( tokenResponseElement );
}
var cvvVal = c;

var tokenResponseElement =
/**
* Get hidden
*
* @type {HTMLInputElement}
*/
(document.getElementById( that.id + '-token_response' ));
if ( ! tokenResponseElement) {
tokenResponseElement = document.createElement( 'input' );
tokenResponseElement.id = that.id + '-token_response';
tokenResponseElement.name = that.id + '[token_response]';
tokenResponseElement.type = 'hidden';
that.getForm().appendChild( tokenResponseElement );
}

tokenResponseElement.value = JSON.stringify( response );
this.placeOrder();
response.details.cardSecurityCode = cvvVal;
tokenResponseElement.value = JSON.stringify( response );
that.placeOrder();
});
},

/**
Expand Down Expand Up @@ -283,6 +315,7 @@
* @returns
*/
handleErrors: function ( error ) {
this.resetValidationErrors();
this.unblockOnError();

if ( ! error.reasons ) {
Expand All @@ -297,6 +330,42 @@
case 'INVALID_CARD_NUMBER':
this.showValidationError( 'card-number' );
break;
case 'INVALID_CARD_EXPIRATION':
this.showValidationError( 'card-expiration' );
break;
case 'INVALID_CARD_SECURITY_CODE':
this.showValidationError( 'card-cvv' );
break;
case 'MANDATORY_DATA_MISSING':
var n = reason.message.search( "expiry_month" );
if ( n>=0 ) {
this.showValidationError( 'card-expiration' );
break;
}
var n = reason.message.search( "card.cvn.number" );
if ( n>=0 ) {
this.showValidationError( 'card-cvv' );
break;
}
case 'INVALID_REQUEST_DATA':
var n = reason.message.search( "number contains unexpected data" );
if ( n>=0 ) {
this.showValidationError( 'card-number' );
break;
}
var n = reason.message.search( "Luhn Check" );
if ( n>=0 ) {
this.showValidationError( 'card-number' );
break;
}
var n = reason.message.search( "cvv contains unexpected data" );
if ( n>=0 ) {
this.showValidationError( 'card-cvv' );
break;
}
case 'ERROR':
alert(reason.message);
break;
default:
break;
}
Expand Down Expand Up @@ -335,7 +404,7 @@
* @returns {object}
*/
getStyleConfiguration: function () {
var imageBase = 'https://api2.heartlandportico.com/securesubmit.v1/token/gp-1.3.0/assets';
var imageBase = 'https://api2.heartlandportico.com/securesubmit.v1/token/gp-1.6.0/assets';
return {
'html': {
'font-size': '62.5%'
Expand Down
7 changes: 2 additions & 5 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"type": "wordpress-plugin",
"require": {
"composer/installers": "^1.7",
"globalpayments/php-sdk": "dev-transIT-support"
"globalpayments/php-sdk": "^2.2.3"
},
"require-dev": {
"phpunit/phpunit": "^7.5",
Expand Down Expand Up @@ -34,8 +34,5 @@
"scripts-descriptions": {
"test": "Analyze code against the WordPress coding standards with PHP_CodeSniffer, and Run unit tests",
"fix": "Fix coding standards warnings/errors automatically with PHP Code Beautifier"
},
"repositories": [
{ "type": "git", "url": "[email protected]:devportal/php-sdk-v3" }
]
}
}
57 changes: 42 additions & 15 deletions src/Data/PaymentTokenData.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,13 @@ class PaymentTokenData {
*/
protected $request;

/**
* Used w/TransIT gateway
*
* @var string
*/
public static $tsepCvv = null;

/**
* Standardize getting single- and multi-use token data
*
Expand All @@ -47,33 +54,51 @@ public function get_token() {
return $token;
}

public function save_new_token( $multi_use_token ) {
public function save_new_token( $multi_use_token, $card_brand_txn_id = null ) {
$user_id = get_current_user_id();
$current_tokens = WC_Payment_Tokens::get_customer_tokens( $user_id, $this->request->gateway_id );

// a card number should only have a single token stored
foreach ( $current_tokens as $t ) {
if ( $t->get_token() === $multi_use_token ) {
$t->delete( true );
$token = $this->get_single_use_token();

if ( !empty( $token ) ) {
// a card number should only have a single token stored
foreach ( $current_tokens as $t ) {
if ( $t->get_token() === $multi_use_token ) {
$t->delete( true );
}
}
}

$token = $this->get_single_use_token();
$token->set_token( $multi_use_token );
$token->set_user_id( $user_id );
$token->set_gateway_id( $this->request->gateway_id );
$token->add_meta_data( self::KEY_SHOULD_SAVE_TOKEN, false, true );
$token->save();
if ( ! $token->get_meta( self::KEY_SHOULD_SAVE_TOKEN, true ) ) {
return;
}

$token->set_token( $multi_use_token );
$token->add_meta_data( 'card_brand_txn_id', $card_brand_txn_id );
$token->set_user_id( $user_id );
$token->set_gateway_id( $this->request->gateway_id );
$token->add_meta_data( self::KEY_SHOULD_SAVE_TOKEN, false, true );
$token->save();
}
}

public function get_single_use_token() {
if ( null === $this->request ) {
return null;
}

$gateway = $this->request->get_request_data( 'payment_method' );
$data = json_decode( stripslashes( $this->request->get_request_data( $gateway )['token_response'] ) );
$token = new WC_Payment_Token_CC();
$gateway = $this->request->get_request_data( 'payment_method' );
$request_data = $this->request->get_request_data( $gateway );
if ( ! isset( $request_data['token_response'] ) ) {
return null;
}

$data = json_decode( stripslashes( $request_data['token_response'] ) );

if ( empty( $data ) ) {
return null;
}

$token = new WC_Payment_Token_CC();

// phpcs:disable WordPress.NamingConventions.ValidVariableName
$token->add_meta_data( self::KEY_SHOULD_SAVE_TOKEN, $this->get_should_save_for_later(), true );
Expand All @@ -91,6 +116,8 @@ public function get_single_use_token() {
$token->set_expiry_month( $data->details->expiryMonth );
}

static::$tsepCvv = isset( $data->details->cardSecurityCode ) ? $data->details->cardSecurityCode : null;

if ( isset( $data->details->cardType ) && isset( $this->card_type_map[ $data->details->cardType ] ) ) {
$token->set_card_type( $this->card_type_map[ $data->details->cardType ] );
}
Expand Down
Loading