Zum Inhalt

Auftragserfassung und -speicherung in Datenbank

Das ist ein Komplettbeispiel und baut auf die Kenntnisse aus den Tutorials Auftragsbearbeitung, Subtabelle und Entfernung auf. Hier können Sie das fertige Template Auftragserfassung runterladen. Zur Ausführung des Templates muss die notwendige Datenbankverbindung hergestellt werden. Schauen Sie dazu in das Kapitel Verknüpfung Datenbank.

Arbeiten mit Subformularen

In diesem Prozess werden Aufträge von Kunden erfasst und in der Datenbank gespeichert. Wir erstellen nun ein neues Template wie in folgender Abbildung dargestellt. Hierbei werden die beiden Webformulare der Prozessschritte Stammdaten abfragen und Auftrag anzeigen aus dem Tutorial Auftragsbearbeitung im ersten Schritt Auftrag erfassen zusammengefasst und die Groupboxen des ersten Formulars durch eine Subtabelle ersetzt. Im zweiten Schritt geht es um die Speicherung der Auftragspositionen in die Datenbank.

Um zwei Formulare in einem Schritt zu bearbeiten, benutzen wir Mehrblatt-Formulare also Subformulare. Wählen Sie im Edit-Menü Add Subform und legen die Beschriftung des Formularreiters fest. Wir bennennen das erste Subformular Anlegen Auftrag, wo wir den Kunden und das Auftragsdatum auswählen und dazu einen Auftrag anlegen. In einem weiteren Subformular Erfassen Auftragspositionen erfassen wir die Auftragspositionen. Auf die Erstellung der einzelnen Subformulare mit zugehörigen Controls gehen wir später ein.

Per Default werden alle Subformulare angezeigt und man kann diese durch Anklicken des entsprechenden Reiters aktivieren, wie in folgenden Abbildungen angedeutet.

Will man die Subformulare gezielt einblenden, etwa dass man erst nach vollständigem Ausfüllen des Subformulars Anlegen Auftrag das Subformular Erfassen Auftragspositionen bearbeiten können soll, so kann man dies mittels der Funktionen af_setSubformHidden(subformID, hidden) und af_activateSubform(subformID) realisieren. In den folgenden Abbildungen wird das zweite Subformular erst nach der Bearbeitung des ersten Formulars aktiviert.

Hierzu wird auf Formularebene ein onload-Ereignis definiert und dort die Funktion init() hinterlegt, die dafür sorgt, dass das Subformular Erfassen Auftragspositionen ausgeblendet und der Button auftrag_anlegen_button auf disabled gesetzt wird.


function init() 
{ 
 // Hide Erfassen Auftragspositionen + disable "Auftrag anlegen" 
 af_setSubformHidden("Erfassen Auftragspositionen", true); 
 af_setDisabled("auftrag_anlegen_button", true); 
} 

Der Button auftrag_anlegen_button wird enabled, wenn die Felder für Kundennummer und Auftragsdatum mit Werten versorgt wurden. Hierfür wurde bei beiden Feldern ein onchange-Ereignisse definiert, welche die Funktion checkEnableButton() (siehe nächste Abbildung) rufen, die ggf. den Button „freischaltet“.


function checkEnableButton() 
{ 
 // Prueft, ob Kundennummer und Auftragsdatum gesetzt sind 
 // und schaltet ggf. den Button ‚Auftrag anlegen’ frei 
 if (af_hasValue("kdnr_textbox") && af_hasValue("auftragsdatum_date")) 
 af_setDisabled("auftrag_anlegen_button", false); 
 else 
 af_setDisabled("auftrag_anlegen_button", true); 
}

Das „Umschalten“ von Subformular Anlegen Auftrag auf das FormularErfassen Auftragspositionen erfolgt durch die Funktion validateSubform0(), die beim onclick-Ereignis des Button auftrag_anlegen_button hinterlegt ist.


