<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>Spryker Documentation</title>
        <description>Spryker documentation center.</description>
        <link>https://docs.spryker.com/</link>
        <atom:link href="https://docs.spryker.com/feed.xml" rel="self" type="application/rss+xml"/>
        <lastBuildDate>Wed, 22 Apr 2026 07:08:04 +0000</lastBuildDate>
        <generator>Jekyll v4.2.2</generator>
        
        
        <item>
            <title>Enable and disable maintenance mode</title>
            <description>&lt;p&gt;Maintenance mode is used many cases, like deploying a new application version or fixing an unexpected error. To automate the process, we created dedicated pipelines for enabling and disabling maintenance mode. The following sections describe how to run maintenance mode pipelines. After you update the maintenance page, rebuild the images by running a normal or destructive deployment pipeline.&lt;/p&gt;
&lt;section class=&apos;info-block &apos;&gt;&lt;i class=&apos;info-block__icon icon-info&apos;&gt;&lt;/i&gt;&lt;div class=&apos;info-block__content&apos;&gt;
&lt;p&gt;This feature is part of a gradual rollout and will be available to everyone eventually. We will notify your team once your project is onboarded.&lt;/p&gt;
&lt;/div&gt;&lt;/section&gt;
&lt;h2 id=&quot;prerequisites&quot;&gt;Prerequisites&lt;/h2&gt;
&lt;p&gt;When you enable maintenance mode, the landing pages of your applications, like the Back Office or Storefront, are replaced with maintenance pages in &lt;code&gt;public//maintenance/index.html&lt;/code&gt;. Adjust the pages to match the design of your application and fulfill business requirements.&lt;/p&gt;
&lt;h3 id=&quot;per-store-and-per-region-maintenance-pages&quot;&gt;Per-store and per-region maintenance pages&lt;/h3&gt;
&lt;section class=&apos;info-block &apos;&gt;&lt;i class=&apos;info-block__icon icon-info&apos;&gt;&lt;/i&gt;&lt;div class=&apos;info-block__content&apos;&gt;
&lt;p&gt;Per-store and per-region maintenance pages require Docker SDK version 1.75.0 or higher.&lt;/p&gt;
&lt;/div&gt;&lt;/section&gt;
&lt;p&gt;By default, all endpoints of an application share the same maintenance page located at &lt;code&gt;public/{application}/maintenance/index.html&lt;/code&gt;—for example, &lt;code&gt;public/Yves/maintenance/index.html&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;You can customize the maintenance page per store or per region by placing an &lt;code&gt;index.html&lt;/code&gt; file in a subdirectory named after the store or region code:&lt;/p&gt;
&lt;div class=&quot;language-text highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;public/Yves/maintenance/
├── index.html          # Default maintenance page (fallback)
├── EU/
│   └── index.html      # Maintenance page for EU region
├── US/
│   └── index.html      # Maintenance page for US region
├── DE/
│   └── index.html      # Maintenance page for DE store (legacy store mode)
└── AT/
    └── index.html      # Maintenance page for AT store (legacy store mode)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The same structure applies to all applications, such as &lt;code&gt;Backoffice&lt;/code&gt;, &lt;code&gt;MerchantPortal&lt;/code&gt;, and &lt;code&gt;Zed&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Nginx resolves the maintenance page using the following fallback order.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Dynamic store mode&lt;/strong&gt; (region-based endpoints):&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;maintenance/{region}/index.html&lt;/code&gt;—region-specific page&lt;/li&gt;
&lt;li&gt;&lt;code&gt;maintenance/index.html&lt;/code&gt;—default page&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Legacy store mode&lt;/strong&gt; (store-based endpoints):&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;maintenance/{store}/index.html&lt;/code&gt;—store-specific page&lt;/li&gt;
&lt;li&gt;&lt;code&gt;maintenance/{region}/index.html&lt;/code&gt;—region-specific page&lt;/li&gt;
&lt;li&gt;&lt;code&gt;maintenance/index.html&lt;/code&gt;—default page&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;If no store-specific or region-specific page exists, the default &lt;code&gt;maintenance/index.html&lt;/code&gt; is served. The default maintenance page is required and must always be present.&lt;/p&gt;
&lt;h2 id=&quot;enable-maintenance-mode&quot;&gt;Enable maintenance mode&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;In the AWS Management Console, go to &lt;strong&gt;Services&lt;/strong&gt; &amp;gt; &lt;strong&gt;CodePipeline&lt;/strong&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;On the &lt;strong&gt;Pipelines&lt;/strong&gt; pane, click &lt;strong&gt;Maintenance_Enable_{ENVIRONMENT_NAME}&lt;/strong&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;On the pipeline’s page, click &lt;strong&gt;Release change&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;The deployment time depends on the application’s complexity. Once the deployment is finished, Storefront and Back Office visitors should see the maintenance page. To get access to the frontend applications in maintenance mode, you can allowlist the needed IP addresses. For instructions, see &lt;a href=&quot;/docs/ca/dev/manage-maintenance-mode/configure-access-to-applications-in-maintenance-mode.html&quot;&gt;Configure access to applications in maintenance mode&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&quot;https://spryker.s3.eu-central-1.amazonaws.com/docs/cloud/spryker-cloud-commerce-os/enable-and-disable-maintenance-mode.md/maintenance-enable-pipeline.png&quot; alt=&quot;Maintenance mode enable pipeline&quot; /&gt;&lt;/p&gt;
&lt;h2 id=&quot;disable-maintenance-mode&quot;&gt;Disable maintenance mode&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;In the AWS Management Console, go to &lt;strong&gt;Services&lt;/strong&gt; &amp;gt; &lt;strong&gt;CodePipeline&lt;/strong&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;On the &lt;strong&gt;Pipelines&lt;/strong&gt; pane, click &lt;strong&gt;Maintenance_Disable_{ENVIRONMENT_NAME}&lt;/strong&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;On the pipeline’s page, click &lt;strong&gt;Release change&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;The deployment time depends on the application’s complexity. Once the deployment is finished, Storefront and Back Office visitors will be able to access the application.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&quot;https://spryker.s3.eu-central-1.amazonaws.com/docs/cloud/spryker-cloud-commerce-os/enable-and-disable-maintenance-mode.md/maintenance-disable-pipeline.png&quot; alt=&quot;Maintenance mode disable pipeline&quot; /&gt;&lt;/p&gt;
</description>
            <pubDate>Wed, 22 Apr 2026 07:07:32 +0000</pubDate>
            <link>https://docs.spryker.com/docs/ca/dev/manage-maintenance-mode/enable-and-disable-maintenance-mode.html</link>
            <guid isPermaLink="true">https://docs.spryker.com/docs/ca/dev/manage-maintenance-mode/enable-and-disable-maintenance-mode.html</guid>
            
            
        </item>
        
        <item>
            <title>Integrate Vertex</title>
            <description>This document describes how to integrate [Vertex](/docs/pbc/all/tax-management/latest/base-shop/third-party-integrations/vertex/vertex.html) into a Spryker shop.

## Prerequisites

Before integrating Vertex, ensure the following prerequisites are met:

- Make sure that your deployment pipeline executes database migrations.

## 1. Install the module

Install the Vertex module using Composer:

```bash
composer require spryker-eco/vertex
```

## 2. Configure the module

Add the following configuration to `config/Shared/config_default.php`:

```php
use SprykerEco\Shared\Vertex\VertexConstants;

$config[VertexConstants::IS_ACTIVE] = getenv(&apos;VERTEX_IS_ACTIVE&apos;);
$config[VertexConstants::CLIENT_ID] = getenv(&apos;VERTEX_CLIENT_ID&apos;);
$config[VertexConstants::CLIENT_SECRET] = getenv(&apos;VERTEX_CLIENT_SECRET&apos;);
$config[VertexConstants::SECURITY_URI] = getenv(&apos;VERTEX_SECURITY_URI&apos;);
$config[VertexConstants::TRANSACTION_CALLS_URI] = getenv(&apos;VERTEX_TRANSACTION_CALLS_URI&apos;);
// Optional: Tax ID Validator (requires Vertex Validator, previously known as Taxamo, see https://developer.vertexinc.com/vertex-e-commerce/docs/stand-alone-deployments)
$config[VertexConstants::TAXAMO_API_URL] = getenv(&apos;TAXAMO_API_URL&apos;);
$config[VertexConstants::TAXAMO_TOKEN] = getenv(&apos;TAXAMO_TOKEN&apos;);

// Optional: Vendor Code
$config[VertexConstants::VENDOR_CODE] = &apos;&apos;;
```

### Required configuration constants

