Skip to main content
Version: 2023.3

Recurring Payment

Pimcore currently supports recurring payment for the payment provider Datatrans (Alias). It is performed via backend operations (server-to-server) which are used to create a new order and a new payment attempt by reusing the payment information available in a previous order, the so-called source order.

Recurring payment can for example be used to implement sequential payments like hiring or leasing agreements, or also to perform a one time payment for an authorized user which already committed at least one previous order successfully.

Additional Information​

Best Practice​

Bad Way​

Recurring Payment BadRecurring Payment BadRecurring Payment Bad

Good Way​

Recurring Payment GoodRecurring Payment GoodRecurring Payment Good

Implementation​

The following code will briefly show how to perform a one time payment inside the checkout process for Wirecard Checkout Page (former known as Qpay).

CheckoutController.php​

public function paymentAction(Request $request): Response
{
$factory = \Pimcore\Bundle\EcommerceFrameworkBundle\Factory::getInstance();

$checkoutManager = $factory->getCheckoutManager($this->cart);
$user = $this->getUser();

// open payment or submit recurring payment
if ($request->getMethod() == 'POST') {
if ($sourceOrderId = $request->get("recurring-payment")) {
/* Recurring Payment */
if ($user && $sourceOrderId) {
$sourceOrder = \Pimcore\Model\DataObject\OnlineShopOrder::getById($sourceOrderId);

try {
$targetOrder = $checkoutManager->startAndCommitRecurringOrderPayment($sourceOrder, $user->getId());
return $this->redirect($this->generateUrl('checkout', ['action' => 'completed']));
} catch (\Exception $exception) {
// show warning
}
}
}
}

$templateParams = [];
$paymentMethods = ["SEPA-DD", "CCARD"]; // supported payment methods

if ($user) {
$sourceOrders = [];

foreach ($paymentMethods as $paymentMethod) {
$orderManager = $factory->getOrderManager();
$sourceOrder = $orderManager->getRecurringPaymentSourceOrder($user->getId(), $checkoutManager->getPayment(), $paymentMethod);

$sourceOrders[$paymentMethod] = $sourceOrder;
}

$templateParams['sourceOrders'] = $sourceOrders;
}

$templateParams['paymentMethods'] = $paymentMethods;

return $this->render('checkout/payment.html.twig', $templateParams);
}

payment.html.php​

?>
<form method="post" action="{{ pimcore_url({action: 'confirm'}, 'checkout', true) }}">

{% if sourceOrders is not empty %}

<h4>{{ 'checkout.use-recurring-payment'|trans }}</h4>

{% for paymentMethod in paymentMethods %}
{% if sourceOrders[paymentMethod] is defined %}
{% set sourceOrder = sourceOrders[paymentMethod] %}
{% set paymentProvider = sourceOrder.paymentProvider.paymentProviderQpay %}
{% if paymentProvider %}
{% currentPaymentMethod = paymentProvider.Auth_paymentType %}
<p>
<input name="recurring-payment" value="{{ sourceOrder.id }}" type="radio">
<strong>{{ currentPaymentMethod }}</strong>

{% if currentPaymentMethod is same as('SEPA-DD') %}
{{ paymentProvider.Auth_bankAccountOwner }} {{ paymentProvider.Auth_bankAccountIBAN }}
{% elseif currentPaymentMethod is same as('CCARD') %}
{{ paymentProvider.Auth_maskedPan }} {{ paymentProvider.Auth_expiry }}
{% endif %}
</p>
{% endif %}
{% endif %}
{% endfor %}

<hr>
{% endif %}

</form>

ecommerce.yaml​

payment_manager:
providers:
qpay:
profiles:
sandbox:
secret: 'CHCSH7UGHVVX2P7EHDHSY4T2S4CGYK4QBE4M5YUUG2ND5BEZWNRZW5EJYVJQ'
customer: 'D200411'
toolkit_password: 'XXXXXXX' # necessary for recurPayment operation
optional_payment_properties:
- paymentType
- transactionIdentifier # necessary for recurPayment based on SEPA DIRECT DEBIT
recurring_payment_enabled: true # enable recurring payment