Hinzugefügter Wert im Cart LineItem Payload wird nicht an E-Mail Template durchgereicht

Hallo,
ich möchte gerne in meinem Subscriber den Cart LineItem Payload mit eigenen Werten erweitern. Nachdem ich das Produkt dem Warenkorb hinzugefügt habe, erscheinen diese auch im Debugging im Payload. Leider gehen diese dann auf dem Weg zum Mail-Template verloren.
Ich benutze im Moment die die SW 6.4.14.0

    public static function getSubscribedEvents(): array
    {
        return [
            AfterLineItemAddedEvent::class => 'afterLineItemAdded',
            MailBeforeValidateEvent::class => 'mailBeforeSent',
        ];
    }  

Hier werden die Werte hinzugefügt und können im Debugger im Objekt gesehen werden:

public function afterLineItemAdded(AfterLineItemAddedEvent $event)
    {
        // liefert alle im Warenkorb befindlichen LineItems
        $cartLineItems = $event->getCart()->getLineItems(); // Shopware\Core\Checkout\Cart\LineItem\LineItemCollection
        
        foreach ($cartLineItems as $lineItem) {
            $packUnits = array("packUnit"=>"Karton", "packUnitPlural"=>"Kartons");
            $lineItem->setPayloadValue("packUnits", $packUnits);
        }
    }

und hier sind diese Werte „verloren gegangen“. Die neuen Werte im Payload tauchen in $data nicht mehr auf

public function mailBeforeSent(MailBeforeValidateEvent $event)
    {
        $data = $event->getTemplateData();
        error_log(print_r($data, true)."\n", 3, getcwd().'/data_getTemplateData.log');
    }
  1. Kann es sein, dass es das LineItemAddedEvent nicht mehr gibt? Ich habe nur die Before- und AfterLineItemAdded-Events gefunden.
  2. Weiss jemand was ich falsch mache oder kann mir vielleicht jemand zum Problem einen Tipp geben?

Vielen Dank
Beste Grüsse
Andreas

Wenn das ein After-Event ist, dann wird was du dort einträgst eventuell gar nicht übernommen, bzw. ins Mail-Template kommt wahrscheinlich nur was auch in der Datenbank steht.

Die Einträge im Admin-Bereich Kataloge → Produkte → (Produkt) Bearbeiten → Spezifikation → Verpackungseinheit & Verpackungseinheit-Mehrzahl werden in die Tabelle product_translation als pack_unit & pack_unit_plural gespeichert, und stehen im Template über (Twig) product.translated.packUnit & product.translated.packUnitPlural zur Verfügung.

Hallo FritzPerson, vielen Dank für deine Antwort :slight_smile:
Wenn ich mich nicht irre, dann habe ich im Mail-Template (Bestätigungs-Mail) nur Zugriff auf das order-Objekt inklusive dazugehörigen Payload. Ich kann auf das Feld product.translated.packUnit nur auf page-Objekt Ebene zugreifen und nicht im Mail-Template, oder doch? Wenn ich aber z.B. ein Zusatzfeld im Produkt anlege dann wird das bis in die Order durchgeschleift und ich kann mittels lineItem.payload.customFields.name_zusatzfeld auf das Zusatzfeld zugreifen. Das funktioniert einwandfrei. Ich möchte aber nach Möglichkeit auf das Zusatzfeld verzichten und stattdessen das Feld Verpackungseinheit aus der Produkt-Spezifikation in meiner Bestätigungs-Email verwenden. Auf das von Dir vorgeschlagene Feld product.translated.packUnit kann ich in dem Mail-Template nicht zugreifen. Oder verstehe ich hier irgendetwas falsch?
Nachtrag: In der Tabelle order_line_item wird im Feld Payload der Payload der Order gespeichert. Aus irgendwelchen Gründen wird meine programmatische Erweiterung des Payloads nicht dort gespeichert und ich weiss nicht warum.

@AndiMu Ich dachte man käme über LineItem an Product, aber das geht anscheinend im Template nicht. Habe es eben probiert, z.B. auch order.lineItems.first.product.packUnit.

Wenn du trotzdem irgendwo einen Wert hast, an dem abhängt ob Karton oder Kartons in der Mail stehen soll, dann könntest du eventuell auch ein Twig if/else/endif ins Template einbauen, also z.B:

{% if lineItem.quantity > 1 %}
Kartons
{% else %}
Karton
{% endif %}

Guten Morgen FritzPerson,
ich danke Dir für deinen Vorschlag. Leider ist dieser nicht anwendbar, da ich mich nicht darauf verlassen kann, dass sich die Verpackungseinheit auf Produktebene nicht unterscheiden kann. Ich werde also weiter tüfteln und hier hoffentlich (irgendwann :slight_smile: ) eine fertige Lösung bereitstellen.

@AndiMu: Ah OK, vielleicht wäre dann noch eine Option: Add data to mails - Shopware Developer

Ich denke theoretisch könnte man sogar das bestehende templateData-Array erweitern, ja nachdem was schon drin steht.

Vielen Dank für deinen Hinweis auf Add data to mails - Shopware Developer.
Wenn ich das Event MailBeforeValidateEvent und z.B. den Code

$data = $event->getTemplateData();
$data["testKey"] = "Ich bin ein Test";
$event->setTemplateData($data);