| Constant | Description | Where to get the value |
|----------|-------------|------------------------|
| `IS_ACTIVE` | Enables or disables Vertex tax calculation. | Set to `true` to enable. |
| `CLIENT_ID` | OAuth client ID for the Vertex API. | Obtain from your Vertex account. For details, see [Vertex documentation](https://tax-calc-api.vertexcloud.com/resources/index.html). |
| `CLIENT_SECRET` | OAuth client secret for the Vertex API. | Obtain from your Vertex account. For details, see [Vertex documentation](https://tax-calc-api.vertexcloud.com/resources/index.html). |
| `SECURITY_URI` | Vertex OAuth security endpoint. | Obtain from your Vertex platform. For details, see [Vertex documentation](https://tax-calc-api.vertexcloud.com/resources/index.html). |
| `TRANSACTION_CALLS_URI` | Vertex transaction calls endpoint. | Obtain from your Vertex platform. For details, see [Vertex documentation](https://tax-calc-api.vertexcloud.com/resources/index.html). |

### Optional configuration constants

| Constant | Description | Where to get the value |
|----------|-------------|------------------------|
| `TAXAMO_API_URL` | Vertex Validator API URL for tax ID validation. | Obtain from your Vertex Validator environment. For details, see [Standalone Vertex Validator](https://developer.vertexinc.com/vertex-e-commerce/docs/stand-alone-deployments). |
| `TAXAMO_TOKEN` | Vertex Validator API authentication token. | Obtain from your Vertex Validator account. For details, see [Accessing the APIs](https://developer.vertexinc.com/vertex-marketplaces/docs/getting-started-1). |
| `VENDOR_CODE` | Vendor code for Vertex tax calculations. | Set in your Vertex account. |
| `DEFAULT_TAXPAYER_COMPANY_CODE` | Default taxpayer company code. | The company code you set in your Vertex account. |

## 3. Override feature flags

The `isTaxIdValidatorEnabled`, `isTaxAssistEnabled`, and `isInvoicingEnabled` methods default to `false` and are not driven by constants. To enable them, override `src/Pyz/Zed/Vertex/VertexConfig.php`:

```php
namespace Pyz\Zed\Vertex;

use SprykerEco\Zed\Vertex\VertexConfig as SprykerEcoVertexConfig;

class VertexConfig extends SprykerEcoVertexConfig
{
    public function isTaxIdValidatorEnabled(): bool
    {
        return true;
    }

    public function isTaxAssistEnabled(): bool
    {
        return true;
    }

    public function isInvoicingEnabled(): bool
    {
        return true;
    }
}
```

### Config methods

The following methods must be overridden in `src/Pyz/Zed/Vertex/VertexConfig.php` to enable the respective features:

| Method | Default | Description                                                                                                                                                                       |
|--------|---------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `isTaxIdValidatorEnabled()` | `false` | Enables tax ID validation via [Vertex Validator](https://developer.vertexinc.com/vertex-e-commerce/docs/stand-alone-deployments). Requires `TAXAMO_API_URL` and `TAXAMO_TOKEN` to be set.                                                                                     |
| `isTaxAssistEnabled()` | `false` | Enables the tax assist feature. Return Assisted Parameters in the response that will provide more details about the calculation. The logs can be checked in the Vertex Dashboard. |
| `isInvoicingEnabled()` | `false` | Enables invoicing functionality. Requires OMS plugins to be registered. See [Register OMS plugins](#register-oms-plugins).                                                        |
| `getSellerCountryCode()` | `&apos;&apos;` | Overrides the default seller country code (2-letter ISO code, for example, `US`). Defaults to the first country of the store.                                                     |
| `getCustomerCountryCode()` | `&apos;&apos;` | Overrides the default customer country code (applied only when no customer billing address is provided).  Defaults to the first country of the store.                             |

## 4. Set up the database schema

Install the database schema:

```bash
vendor/bin/console propel:install
```

## 5. Generate transfer objects

Generate transfer objects for the module:

```bash
vendor/bin/console transfer:generate
```

## 6. Import glossary data

The module provides translation data for tax validation messages.

**Option 1: Import using the module&apos;s configuration file**

```bash
vendor/bin/console data:import --config=vendor/spryker-eco/vertex/data/import/vertex.yml
```

**Option 2: Copy file content and import individually**

Copy content from `vendor/spryker-eco/vertex/data/import/*.csv` to the corresponding files in `data/import/common/common/`. Then run:

```bash
vendor/bin/console data:import glossary
```

**Option 3: Add to the project&apos;s main import configuration**

Add the import actions to your project&apos;s main data import configuration file and include them in your regular import pipeline.

## 7. Register plugins

### Register the tax calculation plugin

Add the Vertex calculation plugin to `src/Pyz/Zed/Calculation/CalculationDependencyProvider.php`:

```php
use SprykerEco\Zed\Vertex\Communication\Plugin\Calculation\VertexCalculationPlugin;

protected function getQuoteCalculatorPluginStack(Container $container): array
{
    return [
        //...

        # Suggested plugins order is shown.

        new ItemDiscountAmountFullAggregatorPlugin(),

        # This plugin is replacing other tax calculation plugins in the stack and will use them as a fallback.
        # No other tax calculation plugins except for VertexCalculationPlugin should be present in the stack.
        new VertexCalculationPlugin(),

        new PriceToPayAggregatorPlugin(),

        //...
    ];
}

protected function getOrderCalculatorPluginStack(Container $container): array
{
    return [
        //...

        # Suggested plugins order is shown.

        new ItemDiscountAmountFullAggregatorPlugin(),

        # This plugin is replacing other tax calculation plugins in the stack and will use them as a fallback.
        # No other tax calculation plugins except for VertexCalculationPlugin should be present in the stack.
        new VertexCalculationPlugin(),

        new PriceToPayAggregatorPlugin(),

        //...
    ];
}
```

#### Register Fallback Calculation Plugins

Add order and quote Fallback Calculation Plugins to `src/Pyz/Zed/Vertex/VertexDependencyProvider.php`:

```php
use Spryker\Zed\Calculation\Communication\Plugin\Calculator\ItemTaxAmountFullAggregatorPlugin;
use Spryker\Zed\Calculation\Communication\Plugin\Calculator\PriceToPayAggregatorPlugin;
use Spryker\Zed\Tax\Communication\Plugin\Calculator\TaxAmountAfterCancellationCalculatorPlugin;
use Spryker\Zed\Tax\Communication\Plugin\Calculator\TaxAmountCalculatorPlugin;
use Spryker\Zed\Tax\Communication\Plugin\Calculator\TaxRateAverageAggregatorPlugin;

/**
 * {@inheritDoc}
 *
 * @return array&lt;\Spryker\Zed\CalculationExtension\Dependency\Plugin\CalculationPluginInterface&gt;
 */
protected function getFallbackQuoteCalculationPlugins(): array
{
    return [
        # These plugins will be called if Vertex configuration is missing or Vertex is disabled.
        # Please note that this list includes PriceToPayAggregatorPlugin - this plugin isn&apos;t a part of tax calculation logic but it&apos;s required by TaxRateAverageAggregatorPlugin.
        new TaxAmountCalculatorPlugin(),
        new ItemTaxAmountFullAggregatorPlugin(),
        new PriceToPayAggregatorPlugin(),
        new TaxRateAverageAggregatorPlugin(),
    ];
}

/**
 * {@inheritDoc}
 *
 * @return array&lt;\Spryker\Zed\CalculationExtension\Dependency\Plugin\CalculationPluginInterface&gt;
 */
protected function getFallbackOrderCalculationPlugins(): array
{
    return [
        # These plugins will be called if Vertex configuration is missing or Vertex is disabled.
        # Please note that this list includes PriceToPayAggregatorPlugin - this plugin isn&apos;t a part of tax calculation logic but it&apos;s required by TaxAmountAfterCancellationCalculatorPlugin.
        new TaxAmountCalculatorPlugin(),
        new ItemTaxAmountFullAggregatorPlugin(),
        new PriceToPayAggregatorPlugin(),
        new TaxAmountAfterCancellationCalculatorPlugin(),
    ];
}
```

In general, `getFallbackQuoteCalculationPlugins()` and `getFallbackOrderCalculationPlugins()` methods should contain the tax calculation plugins, which are replaced by `VertexCalculationPlugin` in `\Pyz\Zed\Calculation\CalculationDependencyProvider`.
The code snippet above is an example of such configuration based on the Spryker default tax calculation plugins.
Tax calculation plugins moved:
- from `getQuoteCalculatorPluginStack` method: `TaxAmountCalculatorPlugin`, `ItemTaxAmountFullAggregatorPlugin`, `PriceToPayAggregatorPlugin`, `TaxRateAverageAggregatorPlugin`
- from `getOrderCalculatorPluginStack` method: `TaxAmountCalculatorPlugin`, `ItemTaxAmountFullAggregatorPlugin`, `PriceToPayAggregatorPlugin`, `TaxAmountAfterCancellationCalculatorPlugin`

{% info_block infoBox &quot;Fallback behavior&quot; %}

There are three different failure scenarios where `VertexCalculationPlugin` might need to use a fallback logic:

1. Vertex isn&apos;t connected: fallback plugins defined in `getFallbackQuoteCalculationPlugins()` and `getFallbackOrderCalculationPlugins()` will be used to calculate taxes.
2. Vertex is disabled: fallback plugins defined in `getFallbackQuoteCalculationPlugins()` and `getFallbackOrderCalculationPlugins()` will be used to calculate taxes.
3. Vertex is not responding or is responding with an error: tax value will be set to zero, and the customer will be able to proceed with the checkout.

{% endinfo_block %}

### Register CalculableObject and order expander plugins

Add order and CalculableObject expander plugins to `src/Pyz/Zed/Vertex/VertexDependencyProvider.php`. The proposed plugins are examples, you can select which ones to register based on your requirements or create custom ones if needed.

```php
use SprykerEco\Zed\Vertex\Communication\Plugin\Order\OrderCustomerWithVertexCodeExpanderPlugin;
use SprykerEco\Zed\Vertex\Communication\Plugin\Order\OrderExpensesWithVertexCodeExpanderPlugin;
use SprykerEco\Zed\Vertex\Communication\Plugin\Order\OrderItemProductOptionWithVertexCodeExpanderPlugin;
use SprykerEco\Zed\Vertex\Communication\Plugin\Order\OrderItemWithVertexSpecificFieldsExpanderPlugin;
use SprykerEco\Zed\Vertex\Communication\Plugin\Quote\CalculableObjectCustomerWithVertexCodeExpanderPlugin;
use SprykerEco\Zed\Vertex\Communication\Plugin\Quote\CalculableObjectExpensesWithVertexCodeExpanderPlugin;
use SprykerEco\Zed\Vertex\Communication\Plugin\Quote\CalculableObjectItemProductOptionWithVertexCodeExpanderPlugin;
use SprykerEco\Zed\Vertex\Communication\Plugin\Quote\CalculableObjectItemWithVertexSpecificFieldsExpanderPlugin;

protected function getCalculableObjectVertexExpanderPlugins(): array
{
    return [
        // ... other plugins
        new CalculableObjectCustomerWithVertexCodeExpanderPlugin(),
        new CalculableObjectExpensesWithVertexCodeExpanderPlugin(),
        new CalculableObjectItemProductOptionWithVertexCodeExpanderPlugin(),
        new CalculableObjectItemWithVertexSpecificFieldsExpanderPlugin(),
    ];
}

protected function getOrderVertexExpanderPlugins(): array
{
    return [
        // ... other plugins
        new OrderCustomerWithVertexCodeExpanderPlugin(),
        new OrderExpensesWithVertexCodeExpanderPlugin(),
        new OrderItemProductOptionWithVertexCodeExpanderPlugin(),
        new OrderItemWithVertexSpecificFieldsExpanderPlugin(),
    ];
}
```

## 8. Configure the Shop Application dependency provider

Add the following code to `src/Pyz/Yves/ShopApplication/ShopApplicationDependencyProvider.php`:

```php

namespace Pyz\Yves\ShopApplication;

use SprykerShop\Yves\ShopApplication\ShopApplicationDependencyProvider as SprykerShopApplicationDependencyProvider;
use SprykerShop\Yves\CartPage\Widget\CartSummaryHideTaxAmountWidget;

class ShopApplicationDependencyProvider extends SprykerShopApplicationDependencyProvider
{
    /**
     * @phpstan-return array&lt;class-string&lt;\Spryker\Yves\Kernel\Widget\AbstractWidget&gt;&gt;
     *
     * @return array&lt;string&gt;
     */
    protected function getGlobalWidgets(): array
    {
        return [
            //...

            # This widget is replacing Spryker default tax display in cart summary page with text stating that tax amount will be calculated during checkout process.
            CartSummaryHideTaxAmountWidget::class,
        ];
    }
}

```

If you have custom Yves templates or make your own Frontend, add `CartSummaryHideTaxAmountWidget` to your template. The core template is located at `SprykerShop/Yves/CartPage/Theme/default/components/molecules/cart-summary/cart-summary.twig`.

Here is an example with `CartSummaryHideTaxAmountWidget`:

```html
{% raw %}
&lt;li class=&quot;list__item spacing-y&quot;&gt;
    {{ &apos;cart.total.tax_total&apos; | trans }}
    {% widget &apos;CartSummaryHideTaxAmountWidget&apos; args [data.cart] only %}
    {% nowidget %}
        &lt;span class=&quot;float-right&quot;&gt;{{ data.cart.totals.taxTotal.amount | money(true, data.cart.currency.code) }}&lt;/span&gt;
    {% endwidget %}
&lt;/li&gt;
{% endraw %}
```

## 9. Optional: Sending tax invoices to Vertex and handling refunds

Configure payment `config/Zed/oms/{your_payment_oms}.xml`as in the following example:

```xml
&lt;?xml version=&quot;1.0&quot;?&gt;
&lt;statemachine
    xmlns=&quot;spryker:oms-01&quot;
    xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
    xsi:schemaLocation=&quot;spryker:oms-01 http://static.spryker.com/oms-01.xsd&quot;
&gt;

    &lt;process name=&quot;SomePaymentProcess&quot; main=&quot;true&quot;&gt;

        &lt;!-- other configurations --&gt;

        &lt;states&gt;

            &lt;!-- other states --&gt;

            &lt;state name=&quot;tax invoice submitted&quot; reserved=&quot;true&quot; display=&quot;oms.state.paid&quot;/&gt;

            &lt;!-- other states --&gt;

        &lt;/states&gt;

        &lt;transitions&gt;

            &lt;!-- other transitions --&gt;

            &lt;transition happy=&quot;true&quot;&gt;
                &lt;source&gt;paid&lt;/source&gt; &lt;!-- Suggested that paid transition should be the source, but it&apos;s up to you --&gt;
                &lt;target&gt;tax invoice submitted&lt;/target&gt;
                &lt;event&gt;submit tax invoice&lt;/event&gt;
            &lt;/transition&gt;

            &lt;!-- other transitions --&gt;

            &lt;transition happy=&quot;true&quot;&gt;
                &lt;source&gt;tax invoice submitted&lt;/source&gt;

                &lt;!-- Here are the contents of the target transition --&gt;

            &lt;/transition&gt;

            &lt;!-- other transitions --&gt;

        &lt;/transitions&gt;

        &lt;events&gt;

            &lt;!-- other events --&gt;

            &lt;event name=&quot;submit tax invoice&quot; onEnter=&quot;true&quot; command=&quot;Vertex/SubmitPaymentTaxInvoice&quot;/&gt;

            &lt;!-- other events --&gt;

        &lt;/events&gt;

    &lt;/process&gt;

&lt;/statemachine&gt;
```

### Register OMS plugins

{% info_block infoBox &quot;Optional&quot; %}

This step is required only if you want to use invoicing functionality. Make sure `isInvoicingEnabled()` is set to `true` in `VertexConfig.php`.

{% endinfo_block %}

Add OMS plugins to `src/Pyz/Zed/Oms/OmsDependencyProvider.php`:

```php
use SprykerEco\Zed\Vertex\Communication\Plugin\Oms\Command\VertexSubmitPaymentTaxInvoicePlugin;
use SprykerEco\Zed\Vertex\Communication\Plugin\Oms\VertexOrderRefundedEventListenerPlugin;

# This configuration is necessary for Invoice functionality
protected function extendCommandPlugins(Container $container): Container
{
    $container-&gt;extend(self::COMMAND_PLUGINS, function (CommandCollectionInterface $commandCollection) {
        // ... other command plugins
        $commandCollection-&gt;add(new VertexSubmitPaymentTaxInvoicePlugin(), &apos;Vertex/SubmitPaymentTaxInvoice&apos;);

        return $commandCollection;
    });

    return $container;
}

# This configuration is necessary for Refund functionality
protected function getOmsEventTriggeredListenerPlugins(Container $container): array
{
    return [
        // ... other plugins
        new VertexOrderRefundedEventListenerPlugin(),
    ];
}
```

This configuration of `getOmsEventTriggeredListenerPlugins` method is required to ensure that the correct tax amount will be used during the refund process.

{% info_block infoBox &quot;OMS configuration requirement&quot; %}

The refund functionality will only work if the OMS event is called `refund`.

{% endinfo_block %}

## Next steps

- [Configure Vertex-specific metadata](/docs/pbc/all/tax-management/latest/base-shop/third-party-integrations/vertex/install-vertex/configure-vertex-specific-metadata.html)
- [Migrate from the ACP Vertex app](/docs/pbc/all/tax-management/latest/base-shop/third-party-integrations/vertex/install-vertex/migrate-from-acp-to-vertex.html)</description>
            <pubDate>Tue, 21 Apr 2026 13:03:28 +0000</pubDate>
            <link>https://docs.spryker.com/docs/pbc/all/tax-management/latest/base-shop/third-party-integrations/vertex/install-vertex/integrate-vertex.html</link>
            <guid isPermaLink="true">https://docs.spryker.com/docs/pbc/all/tax-management/latest/base-shop/third-party-integrations/vertex/install-vertex/integrate-vertex.html</guid>
            
            
        </item>
        
        <item>
            <title>Enable Dynamic Multistore</title>
            <description>&lt;p&gt;This document describes how to enable &lt;a href=&quot;/docs/pbc/all/dynamic-multistore/latest/base-shop/dynamic-multistore-feature-overview.html&quot;&gt;Dynamic Multistore&lt;/a&gt; (DMS).&lt;/p&gt;
&lt;h2 id=&quot;prerequisites&quot;&gt;Prerequisites&lt;/h2&gt;
&lt;p&gt;If your project version is below 202307.0, &lt;a href=&quot;/docs/pbc/all/dynamic-multistore/latest/base-shop/install-and-upgrade/install-features/install-dynamic-multistore.html&quot;&gt;Install Dynamic Multistore&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;enable-dynamic-multistore&quot;&gt;Enable Dynamic Multistore&lt;/h3&gt;
&lt;section class=&apos;info-block info-block--warning&apos;&gt;&lt;i class=&apos;info-block__icon icon-warning&apos;&gt;&lt;/i&gt;&lt;div class=&apos;info-block__content&apos;&gt;&lt;div class=&quot;info-block__title&quot;&gt;Staging environment&lt;/div&gt;
To avoid unexpected downtime and data loss, perform and test *all* of the following steps in a staging environment first.
&lt;/div&gt;&lt;/section&gt;
&lt;ol&gt;
&lt;li&gt;Replace &lt;code&gt;StoreClient::getCurrentStore()&lt;/code&gt; and &lt;code&gt;StoreFacade::getCurrentStore()&lt;/code&gt; methods with &lt;code&gt;StoreStorageClient:getStoreNames()&lt;/code&gt;, &lt;code&gt;StoreStorageClient::findStoreByName()&lt;/code&gt;, or &lt;code&gt;StoreFacade::getStoreCollection()&lt;/code&gt; in the following:&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;Back Office&lt;/li&gt;
&lt;li&gt;Merchant Portal&lt;/li&gt;
&lt;li&gt;Console Commands&lt;/li&gt;
&lt;li&gt;Gateway&lt;/li&gt;
&lt;li&gt;BackendAPI&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;Update custom console commands to meet the following rules:&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Store(Facade|Client)::getCurrentStore()&lt;/code&gt; isn’t used in the code a console command executes.&lt;/li&gt;
&lt;li&gt;All store-aware commands implement &lt;code&gt;Spryker\Zed\Kernel\Communication\Console\StoreAwareConsole&lt;/code&gt; and execute actions for a specific store if a store parameter is provided; if not provided, actions are executed for all the stores in the region.&lt;/li&gt;
&lt;li&gt;Optional: We recommend using the &lt;code&gt;--store&lt;/code&gt; parameter instead of &lt;code&gt;APPLICATION_STORE&lt;/code&gt; env variable; both methods are supported.&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;
&lt;p&gt;After enabling DMS, the basic domain structure must change from store to region for all the applications. For example, &lt;code&gt;https://yves.de.mysprykershop.com&lt;/code&gt; will change to &lt;code&gt;https://yves.eu.mysprykershop.com&lt;/code&gt;. To prevent negative SEO effects, set up the needed redirects. If your target domain doesn’t change, for example it doesn’t contain a region name - yves.mysprykershop.com - you may skip this step.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;DMS changes the structure of RabbitMQ messages. When you’re ready for the migration, wait for all the remaining messages in the queue to be processed. When the queue is empty, enable the maintenance mode.
The downtime associated with the maintenance mode is limited to the deployment time, which usually takes up to an hour.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Update AWS deployment files to DMS mode using the example:&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Original environment variables section:&lt;/p&gt;
&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;na&quot;&gt;SPRYKER_HOOK_BEFORE_DEPLOY&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;vendor/bin/install&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;-r&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;pre-deploy.dynamic-store-off&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;-vvv&apos;&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;SPRYKER_HOOK_AFTER_DEPLOY&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;true&apos;&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;SPRYKER_HOOK_INSTALL&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;vendor/bin/install&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;-r&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;production.dynamic-store-off&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;--no-ansi&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;-vvv&apos;&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;SPRYKER_HOOK_DESTRUCTIVE_INSTALL&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;vendor/bin/install&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;-r&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;destructive.dynamic-store-off&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;--no-ansi&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;-vvv&apos;&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;SPRYKER_YVES_HOST_DE&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;de.&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;SPRYKER_YVES_HOST_AT&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;at.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Updated environment variables section:&lt;/p&gt;
&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;na&quot;&gt;SPRYKER_HOOK_BEFORE_DEPLOY&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;vendor/bin/install&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;-r&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;pre-deploy&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;-vvv&apos;&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;SPRYKER_HOOK_AFTER_DEPLOY&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;true&apos;&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;SPRYKER_HOOK_INSTALL&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;vendor/bin/install&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;-r&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;dynamic-store&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;--no-ansi&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;-vvv&apos;&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;SPRYKER_HOOK_DESTRUCTIVE_INSTALL&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;vendor/bin/install&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;-r&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;destructive&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;--no-ansi&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;-vvv&apos;&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;SPRYKER_DYNAMIC_STORE_MODE&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;true&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;SPRYKER_YVES_HOST_EU&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;yves.eu.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Original regions section:&lt;/p&gt;
&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;na&quot;&gt;regions&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;stores&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;DE&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;services&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;broker&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;na&quot;&gt;namespace&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;de_queue&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;key_value_store&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;na&quot;&gt;namespace&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;search&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;na&quot;&gt;namespace&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;de_search&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;session&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;na&quot;&gt;namespace&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;2&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;AT&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;services&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;broker&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;na&quot;&gt;namespace&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;at_queue&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;key_value_store&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;na&quot;&gt;namespace&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;3&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;search&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;na&quot;&gt;namespace&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;at_search&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;session&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;na&quot;&gt;namespace&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;4&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Updated regions section:&lt;/p&gt;
&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;na&quot;&gt;regions&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;broker&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;namespace&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;eu-docker&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;key_value_store&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;namespace&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;search&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;namespace&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;eu_search&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;ol start=&quot;6&quot;&gt;
&lt;li&gt;Run a normal deploy for your server pipeline.&lt;/li&gt;
&lt;/ol&gt;
&lt;section class=&apos;info-block info-block--warning&apos;&gt;&lt;i class=&apos;info-block__icon icon-warning&apos;&gt;&lt;/i&gt;&lt;div class=&apos;info-block__content&apos;&gt;&lt;div class=&quot;info-block__title&quot;&gt;Verification&lt;/div&gt;
- Make sure your store is available at `https://yves.eu.mysprykershop.com` or `https://backoffice.eu.mysprykershop.com`.
- Make sure the store switcher is displayed on the Storefront.
&lt;/div&gt;&lt;/section&gt;
&lt;p&gt;Your shop is now running in DMS mode.&lt;/p&gt;
&lt;h3 id=&quot;check-if-dynamic-multistore-is-enabled&quot;&gt;Check if Dynamic Multistore is enabled&lt;/h3&gt;
&lt;p&gt;DMS is enabled if at least one of the following applies:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Using environment: If the value of &lt;code&gt;SPRYKER_DYNAMIC_STORE_MODE&lt;/code&gt; environment variable is &lt;code&gt;true&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Using interface: In the Back Office &amp;gt; &lt;strong&gt;Administration&lt;/strong&gt; &amp;gt; &lt;strong&gt;Stores&lt;/strong&gt;, an &lt;strong&gt;Edit&lt;/strong&gt; button is displayed next to each store.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;disable-dynamic-multistore&quot;&gt;Disable Dynamic Multistore&lt;/h2&gt;
&lt;section class=&apos;info-block info-block--warning&apos;&gt;&lt;i class=&apos;info-block__icon icon-warning&apos;&gt;&lt;/i&gt;&lt;div class=&apos;info-block__content&apos;&gt;&lt;div class=&quot;info-block__title&quot;&gt;Staging environment&lt;/div&gt;
To avoid unexpected downtime and data loss, perform and test *all* of the following steps in a staging environment first.
&lt;/div&gt;&lt;/section&gt;
&lt;ol&gt;
&lt;li&gt;After disabling DMS, the basic domain structure will change from region to store for all the applications. To prevent negative SEO effects, set up the needed redirects.&lt;/li&gt;
&lt;li&gt;DMS changes the structure of RabbitMQ messages. When you’re ready for the migration, wait for all the remaining messages in the queue to be processed. When the queue is empty, enable the maintenance mode.
(Expected downtime is limited to the deployment time, normally it takes less than 1hr)&lt;/li&gt;
&lt;li&gt;Revert changes in deploy files to disable DMS:&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Original environment variables section:&lt;/p&gt;
&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;na&quot;&gt;SPRYKER_HOOK_BEFORE_DEPLOY&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;vendor/bin/install&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;-r&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;pre-deploy&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;-vvv&apos;&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;SPRYKER_HOOK_AFTER_DEPLOY&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;true&apos;&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;SPRYKER_HOOK_INSTALL&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;vendor/bin/install&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;-r&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;dynamic-store&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;--no-ansi&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;-vvv&apos;&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;SPRYKER_HOOK_DESTRUCTIVE_INSTALL&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;vendor/bin/install&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;-r&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;destructive&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;--no-ansi&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;-vvv&apos;&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;SPRYKER_DYNAMIC_STORE_MODE&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;true&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;SPRYKER_YVES_HOST_EU&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;yves.eu.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Updated environment variables section:&lt;/p&gt;
&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;na&quot;&gt;SPRYKER_HOOK_BEFORE_DEPLOY&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;vendor/bin/install&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;-r&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;pre-deploy.dynamic-store-off&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;-vvv&apos;&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;SPRYKER_HOOK_AFTER_DEPLOY&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;true&apos;&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;SPRYKER_HOOK_INSTALL&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;vendor/bin/install&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;-r&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;production.dynamic-store-off&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;--no-ansi&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;-vvv&apos;&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;SPRYKER_HOOK_DESTRUCTIVE_INSTALL&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;vendor/bin/install&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;-r&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;destructive.dynamic-store-off&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;--no-ansi&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;-vvv&apos;&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;SPRYKER_YVES_HOST_DE&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;de.&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;SPRYKER_YVES_HOST_AT&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;at.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Original regions section:&lt;/p&gt;
&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;na&quot;&gt;regions&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;broker&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;namespace&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;eu-docker&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;key_value_store&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;namespace&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;search&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;namespace&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;eu_search&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Updated regions section:&lt;/p&gt;
&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;na&quot;&gt;regions&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;stores&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;DE&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;services&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;broker&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;na&quot;&gt;namespace&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;de_queue&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;key_value_store&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;na&quot;&gt;namespace&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;search&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;na&quot;&gt;namespace&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;de_search&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;session&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;na&quot;&gt;namespace&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;2&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;AT&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;services&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;broker&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;na&quot;&gt;namespace&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;at_queue&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;key_value_store&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;na&quot;&gt;namespace&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;3&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;search&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;na&quot;&gt;namespace&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;at_search&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;session&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;na&quot;&gt;namespace&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;4&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;ol start=&quot;6&quot;&gt;
&lt;li&gt;Run a normal deploy for your server pipeline.&lt;/li&gt;
&lt;/ol&gt;
&lt;section class=&apos;info-block info-block--warning&apos;&gt;&lt;i class=&apos;info-block__icon icon-warning&apos;&gt;&lt;/i&gt;&lt;div class=&apos;info-block__content&apos;&gt;&lt;div class=&quot;info-block__title&quot;&gt;Verification&lt;/div&gt;
- Make sure your store is available at `https://yves.de.mysprykershop.com` or `https://backoffice.de.mysprykershop.com`.
- Make sure the store switcher is *not* displayed on the Storefront.
&lt;/div&gt;&lt;/section&gt;
</description>
            <pubDate>Mon, 20 Apr 2026 14:20:29 +0000</pubDate>
            <link>https://docs.spryker.com/docs/pbc/all/dynamic-multistore/latest/base-shop/enable-dynamic-multistore.html</link>
            <guid isPermaLink="true">https://docs.spryker.com/docs/pbc/all/dynamic-multistore/latest/base-shop/enable-dynamic-multistore.html</guid>
            
            
        </item>
        
        <item>
            <title>Install and configure Stripe prerequisites for Marketplace</title>
            <description>This document covers marketplace-specific additions to the base shop Stripe integration. Before following the steps below, complete [Integrate Stripe](/docs/pbc/all/payment-service-provider/latest/base-shop/third-party-integrations/stripe/install-and-configure-stripe-prerequisites.html), making sure to apply all steps marked as **marketplace only**.

{% info_block infoBox &quot;OMS process&quot; %}

In Step 3 of the base shop guide, use `StripeManualMarketplace01` instead of `StripeManual01`.

{% endinfo_block %}

## Add Merchant Portal navigation

Update `config/Zed/navigation-main-merchant-portal.xml` to add the Payment Settings entry for merchants:

```xml
&lt;?xml version=&quot;1.0&quot;?&gt;
&lt;config&gt;
    ...

    &lt;merchant-portal-payment-settings&gt;
        &lt;label&gt;Payment Settings&lt;/label&gt;
        &lt;title&gt;Payment Settings&lt;/title&gt;
        &lt;icon&gt;payment&lt;/icon&gt;
        &lt;bundle&gt;merchant-app-merchant-portal-gui&lt;/bundle&gt;
        &lt;controller&gt;payment-settings&lt;/controller&gt;
        &lt;action&gt;index&lt;/action&gt;
        &lt;pages&gt;
            &lt;onboarding&gt;
                &lt;label&gt;Onboarding&lt;/label&gt;
                &lt;title&gt;Onboarding&lt;/title&gt;
                &lt;icon&gt;payment&lt;/icon&gt;
                &lt;bundle&gt;merchant-app-merchant-portal-gui&lt;/bundle&gt;
                &lt;controller&gt;payment-settings&lt;/controller&gt;
                &lt;action&gt;onboarding&lt;/action&gt;
                &lt;visible&gt;0&lt;/visible&gt;
            &lt;/onboarding&gt;
        &lt;/pages&gt;
    &lt;/merchant-portal-payment-settings&gt;
&lt;/config&gt;
```

## Register ACL plugins

Add the following plugins to the listed methods:

| PLUGIN | METHOD |
|--------|--------|
| `\Spryker\Zed\MerchantAppMerchantPortalGui\Communication\Plugin\AclMerchantPortal\MerchantAppMerchantPortalGuiMerchantAclRuleExpanderPlugin` | `\Pyz\Zed\AclMerchantPortal\AclMerchantPortalDependencyProvider::getMerchantAclRuleExpanderPlugins()` |
| `\Spryker\Zed\MerchantAppMerchantPortalGui\Communication\Plugin\AclMerchantPortal\MerchantAppAclEntityConfigurationExpanderPlugin` | `\Pyz\Zed\AclMerchantPortal\AclMerchantPortalDependencyProvider::getAclEntityConfigurationExpanderPlugins()` |
| `\Spryker\Zed\Payment\Communication\Plugin\AclMerchantPortal\PaymentAclEntityConfigurationExpanderPlugin` | `\Pyz\Zed\AclMerchantPortal\AclMerchantPortalDependencyProvider::getAclEntityConfigurationExpanderPlugins()` |
| `\Spryker\Zed\SalesPaymentMerchant\Communication\Plugin\AclMerchantPortal\SalesPaymentMerchantAclEntityConfigurationExpanderPlugin` | `\Pyz\Zed\AclMerchantPortal\AclMerchantPortalDependencyProvider::getAclEntityConfigurationExpanderPlugins()` |

## Configure ACL installer rules

Add `merchant-app-merchant-portal-gui` to the Merchant Portal ACL deny rules:

&lt;details&gt;
  &lt;summary&gt;\Pyz\Zed\Acl\AclConfig::addMerchantPortalInstallerRules()&lt;/summary&gt;

```php
&lt;?php

namespace Pyz\Zed\Acl;

use Spryker\Shared\Acl\AclConstants;
use Spryker\Zed\Acl\AclConfig as SprykerAclConfig;

class AclConfig extends SprykerAclConfig
{
    protected const RULE_TYPE_DENY = &apos;deny&apos;;

    /**
     * @return array&lt;array&lt;string, mixed&gt;&gt;
     */
    public function getInstallerRules(): array
    {
        $installerRules = $this-&gt;addMerchantPortalInstallerRules($installerRules);

        return $installerRules;
    }

    /**
     * @param array&lt;array&lt;string, mixed&gt;&gt; $installerRules
     *
     * @return array&lt;array&lt;string, mixed&gt;&gt;
     */
    protected function addMerchantPortalInstallerRules(array $installerRules): array
    {
        $bundleNames = [
            &apos;merchant-app-merchant-portal-gui&apos;,
        ];

        foreach ($bundleNames as $bundleName) {
            $installerRules[] = [
                &apos;bundle&apos; =&gt; $bundleName,
                &apos;controller&apos; =&gt; AclConstants::VALIDATOR_WILDCARD,
                &apos;action&apos; =&gt; AclConstants::VALIDATOR_WILDCARD,
                &apos;type&apos; =&gt; static::RULE_TYPE_DENY,
                &apos;role&apos; =&gt; AclConstants::ROOT_ROLE,
            ];
        }

        return $installerRules;
    }
}
```

&lt;/details&gt;

## Enable redirect from third-party websites

To enable merchants to be redirected to the Merchant Portal from third-party websites, add `redirect.php` to the public folder of your Merchant Portal: [/public/MerchantPortal/redirect.php](https://github.com/spryker-shop/b2c-demo-marketplace/blob/master/public/MerchantPortal/redirect.php).

## Enable merchant commissions

To enable merchant commissions for payout calculation, [install the Marketplace Merchant Commission feature](/docs/pbc/all/merchant-management/latest/marketplace/install-and-upgrade/install-features/install-the-marketplace-merchant-commission-feature.html).

## Next step

[Configure merchant transfers for Stripe](/docs/pbc/all/payment-service-provider/latest/marketplace/stripe-third-party-integration/configure-merchant-transfers-for-stripe.html)
</description>
            <pubDate>Mon, 20 Apr 2026 12:40:12 +0000</pubDate>
            <link>https://docs.spryker.com/docs/pbc/all/payment-service-provider/latest/marketplace/stripe-third-party-integration/install-and-configure-stripe-prerequisites-for-marketplace.html</link>
            <guid isPermaLink="true">https://docs.spryker.com/docs/pbc/all/payment-service-provider/latest/marketplace/stripe-third-party-integration/install-and-configure-stripe-prerequisites-for-marketplace.html</guid>
            
            
        </item>
        
        <item>
            <title>AI Dev SDK</title>
            <description>&lt;section class=&apos;info-block info-block--warning&apos;&gt;&lt;i class=&apos;info-block__icon icon-warning&apos;&gt;&lt;/i&gt;&lt;div class=&apos;info-block__content&apos;&gt;&lt;div class=&quot;info-block__title&quot;&gt;Warning&lt;/div&gt;
&lt;p&gt;Before you use AI-related tools, consult your legal department.&lt;/p&gt;
&lt;/div&gt;&lt;/section&gt;
&lt;h2 id=&quot;overview&quot;&gt;Overview&lt;/h2&gt;
&lt;p&gt;When you use AI tools to write code, they rely on general patterns, which leads to mistakes and requires you to repeatedly explain your project structure.&lt;/p&gt;
&lt;p&gt;The AI Dev SDK provides an MCP server, which is a console command that your AI tool runs in your project’s Docker container and helps it to increase Spryker-context awareness. MCP (Model Context Protocol) is a standard protocol that lets AI tools request specific information from external sources, similar to how a browser requests data from an API.&lt;/p&gt;
&lt;h2 id=&quot;how-it-works&quot;&gt;How it works&lt;/h2&gt;
&lt;p&gt;After you install the SDK, &lt;a href=&quot;/docs/dg/dev/ai/ai-dev/ai-dev-mcp-server.html&quot;&gt;add a simple configuration&lt;/a&gt; to your AI tool. When your Spryker project is running, your AI tool can access Spryker-specific information and prompts through the MCP server.&lt;/p&gt;
&lt;h2 id=&quot;result&quot;&gt;Result&lt;/h2&gt;
&lt;p&gt;AI generates better code faster and with fewer errors. You spend less time correcting mistakes and explaining Spryker concepts.&lt;/p&gt;
&lt;h2 id=&quot;key-capabilities&quot;&gt;Key capabilities&lt;/h2&gt;
&lt;h3 id=&quot;faster-spryker-specific-answers&quot;&gt;Faster Spryker-specific answers&lt;/h3&gt;
&lt;p&gt;AI can search Spryker documentation instead of requiring you to explain basic concepts or guessing how features work.&lt;/p&gt;
&lt;h3 id=&quot;smarter-code-generation&quot;&gt;Smarter code generation&lt;/h3&gt;
&lt;p&gt;AI can look up your actual transfer objects, module dependencies, and interface methods so that the generated code matches your project structure instead of relying on assumptions.&lt;/p&gt;
&lt;h3 id=&quot;oms-debugging-made-easy&quot;&gt;OMS debugging made easy&lt;/h3&gt;
&lt;p&gt;AI can analyze your OMS flows to find possible next states, transitions, conditions, and timeouts for any order or state. This capability is especially helpful when you work with complex OMS schemas. You no longer need to manually follow arrows in large diagrams.&lt;/p&gt;
&lt;h3 id=&quot;working-with-complex-data-imports&quot;&gt;Working with complex data imports&lt;/h3&gt;
&lt;p&gt;AI can analyze, modify, and transform multi-column CSV files correctly. This task normally requires significant manual effort.&lt;/p&gt;
&lt;h3 id=&quot;sharing-prompts-across-your-team&quot;&gt;Sharing prompts across your team&lt;/h3&gt;
&lt;p&gt;The SDK includes access to the Spryker prompt library, and you can add your own project-specific prompts. This means your team can reuse effective prompts instead of everyone writing their own.&lt;/p&gt;
&lt;h3 id=&quot;database-queries&quot;&gt;Database queries&lt;/h3&gt;
&lt;p&gt;AI can execute read-only database queries to inspect data when debugging issues.&lt;/p&gt;
&lt;h3 id=&quot;extensible-for-your-project&quot;&gt;Extensible for your project&lt;/h3&gt;
&lt;p&gt;You can extend the MCP server by creating custom plugins (to add new tools) and custom prompts.&lt;/p&gt;
&lt;h2 id=&quot;install-the-ai-dev-sdk&quot;&gt;Install the AI Dev SDK&lt;/h2&gt;
&lt;h3 id=&quot;prerequisites&quot;&gt;Prerequisites&lt;/h3&gt;
&lt;p&gt;Ensure that you have a Spryker project with Composer installed.&lt;/p&gt;
&lt;h3 id=&quot;installation-steps&quot;&gt;Installation steps&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Require the package as a development dependency:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;composer require spryker-sdk/ai-dev &lt;span class=&quot;nt&quot;&gt;--dev&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Generate the transfer objects:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;console transfer:generate
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Register the console commands in your &lt;code&gt;ConsoleDependencyProvider&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;language-php highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kn&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;SprykerSdk\Zed\AiDev\Communication\Console\GenerateAgentsFileConsole&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;SprykerSdk\Zed\AiDev\Communication\Console\GeneratePromptsConsole&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;SprykerSdk\Zed\AiDev\Communication\Console\GenerateSkillsConsole&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;SprykerSdk\Zed\AiDev\Communication\Console\McpServerConsole&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;protected&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;getConsoleCommands&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Container&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$container&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;array&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;mf&quot;&gt;...&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;class_exists&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;McpServerConsole&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;$commands&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;McpServerConsole&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;class_exists&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;GenerateAgentsFileConsole&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;$commands&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;GenerateAgentsFileConsole&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;class_exists&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;GenerateSkillsConsole&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;$commands&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;GenerateSkillsConsole&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;class_exists&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;GeneratePromptsConsole&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;$commands&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;GeneratePromptsConsole&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;mf&quot;&gt;...&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Connect the AI Dev SDK to your AI agent. For detailed configuration instructions, see &lt;a href=&quot;/docs/dg/dev/ai/ai-dev/ai-dev-mcp-server.html&quot;&gt;Configure the AiDev MCP server&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;next-steps&quot;&gt;Next steps&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/docs/dg/dev/ai/ai-dev/ai-dev-mcp-server.html&quot;&gt;Configure the AiDev MCP server&lt;/a&gt; - Set up the connection to your AI tool&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/docs/dg/dev/ai/ai-dev/ai-dev-overview.html&quot;&gt;AI Dev SDK Overview&lt;/a&gt; - Learn more about the AI Dev SDK features and capabilities&lt;/li&gt;
&lt;/ul&gt;
</description>
            <pubDate>Mon, 20 Apr 2026 06:17:01 +0000</pubDate>
            <link>https://docs.spryker.com/docs/dg/dev/ai/ai-dev/ai-dev.html</link>
            <guid isPermaLink="true">https://docs.spryker.com/docs/dg/dev/ai/ai-dev/ai-dev.html</guid>
            
            
        </item>
        
        <item>
            <title>AI Dev SDK Overview</title>
            <description>&lt;section class=&apos;info-block info-block--warning&apos;&gt;&lt;i class=&apos;info-block__icon icon-warning&apos;&gt;&lt;/i&gt;&lt;div class=&apos;info-block__content&apos;&gt;&lt;div class=&quot;info-block__title&quot;&gt;Experimental module&lt;/div&gt;
&lt;p&gt;The AiDev module is experimental and not stable. There is no backward compatibility promise for this module. We welcome your feedback and contributions as we continue to develop and improve this module.&lt;/p&gt;
&lt;/div&gt;&lt;/section&gt;
&lt;section class=&apos;info-block info-block--warning&apos;&gt;&lt;i class=&apos;info-block__icon icon-warning&apos;&gt;&lt;/i&gt;&lt;div class=&apos;info-block__content&apos;&gt;&lt;div class=&quot;info-block__title&quot;&gt;Prerequisites&lt;/div&gt;
&lt;p&gt;This module requires &lt;code&gt;^1.71.0&lt;/code&gt; version of &lt;code&gt;docker/sdk&lt;/code&gt; for proper usage.
Make sure your development environment is up to date before installing the AiDev module.&lt;/p&gt;
&lt;/div&gt;&lt;/section&gt;
&lt;p&gt;This document describes how to integrate and use the AiDev module to connect your Spryker application to AI development tools through the Model Context Protocol (MCP).&lt;/p&gt;
&lt;h2 id=&quot;overview&quot;&gt;Overview&lt;/h2&gt;
&lt;p&gt;The AiDev module provides an MCP server that enables AI assistants to interact with your Spryker application.
It exposes Spryker-specific information through MCP tools and prompts, allowing AI assistants to better understand and work with your codebase.&lt;/p&gt;
&lt;p&gt;The module includes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;MCP Server&lt;/strong&gt;: A console command that runs an MCP server to communicate with AI assistants&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Extension Points&lt;/strong&gt;: Plugin interfaces for adding custom MCP tools and prompts&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Built-in Tools&lt;/strong&gt;: Pre-configured tools for accessing Spryker transfers, interfaces, and OMS information&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Prompt Generation&lt;/strong&gt;: Automatic generation of context-aware prompts from documentation&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;console-commands&quot;&gt;Console commands&lt;/h2&gt;
&lt;p&gt;The AiDev module provides the following console commands:&lt;/p&gt;
&lt;h3 id=&quot;mcp-server-command&quot;&gt;MCP Server Command&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;ai-dev:mcp-server&lt;/code&gt; command starts an MCP server that allows AI assistants to interact with your Spryker application.&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;docker/sdk console ai-dev:mcp-server &lt;span class=&quot;nt&quot;&gt;-q&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;This command:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Starts an MCP server using stdio transport&lt;/li&gt;
&lt;li&gt;Registers all configured MCP tool and prompt plugins&lt;/li&gt;
&lt;li&gt;Automatically generates prompts if they don’t exist&lt;/li&gt;
&lt;li&gt;Listens for requests from AI assistants&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Usage&lt;/strong&gt;: This command is typically configured in AI assistant tools (like Claude Desktop) to enable them to access Spryker-specific information.&lt;/p&gt;
&lt;h3 id=&quot;generate-agents-file-command&quot;&gt;Generate Agents File Command&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;ai-dev:generate-agents-file&lt;/code&gt; command generates an example AI context file (&lt;code&gt;AGENTS.md&lt;/code&gt; or &lt;code&gt;CLAUDE.md&lt;/code&gt;) for your Spryker project. This file provides AI agents with project-specific context, architectural rules, and coding conventions.&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;docker/sdk console ai-dev:generate-agents-file
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;When you run the command, you are prompted to select the output format:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Format&lt;/th&gt;
&lt;th&gt;Supported tools&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;AGENTS.md&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Universal format. Supported by Codex, OpenCode, Cursor, GitHub Copilot, Windsurf, VS Code, and more.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;CLAUDE.md&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Claude Code CLI (Anthropic).&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The command generates a &lt;code&gt;&amp;lt;format&amp;gt;.example.md&lt;/code&gt; file in your project root. Rename it to &lt;code&gt;AGENTS.md&lt;/code&gt; or &lt;code&gt;CLAUDE.md&lt;/code&gt; when ready to use.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Usage&lt;/strong&gt;: Run this command once when setting up AI tooling for a project to give your AI agent Spryker-specific context.&lt;/p&gt;
&lt;h3 id=&quot;generate-skills-command&quot;&gt;Generate Skills Command&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;ai-dev:generate-skills&lt;/code&gt; command generates example AI coding skill files for Spryker project development.&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;docker/sdk console ai-dev:generate-skills
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;When you run the command, you are prompted to select the target AI tool. The command copies example skills into the tool-specific directory:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;AI tool&lt;/th&gt;
&lt;th&gt;Output directory&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Claude Code&lt;/td&gt;
&lt;td&gt;&lt;code&gt;.claude/skills/&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Windsurf&lt;/td&gt;
&lt;td&gt;&lt;code&gt;.windsurf/skills/&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GitHub Copilot&lt;/td&gt;
&lt;td&gt;&lt;code&gt;.github/skills/&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cursor, OpenAI Codex, OpenCode, Agents Convention&lt;/td&gt;
&lt;td&gt;&lt;code&gt;.agents/skills/&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Each skill is generated with a &lt;code&gt;-example&lt;/code&gt; suffix in the directory name. Rename the directories by removing the &lt;code&gt;-example&lt;/code&gt; suffix when ready to use.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Usage&lt;/strong&gt;: Run this command to scaffold reusable AI skills for common Spryker development tasks such as functional testing, data import, Propel schema changes, and frontend development.&lt;/p&gt;
&lt;h3 id=&quot;generate-prompts-command&quot;&gt;Generate Prompts Command&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;ai-dev:generate-prompts&lt;/code&gt; command generates MCP prompts from a configured &lt;a href=&quot;https://github.com/spryker-dev/prompt-library&quot;&gt;Prompt Library&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;docker/sdk console ai-dev:generate-prompts
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;This command:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Fetches prompts&lt;/li&gt;
&lt;li&gt;Generates PHP-based prompt classes&lt;/li&gt;
&lt;li&gt;Stores generated prompts in the configured directory&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Usage&lt;/strong&gt;: Use this command when you need to regenerate prompts from updated documentation or when initializing the module for the first time.&lt;/p&gt;
&lt;h2 id=&quot;extension-points&quot;&gt;Extension points&lt;/h2&gt;
&lt;p&gt;The AiDev module provides plugin interfaces for extending the MCP server with custom functionality:&lt;/p&gt;
&lt;h3 id=&quot;aidevmcptoolplugininterface&quot;&gt;AiDevMcpToolPluginInterface&lt;/h3&gt;
&lt;p&gt;Implement this interface to add custom MCP tools that AI assistants can use to query or interact with your application.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Interface location&lt;/strong&gt;: &lt;code&gt;SprykerSdk\Zed\AiDev\Dependency\AiDevMcpToolPluginInterface&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Integration&lt;/strong&gt;: Register your tool plugins in &lt;code&gt;AiDevDependencyProvider::getMcpToolPlugins()&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;language-php highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;namespace&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Pyz\Zed\AiDev&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;SprykerSdk\Zed\AiDev\AiDevDependencyProvider&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;SprykerAiDevDependencyProvider&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Pyz\Zed\AiDev\Communication\Plugins\CustomAiDevMcpToolPlugin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;AiDevDependencyProvider&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;SprykerAiDevDependencyProvider&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;cd&quot;&gt;/**
     * @return array&amp;lt;\SprykerSdk\Zed\AiDev\Dependency\AiDevMcpToolPluginInterface&amp;gt;
     */&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;protected&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;getMcpToolPlugins&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;array&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;array_merge&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;parent&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getMcpToolPlugins&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;CustomAiDevMcpToolPlugin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h3 id=&quot;aidevmcppromptplugininterface&quot;&gt;AiDevMcpPromptPluginInterface&lt;/h3&gt;
&lt;p&gt;Implement this interface to add custom MCP prompts that provide context or instructions to AI assistants.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Interface location&lt;/strong&gt;: &lt;code&gt;SprykerSdk\Zed\AiDev\Dependency\AiDevMcpPromptPluginInterface&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Integration&lt;/strong&gt;: Register your prompt plugins in &lt;code&gt;AiDevDependencyProvider::getMcpPromptPlugins()&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;language-php highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;namespace&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Pyz\Zed\AiDev&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;SprykerSdk\Zed\AiDev\AiDevDependencyProvider&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;SprykerAiDevDependencyProvider&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Pyz\Zed\AiDev\Communication\Plugins\CustomAiDevMcpPromptPlugin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;AiDevDependencyProvider&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;SprykerAiDevDependencyProvider&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;cd&quot;&gt;/**
     * @return array&amp;lt;\SprykerSdk\Zed\AiDev\Dependency\AiDevMcpPromptPluginInterface&amp;gt;
     */&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;protected&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;getMcpPromptPlugins&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;array&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;CustomAiDevMcpPromptPlugin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h2 id=&quot;configuration&quot;&gt;Configuration&lt;/h2&gt;
&lt;p&gt;The AiDev module can be configured through the &lt;code&gt;AiDevConfig&lt;/code&gt; class. Key configuration options include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Prompt Directory&lt;/strong&gt;: Set the directory where generated prompts are stored&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Refer to the module’s configuration class for available options and their default values.&lt;/p&gt;
&lt;h2 id=&quot;debugging-the-mcp-server&quot;&gt;Debugging the MCP server&lt;/h2&gt;
&lt;p&gt;Before connecting your MCP server to AI assistants, you can test and debug it using the &lt;a href=&quot;https://modelcontextprotocol.io/docs/tools/inspector&quot;&gt;MCP Inspector&lt;/a&gt; tool. The inspector provides a web interface to interact with your MCP server, test tools, and verify that everything works correctly.&lt;/p&gt;
&lt;h3 id=&quot;using-the-mcp-inspector&quot;&gt;Using the MCP Inspector&lt;/h3&gt;
&lt;p&gt;Navigate to your Spryker project directory and run:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;npx @modelcontextprotocol/inspector docker/sdk console ai-dev:mcp-server &lt;span class=&quot;nt&quot;&gt;-q&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;This command will:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Start the MCP Inspector in your browser&lt;/li&gt;
&lt;li&gt;Connect to your local MCP server&lt;/li&gt;
&lt;li&gt;Display all available tools and prompts&lt;/li&gt;
&lt;li&gt;Allow you to test tool calls interactively&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;With Xdebug&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;npx @modelcontextprotocol/inspector docker/sdk cli &lt;span class=&quot;nt&quot;&gt;-x&lt;/span&gt; console ai-dev:mcp-server
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;section class=&apos;info-block &apos;&gt;&lt;i class=&apos;info-block__icon icon-info&apos;&gt;&lt;/i&gt;&lt;div class=&apos;info-block__content&apos;&gt;&lt;div class=&quot;info-block__title&quot;&gt;Node.js required&lt;/div&gt;
&lt;p&gt;The MCP Inspector requires Node.js to be installed on your system. The &lt;code&gt;npx&lt;/code&gt; command will automatically download and run the inspector tool without requiring a global installation.&lt;/p&gt;
&lt;/div&gt;&lt;/section&gt;
&lt;p&gt;&lt;img src=&quot;https://spryker.s3.eu-central-1.amazonaws.com/docs/dg/dev/ai-dev/mcp-inspector.png&quot; alt=&quot;MCP Inspector&quot; /&gt;&lt;/p&gt;
</description>
            <pubDate>Mon, 20 Apr 2026 06:17:01 +0000</pubDate>
            <link>https://docs.spryker.com/docs/dg/dev/ai/ai-dev/ai-dev-overview.html</link>
            <guid isPermaLink="true">https://docs.spryker.com/docs/dg/dev/ai/ai-dev/ai-dev-overview.html</guid>
            
            
        </item>
        
        <item>
            <title>Install the Purchasing Control feature</title>
            <description>{% info_block warningBox &quot;Experimental feature&quot; %}

Experimental feature - not recommended for production use.

{% endinfo_block %}

This document describes how to install the [Purchasing Control feature](/docs/pbc/all/cart-and-checkout/latest/base-shop/feature-overviews/purchasing-control-feature-overview.html).

## Install feature core

Follow the steps below to install the Purchasing Control feature core.

### Prerequisites

To start feature integration, review and install the necessary features:

| NAME | VERSION | INSTALLATION GUIDE |
| --- | --- | --- |
| Spryker Core | {{page.release_tag}} | [Install the Spryker Core feature](/docs/pbc/all/miscellaneous/latest/install-and-upgrade/install-features/install-the-spryker-core-feature.html) |
| Company Account | {{page.release_tag}} | [Install the Company Account feature](/docs/pbc/all/customer-relationship-management/latest/base-shop/install-and-upgrade/install-features/install-the-company-account-feature.html) |
| Checkout | {{page.release_tag}} | [Install the Checkout feature](/docs/pbc/all/cart-and-checkout/latest/base-shop/install-and-upgrade/install-features/install-the-checkout-feature.html) |
| Approval Process | {{page.release_tag}} | [Install the Approval Process feature](/docs/pbc/all/cart-and-checkout/latest/base-shop/install-and-upgrade/install-features/install-the-approval-process-feature.html) |

### 1) Install the required modules

```bash
composer require spryker-feature/purchasing-control:&quot;^0.1.0&quot; spryker-shop/checkout-page:&quot;^3.40.0&quot; --update-with-dependencies
```

### 2) Set up database schema and transfer objects

Apply database changes and generate entity and transfer changes:

```bash
console propel:install
console transfer:generate
```

{% info_block warningBox &quot;Verification&quot; %}

Make sure the following changes have been applied in the database:

| DATABASE ENTITY | TYPE | EVENT |
| --- | --- | --- |
| spy_cost_center | table | created |
| spy_cost_center_to_company_business_unit | table | created |
| spy_budget | table | created |
| spy_budget_consumption | table | created |
| spy_quote.fk_cost_center | column | created |
| spy_quote.fk_budget | column | created |
| spy_sales_order.fk_cost_center | column | created |
| spy_sales_order.fk_budget | column | created |

Make sure the following changes have been applied in transfer objects:

| TRANSFER | TYPE | EVENT | PATH |
| --- | --- | --- | --- |
| CostCenter | class | created | src/Generated/Shared/Transfer/CostCenterTransfer.php |
| CostCenterCollection | class | created | src/Generated/Shared/Transfer/CostCenterCollectionTransfer.php |
| CostCenterCriteria | class | created | src/Generated/Shared/Transfer/CostCenterCriteriaTransfer.php |
| CostCenterResponse | class | created | src/Generated/Shared/Transfer/CostCenterResponseTransfer.php |
| Budget | class | created | src/Generated/Shared/Transfer/BudgetTransfer.php |
| BudgetCollection | class | created | src/Generated/Shared/Transfer/BudgetCollectionTransfer.php |
| BudgetCriteria | class | created | src/Generated/Shared/Transfer/BudgetCriteriaTransfer.php |
| BudgetResponse | class | created | src/Generated/Shared/Transfer/BudgetResponseTransfer.php |
| BudgetConsumption | class | created | src/Generated/Shared/Transfer/BudgetConsumptionTransfer.php |
| Quote.idCostCenter | property | created | src/Generated/Shared/Transfer/QuoteTransfer.php |
| Quote.idBudget | property | created | src/Generated/Shared/Transfer/QuoteTransfer.php |
| Quote.costCenter | property | created | src/Generated/Shared/Transfer/QuoteTransfer.php |
| Quote.budget | property | created | src/Generated/Shared/Transfer/QuoteTransfer.php |

{% endinfo_block %}

### 3) Set up behavior

Enable the following behaviors by registering the plugins.

#### Set up Zed plugins

| PLUGIN | SPECIFICATION | PREREQUISITES | NAMESPACE |
| --- | --- | --- | --- |
| BudgetCheckoutPreConditionPlugin | Validates the cart grand total against the remaining budget before checkout proceeds. Blocks checkout or triggers the approval flow depending on the budget enforcement rule. | None | SprykerFeature\Zed\PurchasingControl\Communication\Plugin\Checkout |
| CostCenterOrderSaverPlugin | Saves the selected cost center and budget references to the sales order during checkout. | None | SprykerFeature\Zed\PurchasingControl\Communication\Plugin\Checkout |
| ConsumeBudgetCheckoutPostSavePlugin | Records budget consumption immediately after the order is saved so the remaining budget balance is accurate for concurrent buyers. Does nothing when no budget is selected on the quote. | None | SprykerFeature\Zed\PurchasingControl\Communication\Plugin\Checkout |
| CostCenterQuoteExpanderPlugin | Expands the quote with the default cost center assigned to the buyer&apos;s business unit when no cost center is already set. | None | SprykerFeature\Zed\PurchasingControl\Communication\Plugin\Quote |
| CostCenterQuoteFieldsAllowedForSavingProviderPlugin | Adds `idCostCenter` and `idBudget` to the list of quote fields persisted to the database. | None | SprykerFeature\Zed\PurchasingControl\Communication\Plugin\Quote |
| RestoreBudgetOmsCommandPlugin | Deletes all budget consumption records for a sales order when the order is cancelled, restoring the consumed budget amount. | None | SprykerFeature\Zed\PurchasingControl\Communication\Plugin\Oms |

**src/Pyz/Zed/Checkout/CheckoutDependencyProvider.php**

```php
&lt;?php

namespace Pyz\Zed\Checkout;

use Spryker\Zed\Checkout\CheckoutDependencyProvider as SprykerCheckoutDependencyProvider;
use Spryker\Zed\Kernel\Container;
use SprykerFeature\Zed\PurchasingControl\Communication\Plugin\Checkout\BudgetCheckoutPreConditionPlugin;
use SprykerFeature\Zed\PurchasingControl\Communication\Plugin\Checkout\ConsumeBudgetCheckoutPostSavePlugin;
use SprykerFeature\Zed\PurchasingControl\Communication\Plugin\Checkout\CostCenterOrderSaverPlugin;

class CheckoutDependencyProvider extends SprykerCheckoutDependencyProvider
{
    /**
     * @param \Spryker\Zed\Kernel\Container $container
     *
     * @return list&lt;\Spryker\Zed\CheckoutExtension\Dependency\Plugin\CheckoutPreConditionPluginInterface&gt;
     */
    protected function getCheckoutPreConditions(Container $container): array
    {
        return [
            // ...
            new BudgetCheckoutPreConditionPlugin(), #PurchasingControlFeature
        ];
    }

    /**
     * @param \Spryker\Zed\Kernel\Container $container
     *
     * @return list&lt;\Spryker\Zed\Checkout\Dependency\Plugin\CheckoutSaveOrderInterface|\Spryker\Zed\CheckoutExtension\Dependency\Plugin\CheckoutDoSaveOrderInterface&gt;
     */
    protected function getCheckoutOrderSavers(Container $container): array
    {
        return [
            // ...
            new CostCenterOrderSaverPlugin(), #PurchasingControlFeature
        ];
    }

    /**
     * @param \Spryker\Zed\Kernel\Container $container
     *
     * @return list&lt;\Spryker\Zed\CheckoutExtension\Dependency\Plugin\CheckoutPostSaveInterface&gt;
     */
    protected function getCheckoutPostHooks(Container $container): array
    {
        return [
            // ...
            new ConsumeBudgetCheckoutPostSavePlugin(), #PurchasingControlFeature
        ];
    }
}
```

{% info_block warningBox &quot;Verification&quot; %}

When a buyer places an order with a budget selected, verify the following:
- Checkout is blocked when the order exceeds a budget with the **Block** enforcement rule.
- An approval request is triggered when the order exceeds a budget with the **Require Approval** rule.
- A warning is displayed when the order exceeds a budget with the **Warn** rule.
- A `spy_budget_consumption` record is created after the order is successfully placed.
- The cost center and budget IDs are saved on the `spy_sales_order` record.

{% endinfo_block %}

**src/Pyz/Zed/Quote/QuoteDependencyProvider.php**

```php
&lt;?php

namespace Pyz\Zed\Quote;

use Spryker\Zed\Quote\QuoteDependencyProvider as SprykerQuoteDependencyProvider;
use SprykerFeature\Zed\PurchasingControl\Communication\Plugin\Quote\CostCenterQuoteExpanderPlugin;
use SprykerFeature\Zed\PurchasingControl\Communication\Plugin\Quote\CostCenterQuoteFieldsAllowedForSavingProviderPlugin;

class QuoteDependencyProvider extends SprykerQuoteDependencyProvider
{
    /**
     * @return array&lt;\Spryker\Zed\QuoteExtension\Dependency\Plugin\QuoteExpanderPluginInterface&gt;
     */
    protected function getQuoteExpanderPlugins(): array
    {
        return [
            // ...
            new CostCenterQuoteExpanderPlugin(), #PurchasingControlFeature
        ];
    }

    /**
     * @return array&lt;\Spryker\Zed\QuoteExtension\Dependency\Plugin\QuoteFieldsAllowedForSavingProviderPluginInterface&gt;
     */
    protected function getQuoteFieldsAllowedForSavingProviderPlugins(): array
    {
        return [
            // ...
            new CostCenterQuoteFieldsAllowedForSavingProviderPlugin(), #PurchasingControlFeature
        ];
    }
}
```

{% info_block warningBox &quot;Verification&quot; %}

When a buyer with an assigned business unit opens a cart, make sure the quote is automatically expanded with the default cost center of their business unit.

Make sure `idCostCenter` and `idBudget` are persisted to the `spy_quote` table when the quote is saved.

{% endinfo_block %}

**src/Pyz/Zed/Oms/OmsDependencyProvider.php**

```php
&lt;?php

namespace Pyz\Zed\Oms;

use Spryker\Zed\Oms\Dependency\Plugin\Command\CommandCollectionInterface;
use Spryker\Zed\Oms\OmsDependencyProvider as SprykerOmsDependencyProvider;
use Spryker\Zed\Kernel\Container;
use SprykerFeature\Zed\PurchasingControl\Communication\Plugin\Oms\RestoreBudgetOmsCommandPlugin;

class OmsDependencyProvider extends SprykerOmsDependencyProvider
{
    /**
     * @param \Spryker\Zed\Kernel\Container $container
     *
     * @return \Spryker\Zed\Kernel\Container
     */
    protected function extendCommandPlugins(Container $container): Container
    {
        $container-&gt;extend(self::COMMAND_PLUGINS, function (CommandCollectionInterface $commandCollection) {
            // ...
            $commandCollection-&gt;add(new RestoreBudgetOmsCommandPlugin(), &apos;CostCenter/RestoreBudget&apos;); #PurchasingControlFeature

            return $commandCollection;
        });

        return $container;
    }
}
```

{% info_block warningBox &quot;Verification&quot; %}

When an order transitions to a cancelled state and the `CostCenter/RestoreBudget` OMS command runs, make sure the corresponding `spy_budget_consumption` records are deleted and the budget balance is restored.

{% endinfo_block %}

### 4) Configure Back Office navigation

Add the Purchasing Control section to the Back Office navigation:

**config/Zed/navigation.xml**

```xml
&lt;?xml version=&quot;1.0&quot;?&gt;
&lt;config&gt;
    &lt;customer&gt;
        ...
        &lt;pages&gt;
            ...
            &lt;purchasing-control&gt;
                &lt;label&gt;Purchasing Control&lt;/label&gt;
                &lt;title&gt;Purchasing Control&lt;/title&gt;
                &lt;bundle&gt;purchasing-control&lt;/bundle&gt;
                &lt;controller&gt;cost-center&lt;/controller&gt;
                &lt;action&gt;index&lt;/action&gt;
            &lt;/purchasing-control&gt;
        &lt;/pages&gt;
    &lt;/customer&gt;
&lt;/config&gt;
```

Rebuild the navigation cache:

```bash
console navigation:build-cache
```

{% info_block warningBox &quot;Verification&quot; %}

In the Back Office, under **Customers**, make sure the **Purchasing Control** menu item is displayed and links to the cost center list page.

{% endinfo_block %}

### 5) Configure the OMS process

Add the `CostCenter/RestoreBudget` command to the `cancel` event in your OMS process XML. The following example uses `DummyPayment01`:

**config/Zed/oms/DummyPayment01.xml**

```xml
&lt;events&gt;
    ...
    &lt;event name=&quot;cancel&quot; manual=&quot;true&quot; command=&quot;CostCenter/RestoreBudget&quot;/&gt;
    ...
&lt;/events&gt;
```

{% info_block warningBox &quot;Verification&quot; %}

In the Back Office, open a placed order and trigger the **cancel** event. Make sure the `spy_budget_consumption` records for the order are deleted and the budget balance is restored.

{% endinfo_block %}

## Install feature frontend

Follow the steps below to install the Purchasing Control feature frontend.

### 1) Import data

Import the following glossary keys for Storefront translations:

**data/import/common/common/glossary.csv**

```csv
purchasing_control.selector.placeholder,Select cost center,en_US
purchasing_control.selector.placeholder,Kostenstelle wählen,de_DE
purchasing_control.budget.selector.label,Budget,en_US
purchasing_control.budget.selector.label,Budget,de_DE
purchasing_control.budget.selector.placeholder,Select budget,en_US
purchasing_control.budget.selector.placeholder,Budget wählen,de_DE
purchasing_control.budget.remaining,Remaining budget,en_US
purchasing_control.budget.remaining,Verbleibendes Budget,de_DE
purchasing_control.summary.cost_center_label,Cost Center,en_US
purchasing_control.summary.cost_center_label,Kostenstelle,de_DE
purchasing_control.summary.budget_label,Budget,en_US
purchasing_control.summary.budget_label,Budget,de_DE
purchasing_control.summary.budget_remaining,remaining,en_US
purchasing_control.summary.budget_remaining,verbleibend,de_DE
purchasing_control.validation.block,&quot;Your order exceeds the allocated budget. Please adjust your order or contact your manager.&quot;,en_US
purchasing_control.validation.block,&quot;Ihre Bestellung überschreitet das zugewiesene Budget. Bitte passen Sie Ihre Bestellung an oder kontaktieren Sie Ihren Manager.&quot;,de_DE
purchasing_control.validation.warn,Your order exceeds the allocated budget.,en_US
purchasing_control.validation.warn,Ihre Bestellung überschreitet das zugewiesene Budget.,de_DE
purchasing_control.validation.require-approval,This order exceeds the budget. Please send it for approval.,en_US
purchasing_control.validation.require-approval,Diese Bestellung überschreitet das Budget. Bitte senden Sie sie zur Genehmigung.,de_DE
purchasing_control.validation.required,&quot;Please select a cost center and budget before placing your order.&quot;,en_US
purchasing_control.validation.required,&quot;Bitte wählen Sie vor der Bestellung eine Kostenstelle und ein Budget aus.&quot;,de_DE
```

Import data:

```bash
console data:import:glossary
```

{% info_block warningBox &quot;Verification&quot; %}

Make sure that, in the database, the configured data has been added to the `spy_glossary_key` and `spy_glossary_translation` tables.

{% endinfo_block %}

### 2) Set up widgets

Register the following global widgets:

| WIDGET | DESCRIPTION | NAMESPACE |
| --- | --- | --- |
| CostCenterSelectorWidget | Renders the cost center and budget selection UI in the cart or checkout. | SprykerFeature\Yves\PurchasingControl\Widget |

**src/Pyz/Yves/ShopApplication/ShopApplicationDependencyProvider.php**

```php
&lt;?php

namespace Pyz\Yves\ShopApplication;

use SprykerShop\Yves\ShopApplication\ShopApplicationDependencyProvider as SprykerShopApplicationDependencyProvider;
use SprykerFeature\Yves\PurchasingControl\Widget\CostCenterSelectorWidget;

class ShopApplicationDependencyProvider extends SprykerShopApplicationDependencyProvider
{
    /**
     * @return array&lt;string&gt;
     */
    protected function getGlobalWidgets(): array
    {
        return [
            // ...
            CostCenterSelectorWidget::class, #PurchasingControlFeature
        ];
    }
}
```

{% info_block warningBox &quot;Verification&quot; %}

Make sure the `CostCenterSelectorWidget` widget is available in Twig templates.

{% endinfo_block %}

### 3) Extend the checkout summary template

Add the `CostCenterSelectorWidget` to the checkout summary page, placing it directly above the `QuoteApprovalWidget` call:

**src/SprykerShop/CheckoutPage/src/SprykerShop/Yves/CheckoutPage/Theme/default/views/summary/summary.twig**

```twig
&lt;div class=&quot;box&quot;&gt;
    {% raw %}{% widget &apos;CostCenterSelectorWidget&apos; args [data.cart] only %}{% endwidget %}{% endraw %}
    {% raw %}{% widget &apos;QuoteApprovalWidget&apos; args [data.cart] only %}{% endwidget %}{% endraw %}
&lt;/div&gt;
```

{% info_block warningBox &quot;Verification&quot; %}

On the checkout summary page, make sure the cost center and budget selector is displayed above the approval widget.

{% endinfo_block %}

### 4) Set up routes

Register the following route provider plugin:

| PLUGIN | SPECIFICATION | PREREQUISITES | NAMESPACE |
| --- | --- | --- | --- |
| CostCenterRouteProviderPlugin | Adds the `POST /cost-center/update-quote` route, which handles cost center and budget selection form submissions from the cart or checkout. | None | SprykerFeature\Yves\PurchasingControl\Plugin\Router |

**src/Pyz/Yves/Router/RouterDependencyProvider.php**

```php
&lt;?php

namespace Pyz\Yves\Router;

use Spryker\Yves\Router\RouterDependencyProvider as SprykerRouterDependencyProvider;
use SprykerFeature\Yves\PurchasingControl\Plugin\Router\CostCenterRouteProviderPlugin;

class RouterDependencyProvider extends SprykerRouterDependencyProvider
{
    /**
     * @return array&lt;\Spryker\Yves\RouterExtension\Dependency\Plugin\RouteProviderPluginInterface&gt;
     */
    protected function getRouteProvider(): array
    {
        return [
            // ...
            new CostCenterRouteProviderPlugin(), #PurchasingControlFeature
        ];
    }
}
```

{% info_block warningBox &quot;Verification&quot; %}

Make sure the route `cost-center-update-quote` is accessible and that submitting the cost center selector form in the cart updates the quote with the selected cost center and budget.

{% endinfo_block %}
</description>
            <pubDate>Fri, 17 Apr 2026 14:22:26 +0000</pubDate>
            <link>https://docs.spryker.com/docs/pbc/all/cart-and-checkout/latest/base-shop/install-and-upgrade/install-features/install-the-purchasing-control-feature.html</link>
            <guid isPermaLink="true">https://docs.spryker.com/docs/pbc/all/cart-and-checkout/latest/base-shop/install-and-upgrade/install-features/install-the-purchasing-control-feature.html</guid>
            
            
        </item>
        
        <item>
            <title>Purchasing Control feature overview</title>
            <description>The *Purchasing Control* feature lets B2B companies track and control procurement spending by assigning orders to cost centers and enforcing configurable budget rules. It extends the existing [Approval Process](/docs/pbc/all/cart-and-checkout/latest/base-shop/feature-overviews/approval-process-feature-overview.html) with a second dimension of spending governance: per-department or per-project budget limits that work alongside the existing per-person permission limits.

{% info_block infoBox &quot;Info&quot; %}

This feature is available in the Back Office and on the Storefront.

{% endinfo_block %}

## Cost centers

A *cost center* is an organizational unit within a company that incurs costs but does not directly generate revenue. Companies use cost centers to track and control spending by department, project, location, or function.

**Common examples:**

- **Departmental:** Marketing, Engineering, HR, Facilities
- **Project-based:** Office Renovation Q2 2026, Trade Show Berlin
- **Location-based:** Warehouse Berlin, Office London

Every purchase a buyer makes is charged to a cost center so the company can track where money is being spent. In ERP systems such as SAP, Oracle, and Microsoft Dynamics, cost centers are a foundational accounting concept - orders flow into the ERP tagged with a cost center code, enabling financial reporting and cost allocation.

## Budgets

A *budget* is a spending limit assigned to a cost center for a defined period - monthly, quarterly, or annually. It represents the maximum amount that a department or project is authorized to spend in that period.

**Example:** The Marketing department has a quarterly procurement budget of €50,000 for office supplies and event materials. Once that budget is consumed, further purchases are either blocked, flagged for review, or escalated for approval.

### Budget enforcement rules

Each budget is configured with one of three enforcement rules:

| RULE | DESCRIPTION |
| --- | --- |
| Block | The order is rejected outright when the budget is exceeded. The buyer cannot proceed to checkout. |
| Warn | A warning is displayed to the buyer, but they can proceed. |
| Require Approval | The order is sent for approval when the budget is exceeded. The buyer cannot complete checkout until an approver accepts the order. |

## Relationship to the Approval Process

Spryker&apos;s existing Approval Process triggers a workflow when a buyer&apos;s order exceeds their *Buy up to grand total* permission. The Purchasing Control feature adds a parallel check: an order might be within a buyer&apos;s personal permission limit but still exceed the cost center&apos;s remaining budget.

Both checks run independently at checkout. If either the permission limit or the budget rule is triggered, the configured action - block, warn, or require approval - is applied. This gives companies layered spending governance: per-person limits *and* per-department or per-project limits.

{% info_block warningBox &quot;Approvals within a business unit&quot; %}

Approvers can only approve orders of employees within their own business unit. This constraint applies to both permission-based and budget-based approval requests.

{% endinfo_block %}

## Cost centers and budgets in the procurement workflow

The typical B2B procurement flow involving cost centers and budgets:

1. **Finance sets budgets.** At the start of a fiscal period, finance allocates budgets to each cost center.
2. **Buyers are assigned to cost centers.** Buyers are linked to one or more cost centers they are authorized to purchase against. Cost centers are linked to company business units, so all users in a business unit are automatically assigned to the corresponding cost centers.
3. **Orders are tagged.** At checkout, the buyer selects which cost center the purchase is charged to. The system automatically selects the active budget for that cost center:
   - If exactly one active budget is available - it is selected automatically.
   - If multiple budgets are available - the buyer selects from a dropdown.
4. **Budget is validated.** The system checks whether the order total fits within the remaining budget for the selected cost center.
5. **Enforcement rules apply.** Based on the configured rule, the order is blocked, a warning is shown, or approval is required.
6. **Budget is consumed.** Once the order is confirmed, the budget balance is reduced by the order amount.
7. **Budget is restored.** If the order is cancelled, the consumed amount is returned to the budget balance.

## Checkout validation outcomes

| SCENARIO | OUTCOME |
| --- | --- |
| Within budget and within permission limit | Buyer completes checkout without additional steps. |
| Exceeds budget  -  Warn rule | A warning is displayed; the buyer proceeds but the order requires approval. |
| Exceeds budget  -  Require Approval rule | The order is sent for approval; the buyer cannot complete checkout until approved. |
| Exceeds Buy up to grand total permission limit | The order is sent for approval, same as the standard Approval Process. |
| Exceeds budget  -  Block rule | Checkout is blocked; no approval option is available. |

## Quote lock

When an order is sent for approval - whether triggered by a budget rule or a permission limit - the quote is locked to preserve the order state during the approval review. Neither the buyer nor the approver can modify the quote while it is pending approval. For details, see [Quote lock functionality](/docs/pbc/all/cart-and-checkout/latest/base-shop/feature-overviews/approval-process-feature-overview.html#quote-lock-functionality).

## Roles and capabilities

| ROLE | CAPABILITIES |
| --- | --- |
| Company Admin (Back Office) | Create, update, activate, and deactivate cost centers. Assign cost centers to business units. Create and manage budgets with amount, period, currency, and enforcement rule. View spend-vs-budget reports. Export reports to CSV. Review the audit log. |
| Buyer (Storefront) | Select a cost center and budget at checkout. View remaining budget for the selected cost center. Submit orders for approval when required. |
| Approver (Storefront) | Review locked quotes pending approval. Approve or reject orders, including those triggered by budget rules. |

## Related Developer documents

| INSTALLATION GUIDES |
| --- |
| [Install the Purchasing Control feature](/docs/pbc/all/cart-and-checkout/latest/base-shop/install-and-upgrade/install-features/install-the-purchasing-control-feature.html) |
</description>
            <pubDate>Fri, 17 Apr 2026 14:20:09 +0000</pubDate>
            <link>https://docs.spryker.com/docs/pbc/all/cart-and-checkout/latest/base-shop/feature-overviews/purchasing-control-feature-overview.html</link>
            <guid isPermaLink="true">https://docs.spryker.com/docs/pbc/all/cart-and-checkout/latest/base-shop/feature-overviews/purchasing-control-feature-overview.html</guid>
            
            
        </item>
        
        <item>
            <title>Stripe</title>
            <description>[Stripe](https://stripe.com/en-de) is a financial infrastructure platform that enables businesses to accept payments, grow their revenue, and accelerate new business opportunities.

The Stripe integration in Spryker is part of [Spryker ecosystem](/docs/integrations/eco-modules) and supports both the default Storefront Yves and Spryker GLUE APIs.

## Supported business models

The Stripe module supports B2B, B2C, and Marketplace models.

## Stripe features

- Interface within the Back Office to configure API keys.
- Support of test (sandbox) or live credentials.
- Storefront Payment Page: when the Stripe payment method is configured, after order submission end users are presented with the Stripe Elements payment form where they can select and complete their payment. This works both on the web and mobile.
- Viewing the activated payment methods in the Stripe dashboard.
- GLUE API support: Support for customers using Spryker headless.
- Authorize payments and capture later: The default OMS configuration lets you authorize cards and capture the order amount either after shipping or based on the established business logic.
- Default OMS Configuration: We provide default OMS configurations (for regular ecommerce sites and marketplaces) that you can use as an example or modify to align with your business logic.

## Stripe payment methods

The Stripe module supports all payments enabled by Stripe in your region. For more information, see [Payment methods in Stripe](https://stripe.com/docs/payments/payment-methods/overview).
However, our team only tested the following payment methods:
- Cards: including Visa and Mastercard
- Debit card
- Bank transfer: supported in some regions, see [Bank transfer payments](https://stripe.com/docs/payments/bank-transfers)
- PayPal
- Klarna
- Apple Pay
- Google Pay
- Direct Debit (SEPA) / Sofortüberweisung
- iDEAL
- Link
- Przelewy24
- Giropay
- US, UK, CA, AU, NZ: AfterPay

## Current limitations

- Partial capture of payment for orders with multiple items isn&apos;t covered (Stripe allows only one capture per PaymentIntent). One payment intent is created per order, and the payment for the order can either be authorized, captured, or cancelled from Stripe&apos;s side.
- Payments can&apos;t be partially canceled.
- Items canceled after capture are handled via refunds. 

## Browser back button handling

Using the browser back button at the Stripe payment form may lead to issues with order persistence and stock management. For instructions on configuring your application to handle this scenario and prevent duplicate orders, see [Configure handling of browser back button action at payment page](/docs/pbc/all/payment-service-provider/latest/base-shop/configure-handling-of-browser-back-button-action-at-hosted-payment-page.html).


## Next step

[Integrate Stripe](/docs/pbc/all/payment-service-provider/latest/base-shop/third-party-integrations/stripe/install-and-configure-stripe-prerequisites.html)
</description>
            <pubDate>Thu, 16 Apr 2026 13:59:55 +0000</pubDate>
            <link>https://docs.spryker.com/docs/pbc/all/payment-service-provider/latest/base-shop/third-party-integrations/stripe/stripe.html</link>
            <guid isPermaLink="true">https://docs.spryker.com/docs/pbc/all/payment-service-provider/latest/base-shop/third-party-integrations/stripe/stripe.html</guid>
            
            
        </item>
        
        <item>
            <title>Stripe OMS configuration for marketplaces</title>
            <description>This document provides guidelines for projects using Stripe in marketplaces.

## OMS configuration

The complete default payment OMS configuration for marketplaces is available in `vendor/spryker-eco/stripe/config/Zed/oms/StripeManualMarketplace01.xml`.

The payment flow of the default OMS involves authorizing the initial payment, which means that the amount is temporarily blocked when the payment method permits. Then, the OMS sends requests to capture, that is, transfer of the previously blocked amount from the customer&apos;s account to the store account.

For more information about the base shop OMS configuration, see [OMS configuration for Stripe](/docs/pbc/all/payment-service-provider/latest/base-shop/third-party-integrations/stripe/project-guidelines-for-stripe/oms-configuration-for-stripe.html).

In addition to the base shop implementation, the Stripe module in Marketplaces requires the following OMS configuration:

- The `MerchantCommission/Calculate` command triggers the calculation of the commission for the merchant. By default, this command is initiated when an order is moved to the `payment captured` state. This command calculates the commission based on your projects settings. For more details on configuration, see  [Marketplace Merchant Commission feature overview](/docs/pbc/all/merchant-management/latest/marketplace/marketplace-merchant-commission-feature-overview.html).

- The `SalesPaymentMerchant/Payout` command initiates the payout to merchant action. By default, this command is initiated after the OMS is in the `delivered` state and the commission was calculated.

- The `SalesPaymentMerchant/ReversePayout` command initiates the reversal of the payout to the merchant action. By default, this command is initiated after the OMS is in the `payment refunded` state.

- The validation of the payout status is done by the `SalesPaymentMerchant/IsMerchantPaidOut` condition. By default, this condition is triggered after a payout is done. When a payout is successful, the OMS moves to the `closed` state. If a payout fails, the OMS moves to the `payout failed` state.

- The `SalesPaymentMerchant/IsMerchantPayoutReversed` condition validates the reverse payout status. By default, this condition is triggered after the reverse payout is done. When a reverse payout is successful, the OMS moves to the `canceled` state. If a reverse payout fails, the OMS moves to the `reverse payout failed` state.

You can change and configure your own payment OMS based on `StripeManualMarketplace01.xml` from the Stripe eco package. For more information about the OMS feature and its configuration, see [Install the Order Management feature](/docs/pbc/all/order-management-system/latest/base-shop/install-and-upgrade/install-features/install-the-order-management-feature.html).

To configure your payment OMS based on `StripeManualMarketplace01.xml`, copy `StripeManualMarketplace01.xml` with the `Subprocess` folder to the project root `config/Zed/oms`. Then, change the file&apos;s name and the value of `&lt;process name=` in the file.

&lt;details&gt;
  &lt;summary&gt;Payout subprocess example&lt;/summary&gt;

```xml
&lt;?xml version=&quot;1.0&quot;?&gt;
&lt;statemachine
        xmlns=&quot;spryker:oms-01&quot;
        xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
        xsi:schemaLocation=&quot;spryker:oms-01 http://static.spryker.com/oms-01.xsd&quot;
&gt;

   &lt;process name=&quot;MerchantPayout&quot;&gt;

      &lt;states&gt;
         &lt;state name=&quot;merchant payout ready&quot; display=&quot;oms.state.payout-merchant&quot;/&gt;
         &lt;state name=&quot;payout failed&quot; display=&quot;oms.state.payout-failed&quot;/&gt;
      &lt;/states&gt;

      &lt;transitions&gt;

         &lt;transition condition=&quot;SalesPaymentMerchant/IsMerchantPaidOut&quot; happy=&quot;true&quot;&gt;
            &lt;source&gt;merchant payout ready&lt;/source&gt;
            &lt;target&gt;closed&lt;/target&gt;
            &lt;event&gt;payout merchant&lt;/event&gt;
         &lt;/transition&gt;

         &lt;transition&gt;
            &lt;source&gt;merchant payout ready&lt;/source&gt;
            &lt;target&gt;payout failed&lt;/target&gt;
            &lt;event&gt;payout merchant&lt;/event&gt;
         &lt;/transition&gt;

         &lt;transition&gt;
            &lt;source&gt;payout failed&lt;/source&gt;
            &lt;target&gt;merchant payout ready&lt;/target&gt;
            &lt;event&gt;retry payout merchant&lt;/event&gt;
         &lt;/transition&gt;

      &lt;/transitions&gt;

      &lt;events&gt;
         &lt;event name=&quot;payout merchant&quot; onEnter=&quot;true&quot; command=&quot;SalesPaymentMerchant/Payout&quot;/&gt;
         &lt;event name=&quot;retry payout merchant&quot; manual=&quot;true&quot;/&gt;
         &lt;event name=&quot;close&quot; manual=&quot;true&quot;/&gt;
      &lt;/events&gt;
   &lt;/process&gt;

&lt;/statemachine&gt;
```

&lt;/details&gt;


&lt;details&gt;
  &lt;summary&gt;Reverse Payout subprocess&lt;/summary&gt;

```xml
&lt;?xml version=&quot;1.0&quot;?&gt;
&lt;statemachine
        xmlns=&quot;spryker:oms-01&quot;
        xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
        xsi:schemaLocation=&quot;spryker:oms-01 http://static.spryker.com/oms-01.xsd&quot;
&gt;

   &lt;process name=&quot;MerchantPayoutReverse&quot;&gt;

      &lt;states&gt;
         &lt;state name=&quot;merchant payout reverse ready&quot; display=&quot;oms.state.payout-reversed&quot;/&gt;
         &lt;state name=&quot;reverse payout failed&quot; display=&quot;oms.state.payout-reversal-failed&quot;/&gt;
      &lt;/states&gt;

      &lt;transitions&gt;

         &lt;transition condition=&quot;SalesPaymentMerchant/IsMerchantPayoutReversed&quot;&gt;
            &lt;source&gt;merchant payout reverse ready&lt;/source&gt;
            &lt;target&gt;canceled&lt;/target&gt;
            &lt;event&gt;reverse payout&lt;/event&gt;
         &lt;/transition&gt;

         &lt;transition&gt;
            &lt;source&gt;merchant payout reverse ready&lt;/source&gt;
            &lt;target&gt;reverse payout failed&lt;/target&gt;
            &lt;event&gt;reverse payout&lt;/event&gt;
         &lt;/transition&gt;

         &lt;transition&gt;
            &lt;source&gt;reverse payout failed&lt;/source&gt;
            &lt;target&gt;merchant payout reverse ready&lt;/target&gt;
            &lt;event&gt;retry reverse payout&lt;/event&gt;
         &lt;/transition&gt;

      &lt;/transitions&gt;

      &lt;events&gt;
         &lt;event name=&quot;reverse payout&quot; onEnter=&quot;true&quot; command=&quot;SalesPaymentMerchant/ReversePayout&quot;/&gt;
         &lt;event name=&quot;retry reverse payout&quot; manual=&quot;true&quot;/&gt;
         &lt;event name=&quot;canceled&quot; manual=&quot;true&quot;/&gt;
      &lt;/events&gt;
   &lt;/process&gt;

&lt;/statemachine&gt;
```

&lt;/details&gt;


## Processing payouts

In the default OMS configuration, a payout to merchants is initiated after the OMS is in `delivered` state and the commission was calculated. This command sends a direct API call to Stripe to initiate the payout to the merchant. The payout status is tracked in the Back Office, and the OMS can either move to `payout failed` or `closed` state. The `payout failed` state is used to track the payout status and inform the Back Office user about the failure. The `closed` state is used to track the successful payout.

### Payout process

1. A customer pays for an order.
2. The money is transferred from the customer&apos;s account, like a bank account, to the marketplace Stripe account.
- The marketplace calculates the commission for the merchant.
- The marketplace initiates a payout to the merchant.
- The money is transferred from the marketplace Stripe account to the merchant&apos;s Stripe account.

### When a payout fails

A payout can fail for many reasons. Examples:
- The merchant&apos;s account isn&apos;t verified
- The merchant&apos;s account isn&apos;t connected to the marketplace Stripe account
- The merchant&apos;s account isn&apos;t active

You can identify the cause of a failure in the Stripe Dashboard. After resolving the issue, the payout can be reinitiated.

## Processing refunds as reverse payout

In the default OMS configuration, a reverse payout can be done for an order or an individual item. The reverse payout action is initiated by a Back Office user triggering the `SalesPaymentMerchant/ReversePayout` command. The selected item or items are used to find the previously made payout in the database and the amount that was paid out to the merchant and make a direct API call to Stripe which does the reverse payout. Based on the response the items go either into `canceled` or `reverse payout failed` state.

### Reverse Payout process

1. A customer returns an item.
2. The money is transferred from the marketplace Stripe account to the customers account, like a bank account.
3. The marketplace initiates a reverse payout from a merchant.
4. The money is transferred from the merchant&apos;s Stripe account to the marketplace Stripe account.


### Reverse payout failures

A reverse payout can fail for many reasons, for example — the merchant&apos;s Stripe account doesn&apos;t have the funds to cover a reverse payout. You can identify the cause of a failure in the Stripe Dashboard. After resolving the issue, the reverse payout can be reinitiated again.
</description>
            <pubDate>Thu, 16 Apr 2026 13:59:55 +0000</pubDate>
            <link>https://docs.spryker.com/docs/pbc/all/payment-service-provider/latest/marketplace/stripe-third-party-integration/stripe-oms-configuration-in-marketplaces.html</link>
            <guid isPermaLink="true">https://docs.spryker.com/docs/pbc/all/payment-service-provider/latest/marketplace/stripe-third-party-integration/stripe-oms-configuration-in-marketplaces.html</guid>
            
            
        </item>
        
    </channel>
</rss>
