Wir bauen eine Schnittstelle fĂŒr die Eingabe von Dokumenten durch Auswahl

Bild

In verschiedenen GeschĂ€ftsanwendungen tritt hĂ€ufig die Aufgabe der Dokumenteingabe auf. In der Regel besteht ein Dokument aus einer Überschrift und einigen Zeilen, die sich jeweils auf ein Objekt (z. B. ein Produkt) beziehen. In den meisten FĂ€llen wird eine regulĂ€re Tabelle verwendet, um DatensĂ€tze in ein Dokument einzugeben, in dem der Benutzer Zeilen hinzufĂŒgen und löschen sowie deren Inhalt Ă€ndern kann.

In einigen FĂ€llen ist ein solches Schema fĂŒr Benutzer jedoch nicht immer praktisch. In diesem Artikel werde ich Ihnen erklĂ€ren, wie Sie mithilfe der Technik der Produktauswahl eine praktische BenutzeroberflĂ€che erstellen.

Herausforderung


In der Regel gibt es bei der Eingabe von Dokumenten fĂŒr den Benutzer eine EinschrĂ€nkung fĂŒr die Gruppe von Objekten, die hinzugefĂŒgt werden können. In diesem Fall ist es fĂŒr den Benutzer logisch, eine Liste solcher Objekte anzuzeigen, mit der Möglichkeit, sie schnell in das Dokument aufzunehmen (und auszuschließen). In den Spalten ist es auch zweckmĂ€ĂŸig, fĂŒr jedes der Objekte die Daten anzuzeigen, die erforderlich sind, um eine Entscheidung ĂŒber die Notwendigkeit zu treffen, sie in das Dokument aufzunehmen. Und schließlich besteht zusammen mit dem Objekt hĂ€ufig die Notwendigkeit, seine Menge einzugeben.

Betrachten wir drei Arten von Dokumenten, die hÀufig in GeschÀftsanwendungen enthalten sind:

  1. Bestellung . In solchen Dokumenten ist es logisch, dass der Benutzer eine Liste aller Waren anzeigt, die beim Lieferanten bestellt werden können. In den Spalten ist es zweckmĂ€ĂŸig, den aktuellen Saldo, den Umsatz fĂŒr ein bestimmtes Intervall sowie die fĂŒr Kauf und Verkauf bestellte Menge anzuzeigen.
  2. Kundenauftrag . Hier wird meistens eine Liste von Waren angezeigt, die sich in der Bilanz des ausgewÀhlten Lagers befinden und dem ausgewÀhlten Kunden zum Verkauf angeboten werden. Aktuelle Preise sollten ebenfalls angezeigt werden.
  3. Änderung der Salden . Dieses Dokument wird verwendet, um die aktuellen Salden im Falle von Abweichungen vom tatsĂ€chlichen Betrag anzupassen. Alle Produkte werden normalerweise in der Auswahl angezeigt, wobei die tatsĂ€chliche Bilanz fĂŒr eines von ihnen eingegeben werden kann. Gleichzeitig wird dem Dokument ein Produkt mit einem Betrag hinzugefĂŒgt, der der Differenz zwischen dem tatsĂ€chlichen und dem aktuellen Saldo entspricht.

Lösung


Als nĂ€chstes werde ich zeigen, wie diese Logik basierend auf der offenen und kostenlosen lsFusion- Plattform schnell und einfach implementiert werden kann. Lassen Sie uns als Beispiel eine Logik fĂŒr die Eingabe einer Bestellung erstellen.

FĂŒgen Sie zunĂ€chst einen Produktleitfaden ĂŒber die Standard- CRUD- OberflĂ€che hinzu:
CLASS Product '' ;
name '' = DATA STRING [ 50 ] (Product);

FORM product ''
OBJECTS p = Product PANEL
PROPERTIES (p) name

EDIT Product OBJECT p //
;

FORM products ''
OBJECTS p = Product
PROPERTIES (p) READONLY name
PROPERTIES (p) NEWSESSION NEW , EDIT , DELETE

