Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[PT-887] Implement Hosted Checkout #12

Merged
merged 7 commits into from
Feb 13, 2024
15 changes: 15 additions & 0 deletions Controller/CancelController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php

namespace OxidEsales\MonduPayment\Controller;

use OxidEsales\Eshop\Core\Registry;
use OxidEsales\Eshop\Core\UtilsView;

class CancelController extends \OxidEsales\Eshop\Application\Controller\FrontendController
{
public function render()
{
Registry::get(UtilsView::class)->addErrorToDisplay('Mondu: Order has been canceled');
Registry::getUtils()->redirect(Registry::getConfig()->getShopSecureHomeUrl() . 'cl=basket', false);
}
}
15 changes: 15 additions & 0 deletions Controller/DeclineController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php

namespace OxidEsales\MonduPayment\Controller;

use OxidEsales\Eshop\Core\Registry;
use OxidEsales\Eshop\Core\UtilsView;

class DeclineController extends \OxidEsales\Eshop\Application\Controller\FrontendController
{
public function render()
{
Registry::get(UtilsView::class)->addErrorToDisplay('Mondu: Order has been declined');
Registry::getUtils()->redirect(Registry::getConfig()->getShopSecureHomeUrl() . 'cl=basket', false);
}
}
7 changes: 5 additions & 2 deletions Controller/MonduCheckoutController.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,17 @@ public function createOrder()
$orderData = $this->_orderMapper->getMappedOrderData($paymentMethod);

$response = $this->_client->createOrder($orderData);
$token = isset($response['uuid']) ? $response['uuid'] : 'error';
$token = $response['uuid'] ?? 'error';

if ($token !== 'error') {
$session = Registry::getSession();
$session->setVariable('mondu_order_uuid', $token);
}

echo json_encode(['token' => $token]);
echo json_encode([
'token' => $token,
'hostedCheckoutUrl' => $response['hosted_checkout_url'] ?? false
]);

exit();
}
Expand Down
112 changes: 99 additions & 13 deletions Controller/OrderController.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,108 @@

namespace OxidEsales\MonduPayment\Controller;

use OxidEsales\Eshop\Application\Model\Basket;
use OxidEsales\Eshop\Application\Model\Order;
use OxidEsales\Eshop\Application\Model\User;
use OxidEsales\Eshop\Core\Exception\StandardException;
use OxidEsales\Eshop\Core\Registry;
use OxidEsales\Eshop\Core\Request;
use OxidEsales\Eshop\Core\UtilsView;
use OxidEsales\MonduPayment\Core\Http\MonduClient;
use OxidEsales\MonduPayment\Core\Utils\MonduHelper;
use Symfony\Component\Config\Definition\Exception\Exception;

class OrderController extends OrderController_parent
{
public function isMonduPayment()
{
$session = Registry::getSession();
$paymentId = $session->getVariable("paymentid");

return MonduHelper::isMonduPayment($paymentId);
}

public function getPaymentPageUrl()
{
$shopUrl = $this->getConfig()->getShopSecureHomeURL();
return $shopUrl . '&cl=payment&payerror=2';
}
private MonduClient $_client;
private User|null|false $_oUser;

public function __construct()
{
parent::__construct();

$this->_client = oxNew(MonduClient::class);
$this->_oUser = $this->getUser();
}

public function isMonduPayment()
{
$session = Registry::getSession();
$paymentId = $session->getVariable('paymentid');

return MonduHelper::isMonduPayment($paymentId);
}

public function getPaymentPageUrl()
{
$shopUrl = \OxidEsales\Eshop\Core\Registry::getConfig()->getShopSecureHomeURL();
return $shopUrl . '&cl=payment&payerror=2';
}

/**
* @throws \Exception
*/
public function execute()
{
if($this->isMonduPayment()){
$orderUuid = Registry::get(Request::class)->getRequestEscapedParameter('order_uuid');

if (!$orderUuid) {
throw new \Exception('Mondu: Not found');
}

$monduOrder = $this->_client->getMonduOrder($orderUuid);
$response = $this->_client->confirmOrder($orderUuid, [
'external_reference_id' => $monduOrder['external_reference_id']
]);

if (isset($response['state']) && $response['state'] == 'confirmed') {
try {
$iSuccess = $this->monduExecute($this->getBasket());

return $this->_getNextStep($iSuccess);
} catch (Exception $e) {
throw new \Exception('Mondu: Error during the order process');
}
}
}

// if user is not logged in set the user
if(!$this->getUser() && isset($this->_oUser)){
$this->setUser($this->_oUser);
}

return parent::execute();
}

/**
* Save order to database, delete order_id from session and redirect to thank you page
*
* @param Basket $oBasket
*
* @return bool|int|mixed
*/
protected function monduExecute(Basket $oBasket)
{
if (!Registry::getSession()->getVariable('sess_challenge')) {
Registry::getSession()->setVariable('sess_challenge', Registry::getUtilsObject()->generateUID());
}

$iSuccess = 0;
$oBasket->calculateBasket(true);
$oOrder = oxNew(Order::class);

try {
$iSuccess = $oOrder->finalizeOrder($oBasket, $oBasket->getUser());
} catch (StandardException $e) {
Registry::get(UtilsView::class)->addErrorToDisplay($e);
}

if ($iSuccess === 1) {
// performing special actions after user finishes order (assignment to special user groups)
$this->_oUser->onOrderExecute($oBasket, $iSuccess);
}

return $iSuccess;
}
}
5 changes: 4 additions & 1 deletion Core/Http/HttpRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,10 @@ public function send_request(string $url, array $data, string $method)

$response = json_decode($response, true);

