Ratenkauf by Easycredit - Installation and Configuration
  • Updated on 05 Mar 2020
  • 11 minutes to read
  • Print
  • Share
  • Dark
    Light

Ratenkauf by Easycredit - Installation and Configuration

  • Print
  • Share
  • Dark
    Light

Installation

To install Easycredit, run the following command in console:

composer require spryker-eco/easycredit

After installation, run the propel:install command or check the following migration:

CREATE SEQUENCE "spy_payment_easycredit_api_log_pk_seq";
 
CREATE TABLE "spy_payment_easycredit_api_log"
(
    "id_payment_easycredit_api_log" INTEGER NOT NULL,
    "type" VARCHAR NOT NULL,
    "request" TEXT NOT NULL,
    "response" TEXT NOT NULL,
    "status_code" INT2,
    "error_code" VARCHAR,
    "error_message" VARCHAR,
    "error_type" VARCHAR,
    "created_at" TIMESTAMP,
    "updated_at" TIMESTAMP,
    PRIMARY KEY ("id_payment_easycredit_api_log")
);
 
CREATE SEQUENCE "spy_payment_easycredit_order_identifier_pk_seq";
 
CREATE TABLE "spy_payment_easycredit_order_identifier"
(
    "id_payment_easycredit_order_identifier" INTEGER NOT NULL,
    "fk_sales_order" INTEGER NOT NULL,
    "identifier" VARCHAR NOT NULL,
    "confirmed" BOOLEAN NOT NULL,
    PRIMARY KEY ("id_payment_easycredit_order_identifier")
);

Configuration

Perform the initial configuration of Easycredit:

<?php
...
use SprykerEco\Shared\Easycredit\EasycreditConstants;
use Spryker\Shared\Oms\OmsConstants;
use Spryker\Shared\Sales\SalesConstants;
 
...
 
$config[OmsConstants::ACTIVE_PROCESSES] = [
    ...
    'Easycredit01',
];
 
$config[SalesConstants::PAYMENT_METHOD_STATEMACHINE_MAPPING] = [
    ...
    'easycredit' => 'Easycredit01',
];
 
...
$config[EasycreditConstants::SHOP_IDENTIFIER] = 'Your shop identifier';
$config[EasycreditConstants::SHOP_TOKEN] = 'Your shop token';
$config[EasycreditConstants::API_URL] = 'https://ratenkauf.easycredit.de/ratenkauf-ws/rest/v2';
$config[EasycreditConstants::SUCCESS_URL] = $config[ApplicationConstants::BASE_URL_YVES] . '/easycredit/payment/success';
$config[EasycreditConstants::CANCELLED_URL] = $config[ApplicationConstants::BASE_URL_YVES] . '/checkout/payment';
$config[EasycreditConstants::DENIED_URL] = $config[ApplicationConstants::BASE_URL_YVES] . '/checkout/payment';

Integration

To integrate Easycredit into your project, do the following:

  1. Update CheckoutPageDependencyProvider by adding a new payment subform and a payment method handler.
    To show the Easycredit payment method on the payment step, define SubFormPlugin and StepHandlerPlugin.

CheckoutPageDependencyProvider.php

public const CLIENT_EASYCREDIT = 'CLIENT_EASYCREDIT';
 
...
    /**
     * @param \Spryker\Yves\Kernel\Container $container
     *
     * @return \Spryker\Yves\Kernel\Container
     */
    public function provideDependencies(Container $container): Container
    {
        $container = parent::provideDependencies($container);
        $container = $this->addEasycreditClient($container);
     
        return $container;
    }
 
    /**
     * @param \Spryker\Yves\Kernel\Container $container
     *
     * @return \Spryker\Yves\Kernel\Container
     */
    protected function addSubFormPluginCollection(Container $container): Container
    {
        $container[static::PAYMENT_SUB_FORMS] = function () {
            $subFormPluginCollection = new SubFormPluginCollection();
            $subFormPluginCollection->add(new EasycreditSubFormPlugin());
 
            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 EasycreditHandlerPlugin(), PaymentTransfer::EASYCREDIT);
             return $stepHandlerPluginCollection;
        };
 
        return $container;
    }
 
    /**
     * @param \Spryker\Yves\Kernel\Container $container
     *
     * @return \Spryker\Yves\Kernel\Container
     */
    protected function addEasycreditClient(Container $container): Container
    {
        $container[static::CLIENT_EASYCREDIT] = function (Container $container) {
            return $container->getLocator()->easycredit()->client();
        };
 
        return $container;
    }
