Warning: You are browsing the documentation from version 4 to 10 of Pimcore.
Please visit https://pimcore.com/docs/platform/ for the latest versions of Pimcore.
Version:
MPay24
Requirement
Mpay24 PHP SDK, which can be installed by adding the composer requirement named "mpay24/mpay24-php": "^4.2".
Configuration
Inside your ecommerce.yml configuration, activate the MPay24 provider.
Implementation
CheckoutController.php (action, where the payment form will be rendered):
...
//important: if payment is active, then keep payment state and do not allow parallel payment!
if ($this->checkoutManager->hasActivePayment() && $this->cart->isCartReadOnly()) {
return $this->redirectToRoute('app_shop_cart_list');
}
$paymentInfo = $this->checkoutManager->startOrderPayment();
$payment = $this->checkoutManager->getPayment();
$paymentFormAsString =
$payment->initPayment(
$this->cart->getPriceCalculator()->getGrandTotal(),
[
'request' => $request,
'paymentInfo' => $paymentInfo
]
);
$order = $this->checkoutManager->getOrder();
$order->setOrderState("");//important to unlock order payment, as order can be locked
$order->save(['versionInfo' => 'Clear state, because payment is not locked yet.']);
$this->view->paymentFormAsString = $paymentFormAsString;
Somewhere in your order.html.php view:
...
<section>
<h2>Select Payment:</h2>
<?=$paymentFormAsString;?>
</section>
...
paymentMethods.html.php view (linked in ecommerce.yml):
<?php
/**
* Partial for payment methods + form generation, called + configured in Mpay24Seamless Provider
* @var $tokenizer
* @var $paymentMethods string[]
* @var $selectedMethod string
*/
// injected $selectedMethod if needed
$selectedMethod = isset($selectedMethod) ? $selectedMethod : 'cc';
?>
<form action="<?=$this->prettyUrl([],'app_shop_payment_start');?>" method="post" class="js-payment-methods-form js-cart-sidebar-update">
<input name="token" type="hidden" value="<?php echo $tokenizer->getToken(); ?>"/>
<? foreach ($paymentMethods as $method => $methodConfig):?>
<div class="custom-radio">
<label>
<input class="custom-radio__input js-payment-method-select" type="radio" name="type" value="<?=strtoupper($method);?>"
data-method="<?=$method;?>"
required="required" <?=$method == $selectedMethod ? 'checked="checked"' : "";?>>
<span class="custom-radio__box"></span>
<span class="custom-radio__text"><?=$this->t('shop.payment.methods.'.$method);?></span>
</label>
</div>
<? if ($method == 'cc'): ?>
<!-- @todo frontend optimise please -->
<div class="js-payment-method-attachment" id="payment-method-attachement-<?=$method;?>" style="<?=$selectedMethod == $method ? '' : 'display:none';?>">
<iframe src="<?php echo $tokenizer->getLocation(); ?>" frameBorder="0"></iframe>
</div>
<?endif;?>
<? endforeach;?>
<input type="submit" href="<?=$this->prettyUrl([], 'app_shop_checkout_start');?>" class="js-payment-submit btn btn-success btn-block mt-4"
value="<?=$this->t('shop.checkout.order.execute-payment');?>"/>
</form>
Example PaymentController.php (Responsiblity payment actions):
<?php
namespace AppBundle\Controller\Shop;
use AppBundle\Controller\AbstractController;
use AppBundle\Ecommerce\OrderManager\OrderManager;
use AppBundle\Service;
use AppBundle\TraitAware\TraitLoggerAware;
use Pimcore\Bundle\EcommerceFrameworkBundle\Factory;
use Pimcore\Bundle\EcommerceFrameworkBundle\Model\AbstractOrder;
use Pimcore\Bundle\EcommerceFrameworkBundle\PaymentManager\Payment\Mpay24Seamless;
use Pimcore\Model\Element\Note;
use Pimcore\Tool;
use Pimcore\Translation\Translator;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\RouterInterface;
use Symfony\Component\Routing\Annotation\Route;
class PaymentController extends AbstractController\AbstractFrontendController
{
use TraitLoggerAware; //initializes getLogger() functionality
/**
* @Route("/{_prefix}/checkout/payment/start", requirements={"_prefix" = "\w\w\/?[\w\-]*"})
* @param Request $request
* @return RedirectResponse|\Symfony\Component\HttpFoundation\Response
* @throws \Exception
* @throws \Pimcore\Bundle\EcommerceFrameworkBundle\Exception\UnsupportedException
*/
public function startAction(Request $request, RouterInterface $router)
{
$serviceShop = \Pimcore::getContainer()->get(Service\Shop::class);
$checkoutManager = Factory::getInstance()->getCheckoutManager(
$serviceShop->getCart()
);
/** @var Mpay24Seamless $payment */
$payment = $checkoutManager->getPayment();
$paymentInfo = $checkoutManager->startOrderPayment();
$paymentType = $request->get('type');
if ($request->isMethod('post')) {
if ($request->isMethod('post') && $paymentType == 'INVOICE') {
$factory = \Pimcore\Bundle\EcommerceFrameworkBundle\Factory::getInstance();
/** @var OrderManager $orderManager */
$orderManager = $factory->getOrderManager();
$order = $orderManager->getOrCreateOrderFromCart($serviceShop->getCart());
$factory->getCommitOrderProcessor()->commitOrder($order);
return $this->redirectToCheckoutSuccessPage($order);
} else {
$baseUrl = Tool::getHostUrl();
$paymentParams = [
'request' => $request,
'order' => $checkoutManager->getOrder(),
'paymentInfo' => $checkoutManager->getOrder()->getPaymentInfo()->get(0),
'successURL' => $baseUrl . $router->generate('app_shop_payment_response', ['type' => 'success', 'elementsclientauth'=>'disabled']),
'errorURL' => $baseUrl . $router->generate('app_shop_payment_response', ['type' => 'error', 'elementsclientauth'=>'disabled']),
'confirmationURL' => $baseUrl . $router->generate('app_shop_payment_response', ['type' => 'confirmation', 'elementsclientauth'=>'disabled']),
];
//either redirect to paypal, etc. or to internal (error) URL
list($redirectUrl, $errorText) = $payment->getInitPaymentRedirectUrl($paymentParams);
if ($errorText) {
$this->addFlash('error', [$errorText]);
//save note for debugging
$order = $checkoutManager->getOrder();
$note = new Note();
$note->setElement($order);
$note->setType("user_payment_denied");
$note->setTitle($errorText);
$note->setUser(0);
$note->save();
return $this->redirectToRoute('app_shop_checkout_start');
}
return new RedirectResponse($redirectUrl);
}
}
}
private function redirectToCheckoutSuccessPage(AbstractOrder $order) {
$factory = \Pimcore\Bundle\EcommerceFrameworkBundle\Factory::getInstance();
$orderManager = $factory->getOrderManager();
$encryptedOrderNumber = $orderManager->getEncryptedOrderNumber($order);
return $this->redirectToRoute('app_shop_checkout_success', ['o' => $encryptedOrderNumber]);
}
/**
* @Route("/{_prefix}/checkout/payment/mpay-response/{type}", requirements={"_prefix" = "\w\w\/?[\w\-]*"})
* @param Request $request
* @return RedirectResponse|\Symfony\Component\HttpFoundation\Response
* @throws \Exception
*/
public function responseAction(Request $request, Translator $translator)
{
$serviceShop = \Pimcore::getContainer()->get(Service\Shop::class);
$checkoutManager = Factory::getInstance()->getCheckoutManager(
$serviceShop->getCart()
);
$type = $request->get('type');
if ($type == 'confirmation') {
//@see https://docs.mpay24.com/docs/backend2backend-integration
$this->getLogger()->info('Mpay24 called confirmation URL.');
$response = new Response();
$response->setContent("OK");
$response->headers->set('Content-Type', 'text/plain');
return $response;
}
//currently errors are also handled via commit processor and result in cancel-statements.
//Thus, the order remains uncommitted.
$commitOrderProcessor = Factory::getInstance()->getCommitOrderProcessor();
/** @var Mpay24Seamless $payment */
$payment = $checkoutManager->getPayment();
try {
$order = $commitOrderProcessor->handlePaymentResponseAndCommitOrderPayment(
$request->query->all(),$payment
);
if ($order->getOrderState() == AbstractOrder::ORDER_STATE_COMMITTED) {
return $this->redirectToCheckoutSuccessPage($order);
}
} catch (\Exception $e) {
$this->getLogger()->error(sprintf('Exception in payment Controller: %s', $e->getMessage()));
}
$this->addFlash('error', [$translator->trans('shop.payment.error-or-cancelled')]);
return $this->redirectToRoute('app_shop_checkout_start');
}
}