diff --git a/CHANGELOG.md b/CHANGELOG.md
index 843fbe96..2521f25f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,6 +6,13 @@
## Latest version
#### Enhancements:
+- GP-API: Add PayLink service
+
+#### Bug Fixes:
+- GP-API: Fix mapping issue on APMs
+
+## v4.0.4 (07/14/2022)
+#### Enhancements:
- GP-API: Add mapping for some missing fields on response 3DS2 initiate step
- GP-ECOM: Add missing optional fields HPP_CUSTOMER_PHONENUMBER_HOME and HPP_CUSTOMER_PHONENUMBER_WORK
- Update Open Banking endpoints
diff --git a/metadata.xml b/metadata.xml
index 402d4051..57e2f7f7 100644
--- a/metadata.xml
+++ b/metadata.xml
@@ -1,3 +1,3 @@
- 4.0.4
+ 4.0.5
\ No newline at end of file
diff --git a/src/Builders/AuthorizationBuilder.php b/src/Builders/AuthorizationBuilder.php
index bfbaee50..edf512d9 100644
--- a/src/Builders/AuthorizationBuilder.php
+++ b/src/Builders/AuthorizationBuilder.php
@@ -499,9 +499,6 @@ class AuthorizationBuilder extends TransactionBuilder
/** @var PhoneNumber */
public $shippingPhone;
- /** string */
- public $paymentLinkId;
-
/** @var RemittanceReferenceType */
public $remittanceReferenceType;
@@ -1411,12 +1408,6 @@ public function withPhoneNumber($phoneCountryCode, $number, $type)
return $this;
}
- public function withPaymentLinkId($paymentLinkId)
- {
- $this->paymentLinkId = $paymentLinkId;
- return $this;
- }
-
public function withRemittanceReference($remittanceReferenceType, $remittanceReferenceValue)
{
$this->remittanceReferenceType = $remittanceReferenceType;
diff --git a/src/Builders/ManagementBuilder.php b/src/Builders/ManagementBuilder.php
index 7e0a50c8..df3d60de 100644
--- a/src/Builders/ManagementBuilder.php
+++ b/src/Builders/ManagementBuilder.php
@@ -296,6 +296,12 @@ protected function setupValidations()
$this->validations->of(TransactionType::TOKEN_UPDATE)
->check('paymentMethod')->isInstanceOf(CreditCardData::class);
+
+ $this->validations->of(TransactionType::PAYLINK_UPDATE)
+ ->check('amount')->isNotNull()
+ ->check('usageMode')->isNotNullInSubProperty('payLinkData')
+ ->check('usageLimit')->isNotNullInSubProperty('payLinkData')
+ ->check('type')->isNotNullInSubProperty('payLinkData');
}
/**
diff --git a/src/Builders/RequestBuilder/GpApi/GpApiAuthorizationRequestBuilder.php b/src/Builders/RequestBuilder/GpApi/GpApiAuthorizationRequestBuilder.php
index 18a93263..0a6591da 100644
--- a/src/Builders/RequestBuilder/GpApi/GpApiAuthorizationRequestBuilder.php
+++ b/src/Builders/RequestBuilder/GpApi/GpApiAuthorizationRequestBuilder.php
@@ -12,6 +12,7 @@
use GlobalPayments\Api\Entities\Enums\GatewayProvider;
use GlobalPayments\Api\Entities\Enums\ManualEntryMethod;
use GlobalPayments\Api\Entities\Enums\CaptureMode;
+use GlobalPayments\Api\Entities\Enums\PayLinkStatus;
use GlobalPayments\Api\Entities\Enums\PaymentEntryMode;
use GlobalPayments\Api\Entities\Enums\PaymentType;
use GlobalPayments\Api\Entities\Enums\PhoneNumberType;
@@ -22,6 +23,7 @@
use GlobalPayments\Api\Entities\GpApi\DTO\PaymentMethod;
use GlobalPayments\Api\Entities\GpApi\GpApiRequest;
use GlobalPayments\Api\Entities\IRequestBuilder;
+use GlobalPayments\Api\Entities\PayLinkData;
use GlobalPayments\Api\Entities\PhoneNumber;
use GlobalPayments\Api\Mapping\EnumMapping;
use GlobalPayments\Api\PaymentMethods\CreditCardData;
@@ -115,6 +117,41 @@ public function buildRequest(BaseBuilder $builder, $config)
$builder->clientTransactionId : GenerationUtils::getGuid();
$requestData['payment_method'] = $this->createPaymentMethodParam($builder, $config);
break;
+ case TransactionType::CREATE:
+ if ($builder->payLinkData instanceof PayLinkData) {
+ /** @var PayLinkData $payLink */
+ $payLink = $builder->payLinkData;
+ $endpoint = GpApiRequest::PAYLINK_ENDPOINT;
+ $verb = 'POST';
+ $requestData['account_name'] = $config->accessTokenInfo->transactionProcessingAccountName;
+ $requestData['type'] = $payLink->type;
+ $requestData['usage_mode'] = $payLink->usageMode;
+ $requestData['usage_limit'] = (string) $payLink->usageLimit;
+ $requestData['reference'] = $builder->clientTransactionId;
+ $requestData['name'] = $payLink->name;
+ $requestData['description'] = $builder->description;
+ $requestData['shippable'] = isset($payLink->isShippable) ?
+ json_encode($payLink->isShippable) : false;
+ $requestData['shipping_amount'] = StringUtils::toNumeric($payLink->shippingAmount);
+ $requestData['expiration_date'] = !empty($payLink->expirationDate) ?
+ (new \DateTime($payLink->expirationDate))->format('Y-m-d\TH:i:s\Z') : null;
+ //@TODO - remove status when GP-API will fix the issue (status shouldn't be sent in request)
+ $requestData['status'] = PayLinkStatus::ACTIVE;
+ $requestData['images'] = $payLink->images;
+ $requestData['transactions'] = [
+ 'amount' => StringUtils::toNumeric($builder->amount),
+ 'channel' => $config->channel,
+ 'currency' => $builder->currency,
+ 'country' => $config->country,
+ 'allowed_payment_methods' => $payLink->allowedPaymentMethods
+ ];
+ $requestData['notifications'] = [
+ 'return_url' => $payLink->returnUrl,
+ 'status_url' => $payLink->statusUpdateUrl,
+ 'cancel_url' => $payLink->cancelUrl
+ ];
+ }
+ break;
default:
return '';
}
diff --git a/src/Builders/RequestBuilder/GpApi/GpApiManagementRequestBuilder.php b/src/Builders/RequestBuilder/GpApi/GpApiManagementRequestBuilder.php
index 6ff01eab..97379170 100644
--- a/src/Builders/RequestBuilder/GpApi/GpApiManagementRequestBuilder.php
+++ b/src/Builders/RequestBuilder/GpApi/GpApiManagementRequestBuilder.php
@@ -190,6 +190,29 @@ public function buildRequest(BaseBuilder $builder, $config)
]
];
break;
+ case TransactionType::PAYLINK_UPDATE:
+ $endpoint = GpApiRequest::PAYLINK_ENDPOINT . '/' . $builder->paymentLinkId;
+ $verb = 'PATCH';
+ $payload = [
+ 'usage_mode'=> $builder->payLinkData->usageMode ?? null,
+ 'usage_limit' => $builder->payLinkData->usageLimit ?? null,
+ 'name' => $builder->payLinkData->name ?? null,
+ 'description' => $builder->description ?? null,
+ 'type' => $builder->payLinkData->type ?? null,
+ 'status' => $builder->payLinkData->status ?? null,
+ 'shippable' => isset($builder->payLinkData->shippable) ?
+ json_encode($builder->payLinkData->shippable) : null,
+ 'shipping_amount' => !empty($builder->payLinkData->shippingAmount) ?
+ StringUtils::toNumeric($builder->payLinkData->shippingAmount) : null,
+ 'transactions' => [
+ 'amount' => !empty($builder->amount) ? StringUtils::toNumeric($builder->amount) : null
+ ],
+ 'expiration_date' => !empty($payLink->expirationDate) ?
+ (new \DateTime($payLink->expirationDate))->format('Y-m-d\TH:i:s\Z') : null,
+
+ 'images' => $builder->payLinkData->images ?? null,
+ ];
+ break;
default:
return null;
}
diff --git a/src/Builders/RequestBuilder/GpApi/GpApiReportRequestBuilder.php b/src/Builders/RequestBuilder/GpApi/GpApiReportRequestBuilder.php
index 4407dfef..39a12edd 100644
--- a/src/Builders/RequestBuilder/GpApi/GpApiReportRequestBuilder.php
+++ b/src/Builders/RequestBuilder/GpApi/GpApiReportRequestBuilder.php
@@ -197,6 +197,21 @@ public function buildRequest(BaseBuilder $builder, $config)
'http_response_code' => $builder->searchBuilder->httpResponseCode
];
break;
+ case ReportType::PAYLINK_DETAIL:
+ $endpoint = GpApiRequest::PAYLINK_ENDPOINT . '/' . $builder->searchBuilder->payLinkId;
+ $verb = 'GET';
+ break;
+ case ReportType::FIND_PAYLINK_PAGED:
+ $endpoint = GpApiRequest::PAYLINK_ENDPOINT;
+ $verb = 'GET';
+ $this->addBasicParams($queryParams, $builder);
+ $queryParams['from_time_created'] = !empty($builder->searchBuilder->startDate) ?
+ $builder->searchBuilder->startDate->format('Y-m-d') : null;
+ $queryParams['to_time_created'] = !empty($builder->searchBuilder->endDate) ?
+ $builder->searchBuilder->endDate->format('Y-m-d') : null;
+ $queryParams['order'] = $builder->order;
+ $queryParams['order_by'] = $builder->payLinkOrderBy;
+ break;
default:
return null;
}
diff --git a/src/Builders/TransactionBuilder.php b/src/Builders/TransactionBuilder.php
index fc1df71b..ad031db6 100644
--- a/src/Builders/TransactionBuilder.php
+++ b/src/Builders/TransactionBuilder.php
@@ -5,6 +5,8 @@
use GlobalPayments\Api\Builders\BaseBuilder\Validations;
use GlobalPayments\Api\Entities\Enums\TransactionModifier;
use GlobalPayments\Api\Entities\Exceptions\ArgumentException;
+use GlobalPayments\Api\Entities\PayLinkData;
+use GlobalPayments\Api\Entities\PayLinkResponse;
use GlobalPayments\Api\Entities\Transaction;
abstract class TransactionBuilder extends BaseBuilder
@@ -69,6 +71,20 @@ abstract class TransactionBuilder extends BaseBuilder
*/
public $supplementaryData;
+ /**
+ * Entity specific to PayLink service
+ *
+ * @var PayLinkData
+ */
+ public $payLinkData;
+
+ /**
+ *A unique identifier generated by Global Payments to identify the payment link.
+ *
+ * string
+ */
+ public $paymentLinkId;
+
/**
* Instantiates a new builder
*
@@ -149,4 +165,17 @@ public function withSupplementaryData($key, $value = null)
return $this;
}
+
+ public function withPayLinkData(PayLinkData $payLinkData)
+ {
+ $this->payLinkData = $payLinkData;
+
+ return $this;
+ }
+
+ public function withPaymentLinkId($paymentLinkId)
+ {
+ $this->paymentLinkId = $paymentLinkId;
+ return $this;
+ }
}
diff --git a/src/Builders/TransactionReportBuilder.php b/src/Builders/TransactionReportBuilder.php
index 15b0b453..ba0e3ba9 100644
--- a/src/Builders/TransactionReportBuilder.php
+++ b/src/Builders/TransactionReportBuilder.php
@@ -5,6 +5,7 @@
use GlobalPayments\Api\Entities\Enums\ActionSortProperty;
use GlobalPayments\Api\Entities\Enums\DepositSortProperty;
use GlobalPayments\Api\Entities\Enums\DisputeSortProperty;
+use GlobalPayments\Api\Entities\Enums\PayLinkSortProperty;
use GlobalPayments\Api\Entities\Enums\SortDirection;
use GlobalPayments\Api\Entities\Enums\StoredPaymentMethodSortProperty;
use GlobalPayments\Api\Entities\Enums\TransactionModifier;
@@ -74,6 +75,9 @@ class TransactionReportBuilder extends ReportBuilder
*/
public $actionOrderBy;
+ /** @var PayLinkSortProperty */
+ public $payLinkOrderBy;
+
/**
* @var SortDirection
*/
@@ -257,6 +261,12 @@ public function withBankPaymentId($bankPaymentId)
return $this;
}
+ public function withPayLinkId($payLinkId)
+ {
+ $this->searchBuilder->payLinkId = $payLinkId;
+ return $this;
+ }
+
/**
* Set the gateway order for the criteria
* @param string $sortProperty sorting property
@@ -293,6 +303,10 @@ public function orderBy($sortProperty, $sortDirection = SortDirection::DESC)
$this->actionOrderBy = $sortProperty;
$this->order = $sortDirection;
break;
+ case ReportType::FIND_PAYLINK_PAGED:
+ $this->payLinkOrderBy = $sortProperty;
+ $this->order = $sortDirection;
+ break;
default:
throw new \InvalidArgumentException("Invalid order found");
}
@@ -318,5 +332,8 @@ protected function setupValidations()
$this->validations->of(ReportType::DOCUMENT_DISPUTE_DETAIL)
->check('disputeDocumentId')->isNotNullInSubProperty('searchBuilder');
+
+ $this->validations->of(ReportType::PAYLINK_DETAIL)
+ ->check('payLinkId')->isNotNullInSubProperty('searchBuilder');
}
}
diff --git a/src/Entities/Enums/PayLinkSortProperty.php b/src/Entities/Enums/PayLinkSortProperty.php
new file mode 100644
index 00000000..d1064796
--- /dev/null
+++ b/src/Entities/Enums/PayLinkSortProperty.php
@@ -0,0 +1,10 @@
+ */
+ public $allowedPaymentMethods;
+
+ /**
+ * The number of the times that the link can be used or paid.
+ * @var integer
+ */
+ public $usageLimit;
+
+ /** @var PayLinkStatus */
+ public $status;
+
+ /**
+ * A descriptive name for the link. This will be visible to the customer on the payment page.
+ *
+ * @var string
+ */
+ public $name;
+
+ /**
+ * Indicates if you want to capture the customers shipping information on the hosted payment page.
+ * If you enable this field you can also set an optional shipping fee in the shipping_amount.
+ * @var boolean
+ */
+ public $isShippable;
+
+ /**
+ * Indicates the cost of shipping when the shippable field is set to YES.
+ * @var float
+ */
+ public $shippingAmount;
+
+ /**
+ * Indicates the date and time after which the link can no longer be used or paid.
+ * @var DateTime
+ */
+ public $expirationDate;
+
+ /**
+ * Images that will be displayed to the customer on the payment page.
+ * @var array
+ */
+ public $images;
+
+ /**
+ * The merchant URL that the customer will be redirected to.
+ *
+ * @var string
+ */
+ public $returnUrl;
+
+ /**
+ * The merchant URL (webhook) to notify the merchant of the latest status of the transaction
+ *
+ * @var string
+ */
+ public $statusUpdateUrl;
+
+ /**
+ * The merchant URL that the customer will be redirected to if they chose to cancel
+ *
+ * @var string
+ */
+ public $cancelUrl;
+}
diff --git a/src/Entities/PayLinkResponse.php b/src/Entities/PayLinkResponse.php
new file mode 100644
index 00000000..7aa2842b
--- /dev/null
+++ b/src/Entities/PayLinkResponse.php
@@ -0,0 +1,112 @@
+
+ */
+ public $images;
+
+ /** @var array */
+ public $allowedPaymentMethods;
+}
\ No newline at end of file
diff --git a/src/Entities/Reporting/PayLinkSummary.php b/src/Entities/Reporting/PayLinkSummary.php
new file mode 100644
index 00000000..ff14a6b2
--- /dev/null
+++ b/src/Entities/Reporting/PayLinkSummary.php
@@ -0,0 +1,126 @@
+
+ */
+ public $allowedPaymentMethods;
+
+ /**
+ * Indicates whether the link can be used once or multiple times
+ *
+ * @var PaymentMethodUsageMode
+ */
+ public $usageMode;
+
+ /**
+ * Indicates the number of times that a link has already been successfully paid.
+ *
+ * @var string
+ */
+ public $usageCount;
+
+ /**
+ * Merchant defined field to reference the transaction.
+ *
+ * @var string
+ */
+ public $reference;
+
+ /**
+ * A descriptive name for the link. This will be visible to the customer on the payment page.
+ *
+ * @var string
+ */
+ public $name;
+
+ /**
+ * A detailed description of your link that will be visible to the customer on the payment page.
+ *
+ * @var string
+ */
+ public $description;
+
+ /**
+ * Indicates if you want to capture the customers shipping information on the hosted payment page.
+ * @var string
+ */
+ public $shippable;
+
+ /**
+ * The number of times a link has been viewed.
+ * @var string
+ */
+ public $viewedCount;
+
+ /**
+ * Indicates the date and time after which the link can no longer be used or paid.
+ * @var DateTime
+ */
+ public $expirationDate;
+
+ /**
+ * Images that will be displayed to the customer on the payment page (base64 encoded image)
+ *
+ * @var array
+ */
+ public $images;
+
+ /**
+ * List of transactions attached to this payment link
+ *
+ * @var array
+ */
+ public $transactions;
+}
\ No newline at end of file
diff --git a/src/Entities/Reporting/SearchCriteriaBuilder.php b/src/Entities/Reporting/SearchCriteriaBuilder.php
index 96aeedeb..a8f7ba37 100644
--- a/src/Entities/Reporting/SearchCriteriaBuilder.php
+++ b/src/Entities/Reporting/SearchCriteriaBuilder.php
@@ -495,6 +495,14 @@ class SearchCriteriaBuilder
*/
public $returnPii;
+ /**
+ * This is the PayLink id
+ *
+ * @var string
+ */
+ public $payLinkId;
+
+
/** END Open Banking search criteria */
public function __construct(TransactionReportBuilder $reportBuilder = null)
diff --git a/src/Entities/Transaction.php b/src/Entities/Transaction.php
index 6de6e64e..713ed950 100644
--- a/src/Entities/Transaction.php
+++ b/src/Entities/Transaction.php
@@ -301,6 +301,9 @@ class Transaction
*/
public $bankPaymentResponse;
+ /** @var PayLinkResponse */
+ public $payLinkResponse;
+
/**
* Creates a `Transaction` object from a stored transaction ID.
*
diff --git a/src/Mapping/GpApiMapping.php b/src/Mapping/GpApiMapping.php
index 90bb92ec..0d8c5c2e 100644
--- a/src/Mapping/GpApiMapping.php
+++ b/src/Mapping/GpApiMapping.php
@@ -17,9 +17,12 @@
use GlobalPayments\Api\Entities\Exceptions\ApiException;
use GlobalPayments\Api\Entities\GpApi\DTO\PaymentMethod;
use GlobalPayments\Api\Entities\GpApi\PagedResult;
+use GlobalPayments\Api\Entities\PayLinkData;
+use GlobalPayments\Api\Entities\PayLinkResponse;
use GlobalPayments\Api\Entities\Reporting\ActionSummary;
use GlobalPayments\Api\Entities\Reporting\DepositSummary;
use GlobalPayments\Api\Entities\Reporting\DisputeSummary;
+use GlobalPayments\Api\Entities\Reporting\PayLinkSummary;
use GlobalPayments\Api\Entities\Reporting\StoredPaymentMethodSummary;
use GlobalPayments\Api\Entities\Reporting\TransactionSummary;
use GlobalPayments\Api\Entities\ThreeDSecure;
@@ -30,7 +33,8 @@
class GpApiMapping
{
const DCC_RESPONSE = 'RATE_LOOKUP';
-
+ const LINK_CREATE = "LINK_CREATE";
+ const LINK_EDIT = "LINK_EDIT";
/**
* Map a reponse to a Transaction object for further chaining
*
@@ -44,20 +48,34 @@ public static function mapResponse($response)
if (empty($response)) {
return $transaction;
}
- $transaction->transactionId = $response->id;
+ $transaction->responseCode = $response->action->result_code;
$transaction->responseMessage = $response->status;
+
+ switch ($response->action->type) {
+ case self::LINK_CREATE:
+ case self::LINK_EDIT:
+ $transaction->payLinkResponse = self::mapPayLinkResponse($response);
+ if (!empty($response->transactions)) {
+ $trn = $response->transactions;
+ $transaction->balanceAmount = isset($trn->amount) ? StringUtils::toAmount($trn->amount) : null;
+ $transaction->payLinkResponse->allowedPaymentMethods = $trn->allowed_payment_methods;
+ }
+
+ return $transaction;
+ }
+
+ $transaction->transactionId = $response->id;
$transaction->balanceAmount = !empty($response->amount) ? StringUtils::toAmount($response->amount) : null;
$transaction->authorizedAmount = ($response->status == TransactionStatus::PREAUTHORIZED && !empty($response->amount)) ?
StringUtils::toAmount($response->amount) : null;
$transaction->timestamp = !empty($response->time_created) ? $response->time_created : '';
-
$transaction->referenceNumber = !empty($response->reference) ? $response->reference : null;
$batchSummary = new BatchSummary();
$batchSummary->batchReference = !empty($response->batch_id) ? $response->batch_id : null;
$batchSummary->totalAmount = !empty($response->amount) ? $response->amount : null;
$batchSummary->transactionCount = !empty($response->transaction_count) ? $response->transaction_count : null;
$transaction->batchSummary = $batchSummary;
- $transaction->responseCode = $response->action->result_code;
+
$transaction->token = substr($response->id, 0, 4) === PaymentMethod::PAYMENT_METHOD_TOKEN_PREFIX ?
$response->id : null;
$transaction->tokenUsageMode = !empty($response->usage_mode) ? $response->usage_mode : null;
@@ -209,30 +227,31 @@ public static function mapReportResponse($response, $reportType)
array_push($report->result, self::mapActionsSummary($action));
}
break;
+ case ReportType::PAYLINK_DETAIL:
+ $report = self::mapPayLinkSummary($response);
+ break;
+ case ReportType::FIND_PAYLINK_PAGED:
+ $report = self::setPagingInfo($response);
+ foreach ($response->links as $link) {
+ array_push($report->result, self::mapPayLinkSummary($link));
+ }
+ break;
default:
throw new ApiException("Report type not supported!");
}
return $report;
}
+
/**
+ * Map the response from the search transaction request
+ *
* @param $response
* @return TransactionSummary
- * @throws \Exception
*/
public static function mapTransactionSummary($response)
{
- $summary = new TransactionSummary();
-
- $summary->transactionId = isset($response->id) ? $response->id : null;
- $summary->transactionDate = new \DateTime($response->time_created);
- $summary->transactionStatus = $response->status;
- $summary->transactionType = $response->type;
- $summary->channel = !empty($response->channel) ? $response->channel : null;
- $summary->amount = StringUtils::toAmount($response->amount);
- $summary->currency = $response->currency;
- $summary->referenceNumber = $response->reference;
- $summary->clientTransactionId = $response->reference;
+ $summary = self::createTransactionSummary($response);
$summary->transactionLocalDate = !empty($response->time_created_reference) ?
new \DateTime($response->time_created_reference) : '';
$summary->batchSequenceNumber = $response->batch_id;
@@ -294,6 +313,8 @@ public static function mapTransactionSummary($response)
}
/**
+ * Map the response from the search deposit request
+ *
* @param Object $response
*
* @return DepositSummary
@@ -345,6 +366,8 @@ public static function mapDepositSummary($response)
}
/**
+ * Map the response from the search dispute response
+ *
* @param Object $response
*
* @return DisputeSummary
@@ -601,11 +624,11 @@ public static function mapResponseAPM($response)
$paymentMethodApm = $response->payment_method->apm;
$apm->redirectUrl = !empty($response->payment_method->redirect_url) ? $response->payment_method->redirect_url : null;
$apm->providerName = $paymentMethodApm->provider;
- $apm->ack = $paymentMethodApm->ack;
+ $apm->ack = $paymentMethodApm->ack ?? null;
$apm->sessionToken = !empty($paymentMethodApm->session_token) ? $paymentMethodApm->session_token : null;
- $apm->correlationReference = $paymentMethodApm->correlation_reference;
- $apm->versionReference = $paymentMethodApm->version_reference;
- $apm->buildReference = $paymentMethodApm->build_reference;
+ $apm->correlationReference = $paymentMethodApm->correlation_reference ?? null;
+ $apm->versionReference = $paymentMethodApm->version_reference ?? null;
+ $apm->buildReference = $paymentMethodApm->build_reference ?? null;
$apm->timeCreatedReference = !empty($paymentMethodApm->time_created_reference) ?
new \DateTime($paymentMethodApm->time_created_reference) : null;
$apm->transactionReference = !empty($paymentMethodApm->transaction_reference) ?
@@ -648,4 +671,85 @@ public static function mapResponseAPM($response)
return $transaction;
}
+
+ /**
+ * @param $response
+ * @return PayLinkSummary
+ */
+ public static function mapPayLinkSummary($response)
+ {
+ $summary = new PayLinkSummary();
+
+ $summary->id = $response->id ?? null;
+ $summary->merchantId = $response->merchant_id ?? null;
+ $summary->merchantName = $response->merchant_name ?? null;
+ $summary->accountId = $response->account_id ?? null;
+ $summary->accountName = $response->account_name ?? null;
+ $summary->url = $response->url ?? null;
+ $summary->status = $response->status ?? null;
+ $summary->type = $response->type ?? null;
+ $summary->allowedPaymentMethods = $response->allowed_payment_methods ?? null; //@TODO check
+ $summary->usageMode = $response->usage_mode ?? null;
+ $summary->usageCount = $response->usage_count ?? null;
+ $summary->reference = $response->reference ?? null;
+ $summary->name = $response->name ?? null;
+ $summary->description = $response->description ?? null;
+ $summary->shippable = $response->shippable ?? null;
+ $summary->viewedCount = $response->viewed_count ?? null;
+ $summary->expirationDate = !empty($response->expiration_date) ?
+ new \DateTime($response->expiration_date) : null;
+ $summary->images = $response->images ?? null;
+
+ if (!empty($response->transactions)) {
+ foreach ($response->transactions as $transaction) {
+ $summary->transactions[] = self::createTransactionSummary($transaction);
+ }
+
+ }
+
+ return $summary;
+ }
+
+
+ public static function mapPayLinkResponse($response)
+ {
+ $payLinkResponse = new PayLinkResponse();
+ $payLinkResponse->id = $response->id;
+ $payLinkResponse->accountName = $response->account_name ?? null;
+ $payLinkResponse->url = $response->url ?? null;
+ $payLinkResponse->status = $response->status ?? null;
+ $payLinkResponse->type = $response->type ?? null;
+ $payLinkResponse->usageMode = $response->usage_mode ?? null;
+ $payLinkResponse->usageLimit = $response->usage_limit ?? null;
+ $payLinkResponse->reference = $response->reference ?? null;
+ $payLinkResponse->name = $response->name ?? null;
+ $payLinkResponse->description = $response->description ?? null;
+ $payLinkResponse->isShippable = $response->shippable ?? null;
+ $payLinkResponse->viewedCount = $response->viewed_count ?? null;
+ $payLinkResponse->expirationDate = !empty($response->expiration_date) ? new \DateTime($response->expiration_date) : null;
+
+ return $payLinkResponse;
+ }
+
+ /**
+ * Create an new TransactionSummary object
+ *
+ * @param $response
+ *
+ * @return TransactionSummary
+ */
+ private static function createTransactionSummary($response)
+ {
+ $transaction = new TransactionSummary();
+ $transaction->transactionId = isset($response->id) ? $response->id : null;
+ $transaction->transactionDate = $response->time_created;
+ $transaction->transactionStatus = $response->status;
+ $transaction->transactionType = $response->type;
+ $transaction->channel = !empty($response->channel) ? $response->channel : null;
+ $transaction->amount = StringUtils::toAmount($response->amount);
+ $transaction->currency = $response->currency;
+ $transaction->referenceNumber = $transaction->clientTransactionId = $response->reference;
+
+ return $transaction;
+ }
}
\ No newline at end of file
diff --git a/src/Services/PayLinkService.php b/src/Services/PayLinkService.php
new file mode 100644
index 00000000..e1675c54
--- /dev/null
+++ b/src/Services/PayLinkService.php
@@ -0,0 +1,39 @@
+withAmount($amount)
+ ->withPayLinkData($payLink);
+ }
+
+ public static function edit($payLinkId)
+ {
+ return (new ManagementBuilder( TransactionType::PAYLINK_UPDATE))
+ ->withPaymentLinkId($payLinkId);
+ }
+
+
+ public static function payLinkDetail($payLinkId)
+ {
+ return (new TransactionReportBuilder(ReportType::PAYLINK_DETAIL))
+ ->withPayLinkId($payLinkId);
+ }
+
+ public static function findPayLink($page, $pageSize)
+ {
+ return (new TransactionReportBuilder(ReportType::FIND_PAYLINK_PAGED))
+ ->withPaging($page, $pageSize);
+ }
+}
\ No newline at end of file
diff --git a/test/Integration/Gateways/GpApiConnector/PayLinkTest.php b/test/Integration/Gateways/GpApiConnector/PayLinkTest.php
new file mode 100644
index 00000000..bdea313f
--- /dev/null
+++ b/test/Integration/Gateways/GpApiConnector/PayLinkTest.php
@@ -0,0 +1,780 @@
+setUpConfig());
+ $this->startDate = (new \DateTime())->modify('-30 days')->setTime(0, 0, 0);
+ $this->endDate = (new \DateTime())->modify('-3 days')->setTime(0, 0, 0);
+
+ $this->payLink = new PayLinkData();
+ $this->payLink->type = PayLinkType::PAYMENT;
+ $this->payLink->usageMode = PaymentMethodUsageMode::SINGLE;
+ $this->payLink->allowedPaymentMethods = [PaymentMethodName::CARD];
+ $this->payLink->usageLimit = 3;
+ $this->payLink->name = 'Mobile Bill Payment';
+ $this->payLink->isShippable = true;
+ $this->payLink->shippingAmount = 1.23;
+ $this->payLink->expirationDate = date('Y-m-d H:i:s', strtotime(' + 10 days'));//date('Y-m-d H:i:s') + 10;
+ $this->payLink->images = [];
+ $this->payLink->returnUrl = 'https://www.example.com/returnUrl';
+ $this->payLink->statusUpdateUrl = 'https://www.example.com/statusUrl';
+ $this->payLink->cancelUrl = 'https://www.example.com/returnUrl';
+
+ $this->card = new CreditCardData();
+ $this->card->number = "4263970000005262";
+ $this->card->expMonth = date('m');
+ $this->card->expYear = date('Y', strtotime('+1 year'));
+ $this->card->cvn = "131";
+ $this->card->cardHolderName = "James Mason";
+
+ $this->shippingAddress = new Address();
+ $this->shippingAddress->streetAddress1 = "Apartment 852";
+ $this->shippingAddress->streetAddress2 = "Complex 741";
+ $this->shippingAddress->streetAddress3 = "no";
+ $this->shippingAddress->city = "Chicago";
+ $this->shippingAddress->postalCode = "5001";
+ $this->shippingAddress->state = "IL";
+ $this->shippingAddress->countryCode = "840";
+
+ $this->browserData = new BrowserData();
+ $this->browserData->acceptHeader = "text/html,application/xhtml+xml,application/xml;q=9,image/webp,img/apng,*/*;q=0.8";
+ $this->browserData->colorDepth = ColorDepth::TWENTY_FOUR_BITS;
+ $this->browserData->ipAddress = "123.123.123.123";
+ $this->browserData->javaEnabled = true;
+ $this->browserData->javaScriptEnabled = true;
+ $this->browserData->language = "en";
+ $this->browserData->screenHeight = 1080;
+ $this->browserData->screenWidth = 1920;
+ $this->browserData->challengWindowSize = ChallengeWindowSize::WINDOWED_600X400;
+ $this->browserData->timeZone = "0";
+ $this->browserData->userAgent = "Mozilla/5.0 (Windows NT 6.1; Win64, x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36";
+ }
+
+ public function setUpConfig()
+ {
+ $config = new GpApiConfig();
+ $config->appId = 'v2yRaFOLwFaQc0fSZTCyAdQCBNByGpVK';
+ $config->appKey = 'oKZpWitk6tORoCVT';
+ $config->channel = Channel::CardNotPresent;
+ $config->environment = Environment::TEST;
+ $config->country = 'GB';
+ $accessTokenInfo = new AccessTokenInfo();
+ $accessTokenInfo->transactionProcessingAccountName = 'LinkManagement';
+ $config->accessTokenInfo = $accessTokenInfo;
+ $config->requestLogger = new SampleRequestLogger(new Logger("logs"));
+
+ return $config;
+ }
+
+ public function testReportPayLinkDetail()
+ {
+ $paylinkId = 'LNK_GderFbTKFzj7X507E7OgDfuRnlKViP';
+ /** @var PayLinkSummary $response */
+ $response = PayLinkService::payLinkDetail($paylinkId)
+ ->execute();
+
+ $this->assertNotNull($response);
+ $this->assertInstanceOf(PayLinkSummary::class, $response);
+ $this->assertEquals($paylinkId, $response->id);
+ }
+
+ public function testReportPayLinkDetail_RandomId()
+ {
+ $paylinkId = GenerationUtils::getGuid();
+
+ $exceptionCaught = false;
+ try {
+ PayLinkService::payLinkDetail($paylinkId)
+ ->execute();
+ } catch (ApiException $e) {
+ $exceptionCaught = true;
+ $this->assertEquals('40118', $e->responseCode);
+ $this->assertEquals("Status Code: RESOURCE_NOT_FOUND - Links " . $paylinkId . " not found at this /ucp/links/" . $paylinkId . "", $e->getMessage());
+ } finally {
+ $this->assertTrue($exceptionCaught);
+ }
+ }
+
+ public function testFindPayLinkByDate()
+ {
+ $response = PayLinkService::findPayLink(1, 10)
+ ->orderBy(PayLinkSortProperty::TIME_CREATED, SortDirection::ASC)
+ ->where(SearchCriteria::START_DATE, $this->startDate)
+ ->andWith(SearchCriteria::END_DATE, $this->endDate)
+ ->execute();
+
+ $this->assertNotNull($response);
+ $this->assertNotEmpty($response->result);
+ /** @var PayLinkSummary $randomPayLink */
+ $randomPayLink = $response->result[array_rand($response->result)];
+ $this->assertNotNull($randomPayLink);
+ $this->assertInstanceOf(PayLinkSummary::class, $randomPayLink);
+ }
+
+ public function testCreatePayLink()
+ {
+ $payLink = new PayLinkData();
+ $payLink->type = PayLinkType::PAYMENT;
+ $payLink->usageMode = PaymentMethodUsageMode::SINGLE;
+ $payLink->allowedPaymentMethods = [PaymentMethodName::CARD];
+ $payLink->usageLimit = 1;
+ $payLink->name = 'Mobile Bill Payment';
+ $payLink->isShippable = true;
+ $payLink->shippingAmount = 1.23;
+ $payLink->expirationDate = date('Y-m-d H:i:s', strtotime(' + 10 days'));//date('Y-m-d H:i:s') + 10;
+ $payLink->images = [];
+ $payLink->returnUrl = 'https://www.example.com/returnUrl';
+ $payLink->statusUpdateUrl = 'https://www.example.com/statusUrl';
+ $payLink->cancelUrl = 'https://www.example.com/returnUrl';
+
+ $response = PayLinkService::create($payLink, $this->amount)
+ ->withCurrency('GBP')
+ ->withClientTransactionId(GenerationUtils::getGuid())
+ ->withDescription('March and April Invoice')
+ ->execute();
+
+ $this->assertPayLinkResponse($response);
+
+ fwrite(STDERR, print_r($response->payLinkResponse->url, TRUE));
+ }
+
+ public function testCreatePayLink_MultipleUsage()
+ {
+ $payLink = new PayLinkData();
+ $payLink->type = PayLinkType::PAYMENT;
+ $payLink->usageMode = PaymentMethodUsageMode::MULTIPLE;
+ $payLink->allowedPaymentMethods = [PaymentMethodName::CARD];
+ $payLink->usageLimit = 2;
+ $payLink->name = 'Mobile Bill Payment';
+ $payLink->isShippable = true;
+ $payLink->shippingAmount = 1.23;
+ $payLink->expirationDate = date('Y-m-d H:i:s', strtotime(' + 10 days'));//date('Y-m-d H:i:s') + 10;
+ $payLink->images = [];
+ $payLink->returnUrl = 'https://www.example.com/returnUrl';
+ $payLink->statusUpdateUrl = 'https://www.example.com/statusUrl';
+ $payLink->cancelUrl = 'https://www.example.com/returnUrl';
+
+ $response = PayLinkService::create($payLink, $this->amount)
+ ->withCurrency('GBP')
+ ->withClientTransactionId(GenerationUtils::getGuid())
+ ->withDescription('March and April Invoice')
+ ->execute();
+
+ $this->assertPayLinkResponse($response);
+
+ fwrite(STDERR, print_r($response->payLinkResponse->url, TRUE));
+ }
+
+ public function testCreatePayLink_ThenCharge()
+ {
+ $response = PayLinkService::create($this->payLink, $this->amount)
+ ->withCurrency('GBP')
+ ->withClientTransactionId(GenerationUtils::getGuid())
+ ->withDescription('March and April Invoice')
+ ->execute();
+
+ $this->assertPayLinkResponse($response);
+
+ fwrite(STDERR, print_r($response->payLinkResponse->url, TRUE));
+
+ ServicesContainer::configureService($this->setupTransactionConfig(), "createTransaction");
+
+ $transaction = $this->card->charge($this->amount)
+ ->withCurrency('GBP')
+ ->withPaymentLinkId($response->payLinkResponse->id)
+ ->execute("createTransaction");
+
+ $this->assertNotNull($transaction);
+ $this->assertEquals('SUCCESS', $transaction->responseCode);
+ $this->assertEquals(TransactionStatus::CAPTURED, $transaction->responseMessage);
+
+ sleep(2);
+
+ $getResponse = PayLinkService::payLinkDetail($response->payLinkResponse->id)
+ ->execute();
+
+ $this->assertNotNull($getResponse);
+ $this->assertInstanceOf(PayLinkSummary::class, $getResponse);
+ $this->assertEquals($response->payLinkResponse->id, $getResponse->id);
+ }
+
+ public function testCreatePayLink_MultipleUsage_ThenCharge()
+ {
+ $this->payLink->usageMode = PaymentMethodUsageMode::MULTIPLE;
+ $this->payLink->usageLimit = 2;
+
+ $response = PayLinkService::create($this->payLink, $this->amount)
+ ->withCurrency('GBP')
+ ->withClientTransactionId(GenerationUtils::getGuid())
+ ->withDescription('March and April Invoice')
+ ->execute();
+
+ $this->assertPayLinkResponse($response);
+
+ fwrite(STDERR, print_r($response->payLinkResponse->url, TRUE));
+
+ ServicesContainer::configureService($this->setupTransactionConfig(), "createTransaction");
+
+ for ($i = 1; $i <= $this->payLink->usageLimit; $i++) {
+ $transaction = $this->card->charge($this->amount)
+ ->withCurrency('GBP')
+ ->withPaymentLinkId($response->payLinkResponse->id)
+ ->execute("createTransaction");
+
+ $this->assertNotNull($transaction);
+ $this->assertEquals('SUCCESS', $transaction->responseCode);
+ $this->assertEquals(TransactionStatus::CAPTURED, $transaction->responseMessage);
+ }
+
+ sleep(2);
+
+ $getResponse = PayLinkService::payLinkDetail($response->payLinkResponse->id)
+ ->execute();
+
+ $this->assertNotNull($getResponse);
+ $this->assertInstanceOf(PayLinkSummary::class, $getResponse);
+ $this->assertEquals($response->payLinkResponse->id, $getResponse->id);
+ $this->assertCount($this->payLink->usageLimit, $getResponse->transactions);
+ $this->assertEquals(0, intval($getResponse->viewedCount));
+ $this->assertEquals(0, intval($getResponse->usageCount));
+ }
+
+ public function testCreatePayLink_ThenAuthorizeAndCapture()
+ {
+ $response = PayLinkService::create($this->payLink, $this->amount)
+ ->withCurrency('GBP')
+ ->withClientTransactionId(GenerationUtils::getGuid())
+ ->withDescription('March and April Invoice')
+ ->execute();
+
+ $this->assertPayLinkResponse($response);
+
+ fwrite(STDERR, print_r($response->payLinkResponse->url, TRUE));
+
+ ServicesContainer::configureService($this->setupTransactionConfig(), "createTransaction");
+
+ $authorize = $this->card->authorize($this->amount)
+ ->withCurrency('GBP')
+ ->withPaymentLinkId($response->payLinkResponse->id)
+ ->execute("createTransaction");
+
+ $this->assertNotNull($authorize);
+ $this->assertEquals('SUCCESS', $authorize->responseCode);
+ $this->assertEquals(TransactionStatus::PREAUTHORIZED, $authorize->responseMessage);
+
+ $capture = $authorize->capture($this->amount)
+ ->execute("createTransaction");
+
+ $this->assertNotNull($capture);
+ $this->assertEquals('SUCCESS', $capture->responseCode);
+ $this->assertEquals(TransactionStatus::CAPTURED, $capture->responseMessage);
+
+ sleep(2);
+
+ $getResponse = PayLinkService::payLinkDetail($response->payLinkResponse->id)
+ ->execute();
+
+ $this->assertNotNull($getResponse);
+ $this->assertInstanceOf(PayLinkSummary::class, $getResponse);
+ $this->assertEquals($response->payLinkResponse->id, $getResponse->id);
+ }
+
+ public function testCreatePayLink_ThenCharge_WithTokenizedCard()
+ {
+ $response = PayLinkService::create($this->payLink, $this->amount)
+ ->withCurrency('GBP')
+ ->withClientTransactionId(GenerationUtils::getGuid())
+ ->withDescription('March and April Invoice')
+ ->execute();
+
+ $this->assertPayLinkResponse($response);
+
+ fwrite(STDERR, print_r($response->payLinkResponse->url, TRUE));
+
+ ServicesContainer::configureService($this->setupTransactionConfig(), "createTransaction");
+
+ $tokenResponse = $this->card->tokenize(true, PaymentMethodUsageMode::SINGLE)
+ ->execute("createTransaction");
+ $tokenId = $tokenResponse->token;
+
+ $tokenizedCard = new CreditCardData();
+ $tokenizedCard->token = $tokenId;
+ $tokenizedCard->cardHolderName = "James Mason";
+
+ $transaction = $tokenizedCard->charge($this->amount)
+ ->withCurrency('GBP')
+ ->withPaymentLinkId($response->payLinkResponse->id)
+ ->execute("createTransaction");
+
+ $this->assertNotNull($transaction);
+ $this->assertEquals('SUCCESS', $transaction->responseCode);
+ $this->assertEquals(TransactionStatus::CAPTURED, $transaction->responseMessage);
+
+ sleep(2);
+
+ $getResponse = PayLinkService::payLinkDetail($response->payLinkResponse->id)
+ ->execute();
+
+ $this->assertNotNull($getResponse);
+ $this->assertInstanceOf(PayLinkSummary::class, $getResponse);
+ $this->assertEquals($response->payLinkResponse->id, $getResponse->id);
+ }
+
+ public function testCreatePayLink_ThenCharge_With3DS()
+ {
+ $response = PayLinkService::create($this->payLink, $this->amount)
+ ->withCurrency('GBP')
+ ->withClientTransactionId(GenerationUtils::getGuid())
+ ->withDescription('March and April Invoice')
+ ->execute();
+
+ $this->assertPayLinkResponse($response);
+
+ fwrite(STDERR, print_r($response->payLinkResponse->url, TRUE));
+
+ ServicesContainer::configureService($this->setupTransactionConfig(), "createTransaction");
+
+ $this->card->number = GpApi3DSTestCards::CARD_AUTH_SUCCESSFUL_V2_2;
+
+ $secureEcom = Secure3dService::checkEnrollment($this->card)
+ ->withCurrency('GBP')
+ ->withAmount($this->amount)
+ ->execute("createTransaction");
+
+ $this->assertNotNull($secureEcom);
+ $this->assertEquals(Secure3dStatus::ENROLLED, $secureEcom->enrolled);
+ $this->assertEquals(Secure3dVersion::TWO, $secureEcom->getVersion());
+ $this->assertEquals(Secure3dStatus::AVAILABLE, $secureEcom->status);
+ $this->assertNotNull($secureEcom->issuerAcsUrl);
+ $this->assertNotNull($secureEcom->payerAuthenticationRequest);
+
+ $initAuth = Secure3dService::initiateAuthentication($this->card, $secureEcom)
+ ->withAmount($this->amount)
+ ->withCurrency('GBP')
+ ->withAuthenticationSource(AuthenticationSource::BROWSER)
+ ->withMethodUrlCompletion(MethodUrlCompletion::YES)
+ ->withOrderCreateDate(date('Y-m-d H:i:s'))
+ ->withAddress($this->shippingAddress, AddressType::SHIPPING)
+ ->withBrowserData($this->browserData)
+ ->execute("createTransaction");
+
+ $this->assertNotNull($initAuth);
+ $this->assertEquals(Secure3dStatus::SUCCESS_AUTHENTICATED, $initAuth->status);
+ $this->assertEquals('YES', $secureEcom->liabilityShift);
+
+ $secureEcom = Secure3dService::getAuthenticationData()
+ ->withServerTransactionId($secureEcom->serverTransactionId)
+ ->execute("createTransaction");
+
+ $this->assertEquals(Secure3dStatus::SUCCESS_AUTHENTICATED, $secureEcom->status);
+
+ $this->card->threeDSecure = $secureEcom;
+
+ $transaction = $this->card->charge($this->amount)
+ ->withCurrency('GBP')
+ ->withPaymentLinkId($response->payLinkResponse->id)
+ ->execute("createTransaction");
+
+ $this->assertNotNull($transaction);
+ $this->assertEquals('SUCCESS', $transaction->responseCode);
+ $this->assertEquals(TransactionStatus::CAPTURED, $transaction->responseMessage);
+
+ sleep(2);
+
+ $getResponse = PayLinkService::payLinkDetail($response->payLinkResponse->id)
+ ->execute();
+
+ $this->assertNotNull($getResponse);
+ $this->assertInstanceOf(PayLinkSummary::class, $getResponse);
+ $this->assertEquals($response->payLinkResponse->id, $getResponse->id);
+ }
+
+ public function testEditPayLink()
+ {
+ $response = PayLinkService::findPayLink(1, 10)
+ ->orderBy(PayLinkSortProperty::TIME_CREATED, SortDirection::ASC)
+ ->where(SearchCriteria::START_DATE, $this->startDate)
+ ->andWith(SearchCriteria::END_DATE, $this->endDate)
+ ->execute();
+
+ $this->assertNotNull($response);
+ $this->assertNotEmpty($response->result);
+ /** @var PayLinkSummary $randomPayLink */
+ $randomPayLink = $response->result[array_rand($response->result)];
+ $this->assertNotNull($randomPayLink);
+ $this->assertInstanceOf(PayLinkSummary::class, $randomPayLink);
+ $this->assertNotNull($randomPayLink->id);
+
+ $payLinkData = new PayLinkData();
+ $payLinkData->name = 'bla bla bla';
+ $payLinkData->usageMode = PaymentMethodUsageMode::MULTIPLE;
+ $payLinkData->type = PayLinkType::PAYMENT;
+ $payLinkData->usageLimit = 5;
+ $payLinkData->isShippable = false;
+ $amount = 10.08;
+ $response = PayLinkService::edit($randomPayLink->id)
+ ->withAmount($amount)
+ ->withPayLinkData($payLinkData)
+ ->withDescription('Update Paylink description')
+ ->execute();
+
+ $this->assertEquals('SUCCESS', $response->responseCode);
+ $this->assertEquals(PayLinkStatus::ACTIVE, $response->responseMessage);
+ $this->assertEquals($amount, $response->balanceAmount);
+ $this->assertNotNull($response->payLinkResponse->url);
+ $this->assertNotNull($response->payLinkResponse->id);
+ }
+
+ public function testCreatePayLink_MissingType()
+ {
+ $this->payLink->type = null;
+
+ $exceptionCaught = false;
+ try {
+ PayLinkService::create($this->payLink, $this->amount)
+ ->withCurrency('GBP')
+ ->withDescription('March and April Invoice')
+ ->execute();
+ } catch (ApiException $e) {
+ $exceptionCaught = true;
+ $this->assertEquals('40005', $e->responseCode);
+ $this->assertEquals('Status Code: MANDATORY_DATA_MISSING - Request expects the following field type', $e->getMessage());
+ } finally {
+ $this->assertTrue($exceptionCaught);
+ }
+ }
+
+ public function testCreatePayLink_MissingUsageMode()
+ {
+ $this->payLink->usageMode = null;
+
+ $exceptionCaught = false;
+ try {
+ PayLinkService::create($this->payLink, $this->amount)
+ ->withCurrency('GBP')
+ ->withDescription('March and April Invoice')
+ ->execute();
+ } catch (ApiException $e) {
+ $exceptionCaught = true;
+ $this->assertEquals('40005', $e->responseCode);
+ $this->assertEquals('Status Code: MANDATORY_DATA_MISSING - Request expects the following field usage_mode', $e->getMessage());
+ } finally {
+ $this->assertTrue($exceptionCaught);
+ }
+ }
+
+ public function testCreatePayLink_MissingPaymentMethod()
+ {
+ $this->payLink->allowedPaymentMethods = null;
+
+ $exceptionCaught = false;
+ try {
+ PayLinkService::create($this->payLink, $this->amount)
+ ->withCurrency('GBP')
+ ->withDescription('March and April Invoice')
+ ->execute();
+ } catch (ApiException $e) {
+ $exceptionCaught = true;
+ $this->assertEquals('40005', $e->responseCode);
+ $this->assertEquals('Status Code: MANDATORY_DATA_MISSING - Request expects the following field transactions.allowed_payment_methods', $e->getMessage());
+ } finally {
+ $this->assertTrue($exceptionCaught);
+ }
+ }
+
+ public function testCreatePayLink_MissingName()
+ {
+ $this->payLink->name = null;
+
+ $exceptionCaught = false;
+ try {
+ PayLinkService::create($this->payLink, $this->amount)
+ ->withCurrency('GBP')
+ ->withDescription('March and April Invoice')
+ ->execute();
+ } catch (ApiException $e) {
+ $exceptionCaught = true;
+ $this->assertEquals('40005', $e->responseCode);
+ $this->assertEquals('Status Code: MANDATORY_DATA_MISSING - Request expects the following field name', $e->getMessage());
+ } finally {
+ $this->assertTrue($exceptionCaught);
+ }
+ }
+
+ public function testCreatePayLink_MissingShippable()
+ {
+ $this->payLink->isShippable = null;
+
+ $exceptionCaught = false;
+ try {
+ PayLinkService::create($this->payLink, $this->amount)
+ ->withCurrency('GBP')
+ ->withDescription('March and April Invoice')
+ ->execute();
+ } catch (ApiException $e) {
+ $exceptionCaught = true;
+ $this->assertEquals('50001', $e->responseCode);
+ $this->assertEquals('Status Code: SYSTEM_ERROR - Internal Server Error', $e->getMessage());
+ } finally {
+ $this->assertTrue($exceptionCaught);
+ }
+ }
+
+ public function testCreatePayLink_MissingShippingAmount()
+ {
+ $this->payLink->shippingAmount = null;
+
+ $exceptionCaught = false;
+ try {
+ PayLinkService::create($this->payLink, $this->amount)
+ ->withCurrency('GBP')
+ ->withDescription('March and April Invoice')
+ ->execute();
+ } catch (ApiException $e) {
+ $exceptionCaught = true;
+ $this->assertEquals('40251', $e->responseCode);
+ $this->assertEquals('Status Code: MANDATORY_DATA_MISSING - Request expects the following fields: shipping_amount.', $e->getMessage());
+ } finally {
+ $this->assertTrue($exceptionCaught);
+ }
+ }
+
+ public function testCreatePayLink_MissingDescription()
+ {
+ $exceptionCaught = false;
+ try {
+ PayLinkService::create($this->payLink, $this->amount)
+ ->withCurrency('GBP')
+ ->execute();
+ } catch (ApiException $e) {
+ $exceptionCaught = true;
+ $this->assertEquals('40005', $e->responseCode);
+ $this->assertEquals('Status Code: MANDATORY_DATA_MISSING - Request expects the following field description', $e->getMessage());
+ } finally {
+ $this->assertTrue($exceptionCaught);
+ }
+ }
+
+ public function testCreatePayLink_MissingCurrency()
+ {
+ $exceptionCaught = false;
+ try {
+ PayLinkService::create($this->payLink, $this->amount)
+ ->withDescription('March and April Invoice')
+ ->execute();
+ } catch (ApiException $e) {
+ $exceptionCaught = true;
+ $this->assertEquals('40005', $e->responseCode);
+ $this->assertEquals('Status Code: MANDATORY_DATA_MISSING - Request expects the following field transactions.currency', $e->getMessage());
+ } finally {
+ $this->assertTrue($exceptionCaught);
+ }
+ }
+
+ //TODO - error message different than create() + no logs
+ public function testEditPayLink_MissingUsageMode()
+ {
+ $this->payLink->usageMode = null;
+
+ $exceptionCaught = false;
+ try {
+ PayLinkService::edit(GenerationUtils::getGuid())
+ ->withAmount($this->amount)
+ ->withPayLinkData($this->payLink)
+ ->withDescription('Update Paylink description')
+ ->execute();
+ } catch (ApiException $e) {
+ $exceptionCaught = true;
+// $this->assertEquals('40005', $e->responseCode);
+ $this->assertEquals('usageMode cannot be null for this transaction type.', $e->getMessage());
+ } finally {
+ $this->assertTrue($exceptionCaught);
+ }
+ }
+
+ public function testEditPayLink_MissingName()
+ {
+ $this->payLink->name = null;
+
+ $exceptionCaught = false;
+ try {
+ PayLinkService::edit(GenerationUtils::getGuid())
+ ->withAmount($this->amount)
+ ->withPayLinkData($this->payLink)
+ ->withDescription('Update Paylink description')
+ ->execute();
+ } catch (ApiException $e) {
+ $exceptionCaught = true;
+ $this->assertEquals('40005', $e->responseCode);
+ $this->assertEquals('Status Code: MANDATORY_DATA_MISSING - Request expects the following field name', $e->getMessage());
+ } finally {
+ $this->assertTrue($exceptionCaught);
+ }
+ }
+
+ //TODO - error message different than create() + no logs
+ public function testEditPayLink_MissingType()
+ {
+ $this->payLink->type = null;
+
+ $exceptionCaught = false;
+ try {
+ PayLinkService::edit(GenerationUtils::getGuid())
+ ->withAmount($this->amount)
+ ->withPayLinkData($this->payLink)
+ ->withDescription('Update Paylink description')
+ ->execute();
+ } catch (ApiException $e) {
+ $exceptionCaught = true;
+// $this->assertEquals('40005', $e->responseCode);
+ $this->assertEquals('type cannot be null for this transaction type.', $e->getMessage());
+ } finally {
+ $this->assertTrue($exceptionCaught);
+ }
+ }
+
+ //TODO - error message different than create() + no logs
+ public function testEditPayLink_MissingUsageLimit()
+ {
+ $this->payLink->usageLimit = null;
+
+ $exceptionCaught = false;
+ try {
+ PayLinkService::edit(GenerationUtils::getGuid())
+ ->withAmount($this->amount)
+ ->withPayLinkData($this->payLink)
+ ->withDescription('Update Paylink description')
+ ->execute();
+ } catch (ApiException $e) {
+ $exceptionCaught = true;
+// $this->assertEquals('40005', $e->responseCode);
+ $this->assertEquals('usageLimit cannot be null for this transaction type.', $e->getMessage());
+ } finally {
+ $this->assertTrue($exceptionCaught);
+ }
+ }
+
+ public function testEditPayLink_MissingDescription()
+ {
+ $exceptionCaught = false;
+ try {
+ PayLinkService::edit(GenerationUtils::getGuid())
+ ->withAmount($this->amount)
+ ->withPayLinkData($this->payLink)
+ ->execute();
+ } catch (ApiException $e) {
+ $exceptionCaught = true;
+ $this->assertEquals('40005', $e->responseCode);
+ $this->assertEquals('Status Code: MANDATORY_DATA_MISSING - Request expects the following field description', $e->getMessage());
+ } finally {
+ $this->assertTrue($exceptionCaught);
+ }
+ }
+
+ //TODO - error message different than create() + no logs
+ public function testEditPayLink_MissingPayLinkData()
+ {
+ $exceptionCaught = false;
+ try {
+ PayLinkService::edit(GenerationUtils::getGuid())
+ ->withAmount($this->amount)
+ ->withDescription('Update Paylink description')
+ ->execute();
+ } catch (ApiException $e) {
+ $exceptionCaught = true;
+// $this->assertEquals('40005', $e->responseCode);
+ $this->assertEquals('Property `usageMode` does not exist on `GlobalPayments\Api\Builders\ManagementBuilder`', $e->getMessage());
+ } finally {
+ $this->assertTrue($exceptionCaught);
+ }
+ }
+
+ public function testEditPayLink_RandomPayLinkId()
+ {
+ $exceptionCaught = false;
+ try {
+ PayLinkService::edit(GenerationUtils::getGuid())
+ ->withAmount($this->amount)
+ ->withPayLinkData($this->payLink)
+ ->withDescription('Update Paylink description')
+ ->execute();
+ } catch (ApiException $e) {
+ $exceptionCaught = true;
+ $this->assertEquals('40108', $e->responseCode);
+ $this->assertEquals('Status Code: INVALID_REQUEST_DATA - You cannot update a link that has a 400 status', $e->getMessage());
+ } finally {
+ $this->assertTrue($exceptionCaught);
+ }
+ }
+
+ private function assertPayLinkResponse(Transaction $response)
+ {
+ $this->assertEquals('SUCCESS', $response->responseCode);
+ $this->assertEquals(PayLinkStatus::ACTIVE, $response->responseMessage);
+ $this->assertEquals($this->amount, $response->balanceAmount);
+ $this->assertNotNull($response->payLinkResponse->url);
+ $this->assertNotNull($response->payLinkResponse->id);
+ }
+
+ private function setupTransactionConfig()
+ {
+ $configTrn = new GpApiConfig();
+ $configTrn->appId = 'oDVjAddrXt3qPJVPqQvrmgqM2MjMoHQS';
+ $configTrn->appKey = 'DHUGdzpjXfTbjZeo';
+ $configTrn->channel = Channel::CardNotPresent;
+ $configTrn->country = 'GB';
+ $configTrn->challengeNotificationUrl = 'https://ensi808o85za.x.pipedream.net/';
+ $configTrn->methodNotificationUrl = 'https://ensi808o85za.x.pipedream.net/';
+ $configTrn->merchantContactUrl = 'https://enp4qhvjseljg.x.pipedream.net/';
+ $configTrn->requestLogger = new SampleRequestLogger(new Logger("logs"));
+
+ return $configTrn;
+ }
+}
\ No newline at end of file