Integrating the Easy Credit payment method for Heidelpay
Edit on GitHubSetup
The following configuration should be implemented after Heidelpay has been installed and integrated.
Configuration
CONFIGURATION KEY | TYPE | DESCRIPTION |
---|---|---|
HeidelpayConstants::CONFIG_HEIDELPAY_EASYCREDIT_CRITERIA_REJECTED_DELIVERY_ADDRESS |
string | Criteria to reject by delivery address (for example ‘Packstation’) |
HeidelpayConstants::CONFIG_HEIDELPAY_EASYCREDIT_CRITERIA_GRAND_TOTAL_LESS_THAN |
int | Criteria to reject if grand total less than (for example 200) |
HeidelpayConstants::CONFIG_HEIDELPAY_EASYCREDIT_CRITERIA_GRAND_TOTAL_MORE_THAN |
int | Criteria to reject if grand total greater than (for example 5000) |
HeidelpayConstants::CONFIG_HEIDELPAY_TRANSACTION_CHANNEL_EASY_CREDIT |
string | Transaction channel for Easy Credit payment method (provided by Heidelpay) |
- Activate Heidelpay Easycredit payment method.
OMS Configuration
$config[OmsConstants::PROCESS_LOCATION] = [
...
APPLICATION_ROOT_DIR . '/vendor/spryker-eco/heidelpay/config/Zed/Oms',
];
$config[OmsConstants::ACTIVE_PROCESSES] = [
...
'HeidelpayEasyCredit01',
];
$config[SalesConstants::PAYMENT_METHOD_STATEMACHINE_MAPPING] = [
...
HeidelpayConfig::PAYMENT_METHOD_EASY_CREDIT => 'HeidelpayEasyCredit01',
];
- Add Easycredit checkout steps to
StepFactory
.
\Pyz\Yves\CheckoutPage\Process\StepFactory
<?php
namespace Pyz\Yves\CheckoutPage\Process;
use Pyz\Yves\CheckoutPage\CheckoutPageDependencyProvider;
use Pyz\Yves\CheckoutPage\Plugin\Provider\CheckoutPageControllerProvider;
use Spryker\Yves\StepEngine\Process\StepCollection;
use SprykerEco\Client\Heidelpay\HeidelpayClientInterface;
use SprykerEco\Yves\Heidelpay\CheckoutPage\Process\Steps\HeidelpayEasycreditInitializeStep;
use SprykerEco\Yves\Heidelpay\CheckoutPage\Process\Steps\HeidelpayEasycreditStep;
use SprykerShop\Yves\CheckoutPage\Process\StepFactory as BaseStepFactory;
use SprykerShop\Yves\HomePage\Plugin\Provider\HomePageControllerProvider;
/**
* @method \SprykerShop\Yves\CheckoutPage\CheckoutPageConfig getConfig()
*/
class StepFactory extends BaseStepFactory
{
/**
* @return \Spryker\Yves\StepEngine\Process\StepCollectionInterface
*/
public function createStepCollection()
{
$stepCollection = new StepCollection(
$this->getUrlGenerator(),
CheckoutPageControllerProvider::CHECKOUT_ERROR
);
$stepCollection
->addStep($this->createEntryStep())
->addStep($this->createCustomerStep())
->addStep($this->createAddressStep())
->addStep($this->createShipmentStep())
->addStep($this->createHeidelpayEasyCreditInitializeStep())
->addStep($this->createPaymentStep())
->addStep($this->createHeidelpayEasyCreditStep())
->addStep($this->createSummaryStep())
->addStep($this->createPlaceOrderStep())
->addStep($this->createSuccessStep());
return $stepCollection;
}
/**
* @return \SprykerEco\Yves\Heidelpay\CheckoutPage\Process\Steps\HeidelpayEasycreditInitializeStep
*/
public function createHeidelpayEasyCreditInitializeStep(): HeidelpayEasycreditInitializeStep
{
return new HeidelpayEasycreditInitializeStep(
CheckoutPageControllerProvider::CHECKOUT_EASYCREDIT_INITIALIZE,
HomePageControllerProvider::ROUTE_HOME,
$this->getHeidelpayClient()
);
}
/**
* @return \SprykerEco\Yves\Heidelpay\CheckoutPage\Process\Steps\HeidelpayEasycreditStep
*/
public function createHeidelpayEasyCreditStep(): HeidelpayEasycreditStep
{
return new HeidelpayEasycreditStep(
CheckoutPageControllerProvider::CHECKOUT_EASYCREDIT,
HomePageControllerProvider::ROUTE_HOME
);
}
/**
* @return \SprykerEco\Client\Heidelpay\HeidelpayClientInterface
*/
public function getHeidelpayClient(): HeidelpayClientInterface
{
return $this->getProvidedDependency(CheckoutPageDependencyProvider::CLIENT_HEIDELPAY);
}
}
- Extend
CheckoutPageFactory
to change step factory creation:
\Pyz\Yves\CheckoutPage\CheckoutPageFactory
<?php
namespace Pyz\Yves\CheckoutPage;
use Pyz\Yves\CheckoutPage\Process\StepFactory;
use SprykerShop\Yves\CheckoutPage\CheckoutPageFactory as SprykerShopCheckoutPageFactory;
class CheckoutPageFactory extends SprykerShopCheckoutPageFactory
{
/**
* @return \Pyz\Yves\CheckoutPage\Process\StepFactory
*/
public function createStepFactory()
{
return new StepFactory();
}
}
- Extend
CheckoutController
to addEasycredit
step action:
\Pyz\Yves\CheckoutPage\Controller\CheckoutController
<?php
namespace Pyz\Yves\CheckoutPage\Controller;
use SprykerShop\Yves\CheckoutPage\Controller\CheckoutController as BaseCheckoutController;
use Symfony\Component\HttpFoundation\Request;
/**
* @method \SprykerShop\Yves\CheckoutPage\CheckoutPageFactory getFactory()
*/
class CheckoutController extends BaseCheckoutController
{
/**
* @param \Symfony\Component\HttpFoundation\Request $request
*
* @return array|\Symfony\Component\HttpFoundation\RedirectResponse
*/
public function easyCreditAction(Request $request)
{
return $this->createStepProcess()->process($request);
}
}
- Extend
CheckoutPageRouteProviderPlugin
to addEasycredit
actions:
\Pyz\Yves\CheckoutPage\Plugin\Router\CheckoutPageControllerProvider
<?php
namespace Pyz\Yves\CheckoutPage\Plugin\Provider;
use Spryker\Yves\Router\Route\RouteCollection;
use SprykerShop\Yves\CheckoutPage\Plugin\Router\CheckoutPageRouteProviderPlugin as SprykerShopCheckoutPageRouteProviderPlugin;
class CheckoutPageRouteProviderPlugin extends SprykerShopCheckoutPageRouteProviderPlugin
{
public const ROUTE_NAME_CHECKOUT_EASYCREDIT = 'checkout-easycredit';
public const ROUTE_NAME_CHECKOUT_EASYCREDIT_INITIALIZE = 'checkout-easycredit-initialize';
/**
* Specification:
* - Adds Routes to the RouteCollection.
*
* @api
*
* @param \Spryker\Yves\Router\Route\RouteCollection $routeCollection
*
* @return \Spryker\Yves\Router\Route\RouteCollection
*/
public function addRoutes(RouteCollection $routeCollection): RouteCollection
{
$route = $this->buildRoute('/checkout/easycredit', 'CheckoutPage', 'Checkout', 'easyCreditAction');
$routeCollection->add(static::ROUTE_NAME_CHECKOUT_EASYCREDIT, $route);
$route = $this->buildRoute('/checkout/easycredit-initialize', 'CheckoutPage', 'Checkout', 'easyCreditAction');
$routeCollection->add(static::ROUTE_NAME_CHECKOUT_EASYCREDIT_INITIALIZE, $route);
return $routeCollection;
}
}
- Update
CheckoutPageDependencyProvider
withEasycredit
related modifications:
\Pyz\Yves\CheckoutPage\CheckoutPageDependencyProvider
<?php
namespace Pyz\Yves\CheckoutPage;
...
use SprykerEco\Yves\Heidelpay\Plugin\Subform\HeidelpayEasyCreditSubFormPlugin;
...
class CheckoutPageDependencyProvider extends SprykerShopCheckoutPageDependencyProvider
{
public const CLIENT_HEIDELPAY = 'CLIENT_HEIDELPAY';
/**
* @param \Spryker\Yves\Kernel\Container $container
*
* @return \Spryker\Yves\Kernel\Container
*/
public function provideDependencies(Container $container)
{
$container = parent::provideDependencies($container);
$container = $this->addHeidelpayClient($container);
return $container;
}
/**
* @param \Spryker\Yves\Kernel\Container $container
*
* @return \Spryker\Yves\Kernel\Container
*/
protected function addSubFormPluginCollection(Container $container): Container
{
$container[self::PAYMENT_SUB_FORMS] = function () {
$subFormPluginCollection = new SubFormPluginCollection();
...
$subFormPluginCollection->add(new HeidelpayEasyCreditSubFormPlugin());
return $subFormPluginCollection;
};
return $container;
}
/**
* @param \Spryker\Yves\Kernel\Container $container
*
* @return \Spryker\Yves\Kernel\Container
*/
protected function addPaymentMethodHandlerPluginCollection(Container $container): Container
{
$container[self::PAYMENT_METHOD_HANDLER] = function () {
$stepHandlerPluginCollection = new StepHandlerPluginCollection();
...
$stepHandlerPluginCollection->add(new HeidelpayHandlerPlugin(), PaymentTransfer::HEIDELPAY_EASY_CREDIT);
return $stepHandlerPluginCollection;
};
return $container;
}
/**
* @param \Spryker\Yves\Kernel\Container $container
*
* @return \Spryker\Yves\Kernel\Container
*/
protected function addHeidelpayClient(Container $container): Container
{
$container[static::CLIENT_HEIDELPAY] = function () use ($container) {
return $container->getLocator()->heidelpay()->client();
};
return $container;
}
}
- Update
payment.twig
template withEasycredit
payment method:
src/Pyz/Yves/CheckoutPage/Theme/default/views/payment/payment.twig
{% extends template('page-layout-checkout', 'CheckoutPage') %}
{% define data = {
backUrl: _view.previousStepUrl,
forms: {
payment: _view.paymentForm
},
title: 'checkout.step.payment.title' | trans,
customForms: {
...
'heidelpay/easy-credit': ['easy-credit', 'heidelpay'],
}
} %}
{% block content %}
...
{% endblock %}
- Update
summary.twig
to template to displayEasycredit
related fees:
src/Pyz/Yves/CheckoutPage/Theme/default/views/payment/payment.twig
{% extends template('page-layout-checkout', 'CheckoutPage') %}
{% define data = {
backUrl: _view.previousStepUrl,
transfer: _view.quoteTransfer,
cartItems: _view.cartItems,
shippingAddress: _view.quoteTransfer.shippingAddress,
billingAddress: _view.quoteTransfer.billingAddress,
shipmentMethod: _view.quoteTransfer.shipment.method.name,
paymentMethod: _view.quoteTransfer.payment.paymentMethod,
heidelpayEasyCredit: _view.quoteTransfer.payment.heidelpayEasyCredit | default(null),
forms: {
summary: _view.summaryForm
},
overview: {
shipmentMethod: _view.quoteTransfer.shipment.method.name,
expenses: _view.quoteTransfer.expenses,
voucherDiscounts: _view.quoteTransfer.voucherDiscounts,
cartRuleDiscounts: _view.quoteTransfer.cartRuleDiscounts,
prices: {
subTotal: _view.quoteTransfer.totals.subtotal,
storeCurrency: _view.quoteTransfer.shipment.method.storeCurrencyPrice,
grandTotal: _view.quoteTransfer.totals.grandtotal,
tax: _view.quoteTransfer.totals.taxtotal.amount,
discountTotal: _view.quoteTransfer.totals.discounttotal | default
}
},
title: 'checkout.step.summary.title' | trans
} %}
{% block content %}
<div class="grid">
<div class="col col--sm-12 col--lg-4">
<div class="box">
<span class="float-right">{{ 'checkout.step.summary.with_method' | trans }} <strong>{{data.paymentMethod}}</strong></span>
<h6>{{ 'checkout.step.summary.payment' | trans }}</h6>
<br>
{% if data.heidelpayEasyCredit is not null %}
<span class="float-right">{{ data.heidelpayEasyCredit.amortisationText }}</span>
<div class="grid">
<a href="{{ data.heidelpayEasyCredit.preContractionInformationUrl }} "class="float-left">
{{ 'heidelpay.payment.easy_credit.pre_contraction_info_link_text' | trans }}
</a>
</div>
<br>
<div>
<ul>
<li><strong>{{ 'heidelpay.payment.easy_credit.order_total' | trans }} </strong>{{ data.heidelpayEasyCredit.totalOrderAmount | money }}</li>
<li><strong>{{ 'heidelpay.payment.easy_credit.interest' | trans }} </strong>{{ data.heidelpayEasyCredit.accruingInterest | money }}</li>
<li><strong>{{ 'heidelpay.payment.easy_credit.total_inc_interest' | trans }} </strong>{{ data.heidelpayEasyCredit.totalAmount | money }}</li>
</ul>
</div>
{% endif %}
<hr/>
{% include molecule('display-address') with {
class: 'text-small',
data: {
address: data.billingAddress
}
} only %}
</div>
<div class="box">
<span class="float-right">{{ 'checkout.step.summary.with_method' | trans }} <strong>{{ data.shipmentMethod }}</strong></span>
<h6>{{ 'checkout.step.summary.shipping' | trans }}</h6>
<hr/>
{% include molecule('display-address') with {
class: 'text-small',
data: {
address: data.shippingAddress
}
} only %}
</div>
</div>
<div class="col col--sm-12 col--lg-8">
<div class="box">
{% for item in data.cartItems %}
{% set item = item.bundleProduct is defined ? item.bundleProduct : item %}
{% embed molecule('summary-item', 'CheckoutPage') with {
data: {
name: item.name,
quantity: item.quantity,
price: item.sumPrice | money,
options: item.productOptions | default({}),
bundleItems: item.bundleItems | default([]),
quantitySalesUnit: item.quantitySalesUnit,
amountSalesUnit: item.amountSalesUnit,
amount: item.amount
},
embed: {
isLast: not loop.last,
item: item
}
} only %}
{% block body %}
{{parent()}}
{% if widgetExists('CartNoteQuoteItemNoteWidgetPlugin') %}
{% if embed.item.cartNote is not empty %}
{{ widget('CartNoteQuoteItemNoteWidgetPlugin', embed.item) }} {# @deprecated Use molecule('note-list', 'CartNoteWidget') instead. #}
{% endif %}
{% elseif embed.item.cartNote is not empty %}
{% include molecule('note-list', 'CartNoteWidget') ignore missing with {
data: {
label: 'cart_note.checkout_page.item_note',
note: embed.item.cartNote
}
} only %}
{% endif %}
{% if embed.isLast %}<hr/>{% endif %}
{% endblock %}
{% endembed %}
{% endfor %}
</div>
{% if data.transfer.cartNote is not empty %}
{% if widgetExists('CartNoteQuoteNoteWidgetPlugin') %}
<div class="box">
{{ widget('CartNoteQuoteNoteWidgetPlugin', data.transfer) }} {#@deprecated Use molecule('note-list', 'CartNoteWidget') instead.#}
</div>
{% else %}
<div class="box">
{% include molecule('note-list', 'CartNoteWidget') ignore missing with {
data: {
label: 'cart_note.checkout_page.quote_note',
note: data.transfer.cartNote
}
} only %}
</div>
{% endif %}
{% endif %}
<div class="box">
{% widget 'CheckoutVoucherFormWidget' args [data.transfer] only %}
{% elsewidget 'CheckoutVoucherFormWidgetPlugin' args [data.transfer] only %} {# @deprecated Use CheckoutVoucherFormWidget instead. #}
{% endwidget %}
</div>
{% embed molecule('form') with {
class: 'box',
data: {
form: data.forms.summary,
submit: {
enable: can('SeeOrderPlaceSubmitPermissionPlugin'),
text: 'checkout.step.place.order' | trans
},
cancel: {
enable: true,
url: data.backUrl,
text: 'general.back.button' | trans
}
},
embed: {
overview: data.overview
}
} only %}
{% block body %}
{% include molecule('summary-overview', 'CheckoutPage') with {
data: embed.overview
} only %}
<hr />
{{parent()}}
{% endblock %}
{% endembed %}
</div>
</div>
{% endblock %}
Checkout Payment Step Display
Displays payment method name with a radio button. No extra input fields are required.
Payment Step Submitting
No further actions are needed, the quote being filled with payment method selection as default. After selecting Easy Credit as a payment method “HP.IN” request will be sent. In the response, Heidelpay returns an URL string which defines where the customer has to be redirected. If everything was ok, the user would be redirected to the Easy Credit Externally.
Summary Review and Order Submitting
Once the customer is redirected back to us, the response from Easy Credit is sent to the Heidelpay, and Heidelpay makes a synchronous POST request to the shop’s CONFIG_HEIDELPAY_PAYMENT_RESPONSE_URL URL
(Yves), with the result of payment (see EasyCreditController::paymentAction()
). It is called “external response transaction,” the result will be persisted in spy_payment_heidelpay_transaction_log
as usual. The most important data here - is the payment reference ID which can be used for further transactions like finalize/reserve/etc
.
After that, the customer can see the order summary page, where they can review all related data.
There the user will see:
- Rate plan (
CRITERION.EASYCREDIT_AMORTISATIONTEXT
) - Interest fees (
CRITERION_EASYCREDIT_ACCRUINGINTEREST
) - Total sum including the interest fees (
CRITERION.EASYCREDIT_TOTALAMOUNT
)
If the customer has not yet completed the HP.IN they must do that again.
On the “save order” event - save Heidelpay payment per order and items, as usual.
When the state machine is initialized, an event “send authorize on registration request” will trigger the authorize on registration request. In case of success, the state will be changed.
Finalize - later on, when the item is shipped to the customer, it is time to call “finalize” command of the state machine. This will send HP.FI request to the Payment API. This is done in FinalizePlugin of the OMS command.
Thank you!
For submitting the form