diff --git a/README.md b/README.md index b88dfd8..919cb07 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,5 @@ # PAYONE Commerce Platform Server SDK PHP -## Introduction - The PHP SDK helps you to communicate with the PAYONE commerce platform server API. Its primary features are: * convenient PHP wrapper around the API calls and responses: @@ -10,21 +8,994 @@ The PHP SDK helps you to communicate with the PAYONE commerce platform server AP * handling of all the details concerning authentication * handling of required meta data -Its use is demonstrated by an example for most calls. The examples execute a call using the provided API keys. +For a general introduction to the API and the different checkout flows see the documentation: + - General introduction to the [PAYONE Commerce Platform](https://docs.payone.com/pcp/payone-commerce-platform) + - Overview of the [checkout flows](https://docs.payone.com/pcp/checkout-flows) + - Available [payment methods](https://docs.payone.com/pcp/checkout-flows) -## Structure of this repository +## Table of Contents -This repository consists out of the following components: - -1. The source code of the SDK itself: `/src` and `/lib` -2. The source code of the unit and integration tests (including the examples): `/tests` -3. The source code for demos is located `examples/*`. Make sure to run `composer install` and `composer dumb-autoload` before. +- [Introduction](#introduction) +- [Requirements](#requirements) +- [Demo App](#demo-app) +- [API Reference](#api-reference) +- [CommunicatorConfiguration](#communicatorconfiguration) + - [Setup your configuration](#setup-your-configuration) + - [Constants](#constants) + - [Methods](#methods) + - [`__construct`](#construct) + - [`setApiKey`](#setapikey) + - [`getApiKey`](#getapikey) + - [`setApiSecret`](#setapisecret) + - [`getApiSecret`](#getapisecret) + - [`getIntegrator`](#getintegrator) + - [`setIntegrator`](#setintegrator) + - [`setHost`](#sethost) + - [`getHost`](#gethost) + - [`getClientMetaInfo`](#getclientmetainfo) + - [`setClientMetaInfo`](#setclientmetainfo) + - [`addClientMetaInfo`](#addclientmetainfo) + - [`getServerMetaInfo`](#getservermetainfo) + - [`setServerMetaInfo`](#setservermetainfo) + - [`addServerMetaInfo`](#addservermetainfo) + - [`getPredefinedHosts`](#getpredefinedhosts) +- [API Clients](#api-clients) + - [CheckoutApiClient](#checkoutapiclient) + - [Methods](#methods-1) + - [`createCheckout`](#createcheckout) + - [`deleteCheckout`](#deletecheckout) + - [`getCheckout`](#getcheckout) + - [`getCheckouts`](#getcheckouts) + - [`updateCheckout`](#updatecheckout) + - [CommerceCaseApiClient](#commercecaseapiclient) + - [Methods](#methods-2) + - [`createCommerceCase`](#createcommercecase) + - [`getCommerceCase`](#getcommercecase) + - [`getCommerceCases`](#getcommercecases) + - [`updateCommerceCase`](#updatecommercecase) + - [OrderManagementCheckoutActionsApiClient](#ordermanagementcheckoutactionsapiclient) + - [Methods](#methods-3) + - [`cancelOrder`](#cancelorder) + - [`createOrder`](#createorder) + - [`deliverOrder`](#deliverorder) + - [`returnOrder`](#returnorder) + - [PaymentExecutionApiClient](#paymentexecutionapiclient) + - [Methods](#methods-4) + - [`cancelPaymentExecution`](#cancelpaymentexecution) + - [`capturePaymentExecution`](#capturepaymentexecution) + - [`completePayment`](#completepayment) + - [`createPayment`](#createpayment) + - [`refundPaymentExecution`](#refundpaymentexecution) + - [PaymentInformationApiClient](#paymentinformationapiclient) + - [Methods](#methods-5) + - [`createPaymentInformation`](#createpaymentinformation) + - [`getPaymentInformation`](#getpaymentinformation) +- [Contributing](#contributing) +- [Development](#development) +- [Structure of this repository](#structure-of-this-repository) ## Requirements PHP 8.2 or above is required. +## Demo App + +This repo contains a demo app that showcases how to implement a [Step-by-Step Checkout](https://docs.payone.com/pcp/checkout-flows/step-by-step-checkout) and a [One-Stop-Checkout](https://docs.payone.com/pcp/checkout-flows/one-step-checkout). + +Before running the app ensure you have run `composer install` and `composer dumb-autoload` within the demo app directory (`./examples/demo-app`). By default all API calls are send to the pre-production environment of the PAYONE Commerce Platform. Note that the created entities can't deleted completely. + +You can run it within the demo app directory via `php src/DemoApp.php`, make sure to provide all necessary environment variables: +1. `API_KEY` a valid api key for the PAYONE Commerce Platform +1. `API_SECRET` a valid api secret for the PAYONE Commerce Platform +1. `MERCHANT_ID` the merchant id which is needed to identify entities, e.g. commerce cases and checkouts, that belong to you. + +[Jump to the demo app](./examples/demo-app/src/DemoApp.php) + +## API Reference + +All contents of this SDK are availble under the namespace `PayoneCommercePlatform\Sdk`. The SDK groups the endpoints of every resource into its own client, e.g. the `PayoneCommercePlatform\Sdk\ApiClient\CheckoutApiClient` can be used to interact with a checkout. To instantiate a singular client a `PayoneCommercePlatform\Sdk\CommunicatorConfiguration` instance has to provided which at least needs an API Key and Secret to connect to PAYONE Commerce Platform. The reponses and requests as well as their contained objects are provided as PHP classes and enums within the `PayoneCommercePlatform\Sdk\Models` namespace. + +### CommunicatorConfiguration +The CommunicatorConfiguration class is responsible for configuring the connection to the PAYONE Commerce Platform. This class holds essential information such as API keys, host URLs, and metadata required to authenticate and interact with the platform's API. Its needed as configuration to interact with any of the resources. Ensure that the API key and secret are securely stored and only passed to the configuration instance when needed. + +#### Setup your configuration + +To create a configuration object `apiKey` and `apiSecret` are required. You can use `CommunicatorConfiguration::getPredefinedHosts()` to get information about different environments of the PAYONE Commerce Platform. Currently `prod` and `preprod` are available. You should also provide an integrator as a `string`, this helps us in debugging and monitoring process. + +```php +` - The client metadata information. + +##### `setClientMetaInfo` + +```php +public function setClientMetaInfo(array $clientMetaInfo): self +``` + +**Description**: +Sets the client metadata information. + +**Parameters**: +- `array $clientMetaInfo`: The client metadata information. + +**Returns**: +`self` + +##### `addClientMetaInfo` + +```php +public function addClientMetaInfo(string $key, string $value): self +``` + +**Description**: +Adds an entry to the client metadata information. + +**Parameters**: +- `string $key`: The key for the metadata entry. +- `string $value`: The value for the metadata entry. + +**Returns**: +`self` + +##### `getServerMetaInfo` + +```php +public function getServerMetaInfo(): array +``` + +**Description**: +Gets the server metadata information. + +**Returns**: +`array` - The server metadata information. + +##### `setServerMetaInfo` + +```php +public function setServerMetaInfo(array $serverMetaInfo): self +``` + +**Description**: +Sets the server metadata information. + +**Parameters**: +- `array $serverMetaInfo`: The server metadata information. + +**Returns**: +`self` + +##### `addServerMetaInfo` + +```php +public function addServerMetaInfo(string $key, string $value): self +``` + +**Description**: +Adds an entry to the server metadata information. + +**Parameters**: +- `string $key`: The key for the metadata entry. +- `string $value`: The value for the metadata entry. + +**Returns**: +`self` + +##### `getPredefinedHosts` + +```php +public static function getPredefinedHosts(): array +``` + +**Description**: +Gets an array of predefined host settings for the PAYONE Commerce Platform. + +**Returns**: +`array` - An array of predefined host settings. + +### API Clients + +There's a API client class for each resource: + +1. [`PayoneCommercePlatform\Sdk\ApiClient\CheckoutApiClient`](#CheckoutApiClient) +1. [`PayoneCommercePlatform\Sdk\ApiClient\CommerceCaseApiClient`](#CommerceCaseApiClient) +1. [`PayoneCommercePlatform\Sdk\ApiClient\OrderManagementCheckoutActionsApiClient`](#OrderManagementCheckoutActionsApiClient) +1. [`PayoneCommercePlatform\Sdk\ApiClient\PaymentExecutionApiClient`](#PaymentExecutionApiClient) +1. [`PayoneCommercePlatform\Sdk\ApiClient\PaymentInformationApiClient`](#PaymentInformationApiClient) + +#### CheckoutApiClient + +The `CheckoutApiClient` class provides methods to interact with the Checkout resource of the PAYONE Commerce Platform API. This includes creating, updating, retrieving, and deleting checkouts within a commerce case. + +You can create a `CheckoutApiClient` by providing a `CommunicatorConfiguration`. [All endpoints](https://docs.payone.com/pcp/commerce-platform-api#tag/Checkout) are directly exposed as methods on the instance. + +```php +` - An array of `CommerceCaseResponse` objects representing the retrieved commerce cases. + +**Exceptions**: +- `ApiErrorResponseException` +- `ApiResponseRetrievalException` + +###### `updateCommerceCase` + +```php +public function updateCommerceCase( + string $merchantId, + string $commerceCaseId, + Customer $customer +): void +``` + +**Description**: +Updates an existing commerce case with new customer information. + +**Parameters**: +- `string $merchantId`: The unique identifier of the merchant. +- `string $commerceCaseId`: The unique identifier of the commerce case to update. +- `Customer $customer`: The customer data to update in the commerce case. + +**Returns**: +`void` + +**Exceptions**: +- `ApiErrorResponseException` +- `ApiResponseRetrievalException` + +#### OrderManagementCheckoutActionsApiClient + +The `OrderManagementCheckoutActionsApiClient` class provides methods to manage orders related to checkouts within a commerce case. This includes operations such as creating, canceling, delivering, and returning orders. + +You can create a `OrderManagementCheckoutActionsApiClient` by providing a `CommunicatorConfiguration`. [All endpoints](https://docs.payone.com/pcp/commerce-platform-api#tag/OrderManagementCheckoutActions) are directly exposed as methods on the instance. + +```php +getCommerceCases($merchantId); -$commerceCase = $res[0]; - - -$request = new CreateCheckoutRequest(amountOfMoney: new AmountOfMoney(1200, 'EUR')); - -$res = $checkoutApiClient->createCheckout($merchantId, $commerceCase->getCommerceCaseId(), $request); -$checkoutApiClient->deleteCheckout($merchantId, $commerceCase->getCommerceCaseId(), $res->getCheckoutId()); -var_dump($res); diff --git a/examples/demo-app/src/DemoApp.php b/examples/demo-app/src/DemoApp.php new file mode 100644 index 0000000..f5fa0ca --- /dev/null +++ b/examples/demo-app/src/DemoApp.php @@ -0,0 +1,275 @@ +merchantId = getenv('MERCHANT_ID'); + if (empty($this->merchantId)) { + throw new \RuntimeException('required environment variable MERCHANT_ID is not set'); + } + $this->config = new CommunicatorConfiguration( + apiKey: $apiKey, + apiSecret: $apiSecret, + host: CommunicatorConfiguration::getPredefinedHosts()['preprod']['url'], + ); + $this->checkoutClient = new CheckoutApiClient($this->config); + $this->commerceCaseClient = new CommerceCaseApiClient($this->config); + $this->paymentExecutionClient = new PaymentExecutionApiClient($this->config); + $this->orderManagementCheckoutClient = new OrderManagementCheckoutActionsApiClient($this->config); + } + + protected function runMultistepCheckout(string $commercaseMerchantReference): void + { + // create the commercase + $commerceCase = $this->commerceCaseClient->createCommerceCase( + $this->merchantId, + new CreateCommerceCaseRequest( + customer: new Customer( + businessRelation: "B2C", + locale: "de", + personalInformation: new PersonalInformation( + dateOfBirth: "19840604", + name: new PersonalName(firstName: "Rich", surname: "Harris") + ), + contactDetails: new ContactDetails(emailAddress: 'mail@mail.com'), + billingAddress: new Address( + countryCode: 'DE', + zip: '40474', + city: 'Düsseldorf', + street: 'Cecilienallee', + houseNumber: '2', + ), + ), + checkout: new CreateCheckoutRequest( + shoppingCart: new ShoppingCartInput( + items: [new CartItemInput( + invoiceData: new CartItemInvoiceData('Frankenstein - Mary Shelley - Hardcover'), + orderLineDetails: new OrderLineDetailsInput( + productCode: 'shelley-42', + productPrice: 1999, + quantity: 1, + productType: ProductType::GOODS, + taxAmount: 19, + ), + )], + ), + ), + ) + ); + // add shipping information + $this->checkoutClient->updateCheckout( + $this->merchantId, + $commerceCase->getCommerceCaseId(), + $commerceCase->getCheckout()->getCheckoutId(), + new PatchCheckoutRequest( + shipping: new Shipping( + address: new AddressPersonal( + countryCode: 'DE', + zip: '40474', + city: 'Düsseldorf', + street: 'Cecilienallee', + houseNumber: '2', + ) + ) + ), + ); + // confirm the order + $this->orderManagementCheckoutClient->createOrder( + $this->merchantId, + $commerceCase->getCommerceCaseId(), + $commerceCase->getCheckout()->getCheckoutId(), + new OrderRequest( + orderType: OrderType::FULL, + orderReferences: new References(merchantReference: 'o-' . $commercaseMerchantReference), + paymentMethodSpecificInput: new PaymentMethodSpecificInput( + paymentChannel: PaymentChannel::ECOMMERCE, + sepaDirectDebitPaymentMethodSpecificInput: new SepaDirectDebitPaymentMethodSpecificInput( + paymentProductId: 771, + paymentProduct771SpecificInput: new SepaDirectDebitPaymentProduct771SpecificInput( + mandate: new ProcessingMandateInformation( + bankAccountIban: new BankAccountInformation( + iban: 'DE75512108001245126199', + accountHolder: 'Rich Harris', + ), + dateOfSignature: '20240730', + recurrenceType: MandateRecurrenceType::UNIQUE, + uniqueMandateReference: 'm-' . $commercaseMerchantReference, + creditorId: 'DE98ZZZ09999999999', + ), + ), + ), + ), + ), + ); + + $checkout = $this->checkoutClient->getCheckout($this->merchantId, $commerceCase->getCommerceCaseId(), $commerceCase->getCheckout()->getCheckoutId()); + var_dump($checkout); + + // items are ready for shipment, the delivery can be performed to capture the money from the reservation + $delivery = $this->orderManagementCheckoutClient->deliverOrder( + $this->merchantId, + $commerceCase->getCommerceCaseId(), + $commerceCase->getCheckout()->getCheckoutId(), + new DeliverRequest(deliverType: DeliverType::FULL, isFinal: true), + ); + var_dump($delivery); + } + + protected function runSingleStepCheckout(string $commerceCaseMerchantReference): void + { + // create commerce case, checkout and execute payment in one go + try { + $createCommerceCaseRequest = new CreateCommerceCaseRequest( + merchantReference: $commerceCaseMerchantReference, + customer: new Customer( + personalInformation: new PersonalInformation( + dateOfBirth: "19840604", + name: new PersonalName(firstName: "Rich", surname: "Harris") + ), + contactDetails: new ContactDetails(emailAddress: 'mail@mail.com'), + billingAddress: new Address( + countryCode: 'DE', + zip: '40474', + city: 'Düsseldorf', + street: 'Cecilienallee', + houseNumber: '2', + ), + ), + checkout: new CreateCheckoutRequest( + autoExecuteOrder: true, + references: new CheckoutReferences(merchantReference: 'c-' . $commerceCaseMerchantReference), + amountOfMoney: new AmountOfMoney(amount: 5199, currencyCode: 'EUR'), + shipping: new Shipping( + address: new AddressPersonal( + countryCode: 'DE', + zip: '40474', + city: 'Düsseldorf', + street: 'Cecilienallee', + houseNumber: '2', + ) + ), + shoppingCart: new ShoppingCartInput( + items: [new CartItemInput( + invoiceData: new CartItemInvoiceData('Hoodie - Scaleshape Logo - L'), + orderLineDetails: new OrderLineDetailsInput( + productPrice: 5199, + quantity: 1, + productType: ProductType::GOODS, + ), + )] + ), + orderRequest: new OrderRequest( + orderReferences: new References(merchantReference: 'o-' . $commerceCaseMerchantReference), + orderType: OrderType::FULL, + paymentMethodSpecificInput: new PaymentMethodSpecificInput( + sepaDirectDebitPaymentMethodSpecificInput: new SepaDirectDebitPaymentMethodSpecificInput( + paymentProductId: 771, + paymentProduct771SpecificInput: new SepaDirectDebitPaymentProduct771SpecificInput( + mandate: new ProcessingMandateInformation( + bankAccountIban: new BankAccountInformation( + iban: 'DE75512108001245126199', + accountHolder: 'Rich Harris', + ), + dateOfSignature: '20240730', + recurrenceType: MandateRecurrenceType::UNIQUE, + uniqueMandateReference: 'm-' . $commerceCaseMerchantReference, + creditorId: 'DE98ZZZ09999999999', + ), + ), + ), + ), + ), + ), + ); + $response = $this->commerceCaseClient->createCommerceCase($this->merchantId, $createCommerceCaseRequest); + var_dump($response); + $response2 = $this->orderManagementCheckoutClient->deliverOrder( + $this->merchantId, + $response->getCommerceCaseId(), + $response->getCheckout()->getCheckoutId(), + new DeliverRequest(deliverType: DeliverType::FULL, isFinal: true), + ); + var_dump($response2); + } catch (ApiErrorResponseException $e) { + fwrite(\STDERR, $e->getTraceAsString() . "\n"); + fwrite(\STDERR, print_r($e->getErrors(), true)); + exit(1); + } + } + + public function runApp(): void + { + // see: https://docs.payone.com/pcp/checkout-flows/one-step-checkout + // not that the given reference must be unique and has to renewed after each run + $this->runSingleStepCheckout('comb1b3'); + // see: https://docs.payone.com/pcp/checkout-flows/step-by-step-checkout + // not that the given reference must be unique and has to renewed after each run + $this->runMultistepCheckout('com1a3b'); + } + + public static function run(): void + { + $app = new DemoApp(); + $app->runApp(); + } +} +DemoApp::run(); diff --git a/src/PayoneCommercePlatform/Sdk/ApiClient/BaseApiClient.php b/src/PayoneCommercePlatform/Sdk/ApiClient/BaseApiClient.php index c5627fa..786f9fe 100644 --- a/src/PayoneCommercePlatform/Sdk/ApiClient/BaseApiClient.php +++ b/src/PayoneCommercePlatform/Sdk/ApiClient/BaseApiClient.php @@ -83,11 +83,12 @@ protected function makeApiCall(Request $request, ?string $type = null): array { $request = $this->requestHeaderGenerator->generateAdditionalRequestHeaders($request); try { - $response = $this->client->send($request, []); - $this->handleError($response); + $response = $this->client->send($request, ['http_errors' => false]); } catch (RequestException $e) { throw new ApiResponseRetrievalException( statusCode: (int) $e->getCode(), + uri: $request->getUri(), + httpMethod: $request->getMethod(), responseBody: $e->getResponse() ? (string) $e->getResponse()->getBody() : "", message: "[{$e->getCode()}] {$e->getMessage()}", previous: $e, @@ -95,13 +96,15 @@ protected function makeApiCall(Request $request, ?string $type = null): array } catch (ConnectException $e) { throw new ApiResponseRetrievalException( statusCode: (int) $e->getCode(), + uri: $request->getUri(), + httpMethod: $request->getMethod(), responseBody: "", message: "[{$e->getCode()}] {$e->getMessage()}", previous: $e, ); } - $this->handleError($response); + $this->handleError($request, $response); if ($type === null) { return [$type, $response->getStatusCode(), $response->getHeaders()]; @@ -118,6 +121,8 @@ protected function makeApiCall(Request $request, ?string $type = null): array ]; } catch (NotEncodableValueException | UnexpectedValueException $exception) { throw new ApiResponseRetrievalException( + uri: $request->getUri(), + httpMethod: $request->getMethod(), message: sprintf( 'Error JSON decoding server response (%s)', $request->getUri() @@ -129,7 +134,7 @@ protected function makeApiCall(Request $request, ?string $type = null): array } } - protected function handleError(ResponseInterface $response): void + protected function handleError(Request $request, ResponseInterface $response): void { $statusCode = (int) ($response->getStatusCode()); if ($statusCode >= 200 && $statusCode <= 299) { @@ -143,18 +148,24 @@ protected function handleError(ResponseInterface $response): void if (get_class($res) !== ErrorResponse::class || $res->getErrors() === null || count($res->getErrors()) === 0) { throw new ApiResponseRetrievalException( statusCode: $statusCode, + uri: $request->getUri(), + httpMethod: $request->getMethod(), message: "failed to retrieve error response or errors are empty", responseBody: $contents, ); } else { throw new ApiErrorResponseException( statusCode: $statusCode, + uri: $request->getUri(), + httpMethod: $request->getMethod(), responseBody: $contents, errors: $res->getErrors(), ); } } catch (NotEncodableValueException | UnexpectedValueException $exception) { throw new ApiResponseRetrievalException( + uri: $request->getUri(), + httpMethod: $request->getMethod(), statusCode: $statusCode, message: sprintf( 'Error JSON decoding error server response' @@ -165,6 +176,15 @@ protected function handleError(ResponseInterface $response): void } } + protected function serialize(mixed $data): string + { + // by default an object with all properties set to null, is encoded as `[]` + // php can't figure out if this is an list of things or an empty associative array + // so we enforce `{}` for empty objects. Do not use JSON_FORCE_OBJECT, as it will + // convert every array into an object + return self::$serializer->serialize($data, 'json', ['preserve_empty_objects' => true]); + } + public static function init(): void { $phpDocExtractor = new PhpDocExtractor(); @@ -176,10 +196,10 @@ public static function init(): void self::$serializer = new Serializer( normalizers: [ new ArrayDenormalizer(), new DateTimeNormalizer(), - new GetSetMethodNormalizer(propertyTypeExtractor: $propertyTypeExtractor), + new GetSetMethodNormalizer(propertyTypeExtractor: $propertyTypeExtractor, defaultContext: ['skip_null_values' => true]), new BackedEnumNormalizer(), ], - encoders: [new JsonEncoder()] + encoders: [new JsonEncoder()], ); } diff --git a/src/PayoneCommercePlatform/Sdk/ApiClient/CheckoutApiClient.php b/src/PayoneCommercePlatform/Sdk/ApiClient/CheckoutApiClient.php index d42feac..f934fca 100644 --- a/src/PayoneCommercePlatform/Sdk/ApiClient/CheckoutApiClient.php +++ b/src/PayoneCommercePlatform/Sdk/ApiClient/CheckoutApiClient.php @@ -67,7 +67,7 @@ protected function createCheckoutRequest( /** @var array */ $headers = ['Content-Type' => self::MEDIA_TYPE_JSON]; - $httpBody = self::$serializer->serialize($createCheckoutRequest, 'json'); + $httpBody = $this->serialize($createCheckoutRequest); $operationHost = $this->config->getHost(); return new Request( @@ -309,7 +309,7 @@ protected function updateCheckoutRequest(string $merchantId, string $commerceCas $headers = ['Content-Type' => self::MEDIA_TYPE_JSON]; // json_encode the body - $httpBody = self::$serializer->serialize($patchCheckoutRequest, 'json'); + $httpBody = $this->serialize($patchCheckoutRequest); $operationHost = $this->config->getHost(); return new Request( diff --git a/src/PayoneCommercePlatform/Sdk/ApiClient/CommerceCaseApiClient.php b/src/PayoneCommercePlatform/Sdk/ApiClient/CommerceCaseApiClient.php index 6f17f06..8d09c05 100644 --- a/src/PayoneCommercePlatform/Sdk/ApiClient/CommerceCaseApiClient.php +++ b/src/PayoneCommercePlatform/Sdk/ApiClient/CommerceCaseApiClient.php @@ -55,7 +55,7 @@ protected function createCommerceCaseRequest(string $merchantId, CreateCommerceC /** @var array */ $headers = ['Content-Type' => self::MEDIA_TYPE_JSON]; - $httpBody = self::$serializer->serialize($createCommerceCaseRequest, 'json'); + $httpBody = $this->serialize($createCommerceCaseRequest); $operationHost = $this->config->getHost(); return new Request( @@ -226,7 +226,11 @@ protected function updateCommerceCaseRequest(string $merchantId, string $commerc /** @var array */ $headers = ['Content-Type' => self::MEDIA_TYPE_JSON]; - $httpBody = self::$serializer->serialize($customer, 'json'); + // there was a mismatch between the OpenAPI specification file and the actual api + // the customer has to be wrapped in an object containing the customer as the `customer` property + // to avoid creating another Model to just wrap the customer we inline that stuff + // see: https://docs.payone.com/pcp/commerce-platform-api?fullwidth=1#tag/CommerceCase/operation/updateCommerceCase + $httpBody = $this->serialize(["customer" => $customer]); $operationHost = $this->config->getHost(); return new Request( diff --git a/src/PayoneCommercePlatform/Sdk/ApiClient/OrderManagementCheckoutActionsApiClient.php b/src/PayoneCommercePlatform/Sdk/ApiClient/OrderManagementCheckoutActionsApiClient.php index f7786f0..27d4bc1 100644 --- a/src/PayoneCommercePlatform/Sdk/ApiClient/OrderManagementCheckoutActionsApiClient.php +++ b/src/PayoneCommercePlatform/Sdk/ApiClient/OrderManagementCheckoutActionsApiClient.php @@ -77,7 +77,7 @@ protected function cancelOrderRequest( $headers = ['Content-Type' => self::MEDIA_TYPE_JSON]; if ($cancelRequest !== null) { - $httpBody = self::$serializer->serialize($cancelRequest, 'json'); + $httpBody = $this->serialize($cancelRequest); } $operationHost = $this->config->getHost(); @@ -149,7 +149,7 @@ protected function createOrderRequest( /** @var array */ $headers = ['Content-Type' => self::MEDIA_TYPE_JSON]; - $httpBody = self::$serializer->serialize($orderRequest, 'json'); + $httpBody = $this->serialize($orderRequest); $operationHost = $this->config->getHost(); return new Request( @@ -224,7 +224,7 @@ protected function deliverOrderRequest( /** @var array */ $headers = ['Content-Type' => self::MEDIA_TYPE_JSON]; - $httpBody = self::$serializer->serialize($deliverRequest, 'json'); + $httpBody = $this->serialize($deliverRequest); $operationHost = $this->config->getHost(); return new Request( @@ -295,7 +295,7 @@ protected function returnOrderRequest( $headers = ['Content-Type' => self::MEDIA_TYPE_JSON]; if ($returnRequest !== null) { - $httpBody = self::$serializer->serialize($returnRequest, 'json'); + $httpBody = $this->serialize($returnRequest); } $operationHost = $this->config->getHost(); diff --git a/src/PayoneCommercePlatform/Sdk/ApiClient/PaymentExecutionApiClient.php b/src/PayoneCommercePlatform/Sdk/ApiClient/PaymentExecutionApiClient.php index 7060a68..4553a9b 100644 --- a/src/PayoneCommercePlatform/Sdk/ApiClient/PaymentExecutionApiClient.php +++ b/src/PayoneCommercePlatform/Sdk/ApiClient/PaymentExecutionApiClient.php @@ -90,7 +90,7 @@ protected function cancelPaymentExecutionRequest( /** @var array */ $headers = ['Content-Type' => self::MEDIA_TYPE_JSON]; - $httpBody = self::$serializer->serialize($cancelPaymentRequest, 'json'); + $httpBody = $this->serialize($cancelPaymentRequest); $operationHost = $this->config->getHost(); return new Request( @@ -172,7 +172,7 @@ protected function capturePaymentExecutionRequest( /** @var array */ $headers = ['Content-Type' => self::MEDIA_TYPE_JSON]; - $httpBody = self::$serializer->serialize($capturePaymentRequest, 'json'); + $httpBody = $this->serialize($capturePaymentRequest); $operationHost = $this->config->getHost(); return new Request( @@ -244,7 +244,7 @@ protected function completePaymentRequest(string $merchantId, string $commerceCa /** @var array */ $headers = ['Content-Type' => self::MEDIA_TYPE_JSON]; - $httpBody = self::$serializer->serialize($completePaymentRequest, 'json'); + $httpBody = $this->serialize($completePaymentRequest); $operationHost = $this->config->getHost(); return new Request( @@ -310,7 +310,7 @@ protected function createPaymentRequest(string $merchantId, string $commerceCase /** @var array */ $headers = ['Content-Type' => self::MEDIA_TYPE_JSON]; - $httpBody = self::$serializer->serialize($paymentExecutionRequest, 'json'); + $httpBody = $this->serialize($paymentExecutionRequest); $operationHost = $this->config->getHost(); return new Request( @@ -389,7 +389,7 @@ protected function refundPaymentExecutionRequest( /** @var array */ $headers = ['Content-Type' => self::MEDIA_TYPE_JSON]; - $httpBody = self::$serializer->serialize($refundRequest, 'json'); + $httpBody = $this->serialize($refundRequest); $operationHost = $this->config->getHost(); return new Request( diff --git a/src/PayoneCommercePlatform/Sdk/ApiClient/PaymentInformationApiClient.php b/src/PayoneCommercePlatform/Sdk/ApiClient/PaymentInformationApiClient.php index bb979f9..5f444d9 100644 --- a/src/PayoneCommercePlatform/Sdk/ApiClient/PaymentInformationApiClient.php +++ b/src/PayoneCommercePlatform/Sdk/ApiClient/PaymentInformationApiClient.php @@ -73,7 +73,7 @@ protected function createPaymentInformationRequest( /** @var array */ $headers = ['Content-Type' => self::MEDIA_TYPE_JSON]; - $httpBody = self::$serializer->serialize($paymentInformationRequest, 'json'); + $httpBody = $this->serialize($paymentInformationRequest); $operationHost = $this->config->getHost(); return new Request( diff --git a/src/PayoneCommercePlatform/Sdk/Errors/ApiErrorResponseException.php b/src/PayoneCommercePlatform/Sdk/Errors/ApiErrorResponseException.php index 77aa9ce..2293ef1 100644 --- a/src/PayoneCommercePlatform/Sdk/Errors/ApiErrorResponseException.php +++ b/src/PayoneCommercePlatform/Sdk/Errors/ApiErrorResponseException.php @@ -26,12 +26,21 @@ class ApiErrorResponseException extends ApiException */ public function __construct( int $statusCode, + string $uri, + string $httpMethod, string $responseBody, array $errors, ?string $message = null, ?Throwable $previous = null, ) { - parent::__construct($statusCode, $responseBody, $message, $previous); + parent::__construct( + statusCode: $statusCode, + uri: $uri, + httpMethod: $httpMethod, + responseBody: $responseBody, + message: $message, + previous: $previous + ); $this->errors = $errors; } diff --git a/src/PayoneCommercePlatform/Sdk/Errors/ApiException.php b/src/PayoneCommercePlatform/Sdk/Errors/ApiException.php index d107764..a297fc3 100644 --- a/src/PayoneCommercePlatform/Sdk/Errors/ApiException.php +++ b/src/PayoneCommercePlatform/Sdk/Errors/ApiException.php @@ -7,6 +7,19 @@ class ApiException extends Exception { + /** + * The URI of the request + * + * @var string + */ + protected string $uri; + + /** + * The HTTP method of the request + * + * @var string + */ + protected string $httpMethod; /** * The HTTP body of the server response as string * @@ -25,12 +38,16 @@ class ApiException extends Exception * Constructor * * @param int $statusCode HTTP status code + * @param string $uri The URI of the request + * @param string $httpMethod The HTTP method of the request * @param string|null $responseBody HTTP decoded body of the server response as string * @param string|null $message Custom error message * @param Throwable|null $previous The previous throwable used for the exception chaining. */ public function __construct( int $statusCode, + string $uri, + string $httpMethod, ?string $responseBody = null, ?string $message = null, ?Throwable $previous = null, @@ -39,6 +56,8 @@ public function __construct( $message = sprintf('[%d] Error communicating with the API', $statusCode); } parent::__construct($message, $statusCode, $previous); + $this->uri = $uri; + $this->httpMethod = $httpMethod; $this->statusCode = $statusCode; $this->responseBody = $responseBody; } @@ -53,6 +72,26 @@ public function getStatusCode(): int return $this->statusCode; } + /** + * Gets the URI of the request + * + * @return string URI of the request + */ + public function getUri(): string + { + return $this->uri; + } + + /** + * Gets the HTTP method of the request + * + * @return string HTTP method of the request + */ + public function getHttpMethod(): string + { + return $this->httpMethod; + } + /** * Gets the HTTP body of the server response either as Json or string * diff --git a/src/PayoneCommercePlatform/Sdk/Errors/ApiResponseRetrievalException.php b/src/PayoneCommercePlatform/Sdk/Errors/ApiResponseRetrievalException.php index 339b710..96b0cb9 100644 --- a/src/PayoneCommercePlatform/Sdk/Errors/ApiResponseRetrievalException.php +++ b/src/PayoneCommercePlatform/Sdk/Errors/ApiResponseRetrievalException.php @@ -11,16 +11,27 @@ class ApiResponseRetrievalException extends ApiException * Constructor * * @param int $statusCode HTTP status code + * @param string $uri The URI of the request + * @param string $httpMethod The HTTP method of the request * @param string $responseBody HTTP decoded body of the server response as string * @param ?string $message Custom error message * @param Throwable|null $previous The previous throwable used for the exception chaining. */ public function __construct( int $statusCode, + string $uri, + string $httpMethod, string $responseBody, ?string $message = null, ?Throwable $previous = null, ) { - parent::__construct(statusCode: $statusCode, responseBody: $responseBody, message: $message, previous: $previous); + parent::__construct( + statusCode: $statusCode, + uri: $uri, + httpMethod: $httpMethod, + responseBody: $responseBody, + message: $message, + previous: $previous + ); } } diff --git a/src/PayoneCommercePlatform/Sdk/Models/AmountOfMoney.php b/src/PayoneCommercePlatform/Sdk/Models/AmountOfMoney.php index 3f144f1..ebab3c4 100644 --- a/src/PayoneCommercePlatform/Sdk/Models/AmountOfMoney.php +++ b/src/PayoneCommercePlatform/Sdk/Models/AmountOfMoney.php @@ -7,43 +7,43 @@ class AmountOfMoney { /** - * @var int Amount in cents and always having 2 decimals + * @var int|null Amount in cents and always having 2 decimals */ #[SerializedName('amount')] - protected int $amount; + protected ?int $amount; /** - * @var string Three-letter ISO currency code representing the currency for the amount + * @var string|null Three-letter ISO currency code representing the currency for the amount */ #[SerializedName('currencyCode')] - protected string $currencyCode; + protected ?string $currencyCode; public function __construct( - int $amount, - string $currencyCode + ?int $amount = null, + ?string $currencyCode = null ) { $this->amount = $amount; $this->currencyCode = $currencyCode; } // Getters and Setters - public function getAmount(): int + public function getAmount(): ?int { return $this->amount; } - public function setAmount(int $amount): self + public function setAmount(?int $amount): self { $this->amount = $amount; return $this; } - public function getCurrencyCode(): string + public function getCurrencyCode(): ?string { return $this->currencyCode; } - public function setCurrencyCode(string $currencyCode): self + public function setCurrencyCode(?string $currencyCode): self { $this->currencyCode = $currencyCode; return $this; diff --git a/src/PayoneCommercePlatform/Sdk/Models/CheckoutResponse.php b/src/PayoneCommercePlatform/Sdk/Models/CheckoutResponse.php index 96a5eda..1e6390a 100644 --- a/src/PayoneCommercePlatform/Sdk/Models/CheckoutResponse.php +++ b/src/PayoneCommercePlatform/Sdk/Models/CheckoutResponse.php @@ -31,10 +31,10 @@ class CheckoutResponse protected string $checkoutId; /** - * @var string Unique identifier for the customer. + * @var string|null Unique identifier for the customer. */ #[SerializedName('merchantCustomerId')] - protected string $merchantCustomerId; + protected ?string $merchantCustomerId; /** * @var AmountOfMoney|null The amount of money for the checkout. @@ -99,7 +99,7 @@ class CheckoutResponse /** * @param string $commerceCaseId Reference to the Commerce Case. * @param string $checkoutId Reference to the Checkout. - * @param string $merchantCustomerId Unique identifier for the customer. + * @param string|null $merchantCustomerId Unique identifier for the customer. * @param AmountOfMoney|null $amountOfMoney The amount of money for the checkout. * @param CheckoutReferences|null $references References for the checkout. * @param Shipping|null $shipping Shipping information for the checkout. @@ -114,7 +114,7 @@ class CheckoutResponse public function __construct( string $commerceCaseId, string $checkoutId, - string $merchantCustomerId, + ?string $merchantCustomerId = null, ?AmountOfMoney $amountOfMoney = null, ?CheckoutReferences $references = null, ?Shipping $shipping = null, @@ -164,12 +164,12 @@ public function setCheckoutId(string $checkoutId): self return $this; } - public function getMerchantCustomerId(): string + public function getMerchantCustomerId(): ?string { return $this->merchantCustomerId; } - public function setMerchantCustomerId(string $merchantCustomerId): self + public function setMerchantCustomerId(?string $merchantCustomerId): self { $this->merchantCustomerId = $merchantCustomerId; return $this; diff --git a/src/PayoneCommercePlatform/Sdk/Models/OrderRequest.php b/src/PayoneCommercePlatform/Sdk/Models/OrderRequest.php index 83b7a78..9936075 100644 --- a/src/PayoneCommercePlatform/Sdk/Models/OrderRequest.php +++ b/src/PayoneCommercePlatform/Sdk/Models/OrderRequest.php @@ -20,10 +20,10 @@ class OrderRequest protected ?OrderType $orderType; /** - * @var References References for the order. + * @var References|null References for the order. */ #[SerializedName('orderReferences')] - protected References $orderReferences; + protected ?References $orderReferences; /** * @var OrderItem[]|null List of items for the order, required for orderType = PARTIAL. @@ -39,12 +39,12 @@ class OrderRequest /** * @param OrderType|null $orderType The orderType refers to the ShoppingCart of the Checkout. - * @param References $orderReferences References for the order. + * @param References $orderReferences|null References for the order. * @param OrderItem[]|null $items List of items for the order, required for orderType = PARTIAL. * @param PaymentMethodSpecificInput|null $paymentMethodSpecificInput Specific input details for the payment method. */ public function __construct( - References $orderReferences, + ?References $orderReferences = null, ?OrderType $orderType = null, ?array $items = null, ?PaymentMethodSpecificInput $paymentMethodSpecificInput = null @@ -67,12 +67,12 @@ public function setOrderType(?OrderType $orderType): self return $this; } - public function getOrderReferences(): References + public function getOrderReferences(): ?References { return $this->orderReferences; } - public function setOrderReferences(References $orderReferences): self + public function setOrderReferences(?References $orderReferences): self { $this->orderReferences = $orderReferences; return $this; diff --git a/src/PayoneCommercePlatform/Sdk/Models/PaymentExecutionSpecificInput.php b/src/PayoneCommercePlatform/Sdk/Models/PaymentExecutionSpecificInput.php index c385edb..64250d0 100644 --- a/src/PayoneCommercePlatform/Sdk/Models/PaymentExecutionSpecificInput.php +++ b/src/PayoneCommercePlatform/Sdk/Models/PaymentExecutionSpecificInput.php @@ -25,13 +25,13 @@ class PaymentExecutionSpecificInput protected ?ShoppingCartInput $shoppingCart; /** - * @var References Payment references linked to this transaction. + * @var References|null Payment references linked to this transaction. */ #[SerializedName('paymentReferences')] - protected References $paymentReferences; + protected ?References $paymentReferences; public function __construct( - References $paymentReferences, + ?References $paymentReferences = null, ?AmountOfMoney $amountOfMoney = null, ?ShoppingCartInput $shoppingCart = null ) { @@ -63,12 +63,12 @@ public function setShoppingCart(?ShoppingCartInput $shoppingCart): self return $this; } - public function getPaymentReferences(): References + public function getPaymentReferences(): ?References { return $this->paymentReferences; } - public function setPaymentReferences(References $paymentReferences): self + public function setPaymentReferences(?References $paymentReferences): self { $this->paymentReferences = $paymentReferences; return $this; diff --git a/src/PayoneCommercePlatform/Sdk/Models/PaymentInformationResponse.php b/src/PayoneCommercePlatform/Sdk/Models/PaymentInformationResponse.php index c335e58..0765d5a 100644 --- a/src/PayoneCommercePlatform/Sdk/Models/PaymentInformationResponse.php +++ b/src/PayoneCommercePlatform/Sdk/Models/PaymentInformationResponse.php @@ -25,10 +25,10 @@ class PaymentInformationResponse protected string $checkoutId; /** - * @var string Unique identifier of the customer. + * @var string|null Unique identifier of the customer. */ #[SerializedName('merchantCustomerId')] - protected string $merchantCustomerId; + protected ?string $merchantCustomerId; /** * @var string Unique ID of the Payment Information. @@ -49,22 +49,22 @@ class PaymentInformationResponse protected int $paymentProductId; /** - * @var string Unique identifier of the POS terminal of the payment transaction. + * @var string|null Unique identifier of the POS terminal of the payment transaction. */ #[SerializedName('terminalId')] - protected string $terminalId; + protected ?string $terminalId; /** - * @var string Unique ID that identifies a store location or transaction point and which refers to the contract number of the merchant accepting the card. + * @var string|null Unique ID that identifies a store location or transaction point and which refers to the contract number of the merchant accepting the card. */ #[SerializedName('cardAcceptorId')] - protected string $cardAcceptorId; + protected ?string $cardAcceptorId; /** - * @var string Unique reference of the PaymentInformation. In case of card present transactions, the reference from the ECR or terminal will be used. It is always the reference for external transactions. (e.g. card present payments, cash payments or payments processed by other payment providers). + * @var string|null Unique reference of the PaymentInformation. In case of card present transactions, the reference from the ECR or terminal will be used. It is always the reference for external transactions. (e.g. card present payments, cash payments or payments processed by other payment providers). */ #[SerializedName('merchantReference')] - protected string $merchantReference; + protected ?string $merchantReference; /** * @var CardPaymentDetails|null Card payment details. @@ -81,25 +81,25 @@ class PaymentInformationResponse /** * @param string $commerceCaseId Unique ID of the Commerce Case. * @param string $checkoutId Unique ID of the Checkout. - * @param string $merchantCustomerId Unique identifier of the customer. * @param string $paymentInformationId Unique ID of the Payment Information. * @param PaymentChannel|null $paymentChannel Payment channel. * @param int $paymentProductId Payment product identifier. - * @param string $terminalId Unique identifier of the POS terminal of the payment transaction. - * @param string $cardAcceptorId Unique ID that identifies a store location or transaction point and which refers to the contract number of the merchant accepting the card. - * @param string $merchantReference Unique reference of the PaymentInformation. In case of card present transactions, the reference from the ECR or terminal will be used. It is always the reference for external transactions. (e.g. card present payments, cash payments or payments processed by other payment providers). + * @param string|null $cardAcceptorId Unique ID that identifies a store location or transaction point and which refers to the contract number of the merchant accepting the card. + * @param string|null $merchantReference Unique reference of the PaymentInformation. In case of card present transactions, the reference from the ECR or terminal will be used. It is always the reference for external transactions. (e.g. card present payments, cash payments or payments processed by other payment providers). + * @param string|null $terminalId Unique identifier of the POS terminal of the payment transaction. + * @param string|null $merchantCustomerId Unique identifier of the customer. * @param CardPaymentDetails|null $cardPaymentDetails Card payment details. * @param PaymentEvent[]|null $events List of payment events. */ public function __construct( string $commerceCaseId, string $checkoutId, - string $merchantCustomerId, string $paymentInformationId, int $paymentProductId, - string $terminalId, - string $cardAcceptorId, - string $merchantReference, + ?string $cardAcceptorId = null, + ?string $merchantReference = null, + ?string $terminalId = null, + ?string $merchantCustomerId = null, ?PaymentChannel $paymentChannel = null, ?CardPaymentDetails $cardPaymentDetails = null, ?array $events = null @@ -140,12 +140,12 @@ public function setCheckoutId(string $checkoutId): self return $this; } - public function getMerchantCustomerId(): string + public function getMerchantCustomerId(): ?string { return $this->merchantCustomerId; } - public function setMerchantCustomerId(string $merchantCustomerId): self + public function setMerchantCustomerId(?string $merchantCustomerId): self { $this->merchantCustomerId = $merchantCustomerId; return $this; @@ -184,18 +184,18 @@ public function setPaymentProductId(int $paymentProductId): self return $this; } - public function getTerminalId(): string + public function getTerminalId(): ?string { return $this->terminalId; } - public function setTerminalId(string $terminalId): self + public function setTerminalId(?string $terminalId): self { $this->terminalId = $terminalId; return $this; } - public function getCardAcceptorId(): string + public function getCardAcceptorId(): ?string { return $this->cardAcceptorId; } @@ -206,7 +206,7 @@ public function setCardAcceptorId(string $cardAcceptorId): self return $this; } - public function getMerchantReference(): string + public function getMerchantReference(): ?string { return $this->merchantReference; } diff --git a/src/PayoneCommercePlatform/Sdk/Models/ProcessingMandateInformation.php b/src/PayoneCommercePlatform/Sdk/Models/ProcessingMandateInformation.php index a4d9c6d..be0119b 100644 --- a/src/PayoneCommercePlatform/Sdk/Models/ProcessingMandateInformation.php +++ b/src/PayoneCommercePlatform/Sdk/Models/ProcessingMandateInformation.php @@ -12,41 +12,41 @@ class ProcessingMandateInformation { /** - * @var BankAccountInformation Bank account IBAN information. + * @var BankAccountInformation|null Bank account IBAN information. */ #[SerializedName('bankAccountIban')] - protected BankAccountInformation $bankAccountIban; + protected ?BankAccountInformation $bankAccountIban; /** - * @var MandateRecurrenceType Recurrence type of the mandate. + * @var MandateRecurrenceType|null Recurrence type of the mandate. */ #[SerializedName('recurrenceType')] - protected MandateRecurrenceType $recurrenceType; + protected ?MandateRecurrenceType $recurrenceType; /** - * @var string The unique identifier of the mandate. + * @var string|null The unique identifier of the mandate. */ #[SerializedName('uniqueMandateReference')] - protected string $uniqueMandateReference; + protected ?string $uniqueMandateReference; /** - * @var string The date of signature of the mandate. Format YYYYMMDD. + * @var string|null The date of signature of the mandate. Format YYYYMMDD. */ #[SerializedName('dateOfSignature')] - protected string $dateOfSignature; + protected ?string $dateOfSignature; /** - * @var string Your unique creditor identifier. + * @var string|null Your unique creditor identifier. */ #[SerializedName('creditorId')] - protected string $creditorId; + protected ?string $creditorId; public function __construct( - BankAccountInformation $bankAccountIban, - MandateRecurrenceType $recurrenceType, - string $uniqueMandateReference, - string $dateOfSignature, - string $creditorId + ?BankAccountInformation $bankAccountIban = null, + ?MandateRecurrenceType $recurrenceType = null, + ?string $uniqueMandateReference = null, + ?string $dateOfSignature = null, + ?string $creditorId = null, ) { $this->bankAccountIban = $bankAccountIban; $this->recurrenceType = $recurrenceType; @@ -56,7 +56,7 @@ public function __construct( } // Getters and Setters - public function getBankAccountIban(): BankAccountInformation + public function getBankAccountIban(): ?BankAccountInformation { return $this->bankAccountIban; } @@ -67,7 +67,7 @@ public function setBankAccountIban(BankAccountInformation $bankAccountIban): sel return $this; } - public function getRecurrenceType(): MandateRecurrenceType + public function getRecurrenceType(): ?MandateRecurrenceType { return $this->recurrenceType; } @@ -78,7 +78,7 @@ public function setRecurrenceType(MandateRecurrenceType $recurrenceType): self return $this; } - public function getUniqueMandateReference(): string + public function getUniqueMandateReference(): ?string { return $this->uniqueMandateReference; } @@ -89,7 +89,7 @@ public function setUniqueMandateReference(string $uniqueMandateReference): self return $this; } - public function getDateOfSignature(): string + public function getDateOfSignature(): ?string { return $this->dateOfSignature; } @@ -100,7 +100,7 @@ public function setDateOfSignature(string $dateOfSignature): self return $this; } - public function getCreditorId(): string + public function getCreditorId(): ?string { return $this->creditorId; } diff --git a/src/PayoneCommercePlatform/Sdk/Models/References.php b/src/PayoneCommercePlatform/Sdk/Models/References.php index 0f50de5..4824bd8 100644 --- a/src/PayoneCommercePlatform/Sdk/Models/References.php +++ b/src/PayoneCommercePlatform/Sdk/Models/References.php @@ -16,10 +16,10 @@ class References protected ?string $descriptor; /** - * @var string The merchantReference is a unique identifier for a payment and can be used for reporting purposes. The merchantReference is required for the execution of a payment and has to be unique. In case a payment has failed the same merchantReference can be used again. Once a successful payment has been made the same merchantReference can no longer be used and will be rejected. + * @var string|null The merchantReference is a unique identifier for a payment and can be used for reporting purposes. The merchantReference is required for the execution of a payment and has to be unique. In case a payment has failed the same merchantReference can be used again. Once a successful payment has been made the same merchantReference can no longer be used and will be rejected. */ #[SerializedName('merchantReference')] - protected string $merchantReference; + protected ?string $merchantReference; /** * @var string|null It allows you to store additional parameters for the transaction in JSON format. This field must not contain any personal data. @@ -28,7 +28,7 @@ class References protected ?string $merchantParameters; public function __construct( - string $merchantReference, + ?string $merchantReference = null, ?string $descriptor = null, ?string $merchantParameters = null ) { @@ -49,12 +49,12 @@ public function setDescriptor(?string $descriptor): self return $this; } - public function getMerchantReference(): string + public function getMerchantReference(): ?string { return $this->merchantReference; } - public function setMerchantReference(string $merchantReference): self + public function setMerchantReference(?string $merchantReference): self { $this->merchantReference = $merchantReference; return $this;