Implement Direct Debit in Yves

Edit on GitHub

The first step of the Direct Debit payment method implementation is setting it up on Yves. This document provides step-by-step instructions on how to do that.

Prerequisites

Before proceeding with the first step, the form creation, add a new module on the project level in Yves—for example, the PaymentMethods module. If you haven’t had any experience in creating a new module yet, see Tutorial: Add a new module.

Create a Form folder in the module.

Create a form

The starting point is to create a form in Yves.

To create a form, follow these steps.

1. Add the data provider

In the created PaymentMethods module, add the data provider to the Form/DataProvider/ folder:

<?php
namespace Pyz\Yves\PaymentMethods\Form\DataProvider;

use Generated\Shared\Transfer\PaymentDirectDebitTransfer;
use Generated\Shared\Transfer\PaymentTransfer;
use Generated\Shared\Transfer\QuoteTransfer;

class DirectDebitDataProvider
{

	/**
	* @param \Generated\Shared\Transfer\QuoteTransfer $quoteTransfer
	*
	* @return \Generated\Shared\Transfer\QuoteTransfer
	*/
	public function getData(QuoteTransfer $quoteTransfer)
	{
		if ($quoteTransfer->getPayment() === null) {
			$paymentTransfer = new PaymentTransfer();
			$paymentTransfer->setPaymentMethodsDirectDebit(new PaymentDirectDebitTransfer());
			$paymentTransfer->setDummyPaymentCreditCard(new PaymentDirectDebitTransfer());
			$quoteTransfer->setPayment($paymentTransfer);
		}

		return $quoteTransfer;
	}

	/**
	* @param \Generated\Shared\Transfer\QuoteTransfer $quoteTransfer
	*
	* @return array
	*/
	public function getOptions(QuoteTransfer $quoteTransfer)
	{
		return [];
	}

}

2. Implement the form

<?php
namespace Pyz\Yves\PaymentMethods\Form;

use Generated\Shared\Transfer\PaymentDirectDebitTransfer;
use Pyz\Shared\PaymentMethods\PaymentMethodsConstants;
use Spryker\Yves\StepEngine\Dependency\Form\AbstractSubFormType;
use Spryker\Yves\StepEngine\Dependency\Form\SubFormInterface;
use Spryker\Yves\StepEngine\Dependency\Form\SubFormProviderNameInterface;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Validator\Constraints\NotBlank;

class DirectDebitForm extends AbstractSubFormType implements SubFormInterface, SubFormProviderNameInterface
{
	const FIELD_BANK_ACCOUNT_HOLDER = 'bank_account_holder';
	const FIELD_BANK_ACCOUNT_IBAN = 'bank_account_iban';
	const FIELD_BANK_ACCOUNT_BIC = 'bank_account_bic';

	/**
	* @param \Symfony\Component\OptionsResolver\OptionsResolver $resolver
	*
	* @return void
	*/
	public function configureOptions(OptionsResolver $resolver)
	{
		$resolver->setDefaults([
			'data_class' => PaymentDirectDebitTransfer::class,
		])->setRequired(self::OPTIONS_FIELD_NAME);
	}

	/**
	* @param \Symfony\Component\Form\FormBuilderInterface $builder
	* @param array $options
	*
	* @return void
	*/
	public function buildForm(FormBuilderInterface $builder, array $options): void
	{
		$this->addBankAccountHolderField($builder);
		$this->addBankAccountIbanField($builder);
		$this->addBankAccountBicField($builder);
	}

	/**
	* @return string
	*/
	public function getTemplatePath()
	{
		return PaymentMethodsConstants::PROVIDER . '/views/' . PaymentMethodsConstants::PAYMENT_METHOD_DIRECTDEBIT;
	}

	/**
	* @return string
	*/
	public function getName()
	{
		return PaymentMethodsConstants::PAYMENT_METHOD_DIRECTDEBIT;
	}

	/**
	* @return string
	*/
	public function getProviderName()
	{
		return PaymentMethodsConstants::PROVIDER;
	}

	/**
	* @return string
	*/
	public function getPropertyPath()
	{
		return PaymentMethodsConstants::PAYMENT_METHOD_DIRECTDEBIT;
	}