LIST Product OBJECT p // ,
;

NAVIGATOR {
NEW products;
}

Wir erstellen das Konzept eines Lieferanten und geben in Form der Bearbeitung die Möglichkeit, die Produkte auszuwÀhlen, mit denen er arbeitet:
CLASS Supplier '' ;
name '' = DATA STRING [ 50 ] (Supplier);

in '' = DATA BOOLEAN (Supplier, Product); // TRUE,

FORM supplier ''
OBJECTS s = Supplier PANEL
PROPERTIES (s) name

OBJECTS p = Product //
PROPERTIES in(s, p), name(p) READONLY //

EDIT Supplier OBJECT s
;

FORM suppliers ''
OBJECTS s = Supplier
PROPERTIES (s) READONLY name
PROPERTIES (s) NEWSESSION NEW , EDIT , DELETE

LIST Supplier OBJECT s
;

NAVIGATOR {
NEW suppliers;
}

Deklarieren Sie die Ordnungslogik mit den Zeilen:
CLASS Order '' ;
date '' = DATA DATE (Order);
number '' = DATA INTEGER (Order);

supplier '' = DATA Supplier (Order);
nameSupplier '' (Order o) = name(supplier(o));

CLASS OrderDetail ' ' ;
order '' = DATA Order (OrderDetail) NONULL DELETE ;

FĂŒgen Sie den Linien Produkte und Mengen hinzu:
product '' = DATA Product (OrderDetail);
nameProduct '' (OrderDetail d) = name(product(d));

quantity '-' = DATA NUMERIC [ 14 , 3 ] (OrderDetail);

Wir fahren direkt mit der Erstellung des von uns benötigten Auftragsbearbeitungsformulars fort. FĂŒgen Sie zunĂ€chst die Bestellung selbst und ihre Zeilen hinzu:
FORM order ''
OBJECTS o = Order PANEL
PROPERTIES (o) date, number, nameSupplier

OBJECTS d = OrderDetail
PROPERTIES (d) nameProduct, quantity, NEW , DELETE
FILTERS order(d) = o

EDIT Order OBJECT o
;

Auf diese Weise erhalten wir eine Standardschnittstelle fĂŒr die Arbeit mit Auftragspositionen durch HinzufĂŒgen und Entfernen.
Als nĂ€chstes fĂŒgen wir diesem Formular die Auswahlfunktion hinzu, die wir benötigen. Erstellen Sie dazu zunĂ€chst ein Objekt im Formular mit einer Liste aller Waren, in der nur diejenigen gefiltert werden, die beim ausgewĂ€hlten Lieferanten bestellen dĂŒrfen:
EXTEND FORM order
OBJECTS p = Product
PROPERTIES name(p) READONLY
FILTERS in(supplier(o), p) //
;

Wir haben das Design so eingerichtet, dass die Bestellpositionen und die Auswahl als Registerkarten eines Containers angezeigt werden:
DESIGN order {
OBJECTS {
NEW pane { //
fill = 1 ; //
type = TABBED ; // ,
MOVE BOX (d); //
MOVE BOX (p) { //
caption = '' ;
}
}
}
}

Wir erstellen Hilfseigenschaften fĂŒr die Anzeige und Eingabe der Menge durch den Benutzer in der entsprechenden Spalte:
quantity '-' (Order o, Product p) =
GROUP SUM quantity(OrderDetail d) BY order(d), product(d);
lastOrderDetail ' ' (Order o, Product p) =
GROUP LAST OrderDetail d ORDER d BY order(d), product(d);