function validateSubform0() 
{ 
 // Prüfung, ob Subform0 vollständig ausgefüllt wurde. 
 // Falls ja, umschalten auf Subform1 
 if (af_hasValue("kdnr_textbox") && af_hasValue("auftragsdatum_date")) 
 { 
 af_setSubformHidden("Anlegen Auftrag", true); 
 af_setSubformHidden("Erfassen Auftragspositionen", false); 
 af_activateSubform("Erfassen Auftragspositionen"); 
 } 
 else 
 alert("Auftragserfassung ist unvollständig!"); 
} 

Realisierung von Auswahl-Tabellen

Im Subformular Anlegen Auftrag erstellen wir eine Subtable Kunde_SubtableView mit den Spalten Auswahl, Nummer, Name, Stadt und Bonitaet. Die weiteren Controls entnehmen Sie der folgenden Abbildung. Dabei verweist das Auftragsdatum auf das Output Parameter AuftrDatum und die Kundennummer Textbox auf KdNr.

Die Auswahl von Zeilen in einer Tabelle erfolgt im WebForm-Designer mittels Checkbox. Wir müssen daher der Subtabelle eine Checkbox-Spalte wie in der nächsten Abbildung dargestellt hinzufügen. Die Spalte Auswahl ist vom Typ Checkbox und besitzt keine caption. Die Checkbox-Einträge in den einzelnen Zeilen sind hierbei erst einmal unabhängig voneinander. D.h. wir können eine Checkbox aktivieren und deaktivieren, ohne dass dies sich diese auf die anderen Checkboxen in derselben Spalte auswirkt; die Mehrfachauswahl ist somit der Default. Welche Zeilen ausgewählt wurden, können wir mittels eines Schleifendurchlaufs und Anwendung der Funktion af_isChecked(controlname) ermitteln. In diesem Subformular soll nur ein Kunde aus der Subtabelle ausgewählt werden. Die zugehörige Datenstruktur der Subtable sieht wie folgt aus:

Die Verknüpfung der Subtable mit der Datenstruktur und die Versorgung mit Daten sowie die Zuordnung von Ein- und Ausgabeparametern erfolgen wie im Tutorial Auftragsbearbeitung (sehen Sie dazu das ganze Tutorial an) beschrieben. Die SQL-Anfragen für die Daten sehen wie folgt aus:
Anfrage Erstellen Kundenliste für Kunde_SubtableView:


SELECT kdnr, kdname, kdstadt, bonitaet  
FROM public.kunden  
ORDER by kdname  

Anfrage Ausgabe ausgewählter Kunde für die Kunden Textboxen im zweiten Subformular:

 
SELECT kdnr, kdname, kdstadt     
FROM kunden   
WHERE kdnr = $kdnr_textbox$  

Anfrage Teilekatalog für TeileKatalog_SubtableView:

  
SELECT p.teileid, p.farbe, t.teilename, p.preis   
FROM teiletypen as t join preisliste as p   
ON t.teileid = p.teileid   
ORDER by teileid;   

Im Subformular Erfassen Auftragspositionen sind zwei Subtabellen TeileKatalog_SubtableView und AuftragsPos_SubtableView enthalten. Zusätzlich gibt es Textboxen zur Ausgabe des ausgewählten Kunden und ein Datumselement auftragsdatum_date2 zur Anzeige des Auftragsdatums aus dem ersten Subformular. Aus dem Teilekatalog in der ersten Subtabelle dürfen mehrere Zeilen ausgewählt und für diese ausgewählten Teilen in der zweiten Subtabelle die Anzahl manuell erfasst werden.

Die zugehörigen Datenstrukturen der Subtabellen sind wie folgt:

