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})
    """);
}