...
  1. The next dependency provider you should update is OmsDependencyProvider.
    To use commands and conditions for events in OMS, define them.

OmsDependencyProvider

...
$container->extend(self::CONDITION_PLUGINS, function (ConditionCollectionInterface $conditionCollection) {
    $conditionCollection->add(new IsOrderConfirmedPlugin(), 'Easycredit/IsOrderConfirmed');
    return $conditionCollection;
});
...
  1. And one more dependency provider to be updated is CheckoutDependencyProvider.
    To send requests to Easycredit, you need the technical order identifier value. After adding this plugin, the order identifier will be saved to the database in table spy_payment_easycredit_order_identifier.

CheckoutDependencyProvider

...
protected function getCheckoutOrderSavers(Container $container)
{
    return [
        ...
        new EasycreditOrderIdentifierPlugin(),
    ];
}
 
...

To use Easycredit requests during the checkout process, you have to create your own checkout steps. To implement the checkout steps, follow the guidelines below:

  1. Extend StepFactory.

CheckoutPageFactory

<?php

namespace Pyz\Yves\CheckoutPage;

use Pyz\Yves\CheckoutPage\Process\StepFactory;
use SprykerShop\Yves\CheckoutPage\CheckoutPageFactory as SprykerCheckoutPageFactory;

class CheckoutPageFactory extends SprykerCheckoutPageFactory
{
	/**
	 * @return \SprykerShop\Yves\CheckoutPage\Process\StepFactory
	 */
	public function createStepFactory()
	{
		return new StepFactory();
	}
}
  1. Implement StepFactory as shown in this example:

StepFactory

<?php

namespace Pyz\Yves\CheckoutPage\Process;

use Pyz\Yves\CheckoutPage\CheckoutPageDependencyProvider;
use Pyz\Yves\CheckoutPage\Plugin\Provider\CheckoutPageControllerProvider;
use Pyz\Yves\CheckoutPage\Process\Steps\EasycreditStep;
use Pyz\Yves\CheckoutPage\Process\Steps\ShipmentStep;
use Pyz\Yves\CheckoutPage\Process\Steps\SummaryStep;
use Spryker\Client\Messenger\MessengerClientInterface;
use Spryker\Yves\StepEngine\Dependency\Step\StepInterface;
use Spryker\Yves\StepEngine\Process\StepCollection;
use Spryker\Zed\Messenger\Business\MessengerFacadeInterface;
use SprykerEco\Client\Easycredit\EasycreditClient;
use SprykerShop\Yves\CheckoutPage\Process\StepFactory as SprykerStepFactory;
use SprykerShop\Yves\HomePage\Plugin\Provider\HomePageControllerProvider;

class StepFactory extends SprykerStepFactory
{
    /**
     * @return StepInterface
     */
    public function createEasycreditStep(): StepInterface
    {
        return new EasycreditStep(
            CheckoutPageControllerProvider::CHECKOUT_EASY_CREDIT,
            HomePageControllerProvider::ROUTE_HOME,
            $this->getEasycreditClient()
        );
    }

    /**
    * @return StepInterface
    */
    public function createSummaryStep(): StepInterface
    {
          return new SprykerShopSummaryStep(
            $this->getProductBundleClient(),
            $this->getShipmentService(),
            $this->getConfig(),
            SprykerShopCheckoutPageControllerProvider::CHECKOUT_SUMMARY,
            HomePageControllerProvider::ROUTE_HOME,
            $this->getCheckoutClient()
        );

    }