Für die Ausgabe des Kunden verknüpfen wir die Textboxen mit den entsprechenden Spalten aus der Anfrage Ausgabe ausgewählter Kunde. Die Kundendaten werden durch ein Script kundeGewaehlt(elem), welches durch ein onclick-Ereignis in der Auswahlspalte der Subtabelle Kunde_SubtableView aufgerufen wird, übermittelt. Das Ergebnis der Anfrage Teilekatalog zeigen wir in der Subtabelle TeileKatalog_SubtableView. Die Übertragung der ausgewählten Teile in die Auftragspositionstabelle AufragsPos_SubtableView erfolgt durch ein Javascript rowSelected(elem), das als ein onclick-Ereignis in der Spalte Auswahl der Subtabelle TeileKatalog_SubtableView aufgerufen wird. Es existieren noch weitere Scripte zum Ein- und Ausblenden sowie zur Initialisierung der Subformulare. In der folgenden Tabelle finden Sie eine Übersicht von allen Javascripten, die in diesem Prozessschritt vorkommen.

Name der Funktion Control Ereignistyp
function init() Main Form onload
checkEnableButton() KdNr in Subform0 Anlegen Auftrag onchange
checkEnableButton() Auftragsdatum in Subform0 Anlegen Auftrag onchange
copyDate() Datumsfeld in Subform0 Anlegen Auftrag onchange
validateSubform0() auftrag anlegen_button onclick
validateForm() Main Form onsubmit
kundeGewaehlt(elem) Spalte Auswahl in Subtable Kunde_SubtableView onclick
rowSelected(elem) Spalte Auswahl in Subtable TeileKatalog_SubtableView onclick

Nun folgen die Scripte:


function init() 
{ 
 // Hide Erfassen Auftragspositionen + disable 'Auftrag anlegen" 
 af_setSubformHidden("Erfassen Auftragspositionen", true); 
 af_setDisabled("auftrag_anlegen_button", true); 
}