Die erste Eigenschaft berĂŒcksichtigt die Menge fĂŒr diese Bestellung und das Produkt in diesem Dokument. Die zweite findet die letzte Zeile (der Benutzer kann mehrere Zeilen mit einem Produkt eingeben).
Als NĂ€chstes erstellen wir eine Aktion, mit der der Benutzer den Wert in die entsprechende Spalte auf der Registerkarte Auswahl eingibt:
changeQuantity ' -' (Order o, Product p) {
INPUT q = NUMERIC [ 14 , 3 ] DO { //
IF lastOrderDetail(o, p) THEN { // ,
IF q THEN //
quantity(OrderDetail d) <- q IF d = lastOrderDetail(o, p)
WHERE order(d) = o AND product(d) = p; //
ELSE // -
DELETE OrderDetail d WHERE order(d) = o AND product(d) == p;
} ELSE
IF q THEN
NEW d = OrderDetail { //
order(d) <- o;
product(d) <- p;
quantity(d) <- q;
}
}
}

Schließlich fĂŒgen wir dem Formular eine Spalte hinzu, die die Aktion angibt, die ausgefĂŒhrt werden soll, wenn der Benutzer versucht, seinen Wert zu Ă€ndern:
EXTEND FORM order
PROPERTIES (o, p) quantity ON CHANGE changeQuantity(o, p)
;

Es bleibt nur ein Formular mit einer Liste von Bestellungen zu zeichnen und es dem Navigator hinzuzufĂŒgen:
FORM orders ''
OBJECTS o = Order
PROPERTIES (o) READONLY date, number
PROPERTIES (o) NEWSESSION NEW , EDIT , DELETE
;

NAVIGATOR {
NEW orders;
}

Das resultierende Formular sieht ungefĂ€hr so ​​aus:

Bild

Alle Änderungen, die an einer der Registerkarten vorgenommen werden, werden automatisch auf die andere Registerkarte ĂŒbertragen.

In realen ERP-Systemen werden dem Formular erheblich mehr Spalten und andere Elemente hinzugefĂŒgt. In einer dieser Implementierungen sieht es beispielsweise so aus:

Bild


Lassen Sie uns sehen, wie diese FunktionalitÀt in anderen GeschÀftsanwendungen implementiert wird.

1C


In verschiedenen Konfigurationen von 1C weist die Auswahllogik bestimmte Unterschiede auf, aber das Prinzip ist mehr oder weniger dasselbe. Auf dem Dokumentbearbeitungsformular befindet sich eine SchaltflÀche AuswÀhlen, die einen Dialog mit der Warenauswahl aufruft:

Bild

In diesem Dialog können Sie die Ware wie folgt auswÀhlen:

Bild

Dieser Mechanismus weist mindestens zwei Unannehmlichkeiten auf.

Um die Menge des Produkts zum Dokument hinzuzufĂŒgen (und meistens kennt der Benutzer bereits die Menge, die er hinzufĂŒgen möchte), mĂŒssen Sie zuerst auf das Produkt doppelklicken, es den Zeilen hinzufĂŒgen und dann die Menge in den Zeilen Ă€ndern. DarĂŒber hinaus sieht der Benutzer in der Produktliste nicht, ob und mit welcher Menge dieses Produkt bereits hinzugefĂŒgt wurde. DarĂŒber hinaus „verbraucht“ ein solches Schema zusĂ€tzlichen Speicherplatz, da Sie zwei Tabellen auf einem Bildschirm anstatt auf einem anzeigen mĂŒssen.

Zweitens, nachdem Sie die Zeilen direkt zum Dokument hinzugefĂŒgt haben und Sie erneut auf die SchaltflĂ€che AuswĂ€hlen klicken, beginnt die Auswahl „von vorne“. In der unteren Tabelle werden keine Zeilen angezeigt, und zum Zeitpunkt der erneuten Auswahl ist nicht klar, was bereits im Dokument enthalten ist und was nicht. Es verstĂ¶ĂŸt auch gegen eine der wichtigen Regeln beim Erstellen der BenutzeroberflĂ€che: Wenn sich der Benutzer irrt, muss ihm die Möglichkeit gegeben werden, zurĂŒck zu gehen und den Fehler zu beheben. Hier stellt sich heraus, dass er nicht zur Auswahl von Waren mit denselben Daten zurĂŒckkehren kann wie vor dem Klicken auf die SchaltflĂ€che HinzufĂŒgen zum Dokument.