   /**
    * @return StepInterface
    */
    public function createShipmentStep(): StepInterface
    {
        return new ShipmentStep(
            $this->getCalculationClient(),
            $this->getShipmentPlugins(),
            $this->createShipmentStepPostConditionChecker(),
            $this->createGiftCardItemsChecker(),
            SprykerShopCheckoutPageControllerProvider::CHECKOUT_SHIPMENT,
            HomePageControllerProvider::ROUTE_HOME,
            $this->getEasycreditClient()
        );

    }

    /**
     * @return \Spryker\Yves\StepEngine\Process\StepCollectionInterface
     */
    public function createStepCollection(): StepCollectionInterface
    {
        $stepCollection = new StepCollection(
            $this->getUrlGenerator(),            {% if data.easycredit %}
                {% include molecule('easycredit-summary', 'Easycredit') with {
                    data: {
                        interest: data.easycredit.interest,
                        url: data.easycredit.url,
                        text: data.easycredit.text
                    }
                } only %}
            {% endif %}

            CheckoutPageControllerProvider::CHECKOUT_ERROR
        );
         $stepCollection
            ->addStep($this->createEntryStep())
            ->addStep($this->createCustomerStep())
            ->addStep($this->createAddressStep())
            ->addStep($this->createShipmentStep())
            ->addStep($this->createPaymentStep())
            ->addStep($this->createEasycreditStep())
            ->addStep($this->createSummaryStep())
            ->addStep($this->createPlaceOrderStep())
            ->addStep($this->createSuccessStep());
         return $stepCollection;
    }

    /**
     * @return EasycreditClientInterface
     */
    protected function getEasycreditClient(): EasycreditClientInterface
    {
        return $this->getProvidedDependency(CheckoutPageDependencyProvider::CLIENT_EASYCREDIT);
    }
}
  1. Now you can extend the basic steps on the project level and can create your Easycredit step that will be called when a user takes Easycredit as PaymentMethod.
    Examples of steps implementations:

EasycreditStep.php

<?php

namespace Pyz\Yves\CheckoutPage\Process\Steps;

use Spryker\Shared\Kernel\Transfer\AbstractTransfer;
use Spryker\Yves\StepEngine\Dependency\Step\AbstractBaseStep;
use Spryker\Yves\StepEngine\Dependency\Step\StepWithExternalRedirectInterface;
use SprykerEco\Client\Easycredit\EasycreditClient;
use SprykerEco\Shared\Easycredit\EasycreditConfig;
use Symfony\Component\HttpFoundation\Request;

class EasycreditStep extends AbstractBaseStep implements StepWithExternalRedirectInterface
{
    protected const URL_EASYCREDIT_REDIRECT_URL = 'https://ratenkauf.easycredit.de/ratenkauf/content/intern/einstieg.jsf?vorgangskennung=';

    /**
     * @var string
     */
    protected $redirectUrl = '';

   /**
    * @var \SprykerEco\Client\Easycredit\EasycreditClientInterface
    */
    protected $easycreditClient;

     /**
     * @param string $stepRoute
     * @param string $escapeRoute
     * @param \SprykerEco\Client\Easycredit\EasycreditClientInterface $easycreditClient
     */
    public function __construct(
        $stepRoute,
        $escapeRoute,
        EasycreditClientInterface $easycreditClient
    ) {
        parent::__construct($stepRoute, $escapeRoute);
        $this->easycreditClient = $easycreditClient;
    }

    /**
     * @param \Spryker\Shared\Kernel\Transfer\AbstractTransfer|\Generated\Shared\Transfer\QuoteTransfer $quoteTransfer
     *
     * @return bool
     */
    public function requireInput(AbstractTransfer $quoteTransfer)
    {
        return false;
    }