if (@$response['errors'] != null || @$response['error'] != null) {
if (
(isset($response['errors']) && $response['errors'] != null) ||
(isset($response['error']) && $response['error'] != null)
) {
throw new InvalidRequestException('[MONDU__ERROR] ' . json_encode($response), $data, $response);
}

Expand Down
20 changes: 16 additions & 4 deletions Core/Http/MonduClient.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ class MonduClient
{
private Config $_config;
private HttpRequest $_client;
private $_baseUrl = '';
private $_logger = null;
private $_baseUrl;
private $_logger;

public function __construct()
{
Expand All @@ -40,12 +40,24 @@ public function createOrder($data = [])
return $order['order'] ?? null;
}

public function authorizeOrder($data = [])
{
$order = $this->sendRequest('POST', 'orders', $data);
return $order['order'] ?? null;
}

public function updateOrderExternalInfo($orderUuid, $data = [])
{
$order = $this->sendRequest('POST', 'orders/' . $orderUuid . '/update_external_info', $data);
return $order['order'] ?? null;
}

public function confirmOrder($orderUuid, $data = [])
{
$order = $this->sendRequest('POST', 'orders/' . $orderUuid . '/confirm', $data);
return $order['order'] ?? null;
}

public function getMonduOrder($orderUuid)
{
$order = $this->sendRequest('GET', 'orders/' . $orderUuid);
Expand Down Expand Up @@ -108,8 +120,8 @@ protected function sendRequest($method = 'GET', $url = '', $body = [])
{
try {
$url = $this->_baseUrl . $url;
$response = $this->_client->send_request($url, $body, $method);
return $response;

return $this->_client->send_request($url, $body, $method);
} catch (InvalidRequestException $e) {
$this->_logger->error("MonduClient [{$method} {$url}]: Failed with an exception message: {$e->getString()}");

Expand Down
12 changes: 10 additions & 2 deletions Core/Mappers/MonduOrderMapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace OxidEsales\MonduPayment\Core\Mappers;

use OxidEsales\Eshop\Core\Registry;
use OxidEsales\MonduPayment\Core\Utils\MonduHelper;

class MonduOrderMapper
Expand Down Expand Up @@ -36,20 +37,27 @@ protected function getBasketUser()

public function getMappedOrderData($paymentMethod)
{
$session = Registry::getSession();
$basket = $this->getBasket();

$monduOrderUuid = $session->getVariable('mondu_order_uuid');
$tax = array_values($basket->getProductVats(false))[0];
$discount = $basket->getTotalDiscount()->getPrice();
$shipping = $basket->getDeliveryCost()->getPrice();
$shopUrl = Registry::getConfig()->getCurrentShopUrl();

$externalReferenceId = uniqid('M_OX_');
$data = [
"currency" => $basket->getBasketCurrency()->name,
"payment_method" => $paymentMethod,
"external_reference_id" => uniqid('M_OX_'),
"external_reference_id" => $externalReferenceId,
"gross_amount_cents" => round($basket->getPriceForPayment() * 100),
"buyer" => MonduHelper::removeEmptyElementsFromArray($this->getBuyerData()),
"billing_address" => MonduHelper::removeEmptyElementsFromArray($this->getUserBillingAddress()),
"shipping_address" => MonduHelper::removeEmptyElementsFromArray($this->getUserDeliveryAddress()),
"success_url" => $shopUrl . '?cl=order&fnc=execute&order_uuid=' . $monduOrderUuid . '&sDeliveryAddressMD5=' . $this->getBasketUser()->getEncodedDeliveryAddress(),
"cancel_url" => $shopUrl . '?cl=oemonducancel',
"declined_url" => $shopUrl . '?cl=oemondudeclined',
"state_flow" => 'authorization_flow',
"lines" => [[
"tax_cents" => round($tax * 100),
"shipping_price_cents" => round($shipping * 100),
Expand Down
2 changes: 1 addition & 1 deletion Core/Utils/MonduHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public static function showErrorMessage($message = '')

public static function isMonduPayment($paymentId = '')
{
return stripos($paymentId, "oxmondu") !== false;
return stripos($paymentId, 'oxmondu') !== false;
}

public static function isMonduModuleActive()
Expand Down
4 changes: 3 additions & 1 deletion metadata.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,9 @@
),
'controllers' => array(
'oemonducheckout' => \OxidEsales\MonduPayment\Controller\MonduCheckoutController::class,
'oemonduwebhooks' => \OxidEsales\MonduPayment\Controller\MonduWebhooksController::class
'oemonduwebhooks' => \OxidEsales\MonduPayment\Controller\MonduWebhooksController::class,
'oemonducancel' => \OxidEsales\MonduPayment\Controller\CancelController::class,
'oemondudecline' => \OxidEsales\MonduPayment\Controller\DeclineController::class
),
'blocks' => array(
array(
Expand Down
14 changes: 9 additions & 5 deletions out/src/js/mondu_checkout.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,17 @@ class MonduCheckout {
event.preventDefault();

if (this._isWidgetLoaded) {
const token = await this._getMonduToken();
const monduOrderData = await this._getMonduOrderData();

if (!token) {
if (!monduOrderData || !monduOrderData.token) {
window.location.href = this._paymentUrl;
}

this._renderWidget(token);
if (monduOrderData.hostedCheckoutUrl) {
window.location.href = monduOrderData.hostedCheckoutUrl;
} else {
this._renderWidget(monduOrderData.token);
}
}
}

Expand All @@ -57,13 +61,13 @@ class MonduCheckout {
});
}

async _getMonduToken() {
async _getMonduOrderData() {
try {
const client = new HttpRequest();
const { data } = await client.post('?cl=oemonducheckout&fnc=createOrder', {});

if (data.token !== 'error') {
return data.token;
return data;
} else {
return null;
}
Expand Down