How can we set custom fields per cart line item?

Hello,

Does anynone knows how can we set a custom field for a line item?

We notice that we can set per Payment, Shipping, …but not for a cart line item. 

We checked ‚Shopware\Core\Checkout\Cart\LineItem‘ but there are no setter/getter and no variable.

We need to save additional data to cart line item and we want this data to be persistent within order line items too.

Does anyone knows how to achieve that? Maybe by extending Shopware\Core\Checkout\Cart\LineItem and implement there setter/getter. We notice that ‚order_line_item‘ table does have a ‚custom_fields‘ field. 

Any help would be appreciated.

 

Best regards,

Sorin

push

Good question, any solution? 

If i use Javascript fetch and the Shopware 6 - Sales-Channel API with  POST  /sales-channel-api/v1/checkout/cart/product/{id} from the Documentation* to add products. But there is no example or explenation how to use the payload or how it sould look like to set/write the customFields?

To get/read the customFields this works fine:

fetch(serverUrl + '/sales-channel-api/v1/product/' + id + '?associations[properties][]', {
    'method': 'GET',
    'headers': getHeadersWithToken(false)
})...

regards, mii

* Documentation: https://docs.shopware.com/en/shopware-platform-dev-en/api/sales-channel-cart-api?category=shopware-platform-dev-en/api

Achieving this in the current state of shopware 6 seems to be quite a tedious task.

I was surprised this was rather difficult to achieve as it seems quite a common use case when working with eCommerce frameworks, especially within the enterprise sector.

To be able to store information on order item level I had to do the following (for sure this might not be best practice but it works, maybe it will help somebody):

  1. Find a way to add custom data to your cart (line) items.

Line items are stored inside the cart table, to be specific in a serialized form inside the cart column.
(This implementation for sure raises some questions but it is what it is, I guess)

You want to find a way to add custom data to the line items stored there. In my case I rewrote the CartLineItemController (\Shopware\Storefront\Controller\CartLineItemController::addLineItems) to store additional data on line item level.

  1. Create a new Struct class (inheriting from \Shopware\Core\Framework\Struct\Struct) that will then be used to extend a line item (at the point where you add your custom data).

  2. Add your custom data to the line item via your newly created custom struct. It works like this:

$lineItem->addExtension(‘my_custom_struct’, new MyCustomStruct($myCustomData));

  1. Finally, as the custom data is now stored inside the cart item you want to make sure it gets copied to the order line items (table order_line_item) when the order gets placed.
    For that further rewriting is required.
    I rewrote \Shopware\Core\Checkout\Cart\Order\Transformer\LineItemTransformer::transform for this.
    You can utilize custom fields as per documentation (https://docs.shopware.com/en/shopware-platform-dev-en/internals/core/data-abstraction-layer/custom-field), as they are supported for order line items.

if ($lineItem->getExtension(‘my_custom_struct’)) {
    $myCustomFieldData = [‘my_custom_field’ => $lineItem->getExtension(‘my_custom_struct’)->getMyCustomData()];
}

$data = [
    ‘id’ => $id,
    ‘identifier’ => $lineItem->getId(),
    ‘productId’ => $productId,
    …
    ‘customFields’ => $myCustomFieldData
];

That’s it. The custom data is now stored inside a custom field on the order line item and is accessible as per documentation. 

1 „Gefällt mir“

The CartLineItems have a property named payload where product custom fields and such things are stored within. In my case I used the LineItemAddedEvent to modify this payload.

e.g.

    /**
     * @param LineItemAddedEvent $event
     * @throws \Shopware\Core\Checkout\Cart\Exception\InvalidPayloadException
     */
    public function onLineItemAdded(LineItemAddedEvent $event): void
    {
        $lineItem = $event->getLineItem();
        foreach ($this->requestStack->getCurrentRequest()->get('lineItems') as $key => $item) {
            if ($lineItem->getId() == $key && isset($item['anotherCartFormValue'])) {
                $lineItem->setPayloadValue('anotherCartFormValue', $item['anotherCartFormValue']);
            }
        }

        // or do some other stuff with the payload
    }

This payload will be used in any step of the checkout without getting overwritten anymore, and is stored in the cart table.

4 „Gefällt mir“

hi

is it possible to display this updated payload in order line item in admin ?

1 „Gefällt mir“

@mowlwurf schrieb:

The CartLineItems have a property named payload where product custom fields and such things are stored within. In my case I used the LineItemAddedEvent to modify this payload.

Wow, how could I miss this. The payload approach is definitely less obtrusive and a lot easier to implement.

is it possible to display this updated payload in order line item in admin ?

Yes. It comes with the order line item. You can display it in the backend by overwriting e.g. sw-order-detail-base.html.twig like this (might not look pretty, but you get the idea):

{% block sw_order_detail_base__user_card %}
    
        
            {{ lineItem.payload.myCustomPayload }}
        
    
    {% parent %}
{% endblock %}

 

1 „Gefällt mir“

Thanks for the pointers.

Another way to display it in the order-line-items-grid. Don’t know yet if there are any sideeffects though.

In e. g. ./MyPlugin/src/Resources/app/administration/src/main.js

const { Component } = Shopware;

Component.override('sw-order-line-items-grid', {
    computed: {

        getLineItemColumns() {
            const columns = this.$super('getLineItemColumns');

            columns.push({
                property: 'payload.myCustomPayload',
                dataIndex: 'payload.myCustomPayload',
                label: 'myCustomPayload',
                allowResize: false,
                primary: false,
                inlineEdit: false,
                width: '200px'
            });

            return columns;
        }
    }
});

 

1 „Gefällt mir“

Hi!
does anyone know if is it possibile to create a new rule for the builder based on custom values stored in this cart line item payload?

thanks

@mowlwurf

Thank you so much!