Implement Direct Debit in Yves
Edit on GitHubThe 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:
- In Yves, create the
directdebit.twig
template file in thePaymentMethods/Theme/
folder andApplicationConstants::YVES_THEME
config value directory. - 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.
Thank you!
For submitting the form