From f4b5005b1d339131d7d1d00a0bf5c9066a322c16 Mon Sep 17 00:00:00 2001 From: Jakub Menzel Date: Wed, 11 Mar 2026 08:51:27 +0100 Subject: [PATCH 1/2] Terminal client - CloudPOS --- README.md | 38 +++++ src/ClientTerminal.php | 122 ++++++++++++++++ src/Comgate.php | 16 +++ src/Config.php | 1 + .../Codes/TerminalPaymentStatusCode.php | 20 +++ src/Entity/Codes/TerminalStatusCode.php | 21 +++ src/Entity/Request/TerminalClosingRequest.php | 19 +++ .../Request/TerminalPaymentCancelRequest.php | 40 ++++++ .../Request/TerminalPaymentCreateRequest.php | 33 +++++ .../Request/TerminalPaymentStatusRequest.php | 40 ++++++ .../Request/TerminalRefundCancelRequest.php | 40 ++++++ .../Request/TerminalRefundCreateRequest.php | 33 +++++ .../Request/TerminalRefundStatusRequest.php | 40 ++++++ src/Entity/Request/TerminalStatusRequest.php | 19 +++ .../Response/TerminalClosingResponse.php | 79 +++++++++++ .../TerminalPaymentCancelResponse.php | 53 +++++++ .../TerminalPaymentCreateResponse.php | 107 ++++++++++++++ .../TerminalPaymentStatusResponse.php | 130 ++++++++++++++++++ .../Response/TerminalRefundCancelResponse.php | 53 +++++++ .../Response/TerminalRefundCreateResponse.php | 60 ++++++++ .../Response/TerminalRefundStatusResponse.php | 102 ++++++++++++++ .../Response/TerminalStatusResponse.php | 49 +++++++ src/Entity/TerminalPayment.php | 69 ++++++++++ src/Entity/TerminalRefund.php | 69 ++++++++++ src/Http/ITransport.php | 16 +++ src/Http/Transport.php | 100 +++++++++++++- 26 files changed, 1368 insertions(+), 1 deletion(-) create mode 100644 src/ClientTerminal.php create mode 100644 src/Entity/Codes/TerminalPaymentStatusCode.php create mode 100644 src/Entity/Codes/TerminalStatusCode.php create mode 100644 src/Entity/Request/TerminalClosingRequest.php create mode 100644 src/Entity/Request/TerminalPaymentCancelRequest.php create mode 100644 src/Entity/Request/TerminalPaymentCreateRequest.php create mode 100644 src/Entity/Request/TerminalPaymentStatusRequest.php create mode 100644 src/Entity/Request/TerminalRefundCancelRequest.php create mode 100644 src/Entity/Request/TerminalRefundCreateRequest.php create mode 100644 src/Entity/Request/TerminalRefundStatusRequest.php create mode 100644 src/Entity/Request/TerminalStatusRequest.php create mode 100644 src/Entity/Response/TerminalClosingResponse.php create mode 100644 src/Entity/Response/TerminalPaymentCancelResponse.php create mode 100644 src/Entity/Response/TerminalPaymentCreateResponse.php create mode 100644 src/Entity/Response/TerminalPaymentStatusResponse.php create mode 100644 src/Entity/Response/TerminalRefundCancelResponse.php create mode 100644 src/Entity/Response/TerminalRefundCreateResponse.php create mode 100644 src/Entity/Response/TerminalRefundStatusResponse.php create mode 100644 src/Entity/Response/TerminalStatusResponse.php create mode 100644 src/Entity/TerminalPayment.php create mode 100644 src/Entity/TerminalRefund.php diff --git a/README.md b/README.md index 50ae0ff..36442a9 100644 --- a/README.md +++ b/README.md @@ -265,6 +265,44 @@ try{ ``` +### Create terminal CloudPOS payment +#### API Documentation +https://apidoc.comgate.cz/api/rest-terminal +```php +use Comgate\SDK\Comgate; +use Comgate\SDK\Entity\Codes\CurrencyCode; +use Comgate\SDK\Entity\Codes\RequestCode; +use Comgate\SDK\Entity\Money; +use Comgate\SDK\Entity\TerminalPayment; +use Comgate\SDK\Entity\TerminalRefund; +use Comgate\SDK\Exception\ApiException; + +$clientTerminal = Comgate::defaultsRest() + ->setMerchant('123456') // get on portal.comgate.cz + ->setSecret('foobarbaz') // get on portal.comgate.cz + ->createTerminalClient(); + +$terminalPayment = new TerminalPayment(); +$terminalPayment + ->setPrice(Money::ofInt(4)) + ->setCurr(CurrencyCode::CZK) + ->setRefId('123456'); + +try { + $createTerminalPaymentResponse = $clientTerminal->createPayment($terminalPayment); + if ($createTerminalPaymentResponse->getCode() === RequestCode::OK) { + + // save ID of terminal payment in your system + echo 'created terminal payment: ' . $createTerminalPaymentResponse->getTransId(); + + } else { + var_dump($createTerminalPaymentResponse->getMessage()); + } +} catch (ApiException $e) { + var_dump($e->getMessage()); +} +``` + ### Debugging #### Logging diff --git a/src/ClientTerminal.php b/src/ClientTerminal.php new file mode 100644 index 0000000..5b04f93 --- /dev/null +++ b/src/ClientTerminal.php @@ -0,0 +1,122 @@ +transport = $transport; + } + + /** + * Vytvoří novou platbu na terminálu + */ + public function createPayment(TerminalPayment $terminalPayment): TerminalPaymentCreateResponse + { + $request = new TerminalPaymentCreateRequest($terminalPayment); + $response = $this->transport->postJson($request->getUrn(), $request->toArray()); + return new TerminalPaymentCreateResponse($response); + } + + /** + * Zjistí stav platby na terminálu + */ + public function getPaymentStatus(string $transId): TerminalPaymentStatusResponse + { + $request = new TerminalPaymentStatusRequest($transId); + $response = $this->transport->get($this->replacePathParam($request->getUrn(), $transId)); + return new TerminalPaymentStatusResponse($response); + } + + /** + * Zruší platbu na terminálu + */ + public function cancelPayment(string $transId): TerminalPaymentCancelResponse + { + $request = new TerminalPaymentCancelRequest($transId); + $response = $this->transport->delete($this->replacePathParam($request->getUrn(), $transId)); + return new TerminalPaymentCancelResponse($response); + } + + /** + * Provede uzávěrku na terminálu + */ + public function createClosing(): TerminalClosingResponse + { + $request = new TerminalClosingRequest(); + $response = $this->transport->postJson($request->getUrn(), $request->toArray()); + return new TerminalClosingResponse($response); + } + + /** + * Vytvoří nový návrat (refund) na terminálu + */ + public function createRefund(TerminalRefund $terminalRefund): TerminalRefundCreateResponse + { + $request = new TerminalRefundCreateRequest($terminalRefund); + $response = $this->transport->postJson($request->getUrn(), $request->toArray()); + return new TerminalRefundCreateResponse($response); + } + + /** + * Zjistí stav návratu na terminálu + */ + public function getRefundStatus(string $transId): TerminalRefundStatusResponse + { + $request = new TerminalRefundStatusRequest($transId); + $response = $this->transport->get($this->replacePathParam($request->getUrn(), $transId)); + return new TerminalRefundStatusResponse($response); + } + + /** + * Zruší návrat na terminálu + */ + public function cancelRefund(string $transId): TerminalRefundCancelResponse + { + $request = new TerminalRefundCancelRequest($transId); + $response = $this->transport->delete($this->replacePathParam($request->getUrn(), $transId)); + return new TerminalRefundCancelResponse($response); + } + + /** + * Zjistí stav terminálu + */ + public function getTerminalStatus(): TerminalStatusResponse + { + $request = new TerminalStatusRequest(); + $response = $this->transport->get($request->getUrn()); + return new TerminalStatusResponse($response); + } + + /** + * Nahradí {transId} v URN skutečným transId + */ + private function replacePathParam(string $urn, string $transId): string + { + return str_replace('{transId}', $transId, $urn); + } +} diff --git a/src/Comgate.php b/src/Comgate.php index 035f660..8ef554b 100644 --- a/src/Comgate.php +++ b/src/Comgate.php @@ -36,6 +36,17 @@ public static function defaults(): self return $self; } + /** + * @return static + */ + public static function defaultsRest(): self + { + $self = new static(); + $self->url = Config::URL_REST; + + return $self; + } + /** * @return static */ @@ -81,6 +92,11 @@ public function createClient(): Client return new Client($this->createTransport()); } + public function createTerminalClient(): ClientTerminal + { + return new ClientTerminal($this->createTransport()); + } + protected function createConfig(): Config { return new Config($this->merchant, $this->secret, $this->url); diff --git a/src/Config.php b/src/Config.php index e42c31a..57ad3ac 100644 --- a/src/Config.php +++ b/src/Config.php @@ -5,6 +5,7 @@ class Config { public const URL = 'https://payments.comgate.cz/v1.0/'; + public const URL_REST = 'https://payments.comgate.cz/v2.0/'; /** @var string */ private $merchant; diff --git a/src/Entity/Codes/TerminalPaymentStatusCode.php b/src/Entity/Codes/TerminalPaymentStatusCode.php new file mode 100644 index 0000000..a9e36d1 --- /dev/null +++ b/src/Entity/Codes/TerminalPaymentStatusCode.php @@ -0,0 +1,20 @@ + + */ + public function toArray(): array + { + return []; + } +} diff --git a/src/Entity/Request/TerminalPaymentCancelRequest.php b/src/Entity/Request/TerminalPaymentCancelRequest.php new file mode 100644 index 0000000..43c724b --- /dev/null +++ b/src/Entity/Request/TerminalPaymentCancelRequest.php @@ -0,0 +1,40 @@ +transId = $transId; + } + + public function getUrn(): string + { + return 'terminalPayment/transId/{transId}.json'; + } + + /** + * @return array + */ + public function toArray(): array + { + return [ + 'transId' => $this->transId, + ]; + } + + public function getTransId(): string + { + return $this->transId; + } + + public function setTransId(string $transId): self + { + $this->transId = $transId; + return $this; + } +} diff --git a/src/Entity/Request/TerminalPaymentCreateRequest.php b/src/Entity/Request/TerminalPaymentCreateRequest.php new file mode 100644 index 0000000..e1b79a4 --- /dev/null +++ b/src/Entity/Request/TerminalPaymentCreateRequest.php @@ -0,0 +1,33 @@ +terminalPayment = $terminalPayment; + } + + public function getUrn(): string + { + return 'terminalPayment.json'; + } + + /** + * @return array + */ + public function toArray(): array + { + return array_filter([ + 'price' => $this->terminalPayment->getPrice()->get(), + 'curr' => $this->terminalPayment->getCurr(), + 'refId' => $this->terminalPayment->getRefId(), + ], function ($v) { return $v !== null; }); + } +} diff --git a/src/Entity/Request/TerminalPaymentStatusRequest.php b/src/Entity/Request/TerminalPaymentStatusRequest.php new file mode 100644 index 0000000..cbb6240 --- /dev/null +++ b/src/Entity/Request/TerminalPaymentStatusRequest.php @@ -0,0 +1,40 @@ +transId = $transId; + } + + public function getUrn(): string + { + return 'terminalPayment/transId/{transId}.json'; + } + + /** + * @return array + */ + public function toArray(): array + { + return [ + 'transId' => $this->transId, + ]; + } + + public function getTransId(): string + { + return $this->transId; + } + + public function setTransId(string $transId): self + { + $this->transId = $transId; + return $this; + } +} diff --git a/src/Entity/Request/TerminalRefundCancelRequest.php b/src/Entity/Request/TerminalRefundCancelRequest.php new file mode 100644 index 0000000..c2c5147 --- /dev/null +++ b/src/Entity/Request/TerminalRefundCancelRequest.php @@ -0,0 +1,40 @@ +transId = $transId; + } + + public function getUrn(): string + { + return 'terminalRefund/transId/{transId}.json'; + } + + /** + * @return array + */ + public function toArray(): array + { + return [ + 'transId' => $this->transId, + ]; + } + + public function getTransId(): string + { + return $this->transId; + } + + public function setTransId(string $transId): self + { + $this->transId = $transId; + return $this; + } +} diff --git a/src/Entity/Request/TerminalRefundCreateRequest.php b/src/Entity/Request/TerminalRefundCreateRequest.php new file mode 100644 index 0000000..6f370b5 --- /dev/null +++ b/src/Entity/Request/TerminalRefundCreateRequest.php @@ -0,0 +1,33 @@ +terminalRefund = $terminalRefund; + } + + public function getUrn(): string + { + return 'terminalRefund.json'; + } + + /** + * @return array + */ + public function toArray(): array + { + return array_filter([ + 'price' => $this->terminalRefund->getPrice()->get(), + 'curr' => $this->terminalRefund->getCurr(), + 'refId' => $this->terminalRefund->getRefId(), + ], function ($v) { return $v !== null; }); + } +} diff --git a/src/Entity/Request/TerminalRefundStatusRequest.php b/src/Entity/Request/TerminalRefundStatusRequest.php new file mode 100644 index 0000000..af4ce1a --- /dev/null +++ b/src/Entity/Request/TerminalRefundStatusRequest.php @@ -0,0 +1,40 @@ +transId = $transId; + } + + public function getUrn(): string + { + return 'terminalRefund/transId/{transId}.json'; + } + + /** + * @return array + */ + public function toArray(): array + { + return [ + 'transId' => $this->transId, + ]; + } + + public function getTransId(): string + { + return $this->transId; + } + + public function setTransId(string $transId): self + { + $this->transId = $transId; + return $this; + } +} diff --git a/src/Entity/Request/TerminalStatusRequest.php b/src/Entity/Request/TerminalStatusRequest.php new file mode 100644 index 0000000..0645b99 --- /dev/null +++ b/src/Entity/Request/TerminalStatusRequest.php @@ -0,0 +1,19 @@ + + */ + public function toArray(): array + { + return []; + } +} diff --git a/src/Entity/Response/TerminalClosingResponse.php b/src/Entity/Response/TerminalClosingResponse.php new file mode 100644 index 0000000..1d61163 --- /dev/null +++ b/src/Entity/Response/TerminalClosingResponse.php @@ -0,0 +1,79 @@ +> */ + protected $batchData = []; + + /** + * @param Response $response + * @throws ApiException + */ + public function __construct(Response $response) + { + $data = json_decode($response->getContent(), true); + + $code = (int) ($data['code'] ?? 1500); + $message = $data['message'] ?? ''; + + switch ($code) { + case 0: + $this->setCode($code) + ->setMessage($message) + ->setBatchNumber((int) ($data['batchNumber'] ?? 0)); + + if (isset($data['batchData']) && is_array($data['batchData'])) { + $this->setBatchData($data['batchData']); + } + break; + + default: + throw new ApiException($message, $code); + } + } + + /** + * @return array + */ + public function toArray(): array + { + return [ + 'code' => $this->getCode(), + 'message' => $this->getMessage(), + 'batchNumber' => $this->getBatchNumber(), + 'batchData' => $this->getBatchData(), + ]; + } + + public function getCode(): int { return $this->code; } + public function setCode(int $code): self { $this->code = $code; return $this; } + public function getMessage(): string { return $this->message; } + public function setMessage(string $message): self { $this->message = $message; return $this; } + public function getBatchNumber(): int { return $this->batchNumber; } + public function setBatchNumber(int $batchNumber): self { $this->batchNumber = $batchNumber; return $this; } + + /** + * @return array> + */ + public function getBatchData(): array { return $this->batchData; } + + /** + * @param array> $batchData + * @return self + */ + public function setBatchData(array $batchData): self { $this->batchData = $batchData; return $this; } +} diff --git a/src/Entity/Response/TerminalPaymentCancelResponse.php b/src/Entity/Response/TerminalPaymentCancelResponse.php new file mode 100644 index 0000000..1607df6 --- /dev/null +++ b/src/Entity/Response/TerminalPaymentCancelResponse.php @@ -0,0 +1,53 @@ +getContent(), true); + + $code = (int) ($data['code'] ?? 1500); + $message = $data['message'] ?? ''; + + switch ($code) { + case 0: + $this->setCode($code) + ->setMessage($message); + break; + + default: + throw new ApiException($message, $code); + } + } + + /** + * @return array + */ + public function toArray(): array + { + return [ + 'code' => $this->getCode(), + 'message' => $this->getMessage(), + ]; + } + + public function getCode(): int { return $this->code; } + public function setCode(int $code): self { $this->code = $code; return $this; } + public function getMessage(): string { return $this->message; } + public function setMessage(string $message): self { $this->message = $message; return $this; } +} diff --git a/src/Entity/Response/TerminalPaymentCreateResponse.php b/src/Entity/Response/TerminalPaymentCreateResponse.php new file mode 100644 index 0000000..87c1fe3 --- /dev/null +++ b/src/Entity/Response/TerminalPaymentCreateResponse.php @@ -0,0 +1,107 @@ +getContent(), true); + + $code = (int) ($data['code'] ?? 1500); + $message = $data['message'] ?? ''; + + switch ($code) { + case 0: + $this->setCode($code) + ->setMessage($message) + ->setTransId($data['transId'] ?? ''); + break; + + default: + throw new ApiException($message, $code); + } + } + + /** + * @return array + */ + public function toArray(): array + { + return [ + 'code' => $this->getCode(), + 'message' => $this->getMessage(), + 'transId' => $this->getTransId(), + ]; + } + + /** + * @return int + */ + public function getCode(): int + { + return $this->code; + } + + /** + * @param int $code + * @return self + */ + public function setCode(int $code): self + { + $this->code = $code; + return $this; + } + + /** + * @return string + */ + public function getMessage(): string + { + return $this->message; + } + + /** + * @param string $message + * @return self + */ + public function setMessage(string $message): self + { + $this->message = $message; + return $this; + } + + /** + * @return string + */ + public function getTransId(): string + { + return $this->transId; + } + + /** + * @param string $transId + * @return self + */ + public function setTransId(string $transId): self + { + $this->transId = $transId; + return $this; + } +} diff --git a/src/Entity/Response/TerminalPaymentStatusResponse.php b/src/Entity/Response/TerminalPaymentStatusResponse.php new file mode 100644 index 0000000..e681966 --- /dev/null +++ b/src/Entity/Response/TerminalPaymentStatusResponse.php @@ -0,0 +1,130 @@ +getContent(), true); + + $code = (int) ($data['code'] ?? 1500); + $message = $data['message'] ?? ''; + + switch ($code) { + case 0: + $this->setCode($code) + ->setMessage($message) + ->setPrice((int) ($data['price'] ?? 0)) + ->setCurr($data['curr'] ?? '') + ->setRefId($data['refId'] ?? '') + ->setTransId($data['transId'] ?? '') + ->setStatus($data['status'] ?? '') + ->setFee($data['fee'] ?? '') + ->setCardValid($data['cardValid'] ?? '') + ->setCardNumber($data['cardNumber'] ?? '') + ->setPaymentErrorReason($data['paymentErrorReason'] ?? '') + ->setReversed((bool) ($data['reversed'] ?? false)) + ->setAmountRefunded($data['amountRefunded'] ?? ''); + break; + + default: + throw new ApiException($message, $code); + } + } + + /** + * @return array + */ + public function toArray(): array + { + return [ + 'code' => $this->getCode(), + 'message' => $this->getMessage(), + 'price' => $this->getPrice(), + 'curr' => $this->getCurr(), + 'refId' => $this->getRefId(), + 'transId' => $this->getTransId(), + 'status' => $this->getStatus(), + 'fee' => $this->getFee(), + 'cardValid' => $this->getCardValid(), + 'cardNumber' => $this->getCardNumber(), + 'paymentErrorReason' => $this->getPaymentErrorReason(), + 'reversed' => $this->isReversed(), + 'amountRefunded' => $this->getAmountRefunded(), + ]; + } + + public function getCode(): int { return $this->code; } + public function setCode(int $code): self { $this->code = $code; return $this; } + public function getMessage(): string { return $this->message; } + public function setMessage(string $message): self { $this->message = $message; return $this; } + public function getPrice(): int { return $this->price; } + public function setPrice(int $price): self { $this->price = $price; return $this; } + public function getCurr(): string { return $this->curr; } + public function setCurr(string $curr): self { $this->curr = $curr; return $this; } + public function getRefId(): string { return $this->refId; } + public function setRefId(string $refId): self { $this->refId = $refId; return $this; } + public function getTransId(): string { return $this->transId; } + public function setTransId(string $transId): self { $this->transId = $transId; return $this; } + public function getStatus(): string { return $this->status; } + public function setStatus(string $status): self { $this->status = $status; return $this; } + public function getFee(): string { return $this->fee; } + public function setFee(string $fee): self { $this->fee = $fee; return $this; } + public function getCardValid(): string { return $this->cardValid; } + public function setCardValid(string $cardValid): self { $this->cardValid = $cardValid; return $this; } + public function getCardNumber(): string { return $this->cardNumber; } + public function setCardNumber(string $cardNumber): self { $this->cardNumber = $cardNumber; return $this; } + public function getPaymentErrorReason(): string { return $this->paymentErrorReason; } + public function setPaymentErrorReason(string $paymentErrorReason): self { $this->paymentErrorReason = $paymentErrorReason; return $this; } + public function isReversed(): bool { return $this->reversed; } + public function setReversed(bool $reversed): self { $this->reversed = $reversed; return $this; } + public function getAmountRefunded(): string { return $this->amountRefunded; } + public function setAmountRefunded(string $amountRefunded): self { $this->amountRefunded = $amountRefunded; return $this; } +} diff --git a/src/Entity/Response/TerminalRefundCancelResponse.php b/src/Entity/Response/TerminalRefundCancelResponse.php new file mode 100644 index 0000000..f5aecaf --- /dev/null +++ b/src/Entity/Response/TerminalRefundCancelResponse.php @@ -0,0 +1,53 @@ +getContent(), true); + + $code = (int) ($data['code'] ?? 1500); + $message = $data['message'] ?? ''; + + switch ($code) { + case 0: + $this->setCode($code) + ->setMessage($message); + break; + + default: + throw new ApiException($message, $code); + } + } + + /** + * @return array + */ + public function toArray(): array + { + return [ + 'code' => $this->getCode(), + 'message' => $this->getMessage(), + ]; + } + + public function getCode(): int { return $this->code; } + public function setCode(int $code): self { $this->code = $code; return $this; } + public function getMessage(): string { return $this->message; } + public function setMessage(string $message): self { $this->message = $message; return $this; } +} diff --git a/src/Entity/Response/TerminalRefundCreateResponse.php b/src/Entity/Response/TerminalRefundCreateResponse.php new file mode 100644 index 0000000..60dc5f8 --- /dev/null +++ b/src/Entity/Response/TerminalRefundCreateResponse.php @@ -0,0 +1,60 @@ +getContent(), true); + + $code = (int) ($data['code'] ?? 1500); + $message = $data['message'] ?? ''; + + switch ($code) { + case 0: + $this->setCode($code) + ->setMessage($message) + ->setTransId($data['transId'] ?? ''); + break; + + default: + throw new ApiException($message, $code); + } + } + + /** + * @return array + */ + public function toArray(): array + { + return [ + 'code' => $this->getCode(), + 'message' => $this->getMessage(), + 'transId' => $this->getTransId(), + ]; + } + + public function getCode(): int { return $this->code; } + public function setCode(int $code): self { $this->code = $code; return $this; } + public function getMessage(): string { return $this->message; } + public function setMessage(string $message): self { $this->message = $message; return $this; } + public function getTransId(): string { return $this->transId; } + public function setTransId(string $transId): self { $this->transId = $transId; return $this; } +} diff --git a/src/Entity/Response/TerminalRefundStatusResponse.php b/src/Entity/Response/TerminalRefundStatusResponse.php new file mode 100644 index 0000000..27d36f7 --- /dev/null +++ b/src/Entity/Response/TerminalRefundStatusResponse.php @@ -0,0 +1,102 @@ +getContent(), true); + + $code = (int) ($data['code'] ?? 1500); + $message = $data['message'] ?? ''; + + switch ($code) { + case 0: + $this->setCode($code) + ->setMessage($message) + ->setPrice((int) ($data['price'] ?? 0)) + ->setCurr($data['curr'] ?? '') + ->setRefId($data['refId'] ?? '') + ->setTransId($data['transId'] ?? '') + ->setStatus($data['status'] ?? '') + ->setCardNumber($data['cardNumber'] ?? '') + ->setReversed((bool) ($data['reversed'] ?? false)); + break; + + default: + throw new ApiException($message, $code); + } + } + + /** + * @return array + */ + public function toArray(): array + { + return [ + 'code' => $this->getCode(), + 'message' => $this->getMessage(), + 'price' => $this->getPrice(), + 'curr' => $this->getCurr(), + 'refId' => $this->getRefId(), + 'transId' => $this->getTransId(), + 'status' => $this->getStatus(), + 'cardNumber' => $this->getCardNumber(), + 'reversed' => $this->isReversed(), + ]; + } + + public function getCode(): int { return $this->code; } + public function setCode(int $code): self { $this->code = $code; return $this; } + public function getMessage(): string { return $this->message; } + public function setMessage(string $message): self { $this->message = $message; return $this; } + public function getPrice(): int { return $this->price; } + public function setPrice(int $price): self { $this->price = $price; return $this; } + public function getCurr(): string { return $this->curr; } + public function setCurr(string $curr): self { $this->curr = $curr; return $this; } + public function getRefId(): string { return $this->refId; } + public function setRefId(string $refId): self { $this->refId = $refId; return $this; } + public function getTransId(): string { return $this->transId; } + public function setTransId(string $transId): self { $this->transId = $transId; return $this; } + public function getStatus(): string { return $this->status; } + public function setStatus(string $status): self { $this->status = $status; return $this; } + public function getCardNumber(): string { return $this->cardNumber; } + public function setCardNumber(string $cardNumber): self { $this->cardNumber = $cardNumber; return $this; } + public function isReversed(): bool { return $this->reversed; } + public function setReversed(bool $reversed): self { $this->reversed = $reversed; return $this; } +} diff --git a/src/Entity/Response/TerminalStatusResponse.php b/src/Entity/Response/TerminalStatusResponse.php new file mode 100644 index 0000000..5aa1d17 --- /dev/null +++ b/src/Entity/Response/TerminalStatusResponse.php @@ -0,0 +1,49 @@ +getContent(), true); + + $this->setStatus($data['status'] ?? 'UNKNOWN'); + } + + /** + * @return array + */ + public function toArray(): array + { + return [ + 'status' => $this->getStatus(), + ]; + } + + /** + * @return string + */ + public function getStatus(): string + { + return $this->status; + } + + /** + * @param string $status + * @return self + */ + public function setStatus(string $status): self + { + $this->status = $status; + return $this; + } +} diff --git a/src/Entity/TerminalPayment.php b/src/Entity/TerminalPayment.php new file mode 100644 index 0000000..092cf5d --- /dev/null +++ b/src/Entity/TerminalPayment.php @@ -0,0 +1,69 @@ +price; + } + + /** + * @param int|float|Money $price + * @return self + */ + public function setPrice($price): self + { + $this->price = Money::of($price); + return $this; + } + + /** + * @return string + */ + public function getCurr(): string + { + return $this->curr; + } + + /** + * @param string $curr Kód měny dle ISO 4217 (CZK, EUR) + * @return self + */ + public function setCurr(string $curr): self + { + $this->curr = $curr; + return $this; + } + + /** + * @return string|null + */ + public function getRefId(): ?string + { + return $this->refId; + } + + /** + * @param string|null $refId Variabilní symbol nebo číslo objednávky na straně klienta + * @return self + */ + public function setRefId(?string $refId): self + { + $this->refId = $refId; + return $this; + } +} diff --git a/src/Entity/TerminalRefund.php b/src/Entity/TerminalRefund.php new file mode 100644 index 0000000..553d220 --- /dev/null +++ b/src/Entity/TerminalRefund.php @@ -0,0 +1,69 @@ +price; + } + + /** + * @param int|float|Money $price + * @return self + */ + public function setPrice($price): self + { + $this->price = Money::of($price); + return $this; + } + + /** + * @return string + */ + public function getCurr(): string + { + return $this->curr; + } + + /** + * @param string $curr Kód měny dle ISO 4217 (CZK, EUR) + * @return self + */ + public function setCurr(string $curr): self + { + $this->curr = $curr; + return $this; + } + + /** + * @return string|null + */ + public function getRefId(): ?string + { + return $this->refId; + } + + /** + * @param string|null $refId Variabilní symbol nebo číslo objednávky na straně klienta + * @return self + */ + public function setRefId(?string $refId): self + { + $this->refId = $refId; + return $this; + } +} diff --git a/src/Http/ITransport.php b/src/Http/ITransport.php index 5a05411..047e0d4 100644 --- a/src/Http/ITransport.php +++ b/src/Http/ITransport.php @@ -9,4 +9,20 @@ interface ITransport * @param mixed[] $options */ public function post(string $uri, array $data, array $options = []): Response; + + /** + * @param mixed[] $data + * @param mixed[] $options + */ + public function postJson(string $uri, array $data, array $options = []): Response; + + /** + * @param mixed[] $options + */ + public function get(string $uri, array $options = []): Response; + + /** + * @param mixed[] $options + */ + public function delete(string $uri, array $options = []): Response; } diff --git a/src/Http/Transport.php b/src/Http/Transport.php index 17da99e..edd9784 100644 --- a/src/Http/Transport.php +++ b/src/Http/Transport.php @@ -87,7 +87,105 @@ public function post(string $urn, array $data, array $options = []): Response throw new ComgateException("Request failed: {$e}", 0); } - return new Response(self::createResponse($response)); + return new Response($this->createResponse($response)); + } + + /** + * @param mixed[] $options + */ + public function get(string $urn, array $options = []): Response + { + return $this->makeRestRequest('GET', $urn, [], $options); + } + + /** + * @param mixed[] $data + * @param mixed[] $options + */ + public function postJson(string $urn, array $data, array $options = []): Response + { + return $this->makeRestRequest('POST', $urn, $data, $options); + } + + /** + * @param mixed[] $options + */ + public function delete(string $urn, array $options = []): Response + { + return $this->makeRestRequest('DELETE', $urn, [], $options); + } + + /** + * @param mixed[] $data + * @param mixed[] $options + */ + private function makeRestRequest(string $method, string $urn, array $data = [], array $options = []): Response + { + $curl = curl_init(); + + // Příprava URL s Basic Auth + $url = $this->config->getUrl() . $urn; + $auth = base64_encode($this->config->getMerchant() . ':' . $this->config->getSecret()); + + $headers = [ + 'Authorization: Basic ' . $auth, + 'Content-Type: application/json', + ]; + + curl_setopt($curl, CURLOPT_URL, $url); + curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $method); + curl_setopt($curl, CURLOPT_HTTPHEADER, $headers); + curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); + curl_setopt($curl, CURLOPT_HEADER, true); + + if ($method === 'POST' && !empty($data)) { + curl_setopt($curl, CURLOPT_POSTFIELDS, json_encode($data)); + } + + if (isset($_ENV['APPLICATION_ENV']) && $_ENV['APPLICATION_ENV'] === 'sdk-github') { + curl_setopt($curl, CURLOPT_HTTPHEADER, array_merge($headers, [ + 'CF-Access-Client-Id: ' . $_ENV['CF_ACCESS_CLIENT_ID'], + 'CF-Access-Client-Secret: ' . $_ENV['CF_ACCESS_CLIENT_SECRET'], + ])); + } + + $response = curl_exec($curl); + $httpCode = curl_getinfo($curl, CURLINFO_HTTP_CODE); + $e = curl_error($curl); + + if ($this->logger !== null) { + $this->logger->log(LogLevel::INFO, 'REST Request to "' . $url . '" sent'); + $this->logger->log(LogLevel::DEBUG, 'Response: ' . $response); + $this->logger->log(LogLevel::DEBUG, 'cURL info: ' . json_encode(curl_getinfo($curl))); + + switch (true){ + case ($response === false): + $log = [LogLevel::ERROR, 'cURL request failed: ' . $e]; + break; + case ($httpCode >= 500): + $log = [LogLevel::CRITICAL, 'Server error: HTTP code ' . $httpCode]; + break; + case ($httpCode >= 400): + $log = [LogLevel::ERROR, 'Client error: HTTP code ' . $httpCode]; + break; + default: + $log = [LogLevel::INFO, 'cURL request completed successfully.']; + break; + } + $this->logger->log(...$log); + } + + // PHP 8.5+ automatically closes the handle + // for lower versions we need to close it manually + if(PHP_VERSION_ID < 80500){ + curl_close($curl); + }; + + if ($e != '') { + throw new ComgateException("Request failed: {$e}", 0); + } + + return new Response($this->createResponse($response)); } /** From e1f77f2cfef0796db3f12327e2ef6dd88628d2d1 Mon Sep 17 00:00:00 2001 From: Jakub Menzel Date: Wed, 11 Mar 2026 09:00:01 +0100 Subject: [PATCH 2/2] Terminal client - CloudPOS --- src/Entity/Request/TerminalClosingRequest.php | 2 +- src/Entity/Request/TerminalStatusRequest.php | 2 +- src/Http/Transport.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Entity/Request/TerminalClosingRequest.php b/src/Entity/Request/TerminalClosingRequest.php index 8fa2e63..82983ff 100644 --- a/src/Entity/Request/TerminalClosingRequest.php +++ b/src/Entity/Request/TerminalClosingRequest.php @@ -10,7 +10,7 @@ public function getUrn(): string } /** - * @return array + * @return array */ public function toArray(): array { diff --git a/src/Entity/Request/TerminalStatusRequest.php b/src/Entity/Request/TerminalStatusRequest.php index 0645b99..bfd3757 100644 --- a/src/Entity/Request/TerminalStatusRequest.php +++ b/src/Entity/Request/TerminalStatusRequest.php @@ -10,7 +10,7 @@ public function getUrn(): string } /** - * @return array + * @return array */ public function toArray(): array { diff --git a/src/Http/Transport.php b/src/Http/Transport.php index edd9784..c6dc507 100644 --- a/src/Http/Transport.php +++ b/src/Http/Transport.php @@ -138,7 +138,7 @@ private function makeRestRequest(string $method, string $urn, array $data = [], curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); curl_setopt($curl, CURLOPT_HEADER, true); - if ($method === 'POST' && !empty($data)) { + if ($method === 'POST' && count($data) != 0) { curl_setopt($curl, CURLOPT_POSTFIELDS, json_encode($data)); }