In 1C ist es jedoch möglich, dass Sie das obige Schema implementieren. Aus irgendeinem Grund wird jedoch in den typischen Konfigurationen, die auf der Site mit Demos verfĂŒgbar sind, ein anderes verwendet.

Microsoft Dynamics 365


Als Lösung habe ich Retail gewÀhlt (nur darin habe ich Àhnliche Funktionen unter https://trials.dynamics.com gefunden ). Darin können Sie die Auswahl im Bestellformular auf zwei Arten aufrufen:

Bild

Die erste SchaltflÀche ist nach dem 1C-Schema implementiert (obwohl es viel weniger Spalten gibt), daher werde ich nicht weiter darauf eingehen.

Die zweite SchaltflÀche öffnet einen Dialog mit einer Liste von Produkten, in denen die Menge bereits in Spalten eingegeben werden kann. Dies geschieht jedoch auf sehr eigenartige Weise.

Erstens werden dort standardmĂ€ĂŸig nur Produktcodes angezeigt (auch ohne Namen). NatĂŒrlich verstehe ich, dass Sie dort Erweiterungen erstellen und andere Spalten einfĂŒgen können, aber dieses Verhalten in der Basisversion zu sehen, ist etwas seltsam.

Zweitens war Microsoft anscheinend so begeistert von dem Design, dass sie aus irgendeinem Grund bei der normalen Verarbeitung von Bildlaufdaten, der Verarbeitung von Tricks und Ereignissen punkten konnten. Es sieht ungefĂ€hr so ​​aus:

Bild

WĂ€hrend des normalen Tastaturbetriebs werden die aktuellen Serien beim erneuten Lesen von Daten stĂ€ndig umgeschaltet. Gleichzeitig können Sie erst mit der Eingabe beginnen, nachdem Sie auf die gesamte Ereignisverarbeitung gewartet haben. Andernfalls wird die Menge entweder ĂŒberhaupt nicht oder in der falschen Reihe eingegeben. Wie echte Benutzer damit arbeiten, bleibt mir ein RĂ€tsel. Anscheinend nutzen nur wenige Menschen diese FunktionalitĂ€t speziell. Nun, oder es sind die EinschrĂ€nkungen der Demo, aber im Betrieb funktioniert alles gut.

Fazit


Das beschriebene Dokumenteneingabeschema ĂŒber eine separate Auswahlregisterkarte wurde von unseren Benutzern sehr geschĂ€tzt.

In der Praxis kann dieses Konzept auf verschiedene Weise kompliziert sein. Zeigen Sie beispielsweise anstelle einer Produktliste eine Artikelliste mit der Möglichkeit an, fĂŒr einzelne Merkmale unterschiedliche Mengen einzugeben. Oder in einem der Dokumente befanden sich Lager in den Zeilen, und es war erforderlich, die Mengen fĂŒr jedes dieser Lager in den Spalten festzulegen.

Ein solches Schema kann beispielsweise in derselben Reaktion implementiert werden, indem die aktuellen Zeilen des Dokuments als Status verwendet und mit zwei Komponenten auf zwei verschiedenen Registerkarten angezeigt werden. Es sollte jedoch beachtet werden, dass es in der Tabelle viele EintrĂ€ge mit Waren geben kann und Sie die sogenannte „unendliche Schriftrolle“ implementieren mĂŒssen. DarĂŒber hinaus ist es ratsam, dem Benutzer die Möglichkeit hinzuzufĂŒgen, Produkte in dieser Liste zu sortieren und zu filtern (und dies muss auf dem Server und nicht auf dem Client erfolgen, um keine zusĂ€tzlichen Daten dorthin zu ziehen). All dies wird fĂŒr den Entwickler zu einer eher nicht trivialen Aufgabe.

In der lsFusion-Plattform ist diese FunktionalitĂ€t sofort implementiert und erfordert nur den oben beschriebenen Code. Sie können versuchen, wie es funktioniert, und wenn Sie möchten, können Sie den Code online auf der entsprechenden Seite Ă€ndern. Hier ist der gesamte Quellcode, der auf der Registerkarte Plattform und dann durch Klicken auf Wiedergabe eingefĂŒgt werden kann:

Quellcode
CLASS Product '' ;
name '' = DATA STRING [ 50 ] (Product);

FORM product ''
OBJECTS p = Product PANEL
PROPERTIES (p) name

EDIT Product OBJECT p //
;

FORM products ''
OBJECTS p = Product
PROPERTIES (p) READONLY name
PROPERTIES (p) NEWSESSION NEW , EDIT , DELETE

LIST Product OBJECT p // ,
;

NAVIGATOR {
NEW products;
}

CLASS Supplier '' ;
name '' = DATA STRING [ 50 ] (Supplier);

in '' = DATA BOOLEAN (Supplier, Product); // TRUE,

FORM supplier ''
OBJECTS s = Supplier PANEL
PROPERTIES (s) name

OBJECTS p = Product //
PROPERTIES in(s, p), name(p) READONLY //

EDIT Supplier OBJECT s
;

FORM suppliers ''
OBJECTS s = Supplier
PROPERTIES (s) READONLY name
PROPERTIES (s) NEWSESSION NEW , EDIT , DELETE

LIST Supplier OBJECT s
;

NAVIGATOR {
NEW suppliers;
}

CLASS Order '' ;
date '' = DATA DATE (Order);
number '' = DATA INTEGER (Order);

supplier '' = DATA Supplier (Order);
nameSupplier '' (Order o) = name(supplier(o));

CLASS OrderDetail ' ' ;
order '' = DATA Order (OrderDetail) NONULL DELETE ;

product '' = DATA Product (OrderDetail);
nameProduct '' (OrderDetail d) = name(product(d));

quantity '-' = DATA NUMERIC [ 14 , 3 ] (OrderDetail);

FORM order ''
OBJECTS o = Order PANEL
PROPERTIES (o) date, number, nameSupplier

OBJECTS d = OrderDetail
PROPERTIES (d) nameProduct, quantity, NEW , DELETE
FILTERS order(d) = o

EDIT Order OBJECT o
;

EXTEND FORM order
OBJECTS p = Product
PROPERTIES name(p) READONLY
FILTERS in(supplier(o), p) //
;

DESIGN order {
OBJECTS {
NEW pane { //
fill = 1 ; //
type = TABBED ; // ,
MOVE BOX (d); //
MOVE BOX (p) { //
caption = '' ;
}
}
}
}

quantity '-' (Order o, Product p) =
GROUP SUM quantity(OrderDetail d) BY order(d), product(d);
lastOrderDetail ' ' (Order o, Product p) =
GROUP LAST OrderDetail d ORDER d BY order(d), product(d);

changeQuantity ' -' (Order o, Product p) {
INPUT q = NUMERIC [ 14 , 3 ] DO { //
IF lastOrderDetail(o, p) THEN { // ,
IF q THEN //
quantity(OrderDetail d) <- q IF d = lastOrderDetail(o, p)
WHERE order(d) = o AND product(d) = p; //
ELSE // -
DELETE OrderDetail d WHERE order(d) = o AND product(d) == p;
} ELSE
IF q THEN
NEW d = OrderDetail { //
order(d) <- o;
product(d) <- p;
quantity(d) <- q;
}
}
}

EXTEND FORM order
PROPERTIES (o, p) quantity ON CHANGE changeQuantity(o, p)
;

FORM orders ''
OBJECTS o = Order
PROPERTIES (o) READONLY date, number
PROPERTIES (o) NEWSESSION NEW , EDIT , DELETE
;

NAVIGATOR {
NEW orders;
}

Source: https://habr.com/ru/post/de464487/


All Articles