Skip to content

Commit

Permalink
BuildMaster release: 2.2.14
Browse files Browse the repository at this point in the history
  • Loading branch information
securesubmit-buildmaster committed May 11, 2021
1 parent 97ba46c commit f53bb9d
Show file tree
Hide file tree
Showing 17 changed files with 565 additions and 261 deletions.
14 changes: 13 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,18 @@

#### Enhancements:

- Set global merchant country configuration where required
- Update GP-API to 2021-03-22 version
- 3DS Status Mapping - Missed Mapping and Revise some mappings
- Update ACS simulator for 3DS2 to use values from initiate response for the form fields name required in the POST redirect
- Change position of fields: "source", "preference", "message_version" need to exist in the "three_ds" sub-object in the 3DS2 initiate call
- Remove "/detokenize" endpoint from GP-API
- Update GP-API production endpoint

## v2.2.13 (04/29/2021)

#### Enhancements:

- Set global merchant country configuration where required for GP-API
- Add GP-API 3DS new tests
- Add additional GP-API 3DS mappings
- Add additional GP-API transaction summary mappings
Expand All @@ -17,6 +28,7 @@
- Add GP-API actions report
- Add GP-API reauthorization functionality
- Add GP-API EBT new tests
- Add Exemption Optimization service for GP-ECOM

#### Bug Fixes:

Expand Down
2 changes: 1 addition & 1 deletion src/Entities/Enums/ServiceEndpoints.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,5 @@ class ServiceEndpoints extends Enum
const PROPAY_PRODUCTION = "https://epay.propay.com/API/PropayAPI.aspx";
const PROPAY_PRODUCTION_CANADIAN = "https://www.propaycanada.ca/API/PropayAPI.aspx";
const GP_API_TEST = "https://apis.sandbox.globalpay.com/ucp";
const GP_API_PRODUCTION = "https://apis.globalpay.com";
const GP_API_PRODUCTION = "https://apis.globalpay.com/ucp";
}
4 changes: 0 additions & 4 deletions src/Entities/GpApi/GpApiManagementRequestBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,6 @@ public function buildRequest(BaseBuilder $builder, $config)
{
$payload = [];
switch ($builder->transactionType) {
case TransactionType::DETOKENIZE:
$endpoint = GpApiRequest::PAYMENT_METHODS_ENDPOINT . '/' . $builder->paymentMethod->token . '/detokenize';
$verb = 'POST';
break;
case TransactionType::TOKEN_DELETE:
$endpoint = GpApiRequest::PAYMENT_METHODS_ENDPOINT . '/' . $builder->paymentMethod->token;
$verb = 'DELETE';
Expand Down
2 changes: 2 additions & 0 deletions src/Entities/GpApi/GpApiReportRequestBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,8 @@ public function buildRequest(BaseBuilder $builder, $config)
$builder->searchBuilder->fromTimeLastUpdated->format('Y-m-d') : null,
'to_time_last_updated' => !empty($builder->searchBuilder->toTimeLastUpdated) ?
$builder->searchBuilder->toTimeLastUpdated->format('Y-m-d') : null,
'id' => !empty($builder->searchBuilder->storedPaymentMethodId) ?
$builder->searchBuilder->storedPaymentMethodId : null
];
break;
case ReportType::STORED_PAYMENT_METHOD_DETAIL:
Expand Down
24 changes: 14 additions & 10 deletions src/Entities/GpApi/GpApiSecure3DRequestBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -98,9 +98,12 @@ private function verifyEnrolled(Secure3dBuilder $builder, GpApiConfig $config)
private function initiateAuthenticationData(Secure3dBuilder $builder, GpApiConfig $config)
{
$threeDS = [];
$threeDS['preference'] = $builder->challengeRequestIndicator;
$threeDS['three_ds'] = [
'source' => (string) $builder->authenticationSource,
'preference' => $builder->challengeRequestIndicator,
'message_version' => $builder->messageVersion
];
$threeDS['method_url_completion_status'] = (string) $builder->methodUrlCompletion;
$threeDS['source'] = (string) $builder->authenticationSource;
$threeDS['merchant_contact_url'] = 'https://enp4qhvjseljg.x.pipedream.net/'; // @TODO
$order = [
'time_created_reference' => !empty($builder->orderCreateDate) ?
Expand All @@ -118,7 +121,7 @@ private function initiateAuthenticationData(Secure3dBuilder $builder, GpApiConfi
'shipping_name_matches_cardholder_name' => $builder->getShippingNameMatchesCardHolderName(),
'preorder_indicator' => (string) $builder->preOrderIndicator,
'preorder_availability_date' => !empty($builder->preOrderAvailabilityDate) ?
$builder->preOrderAvailabilityDate->format('Y-m-d') : null,
(new \DateTime($builder->preOrderAvailabilityDate))->format('Y-m-d') : null,
'reorder_indicator' => (string) $builder->reorderIndicator,
'transaction_type' => $builder->orderTransactionType
];
Expand All @@ -140,12 +143,12 @@ private function initiateAuthenticationData(Secure3dBuilder $builder, GpApiConfi
'reference' => $builder->customerAccountId,
'account_age' => (string) $builder->accountAgeIndicator,
'account_creation_date' => !empty($builder->accountCreateDate) ?
$builder->accountCreateDate->format('Y-m-d') : null,
(new \DateTime($builder->accountCreateDate))->format('Y-m-d') : null,
'account_change_date' => !empty($builder->accountChangeDate) ?
$builder->accountChangeDate->format('Y-m-d') : null,
(new \DateTime($builder->accountChangeDate))->format('Y-m-d') : null,
'account_change_indicator' => (string) $builder->accountChangeIndicator,
'account_password_change_date' => !empty($builder->passwordChangeDate) ?
$builder->passwordChangeDate->format('Y-m-d') : null,
(new \DateTime($builder->passwordChangeDate))->format('Y-m-d') : null,
'account_password_change_indicator' => (string) $builder->passwordChangeIndicator,
'home_phone' => [
'country_code' => $builder->homeCountryCode,
Expand All @@ -156,23 +159,23 @@ private function initiateAuthenticationData(Secure3dBuilder $builder, GpApiConfi
'subscriber_number' => $builder->workNumber
],
'payment_account_creation_date' => !empty($builder->paymentAccountCreateDate) ?
$builder->paymentAccountCreateDate->format('Y-m-d') : null,
(new \DateTime($builder->paymentAccountCreateDate))->format('Y-m-d') : null,
'payment_account_age_indicator' => (string) $builder->paymentAgeIndicator,
'suspicious_account_activity' => $builder->previousSuspiciousActivity,
'purchases_last_6months_count' => $builder->numberOfPurchasesInLastSixMonths,
'transactions_last_24hours_count' => $builder->numberOfTransactionsInLast24Hours,
'transaction_last_year_count' => $builder->numberOfTransactionsInLastYear,
'provision_attempt_last_24hours_count' => $builder->numberOfAddCardAttemptsInLast24Hours,
'shipping_address_time_created_reference' => !empty($builder->shippingAddressCreateDate) ?
$builder->shippingAddressCreateDate->format('Y-m-d') : null,
(new \DateTime($builder->shippingAddressCreateDate))->format('Y-m-d') : null,
'shipping_address_creation_indicator' => (string) $builder->shippingAddressUsageIndicator
];

$threeDS['payer_prior_three_ds_authentication_data'] = [
'authentication_method' => (string) $builder->priorAuthenticationMethod,
'acs_transaction_reference' => $builder->priorAuthenticationTransactionId,
'authentication_timestamp' => !empty($builder->priorAuthenticationTimestamp) ?
$builder->priorAuthenticationTimestamp->format('Y-m-d\TH:i:s.u\Z') : null,
(new \DateTime($builder->priorAuthenticationTimestamp))->format('Y-m-d\TH:i:s.u\Z') : null,
'authentication_data' => $builder->priorAuthenticationData
];

Expand All @@ -185,9 +188,10 @@ private function initiateAuthenticationData(Secure3dBuilder $builder, GpApiConfi
$threeDS['payer_login_data'] = [
'authentication_data' => $builder->customerAuthenticationData,
'authentication_timestamp' => !empty($builder->customerAuthenticationTimestamp) ?
$builder->customerAuthenticationTimestamp->format('Y-m-d\TH:i:s.u\Z') : null,
(new \DateTime($builder->customerAuthenticationTimestamp))->format('Y-m-d\TH:i:s.u\Z') : null,
'authentication_type' => (string) $builder->customerAuthenticationMethod
];

if (!empty($builder->browserData)) {
$threeDS['browser_data'] = [
'accept_header' => $builder->browserData->acceptHeader,
Expand Down
3 changes: 2 additions & 1 deletion src/Entities/Reporting/SearchCriteria.php
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,8 @@ class SearchCriteria extends Enum
const CARDHOLDER_NAME = 'name';
const DEPOSIT_ID = 'depositId';
const FROM_TIME_LAST_UPDATED = 'fromTimeLastUpdated';
const TO_TIME_LAST_UPDATED = 'fromTimeLastUpdated';
const TO_TIME_LAST_UPDATED = 'toTimeLastUpdated';
const STORED_PAYMENT_METHOD_ID = 'storedPaymentMethodId';
const STORED_PAYMENT_METHOD_STATUS = 'storedPaymentMethodStatus';
const ACTION_TYPE = 'actionType';
const ACTION_ID = 'actionId';
Expand Down
25 changes: 17 additions & 8 deletions src/Gateways/GpApiConnector.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@

class GpApiConnector extends RestGateway implements IPaymentGateway, ISecure3dProvider
{
const GP_API_VERSION = '2020-12-22';
const GP_API_VERSION = '2021-03-22';
const IDEMPOTENCY_HEADER = 'x-gp-idempotency';
/**
* @var $gpApiConfig GpApiConfig
Expand Down Expand Up @@ -222,16 +222,25 @@ public function signIn()

$this->accessToken = $response->getToken();
$this->headers['Authorization'] = sprintf('Bearer %s', $this->accessToken);
if (empty($accessTokenInfo)) {
if (!$accessTokenInfo instanceof AccessTokenInfo) {
$accessTokenInfo = new AccessTokenInfo();
}
$accessTokenInfo->accessToken = $response->getToken();
$accessTokenInfo->dataAccountName = $response->getDataAccountName();
$accessTokenInfo->tokenizationAccountName = $response->getTokenizationAccountName();
$accessTokenInfo->transactionProcessingAccountName = $response->getTransactionProcessingAccountName();
$accessTokenInfo->disputeManagementAccountName = $response->getDisputeManagementAccountName();
if (empty($accessTokenInfo->accessToken)) {
$accessTokenInfo->accessToken = $response->getToken();
}
if (empty($accessTokenInfo->dataAccountName)) {
$accessTokenInfo->dataAccountName = $response->getDataAccountName();
}
if (empty($accessTokenInfo->tokenizationAccountName)) {
$accessTokenInfo->tokenizationAccountName = $response->getTokenizationAccountName();
}
if (empty($accessTokenInfo->transactionProcessingAccountName)) {
$accessTokenInfo->transactionProcessingAccountName = $response->getTransactionProcessingAccountName();
}
if (empty($accessTokenInfo->disputeManagementAccountName)) {
$accessTokenInfo->disputeManagementAccountName = $response->getDisputeManagementAccountName();
}
$this->gpApiConfig->accessTokenInfo = $accessTokenInfo;

}

/**
Expand Down
3 changes: 3 additions & 0 deletions src/Gateways/RestGateway.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ protected function doTransaction(
if (!in_array($response->statusCode, [200, 204])) {
$parsed = json_decode($response->rawResponse);
$error = isset($parsed->error) ? $parsed->error : $parsed;
if (empty($error)) {
throw new GatewayException(sprintf('Status Code: %s', $response->statusCode));
}
if ($this->isGpApi()) {
$gatewayException = new GatewayException(
sprintf(
Expand Down
6 changes: 5 additions & 1 deletion src/Services/HostedService.php
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,11 @@ public function parseResponse($response, $encoded = false)
$ref->transactionId = $transactionId;

$trans = new Transaction();
$trans->authorizedAmount = $response["AMOUNT"];

if (isset($response["AMOUNT"])) {
$trans->authorizedAmount = $response["AMOUNT"];
}

$trans->cvnResponseCode = $response["CVNRESULT"];
$trans->responseCode = $result;
$trans->responseMessage = $message;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -423,38 +423,6 @@ public function testCardTokenization()
$this->assertEquals('ACTIVE', $response->responseMessage);
}

public function testCardTokenizationThenPayingWithToken_UsageModeSingle()
{
// process an auto-capture authorization
$response = $this->card->tokenize()
->withPaymentMethodUsageMode(PaymentMethodUsageMode::SINGLE)
->execute();
$tokenId = $response->token;

$tokenizedCard = new CreditCardData();
$tokenizedCard->token = $tokenId;
$tokenizedCard->cardHolderName = "James Mason";

$detokenizedCard = $tokenizedCard->detokenize();
$this->assertNotNull($detokenizedCard);
$this->assertEquals($this->card->number, $detokenizedCard->cardNumber);
$this->assertEquals($this->card->cvn, $detokenizedCard->cvnResponseCode);

$response = $tokenizedCard->charge(10)
->withCurrency("USD")
->execute();

$this->assertNotNull($response);
$this->assertEquals('SUCCESS', $response->responseCode);
$this->assertEquals(TransactionStatus::CAPTURED, $response->responseMessage);

$detokenizedCard = $tokenizedCard->detokenize();

$this->assertNotNull($detokenizedCard);
$this->assertEquals($this->card->number, $detokenizedCard->cardNumber);
$this->assertNull($detokenizedCard->cvnResponseCode);
}

public function testCardTokenizationThenPayingWithToken_SingleToMultiUse()
{
// process an auto-capture authorization
Expand Down Expand Up @@ -611,35 +579,6 @@ public function testVerifyTokenizedPaymentMethod_WrongID()
}
}

public function testDetokenizePaymentMethodWithIdempotencyKey()
{
try {
// process an auto-capture authorization
$response = $this->card->tokenize()
->execute();

} catch (ApiException $e) {
$this->fail('Credit Card Tokenization failed ' . $e->getMessage());
}
$tokenizedCard = new CreditCardData();
$tokenizedCard->token = $response->token;

$detokenizedCard = (new ManagementBuilder(TransactionType::DETOKENIZE, $tokenizedCard))
->withIdempotencyKey($this->idempotencyKey)
->execute();

$this->assertNotNull($response);
$this->assertEquals($this->card->number, $detokenizedCard->cardNumber);
$this->assertEquals($this->card->expMonth, $detokenizedCard->cardExpMonth);

try {
$tokenizedCard->detokenize();
} catch (GatewayException $e) {
$this->assertEquals('40039', $e->responseCode);
$this->assertContains('Idempotency Key seen before', $e->getMessage());
}
}

public function testCreditVerifyx()
{
$response = $this->card->verify()
Expand All @@ -663,44 +602,6 @@ public function testCreditVerifyWithIdempotencyKey()
$this->assertEquals('VERIFIED', $response->responseMessage);
}

public function testCardTokenizationThenCardDetokenization()
{
try {
// process an auto-capture authorization
$response = $this->card->tokenize()
->execute();

} catch (ApiException $e) {
$this->fail('Credit Card Tokenization failed ' . $e->getMessage());
}

$tokenId = $response->token;

$tokenizedCard = new CreditCardData();
$tokenizedCard->token = $tokenId;

try {
$response = $tokenizedCard->detokenize();
} catch (ApiException $e) {
$this->fail('Credit Card detokenization failed ' . $e->getMessage());
}

$this->assertEquals('SUCCESS', $response->responseCode);
}

public function testCardDetokenization_WrongId()
{
$tokenizedCard = new CreditCardData();
$tokenizedCard->token = "PMT_" . GenerationUtils::getGuid();

try {
$tokenizedCard->detokenize();
} catch (ApiException $e) {
$this->assertEquals('40116', $e->responseCode);
$this->assertEquals('Status Code: RESOURCE_NOT_FOUND - payment_method ' . $tokenizedCard->token . ' not found at this location.', $e->getMessage());
}
}

public function testCardTokenizationThenDeletion()
{
// process an auto-capture authorization
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -511,9 +511,15 @@ public function testReauthorizedAnExistingTransaction()
$transaction = new Transaction();
$transaction->transactionId = $result->transactionId;

$response = $transaction->reauthorized($result->amount)->execute();
$reverse = $transaction->reverse()->execute();

$this->assertNotNull($reverse);
$this->assertEquals('SUCCESS', $reverse->responseCode);
$this->assertEquals(TransactionStatus::REVERSED, $reverse->responseMessage);

$response = $reverse->reauthorized()->execute();
$this->assertNotNull($response);
$this->assertEquals('SUCCESS', $response->responseCode);
$this->assertEquals(TransactionStatus::CAPTURED, $response->responseMessage);
$this->assertEquals(TransactionStatus::PREAUTHORIZED, $response->responseMessage);
}
}
10 changes: 6 additions & 4 deletions test/Integration/Gateways/GpApiConnector/GpApi3DS1Test.php
Original file line number Diff line number Diff line change
Expand Up @@ -264,13 +264,14 @@ public function testCardHolderEnrolled_PostResult()
$authClient->setGatewayProvider($this->gatewayProvider);
$authResponse = $authClient->authenticate_v1($secureEcom);
$this->assertTrue($authResponse->getStatus());
$this->assertNotEmpty($authResponse->getMerchantData());

$secureEcom = Secure3dService::getAuthenticationData()
->withServerTransactionId($secureEcom->serverTransactionId)
->withServerTransactionId($authResponse->getMerchantData())
->withPayerAuthenticationResponse($authResponse->getAuthResponse())
->execute();

$this->assertEquals('AUTHENTICATION_SUCCESSFUL', $secureEcom->status);
$this->assertEquals('SUCCESS_AUTHENTICATED', $secureEcom->status);
$this->assertTrue($secureEcom->challengeMandated);
$this->assertNotNull($secureEcom->issuerAcsUrl);
$this->assertNotNull($secureEcom->payerAuthenticationRequest);
Expand All @@ -295,14 +296,15 @@ public function testCardHolderEnrolled_PostResult_WithIdempotencyKey()
$authClient->setGatewayProvider($this->gatewayProvider);
$authResponse = $authClient->authenticate_v1($secureEcom);
$this->assertTrue($authResponse->getStatus());
$this->assertNotEmpty($authResponse->getMerchantData());

$secureEcom = Secure3dService::getAuthenticationData()
->withServerTransactionId($secureEcom->serverTransactionId)
->withServerTransactionId($authResponse->getMerchantData())
->withPayerAuthenticationResponse($authResponse->getAuthResponse())
->withIdempotencyKey($idempotencyKey)
->execute();

$this->assertEquals('AUTHENTICATION_SUCCESSFUL', $secureEcom->status);
$this->assertEquals('SUCCESS_AUTHENTICATED', $secureEcom->status);
$this->assertTrue($secureEcom->challengeMandated);
$this->assertNotNull($secureEcom->issuerAcsUrl);
$this->assertNotNull($secureEcom->payerAuthenticationRequest);
Expand Down
Loading

0 comments on commit f53bb9d

Please sign in to comment.