	/**
	* @param \Symfony\Component\Form\FormBuilderInterface $builder
	*
	* @return $this
	*/
	protected function addBankAccountHolderField(FormBuilderInterface $builder)
	{
		$builder->add(
			static::FIELD_BANK_ACCOUNT_HOLDER,
			TextType::class,
			[
				'label' => static::FIELD_BANK_ACCOUNT_HOLDER,
				'constraints' => [
					$this->createNotBlankConstraint(),
				],
			]
		);

		return $this;
	}

	/**
	* @param \Symfony\Component\Form\FormBuilderInterface $builder
	*
	* @return $this
	*/
	protected function addBankAccountIbanField(FormBuilderInterface $builder)
	{
		$builder->add(
			static::FIELD_BANK_ACCOUNT_IBAN,
			TextType::class,
			[
				'label' => static::FIELD_BANK_ACCOUNT_IBAN,
				'constraints' => [
					$this->createNotBlankConstraint(),
				],
			]
		);

		return $this;
	}

	/**
	* @param \Symfony\Component\Form\FormBuilderInterface $builder
	*
	* @return $this
	*/
	protected function addBankAccountBicField(FormBuilderInterface $builder)
	{
		$builder->add(
			static::FIELD_BANK_ACCOUNT_BIC,
			TextType::class,
			[
				'label' => static::FIELD_BANK_ACCOUNT_BIC,
				'constraints' => [
					$this->createNotBlankConstraint(),
				],
			]
		);

		return $this;
	}

	/**
	* @return \Symfony\Component\Validator\Constraint
	*/
	protected function createNotBlankConstraint()
	{
		return new NotBlank(['groups' => $this->getPropertyPath()]);
	}
}

3. Add a plugin

After the form has been implemented, plug this form into the checkout by adding a plugin to the Plugin folder:

<?php
namespace Pyz\Yves\PaymentMethods\Plugin;


use Spryker\Yves\Kernel\AbstractPlugin;
use Spryker\Yves\StepEngine\Dependency\Plugin\Form\SubFormPluginInterface;

/**
* @method \Pyz\Yves\PaymentMethods\PaymentMethodsFactory getFactory()
*/
class DirectDebitSubFormPlugin extends AbstractPlugin implements SubFormPluginInterface
{
	/**
	* @return \Pyz\Yves\PaymentMethods\Form\DirectDebitForm
	*/
	public function createSubForm()
	{
		return $this->getFactory()->createDirectDebitForm();
	}

	/**
	* @return \Pyz\Yves\PaymentMethods\Form\DataProvider\DirectDebitDataProvider
	*/
	public function createSubFormDataProvider()
	{
		return $this->getFactory()->createDirectDebitFormDataProvider();
	}
}

Setup a payment handler

The next step is setting up the payment handler. Follow these steps to accomplish the procedure.

1. Handle a new payment type

To handle the new payment type, add the DirectDebitHandler class to the Handler/ folder:

<?php
namespace Pyz\Yves\PaymentMethods\Handler;

use Generated\Shared\Transfer\QuoteTransfer;
use Pyz\Shared\PaymentMethods\PaymentMethodsConstants;
use Symfony\Component\HttpFoundation\Request;

class DirectDebitHandler
{

	/**
	* @const string
	*/
	const PAYMENT_PROVIDER = PaymentMethodsConstants::PROVIDER;

	/**
	* @const string
	*/
	const PAYMENT_METHOD = PaymentMethodsConstants::PAYMENT_METHOD_DIRECTDEBIT;

	/**
	* @param \Symfony\Component\HttpFoundation\Request $request
	* @param \Generated\Shared\Transfer\QuoteTransfer $quoteTransfer
	*
	* @return \Generated\Shared\Transfer\QuoteTransfer
	*/
	public function addPaymentToQuote(Request $request, QuoteTransfer $quoteTransfer)
	{
		$quoteTransfer->getPayment()
			->setPaymentProvider(static::PAYMENT_PROVIDER)
			->setPaymentMethod(static::PAYMENT_METHOD);

		return $quoteTransfer;
	}
}

2. Plug the payment handler into the checkout

To plug this payment handler into the checkout, add a plugin to the following folders:

  • the Plugin/ folder:
<?php

namespace Pyz\Yves\PaymentMethods\Plugin;

