From 55dddb1d21a83200e68da4e0416ceed57291e96a Mon Sep 17 00:00:00 2001 From: securesubmit-buildmaster Date: Thu, 28 Jul 2022 09:03:01 -0400 Subject: [PATCH] OctopusDeploy release: 4.0.5 --- CHANGELOG.md | 7 + metadata.xml | 2 +- src/Builders/AuthorizationBuilder.php | 9 - src/Builders/ManagementBuilder.php | 6 + .../GpApiAuthorizationRequestBuilder.php | 37 + .../GpApi/GpApiManagementRequestBuilder.php | 23 + .../GpApi/GpApiReportRequestBuilder.php | 15 + src/Builders/TransactionBuilder.php | 29 + src/Builders/TransactionReportBuilder.php | 17 + src/Entities/Enums/PayLinkSortProperty.php | 10 + src/Entities/Enums/PayLinkStatus.php | 14 + src/Entities/Enums/PayLinkType.php | 8 + src/Entities/Enums/ReportType.php | 2 + src/Entities/Enums/TransactionType.php | 1 + src/Entities/GpApi/GpApiRequest.php | 3 +- src/Entities/PayLinkData.php | 93 +++ src/Entities/PayLinkResponse.php | 112 +++ src/Entities/Reporting/PayLinkSummary.php | 126 +++ .../Reporting/SearchCriteriaBuilder.php | 8 + src/Entities/Transaction.php | 3 + src/Mapping/GpApiMapping.php | 144 +++- src/Services/PayLinkService.php | 39 + .../Gateways/GpApiConnector/PayLinkTest.php | 780 ++++++++++++++++++ 23 files changed, 1457 insertions(+), 31 deletions(-) create mode 100644 src/Entities/Enums/PayLinkSortProperty.php create mode 100644 src/Entities/Enums/PayLinkStatus.php create mode 100644 src/Entities/Enums/PayLinkType.php create mode 100644 src/Entities/PayLinkData.php create mode 100644 src/Entities/PayLinkResponse.php create mode 100644 src/Entities/Reporting/PayLinkSummary.php create mode 100644 src/Services/PayLinkService.php create mode 100644 test/Integration/Gateways/GpApiConnector/PayLinkTest.php 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