verwende, dann kann ich auf dieses Feld im Mail-Template mittels {{ testKey }} zugreifen. Das ähnelt dem Add data to mails - Shopware Developer Vorgehen.

Die Herausforderung ist jedoch, dass ich, bezogen auf meine LineItems, unterschiedliche Angaben im Payload haben möchte/könnte. Im unwahrscheinlichsten Fall könnte ich z.B. zehn Produkte mit zehn unterschiedlichen Verpackungseinheiten haben. Und diese möchte ich gerne hinter der gewünschten Menge in der Bestätigungs-Mail ebenfalls aufzeigen.
Als Hilfe benutze ich im Moment ein Custom_Field im Produkt um die Verpackungseinheit zu hinterlegen. Das Feld wird nämlich anstandslos bis in die Order mitgenommen. Darauf kann ich auch im Mail-Template einfach zugreifen.

Ich werde weiter tüfteln un danke Dir :slight_smile:

@AndiMu, dein Vorgehen mit dem CustomField klingt für mich zumindest als sei es die beste Lösung.

Wegen der Typisierung in PHP könntest du theoretisch schon jedes Objekt in $data anpassen. Z.B. mit einer eigenen Klasse die von OrderLineItemEntity erbt und eigene Variablen enthält, also bspw. MyOrderLineItemEntity mit einer Variable public string $myString. Dann könntest du in MailBeforeValidateEvent so etwas machen:

/** @var MyOrderLineItemEntity $lineItem */
foreach ($data['order']['lineItems'] as $lineItem) { // nicht sicher ob $data['order']['lineItems'] richtig ist
    $lineItem->myString = "test";
}

Aber ich weiß nicht wie sinnvoll das ist, und es wird auch bei jeder Mail gemacht.

Hallo @AndiMu, wenn dein Payload der LineItem hinzugefügt worden ist, und dieser auch in der DB gespeichert wird (order_line_items), dann kannst du im E-Mail Template mit {{ nestedItem.payload.PAYLOADNAME }} auf den Payload zugreifen.

So wie ich dich verstanden habe, wird dein Payload aber nicht in der DB gespeichert?
Da du auf das Event AfterLineItemAddedEvent lauschst, müsstest du den Cart noch persistieren, damit deine Änderungen übernommen werden. Wenn du den BeforeLineItemAddedEvent verwendest, sollte dein Payload auch in der DB gespeichert werden.

vg

@FritzPerson Auf den ersten Blick würde ich sagen, das dies vielleicht auch ein gangbarer Weg für die Erweiterung des Payloads mit Mail-Template Ausgabe wäre. Vielen Dank für deinen Input :slight_smile:

@abdullah Der Wechsel auf das BeforeLineItemAddedEvent hat mir die Lösung gebracht. Der Payload wird jetzt persistiert (Tab. order_line_item) und ich kann wie von Dir beschrieben auf die Felder in meinem Mail-Template zugreifen. Vielen Dank für deine Hilfe :slight_smile:

Ich werde auf jeden Fall hier noch die Lösung dokumentieren.

Schönen Tag euch Beiden und beste Grüsse
Andreas

Für diejenigen die es interessiert, ist hier meine Lösung:

private EntityRepository $productRepository;

public function __construct(EntityRepository $productRepository)
    {
        $this->productRepository = $productRepository;
    }

public static function getSubscribedEvents(): array
    {
        return [
            BeforeLineItemAddedEvent::class => 'beforeLineItemAdded'
        ];
    }

public function beforeLineItemAdded(BeforeLineItemAddedEvent $event)
    {
      
        // liefert neu hinzugefügtes LineItem im Warenkorb
        $lineItem = $event->getLineItem(); // Shopware\Core\Checkout\Cart\LineItem\LineItem

        $criteria = new Criteria();
        $criteria->addFilter(new EqualsFilter('id', $lineItem->getId()));
        $criteria->setLimit(1);
        
        // Hole Produkt-Datensatz zum LineItem
        $products = $this->productRepository->search($criteria, $event->getContext()); // Shopware\Core\Framework\DataAbstractionLayer\Search\EntitySearchResult
        
        foreach ($products as $product) // $product = Shopware\Core\Content\Product\ProductEntity
        { 
            // Checke packUnit-Felder für das LineItem
            if (($product->getPackUnit() !== null) && ($product->getPackUnitPlural() !== null)){
                $packUnits = array("packUnit"=>$product->getPackUnit(), "packUnitPlural"=>$product->getPackUnitPlural());
                $lineItem->setPayloadValue("packUnits", $packUnits);
            }
        }
    }

Der Zugriff im HTML-Template erfolgt über {{ nestedItem.payload.packUnits.packUnit }} oder {{ nestedItem.payload.packUnits.packUnitPlural }}
Der Zugriff im TXT-Template erfolgt bei mir über {{ lineItem.payload.packUnits.packUnit }} oder {{ lineItem.payload.packUnits.packUnitPlural }}

Beste Grüsse
Andreas

Hallo Andreas,

hast Du für diese erweiterung ein Plugin erstellt?

Gruß
Markus

Hallo Markus,

vielleicht hilft Dir das als Starter:

Beste Grüsse
Andreas

Hallo Adreas,

danke schön, für das bereitstellen vom Plugin.

Grüße
Markus