Order Management feature integration
Edit on GitHubThe following feature integration guide expects the basic feature to be in place.
The current feature integration guide only adds the following functionalities:
Order cancellation behavior
Show `display names` for order item states
Invoice generation
Install Feature Core
Follow the steps below to install the Order Management feature core.
Prerequisites
To start feature integration, overview and install the necessary features:
Name | Version |
---|---|
Spryker Core | 202005.0 |
Mailing & Notifications | 202005.0 |
1) Install the required modules using Composer
Run the following command(s) to install the required modules:
composer require spryker-feature/order-management: "202005.0" --update-with-dependencies
Set up Database Schema and Transfer Objects
Run the following commands to apply database changes and generate transfer changes:
console transfer:generate
console propel:install
console transfer:entity:generate
Make sure that the following changes have been applied in database:
Datatabase Entity | Type | Event |
---|---|---|
spy_sales_order_invoice |
table | created |
Make sure that the following changes have been applied in transfer objects:
Transfer | Type | Event | Path |
---|---|---|---|
OrderInvoice |
class | created | src/Generated/Shared/Transfer/OrderInvoiceTransfer |
OrderInvoiceSendRequest |
class | created | src/Generated/Shared/Transfer/OrderInvoiceSendRequestTransfer |
OrderInvoiceSendResponse |
class | created | src/Generated/Shared/Transfer/OrderInvoiceSendResponseTransfer |
OrderInvoiceCriteria |
class | created | src/Generated/Shared/Transfer/OrderInvoiceCriteriaTransfer |
OrderInvoiceCollection |
class | created | src/Generated/Shared/Transfer/OrderInvoiceCollectionTransfer |
OrderInvoiceResponse |
class | created | src/Generated/Shared/Transfer/OrderInvoiceResponseTransfer |
Mail.recipientBccs |
property | created | src/Generated/Shared/Transfer/MailTransfer |
3) Set up Configuration
Set up the following configuration.
2.1) Configure OMS
The cancellable
flag allows to proceed to the order cancel
process.
The display
attribute allows to attach the display name
attribute to specific order item states.
TheDummyInvoice
sub-process allows triggering invoice-generate
events.
<process name="DummyInvoice">
<states>
<state name="invoice generated"/>
</states>
<transitions>
<transition>
<source>confirmed</source>
<target>invoice generated</target>
<event>invoice-generate</event>
</transition>
<transition>
<source>invoice generated</source>
<target>waiting</target>
<target>invoice-generated</target>
</transition>
</transitions>
<events>
<event name="invoice-generate" manual="true" command="Invoice/Generate"/>
<event name="invoice-generated" onEnter="true"/>
</events>
</process>
The verification of the invoice state machine configuration will be checked in a later step.
Using the DummyPayment01.xml
process as an example, adjust your OMS state-machine configuration according to your project’s requirements.
config/Zed/oms/DummyPayment01.xml
<?xml version="1.0"?>
<statemachine
xmlns="spryker:oms-01"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="spryker:oms-01 http://static.spryker.com/oms-01.xsd">
<process name="DummyPayment01" main="true">
<subprocesses>
<process>DummyInvoice</process>
</subprocesses>
<states>
<state name="new" reserved="true" display="oms.state.new">
<flag>cancellable</flag>
</state>
<state name="payment pending" reserved="true" display="oms.state.payment-pending">
<flag>cancellable</flag>
</state>
<state name="invalid" display="oms.state.invalid">
<flag>exclude from customer</flag>
</state>
<state name="cancelled" display="oms.state.canceled">
<flag>exclude from customer</flag>
</state>
<state name="paid" reserved="true" display="oms.state.paid">
<flag>cancellable</flag>
</state>
<state name="confirmed" reserved="true" display="oms.state.confirmed">
<flag>cancellable</flag>
</state>
<state name="waiting" reserved="true" display="oms.state.waiting"/>
<state name="exported" reserved="true" display="oms.state.exported"/>
<state name="shipped" reserved="true" display="oms.state.shipped"/>
<state name="delivered" display="oms.state.delivered"/>
<state name="closed" display="oms.state.closed"/>
</states>
<transitions>
<transition happy="true" condition="DummyPayment/IsAuthorized">
<source>new</source>
<target>payment pending</target>
<event>authorize</event>
</transition>
<transition>
<source>new</source>
<target>invalid</target>
<event>authorize</event>
</transition>
<transition>
<source>new</source>
<target>cancelled</target>
<event>cancel</event>
</transition>
<transition happy="true" condition="DummyPayment/IsPayed">
<source>payment pending</source>
<target>paid</target>
<event>pay</event>
</transition>
<transition>
<source>payment pending</source>
<target>cancelled</target>
<event>pay</event>
</transition>
<transition>
<source>payment pending</source>
<target>cancelled</target>
<event>cancel</event>
</transition>
<transition happy="true">
<source>paid</source>
<target>confirmed</target>
<event>confirm</event>
</transition>
<transition happy="true">
<source>confirmed</source>
<target>waiting</target>
<event>skip timeout</event>
</transition>
<transition>
<source>confirmed</source>
<target>cancelled</target>
<event>cancel</event>
</transition>
<transition happy="true">
<source>waiting</source>
<target>exported</target>
<event>check giftcard purchase</event>
</transition>
<transition happy="true" condition="GiftCard/IsGiftCard">
<source>waiting</source>
<target>gift card purchased</target>
<event>check giftcard purchase</event>
</transition>
<transition happy="true">
<source>gift card shipped</source>
<target>delivered</target>
<event>complete gift card creation</event>
</transition>
<transition happy="true">
<source>exported</source>
<target>shipped</target>
<event>ship</event>
</transition>
<transition happy="true">
<source>shipped</source>
<target>delivered</target>
<event>stock-update</event>
</transition>
<transition happy="true">
<source>delivered</source>
<target>closed</target>
<event>close</event>
</transition>
</transitions>
<events>
<event name="authorize" onEnter="true"/>
<event name="pay" manual="true" timeout="1 hour" timeoutProcessor="OmsTimeout/Initiation" command="DummyPayment/Pay"/>
<event name="confirm" onEnter="true" manual="true" command="Oms/SendOrderConfirmation"/>
<event name="skip timeout" manual="true" timeout="30 minute"/>
<event name="cancel" manual="true"/>
<event name="export" onEnter="true" manual="true" command="Oms/SendOrderShipped"/>
<event name="ship" manual="true" command="Oms/SendOrderShipped"/>
<event name="stock-update" manual="true"/>
<event name="close" manual="true" timeout="1 hour"/>
</events>
</process>
<process name="DummyInvoice" file="DummySubprocess/DummyInvoice01.xml"/>
</statemachine>
Ensure that you’ve configured the OMS:
-
Go to the Back Office > Administration > OMS.
-
Select DummyPayment01 [preview-version].
-
Ensure that the
new
,payment pending
,paid
, andconfirmed
states keep thecancellable
tag inside. -
Ensure that
invoice generated
state was added.
2.2) Configure Fallback Display Name Prefix
Adjust configuration according to your project’s needs:
src/Pyz/Zed/Oms/OmsConfig.php
<?php
namespace Pyz\Zed\Oms;
use Spryker\Zed\Oms\OmsConfig as SprykerOmsConfig;
class OmsConfig extends SprykerOmsConfig
{
/**
* Specification:
* - Uses fallback prefix in concatenation with the normalized state name, in case the display property is not defined for the state.
*
* @return string
*/
public function getFallbackDisplayNamePrefix(): string
{
return 'oms.state.';
}
}
Once you’ve finished setting up behavior, ensure that, on the following Storefront pages, the item states are displayed correctly even if the display
property is not set in the process definition:
- Customer overview
- Order history
- Order details
- Returns
- Return details
Adjust configuration according to your project’s needs:
src/Pyz/Zed/SalesInvoice/SalesInvoiceConfig.php
<?php
namespace Pyz\Zed\SalesInvoice;
use Spryker\Zed\SalesInvoice\SalesInvoiceConfig as SprykerSalesInvoiceConfig;
class SalesInvoiceConfig extends SprykerSalesInvoiceConfig
{
/**
* @api
*
* @return string
*/
public function getOrderInvoiceTemplatePath(): string
{
return 'SalesInvoice/Invoice/Invoice.twig';
}
}
Add oder invoice twig template. For example:
src/Pyz/Zed/SalesInvoice/Presentation/Invoice/Invoice.twig
{# @var order \Generated\Shared\Transfer\OrderTransfer #}
{# @var invoice \Generated\Shared\Transfer\OrderInvoiceTransfer #}
<!doctype html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0 " />
<title></title>
<style type="text/css">
body {
margin: 0;
padding: 0;
font-size: 16px;
box-sizing: border-box;
}
table {
max-width: 600px;
margin: 0 auto;
border-collapse: collapse;
}
.products-table {
border: 1px solid #000;
}
.products-table td,
.products-table th {
padding: 5px 10px;
}
.background-gray {
background: #e6e6e6;
}
.text-small {
font-size: 13px;
}
.spacing-bottom {
padding-bottom: 15px;
}
.spacing-right {
padding-right: 15px;
}
.align-top {
vertical-align: top;
}
.text-left {
text-align: left;
}
.text-center {
text-align: center;
}
</style>
</head>
<body>
<table>
<tr>
<td width="300" class="align-top">
<img src="" width="200" alt="Logo">
</td>
<td width="300">
<strong>{{ 'order_invoice.invoice_template.company.name' | trans }}</strong>
<div class="spacing-bottom text-small">{{ 'order_invoice.invoice_template.company.group' | trans }}</div>
<div class="spacing-bottom text-small">{{ 'order_invoice.invoice_template.company.address' | trans | raw }}</div>
</td>
</tr>
<tr>
<td width="300">
<div class="spacing-bottom spacing-right">
<strong>{{ 'order_invoice.invoice_template.merchant.name' | trans }}</strong>
<div class="text-small">{{ 'order_invoice.invoice_template.merchant.address' | trans }}</div>
</div>
<div class="spacing-bottom">
{{ order.billingAddress.firstName }} {{ order.billingAddress.lastName }}<br>
{{ order.billingAddress.address1 }} {{ order.billingAddress.address2 }} {{ order.billingAddress.address3 }}<br>
{{ order.billingAddress.zipcode }} {{ order.billingAddress.city }}<br>
{{ order.billingAddress.region }}
</div>
</td>
<td width="300" class="align-top">
<div class="spacing-bottom">{{ invoice.issueDate | date('d. M Y') }}</div>
</td>
</tr>
</table>
<table>
<tr>
<td width="600">
<div class="spacing-bottom">
<strong>{{ 'order_invoice.invoice_template.reference' | trans }} {{ invoice.reference }}</strong>
</div>
</td>
</tr>
<tr>
<td width="600">
<div class="spacing-bottom">{{ 'order_invoice.invoice_template.introduction' | trans }}</div>
</td>
</tr>
</table>
<table class="products-table">
<thead>
<tr class="background-gray">
<th width="75"><strong>{{ 'order_invoice.invoice_template.table.number' | trans }}</strong></th>
<th width="75"><strong>{{ 'order_invoice.invoice_template.table.quantity' | trans }}</strong></th>
<th width="275" class="text-left"><strong>{{ 'order_invoice.invoice_template.table.name' | trans }}</strong></th>
<th width="100"><strong>{{ 'order_invoice.invoice_template.table.tax' | trans }}</strong></th>
<th width="75"><strong>{{ 'order_invoice.invoice_template.table.price' | trans | raw }}</strong></th>
</tr>
</thead>
<tbody>
{% set linenumber = 0 %}
{% set renderedBundles = [] %}
{% set taxes = {} %}
{% set itemSumByTaxes = {} %}
{% for item in order.items %}
{# @var item \Generated\Shared\Transfer\ItemTransfer #}
{% set taxRate = item.taxRate %}
{% set rateSum = taxes[item.taxRate] | default(0) + item.sumTaxAmountFullAggregation %}
{% set taxes = taxes | merge({ (taxRate): rateSum }) %}
{% set rateItemSum = itemSumByTaxes[taxRate] | default(0) + item.sumPriceToPayAggregation %}
{% set itemSumByTaxes = itemSumByTaxes | merge({ (taxRate): rateItemSum }) %}
{% if item.productBundle is not defined or item.productBundle is null %}
{% set linenumber = linenumber + 1 %}
<tr>
<td class="text-center">{{ linenumber }}</td>
<td class="text-center">{{ item.quantity }}</td>
<td>{{ item.name }}</td>
<td class="text-center">{{ item.taxRate | number_format }}%</td>
<td class="text-center">{{ item.sumPriceToPayAggregation | money(true, order.currencyIsoCode) }}</td>
</tr>
{% endif %}
{% if item.productBundle is defined and item.productBundle is not null %}
{% if item.relatedBundleItemIdentifier not in renderedBundles %}
{# @var productBundle \Generated\Shared\Transfer\ItemTransfer #}
{% set linenumber = linenumber + 1 %}
{% set productBundle = item.productBundle %}
<tr>
<td class="text-center">{{ linenumber }}</td>
<td class="text-center">{{ productBundle.quantity }}</td>
<td>{{ productBundle.name }}</td>
<td class="text-center">{{ productBundle.taxRate | number_format }}%</td>
<td class="text-center">{{ productBundle.sumPriceToPayAggregation | money(true, order.currencyIsoCode) }}</td>
</tr>
{% for bundleditem in order.items %}
{% if item.relatedBundleItemIdentifier == bundleditem.relatedBundleItemIdentifier %}
<tr>
<td></td>
<td class="text-center">{{ bundleditem.quantity }}</td>
<td>{{ bundleditem.name }}</td>
<td class="text-center">{{ bundleditem.taxRate | number_format }}%</td>
<td class="text-center">{{ bundleditem.sumPriceToPayAggregation | money(true, order.currencyIsoCode) }}</td>
</tr>
{% endif %}
{% endfor %}
{% set renderedBundles = renderedBundles | merge([item.relatedBundleItemIdentifier]) %}
{% endif %}
{% endif %}
{% endfor %}
{% for expense in order.expenses %}
{% set linenumber = linenumber + 1 %}
{% set taxRate = expense.taxRate %}
{% set rateSum = taxes[expense.taxRate] | default(0) + expense.sumTaxAmount %}
{% set taxes = taxes | merge({ (taxRate): rateSum }) %}
{% set rateItemSum = itemSumByTaxes[taxRate] | default(0) + expense.sumPriceToPayAggregation %}
{% set itemSumByTaxes = itemSumByTaxes | merge({ (taxRate): rateItemSum }) %}
<tr>
<td class="text-center">{{ linenumber }}</td>
<td></td>
<td>{{ expense.name }}</td>
<td class="text-center">{{ expense.taxRate | number_format }}%</td>
<td class="text-center">{{ expense.sumPrice | money(true, order.currencyIsoCode) }}</td>
</tr>
{% endfor %}
<tr class="background-gray">
<td colspan="3"></td>
<td>{{ 'order_invoice.invoice_template.table.subtotal' | trans }}</td>
<td class="text-center">{{ order.totals.subtotal | money(true, order.currencyIsoCode) }}</td>
</tr>
<tr class="background-gray">
<td colspan="3"></td>
<td>{{ 'order_invoice.invoice_template.table.discount' | trans }}</td>
<td class="text-center">{{ order.totals.discountTotal | money(true, order.currencyIsoCode) }}</td>
</tr>
{% for rate, tax in taxes %}
<tr>
<td colspan="2">{{ 'order_invoice.invoice_template.table.tax.included' | trans({ '%tax_rate%': rate | number_format }) }}</td>
<td class="text-center">{{ (itemSumByTaxes[rate] - tax) | money(true, order.currencyIsoCode) }}</td>
<td class="text-center">{{ 'order_invoice.invoice_template.table.tax.name' | trans }}</td>
<td class="text-center">{{ tax | money(true, order.currencyIsoCode) }}</td>
</tr>
{% endfor %}
<tr>
<td colspan="2">{{ 'order_invoice.invoice_template.table.total.net' | trans }}</td>
<td class="text-center">{{ (order.totals.grandTotal - order.totals.taxTotal.amount) | money(true, order.currencyIsoCode) }}</td>
<td colspan="2"></td>
</tr>
<tr class="background-gray">
<td colspan="3"></td>
<td><strong>{{ 'order_invoice.invoice_template.table.grandtotal' | trans }}</strong></td>
<td class="text-center">{{ order.totals.grandTotal | money(true, order.currencyIsoCode) }}</td>
</tr>
</tbody>
</table>
</body>
</html>
The verification of the invoice template configuration will be checked in a later step.
4) Add Translations
An oms.state.
prefixed translation key is a combination of the OmsConfig::getFallbackDisplayNamePrefix()
and a normalized state machine name. If you have different OMS state-machine states or a fallback display name prefix, adjust the corresponding translations.
By default, in state machine names:
- Spaces are replaced with dashes.
- All the words are decapitalized.
Add translations as follows:
- Append glossary according to your configuration:
sales.error.customer_order_not_found,Customer Order not found.,en_US
sales.error.customer_order_not_found,Die Bestellung wurde nicht gefunden.,de_DE
sales.error.order_cannot_be_canceled_due_to_wrong_item_state,Order cannot be canceled due to wrong item state.,en_US
sales.error.order_cannot_be_canceled_due_to_wrong_item_state,Die Bestellung kann wegen dem falschen Artikelstatus nicht storniert werden.,de_DE
oms.state.new,New,en_US
oms.state.new,Neu,de_DE
oms.state.payment-pending,Payment pending,en_US
oms.state.payment-pending,Ausstehende Zahlung,de_DE
oms.state.invalid,Ivalid,en_US
oms.state.invalid,Ungültig,de_DE
oms.state.canceled,Canceled,en_US
oms.state.canceled,Abgebrochen,de_DE
oms.state.paid,Paid,en_US
oms.state.paid,Bezahlt,de_DE
oms.state.confirmed,Confirmed,en_US
oms.state.confirmed,Bestätigt,de_DE
oms.state.waiting,Waiting,en_US
oms.state.waiting,Warten,de_DE
oms.state.exported,Exported,en_US
oms.state.exported,Exportiert,de_DE
oms.state.shipped,Shipped,en_US
oms.state.shipped,Versandt,de_DE
oms.state.delivered,Delivered,en_US
oms.state.delivered,Geliefert,de_DE
quote_request.status.closed,Closed,en_US
quote_request.status.closed,Geschlossen,de_DE
mail.order_invoice.subject,"Invoice: %invoiceReference%",en_US
mail.order_invoice.subject,"Rechnung: %invoiceReference%",de_DE
- Import data:
console data:import:glossary
Ensure that, in the database, the configured data has been added to the spy_glossary
table.
5) Set up Behavior
Set up the following behaviors.
5.1) Set up Order Item Display Name
Plugin | Specification | Prerequisites | Namespace |
---|---|---|---|
CurrencyIsoCodeOrderItemExpanderPlugin |
Expands order items with currency codes (ISO). | None | Spryker\Zed\Sales\Communication\Plugin\Sales |
StateHistoryOrderItemExpanderPlugin |
Expands order items with history states. | None | Spryker\Zed\Oms\Communication\Plugin\Sales |
ItemStateOrderItemExpanderPlugin |
Expands order items with its item states. | None | Spryker\Zed\Oms\Communication\Plugin\Sales |
OrderAggregatedItemStateSearchOrderExpanderPlugin |
Expands orders with aggregated item states. | None | Spryker\Zed\Oms\Communication\Plugin\Sales |
src/Pyz/Zed/Sales/SalesDependencyProvider.php
<?php
namespace Pyz\Zed\Sales;
use Spryker\Zed\Sales\Communication\Plugin\Sales\CurrencyIsoCodeOrderItemExpanderPlugin;
use Spryker\Zed\Oms\Communication\Plugin\Sales\ItemStateOrderItemExpanderPlugin;
use Spryker\Zed\Oms\Communication\Plugin\Sales\OrderAggregatedItemStateSearchOrderExpanderPlugin;
use Spryker\Zed\Sales\SalesDependencyProvider as SprykerSalesDependencyProvider;
class SalesDependencyProvider extends SprykerSalesDependencyProvider
{
/**
* @return \Spryker\Zed\SalesExtension\Dependency\Plugin\OrderItemExpanderPluginInterface[]
*/
protected function getOrderItemExpanderPlugins(): array
{
return [
new CurrencyIsoCodeOrderItemExpanderPlugin(),
new StateHistoryOrderItemExpanderPlugin(),
new ItemStateOrderItemExpanderPlugin(),
];
}
/**
* @return \Spryker\Zed\SalesExtension\Dependency\Plugin\SearchOrderExpanderPluginInterface[]
*/
protected function getSearchOrderExpanderPlugins(): array
{
return [
new OrderAggregatedItemStateSearchOrderExpanderPlugin()
];
}
}
Ensure that:
- Every order item from the
SalesFacade::getOrderItems()
result contains:- Currency ISO code
- State history code
- Item state data
- Every order from the
SalesFacade::getCustomerOrders()
result contains aggregated item state data.
5.2) Set up Order Cancellation Behavior
Plugin | Specification | Prerequisites | Namespace |
---|---|---|---|
IsCancellableOrderExpanderPlugin | Checks if each order item has the cancellable flag. | None | Spryker\Zed\Sales\Communication\Plugin\Sales |
IsCancellableSearchOrderExpanderPlugin | Checks if each order item has the cancellable flag. | None | Spryker\Zed\Oms\Communication\Plugin\Sales |
src/Pyz/Zed/Sales/SalesDependencyProvider.php
<?php
namespace Pyz\Zed\Sales;
use Spryker\Zed\Sales\Communication\Plugin\Sales\CurrencyIsoCodeOrderItemExpanderPlugin;
use Spryker\Zed\Sales\SalesDependencyProvider as SprykerSalesDependencyProvider;
class SalesDependencyProvider extends SprykerSalesDependencyProvider
{
/**
* @return \Spryker\Zed\SalesExtension\Dependency\Plugin\SearchOrderExpanderPluginInterface[]
*/
protected function getSearchOrderExpanderPlugins(): array
{
return [
new IsCancellableSearchOrderExpanderPlugin(),
];
}
/**
* @return \Spryker\Zed\SalesExtension\Dependency\Plugin\OrderExpanderPluginInterface[]
*/
protected function getOrderHydrationPlugins(): array
{
return [
new IsCancellableOrderExpanderPlugin(),
];
}
}
Ensure that, on the following pages, each order contains the isCancellable
flag:
- The Storefront:
- Order History
- Overview
- The Back Office:
- Overview of Orders
5.3) Set up Order Invoice Generation Behavior
5.3.1) Setup Order Invoice Mail Type
Plugin | Specification | Prerequisites | Namespace |
---|---|---|---|
OrderInvoiceMailTypePlugin |
An email type that prepares invoice email for an order. | cell | cell |
src/Pyz/Zed/Mail/MailDependencyProvider.php |
<?php
namespace Pyz\Zed\Mail;
use Spryker\Zed\Kernel\Container;
use Spryker\Zed\Mail\Business\Model\Mail\MailTypeCollectionAddInterface;
use Spryker\Zed\Mail\Business\Model\Provider\MailProviderCollectionAddInterface;
use Spryker\Zed\Mail\MailDependencyProvider as SprykerMailDependencyProvider;
use Spryker\Zed\SalesInvoice\Communication\Plugin\Mail\OrderInvoiceMailTypePlugin;
class MailDependencyProvider extends SprykerMailDependencyProvider
{
/**
* @param \Spryker\Zed\Kernel\Container $container
*
* @return \Spryker\Zed\Kernel\Container
*/
public function provideBusinessLayerDependencies(Container $container)
{
$container = parent::provideBusinessLayerDependencies($container);
$container->extend(static::MAIL_TYPE_COLLECTION, function (MailTypeCollectionAddInterface $mailCollection) {
$mailCollection
->add(new OrderInvoiceMailTypePlugin());
return $mailCollection;
});
return $container;
}
}
5.3.2) Set up Order Invoice OMS Command
Plugin | Specification | Prerequisites | Namespace |
---|---|---|---|
GenerateOrderInvoiceCommandPlugin |
A command in OMS state machine, that generates invoice for order. | None | Spryker\Zed\SalesInvoice\Communication\Plugin\Oms |
src/Pyz/Zed/Oms/OmsDependencyProvider.php
<?php
namespace Pyz\Zed\Oms;
use Spryker\Zed\Kernel\Container;
use Spryker\Zed\Oms\Dependency\Plugin\Command\CommandCollectionInterface;
use Spryker\Zed\Oms\OmsDependencyProvider as SprykerOmsDependencyProvider;
use Spryker\Zed\SalesInvoice\Communication\Plugin\Oms\GenerateOrderInvoiceCommandPlugin;
class OmsDependencyProvider extends SprykerOmsDependencyProvider
{
/**
* @param \Spryker\Zed\Kernel\Container $container
*
* @return \Spryker\Zed\Kernel\Container
*/
protected function extendCommandPlugins(Container $container): Container
{
$container->extend(static::COMMAND_PLUGINS, function (CommandCollectionInterface $commandCollection) {
$commandCollection->add(new GenerateOrderInvoiceCommandPlugin(), 'Invoice/Generate');
return $commandCollection;
});
return $container;
}
}
5.3.3) Set up Order Invoice OMS Command
Plugin | Specification | Prerequisites | Namespace |
---|---|---|---|
OrderInvoiceSendConsole |
A console command that sends not-yet-sent order invoices via email. | None | Spryker\Zed\SalesInvoice\Communication\Console |
src/Pyz/Zed/Oms/OmsDependencyProvider.php
<?php
namespace Pyz\Zed\Oms;
use Spryker\Zed\Console\ConsoleDependencyProvider as SprykerConsoleDependencyProvider;
use Spryker\Zed\Kernel\Container;
use Spryker\Zed\SalesInvoice\Communication\Console\OrderInvoiceSendConsole;
class ConsoleDependencyProvider extends SprykerConsoleDependencyProvider
{
/**
* @param \Spryker\Zed\Kernel\Container $container
*
* @return \Symfony\Component\Console\Command\Command[]
*/
protected function getConsoleCommands(Container $container): array
{
$commands = [
new OrderInvoiceSendConsole(),
];
return $commands;
}
}
Adjust scheduler project configuration: config/Zed/cronjobs/jenkins.php
/* Order invoice */
$jobs[] = [
'name' => 'order-invoice-send',
'command' => '$PHP_BIN vendor/bin/console order:invoice:send',
'schedule' => '*/5 * * * *',
'enable' => true,
'stores' => $allStores,
];
To apply scheduler configuration update, run next commands:
vendor/bin/console scheduler:suspend
vendor/bin/console scheduler:setup
vendor/bin/console scheduler:resume
Once all invoice related configuration was set up, ensure that the right order invoice template was assigned to the order (spy_sales_order_invoice
) after moving at least 1 item in the order to invoice generated
state based on your DummyInvoice01.xml
and SalesInvoiceConfig::getOrderInvoiceTemplatePath()
configuration.
The email with the invoice based on the configured invoice template should be sent to the email address of the order’s customer within the scheduled (5 mins) time.
Install Feature Front End
Follow the steps below to install the feature front end.
Prerequisites
Overview and install the necessary features before beginning the integration step.
Name | Version |
---|---|
Spryker Core | 202005.0 |
1) Install the required modules using Composer
Run the following command(s) to install the required modules:
composer require spryker-feature/order-management: "202005.0" --update-with-dependencies
2) Add Translations
Add translations as follows:
- Append glossary according to your configuration:
order_cancel_widget.cancel_order,Cancel Order,en_US
order_cancel_widget.cancel_order,Bestellung stornieren,de_DE
order_cancel_widget.order.cancelled,Order was canceled successfully.,en_US
order_cancel_widget.order.cancelled,Die Bestellung wurde erfolgreich storniert.,de_DE
- Import data:
console data:import:glossary
Ensure that, in the database, the configured data has been added to the spy_glossary
table.
3) Enable Controllers
Register the following route provider(s) on the Storefront:
Provider | Namespace |
---|---|
OrderCancelWidgetRouteProviderPlugin |
SprykerShop\Yves\OrderCancelWidget\Plugin\Router |
src/Pyz/Yves/Router/RouterDependencyProvider.php
<?php
namespace Pyz\Yves\Router;
use Spryker\Yves\Router\RouterDependencyProvider as SprykerRouterDependencyProvider;
use SprykerShop\Yves\OrderCancelWidget\Plugin\Router\OrderCancelWidgetRouteProviderPlugin;
class RouterDependencyProvider extends SprykerRouterDependencyProvider
{
/**
* @return \Spryker\Yves\RouterExtension\Dependency\Plugin\RouteProviderPluginInterface[]
*/
protected function getRouteProvider(): array
{
return [
new OrderCancelWidgetRouteProviderPlugin(),
];
}
}
Ensure that the yves.mysprykershop.com/order/cancel
route is available for POST requests.
4) Set up Behavior
Set up the following behaviors.
4.1) Set up Order Cancellation Behavior
Plugin | Specification | Prerequisites | Namespace |
---|---|---|---|
OrderCancelButtonWidget |
Shows a Cancel button on the Storefront. | None | SprykerShop\Yves\OrderCancelWidget\Widget |
src/Pyz/Yves/ShopApplication/ShopApplicationDependencyProvider.php
<?php
namespace Pyz\Yves\ShopApplication;
use SprykerShop\Yves\OrderCancelWidget\Widget\OrderCancelButtonWidget;
use SprykerShop\Yves\ShopApplication\ShopApplicationDependencyProvider as SprykerShopApplicationDependencyProvider;
class ShopApplicationDependencyProvider extends SprykerShopApplicationDependencyProvider
{
/**
* @return string[]
*/
protected function getGlobalWidgets(): array
{
return [
OrderCancelButtonWidget::class,
];
}
}
Ensure that:
- The
OrderCancelButtonWidget
widget has been registered. - The Cancel button is displayed on the Order Details page on the Storefront.
4.2) Set up Order Item Display Names
Ensure that:
- You can see the aggregated order item states in the item state table column on the Customer Overview and Order History pages on the Storefront;
- Aggregated return item states are displayed on the Return Page on the Storefront.
- Item states are displayed on the Order Details and Return Details pages on the Storefront.
Thank you!
For submitting the form