    /**
     * @param \Symfony\Component\HttpFoundation\Request $request
     * @param \Spryker\Shared\Kernel\Transfer\AbstractTransfer|\Generated\Shared\Transfer\QuoteTransfer $quoteTransfer
     *
     * @return \Spryker\Shared\Kernel\Transfer\AbstractTransfer
     */
    public function execute(Request $request, AbstractTransfer $quoteTransfer)
    {
        $payment = $quoteTransfer->getPayment();
         if ($payment->getPaymentSelection() === 'easycredit') {
            $responseTransfer = $this->easycreditClient->sendInitializePaymentRequest($quoteTransfer);
            $this->redirectUrl = static::URL_EASYCREDIT_REDIRECT_URL . $responseTransfer->getPaymentIdentifier();
            $quoteTransfer->getPayment()->getEasycredit()->setVorgangskennung($responseTransfer->getPaymentIdentifier());
        }
         return $quoteTransfer;
    }

    /**
     * @param \Spryker\Shared\Kernel\Transfer\AbstractTransfer|\Generated\Shared\Transfer\QuoteTransfer $quoteTransfer
     *
     * @return bool
     */
    public function postCondition(AbstractTransfer $quoteTransfer)
    {
        return true;
    }

    /**
     * Return external redirect url, when redirect occurs not within same application. Used after execute.
     *
     * @return string
     */
    public function getExternalRedirectUrl()
    {
        return $this->redirectUrl;
    }

    /**
     * Requirements for this step, return true when satisfied.
     *
     * @param \Generated\Shared\Transfer\QuoteTransfer $quoteTransfer
     *
     * @return bool
     */
    public function preCondition(AbstractTransfer $quoteTransfer)
    {
        return true;
    }
    

ShipmentStep.php

<?php

namespace Pyz\Yves\CheckoutPage\Process\Steps;

use Generated\Shared\Transfer\EasycreditLegalTextTransfer;
use Generated\Shared\Transfer\QuoteTransfer;
use Spryker\Shared\Kernel\Transfer\AbstractTransfer;
use Spryker\Yves\StepEngine\Dependency\Plugin\Handler\StepHandlerPluginCollection;
use SprykerEco\Client\Easycredit\EasycreditClient;
use SprykerEco\Shared\Easycredit\EasycreditConfig;
use SprykerShop\Yves\CheckoutPage\Dependency\Client\CheckoutPageToCalculationClientInterface;
use SprykerShop\Yves\CheckoutPage\Process\Steps\ShipmentStep as SprykerShipmentStep;
use Symfony\Component\HttpFoundation\Request;

class ShipmentStep extends SprykerShipmentStep
{
    /**
     * @var EasycreditClientInterface
     */
    protected $easycreditClient;

    public function __construct(
        CheckoutPageToCalculationClientInterface $calculationClient,
        StepHandlerPluginCollection $shipmentPlugins,
        string $stepRoute,
        string $escapeRoute,
        EasycreditClientInterface $client
    ) {
        parent::__construct($calculationClient, $shipmentPlugins, $stepRoute, $escapeRoute);
        $this->easycreditClient = $client;
    }

