Baike.dev
All toolsAI codingTrendingOpen sourceNewsSubmit
Log in
Back to tool/Back to issues
#19238·Sylius

[AdminBundle] Order show page renders payment and shipment states through the order-level state macros, producing wrong badge colours

Author: DarkorzerarkoCreated Sep 16, 2026Updated Sep 16, 2026
LabelsPotential Bug

Sylius version(s) affected

All 2.X

Description

The order show page renders the state of each individual payment and shipment using macros written for a different state machine graph.

src/Sylius/Bundle/AdminBundle/templates/order/show/content/sections/payments/item/state.html.twig:

twig
{% from '@SyliusAdmin/order/macro/order_payment_state_label.html.twig' import label %}

{% set payment = hookable_metadata.context.payment %}

<td class="w-1" {{ sylius_test_html_attribute('payment-state') }}>
    {{ label(payment.state) }}
</td>

payment.state belongs to the sylius_payment graph (Sylius\Component\Payment\Model\PaymentInterface), but order_payment_state_label.html.twig maps badge colours from Sylius\Component\Core\OrderPaymentStates — the order-level aggregate graph (sylius_order_payment). The two graphs share only three state names.

The same mismatch exists for shipments in .../sections/shipments/item/state.html.twig, which passes shipment.state (sylius_shipment graph) to order_shipping_state_label.html.twig (OrderShippingStates).

Only three macros exist under src/Sylius/Bundle/AdminBundle/templates/order/macro/, and all three are for order-level graphs — there is no per-payment or per-shipment equivalent, so the closest-named macro appears to have been picked during the 2.x rewrite.

The mismatch is silent because of the |default('') in the macro:

twig
<span class="badge {{ state_badge[state]|default('') }}" ...>

Any state that is not a key of the order-level map falls through to an unstyled grey badge instead of raising an error. The label text itself is correct, since it is built from 'sylius.ui.' ~ state and those translation keys all exist in UiBundle/Resources/translations/messages.en.yml.

The colours are already defined correctly elsewhere

Sylius already ships correct per-graph colour maps, used by the Payments and Shipments grids (AdminBundle/Resources/config/grids/payment.yml:47):

  • src/Sylius/Bundle/AdminBundle/templates/shared/grid/field/payment_state.html.twig
  • src/Sylius/Bundle/AdminBundle/templates/shared/grid/field/shipment_state.html.twig

So the very same payment gets two different badge colours depending on where an administrator looks at it:

sylius_payment state Payments grid (correct) Order show page (current)
cart bg-lime-lt — grey
new — grey — grey
processing bg-indigo-lt — grey
authorized bg-orange-lt bg-indigo-lt
completed bg-green-lt — grey
failed bg-red-lt — grey
cancelled bg-yellow-lt bg-orange-lt
refunded bg-purple-lt bg-purple-lt
unknown not mapped — grey

The screenshots below show one order with one payment in each state from new to refunded, first on the order show page and then in the Payments grid filtered to that order's channel:

Order show page, Payments section: New, Processing, Completed and Failed are grey, Authorized is indigo, Cancelled is orange

Image

Payments grid, same payments: Processing indigo, Authorized orange, Completed green, Failed red, Cancelled yellow

Image

Shipments show the same inconsistency, limited to the cancelled state:

sylius_shipment state Shipments grid (correct) Order show page (current)
cart — grey — grey
ready bg-blue-lt bg-blue-lt
shipped bg-green-lt bg-green-lt
cancelled bg-red-lt bg-orange-lt

The same order has one shipment each in ready, shipped and cancelled:

Order show page, Shipments section: Cancelled is orange

Image

Shipments grid, same shipments: Cancelled is red

Image

Two distinct problems fall out of this:

  1. The two most operationally important payment states lose their colour entirely. completed and failed both render as identical unstyled grey badges on the order show page (rows 4 and 5 of the first screenshot), so a successful and a failed payment are visually indistinguishable at a glance. processing is likewise grey.
  2. authorized and cancelled are not merely uncoloured — they are given a colour that means something else. authorized renders indigo, which in the Payments grid means processing; cancelled renders orange, which in the order-level map means cancelled but in the payment grid is authorized. Shipment cancelled renders orange instead of red. This is a worse failure mode than the grey fallback, because the badge looks deliberate.

Test attribute leakage

The macros hardcode their own test attributes, which are for the order-level badges:

twig
<span class="badge ..." {{ sylius_test_html_attribute('order-payment-state') }}>