use Spryker\Shared\Kernel\Transfer\AbstractTransfer;
use Spryker\Yves\Kernel\AbstractPlugin;
use Spryker\Yves\StepEngine\Dependency\Plugin\Handler\StepHandlerPluginInterface;
use Symfony\Component\HttpFoundation\Request;

/**
* @method \Pyz\Yves\PaymentMethods\PaymentMethodsFactory getFactory()
*/
class DirectDebitHandlerPlugin extends AbstractPlugin implements StepHandlerPluginInterface
{

	/**
	* @param \Symfony\Component\HttpFoundation\Request $request
	* @param \Generated\Shared\Transfer\QuoteTransfer|\Spryker\Shared\Kernel\Transfer\AbstractTransfer $quoteTransfer
	*
	* @return \Generated\Shared\Transfer\QuoteTransfer
	*/
	public function addToDataClass(Request $request, AbstractTransfer $quoteTransfer)
	{
		$this->getFactory()->createDirectDebitHandler()->addPaymentToQuote($request, $quoteTransfer);
	}

}
  • the Handler/ folder:
<?php

namespace Pyz\Yves\PaymentMethods\Handler;

use Generated\Shared\Transfer\PaymentTransfer;
use Generated\Shared\Transfer\QuoteTransfer;
use Pyz\Shared\PaymentMethods\PaymentMethodsConstants;
use Symfony\Component\HttpFoundation\Request;

class DirectDebitHandler
{

	/**
	* @const string
	*/
	const PAYMENT_PROVIDER = PaymentMethodsConstants::PROVIDER;

	/**
	* @const string
	*/
	const PAYMENT_METHOD = PaymentMethodsConstants::PAYMENT_METHOD_DIRECTDEBIT;

	/**
	* @param \Symfony\Component\HttpFoundation\Request $request
	* @param \Generated\Shared\Transfer\QuoteTransfer $quoteTransfer
	*
	* @return \Generated\Shared\Transfer\QuoteTransfer
	*/
	public function addPaymentToQuote(Request $request, QuoteTransfer $quoteTransfer)
	{
		$quoteTransfer->getPayment()		
			->setPaymentProvider(static::PAYMENT_PROVIDER)
			->setPaymentMethod(static::PAYMENT_METHOD);

		return $quoteTransfer;
	}
}

Create a Direct Debit Twig template

This section shows how to create the Twig template that is rendered when the direct debit payment method is selected under the configured path.

To create the Direct Debit twig template, do the following:

  1. In Yves, create the directdebit.twig template file in the PaymentMethods/Theme/ folder and ApplicationConstants::YVES_THEME config value directory.
  2. Adjust the path according to the theme you are currently using.

Code sample:

<div class="payment-subform directdebit-form">
<h4>{{ 'payment.paymentMethodsDirectDebit.directdebit.bankaccount' | trans }}</h4>
<label>{{ 'payment.paymentMethodsDirectDebit.directdebit.holder' | trans }}</label>
	<div class="field">
		{{ form_widget(form.paymentMethodsDirectDebit.bank_account_holder, { 'attr': {'placeholder': 'payment.paymentMethodsDirectDebit.directdebit.holder' | trans } }) }}
		{{ form_errors(form.paymentMethodsDirectDebit.bank_account_holder) }}
</div>
	<label>{{ 'payment.paymentMethodsDirectDebit.directdebit.iban' | trans }}</label>
	<div class="field">
		{{ form_widget(form.paymentMethodsDirectDebit.bank_account_iban, { 'attr': {'placeholder': 'payment.paymentMethodsDirectDebit.directdebit.iban' | trans } }) }}
		{{ form_errors(form.paymentMethodsDirectDebit.bank_account_iban) }}
</div>
	<label>{{ 'payment.paymentMethodsDirectDebit.directdebit.bic' | trans }}</label>
	<div class="field">
		{{ form_widget(form.paymentMethodsDirectDebit.bank_account_bic, { 'attr': {'placeholder': 'payment.paymentMethodsDirectDebit.directdebit.bic' | trans } }) }}
		{{ form_errors(form.paymentMethodsDirectDebit.bank_account_bic) }}
</div>
		{{ form_widget(form.paymentMethodsDirectDebit) }}
		{{ form_errors(form.paymentMethodsDirectDebit) }}
</div>

Add the factory and the dependency provider for this new module in Yves.

What’s next?

After the form has been created and the payment handler has been set up, you need to integrate them into the Checkout module.