    /**
     * @param Request $request
     * @param QuoteTransfer $quoteTransfer
     * @return \Generated\Shared\Transfer\QuoteTransfer
     */
    public function execute(Request $request, AbstractTransfer $quoteTransfer)
    {
        $easycreditLegalTextTransfer = new EasycreditLegalTextTransfer();
        $easycreditLegalTextTransfer->setText($this->easycreditClient->sendApprovalTextRequest()->getText());
        $quoteTransfer->setEasycreditLegalText($easycreditLegalTextTransfer);
        return parent::execute($request, $quoteTransfer);
    }
}

SummaryStep.php

<?php

namespace Pyz\Yves\CheckoutPage\Process\Steps;

use Spryker\Shared\Kernel\Transfer\AbstractTransfer;
use SprykerEco\Client\Easycredit\EasycreditClient;
use SprykerShop\Yves\CheckoutPage\Dependency\Client\CheckoutPageToProductBundleClientInterface;
use SprykerShop\Yves\CheckoutPage\Process\Steps\SummaryStep as SprykerSummaryStep;
use Symfony\Component\HttpFoundation\Request;

class SummaryStep extends SprykerSummaryStep
{
     /**
     * @param \Generated\Shared\Transfer\QuoteTransfer $quoteTransfer
     *
     * @return array
     */
    public function getTemplateVariables(AbstractTransfer $quoteTransfer)
    {
        $easycreditData = [];
             if ($quoteTransfer->getPayment() && $quoteTransfer->getPayment()->getEasycredit()) {
            $easycreditData = [
                'interest' => $quoteTransfer->getPayment()->getEasycredit()->getAnfallendeZinsen(),
                'url' => $quoteTransfer->getPayment()->getEasycredit()->getUrlVorvertraglicheInformationen(),
                'text' => $quoteTransfer->getPayment()->getEasycredit()->getTilgungsplanText(),
            ];
        }

        return [
            'quoteTransfer' => $quoteTransfer,
            'cartItems' => $this->productBundleClient->getGroupedBundleItems(
                $quoteTransfer->getItems(),
                $quoteTransfer->getBundleItems()
            ),
            'easycredit' => $easycreditData,
        ];
    }
}
  1. To run the step process for the new Easycredit step, extend the default CheckoutController with a new action for handling the Easycredit step.

\CheckoutController

<?php

namespace Pyz\Yves\CheckoutPage\Controller;

use SprykerShop\Yves\CheckoutPage\Controller\CheckoutController as SprykerCheckoutController;
use Symfony\Component\HttpFoundation\Request;

class CheckoutController extends SprykerCheckoutController
{
	/**
	 * @param \Symfony\Component\HttpFoundation\Request $request
	 *
	 * @return array|\Symfony\Component\HttpFoundation\RedirectResponse
	 */
	public function easyCreditAction(Request $request)
	{
		return $this->createStepProcess()->process($request);
	}
}
  1. After creating a new action in the checkout controller, define a new route in CheckoutPageRouteProviderPlugin.

CheckoutPageRouteProviderPlugin.php

<?php

namespace Pyz\Yves\CheckoutPage\Plugin\Router;

use SprykerShop\Yves\CheckoutPage\Plugin\Router\CheckoutPageRouteProviderPlugin as SprykerCheckoutPageRouteProviderPlugin;
use Spryker\Yves\Router\Route\RouteCollection;

class CheckoutPageRouteProviderPlugin extends SprykerCheckoutPageRouteProviderPlugin
{
    public const CHECKOUT_EASY_CREDIT = 'easy-credit';
    protected const ROUTE_CART = 'cart';

    /**
     * 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
    {
        $routeCollection = parent::addRoutes($routeCollection);

        $routeCollection = $this->addEasycreditStepRoute($routeCollection);

        return $routeCollection;
    }

    /**
     * @param \Spryker\Yves\Router\Route\RouteCollection $routeCollection
     */
    public function addEasycreditStepRoute($routeCollection)
    {
        $route = $this->buildRoute('/checkout/easycredit', 'CheckoutPage', 'Checkout', 'easyCredit');
        $route = $route->setMethods(['GET', 'POST']);
        $routeCollection->add(static::CHECKOUT_EASY_CREDIT, $route);

        return $routeCollection;
    }
}

  1. Also, the Easycredit bundle has its own YvesController for handling a success response from Easycredit, so you have to define a controller in RouterDependencyProvider.

RouterDependencyProvider.php

<?php

namespace Pyz\Yves\Router;

...
use Pyz\Yves\CheckoutPage\Plugin\Router\CheckoutPageRouteProviderPlugin;
...

class RouterDependencyProvider extends SprykerRouterDependencyProvider
{