function checkEnableButton() 
{ 
 // Prueft, ob Kundennummer und Auftragsdatum gesetzt sind 
 // und schaltet ggf. den Button ‚Auftrag anlegen’ frei 
 if (af_hasValue("kdnr_textbox") && af_hasValue("auftragsdatum_date")) 
   af_setDisabled("auftrag_anlegen_button", false); 
 else 
   af_setDisabled("auftrag_anlegen_button", true); 
}
function copyDate() 
{ 
 // Uebernimmt ausgewähltes Auftragsdatum in Subform2 
 var datum = af_getValue("auftragsdatum_date"); 
 af_setValue("auftragsdatum_date2", datum); 
} 
function validateSubform0() 
{ 
 // Prüfung, ob Subform0 vollständig ausgefüllt wurde. 
 // Falls ja, umschalten auf Subform1 
 if (af_hasValue("kdnr_textbox") && af_hasValue("auftragsdatum_date")) 
   { 
     af_setSubformHidden("Anlegen Auftrag", true); 
     af_setSubformHidden("Erfassen Auftragspositionen", false); 
     af_activateSubform("Erfassen Auftragspositionen"); 
    } 
  else 
    alert("Auftragserfassung ist unvollständig!"); 
} 
function validateForm() 
{ 
 // Prüfung, ob SEND erlaubt werden kann 
 if (!af_hasValue("kdnr_textbox") || !af_hasValue("auftragsdatum_date")) 
   { 
     alert("Auftragserfassung ist unvollständig: Kundennummer o. Auftragsdatum fehlt!"); 
     return false; 
   } 
 else if 
   (af_getSubtableViewRowCount("AuftragsPos_SubtableView") < 1) 
     { 
        alert("Keine Auftragspositionen erfasst!"); 
        return false; 
      } 
  else 
    return true; 
}
function kundeGewaehlt(elem) 
{ 
  var rowID = elem.id.split(":")[2]; // Zeilennummer über die ID des Elements herausfinden 
  // falls "checked", alle anderen Checkeinträge löschen und Kontrollausgabe aktualisieren 
  if(af_isChecked("Kunde_SubtableView:Auswahl:" + rowID)) 
    { 
      var maxRowIndex = af_getSubtableViewRowCount("Kunde_SubtableView"); 
      for (var i = 1; i <= maxRowIndex; i++) 
        if (i != rowID) 
          af_setValue("Kunde_SubtableView:Auswahl:" + i,false, false); # 
        else // i == rowID 
          { 
            // Übertragen Werte in Kundennummer-Textbox 
            var kdnr = af_getValue("Kunde_SubtableView:Nummer:" + rowID); 
            var kdname = af_getValue("Kunde_SubtableView:Name:" + rowID); 
            var kdstadt = af_getValue("Kunde_SubtableView:Stadt:" + rowID); 
            af_setValue("kdnr_textbox", kdnr); af_setValue("kdnr_textbox2", kdnr); 
            af_setValue("kdname_textbox", kdname); af_setValue("kdstadt_textbox", kdstadt); 
          } 
    } 
    else 
      af_setValue("kdnr_textbox", ""); 
} 
function rowSelected(elem) 
{ 
  // Zeilennummer über die ID des Elements herausfinden 
  var rowID = elem.id.split(":")[2]; 
  // falls "checked", alle anderen Checkeinträge löschen, 
  // Kontrollausgabe aktualisieren 
  if(af_isChecked("TeileKatalog_SubtableView:auswahl:" + rowID)) 
    { 
      var maxRowIndex = af_getSubtableViewRowCount("TeileKatalog_SubtableView"); 
      for (var i = 1; i <= maxRowIndex; i++) 
        if (i != rowID) 
          af_setValue("TeileKatalog_SubtableView:auswahl:" + i,false, false); 
        else // i == rowID 
          { 
            // Übertragen Werte in Auftragspositionstabelle 
            var teilenr = af_getValue("TeileKatalog_SubtableView:teileid:" + rowID); 
            var farbe = af_getValue("TeileKatalog_SubtableView:farbe:" + rowID); 
            var teilename = af_getValue("TeileKatalog_SubtableView:teilename:" + rowID); 
            var preis = af_getValue("TeileKatalog_SubtableView:preis:" + rowID); 
            af_addSubtableRow("AuftragsPos_SubtableView"); 
            var newRow = af_getSubtableViewRowCount("AuftragsPos_SubtableView"); 
            af_setValue("AuftragsPos_SubtableView:teilenr:" + newRow, teilenr); 
            af_setValue("AuftragsPos_SubtableView:farbe:" + newRow, farbe); 
            af_setValue("AuftragsPos_SubtableView:teilename:" + newRow, teilename); 
            af_setValue("AuftragsPos_SubtableView:preis:" + newRow, preis); 

           } 
    } 
}

Realisierung von „Single-Selection“-Auswahltabellen

Wie bereits vorstehend erwähnt, ist die Mehrfachauswahl von Checkboxen einer Subtabelle der Default. Falls uns nur die Anzahl der ausgewählten Zeilen oder die Spaltensumme interessiert, dann müssen wir lediglich eine JavaScript-Funktion realisieren, mit der wir die einzelnen Zeilen durchlaufen der SubtableView durchlaufen und das Checkbox-Attribut mittels af_isChecked(…) auf true bzw. false prüfen. In unserem ersten Subformular brauchen wir aber eine Single-Selection Auswahltabelle, aus der wir einen Kunden auswählen und die Kundennummer anzeigen. Danach werden die Kundendaten und das Auftragsdatum im zweiten Subformular angezeigt.

