From 1a9b4aecfe20b9fa79c8e8817dbd929b4dca4a4d Mon Sep 17 00:00:00 2001 From: Leith Caldwell Date: Fri, 18 Jul 2025 12:17:39 +1200 Subject: [PATCH] Update * add refund() support * add support for MOTO transactions * update complete purchase requests to validate necessary URL parameters --- src/Gateway.php | 6 +++ src/Message/CompletePurchaseRequest.php | 2 + src/Message/PurchaseRequest.php | 18 ++++++++- src/Message/RefundRequest.php | 50 ++++++++++++++++++++++++ src/Message/RefundResponse.php | 51 +++++++++++++++++++++++++ tests/GatewayTest.php | 2 +- 6 files changed, 127 insertions(+), 2 deletions(-) create mode 100644 src/Message/RefundRequest.php create mode 100644 src/Message/RefundResponse.php diff --git a/src/Gateway.php b/src/Gateway.php index 8472f43..1c0b932 100644 --- a/src/Gateway.php +++ b/src/Gateway.php @@ -5,6 +5,7 @@ use Omnipay\Common\AbstractGateway; use Omnipay\Worldline\Message\CompletePurchaseRequest; use Omnipay\Worldline\Message\PurchaseRequest; +use Omnipay\Worldline\Message\RefundRequest; /** * Worldline Hosted Checkout Gateway @@ -69,4 +70,9 @@ public function completePurchase(array $parameters = []) { return $this->createRequest(CompletePurchaseRequest::class, $parameters); } + + public function refund(array $parameters = []) + { + return $this->createRequest(RefundRequest::class, $parameters); + } } diff --git a/src/Message/CompletePurchaseRequest.php b/src/Message/CompletePurchaseRequest.php index 05496e2..ce4665f 100644 --- a/src/Message/CompletePurchaseRequest.php +++ b/src/Message/CompletePurchaseRequest.php @@ -23,6 +23,8 @@ public function setHostedCheckoutId($value) public function getData() { + $this->validate('merchantId', 'hostedCheckoutId'); + return $this->httpRequest->request->all(); } diff --git a/src/Message/PurchaseRequest.php b/src/Message/PurchaseRequest.php index 052aa58..6604095 100644 --- a/src/Message/PurchaseRequest.php +++ b/src/Message/PurchaseRequest.php @@ -115,6 +115,22 @@ public function setSessionTimeout($value) return $this->setParameter('sessionTimeout', $value); } + public function getTransactionChannel() + { + return $this->getParameter('transactionChannel'); + } + + /** + * Transaction channel can only be either 'ECOMMERCE' or 'MOTO' + */ + public function setTransactionChannel($value) + { + if (!in_array($value, ['ECOMMERCE', 'MOTO'])) { + $value = null; + } + return $this->setParameter('transactionChannel', $value); + } + public function getData() { $this->validate('merchantId', 'amount', 'currency'); @@ -141,7 +157,7 @@ public function getData() $data = [ 'cardPaymentMethodSpecificInput' => [ 'authorizationMode' => 'SALE', - 'transactionChannel' => 'ECOMMERCE', + 'transactionChannel' => $this->getTransactionChannel() ?? 'ECOMMERCE', ], 'hostedCheckoutSpecificInput' => [ // if adding locale, validate locale against known formats diff --git a/src/Message/RefundRequest.php b/src/Message/RefundRequest.php new file mode 100644 index 0000000..f98939a --- /dev/null +++ b/src/Message/RefundRequest.php @@ -0,0 +1,50 @@ +getParameter('paymentId'); + } + + public function setPaymentId($value) + { + return $this->setParameter('paymentId', $value); + } + + public function getData() + { + $this->validate('merchantId', 'amount', 'currency', 'paymentId'); + + $data = [ + 'amountOfMoney' => [ + 'amount' => $this->getAmountInteger(), + 'currencyCode' => $this->getCurrency(), + ], + 'operationReferences' => [ + 'merchantReference' => $this->getTransactionId(), + ], + ]; + + return $data; + } + + protected function createResponse($data) + { + return $this->response = new RefundResponse($this, json_decode($data)); + } + + protected function getAction() + { + return '/v2/'.$this->getMerchantId().'/payments/'.$this->getPaymentId(); + } +} diff --git a/src/Message/RefundResponse.php b/src/Message/RefundResponse.php new file mode 100644 index 0000000..d2983a8 --- /dev/null +++ b/src/Message/RefundResponse.php @@ -0,0 +1,51 @@ +data->errorId) && $this->data->status == 'REFUNDED'; + } + + /** + * Numeric status code (also in back office / report files) + * + * @return null|string + */ + public function getCode() + { + return $this->data->statusOutput->statusCode ?? $this->data->refundResult->statusOutput->statusCode ?? null; + } + + /** + * Get the authorisation code if available. + * + * @return null|string + */ + public function getTransactionReference() + { + return $this->data->id ?? null; + } + + /** + * Get the merchant response message if available. + * + * @return null|string + */ + public function getMessage() + { + return $this->data->status ?? $this->data->errorId ?? null; + } +} diff --git a/tests/GatewayTest.php b/tests/GatewayTest.php index c304c4b..08b7125 100644 --- a/tests/GatewayTest.php +++ b/tests/GatewayTest.php @@ -65,7 +65,7 @@ public function testCompletePurchaseFailure() $options = array_merge($this->options, ['hostedCheckoutId' => '0000000001']); - $response = $this->gateway->completePurchase($this->options)->send(); + $response = $this->gateway->completePurchase($options)->send(); $this->assertFalse($response->isSuccessful()); $this->assertFalse($response->isRedirect());