	...
	protected function getRouteProvider(): array
	{
		...
		new CheckoutPageRouteProviderPlugin(),
		...
	}
	...
}

Frontend Part

To show the Easycredit info on the Product Details page, at the Summary and Payment steps, you have to extend some views on the project level .

You can find some examples below in [payment.twig](#payment-step), summary.twig and pdp.twig.

payment.twig

Payment step - 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: {
        'Easycredit/easycredit': 1
    }
} %}
{% block content %}
    {% embed molecule('form') with {
        class: 'box',
        data: {
            form: data.forms.payment,
            options: {
                attr: {
                    id: 'payment-form'
                }
            },
            submit: {
                enable: true,
                text: 'checkout.step.summary' | trans
            },
            cancel: {
                enable: true,
                url: data.backUrl,
                text: 'general.back.button' | trans
            },
            customForms: data.customForms
        }
    } only %}
        {% block fieldset %}
            {% for name, choices in data.form.paymentSelection.vars.choices %}
                {% set paymentProviderIndex = loop.index0 %}
                <h5>{{ ('checkout.payment.provider.' ~ name) | trans }}</h5>
                <ul>
                    {% for key, choice in choices %}
                        <li class="list__item spacing-y clear">
                            {% embed molecule('form') with {
                                data: {
                                    form: data.form[data.form.paymentSelection[key].vars.value],
                                    enableStart: false,
                                    enableEnd: false,
                                    customForms: data.customForms
                                },
                                embed: {
                                    index: loop.index ~ '-' ~ paymentProviderIndex,
                                    toggler: data.form.paymentSelection[key]
                                }
                            } only %}
                                {% block fieldset %}
                                    {{ form_row(embed.toggler, {
                                        required: false,
                                        component: molecule('toggler-radio'),
                                        attributes: {
                                            'target-selector': '.js-payment-method-' ~ embed.index,
                                            'class-to-toggle': 'is-hidden'
                                        }
                                    }) }}
                                    <div class="col col--sm-12 is-hidden js-payment-method-{{embed.index}}">
                                        <div class="col col--sm-12 col--md-6">
                                            {% if data.customForms[data.form.vars.template_path] is not defined %}
                                                {{ parent() }}
                                            {% else %}
                                                {% include view('easycredit', 'Easycredit') with {
                                                    data: {
                                                        form: data.form,
                                                        legalText: data.form.vars.legalText
                                                    }
                                                } only  %}
                                            {% endif %}
                                        </div>
                                    </div>
                                {% endblock %}
                            {% endembed %}
                        </li>
                    {% endfor %}
                </ul>
            {% endfor %}
        {% endblock %}
    {% endembed %}
{% endblock %}
summary.twig

Summary step - src/Pyz/Yves/CheckoutPage/Theme/default/views/summary/summary.twig

