In verschiedenen Anwendungen besteht die Aufgabe regelmäßig darin, die Logik der zeitlichen Änderung eines Attributs eines Objekts relativ zu einem bestimmten Subjekt (oder Subjekten) zu unterstützen. Dies kann beispielsweise eine Änderung des Einzelhandelspreises von Waren in Geschäften oder KPI-Indikatoren für Mitarbeiter sein.
In diesem Artikel werde ich zeigen, welche Domänenlogik und Schnittstellen erstellt werden können, um dieses Problem zu lösen. Ich werde sofort reservieren, dass dies den Einfluss des Benutzers auf das Attribut und nicht die Reflexion der historischen Änderung betrifft.
Die Implementierung wird auf der Grundlage der offenen und kostenlosen
lsFusion- Plattform vorgestellt. Ein ähnliches Schema kann jedoch angewendet werden, wenn eine andere Technologie verwendet wird.
Einführung
Für eine einfachere Darstellung und ein einfacheres Verständnis des Artikels nehmen wir den Preis als Attribut, das Produkt als Objekt und das Lager als Thema. In diesem Fall ist das Datum das minimal mögliche Intervall zum Festlegen des Attributs. Auf diese Weise kann der Benutzer den Preis für ein bestimmtes Datum für ein Produkt und ein Lager bestimmen.
Das Benutzereingabeschema für Preisänderungen ähnelt dem in klassischen Versionskontrollsystemen verwendeten. Jede Änderung aus Sicht der Domänenlogik ist ein einzelnes
Commit , auf dessen Grundlage der Status für ein bestimmtes Datum berechnet wird. In vielen Themenbereichen werden solche Commits als Dokumente oder Transaktionen bezeichnet. In diesem Fall meinen wir mit diesem Commit die sogenannte Preisliste. In jeder Preisliste sind die darin enthaltenen Waren und Lager sowie die Gültigkeitsdauer angegeben.
Das beschriebene Schema hat folgende Vorteile:
- Atomizität . Jede Änderung wird als separates Dokument ausgestellt. Daher können diese Dokumente vorübergehend gespeichert, aber nicht gebucht werden. Wenn Sie es falsch eingeben, ist es einfach, die gesamte Änderung zurückzusetzen.
- Transparenz Es ist einfach festzustellen, wer die Änderung wann vorgenommen hat, und den Grund anzugeben, indem Sie einen Kommentar zum Dokument abgeben.
Der Hauptunterschied zum Versionskontrollsystem besteht darin, dass explizite Festschreibungen unabhängig voneinander sind. Somit ist es jederzeit möglich, alle Commits relativ schmerzlos zu löschen. Darüber hinaus kann jedes dieser Commits so eingestellt werden, dass es endet, wenn es nicht mehr funktioniert, was natürlich nicht im Versionskontrollsystem enthalten ist.
Implementierung
Wir beginnen die Definition der Domänenlogik mit Lagern. Lassen Sie uns die Lösung etwas komplizieren, indem wir Lager zu einer Hierarchie einer Gruppe dynamischer Tiefen kombinieren. Nach welchem Prinzip dies geschieht, wird im entsprechenden
Artikel beschrieben. Daher gebe ich nur einen Code an, der Gruppen deklariert und Formulare zum Bearbeiten erstellt:
Ankündigung der Lagergruppe Beispiel für eine Gruppenhierarchie Als nächstes deklarieren Sie Lagerhäuser, die an eine der Gruppen gebunden werden können:
Und schließlich erklären Sie die Logik der Waren:
Wir fahren direkt mit der Erstellung der Logik von Preislisten fort. Zunächst legen wir die
Preislistenklasse selbst sowie deren Gültigkeitsdauer fest:
Wir glauben, dass die Preisliste endlos ist, wenn kein
Datum festgelegt wurde.
Wir fügen ein Ereignis hinzu, das beim Erstellen der Preisliste automatisch das aktuelle Datum festlegt, ab dem die Inbetriebnahme beginnt.
Das Schlüsselwort
LOCAL bedeutet, dass das Ereignis nicht ausgelöst wird, wenn das Speichern auf die Datenbank angewendet wird, sondern sofort, wenn die Änderung vorgenommen wird.
Fügen Sie dann den Benutzer, der es erstellt hat, und die Erstellungszeit hinzu:
Erstellen Sie nun ein Ereignis, das sie automatisch ausfüllt:
Dieses Ereignis wird im Gegensatz zum vorherigen nur ausgelöst, wenn auf die Schaltfläche Speichern geklickt wird. Das heißt, während einer Sicherungstransaktion in der Datenbank.
Erstellen Sie als Nächstes die Preislistenzeilen, in denen die Waren und Preise festgelegt werden:
Das Attribut
NONULL gibt an, dass die Eigenschaft
priceList immer festgelegt werden soll, und
DELETE gibt an, dass die entsprechende Zeile automatisch gelöscht werden soll, wenn der Eigenschaftswert auf Null gesetzt wird (z. B. beim Löschen der Preisliste).
Für die zukünftige Verwendung erstellen wir Eigenschaften, die den Gültigkeitszeitraum der Preislistenzeilen bestimmen:
Jetzt binden wir die Preisliste an die Lager, für die sie betrieben wird. Fügen Sie zunächst die primäre Eigenschaft hinzu. Dies ist der Fall, wenn die gesamte Gruppe von Lagern in der Preisliste enthalten ist:
Wir berechnen die „Einbeziehung“ der Gruppe unter Berücksichtigung der ausgewählten Eltern (wie im Artikel über Hierarchien beschrieben):
Fügen Sie die primäre Eigenschaft hinzu, mit der Sie angeben können, dass die Preisliste für ein bestimmtes Lager gilt:
Wir berechnen die endgültige Eigenschaft, die bestimmt, dass die Preisliste die Preise im entsprechenden Lager ändert, unter Berücksichtigung der Gruppen:
Erstellen Sie eine Eigenschaft, in der die Namen aller ausgewählten Gruppen und Lager der Preisliste angezeigt werden, damit ein bequemerer Benutzer die Liste der Preislisten anzeigen kann:
Der letzte Schritt in der Beschreibung der Domänenlogik berechnet direkt den aktuellen Preis der Waren im Lager. Erstellen Sie dazu eine Eigenschaft, die die letzte Datumszeile der Preisliste mit der gewünschten Ware, dem gewünschten Lager und dem gewünschten Gültigkeitszeitraum findet:
In der Logik der Berechnung dieser Eigenschaft sind verschiedene Variationen möglich. Sie können sowohl den Filter für das Schlagen von Zeilen (z. B. das Hinzufügen einer Bedingung in
WHERE , in der die Preisliste veröffentlicht wird) als auch die Bestellung ändern. Es ist zu beachten, dass das Objekt selbst oder vielmehr seine interne Kennung durch den zweiten Parameter zur Auswahlreihenfolge hinzugefügt wurde. Dies ist notwendig, damit der Preiswert immer eindeutig bestimmt wird.
Basierend auf der erhaltenen Preislistenzeile bestimmen wir den Preiswert und dessen Gültigkeitsdauer:
Sie werden in Benutzeroberflächentabellen weiter verwendet.
Als nächstes fahren wir mit dem Aufbau der Benutzeroberfläche fort. Zuerst zeichnen wir ein Formular zum Bearbeiten der Preisliste. Erstellen Sie ein Formular und fügen Sie dort die „Kopfzeile“ des Dokuments hinzu:
Fügen Sie die Preislistenzeile zum Formular hinzu:
Fügen Sie als Nächstes einen Baum hinzu, in dem sich sowohl Gruppen als auch Lager befinden:
Gleichzeitig werden dem Baum Eigenschaften für Gruppen und Lager hinzugefügt. Die Plattform zeigt diese oder jene Eigenschaft je nach Objekt in der Reihenfolge an, in der sie dem Formular hinzugefügt wurden.
Wir passen das Design des Formulars so an, dass Waren und Lager in separaten Registerkarten gezeichnet werden:
Das Bearbeitungsformular sieht folgendermaßen aus:
Es bleibt die Grundform des Preismanagements aufzubauen. Es besteht aus zwei Registerkarten. Die erste zeigt eine Liste aller Preislisten (ähnlich der Liste der Commits). Auf der zweiten Registerkarte werden die aktuellen Preise für ein bestimmtes Lager für das ausgewählte Datum angezeigt.
Um die erste Registerkarte zu implementieren, fügen Sie dem Formular eine Liste mit Preislisten mit Zeilen für eine schnelle Vorschau hinzu:
Für die zweite Registerkarte fügen wir zunächst das Datum hinzu, an dem die Preise angezeigt werden, den Baum der Lagergruppen sowie die Lager selbst:
In der Liste der Lager werden alle Lager angezeigt, die Nachkommen der oben ausgewählten Gruppe sind.
Fügen Sie als Nächstes dem Formular eine Liste der Waren hinzu, für die zum ausgewählten Datum gültige Preise für das Lager gelten:
Sowohl der Preis selbst als auch die Gültigkeitsdauer werden zu den Spalten hinzugefügt. Sie können auch die Preislistennummer hinzufügen. Diese Tabelle ähnelt dann der Logik von Anmerkungen in Versionskontrollsystemen.
Damit der Benutzer verstehen kann, woher ein solcher Preis stammt, fügen wir die Liste der Preislistenzeilen mit geeigneten Waren und Lagern hinzu:
Markieren Sie mit dem Attribut
HINTERGRUND die Zeile, in der der in der Tabelle angegebene Preis ermittelt wurde.
Zur Vereinfachung des Benutzers werden wir außerdem die Möglichkeit hinzufügen, das Bearbeitungsformular der entsprechenden Preisliste in einer neuen Sitzung unmittelbar aus dieser Geschichte heraus zu öffnen:
Um dies zu erreichen, müssen Sie die Aktion angeben, die ausgeführt wird, wenn Sie versuchen, eine Zeile zu bearbeiten, indem Sie die integrierte
Bearbeitungsaktion implementieren. Anschließend wird dem Formular auf standardmäßige Weise eine Standardschaltfläche zum Bearbeiten eines Objekts über einen Dialogaufruf hinzugefügt.
Und schließlich bilden wir das endgültige Design des Formulars:
Hier wird zuerst der
Fenstercontainer hinzugefügt, der aus zwei Registerkarten besteht:
Preislisten und
Preise . Der erste von ihnen fügt nur eine Liste von Preislisten und Zeilen hinzu. Im zweiten werden zwei Bedienfelder erstellt:
leftPane und
rightPane . Das linke Feld enthält das Datum und die Lager, und das rechte Feld enthält die Waren- und Preishistorie.
Ergebnis
Betrachten Sie die Hauptoptionen für die Verwendung der resultierenden Logik.
Angenommen, wir haben zwei separate Preislisten für verschiedene Warengruppen. Abhängig vom ausgewählten Lager werden dann auf der Registerkarte mit den Preisen nur Produkte aus den entsprechenden Preislisten angezeigt:
Erstellen Sie nun eine neue Preisliste mit einer begrenzten Gültigkeitsdauer, eine abgespeckte Liste der Lager und einen neuen Preis. Wenn wir auf der zweiten Registerkarte ein Datum im Bereich der neuen Preisliste auswählen, erhalten wir einen neuen Preis daraus. Sobald die Gültigkeitsdauer abläuft, kehrt der alte Preis wieder vom ursprünglichen Preis zurück:
Mit demselben Mechanismus können Sie die Aktion bestimmter Preise ab einem bestimmten Datum „abbrechen“. Wenn Sie beispielsweise einen neuen Preis eingeben, ohne einen Preis anzugeben, wird der Preis zurückgesetzt und die Ware verschwindet aus dem Filter. In diesem Fall kehrt beim Löschen des eingegebenen Dokuments alles in den alten Zustand zurück:
Das resultierende Eigentum mit dem Preis der Waren durch das Lager am Datum kann in verschiedenen Ereignissen oder anderen Formen weiter verwendet werden. Sie können beispielsweise eine automatische Preisgestaltung in einer Bestellung basierend auf dieser Preislogik vornehmen:
Ein schöner Bonus in dieser Logik ist, dass beim Hinzufügen eines neuen Lagers zur Gruppe automatisch Preise aus bereits erstellten Preislisten darauf angewendet werden. Das gleiche passiert, wenn Sie die Gruppe für das Lager ändern.
Wenn Sie möchten, können Sie die Spalte mit dem Preis auf der Registerkarte mit den aktuellen Preisen bearbeiten und eine Schaltfläche hinzufügen, mit der ein neues Commit für die geänderten Preise erstellt wird.
Fazit
In der Lösung auf Plattformebene werden weder Nachschlagewerke noch Dokumente mit Zeichenfolgen, Register, Berichte und andere unnötige Abstraktionen verwendet. Alles wird ausschließlich nach den Konzepten von Klassen und Eigenschaften durchgeführt. Beachten Sie, dass diese ziemlich komplexe Logik in ungefähr 150 aussagekräftigen Codezeilen auf lsFusion implementiert wurde. Es ist eine viel schwierigere Aufgabe, es in derselben Formulierung auf anderen Plattformen (z. B. 1C) zu implementieren.
Das oben beschriebene Schema wird häufig in der auf lsFusion basierenden
ERP-Lösung verwendet . Mit verschiedenen Modifikationen werden Preislisten von Lieferanten, Management-Einzelhandelspreise, Lagerbestände und viele andere Management-Parameter unterstützt.
Die Vorlage kann kompliziert werden, indem dem Dokument mehrere Entitäten hinzugefügt werden (z. B. kann dem Lager ein Lieferant hinzugefügt werden) und mehrere Attribute gleichzeitig in einem Dokument definiert werden. Insbesondere können Sie die Entität Preistyp hinzufügen und in der Belegzeile den Preis für das Tupel der Zeile und den entsprechenden Preistyp festlegen. In der oben beschriebenen Logik müssen Sie einigen Eigenschaften nur einige zusätzliche Parameter hinzufügen.
Mit Hilfe mehrerer zusätzlicher Codezeilen ist es möglich, alle Änderungsdatensätze in einer Tabelle zu denormalisieren, auf der der entsprechende Index erstellt werden kann. Dann erfolgt die Auswahl eines beliebigen Wertes für ein beliebiges Datum in einer logarithmischen Zeit. Eine solche Optimierung ist erforderlich, wenn diese Tabelle mehrere hundert Millionen Datensätze enthält.
Sie können das erstellte Beispiel online auf der entsprechenden
Seite der Site (Abschnitt Plattform) ausprobieren. Hier ist der gesamte Quellcode, den Sie in das gewünschte Feld einfügen müssen: