diff --git a/doc/index.md b/doc/index.md index 6402665..d0aa010 100644 --- a/doc/index.md +++ b/doc/index.md @@ -123,7 +123,7 @@ Will create payment. ### realizePreauthorizedPayment -Will realize preauth payment +Will realize preauth payment (V2 API endpoint). #### Parameters @@ -131,6 +131,12 @@ Will realize preauth payment | --- | --- | --- | | $params | RealizePreauthorizedPaymentParams | required | +#### Return + +| return type | | +| --- | --- | +| RealizePreauthorizedPaymentResult | Result with `getState()` returning 'paid' or 'waiting_for_confirmation' | + ### cancelPreauthorizedPayment Will cancel preauth payment @@ -182,48 +188,71 @@ Return information about transactions history ### realizeRegularSubscriptionPayment -Realize subscription payment. +Realize subscription payment (V2 API endpoint). #### Parameters | name | type | | description | | --- | --- | --- | --- | -| $uid | string | required | UID of parent payment | +| $parentPaymentUid | string | required | UID of parent payment | | $params | RealizeRegularSubscriptionPaymentParams | required | | +#### Return + +| return type | | +| --- | --- | +| RecurringPaymentResult | Result with `getState()` and `isRecurringPaymentsAvailable()` | + ### realizeIrregularSubscriptionPayment -Realize subscription payment. +Realize subscription payment (V2 API endpoint). #### Parameters | name | type | | description | | --- | --- | --- | --- | -| $uid | string | required | UID of parent payment | +| $parentPaymentUid | string | required | UID of parent payment | | $params | RealizeIrregularSubscriptionPaymentParams | required | | +#### Return + +| return type | | +| --- | --- | +| RecurringPaymentResult | Result with `getState()` and `isRecurringPaymentsAvailable()` | + ### realizeUsageBasedSubscriptionPayment -Realize subscription payment. +Realize subscription payment (V2 API endpoint). #### Parameters | name | type | | description | | --- | --- | --- | --- | -| $uid | string | required | UID of parent payment | +| $parentPaymentUid | string | required | UID of parent payment | | $params | RealizeUsageBasedSubscriptionPaymentParams | required | | +#### Return + +| return type | | +| --- | --- | +| RecurringPaymentResult | Result with `getState()` and `isRecurringPaymentsAvailable()` | ### realizePaymentBySavedAuthorization -Create new payment using saved authorization. +Create new payment using saved authorization (V2 API endpoint). #### Parameters | name | type | | description | | --- | --- | --- | --- | -| $uid | string | required | UID of parent payment | -| $params | RealizePaymentBySavedAuthorizationParams | required | | +| $parentPaymentUid | string | required | UID of parent payment | +| $params | RealizePaymentBySavedAuthorizationParams | required | Requires amount and currency code | + +#### Return + +| return type | | +| --- | --- | +| RecurringPaymentResult | Result with `getState()` and `isRecurringPaymentsAvailable()` | ### getPaymentUrlsForPayment diff --git a/doc/preauth-payments.md b/doc/preauth-payments.md index a246cd7..4c41f6f 100644 --- a/doc/preauth-payments.md +++ b/doc/preauth-payments.md @@ -1,6 +1,6 @@ # Preauthorized payments -A **preauthorized payment** allows you to reserve (authorize) funds on a customer’s account and capture them later. +A **preauthorized payment** allows you to reserve (authorize) funds on a customer's account and capture them later. This is useful for cases like hotel bookings or rentals, where you charge the customer only after confirming service delivery. By setting `setIsDeposit(false)` when creating a payment, the payment is created as a **preauthorization** instead of a direct deposit. @@ -26,13 +26,29 @@ $thePayClient->createPayment($params); Once you are ready to capture the funds, call `realizePreauthorizedPayment()`: ```php +use ThePay\ApiClient\Model\RealizePreauthorizedPaymentResult; + /** @var \ThePay\ApiClient\TheClient $thePayClient */ $params = new \ThePay\ApiClient\Model\RealizePreauthorizedPaymentParams(100, 'PREAUTH_PAYMENT_001'); -$thePayClient->realizePreauthorizedPayment($params); +$result = $thePayClient->realizePreauthorizedPayment($params); + +match ($result->getState()) { + RealizePreauthorizedPaymentResult::STATE_PAID => + echo 'Preauthorized payment was realized successfully', + + RealizePreauthorizedPaymentResult::STATE_WAITING_FOR_CONFIRMATION => + echo 'Payment is being processed, you will receive a notification when complete', +}; ``` You may capture less than the originally preauthorized amount, but never more. +**Note about V2 API:** +The V2 API supports asynchronous payment processing: +- State `paid` means immediate success +- State `waiting_for_confirmation` means the payment is being processed asynchronously +- You will receive a notification when the async payment completes (state changes to `paid` or `preauth_cancelled`) + ## Cancel a Preauthorized Payment If you decide not to capture the funds, you can cancel the preauthorization: @@ -43,4 +59,4 @@ $thePayClient->cancelPreauthorizedPayment('PREAUTH_PAYMENT_001'); ``` **Note on fund release:** -- While the preauthorization is cancelled immediately on ThePay’s side, banks may take some time to release the reserved funds back to the customer’s account. +- While the preauthorization is cancelled immediately on ThePay's side, banks may take some time to release the reserved funds back to the customer's account. diff --git a/doc/saving-authorization.md b/doc/saving-authorization.md index 78c9f23..d1f3b5e 100644 --- a/doc/saving-authorization.md +++ b/doc/saving-authorization.md @@ -1,7 +1,7 @@ # Saving Card Authorization -It is possible to store a customer’s card authorization by enabling the `save_authorization` parameter when creating a payment. -This allows you to create follow-up (“child”) payments seamlessly, without requiring the customer to reauthorize their card. +It is possible to store a customer's card authorization by enabling the `save_authorization` parameter when creating a payment. +This allows you to create follow-up ("child") payments seamlessly, without requiring the customer to reauthorize their card. However, this feature must not be confused with — or used for — [subscription payments](subscription.md). Those have a separate workflow and rules. @@ -29,22 +29,47 @@ Once the payment is successfully completed, the system will store a reusable aut After the original payment (with `save_authorization = true`) has been paid, you can realize a new payment using the stored authorization: ```php +use ThePay\ApiClient\Model\RecurringPaymentResult; + /** @var \ThePay\ApiClient\TheClient $thePayClient */ // First parameter: UID of the new (child) payment -// Second parameter: amount in cents (optional; if null, parent amount is used; required if currency is set) -// Third parameter: currency code (optional; if null, parent currency is used; required if amount is set) -$params = new \ThePay\ApiClient\Model\RealizePaymentBySavedAuthorizationParams('uid_childpayment', 1000, 'EUR'); +// Second parameter: amount in cents (required) +// Third parameter: currency code (required) +$params = new \ThePay\ApiClient\Model\RealizePaymentBySavedAuthorizationParams('childpayment', 1000, 'EUR'); // adding items is optional, if you do not add any item, items from parent payment will be used $item = new \ThePay\ApiClient\Model\CreatePaymentItem('item', 'Server setup', 1000, 1); $params->addItem($item); // First parameter: UID of the parent payment (one created with saveAuthorization=true) -// The method returns ApiResponse -$response = $thePayClient->realizePaymentBySavedAuthorization('uid_savedauthtest', $params); +// The method returns RecurringPaymentResult +$result = $thePayClient->realizePaymentBySavedAuthorization('uid_savedauthtest', $params); + +match ($result->getState()) { + RecurringPaymentResult::STATE_PAID => + echo 'Payment was realized using saved authorization', + + RecurringPaymentResult::STATE_WAITING_FOR_CONFIRMATION => + echo 'Payment is being processed, you will receive a notification when complete', -if ($response->wasSuccessful()) { - echo 'Payment was realized using saved authorization'; + RecurringPaymentResult::STATE_ERROR => + echo 'Payment was not realized', +}; + +// Check if more payments can be realized with this saved authorization +if (!$result->isRecurringPaymentsAvailable()) { + // Saved authorization is no longer valid, customer needs to authorize a new payment + echo 'Saved authorization is no longer valid, customer needs to authorize a new payment'; } ``` + +**Note about V2 API:** +The V2 API introduces several important changes: +- **Amount and currency are now required** - you must always specify both parameters +- **Asynchronous processing**: Payment may have these states: + - `paid` - Payment realized successfully + - `error` - Payment realization failed + - `waiting_for_confirmation` - Payment is being processed asynchronously +- **Parent availability tracking**: Check `isRecurringPaymentsAvailable()` to know if the saved authorization is still valid +- You will receive a notification when async payments complete (state changes to `paid` or `error`) diff --git a/doc/subscription.md b/doc/subscription.md index 292c09b..e5576f8 100644 --- a/doc/subscription.md +++ b/doc/subscription.md @@ -46,6 +46,8 @@ After the parent payment is paid, you may charge the customer again using one of ### Realizing a Regular (Fixed Interval & Fixed Amount) Subscription ```php +use ThePay\ApiClient\Model\RecurringPaymentResult; + /** @var \ThePay\ApiClient\TheClient $thePayClient */ // UID of the new (child) payment @@ -56,17 +58,40 @@ $item = new \ThePay\ApiClient\Model\CreatePaymentItem('item', 'Magazine #2', 105 $params->addItem($item); // Parent payment UID is passed as the first parameter. -// Method returns an ApiResponse. -$response = $thePayClient->realizeRegularSubscriptionPayment('uid_subscriptionpayment', $params); +// Method returns a RecurringPaymentResult. +$result = $thePayClient->realizeRegularSubscriptionPayment('uid_subscriptionpayment', $params); + +match ($result->getState()) { + RecurringPaymentResult::STATE_PAID => + echo 'Subscription payment was realized', + + RecurringPaymentResult::STATE_WAITING_FOR_CONFIRMATION => + echo 'Payment is being processed, you will receive a notification when complete', + + RecurringPaymentResult::STATE_ERROR => + echo 'Payment was not realized', +}; -if ($response->wasSuccessful()) { - echo 'Subscription payment was realized'; +// Check if more payments can be realized with this parent +if (!$result->isRecurringPaymentsAvailable()) { + // No more payments can be realized with this parent, inform customer to create new subscription + echo 'Saved authorization is no longer valid, customer needs to authorize a new payment'; } ``` +**Note about V2 API:** +The V2 API supports asynchronous payment processing: +- State `paid` means immediate success +- State `error` means immediate failure +- State `waiting_for_confirmation` means the payment is being processed asynchronously +- You will receive a notification when the async payment completes (state changes to `paid` or `error`) +- Always check `isRecurringPaymentsAvailable()` to know if the subscription should end + ### Realizing an Irregular (Variable Interval & Fixed Amount) Subscription ```php +use ThePay\ApiClient\Model\RecurringPaymentResult; + /** @var \ThePay\ApiClient\TheClient $thePayClient */ // UID of the new (child) payment @@ -77,17 +102,32 @@ $item = new \ThePay\ApiClient\Model\CreatePaymentItem('item', 'New book', 10520, $params->addItem($item); // Parent payment UID is passed as the first parameter. -// Method returns an ApiResponse. -$response = $thePayClient->realizeIrregularSubscriptionPayment('uid_subscriptionpayment', $params); +// Method returns a RecurringPaymentResult. +$result = $thePayClient->realizeIrregularSubscriptionPayment('uid_subscriptionpayment', $params); + +match ($result->getState()) { + RecurringPaymentResult::STATE_PAID => + echo 'Subscription payment was realized', -if ($response->wasSuccessful()) { - echo 'Subscription payment was realized'; + RecurringPaymentResult::STATE_WAITING_FOR_CONFIRMATION => + echo 'Payment is being processed, you will receive a notification when complete', + + RecurringPaymentResult::STATE_ERROR => + echo 'Payment was not realized', +}; + +// Check if more payments can be realized +if (!$result->isRecurringPaymentsAvailable()) { + // Parent payment no longer available for new subscriptions + echo 'Parent payment no longer available for new subscriptions'; } ``` ### Realizing a Usage-Based (Fixed Interval & Variable Amount) Subscription ```php +use ThePay\ApiClient\Model\RecurringPaymentResult; + /** @var \ThePay\ApiClient\TheClient $thePayClient */ // First param: UID of child payment @@ -100,10 +140,23 @@ $params->addItem($item); // Parent payment UID is passed as the first parameter. -// Method returns an ApiResponse. -$response = $thePayClient->realizeUsageBasedSubscriptionPayment('uid_subscriptionpayment', $params); +// Method returns a RecurringPaymentResult. +$result = $thePayClient->realizeUsageBasedSubscriptionPayment('uid_subscriptionpayment', $params); + +match ($result->getState()) { + RecurringPaymentResult::STATE_PAID => + echo 'Subscription payment was realized', + + RecurringPaymentResult::STATE_WAITING_FOR_CONFIRMATION => + echo 'Payment is being processed, you will receive a notification when complete', + + RecurringPaymentResult::STATE_ERROR => + echo 'Payment was not realized', +}; -if ($response->wasSuccessful()) { - echo 'Subscription payment was realized'; +// Check if more payments can be realized +if (!$result->isRecurringPaymentsAvailable()) { + // Parent payment no longer available for new subscriptions + echo 'Parent payment no longer available for new subscriptions'; } ``` diff --git a/src/Model/ApiResponse.php b/src/Model/ApiResponse.php deleted file mode 100644 index 0265b3b..0000000 --- a/src/Model/ApiResponse.php +++ /dev/null @@ -1,66 +0,0 @@ - $values - * @param int $statusCode - */ - public function __construct($values, $statusCode) - { - $data = is_array($values) ? $values : Json::decode($values, true); - - $this->state = isset($data['state']) ? $data['state'] : null; - $this->message = isset($data['message']) ? $data['message'] : null; - $this->statusCode = $statusCode; - } - - /** - * @return string|null - */ - public function getState() - { - return $this->state; - } - - /** - * @return string|null - */ - public function getMessage() - { - return $this->message; - } - - /** - * @return int - */ - public function getStatusCode() - { - return $this->statusCode; - } - - /** - * Determines if the subscription payment was realized. - * - * @return bool - */ - public function wasSuccessful() - { - return $this->statusCode === 200 && $this->state === 'success'; - } -} diff --git a/src/Model/RealizePaymentBySavedAuthorizationParams.php b/src/Model/RealizePaymentBySavedAuthorizationParams.php index 95b68d2..9aadac9 100644 --- a/src/Model/RealizePaymentBySavedAuthorizationParams.php +++ b/src/Model/RealizePaymentBySavedAuthorizationParams.php @@ -2,14 +2,13 @@ namespace ThePay\ApiClient\Model; -use InvalidArgumentException; use ThePay\ApiClient\ValueObject\Amount; use ThePay\ApiClient\ValueObject\CurrencyCode; use ThePay\ApiClient\ValueObject\Identifier; final class RealizePaymentBySavedAuthorizationParams implements SignableRequest { - /** @var Amount|null */ + /** @var Amount */ private $amount; /** @var CreatePaymentItem[] */ @@ -18,7 +17,7 @@ final class RealizePaymentBySavedAuthorizationParams implements SignableRequest /** @var Identifier */ private $uid; - /** @var CurrencyCode|null */ + /** @var CurrencyCode */ private $currencyCode; /** @var string|null */ @@ -27,25 +26,26 @@ final class RealizePaymentBySavedAuthorizationParams implements SignableRequest /** @var string|null */ protected $descriptionForMerchant = null; + protected ?string $notifUrl = null; + /** * RealizePaymentBySavedAuthorizationParams constructor. * * @param string $uid - * @param int|null $amount - payment amount in cents, if set to null it will use amount from parent payment, required if $currencyCode is present - * @param string|null $currencyCode required if $amount is present + * @param int $amount - payment amount in cents (required) + * @param string $currencyCode - currency code (required) * @param string|null $orderId * @param string|null $descriptionForMerchant + * @param string|null $notifUrl */ - public function __construct($uid, $amount = null, $currencyCode = null, $orderId = null, $descriptionForMerchant = null) + public function __construct($uid, $amount, $currencyCode, $orderId = null, $descriptionForMerchant = null, ?string $notifUrl = null) { - if (($amount === null && $currencyCode !== null) || ($amount !== null && $currencyCode === null)) { - throw new InvalidArgumentException('Amount and currency code is required if one of these parameters have value.'); - } $this->uid = new Identifier($uid); - $this->amount = $amount === null ? null : new Amount($amount); - $this->currencyCode = $currencyCode === null ? null : new CurrencyCode($currencyCode); + $this->amount = new Amount($amount); + $this->currencyCode = new CurrencyCode($currencyCode); $this->orderId = $orderId; $this->descriptionForMerchant = $descriptionForMerchant; + $this->notifUrl = $notifUrl; } /** @@ -96,6 +96,17 @@ public function getDescriptionForMerchant() return $this->descriptionForMerchant; } + public function getNotifUrl(): ?string + { + return $this->notifUrl; + } + + public function setNotifUrl(string $notifUrl): self + { + $this->notifUrl = $notifUrl; + return $this; + } + /** * If no items will be set, the items from parent payment will be used. * @@ -116,22 +127,25 @@ public function toArray() { $result = [ 'uid' => $this->uid->getValue(), - 'items' => null, - 'orderId' => $this->orderId, - 'descriptionForMerchant' => $this->descriptionForMerchant, + 'value' => [ + 'amount' => (string) $this->amount->getValue(), + 'currency' => $this->currencyCode->getValue(), + ], + 'order_id' => $this->orderId, + 'description_for_merchant' => $this->descriptionForMerchant, ]; if ($this->items) { + $result['items'] = []; foreach ($this->items as $item) { $result['items'][] = $item->toArray(); } + } else { + $result['items'] = null; } - if ($this->amount) { - $result['value'] = [ - 'amount' => $this->amount->getValue(), - 'currency' => $this->currencyCode->getValue(), - ]; + if ($this->notifUrl !== null) { + $result['notif_url'] = $this->notifUrl; } return $result; diff --git a/src/Model/RealizePreauthorizedPaymentResult.php b/src/Model/RealizePreauthorizedPaymentResult.php new file mode 100644 index 0000000..aaeb5ac --- /dev/null +++ b/src/Model/RealizePreauthorizedPaymentResult.php @@ -0,0 +1,38 @@ + $data + */ + public function __construct($data) + { + $decoded = is_array($data) ? $data : Json::decode($data, true); + + $this->state = $decoded['state']; + } + + /** + * @return self::STATE_* + */ + public function getState(): string + { + return $this->state; + } +} diff --git a/src/Model/RealizeSubscriptionPaymentParams.php b/src/Model/RealizeSubscriptionPaymentParams.php index a430991..d074de0 100644 --- a/src/Model/RealizeSubscriptionPaymentParams.php +++ b/src/Model/RealizeSubscriptionPaymentParams.php @@ -22,6 +22,8 @@ abstract class RealizeSubscriptionPaymentParams implements SignableRequest /** @var string|null */ protected $descriptionForMerchant = null; + protected ?string $notifUrl = null; + /** * @return Amount */ @@ -62,6 +64,17 @@ public function getDescriptionForMerchant() return $this->descriptionForMerchant; } + public function getNotifUrl(): ?string + { + return $this->notifUrl; + } + + public function setNotifUrl(string $notifUrl): self + { + $this->notifUrl = $notifUrl; + return $this; + } + /** * If no items will be set, the items from parent payment will be used. * @@ -81,7 +94,7 @@ public function addItem(CreatePaymentItem $item) public function toArray() { $result = [ - 'payment_uid' => $this->uid->getValue(), + 'uid' => $this->uid->getValue(), 'items' => null, 'order_id' => $this->orderId, 'description_for_merchant' => $this->descriptionForMerchant, @@ -94,7 +107,11 @@ public function toArray() } if ($this->amount) { - $result['amount'] = $this->amount->getValue(); + $result['amount'] = (string) $this->amount->getValue(); + } + + if ($this->notifUrl !== null) { + $result['notif_url'] = $this->notifUrl; } return $result; diff --git a/src/Model/RecurringPaymentResult.php b/src/Model/RecurringPaymentResult.php new file mode 100644 index 0000000..628813b --- /dev/null +++ b/src/Model/RecurringPaymentResult.php @@ -0,0 +1,69 @@ + $data + */ + public function __construct($data) + { + $decoded = is_array($data) ? $data : Json::decode($data, true); + + $this->state = $decoded['state']; + $this->message = $decoded['message'] ?? null; + $this->recurringPaymentsAvailable = $decoded['parent']['recurring_payments_available'] ?? true; + } + + /** + * @return self::STATE_* + */ + public function getState(): string + { + return $this->state; + } + + /** + * Get optional message describing the result. + */ + public function getMessage(): ?string + { + return $this->message; + } + + /** + * Check if more recurring payments can be realized using the parent payment. + * + * When false, the subscription/authorization should end because the parent + * payment is no longer available for new realizations. + * + * In this case, you should inform the customer to create a new subscription + * or authorize a new payment. + */ + public function isRecurringPaymentsAvailable(): bool + { + return $this->recurringPaymentsAvailable; + } +} diff --git a/src/Service/ApiService.php b/src/Service/ApiService.php index daff607..f1a1aa9 100644 --- a/src/Service/ApiService.php +++ b/src/Service/ApiService.php @@ -10,7 +10,6 @@ use ThePay\ApiClient\Filter\PaymentsFilter; use ThePay\ApiClient\Filter\TransactionFilter; use ThePay\ApiClient\Model\AccountBalance; -use ThePay\ApiClient\Model\ApiResponse; use ThePay\ApiClient\Model\Collection\PaymentCollection; use ThePay\ApiClient\Model\Collection\PaymentMethodCollection; use ThePay\ApiClient\Model\Collection\TransactionCollection; @@ -25,8 +24,10 @@ use ThePay\ApiClient\Model\RealizeIrregularSubscriptionPaymentParams; use ThePay\ApiClient\Model\RealizePaymentBySavedAuthorizationParams; use ThePay\ApiClient\Model\RealizePreauthorizedPaymentParams; +use ThePay\ApiClient\Model\RealizePreauthorizedPaymentResult; use ThePay\ApiClient\Model\RealizeRegularSubscriptionPaymentParams; use ThePay\ApiClient\Model\RealizeUsageBasedSubscriptionPaymentParams; +use ThePay\ApiClient\Model\RecurringPaymentResult; use ThePay\ApiClient\TheClient; use ThePay\ApiClient\TheConfig; use ThePay\ApiClient\Utils\Json; @@ -256,18 +257,18 @@ public function getPayments(PaymentsFilter $filter, int $page = 1, int $limit = * * @throws ApiException */ - public function realizeRegularSubscriptionPayment(Identifier $parentPaymentUid, RealizeRegularSubscriptionPaymentParams $params): ApiResponse + public function realizeRegularSubscriptionPayment(Identifier $parentPaymentUid, RealizeRegularSubscriptionPaymentParams $params): RecurringPaymentResult { $jsonParams = $params->toArray(); - $url = $this->url(['payments', $parentPaymentUid, 'subscription', SubscriptionType::REGULAR]); + $url = $this->url(['projects', $this->config->getProjectId(), 'payments', $parentPaymentUid, 'subscription', SubscriptionType::REGULAR], [], false, 'v2'); $response = $this->sendRequest(self::METHOD_POST, $url, $jsonParams); - if ( ! in_array($response->getStatusCode(), [200, 201], true)) { + if ( ! in_array($response->getStatusCode(), [200, 202], true)) { throw $this->buildException($url, $response); } - return new ApiResponse($response->getBody()->getContents(), $response->getStatusCode()); + return new RecurringPaymentResult($response->getBody()->getContents()); } /** @@ -275,18 +276,18 @@ public function realizeRegularSubscriptionPayment(Identifier $parentPaymentUid, * * @throws ApiException */ - public function realizeIrregularSubscriptionPayment(Identifier $parentPaymentUid, RealizeIrregularSubscriptionPaymentParams $params): ApiResponse + public function realizeIrregularSubscriptionPayment(Identifier $parentPaymentUid, RealizeIrregularSubscriptionPaymentParams $params): RecurringPaymentResult { $jsonParams = $params->toArray(); - $url = $this->url(['payments', $parentPaymentUid, 'subscription', SubscriptionType::IRREGULAR]); + $url = $this->url(['projects', $this->config->getProjectId(), 'payments', $parentPaymentUid, 'subscription', SubscriptionType::IRREGULAR], [], false, 'v2'); $response = $this->sendRequest(self::METHOD_POST, $url, $jsonParams); - if ( ! in_array($response->getStatusCode(), [200, 201], true)) { + if ( ! in_array($response->getStatusCode(), [200, 202], true)) { throw $this->buildException($url, $response); } - return new ApiResponse($response->getBody()->getContents(), $response->getStatusCode()); + return new RecurringPaymentResult($response->getBody()->getContents()); } /** @@ -294,18 +295,18 @@ public function realizeIrregularSubscriptionPayment(Identifier $parentPaymentUid * * @throws ApiException */ - public function realizeUsageBasedSubscriptionPayment(Identifier $parentPaymentUid, RealizeUsageBasedSubscriptionPaymentParams $params): ApiResponse + public function realizeUsageBasedSubscriptionPayment(Identifier $parentPaymentUid, RealizeUsageBasedSubscriptionPaymentParams $params): RecurringPaymentResult { $jsonParams = $params->toArray(); - $url = $this->url(['payments', $parentPaymentUid, 'subscription', SubscriptionType::USAGE_BASED]); + $url = $this->url(['projects', $this->config->getProjectId(), 'payments', $parentPaymentUid, 'subscription', SubscriptionType::USAGE_BASED], [], false, 'v2'); $response = $this->sendRequest(self::METHOD_POST, $url, $jsonParams); - if ( ! in_array($response->getStatusCode(), [200, 201], true)) { + if ( ! in_array($response->getStatusCode(), [200, 202], true)) { throw $this->buildException($url, $response); } - return new ApiResponse($response->getBody()->getContents(), $response->getStatusCode()); + return new RecurringPaymentResult($response->getBody()->getContents()); } /** @@ -313,18 +314,18 @@ public function realizeUsageBasedSubscriptionPayment(Identifier $parentPaymentUi * * @throws ApiException */ - public function realizePaymentBySavedAuthorization(Identifier $parentPaymentUid, RealizePaymentBySavedAuthorizationParams $params): ApiResponse + public function realizePaymentBySavedAuthorization(Identifier $parentPaymentUid, RealizePaymentBySavedAuthorizationParams $params): RecurringPaymentResult { $jsonParams = $params->toArray(); - $url = $this->url(['payments', $parentPaymentUid, 'savedauthorization']); + $url = $this->url(['projects', $this->config->getProjectId(), 'payments', $parentPaymentUid, 'savedauthorization'], [], false, 'v2'); $response = $this->sendRequest(self::METHOD_POST, $url, $jsonParams); - if ( ! in_array($response->getStatusCode(), [200, 201], true)) { + if ( ! in_array($response->getStatusCode(), [200, 202], true)) { throw $this->buildException($url, $response); } - return new ApiResponse($response->getBody()->getContents(), $response->getStatusCode()); + return new RecurringPaymentResult($response->getBody()->getContents()); } @@ -372,18 +373,22 @@ public function changePaymentMethod(Identifier $uid, string $methodCode): void /** * @throws ApiException */ - public function realizePreauthorizedPayment(RealizePreauthorizedPaymentParams $params): void + public function realizePreauthorizedPayment(RealizePreauthorizedPaymentParams $params): RealizePreauthorizedPaymentResult { $url = $this->url([ + 'projects', + $this->config->getProjectId(), 'payments', $params->getUid(), 'preauthorized', - ]); + ], [], false, 'v2'); $response = $this->sendRequest(self::METHOD_POST, $url, $params->toArray()); - if ($response->getStatusCode() !== 204) { + if ( ! in_array($response->getStatusCode(), [200, 202], true)) { throw $this->buildException($url, $response); } + + return new RealizePreauthorizedPaymentResult($response->getBody()->getContents()); } /** @@ -503,9 +508,10 @@ public function generatePaymentConfirmationPdf(Identifier $uid, ?LanguageCode $l * @param array $path * @param array $arguments * @param bool $includeProject + * @param non-empty-string|null $specificVersion * @return string */ - private function url($path = [], $arguments = [], $includeProject = true) + private function url($path = [], $arguments = [], $includeProject = true, ?string $specificVersion = null) { if ( ! isset($arguments['merchant_id'])) { ($arguments['merchant_id'] = $this->config->getMerchantId()); @@ -524,7 +530,7 @@ private function url($path = [], $arguments = [], $includeProject = true) $pathImploded .= '/'; } - $apiUrl = $this->config->getApiUrl(); + $apiUrl = $this->config->getApiUrl($specificVersion); $pathImploded = substr($pathImploded, 0, -1); diff --git a/src/Service/ApiServiceInterface.php b/src/Service/ApiServiceInterface.php index 094bd57..d2032b5 100644 --- a/src/Service/ApiServiceInterface.php +++ b/src/Service/ApiServiceInterface.php @@ -6,7 +6,6 @@ use ThePay\ApiClient\Filter\PaymentsFilter; use ThePay\ApiClient\Filter\TransactionFilter; use ThePay\ApiClient\Model\AccountBalance; -use ThePay\ApiClient\Model\ApiResponse; use ThePay\ApiClient\Model\Collection\PaymentCollection; use ThePay\ApiClient\Model\Collection\PaymentMethodCollection; use ThePay\ApiClient\Model\Collection\TransactionCollection; @@ -19,8 +18,10 @@ use ThePay\ApiClient\Model\RealizeIrregularSubscriptionPaymentParams; use ThePay\ApiClient\Model\RealizePaymentBySavedAuthorizationParams; use ThePay\ApiClient\Model\RealizePreauthorizedPaymentParams; +use ThePay\ApiClient\Model\RealizePreauthorizedPaymentResult; use ThePay\ApiClient\Model\RealizeRegularSubscriptionPaymentParams; use ThePay\ApiClient\Model\RealizeUsageBasedSubscriptionPaymentParams; +use ThePay\ApiClient\Model\RecurringPaymentResult; use ThePay\ApiClient\ValueObject\Amount; use ThePay\ApiClient\ValueObject\Identifier; use ThePay\ApiClient\ValueObject\LanguageCode; @@ -61,34 +62,34 @@ public function invalidatePayment(Identifier $paymentUid); /** * @param Identifier $parentPaymentUid UID of payment which initialized this subscription. * @param RealizeRegularSubscriptionPaymentParams $params - * @return ApiResponse + * @return RecurringPaymentResult * @throws ApiException */ - public function realizeRegularSubscriptionPayment(Identifier $parentPaymentUid, RealizeRegularSubscriptionPaymentParams $params); + public function realizeRegularSubscriptionPayment(Identifier $parentPaymentUid, RealizeRegularSubscriptionPaymentParams $params): RecurringPaymentResult; /** * @param Identifier $parentPaymentUid UID of payment which initialized this subscription. * @param RealizeIrregularSubscriptionPaymentParams $params - * @return ApiResponse + * @return RecurringPaymentResult * @throws ApiException */ - public function realizeIrregularSubscriptionPayment(Identifier $parentPaymentUid, RealizeIrregularSubscriptionPaymentParams $params); + public function realizeIrregularSubscriptionPayment(Identifier $parentPaymentUid, RealizeIrregularSubscriptionPaymentParams $params): RecurringPaymentResult; /** * @param Identifier $parentPaymentUid UID of payment which initialized this subscription. * @param RealizeUsageBasedSubscriptionPaymentParams $params - * @return ApiResponse + * @return RecurringPaymentResult * @throws ApiException */ - public function realizeUsageBasedSubscriptionPayment(Identifier $parentPaymentUid, RealizeUsageBasedSubscriptionPaymentParams $params); + public function realizeUsageBasedSubscriptionPayment(Identifier $parentPaymentUid, RealizeUsageBasedSubscriptionPaymentParams $params): RecurringPaymentResult; /** * @param Identifier $parentPaymentUid UID of first payment created with save_authorization=true. * @param RealizePaymentBySavedAuthorizationParams $params - * @return ApiResponse + * @return RecurringPaymentResult * @throws ApiException */ - public function realizePaymentBySavedAuthorization(Identifier $parentPaymentUid, RealizePaymentBySavedAuthorizationParams $params); + public function realizePaymentBySavedAuthorization(Identifier $parentPaymentUid, RealizePaymentBySavedAuthorizationParams $params): RecurringPaymentResult; /** * @param int<1, max> $page @@ -118,7 +119,10 @@ public function getAccountTransactionHistory(TransactionFilter $filter, int $pag */ public function createPayment(CreatePaymentParams $createPaymentParams, ?string $methodCode = null): CreatePaymentResponse; - public function realizePreauthorizedPayment(RealizePreauthorizedPaymentParams $params): void; + /** + * @throws ApiException + */ + public function realizePreauthorizedPayment(RealizePreauthorizedPaymentParams $params): RealizePreauthorizedPaymentResult; public function cancelPreauthorizedPayment(Identifier $uid): void; diff --git a/src/TheClient.php b/src/TheClient.php index db78306..112fbb0 100644 --- a/src/TheClient.php +++ b/src/TheClient.php @@ -9,7 +9,6 @@ use ThePay\ApiClient\Filter\PaymentsFilter; use ThePay\ApiClient\Filter\TransactionFilter; use ThePay\ApiClient\Model\AccountBalance; -use ThePay\ApiClient\Model\ApiResponse; use ThePay\ApiClient\Model\Collection\PaymentCollection; use ThePay\ApiClient\Model\Collection\PaymentMethodCollection; use ThePay\ApiClient\Model\CreatePaymentParams; @@ -20,8 +19,10 @@ use ThePay\ApiClient\Model\RealizeIrregularSubscriptionPaymentParams; use ThePay\ApiClient\Model\RealizePaymentBySavedAuthorizationParams; use ThePay\ApiClient\Model\RealizePreauthorizedPaymentParams; +use ThePay\ApiClient\Model\RealizePreauthorizedPaymentResult; use ThePay\ApiClient\Model\RealizeRegularSubscriptionPaymentParams; use ThePay\ApiClient\Model\RealizeUsageBasedSubscriptionPaymentParams; +use ThePay\ApiClient\Model\RecurringPaymentResult; use ThePay\ApiClient\Model\SimplePayment; use ThePay\ApiClient\Model\SimpleTransaction; use ThePay\ApiClient\Service\ApiServiceInterface; @@ -146,10 +147,10 @@ public function invalidatePayment($paymentUid) /** * @param string $parentPaymentUid UID of payment which initialized this subscription. * @param RealizeRegularSubscriptionPaymentParams $params - * @return ApiResponse + * @return RecurringPaymentResult * @throws ApiException|InvalidArgumentException */ - public function realizeRegularSubscriptionPayment($parentPaymentUid, RealizeRegularSubscriptionPaymentParams $params) + public function realizeRegularSubscriptionPayment($parentPaymentUid, RealizeRegularSubscriptionPaymentParams $params): RecurringPaymentResult { $this->validateUid($parentPaymentUid); return $this->api->realizeRegularSubscriptionPayment(new Identifier($parentPaymentUid), $params); @@ -158,10 +159,10 @@ public function realizeRegularSubscriptionPayment($parentPaymentUid, RealizeRegu /** * @param string $parentPaymentUid UID of payment which initialized this subscription. * @param RealizeIrregularSubscriptionPaymentParams $params - * @return ApiResponse + * @return RecurringPaymentResult * @throws ApiException|InvalidArgumentException */ - public function realizeIrregularSubscriptionPayment($parentPaymentUid, RealizeIrregularSubscriptionPaymentParams $params) + public function realizeIrregularSubscriptionPayment($parentPaymentUid, RealizeIrregularSubscriptionPaymentParams $params): RecurringPaymentResult { $this->validateUid($parentPaymentUid); return $this->api->realizeIrregularSubscriptionPayment(new Identifier($parentPaymentUid), $params); @@ -170,10 +171,10 @@ public function realizeIrregularSubscriptionPayment($parentPaymentUid, RealizeIr /** * @param string $parentPaymentUid UID of payment which initialized this subscription. * @param RealizeUsageBasedSubscriptionPaymentParams $params - * @return ApiResponse + * @return RecurringPaymentResult * @throws ApiException|InvalidArgumentException */ - public function realizeUsageBasedSubscriptionPayment($parentPaymentUid, RealizeUsageBasedSubscriptionPaymentParams $params) + public function realizeUsageBasedSubscriptionPayment($parentPaymentUid, RealizeUsageBasedSubscriptionPaymentParams $params): RecurringPaymentResult { $this->validateUid($parentPaymentUid); return $this->api->realizeUsageBasedSubscriptionPayment(new Identifier($parentPaymentUid), $params); @@ -182,10 +183,10 @@ public function realizeUsageBasedSubscriptionPayment($parentPaymentUid, RealizeU /** * @param string $parentPaymentUid UID of first payment created with save_authorization=true. * @param RealizePaymentBySavedAuthorizationParams $params - * @return ApiResponse + * @return RecurringPaymentResult * @throws ApiException|InvalidArgumentException */ - public function realizePaymentBySavedAuthorization($parentPaymentUid, RealizePaymentBySavedAuthorizationParams $params) + public function realizePaymentBySavedAuthorization($parentPaymentUid, RealizePaymentBySavedAuthorizationParams $params): RecurringPaymentResult { $this->validateUid($parentPaymentUid); return $this->api->realizePaymentBySavedAuthorization(new Identifier($parentPaymentUid), $params); @@ -283,13 +284,13 @@ public function changePaymentMethod(string $paymentUid, string $methodCode): voi /** * @param RealizePreauthorizedPaymentParams $params - * + * @return RealizePreauthorizedPaymentResult * @throws ApiException|InvalidArgumentException */ - public function realizePreauthorizedPayment(RealizePreauthorizedPaymentParams $params): void + public function realizePreauthorizedPayment(RealizePreauthorizedPaymentParams $params): RealizePreauthorizedPaymentResult { $this->validateUid($params->getUid()->getValue()); - $this + return $this ->api ->realizePreauthorizedPayment($params); } diff --git a/src/TheConfig.php b/src/TheConfig.php index ba5309a..85b8805 100644 --- a/src/TheConfig.php +++ b/src/TheConfig.php @@ -57,10 +57,14 @@ public function getGateUrl() } /** + * @param non-empty-string|null $specificVersion If specified, it will use this version of the API instead of the default one. * @return string */ - public function getApiUrl() + public function getApiUrl(?string $specificVersion = null): string { + if ($specificVersion !== null) { + return $this->apiUrl->getValue() . $specificVersion . '/'; + } return $this->apiUrl->getValue() . $this->apiVersion . '/'; } diff --git a/tests/RealizePreauthorizationPaymentTest.php b/tests/RealizePreauthorizationPaymentTest.php index a467aff..8ce22b8 100644 --- a/tests/RealizePreauthorizationPaymentTest.php +++ b/tests/RealizePreauthorizationPaymentTest.php @@ -11,6 +11,7 @@ use Psr\Http\Message\RequestInterface; use Psr\Http\Message\ResponseInterface; use ThePay\ApiClient\Model\RealizePreauthorizedPaymentParams; +use ThePay\ApiClient\Model\RealizePreauthorizedPaymentResult; use ThePay\ApiClient\Service\ApiService; use ThePay\ApiClient\Service\SignatureService; use ThePay\ApiClient\TheClient; @@ -46,7 +47,7 @@ public function testRequest(): void ->expects(self::once()) ->method('sendRequest') ->willReturnCallback(function (RequestInterface $request): ResponseInterface { - $expectedUrl = $this->config->getApiUrl() . 'projects/1/payments/abc/preauthorized?merchant_id=' . self::MERCHANT_ID; + $expectedUrl = $this->config->getApiUrl('v2') . 'projects/1/payments/abc/preauthorized?merchant_id=' . self::MERCHANT_ID; self::assertSame('POST', $request->getMethod()); self::assertSame($expectedUrl, $request->getUri()->__toString()); @@ -56,7 +57,10 @@ public function testRequest(): void }) ; - $this->client->realizePreauthorizedPayment(new RealizePreauthorizedPaymentParams(100, 'abc')); + $response = $this->client->realizePreauthorizedPayment(new RealizePreauthorizedPaymentParams(100, 'abc')); + + self::assertInstanceOf(RealizePreauthorizedPaymentResult::class, $response); + self::assertSame(RealizePreauthorizedPaymentResult::STATE_PAID, $response->getState()); } public function testNotOkResponse(): void @@ -70,7 +74,7 @@ public function testNotOkResponse(): void private function getOkResponse(): ResponseInterface { - return new Response(204); + return new Response(200, [], '{"state":"paid"}'); } private function getNotOkResponse(): ResponseInterface diff --git a/tests/RealizeSavedAuthorizationPaymentTest.php b/tests/RealizeSavedAuthorizationPaymentTest.php index 6e2e067..00812e9 100644 --- a/tests/RealizeSavedAuthorizationPaymentTest.php +++ b/tests/RealizeSavedAuthorizationPaymentTest.php @@ -4,7 +4,7 @@ namespace ThePay\ApiClient\Tests; -use ThePay\ApiClient\Model\ApiResponse; +use ThePay\ApiClient\Model\RecurringPaymentResult; use ThePay\ApiClient\Model\RealizePaymentBySavedAuthorizationParams; use ThePay\ApiClient\Service\ApiServiceInterface; use ThePay\ApiClient\TheClient; @@ -17,12 +17,14 @@ protected function setUp(): void { parent::setUp(); - $okResponse = new ApiResponse( + $okResponse = new RecurringPaymentResult( '{ - "state": "success", - "message": "Ok" - }', - 200 + "state": "paid", + "message": "Ok", + "parent": { + "recurring_payments_available": true + } + }' ); $apiService = $this->createMock(ApiServiceInterface::class); @@ -33,9 +35,11 @@ protected function setUp(): void public function testRealizePaymentBySavedAuthorization(): void { - $params = new RealizePaymentBySavedAuthorizationParams('childPayment'); + $params = new RealizePaymentBySavedAuthorizationParams('childPayment', 10000, 'CZK'); $result = $this->client->realizePaymentBySavedAuthorization('parentUid', $params); - self::assertSame(ApiResponse::class, get_class($result)); + self::assertSame(RecurringPaymentResult::class, get_class($result)); + self::assertSame(RecurringPaymentResult::STATE_PAID, $result->getState()); + self::assertTrue($result->isRecurringPaymentsAvailable()); } } diff --git a/tests/RealizeSubscriptionPaymentTest.php b/tests/RealizeSubscriptionPaymentTest.php index 246441f..c86ebe2 100644 --- a/tests/RealizeSubscriptionPaymentTest.php +++ b/tests/RealizeSubscriptionPaymentTest.php @@ -4,7 +4,7 @@ namespace ThePay\ApiClient\Tests; -use ThePay\ApiClient\Model\ApiResponse; +use ThePay\ApiClient\Model\RecurringPaymentResult; use ThePay\ApiClient\Model\RealizeIrregularSubscriptionPaymentParams; use ThePay\ApiClient\Model\RealizeRegularSubscriptionPaymentParams; use ThePay\ApiClient\Model\RealizeUsageBasedSubscriptionPaymentParams; @@ -19,12 +19,14 @@ protected function setUp(): void { parent::setUp(); - $okResponse = new ApiResponse( + $okResponse = new RecurringPaymentResult( '{ - "state": "success", - "message": "Ok" - }', - 200 + "state": "paid", + "message": "Ok", + "parent": { + "recurring_payments_available": true + } + }' ); $apiService = $this->createMock(ApiServiceInterface::class); @@ -40,16 +42,20 @@ public function testRealizeSubscriptionPayment(): void $params = new RealizeRegularSubscriptionPaymentParams('childPayment'); $result = $this->client->realizeRegularSubscriptionPayment('parentUid', $params); - self::assertSame(ApiResponse::class, get_class($result)); + self::assertSame(RecurringPaymentResult::class, get_class($result)); + self::assertSame(RecurringPaymentResult::STATE_PAID, $result->getState()); + self::assertTrue($result->isRecurringPaymentsAvailable()); $params = new RealizeIrregularSubscriptionPaymentParams('childPayment2'); $result = $this->client->realizeIrregularSubscriptionPayment('parentUid', $params); - self::assertSame(ApiResponse::class, get_class($result)); + self::assertSame(RecurringPaymentResult::class, get_class($result)); + self::assertSame(RecurringPaymentResult::STATE_PAID, $result->getState()); $params = new RealizeUsageBasedSubscriptionPaymentParams('childPayment3', 1000); $result = $this->client->realizeUsageBasedSubscriptionPayment('parentUid', $params); - self::assertSame(ApiResponse::class, get_class($result)); + self::assertSame(RecurringPaymentResult::class, get_class($result)); + self::assertSame(RecurringPaymentResult::STATE_PAID, $result->getState()); } }