In einer „Single-Selection“-Auswahltabelle kann stets nur max. eine Zeile per Checkbox ausgewählt sein, wie bei uns in der Kunde Subtabelle der Fall ist. Ein solches „Single-Selection“-Verhalten können wir einer SubtableView dadurch aufprägen, dass wir bei Auswahl einer Zeile die Checkboxen aller anderen Zeilen mit af_setValue(…) auf „false“ setzen . Da die Anwendungen der af_setValue-Funktion in diesen Checkboxen wiederum selbst onclick-Ereignisse auslösen („kaskadierende Events“) können, müssen wir in den af_setValue-Funktionsaufrufen den (optionalen) dritten Parameter auf false setzen, was das Auslösen von Events unterdrückt (siehe die mit # markierte Zeile weiter oben der Funktion kundeGewaehlt(elem) ).

Um herauszufinden, in welche Zeile geklickt wurde, definieren wir in der Checkbox-Spalte der SubtableView ein „onclick“-Ereignis. Bei diesem hinterlegen wir eine JavaScript-Funktion, der wir als Aufrufparameter „this“ übergeben. Die nächste Abbildung illustriert die Definition dieses Ereignisses und die Hinterlegung einer JavaScript Funktion namens kundeGewaehlt(this).

Das Attribut KdNr der gewählten Zeile wird in einer Textbox ausgegeben bzw. deren Inhalt gelöscht, wenn keine Zeile markiert ist. Nach der Kundenauswahl wird mittels auftrag_anlegen_button auf das zweite Subformular „umgeschaltet“, in dem die Positionen des Auftrags erfasst werden. Die Artikel werden per Single-Selection-Auswahltabelle ausgewählt und in der zweiten Subtabelle AuftragsPos_SubtableView angezeigt. Hier hinterlegen wir die Funktion rowSelected(elem) bei der Spalte Auswahl der Subtabelle TeileKatalog_SubtableView wieder als onclick-Ereignis. In dieser Funktion werden die gewählten Artikeln aus dem Teilekatalog in die Auftragspositionentabelle übernommen und um die gewünschte Anzahl ergänzt.

Speicherung in Datenbank

In den zweiten Prozessschritt Auftrag->DB binden wir eine Scripting-Aktivität executeScript und konfigurieren im Assistenten der Aktivität die Datenbankverbindung unter Extensions wie in der folgenden Abbildung dargestellt.

Das auszuführende Skript wird im Assistenten der Scripting-Aktivität wie in der folgenden Abbildung eingegeben. Als Skriptsprache wird Groovy benutzt und während der Eingabe durch Execute Script (rechts unten) auf Syntaxfehler getestet. Für die Speicherung der Aufträge in die Datenbank wird zuerst die Verbindung zur Datenbank hergestellt und danach zwei Insert-Abfragen ausgeführt. Die Inputparameter AuftrDatum und KdNr werden für die erste, die Subtable AuftragsPos für die zweite Abfrage verwendet. Vor der ersten Abfrage wird die höchste Auftragsnummer ermittelt und in die Tabelle auftraege mit den Daten des ausgewählten Kunden eingetragen. Für die Eintragung der Auftragspositionen in die Datenbanktabelle auftragspos wird jede Zeile der Subtable AuftragsPos ausgelesen und dabei die Nummer der Auftragspositionen automatisch ermittelt.


import de.aristaflow.adept2.extensions.datatypes.WebFormSubtable;
import java.sql.Timestamp;

def con = _jdbc.getConnection();
def sql = new Sql(con);

def auftrnr = sql.firstRow("SELECT MAX(auftrnr) + 1 AS auftrnr FROM auftraege")['auftrnr'];

def datum = new Timestamp($AuftrDatum.getTime());

sql.executeInsert("""
    INSERT INTO auftraege (auftrnr, kdnr, auftrdatum)
    VALUES (${auftrnr}, ${$KdNr}, ${datum})
""");

WebFormSubtable st = new WebFormSubtable();
st.loadFromUDTValue($AuftragsPos);
var anzahlPos = st.getRowCount();

for (i = 0; i < anzahlPos; i++)
{
    def pos = i + 1;
    def teileid = st.getValue("TeileNr", i);
    def farbe = st.getValue("Farbe", i); 
    def anzahl = st.getValue("Anzahl", i);

    sql.executeInsert("""
        INSERT INTO auftragspos (auftrnr, pos, teileid, farbe, anzahl)
        VALUES (${auftrnr}, ${pos}, ${teileid}, ${farbe}, ${anzahl})
    """);
}