KEMBAR78
Pimcore E | PDF | Class (Computer Programming) | Point Of Sale
0% found this document useful (0 votes)
120 views448 pages

Pimcore E

The Pimcore E-Commerce Framework is designed to address the complexities of modern e-commerce projects, offering a developer-friendly toolkit for creating customized solutions. It features a component-based architecture that separates backend functionality from frontend presentation, facilitating agile development and integration with various systems. Key functionalities include product management, pricing systems, checkout processes, and order management, all configurable to meet specific business needs.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
120 views448 pages

Pimcore E

The Pimcore E-Commerce Framework is designed to address the complexities of modern e-commerce projects, offering a developer-friendly toolkit for creating customized solutions. It features a component-based architecture that separates backend functionality from frontend presentation, facilitating agile development and integration with various systems. Key functionalities include product management, pricing systems, checkout processes, and order management, all configurable to meet specific business needs.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 448

Pimcore E-Commerce Framework Overview

User

E-Commerce Framework

Why Pimcore E-Commerce Framework

The e-commerce environment has fundamentally changed and e-commerce


projects often face new challenges like:

complex product structures: lots of data attributes, complex product


relations, configurable product systems, different sources for products

complex pricing structures: product dependent price sources, tier pricing,


pricing matrices, individual pricing rules, integration of remote pricing
services

complex availability calculations

thousands customer groups with: customer group specific prices, customer


group specific assortments

individual checkouts: individual integration of backend systems,


integration of multi-channel processes into checkout workflow

individual design

highly agile projects with changing requirements: 'fail fast', fast


changing environments and requirements

etc.

We think for these challenges a default shop system that pops out of a box,
that has a fixed product data model, fixed workflows, a template based
frontend and needs to be connected and integrated with other systems via
interfaces is not the tool to go for.

We think for these challenges you need...

a framework for developers to build outstanding e-commerce solutions for


customers,

with a native integration into Pimcore,

with a component based architecture


and a strict separation between backend functionality and frontend
presentation.

That is the idea behind the E-Commerce Framework of Pimcore. Like Pimcore
itself, it is not a ready made system, it is a set of tools and
functionality to help building e-commerce applications really fast and
flexible.

Provided Functionality in a Nutshell

Tools for indexing, listing, searching and filtering products

Implementations of carts, wish lists, comparison lists, etc.

Concepts for flexible and complex pricing, taxes and availability


functionality

Functionality and tools for implementing checkout processes

Pricing Rules and Vouchers

Tools for working with and managing Orders

Concepts for setting up multi tenant and multi shop solutions

For a first impression have a look at our Demo. For more complex solutions
have a look at our case studies.

Working With E-Commerce Framework

Following aspects are short-cuts into the documentation for start working
with the E-Commerce Framework:

Architecture Overview

Installation and Configuration

Indexing and Listing Products

Filtering Products

Working with Prices

Working with Carts

Setting up Checkouts

Integrating Payment Functionality


Working with Orders

Tracking Manager

Events

ChatGPT

## Why Choose the Pimcore E-Commerce Framework?

The e-commerce landscape has evolved significantly, posing new challenges


for e-commerce projects such as:

### Complex Product Structures

- **Extensive Data Attributes:** Handling products with numerous


attributes.

- **Product Relations:** Managing complex inter-product relationships.

- **Configurable Products:** Creating systems for customizable products.

- **Diverse Sources:** Integrating products from various sources.

### Complex Pricing Structures

- **Multiple Price Sources:** Handling product-specific price data.

- **Tier Pricing:** Implementing pricing that varies with quantity.

- **Pricing Matrices:** Managing complex pricing scenarios.

- **Individual Pricing Rules:** Creating custom pricing rules.

- **Remote Services Integration:** Connecting to external pricing services.

### Availability Calculations

- **Sophisticated Availability Rules:** Implementing complex logic to


determine product availability.

### Customer Group Management


- **Customer-Specific Pricing:** Assigning prices based on customer groups.

- **Assortments:** Creating specific product assortments for different


customer groups.

### Custom Checkout Processes

- **Backend System Integration:** Customizing backend integrations for


checkouts.

- **Multi-Channel Workflows:** Integrating multi-channel processes into


checkout.

### Individual Design and Agility

- **Custom Designs:** Creating unique, custom front-end designs.

- **Agility:** Adapting to fast-changing requirements and failing fast for


rapid iteration.

### Flexible and Developer-Friendly

For these challenges, a traditional out-of-the-box shop system with fixed


product data models, workflows, and template-based frontends that require
extensive integration isn't ideal. Instead, you need:

- **A Developer Framework:** A toolkit for developers to build custom e-


commerce solutions.

- **Native Pimcore Integration:** Seamless integration with Pimcore.

- **Component-Based Architecture:** Flexible, modular components.

- **Backend-Frontend Separation:** Clear distinction between backend logic


and frontend presentation.

## Provided Functionality in a Nutshell

### Product Management

- **Indexing, Listing, Searching, Filtering:** Efficient tools for managing


and displaying products.
### Cart and Wishlist Management

- **Carts, Wishlists, Comparison Lists:** Ready-to-use implementations for


common e-commerce features.

### Pricing and Availability

- **Flexible Pricing and Taxes:** Tools for handling complex pricing and
tax scenarios.

- **Availability:** Functions for managing product availability.

### Checkout Processes

- **Custom Checkouts:** Tools for implementing tailored checkout processes.

- **Payment Integration:** Easily integrate various payment


functionalities.

### Order Management

- **Order Tools:** Comprehensive tools for managing orders.

- **Pricing Rules and Vouchers:** Implementing pricing rules and voucher


systems.

### Multi-Tenant and Multi-Shop Solutions

- **Multi-Shop Setup:** Concepts for creating and managing multiple shops


within a single Pimcore instance.

## Getting Started with the E-Commerce Framework

### Key Documentation Sections:

- **[Architecture
Overview](https://pimcore.com/docs/pimcore/current/Development_Documentatio
n/E-Commerce_Framework/Architecture_Overview.html)**
- **[Installation and
Configuration](https://pimcore.com/docs/pimcore/current/Development_Documen
tation/E-Commerce_Framework/Installation_and_Configuration.html)**

- **[Indexing and Listing


Products](https://pimcore.com/docs/pimcore/current/Development_Documentatio
n/E-Commerce_Framework/Indexing_and_Listing_Products.html)**

- **[Filtering
Products](https://pimcore.com/docs/pimcore/current/Development_Documentatio
n/E-Commerce_Framework/Filtering_Products.html)**

- **[Working with
Prices](https://pimcore.com/docs/pimcore/current/Development_Documentation/
E-Commerce_Framework/Working_with_Prices.html)**

- **[Working with
Carts](https://pimcore.com/docs/pimcore/current/Development_Documentation/
E-Commerce_Framework/Working_with_Carts.html)**

- **[Setting up
Checkouts](https://pimcore.com/docs/pimcore/current/Development_Documentati
on/E-Commerce_Framework/Setting_up_Checkouts.html)**

- **[Integrating Payment
Functionality](https://pimcore.com/docs/pimcore/current/Development_Documen
tation/E-Commerce_Framework/Integrating_Payment_Functionality.html)**

- **[Working with
Orders](https://pimcore.com/docs/pimcore/current/Development_Documentation/
E-Commerce_Framework/Working_with_Orders.html)**

- **[Tracking
Manager](https://pimcore.com/docs/pimcore/current/Development_Documentation
/E-Commerce_Framework/Tracking_Manager.html)**

-
**[Events](https://pimcore.com/docs/pimcore/current/Development_Documentati
on/E-Commerce_Framework/Events.html)**

For a practical demonstration, you can explore the [Pimcore


Demo](https://demo.pimcore.com/) and review complex case studies to
understand the framework's capabilities.

User

Architecture Overview

The following architecture overview shows available framework components.


The component configuration takes place in the pimcore_ecommerce_framework
configuration node and a factory is responsible for resolving of the
implementations. For each component a custom implementation can be
configured and used.
bigpicture

Separation of Concerns

We try to separate different functionality and encapsulate them as good as


possible in the different components. Following list should state the basic
ideas and represent a guideline for future extensions:

Index Service

The Index Service is responsible for all aspects concerning indexing


products and providing an API to access product data from the index.

These aspects contain among other things:

Defining which attributes should be indexed.

Implementations for different search backends (e.g. mysql, elasticsearch,


fact finder, findologic).

Product Lists as the API to access the product data stored in the search
index. Product Lists can be used by controllers to display product
listings.

Filter Service

The Filter Service is responsible for all aspects concerning filtering


products and setting up a filtered navigation. It is tightly coupled with
the Product Lists of the Index Service, provides the developer a simple API
for building a layered navigation and takes care of query generation,
counting results and stuff.

Availability System

The Availability System is responsible for all aspects concerning product


availability. Here the logic for calculating availabilities, calling
external availability services, etc. is encapsulated. Each product has an
Availability System assigned and when it comes to getting the availability
of a product, this should be delegated to the Availability System of the
product.
Price System and Taxes

Like Availability Systems, there are Price Systems which are responsible
for all aspects of getting product prices. Here the logic of calculating
the product prices should be encapsulated. Each product has a Price System
and when it comes to getting the price of a product, this should be
delegated to the Price System of the product.

Also Tax Management is located in this component.

Pricing Manager

In addition to the Price System, there is the Pricing Manager which is


responsible for all aspects concerning modification of prices for marketing
purposes. Therefore pricing rules (e.g. certain products, certain time
frames, ...) build conditions which need to be valid that certain pricing
actions (e.g. product price discount, free shipping, ...) are executed.

Voucher System

The Voucher System is responsible for all aspects concerning vouchers for
customers. These aspects contain among other things:

Voucher Services

Voucher Tokens

Voucher Statistics

Modification of product prices based on vouchers which is done with the


help of the Pricing Manager.

Cart Manager

The Cart Manager is responsible for all aspects concerning carts. These
aspects contain among other things:

Different cart implementations

CRUD-Operations on carts

Price calculations for carts

Price modifications for carts (like shipping costs, etc.)


Checkout Manager

The Checkout Manager is responsible for all aspects concerning checkout


process and an one-stop API for getting through the checkout process. The
Checkout Manager always works with a cart and at certain points in the
checkout process it delegates to other components to convert the cart to an
order object (Order Manager), start payment operations (Commit Order
Processor and Payment Manager) and commits the order (Commit Order
Processor).

Commit Order Processor

The Commit Order Processor is part of the Checkout Manager namespace and is
responsible for all aspects concerning committing and order.

These aspects contain among other things:

Handle payment response

commit order payment

commit order and send order to other backend systems (e.g. erp system)

In contrast to the Checkout Manager, the Commit Order Processor does not
work with carts anymore and can be initialized without a cart. Therefore it
also can be used to commit orders in combination with server side payment
notifications when no cart is available anymore.

Payment Manager

The Payment Manager is responsible for all aspects concerning payment. The
main aspect is the implementation of different Payment Providers to
integrate them into the framework.

Order Manager

The Order Manager is responsible for all aspects of working with orders
except committing them (which is the responsibility of the Commit Order
Processor). These aspects contain among other things:

Creating orders based on carts

Order Storage
Loading orders

Loading order lists and filter them (Order List)

Working with orders after order commit (Order Agent)

ChatGPT

## Pimcore E-Commerce Framework Architecture Overview

The Pimcore E-Commerce Framework is designed to provide a flexible and


robust set of tools for building custom e-commerce solutions. It leverages
a component-based architecture with a strict separation of concerns,
ensuring that different functionalities are well encapsulated within
distinct components. Here's a detailed look at the key components:

### Index Service

The **Index Service** handles all aspects of product indexing and provides
an API for accessing product data from the index.

- **Attribute Definition:** Determine which attributes are indexed.

- **Search Backend Implementations:** Supports various search backends like


MySQL, Elasticsearch, Fact Finder, Findologic.

- **Product Lists:** API for accessing indexed product data, used by


controllers to display product listings.

### Filter Service

The **Filter Service** manages product filtering and filtered navigation.

- **Layered Navigation:** Provides a simple API for building layered


navigation.

- **Query Generation and Result Counting:** Handles the generation of


queries and counting of filtered results.

- **Integration with Index Service:** Works closely with Product Lists for
displaying filtered products.
### Availability System

The **Availability System** deals with product availability calculations


and integration with external availability services.

- **Availability Logic:** Encapsulates the logic for determining product


availability.

- **External Services:** Integrates with external availability services.

- **Product Assignment:** Each product has an assigned Availability System


for availability checks.

### Price System and Taxes

The **Price System** manages product pricing and tax calculations.

- **Price Calculation:** Encapsulates logic for calculating product prices.

- **Product Assignment:** Each product has an assigned Price System.

- **Tax Management:** Manages tax calculations and assignments.

### Pricing Manager

The **Pricing Manager** handles modifications to product prices for


marketing purposes.

- **Pricing Rules:** Conditions under which certain pricing actions (e.g.,


discounts, free shipping) are executed.

- **Pricing Actions:** Actions that modify product prices based on the


rules.

### Voucher System

The **Voucher System** manages customer vouchers.

- **Voucher Services:** Core functionalities related to vouchers.


- **Voucher Tokens:** Handles the creation and validation of voucher
tokens.

- **Voucher Statistics:** Tracks voucher usage and effectiveness.

- **Price Modifications:** Works with the Pricing Manager to apply voucher-


based price changes.

### Cart Manager

The **Cart Manager** oversees all cart-related operations.

- **Cart Implementations:** Different types of cart implementations.

- **CRUD Operations:** Create, Read, Update, Delete operations on carts.

- **Price Calculations:** Computes prices for cart items.

- **Price Modifications:** Applies additional charges or discounts (e.g.,


shipping costs).

### Checkout Manager

The **Checkout Manager** handles the entire checkout process.

- **Cart to Order Conversion:** Converts cart to order object via the Order
Manager.

- **Payment Operations:** Initiates payment processes through the Payment


Manager.

- **Order Commitment:** Commits the order using the Commit Order Processor.

### Commit Order Processor

The **Commit Order Processor** finalizes the order process.

- **Payment Handling:** Manages payment responses and commits payments.

- **Order Commitment:** Sends the committed order to backend systems (e.g.,


ERP).
- **Independent Operation:** Can commit orders without a cart, useful for
server-side payment notifications.

### Payment Manager

The **Payment Manager** integrates various payment providers into the


framework.

- **Payment Providers:** Implements different payment methods.

- **Payment Processing:** Manages the entire payment transaction lifecycle.

### Order Manager

The **Order Manager** manages all post-commit order operations.

- **Order Creation:** Creates orders from carts.

- **Order Storage:** Handles storage and retrieval of orders.

- **Order Lists:** Loads and filters order lists.

- **Order Post-Processing:** Manages orders after they are committed (Order


Agent).

## Component Configuration

All components are configured within the `pimcore_ecommerce_framework`


configuration node. The framework uses a factory pattern to resolve the
implementations, allowing for custom implementations for each component.

## Conclusion

The Pimcore E-Commerce Framework's architecture provides a flexible,


modular approach to building e-commerce solutions. By separating concerns
and encapsulating functionalities within distinct components, it ensures
scalability, maintainability, and ease of customization.

User

Installation and First Configuration


This section describes the installation of the E-Commerce Framework and the
first steps of configuration.

Installation

Minimum Requirements

Pimcore >= 11.0

Install

Install bundle via composer:

composer require pimcore/ecommerce-framework-bundle

Enable bundle via console or extensions manager:

php bin/console pimcore:bundle:install PimcoreEcommerceFrameworkBundle

Check if the bundle has been installed:

php bin/console pimcore:bundle:list

+---------------------------------+---------+-----------+----+-----+-----+

| Bundle | Enabled | Installed | I? | UI? | UP? |

+---------------------------------+---------+-----------+----+-----+-----+

| PimcoreEcommerceFrameworkBundle | ✔ | ✔ | ❌ | ✔ | ❌ |

+---------------------------------+---------+-----------+----+-----+-----+

The installer does following tasks:

Install several field collections.


Install several object classes.

Install several object bricks.

Create additional tables for carts, pricing rules, vouchers, etc.

Import translations for Pimcore Admin UI and Order Backend.

Add additional permissions.

If either classes, field collections, object bricks or tables already


exist, the installation cannot be started.

After this installation routine, additional configurations have to be made


- most important Product and ProductCategory. Please see Configuration for
further information on available options.

Configure Product and Product Category Class

The E-Commerce Framework installation does not create classes for products
and product categories. That is because the framework does not limit you on
specific classes or class structures. Literally every class can act as a
product or product category class and it is also possible to have several
product classes (if necessary).

The only requirement is, that the classes have to be 'prepared' for being
products or product categories.

Product

There are two ways of preparing a Pimcore class for product-usage in the E-
Commerce Framework

The Pimcore class needs to extend the abstract class \Pimcore\Bundle\


EcommerceFrameworkBundle\Model\AbstractProduct

This is useful, when both product index and checkout functionality are
based on the E-Commerce Framework.

Make sure that the Pimcore class implements either \Pimcore\Bundle\


EcommerceFrameworkBundle\Model\IndexableInterface or \Pimcore\Bundle\
EcommerceFrameworkBundle\Model\CheckoutableInterface - or both, depending
on the use case it is used for.
This is useful, when e.g. only checkout functionality is based on the E-
Commerce Framework, but not the product presentation.

The interfaces define methods that are needed for the two use cases and
need to be implemented.

For the abstract class use the parent class functionality of Pimcore. For
implementing the interfaces use either the parent class functionality or
the overriding models functionality of Pimcore (see also Overriding
Models).

If using the abstract class, also have a look at its implementation. You
might need to override a few methods that cannot be implemented by the
abstract class and throw an exception depending on the use case you are
using it.

Product Category

When a product category class is used, this class needs to extend the
abstract class \Pimcore\Bundle\EcommerceFrameworkBundle\Model\
AbstractCategory.

For product categories only one Pimcore class should be used. For products,
several Pimcore classes can be used. Possibly the index update scripts need
to be adapted.

Configuring Pimcore Ecommerce Framework

The E-Commerce Framework is split up into multiple components which can be


configured individually. For further reading please see:

Configuration describes configuration features valid for the whole


framework configuration

PimcoreEcommerceFrameworkBundle Configuration Reference contains a


reference of the whole configuration tree

Please see the following sections for a description of each component and
and a configuration reference describing the configuration entries relevant
to the component:

Cart Manager
Price Systems

Availability Systems

Checkout Manager and Checkout Steps

Payment Providers

Index Service and which attributes should be in the Product Index

Pricing Manager

...

For detailed information see comments within the configuration file.


Depending on your use case, you might not need all components configured in
the configuration file.

During development you will return to the configuration and adjust the
settings multiple times.

ChatGPT

## Installation and First Configuration of Pimcore E-Commerce Framework

### Minimum Requirements

- **Pimcore Version:** Pimcore >= 11.0

### Installation Steps

1. **Install the Bundle via Composer:**

```bash

composer require pimcore/ecommerce-framework-bundle

```

2. **Enable the Bundle:**

You can enable the bundle using the console or the extensions manager.
```bash

php bin/console pimcore:bundle:install PimcoreEcommerceFrameworkBundle

```

3. **Verify Installation:**

Check if the bundle has been successfully installed.

```bash

php bin/console pimcore:bundle:list

```

You should see:

```plaintext

+---------------------------------+---------+-----------+----+-----
+-----+

| Bundle | Enabled | Installed | I? | UI? | UP?


|

+---------------------------------+---------+-----------+----+-----
+-----+

| PimcoreEcommerceFrameworkBundle | ✔ | ✔ | ❌ | ✔ | ❌
|

+---------------------------------+---------+-----------+----+-----
+-----+

```

### Installation Tasks

The installer performs the following tasks:

- Installs several field collections.

- Installs several object classes.

- Installs several object bricks.

- Creates additional tables for carts, pricing rules, vouchers, etc.


- Imports translations for Pimcore Admin UI and Order Backend.

- Adds additional permissions.

> **Note:** If classes, field collections, object bricks, or tables already


exist, the installation cannot be started.

### Post-Installation Configuration

#### Configuring Product and Product Category Classes

The E-Commerce Framework does not create product and product category
classes. You must configure these manually.

1. **Product Configuration:**

There are two ways to prepare a Pimcore class for product usage in the
E-Commerce Framework:

- **Extend Abstract Class:**

The class should extend `\Pimcore\Bundle\EcommerceFrameworkBundle\


Model\AbstractProduct`. This is useful when both product index and checkout
functionality rely on the E-Commerce Framework.

```php

use Pimcore\Bundle\EcommerceFrameworkBundle\Model\AbstractProduct;

class MyProduct extends AbstractProduct {

// Implement necessary methods

```
- **Implement Interfaces:**

The class should implement `\Pimcore\Bundle\EcommerceFrameworkBundle\


Model\IndexableInterface` or `\Pimcore\Bundle\EcommerceFrameworkBundle\
Model\CheckoutableInterface` (or both) based on the required functionality.

```php

use Pimcore\Bundle\EcommerceFrameworkBundle\Model\IndexableInterface;

use Pimcore\Bundle\EcommerceFrameworkBundle\Model\
CheckoutableInterface;

class MyProduct implements IndexableInterface, CheckoutableInterface {

// Implement necessary methods

```

2. **Product Category Configuration:**

Product category classes should extend `\Pimcore\Bundle\


EcommerceFrameworkBundle\Model\AbstractCategory`.

```php

use Pimcore\Bundle\EcommerceFrameworkBundle\Model\AbstractCategory;

class MyProductCategory extends AbstractCategory {

// Implement necessary methods

```

> **Note:** For product categories, only one Pimcore class should be used.
For products, multiple classes can be utilized, which might require
adapting index update scripts.
### Configuring the Pimcore E-Commerce Framework

The E-Commerce Framework is divided into multiple components that can be


configured individually. Key configuration areas include:

- **Cart Manager**

- **Price Systems**

- **Availability Systems**

- **Checkout Manager and Checkout Steps**

- **Payment Providers**

- **Index Service (Product Attributes)**

- **Pricing Manager**

### Configuration Reference

#### General Configuration

For a comprehensive guide to configuring the framework, refer to the


configuration file comments and the following resources:

-
**[Configuration](https://pimcore.com/docs/pimcore/current/Development_Docu
mentation/E-Commerce_Framework/Configuration.html)**: General framework
configuration features.

- **[PimcoreEcommerceFrameworkBundle Configuration
Reference](https://pimcore.com/docs/pimcore/current/Development_Documentati
on/E-Commerce_Framework/
PimcoreEcommerceFrameworkBundle_Configuration_Reference.html)**: Detailed
configuration tree reference.

#### Component Configuration


Each component has specific configuration entries. Refer to the relevant
sections for detailed configuration instructions:

- **[Cart
Manager](https://pimcore.com/docs/pimcore/current/Development_Documentation
/E-Commerce_Framework/Cart_Manager.html)**

- **[Price
Systems](https://pimcore.com/docs/pimcore/current/Development_Documentation
/E-Commerce_Framework/Price_Systems.html)**

- **[Availability
Systems](https://pimcore.com/docs/pimcore/current/Development_Documentation
/E-Commerce_Framework/Availability_Systems.html)**

- **[Checkout Manager and Checkout


Steps](https://pimcore.com/docs/pimcore/current/Development_Documentation/
E-Commerce_Framework/Checkout_Manager_and_Checkout_Steps.html)**

- **[Payment
Providers](https://pimcore.com/docs/pimcore/current/Development_Documentati
on/E-Commerce_Framework/Payment_Providers.html)**

- **[Index
Service](https://pimcore.com/docs/pimcore/current/Development_Documentation
/E-Commerce_Framework/Index_Service.html)**

- **[Pricing
Manager](https://pimcore.com/docs/pimcore/current/Development_Documentation
/E-Commerce_Framework/Pricing_Manager.html)**

> **Tip:** During development, you will frequently revisit and adjust the
configuration settings to fine-tune your e-commerce solution.

By following these steps and guidelines, you can successfully install and
configure the Pimcore E-Commerce Framework to create a robust, flexible,
and scalable e-commerce solution.

User

Configuration

The E-Commerce Framework is implemented as semantic bundle configuration


which means that you can configure the framework in any of the loaded
config files (e.g. /config/config.yaml or
*Bundle/Resources/config/pimcore/config.yaml) by adding configuration to
the pimcore_ecommerce_framework node.

The configuration is built upon the Symfony Config Component and defines a
well-known configuration tree which is validated against a defined
configuration structure. While configuring the framework you'll get instant
feedback on configuration errors. As Pimcore defines a standard
configuration for the E-Commerce Framework, your custom configuration will
be merged into the standard configuration. You can dump the final (merged,
validated and normalized) configuration at any time with the following
command:

$ bin/console debug:config pimcore_ecommerce_framework

A reference of available configuration entries can be found on


PimcoreEcommerceFrameworkBundle Configuration Reference.

As the E-Commerce Framework makes heavy use of Symfony service definitions


and you'll need to reference IDs of custom services in the configuration
it's advised that you are comfortable to work with Symfony's Service
Container.

Tenant support and _defaults sections

As certain components of the E-Commerce Framework support different


tenants, Pimcore adds a way to specify settings which are common to all
tenants in a special tenant named _defaults. If such a tenant exists, its
values will be merged into all other tenants and the _defaults tenant will
be removed afterwards. The logic described below applies to all components
supporting tenants.

As example, a simple cart_manager configuration section which defines a


default and a noShipping tenant:

pimcore_ecommerce_framework:

cart_manager:

tenants:

# _defaults will be automatically merged into every tenant and


removed afterwards

# the result will be a default and a noShipping

_defaults:

cart:
factory_id: CartFactoryId

price_calculator:

factory_id: PriceCalculatorFactoryId

factory_options:

foo: bar

default:

price_calculator:

factory_options:

baz: 1234

noShipping:

price_calculator:

factory_options:

baz: 4321

In addition to the _defaults tenant, you can define additional tenants


starting with _defaults to make use of YAML inheritance.

pimcore_ecommerce_framework:

cart_manager:

tenants:

_defaults_foo:

price_calculator:

factory_options: &defaults_foo_options # define an


anchor

class: MyCommonCalculatorClass
default:

price_calculator:

factory_options:

<<: *defaults_foo_options # import anchor

anotherOne:

price_calculator:

factory_options:

<<: *defaults_foo_options # import anchor

Of course you can still use the PHP config file format by importing a PHP
config file from your config.yaml to be completely free how to merge common
configuration entries.

Service IDs and tenant specifics

When configuring tenant specific services, there are multiple configuration


entries demanding a service ID as configuration value. This means, the
system expects the configured value to be available as service definition
on the container. You can read through the service definitions defined in
PimcoreEcommerceFrameworkBundle to get an insight of default e-commerce
services.

As an example let's take a look at a price system configuration:

# when loading the "default" price system, use a service named "App\
Ecommerce\PriceSystem\CustomPriceSystem"

pimcore_ecommerce_framework:

price_systems:

default:

# price system defined and configured as container service


id: App\Ecommerce\PriceSystem\CustomPriceSystem

The configuration above expects something like this configured as service:

services:

App\Ecommerce\PriceSystem\CustomPriceSystem:

arguments:

- 'foo'

The "default" price system is just an alias to your existing service and
when loading that price system, your service will be directly loaded.
Getting the "default" price system from the ecommerce framework factory
will result in the same instance as getting App\Ecommerce\PriceSystem\
CustomPriceSystem directly from the container.

Service IDs in tenant context

Now let's take a look at another example handling tenants:

pimcore_ecommerce_framework:

order_manager:

tenants:

default:

order_manager_id: Pimcore\Bundle\EcommerceFrameworkBundle\
OrderManager\OrderManager

options:

# parent_order_folder: /orders/default/%%Y/%%m/%%d #
deprecated and discouraged

order_parent_path: /orders/default/*Y*/*M*/*D*

b2b:
order_manager_id: Pimcore\Bundle\EcommerceFrameworkBundle\
OrderManager\OrderManager

options:

# parent_order_folder: /orders/b2b/%%Y/%%m/%%d #
deprecated and discouraged

order_parent_path: /orders/b2b/*Y*/*M*/*D*

As you can see we define 2 tenants default and b2b with the same order
manager ID but with different options for each tenant. In this case it's
not possible to just alias the default or the b2b order manager to the
given service ID as we need multiple order manager instances based on this
service definition. In this case the framework takes the configured service
ID as template to configure 2 independent child services by utilizing the
configured service id as parent service.

This means, that when you request the Pimcore\Bundle\


EcommerceFrameworkBundle\OrderManager\OrderManager service from the
container, it would be neither the default nor the b2b tenant. In fact,
getting that service directly wouldn't work anyways as it is missing
dependencies. If you take a look at the service definition you can see that
the definition is missing the OrderAgentFactoryInterface argument which
will be resolved and set for each tenant specific order manager.

In short, when configuring multiple tenant specific service to the same


service id the framework will:

create a new child definition from the configured service

set tenant specific arguments (as the options above) to the tenant specific
child service

register the child service under a another ID which can be resolved by the
factory

To keep your services clean and give the service container more
optimization (and performance) possibilities you should define your parent
services as private (see order manager definition in the linked config
above) as this will result in the parent definition being removed from the
compiled container.
This child definition pattern applies to nearly all service IDs configured
inside tenants with the exception of reusable services (e.g. getters and
interpreters in the product index configuration) which do not have an
internal state and therefore can be reused throughout multiple tenants.

ChatGPT

## Configuration of the Pimcore E-Commerce Framework

The E-Commerce Framework is configured as a semantic bundle, allowing you


to customize it within any loaded config files (e.g., `/config/config.yaml`
or `*Bundle/Resources/config/pimcore/config.yaml`) by adding settings to
the `pimcore_ecommerce_framework` node. It utilizes the Symfony Config
Component, which provides a structured configuration tree validated against
a predefined schema. This ensures that configuration errors are identified
instantly.

### Key Configuration Steps

1. **Dump the Final Configuration:**

You can view the merged, validated, and normalized configuration at any
time using the following command:

```bash

bin/console debug:config pimcore_ecommerce_framework

```

2. **Reference Documentation:**

Refer to the [PimcoreEcommerceFrameworkBundle Configuration Reference]


(https://pimcore.com/docs/pimcore/current/Development_Documentation/E-
Commerce_Framework/
PimcoreEcommerceFrameworkBundle_Configuration_Reference.html) for a
comprehensive list of available configuration entries.

### Tenant Support and _defaults Sections

Certain components support different tenants. Pimcore allows you to specify


settings common to all tenants using a special tenant named `_defaults`.
These settings are automatically merged into all other tenants.
#### Example Configuration:

```yaml

pimcore_ecommerce_framework:

cart_manager:

tenants:

_defaults:

cart:

factory_id: CartFactoryId

price_calculator:

factory_id: PriceCalculatorFactoryId

factory_options:

foo: bar

default:

price_calculator:

factory_options:

baz: 1234

noShipping:

price_calculator:

factory_options:

baz: 4321

```

You can also define additional tenants starting with `_defaults` to utilize
YAML inheritance.
#### Inheritance Example:

```yaml

pimcore_ecommerce_framework:

cart_manager:

tenants:

_defaults_foo:

price_calculator:

factory_options: &defaults_foo_options

class: MyCommonCalculatorClass

default:

price_calculator:

factory_options:

<<: *defaults_foo_options

anotherOne:

price_calculator:

factory_options:

<<: *defaults_foo_options

```

### Service IDs and Tenant-Specific Services

When configuring tenant-specific services, multiple entries might require a


service ID as the configuration value. This means the system expects the
configured value to be available as a service definition in the container.
#### Example: Price System Configuration

```yaml

pimcore_ecommerce_framework:

price_systems:

default:

id: App\Ecommerce\PriceSystem\CustomPriceSystem

```

Service definition:

```yaml

services:

App\Ecommerce\PriceSystem\CustomPriceSystem:

arguments:

- 'foo'

```

### Tenant-Specific Service Configuration

In cases where multiple tenant-specific services are needed, you can define
these in a way that each tenant has its own instance derived from a common
service template.

#### Example: Order Manager Configuration

```yaml

pimcore_ecommerce_framework:

order_manager:

tenants:

default:
order_manager_id: Pimcore\Bundle\EcommerceFrameworkBundle\
OrderManager\OrderManager

options:

order_parent_path: /orders/default/*Y*/*M*/*D*

b2b:

order_manager_id: Pimcore\Bundle\EcommerceFrameworkBundle\
OrderManager\OrderManager

options:

order_parent_path: /orders/b2b/*Y*/*M*/*D*

```

In this configuration:

- The `order_manager_id` is used as a template to create two independent


child services with tenant-specific options.

- The framework handles the creation of child definitions and assigns


tenant-specific arguments to these child services, which are then
registered under different IDs for factory resolution.

> **Note:** When configuring multiple tenant-specific services to the same


service ID, the framework will:

1. Create a new child definition from the configured service.

2. Set tenant-specific arguments to the child service.

3. Register the child service under another ID for resolution by the


factory.

### Best Practices

- **Parent Services:** Define parent services as private to optimize the


service container and improve performance. The parent definition is removed
from the compiled container, leaving only the tenant-specific child
services.
By adhering to these configuration guidelines and leveraging the flexible
architecture of the Pimcore E-Commerce Framework, you can build a robust
and scalable e-commerce solution tailored to your specific needs.

User

PimcoreEcommerceFrameworkBundle Configuration Reference

The following is the generated reference for the


pimcore_ecommerce_framework configuration tree. This reference can be
generated by issuing the following command:

$ bin/console config:dump-reference pimcore_ecommerce_framework

IMPORTANT This is just a reference for the configuration tree, you need to
adjust it to replace the required configurations by setting up the
respective module.

# Default configuration for extension with alias:


"pimcore_ecommerce_framework"

pimcore_ecommerce_framework:

# Default scale used for Decimal objects

decimal_scale: 4

# Configuration of Pimcore backend menu entries

pimcore:

menu:

# Enabling/Disabling Pricing Rules menu entry. User specific


settings can be done via permissions.

pricing_rules:

enabled: true
# Configuring order list menu - enabling/disabling and defining
route of order list to inject custom implementations of order backend.

order_list:

enabled: true

route: pimcore_ecommerce_backend_admin-
order_list

path: null

# Configuration of e-commerce framework factory

factory:

# Service Id of factory implementation

factory_id: Pimcore\Bundle\EcommerceFrameworkBundle\
Factory

# If true the factory will not fall back to the default tenant if a
tenant is passed but not existing

strict_tenants: false

# Configuration of environment

environment:

environment_id: Pimcore\Bundle\EcommerceFrameworkBundle\
SessionEnvironment

options: []

# Settings for cart manager

cart_manager:

# Configuration per tenant. If a _defaults key is set, it will be


merged into every tenant. It needs to be set in every file. A tenant named
"default" is mandatory.
tenants:

# Examples:

_defaults:

cart:

factory_id: CartFactory

default:

cart:

factory_options:

cart_class_name: Pimcore\Bundle\
EcommerceFrameworkBundle\CartManager\Cart

price_calculator:

modificators:

shipping:

class: Pimcore\Bundle\
EcommerceFrameworkBundle\CartManager\CartPriceModificator\Shipping

options:

charge: 5.90

noShipping:

price_calculator:

factory_id: PriceCalculatorFactory

modificators: []

# Prototype

name:

# Service id of cart service


cart_manager_id: Pimcore\Bundle\
EcommerceFrameworkBundle\CartManager\MultiCartManager

# Configuration for carts

cart:

# Service id of cart factory and configuration array

factory_id: Pimcore\Bundle\
EcommerceFrameworkBundle\CartManager\CartFactory

factory_options:

# Defaults:

cart_class_name: Pimcore\Bundle\
EcommerceFrameworkBundle\CartManager\Cart

guest_cart_class_name: Pimcore\Bundle\
EcommerceFrameworkBundle\CartManager\SessionCart

price_calculator:

factory_id: Pimcore\Bundle\
EcommerceFrameworkBundle\CartManager\CartPriceCalculatorFactory

factory_options:

# 'class' defines the class name of the price


calculator, which the factory instantiates.

# If you wish to replace or extend the price


calculation routine shipped with the e-commerce

# framework provide your custom class name here.

class: Pimcore\Bundle\EcommerceFrameworkBundle\
CartManager\CartPriceCalculator

# List price modificators for cart, e.g. for shipping-


cost, special discounts, etc. Key is name of modificator.

modificators:
# Prototype

name:

class: ~ # Required

options: []

# Configuration of Order Manager

order_manager:

# Configuration per tenant. If a _defaults key is set, it will be


merged into every tenant. A tenant named "default" is mandatory.

tenants:

# Prototype

name:

# Service id for order manager implementation

order_manager_id: Pimcore\Bundle\
EcommerceFrameworkBundle\OrderManager\V7\OrderManager

# Options for order manager

options:

# Pimcore object class for orders

order_class: \Pimcore\Model\DataObject\
OnlineShopOrder

# Pimcore object class for order items

order_item_class: \Pimcore\Model\DataObject\
OnlineShopOrderItem
# Class for order listing

list_class: Pimcore\Bundle\
EcommerceFrameworkBundle\OrderManager\Order\Listing

# Class for order item listing

list_item_class: Pimcore\Bundle\
EcommerceFrameworkBundle\OrderManager\Order\Listing\Item

# Default parent folder for new orders

# parent_order_folder: /order/%%Y/%%m/%%d # deprecated


and discouraged

order_parent_path: /order/*Y*/*M*/*D*

order_agent:

# Service id for order agent factory

factory_id: Pimcore\Bundle\
EcommerceFrameworkBundle\OrderManager\Order\AgentFactory

factory_options: []

# Configuration of Pricing Manager

pricing_manager:

# Condition mapping from name to used class

conditions:

# Prototype

name: ~

# Action mapping from name to used class


actions:

# Prototype

name: ~

# Configuration per tenant. If a _defaults key is set, it will be


merged into every tenant. A tenant named "default" is mandatory.

tenants:

default: ~

# Prototype

name:

enabled: true

# Service id of pricing manager

pricing_manager_id: Pimcore\Bundle\
EcommerceFrameworkBundle\PricingManager\PricingManager

# Options for pricing manager

pricing_manager_options:

rule_class: Pimcore\Bundle\
EcommerceFrameworkBundle\PricingManager\Rule

price_info_class: Pimcore\Bundle\
EcommerceFrameworkBundle\PricingManager\PriceInfo

environment_class: Pimcore\Bundle\
EcommerceFrameworkBundle\PricingManager\Environment

# Configuration of price systems - key is name of price system.

price_systems:
# Prototype

name:

id: ~ # Required

# Configuration of availability systems - key is name of price system.

availability_systems:

# Prototype

name:

id: ~ # Required

# Configuration of checkout manager

checkout_manager:

# Configuration per tenant. If a _defaults key is set, it will be


merged into every tenant. A tenant named "default" is mandatory.

tenants:

# Prototype

name:

factory_id: Pimcore\Bundle\
EcommerceFrameworkBundle\CheckoutManager\CheckoutManagerFactory

factory_options: []

# Define payment provider which should be used for payment.


Payment providers are defined in payment_manager section.

payment:
provider: null

# Define used commit order processor

commit_order_processor:

id: Pimcore\Bundle\
EcommerceFrameworkBundle\CheckoutManager\V7\CommitOrderProcessor

options: []

# Define different checkout steps which need to be


committed before commit of order is possible

steps:

# Prototype

name:

class: ~ # Required

options: []

# Configuration of payment manager and payment providers

payment_manager:

payment_manager_id: Pimcore\Bundle\EcommerceFrameworkBundle\
PaymentManager\PaymentManager

# Configuration of payment providers, key is name of provider.

providers:

# Prototype

name:

name: ~
# Service id of payment provider implementation

provider_id: ~ # Required

# Currently active profile

profile: ~ # Required

# Available profiles with options

profiles:

# Prototype

name:

# Prototype

name: ~

# Configuration of index service

index_service:

index_service_id: Pimcore\Bundle\EcommerceFrameworkBundle\
IndexService\IndexService

default_tenant: default

# Configure assortment tenants - at least one tenant has to be


configured. If a _defaults key is set, it will be merged into every tenant.

tenants:

# Prototype

name:
enabled: true

# Service id of config implementation

config_id: Pimcore\Bundle\
EcommerceFrameworkBundle\IndexService\Config\DefaultMysql

config_options: []

# Worker id of worker implementation. Can be omitted, then


default worker id of configured config is used.

worker_id: ~

# Placeholder values in this tenant attributes definition


(locale: "%%locale%%") will be replaced by the given placeholder value (eg.
"de_AT")

placeholders:

'%%locale%%': 'de_AT'

# Add columns for general fulltext search index of product


list - they must be part of the column configuration below

search_attributes: []

# Attributes definition for product index - key is name of


attribute

attributes:

# Prototype

name:

name: ~ # Required

# Defines object attribute field name, can be


omitted if the same like name of index attribute
field_name: null

# Type of index attribute (database column or


elasticsearch data type)

type: null

# Locale for localized fields, can be omitted if


not necessary

locale: null

# Defines filter group for filter definition in


filter service

filter_group: null

options: []

# Service id of getter for this field

getter_id: null

getter_options: []

# Service id of interpreter for this field

interpreter_id: null

interpreter_options: []

# Hides field in field list selection data type of


filter service - default to false

hide_in_fieldlist_datatype: false

# Configuration of filter service

filter_service:
# Configuration per tenant. If a _defaults key is set, it will be
merged into every tenant.

tenants:

# Prototype

name:

enabled: true

service_id: Pimcore\Bundle\
EcommerceFrameworkBundle\FilterService\FilterService

# Assign backend implementations and views to filter type


field collections

filter_types:

# Prototype

name:

# Service id for filter type implementation

filter_type_id: ~ # Required

# Default template for filter, can be overwritten


in filter definition

template: ~ # Required

options: []

# Configuration of voucher service

voucher_service:
# Service id of voucher service implementation

voucher_service_id: Pimcore\Bundle\EcommerceFrameworkBundle\
VoucherService\DefaultService

voucher_service_options:

# Reservations older than x MINUTES get removed by maintenance


task

reservation_minutes_threshold: 5

# Statistics older than x DAYS get removed by maintenance task

statistics_days_threshold: 30

# Configuration of token managers

token_managers:

# Service id of token manager factory

factory_id: Pimcore\Bundle\EcommerceFrameworkBundle\
VoucherService\TokenManager\TokenManagerFactory

# Mapping for token manager implementations

mapping:

# Prototype

name: ~

# Configuration of offer tool

offer_tool:
# Service id for offer tool service

service_id: Pimcore\Bundle\EcommerceFrameworkBundle\
OfferTool\DefaultService

order_storage:

# Pimcore object class for offers

offer_class: Pimcore\Model\DataObject\OfferToolOffer

# Pimcore object class for offer items

offer_item_class: Pimcore\Model\DataObject\
OfferToolOfferItem

# default path for new offers

offer_parent_path: /offertool/offers/*Y*/*M*

#parent_folder_path: /offertool/offers/%%Y/%%m # deprecated


and discouraged, use offer_parent_path instead

# Configuration of Tracking Manager

tracking_manager:

# Service id of tracking manager

tracking_manager_id: Pimcore\Bundle\EcommerceFrameworkBundle\
Tracking\TrackingManager

# Enable/Disable trackers and configure them

trackers:

# Prototype

enhanced_ecommerce:
# Service id for tracker

id: Pimcore\Bundle\EcommerceFrameworkBundle\Tracking\
Tracker\Analytics\EnhancedEcommerce

enabled: false

# Service id for item builder for tracker

item_builder_id: Pimcore\Bundle\
EcommerceFrameworkBundle\Tracking\TrackingItemBuilder

# List of assortment and checkout tenants where this


tracker should be activated for.

tenants:

# Add list of assortment tenants where the tracker


should be activated for. Empty array means activated for all tenants.

assortment: []

# Add list of checkout tenants where the tracker should


be activated for. Empty array means activated for all tenants.

checkout: []

ChatGPT

The Pimcore E-Commerce Framework's configuration tree is extensive and


allows for a high degree of customization to meet various business needs.
Below is a detailed reference for configuring the different components of
the `pimcore_ecommerce_framework`.

### Configuration Tree

```yaml
pimcore_ecommerce_framework:

# Default scale used for Decimal objects

decimal_scale: 4

# Configuration of Pimcore backend menu entries

pimcore:

menu:

pricing_rules:

enabled: true

order_list:

enabled: true

route: pimcore_ecommerce_backend_admin-order_list

path: null

# Configuration of e-commerce framework factory

factory:

factory_id: Pimcore\Bundle\EcommerceFrameworkBundle\Factory

strict_tenants: false

# Configuration of environment

environment:

environment_id: Pimcore\Bundle\EcommerceFrameworkBundle\
SessionEnvironment

options: []

# Settings for cart manager

cart_manager:
tenants:

_defaults:

cart:

factory_id: CartFactory

default:

cart:

factory_options:

cart_class_name: Pimcore\Bundle\
EcommerceFrameworkBundle\CartManager\Cart

price_calculator:

modificators:

shipping:

class: Pimcore\Bundle\EcommerceFrameworkBundle\
CartManager\CartPriceModificator\Shipping

options:

charge: 5.90

noShipping:

price_calculator:

factory_id: PriceCalculatorFactory

modificators: []

# Prototype

name:

cart_manager_id: Pimcore\Bundle\EcommerceFrameworkBundle\
CartManager\MultiCartManager

cart:

factory_id: Pimcore\Bundle\EcommerceFrameworkBundle\
CartManager\CartFactory

factory_options:
cart_class_name: Pimcore\Bundle\
EcommerceFrameworkBundle\CartManager\Cart

guest_cart_class_name: Pimcore\Bundle\
EcommerceFrameworkBundle\CartManager\SessionCart

price_calculator:

factory_id: Pimcore\Bundle\EcommerceFrameworkBundle\
CartManager\CartPriceCalculatorFactory

factory_options:

class: Pimcore\Bundle\EcommerceFrameworkBundle\
CartManager\CartPriceCalculator

modificators:

# Prototype

name:

class: ~ # Required

options: []

# Configuration of Order Manager

order_manager:

tenants:

# Prototype

name:

order_manager_id: Pimcore\Bundle\EcommerceFrameworkBundle\
OrderManager\V7\OrderManager

options:

order_class: \Pimcore\Model\DataObject\OnlineShopOrder

order_item_class: \Pimcore\Model\DataObject\
OnlineShopOrderItem

list_class: Pimcore\Bundle\EcommerceFrameworkBundle\
OrderManager\Order\Listing

list_item_class: Pimcore\Bundle\
EcommerceFrameworkBundle\OrderManager\Order\Listing\Item
order_parent_path: /order/*Y*/*M*/*D*

order_agent:

factory_id: Pimcore\Bundle\EcommerceFrameworkBundle\
OrderManager\Order\AgentFactory

factory_options: []

# Configuration of Pricing Manager

pricing_manager:

conditions:

# Prototype

name: ~

actions:

# Prototype

name: ~

tenants:

default: ~

# Prototype

name:

enabled: true

pricing_manager_id: Pimcore\Bundle\
EcommerceFrameworkBundle\PricingManager\PricingManager

pricing_manager_options:

rule_class: Pimcore\Bundle\EcommerceFrameworkBundle\
PricingManager\Rule

price_info_class: Pimcore\Bundle\
EcommerceFrameworkBundle\PricingManager\PriceInfo
environment_class: Pimcore\Bundle\
EcommerceFrameworkBundle\PricingManager\Environment

# Configuration of price systems

price_systems:

# Prototype

name:

id: ~ # Required

# Configuration of availability systems

availability_systems:

# Prototype

name:

id: ~ # Required

# Configuration of checkout manager

checkout_manager:

tenants:

# Prototype

name:

factory_id: Pimcore\Bundle\EcommerceFrameworkBundle\
CheckoutManager\CheckoutManagerFactory

factory_options: []

payment:

provider: null

commit_order_processor:

id: Pimcore\Bundle\EcommerceFrameworkBundle\
CheckoutManager\V7\CommitOrderProcessor
options: []

steps:

# Prototype

name:

class: ~ # Required

options: []

# Configuration of payment manager and payment providers

payment_manager:

payment_manager_id: Pimcore\Bundle\EcommerceFrameworkBundle\
PaymentManager\PaymentManager

providers:

# Prototype

name:

name: ~

provider_id: ~ # Required

profile: ~ # Required

profiles:

# Prototype

name:

# Prototype

name: ~

# Configuration of index service

index_service:

index_service_id: Pimcore\Bundle\EcommerceFrameworkBundle\
IndexService\IndexService

default_tenant: default
tenants:

# Prototype

name:

enabled: true

config_id: Pimcore\Bundle\EcommerceFrameworkBundle\
IndexService\Config\DefaultMysql

config_options: []

worker_id: ~

placeholders:

'%%locale%%': 'de_AT'

search_attributes: []

attributes:

# Prototype

name:

name: ~ # Required

field_name: null

type: null

locale: null

filter_group: null

options: []

getter_id: null

getter_options: []

interpreter_id: null

interpreter_options: []

hide_in_fieldlist_datatype: false

# Configuration of filter service


filter_service:

tenants:

# Prototype

name:

enabled: true

service_id: Pimcore\Bundle\EcommerceFrameworkBundle\
FilterService\FilterService

filter_types:

# Prototype

name:

filter_type_id: ~ # Required

template: ~ # Required

options: []

# Configuration of voucher service

voucher_service:

voucher_service_id: Pimcore\Bundle\EcommerceFrameworkBundle\
VoucherService\DefaultService

voucher_service_options:

reservation_minutes_threshold: 5

statistics_days_threshold: 30

token_managers:

factory_id: Pimcore\Bundle\EcommerceFrameworkBundle\
VoucherService\TokenManager\TokenManagerFactory

mapping:

# Prototype

name: ~
# Configuration of offer tool

offer_tool:

service_id: Pimcore\Bundle\EcommerceFrameworkBundle\OfferTool\
DefaultService

order_storage:

offer_class: Pimcore\Model\DataObject\OfferToolOffer

offer_item_class: Pimcore\Model\DataObject\OfferToolOfferItem

offer_parent_path: /offertool/offers/*Y*/*M*

# Configuration of Tracking Manager

tracking_manager:

tracking_manager_id: Pimcore\Bundle\EcommerceFrameworkBundle\
Tracking\TrackingManager

trackers:

# Prototype

enhanced_ecommerce:

id: Pimcore\Bundle\EcommerceFrameworkBundle\Tracking\
Tracker\Analytics\EnhancedEcommerce

enabled: false

item_builder_id: Pimcore\Bundle\EcommerceFrameworkBundle\
Tracking\TrackingItemBuilder

tenants:

assortment: []

checkout: []

```

### Detailed Explanation of Configuration Sections

#### General Settings


- **`decimal_scale`:** Specifies the default scale for decimal objects.

#### Pimcore Backend Menu Configuration

- **`pimcore.menu`:** Manages the visibility and settings of backend menu


entries.

- **`pricing_rules`:** Enables or disables the Pricing Rules menu entry.

- **`order_list`:** Configures the order list menu entry, including


enabling/disabling and defining the route.

#### Factory Configuration

- **`factory`:** Defines the factory service and tenant behavior.

- **`factory_id`:** Service ID of the factory implementation.

- **`strict_tenants`:** If true, the factory will not fall back to the


default tenant if a specified tenant does not exist.

#### Environment Configuration

- **`environment`:** Specifies the environment configuration.

- **`environment_id`:** Service ID for the session environment.

- **`options`:** Additional options for the environment.

#### Cart Manager Configuration

- **`cart_manager`:** Defines settings for the cart manager, supporting


multiple tenants.

- **`tenants`:** Contains tenant-specific configurations.

- **`_defaults`:** Settings common to all tenants.

- **`default`:** Mandatory tenant configuration.

- **`name`:** Prototype for tenant configurations.

#### Order Manager Configuration


- **`order_manager`:** Manages order-related settings.

- **`tenants`:** Tenant-specific configurations.

- **`name`:** Prototype for tenant configurations.

#### Pricing Manager Configuration

- **`pricing_manager`:** Handles pricing rules and actions.

- **`conditions`:** Maps condition names to classes.

- **`actions`:** Maps action names to classes.

- **`tenants`:** Tenant-specific configurations.

#### Price Systems Configuration

- **`price_systems`:** Configures different price systems.

- **`name`:** Prototype for price system configurations.

#### Availability Systems Configuration

- **`availability_systems`:** Configures different availability systems.

- **`name`:** Prototype for availability system configurations.

#### Checkout Manager Configuration

- **`checkout_manager`:** Manages the checkout process.

- **`tenants`:** Tenant-specific configurations.

#### Payment Manager Configuration

- **`payment_manager`:** Configures payment providers and the payment


manager.

- **`providers`:** Configures individual payment providers.


#### Index Service Configuration

- **`index_service`:** Manages the index service and tenant-specific


settings.

- **`tenants`:** Tenant-specific configurations.

#### Filter Service Configuration

ChatGPT

- **`filter_service`:** Configures the filter service.

- **`tenants`:** Tenant-specific configurations.

#### Voucher Service Configuration

- **`voucher_service`:** Manages voucher-related settings.

- **`voucher_service_options`:** Options for the voucher service.

- **`token_managers`:** Configures token managers.

#### Offer Tool Configuration

- **`offer_tool`:** Manages offer tool settings.

- **`order_storage`:** Configures offer storage settings.

#### Tracking Manager Configuration

- **`tracking_manager`:** Manages tracking settings.

- **`trackers`:** Configures individual trackers.

### Example Configurations

#### Example Cart Manager Configuration


```yaml

pimcore_ecommerce_framework:

cart_manager:

tenants:

_defaults:

cart:

factory_id: CartFactory

default:

cart:

factory_options:

cart_class_name: Pimcore\Bundle\
EcommerceFrameworkBundle\CartManager\Cart

price_calculator:

modificators:

shipping:

class: Pimcore\Bundle\EcommerceFrameworkBundle\
CartManager\CartPriceModificator\Shipping

options:

charge: 5.90

noShipping:

price_calculator:

factory_id: PriceCalculatorFactory

modificators: []

```

#### Example Order Manager Configuration

```yaml

pimcore_ecommerce_framework:
order_manager:

tenants:

default:

order_manager_id: Pimcore\Bundle\EcommerceFrameworkBundle\
OrderManager\V7\OrderManager

options:

order_class: \Pimcore\Model\DataObject\OnlineShopOrder

order_item_class: \Pimcore\Model\DataObject\
OnlineShopOrderItem

list_class: Pimcore\Bundle\EcommerceFrameworkBundle\
OrderManager\Order\Listing

list_item_class: Pimcore\Bundle\
EcommerceFrameworkBundle\OrderManager\Order\Listing\Item

order_parent_path: /order/*Y*/*M*/*D*

order_agent:

factory_id: Pimcore\Bundle\EcommerceFrameworkBundle\
OrderManager\Order\AgentFactory

factory_options: []

```

These configurations can be customized further to fit specific business


requirements. For detailed component configurations, refer to the
respective sections in the documentation.

User

Index Service

The Index Service (in combination with the Filter Service) provides
functionality for indexing, listing, filtering and searching products.

In the heart of this component is the Product Index - an optimized storage


of product data for all kinds of queries. Depending on the implementation,
the Product Index is stored in a special mysql table, in elasticsearch or
any other search provider (currently implemented are fact finder and
findologic). These implementations can be configured in Assortment Tenants.
The default tenant always uses DefaultMysql as implementation.
The separate Product Index has several advantages:

It is completely independent from the Pimcore object structure, only


contains needed information and can pre-calculate complex data.

It can be optimized without any side effects on Pimcore for requirements


considering filtering, listing and searching products.

It supports assortment tenants and therefore allows optimized indices for


multiple assortments within one system.

Based on the Product Index the Product List provides a one stop API for
accessing data and listing products.

See the following topics for details:

Configuration of the product index

Assortment Tenant configuration

Data architecture and indexing process

Working with Product Lists

Mockup Objects in Product List Results

ChatGPT

## Index Service Overview

The Index Service, in combination with the Filter Service, offers powerful
functionality for indexing, listing, filtering, and searching products
within Pimcore's E-Commerce Framework.

### Key Components

#### Product Index


The **Product Index** is an optimized storage solution for product data,
designed for various types of queries. Depending on the implementation, the
Product Index can be stored in different backends such as:

- **MySQL (Default):** DefaultMysql implementation.

- **Elasticsearch**

- **Fact Finder**

- **Findologic**

### Advantages of the Product Index

1. **Independence:** The Product Index is separate from the Pimcore object


structure, containing only necessary information and pre-calculated complex
data.

2. **Optimization:** It can be optimized for filtering, listing, and


searching products without affecting Pimcore's core functionalities.

3. **Assortment Tenants:** Supports multiple optimized indices for


different assortments within a single system.

4. **Product List API:** Provides a comprehensive API for accessing and


listing products based on the Product Index.

### Configuration and Usage

#### Configuration of the Product Index

Configuring the product index involves defining how and where the product
data will be stored and accessed. This is usually done in the configuration
files, specifying the details for each tenant and their respective indexing
methods.

#### Assortment Tenant Configuration

Assortment tenants allow you to create optimized indices for different


product assortments within your e-commerce system. Each tenant can have its
own unique configuration, tailored to the specific needs of that
assortment.
#### Data Architecture and Indexing Process

The data architecture involves structuring the product data for efficient
indexing and retrieval. The indexing process ensures that the product data
is processed and stored in the Product Index, ready for fast queries.

#### Working with Product Lists

The Product List API provides a unified interface for accessing product
data from the Product Index. It supports various operations such as listing
products, applying filters, and executing searches.

#### Mockup Objects in Product List Results

Mockup objects are placeholder objects used in product list results to


ensure consistent data structures during testing and development.

### Example Configuration

#### Index Service Configuration

```yaml

pimcore_ecommerce_framework:

index_service:

index_service_id: Pimcore\Bundle\EcommerceFrameworkBundle\
IndexService\IndexService

default_tenant: default

tenants:

default:

enabled: true

config_id: Pimcore\Bundle\EcommerceFrameworkBundle\
IndexService\Config\DefaultMysql

config_options: []

worker_id: ~
placeholders:

'%%locale%%': 'de_AT'

search_attributes: []

attributes:

product_name:

name: product_name

field_name: name

type: string

locale: null

filter_group: general

options: []

getter_id: null

getter_options: []

interpreter_id: null

interpreter_options: []

hide_in_fieldlist_datatype: false

```

This configuration specifies the use of the DefaultMysql implementation for


the default tenant, along with several attributes and options for the
product index.

### Conclusion

The Index Service and its integration with the Filter Service provide a
robust framework for managing product data in Pimcore's E-Commerce
Framework. By configuring the Product Index and utilizing the Product List
API, you can efficiently handle complex queries, filtering, and listing of
products, tailored to the needs of different assortments and tenants within
your system.

User
Product Index Configuration

The configuration of the Product Index defines the content of the Product
Index (which attributes are extracted how and stored where) and takes place
in the pimcore_ecommerce_framework configuration within the section
index_service. The product index can define multiple tenants (see
Assortment Tenant Configuration) which can be configured individually. Each
tenant defines a set of attributes to index/search and a configuration and
worker class responsible for storing and managing the index.

pimcore_ecommerce_framework:

index_service:

# product index defines multiple tenants which can be disabled


individually

# a tenant can define placeholders which will be replaced

tenants:

_defaults:

attributes:

name:

type: varchar(255)

filter_group: string

locale: '%%locale%%'

default:

enabled: false

# service ID of the desired configuration

config_id: Pimcore\Bundle\EcommerceFrameworkBundle\
IndexService\Config\DefaultMysql

# optional set of options passed to the config service -


available options vary by config

# implementation
config_options:

foo: bar

# optional - id of the worker handling the index. worker


and config must be matching as a worker

# is only able to accept a certain config implementation


(e.g. an elasticsearch worker can only operate

# on an elasticsearch config). as long as you don't


implement a custom worker you can omit the wotker_id

# as the system is able to automatically resolve the worker


for a given config

worker_id: Pimcore\Bundle\EcommerceFrameworkBundle\
IndexService\Worker\DefaultMysql

# placeholders will be replaced with the value defined here

# you can use placeholders to define multiple tenant


configuration

# via _defaults which set the locale based on a placeholder

# in this example, the "default" tenant will have the


attributes name

# and seoname and use "de_AT" as locale for the "name"


attribute

# please make sure to use double %% or another char as {}


to denote placeholders

# as "%locale%" would be replaced by the "%locale%"


container parameter instead

# of the placeholder

placeholders:

'%%locale%%': de_AT
# add columns for general fulltext search index of
productlist

# they must be part of the attributes configuration below

search_attributes:

- name

- seoname

# defines search index attributes and how they're gathered

# as the _defaults entry already defines a name attribute,


we'll end

# up with name and seoname here

attributes:

seoname:

type: varchar(255)

filter_group: string

INT:

attributes:

name_en: &name_en

locale: '%%locale%%'

filter_group: string

placeholders:

'%%locale%%': en

BE:

attributes:

name_fr:

<<: *name_en

# placeholders will be replaced with the value


defined here
# attribute level placeholders will be processed
before tenant level placeholders

# in this example, the "BE" (belgium) tenant will


have the attributes "name_fr", "name_de"

# and "name_nl" referencing the same attribute


config as tenant "INT" (international)

# with attribute "name_en", but using use "fr",


"de" and "nl" as locale

placeholders:

'%%locale%%': fr

name_de:

<<: *name_en

placeholders:

'%%locale%%': de

name_nl:

<<: *name_en

placeholders:

'%%locale%%': nl

example_tenant:

attributes:

rucksacksLoad:

type: 'double'

filter_group: double

# a getter is a specific service responsible for


getting the value from an object

# this must be defined as service - as we use the


class name as service id you can

# just use the fully qualified class name. you can


use your own getters if you define
# them as service first

getter_id: Pimcore\Bundle\EcommerceFrameworkBundle\
IndexService\Getter\DefaultBrickGetter

# options passed to the getter. available options


vary by getter implementation - see

# getter for available options

getter_options:

brickfield: specificAttributes

bricktype: rucksackSpecs

fieldname: load

# an interpreter can further transform the value


retrieved by the getter. same logic applies as

# for getters - interpreter must be defined as


service

interpreter_id: Pimcore\Bundle\
EcommerceFrameworkBundle\IndexService\Interpreter\Numeric

# interpreter can define options which are passed


to the interpreter when interpreting the value

interpreter_options: {}

search_attributes

Defines attributes which should be considered in fulltext-search. All


attributes must be defined within the attributes-section.

attributes

Defines for all attributes if and how they should be indexed. Each
attribute is referenced with an unique name (e.g. seoname or rucksacksLoad
in the example above) which is the name of the attribute in the product
index. The following configuration options are available:

type (mandatory for mysql): Datatype for column in Product Index.

field_name (optional): Field name in product object, needed if it is


different than name in index. Defaults to name

locale (optional): Used locale for data retrieving if field is in a


localized field.

getter_id (optional): Service ID of a special getter implementation for


getting attribute value. Per default, the method get<NAME>() of the product
object is called. If this is not suitable, an alternative getter class can
be defined which is responsible for getting the value. This can be used for
calculations, getting complex values (field collections, object bricks),
etc. Getter implementations need to implement \Pimcore\Bundle\
EcommerceFrameworkBundle\IndexService\Getter\GetterInterface interface and
be defined as service. Best practice is to use the fully qualified class
name as service ID and to reference the class name in the configuration.

getter_options (optional): options passed to the getter when resolving a


value. Available options vary by getter implementation.

interpreter_id (optional): By default all data is stored without any


transformation in the Product Index. With an interpreter, this data can be
transformed and manipulated before storing. This can be used for only
saving IDs of assets, normalization of data, special treatment of
relations, etc. Interpreter implementations need to implement Pimcore\
Bundle\EcommerceFrameworkBundle\IndexService\Interpreter\
InterpreterInterface interface. The same service ID best practices as for
getters apply to interpreters.

interpreter_options (optional): options passed to the interpreter.


Available options vary by interpreter implementation.

hide_in_fieldlist_datatype (optional): Hides column in FieldList drop down


(see FilterService for more information).

filter_group (optional): Defines filter group for the FieldList drop down
(see FilterService for more information).

Relations in Product Index

Relations are stored in a special way in Product Index and also need to be
filtered in a different way in the Product List.

In order to store relations correctly in the Product Index, relation


attributes must have an interpreter defined which implements the interface
Pimcore\Bundle\EcommerceFrameworkBundle\IndexService\Interpreter\
RelationInterpreterInterface.
Selection of available Getters:

Pimcore\Bundle\EcommerceFrameworkBundle\IndexService\Getter\
DefaultBrickGetter: Gets data from an Object Brick. Needed configuration:

brickfield: Field name of Object Brick, e.g. bricks.

bricktype: Type of Object Brick, e.g. TentBrick.

fieldname: Field name of attribute in Object Brick, e.g. height.

Pimcore\Bundle\EcommerceFrameworkBundle\IndexService\Getter\
DefaultBrickGetterSequence: Same as DefaultBrickGetter, but can use more
than one source definition and stores first found value in Product Index.

Pimcore\Bundle\EcommerceFrameworkBundle\IndexService\Getter\
DefaultBrickGetterSequenceToMultiselect: Like DefaultBrickGetterSequence,
but stores all found values as a multi select in the Product Index.

Pimcore\Bundle\EcommerceFrameworkBundle\IndexService\Getter\TagsGetter:
Gets Tags of product object and returns them as array.

Pimcore\Bundle\EcommerceFrameworkBundle\IndexService\Getter\
DefaultClassificationAttributeGetter: Gets attribute value from
classification store. Possible options:

key_id - id of the classification store attribute

group_id - id of the group related to the id | key can occur multiple times
in classification store field through multiple groups

fieldname - name of the field upon which the classification store is saved
on the specific object (defaults to attributes)

Selection of available Interpreters:

Pimcore\Bundle\EcommerceFrameworkBundle\IndexService\Interpreter\AssetId:
Stores only asset id into Product Index.

Pimcore\Bundle\EcommerceFrameworkBundle\IndexService\Interpreter\
DefaultObjects: Default interpreter to store object relations as relations
into the Product Index.

Pimcore\Bundle\EcommerceFrameworkBundle\IndexService\Interpreter\
DefaultRelations: Same as DefaultObjects but also for other relations to
Assets and Documents. Also can deal with ObjectMetadata.

Pimcore\Bundle\EcommerceFrameworkBundle\IndexService\Interpreter\
DefaultStructuredTable: Interpreter for structured table data type. Expects
following configuration options:

row
column

Pimcore\Bundle\EcommerceFrameworkBundle\IndexService\Interpreter\IdList:
Returns id list of given values as CSV list. If configuration option
multiSelectEncoded is set, it returns id list encoded as multi select
(relevant for filtering in Product List).

Pimcore\Bundle\EcommerceFrameworkBundle\IndexService\Interpreter\Numeric:
Returns floatval of given value.

Pimcore\Bundle\EcommerceFrameworkBundle\IndexService\Interpreter\
QuantityValue: Interprets quantity value data types, by default by
serializing it to string, when config option onlyValue set to true, it
returns only value

Pimcore\Bundle\EcommerceFrameworkBundle\IndexService\Interpreter\ObjectId:
Returns id of given object.

Pimcore\Bundle\EcommerceFrameworkBundle\IndexService\Interpreter\
ObjectIdSum: Calculates sum if ids of given objects. Could be used for
similarity calculation.

Pimcore\Bundle\EcommerceFrameworkBundle\IndexService\Interpreter\
ObjectValue: Get value from an related object. Expects following
configuration options:

['target']['fieldname']: Field name of value to get. Is used for getter


generation which is called on given object.

['target']['locale']: Locale is optionally passed as first parameter to


getter.

Pimcore\Bundle\EcommerceFrameworkBundle\IndexService\Interpreter\Round:
Rounds given value to integer.

Pimcore\Bundle\EcommerceFrameworkBundle\IndexService\Interpreter\Soundex:
Returns soundex of given value. Could be used for similarity calculation.

Pimcore\Bundle\EcommerceFrameworkBundle\IndexService\Interpreter\
DefaultClassificationStore: Stores all classification store attributes of a
data object to the index. Only usable in combination with elasticsearch.
See Filter Classification Store for details.

Depending on the Product Index implementation, the Product Index


configuration can be slightly different. See sample configurations for
specific Product Iindex implementations.

ChatGPT

## Product Index Configuration

The Product Index configuration in Pimcore defines how product attributes


are extracted, transformed, and stored. This configuration is crucial for
optimizing queries, indexing, and filtering product data. Here's a
comprehensive guide to configuring the Product Index within the
`pimcore_ecommerce_framework` configuration.

### Configuration Structure

```yaml

pimcore_ecommerce_framework:

index_service:

tenants:

_defaults:

attributes:

name:

type: varchar(255)

filter_group: string

locale: '%%locale%%'

default:

enabled: true

config_id: Pimcore\Bundle\EcommerceFrameworkBundle\
IndexService\Config\DefaultMysql

config_options:

foo: bar

worker_id: Pimcore\Bundle\EcommerceFrameworkBundle\
IndexService\Worker\DefaultMysql

placeholders:

'%%locale%%': de_AT

search_attributes:

- name
- seoname

attributes:

name:

type: varchar(255)

filter_group: string

seoname:

type: varchar(255)

filter_group: string

INT:

attributes:

name_en: &name_en

locale: '%%locale%%'

filter_group: string

placeholders:

'%%locale%%': en

BE:

attributes:

name_fr:

<<: *name_en

placeholders:

'%%locale%%': fr

name_de:

<<: *name_en

placeholders:

'%%locale%%': de

name_nl:

<<: *name_en
placeholders:

'%%locale%%': nl

example_tenant:

attributes:

rucksacksLoad:

type: 'double'

filter_group: double

getter_id: Pimcore\Bundle\EcommerceFrameworkBundle\
IndexService\Getter\DefaultBrickGetter

getter_options:

brickfield: specificAttributes

bricktype: rucksackSpecs

fieldname: load

interpreter_id: Pimcore\Bundle\
EcommerceFrameworkBundle\IndexService\Interpreter\Numeric

interpreter_options: {}

```

### Configuration Details

#### Tenants

The configuration supports multiple tenants, each with its own set of
indexed attributes and options. Tenants allow you to create optimized
indices for different product assortments.

- **_defaults:** Common settings for all tenants. These settings are merged
into every tenant configuration.

- **default:** Mandatory tenant configuration.


- **other tenants (e.g., INT, BE):** Additional tenants with unique
configurations.

#### Attributes

Defines the attributes to be indexed for each tenant. Each attribute can
have the following options:

- **type (mandatory for MySQL):** The data type of the attribute (e.g.,
varchar(255), double).

- **field_name:** The name of the field in the product object if different


from the index name.

- **locale:** The locale used for data retrieval if the field is localized.

- **getter_id:** The service ID of a custom getter for retrieving attribute


values.

- **getter_options:** Options passed to the getter.

- **interpreter_id:** The service ID of a custom interpreter for


transforming attribute values before storing them.

- **interpreter_options:** Options passed to the interpreter.

- **filter_group:** Defines the filter group for the FieldList dropdown in


the FilterService.

- **hide_in_fieldlist_datatype:** Hides the column in the FieldList


dropdown.

#### Example Attribute Configuration

```yaml

attributes:

name:

type: varchar(255)

filter_group: string
seoname:

type: varchar(255)

filter_group: string

rucksacksLoad:

type: 'double'

filter_group: double

getter_id: Pimcore\Bundle\EcommerceFrameworkBundle\IndexService\
Getter\DefaultBrickGetter

getter_options:

brickfield: specificAttributes

bricktype: rucksackSpecs

fieldname: load

interpreter_id: Pimcore\Bundle\EcommerceFrameworkBundle\
IndexService\Interpreter\Numeric

interpreter_options: {}

```

### Getters

Getters are services responsible for retrieving the value of an attribute


from a product object. They can be customized and need to implement the
`GetterInterface`.

- **DefaultBrickGetter:** Retrieves data from an Object Brick.

- **Options:**

- `brickfield`: Field name of the Object Brick.

- `bricktype`: Type of Object Brick.

- `fieldname`: Attribute field name in the Object Brick.


### Interpreters

Interpreters transform and manipulate attribute values before storing them


in the Product Index. They need to implement the `InterpreterInterface`.

- **Numeric:** Returns the float value of the given value.

### Example Configuration with Getters and Interpreters

```yaml

attributes:

rucksacksLoad:

type: 'double'

filter_group: double

getter_id: Pimcore\Bundle\EcommerceFrameworkBundle\IndexService\
Getter\DefaultBrickGetter

getter_options:

brickfield: specificAttributes

bricktype: rucksackSpecs

fieldname: load

interpreter_id: Pimcore\Bundle\EcommerceFrameworkBundle\
IndexService\Interpreter\Numeric

interpreter_options: {}

```

### Search Attributes

Defines attributes that should be included in fulltext searches. These


attributes must be part of the attributes configuration.
```yaml

search_attributes:

- name

- seoname

```

### Placeholder Values

Placeholders allow you to define multiple tenant configurations by setting


values that can be dynamically replaced.

```yaml

placeholders:

'%%locale%%': de_AT

```

### Complete Example

Here's a complete example configuration for the Product Index with multiple
tenants, getters, interpreters, and placeholders.

```yaml

pimcore_ecommerce_framework:

index_service:

tenants:

_defaults:

attributes:
name:

type: varchar(255)

filter_group: string

locale: '%%locale%%'

default:

enabled: true

config_id: Pimcore\Bundle\EcommerceFrameworkBundle\
IndexService\Config\DefaultMysql

config_options:

foo: bar

worker_id: Pimcore\Bundle\EcommerceFrameworkBundle\
IndexService\Worker\DefaultMysql

placeholders:

'%%locale%%': de_AT

search_attributes:

- name

- seoname

attributes:

name:

type: varchar(255)

filter_group: string

seoname:

type: varchar(255)

filter_group: string

INT:

attributes:

name_en: &name_en

locale: '%%locale%%'
filter_group: string

placeholders:

'%%locale%%': en

BE:

attributes:

name_fr:

<<: *name_en

placeholders:

'%%locale%%': fr

name_de:

<<: *name_en

placeholders:

'%%locale%%': de

name_nl:

<<: *name_en

placeholders:

'%%locale%%': nl

example_tenant:

attributes:

rucksacksLoad:

type: 'double'

filter_group: double

getter_id: Pimcore\Bundle\EcommerceFrameworkBundle\
IndexService\Getter\DefaultBrickGetter

getter_options:

brickfield: specificAttributes

bricktype: rucksackSpecs
fieldname: load

interpreter_id: Pimcore\Bundle\
EcommerceFrameworkBundle\IndexService\Interpreter\Numeric

interpreter_options: {}

```

This configuration sets up the Product Index for various tenants, each with
its own attributes and options, utilizing getters and interpreters to
retrieve and transform data as needed.

User

Assortment Tenant Configuration

The E-Commerce Framework provides a two level Assortment Tenant system for
the Product Index:

Assortment Tenant: The first level of tenants are heavy-weight tenants.


They allow multiple shop instances within one system. The shop instances
are completely independent from each other and can contain complete
different products, index attributes and even use different product index
implementations.

Assortment Subtenant: The second level of tenants are light-weight tenants,


which exist within a shop instance. Light-weight tenants use the same
Product Index with the same attributes as their parent shop, but can
contain a subset of the products. So they are meant to be used for
implementing different product assortments within one shop.

One system can have multiple tenants (heavy- and light-weight). But too
many tenants can have bad effects on the performance of saving products,
since all Product Indices need to be updated on every save.

By default the system always uses one heavy-weight tenant (which is


DefaultMysql), but the default tenant can be disabled.

Assortment Tenants

For setting up an Assortment Tenant, following steps are necessary:


Implementation of a Tenant Config: The Tenant Config class is the central
configuration of an assortment tenant, defines which products are available
for the tenant and provides the connection to the used Product Index
implementation. It needs to implement Pimcore\Bundle\
EcommerceFrameworkBundle\IndexService\Config\ConfigInterface. For detailed
information see in-source documentation of the interface. Following
implementations are provided by the framework and may be extended:

Pimcore\Bundle\EcommerceFrameworkBundle\IndexService\Config\DefaultMysql:
Provides a simple mysql implementation of the product index.

Pimcore\Bundle\EcommerceFrameworkBundle\IndexService\ConfigOptimizedMysql:
Provides an optimized mysql implementation of the product index.

Pimcore\Bundle\EcommerceFrameworkBundle\IndexService\Config\ElasticSearch:
Provides a default elasticsearch implementation of the product index.

Pimcore\Bundle\EcommerceFrameworkBundle\IndexService\Config\
DefaultFindologic: Provides a default findologic implementation of the
product index.

Configuring Assortment Tenants within configuration: Each tenant has to be


configured within the index_service configuration by defining the tenant
config class and index attributes. Depending on the Product Index
implementation, additional configuration may be necessary.

Declare the service: You need to declare the service as well so the class
can be used. On your service configuration or for instance at the top of
the ecommerce configuration file:

services:

MyBundle\Service\MySubtenantConfig:

calls:

- [setAttributeFactory, ['@Pimcore\Bundle\
EcommerceFrameworkBundle\IndexService\Config\AttributeFactory']]

Setting current Assortment Tenant for Frontend

The E-Commerce Framework Environment provides following methods to set the


current Assortment Tenant when working with Product Lists in Code:
<?php

/**

* sets current assortment tenant which is used for indexing and


product lists

* @param string $tenant

* @return mixed

*/

public function setCurrentAssortmentTenant($tenant);

/**

* gets current assortment tenant which is used for indexing and


product lists

* @return string

*/

public function getCurrentAssortmentTenant();

/**

* sets current assortment sub tenant which is used for indexing and
product lists

* @param string $subTenant

* @return mixed

*/

public function setCurrentAssortmentSubTenant($subTenant);


/**

* gets current assortment sub tenant which is used for indexing and
product lists

* @return string

*/

public function getCurrentAssortmentSubTenant();

The current Assortment Tenant has to be set in the application controllers,


e.g. after the login of a specific customer. The Index Service provides the
corresponding Product List implementation based on the current tenant.

Example:

<?php

$factory = \Pimcore\Bundle\EcommerceFrameworkBundle\
Factory::getInstance();

//setting assortment tenant

$environment = $factory->getEnvironment();

$environment->setCurrentAssortmentTenant("elasticsearch");

//getting suitable product list

$productlist = $factory->getIndexService()-
>getProductListForCurrentTenant();

//doing stuff with product list

Assortment Subtenants

Subtenants are light-weight tenants, which share the same Product Index
with the same attributes as their parent assortment tenant.
Implementing an Assortment Subtenant for MySQL

The mapping which product is assigned to with subtenant is done with an


additional mapping table. The necessary joins and conditions are
implemented within additional methods within Pimcore\Bundle\
EcommerceFrameworkBundle\IndexService\Config\MysqlConfigInterface:

/**

* return table name of product index tenant relations for subtenants

* @return string

*/

public function getTenantRelationTablename();

/**

* return join statement in case of subtenants

* @return string

*/

public function getJoins();

/**

* returns additional condition in case of subtenants

* @return string

*/

public function getCondition();


In order to populate the additional mapping data, also following methods
have to be implemented:

/**

* in case of subtenants returns a data structure containing all sub


tenants

* @param IndexableInterface $object

* @param int|null $subObjectId

* @return mixed $subTenantData

*/

public function prepareSubTenantEntries(IndexableInterface $object,


$subObjectId = null);

/**

* populates index for tenant relations based on given data

* @param mixed $objectId

* @param mixed $subTenantData

* @param mixed $subObjectId

* @return void

*/

public function updateSubTenantEntries($objectId, $subTenantData,


$subObjectId = null);

For an complete example have a look at the sample implementation.


Implementing an Assortment Subtenant for Elasticsearch

In order to populate the additional mapping data, the following method has
to be implemented:

/**

* in case of subtenants returns a data structure containing all sub


tenants

* @param IndexableInterface $object

* @param int|null $subObjectId

* @return array $subTenantData

*/

public function prepareSubTenantEntries(IndexableInterface $object,


$subObjectId = null);

For an complete example have a look at the sample implementation.

Note: This is currently only implemented for MySQL and elasticsearch based
product index implementations.

ChatGPT

## Assortment Tenant Configuration

The E-Commerce Framework supports a two-level Assortment Tenant system for


the Product Index:
1. **Assortment Tenant:** These are heavy-weight tenants, allowing multiple
independent shop instances within one system. Each tenant can have
different products, index attributes, and Product Index implementations.

2. **Assortment Subtenant:** These are light-weight tenants within a shop


instance, sharing the same Product Index and attributes as the parent
tenant but containing a subset of products.

### Assortment Tenant Configuration

### Steps to Configure an Assortment Tenant

1. **Implementing a Tenant Config:**

- The Tenant Config class defines the product availability and Product
Index connection. It must implement `Pimcore\Bundle\
EcommerceFrameworkBundle\IndexService\Config\ConfigInterface`.

- Available implementations provided by the framework include:

- `Pimcore\Bundle\EcommerceFrameworkBundle\IndexService\Config\
DefaultMysql`

- `Pimcore\Bundle\EcommerceFrameworkBundle\IndexService\
ConfigOptimizedMysql`

- `Pimcore\Bundle\EcommerceFrameworkBundle\IndexService\Config\
ElasticSearch`

- `Pimcore\Bundle\EcommerceFrameworkBundle\IndexService\Config\
DefaultFindologic`

2. **Configuring Assortment Tenants:**

- Configure each tenant within the `index_service` configuration by


defining the tenant config class and index attributes.

- Declare the service for the tenant config class.

### Example Configuration

```yaml
pimcore_ecommerce_framework:

index_service:

tenants:

default:

enabled: true

config_id: Pimcore\Bundle\EcommerceFrameworkBundle\
IndexService\Config\DefaultMysql

config_options: []

worker_id: Pimcore\Bundle\EcommerceFrameworkBundle\
IndexService\Worker\DefaultMysql

placeholders:

'%%locale%%': de_AT

search_attributes:

- name

- seoname

attributes:

name:

type: varchar(255)

filter_group: string

seoname:

type: varchar(255)

filter_group: string

elasticsearch_tenant:

enabled: true

config_id: Pimcore\Bundle\EcommerceFrameworkBundle\
IndexService\Config\ElasticSearch

config_options: []

worker_id: Pimcore\Bundle\EcommerceFrameworkBundle\
IndexService\Worker\ElasticSearch
search_attributes:

- name

- description

attributes:

name:

type: text

filter_group: string

description:

type: text

filter_group: string

```

### Declaring the Service

Ensure that the service for the tenant config class is declared, so it can
be used by the framework.

```yaml

services:

MyBundle\Service\MyTenantConfig:

calls:

- [setAttributeFactory, ['@Pimcore\Bundle\
EcommerceFrameworkBundle\IndexService\Config\AttributeFactory']]

```

### Setting the Current Assortment Tenant in Frontend


The E-Commerce Framework Environment provides methods to set and get the
current Assortment Tenant and Subtenant.

```php

<?php

$factory = \Pimcore\Bundle\EcommerceFrameworkBundle\Factory::getInstance();

// Setting assortment tenant

$environment = $factory->getEnvironment();

$environment->setCurrentAssortmentTenant("elasticsearch_tenant");

// Getting suitable product list

$productlist = $factory->getIndexService()-
>getProductListForCurrentTenant();

// Doing stuff with product list

```

### Assortment Subtenant Configuration

Subtenants share the same Product Index with the same attributes as their
parent tenant but can have a subset of the products.

### Implementing an Assortment Subtenant for MySQL

For MySQL, the subtenant configuration involves mapping product assignments


with an additional mapping table and implementing necessary methods for
joins and conditions.
#### Example Configuration for MySQL Subtenant

```php

<?php

class MySubtenantConfig implements Pimcore\Bundle\EcommerceFrameworkBundle\


IndexService\Config\MysqlConfigInterface

// Implementation of required methods

public function getTenantRelationTablename() {

return 'my_subtenant_relation_table';

public function getJoins() {

return 'JOIN my_subtenant_relation_table ON ...';

public function getCondition() {

return 'my_subtenant_relation_table.subtenant_id = ...';

public function prepareSubTenantEntries(IndexableInterface $object,


$subObjectId = null) {

// Prepare subtenant entries

}
public function updateSubTenantEntries($objectId, $subTenantData,
$subObjectId = null) {

// Update subtenant entries

```

### Implementing an Assortment Subtenant for Elasticsearch

For Elasticsearch, the subtenant configuration involves implementing


methods to prepare subtenant entries.

#### Example Configuration for Elasticsearch Subtenant

```php

<?php

class MyElasticsearchSubtenantConfig implements Pimcore\Bundle\


EcommerceFrameworkBundle\IndexService\Config\ElasticsearchConfigInterface

// Implementation of required methods

public function prepareSubTenantEntries(IndexableInterface $object,


$subObjectId = null) {

// Prepare subtenant entries

```
### Complete Example of Tenant and Subtenant Configuration

Here's a complete example demonstrating the configuration of tenants and


subtenants:

```yaml

pimcore_ecommerce_framework:

index_service:

tenants:

default:

enabled: true

config_id: Pimcore\Bundle\EcommerceFrameworkBundle\
IndexService\Config\DefaultMysql

config_options: []

worker_id: Pimcore\Bundle\EcommerceFrameworkBundle\
IndexService\Worker\DefaultMysql

placeholders:

'%%locale%%': de_AT

search_attributes:

- name

- seoname

attributes:

name:

type: varchar(255)

filter_group: string

seoname:

type: varchar(255)

filter_group: string
elasticsearch_tenant:

enabled: true

config_id: Pimcore\Bundle\EcommerceFrameworkBundle\
IndexService\Config\ElasticSearch

config_options: []

worker_id: Pimcore\Bundle\EcommerceFrameworkBundle\
IndexService\Worker\ElasticSearch

search_attributes:

- name

- description

attributes:

name:

type: text

filter_group: string

description:

type: text

filter_group: string

subtenant_mysql:

enabled: true

config_id: MyBundle\Service\MySubtenantConfig

config_options: []

worker_id: Pimcore\Bundle\EcommerceFrameworkBundle\
IndexService\Worker\DefaultMysql

attributes:

subtenant_attribute:

type: varchar(255)

filter_group: string

subtenant_elasticsearch:
enabled: true

config_id: MyBundle\Service\MyElasticsearchSubtenantConfig

config_options: []

worker_id: Pimcore\Bundle\EcommerceFrameworkBundle\
IndexService\Worker\ElasticSearch

attributes:

subtenant_attribute:

type: text

filter_group: string

```

### Summary

By leveraging the Assortment Tenant and Subtenant configurations, you can


create highly customized and optimized product indices tailored to the
needs of different shop instances and product assortments within your
Pimcore E-Commerce Framework.

User

Data Architecture and Indexing Process

Depending on the Product Index implementation, there are two different


Product Index data architectures and ways for indexing: Simple Mysql
Architecture and Optimized Architecture.

For indexing itself the provided Pimcore console commands can be used.

Simple Mysql Architecture

Pimcore object data is transferred directly to the Product Index.

After every update of a Pimcore object, the changes are directly written
into the Product Index.

Only used for \Pimcore\Bundle\EcommerceFrameworkBundle\IndexService\Config\


DefaultMysql
Updates of dependent objects (like child objects, variants that inherit
data, related objects) are not transferred into the index automatically.

productindex-simple

Console Commands for Simple Mysql Architecture

For manually updating the whole index use following command:

php bin/console ecommerce:indexservice:bootstrap --update-index

If you need to create or update the index structures you can use:

php bin/console ecommerce:indexservice:bootstrap --create-or-update-index-


structure

By default, Pimcore assumes that the product class is Pimcore\Model\


DataObject\Product. If you have a different product class name, please use
the --object-list-class param and provide the listing class name that
should be used.

For further details (e.g. only updating certain product types, apply list
conditions) see --help section of the ecommerce:indexservice:bootstrap
command.

Optimized Architecture

In the optimized architecture, object data is transferred not directly to


the Product Index.

In this case a so called store table is between the Pimcore objects and the
Product Index. This store table enables to ...

... update the Product Index only if index relevant data has changed.
Therefore the load on the index itself is reduced and unnecessary write
operations are prevented.

... update the Product Index asynchronously and therefore update also
dependent elements (children, variants, ...) of an updated Pimcore object
without impact on save performance.
... rebuilding the whole Product Index out of the store table much faster
since no direct interaction with Pimcore objects is needed.

After every update of a Pimcore object, the changes are written into the
store table and all child objects of the updated object are added to the so
called preparation queue (see later). As a consequence a periodic full
update should not be necessary any more.

Used for optimized mysql, elasticsearch, ...

productindex-optimized

Console Commands for Optimized Architecture

For updating data in index following commands are available.

For process the preparation queue and update Pimcore objects to the index
store table, use following command. This command should be executed
periodically (e.g. all 10 minutes).

php bin/console ecommerce:indexservice:process-preparation-queue

To update the Product Index based on changes stored in the store table use
the following command. This command should be executed periodically (e.g.
all 10 minutes).

php bin/console ecommerce:indexservice:process-update-queue

For manually update all Pimcore objects in the index store use following
command. As stated before, this should only be necessary for an initial
fill-up of the index. After that, at least Product Index Store and Pimcore
objects should always be in sync. It is important to execute
ecommerce:indexservice:process-preparation-queue and
ecommerce:indexservice:process-update-queue periodically though.

php bin/console ecommerce:indexservice:bootstrap --update-index

By default, Pimcore assumes that the product class is Pimcore\Model\


DataObject\Product. If you have a different product class name, please use
the --object-list-class param and provide the listing class name that
should be used.
Invalidate either the preparation queue or the index-update queue. This is
usually only needed during development when the store table is out of sync.
Reset the preparation queue for instance when your product model returns
updated data for a field.

php bin/console ecommerce:indexservice:reset-queue preparation --


tenant=MyTenant

php bin/console ecommerce:indexservice:reset-queue update-index --


tenant=MyTenant

If you need to create or update the index structures you can still use:

php bin/console ecommerce:indexservice:bootstrap --create-or-update-index-


structure

For further details see --help section of the commands.

Paralelization of Indexing

All indexing commands include the parallelization trait of webmozart. Thus


indexing can be parallelized very easily by adding the --processes=X option
to the command.

Be aware that depending on the command too many parallel processes might
cause deadlocks on database.

ChatGPT

## Data Architecture and Indexing Process in Pimcore E-Commerce Framework

### Product Index Architectures

There are two main data architectures and indexing processes depending on
the Product Index implementation:

1. **Simple MySQL Architecture**


2. **Optimized Architecture**

### 1. Simple MySQL Architecture

In the Simple MySQL Architecture, Pimcore object data is transferred


directly to the Product Index. This architecture is straightforward but has
some limitations, especially with handling dependent objects.

#### Key Features

- **Direct Transfer:** Object data is directly written into the Product


Index after every update.

- **Immediate Updates:** Changes are immediately reflected in the Product


Index.

- **Limited Scope:** Does not automatically update dependent objects (e.g.,


child objects, variants, related objects).

- **Implementation:** Used for `\Pimcore\Bundle\EcommerceFrameworkBundle\


IndexService\Config\DefaultMysql`.

#### Console Commands for Simple MySQL Architecture

- **Manually Update the Whole Index:**

```bash

php bin/console ecommerce:indexservice:bootstrap --update-index

```

- **Create or Update Index Structures:**

```bash

php bin/console ecommerce:indexservice:bootstrap --create-or-update-


index-structure

```
- **Specify a Different Product Class:**

```bash

php bin/console ecommerce:indexservice:bootstrap --object-list-


class="Your\Custom\ProductClass"

```

### 2. Optimized Architecture

In the Optimized Architecture, a store table is used between Pimcore


objects and the Product Index. This allows for more efficient indexing and
updating processes.

#### Key Features

- **Intermediary Store Table:** Changes are written to a store table before


being transferred to the Product Index.

- **Efficient Updates:** Updates the Product Index only if relevant data


has changed, reducing unnecessary write operations.

- **Asynchronous Processing:** Updates can be processed asynchronously,


allowing for updates to dependent elements without impacting save
performance.

- **Faster Rebuilds:** The Product Index can be rebuilt quickly from the
store table without direct interaction with Pimcore objects.

- **Implementation:** Used for optimized MySQL, Elasticsearch, and other


advanced configurations.

#### Console Commands for Optimized Architecture

- **Process the Preparation Queue:**

```bash

php bin/console ecommerce:indexservice:process-preparation-queue


```

This command should be executed periodically (e.g., every 10 minutes).

- **Process the Update Queue:**

```bash

php bin/console ecommerce:indexservice:process-update-queue

```

This command should also be executed periodically (e.g., every 10


minutes).

- **Manually Update All Pimcore Objects in the Index Store:**

```bash

php bin/console ecommerce:indexservice:bootstrap --update-index

```

- **Invalidate Queues (Preparation or Update):**

```bash

php bin/console ecommerce:indexservice:reset-queue preparation --


tenant=MyTenant

php bin/console ecommerce:indexservice:reset-queue update-index --


tenant=MyTenant

```

- **Create or Update Index Structures:**

```bash

php bin/console ecommerce:indexservice:bootstrap --create-or-update-


index-structure

```
- **Specify a Different Product Class:**

```bash

php bin/console ecommerce:indexservice:bootstrap --object-list-


class="Your\Custom\ProductClass"

```

### Parallelization of Indexing

All indexing commands support parallelization using the `webmozart`


parallelization trait. You can parallelize the indexing process by adding
the `--processes=X` option to the command.

#### Example:

```bash

php bin/console ecommerce:indexservice:process-update-queue --processes=4

```

**Note:** Using too many parallel processes may cause database deadlocks.

### Summary

The choice between Simple MySQL Architecture and Optimized Architecture


depends on the specific needs and complexity of your e-commerce setup. The
Simple MySQL Architecture is straightforward and easy to implement but may
not handle complex relationships and dependent objects efficiently. The
Optimized Architecture, on the other hand, offers more flexibility and
efficiency by using an intermediary store table and supporting asynchronous
updates, making it suitable for more complex and large-scale
implementations.

User

Special Aspects for Elasticsearch

Basically Elasticsearch worker works as described in the optimized


architecture. Currently, Elasticsearch 8 is supported.
Installation

Elasticsearch 8

To work properly Pimcore requires the Elasticsearch client, install them


with: composer require pimcore/elasticsearch-client.

Index Configuration

Elasticsearch provides a couple of additional configuration options for the


index to utilize elasticsearch features. See Configuration Details for more
information.

Reindexing Mode

It is possible that elasticsearch cannot update the mapping, e.g. if data


types of attributes change on the fly. For this case, a reindex is
necessary. If it is necessary, a native ES reindex is executed
automatically during bin/console ecommerce:indexservice:bootstrap --create-
or-update-index-structure.

While reindex is executed, no updates are written to the ES index. The


changes remain in store table and are transferred to index during next
execution of bin/console ecommerce:indexservice:process-update-queue after
reindex is finished.

All queries that take place during reindex go to the old index. As soon the
reindex is finished, the current index is switched to the newly created
index and the old index is deleted.

As a result, during reindex the results delivered by Product Lists can


contain old data.

To manually start a reindex, following command can be used: bin/console


ecommerce:indexservice:elasticsearch-sync reindex.

Indexing of Classification Store Attributes

With elasticsearch it is possible to index all attributes of Classification


Store data without defining an attribute for each single classification
store key.
For details see Filter Classification Store in Filter Service
documentation.

Synonyms

Pimcore provides an out-of-the box integration for synonyms in


elasticsearch. See Synonyms for details.

ChatGPT

## Special Aspects for Elasticsearch in Pimcore E-Commerce Framework

Elasticsearch offers powerful capabilities for indexing and searching,


which can be leveraged within the Pimcore E-Commerce Framework. Here are
the special aspects and configurations required for using Elasticsearch as
your Product Index.

### Installation

To use Elasticsearch with Pimcore, you need to install the Elasticsearch


client.

#### Step-by-Step Installation

1. **Install Elasticsearch Client:**

```bash

composer require pimcore/elasticsearch-client

```

2. **Configure Elasticsearch in your `pimcore_ecommerce_framework`:**

Ensure your configuration file reflects the necessary settings for


Elasticsearch.
### Index Configuration

Elasticsearch allows additional configurations to utilize its advanced


features. Here are the key points for configuring Elasticsearch within
Pimcore.

#### Example Configuration

```yaml

pimcore_ecommerce_framework:

index_service:

tenants:

default:

enabled: true

config_id: Pimcore\Bundle\EcommerceFrameworkBundle\
IndexService\Config\ElasticSearch

config_options:

index_name: my_custom_index

number_of_shards: 3

number_of_replicas: 2

worker_id: Pimcore\Bundle\EcommerceFrameworkBundle\
IndexService\Worker\ElasticSearch

search_attributes:

- name

- description

attributes:

name:

type: text

filter_group: string
description:

type: text

filter_group: string

```

### Reindexing Mode

Elasticsearch may require reindexing if the data types of attributes


change. Pimcore handles reindexing automatically during index structure
creation or updates.

#### Automatic Reindexing

1. **Reindex Execution:**

When necessary, a native Elasticsearch reindex is automatically executed


during:

```bash

php bin/console ecommerce:indexservice:bootstrap --create-or-update-


index-structure

```

2. **Behavior During Reindex:**

- **Index Updates:** Updates are paused during reindexing.

- **Data Storage:** Changes are stored in the store table.

- **Query Execution:** Queries are directed to the old index until the
reindexing is complete.

- **Index Switch:** Once reindexing is done, the new index is activated,


and the old index is deleted.

3. **Manual Reindexing:**
To manually start a reindex:

```bash

php bin/console ecommerce:indexservice:elasticsearch-sync reindex

```

### Indexing of Classification Store Attributes

Elasticsearch can index all attributes of the Classification Store data


without needing to define an attribute for each key. This simplifies the
process and improves efficiency.

#### Example Configuration

```yaml

pimcore_ecommerce_framework:

index_service:

tenants:

default:

enabled: true

config_id: Pimcore\Bundle\EcommerceFrameworkBundle\
IndexService\Config\ElasticSearch

config_options: []

search_attributes:

- classification_store

attributes:

classification_store:

type: object

getter_id: Pimcore\Bundle\EcommerceFrameworkBundle\
IndexService\Getter\DefaultClassificationAttributeGetter
getter_options:

key_id: your_key_id

group_id: your_group_id

fieldname: attributes

```

### Synonyms

Pimcore integrates with Elasticsearch to support synonyms out of the box.


This feature enhances search functionality by allowing different terms with
similar meanings to be treated equivalently.

#### Configuring Synonyms

1. **Define Synonyms:**

Create a synonyms file or list that Elasticsearch can use.

2. **Integrate Synonyms in Configuration:**

Update your Elasticsearch index configuration to include the synonyms.

### Example Commands

#### Update the Whole Index

```bash

php bin/console ecommerce:indexservice:bootstrap --update-index

```

#### Create or Update Index Structures


```bash

php bin/console ecommerce:indexservice:bootstrap --create-or-update-index-


structure

```

#### Process Preparation Queue

```bash

php bin/console ecommerce:indexservice:process-preparation-queue

```

Execute periodically, e.g., every 10 minutes.

#### Process Update Queue

```bash

php bin/console ecommerce:indexservice:process-update-queue

```

Execute periodically, e.g., every 10 minutes.

#### Manually Start Reindex

```bash

php bin/console ecommerce:indexservice:elasticsearch-sync reindex

```

### Parallelization of Indexing

You can parallelize indexing commands using the `--processes=X` option.

#### Example:
```bash

php bin/console ecommerce:indexservice:process-update-queue --processes=4

```

### Summary

By integrating Elasticsearch into the Pimcore E-Commerce Framework, you can


leverage advanced indexing and search capabilities, including efficient
data handling, support for synonyms, and enhanced performance through
optimized architecture and asynchronous updates. Ensure to configure your
Elasticsearch settings appropriately and use the provided console commands
to manage indexing and reindexing processes effectively.

User

Configuration Configuration

Following aspects need to be considered in index configuration:

General Configuration Options

In the config_options area general elasticsearch settings can be made -


like hosts, index settings, etc.

client_config

logging: (deprecated, for Elasticsearch 7 only) true/false to activate


logging of elasticsearch client

indexName: index name to be used, if not provided tenant name is used as


index name

index_settings

Index settings that are used when creating a new index. They are passed 1:1
as settings param to the body of the create index command. Details see also
elasticsearch Docs.

es_client_name (for Elasticsearch 8 only)

Elasticsearch 8 client configuration takes place via Pimcore Elasticsearch


Client Bundle and has two parts.
Configuring an elasticsearch client in separate configuration

# Configure an elasticsearch client

pimcore_elasticsearch_client:

es_clients:

default:

hosts: ['elastic:9200']

username: 'elastic'

password: 'somethingsecret'

logger_channel: 'pimcore.elasticsearch'

Define the client name to be used by an elasticsearch tenant. This will be


done via the es_client_name configuration in the config_options.

synonym_providers

Specify synonym providers for synonym filters defined in filter section of


index settings. For details see Synonyms.

Sample Config

pimcore_ecommerce_framework:

index_service:

tenants:

MyEsTenant:

worker_id: Pimcore\Bundle\EcommerceFrameworkBundle\
IndexService\Worker\ElasticSearch\DefaultElasticSearch8

config_id: Pimcore\Bundle\EcommerceFrameworkBundle\
IndexService\Config\ElasticSearch

config_options:

client_config:
logging: false

indexName: 'ecommerce-demo-elasticsearch'

# elasticsearch client name, for Elasticsearch 8 only

es_client_name: default

index_settings:

number_of_shards: 5

number_of_replicas: 0

max_ngram_diff: 30

analysis:

analyzer:

my_ngram_analyzer:

tokenizer: my_ngram_tokenizer

allow_list_analyzer:

tokenizer: standard

filter:

- allow_list_filter

tokenizer:

my_ngram_tokenizer:

type: ngram

min_gram: 2

max_gram: 15

token_chars: [letter, digit]

filter:

allow_list_filter:

type: keep
keep_words:

- was

- WAS

Data Types for attributes

The type of the data attributes needs to be set to elasticsearch data


types..

pimcore_ecommerce_framework:

index_service:

tenants:

MyEsTenant:

attributes:

name:

locale: '%%locale%%'

type: keyword

In addition to the type configuration, you also can provide custom mappings
for a field. If provided, these mapping configurations are used for
creating the mapping of the elasticsearch index.

You can also skip the type and mapping, then ES will try to create dynamic
mapping.

pimcore_ecommerce_framework:

index_service:

tenants:
MyEsTenant:

attributes:

name:

locale: '%%locale%%'

type: text

options:

mapping:

type: text

store: true

index: not_analyzed

fields:

analyzed:

type: text

analyzer: german

analyzed_ngram:

type: text

analyzer: my_ngram_analyzer

ChatGPT

## Elasticsearch Configuration for Pimcore E-Commerce Framework

When integrating Elasticsearch with Pimcore, it's essential to configure


various settings to leverage Elasticsearch's full capabilities. Here's a
detailed guide on setting up Elasticsearch in the Pimcore E-Commerce
Framework.

### General Configuration Options


#### `config_options` Section

This section allows you to set general Elasticsearch settings such as


hosts, index settings, and client configurations.

1. **Client Configuration (`client_config`):**

- **`logging`:** Enable or disable logging of Elasticsearch client


(deprecated in Elasticsearch 8).

- **`indexName`:** Specify the index name to be used. If not provided,


the tenant name is used as the index name.

2. **Index Settings (`index_settings`):**

- These settings are passed 1:1 as the `settings` parameter to the body
of the `create index` command. For more details, refer to the
[Elasticsearch
documentation](https://www.elastic.co/guide/en/elasticsearch/reference/
current/indices-create-index.html).

3. **Elasticsearch Client Name (`es_client_name`):**

- For Elasticsearch 8, configure the Elasticsearch client via the


Pimcore Elasticsearch Client Bundle and specify the client name.

### Elasticsearch 8 Client Configuration

#### Configure Elasticsearch Client

This configuration is done separately in the Pimcore Elasticsearch Client


Bundle:

```yaml

pimcore_elasticsearch_client:

es_clients:
default:

hosts: ['http://elastic:9200']

username: 'elastic'

password: 'somethingsecret'

logger_channel: 'pimcore.elasticsearch'

```

#### Reference Client in Tenant Configuration

In the `config_options` of the tenant configuration, specify the client


name to be used:

```yaml

pimcore_ecommerce_framework:

index_service:

tenants:

MyEsTenant:

worker_id: Pimcore\Bundle\EcommerceFrameworkBundle\
IndexService\Worker\ElasticSearch\DefaultElasticSearch8

config_id: Pimcore\Bundle\EcommerceFrameworkBundle\
IndexService\Config\ElasticSearch

config_options:

client_config:

logging: false

indexName: 'ecommerce-demo-elasticsearch'

es_client_name: default
index_settings:

number_of_shards: 5

number_of_replicas: 0

max_ngram_diff: 30

analysis:

analyzer:

my_ngram_analyzer:

tokenizer: my_ngram_tokenizer

allow_list_analyzer:

tokenizer: standard

filter:

- allow_list_filter

tokenizer:

my_ngram_tokenizer:

type: ngram

min_gram: 2

max_gram: 15

token_chars: [letter, digit]

filter:

allow_list_filter:

type: keep

keep_words:

- was

- WAS

```
### Data Types for Attributes

Specify Elasticsearch data types for your attributes in the `attributes`


section of the tenant configuration. You can also provide custom mappings
for each field.

#### Basic Attribute Configuration

```yaml

pimcore_ecommerce_framework:

index_service:

tenants:

MyEsTenant:

attributes:

name:

locale: '%%locale%%'

type: keyword

```

#### Custom Mappings

If you want to provide custom mappings for a field, you can add the
`mapping` configuration:

```yaml

pimcore_ecommerce_framework:

index_service:

tenants:
MyEsTenant:

attributes:

name:

locale: '%%locale%%'

type: text

options:

mapping:

type: text

store: true

index: not_analyzed

fields:

analyzed:

type: text

analyzer: german

analyzed_ngram:

type: text

analyzer: my_ngram_analyzer

```

### Sample Full Configuration

Here's a sample full configuration combining all aspects mentioned:

```yaml

pimcore_elasticsearch_client:

es_clients:

default:
hosts: ['http://elastic:9200']

username: 'elastic'

password: 'somethingsecret'

logger_channel: 'pimcore.elasticsearch'

pimcore_ecommerce_framework:

index_service:

tenants:

MyEsTenant:

worker_id: Pimcore\Bundle\EcommerceFrameworkBundle\
IndexService\Worker\ElasticSearch\DefaultElasticSearch8

config_id: Pimcore\Bundle\EcommerceFrameworkBundle\
IndexService\Config\ElasticSearch

config_options:

client_config:

logging: false

indexName: 'ecommerce-demo-elasticsearch'

es_client_name: default

index_settings:

number_of_shards: 5

number_of_replicas: 0

max_ngram_diff: 30

analysis:

analyzer:

my_ngram_analyzer:

tokenizer: my_ngram_tokenizer

allow_list_analyzer:

tokenizer: standard
filter:

- allow_list_filter

tokenizer:

my_ngram_tokenizer:

type: ngram

min_gram: 2

max_gram: 15

token_chars: [letter, digit]

filter:

allow_list_filter:

type: keep

keep_words:

- was

- WAS

attributes:

name:

locale: '%%locale%%'

type: text

options:

mapping:

type: text

store: true

index: not_analyzed

fields:

analyzed:

type: text

analyzer: german
analyzed_ngram:

type: text

analyzer: my_ngram_analyzer

```

### Additional Notes

- **Synonym Providers:** To specify synonym providers for synonym filters,


see the Synonyms documentation for more details.

- **Dynamic Mapping:** If you skip the type and mapping, Elasticsearch will
attempt to create dynamic mappings for your fields.

This comprehensive configuration guide should help you set up and optimize
Elasticsearch for use with the Pimcore E-Commerce Framework, ensuring you
leverage the full capabilities of Elasticsearch for efficient and scalable
product indexing and searching.

User

Synonyms

Synonyms

With elasticsearch so called synonym filters can be configured to further


optimize search behavior. For details see Synonym Token Filter and
following pages at elasticsearch documentation.

Pimcore provides an out-of-the box integration to provide synonyms for the


synonym filters of elasticsearch.

Synonym Providers

Synonym providers are symfony services that implement the


SynonymProviderInterface, load synonyms from a specific source and provide
it for using them in elasticsearch synonym filters.

Sources can be simple files, Pimcore assets, Pimcore data objects, database
tables or what ever source is needed. Pimcore ships with a simple
FileSynonymProvider that can be used right away. The synonym source is a
file (e.g. a Pimcore asset) that follows the Solr file format.

Besides the service configuration itself, the synonym providers need to be


configured in index service configuration as follows.

pimcore_ecommerce_framework:

index_service:

tenants:

<YOUR_ELASTIC_SEARCH_TENANT>:

enabled: true

worker_id: Pimcore\Bundle\EcommerceFrameworkBundle\
IndexService\Worker\ElasticSearch\DefaultElasticSearch8

config_id: Pimcore\Bundle\EcommerceFrameworkBundle\
IndexService\Config\ElasticSearch

config_options:

synonym_providers:

app_synonym_filter:

# service ID of synonym provider to use

provider_id: Pimcore\Bundle\
EcommerceFrameworkBundle\IndexService\SynonymProvider\FileSynonymProvider

# additional options for synonym provider (are


applied to a child-service instance of given synonym provider

options:

synonymFile:
'%kernel.project_dir%/public/var/assets/system/synonyms.txt'

Matching Synonym Providers to Synonym Filters


Matching between synonym providers and synonym filters in index settings
takes place via name. In the sample below there the synonym provider
app_synonym_filter provides the synonyms for the filter app_synonym_filter.

The filter definition in the index settings can hold just an empty array
(as some definition is required). During index building, index resetting or
reloading of synonyms, the synonyms are loaded from synonyms provider and
injected to the synonyms array of the corresponding synonyms filter.

pimcore_ecommerce_framework:

index_service:

tenants:

<YOUR_ELASTIC_SEARCH_TENANT>:

enabled: true

worker_id: Pimcore\Bundle\EcommerceFrameworkBundle\
IndexService\Worker\ElasticSearch\DefaultElasticSearch8

config_id: Pimcore\Bundle\EcommerceFrameworkBundle\
IndexService\Config\ElasticSearch

config_options:

synonym_providers:

app_synonym_filter:

# service ID of synonym provider to use

provider_id: Pimcore\Bundle\
EcommerceFrameworkBundle\IndexService\SynonymProvider\FileSynonymProvider

# additional options for synonym provider (are


applied to a child-service instance of given synonym provider

options:

synonymFile:
'%kernel.project_dir%/public/var/assets/system/synonyms.txt'

index_settings:
analysis:

filter:

app_synonym_filter: # mapping between


synonym_provider and filter based on name

type: synonym # or synonym_graph or any


other ES type

synonyms: [] # provide an empy array


here, for ES6 [], for ES5[""]

Don't forget to also add the synonyms filter to an analysers filter array
where needed - as described in elasticsearch docs.

Updating Synonyms

There are three ways of updating the synonyms in the elasticsearch index.
For all applies that the synonyms are loaded from synonyms provider and
injected to the synonyms array of the corresponding synonyms filter by
Pimcore.

Index Creation

During index creation the synonyms are loaded from synonym providers and
applied to index.

Reindex

During reindex the synonyms are loaded from synonym providers and applied
to index when new index is created.

This is the recommended way to update synonyms during runtime at a


production system as there is no service downtime.

Elasticsearch sync command


With the command bin/console ecommerce:indexservice:elasticsearch-sync
update-synonyms synonyms can be updated in the current index. For that, the
index has to be closed and reopened which means a short downtime of the
index.

ChatGPT

## Synonyms in Elasticsearch for Pimcore E-Commerce Framework

Synonyms in Elasticsearch help optimize search behavior by matching


different terms with similar meanings. Pimcore integrates this
functionality through synonym filters and synonym providers.

### Synonym Providers

Synonym providers in Pimcore are Symfony services that implement the


`SynonymProviderInterface`. They load synonyms from various sources, such
as files, assets, data objects, or databases, and provide them to
Elasticsearch synonym filters. Pimcore includes a `FileSynonymProvider` for
quick integration.

#### FileSynonymProvider Example

1. **Service Configuration**

Define the service for the synonym provider in your `services.yaml` or


configuration file:

```yaml

services:

app.synonym_provider.file:

class: Pimcore\Bundle\EcommerceFrameworkBundle\IndexService\
SynonymProvider\FileSynonymProvider
arguments:
['%kernel.project_dir%/public/var/assets/system/synonyms.txt']

```

2. **Index Service Configuration**

Configure the synonym provider in the `index_service` configuration:

```yaml

pimcore_ecommerce_framework:

index_service:

tenants:

MyEsTenant:

enabled: true

worker_id: Pimcore\Bundle\EcommerceFrameworkBundle\
IndexService\Worker\ElasticSearch\DefaultElasticSearch8

config_id: Pimcore\Bundle\EcommerceFrameworkBundle\
IndexService\Config\ElasticSearch

config_options:

synonym_providers:

app_synonym_filter:

provider_id: app.synonym_provider.file

options:

synonymFile:
'%kernel.project_dir%/public/var/assets/system/synonyms.txt'

```

### Matching Synonym Providers to Synonym Filters


Synonym providers and synonym filters are matched by name. The following
example shows how to match a synonym provider to a synonym filter in
Elasticsearch index settings.

#### Example Configuration

1. **Index Service Configuration with Synonym Provider**

```yaml

pimcore_ecommerce_framework:

index_service:

tenants:

MyEsTenant:

enabled: true

worker_id: Pimcore\Bundle\EcommerceFrameworkBundle\
IndexService\Worker\ElasticSearch\DefaultElasticSearch8

config_id: Pimcore\Bundle\EcommerceFrameworkBundle\
IndexService\Config\ElasticSearch

config_options:

synonym_providers:

app_synonym_filter:

provider_id: Pimcore\Bundle\
EcommerceFrameworkBundle\IndexService\SynonymProvider\FileSynonymProvider

options:

synonymFile:
'%kernel.project_dir%/public/var/assets/system/synonyms.txt'

index_settings:

analysis:

filter:

app_synonym_filter:
type: synonym

synonyms: [] # Provide an empty


array here

```

2. **Add Synonyms Filter to Analyzer's Filter Array**

Update the `analysis` section to include the synonyms filter in the


appropriate analyzers:

```yaml

pimcore_ecommerce_framework:

index_service:

tenants:

MyEsTenant:

config_options:

index_settings:

analysis:

analyzer:

my_custom_analyzer:

type: custom

tokenizer: standard

filter:

- lowercase

- app_synonym_filter

```

### Updating Synonyms


#### Index Creation

During index creation, synonyms are loaded from synonym providers and
applied to the index.

#### Reindex

During a reindex, synonyms are updated from the synonym providers and
applied to the new index. This approach is recommended for updating
synonyms in a production environment without downtime.

#### Elasticsearch Sync Command

To update synonyms in the current index, use the following command. This
requires closing and reopening the index, resulting in a short downtime.

```bash

php bin/console ecommerce:indexservice:elasticsearch-sync update-synonyms

```

### Summary

Integrating synonyms in Elasticsearch within the Pimcore E-Commerce


Framework involves configuring synonym providers, matching them with
synonym filters, and updating the index as necessary. By following these
steps, you can enhance search capabilities and provide a more robust search
experience for users.

### Complete Example


```yaml

pimcore_elasticsearch_client:

es_clients:

default:

hosts: ['http://elastic:9200']

username: 'elastic'

password: 'somethingsecret'

logger_channel: 'pimcore.elasticsearch'

pimcore_ecommerce_framework:

index_service:

tenants:

MyEsTenant:

enabled: true

worker_id: Pimcore\Bundle\EcommerceFrameworkBundle\
IndexService\Worker\ElasticSearch\DefaultElasticSearch8

config_id: Pimcore\Bundle\EcommerceFrameworkBundle\
IndexService\Config\ElasticSearch

config_options:

synonym_providers:

app_synonym_filter:

provider_id: Pimcore\Bundle\
EcommerceFrameworkBundle\IndexService\SynonymProvider\FileSynonymProvider

options:

synonymFile:
'%kernel.project_dir%/public/var/assets/system/synonyms.txt'

es_client_name: default

index_settings:

number_of_shards: 5
number_of_replicas: 0

max_ngram_diff: 30

analysis:

analyzer:

my_custom_analyzer:

type: custom

tokenizer: standard

filter:

- lowercase

- app_synonym_filter

filter:

app_synonym_filter:

type: synonym

synonyms: []

attributes:

name:

locale: '%%locale%%'

type: text

options:

mapping:

type: text

store: true

index: not_analyzed

fields:

analyzed:

type: text

analyzer: standard
analyzed_ngram:

type: text

analyzer: my_custom_analyzer

```

This configuration ensures that synonyms are properly integrated and


utilized within Elasticsearch, enhancing the search functionality of your
Pimcore E-Commerce Framework.

User

Special Aspects for Findologic Exporter

Basically findologic worker works as described in the optimized


architecture. But there is an additional speciality with the export:

Executing php bin/console ecommerce:indexservice:process-update-queue does


not write the data directly to Findologic, but into an extra table \
Pimcore\Bundle\EcommerceFrameworkBundle\IndexService\Worker\
DefaultFindologic::EXPORT_TABLE_NAME (default is
ecommerceframework_productindex_export_findologic).

Findologic then can use the endpoint /ecommerceframework/findologic-export,


which delivers all data directly based on the export table. Valid
parameters for this endpoint are:

start: Pagination start.

count: Count of delivered entries.

shopKey: Shop key to identify the shop.

id: Filter for Product-ID

type: Filter for type

ChatGPT

## Special Aspects for Findologic Exporter


When using the Findologic exporter with Pimcore's E-Commerce Framework,
there are additional specifics to consider, especially regarding data
export and endpoint integration.

### Overview

The Findologic worker operates under the optimized architecture but


includes a unique export process. Instead of writing data directly to
Findologic, the data is written to an extra table. Findologic can then
fetch the data from this table using a dedicated endpoint.

### Key Points

1. **Data Export to Findologic Table:**

- When you execute the command to process the update queue, data is not
sent directly to Findologic.

- Instead, data is written to an export table defined by


`DefaultFindologic::EXPORT_TABLE_NAME` (default is
`ecommerceframework_productindex_export_findologic`).

2. **Findologic Data Fetching Endpoint:**

- Findologic uses the endpoint `/ecommerceframework/findologic-export`


to fetch data directly from the export table.

- The endpoint supports several parameters for data filtering and


pagination.

### Endpoint Parameters

- **`start`:** The starting point for pagination.

- **`count`:** The number of entries to deliver.

- **`shopKey`:** The shop key to identify the shop.

- **`id`:** Filter based on Product ID.


- **`type`:** Filter based on the type.

### Example Configuration

#### Configuring the Findologic Exporter

1. **Tenant Configuration:**

```yaml

pimcore_ecommerce_framework:

index_service:

tenants:

MyFindologicTenant:

enabled: true

worker_id: Pimcore\Bundle\EcommerceFrameworkBundle\
IndexService\Worker\DefaultFindologic

config_id: Pimcore\Bundle\EcommerceFrameworkBundle\
IndexService\Config\Findologic

config_options:

export_table_name:
ecommerceframework_productindex_export_findologic

# Additional configuration options can be added here

attributes:

name:

type: text

price:

type: float

description:
type: text

```

2. **Running Commands:**

- **Process the Update Queue:**

```bash

php bin/console ecommerce:indexservice:process-update-queue

```

- **Create or Update Index Structures:**

```bash

php bin/console ecommerce:indexservice:bootstrap --create-or-update-


index-structure

```

- **Manually Update All Pimcore Objects in the Index Store:**

```bash

php bin/console ecommerce:indexservice:bootstrap --update-index

```

### Fetching Data from the Export Table

Findologic can fetch data using the following endpoint:

**Endpoint URL:**

```
/ecommerceframework/findologic-export

```

**Example Request:**

```

GET /ecommerceframework/findologic-export?
start=0&count=100&shopKey=myShopKey

```

**Parameters:**

- **`start`:** (integer) The starting point for pagination (e.g., 0).

- **`count`:** (integer) The number of entries to return (e.g., 100).

- **`shopKey`:** (string) The key identifying the shop (e.g., myShopKey).

- **`id`:** (integer, optional) Filter results by Product ID.

- **`type`:** (string, optional) Filter results by type.

### Example Workflow

1. **Update the Export Table:**

Run the update queue command to ensure the export table is populated
with the latest product data.

```bash

php bin/console ecommerce:indexservice:process-update-queue

```

2. **Findologic Fetches Data:**

Findologic sends a request to the export endpoint to fetch the updated


product data.
```http

GET /ecommerceframework/findologic-export?
start=0&count=100&shopKey=myShopKey

```

### Summary

By configuring the Findologic exporter in Pimcore's E-Commerce Framework,


you can efficiently manage product data export to Findologic. The process
involves writing data to an intermediate export table and providing an
endpoint for Findologic to fetch this data. This setup ensures a seamless
integration and efficient data handling for your e-commerce needs.

User

Product List

Working with Product Lists

The API for getting (and filtering, ...) products out of the Product Index
are so called Product Lists. They all implement the interface \Pimcore\
Bundle\EcommerceFrameworkBundle\IndexService\ProductList\
ProductListInterface and need to be Product Index implementation specific.
Detailed method documentation is available in in-source documentation.

For how to get a Product List instance suitable for the current Product
Index implementation and filter for products see following code sample:

<?php

$list = \Pimcore\Bundle\EcommerceFrameworkBundle\Factory::getInstance()-
>getIndexService()->getProductListForCurrentTenant();

$list->addCondition("name = 'testproduct'", 'name');

$list->addRelationCondition('category', "dest IN (1024,1025,1026)");

$list->setOrder("ASC");

$list->setOrderKey('name');

$list->load();
All filtered attributes need to be in the Product Index. The Product List
implements all iterator and paginator interfaces and can be used in foreach
loops and in combination with Knp\Paginator.

For logging standard Symfony logging is used. E-Commerce Framework Product


Indices log into special channels like pimcore_ecommerce_indexupdater,
pimcore_ecommerce_sql, pimcore_ecommerce_es and
pimcore_ecommerce_findologic.

ChatGPT

## Working with Product Lists in Pimcore E-Commerce Framework

The API for retrieving and filtering products from the Product Index in
Pimcore is handled through Product Lists. These lists are specific to the
Product Index implementation and adhere to the `ProductListInterface`.

### Getting and Filtering Products

To obtain a Product List instance that is suitable for the current Product
Index implementation and to filter products, follow the example below:

### Code Sample

```php

<?php

use Pimcore\Bundle\EcommerceFrameworkBundle\Factory;

// Get a Product List instance for the current tenant

$list = Factory::getInstance()->getIndexService()-
>getProductListForCurrentTenant();
// Add conditions to filter products

$list->addCondition("name = 'testproduct'", 'name');

$list->addRelationCondition('category', "dest IN (1024,1025,1026)");

// Set ordering

$list->setOrder("ASC");

$list->setOrderKey('name');

// Load the filtered product list

$products = $list->load();

```

### Explanation of Code

- **Get Product List Instance:**

```php

$list = Factory::getInstance()->getIndexService()-
>getProductListForCurrentTenant();

```

This method retrieves a Product List instance suitable for the current
tenant's Product Index implementation.

- **Add Conditions:**

```php

$list->addCondition("name = 'testproduct'", 'name');

$list->addRelationCondition('category', "dest IN (1024,1025,1026)");

```
Conditions are added to filter the products based on specific attributes.
The attributes need to be part of the Product Index.

- **Set Order:**

```php

$list->setOrder("ASC");

$list->setOrderKey('name');

```

Define the order and the key to order by.

- **Load Products:**

```php

$products = $list->load();

```

Load the products that match the specified conditions and ordering.

### Attributes in Product Index

All attributes used for filtering must be included in the Product Index.
Ensure that these attributes are configured appropriately in your Product
Index configuration.

### Using Product Lists with Iterators and Paginators

Product Lists in Pimcore implement iterator and paginator interfaces,


making them compatible with foreach loops and pagination libraries like
`Knp\Paginator`.

### Example with Foreach Loop


```php

<?php

foreach ($list as $product) {

echo $product->getName();

```

### Example with Knp\Paginator

```php

<?php

use Knp\Component\Pager\PaginatorInterface;

// Assuming $paginator is an instance of KnpPaginator

$pagination = $paginator->paginate(

$list, /* query NOT result */

$request->query->getInt('page', 1), /* page number */

10 /* limit per page */

);

```

### Logging

Pimcore's E-Commerce Framework uses standard Symfony logging. Product


Indices log into specific channels, such as:
- `pimcore_ecommerce_indexupdater`

- `pimcore_ecommerce_sql`

- `pimcore_ecommerce_es`

- `pimcore_ecommerce_findologic`

These logs can help you monitor and debug the indexing and retrieval
processes.

### Summary

By using Product Lists, you can effectively retrieve and filter products
from the Product Index in Pimcore. The example code provided demonstrates
how to obtain a Product List instance, apply filters, set ordering, and
load the products. Additionally, Product Lists support iterators and
pagination, facilitating smooth integration with UI components. Logging
through specific channels ensures that you can track the indexing and
retrieval processes for effective debugging and monitoring.

User

Mockup Objects in Product List Results

Normally the result of Product Lists contain Pimcore product objects. When
retrieving lists with many entries this can result in performance issues
during rendering product listings - especially on high traffic applications
when Pimcore product objects are very complex, heavily use content
inheritance and have lots of relations.

To address this issue, Product Lists can return so called Mockup objects
instead of the original Pimcore product objects. The idea is that these
Mockup objects are a lightweight a selection of the product data, therefore
are much smaller and load faster.

By default the optimized product index implementations of the E-Commerce


Framework support Mockup objects in a transparent way and you can take
advantage from the faster loading times.

This means that the corresponding product lists return Mockup objects which
contain all data that is stored into the product index. If a getter is
called on the Mockup object (e.g. $product->getName()), it first tries to
get the requested data from the index data. If the data is not available,
the call is delegated to the original Pimcore object. Then the call is
delegated, following log message is written to Pimcore log files - if
system is in debug mode as WARN, otherwise as INFO.

"Method $method not in Mockup implemented, delegating to object with id


{$this->id}."

So, the only thing you need to take care about: make sure that all the data
that is printed in product listing is available in the product index.

Using Custom Mockup Object Implementation

Of course, it might be necessary to use custom Mockup implementations. To


do you, overwrite the createMockupObject($objectId, $data, $relations)
method in your Config implementation. For an example see MyOptimizedMysql
in the Demo.

ChatGPT

## Mockup Objects in Product List Results

When dealing with high traffic applications and complex Pimcore product
objects, performance issues can arise, especially during product listing
rendering. To address this, Pimcore's E-Commerce Framework supports the use
of Mockup objects in product lists. These lightweight objects improve
performance by loading faster and containing only a selection of product
data.

### How Mockup Objects Work

- **Transparent Integration:** The optimized product index implementations


in Pimcore E-Commerce Framework support Mockup objects by default.

- **Data Retrieval:** Mockup objects attempt to retrieve requested data


from the index. If the data is not available, the call is delegated to the
original Pimcore product object.

- **Logging:** If a method is not implemented in the Mockup object and the


call is delegated to the original object, a log message is written. In
debug mode, this is logged as WARN; otherwise, it is logged as INFO:
```

"Method $method not in Mockup implemented, delegating to object with id


{$this->id}."

```

### Example Code for Using Mockup Objects

Here's an example of how to work with Product Lists that return Mockup
objects:

```php

<?php

use Pimcore\Bundle\EcommerceFrameworkBundle\Factory;

// Get a Product List instance for the current tenant

$list = Factory::getInstance()->getIndexService()-
>getProductListForCurrentTenant();

// Add conditions to filter products

$list->addCondition("name = 'testproduct'", 'name');

$list->addRelationCondition('category', "dest IN (1024,1025,1026)");

// Set ordering

$list->setOrder("ASC");

$list->setOrderKey('name');

// Load the filtered product list

$products = $list->load();
// Iterate through the products

foreach ($products as $product) {

// Using a getter on a Mockup object

echo $product->getName();

```

### Custom Mockup Object Implementation

In some cases, you might need to use custom Mockup implementations. To do


this, you need to overwrite the `createMockupObject($objectId, $data,
$relations)` method in your Config implementation.

#### Example Custom Mockup Implementation

1. **Create Custom Mockup Class:**

```php

namespace App\Ecommerce\Mockup;

use Pimcore\Bundle\EcommerceFrameworkBundle\IndexService\MockupObject;

class CustomMockupObject extends MockupObject

public function getCustomData()

return $this->data['customData'] ?? null;


}

```

2. **Overwrite `createMockupObject` Method:**

```php

namespace App\Ecommerce\Config;

use Pimcore\Bundle\EcommerceFrameworkBundle\IndexService\Config\
OptimizedMysql;

class MyOptimizedMysql extends OptimizedMysql

protected function createMockupObject($objectId, $data, $relations)

return new \App\Ecommerce\Mockup\CustomMockupObject($objectId,


$data, $relations);

```

3. **Configure the Custom Implementation:**

```yaml

pimcore_ecommerce_framework:

index_service:

tenants:
MyOptimizedTenant:

enabled: true

worker_id: Pimcore\Bundle\EcommerceFrameworkBundle\
IndexService\Worker\OptimizedMysql

config_id: App\Ecommerce\Config\MyOptimizedMysql

config_options: []

attributes:

name:

type: text

customData:

type: keyword

```

### Ensuring Data Availability in Product Index

To ensure that Mockup objects function correctly, make sure that all the
data needed for product listings is available in the product index. Define
the necessary attributes in the product index configuration.

### Summary

Mockup objects provide a lightweight and efficient way to handle product


listings in high traffic and complex applications. By implementing Mockup
objects, you can improve performance and ensure faster data retrieval. For
custom needs, you can create and configure custom Mockup objects to handle
specific data requirements.

User

Filter Service

Basic Idea of the Filter Service

The Filter Service supports the developers in setting up E-Commerce product


listings with filters and layered navigation known from classic shop
systems. Therefore it provides functionality to ...
... configure available filters and to set up the product listings in the
frontend.

... generating the necessary filter conditions for the Product Index based
on the filter type and user input.

... printing out the configured filter with possible filter values etc. to
the frontend.

To provide this functionality, a few components are necessary. The Filter


Service links all these components together and provides the developer a
clean API for creating product listings in the frontend.

1 - Setting up Filter Types

Each product listing has different filters like drop downs, multi selects,
input fields, number ranges, etc. Each of these Filter Types require

special configuration

special presentation in the view

special filter conditions for the Product Index

The Filter Types are responsible for these three tasks and can be used for
composing filter definition objects (see next chapter).

The backend implementation of Filter Types takes place in php classes which
extend the abstract class \Pimcore\Bundle\EcommerceFrameworkBundle\
FilterService\FilterType\AbstractFilterType and are responsible for
creating the correct filter conditions based on the Product Index
implementation and rendering the filter output to the frontend.

Therefore \Pimcore\Bundle\EcommerceFrameworkBundle\FilterService\
FilterType\AbstractFilterType expects the two methods getFilterValues() and
addCondition() to be implemented.

Each Filter Type needs to be defined as service and registered on the


pimcore_ecommerce_framework.filter_service configuration. The framework
already defines a number of core filter types in
filter_service_filter_types.yaml.
FilterTypes are dependent of the used index backend. You need to use
different FilterTypes when using MySQL or ElasticSearch etc. Pimcore ships
with FilterTypes implementations for all supported index backends. For
details see for example Elasticsearch Config.

pimcore_ecommerce_framework:

filter_service:

tenants:

default:

# assign backend implementations and views to filter type


field collections

filter_types:

# filter type for the FilterNumberRange field


collection

FilterNumberRange:

# service id for filter type implementation

filter_type_id: Pimcore\Bundle\
EcommerceFrameworkBundle\FilterService\FilterType\NumberRange

# default template for filter, can be overwritten


in filter definition

template: ':Shop/filters:range.html.php'

FilterNumberRangeSelection:

filter_type_id: Pimcore\Bundle\
EcommerceFrameworkBundle\FilterService\FilterType\NumberRangeSelection

template: ':Shop/filters:numberrange.html.php'

FilterSelect:

filter_type_id: Pimcore\Bundle\
EcommerceFrameworkBundle\FilterService\FilterType\Select

template: ':Shop/filters:select.html.php'
FilterSelectFromMultiSelect:

filter_type_id: Pimcore\Bundle\
EcommerceFrameworkBundle\FilterService\FilterType\SelectFromMultiSelect

template: ':Shop/filters:select.html.php'

FilterMultiSelect:

filter_type_id: Pimcore\Bundle\
EcommerceFrameworkBundle\FilterService\FilterType\MultiSelect

template: ':Shop/filters:multiselect.html.php'

FilterMultiSelectFromMultiSelect:

filter_type_id: Pimcore\Bundle\
EcommerceFrameworkBundle\FilterService\FilterType\
MultiSelectFromMultiSelect

template: ':Shop/filters:multiselect.html.php'

FilterMultiRelation:

filter_type_id: Pimcore\Bundle\
EcommerceFrameworkBundle\FilterService\FilterType\MultiSelectRelation

template: ':Shop/filters:multiselect-
relation.html.php'

FilterCategory:

filter_type_id: Pimcore\Bundle\
EcommerceFrameworkBundle\FilterService\FilterType\SelectCategory

template: ':Shop/filters:select_category.html.php'

FilterRelation:

filter_type_id: Pimcore\Bundle\
EcommerceFrameworkBundle\FilterService\FilterType\SelectRelation
template: ':Shop/filters:object_relation.html.php'

Optionally, you can configure a custom filter service which relies on a


custom helper implementation. The helper is a tool for the Pimcore backend
controller to get possible group by values for a certain field (used by
object data type IndexFieldSelection, e.g. in filter definitions). First,
create your filter service definition:

services:

app.custom_filter_service:

class: Pimcore\Bundle\EcommerceFrameworkBundle\FilterService\
FilterService

arguments:

- '@Pimcore\Bundle\EcommerceFrameworkBundle\FilterService\
FilterGroupHelper'

You can now use the service definition in the filter_service config:

pimcore_ecommerce_framework:

filter_service:

tenants:

default:

service_id: app.custom_filter_service

filter_types:

# ...

Configuration elements are:


FilterCategory: The key of the array represents the field collection type
(= name of field collection) for configuration in filter definition objects
(see next chapter).

class: Backend implementation of the filter type.

script: Default view script of the filter type, can be overwritten in the
filter definition objects. You can find some script filter examples in the
Demo here.

Helper: Is a helper implementation that gets available values for pre


select settings in the filter definition objects based on the filter group
setting in the index attributes definition.

2 - Setting up FilterDefinition Objects

The configuration of available filters and the set up of product listings


in the frontend takes place in FilterDefinition Pimcore objects.
Configuration options are beside others:

General settings like page size etc.

PreConditions for pre filtering of products, e.g. only products of a


certain category. These preconditions cannot be changed by the user in the
frontend.

Filters that are visible in the frontend.

FilterDefinition

The configuration of preconditions and filters is done by field collection


entries, whereby the field collection types are mapped to Filter Types and
their backend implementations in the
pimcore_ecommerce_framework.filter_service config section (see previous
chapter). The Filter Definition class can be extended and modified to
custom needs of the system.

Filter Definition objects can be assigned to category objects to build up


automatic category pages or to area bricks in Pimcore documents to set up
manual landing pages etc. Both is demonstrated at our Demo and also
available as source code.
In case that a filter contains relational objects (FilterMultiRelation,
FilterRelation, etc.), the getName() method of the object is used to render
the text in pre-select lists and filters. Implement the
getNameForFilterDefinition() method in your data objects to show customized
(HTML) texts, including icons.

3 - Putting it all together

Once Filter Types and Filter Definitions are set up, it is quite easy to
put it all together and use the Filter Service in controller actions.

Controller

For setting up the Filter Service (including Product List with Knp\
Paginator) within the controller use following sample:

<?php

$ecommerceFactory = \Pimcore\Bundle\EcommerceFrameworkBundle\
Factory::getInstance();

$templateParams = [];

$params = array_merge($request->query->all(), $request->attributes->all());

$indexService = $ecommerceFactory->getIndexService();

$productListing = $indexService->getProductListForCurrentTenant();

$templateParams['productListing'] = $productListing;

//get filter definition from document, category or global settings

$filterDefinition = //TODO ...get from somewhere;

// create and init filter service

$filterService = $ecommerceFactory->getFilterService();
(new \Pimcore\Bundle\EcommerceFrameworkBundle\FilterService\ListHelper)-
>setupProductList($filterDefinition, $productListing, $params,
$filterService, true, true);

$templateParams['filterService'] = $filterService;

$templateParams['filterDefinition'] = $filterDefinition;

// inject and use Knp Paginator service: PaginatorInterface $paginator

$paginator = $paginator->paginate(

$productListing,

$request->get('page', 1),

18

);

$templateParams['results'] = $paginator;

$templateParams['paginationVariables'] = $paginator->getPaginationData();

return $this->render('Path/template.html.twig', $templateParams);

For a sample of a controller see our demo here.

View

For putting all filters to the frontend use following sample. It is


important that this sample is inside a form in order to get the parameter
of changed filters delivered back to the controller.

{% if(filterDefinition.filters|length > 0) %}

{% for filter in filterDefinition.filters %}

{% set filterMarkup = filterService.filterFrontend(filter,


productListing, currentFilter) %}
{{ filterMarkup | raw }}

{% endfor %}

{% endif %}

ChatGPT

## Filter Service in Pimcore E-Commerce Framework

The Filter Service in Pimcore's E-Commerce Framework helps developers


create E-Commerce product listings with filters and layered navigation.
This guide explains how to set up and use the Filter Service effectively.

### 1. Setting up Filter Types

Filter types define the types of filters used in product listings, such as
dropdowns, multi-selects, input fields, and number ranges. Each filter type
requires special configuration, presentation, and filter conditions.

#### Configuration Example

Define filter types in the `pimcore_ecommerce_framework.filter_service`


configuration:

```yaml

pimcore_ecommerce_framework:

filter_service:

tenants:

default:

filter_types:
FilterNumberRange:

filter_type_id: Pimcore\Bundle\
EcommerceFrameworkBundle\FilterService\FilterType\NumberRange

template: ':Shop/filters:range.html.php'

FilterSelect:

filter_type_id: Pimcore\Bundle\
EcommerceFrameworkBundle\FilterService\FilterType\Select

template: ':Shop/filters:select.html.php'

```

#### Custom Filter Service

To configure a custom filter service, create a service definition and use


it in the filter service configuration:

```yaml

services:

app.custom_filter_service:

class: Pimcore\Bundle\EcommerceFrameworkBundle\FilterService\
FilterService

arguments:

- '@Pimcore\Bundle\EcommerceFrameworkBundle\FilterService\
FilterGroupHelper'

pimcore_ecommerce_framework:

filter_service:

tenants:

default:

service_id: app.custom_filter_service
filter_types:

# Define your filter types here

```

### 2. Setting up FilterDefinition Objects

FilterDefinition objects configure available filters and set up product


listings in the frontend. These objects can include general settings,
preconditions, and visible filters.

#### Example FilterDefinition Configuration

Create FilterDefinition objects in Pimcore and map them to filter types in


your configuration:

```yaml

pimcore_ecommerce_framework:

filter_service:

tenants:

default:

filter_types:

FilterNumberRange:

filter_type_id: Pimcore\Bundle\
EcommerceFrameworkBundle\FilterService\FilterType\NumberRange

template: ':Shop/filters:range.html.php'

```

Assign FilterDefinition objects to category objects for automatic category


pages or to area bricks in Pimcore documents for manual landing pages.
### 3. Putting it All Together

Integrate the Filter Service with your controllers and views to create
dynamic product listings.

#### Controller Setup

Here's an example of setting up the Filter Service within a controller:

```php

<?php

use Pimcore\Bundle\EcommerceFrameworkBundle\Factory;

use Pimcore\Bundle\EcommerceFrameworkBundle\FilterService\ListHelper;

use Knp\Component\Pager\PaginatorInterface;

use Symfony\Component\HttpFoundation\Request;

// Controller action

public function productListAction(Request $request, PaginatorInterface


$paginator)

$ecommerceFactory = Factory::getInstance();

$templateParams = [];

$params = array_merge($request->query->all(), $request->attributes-


>all());

$indexService = $ecommerceFactory->getIndexService();

$productListing = $indexService->getProductListForCurrentTenant();
$templateParams['productListing'] = $productListing;

// Get filter definition from document, category or global settings

$filterDefinition = // TODO: Retrieve the filter definition

// Create and init filter service

$filterService = $ecommerceFactory->getFilterService();

(new ListHelper())->setupProductList($filterDefinition,
$productListing, $params, $filterService, true, true);

$templateParams['filterService'] = $filterService;

$templateParams['filterDefinition'] = $filterDefinition;

// Inject and use Knp Paginator service

$pagination = $paginator->paginate(

$productListing,

$request->get('page', 1),

18

);

$templateParams['results'] = $pagination;

$templateParams['paginationVariables'] = $pagination-
>getPaginationData();

return $this->render('Path/template.html.twig', $templateParams);

```

#### View Setup


Render filters in the frontend:

```twig

<form method="get" action="{{ path('your_route') }}">

{% if filterDefinition.filters|length > 0 %}

{% for filter in filterDefinition.filters %}

{% set filterMarkup = filterService.filterFrontend(filter,


productListing, currentFilter) %}

{{ filterMarkup | raw }}

{% endfor %}

{% endif %}

<button type="submit">Apply Filters</button>

</form>

```

### Conclusion

By setting up filter types, configuring FilterDefinition objects, and


integrating the Filter Service in controllers and views, you can create
powerful, dynamic product listings with layered navigation in Pimcore's E-
Commerce Framework. This approach ensures efficient filtering and better
user experience for your e-commerce application.

User

Filter Service with Elasticsearch

Definition of Filter Types

When using elasticsearch as Product Index, different FilterTypes must be


configured for the corresponding tenant. These filter types create the
elasticsearch specific conditions for each filter.

Here is an example for the configuration:


pimcore_ecommerce_framework:

filter_service:

tenants:

ElasticSearch:

filter_types:

FilterNumberRange:

# Service id for filter type implementation

filter_type_id: Pimcore\Bundle\
EcommerceFrameworkBundle\FilterService\FilterType\ElasticSearch\NumberRange

# Default template for filter, can be overwritten


in filter definition

template: ':Shop/filters:range.html.php'

FilterNumberRangeSelection:

filter_type_id: Pimcore\Bundle\
EcommerceFrameworkBundle\FilterService\FilterType\ElasticSearch\
NumberRangeSelection

template: ':Shop/filters:numberrange.html.php'

FilterSelect:

filter_type_id: Pimcore\Bundle\
EcommerceFrameworkBundle\FilterService\FilterType\ElasticSearch\Select

template: ':Shop/filters:select.html.php'

FilterSelectFromMultiSelect:

filter_type_id: Pimcore\Bundle\
EcommerceFrameworkBundle\FilterService\FilterType\ElasticSearch\
SelectFromMultiSelect

template: ':Shop/filters:select.html.php'

FilterMultiSelect:
filter_type_id: Pimcore\Bundle\
EcommerceFrameworkBundle\FilterService\FilterType\ElasticSearch\MultiSelect

template: ':Shop/filters:multiselect.html.php'

FilterMultiSelectFromMultiSelect:

filter_type_id: Pimcore\Bundle\
EcommerceFrameworkBundle\FilterService\FilterType\ElasticSearch\
MultiSelectFromMultiSelect

template: ':Shop/filters:multiselect.html.php'

FilterMultiRelation:

filter_type_id: Pimcore\Bundle\
EcommerceFrameworkBundle\FilterService\FilterType\ElasticSearch\
MultiSelectRelation

template: ':Shop/filters:multiselect-
relation.html.php'

FilterCategory:

filter_type_id: Pimcore\Bundle\
EcommerceFrameworkBundle\FilterService\FilterType\ElasticSearch\
SelectCategory

template: ':Shop/filters:select_category.html.php'

FilterRelation:

filter_type_id: Pimcore\Bundle\
EcommerceFrameworkBundle\FilterService\FilterType\ElasticSearch\
SelectRelation

template: ':Shop/filters:object_relation.html.php'

Filtering for Classification Store Attributes

With the document structure of elasticsearch it is easily possible to index


and filter for classification store attributes without defining them all
als separate attributes in the index definition. See Filter Classification
Store for details.

Filtering for Nested Documents in General

For information how to take leverage of the nested documents feature for
elasticsearch and make even more sophisticated search queries, have a look
at Filter Nested Documents.

ChatGPT

## Filter Service with Elasticsearch in Pimcore E-Commerce Framework

When using Elasticsearch as the Product Index in Pimcore's E-Commerce


Framework, you need to configure specific filter types for the
Elasticsearch tenant. These filter types create Elasticsearch-specific
conditions for each filter, allowing for powerful and optimized product
filtering.

### Configuring Filter Types for Elasticsearch

To configure filter types for Elasticsearch, define them in the


`pimcore_ecommerce_framework.filter_service` configuration section for the
Elasticsearch tenant.

### Example Configuration

Here's an example configuration for defining various filter types for an


Elasticsearch tenant:

```yaml

pimcore_ecommerce_framework:

filter_service:

tenants:

ElasticSearch:
filter_types:

FilterNumberRange:

filter_type_id: Pimcore\Bundle\
EcommerceFrameworkBundle\FilterService\FilterType\ElasticSearch\NumberRange

template: ':Shop/filters:range.html.php'

FilterNumberRangeSelection:

filter_type_id: Pimcore\Bundle\
EcommerceFrameworkBundle\FilterService\FilterType\ElasticSearch\
NumberRangeSelection

template: ':Shop/filters:numberrange.html.php'

FilterSelect:

filter_type_id: Pimcore\Bundle\
EcommerceFrameworkBundle\FilterService\FilterType\ElasticSearch\Select

template: ':Shop/filters:select.html.php'

FilterSelectFromMultiSelect:

filter_type_id: Pimcore\Bundle\
EcommerceFrameworkBundle\FilterService\FilterType\ElasticSearch\
SelectFromMultiSelect

template: ':Shop/filters:select.html.php'

FilterMultiSelect:

filter_type_id: Pimcore\Bundle\
EcommerceFrameworkBundle\FilterService\FilterType\ElasticSearch\MultiSelect

template: ':Shop/filters:multiselect.html.php'

FilterMultiSelectFromMultiSelect:

filter_type_id: Pimcore\Bundle\
EcommerceFrameworkBundle\FilterService\FilterType\ElasticSearch\
MultiSelectFromMultiSelect

template: ':Shop/filters:multiselect.html.php'

FilterMultiRelation:

filter_type_id: Pimcore\Bundle\
EcommerceFrameworkBundle\FilterService\FilterType\ElasticSearch\
MultiSelectRelation
template: ':Shop/filters:multiselect-
relation.html.php'

FilterCategory:

filter_type_id: Pimcore\Bundle\
EcommerceFrameworkBundle\FilterService\FilterType\ElasticSearch\
SelectCategory

template: ':Shop/filters:select_category.html.php'

FilterRelation:

filter_type_id: Pimcore\Bundle\
EcommerceFrameworkBundle\FilterService\FilterType\ElasticSearch\
SelectRelation

template: ':Shop/filters:object_relation.html.php'

```

### Filtering for Classification Store Attributes

Elasticsearch allows for efficient indexing and filtering of classification


store attributes without needing to define each attribute separately in the
index definition. This flexibility enables you to work with complex product
data more effectively.

### Filtering for Nested Documents

Elasticsearch's nested documents feature allows for sophisticated search


queries, enabling you to perform complex filtering operations on nested
objects within your product data. This can be particularly useful for
filtering on attributes within nested documents.

### Implementing Filter Service in Controller and View

To use the Filter Service in your controller and view, follow the steps
below:
#### Controller Setup

1. **Initialize the Filter Service:**

```php

<?php

use Pimcore\Bundle\EcommerceFrameworkBundle\Factory;

use Pimcore\Bundle\EcommerceFrameworkBundle\FilterService\ListHelper;

use Knp\Component\Pager\PaginatorInterface;

use Symfony\Component\HttpFoundation\Request;

// Controller action

public function productListAction(Request $request, PaginatorInterface


$paginator)

$ecommerceFactory = Factory::getInstance();

$templateParams = [];

$params = array_merge($request->query->all(), $request->attributes-


>all());

$indexService = $ecommerceFactory->getIndexService();

$productListing = $indexService->getProductListForCurrentTenant();

$templateParams['productListing'] = $productListing;

// Get filter definition from document, category, or global


settings

$filterDefinition = // TODO: Retrieve the filter definition


// Create and init filter service

$filterService = $ecommerceFactory->getFilterService();

(new ListHelper())->setupProductList($filterDefinition,
$productListing, $params, $filterService, true, true);

$templateParams['filterService'] = $filterService;

$templateParams['filterDefinition'] = $filterDefinition;

// Inject and use Knp Paginator service

$pagination = $paginator->paginate(

$productListing,

$request->get('page', 1),

18

);

$templateParams['results'] = $pagination;

$templateParams['paginationVariables'] = $pagination-
>getPaginationData();

return $this->render('Path/template.html.twig', $templateParams);

```

#### View Setup

2. **Render Filters in the Frontend:**

```twig

<form method="get" action="{{ path('your_route') }}">

{% if filterDefinition.filters|length > 0 %}
{% for filter in filterDefinition.filters %}

{% set filterMarkup = filterService.filterFrontend(filter,


productListing, currentFilter) %}

{{ filterMarkup | raw }}

{% endfor %}

{% endif %}

<button type="submit">Apply Filters</button>

</form>

```

### Summary

By configuring specific filter types for Elasticsearch in the Pimcore E-


Commerce Framework, you can leverage the powerful indexing and search
capabilities of Elasticsearch. This setup allows for efficient and dynamic
product filtering, enhancing the user experience in your e-commerce
application. Be sure to define your filter types and integrate the Filter
Service properly in both the controller and the view to achieve optimal
results.

User

Filter Classification Store

With elasticsearch it is possible to index all attributes of Classification


Store data without defining an attribute for each single classification
store key.

To do so, follow these steps

1) Index Definition

Pimcore ships with a special interpreter to load all classification store


attributes to the index. To use this interpreter add following attribute
configuration into your index definition:

some_field_name:
fieldname: 'my_classification_store_field_name'

interpreter: Pimcore\Bundle\EcommerceFrameworkBundle\IndexService\
Interpreter\DefaultClassificationStore

filtergroup: classificationstore

options:

mapping:

type: 'object'

properties:

keys:

type: 'long'

values:

type: 'object'

This results in a data structure in your index similar to this:

"some_field_name" : {

"values" : {

"1" : [

"one value"

],

"2" : [

"another value"

],

"3" : [

"123",
"99"

],

"5" : [

"AT",

"DZ"

],

"4" : [

""

},

"keys" : [

1,

2,

3,

5,

This contains all the classification store IDs as well as all the data.

2) Filter Type

To interpret the indexed data correctly, a special filter type is needed.


As this filter type works only in combination with elasticsearch, it is not
activated by default. Following steps are necessary to activate it:

make sure the field collection FilteSelectClsStoreAttributes is installed


and is allowed in the filter list of the filter definition class.

add following filter type mapping (see here for details):


FilteSelectClsStoreAttributes:

filter_type_id: Pimcore\Bundle\EcommerceFrameworkBundle\FilterService\
FilterType\ElasticSearch\SelectClassificationStoreAttributes

template: 'product/filters/nested_attributes.html.twig'

3) Template

The template for the filter has to render not only one filter, but the
whole list of possible filters for the classification store attributes. For
a sample template see our demo.

ChatGPT

## Filtering Classification Store Attributes with Elasticsearch

Pimcore allows indexing all attributes of a Classification Store using


Elasticsearch without needing to define each attribute individually. This
setup improves efficiency and flexibility when dealing with complex product
data.

### Steps to Implement Classification Store Filtering

### 1. Index Definition

To load all Classification Store attributes into the index, you need to
configure a special interpreter. Add the following attribute configuration
to your index definition:

```yaml

pimcore_ecommerce_framework:

index_service:

tenants:

ElasticSearch:
attributes:

classification_store:

fieldname: 'my_classification_store_field_name'

interpreter: Pimcore\Bundle\
EcommerceFrameworkBundle\IndexService\Interpreter\
DefaultClassificationStore

filtergroup: classificationstore

options:

mapping:

type: 'object'

properties:

keys:

type: 'long'

values:

type: 'object'

```

#### Resulting Data Structure

This configuration results in an index data structure like this:

```json

"classification_store": {

"values": {

"1": ["one value"],

"2": ["another value"],

"3": ["123", "99"],

"5": ["AT", "DZ"],


"4": [""]

},

"keys": [1, 2, 3, 5, 4]

```

This structure includes all Classification Store IDs and their associated
data.

### 2. Filter Type

To correctly interpret the indexed data, a special filter type is needed.


This filter type is specific to Elasticsearch.

#### Steps to Activate the Filter Type

1. **Ensure the Field Collection is Installed:**

Ensure the `FilteSelectClsStoreAttributes` field collection is installed


and allowed in the filter list of the Filter Definition class.

2. **Add Filter Type Mapping:**

```yaml

pimcore_ecommerce_framework:

filter_service:

tenants:

ElasticSearch:

filter_types:
FilteSelectClsStoreAttributes:

filter_type_id: Pimcore\Bundle\
EcommerceFrameworkBundle\FilterService\FilterType\ElasticSearch\
SelectClassificationStoreAttributes

template:
'product/filters/nested_attributes.html.twig'

```

### 3. Template

The template for the filter must render the entire list of possible filters
for the Classification Store attributes. Here’s an example template for
rendering nested attributes filters:

#### Example Twig Template

```twig

{% for attribute in filter.attributes %}

<div class="filter-group">

<label>{{ attribute.label }}</label>

<select name="{{ attribute.name }}">

<option value="">All</option>

{% for option in attribute.options %}

<option value="{{ option.value }}">{{ option.label


}}</option>

{% endfor %}

</select>

</div>

{% endfor %}

```
### Putting It All Together

#### Controller

Here's an example of setting up the Filter Service within a controller:

```php

<?php

use Pimcore\Bundle\EcommerceFrameworkBundle\Factory;

use Pimcore\Bundle\EcommerceFrameworkBundle\FilterService\ListHelper;

use Knp\Component\Pager\PaginatorInterface;

use Symfony\Component\HttpFoundation\Request;

public function productListAction(Request $request, PaginatorInterface


$paginator)

$ecommerceFactory = Factory::getInstance();

$templateParams = [];

$params = array_merge($request->query->all(), $request->attributes-


>all());

$indexService = $ecommerceFactory->getIndexService();

$productListing = $indexService->getProductListForCurrentTenant();

$templateParams['productListing'] = $productListing;

// Retrieve the filter definition

$filterDefinition = // TODO: Retrieve the filter definition


// Initialize filter service

$filterService = $ecommerceFactory->getFilterService();

(new ListHelper())->setupProductList($filterDefinition,
$productListing, $params, $filterService, true, true);

$templateParams['filterService'] = $filterService;

$templateParams['filterDefinition'] = $filterDefinition;

// Use Knp Paginator service

$pagination = $paginator->paginate(

$productListing,

$request->get('page', 1),

18

);

$templateParams['results'] = $pagination;

$templateParams['paginationVariables'] = $pagination-
>getPaginationData();

return $this->render('Path/template.html.twig', $templateParams);

```

#### View

Render the filters in the frontend using a form:

```twig

<form method="get" action="{{ path('your_route') }}">


{% if filterDefinition.filters|length > 0 %}

{% for filter in filterDefinition.filters %}

{% set filterMarkup = filterService.filterFrontend(filter,


productListing, currentFilter) %}

{{ filterMarkup | raw }}

{% endfor %}

{% endif %}

<button type="submit">Apply Filters</button>

</form>

```

### Summary

By configuring your Elasticsearch index and setting up the appropriate


filter types, you can efficiently manage and filter Classification Store
attributes. Ensure your templates and controllers are correctly set up to
leverage these filters, providing a seamless user experience in your
Pimcore E-Commerce application.

User

Filter for nested documents

In some cases it is necessary to store an array of objects, but in a way so


that they can be queried independently of each other, i.e. if you want to
store an array of additional data from field collections. The data in your
index may look as follows:

"_source": {

"attributes": {

"my_attributes": [

"id": "12345",
"name": "Höhe",

"value": "15 mm"

},

"id": "12346",

"name": "Länge",

"value": "7 mm"

},

"id": "12347",

"name": "Breite",

"value": "30 mm"

To utilize the nested document functionality the mapping type of the field
my_attributes must be defined as nested, to let elasticsearch know about
the sub-documents:

attributes:

filtergroup: string

type: 'nested'

options:

mapping:

type: 'nested'
interpreter_id: App\Ecommerce\IndexService\Interpreter\MyAttributes

interpreter_options:

locale: '%%locale%%'

Now you can create a filter for the nested document field, which has to be
defined in a nested manner as well:

class SelectMyAttribute extends \Pimcore\Bundle\EcommerceFrameworkBundle\


FilterService\FilterType\AbstractFilterType

public function prepareGroupByValues(AbstractFilterDefinitionType


$filterDefinition, ProductListInterface $productList): void

/** @var AbstractElasticSearch $productList */

$nestedPath = "attributes.my_attributes";

// first group by id

$subAggregationField = $nestedPath . ".id";

// then group by value

$subSubAggregationField = $nestedPath . ".value.keyword";

$productList->prepareGroupByValuesWithConfig($this-
>getField($filterDefinition), true, false, [

"nested" => [

"path" => $nestedPath

],

"aggs" => [
$subAggregationField => [

"terms" => [

"size" => 200,

"field" => $subAggregationField

],

"aggs" => [

$subSubAggregationField => [

"terms" => [

"size" => 200,

"field" => $subSubAggregationField

]);

public function addCondition(AbstractFilterDefinitionType


$filterDefinition, ProductListInterface $productList, array $currentFilter,
array $params, bool $isPrecondition = false): void

$nestedPath = "attributes.my_attributes";

// @todo: get $myAttributeValue and $myAttributeId from request


params

$condition = [
"nested" => [

"path" => $nestedPath,

"query" => [

"bool" => [

$mode => [

"term" => [

$nestedPath . ".value.keyword" =>


$myAttributeValue

],

"term" => [

$nestedPath."id" => $myAttributeId

];

$productList->addCondition($condition, $this-
>getField($filterDefinition));

public function getFilterValues(AbstractFilterDefinitionType


$filterDefinition, ProductListInterface $productList, array
$currentFilter): array
{

$field = $this->getField($filterDefinition);

$this->prepareGroupByValues($filterDefinition, $productList);

$values = $productList->getGroupByValues($field, true, !


$filterDefinition->getUseAndCondition());

return [

'label' => $filterDefinition->getLabel(),

'values' => $values,

'metaData' => $filterDefinition->getMetaData(),

'hasValue' => $this->hasValue,

];

Further information

Read more about

nested documents

nested queries

nested aggregations

in the official elasticsearch documentation.

ChatGPT

## Filtering for Nested Documents in Elasticsearch with Pimcore


Elasticsearch supports the concept of nested documents, which allows you to
store arrays of objects that can be queried independently. This is useful
for complex data structures like arrays of field collections. Here's how to
set up and use nested documents in Pimcore's E-Commerce Framework.

### Step-by-Step Guide

### 1. Index Definition

Define the field as nested in your Elasticsearch index configuration. This


lets Elasticsearch know to treat the sub-documents as independent entities.

#### Example Configuration

```yaml

pimcore_ecommerce_framework:

index_service:

tenants:

ElasticSearch:

attributes:

my_attributes:

filtergroup: string

type: 'nested'

options:

mapping:

type: 'nested'

interpreter_id: App\Ecommerce\IndexService\
Interpreter\MyAttributes

interpreter_options:
locale: '%%locale%%'

```

### 2. Implementing Custom Filter Type

Create a custom filter type to handle nested documents. This filter type
will prepare the group-by values, add conditions to the query, and fetch
filter values.

#### Custom Filter Type Class

```php

<?php

namespace App\Ecommerce\FilterService\FilterType;

use Pimcore\Bundle\EcommerceFrameworkBundle\FilterService\FilterType\
AbstractFilterType;

use Pimcore\Bundle\EcommerceFrameworkBundle\FilterService\FilterType\
AbstractFilterDefinitionType;

use Pimcore\Bundle\EcommerceFrameworkBundle\IndexService\ProductList\
ProductListInterface;

use Pimcore\Bundle\EcommerceFrameworkBundle\IndexService\ElasticSearch\
AbstractElasticSearch;

class SelectMyAttribute extends AbstractFilterType

public function prepareGroupByValues(AbstractFilterDefinitionType


$filterDefinition, ProductListInterface $productList): void

/** @var AbstractElasticSearch $productList */


$nestedPath = "attributes.my_attributes";

// first group by id

$subAggregationField = $nestedPath . ".id";

// then group by value

$subSubAggregationField = $nestedPath . ".value.keyword";

$productList->prepareGroupByValuesWithConfig($this-
>getField($filterDefinition), true, false, [

"nested" => [

"path" => $nestedPath

],

"aggs" => [

$subAggregationField => [

"terms" => [

"size" => 200,

"field" => $subAggregationField

],

"aggs" => [

$subSubAggregationField => [

"terms" => [

"size" => 200,

"field" => $subSubAggregationField

]
]

]);

public function addCondition(AbstractFilterDefinitionType


$filterDefinition, ProductListInterface $productList, array $currentFilter,
array $params, bool $isPrecondition = false): void

$nestedPath = "attributes.my_attributes";

// @todo: get $myAttributeValue and $myAttributeId from request


params

$myAttributeValue = $params['my_attribute_value'] ?? null;

$myAttributeId = $params['my_attribute_id'] ?? null;

$condition = [

"nested" => [

"path" => $nestedPath,

"query" => [

"bool" => [

"must" => [

"term" => [

$nestedPath . ".value.keyword" =>


$myAttributeValue

],
[

"term" => [

$nestedPath . ".id" => $myAttributeId

];

$productList->addCondition($condition, $this-
>getField($filterDefinition));

public function getFilterValues(AbstractFilterDefinitionType


$filterDefinition, ProductListInterface $productList, array
$currentFilter): array

$field = $this->getField($filterDefinition);

$this->prepareGroupByValues($filterDefinition, $productList);

$values = $productList->getGroupByValues($field, true, !


$filterDefinition->getUseAndCondition());

return [

'label' => $filterDefinition->getLabel(),

'values' => $values,

'metaData' => $filterDefinition->getMetaData(),


'hasValue' => $this->hasValue,

];

```

### 3. Configuration

Add the custom filter type to your


`pimcore_ecommerce_framework.filter_service` configuration.

```yaml

pimcore_ecommerce_framework:

filter_service:

tenants:

ElasticSearch:

filter_types:

SelectMyAttribute:

filter_type_id: App\Ecommerce\FilterService\
FilterType\SelectMyAttribute

template:
'product/filters/nested_attributes.html.twig'

```

### 4. Using the Filter in Controller and View

#### Controller
Initialize and use the custom filter type in your controller:

```php

<?php

use Pimcore\Bundle\EcommerceFrameworkBundle\Factory;

use Pimcore\Bundle\EcommerceFrameworkBundle\FilterService\ListHelper;

use Knp\Component\Pager\PaginatorInterface;

use Symfony\Component\HttpFoundation\Request;

public function productListAction(Request $request, PaginatorInterface


$paginator)

$ecommerceFactory = Factory::getInstance();

$templateParams = [];

$params = array_merge($request->query->all(), $request->attributes-


>all());

$indexService = $ecommerceFactory->getIndexService();

$productListing = $indexService->getProductListForCurrentTenant();

$templateParams['productListing'] = $productListing;

// Retrieve the filter definition

$filterDefinition = // TODO: Retrieve the filter definition

// Initialize filter service

$filterService = $ecommerceFactory->getFilterService();

(new ListHelper())->setupProductList($filterDefinition,
$productListing, $params, $filterService, true, true);
$templateParams['filterService'] = $filterService;

$templateParams['filterDefinition'] = $filterDefinition;

// Use Knp Paginator service

$pagination = $paginator->paginate(

$productListing,

$request->get('page', 1),

18

);

$templateParams['results'] = $pagination;

$templateParams['paginationVariables'] = $pagination-
>getPaginationData();

return $this->render('Path/template.html.twig', $templateParams);

```

#### View

Render the filters in the frontend:

```twig

<form method="get" action="{{ path('your_route') }}">

{% if filterDefinition.filters|length > 0 %}

{% for filter in filterDefinition.filters %}

{% set filterMarkup = filterService.filterFrontend(filter,


productListing, currentFilter) %}

{{ filterMarkup | raw }}
{% endfor %}

{% endif %}

<button type="submit">Apply Filters</button>

</form>

```

### Conclusion

By configuring Elasticsearch with nested document support and implementing


custom filter types, you can efficiently manage complex data structures and
provide powerful filtering capabilities in your Pimcore E-Commerce
Framework. Ensure your controller and view are set up to handle the custom
filters and display the filtered results effectively.

User

Working with Prices

Prices are an essential part of every E-Commerce solution. In order to be


able to implement complex and very custom pricing schemes, the E-Commerce
Framework has the concept of Pricing Systems. These Pricing Systems
encapsulate all the logic of retrieving and calculating prices.

The Tax Management Component adds functionality for dealing with taxes and
should be flexible enough to implement all kinds of tax structures.

With Pricing Rules and Vouchers marketing actions can be implemented.

For details on how to calculate with prices, see Calculate with Prices.

ChatGPT

## Working with Prices in Pimcore E-Commerce Framework

Prices are a crucial part of any e-commerce solution. The Pimcore E-


Commerce Framework provides a robust system for managing prices, including
support for complex pricing schemes, tax management, pricing rules, and
vouchers.
### Overview of Pricing Systems

Pricing Systems in Pimcore encapsulate all the logic needed to retrieve and
calculate prices. They are flexible and extensible, allowing you to
implement custom pricing schemes to meet your specific business needs.

### Key Components

1. **Pricing Systems**: Encapsulate logic for retrieving and calculating


prices.

2. **Tax Management**: Adds functionality for dealing with various tax


structures.

3. **Pricing Rules**: Implement marketing actions based on specific


conditions.

4. **Vouchers**: Implement discount mechanisms and special offers.

### Configuring Pricing Systems

To use a Pricing System, you need to define it in your configuration.


Here's an example:

#### Configuration Example

```yaml

pimcore_ecommerce_framework:

price_systems:

default:

id: App\Ecommerce\PriceSystem\CustomPriceSystem

```
#### Custom Price System Class

Create a custom Price System class that implements the logic for
calculating prices:

```php

<?php

namespace App\Ecommerce\PriceSystem;

use Pimcore\Bundle\EcommerceFrameworkBundle\PricingManager\PriceSystem\
PriceSystemInterface;

use Pimcore\Model\DataObject\AbstractObject;

class CustomPriceSystem implements PriceSystemInterface

public function getPrice(AbstractObject $product, $context = [])

// Implement your price calculation logic here

$basePrice = $product->getBasePrice();

// Apply custom logic, e.g., discounts, taxes, etc.

$finalPrice = $basePrice * 1.2; // Example logic

return $finalPrice;

}
```

### Tax Management

The Tax Management component handles tax calculations and can be configured
to support various tax structures.

#### Example Configuration

```yaml

pimcore_ecommerce_framework:

tax_manager:

default:

id: App\Ecommerce\TaxManager\CustomTaxManager

```

#### Custom Tax Manager Class

Create a custom Tax Manager class to implement tax calculation logic:

```php

<?php

namespace App\Ecommerce\TaxManager;

use Pimcore\Bundle\EcommerceFrameworkBundle\PricingManager\TaxManager\
TaxManagerInterface;

use Pimcore\Model\DataObject\AbstractObject;
class CustomTaxManager implements TaxManagerInterface

public function calculateTax(AbstractObject $product, $context = [])

// Implement your tax calculation logic here

$taxRate = 0.2; // Example tax rate

return $product->getBasePrice() * $taxRate;

```

### Pricing Rules

Pricing Rules allow you to implement marketing actions based on specific


conditions. They can be used to apply discounts, special offers, and other
promotional activities.

#### Example Configuration

```yaml

pimcore_ecommerce_framework:

pricing_manager:

default:

pricing_manager_id: Pimcore\Bundle\EcommerceFrameworkBundle\
PricingManager\PricingManager

pricing_manager_options:
rule_class: Pimcore\Bundle\EcommerceFrameworkBundle\
PricingManager\Rule

price_info_class: Pimcore\Bundle\EcommerceFrameworkBundle\
PricingManager\PriceInfo

environment_class: Pimcore\Bundle\EcommerceFrameworkBundle\
PricingManager\Environment

```

### Vouchers

Vouchers can be used to implement discount mechanisms and special offers.


They provide a way to offer promotional codes and discounts to customers.

#### Example Configuration

```yaml

pimcore_ecommerce_framework:

voucher_service:

voucher_service_id: Pimcore\Bundle\EcommerceFrameworkBundle\
VoucherService\DefaultService

voucher_service_options:

reservation_minutes_threshold: 5

statistics_days_threshold: 30

token_managers:

factory_id: Pimcore\Bundle\EcommerceFrameworkBundle\
VoucherService\TokenManager\TokenManagerFactory

mapping:

default:

id: App\Ecommerce\VoucherService\CustomTokenManager

```
### Example Workflow for Calculating Prices

Here's an example of how to use the Pricing System, Tax Management, and
Vouchers to calculate a final price for a product.

#### Controller Example

```php

<?php

namespace App\Controller;

use Pimcore\Bundle\EcommerceFrameworkBundle\Factory;

use Pimcore\Model\DataObject\Product;

use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;

use Symfony\Component\HttpFoundation\Request;

use Symfony\Component\HttpFoundation\Response;

class ProductController extends AbstractController

public function calculatePriceAction(Request $request, $productId)

$product = Product::getById($productId);

$ecommerceFactory = Factory::getInstance();

$priceSystem = $ecommerceFactory->getPriceSystem();
$taxManager = $ecommerceFactory->getTaxManager();

$voucherService = $ecommerceFactory->getVoucherService();

// Calculate base price

$price = $priceSystem->getPrice($product);

// Calculate tax

$tax = $taxManager->calculateTax($product);

// Apply vouchers (example)

$voucherCode = $request->get('voucherCode');

if ($voucherCode) {

$voucher = $voucherService->validateVoucher($voucherCode);

if ($voucher) {

$price -= $voucher->getDiscount();

// Calculate final price

$finalPrice = $price + $tax;

return new Response(sprintf('Final price for product %d: %.2f',


$productId, $finalPrice));

```
### Summary

By configuring and utilizing the Pricing System, Tax Management, Pricing


Rules, and Vouchers in Pimcore's E-Commerce Framework, you can implement
complex and customized pricing schemes. These components provide a flexible
way to handle price calculations, tax management, and promotional
activities, ensuring your e-commerce solution meets all your business
needs.

User

Price Systems

In terms of pricing, the E-Commerce Framework has the concept of Price


Systems. These Price Systems are responsible for retrieving or calculating
prices and returning so called PriceInfo objects which contain the
calculated prices. Each product can have its own Price System.

So very complex pricing structures and different price sources can be


integrated into the system quite easily.

In terms of product availabilities and stocks, the very similar concept of


Availability Systems is used.

Configuration of Price Systems

A price system is a class implementing Pimcore\Bundle\


EcommerceFrameworkBundle\PriceSystem\PriceSystemInterface which is defined
as service and registered with a name in the
pimcore_ecommerce_framework.price_systems configuration tree. The framework
already ships with a number of concrete implementations which you can use
as starting point.

There are 3 places where the configuration of Price Systems takes place:

Product class: Each product has to implement the method


getPriceSystemName() which returns the name of its Price System.

Service definition: Each price system must be registered as service

Configuration: The price_systems section maps price system names to service


IDs
The product class returns the name of a price system:

<?php

class MyProduct implements \Pimcore\Bundle\EcommerceFrameworkBundle\Model\


CheckoutableInterface

public function getPriceSystemName(): string

return 'foo';

Each price system must be defined as service (either a service defined by


core configuration or your custom services):

# services.yaml

services:

_defaults:

autowire: true

autoconfigure: true

# defines a completely custom price system as service

# arguments depend on your implementation

App\Ecommerce\PriceSystem\CustomPriceSystem:

arguments:

- 'bar'
# this reuses a core price system, but defines a new service which sets
custom options

# on the price system (a custom price attribute). available options


vary by implementation

app.custom_attribute_price_system:

class: Pimcore\Bundle\EcommerceFrameworkBundle\PriceSystem\
AttributePriceSystem

arguments:

$options:

attribute_name: customPriceField

The price_systems configuration maps names to service IDs:

pimcore_ecommerce_framework:

# defines 3 price systems

price_systems:

# the attribute price system is already defined in core


price_systems.yaml service definition

default:

id: Pimcore\Bundle\EcommerceFrameworkBundle\PriceSystem\
AttributePriceSystem

foo:

id: App\Ecommerce\PriceSystem\CustomPriceSystem

bar:

id: app.custom_attribute_price_system
The simplest price system is Pimcore\Bundle\EcommerceFrameworkBundle\
PriceSystem\AttributePriceSystem which reads the price from an attribute of
the product object. For implementing custom price systems have a look at
method comments of \Pimcore\Bundle\EcommerceFrameworkBundle\PriceSystem\
PriceSystemInterface and the implementations of the existing price systems.

Getting and Printing Prices

Once the Price Systems are set up correctly, working with prices should be
quite easy. Each product has the method getOSPrice() which returns a \
Pimcore\Bundle\EcommerceFrameworkBundle\PriceSystem\PriceInterface object
with the price of the product.

Internally the product gets its Price System and starts the price
calculation to get the price.

When the price system returns a custom PriceInfo object (e.g. with
additional stock prices, customer specific prices etc.), this PriceInfo can
be retrieved by calling getOSPriceInfo() method of the product object.

A sample for printing the price on a product detail page is:

<p class="price">

<span>{{ product.OSPrice }}</span>

</p>

ChatGPT

## Price Systems in Pimcore E-Commerce Framework

Pimcore's E-Commerce Framework utilizes the concept of Price Systems to


handle complex pricing structures and different price sources. Each product
can have its own Price System, allowing for flexible and customized pricing
calculations.

### Key Concepts

1. **Price Systems**: Responsible for retrieving or calculating prices and


returning `PriceInfo` objects.

2. **PriceInfo Objects**: Contain the calculated prices.

3. **Availability Systems**: Similar concept for managing product


availabilities and stocks.

### Configuration of Price Systems

Price Systems are classes that implement the `Pimcore\Bundle\


EcommerceFrameworkBundle\PriceSystem\PriceSystemInterface`. They are
defined as services and registered in the
`pimcore_ecommerce_framework.price_systems` configuration tree.

### Steps to Configure Price Systems

1. **Product Class Configuration**:

Each product must implement the `getPriceSystemName` method to return


the name of its Price System.

```php

<?php

class MyProduct implements \Pimcore\Bundle\EcommerceFrameworkBundle\


Model\CheckoutableInterface

public function getPriceSystemName(): string


{

return 'foo';

```

2. **Service Definition**:

Define each Price System as a service in your `services.yaml`.

```yaml

services:

_defaults:

autowire: true

autoconfigure: true

# Custom price system service

App\Ecommerce\PriceSystem\CustomPriceSystem:

arguments:

- 'bar'

# Core price system with custom options

app.custom_attribute_price_system:

class: Pimcore\Bundle\EcommerceFrameworkBundle\PriceSystem\
AttributePriceSystem

arguments:

$options:

attribute_name: customPriceField
```

3. **Configuration Mapping**:

Map the Price System names to service IDs in the


`pimcore_ecommerce_framework.price_systems` configuration.

```yaml

pimcore_ecommerce_framework:

price_systems:

default:

id: Pimcore\Bundle\EcommerceFrameworkBundle\PriceSystem\
AttributePriceSystem

foo:

id: App\Ecommerce\PriceSystem\CustomPriceSystem

bar:

id: app.custom_attribute_price_system

```

### Implementing a Custom Price System

To implement a custom Price System, create a class that implements the


`PriceSystemInterface`.

#### Custom Price System Class

```php

<?php
namespace App\Ecommerce\PriceSystem;

use Pimcore\Bundle\EcommerceFrameworkBundle\PriceSystem\
PriceSystemInterface;

use Pimcore\Model\DataObject\AbstractObject;

use Pimcore\Bundle\EcommerceFrameworkBundle\PriceSystem\PriceInfo;

class CustomPriceSystem implements PriceSystemInterface

public function getPrice(AbstractObject $product, array $context = []):


PriceInfo

// Implement your price calculation logic here

$basePrice = $product->getBasePrice();

// Apply custom logic, e.g., discounts, taxes, etc.

$finalPrice = $basePrice * 1.2; // Example logic

return new PriceInfo($finalPrice);

```

### Working with Prices

Once the Price Systems are set up correctly, retrieving and displaying
prices is straightforward.
1. **Getting Prices**:

Each product has a `getOSPrice` method that returns a `PriceInterface`


object with the product's price.

```php

$price = $product->getOSPrice();

```

2. **Getting PriceInfo**:

If the Price System returns a custom `PriceInfo` object, it can be


retrieved using the `getOSPriceInfo` method.

```php

$priceInfo = $product->getOSPriceInfo();

```

3. **Displaying Prices in Templates**:

To display the price on a product detail page, you can use the following
Twig template code:

```twig

<p class="price">

<span>{{ product.OSPrice }}</span>

</p>

```

### Example Workflow


Here’s an example workflow for setting up and using a custom Price System:

1. **Define the Custom Price System Class**:

```php

<?php

namespace App\Ecommerce\PriceSystem;

use Pimcore\Bundle\EcommerceFrameworkBundle\PriceSystem\
PriceSystemInterface;

use Pimcore\Model\DataObject\AbstractObject;

use Pimcore\Bundle\EcommerceFrameworkBundle\PriceSystem\PriceInfo;

class CustomPriceSystem implements PriceSystemInterface

public function getPrice(AbstractObject $product, array $context =


[]): PriceInfo

// Custom price calculation logic

$basePrice = $product->getBasePrice();

$finalPrice = $basePrice * 1.2;

return new PriceInfo($finalPrice);

```
2. **Register the Service**:

```yaml

services:

App\Ecommerce\PriceSystem\CustomPriceSystem:

arguments:

- 'bar'

```

3. **Map the Price System**:

```yaml

pimcore_ecommerce_framework:

price_systems:

foo:

id: App\Ecommerce\PriceSystem\CustomPriceSystem

```

4. **Implement the Product Class**:

```php

<?php

class MyProduct implements \Pimcore\Bundle\EcommerceFrameworkBundle\


Model\CheckoutableInterface

public function getPriceSystemName(): string


{

return 'foo';

```

5. **Display the Price in a Twig Template**:

```twig

<p class="price">

<span>{{ product.OSPrice }}</span>

</p>

```

### Conclusion

By configuring and utilizing Price Systems in Pimcore's E-Commerce


Framework, you can implement complex and flexible pricing schemes tailored
to your business needs. This approach ensures accurate price calculations
and enhances the overall shopping experience for your customers.

User

Tax Management

Within the Price Systems there is a Tax Management component to deal with
all sorts of taxes. So it is possible to calculate and print out taxes as
needed.

The Tax Management is quite transparent and should not affect the system
very deeply. As a result - if not necessary (e.g. because you have a B2B
system, etc.) - you don't need to deal with taxes in E-Commerce Framework
at all. Also, if you have your very own tax implementation, this should be
perfectly possible and you should need to not deal with the Tax Management
in the E-Commerce Framework at all. Just use all the default values and
every thing should be fine.
Components of Tax Management

If you need to deal with taxes following components are important to know
of:

Tax Configuration with OnlineShopTaxClass

The configuration of taxes is done with OnlineShopTaxClass Pimcore objects


within in the Pimcore Backend UI. The actual tax calculation is always
based on the configuration of such a tax class. So, tax configurations for
different countries and product groups can be established. The tax
calculation is always based on one tax class, a combination of tax classes
is not possible. The configuration concludes a TaxEntryCombinationMode
(combine and one after another) and one or more tax entries with a name and
a tax rate in percent.

tax classes

The selection of the correct tax class (for a certain country and a certain
product group) is done by the Price System (see next section).

Tax Class Selection with Price Systems

The Price System decides for each product and environment which tax class
to take for tax calculation. Therefore following two methods need to be
implemented:

getTaxClassForProduct: Should return tax class for given product. The


default implementation returns a generic tax class based on the Website
Settings or - if not set - an empty tax class.

getTaxClassForPriceModification: See later for more information.

The logic behind the tax class selection can be of any complexity. It can
be based on a simple Website Setting (for one tax class fits all), or based
on a complex matrix with product group, sending country, delivering country
and several other aspects.

Tax Calculation with TaxCalculationService


The actual tax calculation is done in the
TaxCalculationService::updateTaxes(PriceInterface $price, $calculationMode
= self::CALCULATION_FROM_NET) method. It updates taxes in given price
object by using its tax entries, tax combination mode and net or gross
amount based on the given $calculationMode.

The calculation is done by the framework in two places:

By Price Systems when creating the PriceInfo objects

By PriceInterface objects when setAmount, setGrossAmount or setNetAmount is


called and $recalc is set to true.

The PriceInterface object

Every price in the E-Commerce Framework comes down to an PriceInterface


object. Therefore also all calculated taxes and all necessary information
for calculating taxes is stored in PriceInterface objects. Following
methods are important:

getTaxEntries(), setTaxEntries($taxEntries): Sets and gets tax entries for


price. Each price can have one or more tax entries based on the tax laws.
Each of these tax entries contain percent rate and calculated amount. The
order of the tax entries is important.

getTaxEntryCombinationMode(),
setTaxEntryCombinationMode($taxEntryCombinationMode): Sets and gets the tax
entry combination mode which defines how tax calculation is done based on
the tax entries:

TaxEntry::CALCULATION_MODE_COMBINE: Sum up all tax rates and calculate tax


amount afterwards.

TaxEntry::CALCULATION_MODE_ONE_AFTER_ANOTHER: For each tax rate calculate


tax amount, add it to total price and then calculate tax amount for next
tax rate based on new total sum.

TaxEntry::CALCULATION_MODE_FIXED: Amounts and percent rates are fixed and


cannot be (re)calculated based on information within the PriceInterface
object. This mode is needed for subTotal and grandTotal in
CartPriceCalculator.

getGrossAmount(), setGrossAmount($grossAmount, $recalc = false): Sets and


gets gross amount of price. If $recalc is set to true, corresponding net
price is calculated based on tax entries and tax entry combination mode.

getNetAmount(), setNetAmount($netAmount, $recalc = false): Sets and gets


net amount of price. If $recalc is set to true, corresponding gross price
is calculated based on tax entries and tax entry combination mode.
getAmount(), setAmount($amount, $priceMode = self::PRICE_MODE_GROSS,
$recalc = false): Gets the gross amount by default and sets the gross or
net amount based on the params.

Special Aspects

Tax Calculation in Pricing Rules

E-Commerce Framework Pricing Rules always modify the gross price of the
product and recalculate the net price based on the tax entries of the
product price. So specified discount amounts on product level need to be
configured as gross discounts.

Since cart discounts are implemented as CartPriceModificators the next


point is important for them. It might be necessary to extend the default
implementation of the cart discounts for the correct selection of the tax
class for discounts. The default implementation uses the
getTaxClassForPriceModification method of the Price System called default
for tax class selection.

Tax Calculation in CartPriceModificators

The CartPriceModificators themselves can decide if the modification should


be done as net or gross amount since the interface
ModificatedPriceInterface extends PriceInterface and therefore all tax
related information as explained above. The method
getTaxClassForPriceModification in Price Systems can be used to delegate
the tax class selection to Price Systems.

Putting the Pieces Together

For setting up the tax management, following steps are necessary.

1) Defining Tax Classes

Create and configure all the OnlineShopTaxClass objects within Pimcore.

2) Configuring Price System

Setup the correct price systems and implement their methods


getTaxClassForProduct and getTaxClassForPriceModification. It might also be
necessary to have a look at the CartPriceModificator for cart discounts and
make sure that it selects the correct tax class.
3) Printing Taxes

To print taxes into the frontend use following samples:

Product Detail Page

{% set price = product.OSPrise %}

<strong>{{ price }}</strong>

<div class="tax">

<p><strong>{{ 'shop.detail.included_tax'|trans }}'</strong></p>

<ul>

{% for entry in price.taxEntries %}

<li>{{ entry.entry.name }}: {{ entry.percent }}%


({{ price.currency.toCurrency(entry.amount) }})</li>

{% endfor %}

</ul>

</div>

Cart

{% set grandTotal = cart.priceCalculator.grandTotal %}

{% if grandTotal.taxEntries %}

<tr>

<td>{{ 'cart.taxes'|trans }}</td>

<td>

{% for taxEntry in grandTotal.taxEntries %}

{{ taxEntry.entry.name }}: {{ taxEntry.percent }}%


({{ grandTotal.currency.toCurrency(taxEntry.amount) }})<br/>

{% endfor %}
</td>

</tr>

{% endif %}

Order Confirmation Mail

{% if order.taxInfo %}

<tr>

<td>{{ 'cart.taxes'|trans }}</td>

<td>

{% for taxEntry in order.taxInfo %}

{{ taxEntry[0] }}: {{ taxEntry[1] }}


({{ currency.toCurrency(taxEntry[2])) }})<br/>

{% endfor %}

</td>

</tr>

{% endif %}

4) Taxes in OnlineShopOrders

Make sure that all tax related attributes are available in OnlineShopOrder
and OnlineShopOrderItem. Then the E-Commerce Framework populates all needed
values automatically and therefore stores the tax information in the order
objects.

ChatGPT

## Tax Management in Pimcore E-Commerce Framework

Pimcore's E-Commerce Framework includes a robust Tax Management component


to handle various tax calculations and configurations. This allows for
flexible tax management suitable for different business needs, including
B2C and B2B environments.
### Key Components of Tax Management

1. **OnlineShopTaxClass**: Configures taxes for different countries and


product groups.

2. **Price Systems**: Selects the correct tax class for each product and
price modification.

3. **TaxCalculationService**: Calculates and updates taxes based on the


given mode (net or gross).

4. **PriceInterface**: Stores all calculated taxes and necessary


information for tax calculation.

### Steps to Implement Tax Management

### 1. Defining Tax Classes

Tax classes are configured using `OnlineShopTaxClass` objects in the


Pimcore Backend UI. Each tax class can have one or more tax entries with a
name and tax rate.

#### Example Tax Class Configuration

![Tax Classes](https://path/to/tax-classes-image.png)

### 2. Configuring Price Systems

Price Systems decide which tax class to use for tax calculations. Implement
the following methods in your Price System:

- `getTaxClassForProduct`: Returns the tax class for the given product.


- `getTaxClassForPriceModification`: Returns the tax class for price
modifications.

#### Example Price System Implementation

```php

<?php

namespace App\Ecommerce\PriceSystem;

use Pimcore\Bundle\EcommerceFrameworkBundle\PriceSystem\
PriceSystemInterface;

use Pimcore\Model\DataObject\AbstractObject;

use Pimcore\Bundle\EcommerceFrameworkBundle\PriceSystem\PriceInfo;

use Pimcore\Model\DataObject\OnlineShopTaxClass;

class CustomPriceSystem implements PriceSystemInterface

public function getTaxClassForProduct(AbstractObject $product):


OnlineShopTaxClass

// Implement logic to select the appropriate tax class for the


product

return $this->getTaxClassByName('default_tax_class');

public function getTaxClassForPriceModification(AbstractObject


$product): OnlineShopTaxClass

{
// Implement logic to select the appropriate tax class for price
modifications

return $this->getTaxClassByName('discount_tax_class');

private function getTaxClassByName($name)

return OnlineShopTaxClass::getByName($name);

```

### 3. Tax Calculation with TaxCalculationService

The `TaxCalculationService` performs the actual tax calculations. It


updates taxes in the given `PriceInterface` object using the tax entries,
combination mode, and calculation mode (net or gross).

### 4. Working with PriceInterface

Every price in the E-Commerce Framework is represented by a


`PriceInterface` object. This object contains all tax-related information
and methods to manage tax calculations:

- `getTaxEntries()`, `setTaxEntries($taxEntries)`: Get and set tax entries.

- `getTaxEntryCombinationMode()`, `setTaxEntryCombinationMode($mode)`: Get


and set the tax entry combination mode.

- `getGrossAmount()`, `setGrossAmount($amount, $recalc = false)`: Get and


set the gross amount.

- `getNetAmount()`, `setNetAmount($amount, $recalc = false)`: Get and set


the net amount.
- `getAmount()`, `setAmount($amount, $priceMode = self::PRICE_MODE_GROSS,
$recalc = false)`: Get and set the amount based on the price mode (gross or
net).

### Special Aspects

#### Tax Calculation in Pricing Rules

Pricing rules always modify the gross price and recalculate the net price
based on the tax entries.

#### Tax Calculation in CartPriceModificators

Cart price modifiers can decide whether the modification should be done on
the net or gross amount. They use the `getTaxClassForPriceModification`
method of the Price System for tax class selection.

### Example: Putting It All Together

#### Defining Tax Classes

Create and configure `OnlineShopTaxClass` objects in Pimcore.

#### Configuring Price System

Setup the Price System and implement the methods for tax class selection.

#### Printing Taxes in the Frontend


##### Product Detail Page

```twig

{% set price = product.OSPrice %}

<strong>{{ price }}</strong>

<div class="tax">

<p><strong>{{ 'shop.detail.included_tax'|trans }}</strong></p>

<ul>

{% for entry in price.taxEntries %}

<li>{{ entry.entry.name }}: {{ entry.percent }}%


({{ price.currency.toCurrency(entry.amount) }})</li>

{% endfor %}

</ul>

</div>

```

##### Cart

```twig

{% set grandTotal = cart.priceCalculator.grandTotal %}

{% if grandTotal.taxEntries %}

<tr>

<td>{{ 'cart.taxes'|trans }}</td>

<td>

{% for taxEntry in grandTotal.taxEntries %}

{{ taxEntry.entry.name }}: {{ taxEntry.percent }}%


({{ grandTotal.currency.toCurrency(taxEntry.amount) }})<br/>
{% endfor %}

</td>

</tr>

{% endif %}

```

##### Order Confirmation Mail

```twig

{% if order.taxInfo %}

<tr>

<td>{{ 'cart.taxes'|trans }}</td>

<td>

{% for taxEntry in order.taxInfo %}

{{ taxEntry[0] }}: {{ taxEntry[1] }}


({{ currency.toCurrency(taxEntry[2]) }})<br/>

{% endfor %}

</td>

</tr>

{% endif %}

```

### Summary

By configuring tax classes, setting up Price Systems, and implementing tax


calculation logic, you can effectively manage taxes in Pimcore's E-Commerce
Framework. This setup allows for flexible and accurate tax calculations,
ensuring compliance with various tax regulations and enhancing the overall
user experience.
User

Pricing Rules

Pricing Rules are supported by the E-Commerce Framework out of the box. The
pricing rules themselves can be configured in the Pimcore Backend UI by
putting conditions and actions together.

Pricing Rules

Once active, all rules are checked and applied automatically by the system
- including reducing product prices, adding price modificators to reduce
cart totals, removing shipping costs and adding gift items to the cart.

To print the applied rules in the frontend, the developer needs to add some
lines of code. Depending on the location, following scripts can be used.

Product Detail Page

{% set priceInfo = product.OSPriceInfo %}

{% if priceInfo.rules %}

<div class="discounts">

<p><strong>{{ 'shop.detail.your_benefit'|trans
}}</strong></p>

<ul>

<?php foreach($priceInfo->getRules() as $rule ) { ?>

{% for rule in priceInfo.rules %}

<?php foreach($rule->getActions() as
$action) { ?>

{% for action in rule.actions %}

{% if action is instanceof('Pimcore\Bundle\
EcommerceFrameworkBundle\PricingManager\Action\ProductDiscount') %}

{% if action.amount > 0 %}
<li>{{ rule.label }}
{{ 'shop.detail.your_benefit.discount.amount'|trans([action.amount])
}}</li>

{% elseif action.percent > 0 %}

<li>{{ rule.label }}
{{ 'shop.detail.your_benefit.discount.percent'|
trans([action.percent]) }}</li>

{% endif %}

{% elseif action is
instanceof('Pimcore\Bundle\EcommerceFrameworkBundle\PricingManager\Action\
GiftInterface') %}

<li>

{{ 'shop.detail.your_benefit.discount.gift'|
trans }}, <a
href="{{ action.product.getShopDetailLink() }}">{{ action.product.name }}</
a>

</li>

{% elseif action is instanceof('Pimcore\Bundle\


EcommerceFrameworkBundle\PricingManager\Action\FreeShipping') %}

<li>

{{ 'shop.detail.your_benefit.discount.freeshipping'|trans }}

</li>

<?php } ?>

{% endfor %}

{% endfor %}

</ul>

</div>

{% endif %}

Cart Product List - Printing Gift Items

{% for item in car.giftItems %}


{% set linkDetail = item.product.shopDetailLink %}

<tr>

<td class="cart-list-items-image">

<a href="{{ linkDetail }}" >

<img src="{{ item.product.firstImage({width:


120, height: 120, aspectratio: true}) }}" alt="" border="0" />

</a>

</td>

<td class="cart-list-items-name" valign="top">

<a href="{{ linkDetail }}"


>{{ item.product.OSName }}</a>

</td>

<td class="cart-list-items-quantity">

{{ item.count }}

</td>

</tr>

{% endfor %}

All other price modifications on cart level are included as cart price
modificators. See Cart manager for more details and how to print them.

ChatGPT

## Pricing Rules in Pimcore E-Commerce Framework

Pimcore's E-Commerce Framework supports pricing rules out of the box. These
rules can be configured in the Pimcore Backend UI and are automatically
applied by the system. They can be used to reduce product prices, apply
discounts, remove shipping costs, and add gift items to the cart.

### Configuring Pricing Rules


Pricing rules are set up by combining conditions and actions. This allows
you to create complex marketing strategies directly within the Pimcore
backend.

### Displaying Applied Pricing Rules in the Frontend

To display the pricing rules applied to a product or cart, you need to add
some custom code to your templates. Here are examples for different
scenarios.

### 1. Product Detail Page

To display the applied pricing rules on the product detail page, use the
following Twig template code:

```twig

{% set priceInfo = product.OSPriceInfo %}

{% if priceInfo.rules %}

<div class="discounts">

<p><strong>{{ 'shop.detail.your_benefit'|trans }}</strong></p>

<ul>

{% for rule in priceInfo.rules %}

{% for action in rule.actions %}

{% if action is instanceof('Pimcore\Bundle\
EcommerceFrameworkBundle\PricingManager\Action\ProductDiscount') %}

{% if action.amount > 0 %}

<li>{{ rule.label }}
{{ 'shop.detail.your_benefit.discount.amount'|trans({'%amount%':
action.amount}) }}</li>

{% elseif action.percent > 0 %}


<li>{{ rule.label }}
{{ 'shop.detail.your_benefit.discount.percent'|trans({'%percent%':
action.percent}) }}</li>

{% endif %}

{% elseif action is instanceof('Pimcore\Bundle\


EcommerceFrameworkBundle\PricingManager\Action\GiftInterface') %}

<li>

{{ 'shop.detail.your_benefit.discount.gift'|
trans }}, <a
href="{{ action.product.getShopDetailLink() }}">{{ action.product.name }}</
a>

</li>

{% elseif action is instanceof('Pimcore\Bundle\


EcommerceFrameworkBundle\PricingManager\Action\FreeShipping') %}

<li>{{ 'shop.detail.your_benefit.discount.freeshipping'|trans }}</li>

{% endif %}

{% endfor %}

{% endfor %}

</ul>

</div>

{% endif %}

```

### 2. Cart Product List - Printing Gift Items

To display gift items added to the cart by pricing rules, use the following
Twig template code:

```twig

{% for item in cart.giftItems %}

{% set linkDetail = item.product.shopDetailLink %}


<tr>

<td class="cart-list-items-image">

<a href="{{ linkDetail }}">

<img src="{{ item.product.firstImage({width: 120, height:


120, aspectratio: true}) }}" alt="" border="0" />

</a>

</td>

<td class="cart-list-items-name" valign="top">

<a href="{{ linkDetail }}">{{ item.product.OSName }}</a>

</td>

<td class="cart-list-items-quantity">

{{ item.count }}

</td>

</tr>

{% endfor %}

```

### 3. Cart Price Modifications

All other price modifications at the cart level are included as cart price
modifiers. You can print them similarly by accessing the price modifiers
from the cart object.

### Example: Displaying Cart Price Modifications

Here's an example of how to display cart price modifications in the cart


template:

```twig
{% set grandTotal = cart.priceCalculator.grandTotal %}

{% if grandTotal.taxEntries %}

<tr>

<td>{{ 'cart.taxes'|trans }}</td>

<td>

{% for taxEntry in grandTotal.taxEntries %}

{{ taxEntry.entry.name }}: {{ taxEntry.percent }}%


({{ grandTotal.currency.toCurrency(taxEntry.amount) }})<br/>

{% endfor %}

</td>

</tr>

{% endif %}

```

### Summary

By setting up pricing rules in the Pimcore backend and adding the


appropriate code to your templates, you can provide dynamic pricing and
discounts to your customers. This enhances the shopping experience and
allows you to implement complex marketing strategies effortlessly.

User

Vouchers

Like Pricing Rules, also vouchers are supported out of the box by the
framework. To use vouchers, following steps are necessary:

Create an OnlineShopVoucherSeries object.

Create tokens based on the OnlineShopVoucherSeries.

Create a Pricing Rule for the OnlineShopVoucherSeries and define the


benefit of the voucher.

Allow the user to add a token to his cart.


Display voucher information to user.

Create an OnlineShopVoucherSeries object

A voucher series contains basic information of the voucher and settings for
creating the voucher tokens. It is represented by OnlineShopVoucherSeries
objects. The corresponding class is added to the system during installation
of the E-Commerce Framework. Creating Voucher Series

Currently there are two types of vouchers supported - Single and Pattern.

Single: One single token is defined that can be used multiple times.
Voucher Series Settings Single

Pattern: Tokens are generated based on a certain pattern definition.


Voucher Series Settings Pattern

Create tokens based on the OnlineShopVoucherSeries

In the Pimcore Backend UI, each OnlineShopVoucherSeries object has an


additional tab for managing the voucher tokens. Depending on the token type
there are different functions for managing the tokens and some statistics
concerning the voucher.

Simple: 'Activate' the token and specify how often it may be used. Create
Tokens Simple

Pattern: Create tokens based on the defined pattern, export created tokens
as csv and get an overview of created tokens and their usages. Create
Tokens Pattern

Create a Pricing Rule for the OnlineShopVoucherSeries

Once a voucher series is defined and tokens are created, a pricing rule has
to define the benefits of the voucher. To do so, a special condition allows
to specify the voucher series the pricing rule should be valid for. As
action all available actions for pricing rules can be used.

The voucher token condition also can contain an error message, that can be
shown if voucher token is added to cart, but not all other conditions of
the pricing rule are met.

Pricing Rule
Allow the User to Add a Token to his Cart

A voucher token is always applied to a cart. To do so, use following


snippet.

<?php

if ($token = strip_tags($request->get('voucher-code', ''))) {

try {

$success = $cart->addVoucherToken($token);

if ($success) {

$this->addFlash('success', $translator->trans('cart.voucher-
code-added'));

} else {

$this->addFlash('danger', $translator->trans('cart.voucher-
code-cound-not-be-added'));

} catch (VoucherServiceException $e) {

$this->addFlash('danger', $translator->trans('cart.error-voucher-
code-' . $e->getCode()));

Error Codes of Exceptions thrown

Code Description

1 Token already in use.

2 Token already reserved.

3 Token reservation not possible.

4 No token for this code exists.


5 Criteria oncePerCart: Token of same series already in cart.

6 Criteria onlyTokenPerCart: Tokens in cart and tried to add token of


type "only".

7 Criteria onlyTokenPerCart: Token of type "only" already in cart.

8 No more usages for a single token.

8 Token code not found in cart.

Display Voucher Information

Since benefits for vouchers are defined via pricing rules, no special
actions are needed to display them. They are just displayed the same way as
all other Pricing Rules.

Another consequence of defining the benefits of vouchers via pricing rules


is, that additional criteria (like date range etc.) can be defined to be
required to get the benefits. To get all necessary detail information about
vouchers, use getPricingManagerTokenInformationDetails of the cart or the
voucher service. This method returns an array of
PricingManagerTokenInformation for each added token with following
information:

Voucher Token

Token Object

List of applied pricing rules that require the given voucher token.

List of not applied pricing rules that would take the given voucher token
into account but are not applied because some other conditions are not met.

List of error messages that are defined in voucher token conditions of all
pricing rules that would take the given voucher token into account but are
not applied because some other conditions are not met.

Flag that indicates if no pricing rules are defined for the given voucher
token at all.

See an sample snippet to display the voucher information to the customer:

<form method="post" action="{{ path('shop-cart-apply-voucher') }}"


class="card p-2 mb-4">

{% if (cart.pricingManagerTokenInformationDetails | length > 0) %}


<ul class="list-group pb-3">

{% for codeInfo in cart.pricingManagerTokenInformationDetails %}

<li class="list-group-item">

<div class="row">

<div class="col-10" style="padding-top: 4px">

<div>{{ codeInfo.tokenCode }}</div>

{% if (codeInfo.errorMessages | length) > 0 %}

<small class="text-
muted">{{ codeInfo.errorMessages | join(', ') }}</small>

{% endif %}

{% if (codeInfo.noValidRule) %}

<small class="text-muted">{{ 'cart.voucher-no-


rule' | trans }}</small>

{% endif %}

</div>

<div class="col-2">

<a href="{{ path('shop-cart-remove-voucher',


{'voucher-code': codeInfo.tokenCode}) }}" class="btn btn-outline-danger
btn-sm">

<i class="fa fa-trash" aria-hidden="true"></i>

</a>

</div>
</div>

</li>

{% endfor %}

</ul>

{% endif %}

<div class="input-group">

<input name="voucher-code" type="text" class="form-control"


placeholder="{{ 'cart.voucher-code' | trans }}">

<div class="input-group-append">

<button type="submit" class="btn btn-secondary">{{ 'cart.apply-


voucher-code' | trans }}</button>

</div>

</div>

</form>

ChatGPT

## Using Vouchers in Pimcore E-Commerce Framework

Pimcore's E-Commerce Framework supports vouchers out of the box, allowing


for flexible and powerful promotional campaigns. Here's how to set up and
use vouchers in your Pimcore e-commerce application.

### Steps to Implement Vouchers

1. **Create an OnlineShopVoucherSeries Object**


2. **Create Tokens Based on the OnlineShopVoucherSeries**

3. **Create a Pricing Rule for the OnlineShopVoucherSeries**

4. **Allow the User to Add a Token to Their Cart**

5. **Display Voucher Information to the User**

### 1. Create an OnlineShopVoucherSeries Object

An `OnlineShopVoucherSeries` object contains the basic information and


settings for creating voucher tokens. Two types of vouchers are supported:

- **Single**: One single token that can be used multiple times.

- **Pattern**: Tokens generated based on a pattern.

#### Example

**Voucher Series Settings - Single:**

![Voucher Series Settings Single](https://path/to/single-voucher-settings-


image.png)

**Voucher Series Settings - Pattern:**

![Voucher Series Settings Pattern](https://path/to/pattern-voucher-


settings-image.png)

### 2. Create Tokens Based on the OnlineShopVoucherSeries

Each `OnlineShopVoucherSeries` object has a tab for managing voucher tokens


in the Pimcore Backend UI.
- **Simple**: Activate the token and specify how often it may be used.

- **Pattern**: Create tokens based on the pattern, export tokens as CSV,


and view token statistics.

### 3. Create a Pricing Rule for the OnlineShopVoucherSeries

Define the benefits of the voucher using a pricing rule. This involves
specifying the voucher series the rule applies to and setting the actions.

#### Example Pricing Rule

![Pricing Rule](https://path/to/pricing-rule-image.png)

### 4. Allow the User to Add a Token to Their Cart

A voucher token is applied to a cart. Use the following PHP snippet to add
a voucher token to the cart:

```php

<?php

if ($token = strip_tags($request->get('voucher-code', ''))) {

try {

$success = $cart->addVoucherToken($token);

if ($success) {

$this->addFlash('success', $translator->trans('cart.voucher-
code-added'));

} else {
$this->addFlash('danger', $translator->trans('cart.voucher-
code-could-not-be-added'));

} catch (VoucherServiceException $e) {

$this->addFlash('danger', $translator->trans('cart.error-voucher-
code-' . $e->getCode()));

```

#### Error Codes

| Code | Description |

|------|-------------|

| 1 | Token already in use. |

| 2 | Token already reserved. |

| 3 | Token reservation not possible. |

| 4 | No token for this code exists. |

| 5 | Token of the same series already in the cart. |

| 6 | Tried to add token of type "only" while other tokens exist. |

| 7 | Token of type "only" already in the cart. |

| 8 | No more usages for a single token. |

| 9 | Token code not found in the cart. |

### 5. Display Voucher Information to the User

Voucher benefits are defined via pricing rules, so they are displayed in
the same way as other pricing rules. Use
`getPricingManagerTokenInformationDetails` to retrieve detailed voucher
information.

#### Example Snippet to Display Voucher Information

```twig

<form method="post" action="{{ path('shop-cart-apply-voucher') }}"


class="card p-2 mb-4">

{% if cart.pricingManagerTokenInformationDetails | length > 0 %}

<ul class="list-group pb-3">

{% for codeInfo in cart.pricingManagerTokenInformationDetails


%}

<li class="list-group-item">

<div class="row">

<div class="col-10" style="padding-top: 4px">

<div>{{ codeInfo.tokenCode }}</div>

{% if codeInfo.errorMessages | length > 0 %}

<small class="text-
muted">{{ codeInfo.errorMessages | join(', ') }}</small>

{% endif %}

{% if codeInfo.noValidRule %}

<small class="text-muted">{{ 'cart.voucher-


no-rule' | trans }}</small>

{% endif %}

</div>

<div class="col-2">

<a href="{{ path('shop-cart-remove-voucher',


{'voucher-code': codeInfo.tokenCode}) }}" class="btn btn-outline-danger
btn-sm">

<i class="fa fa-trash" aria-


hidden="true"></i>
</a>

</div>

</div>

</li>

{% endfor %}

</ul>

{% endif %}

<div class="input-group">

<input name="voucher-code" type="text" class="form-control"


placeholder="{{ 'cart.voucher-code' | trans }}">

<div class="input-group-append">

<button type="submit" class="btn btn-secondary">{{ 'cart.apply-


voucher-code' | trans }}</button>

</div>

</div>

</form>

```

### Summary

By following these steps, you can effectively manage and apply vouchers in
your Pimcore E-Commerce application. This setup allows for flexible
promotional campaigns, enhancing the user experience and encouraging
customer loyalty.

User

Calculate with Prices

As floating point numbers (float, double) are not able to represent numbers
exactly (see here if you want to know details), and exact numbers are a
strict demand to e-commerce applications the E-Commerce Framrwork uses
Decimal value objects instead of floats to represent prices. These value
objects internally store the represented value as integer by defining a
fixed amount of supported digits (so-called scale) after the comma and by
multiplying the actual value with the given scale on construction. The
scale is set to 4 by default, but can be changed globally in the
pimcore_ecommerce_framework.decimal_scale config entry.

An example: Given a scale of 4, a Decimal will internally represent a


number of 123.45 as 1234500 by calculating 123.45 * 10^4 = 1234500.

To calculate with these values, the Decimal class exposes methods like
add(), sub(), mul(), div() and others to run calculations without having to
deal with the internal scale representation. For details see the Decimal
class definition and the corresponding test which contains a lot of usage
examples and describes the Decimal behaviour quite well.

Important: The Decimal is designed as immutable value object. Every


operation yields a new instance of a Decimal representing the new value.
Please be aware that this needs to be considered when calculating with
Decimals and/or when extending the Decimal class with custom functionality.

On the DB side, all E-Commerce Framework class definitions supporting price


values were updated to store prices as DECIMAL data type. This means, when
fetching a price value from an ecommerce-object (e.g. an order), it will be
a string instead of a float. This string can directly be passed to the
Decimal value object's create() method.

A usage example:

<?php

use Pimcore\Bundle\EcommerceFrameworkBundle\Type\Decimal;

$a = Decimal::create(10);

$b = Decimal::create(20);

$c = $a->add($b);

var_dump($c->asString()); // 30.0000 as the default string representation


contains all digits depending on the scale
// regarding immutability:

$a->add($b);

// $a is still 10 and will never be changed - the add() method returns a


new object ($c in the example above)

$a->equals(Decimal::create(30)); // false

$a->equals(Decimal::create(10)); // true

In most cases, you should be able to build a Decimal object by using the
static create() method which is able to build a Decimal from strings,
integers and floating point numbers. If needed, you can also make use of a
number of from* methods directly exposing costruction logic for a specific
type (e.g. fromDecimal(Decimal $decimal)).

Rounding logic

The Decimal object will try to avoid rounding and calculating with floats
if possible. If you pass a string to the create() method, it will try to
convert the numeric string to an integer with string operations before
falling back to converting it into a float which is rounded.

Examples (given a scale of 4):

Decimal::create('123') will just add 4 chars of 0 to the string and cast it


to an integer (no floats involved) - results in 1230000

Decimal::create('123.45') will move the dot to the right by 2 places and


add 2 chars of 0 - results in 1234500

However, if the given value exceeds the maximum scale or is a float value,
the create() method needs to fall back to float calculations and rounding
to generate the integer representation:

Decimal::create('123.1234567') with a string value will fall back to float


calculations as the amount of digits after the comma exceed the scale of 4.
The value is first multiplied with 10^4, resulting in PHP casting the
string to float. The float 1231234.567 is then passed to PHP's round()
function with a precision parameter of 0 and a default rounding mode of
PHP_ROUND_HALF_UP, resulting in an integer representation of 1231235 (note
the rounding on the last digit).

Decimal::create(123.1234567) with a float value will have the same


behaviour as above (skipping the string conversion).

You can influence how rounding is applied by specifying the $roundingMode


parameter on the create() method:

<?php

use Pimcore\Bundle\EcommerceFrameworkBundle\Type\Decimal;

var_dump(Decimal::create('123.55555', 4, PHP_ROUND_HALF_DOWN)->asString());
// 123.5555

var_dump(Decimal::create('123.55555', 4, PHP_ROUND_HALF_UP)->asString());
// 123.5556

Please be aware that as rounding is applied only when exceeding the scale,
the following can happen:

<?php

use Pimcore\Bundle\EcommerceFrameworkBundle\Type\Decimal;

// supported by scale -> 1.9999

var_dump(Decimal::create('1.9999')->asString());

// rounding is applied -> 2.0000

var_dump(Decimal::create('1.99999')->asString());
This is important to know as it could lead to unexpected calculation
results. The DECIMAL mysql data type has the same behaviour - if you
calculate with Decimals at a higher scale you still need to update your
class definitions to match that scale as otherwise the same rounding logic
will be applied by the database. However, while doing calculations (e.g.
tax or discount calculations, reports), you're free to calculate at a
higher scale by passing the scale parameter to the create() method and just
setting the resulting value to the scale represented on the DB. Example:

<?php

use Pimcore\Bundle\EcommerceFrameworkBundle\Type\Decimal;

// operate at a high scale supporting 8 digits after the comma

$a = Decimal::create(10, 8);

// do calculations

$b = $a->toPercentage(15);

// create a representation with a lower scale - at this point rounding


logic will be applied

$result = $b->withScale(4);

// an order object

$order->setTotalPrice($result->asString());

$order->save();

Extending the Decimal class

You're free to add custom calculation logic to the Decimal class, but
please make sure every operation returns a new instance holding the
calculated value. An object can never change its internal state (value and
scale) after construction!
Caveats/aspects good to know

In order to have sufficient number of digits in integer datatype, your


system should run on 64 bit infrastructure. On 32 bit systems, you would be
able to handle prices up to 214,748.3647 only (since max int value with 32
bit is 2,147,483,647). The Decimal implementation contains logic to throw
an exception on an integer overflow in case the used numbers are too
large/small.

ChatGPT

## Working with Prices in Pimcore E-Commerce Framework

### Decimal Value Objects

To handle prices accurately, the Pimcore E-Commerce Framework uses


`Decimal` value objects instead of floating point numbers. This ensures
precise price representation and calculations. The `Decimal` class
internally stores the value as an integer, scaled to a fixed number of
digits after the decimal point.

### Scale Configuration

The default scale (number of digits after the decimal point) is set to 4
but can be adjusted globally via the
`pimcore_ecommerce_framework.decimal_scale` configuration entry.

**Example**: With a scale of 4, the number 123.45 is internally represented


as 1234500 (i.e., 123.45 * 10^4 = 1234500).

### Creating and Using Decimal Objects

The `Decimal` class provides methods like `add()`, `sub()`, `mul()`, and
`div()` for calculations, ensuring the internal scale representation is
managed correctly.

**Example Usage**:
```php

use Pimcore\Bundle\EcommerceFrameworkBundle\Type\Decimal;

$a = Decimal::create(10);

$b = Decimal::create(20);

$c = $a->add($b);

echo $c->asString(); // Outputs: 30.0000

// Immutability example:

$a->add($b);

echo $a->asString(); // Outputs: 10.0000

echo $a->equals(Decimal::create(30)); // Outputs: false

echo $a->equals(Decimal::create(10)); // Outputs: true

```

### Construction Methods

You can create a `Decimal` object using various methods:

- `create()`: Builds a `Decimal` from strings, integers, and floats.

- `fromDecimal()`: Builds a `Decimal` from another `Decimal` object.

### Rounding Logic


The `Decimal` object avoids floating-point calculations when possible. When
necessary, it uses PHP's rounding functions.

**Examples**:

```php

use Pimcore\Bundle\EcommerceFrameworkBundle\Type\Decimal;

echo Decimal::create('123')->asString(); // Outputs: 123.0000

echo Decimal::create('123.45')->asString(); // Outputs: 123.4500

echo Decimal::create('123.1234567', 4, PHP_ROUND_HALF_UP)->asString(); //


Outputs: 123.1235

echo Decimal::create('123.1234567', 4, PHP_ROUND_HALF_DOWN)->asString(); //


Outputs: 123.1234

```

### Rounding and Scale Examples

When the value exceeds the scale, rounding is applied:

```php

use Pimcore\Bundle\EcommerceFrameworkBundle\Type\Decimal;

echo Decimal::create('1.9999')->asString(); // Outputs: 1.9999

echo Decimal::create('1.99999')->asString(); // Outputs: 2.0000

```

### Calculating with Higher Scale

You can perform calculations at a higher scale and then adjust the result
to a lower scale for storage.
**Example**:

```php

use Pimcore\Bundle\EcommerceFrameworkBundle\Type\Decimal;

// Higher scale calculation

$a = Decimal::create(10, 8);

$b = $a->toPercentage(15);

// Adjusting to a lower scale

$result = $b->withScale(4);

$order->setTotalPrice($result->asString());

$order->save();

```

### Extending the Decimal Class

When extending the `Decimal` class, ensure that every operation returns a
new instance, as `Decimal` objects are immutable.

### Caveats

- Ensure your system runs on a 64-bit infrastructure to handle large price


values accurately. On 32-bit systems, the maximum price is limited to
214,748.3647 due to the 32-bit integer limit.

- The `Decimal` class includes logic to throw an exception on integer


overflow, preventing inaccuracies due to excessively large or small values.
### Summary

The Pimcore E-Commerce Framework's use of `Decimal` value objects ensures


precise price calculations, essential for e-commerce applications. By
leveraging the provided methods and adhering to the immutability principle,
you can perform accurate and reliable pricing operations.

User

Working with Availabilities

For availabilities there is a similar concepts like the PriceSystems for


prices - which is called Availability Systems.

The Availability Systems are responsible for retrieving or calculating


availabilities of a product and returning a so called AvailabilityInfo
object which contains all the availability information. Each product can
have its own Availability System.

Configuration of Availability Systems

An availability system is a class implementing Pimcore\Bundle\


EcommerceFrameworkBundle\AvailabilitySystem\AvailabilitySystemInterface
which is defined as service and registered with a name in the
pimcore_ecommerce_framework.availability_systems configuration tree.

Currently, the framework ships only with a sample implementation which you
can use as starting point.

There are 3 places where the configuration of Availability Systems takes


place:

Product class: Each product has to implement the method


getAvailabilitySystemName() which returns the name of its Availability
System.

Service definition: Each Availability System must be registered as service

Configuration: The availability_systems section maps Availability System


names to service IDs

The product class returns the name of an Availability System:


<?php

class MyProduct implements \Pimcore\Bundle\EcommerceFrameworkBundle\Model\


CheckoutableInterface

public function getAvailabilitySystemName(): string

return 'myAvailabilitySystem';

Each Availability System must be defined as service (either a service


defined by core configuration or your custom services):

# services.yaml

_defaults:

public: false

autowire: true

autoconfigure: true

# AVAILABILITY SYSTEMS

Pimcore\Bundle\EcommerceFrameworkBundle\AvailabilitySystem\
AvailabilitySystem: ~
The availability_systems configuration maps names to service IDs:

pimcore_ecommerce_framework:

# defines 3 availability systems

availability_systems:

# the availability system is already defined in core


availability_systems.yaml service definition

default:

id: Pimcore\Bundle\EcommerceFrameworkBundle\AvailabilitySystem\
AvailabilitySystem

foo:

id: App\Ecommerce\AvailabilitySystem\CustomAvailabilitySystem

bar:

id: app.custom_attribute_availability_system

Getting Availabilities

Each product (if it implements CheckoutableInterface) needs to implement


the method getOSAvailabilityInfo which in the default implementation gets
the corresponding Availability System and calculates the availability.

The return value is an AvailabilityInterface object, which at least has one


getAvailable method and can contain additional availability information
(e.g. availability for different storage locations etc.).

This can be used to visualize availability on product detail pages or to


check, if a product can actually be checked out.

ChatGPT
## Working with Availabilities in Pimcore E-Commerce Framework

### Overview

Pimcore E-Commerce Framework provides a system for managing product


availabilities called **Availability Systems**. These systems are
responsible for retrieving or calculating the availability of a product and
returning an `AvailabilityInfo` object containing all the relevant
availability information. Each product can have its own Availability
System.

### Configuration of Availability Systems

Availability Systems are configured through a combination of product class


methods, service definitions, and framework configuration entries.

### Steps to Configure Availability Systems

1. **Implement the Availability System Interface**

2. **Define the Service**

3. **Map the Configuration**

### 1. Implement the Availability System Interface

An Availability System is a class that implements the `Pimcore\Bundle\


EcommerceFrameworkBundle\AvailabilitySystem\AvailabilitySystemInterface`.
Each product must implement the `getAvailabilitySystemName()` method to
return the name of its Availability System.

#### Example: Product Class Implementation

```php
<?php

class MyProduct implements \Pimcore\Bundle\EcommerceFrameworkBundle\Model\


CheckoutableInterface

public function getAvailabilitySystemName(): string

return 'myAvailabilitySystem';

```

### 2. Define the Service

Each Availability System must be defined as a service. This can be a core


service or a custom service.

#### Example: services.yaml

```yaml

services:

_defaults:

public: false

autowire: true

autoconfigure: true

# Define the default availability system


Pimcore\Bundle\EcommerceFrameworkBundle\AvailabilitySystem\
AvailabilitySystem: ~

# Define a custom availability system

App\Ecommerce\AvailabilitySystem\CustomAvailabilitySystem:

arguments: ['@some_dependency']

```

### 3. Map the Configuration

The `availability_systems` section in the configuration tree maps names to


service IDs.

#### Example: Configuration (config.yaml)

```yaml

pimcore_ecommerce_framework:

availability_systems:

default:

id: Pimcore\Bundle\EcommerceFrameworkBundle\AvailabilitySystem\
AvailabilitySystem

foo:

id: App\Ecommerce\AvailabilitySystem\CustomAvailabilitySystem

bar:

id: app.custom_attribute_availability_system

```

### Example Custom Availability System


#### Custom Availability System Class

```php

<?php

namespace App\Ecommerce\AvailabilitySystem;

use Pimcore\Bundle\EcommerceFrameworkBundle\AvailabilitySystem\
AvailabilitySystemInterface;

use Pimcore\Model\DataObject\AbstractObject;

use Pimcore\Bundle\EcommerceFrameworkBundle\AvailabilitySystem\
AvailabilityInfo;

class CustomAvailabilitySystem implements AvailabilitySystemInterface

public function getAvailability(AbstractObject $product):


AvailabilityInfo

// Custom logic to determine availability

$isAvailable = $product->getStock() > 0;

return new AvailabilityInfo($isAvailable);

```

### Retrieving Availabilities


Each product that implements `CheckoutableInterface` must implement the
`getOSAvailabilityInfo()` method. This method retrieves the corresponding
Availability System and calculates the availability.

#### Example: Product Class Method

```php

<?php

use Pimcore\Bundle\EcommerceFrameworkBundle\AvailabilitySystem\
AvailabilityInfo;

class MyProduct implements \Pimcore\Bundle\EcommerceFrameworkBundle\Model\


CheckoutableInterface

public function getOSAvailabilityInfo(): AvailabilityInfo

$availabilitySystemName = $this->getAvailabilitySystemName();

$availabilitySystem = \Pimcore::getContainer()-
>get('pimcore_ecommerce.factory')

->getAvailabilitySystem($availabilitySystemName);

return $availabilitySystem->getAvailability($this);

```

### Using Availability Information


The returned `AvailabilityInfo` object can be used to visualize
availability on product detail pages or to check if a product can be
checked out.

#### Example: Displaying Availability on Product Detail Page

```twig

{% set availabilityInfo = product.OSAvailabilityInfo %}

{% if availabilityInfo.isAvailable %}

<p class="available">In Stock</p>

{% else %}

<p class="not-available">Out of Stock</p>

{% endif %}

```

### Summary

By following these steps, you can configure and use Availability Systems in
Pimcore's E-Commerce Framework. This setup allows for flexible and
customized availability calculations, enhancing the overall shopping
experience for your customers.

User

Cart Manager

The Cart Manager is responsible for all aspects concerning carts and can
manage multiple carts. Important to know is, that in the E-Commerce
Framework every user specific product collection is a cart. No matter how
it is called (cart, wish list, compare list, ...), all these product
collections need the same base functionality. Therefore, all different
product collections are carts with a specific name.

Working with Carts


Creating carts

<?php

$manager = Factory::getInstance()->getCartManager();

$cartId = $manager->createCart(array('name' => $cartName));

$cart = $manager->getCart( $cartId );

Adding and removing products

<?php

$manager = Factory::getInstance()->getCartManager();

$cart = $manager->getCartByName($cartName);

$id = $cart->addItem( $product, $amount );

$cart->save();

$cart->removeItem( $id );

$cart->save();

//alternative way

$cartItemId = $manager->addToCart( $product, $amount, $cart->getId() );

//save is done automatically

$manager->removeFromCart($cartItemId, $cartId);

//save is done automatically

List products of cart


<?php

$manager = Factory::getInstance()->getCartManager();

$cart = $manager->getCartByName($cartName);

if (count($cart->getItems()) > 0) {

foreach ($cart->getItems() as $item) {

$product = $item->getProduct();

//item key

$cartItemId = $item->getItemKey();

//item amount

$amount = $item->getCount();

//price info and price

$priceInfo = $item->getPriceInfo();

$price = $item->getPrice();

Price Calculation in Carts

Each cart has a CartPriceCalculator (configuration see below) which is


responsible for calculating total sums of the cart. The CartPriceCalculator
sums up all product prices to a sub total, adds (or subtracts) so called
price modificators like shipping costs, cart discounts, etc. and then
calculates a grand total.

See sample below for how to get the different sums:


<?php

// delivers sum without any price modifications

$subTotal = $cart->getPriceCalculator()->getSubTotal();

// iterates through all price modifications

foreach ($cart->getPriceCalculator()->getPriceModifications() as $name =>


$modification) {

// $name is the label of a modification

// $modification is an implementation of \Pimcore\Bundle\


EcommerceFrameworkBundle\PriceSystem\ModificatedPriceInterface

// delivers sum including all price modifications

$grandTotal = $cart->getPriceCalculator()->getGrandTotal();

Configuration of Cart Manager

The configuration takes place in the


pimcore_ecommerce_framework.cart_manager configuration section which is
tenant aware.

pimcore_ecommerce_framework:

cart_manager:

tenants:

# defaults for all cart managers

_defaults:

# define service manager id of cart service - following


value is default and can be omitted

cart_manager_id: Pimcore\Bundle\EcommerceFrameworkBundle\
CartManager\MultiCartManager
# configuration for carts - the following values are set by
default and can be omitted

cart:

# service ID of a cart factory which creates individual


carts at runtime

factory_id: Pimcore\Bundle\EcommerceFrameworkBundle\
CartManager\CartFactory

# options passed to cart factory, e.g. the cart class


(available options vary by factory implementation)

factory_options:

cart_class_name: Pimcore\Bundle\
EcommerceFrameworkBundle\CartManager\Cart

guest_cart_class_name: Pimcore\Bundle\
EcommerceFrameworkBundle\CartManager\SessionCart

default:

price_calculator:

# list price modificators for cart, e.g. for shipping-


cost, special discounts, ...

# key is name of modificator

modificators:

shipping:

class: Pimcore\Bundle\EcommerceFrameworkBundle\
CartManager\CartPriceModificator\Shipping

# configuration options for price modificator

options:

charge: "5.90"

# additional checkout tenant for cart manager


# - active tenant is set at \Pimcore\Bundle\
EcommerceFrameworkBundle\EnvironmentInterface::setCurrentCheckoutTenant()

noShipping: ~ # inherits from _defaults

Following elements are configured:

Cart manager service ID: The cart manager is the basic entry point for
working with carts. It is responsible for all interactions with different
carts and provides functionality as creating carts, adding/removing
products and also creates the corresponding price calculator.

Cart factory service ID: builds carts when needed and can be configured
with cart class name and further options varying by factory implementation

Price calculator factory service ID + options and modificators: The price


calculator is a framework for calculation and modification (shipping costs,
discounts, ...) of prices on cart level. Each modification is implemented
in a CartPriceModificatorInterface class. See Shipping or Discount for
examples.

Available Cart Implementations

Following cart implementations are shipped with Pimcore core and can be
configured in the factory_options section of the cart manager
configuration:

Session-Cart (class name Pimcore\Bundle\EcommerceFrameworkBundle\


CartManager\SessionCart): This cart implementation stores all cart
information in the session of the user. If the session is cleared, also the
carts are deleted. Use this implementation when no user login is available
and storing carts in the database has no benefit.

Database-Cart (class name Pimcore\Bundle\EcommerceFrameworkBundle\


CartManager\Cart): This cart implementation stores all cart information in
the database. In this case, it is important that the currently logged in
user is set to the E-Commerce Framework Environment with the code snippet
in the box below. Use this implementation when user logins are available
and the carts should be persisted beyond session lifetime.

Note: if you are using the database cart, don't forget to set the currently
logged in user to the environment like follows: Factory::getInstance()-
>getEnvironment()->setCurrentUserId(YOUR_USER_ID)
Checkout Tenants for Carts

The E-Commerce Framework has the concept of so called Checkout Tenants


which allow different cart manager and checkout manager configurations
based on a currently active checkout tenant.

The current checkout tenant is set in the framework environment as follows:

<?php

$environment = Factory::getInstance()->getEnvironment();

$environment->setCurrentCheckoutTenant('default');

$environment->save();

$environment->setCurrentCheckoutTenant('noShipping');

$environment->save();

Once set, the cart manager uses all specific settings of the currently
active checkout tenant which are configured in the configuration
(identified by tenant name).

See also Demo for some examples.

Adding Custom Properties to Cart Items

Following steps are necessary to add additional custom properties to cart


items:

Extend Pimcore\Bundle\EcommerceFrameworkBundle\CartManager\CartItem
implementation and add your custom properties including getters/setters.

Extend Cart::getCartItemClassName implementation and make sure your custom


CartItem implementation gets returned.
Provide the custom properties as key-value pairs in $params parameter in
the following methods:

Pimcore\Bundle\EcommerceFrameworkBundle\CartManager\AbstractCart::addItem

Pimcore\Bundle\EcommerceFrameworkBundle\CartManager\
AbstractCart::updateItem

Pimcore\Bundle\EcommerceFrameworkBundle\CartManager\
CartManagerInterface::addToCart

ChatGPT

## Cart Manager in Pimcore E-Commerce Framework

The Cart Manager in Pimcore E-Commerce Framework manages all aspects


related to carts, including creating, adding/removing products, and
calculating prices. Each user-specific product collection (cart, wishlist,
compare list, etc.) is managed as a cart within this framework.

### Working with Carts

#### Creating Carts

```php

$manager = Factory::getInstance()->getCartManager();

$cartId = $manager->createCart(['name' => $cartName]);

$cart = $manager->getCart($cartId);

```

#### Adding and Removing Products

```php

$manager = Factory::getInstance()->getCartManager();

$cart = $manager->getCartByName($cartName);
$id = $cart->addItem($product, $amount);

$cart->save();

$cart->removeItem($id);

$cart->save();

// Alternative way

$cartItemId = $manager->addToCart($product, $amount, $cart->getId());

// Save is done automatically

$manager->removeFromCart($cartItemId, $cartId);

// Save is done automatically

```

#### Listing Products in a Cart

```php

$manager = Factory::getInstance()->getCartManager();

$cart = $manager->getCartByName($cartName);

if (count($cart->getItems()) > 0) {

foreach ($cart->getItems() as $item) {

$product = $item->getProduct();

// Item key

$cartItemId = $item->getItemKey();
// Item amount

$amount = $item->getCount();

// Price info and price

$priceInfo = $item->getPriceInfo();

$price = $item->getPrice();

```

### Price Calculation in Carts

Each cart has a `CartPriceCalculator` that is responsible for calculating


the total sums of the cart. The calculator sums up all product prices to a
subtotal, applies price modifications (e.g., shipping costs, discounts),
and calculates the grand total.

#### Example: Retrieving Sums

```php

// Delivers sum without any price modifications

$subTotal = $cart->getPriceCalculator()->getSubTotal();

// Iterates through all price modifications

foreach ($cart->getPriceCalculator()->getPriceModifications() as $name =>


$modification) {

// $name is the label of a modification


// $modification is an implementation of \Pimcore\Bundle\
EcommerceFrameworkBundle\PriceSystem\ModificatedPriceInterface

// Delivers sum including all price modifications

$grandTotal = $cart->getPriceCalculator()->getGrandTotal();

```

### Configuration of Cart Manager

Configuration is defined in the `pimcore_ecommerce_framework.cart_manager`


section of the configuration file and is tenant-aware.

#### Example Configuration

```yaml

pimcore_ecommerce_framework:

cart_manager:

tenants:

# defaults for all cart managers

_defaults:

# define service manager id of cart service - following


value is default and can be omitted

cart_manager_id: Pimcore\Bundle\EcommerceFrameworkBundle\
CartManager\MultiCartManager

# configuration for carts - the following values are set by


default and can be omitted

cart:
# service ID of a cart factory which creates individual
carts at runtime

factory_id: Pimcore\Bundle\EcommerceFrameworkBundle\
CartManager\CartFactory

# options passed to cart factory, e.g. the cart class


(available options vary by factory implementation)

factory_options:

cart_class_name: Pimcore\Bundle\
EcommerceFrameworkBundle\CartManager\Cart

guest_cart_class_name: Pimcore\Bundle\
EcommerceFrameworkBundle\CartManager\SessionCart

default:

price_calculator:

# list price modificators for cart, e.g. for shipping-


cost, special discounts, ...

# key is name of modificator

modificators:

shipping:

class: Pimcore\Bundle\EcommerceFrameworkBundle\
CartManager\CartPriceModificator\Shipping

# configuration options for price modificator

options:

charge: "5.90"

# additional checkout tenant for cart manager

# - active tenant is set at \Pimcore\Bundle\


EcommerceFrameworkBundle\EnvironmentInterface::setCurrentCheckoutTenant()

noShipping: ~ # inherits from _defaults

```
### Elements of Configuration

- **Cart manager service ID**: Entry point for working with carts,
responsible for creating carts and interacting with them.

- **Cart factory service ID**: Builds carts when needed, configurable with
cart class name and other options.

- **Price calculator factory service ID**: Calculates and modifies prices


on the cart level (e.g., shipping costs, discounts).

### Available Cart Implementations

- **Session-Cart** (`Pimcore\Bundle\EcommerceFrameworkBundle\CartManager\
SessionCart`): Stores cart information in the user's session. Ideal for
guest users without login.

- **Database-Cart** (`Pimcore\Bundle\EcommerceFrameworkBundle\CartManager\
Cart`): Stores cart information in the database. Ideal for logged-in users,
ensuring persistence beyond session lifetime.

### Setting Current User for Database Cart

```php

Factory::getInstance()->getEnvironment()->setCurrentUserId(YOUR_USER_ID);

```

### Checkout Tenants for Carts

Checkout Tenants allow different cart manager and checkout manager


configurations based on the active tenant.

#### Setting the Checkout Tenant


```php

$environment = Factory::getInstance()->getEnvironment();

$environment->setCurrentCheckoutTenant('default');

$environment->save();

$environment->setCurrentCheckoutTenant('noShipping');

$environment->save();

```

### Adding Custom Properties to Cart Items

1. **Extend CartItem Implementation**

```php

namespace App\Ecommerce\CartManager;

use Pimcore\Bundle\EcommerceFrameworkBundle\CartManager\CartItem;

class CustomCartItem extends CartItem

private $customProperty;

public function getCustomProperty()

return $this->customProperty;

}
public function setCustomProperty($customProperty)

$this->customProperty = $customProperty;

```

2. **Extend Cart Implementation**

```php

namespace App\Ecommerce\CartManager;

use Pimcore\Bundle\EcommerceFrameworkBundle\CartManager\Cart;

class CustomCart extends Cart

protected function getCartItemClassName()

return CustomCartItem::class;

```

3. **Provide Custom Properties**

```php
$cart->addItem($product, $amount, ['customProperty' => 'value']);

```

By following these steps, you can effectively manage and customize the cart
functionalities in Pimcore's E-Commerce Framework. This flexibility allows
you to adapt the cart system to meet various business requirements.

User

Checkout Manager

The Checkout Manager is responsible for all aspects concerning checkout


process and an one-stop API for getting through the checkout process.

But: The checkout manager is not an out-of-the-box checkout process! It is


a tool and a set of components the developer can use to create a use case
specific checkout process.

Starting with Pimcore 6.1 an optimized checkout manager architecture was


introduced. This is parallel to the old architecture, which is deprecated
now and will be removed in Pimcore 10. For details see Checkout Manager
Details.

Involved Modules and their function

Controller: Website Controller that controls the flow.

Cart: Cart is the cart and user should be able to modify the cart all the
time.

CheckoutManager: One-Stop API for controller to manage checkout, start and


handle payments and commit orders.

OrderManager: API for working with orders - creating them, listing them,
etc.

OrderAgent: API for manipulating single order, also responsible for status
management of payments within order.

PaymentProvider: Interface to payment provider.

CommitOrderProcessor: Worker that handles all steps to commit order after


payment was successfully finished by user.

See following sub pages for detailed information


Basic configuration of Checkout Manager

Setting up Checkout Steps

Committing Orders

Integrating Payment

Using Checkout Tenants

ChatGPT

## Checkout Manager in Pimcore E-Commerce Framework

The Checkout Manager is a comprehensive tool and set of components designed


to facilitate the creation of a customized checkout process. It integrates
various modules such as controllers, carts, payment providers, and order
management to ensure a seamless and flexible checkout experience.

### Involved Modules and Their Functions

1. **Controller**: Manages the flow of the checkout process through website


controllers.

2. **Cart**: Allows users to modify the cart at any time during the
checkout process.

3. **CheckoutManager**: Provides a one-stop API for managing the checkout


process, starting and handling payments, and committing orders.

4. **OrderManager**: API for creating, listing, and managing orders.

5. **OrderAgent**: API for manipulating single orders and managing payment


statuses within orders.

6. **PaymentProvider**: Interface to various payment providers.

7. **CommitOrderProcessor**: Handles all steps to commit the order after


payment is successfully completed.

### Basic Configuration of Checkout Manager


The configuration is defined in the
`pimcore_ecommerce_framework.checkout_manager` section of the configuration
file and is tenant-aware.

#### Example Configuration

```yaml

pimcore_ecommerce_framework:

checkout_manager:

tenants:

# defaults for all checkout managers

_defaults:

# define service manager id of checkout manager - following


value is default and can be omitted

factory_id: Pimcore\Bundle\EcommerceFrameworkBundle\
CheckoutManager\CheckoutManagerFactory

# configuration for checkout steps - the following values


are set by default and can be omitted

steps:

review:

class: Pimcore\Bundle\EcommerceFrameworkBundle\
CheckoutManager\Step\ReviewStep

options:

template: ':Checkout:review.html.twig'

default:

# Define payment provider to use

payment:

provider: my_payment_provider
# Define commit order processor

commit_order_processor:

id: Pimcore\Bundle\EcommerceFrameworkBundle\
CheckoutManager\CommitOrderProcessor

options: []

```

### Setting Up Checkout Steps

Checkout steps define the flow of the checkout process. Each step is a
class that implements specific logic for a stage in the checkout process.

#### Example: Defining Checkout Steps

```yaml

pimcore_ecommerce_framework:

checkout_manager:

tenants:

default:

steps:

review:

class: Pimcore\Bundle\EcommerceFrameworkBundle\
CheckoutManager\Step\ReviewStep

options:

template: ':Checkout:review.html.twig'

payment:

class: Pimcore\Bundle\EcommerceFrameworkBundle\
CheckoutManager\Step\PaymentStep
options:

template: ':Checkout:payment.html.twig'

confirmation:

class: Pimcore\Bundle\EcommerceFrameworkBundle\
CheckoutManager\Step\ConfirmationStep

options:

template: ':Checkout:confirmation.html.twig'

```

### Committing Orders

The `CommitOrderProcessor` is responsible for finalizing the order after


payment is completed. It handles order creation, payment status updates,
and order confirmation.

#### Example: Order Committing

```php

$checkoutManager = $factory->getCheckoutManager();

$checkoutManager->startCheckout($cart, $user, $checkoutTenant);

$commitOrderProcessor = $checkoutManager->getCommitOrderProcessor();

$commitOrderProcessor->commitOrder($order, $paymentStatus);

```

### Integrating Payment

Payment integration is done through `PaymentProvider` interfaces. Each


payment provider handles the interaction with different payment gateways.
#### Example: Payment Provider Configuration

```yaml

pimcore_ecommerce_framework:

payment_manager:

providers:

my_payment_provider:

provider_id: App\Ecommerce\PaymentProvider\
MyPaymentProvider

profile: default

profiles:

default:

username: 'my_username'

password: 'my_password'

```

#### Example: Payment Provider Implementation

```php

namespace App\Ecommerce\PaymentProvider;

use Pimcore\Bundle\EcommerceFrameworkBundle\PaymentManager\
PaymentProviderInterface;

class MyPaymentProvider implements PaymentProviderInterface

public function processPayment($order, $paymentDetails)


{

// Implement payment processing logic

public function getPaymentStatus($order)

// Implement logic to retrieve payment status

```

### Using Checkout Tenants

Checkout Tenants allow different configurations for the checkout process


based on the active tenant. This enables multiple checkout flows within the
same system.

#### Example: Setting Checkout Tenant

```php

$environment = Factory::getInstance()->getEnvironment();

$environment->setCurrentCheckoutTenant('default');

$environment->save();

$environment->setCurrentCheckoutTenant('customTenant');

$environment->save();

```
### Summary

The Checkout Manager in Pimcore E-Commerce Framework provides a robust and


flexible set of tools to create a custom checkout process. By leveraging
the various modules and configuration options, developers can tailor the
checkout experience to meet specific business needs. This comprehensive
approach ensures that all aspects of the checkout, from cart management to
payment processing, are seamlessly integrated and easily manageable.

User

Basic Configuration

The configuration takes place in the


pimcore_ecommerce_framework.checkout_manager configuration section and is
tenant aware.

pimcore_ecommerce_config:

checkout_manager:

tenants:

_defaults:

# the following two values are default values an can be


omitted

# service ID of a checkout manager factory which builds


cart specific checkout managers

factory_id: Pimcore\Bundle\EcommerceFrameworkBundle\
CheckoutManager\CheckoutManagerFactory

# options passed to the factory - available options vary by


implementation

factory_options:

class: \Pimcore\Bundle\EcommerceFrameworkBundle\
CheckoutManager\V7\CheckoutManager

handle_pending_payments_strategy: Pimcore\Bundle\
EcommerceFrameworkBundle\CheckoutManager\V7\HandlePendingPayments\
CancelPaymentOrRecreateOrderStrategy

# commit order processor


commit_order_processor:

# order processor service ID

id: Pimcore\Bundle\EcommerceFrameworkBundle\
CheckoutManager\V7\CommitOrderProcessor

# options passed to the commit order processor -


available options vary by implementation

options:

confirmation_mail: /en/emails/order-confirmation

# define different checkout steps which need to be


committed before commit of order is possible

steps:

deliveryaddress:

class: \Pimcore\Bundle\EcommerceFrameworkBundle\
CheckoutManager\DeliveryAddress

# example step from the Ecommerce demo, which extends


AbstractStep

confirm:

class: \App\Ecommerce\Checkout\Confirm

default:

# define payment provider which should be used for payment.

# payment providers are defined in payment_manager section.

payment:

provider: qpay

paypal:
payment:

provider: paypal

Following elements are configured:

Service ID and options of the checkout manager factory: The Checkout


Manager is a central player of the checkout process. It checks the state of
single checkout steps, is responsible for the payment integration and also
calls the commit order processor in the end. As the a checkout manager is
specific to a cart instance, checkout manager factory takes care of
creating checkout managers on demand.

Optional configuration option handle_pending_payments_strategy defines


strategy how to handle pending payments. See Integrating Payment for
details.

Checkout steps and their implementation: Each checkout step (e.g. Delivery
address, delivery date, ...) needs a concrete checkout step implementation.
The implementation is responsible for storing and validating the necessary
data, is project dependent and has to be implemented for each project.

Service ID and options of the commit order processor: When finalization of


the order is done by the commit order processor. This is the places, where
custom ERP integrations and other project dependent order finishing stuff
should be placed.

Additional stuff like:

Mail configuration

Payment Implementation

Checkout Tenants

ChatGPT

## Basic Configuration of Checkout Manager

The configuration of the Checkout Manager in the Pimcore E-Commerce


Framework is managed within the
`pimcore_ecommerce_framework.checkout_manager` section of the configuration
file. This setup is tenant-aware, allowing for multiple checkout flows
within the same system.
### Example Configuration

```yaml

pimcore_ecommerce_framework:

checkout_manager:

tenants:

_defaults:

# Service ID of a checkout manager factory which builds


cart specific checkout managers

factory_id: Pimcore\Bundle\EcommerceFrameworkBundle\
CheckoutManager\CheckoutManagerFactory

# Options passed to the factory - available options vary by


implementation

factory_options:

class: \Pimcore\Bundle\EcommerceFrameworkBundle\
CheckoutManager\V7\CheckoutManager

handle_pending_payments_strategy: Pimcore\Bundle\
EcommerceFrameworkBundle\CheckoutManager\V7\HandlePendingPayments\
CancelPaymentOrRecreateOrderStrategy

# Commit order processor

commit_order_processor:

# Order processor service ID

id: Pimcore\Bundle\EcommerceFrameworkBundle\
CheckoutManager\V7\CommitOrderProcessor

# Options passed to the commit order processor -


available options vary by implementation

options:
confirmation_mail: /en/emails/order-confirmation

# Define different checkout steps which need to be


committed before commit of order is possible

steps:

deliveryaddress:

class: \Pimcore\Bundle\EcommerceFrameworkBundle\
CheckoutManager\DeliveryAddress

# Example step from the Ecommerce demo, which extends


AbstractStep

confirm:

class: \App\Ecommerce\Checkout\Confirm

default:

# Define payment provider which should be used for payment.

# Payment providers are defined in payment_manager section.

payment:

provider: qpay

paypal:

payment:

provider: paypal

```

### Configured Elements

1. **Service ID and Options of the Checkout Manager Factory**


- **Factory ID**: Identifies the factory that creates checkout managers
for specific cart instances.

- **Factory Options**: Includes settings like the class of the checkout


manager and strategies for handling pending payments.

2. **Handle Pending Payments Strategy**

- **Strategy**: Defines how to handle pending payments. For example,


`CancelPaymentOrRecreateOrderStrategy`.

3. **Checkout Steps and Their Implementation**

- Each step in the checkout process (e.g., delivery address, delivery


date) needs a concrete implementation. These steps are responsible for
storing and validating necessary data. Example:

```yaml

steps:

deliveryaddress:

class: \Pimcore\Bundle\EcommerceFrameworkBundle\
CheckoutManager\DeliveryAddress

confirm:

class: \App\Ecommerce\Checkout\Confirm

```

4. **Commit Order Processor**

- **Order Processor Service ID**: Identifies the service responsible


for finalizing the order.

- **Options**: Includes settings such as the path to the confirmation


email template.

5. **Additional Configurations**

- **Mail Configuration**: Specifies the email templates to be used


during the checkout process.
- **Payment Implementation**: Configures payment providers used in the
checkout process.

- **Checkout Tenants**: Allows for tenant-specific configurations,


enabling different checkout flows within the same system.

### Explanation of Key Elements

#### 1. Checkout Manager Factory

The Checkout Manager Factory is central to the checkout process. It ensures


that each cart instance has a specific checkout manager that handles the
state of individual checkout steps, integrates payment, and invokes the
commit order processor.

#### 2. Handle Pending Payments Strategy

The strategy for handling pending payments defines how the system should
manage payments that are not completed immediately. This can include
cancelling pending payments or recreating orders.

#### 3. Checkout Steps

Checkout steps are custom implementations that handle specific parts of the
checkout process. They are responsible for data validation and storage.
Each step is configured with a class that implements the required
functionality.

#### 4. Commit Order Processor

The commit order processor finalizes the order by performing tasks such as
integrating with ERP systems and sending confirmation emails. It is
customizable to meet specific project requirements.
#### 5. Additional Configurations

Additional settings include mail configurations for sending order


confirmations, payment provider settings, and tenant-specific checkout
flows.

### Summary

By configuring the Checkout Manager and its associated components,


developers can create a flexible and customizable checkout process tailored
to specific business needs. The tenant-aware configuration allows for
multiple checkout flows within the same system, ensuring that different
user groups can have unique checkout experiences.

User

Checkout Steps

For each checkout step (e.g. delivery address, delivery date, ...) there
has to be a concrete checkout step implementation. This implementation is
responsible for storage and loading of necessary checkout data for each
step. It needs to extend \Pimcore\Bundle\EcommerceFrameworkBundle\
CheckoutManager\AbstractStep and implement \Pimcore\Bundle\
EcommerceFrameworkBundle\CheckoutManager\CheckoutStepInterface.

Following methods have to be implemented:

commit($data): Is called when step is finished and data needs to be saved.

getData(): Returns saved data for this step.

getName(): Returns name of the step.

Configuration of Checkout Steps:

See configuration for checkout step configuration.

Sample Implementation of a Checkout Step:

<?php
namespace Pimcore\Bundle\EcommerceFrameworkBundle\CheckoutManager;

/**

* Class \Pimcore\Bundle\EcommerceFrameworkBundle\CheckoutManager\
DeliveryAddress

* sample implementation for delivery address

*/

class DeliveryAddress extends AbstractStep implements CheckoutStepInterface

/**

* namespace key

*/

const PRIVATE_NAMESPACE = 'delivery_address';

public function getName(): string

return 'deliveryaddress';

/**

* sets delivered data and commits step

*/

public function commit(mixed $data): bool

$this->cart->setCheckoutData(self::PRIVATE_NAMESPACE,
json_encode($data));
return true;

/**

* returns saved data of step

*/

public function getData(): mixed

$data = json_decode($this->cart-
>getCheckoutData(self::PRIVATE_NAMESPACE));

return $data;

Working with Steps:

<?php

$manager = Factory::getInstance()->getCheckoutManager($cart);

$step = $manager->getCheckoutStep("deliveryaddress");

$address = new stdClass();

//fill address

$manager->commitStep($step, $address);

$step = $manager->getCheckoutStep("deliverydate");

$manager->commitStep($step, $data);
$cart->save();

ChatGPT

## Checkout Steps in Pimcore E-Commerce Framework

Each checkout step in the Pimcore E-Commerce Framework must have a concrete
implementation responsible for the storage and retrieval of the necessary
checkout data. These implementations must extend `\Pimcore\Bundle\
EcommerceFrameworkBundle\CheckoutManager\AbstractStep` and implement `\
Pimcore\Bundle\EcommerceFrameworkBundle\CheckoutManager\
CheckoutStepInterface`.

### Required Methods for Checkout Steps

1. **commit($data)**: Called when the step is finished, and data needs to


be saved.

2. **getData()**: Returns the saved data for this step.

3. **getName()**: Returns the name of the step.

### Example Implementation of a Checkout Step

Here is a sample implementation for a delivery address step:

```php

namespace Pimcore\Bundle\EcommerceFrameworkBundle\CheckoutManager;

/**

* Class DeliveryAddress

* Sample implementation for delivery address


*/

class DeliveryAddress extends AbstractStep implements CheckoutStepInterface

/**

* Namespace key

*/

const PRIVATE_NAMESPACE = 'delivery_address';

public function getName(): string

return 'deliveryaddress';

/**

* Sets delivered data and commits step

*/

public function commit(mixed $data): bool

$this->cart->setCheckoutData(self::PRIVATE_NAMESPACE,
json_encode($data));

return true;

/**

* Returns saved data of step

*/
public function getData(): mixed

$data = json_decode($this->cart-
>getCheckoutData(self::PRIVATE_NAMESPACE));

return $data;

```

### Configuration of Checkout Steps

Checkout steps are configured in the `pimcore_ecommerce_framework`


configuration section. Below is an example of how to configure checkout
steps:

```yaml

pimcore_ecommerce_framework:

checkout_manager:

tenants:

default:

steps:

deliveryaddress:

class: \Pimcore\Bundle\EcommerceFrameworkBundle\
CheckoutManager\DeliveryAddress

confirm:

class: \App\Ecommerce\Checkout\Confirm

```
### Working with Steps

Here is an example of how to work with checkout steps in a controller:

```php

$manager = Factory::getInstance()->getCheckoutManager($cart);

// Working with the delivery address step

$step = $manager->getCheckoutStep("deliveryaddress");

$address = new stdClass();

// Fill address with necessary data

$address->street = '123 Main St';

$address->city = 'Anytown';

$address->postalCode = '12345';

$address->country = 'USA';

$manager->commitStep($step, $address);

// Working with another step (e.g., delivery date)

$step = $manager->getCheckoutStep("deliverydate");

$deliveryDate = new stdClass();

// Fill delivery date with necessary data

$deliveryDate->date = '2024-07-25';

$manager->commitStep($step, $deliveryDate);

$cart->save();

```
### Summary

Implementing and configuring checkout steps in the Pimcore E-Commerce


Framework involves creating concrete implementations of each step,
configuring them in the system, and then managing these steps within your
application. This modular approach allows for a highly customizable and
flexible checkout process that can be tailored to specific business needs.

User

Committing Orders

After all checkout steps are completed, the order can be committed. If no
payment is involved, this is done as follows. If payment is involved, have
a look at the Payment Integration docs.

<?php

$manager = Factory::getInstance()->getCheckoutManager($cart);

$order = $manager->commitOrder();

While committing the order, the checkout manager delegates it to the


specified commit order processor implementation, which needs to implement \
Pimcore\Bundle\EcommerceFrameworkBundle\CheckoutManager\
CommitOrderProcessorInterface.

This is the place where all functionality for committing the order (e.g.
sending orders to erp systems, sending order confirmation mails, ...) is
located.

The default implementation \Pimcore\Bundle\EcommerceFrameworkBundle\


CheckoutManager\V7\CommitOrderProcessor provides basic functionality like
creating a Pimcore order object and sending an order confirmation mail.

Order creation itself is delegated to the \Pimcore\Bundle\


EcommerceFrameworkBundle\OrderManager\OrderManagerInterface.

Typically needed Custom Extensions


In simple use cases a project specific implementation needs

...to extend \Pimcore\Bundle\EcommerceFrameworkBundle\OrderManager\V7\


OrderManager and overwrite the method applyCustomCheckoutDataToOrder to add
additional custom fields to the order object and

...to extend \Pimcore\Bundle\EcommerceFrameworkBundle\CheckoutManager\V7\


CommitOrderProcessor and overwrite the method processOrder where website
specific functionality is integrated (sending orders to erp systems, ...).

See following examples for details.

Order Manager

If additional information needs to be stored into the order, the


OrderManager has to be extended. For more Information concerning the
OrderManager see the documentation.

A simple implementation of App\Ecommerce\Order\OrderManager could look


like:

<?php

class OrderManager extends \Pimcore\Bundle\EcommerceFrameworkBundle\


OrderManager\V7\OrderManager

/**

* @throws InvalidConfigException

*/

protected function applyCustomCheckoutDataToOrder(CartInterface $cart,


AbstractOrder $order): AbstractOrder

/** @var AbstractOrder $order */

$order = parent::applyCustomCheckoutDataToOrder($cart, $order);


$checkout = Factory::getInstance()->getCheckoutManager($cart);

$deliveryAddress = $checkout->getCheckoutStep('deliveryaddress') ?
$checkout->getCheckoutStep('deliveryaddress')->getData() : null;

$confirm = $checkout->getCheckoutStep('confirm') ? $checkout-


>getCheckoutStep('confirm')->getData() : null;

if($deliveryAddress) {

//inserting delivery and billing address from checkout step


delivery

$order->setCustomerFirstname( $deliveryAddress->firstname );

$order->setCustomerLastname( $deliveryAddress->lastname );

$order->setCustomerCompany( $deliveryAddress->company );

$order->setCustomerStreet( $deliveryAddress->address );

$order->setCustomerZip( $deliveryAddress->zip );

$order->setCustomerCity( $deliveryAddress->city );

$order->setCustomerCountry( $deliveryAddress->country );

$order->setCustomerEmail( $deliveryAddress->email );

$order->setDeliveryFirstname( $deliveryAddress->firstname );

$order->setDeliveryLastname( $deliveryAddress->lastname );

$order->setDeliveryCompany( $deliveryAddress->company );

$order->setDeliveryStreet( $deliveryAddress->address );

$order->setDeliveryZip( $deliveryAddress->zip );

$order->setDeliveryCity( $deliveryAddress->city );

$order->setDeliveryCountry( $deliveryAddress->country );
} else if($confirm) {

//in quick checkout - only get email-adress from confirm step

$order->setCustomerEmail( $confirm );

return $order;

Commit Order Processor

A simple implementation of \App\Checkout\Processor could look like:

<?php

class Processor extends CommitOrderProcessor

protected function processOrder(AbstractOrder $order): void

//send order to ERP-System

try {

$connector = ERPConnector::getInstance();

$erpOrderNumber = $connector->sendOrder($order);

$order->setOrderNumber($erpOrderNumber);
} catch(Exception $e) {

Logger::error($e->getMessage());

throw $e;

If needed, further methods can be overwritten. E.g. sendConfirmationMail if


special e-mails should be sent to specific persons.

After commit order was successful, the user can be directed to a success-
page.

ChatGPT

## Committing Orders in Pimcore E-Commerce Framework

After all checkout steps are completed, the final step is to commit the
order. This involves saving the order details, sending order confirmation
emails, and potentially integrating with external systems such as ERP.

### Basic Order Commit without Payment

For scenarios where no payment is involved, committing the order is


straightforward:

```php

$manager = Factory::getInstance()->getCheckoutManager($cart);

$order = $manager->commitOrder();

```
### Commit Order Processor

The `CheckoutManager` delegates the order committing process to a specified


`CommitOrderProcessor` implementation. This processor must implement `\
Pimcore\Bundle\EcommerceFrameworkBundle\CheckoutManager\
CommitOrderProcessorInterface`.

### Default Implementation

The default `CommitOrderProcessor` implementation provides basic


functionality like creating a Pimcore order object and sending an order
confirmation email. Order creation is handled by `\Pimcore\Bundle\
EcommerceFrameworkBundle\OrderManager\OrderManagerInterface`.

### Custom Extensions

In more complex scenarios, you will typically need to extend the default
implementations to handle additional custom fields or integrate with
external systems.

### Extending Order Manager

To store additional information in the order, you need to extend the


`OrderManager`.

Here’s a simple implementation of `App\Ecommerce\Order\OrderManager`:

```php

<?php

namespace App\Ecommerce\Order;
use Pimcore\Bundle\EcommerceFrameworkBundle\OrderManager\V7\OrderManager as
BaseOrderManager;

use Pimcore\Bundle\EcommerceFrameworkBundle\Model\AbstractOrder;

use Pimcore\Bundle\EcommerceFrameworkBundle\CartManager\CartInterface;

class OrderManager extends BaseOrderManager

protected function applyCustomCheckoutDataToOrder(CartInterface $cart,


AbstractOrder $order): AbstractOrder

$order = parent::applyCustomCheckoutDataToOrder($cart, $order);

$checkout = \Pimcore\Bundle\EcommerceFrameworkBundle\
Factory::getInstance()->getCheckoutManager($cart);

$deliveryAddress = $checkout->getCheckoutStep('deliveryaddress') ?
$checkout->getCheckoutStep('deliveryaddress')->getData() : null;

$confirm = $checkout->getCheckoutStep('confirm') ? $checkout-


>getCheckoutStep('confirm')->getData() : null;

if ($deliveryAddress) {

// Insert delivery and billing address from checkout step


delivery

$order->setCustomerFirstname($deliveryAddress->firstname);

$order->setCustomerLastname($deliveryAddress->lastname);

$order->setCustomerCompany($deliveryAddress->company);

$order->setCustomerStreet($deliveryAddress->address);

$order->setCustomerZip($deliveryAddress->zip);

$order->setCustomerCity($deliveryAddress->city);

$order->setCustomerCountry($deliveryAddress->country);

$order->setCustomerEmail($deliveryAddress->email);
$order->setDeliveryFirstname($deliveryAddress->firstname);

$order->setDeliveryLastname($deliveryAddress->lastname);

$order->setDeliveryCompany($deliveryAddress->company);

$order->setDeliveryStreet($deliveryAddress->address);

$order->setDeliveryZip($deliveryAddress->zip);

$order->setDeliveryCity($deliveryAddress->city);

$order->setDeliveryCountry($deliveryAddress->country);

} elseif ($confirm) {

// In quick checkout - only get email address from confirm step

$order->setCustomerEmail($confirm);

return $order;

```

### Extending Commit Order Processor

To handle custom logic during the order commit, such as sending the order
to an ERP system, extend the `CommitOrderProcessor`.

Here’s a simple implementation of `\App\Checkout\Processor`:

```php

<?php
namespace App\Checkout;

use Pimcore\Bundle\EcommerceFrameworkBundle\CheckoutManager\V7\
CommitOrderProcessor;

use Pimcore\Bundle\EcommerceFrameworkBundle\Model\AbstractOrder;

use Pimcore\Log\Logger;

class Processor extends CommitOrderProcessor

protected function processOrder(AbstractOrder $order): void

// Send order to ERP-System

try {

$connector = ERPConnector::getInstance();

$erpOrderNumber = $connector->sendOrder($order);

$order->setOrderNumber($erpOrderNumber);

} catch (Exception $e) {

Logger::error($e->getMessage());

throw $e;

```

Further methods can be overridden as needed, such as `sendConfirmationMail`


for sending custom emails.
### Final Steps

After successfully committing the order, the user can be directed to a


success page.

### Summary

The checkout process in Pimcore E-Commerce Framework involves configuring


and extending various components such as the `CheckoutManager`,
`OrderManager`, and `CommitOrderProcessor` to handle custom business logic,
additional fields, and integration with external systems. By following the
steps outlined above, you can customize the checkout process to fit the
specific needs of your e-commerce application.

User

Payment Integration

To integrate payment into the checkout process, instead of calling


$manager->commitOrder(); like described in Committing Orders, a few more
steps are necessary.

Initialize Payment in Controller

After all checkout steps are completed, the payment can be started. This is
done as follows:

/**

* @Route("/checkout-init-payment", name="shop-checkout-init-payment")

*/

public function initPaymentAction(Request $request, Factory $factory) {

// ... do some stuff, and get $cart

/** @var CheckoutManagerInterface $checkoutManager */

$checkoutManager = $factory->getCheckoutManager($cart);
//optional - init payment and get Pimcore internal payment ID (e.g. if
needed for config of payment provider)

$paymentInformation = $checkoutManager->initOrderPayment();

$config = new DatatransRequest([

//all options needed for payment provider - you also can use
setters of the corresponding object

]);

// start payment

$startPaymentResponse = $checkoutManager-
>startOrderPaymentWithPaymentProvider($config);

// depending on response type handle start payment response - e.g.


render form, render snippet, etc.

$paymentForm = $startPaymentResponse->getForm();

return $this->render('payment/init_payment.html.twig', [

'form' => $paymentForm->getForm()->createView()

]);

Build payment view

Once the payment is started, the created payment form needs to be


integrated into the view script. Depending on the payment provider, also
other data structures can be created:

<p>{{ 'Starting Payment' }}</p>


{{ form(form) }}

For more samples see our demo

Handle Payment Response

When the user finishes the payment, the given response (either via redirect
or via server side call) has to be handled as follows. If payment handling
was successful, the order needs to be committed.

A client side handling could look like as follows:

/**

* @Route("/checkout-payment-response", name="shop-checkout-payment-
response")

*/

public function paymentResponseAction(Request $request, Factory $factory,


RequestStack $requestStack) {

// ... do some stuff, and get $cart

$checkoutManager = $factory->getCheckoutManager($cart);

$params = []; // ... get all necessary parameters for payment provider,
e.g. by array_merge($request->query->all(), $request->request->all());

try {

$order = $checkoutManager-
>handlePaymentResponseAndCommitOrderPayment($params);

// optional to clear payment


// if this call is necessary depends on payment provider and
configuration.

// its possible to execute this later (e.g. when shipment is done)

// $payment = $checkoutManager->getPayment();

// $paymentStatus = $payment->executeDebit();

// $orderAgent = Factory::getInstance()->getOrderManager()-
>createOrderAgent($order);

// $orderAgent->updatePayment($paymentStatus);

$session = $requestStack->getSession();

$session->set("last_order_id", $order->getId());

$goto = $this->generateUrl('shop-checkout-completed');

} catch (\Exception $e) {

$this->addFlash('danger', $e->getMessage());

$goto = $this->generateUrl('shop-checkout-address');

return $this->render('payment/payment_response.html.twig', ['goto' =>


$goto]);

A server side handling could look as follows:

<?php
public function serverSideQPayAction(Request $request, Factory
$factory) {

Logger::info("Starting server side call");

$params = array_merge($request->query->all(), $request->request-


>all());

$environment = $factory->getEnvironment();

//if checkout tenant is set via param, use that one for this
request

if($params['checkouttenant']) {

$environment-
>setCurrentCheckoutTenant($params['checkouttenant'], false);

$commitOrderProcessor = $factory->getCommitOrderProcessor();

$paymentProvider = $factory->getPaymentManager()-
>getProvider("unzer");

if($committedOrder = $commitOrderProcessor-
>committedOrderWithSamePaymentExists($params, $paymentProvider)) {

Logger::info("Order with same payment is already committed,


doing nothing. OrderId is " . $committedOrder->getId());

} else {

$order = $commitOrderProcessor-
>handlePaymentResponseAndCommitOrderPayment( $params, $paymentProvider );

Logger::info("Finished server side call. OrderId is " . $order-


>getId());

}
exit("success");

Dealing with Pending Payments

Depending on the shops user journey, it might be possible, that a user


starts multiple payments. Typical use cases for that can be:

User starts payment → user goes back to shop and changes cart → user starts
checkout and payment with modified cart again

User has multiple tabs open → user starts payment in first tab → user
starts another payment in second tab → user finishes first payment → user
finishes second payment

The ecommerce application needs a strategy how to deal with that. Tthe
checkout manager can be configured with one of the following strategies how
to handle pending payments when a new payment is started (with
handle_pending_payments_strategy factory option):

RecreateOrder: Create new order every time a payment is started and leave
old orders untouched.

factory_options:

class: Pimcore\Bundle\EcommerceFrameworkBundle\CheckoutManager\V7\
CheckoutManager

handle_pending_payments_strategy: Pimcore\Bundle\
EcommerceFrameworkBundle\CheckoutManager\V7\HandlePendingPayments\
AlwaysRecreateOrderStrategy

CancelPaymentOrRecreateOrder (default value): Cancel payments if possible


and cart has not changed, create new order when cart has changed.

factory_options:

class: Pimcore\Bundle\EcommerceFrameworkBundle\CheckoutManager\V7\
CheckoutManager
handle_pending_payments_strategy: Pimcore\Bundle\
EcommerceFrameworkBundle\CheckoutManager\V7\HandlePendingPayments\
CancelPaymentOrRecreateOrderStrategy

ThrowException: Throw exceptions to make handling of these cases in


controller possible.

factory_options:

class: Pimcore\Bundle\EcommerceFrameworkBundle\CheckoutManager\V7\
CheckoutManager

handle_pending_payments_strategy: Pimcore\Bundle\
EcommerceFrameworkBundle\CheckoutManager\V7\HandlePendingPayments\
ThrowExceptionStrategy

Above mentioned use cases will now result in following behavior:

User starts payment → user goes back to shop and changes cart → user starts
checkout and payment with modified cart again:

Cart can be changed despite pending payments.

When user restarts payment, new order is created for new payment (with new
cart content):

If user finishes the first payment, first order is finished → all post
order processes are done based on first order.

If user finishes second payment, second order is finished.

If user finishes both payments, user has two orders.

User has multiple tabs open → user starts payment in first tab → user
starts another payment in second tab → user finishes first payment → user
finishes second payment:

Depending on configured CancelPaymentOrRecreateOrderStrategy when user


starts second payment following things can happen:

RecreateOrder: Another order is created and user has two orders when he
finishes both payments.
CancelPaymentOrRecreateOrder: First payment would be cancelled, user only
has one order. When user finishes both payments, both payment information
entries will be in one order.

ThrowException: When starting second payment an exception will be thrown


and controller needs to decide what to do.

It is possible to implement custom strategies as they are just services


implementing HandlePendingPaymentsStrategyInterface.

For more details see Payment Docs section.

ChatGPT

## Payment Integration in Pimcore E-Commerce Framework

Integrating payment into the checkout process involves several steps to


ensure a smooth transaction experience. This guide will walk you through
initializing payments, handling payment responses, and managing pending
payments.

### Initialize Payment in Controller

After completing all checkout steps, the payment process can be initiated.
Here's how to start a payment:

```php

/**

* @Route("/checkout-init-payment", name="shop-checkout-init-payment")

*/

public function initPaymentAction(Request $request, Factory $factory) {

// ... do some stuff, and get $cart

/** @var CheckoutManagerInterface $checkoutManager */


$checkoutManager = $factory->getCheckoutManager($cart);

//optional - init payment and get Pimcore internal payment ID (e.g. if


needed for config of payment provider)

$paymentInformation = $checkoutManager->initOrderPayment();

$config = new DatatransRequest([

//all options needed for payment provider - you also can use
setters of the corresponding object

]);

// start payment

$startPaymentResponse = $checkoutManager-
>startOrderPaymentWithPaymentProvider($config);

// depending on response type handle start payment response - e.g.


render form, render snippet, etc.

$paymentForm = $startPaymentResponse->getForm();

return $this->render('payment/init_payment.html.twig', [

'form' => $paymentForm->getForm()->createView()

]);

```

### Build Payment View

Once the payment is initiated, the created payment form needs to be


integrated into the view script. Depending on the payment provider, other
data structures may also be created:
```twig

<p>{{ 'Starting Payment' }}</p>

{{ form(form) }}

```

### Handle Payment Response

When the user finishes the payment, the response needs to be handled. If
the payment handling is successful, the order is committed.

#### Client-Side Handling

```php

/**

* @Route("/checkout-payment-response", name="shop-checkout-payment-
response")

*/

public function paymentResponseAction(Request $request, Factory $factory,


RequestStack $requestStack) {

// ... do some stuff, and get $cart

$checkoutManager = $factory->getCheckoutManager($cart);

$params = array_merge($request->query->all(), $request->request-


>all());

try {
$order = $checkoutManager-
>handlePaymentResponseAndCommitOrderPayment($params);

// optional to clear payment

// if this call is necessary depends on payment provider and


configuration.

// its possible to execute this later (e.g. when shipment is done)

// $payment = $checkoutManager->getPayment();

// $paymentStatus = $payment->executeDebit();

// $orderAgent = Factory::getInstance()->getOrderManager()-
>createOrderAgent($order);

// $orderAgent->updatePayment($paymentStatus);

$session = $requestStack->getSession();

$session->set("last_order_id", $order->getId());

$goto = $this->generateUrl('shop-checkout-completed');

} catch (\Exception $e) {

$this->addFlash('danger', $e->getMessage());

$goto = $this->generateUrl('shop-checkout-address');

return $this->render('payment/payment_response.html.twig', ['goto' =>


$goto]);

```

#### Server-Side Handling

```php
public function serverSideQPayAction(Request $request, Factory $factory) {

Logger::info("Starting server side call");

$params = array_merge($request->query->all(), $request->request-


>all());

$environment = $factory->getEnvironment();

//if checkout tenant is set via param, use that one for this request

if($params['checkouttenant']) {

$environment->setCurrentCheckoutTenant($params['checkouttenant'],
false);

$commitOrderProcessor = $factory->getCommitOrderProcessor();

$paymentProvider = $factory->getPaymentManager()->getProvider("unzer");

if($committedOrder = $commitOrderProcessor-
>committedOrderWithSamePaymentExists($params, $paymentProvider)) {

Logger::info("Order with same payment is already committed, doing


nothing. OrderId is " . $committedOrder->getId());

} else {

$order = $commitOrderProcessor-
>handlePaymentResponseAndCommitOrderPayment($params, $paymentProvider);

Logger::info("Finished server side call. OrderId is " . $order-


>getId());

exit("success");

}
```

### Dealing with Pending Payments

To handle scenarios where users might start multiple payments, you need a
strategy for managing pending payments. The checkout manager can be
configured with one of the following strategies:

1. **RecreateOrder:** Create a new order every time a payment is started


and leave old orders untouched.

```yaml

factory_options:

class: Pimcore\Bundle\EcommerceFrameworkBundle\CheckoutManager\V7\
CheckoutManager

handle_pending_payments_strategy: Pimcore\Bundle\
EcommerceFrameworkBundle\CheckoutManager\V7\HandlePendingPayments\
AlwaysRecreateOrderStrategy

```

2. **CancelPaymentOrRecreateOrder (default):** Cancel payments if possible


and the cart has not changed, create a new order when the cart has changed.

```yaml

factory_options:

class: Pimcore\Bundle\EcommerceFrameworkBundle\CheckoutManager\V7\
CheckoutManager

handle_pending_payments_strategy: Pimcore\Bundle\
EcommerceFrameworkBundle\CheckoutManager\V7\HandlePendingPayments\
CancelPaymentOrRecreateOrderStrategy

```
3. **ThrowException:** Throw exceptions to make handling these cases
possible in the controller.

```yaml

factory_options:

class: Pimcore\Bundle\EcommerceFrameworkBundle\CheckoutManager\V7\
CheckoutManager

handle_pending_payments_strategy: Pimcore\Bundle\
EcommerceFrameworkBundle\CheckoutManager\V7\HandlePendingPayments\
ThrowExceptionStrategy

```

### Summary

Integrating payment into the checkout process involves initializing the


payment, handling payment responses, and managing pending payments. By
following the steps outlined above, you can ensure a smooth payment process
for your e-commerce application using the Pimcore E-Commerce Framework.

User

Checkout Manager Details

Following documentation page provide a few more insights on Checkout


Manager Architecture.

Architecture Details

Architecture V7

Stars mark places, where events are thrown. For details see EventManager
docs.

ChatGPT

### Checkout Manager Details from the Uploaded Document


#### Overview

The Checkout Manager in Pimcore provides a comprehensive API to handle the


checkout process. It is a key component in building customizable checkout
workflows for e-commerce applications. The architecture ensures
flexibility, allowing developers to integrate various custom features,
payment gateways, and order processing mechanisms.

#### Architecture Details

1. **Checkout Steps**:

- Each checkout step needs to implement `CheckoutStepInterface` and


extend `AbstractStep`.

- Common methods include `commit()` for saving data, `getData()` for


retrieving stored data, and `getName()` for identifying the step.

2. **Order Management**:

- Orders are managed through `OrderManagerInterface`.

- Custom order processing can be achieved by extending the default


`OrderManager` and overriding methods like
`applyCustomCheckoutDataToOrder`.

3. **Payment Integration**:

- Payments are handled via the `PaymentProviderInterface`.

- The payment process can be initiated and managed through methods like
`initOrderPayment()` and `startOrderPaymentWithPaymentProvider()`.

- Handling responses from payment gateways involves validating and


committing the order based on the payment status.

4. **Event Handling**:

- Various events are thrown at different stages of the checkout


process, allowing for custom event-driven actions.
- Event management can be customized based on specific business
requirements.

5. **Custom Implementations**:

- Developers can create custom implementations of key components such


as `CommitOrderProcessor` and `OrderManager` to add specific business
logic, integrate with ERP systems, or handle custom notifications.

- Example: Extending `CommitOrderProcessor` to include sending order


details to an ERP system.

6. **Pending Payments**:

- The framework provides strategies to handle pending payments, such as


recreating orders, canceling previous payments, or throwing exceptions for
manual handling.

- Developers can implement custom strategies by implementing


`HandlePendingPaymentsStrategyInterface`.

#### Key Components and Usage

- **Factory Initialization**:

```php

$manager = Factory::getInstance()->getCheckoutManager($cart);

```

- **Setting Up Steps**:

```php

$step = $manager->getCheckoutStep("deliveryaddress");

$address = new stdClass();

// fill address

$manager->commitStep($step, $address);

$cart->save();
```

- **Committing Orders**:

```php

$order = $manager->commitOrder();

```

- **Payment Initialization**:

```php

$checkoutManager = $factory->getCheckoutManager($cart);

$paymentInformation = $checkoutManager->initOrderPayment();

```

- **Handling Payment Response**:

```php

$params = array_merge($request->query->all(), $request->request->all());

$order = $checkoutManager-
>handlePaymentResponseAndCommitOrderPayment($params);

```

These snippets highlight the modularity and extensibility of the Checkout


Manager, allowing for tailored implementations to fit specific e-commerce
workflows.

For more detailed information, please refer to the full documentation


provided in the PDF【75:0†Checkout Manager.pdf】.

User

Checkout Tenants for Checkout


The E-Commerce Framework has the concept of Checkout Tenants which allow
different cart manager and checkout manager configurations based on a
currently active checkout tenant.

The current checkout tenant is set in the framework environment as follows.


Once set, the checkout manager uses all specific settings of the currently
active checkout tenant.

So different checkout steps, different payment providers etc. can be


implemented within one shop.

<?php

$environment = Factory::getInstance()->getEnvironment();

$environment->setCurrentCheckoutTenant('default');

$environment->save();

$environment->setCurrentCheckoutTenant('noShipping');

$environment->save();

When using server-by-server payment confirmation communication, make sure


that the correct tenant is set during the response handling!

ChatGPT

### Checkout Tenants for Checkout

The concept of Checkout Tenants in the Pimcore E-Commerce Framework allows


for different configurations of the cart manager and checkout manager
depending on the currently active tenant. This enables the implementation
of different checkout steps, payment providers, and other configurations
within a single shop instance.

#### Setting the Current Checkout Tenant


The current checkout tenant is set in the framework environment. Once set,
the checkout manager will use the specific settings configured for the
active tenant.

```php

$environment = Factory::getInstance()->getEnvironment();

$environment->setCurrentCheckoutTenant('default');

$environment->save();

$environment->setCurrentCheckoutTenant('noShipping');

$environment->save();

```

#### Configuration of Checkout Tenants

To configure different checkout tenants, you define them in the


`pimcore_ecommerce_framework` configuration section.

```yaml

pimcore_ecommerce_framework:

checkout_manager:

tenants:

_defaults:

factory_id: Pimcore\Bundle\EcommerceFrameworkBundle\
CheckoutManager\CheckoutManagerFactory

factory_options:

class: \Pimcore\Bundle\EcommerceFrameworkBundle\
CheckoutManager\V7\CheckoutManager

handle_pending_payments_strategy: Pimcore\Bundle\
EcommerceFrameworkBundle\CheckoutManager\V7\HandlePendingPayments\
CancelPaymentOrRecreateOrderStrategy
commit_order_processor:

id: Pimcore\Bundle\EcommerceFrameworkBundle\
CheckoutManager\V7\CommitOrderProcessor

options:

confirmation_mail: /en/emails/order-confirmation

steps:

deliveryaddress:

class: \Pimcore\Bundle\EcommerceFrameworkBundle\
CheckoutManager\DeliveryAddress

confirm:

class: \App\Ecommerce\Checkout\Confirm

default:

payment:

provider: qpay

paypal:

payment:

provider: paypal

```

### Server-Side Payment Confirmation

When handling server-side payment confirmations, it is crucial to ensure


that the correct tenant is set during the response handling. This ensures
that the appropriate configuration and steps are used for processing the
payment and committing the order.

#### Example Server-Side Payment Confirmation Handling


```php

/**

* @Route("/server-side-payment-confirmation",
name="server_side_payment_confirmation")

*/

public function serverSidePaymentConfirmationAction(Request $request,


Factory $factory) {

Logger::info("Starting server side call");

$params = array_merge($request->query->all(), $request->request-


>all());

$environment = $factory->getEnvironment();

// Ensure the correct checkout tenant is set based on request


parameters

if (isset($params['checkouttenant'])) {

$environment->setCurrentCheckoutTenant($params['checkouttenant'],
false);

$commitOrderProcessor = $factory->getCommitOrderProcessor();

$paymentProvider = $factory->getPaymentManager()->getProvider("unzer");

if ($committedOrder = $commitOrderProcessor-
>committedOrderWithSamePaymentExists($params, $paymentProvider)) {

Logger::info("Order with same payment is already committed, doing


nothing. OrderId is " . $committedOrder->getId());

} else {

$order = $commitOrderProcessor-
>handlePaymentResponseAndCommitOrderPayment($params, $paymentProvider);
Logger::info("Finished server side call. OrderId is " . $order-
>getId());

exit("success");

```

### Benefits of Checkout Tenants

1. **Flexibility**: Different checkout processes and payment configurations


can be implemented for various customer groups or scenarios within the same
shop.

2. **Customization**: Tailor the checkout experience based on specific


needs, such as offering different payment providers for different
countries.

3. **Scalability**: Manage complex checkout processes efficiently without


duplicating configuration for each variant.

By leveraging checkout tenants, e-commerce applications built with Pimcore


can provide a more flexible and tailored shopping experience, accommodating
various business needs and customer preferences.

User

Payment Manager

The Payment Manager is responsible for all aspects concerning payment. The
main aspect is the implementation of different Payment Provider to
integrate them into the framework.

Basic workflow

[SHOP] Init payment provider ($payment->initPayment()).

[SHOP] User click pay button and is redirected to the payment provider
page.
[PAYMENT PROVIDER] User fill up payment information and is redirected back
to the shop.

[SHOP] Check if the payment is authorised ($payment->handleResponse()). At


this step the order can be committed.

[SHOP] Clearing payment if its required ($payment->executeDebit())

For more information about integrating Payment into checkout processes see
Integrating Payment Docs.

Configuration

Configuration of Payment Manager takes place in the


pimcore_ecommerce_config.payment_manager config section:

pimcore_ecommerce_config:

payment_manager:

# service ID of payment manager implementation - following value is


default value an can be omitted

payment_manager_id: Pimcore\Bundle\EcommerceFrameworkBundle\
PaymentManager\PaymentManager

# configuration of payment providers, key is name of provider

providers:

datatrans:

# service ID of payment provider implementation

provider_id: Pimcore\Bundle\EcommerceFrameworkBundle\
PaymentManager\Payment\Datatrans

# active profile - you can define multiple profiles in the


section below

profile: sandbox

# available profiles with options - options vary on the


provider implementation as the
profiles:

sandbox:

merchant_id: 1000011011

sign: 30916165706580013

use_digital_signature: false

live:

merchant_id: merchant_id_id

sign: sign_id

use_digital_signature: false

mode: live

ogone:

provider_id: Pimcore\Bundle\EcommerceFrameworkBundle\
PaymentManager\Payment\OGone

profile: sandbox

profiles:

sandbox:

secret: D343DDFD3434

pspid: MyTestAccount

mode: sandbox

# encryptionType: SHA256 or SHA512 (optional)

live:

secret: D343DDFD3434

pspid: MyLiveAccount

mode: live

# encryptionType: SHA256 or SHA512 (optional)

mpay24:
provider_id: Pimcore\Bundle\EcommerceFrameworkBundle\
PaymentManager\Payment\Mpay24Seamless

profile: testsystem

profiles:

_defaults:

#paypal_activate_item_level: true

partial:
Shared/Includes/Shop/Payment/paymentMethods.html.php

payment_methods:

cc:

paypal:

sofort:

invoice:

testsystem:

merchant_id: 95387

password: 7&jcQ%v6RB

testSystem: true

debugMode: true

live:

merchant_id: todo

password: todo

testSystem: false

debugMode: false

hobex:

provider_id: Pimcore\Bundle\EcommerceFrameworkBundle\
PaymentManager\Payment\Hobex

profile: sandbox

profiles:
sandbox:

entityId: '8a829418530df1d201531299e097175c'

authorizationBearer:
'OGE4Mjk0MTg1MzBkZjFkMjAxNTMxMjk5ZTJjMTE3YWF8ZzJnU3BnS2hLUw=='

testSystem: true

payment_methods:

- VISA

- MASTER

- SOFORTUEBERWEISUNG

- SEPA

The payment provider name will be referenced from the checkout manager
configuration and can be used to fetch a specific provider from the payment
manager.

Payment Providers

Following Payment Providers are available as a dedicated bundle to be


integrated into the E-commerce framework:

Datatrans

PayPalSmartButton

Klarna

OGone

MPay24

PayU

Unzer (former Heidelpay)

Hobex

Third-party Payment Provider Integrations


BS PAYONE

Further Payment Aspects

Recurring Payments

ChatGPT

## Payment Manager

The Payment Manager in Pimcore E-Commerce Framework is responsible for


managing payment providers and handling the payment processes. Below are
the main components and workflow of the Payment Manager.

### Basic Workflow

1. **Initialize Payment Provider:** The shop initializes the payment


provider using `$payment->initPayment()`.

2. **User Redirected to Payment Provider:** The user clicks the pay button
and is redirected to the payment provider's page.

3. **User Completes Payment Information:** The user fills in the payment


information and is redirected back to the shop.

4. **Authorize Payment:** The shop checks if the payment is authorized


using `$payment->handleResponse()`. At this step, the order can be
committed.

5. **Execute Payment:** The shop clears the payment if required using


`$payment->executeDebit()`.

### Configuration

The configuration for the Payment Manager is done in the


`pimcore_ecommerce_config.payment_manager` configuration section.

```yaml

pimcore_ecommerce_config:

payment_manager:
# Default service ID for payment manager implementation

payment_manager_id: Pimcore\Bundle\EcommerceFrameworkBundle\
PaymentManager\PaymentManager

# Configuration of payment providers

providers:

datatrans:

provider_id: Pimcore\Bundle\EcommerceFrameworkBundle\
PaymentManager\Payment\Datatrans

profile: sandbox

profiles:

sandbox:

merchant_id: 1000011011

sign: 30916165706580013

use_digital_signature: false

live:

merchant_id: merchant_id_id

sign: sign_id

use_digital_signature: false

mode: live

ogone:

provider_id: Pimcore\Bundle\EcommerceFrameworkBundle\
PaymentManager\Payment\OGone

profile: sandbox

profiles:

sandbox:

secret: D343DDFD3434
pspid: MyTestAccount

mode: sandbox

# encryptionType: SHA256 or SHA512 (optional)

live:

secret: D343DDFD3434

pspid: MyLiveAccount

mode: live

# encryptionType: SHA256 or SHA512 (optional)

mpay24:

provider_id: Pimcore\Bundle\EcommerceFrameworkBundle\
PaymentManager\Payment\Mpay24Seamless

profile: testsystem

profiles:

_defaults:

#paypal_activate_item_level: true

partial:
Shared/Includes/Shop/Payment/paymentMethods.html.php

payment_methods:

cc:

paypal:

sofort:

invoice:

testsystem:

merchant_id: 95387

password: 7&jcQ%v6RB

testSystem: true

debugMode: true
live:

merchant_id: todo

password: todo

testSystem: false

debugMode: false

hobex:

provider_id: Pimcore\Bundle\EcommerceFrameworkBundle\
PaymentManager\Payment\Hobex

profile: sandbox

profiles:

sandbox:

entityId: '8a829418530df1d201531299e097175c'

authorizationBearer:
'OGE4Mjk0MTg1MzBkZjFkMjAxNTMxMjk5ZTJjMTE3YWF8ZzJnU3BnS2hLUw=='

testSystem: true

payment_methods:

- VISA

- MASTER

- SOFORTUEBERWEISUNG

- SEPA

```

### Payment Providers

Below is a list of available payment providers that can be integrated into


the Pimcore E-Commerce framework:
- Datatrans

- PayPalSmartButton

- Klarna

- OGone

- MPay24

- PayU

- Unzer (former Heidelpay)

- Hobex

### Third-party Payment Provider Integrations

In addition to the built-in payment providers, third-party integrations


such as BS PAYONE can be implemented.

### Recurring Payments

The framework also supports recurring payments, though specific


configuration and implementation details would depend on the payment
provider and the use case.

### Example Integration with Payment Provider

#### Initializing Payment in Controller

```php

/**

* @Route("/checkout-init-payment", name="shop-checkout-init-payment")

*/
public function initPaymentAction(Request $request, Factory $factory) {

// ... do some stuff, and get $cart

/** @var CheckoutManagerInterface $checkoutManager */

$checkoutManager = $factory->getCheckoutManager($cart);

// Optional - init payment and get Pimcore internal payment ID (e.g. if


needed for config of payment provider)

$paymentInformation = $checkoutManager->initOrderPayment();

$config = new DatatransRequest([

// All options needed for payment provider - you also can use
setters of the corresponding object

]);

// Start payment

$startPaymentResponse = $checkoutManager-
>startOrderPaymentWithPaymentProvider($config);

// Depending on response type handle start payment response - e.g.


render form, render snippet, etc.

$paymentForm = $startPaymentResponse->getForm();

return $this->render('payment/init_payment.html.twig', [

'form' => $paymentForm->getForm()->createView()

]);

```

#### Handling Payment Response


```php

/**

* @Route("/checkout-payment-response", name="shop-checkout-payment-
response")

*/

public function paymentResponseAction(Request $request, Factory $factory,


RequestStack $requestStack) {

// ... do some stuff, and get $cart

$checkoutManager = $factory->getCheckoutManager($cart);

$params = array_merge($request->query->all(), $request->request-


>all());

try {

$order = $checkoutManager-
>handlePaymentResponseAndCommitOrderPayment($params);

// Optional to clear payment

// if this call is necessary depends on payment provider and


configuration.

// its possible to execute this later (e.g. when shipment is done)

// $payment = $checkoutManager->getPayment();

// $paymentStatus = $payment->executeDebit();

// $orderAgent = Factory::getInstance()->getOrderManager()-
>createOrderAgent($order);

// $orderAgent->updatePayment($paymentStatus);

$session = $requestStack->getSession();

$session->set("last_order_id", $order->getId());
$goto = $this->generateUrl('shop-checkout-completed');

} catch (\Exception $e) {

$this->addFlash('danger', $e->getMessage());

$goto = $this->generateUrl('shop-checkout-address');

return $this->render('payment/payment_response.html.twig', ['goto' =>


$goto]);

```

#### Server-Side Payment Confirmation

```php

/**

* @Route("/server-side-payment-confirmation",
name="server_side_payment_confirmation")

*/

public function serverSidePaymentConfirmationAction(Request $request,


Factory $factory) {

Logger::info("Starting server side call");

$params = array_merge($request->query->all(), $request->request-


>all());

$environment = $factory->getEnvironment();

// Ensure the correct checkout tenant is set based on request


parameters
if (isset($params['checkouttenant'])) {

$environment->setCurrentCheckoutTenant($params['checkouttenant'],
false);

$commitOrderProcessor = $factory->getCommitOrderProcessor();

$paymentProvider = $factory->getPaymentManager()->getProvider("unzer");

if ($committedOrder = $commitOrderProcessor-
>committedOrderWithSamePaymentExists($params, $paymentProvider)) {

Logger::info("Order with same payment is already committed, doing


nothing. OrderId is " . $committedOrder->getId());

} else {

$order = $commitOrderProcessor-
>handlePaymentResponseAndCommitOrderPayment($params, $paymentProvider);

Logger::info("Finished server side call. OrderId is " . $order-


>getId());

exit("success");

```

This configuration and workflow ensure a seamless integration of various


payment providers into the Pimcore E-Commerce Framework, enabling flexible
and reliable payment processing for different e-commerce scenarios.

ChatGPT

### Implementing Recurring Payments

To implement recurring payments in Pimcore's E-Commerce Framework, follow


these guidelines:
### 1. Understanding Recurring Payments

The best practice for handling recurring payments involves keeping track of
the initial payment and using it as a source for subsequent recurring
payments. This ensures that credit card information is not stored beyond
the allowed time, enhancing security and compliance.

#### **Bad Way Example:**

- Initial Payment: 01.01.2013, Amount: 15 Euros, Order Number: 12345

- Recurring Payment 1: 01.05.2013, Amount: 20 Euros, Source Order Number:


12345, Order Number: 23456

- Recurring Payment 2: 01.10.2013, Amount: 20 Euros, Source Order Number:


12345, Order Number: 34567

- Recurring Payment 3: 01.03.2014, Amount: 10 Euros, Source Order Number:


12345, Order Number: 45678

Here, the initial transaction is older than 400 days, so the credit card
data is no longer valid in the system.

#### **Good Way Example:**

- Initial Payment: 01.01.2013, Amount: 15 Euros, Order Number: 12345

- Recurring Payment 1: 01.05.2013, Amount: 20 Euros, Source Order Number:


12345, Order Number: 23456

- Recurring Payment 2: 01.10.2013, Amount: 20 Euros, Source Order Number:


23456, Order Number: 34567

- Recurring Payment 3: 01.03.2014, Amount: 10 Euros, Source Order Number:


34567, Order Number: 45678

Here, the last transaction is within 150 days, so everything remains valid.

### 2. Implementing in Code


#### **Controller for Handling Payments**

The following code shows how to perform a one-time payment and manage
recurring payments using Wirecard (Qpay):

```php

namespace App\Controller;

use Symfony\Component\HttpFoundation\Request;

use Symfony\Component\HttpFoundation\Response;

use Pimcore\Bundle\EcommerceFrameworkBundle\Factory;

class CheckoutController

public function paymentAction(Request $request): Response

$factory = Factory::getInstance();

$checkoutManager = $factory->getCheckoutManager($this->cart);

$user = $this->getUser();

// Open payment or submit recurring payment

if ($request->getMethod() == 'POST') {

if ($sourceOrderId = $request->get("recurring-payment")) {

/* Recurring Payment */

if ($user && $sourceOrderId) {

$sourceOrder = \Pimcore\Model\DataObject\
OnlineShopOrder::getById($sourceOrderId);
try {

$targetOrder = $checkoutManager-
>startAndCommitRecurringOrderPayment($sourceOrder, $user->getId());

return $this->redirect($this-
>generateUrl('checkout', ['action' => 'completed']));

} catch (\Exception $exception) {

// show warning

$templateParams = [];

$paymentMethods = ["SEPA-DD", "CCARD"]; // supported payment


methods

if ($user) {

$sourceOrders = [];

foreach ($paymentMethods as $paymentMethod) {

$orderManager = $factory->getOrderManager();

$sourceOrder = $orderManager-
>getRecurringPaymentSourceOrder($user->getId(), $checkoutManager-
>getPayment(), $paymentMethod);

$sourceOrders[$paymentMethod] = $sourceOrder;

}
$templateParams['sourceOrders'] = $sourceOrders;

$templateParams['paymentMethods'] = $paymentMethods;

return $this->render('checkout/payment.html.twig',
$templateParams);

```

#### **Twig Template for Payment Options**

```twig

<form method="post" action="{{ pimcore_url({action: 'confirm'}, 'checkout',


true) }}">

{% if sourceOrders is not empty %}

<h4>{{ 'checkout.use-recurring-payment'|trans }}</h4>

{% for paymentMethod in paymentMethods %}

{% if sourceOrders[paymentMethod] is defined %}

{% set sourceOrder = sourceOrders[paymentMethod] %}

{% set paymentProvider =
sourceOrder.paymentProvider.paymentProviderQpay %}

{% if paymentProvider %}

{% set currentPaymentMethod =
paymentProvider.Auth_paymentType %}

<p>
<input name="recurring-payment"
value="{{ sourceOrder.id }}" type="radio">

<strong>{{ currentPaymentMethod }}</strong>

{% if currentPaymentMethod is same as('SEPA-DD') %}

{{ paymentProvider.Auth_bankAccountOwner }}
{{ paymentProvider.Auth_bankAccountIBAN }}

{% elseif currentPaymentMethod is same as('CCARD')


%}

{{ paymentProvider.Auth_maskedPan }}
{{ paymentProvider.Auth_expiry }}

{% endif %}

</p>

{% endif %}

{% endif %}

{% endfor %}

<hr>

{% endif %}

</form>

```

#### **Configuration (ecommerce.yaml)**

```yaml

pimcore_ecommerce_framework:

payment_manager:

providers:

qpay:

profiles:
sandbox:

secret:
'CHCSH7UGHVVX2P7EHDHSY4T2S4CGYK4QBE4M5YUUG2ND5BEZWNRZW5EJYVJQ'

customer: 'D200411'

toolkit_password: 'XXXXXXX' # necessary for


recurPayment operation

optional_payment_properties:

- paymentType

- transactionIdentifier # necessary for


recurPayment based on SEPA DIRECT DEBIT

recurring_payment_enabled: true # enable recurring


payment

```

### Best Practices

- **Keep Payment Information Secure:** Ensure that sensitive payment data


is never stored in a way that violates security compliance.

- **Follow Payment Provider Guidelines:** Adhere to the guidelines provided


by your payment provider for recurring payments.

- **Handle Failures Gracefully:** Ensure that your system can handle


failures and retry logic appropriately for recurring payments.

By following these practices and integrating the provided code, you can
effectively manage one-time and recurring payments in Pimcore's E-Commerce
Framework.

User

Order Manager

The Order Manager is responsible for all aspects of working with orders
except committing them (which is the responsibility of the Commit Order
Processor). These aspects contain among other things:

Creating orders based on carts


Order Storage (by default as Pimcore objects)

Loading orders

Loading order lists and filter them (Order List)

Working with orders after order commit (Order Agent)

Configuration

The configuration takes place in the


pimcore_ecommerce_framework.order_manager config section and is tenant
aware.

pimcore_ecommerce_framework:

order_manager:

tenants:

_defaults:

# service ID of order manager implementation

order_manager_id: Pimcore\Bundle\EcommerceFrameworkBundle\
OrderManager\V7\OrderManager

# options for oder manager

options:

# Pimcore object class for orders

order_class: \Pimcore\Model\DataObject\OnlineShopOrder

# Pimcore object class for order items

order_item_class: \Pimcore\Model\DataObject\
OnlineShopOrderItem

# Class for order listing

list_class: Pimcore\Bundle\EcommerceFrameworkBundle\
OrderManager\Order\Listing

# Class for order item listing

list_item_class: Pimcore\Bundle\
EcommerceFrameworkBundle\OrderManager\Order\Listing\Item

# Default parent folder for new orders, will be parsed


by strftime()
# @deprecated since pimcore/ecommerce-framework-bundle
v1.1.0, please use `order_parent_path` instead

# NB: this configuration node will be ignored when the


new one is set

parent_order_folder: /order/%%Y/%%m/%%d # deprecated


and discouraged

# Default parent folder for new order items, can use


Carbon date format parameters wrapped by `*` eg. *D*

order_parent_path: /order/*Y*/*M*/*D*

# Options for oder agent

order_agent:

# service ID of order agent factory - builds order


agents individual to each order

factory_id: Pimcore\Bundle\EcommerceFrameworkBundle\
OrderManager\Order\AgentFactory

# options for order agent factory - available options


vary by factory implementation

factory_options:

agent_class: Pimcore\Bundle\
EcommerceFrameworkBundle\OrderManager\V7\OrderAgent

# inherits from _defaults

default: ~

# inherits from _defaults, but sets another order folder

otherFolder:

options:

# parent_order_folder: /order_otherfolder/%%Y/%%m/%%d #
deprecated and discouraged

order_parent_path: /order_otherfolder/*Y*/*M*/*D*
ChatGPT

## Order Manager in Pimcore E-Commerce Framework

### Overview

The Order Manager handles all aspects of working with orders, except for
committing them (which is the responsibility of the Commit Order
Processor). The functionalities include:

- Creating orders from carts.

- Storing orders (by default as Pimcore objects).

- Loading orders and order lists.

- Filtering orders.

- Managing orders after they are committed (using Order Agent).

### Configuration

The configuration of the Order Manager is tenant-aware and takes place in


the `pimcore_ecommerce_framework.order_manager` configuration section.
Below is an example configuration:

```yaml

pimcore_ecommerce_framework:

order_manager:

tenants:

_defaults:

# Service ID of the order manager implementation

order_manager_id: Pimcore\Bundle\EcommerceFrameworkBundle\
OrderManager\V7\OrderManager

# Options for the order manager

options:
# Pimcore object class for orders

order_class: \Pimcore\Model\DataObject\OnlineShopOrder

# Pimcore object class for order items

order_item_class: \Pimcore\Model\DataObject\
OnlineShopOrderItem

# Class for order listing

list_class: Pimcore\Bundle\EcommerceFrameworkBundle\
OrderManager\Order\Listing

# Class for order item listing

list_item_class: Pimcore\Bundle\
EcommerceFrameworkBundle\OrderManager\Order\Listing\Item

# Default parent folder for new orders, parsed by


strftime()

# Deprecated in favor of order_parent_path

# parent_order_folder: /order/%%Y/%%m/%%d # deprecated

# Default parent folder for new order items, can use


Carbon date format parameters wrapped by `*` eg. *D*

order_parent_path: /order/*Y*/*M*/*D*

# Options for the order agent

order_agent:

# Service ID of the order agent factory, which builds


order agents individual to each order

factory_id: Pimcore\Bundle\EcommerceFrameworkBundle\
OrderManager\Order\AgentFactory
# Options for the order agent factory, available
options vary by factory implementation

factory_options:

agent_class: Pimcore\Bundle\
EcommerceFrameworkBundle\OrderManager\V7\OrderAgent

# Tenant configuration, inherits from _defaults

default: ~

# Tenant configuration, inherits from _defaults, but sets


another order folder

otherFolder:

options:

# parent_order_folder: /order_otherfolder/%%Y/%%m/%%d #
deprecated and discouraged

order_parent_path: /order_otherfolder/*Y*/*M*/*D*

```

### Explanation of Configuration Elements

- **order_manager_id:** Service ID for the order manager implementation.

- **order_class:** Pimcore data object class for orders.

- **order_item_class:** Pimcore data object class for order items.

- **list_class:** Class for order listing.

- **list_item_class:** Class for order item listing.

- **order_parent_path:** Default parent folder for new orders using Carbon


date format.

- **order_agent:** Configuration for the order agent, which includes the


factory ID and options for the order agent factory.

### Usage Examples


#### Creating an Order

To create an order based on a cart, you typically use the Commit Order
Processor, which calls the Order Manager:

```php

$checkoutManager = Factory::getInstance()->getCheckoutManager($cart);

$order = $checkoutManager->commitOrder();

```

#### Loading an Order

To load an order, you can use the Order Manager:

```php

$orderManager = Factory::getInstance()->getOrderManager();

$order = $orderManager->getOrderById($orderId);

```

#### Loading Order List

To load and filter order lists:

```php

$orderManager = Factory::getInstance()->getOrderManager();

$orderList = $orderManager->getOrderList();

$orderList->setOrderKey('creationDate');

$orderList->setOrder('DESC');

$orderList->load();
```

### Custom Extensions

Typically, a project-specific implementation might involve extending the


Order Manager or Order Agent to include additional custom fields or
functionalities:

#### Extending Order Manager

For example, to add custom fields to an order:

```php

class CustomOrderManager extends \Pimcore\Bundle\EcommerceFrameworkBundle\


OrderManager\V7\OrderManager

protected function applyCustomCheckoutDataToOrder(CartInterface $cart,


AbstractOrder $order): AbstractOrder

$order = parent::applyCustomCheckoutDataToOrder($cart, $order);

$checkout = Factory::getInstance()->getCheckoutManager($cart);

$deliveryAddress = $checkout->getCheckoutStep('deliveryaddress') ?
$checkout->getCheckoutStep('deliveryaddress')->getData() : null;

if ($deliveryAddress) {

$order->setCustomerFirstname($deliveryAddress->firstname);

$order->setCustomerLastname($deliveryAddress->lastname);

$order->setCustomerCompany($deliveryAddress->company);

$order->setCustomerStreet($deliveryAddress->address);

$order->setCustomerZip($deliveryAddress->zip);
$order->setCustomerCity($deliveryAddress->city);

$order->setCustomerCountry($deliveryAddress->country);

$order->setCustomerEmail($deliveryAddress->email);

return $order;

```

#### Extending Order Agent

To integrate specific functionality during order processing:

```php

class CustomOrderAgent extends \Pimcore\Bundle\EcommerceFrameworkBundle\


OrderManager\V7\OrderAgent

public function customFunction(AbstractOrder $order): void

// Custom functionality

```

### Conclusion

By configuring and extending the Order Manager and Order Agent, you can
effectively manage and customize the order processing workflows in
Pimcore's E-Commerce Framework to suit specific project requirements.
User

Working with Order Lists

The Order List are a one stop API for filtering and listing order objects.
Of course default Pimcore object lists also can be used for listing order
objects. But Order Lists provide additional functionality in terms of
predefined filters etc.

Basic - Get Newest Orders

<?php

// create new order list

$orderManager = Factory::getInstance()->getOrderManager();

$orderList = $orderManager->createOrderList();

// get the newest 10 orders

$orderList->setOrder( 'order.orderDate desc' );

$orderList->setLimit( 10, 0 );

// iterate

/** @var \Pimcore\Bundle\EcommerceFrameworkBundle\OrderManager\


OrderListItemInterface $order */

foreach($orderList as $order) {

echo $order->getOrdernumber();

// ALTERNATE: use knp paginator service: PaginatorInterface $paginator

$paginator = $paginator->paginate(

$orderList,
$request->get('page', 1),

10

);

foreach($paginator as $order) {

...

Basic - Using Filter

<?php

// create new order list

$orderManager = Factory::getInstance()->getOrderManager();

$orderList = $orderManager->createOrderList();

// create date time filter

$filterDate = new \Pimcore\Bundle\EcommerceFrameworkBundle\OrderManager\


Order\Listing\Filter\OrderDateTime();

$filterDate->setFrom( new DateTime('20.01.2015') );

$filterDate->setTill( new DateTime('31.01.2015') );

// add filter

$orderList->addFilter( $filterDate );
Basic - list Order Items

<?php

// create new order list

$orderManager = Factory::getInstance()->getOrderManager();

$orderList = $orderManager->createOrderList();

// get only orders that are committed

$orderList->setListType( $orderList::LIST_TYPE_ORDER_ITEM );

$orderList->setOrderState( AbstractOrder::ORDER_STATE_COMMITTED );

Advanced - Custom Condition

<?php

// create new order list

$orderManager = Factory::getInstance()->getOrderManager();

$orderList = $orderManager->createOrderList();

// e.g. - search for a specify order number

$query = $orderList->getQuery();

$query->where('order.ordernumber = ?', 'ord_554b425dcae53');


// e.g. - search for a user comment

$query = $orderList->getQuery();

$query->where('order.comment like ?', '%hallo world%');

Expert - High Performance

avoid loading of Pimcore object's for higher performance

<?php

// create new order list

$orderManager = Factory::getInstance()->getOrderManager();

$orderList = $orderManager->createOrderList();

// add all required fields to the select

$orderList->addSelectField(['OrderNumber' => 'order.orderNumber']);

$orderList->addSelectField(['TotalPrice' => 'order.totalPrice']);

$orderList->addSelectField(['Items' => 'count(orderItem.id)']);

Expert - Extended Conditions via Joins

<?php

// e.g. get all orderings for a customer

$orderList->joinCustomer( \Pimcore\Model\DataObject\Customer::classId() );
$orderList->getQuery()->where('customer.id = ?', 12345);

// e.g. filter product number

$orderList->joinProduct( \Pimcore\Model\DataObject\Product::classId() );

$orderList->getQuery()->where('product.productNumber = ?', 'CMD1191');

Generic Filter

Namespace: \Pimcore\Bundle\EcommerceFrameworkBundle\OrderManager\Order\
Listing\Filter

Filter Description

OrderDateTime Date Range Filter

OrderSearch Search order for a specified keyword

Payment Filter by payment state (ok or fail)

Product Filter by product and its variants

ProductType Filter ordered products for the given class names

CustomerObject Filter orders by given Customer Object

Search Generic search filter for searches against a given DB column

Search\Customer Search for customer name

Search\CustomerEmail Search for customer email

Search\PaymentReference Search for a payment reference

ChatGPT

## Working with Order Lists in Pimcore E-Commerce Framework


The Order List API in Pimcore provides a streamlined way to filter and list
order objects, offering predefined filters and additional functionalities
over the default Pimcore object lists.

### Basic Usage: Get Newest Orders

To get the newest orders, create an order list and set the desired order
and limit.

```php

<?php

// Create a new order list

$orderManager = Factory::getInstance()->getOrderManager();

$orderList = $orderManager->createOrderList();

// Get the newest 10 orders

$orderList->setOrder('order.orderDate desc');

$orderList->setLimit(10, 0);

// Iterate through the orders

/** @var \Pimcore\Bundle\EcommerceFrameworkBundle\OrderManager\


OrderListItemInterface $order */

foreach ($orderList as $order) {

echo $order->getOrdernumber();

// ALTERNATE: use knp paginator service: PaginatorInterface $paginator

$paginator = $paginator->paginate(
$orderList,

$request->get('page', 1),

10

);

foreach ($paginator as $order) {

// Do something with each order

?>

```

### Basic Usage: Using Filters

To filter orders by specific criteria, create a filter and add it to the


order list.

```php

<?php

// Create a new order list

$orderManager = Factory::getInstance()->getOrderManager();

$orderList = $orderManager->createOrderList();

// Create a date time filter

$filterDate = new \Pimcore\Bundle\EcommerceFrameworkBundle\OrderManager\


Order\Listing\Filter\OrderDateTime();

$filterDate->setFrom(new DateTime('20.01.2015'));

$filterDate->setTill(new DateTime('31.01.2015'));
// Add the filter to the order list

$orderList->addFilter($filterDate);

?>

```

### Basic Usage: List Order Items

To list only order items and filter orders that are committed:

```php

<?php

// Create a new order list

$orderManager = Factory::getInstance()->getOrderManager();

$orderList = $orderManager->createOrderList();

// Get only orders that are committed

$orderList->setListType($orderList::LIST_TYPE_ORDER_ITEM);

$orderList->setOrderState(AbstractOrder::ORDER_STATE_COMMITTED);

?>

```

### Advanced Usage: Custom Conditions

To apply custom conditions to the order list:


```php

<?php

// Create a new order list

$orderManager = Factory::getInstance()->getOrderManager();

$orderList = $orderManager->createOrderList();

// Example: Search for a specific order number

$query = $orderList->getQuery();

$query->where('order.ordernumber = ?', 'ord_554b425dcae53');

// Example: Search for a user comment

$query = $orderList->getQuery();

query->where('order.comment like ?', '%hello world%');

?>

```

### Expert Usage: High Performance

To avoid loading Pimcore objects for higher performance:

```php

<?php

// Create a new order list

$orderManager = Factory::getInstance()->getOrderManager();

$orderList = $orderManager->createOrderList();
// Add all required fields to the select

$orderList->addSelectField(['OrderNumber' => 'order.orderNumber']);

$orderList->addSelectField(['TotalPrice' => 'order.totalPrice']);

$orderList->addSelectField(['Items' => 'count(orderItem.id)']);

?>

```

### Expert Usage: Extended Conditions via Joins

To join tables and filter by extended conditions:

```php

<?php

// Example: Get all orders for a customer

$orderList->joinCustomer(\Pimcore\Model\DataObject\Customer::classId());

$orderList->getQuery()->where('customer.id = ?', 12345);

// Example: Filter by product number

$orderList->joinProduct(\Pimcore\Model\DataObject\Product::classId());

$orderList->getQuery()->where('product.productNumber = ?', 'CMD1191');

?>

```

### Generic Filters


The namespace for filters is `\Pimcore\Bundle\EcommerceFrameworkBundle\
OrderManager\Order\Listing\Filter`. Some of the filters include:

- **OrderDateTime**: Date range filter.

- **OrderSearch**: Search order for a specified keyword.

- **Payment**: Filter by payment state (ok or fail).

- **Product**: Filter by product and its variants.

- **ProductType**: Filter ordered products by the given class names.

- **CustomerObject**: Filter orders by a given customer object.

- **Search**: Generic search filter for searches against a given DB column.

- **Search\Customer**: Search for customer name.

- **Search\CustomerEmail**: Search for customer email.

- **Search\PaymentReference**: Search for a payment reference.

### Conclusion

The Order List API provides a comprehensive tool for managing and filtering
order data in the Pimcore E-Commerce Framework, allowing for efficient
order processing and retrieval through various predefined and custom
filters.

User

Working with Order Agent

The Order Agent is a one stop API for working with orders, e.g. changing
state of orders, modifying quantity of items, etc. and keeps track of these
changes in a change log.

See following examples for how Order Agent can be used:

Change item quantity

<?php
// load order item

$orderItem = DataObject\OnlineShopOrderItem::getById($this-
>getParam('id'));

$order = $orderItem->getOrder();

// create new order agent

$orderManager = Factory::getInstance()->getOrderManager();

$orderAgent = $orderManager->createOrderAgent($order);

// change amount to 5

/** @var \Pimcore\Model\Element\Note $log */

$log = $orderAgent->itemChangeAmount($orderItem, 5);

// add user comment

$log->addData('message', 'text', 'customer has changed the order by


phone');

$log->save();

Changelog Usage

<?php

// load order

$order = DataObject\OnlineShopOrder::getById($this->getParam('id'));

// create new order agent

$orderManager = Factory::getInstance()->getOrderManager();
$orderAgent = $orderManager->createOrderAgent($order);

// get changelog

/** @var \Pimcore\Model\Element\Note $log */

foreach($orderAgent->getFullChangeLog() as $log) {

...

ChatGPT

## Working with Order Agent in Pimcore E-Commerce Framework

The Order Agent provides a comprehensive API for working with orders,
including changing the state of orders, modifying the quantity of items,
and keeping track of these changes in a changelog.

### Change Item Quantity

To change the quantity of an order item:

```php

<?php

// Load order item

$orderItem = DataObject\OnlineShopOrderItem::getById($this-
>getParam('id'));

$order = $orderItem->getOrder();

// Create a new order agent


$orderManager = Factory::getInstance()->getOrderManager();

$orderAgent = $orderManager->createOrderAgent($order);

// Change the amount to 5

/** @var \Pimcore\Model\Element\Note $log */

$log = $orderAgent->itemChangeAmount($orderItem, 5);

// Add user comment

$log->addData('message', 'text', 'customer has changed the order by


phone');

$log->save();

?>

```

In this example:

1. The order item is loaded using its ID.

2. The corresponding order is retrieved from the order item.

3. A new order agent is created using the order.

4. The quantity of the order item is changed to 5 using the


`itemChangeAmount` method.

5. A user comment is added to the changelog entry and saved.

### Changelog Usage

To retrieve and work with the changelog of an order:

```php

<?php
// Load order

$order = DataObject\OnlineShopOrder::getById($this->getParam('id'));

// Create a new order agent

$orderManager = Factory::getInstance()->getOrderManager();

$orderAgent = $orderManager->createOrderAgent($order);

// Get changelog

/** @var \Pimcore\Model\Element\Note $log */

foreach ($orderAgent->getFullChangeLog() as $log) {

// Do something with each log entry

...

?>

```

In this example:

1. The order is loaded using its ID.

2. A new order agent is created using the order.

3. The full changelog of the order is retrieved using the


`getFullChangeLog` method.

4. Each log entry can be processed as needed.

### Summary

The Order Agent API in Pimcore's E-Commerce Framework simplifies managing


order data and tracking changes through a changelog. This makes it easier
to handle various order-related operations programmatically while
maintaining a history of modifications.

User

Tracking Manager

The Tracking Manager enables e-commerce transaction tracking for e-commerce


websites built with the framework. Due to different tracker
implementations, it supports different tracking services.

Current implementations of trackers are

Google Tag Manager (GTM): \\Pimcore\Bundle\EcommerceFrameworkBundle\


Tracking\Tracker\GoogleTagManager

Google Analytics Classic: \Pimcore\Bundle\EcommerceFrameworkBundle\


Tracking\Tracker\Analytics\Ecommerce

Google Analytics Universal: \Pimcore\Bundle\EcommerceFrameworkBundle\


Tracking\Tracker\Analytics\UniversalEcommerce

Google Analytics Enhanced E-Commerce: \Pimcore\Bundle\


EcommerceFrameworkBundle\Tracking\Tracker\Analytics\EnhancedEcommerce

Supported Tracking Actions

The Tracking Manager supports several tracking actions that can be used.
These tracking actions are delegated to the trackers.

Product Impression

Tracks product impression

$trackingManager->trackProductImpression($product)

Product View

Tracks product view (of detail page)

$trackingManager->trackProductView($product)

Category View

Tracks a category page view

$trackingManager->trackCategoryPageView($category)
Cart Product Action Add

Tracks action for adding product to cart

$trackingManager->trackCartProductActionAdd($cart, $product, $quantity)

Cart Product Action Remove

Tracks action for removing product from cart

$trackingManager->trackProductActionRemove($cart, $product, $quantity)

Cart Update

Tracks a generic cart update for trackers not supporting add/remove. This
can be sent on every cart list or cart change.

$trackingManager->trackProductActionRemove($cart, $product, $quantity)

Checkout

Tracks start of checkout with first step

$trackingManager->trackCheckout($cart)

Checkout Step

Tracks checkout step

$trackingManager->trackCheckoutStep($step, $cart, $stepNumber,


$checkoutOption)

Checkout Complete

Tracks checkout complete

$trackingManager->trackCheckoutComplete($order)

There are 2 deprecated actions which are still supported by should be


replaced with their new counterparts:

Product Action Add (use trackCartProductActionAdd instead)

Tracks action for adding product to cart

$trackingManager->trackProductActionAdd($product, $quantity)

Product Action Remove (use trackCartProductActionRemove instead)

Tracks action for removing product from cart


$trackingManager->trackProductActionRemove($product, $quantity)

Be aware: Depending on the used tracking service some of these actions


might not be available. If so, the tracking action is ignored for this
tracker.

Configuration

The configuration takes place in the


pimcore_ecommerce_framework.tracking_manager config section. If no
TrackingItemBuilder is configured, the TrackingItemBuilder will fall back
to the default implementation \Pimcore\Bundle\EcommerceFrameworkBundle\
Tracking\TrackingItemBuilder. Further information about TrackingItemBuilder
see below.

pimcore_ecommerce_framework:

# tracking manager - define which trackers (e.g. Google Analytics


Universal Ecommerce) are active and should

# be called when you track something via TrackingManager

tracking_manager:

# service ID of tracking manager - the following is the default


value and can be omitted

tracking_manager_id: Pimcore\Bundle\EcommerceFrameworkBundle\
Tracking\TrackingManager

trackers:

# enable the core enhanced_ecommerce tracker with default


options

enhanced_ecommerce:

enabled: true

my_custom_tracker:

# use already defined enhanced ecommerce tracker

id: Pimcore\Bundle\EcommerceFrameworkBundle\Tracking\
Tracker\Analytics\EnhancedEcommerce
# options vary by tracker implementation

options:

template_prefix: App:Tracking/analytics/enhanced

# service id for item builder

item_builder_id: App\Ecommerce\Tracking\TrackingItemBuilder

# List of assortment and checkout tenants where this


tracker should be activated for.

tenants:

# Add list of assortment tenants where the tracker


should be activated for. Empty array means activated for all tenants.

assortment: []

# Add list of checkout tenants where the tracker should


be activated for. Empty array means activated for all tenants.

checkout: []

Tracking Manager With Tenants

The Tracking Manager supports tenants in a different way than the other
framework modules. While with the other modules, the tenant configuration
takes place on the highest level of configuration and each configuration is
only valid for one tenant, the tenant configuration in the tracking manager
takes place within the trackers them self. There a list of assortment and
checkout tenants for which the tracker should be enabled can be provided
(see configuration above).

If nothing is set or an empty array is provided, the tracker is active for


all tenants.
Working with Tracking Manager

For utilizing the Tracking Manager, just call the corresponding methods of
the TrackingManager in your controller. The framework does the rest (adding
necessary code snippets to your view, etc.).

See the following examples

Product Impression

<?php

namespace App\Controller;

use Knp\Component\Pager\PaginatorInterface;

use Pimcore\Bundle\EcommerceFrameworkBundle\Tracking\TrackingManager;

use Pimcore\Controller\FrontendController;

use Symfony\Component\HttpFoundation\Request;

use Symfony\Component\HttpFoundation\Response;

class ShopController extends FrontendController

public function listAction(Request $request, TrackingManager


$trackingManager, PaginatorInterface $paginator): Response

// ...

$paginator = $paginator->paginate($products, $request->get('page',


1));

foreach ($paginator as $product) {


$trackingManager->trackProductImpression($product);

// ...

Checkout

<?php

use Pimcore\Bundle\EcommerceFrameworkBundle\Tracking\TrackingManager;

class CheckoutController extends AbstractCartAware

public function startCheckoutAction(TrackingManager $trackingManager) {

...

$trackingManager->trackCheckout($this->getCart());

...

Project Specific Data

Adding project specific data to tracking items by extending the


TrackingItemBuilder class. The extending class has to be defined as service
and configured on the tracker configuration (see above).
Example for Additional Data in Product Impressions

Define a custom item builder:

<?php

use Pimcore\Bundle\EcommerceFrameworkBundle\Model\ProductInterface;

use Pimcore\Bundle\EcommerceFrameworkBundle\Tracking\
ProductImpressionInterface;

class TrackingItemBuilder extends \Pimcore\Bundle\EcommerceFrameworkBundle\


Tracking\TrackingItemBuilder

private static int $impressionPosition = 0;

public function buildProductImpressionItem(ProductInterface $product):


ProductImpression

$item = parent::buildProductImpressionItem($product);

$item->setId($product->getOSProductNumber());

$item->setList($this->getImpressionListName());

self::$impressionPosition++;

$item->setPosition(self::$impressionPosition);

return $item;

}
}

And define it as service:

services:

App\Ecommerce\Tracking\TrackingItemBuilder: ~

External Links

Google Documentation Enhanced E-Commerce

ChatGPT

## Tracking Manager in Pimcore E-Commerce Framework

The Tracking Manager in Pimcore enables e-commerce transaction tracking for


websites built with the framework. It supports various tracking services
through different tracker implementations.

### Supported Tracker Implementations

- **Google Tag Manager (GTM):** `\\Pimcore\Bundle\EcommerceFrameworkBundle\


Tracking\Tracker\GoogleTagManager`

- **Google Analytics Classic:** `\\Pimcore\Bundle\EcommerceFrameworkBundle\


Tracking\Tracker\Analytics\Ecommerce`

- **Google Analytics Universal:** `\\Pimcore\Bundle\


EcommerceFrameworkBundle\Tracking\Tracker\Analytics\UniversalEcommerce`

- **Google Analytics Enhanced E-Commerce:** `\\Pimcore\Bundle\


EcommerceFrameworkBundle\Tracking\Tracker\Analytics\EnhancedEcommerce`

### Supported Tracking Actions


The Tracking Manager supports various tracking actions, which are delegated
to the trackers. Here are some examples:

- **Product Impression:** Tracks product impression.

```php

$trackingManager->trackProductImpression($product);

```

- **Product View:** Tracks product view (detail page).

```php

$trackingManager->trackProductView($product);

```

- **Category View:** Tracks a category page view.

```php

$trackingManager->trackCategoryPageView($category);

```

- **Cart Product Action Add:** Tracks action for adding product to cart.

```php

$trackingManager->trackCartProductActionAdd($cart, $product, $quantity);

```

- **Cart Product Action Remove:** Tracks action for removing product from
cart.

```php

$trackingManager->trackCartProductActionRemove($cart, $product,
$quantity);

```

- **Cart Update:** Tracks a generic cart update for trackers not supporting
add/remove.

```php

$trackingManager->trackCartUpdate($cart);
```

- **Checkout:** Tracks start of checkout with the first step.

```php

$trackingManager->trackCheckout($cart);

```

- **Checkout Step:** Tracks a checkout step.

```php

$trackingManager->trackCheckoutStep($step, $cart, $stepNumber,


$checkoutOption);

```

- **Checkout Complete:** Tracks checkout completion.

```php

$trackingManager->trackCheckoutComplete($order);

```

### Configuration

Configuration is done in the `pimcore_ecommerce_framework.tracking_manager`


config section. If no `TrackingItemBuilder` is configured, it will fall
back to the default implementation `\\Pimcore\Bundle\
EcommerceFrameworkBundle\Tracking\TrackingItemBuilder`.

```yaml

pimcore_ecommerce_framework:

tracking_manager:

tracking_manager_id: Pimcore\Bundle\EcommerceFrameworkBundle\
Tracking\TrackingManager

trackers:
enhanced_ecommerce:

enabled: true

my_custom_tracker:

id: Pimcore\Bundle\EcommerceFrameworkBundle\Tracking\
Tracker\Analytics\EnhancedEcommerce

options:

template_prefix: App:Tracking/analytics/enhanced

item_builder_id: App\Ecommerce\Tracking\TrackingItemBuilder

tenants:

assortment: []

checkout: []

```

### Tracking Manager with Tenants

The Tracking Manager supports tenants. Each tracker can be configured with
a list of assortment and checkout tenants where the tracker should be
activated. If nothing is set or an empty array is provided, the tracker is
active for all tenants.

### Working with Tracking Manager

To utilize the Tracking Manager, call the corresponding methods in your


controller. The framework handles adding the necessary code snippets to
your view.
#### Example: Product Impression

```php

<?php

namespace App\Controller;

use Knp\Component\Pager\PaginatorInterface;

use Pimcore\Bundle\EcommerceFrameworkBundle\Tracking\TrackingManager;

use Pimcore\Controller\FrontendController;

use Symfony\Component\HttpFoundation\Request;

use Symfony\Component\HttpFoundation\Response;

class ShopController extends FrontendController

public function listAction(Request $request, TrackingManager


$trackingManager, PaginatorInterface $paginator): Response

// ...

$paginator = $paginator->paginate($products, $request->get('page',


1));

foreach ($paginator as $product) {

$trackingManager->trackProductImpression($product);

// ...

}
}

```

#### Example: Checkout

```php

<?php

use Pimcore\Bundle\EcommerceFrameworkBundle\Tracking\TrackingManager;

class CheckoutController extends AbstractCartAware

public function startCheckoutAction(TrackingManager $trackingManager) {

...

$trackingManager->trackCheckout($this->getCart());

...

```

### Project Specific Data

You can add project-specific data to tracking items by extending the


`TrackingItemBuilder` class. Define the extending class as a service and
configure it in the tracker configuration.

#### Example: Additional Data in Product Impressions


Define a custom item builder:

```php

<?php

use Pimcore\Bundle\EcommerceFrameworkBundle\Model\ProductInterface;

use Pimcore\Bundle\EcommerceFrameworkBundle\Tracking\
ProductImpressionInterface;

class TrackingItemBuilder extends \Pimcore\Bundle\EcommerceFrameworkBundle\


Tracking\TrackingItemBuilder

private static int $impressionPosition = 0;

public function buildProductImpressionItem(ProductInterface $product):


ProductImpression

$item = parent::buildProductImpressionItem($product);

$item->setId($product->getOSProductNumber());

$item->setList($this->getImpressionListName());

self::$impressionPosition++;

$item->setPosition(self::$impressionPosition);

return $item;

}
```

And define it as a service:

```yaml

services:

App\Ecommerce\Tracking\TrackingItemBuilder: ~

```

### External Links

- [Google Documentation Enhanced


E-Commerce](https://developers.google.com/analytics/devguides/collection/
analyticsjs/enhanced-ecommerce)

User

Events and Event Listeners

General

This bundle provides additional Events.

It's recommended to have a look into the Pimcore Events and Event Listeners
documentation

Available Events

Ecommerce::Index Service

Ecommerce::Checkout Manager

Ecommerce::Commit Order Processor

Ecommerce::Order Agent

Ecommerce::Order Manager
ChatGPT

## Events and Event Listeners in Pimcore E-Commerce Framework

The Pimcore E-Commerce Framework provides various events to enable


developers to extend and customize the behavior of the e-commerce
processes. It's recommended to review the Pimcore documentation on [Events
and Event
Listeners](https://pimcore.com/docs/10.x/Development_Documentation/
Best_Practices/Event_Listeners.html) for foundational understanding.

### Available Events

Here are the specific events provided by the Pimcore E-Commerce Framework:

### Ecommerce::Index Service

These events relate to the indexing service used for the e-commerce product
data.

### Ecommerce::Checkout Manager

These events are associated with the checkout manager, which handles the
checkout process in the e-commerce system.

### Ecommerce::Commit Order Processor

These events are triggered by the commit order processor, which is


responsible for finalizing orders after payment.

### Ecommerce::Order Agent


These events pertain to the order agent, which is used for managing and
modifying orders after they have been created.

### Ecommerce::Order Manager

These events are linked to the order manager, which handles the overall
order management functionalities, including creating, loading, and
filtering orders.

### Examples

Here are some examples of how to listen to and handle these events in your
Pimcore project.

#### Example: Listening to an Event

First, create an event listener service class:

```php

namespace App\EventListener;

use Pimcore\Event\Model\DataObjectEvent;

use Symfony\Component\EventDispatcher\EventSubscriberInterface;

class ProductIndexListener implements EventSubscriberInterface

public static function getSubscribedEvents(): array

return [
'ecommerce.index_service.update' => 'onIndexServiceUpdate',

];

public function onIndexServiceUpdate(DataObjectEvent $event): void

// Your custom logic here

$object = $event->getObject();

// Perform operations with the object

```

Then, register your event listener as a service in your `services.yaml`


file:

```yaml

services:

App\EventListener\ProductIndexListener:

tags:

- { name: 'kernel.event_subscriber' }

```

#### Example: Custom Checkout Step

Suppose you want to add a custom checkout step and perform some actions
when this step is committed:
```php

namespace App\Ecommerce\Checkout;

use Pimcore\Bundle\EcommerceFrameworkBundle\CheckoutManager\AbstractStep;

use Pimcore\Bundle\EcommerceFrameworkBundle\CheckoutManager\
CheckoutStepInterface;

class CustomCheckoutStep extends AbstractStep implements


CheckoutStepInterface

const PRIVATE_NAMESPACE = 'custom_checkout_step';

public function getName(): string

return 'customcheckout';

public function commit($data): bool

$this->cart->setCheckoutData(self::PRIVATE_NAMESPACE,
json_encode($data));

// Perform custom actions here

return true;

public function getData()

$data = json_decode($this->cart-
>getCheckoutData(self::PRIVATE_NAMESPACE));
return $data;

```

Register the custom checkout step in your configuration:

```yaml

pimcore_ecommerce_framework:

checkout_manager:

tenants:

default:

steps:

customcheckout:

class: \App\Ecommerce\Checkout\CustomCheckoutStep

```

#### Example: Handling Order Commit

Create an event listener to handle actions when an order is committed:

```php

namespace App\EventListener;

use Pimcore\Bundle\EcommerceFrameworkBundle\Event\CommitOrderEvent;

use Symfony\Component\EventDispatcher\EventSubscriberInterface;
class OrderCommitListener implements EventSubscriberInterface

public static function getSubscribedEvents(): array

return [

CommitOrderEvent::NAME => 'onOrderCommit',

];

public function onOrderCommit(CommitOrderEvent $event): void

$order = $event->getOrder();

// Perform actions with the committed order

```

Register the event listener:

```yaml

services:

App\EventListener\OrderCommitListener:

tags:

- { name: 'kernel.event_subscriber' }

```

### Conclusion
Using events and event listeners in the Pimcore E-Commerce Framework allows
for flexible and extensible handling of various e-commerce processes. By
subscribing to specific events, you can customize the behavior and
implement additional logic tailored to your project requirements.

User

I have few questions for the above Pimcore E-commerce Framework, can I ask?

ChatGPT

Absolutely! Feel free to ask any questions you have about the Pimcore E-
Commerce Framework. I'll do my best to provide detailed and accurate
answers.

User

I need answers from the above content.

ChatGPT

Sure, I can help with that. Please go ahead and ask your specific questions
related to the Pimcore E-commerce Framework.

User

give me the list of Out Of The Box features in the Pimcore E-Commerce
Framework

ChatGPT

The Pimcore E-Commerce Framework provides a comprehensive set of out-of-


the-box features designed to help developers build sophisticated e-commerce
solutions. Here is a list of these features:

1. **Data Modeling**:

- Flexible data modeling capabilities to define custom data objects and


relationships.

- Support for product variations and attributes.

- Classification store support for structured data.

2. **Product Indexing**:

- Simple MySQL architecture for direct indexing.


- Optimized architecture with store table for efficient indexing and
updates.

- Support for Elasticsearch for advanced search capabilities.

- Indexing of classification store attributes.

- Support for nested documents in Elasticsearch.

3. **Assortment Management**:

- Two-level assortment tenant system: Assortment Tenant and Assortment


Subtenant.

- Configuration of assortment tenants within the system.

- Mockup objects for performance optimization in product lists.

4. **Pricing and Tax Management**:

- Flexible pricing systems for retrieving and calculating prices.

- Tax management components to handle complex tax calculations.

- Pricing rules and voucher support for marketing actions.

5. **Checkout Process**:

- Modular checkout steps for customized checkout flows.

- Commit order processor for handling order finalization.

- Integration with various payment providers.

- Checkout tenants for different cart and checkout manager


configurations.

6. **Order Management**:

- Order manager for creating and managing orders.

- Order agent for modifying orders and tracking changes.

- Advanced order listing and filtering capabilities.


7. **Cart Management**:

- Multi-cart management for different types of product collections


(e.g., cart, wishlist).

- Session-based and database-based cart implementations.

- Price calculation with cart price calculators.

8. **Tracking and Analytics**:

- Tracking manager for e-commerce transaction tracking.

- Support for multiple tracking services (e.g., Google Tag Manager,


Google Analytics).

- Various tracking actions for product impressions, views, cart actions,


checkout steps, and more.

9. **Payment Integration**:

- Support for multiple payment providers.

- Recurring payments management.

- Handling of payment responses and pending payments.

10. **Events and Event Listeners**:

- Support for additional events specific to e-commerce operations.

- Integration with Pimcore's event system for custom event handling.

11. **Backend Configuration and Management**:

- Comprehensive backend UI for managing product data, tax classes,


voucher series, and more.

- Configuration options for customizing the behavior of various


components.
These features are designed to provide a robust and flexible foundation for
building customized e-commerce solutions using the Pimcore platform.

User

list of features offered in the Pimcore E-Commerce Framework

ChatGPT

The Pimcore E-Commerce Framework offers a wide range of features to support


the development of robust and flexible e-commerce solutions. Here is a
comprehensive list of the features provided:

### General Features:

- **Flexible Data Modeling**: Custom data objects and relationships,


product variations, attributes, and classification store support.

- **Product Indexing**: MySQL and Elasticsearch support, optimized indexing


architecture, classification store attributes indexing, nested documents
support in Elasticsearch.

- **Assortment Management**: Two-level assortment tenant system, mockup


objects for performance optimization.

- **Pricing and Tax Management**: Flexible pricing systems, tax management


components, pricing rules, and vouchers.

- **Checkout Process**: Modular checkout steps, commit order processor,


integration with various payment providers, checkout tenants.

- **Order Management**: Order manager for creation and management, order


agent for modifications and tracking changes, advanced listing, and
filtering capabilities.

- **Cart Management**: Multi-cart management, session-based and database-


based cart implementations, price calculation with cart price calculators.

- **Tracking and Analytics**: E-commerce transaction tracking, support for


multiple tracking services, various tracking actions.

- **Payment Integration**: Multiple payment providers, recurring payments,


handling of payment responses, and pending payments.

- **Events and Event Listeners**: Support for additional events specific to


e-commerce operations, integration with Pimcore's event system.

- **Backend Configuration and Management**: Comprehensive backend UI,


configuration options for customizing component behavior.

### Specific Features:


- **Data Architecture and Indexing Process**: Simple MySQL and optimized
architectures, console commands for indexing.

- **Assortment Tenant Configuration**: Implementation of tenant config,


configuring assortment tenants within the configuration, setting current
assortment tenant for frontend.

- **Filter Service**: Configuration of available filters, filter


definitions, integration with Elasticsearch.

- **Working with Prices**: Decimal value objects for prices, rounding


logic, database storage as DECIMAL data type.

- **Availability Systems**: Retrieving or calculating product availability,


configuration of availability systems.

- **Cart Manager**: Creating carts, adding/removing products, listing


products, cart price calculation, configuration of cart manager.

- **Checkout Manager**: One-stop API for checkout process, modular checkout


steps, committing orders, payment integration.

- **Order Manager**: Creating orders based on carts, order storage, loading


orders, order lists and filtering, working with orders after commit.

- **Tracking Manager**: Product impressions, product views, category views,


cart product actions, checkout tracking.

- **Pricing Rules and Vouchers**: Configurable pricing rules, voucher


series, creating and managing vouchers, applying vouchers to carts.

- **Recurring Payments**: Management of recurring payments, handling


payment failures and successes.

### Integration and Customization:

- **Payment Providers**: Integration with Datatrans, PayPal, Klarna, OGone,


MPay24, PayU, Unzer, Hobex, BS PAYONE.

- **Custom Mockup Object Implementation**: Overwriting `createMockupObject`


method in config implementation.

- **Custom Properties to Cart Items**: Extending `CartItem` implementation,


adding custom properties.

- **Project Specific Data in Tracking**: Extending `TrackingItemBuilder`


class, adding additional data to tracking items.

- **Custom Checkout Steps**: Extending `AbstractStep`, implementing


`CheckoutStepInterface`.
These features enable developers to build highly customized and scalable e-
commerce applications using the Pimcore platform, leveraging its robust
data modeling, indexing, cart management, order processing, and tracking
capabilities.

User

prepare and give me a PPT on the Pimcore E-Commerce Framework to present it


officially

ChatGPT

Sure! Below is an outline for a PowerPoint presentation on the Pimcore E-


Commerce Framework. I'll provide the content for each slide, and you can
use this to create a professional presentation.

---

### Slide 1: Title Slide

**Title:** Introduction to the Pimcore E-Commerce Framework

**Subtitle:** Unlocking the Potential of Flexible and Scalable E-Commerce


Solutions

**Presenter's Name:** [Your Name]

**Date:** [Presentation Date]

---

### Slide 2: Agenda

1. Overview of Pimcore E-Commerce Framework

2. Key Features

3. Data Architecture and Indexing

4. Assortment Management

5. Pricing and Tax Management

6. Checkout Process

7. Order Management
8. Cart Management

9. Tracking and Analytics

10. Payment Integration

11. Customization and Extensibility

12. Q&A

---

### Slide 3: Overview of Pimcore E-Commerce Framework

**Content:**

- Introduction to Pimcore

- E-Commerce Framework Overview

- Benefits of Using Pimcore for E-Commerce

- Flexibility

- Scalability

- Integration Capabilities

---

### Slide 4: Key Features

**Content:**

- Flexible Data Modeling

- Product Indexing

- Assortment Management

- Pricing and Tax Management

- Checkout Process

- Order Management
- Cart Management

- Tracking and Analytics

- Payment Integration

---

### Slide 5: Data Architecture and Indexing

**Content:**

- Simple MySQL and Optimized Architectures

- Console Commands for Indexing

- Support for Classification Store Attributes

- Filtering for Nested Documents

---

### Slide 6: Assortment Management

**Content:**

- Two-Level Assortment Tenant System

- Mockup Objects for Performance Optimization

- Setting Up Assortment Tenants

- Configuration and Management

---

### Slide 7: Pricing and Tax Management

**Content:**

- Pricing Systems and PriceInfo Objects


- Tax Management Components

- Pricing Rules and Vouchers

- Integration with ERP Systems

---

### Slide 8: Checkout Process

**Content:**

- Modular Checkout Steps

- Commit Order Processor

- Integration with Payment Providers

- Checkout Tenants

---

### Slide 9: Order Management

**Content:**

- Creating and Managing Orders

- Order Storage and Retrieval

- Advanced Listing and Filtering

- Working with Orders After Commit

---

### Slide 10: Cart Management

**Content:**

- Multi-Cart Management
- Session-Based and Database-Based Cart Implementations

- Price Calculation with Cart Price Calculators

- Adding Custom Properties to Cart Items

---

### Slide 11: Tracking and Analytics

**Content:**

- E-Commerce Transaction Tracking

- Support for Multiple Tracking Services

- Tracking Actions: Product Impressions, Cart Actions, Checkout Steps

- Custom Tracking Item Builders

---

### Slide 12: Payment Integration

**Content:**

- Integration with Various Payment Providers

- Handling Payment Responses

- Recurring Payments

- Custom Strategies for Handling Pending Payments

---

### Slide 13: Customization and Extensibility

**Content:**

- Custom Mockup Object Implementations


- Extending Decimal Class for Custom Calculations

- Creating Custom Checkout Steps

- Project-Specific Data in Tracking Items

---

### Slide 14: Summary

**Content:**

- Recap of Key Features

- Benefits of Using Pimcore E-Commerce Framework

- Flexibility and Scalability for Any E-Commerce Solution

- Q&A Session

---

### Slide 15: Q&A

**Content:**

- Open the floor for questions from the audience

---

### Slide 16: Thank You

**Content:**

- Thank the audience for their time and participation

- Provide contact information for follow-up questions

---
You can use this outline to create your PowerPoint presentation. Each slide
should have the corresponding content mentioned above, formatted
professionally to fit your presentation style. Let me know if you need
further details or additional content for any of the slides.

User

elaborate the above slides and topics for my understanding to present it

ChatGPT

Sure, here's an expanded version of each slide with detailed explanations


to help you understand the content better and present it effectively:

### Slide 1: Title Slide

**Title:** Introduction to the Pimcore E-Commerce Framework

**Subtitle:** Unlocking the Potential of Flexible and Scalable E-Commerce


Solutions

**Presenter's Name:** [Your Name]

**Date:** [Presentation Date]

---

### Slide 2: Agenda

**Content:**

- **Overview of Pimcore E-Commerce Framework**: Brief introduction to


Pimcore and its E-Commerce capabilities.

- **Key Features**: Highlight the major functionalities and benefits.

- **Data Architecture and Indexing**: Explain the data handling mechanisms.

- **Assortment Management**: Discuss how products are organized and


managed.

- **Pricing and Tax Management**: Cover pricing rules and tax handling.

- **Checkout Process**: Walk through the checkout flow.

- **Order Management**: Detail how orders are managed post-purchase.


- **Cart Management**: Describe cart functionalities.

- **Tracking and Analytics**: Explain how tracking and analytics are


handled.

- **Payment Integration**: Discuss integration with payment providers.

- **Customization and Extensibility**: Highlight the framework's


flexibility.

- **Q&A**: Open the floor for questions.

---

### Slide 3: Overview of Pimcore E-Commerce Framework

**Content:**

- **Introduction to Pimcore**: Pimcore is a leading open-source platform


for managing digital experiences.

- **E-Commerce Framework Overview**: Pimcore's E-Commerce Framework offers


robust tools for building flexible and scalable e-commerce solutions.

- **Benefits of Using Pimcore for E-Commerce**:

- **Flexibility**: Customizable to fit any e-commerce needs.

- **Scalability**: Handles small to enterprise-level e-commerce


solutions.

- **Integration Capabilities**: Easily integrates with existing systems


and third-party services.

---

### Slide 4: Key Features

**Content:**

- **Flexible Data Modeling**: Create custom data structures for products,


categories, and other entities.

- **Product Indexing**: Efficiently index products for fast search and


retrieval.
- **Assortment Management**: Manage different assortments and product
groupings.

- **Pricing and Tax Management**: Implement complex pricing rules and tax
calculations.

- **Checkout Process**: Modular and customizable checkout flow.

- **Order Management**: Comprehensive order handling and processing.

- **Cart Management**: Manage multiple carts and user-specific collections.

- **Tracking and Analytics**: Built-in support for tracking user


interactions and e-commerce events.

- **Payment Integration**: Seamless integration with various payment


providers.

---

### Slide 5: Data Architecture and Indexing

**Content:**

- **Simple MySQL and Optimized Architectures**:

- **Simple MySQL**: Direct transfer of Pimcore object data to the product


index.

- **Optimized Architecture**: Uses a store table for efficient indexing,


asynchronous updates, and better performance.

- **Console Commands for Indexing**: Commands to update the index and


manage indexing structures.

- **Support for Classification Store Attributes**: Index classification


store attributes without separate definitions.

- **Filtering for Nested Documents**: Efficiently query nested documents


for complex data structures.

---

### Slide 6: Assortment Management

**Content:**
- **Two-Level Assortment Tenant System**:

- **Assortment Tenant**: Heavy-weight, independent shop instances.

- **Assortment Subtenant**: Light-weight, subset of products within a


shop instance.

- **Mockup Objects for Performance Optimization**: Lightweight


representations of products to improve performance.

- **Setting Up Assortment Tenants**: Steps to configure assortment tenants,


including tenant config class and service declarations.

- **Configuration and Management**: Define assortment tenants in the


configuration and manage them through the E-Commerce Framework.

---

### Slide 7: Pricing and Tax Management

**Content:**

- **Pricing Systems and PriceInfo Objects**: Customizable pricing systems


that return PriceInfo objects containing calculated prices.

- **Tax Management Components**:

- **OnlineShopTaxClass**: Configure tax classes for different countries


and product groups.

- **TaxCalculationService**: Calculate taxes based on the configured tax


classes.

- **Pricing Rules and Vouchers**:

- **Pricing Rules**: Automatically apply discounts, free shipping, and


other benefits.

- **Vouchers**: Create and manage voucher series, generate tokens, and


apply voucher benefits.

- **Integration with ERP Systems**: Extend default implementations to send


orders to ERP systems or other integrations.

---
### Slide 8: Checkout Process

**Content:**

- **Modular Checkout Steps**: Implement steps like delivery address,


payment options, and order confirmation.

- **Commit Order Processor**: Handles the finalization of the order,


including sending to ERP systems and sending confirmation emails.

- **Integration with Payment Providers**: Seamlessly integrate with payment


gateways for processing payments.

- **Checkout Tenants**: Configure different checkout processes and payment


options based on tenant settings.

---

### Slide 9: Order Management

**Content:**

- **Creating and Managing Orders**: Convert carts to orders and manage them
through the Order Manager.

- **Order Storage and Retrieval**: Store orders as Pimcore objects and


retrieve them as needed.

- **Advanced Listing and Filtering**: Use Order Lists for filtering and
listing orders efficiently.

- **Working with Orders After Commit**: Use Order Agents to modify order
items, track changes, and handle order states.

---

### Slide 10: Cart Management

**Content:**

- **Multi-Cart Management**: Handle multiple carts (e.g., shopping cart,


wish list) for each user.

- **Session-Based and Database-Based Cart Implementations**: Store carts in


user sessions or in the database for persistent storage.
- **Price Calculation with Cart Price Calculators**: Calculate cart totals,
including shipping costs and discounts.

- **Adding Custom Properties to Cart Items**: Extend cart items with custom
properties and manage them through the Cart Manager.

---

### Slide 11: Tracking and Analytics

**Content:**

- **E-Commerce Transaction Tracking**: Track user interactions, product


impressions, and transactions.

- **Support for Multiple Tracking Services**:

- **Google Tag Manager**

- **Google Analytics (Classic, Universal, Enhanced E-Commerce)**

- **Tracking Actions**:

- **Product Impressions**

- **Product Views**

- **Category Views**

- **Cart Actions (Add/Remove)**

- **Checkout Steps**

- **Checkout Completion**

- **Custom Tracking Item Builders**: Extend tracking capabilities to


include project-specific data.

---

### Slide 12: Payment Integration

**Content:**

- **Integration with Various Payment Providers**:


- **Datatrans**

- **PayPal**

- **Klarna**

- **MPay24**

- **Hobex**

- **Handling Payment Responses**: Process payment responses and handle


successful or failed payments.

- **Recurring Payments**: Support for recurring payments and handling


multiple payment attempts.

- **Custom Strategies for Handling Pending Payments**: Implement strategies


to handle pending payments efficiently.

---

### Slide 13: Customization and Extensibility

**Content:**

- **Custom Mockup Object Implementations**: Create custom lightweight


representations of products.

- **Extending Decimal Class for Custom Calculations**: Implement custom


calculation logic while maintaining immutability.

- **Creating Custom Checkout Steps**: Develop project-specific checkout


steps to meet unique requirements.

- **Project-Specific Data in Tracking Items**: Extend tracking items to


include additional data relevant to your project.

---

### Slide 14: Summary

**Content:**

- **Recap of Key Features**: Summarize the major functionalities discussed.

- **Benefits of Using Pimcore E-Commerce Framework**:


- **Flexibility**: Customizable to fit any business needs.

- **Scalability**: Suitable for small to large-scale e-commerce


solutions.

- **Integration**: Easily integrates with existing systems and third-


party services.

- **Q&A Session**: Invite questions from the audience.

---

### Slide 15: Q&A

**Content:**

- **Open the Floor for Questions**: Encourage audience participation and


address their queries.

---

### Slide 16: Thank You

**Content:**

- **Thank the Audience for Their Time and Participation**: Express


gratitude for their attention.

- **Provide Contact Information for Follow-Up Questions**: Share your


contact details for further queries.

---

Use this expanded content to create your PowerPoint presentation. Each


slide should have the corresponding detailed content, formatted to fit your
presentation style. This will help you deliver a comprehensive and engaging
presentation on the Pimcore E-Commerce Framework.

User

Describe in detail below topics from the above Pimcore E-Commerce Framework
Overview of Pimcore E-Commerce Framework

Key Features

Data Architecture and Indexing

Assortment Management

Pricing and Tax Management

Checkout Process

Order Management

Cart Management

Tracking and Analytics

Payment Integration

Customization and Extensibility

ChatGPT

Sure, here’s a detailed description of each topic from the Pimcore E-


Commerce Framework:

### 1. Overview of Pimcore E-Commerce Framework

**Pimcore** is an open-source platform known for its ability to manage


digital experiences, including CMS, DAM, PIM, and e-commerce. The Pimcore
E-Commerce Framework provides a comprehensive set of tools to build
flexible and scalable e-commerce solutions.

**Benefits of Using Pimcore for E-Commerce:**

- **Flexibility**: Highly customizable to meet specific business needs.

- **Scalability**: Capable of handling both small and large-scale e-


commerce applications.

- **Integration**: Easily integrates with other systems, making it a


versatile solution for various business requirements.

---
### 2. Key Features

**Flexible Data Modeling**: Allows creation of custom data structures for


products, categories, and other entities.

- **Product Indexing**: Efficient indexing system for fast search and


retrieval of product data.

- **Assortment Management**: Manage different product assortments and


groupings.

- **Pricing and Tax Management**: Complex pricing rules and tax


calculations are supported.

- **Checkout Process**: Modular checkout process that can be customized.

- **Order Management**: Comprehensive management of orders from creation to


fulfillment.

- **Cart Management**: Ability to manage multiple carts per user, such as


wish lists and shopping carts.

- **Tracking and Analytics**: Built-in support for tracking user


interactions and e-commerce events.

- **Payment Integration**: Seamless integration with various payment


providers.

---

### 3. Data Architecture and Indexing

**Simple MySQL and Optimized Architectures**:

- **Simple MySQL Architecture**: Direct transfer of Pimcore object data to


the product index.

- **Optimized Architecture**: Uses a store table for efficient indexing,


asynchronous updates, and better performance.

**Indexing Commands**:

- Use console commands to update the index and manage indexing structures.

- Support for classification store attributes and filtering for nested


documents.
**Optimized Architecture**:

- Reduces load on the index and improves performance by using a store


table.

- Updates are written to the store table and processed asynchronously.

---

### 4. Assortment Management

**Two-Level Assortment Tenant System**:

- **Assortment Tenant**: Independent shop instances with unique product


sets.

- **Assortment Subtenant**: Subsets of products within a shop instance.

**Mockup Objects**:

- Lightweight representations of products to improve performance by


reducing load times.

- Custom mockup implementations can be created for specific needs.

**Configuration**:

- Set up assortment tenants with specific tenant config classes and service
declarations.

- Manage assortments through the E-Commerce Framework configuration.

---

### 5. Pricing and Tax Management

**Pricing Systems and PriceInfo Objects**:


- Customizable pricing systems that return PriceInfo objects containing
calculated prices.

- Support for complex pricing rules and discount schemes.

**Tax Management**:

- **OnlineShopTaxClass**: Configure tax classes for different regions and


product groups.

- **TaxCalculationService**: Calculate taxes based on configured tax


classes.

**Pricing Rules and Vouchers**:

- Implement rules to automatically apply discounts, free shipping, and


other benefits.

- Create and manage voucher series and tokens to offer promotional


benefits.

---

### 6. Checkout Process

**Modular Checkout Steps**:

- Implement customizable steps like delivery address, payment options, and


order confirmation.

- Each step is responsible for storing and validating necessary data.

**Commit Order Processor**:

- Finalizes the order by sending it to ERP systems, sending confirmation


emails, etc.

- Default implementation creates Pimcore order objects and handles basic


functionalities.

**Checkout Tenants**:
- Allows for different checkout processes and payment options based on
tenant settings.

- Configure different steps and providers for each tenant.

---

### 7. Order Management

**Creating and Managing Orders**:

- Convert carts to orders and manage them through the Order Manager.

- Store orders as Pimcore objects and retrieve them efficiently.

**Advanced Listing and Filtering**:

- Use Order Lists to filter and list orders with predefined filters.

- Load order items and apply advanced filtering conditions.

**Working with Orders After Commit**:

- Use Order Agents to modify order items, track changes, and manage order
states.

- Change item quantities and add custom properties to orders post-commit.

---

### 8. Cart Management

**Multi-Cart Management**:

- Handle multiple carts per user, such as shopping carts, wish lists, and
compare lists.

- Manage carts efficiently with session-based or database-based storage.


**Price Calculation**:

- Cart Price Calculators compute totals, including shipping costs and


discounts.

- Use price modificators to apply cart-level discounts and charges.

**Adding Custom Properties**:

- Extend cart items with custom properties and manage them through the Cart
Manager.

- Customize the cart functionalities to fit specific business needs.

---

### 9. Tracking and Analytics

**E-Commerce Transaction Tracking**:

- Track user interactions, product impressions, and transactions.

- Use tracking actions like product impressions, product views, category


views, cart actions, checkout steps, and checkout completion.

**Support for Multiple Tracking Services**:

- Integrate with Google Tag Manager, Google Analytics (Classic, Universal,


Enhanced E-Commerce).

**Custom Tracking Item Builders**:

- Extend tracking capabilities to include project-specific data.

- Customize tracking actions to fit the specific requirements of the


business.

---
### 10. Payment Integration

**Integration with Payment Providers**:

- Support for various payment providers, including Datatrans, PayPal,


Klarna, MPay24, and Hobex.

**Handling Payment Responses**:

- Process payment responses and handle successful or failed payments.

- Ensure smooth payment flow and secure transactions.

**Recurring Payments**:

- Support for recurring payments and managing multiple payment attempts.

- Implement strategies to handle pending payments efficiently.

---

### 11. Customization and Extensibility

**Custom Mockup Object Implementations**:

- Create lightweight product representations for better performance.

- Implement custom mockup objects tailored to specific business needs.

**Extending Decimal Class**:

- Implement custom calculation logic while maintaining immutability.

- Use Decimal class for precise calculations without floating-point errors.

**Creating Custom Checkout Steps**:

- Develop project-specific checkout steps to meet unique requirements.

- Customize the checkout process to enhance user experience.


**Project-Specific Data in Tracking Items**:

- Extend tracking items to include additional data relevant to your


project.

- Ensure comprehensive tracking and analytics tailored to business needs.

---

Use these detailed descriptions to deepen your understanding of each topic


and present them effectively.

User

Explain me in detail for the below topics in Pimcore E-Commerce Framework

1. Introduction E-commerce Framework

2. Products (Product Index Config.)/Index List Product Service/Elastic


Search

3. Cart Manager

4. Payment Manager/Price Management/Pricing/ Tax Management/Pricing


Rules/Advanced Pricing System

5. Voucher/Offers/Promotions/Promo Codes

6. Customer Account

7. Tracking Manager

8. Checkout Manager

9. Authentication Login/Logout Listeners

ChatGPT

### 1. Introduction to E-commerce Framework


The **Pimcore E-Commerce Framework** is a comprehensive, open-source
platform designed to build flexible and scalable e-commerce solutions. It
is part of the larger Pimcore ecosystem, which includes capabilities for
content management (CMS), digital asset management (DAM), product
information management (PIM), and customer data management (CDP).

**Key Benefits:**

- **Flexibility:** Highly customizable to meet specific business needs.

- **Scalability:** Suitable for small to large-scale e-commerce operations.

- **Integration:** Easily integrates with other systems, enhancing its


versatility.

- **Unified Platform:** Combines multiple functionalities like PIM, DAM,


CMS, and e-commerce in one platform, simplifying data management and
reducing complexity.

### 2. Products (Product Index Configuration) / Index List Product


Service / Elastic Search

**Product Index Configuration:**

- **Data Architecture:** Pimcore supports both Simple MySQL and Optimized


Architectures. The Simple MySQL Architecture transfers Pimcore object data
directly to the Product Index, while the Optimized Architecture uses a
store table for efficient indexing.

- **Indexing Commands:** Console commands are used to update and manage


index structures, ensuring fast and accurate product searches.

**Index List Product Service:**

- This service provides an API for retrieving and filtering products from
the Product Index. The service is tailored to the specific implementation
of the Product Index (e.g., MySQL or Elasticsearch).

**Elasticsearch:**

- **Integration:** Elasticsearch 8 is supported for fast and scalable


search capabilities.

- **Configuration:** Customizable through configuration options like index


settings and client configuration.
- **Reindexing Mode:** Automatically reindexes when necessary to
accommodate changes in data types or schema.

### 3. Cart Manager

**Cart Manager Overview:**

- Responsible for handling all aspects of the shopping cart, including


multiple carts per user (e.g., shopping cart, wish list).

- **Creating Carts:** Carts can be created programmatically and associated


with users or sessions.

- **Adding/Removing Products:** Products can be added or removed from carts


through the Cart Manager API.

- **Price Calculation:** Utilizes Cart Price Calculators to compute totals,


including sub-totals and grand totals, with modifications for discounts,
shipping costs, etc.

- **Configuration:** Defined in the


`pimcore_ecommerce_framework.cart_manager` configuration section,
supporting tenant-specific settings.

### 4. Payment Manager / Price Management / Pricing / Tax Management /


Pricing Rules / Advanced Pricing System

**Payment Manager:**

- Manages payment integrations, supporting various payment providers like


Datatrans, PayPal, Klarna, and more.

- **Workflow:** Involves initializing payment, redirecting to the payment


provider, handling payment response, and committing the order.

**Price Management:**

- **Price Systems:** Configurable pricing systems return PriceInfo objects


containing calculated prices.

- **Tax Management:** Utilizes tax classes (OnlineShopTaxClass) and the


TaxCalculationService to manage and calculate taxes.

- **Pricing Rules:** Define rules for applying discounts, free shipping,


and other benefits automatically.
- **Advanced Pricing System:** Supports complex pricing structures and
custom price calculations.

### 5. Voucher / Offers / Promotions / Promo Codes

**Vouchers:**

- **OnlineShopVoucherSeries:** Manage voucher series, generate tokens, and


define benefits through pricing rules.

- **Integration:** Vouchers can be added to the cart by users and managed


through the cart API.

**Offers and Promotions:**

- Implemented through Pricing Rules, allowing for various marketing actions


like discounts and gift items.

- **Promo Codes:** Managed similarly to vouchers, with tokens and rules


defining their application and benefits.

### 6. Customer Account

**Customer Account Management:**

- **User Data:** Manage customer data, including personal details, order


history, and preferences.

- **Authentication:** Handles login, registration, and account management.

- **Customer-Specific Features:** Support for features like wish lists,


saved carts, and personalized recommendations.

### 7. Tracking Manager

**Tracking E-commerce Transactions:**

- Supports tracking actions such as product impressions, product views,


category views, cart actions, checkout steps, and order completions.
- **Trackers:** Integrates with services like Google Tag Manager, Google
Analytics (Classic, Universal, Enhanced E-Commerce).

- **Configuration:** Set up in
`pimcore_ecommerce_framework.tracking_manager`, enabling specific trackers
for different tenants.

### 8. Checkout Manager

**Checkout Process Management:**

- **Checkout Steps:** Modular steps like delivery address, payment options,


and order confirmation, customizable per project.

- **Commit Order Processor:** Finalizes orders by sending them to ERP


systems, sending confirmation emails, etc.

- **Checkout Tenants:** Allows different checkout configurations for


different scenarios or user types.

### 9. Authentication Login/Logout Listeners

**Authentication Management:**

- **Login/Logout Listeners:** Event listeners that handle actions on user


login and logout.

- **Security:** Ensures secure user authentication and session management.

- **Customization:** Custom listeners can be implemented to extend default


behavior, such as logging activities, updating user data, or triggering
other processes.

These detailed descriptions provide a comprehensive understanding of each


aspect of the Pimcore E-Commerce Framework, helping you effectively present
and utilize its capabilities in your projects.

User

Multi-Language Multi Shop Product Index?

ChatGPT

### Multi-Language Multi-Shop Product Index in Pimcore E-Commerce Framework


Pimcore's E-Commerce Framework is designed to support multi-language and
multi-shop scenarios seamlessly. This capability allows businesses to
manage multiple online stores, each targeting different markets or regions,
and to provide localized content for each market. Here’s an in-depth look
at how this can be achieved:

### 1. Overview

The multi-language, multi-shop functionality in Pimcore leverages its


robust data modeling and indexing capabilities. It ensures that each shop
can have a distinct set of products, languages, and configurations, yet all
managed from a unified backend.

### 2. Product Index Configuration

#### Multi-Language Support

- **Locale-Based Attributes:** Each product attribute can be configured to


support multiple locales. This allows different translations of product
names, descriptions, and other relevant data.

- **Localization:** Content for each product can be localized to meet the


cultural and linguistic needs of different regions.

```yaml

pimcore_ecommerce_framework:

index_service:

tenants:

MyEsTenant:

attributes:

name:

locale: '%%locale%%'

type: keyword

```
#### Multi-Shop Support

- **Assortment Tenants:** The framework supports multiple assortment


tenants, which are heavy-weight tenants representing different shop
instances. Each tenant can have completely independent product sets, index
attributes, and even different product index implementations.

```yaml

pimcore_ecommerce_framework:

index_service:

tenants:

shop1:

config_id: Pimcore\Bundle\EcommerceFrameworkBundle\
IndexService\Config\DefaultMysql

config_options:

client_config:

indexName: 'shop1_index'

shop2:

config_id: Pimcore\Bundle\EcommerceFrameworkBundle\
IndexService\Config\ElasticSearch

config_options:

client_config:

indexName: 'shop2_index'

```

### 3. Assortment Management

#### Assortment Tenants

- **Heavy-Weight Tenants:** These tenants allow for completely independent


shop instances within one system. Each shop can have a unique set of
products, attributes, and configurations.
- **Subtenants:** Light-weight tenants within a shop instance allow for
different product assortments within the same shop, using the same product
index but with subsets of products.

### 4. Data Architecture and Indexing

#### Simple MySQL Architecture

- **Direct Indexing:** Pimcore object data is directly transferred to the


Product Index, suitable for simple implementations with fewer product
updates.

#### Optimized Architecture

- **Store Table:** Uses a store table between Pimcore objects and the
Product Index to reduce load on the index and support asynchronous updates.

- **Elasticsearch Integration:** Provides fast and scalable search


capabilities with support for advanced indexing features.

### 5. Implementation Steps

#### Configuration of Assortment Tenants

- **Tenant Config Class:** Implement a tenant config class that defines


which products are available for the tenant and connects to the product
index implementation.

- **Service Declaration:** Declare the tenant config class as a service.

```yaml

services:

MyBundle\Service\MyTenantConfig:

calls:

- [setAttributeFactory, ['@Pimcore\Bundle\
EcommerceFrameworkBundle\IndexService\Config\AttributeFactory']]

```
#### Setting Current Assortment Tenant

- **Set in Controllers:** Set the current assortment tenant in application


controllers, especially after customer login, to ensure the correct product
list is used.

```php

$factory = \Pimcore\Bundle\EcommerceFrameworkBundle\Factory::getInstance();

$environment = $factory->getEnvironment();

$environment->setCurrentAssortmentTenant("shop1_tenant");

```

### 6. Example Code

#### Setting Up Multi-Shop Index

```yaml

pimcore_ecommerce_framework:

index_service:

tenants:

shop1:

worker_id: Pimcore\Bundle\EcommerceFrameworkBundle\
IndexService\Worker\ElasticSearch\DefaultElasticSearch8

config_id: Pimcore\Bundle\EcommerceFrameworkBundle\
IndexService\Config\ElasticSearch

config_options:

client_config:

indexName: 'shop1_index'

es_client_name: shop1_es_client

shop2:
worker_id: Pimcore\Bundle\EcommerceFrameworkBundle\
IndexService\Worker\ElasticSearch\DefaultElasticSearch8

config_id: Pimcore\Bundle\EcommerceFrameworkBundle\
IndexService\Config\ElasticSearch

config_options:

client_config:

indexName: 'shop2_index'

es_client_name: shop2_es_client

```

#### Localized Product Index

```yaml

pimcore_ecommerce_framework:

index_service:

tenants:

MyEsTenant:

attributes:

name:

locale: '%%locale%%'

type: text

options:

mapping:

type: text

store: true

index: not_analyzed

fields:

analyzed:

type: text
analyzer: english

analyzed_ngram:

type: text

analyzer: my_ngram_analyzer

```

### 7. Key Considerations

- **Performance:** Ensure that the indexing process is optimized for


performance, especially when dealing with large datasets and multiple
tenants.

- **Consistency:** Regularly update and synchronize the product index to


maintain data consistency across different shops and languages.

- **Customization:** Leverage Pimcore’s extensibility to customize the


product index and assortment management according to specific business
requirements.

By following these detailed steps and configurations, businesses can


effectively manage a multi-language, multi-shop e-commerce setup using the
Pimcore E-Commerce Framework. This enables them to provide localized
shopping experiences across different markets while maintaining centralized
control and management of their e-commerce operations.

User

prepare a complete report document on the Pimcore E-Commerce Framework

ChatGPT

## Report on Pimcore E-Commerce Framework

### Table of Contents

1. **Introduction**

2. **Overview of Pimcore E-Commerce Framework**

3. **Key Features**
4. **Data Architecture and Indexing**

5. **Assortment Management**

6. **Pricing and Tax Management**

7. **Checkout Process**

8. **Order Management**

9. **Cart Management**

10. **Tracking and Analytics**

11. **Payment Integration**

12. **Customization and Extensibility**

13. **Multi-Language Multi-Shop Product Index**

14. **Conclusion**

---

### 1. Introduction

The Pimcore E-Commerce Framework is a comprehensive solution designed to


support complex e-commerce operations. It integrates seamlessly with
Pimcore's powerful data management capabilities, providing a robust
platform for managing products, orders, pricing, checkout processes, and
more. This report provides an in-depth look at the various features and
functionalities of the Pimcore E-Commerce Framework.

---

### 2. Overview of Pimcore E-Commerce Framework

The Pimcore E-Commerce Framework offers a flexible and extensible solution


for building and managing e-commerce websites. It supports a wide range of
e-commerce functionalities including product management, cart and checkout
processes, order management, and integration with various payment
providers. The framework is designed to handle multi-language and multi-
shop setups, making it ideal for businesses operating in diverse markets.

---

### 3. Key Features

- **Product Management**: Advanced product indexing and management


capabilities.

- **Cart and Checkout**: Comprehensive cart management and customizable


checkout process.

- **Order Management**: Efficient order creation, storage, and management.

- **Pricing and Tax Management**: Flexible pricing systems and tax


management.

- **Tracking and Analytics**: Integration with tracking tools for detailed


analytics.

- **Payment Integration**: Support for multiple payment providers and


recurring payments.

- **Customization**: Highly extensible to fit specific business needs.

---

### 4. Data Architecture and Indexing

The Pimcore E-Commerce Framework supports two main data architectures for
product indexing: Simple MySQL Architecture and Optimized Architecture.

- **Simple MySQL Architecture**: Direct transfer of Pimcore object data to


the Product Index, suitable for simpler setups.

- **Optimized Architecture**: Utilizes a store table to manage data between


Pimcore objects and the Product Index, reducing load and supporting
asynchronous updates.
Indexing can be performed using the provided Pimcore console commands,
ensuring efficient data management and retrieval.

---

### 5. Assortment Management

The framework supports a two-level Assortment Tenant system:

- **Assortment Tenant**: Heavy-weight tenants for completely independent


shop instances.

- **Assortment Subtenant**: Light-weight tenants within a shop instance,


sharing the same Product Index but with different product subsets.

This structure allows for flexible product assortment management across


multiple shops and product categories.

---

### 6. Pricing and Tax Management

#### Pricing Systems

- **Price Systems**: Responsible for retrieving or calculating prices and


returning PriceInfo objects.

- **Configuration**: Price systems can be customized and mapped to specific


products.

#### Tax Management


- **Tax Classes**: Configured using OnlineShopTaxClass objects to manage
different tax rates and structures.

- **Tax Calculation**: Handled by the TaxCalculationService, ensuring


accurate tax computation based on configured tax classes.

#### Pricing Rules and Vouchers

- **Pricing Rules**: Configurable rules for discounts, promotions, and


other pricing adjustments.

- **Vouchers**: Support for voucher series and tokens, integrated with


pricing rules to offer discounts and promotions.

---

### 7. Checkout Process

The Checkout Manager handles the checkout process, including payment


integration and order commitment. Key components include:

- **Checkout Steps**: Configurable steps for capturing necessary checkout


data.

- **Commit Order Processor**: Manages the finalization of orders, including


ERP integration and order confirmation emails.

---

### 8. Order Management

The Order Manager provides tools for:


- **Order Creation**: Creating orders based on cart data.

- **Order Storage**: Storing orders as Pimcore objects.

- **Order Lists**: Filtering and listing orders using predefined filters.

- **Order Agent**: API for manipulating orders and managing order states.

---

### 9. Cart Management

The Cart Manager handles all aspects of cart functionality:

- **Creating Carts**: Initialize and manage multiple carts per user.

- **Adding/Removing Products**: Manage products within carts.

- **Price Calculation**: Calculate subtotal and total prices, including


price modifications.

- **Checkout Tenants**: Configure different cart and checkout settings


based on active tenants.

---

### 10. Tracking and Analytics

The Tracking Manager integrates with various tracking services to provide


detailed e-commerce analytics:

- **Supported Trackers**: Includes Google Tag Manager, Google Analytics


(Classic, Universal, Enhanced E-Commerce).

- **Tracking Actions**: Product impressions, views, cart actions, checkout


steps, and order completion.
Customization options allow for the addition of project-specific tracking
data.

---

### 11. Payment Integration

The Payment Manager facilitates integration with various payment providers:

- **Supported Providers**: Includes Datatrans, PayPal, Klarna, OGone,


MPay24, Unzer, Hobex.

- **Payment Workflow**: From payment initialization to handling payment


responses and clearing payments.

- **Recurring Payments**: Support for recurring payment setups and


management.

---

### 12. Customization and Extensibility

The Pimcore E-Commerce Framework is highly extensible:

- **Custom Services**: Define custom services for specific functionalities.

- **Event Listeners**: Utilize events and event listeners to customize


behavior.

- **Custom Price and Availability Systems**: Implement custom logic for


pricing and product availability.

---
### 13. Multi-Language Multi-Shop Product Index

The framework supports multi-language and multi-shop setups:

- **Locale-Based Attributes**: Manage product attributes for different


locales.

- **Assortment Tenants**: Configure independent shop instances with unique


product sets and index configurations.

- **Configuration**: Define index configurations for different tenants and


locales to ensure localized content and seamless shop management.

### 14. Conclusion

The Pimcore E-Commerce Framework provides a robust and flexible solution


for managing complex e-commerce operations. Its extensive features, coupled
with the ability to customize and extend functionalities, make it an ideal
choice for businesses looking to deliver a seamless and personalized online
shopping experience across multiple markets and languages.

---

This report provides a comprehensive overview of the Pimcore E-Commerce


Framework, highlighting its key features, architecture, and capabilities.
The framework’s flexibility and extensibility ensure that it can meet the
diverse needs of modern e-commerce businesses.

User

Prepare a report for the understanding of a Business Analyst to conduct


Business Consultation on the Pimcore E-Commerce Framework

ChatGPT

# Business Consultation Report on Pimcore E-Commerce Framework

## Table of Contents
1. **Introduction**

2. **Understanding the Pimcore E-Commerce Framework**

3. **Key Features and Benefits**

4. **Technical Architecture and Data Management**

5. **Assortment Management**

6. **Pricing and Tax Management**

7. **Checkout Process**

8. **Order Management**

9. **Cart Management**

10. **Tracking and Analytics**

11. **Payment Integration**

12. **Customization and Extensibility**

13. **Multi-Language and Multi-Shop Support**

14. **Use Cases and Business Applications**

15. **Conclusion**

---

### 1. Introduction

This report aims to provide a comprehensive understanding of the Pimcore E-


Commerce Framework for a Business Analyst to conduct effective business
consultations. The Pimcore E-Commerce Framework offers a robust and
flexible platform for managing various e-commerce operations, supporting
complex business requirements and customization needs.

---
### 2. Understanding the Pimcore E-Commerce Framework

The Pimcore E-Commerce Framework integrates seamlessly with Pimcore's data


management capabilities, offering a full suite of tools for e-commerce
businesses. It supports product management, cart and checkout processes,
order handling, pricing strategies, and integration with multiple payment
providers.

---

### 3. Key Features and Benefits

- **Product Management**: Efficient product indexing and management with


advanced search capabilities.

- **Flexible Pricing**: Customizable pricing systems and rules for dynamic


pricing strategies.

- **Comprehensive Checkout**: Configurable multi-step checkout process with


payment integration.

- **Order Handling**: Efficient order management and tracking.

- **Analytics and Tracking**: Integration with various tracking tools for


detailed e-commerce analytics.

- **Multi-Language Support**: Manage multiple languages and locales


seamlessly.

- **Extensibility**: Highly customizable to fit specific business needs.

---

### 4. Technical Architecture and Data Management

The Pimcore E-Commerce Framework supports two primary data architectures


for product indexing:
- **Simple MySQL Architecture**: Direct transfer of Pimcore object data to
the Product Index, suitable for simpler setups.

- **Optimized Architecture**: Utilizes a store table to manage data between


Pimcore objects and the Product Index, reducing load and supporting
asynchronous updates.

Indexing can be managed using Pimcore console commands to ensure efficient


data handling.

---

### 5. Assortment Management

Assortment management in the Pimcore E-Commerce Framework is achieved


through a two-level Assortment Tenant system:

- **Assortment Tenant**: Heavy-weight tenants for independent shop


instances with unique products and index attributes.

- **Assortment Subtenant**: Light-weight tenants within a shop instance,


sharing the same Product Index but with different product subsets.

This structure supports flexible product assortment management across


multiple shops and product categories.

---

### 6. Pricing and Tax Management

#### Pricing Systems

The framework supports advanced pricing systems to retrieve or calculate


prices and return detailed price information:
- **Price Systems**: Customizable and mappable to specific products for
complex pricing structures.

- **Pricing Rules**: Configurable rules for discounts, promotions, and


other pricing adjustments.

#### Tax Management

The Tax Management component includes:

- **Tax Classes**: Configured using OnlineShopTaxClass objects to manage


different tax rates and structures.

- **Tax Calculation**: Handled by the TaxCalculationService for accurate


tax computation.

---

### 7. Checkout Process

The Checkout Manager handles the entire checkout process, integrating


payment and finalizing orders. Key components include:

- **Checkout Steps**: Configurable steps for capturing necessary checkout


data.

- **Commit Order Processor**: Manages order finalization, including ERP


integration and order confirmation emails.

---

### 8. Order Management


The Order Manager provides tools for:

- **Order Creation**: Creating orders based on cart data.

- **Order Storage**: Storing orders as Pimcore objects.

- **Order Lists**: Filtering and listing orders using predefined filters.

- **Order Agent**: API for manipulating orders and managing order states.

---

### 9. Cart Management

The Cart Manager handles all aspects of cart functionality:

- **Creating Carts**: Initialize and manage multiple carts per user.

- **Adding/Removing Products**: Manage products within carts.

- **Price Calculation**: Calculate subtotal and total prices, including


price modifications.

- **Checkout Tenants**: Configure different cart and checkout settings


based on active tenants.

---

### 10. Tracking and Analytics

The Tracking Manager integrates with various tracking services to provide


detailed e-commerce analytics:

- **Supported Trackers**: Includes Google Tag Manager, Google Analytics


(Classic, Universal, Enhanced E-Commerce).
- **Tracking Actions**: Product impressions, views, cart actions, checkout
steps, and order completion.

Customization options allow for the addition of project-specific tracking


data.

---

### 11. Payment Integration

The Payment Manager facilitates integration with various payment providers:

- **Supported Providers**: Includes Datatrans, PayPal, Klarna, OGone,


MPay24, Unzer, Hobex.

- **Payment Workflow**: From payment initialization to handling payment


responses and clearing payments.

- **Recurring Payments**: Support for recurring payment setups and


management.

---

### 12. Customization and Extensibility

The Pimcore E-Commerce Framework is highly extensible:

- **Custom Services**: Define custom services for specific functionalities.

- **Event Listeners**: Utilize events and event listeners to customize


behavior.

- **Custom Price and Availability Systems**: Implement custom logic for


pricing and product availability.
---

### 13. Multi-Language and Multi-Shop Support

The framework supports multi-language and multi-shop setups:

- **Locale-Based Attributes**: Manage product attributes for different


locales.

- **Assortment Tenants**: Configure independent shop instances with unique


product sets and index configurations.

- **Configuration**: Define index configurations for different tenants and


locales to ensure localized content and seamless shop management.

---

### 14. Use Cases and Business Applications

The Pimcore E-Commerce Framework can be applied to various business


scenarios, including:

- **B2C E-Commerce**: Comprehensive features for managing a consumer-facing


online store.

- **B2B E-Commerce**: Advanced pricing, tax, and product management


capabilities for business-to-business operations.

- **Multi-Vendor Marketplaces**: Support for multiple vendors and product


assortments within a single platform.

- **International E-Commerce**: Multi-language and multi-currency support


for global e-commerce operations.

---
### 15. Conclusion

The Pimcore E-Commerce Framework offers a robust and flexible solution for
managing complex e-commerce operations. Its extensive features, coupled
with the ability to customize and extend functionalities, make it an ideal
choice for businesses looking to deliver a seamless and personalized online
shopping experience across multiple markets and languages. This report
provides a comprehensive overview of the framework, highlighting its key
features, architecture, and capabilities to aid business analysts in
conducting effective consultations.

User

Prepare a one-source of document for the understanding of a Business


Analyst to conduct Business Consultation on the Pimcore E-Commerce
Framework

ChatGPT

# Business Consultation Document on the Pimcore E-Commerce Framework

## Table of Contents

1. **Introduction**

2. **Overview of Pimcore E-Commerce Framework**

3. **Key Features and Benefits**

4. **Technical Architecture and Data Management**

5. **Assortment Management**

6. **Pricing and Tax Management**

7. **Checkout Process**

8. **Order Management**

9. **Cart Management**

10. **Tracking and Analytics**

11. **Payment Integration**

12. **Customization and Extensibility**

13. **Multi-Language and Multi-Shop Support**


14. **Use Cases and Business Applications**

15. **Conclusion**

---

### 1. Introduction

This document aims to provide a comprehensive understanding of the Pimcore


E-Commerce Framework for Business Analysts. It will facilitate effective
business consultations by detailing the framework's features, architecture,
and capabilities. Pimcore E-Commerce Framework offers a robust and flexible
platform that supports complex business requirements and customization
needs.

---

### 2. Overview of Pimcore E-Commerce Framework

The Pimcore E-Commerce Framework integrates seamlessly with Pimcore's data


management capabilities, providing a comprehensive suite of tools for e-
commerce businesses. It includes product management, cart and checkout
processes, order handling, pricing strategies, and integration with
multiple payment providers.

---

### 3. Key Features and Benefits

- **Product Management**: Efficient product indexing and management with


advanced search capabilities.

- **Flexible Pricing**: Customizable pricing systems and rules for dynamic


pricing strategies.
- **Comprehensive Checkout**: Configurable multi-step checkout process with
payment integration.

- **Order Handling**: Efficient order management and tracking.

- **Analytics and Tracking**: Integration with various tracking tools for


detailed e-commerce analytics.

- **Multi-Language Support**: Manage multiple languages and locales


seamlessly.

- **Extensibility**: Highly customizable to fit specific business needs.

---

### 4. Technical Architecture and Data Management

The Pimcore E-Commerce Framework supports two primary data architectures


for product indexing:

- **Simple MySQL Architecture**: Direct transfer of Pimcore object data to


the Product Index, suitable for simpler setups.

- **Optimized Architecture**: Utilizes a store table to manage data between


Pimcore objects and the Product Index, reducing load and supporting
asynchronous updates.

Indexing can be managed using Pimcore console commands to ensure efficient


data handling.

---

### 5. Assortment Management

Assortment management in the Pimcore E-Commerce Framework is achieved


through a two-level Assortment Tenant system:
- **Assortment Tenant**: Heavy-weight tenants for independent shop
instances with unique products and index attributes.

- **Assortment Subtenant**: Light-weight tenants within a shop instance,


sharing the same Product Index but with different product subsets.

This structure supports flexible product assortment management across


multiple shops and product categories.

---

### 6. Pricing and Tax Management

#### Pricing Systems

The framework supports advanced pricing systems to retrieve or calculate


prices and return detailed price information:

- **Price Systems**: Customizable and mappable to specific products for


complex pricing structures.

- **Pricing Rules**: Configurable rules for discounts, promotions, and


other pricing adjustments.

#### Tax Management

The Tax Management component includes:

- **Tax Classes**: Configured using OnlineShopTaxClass objects to manage


different tax rates and structures.

- **Tax Calculation**: Handled by the TaxCalculationService for accurate


tax computation.
---

### 7. Checkout Process

The Checkout Manager handles the entire checkout process, integrating


payment and finalizing orders. Key components include:

- **Checkout Steps**: Configurable steps for capturing necessary checkout


data.

- **Commit Order Processor**: Manages order finalization, including ERP


integration and order confirmation emails.

---

### 8. Order Management

The Order Manager provides tools for:

- **Order Creation**: Creating orders based on cart data.

- **Order Storage**: Storing orders as Pimcore objects.

- **Order Lists**: Filtering and listing orders using predefined filters.

- **Order Agent**: API for manipulating orders and managing order states.

---

### 9. Cart Management

The Cart Manager handles all aspects of cart functionality:


- **Creating Carts**: Initialize and manage multiple carts per user.

- **Adding/Removing Products**: Manage products within carts.

- **Price Calculation**: Calculate subtotal and total prices, including


price modifications.

- **Checkout Tenants**: Configure different cart and checkout settings


based on active tenants.

---

### 10. Tracking and Analytics

The Tracking Manager integrates with various tracking services to provide


detailed e-commerce analytics:

- **Supported Trackers**: Includes Google Tag Manager, Google Analytics


(Classic, Universal, Enhanced E-Commerce).

- **Tracking Actions**: Product impressions, views, cart actions, checkout


steps, and order completion.

Customization options allow for the addition of project-specific tracking


data.

---

### 11. Payment Integration

The Payment Manager facilitates integration with various payment providers:

- **Supported Providers**: Includes Datatrans, PayPal, Klarna, OGone,


MPay24, Unzer, Hobex.
- **Payment Workflow**: From payment initialization to handling payment
responses and clearing payments.

- **Recurring Payments**: Support for recurring payment setups and


management.

---

### 12. Customization and Extensibility

The Pimcore E-Commerce Framework is highly extensible:

- **Custom Services**: Define custom services for specific functionalities.

- **Event Listeners**: Utilize events and event listeners to customize


behavior.

- **Custom Price and Availability Systems**: Implement custom logic for


pricing and product availability.

---

### 13. Multi-Language and Multi-Shop Support

The framework supports multi-language and multi-shop setups:

- **Locale-Based Attributes**: Manage product attributes for different


locales.

- **Assortment Tenants**: Configure independent shop instances with unique


product sets and index configurations.

- **Configuration**: Define index configurations for different tenants and


locales to ensure localized content and seamless shop management.

---
### 14. Use Cases and Business Applications

The Pimcore E-Commerce Framework can be applied to various business


scenarios, including:

- **B2C E-Commerce**: Comprehensive features for managing a consumer-facing


online store.

- **B2B E-Commerce**: Advanced pricing, tax, and product management


capabilities for business-to-business operations.

- **Multi-Vendor Marketplaces**: Support for multiple vendors and product


assortments within a single platform.

- **International E-Commerce**: Multi-language and multi-currency support


for global e-commerce operations.

---

### 15. Conclusion

The Pimcore E-Commerce Framework offers a robust and flexible solution for
managing complex e-commerce operations. Its extensive features, coupled
with the ability to customize and extend functionalities, make it an ideal
choice for businesses looking to deliver a seamless and personalized online
shopping experience across multiple markets and languages. This report
provides a comprehensive overview of the framework, highlighting its key
features, architecture, and capabilities to aid business analysts in
conducting effective consultations.

You might also like