Inhalte aufrufen

Profilbild
- - - - -

Zusätzliche Daten in Order übernehmen

Datenbank Events

  • Bitte melden Sie sich an, um eine Antwort zu verfassen.
12 Antworten zu diesem Thema

#1 Algorithman

Algorithman

    Advanced Member

  • Members
  • PunktPunktPunkt
  • 39 Beiträge

Geschrieben: 12 May 2023 - 10:35

Guten Morgen,

 

 

ich versuche gerade, unsere zusätzlichen (variablen, vom Kunden änderbaren) Zusatzfelder (z.B: Gravur) in die Order zu übernehmen.

 

Momentan habe ich 3 zusätzliche Tabellen:
AdditionalProductData (Standard-Werte für das Produkt)

AdditionalBasketData (die vom Kunden geänderten Werte)

und

AdditionalOrderData, in der die geänderten Werte aus dem Warenkorb dann in die Order übernommen werden sollen.

 

Um die Daten in die AdditionalOrderData zu schreiben zu können, brauche ich natürlich irgendeinen Einsprungpunkt.

Gefunden habe ich folgendes:

Event OrderPlacedEvent (hat leider nur die Referenz auf die Order als Parameter und ist ausserdem zu spät, da in der Order-EMail die Daten auch stehen sollen, die ein paar Zeilen weiter oben mit FinalizeOrderPlacement angestossen wird)

 