{% extends template('page-layout-checkout', 'CheckoutPage') %}

 {% define data = {
	backUrl: _view.previousStepUrl,
	transfer: _view.quoteTransfer,
	cartItems: _view.cartItems,
	easycredit: _view.easycredit,
	shippingAddress: _view.quoteTransfer.shippingAddress,
	billingAddress: _view.quoteTransfer.billingAddress,
	shipmentMethod: _view.quoteTransfer.shipment.method.name,
	paymentMethod: _view.quoteTransfer.payment.paymentMethod,

	 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>
				<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 %}
			{% if data.easycredit %}
				{% include molecule('easycredit-summary', 'Easycredit') with {
					data: {
						interest: data.easycredit.interest,
						url: data.easycredit.url,
						text: data.easycredit.text
					}
				} only %}
			{% endif %}
		</div>
	</div>
{% endblock %}


pdp.twig

PDP page - src/Pyz/Yves/ProductDetailPage/Theme/default/views/pdp/pdp.twig

{% extends template('page-layout-main') %}

{% define data = {
	product: _view.product,
	productUrl: _view.productUrl,

	title: product.metaTitle | default(_view.product.name),
	metaTitle: product.metaTitle | default(_view.product.name),
	metaDescription: _view.product.metaDescription | default,
	metaKeywords: _view.product.metaKeywords | default
} %}

{% block headScripts %}
	{{ parent() }}
	<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js" type="text/javascript"></script>
{% endblock %}

{% block breadcrumbs %}
	{% widget 'ProductBreadcrumbsWithCategoriesWidget' args [data.product] only %}
	{% elsewidget 'ProductCategoryWidgetPlugin' args [data.product] only %} {# @deprecated Use ProductBreadcrumbsWithCategoriesWidget instead. #}
	{% endwidget %}
{% endblock %}

{% block title %}
	<h3 itemprop="name">{{ data.product.name }}</h3>
	<link itemprop="url" href="{{ data.productUrl }}" />
{% endblock %}

{% block content %}
	<div class="grid">
		<div class="col col--sm-12 col--lg-7 col--xl-8">
			{% include molecule('product-carousel', 'ProductDetailPage') with {
				class: 'box',
				data: {
					product: data.product
				}
			} only %}
	</div>

	<div class="col col--sm-12 col--lg-5 col--xl-4">
		{% include molecule('product-configurator', 'ProductDetailPage') with {
			class: 'box',
			data: {
				product: data.product
			}
		} only %}
	</div>
</div>

{% widget 'ProductAlternativeListWidget' args [data.product] only %}
{% elsewidget 'ProductAlternativeWidgetPlugin' args [data.product] only %} {# @deprecated Use ProductAlternativeListWidget instead. #}
{% endwidget %}

{% include molecule('product-detail', 'ProductDetailPage') with {
	class: 'box',
	data: {
		description: data.product.description,
		attributes: data.product.attributes
	}
} only %}

{% widget 'ProductReplacementForListWidget' args [data.product.sku] only %}
{% elsewidget 'ProductReplacementForWidgetPlugin' args [data.product.sku] only %} {# @deprecated Use ProductReplacementForListWidget instead. #}
{% endwidget %}

{% widget 'ProductDetailPageReviewWidget' args [data.product.idProductAbstract] only %}
{% elsewidget 'ProductReviewWidgetPlugin' args [data.product.idProductAbstract] only %} {# @deprecated Use ProductDetailPageReviewWidget instead. #}
{% endwidget %}

{% widget 'SimilarProductsWidget' args [data.product] only %}
{% elsewidget 'SimilarProductsWidgetPlugin' args [data.product] only %} {# @deprecated Use SimilarProductsWidget instead. #}
{% endwidget %}

{% if widgetExists('ProductCmsBlockWidgetPlugin') %}
	{{ widget('ProductCmsBlockWidgetPlugin', data.product) }} {# @deprecated Use molecule('product-cms-block', 'CmsBlockWidget') instead. #}
{% else %}
	{% include molecule('product-cms-block', 'CmsBlockWidget') ignore missing with {
		class: 'box',
		data: {
			idProductAbstract: data.product.idProductAbstract
		}
	} only %}
{% endif %}

{% endblock %}
Note
You might want to configure the product detail page to add some validation and show the Easycredit badge in src/Pyz/Yves/ProductDetailPage/Theme/default/components/molecules/product-configurator/product-configurator.twig

product-configurator.twig

...
    {% set easyCreditMinTreshold = 20000 %}
    {% set easyCreditMaxTreshold = 500000 %}
    {% if data.product.price > easyCreditMinTreshold and data.product.price < easyCreditMaxTreshold %}
        {% include molecule('easycredit-badge', 'EasyCredit' ) with {
            data: {
                title: 'EasyCredit:',
                id: 'easy-credit-id'
            },
            attributes: {
                'easycredit-options': '{
                    "webshopId": "<Your shop identifier>",
                    "finanzierungsbetrag": "' ~ data.product.price / 100 ~ '" ,
                    "textVariante": "KURZ"
                }'
            }
        } only %}
    {% endif %}
...
Was this article helpful?