Because the item templates already wrap the macro output in data-test-payment-state / data-test-shipment-state, every payment row on the order show page also emits a nested data-test-order-payment-state, and every shipment row a nested data-test-order-shipping-state. The order-level badges in src/Sylius/Bundle/AdminBundle/templates/order/show/content/sections/payments/header/state.html.twig and src/Sylius/Bundle/AdminBundle/templates/order/show/content/sections/shipments/header/state.html.twig do the same, so the attribute is duplicated there as well.

src/Sylius/Behat/Page/Admin/Order/ShowPage.php:408-409 selects the order aggregate state with exactly those selectors:

php
'order_payment_state' => '[data-test-order-payment-state]',
'order_shipping_state' => '[data-test-order-shipping-state]',

These currently resolve to the right element only because the section header precedes the item rows in the DOM and Mink returns the first match. The selector is ambiguous and will break if the sections are ever reordered or a hook injects content above them.

How to reproduce

  1. Install Sylius 2.2 with the standard fixtures.
  2. Place an order and take its payment through to completed (Admin → Orders → (order) → Payments → Complete).
  3. Look at the payment's state badge in the Payments section of the order show page — it is an unstyled grey badge.
  4. Open Admin → Payments and find the same payment in the grid — the badge is green.
  5. Repeat with a payment moved to failed: grey on the order show page, red in the grid.
  6. For the shipment case, cancel an order and compare the shipment badge on the order show page (orange) with Admin → Shipments (red).

Viewing the page source also shows the duplicated attribute on each row:

xml
<td data-test-payment-state="">
    <span class="badge " data-test-order-payment-state="">Completed</span>
</td>

Possible Solution

Add the two missing macros alongside the existing order-level ones and point the item templates at them:

  • @SyliusAdmin/order/macro/payment_state_label.html.twig — keyed on Sylius\Component\Payment\Model\PaymentInterface::STATE_*
  • @SyliusAdmin/order/macro/shipment_state_label.html.twig — keyed on Sylius\Component\Shipping\Model\ShipmentInterface::STATE_*

with sylius_test_html_attribute('payment-state') / ('shipment-state') inside, and the outer attribute removed from the item templates so it is not emitted twice.

The colour values should be taken from the existing grid templates so the two views agree. Given that the colour map would then exist in two places per graph, it may be worth having the grid field templates render through the same macros, which would remove the duplication rather than double it — though that is a slightly wider change and I am happy to keep the PR narrow if the team prefers.

Two smaller decisions to confirm:

  • The grid templates use plain string keys (completed: { color: ... }) while the order macros use constant(...) lookups. The macro convention seems preferable for new macros, but it is worth being explicit about which is intended.
  • unknown is a valid place in the sylius_payment graph but is absent from shared/grid/field/payment_state.html.twig, which — unlike the macros — has no |default on the lookup. Whatever the decision on the main fix, that state should be added to the map.

I am happy to open a PR once the preferred shape is confirmed.

Additional Context

  • Affected templates:

    • src/Sylius/Bundle/AdminBundle/templates/order/show/content/sections/payments/item/state.html.twig
    • src/Sylius/Bundle/AdminBundle/templates/order/show/content/sections/shipments/item/state.html.twig
  • Macros involved (order-level, correct for their own use sites):

    • src/Sylius/Bundle/AdminBundle/templates/order/macro/order_payment_state_label.html.twig
    • src/Sylius/Bundle/AdminBundle/templates/order/macro/order_shipping_state_label.html.twig
  • Existing correct colour maps: src/Sylius/Bundle/AdminBundle/templates/shared/grid/field/payment_state.html.twig, .../shipment_state.html.twig

  • State machine definitions: src/Sylius/Bundle/PaymentBundle/Resources/config/app/state_machine/sylius_payment.yaml (places: cart, new, processing, authorized, completed, failed, cancelled, unknown, refunded)

  • Behat selectors affected: src/Sylius/Behat/Page/Admin/Order/ShowPage.php:79, :116, :408-409

  • Card header templates (not affected by the colour bug):

    • src/Sylius/Bundle/AdminBundle/templates/order/show/content/sections/payments/header/state.html.twig
    • src/Sylius/Bundle/AdminBundle/templates/order/show/content/sections/shipments/header/state.html.twig

    They render the order-wide badge in the top-right corner of the Payments and Shipments cards ("Partially Paid" / "Partially Shipped" in the screenshots). They pass order.paymentState / order.shippingState, which belong to the order-level graphs the macros were written for, so their colours are correct. Their only problem is that both their wrapping <span> and the macro's badge emit data-test-order-payment-state (or data-test-order-shipping-state), so the attribute appears twice, nested.

Source: Sylius/Sylius

View original on GitHubView discussion on GitHub