Implementation of Direct Debit in Yves
Edit on GitHubUsually, the first step of the Direct Debit payment method implementation is set-up on Yves. This article provides step-by-step instructions on how to do that.
Prerequisites
Prior to 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 - Adding a New Module. Create a Form folder in the module.
Creating a Form
The starting point is to create the form in Yves.
To create the form, do the following:
1. Add the data provider
In the created module, in our example PaymentMethods
, 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
Once done, 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();
}
}
Setting up a Payment Handler
The next step is setting up the payment handler. Follow the procedure below to accomplish this.
1. Handle a new payment type
To handle the new payment type, add a 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;
}
}
Creating a Direct Debit Twig Template
This procedure learns you on how to create the Twig template that will be 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, and thenApplicationConstants::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>
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