Wäre es möglich einen zusätzlichen Event einzufügen, der z.B. in OrderProcessingService.PlaceOrder.cs das CartItem und das neu hinzugefügte OrderItem als Parameter übergeben?
Dann kann ich über die alte ShoppingCartItem Id und die GUID im OrderItem eine eindeutige Zuordnung vornehmen und die GUID zurückschreiben in meine Cart-Daten (denn die OrderItems sind zu dem Zeitpunkt noch nicht geschrieben OrderProcessingService.PlaceOrder.cs#L80).

Wenn es da eine bessere Methode gibt (inkl der Moglichkeit ShoppingCartItem Id <-> OrderItem Id zu referenzieren), ich bin offen für Vorschläge.

 

 

Wo es besser gelöst wurde:

Wenn man als Gast etwas in den Warenkorb legt und sich dann einloggt wird der Warenkorb migriert.

Die alten sowie die neuen Warenkorbpositionen sind in die Datenbank geschrieben wenn der Event MigrateShoppingCartEvent ausgelöst wird. Das macht es mir einfach auch meine Daten zu migrieren.

 

 

Beste Grüße

 

Chris



#2 Mark Wördenweber

Mark Wördenweber

    Smartstore Moderator

  • Administrators
  • 5 Beiträge

Geschrieben: 15 May 2023 - 10:37

Hey,

 

Kannst du erklären, warum OrderPlacedEvent für deine Zwecke nicht ausreicht? Welche Informationen fehlen?

Die E-Mail kann so abgefangen und manipuliert werden:

// Event handler to prepare a message model.
public void HandleEvent(MessageModelCreatedEvent message, IWorkContext workContext, IStoreContext storeContext)
{
    // If this is not the correct template, return.
    if (message.MessageContext.MessageTemplate.Name != MessageTemplateNames.OrderPlacedCustomer)
        return;

    dynamic model = message.Model;

    // If no order was attached, return.
    if (model.Order == null)
        return;

    // Add the model data to the message using a Dictionary.
    model.MyModel = new Dictionary<string, object>
    {
        ["OrderId"] = model.Order.ID,
    };

    // Rendering occurs in ZoneRenderingEvent.
}

// Event handler to inject content into a message.
public void HandleEvent(ZoneRenderingEvent message)
{
    // If this is not the message body or the correct template, return.
    if (!message.ZoneName.Equals("body_after") || message.TemplateName != MessageTemplateNames.OrderPlacedCustomer)
        return;

    // Check if the message has the model we want to use.
    var hasMyModel = message.Evaluate("MyModel") != null;

    if (!hasMyModel)
        return;

    // Create the content to inject.
    // Access the model data using '{{Model.Property}}'.
    var hrefLink = "https://www.myshop.com/email/action/?id={{MyModel.OrderId}}";

    var liquid = $"<a href=\"{hrefLink}\" target=\"_blank\">Click for more content</a>";

    // Inject the content into the message.
    message.InjectContent(liquid);
}


#3 Algorithman

Algorithman

    Advanced Member

  • Members
  • PunktPunktPunkt
  • 39 Beiträge

Geschrieben: 15 May 2023 - 10:53

Wie oben schon beschrieben:

 

1. OrderItemId ist noch nicht da (SaveChanges wurde noch nicht aufgerufen).

2. Da ich ja keinen FK haben kann (dazu müsste ich ja das ShoppingCartItem Model ändern) habe ich nur eine 'lose' Referenz über die Id. Das bedeutet aber auch, dass ich im Nachgang, wenn die Order komplett geschrieben ist, diese Referenz verloren hab (ShoppingCartItem ist zu dem Zeitpunkt schon weg).

3. Der Event wird zu spät aufgerufen. Ich brauche die Daten auch für die Email, von daher leider zu spät.

 

Ich hab vorhin einen PR gemacht (https://github.com/s...tstore/pull/707), der würde das Problem lösen.
Wird für jedes OrderItem/OrganizedShoppingCartItem ausgelöst und ich kann pro ShoppingCartItem meine Daten in meine AdditionalOrderData Table übertragen.



#4 Marcus Gesing

Marcus Gesing

    SmartStore AG

  • Administrators
  • 3801 Beiträge

Geschrieben: 15 May 2023 - 18:43

"Wenn es da eine bessere Methode gibt (inkl der Moglichkeit ShoppingCartItem Id <-> OrderItem Id zu referenzieren), ich bin offen für Vorschläge."
ICheckoutStateAccessor.CheckoutState erlaubt es eigene Daten durch den Checkout zu geleiten. Über ShoppingCartItem (flüchtiges Objekt) würde ich keine Zuordnung vornehmen. Stattdessen würde ich einen eindeutigen Hash bestehend aus ShoppingCartItem.ProductId und ShoppingCartItem.AttributesXml verwenden, um später die zugehörige OrderItem auffinden zu können.

Marcus Gesing

Smartstore AG


#5 Algorithman

Algorithman

    Advanced Member

  • Members
  • PunktPunktPunkt
  • 39 Beiträge

Geschrieben: 15 May 2023 - 20:15

Hash aus ProductId und AttributesXML ist bei mir leider nicht ausreichend. Wenn dann müsste ich zusätzlich noch die Anzahl mit in den Hash einbeziehen, was das Problem dann aber nur in den Warenkorb verlagern würde.

 

Die Attribute kann ich sowieso nicht verwenden, wir haben viel zu viele Kombinationen (2x ~500 Farben, Größe 2 Dimensionen auf 10tel Millimeter, Gravur, Kommission, Lagerbestellung, Bügellänge).

 

Unsere Zusatzfelder sind deshalb komplette Freifelder (B2B-Shop, das sind alles Profis, die wissen normalerweise was sie eingeben).

 

Den ICheckoutAccessor hab ich mir angesehen, aber da hab ich genau das gleiche Problem, das OrderItem zum ShoppingCartItem (bzw. zu meinen Daten) zu finden. Es gibt momentan schlicht nur Events/Eingriffspunkte, bei der die Order nocht nicht erstellt oder schon komplett fertig ist aber nichts was auf die einzelnen Positionen eingeht.

 

Übrigens, warum soll ShoppingCartItem flüchtig sein? Ich hab jetzt nichts gesehen, was den Warenkorb unknotrolliert löschen/ändern würde.



#6 Marcus Gesing

Marcus Gesing

    SmartStore AG

  • Administrators
  • 3801 Beiträge

Geschrieben: 15 May 2023 - 21:14

"Übrigens, warum soll ShoppingCartItem flüchtig sein? Ich hab jetzt nichts gesehen, was den Warenkorb unknotrolliert löschen/ändern würde."
Es geht nicht um "unkontrolliert". Die Daten haben eine kurze Lebensdauer, sind eher temporärer Natur, werden von allen und alles gelöscht (Käufer, Admin, PlaceOrder, Wartung...) und bleiben nie dauerhaft erhalten.
 
Normalerweise ist das geschilderte ein Scope-Problem. Ich hätte jetzt nicht erwartet, dass es hier so schwierig ist OrderItem eigene Daten zuzuordnen.... ich schaue mir morgen den Pull-Request an...

Marcus Gesing

Smartstore AG


#7 Algorithman

Algorithman

    Advanced Member

  • Members
  • PunktPunktPunkt
  • 39 Beiträge

Geschrieben: 15 May 2023 - 22:38

Ach so war das gemeint.

Aber da gibt es jedesmal einen Punkt wo ich ansetzen und dadurch meine Table auf dem aktuellen Stand halten kann. Nur eben bei PlaceOrder komm ich nicht drum rum, dass ich vorher und nachher haben muss. Orphaned Entries hab ich eigentlich nie.

 

Wenn die Id immer die ausschlaggebende Sortierung wäre, könnte ich auf das Ganze auch verzichten. Aber da ist mir MySQL früher mal in die Parade gefahren und seitdem verlasse ich mich da nicht mehr darauf :)



#8 Marcus Gesing

Marcus Gesing

    SmartStore AG

  • Administrators
  • 3801 Beiträge

Geschrieben: 16 May 2023 - 08:43

Ich möchte den Pull-Request nicht übernehmen, weil das OrderItemAdded-Event ein SaveChangesAsync für jede OrderItem-Entität erfordert und den Scope-Commit "untergräbt". Stattdessen würde ich vorschlagen OrderPlacedEvent zu erweitern. Was mir vorschwebt sind zwei Sachen. 1. OrderPlacedEvent um ein neue Property "LineItems" zu erweitern, die die benötigten Daten enthält. Blaupause:
public class OrderPlacedEvent
{
  //...
  public List<OrderLineItem> LineItems { get; init; }
}

public class OrderLineItem
{
  public OrderItem OrderItem { get; init; }
  public OrganizedShoppingCartItem CartItem { get; init; }
}
2. IShoppingCartService.DeleteCartAsync muss dafür nach PublishOrderPlacedAsync ausgeführt werden (anstatt vorher).
 
Würde das ihr Problem lösen?

Marcus Gesing

Smartstore AG


#9 Algorithman

Algorithman

    Advanced Member

  • Members
  • PunktPunktPunkt
  • 39 Beiträge

Geschrieben: 16 May 2023 - 09:48

Ist zu dem Zeitpunkt überhaupt ein Scope aktiv? Ich hab nur einen in CheckOrderStatusAsync gesehen und das ist ja danach.

 

Was die Erweiterung des OrderPlacedEvent angeht, von den Daten her ja, vom Zeitpunkt her nein.

Denn der Event wird ja erst nach Versand der Email getriggert, also kann ich für die Email die benötigten Daten nicht abfragen.

 

Ich könnte bei mir die Referenz ändern und die GUID der OrderItems dafür hernehmen (das würde das Speichern überflüssig machen, aber die Suche nach den Daten verlangsamen) aber der Zeitpunkt für so einen Event müsste immer noch vor dem Senden der Email sein. 

 

Davon abgesehen, wie stelle ich eigentlich sicher, dass ich nicht einen Scope unterbreche wenn ich jetzt z.B. in einem EventConsumer die Datenbank benutze?



#10 Marcus Gesing

Marcus Gesing

    SmartStore AG

  • Administrators
  • 3801 Beiträge

Geschrieben: 16 May 2023 - 10:57

Ja, der DeferCommit in CheckOrderStatusAsync soll OrderItem und sonstiges commiten. Die Events laufen nachher, nachdem alles gespeichert wurde.
 
"Davon abgesehen, wie stelle ich eigentlich sicher, dass ich nicht einen Scope unterbreche wenn ich jetzt z.B. in einem EventConsumer die Datenbank benutze?"
Unterbrochen wird da nichts. Getrackte Entitäten werden dann früher und nicht über den Scope-Commit gespeichert. Aber wie gesagt laufen die Events erst nach dem Scope-Commit.
 
"Denn der Event wird ja erst nach Versand der Email getriggert, also kann ich für die Email die benötigten Daten nicht abfragen."
Da wäre wir wieder beim erwähnten Scope-Problem. Einzige Idee wie gesagt Session-Objekt bzw. Checkout-State. So habe ich das immer z.B. bei Zahlungs-Plugins gemacht.
 
"Die Attribute kann ich sowieso nicht verwenden, wir haben viel zu viele Kombinationen (2x ~500 Farben, Größe 2 Dimensionen auf 10tel Millimeter, Gravur, Kommission, Lagerbestellung, Bügellänge). Unsere Zusatzfelder sind deshalb komplette Freifelder (B2B-Shop, das sind alles Profis, die wissen normalerweise was sie eingeben)."
Warum nicht? Was ist das Problem? Alles was von ShoppingCartItem (insb. ShoppingCartItem.RawAttributes) in OrderItem einfließt in den HashCodeCombiner geben. Mit dem erzeugten Hash lässt sich die zugehörige OrderItem identifizieren, indem man seinerseits dessen Properties hashed und beide Hash vergleicht.

Marcus Gesing

Smartstore AG


#11 Algorithman

Algorithman

    Advanced Member

  • Members
  • PunktPunktPunkt
  • 39 Beiträge

Geschrieben: 16 May 2023 - 11:58

 

Warum nicht? Was ist das Problem? Alles was von ShoppingCartItem (insb. ShoppingCartItem.RawAttributes) in OrderItem einfließt in den HashCodeCombiner geben. Mit dem erzeugten Hash lässt sich die zugehörige OrderItem identifizieren, indem man seinerseits dessen Properties hashed und beide Hash vergleicht.

 

Das Problem ist, dass einige davon Freifelder sein müssen (Texteingabe), z.B. Kommission, Gravur, Größe (da gibt es verschiedene Schreibweisen, Optiker sind da von Land zu Land unterschiedlich und zusätzlich noch spezielle Optionen wie 2mm tiefer etc, das würde zu weit führen das hier alles zu erklären).
Und wir produzieren dann anhand der Angaben des Kunden die Brille.

Kurz gesagt, ich muß das als Textfelder durchschleifen, das werde ich nicht verhindern können.

 

 



#12 Marcus Gesing

Marcus Gesing

    SmartStore AG

  • Administrators
  • 3801 Beiträge

Geschrieben: 16 May 2023 - 13:16

Das beantwortet nicht meine Frage. Auch Inhalte von freien Textfeldern sind in ShoppingCartItem.RawAttributes enthalten (wenn ich mich nicht täusche). Selbst wenn sie zusätzliche Daten an OrderItem binden möchten, die sich nirgends in den Smartstore-Entitäten\Properties wiederfinden, dann werfen sie die ebenfalls mit in den HashCodeCombiner. Einfach alles reinpfeffern, was Teil des Inhalts Ihrer Line-Item ist.

Marcus Gesing

Smartstore AG


#13 Algorithman

Algorithman

    Advanced Member

  • Members
  • PunktPunktPunkt
  • 39 Beiträge

Geschrieben: 16 May 2023 - 14:49

Ahh, das Problem hat sich grade in Luft aufgelöst. Ich dachte die Attribute wären nur dafür da, um Produktvariationen zu erstellen... (also im Sinne von rot/gelb/blau, klein/mittel/gross und deren Kombinationen)

 

Ich glaub ich kann das Ganze über Attribute anlegen/verwalten, initial füllen über meine AdditionalProductData via dem neuen CompundMapper und Warenkorb/Order komplett in Ruhe lassen.

 

Sorry für die Arbeit und vielen Dank für die Unterstützung.




Auch markiert mit einem oder mehrerer dieser Schlüsselwörter: Datenbank, Events