...
1. Preisplanung
2. Preisplanung mit Preisen in den Stammdaten
3. Quotenplanung
4. Kopieren mit Bedingung auf dem Wert einer Kennzahl
5. Kopieren mit Bedingung und Iteration über Kennzahlname
6. Plausibilitätsprüfung von Daten
7. Rollierende Planung
8. Abschreibung
9. Rechnen mit Datentyp 'D'
10. Arbeiten mit Zeichenketten
In Version 1 wird geplant, in Version 2 sind die Preise in den Bewegungsdaten abgelegt. Die zu verändernden Merkmale sind:
● Version (0VERSION)
● Geschäftsjahr (0GJAHR)
● Kunde (0CUSTOMER)
Die Sätze haben die Besonderheit, dass die Merkmale Kunde und Geschäftsjahr den Wert nicht zugeordnethaben und deshalb in die Menge der zu verändernden Merkmale aufgenommen werden müssen. Weiterhin muss es für jedes zu planende Objekt in Version 1 ein Objekt in Version 2 geben, über das der Preis ermittelt werden kann. Wenn zu einem Artikel kein Preis geplant ist, wird eine Meldung ausgegeben. Die Berechnung wird nur ausgeführt, wenn die Kombination {MENGE,1,GJAHR,CUSTOMER} geplant, also > 0 ist.
DATA CUSTOMER TYPE 0CUSTOMER.
DATA GJAHR TYPE 0GJAHR.
DATA ARTICLE TYPE 0ARTICLE.
IF {PREIS,2,#,#} = 0.
ARTICLE = OBJV( ).
MESSAGE I001(/SEM/003) WITH ARTICLE.
ELSE.
FOREACH GJAHR, CUSTOMER.
IF {MENGE,1,GJAHR,CUSTOMER} > 0.
{ERLOS,1,GJAHR,CUSTOMER} = {MENGE,1,GJAHR,CUSTOMER} * {PREIS,2,#,#}.
ENDIF.
ENDFOR.
ENDIF.
Das Fehlen des Merkmals Artikel (0ARTICLE) in der Liste der zu verändernden Merkmale scheint überraschend, da sich die Preise, mit denen gerechnet wird, sich auf 0ARTICLE beziehen. Unter ausdrücklicher Einbeziehung des Merkmals 0ARTICLE würde das Beispiel wie folgt aussehen:
DATA CUSTOMER TYPE 0CUSTOMER.
DATA GJAHR TYPE 0GJAHR.
DATA ARTICLE TYPE 0ARTICLE.
FOREACH ARTICLE, GJAHR, CUSTOMER.
IF {PREIS,2,#,#,ARTICLE} = 0.
MESSAGE I001(/SEM/003) WITH ARTICLE.
ELSE.
IF {MENGE,1,GJAHR,CUSTOMER,ARTICLE} > 0.
{ERLOS,1,GJAHR,CUSTOMER,ARTICLE} = {MENGE,1,GJAHR,CUSTOMER,ARTICLE} * {PREIS,2,#,#,ARTICLE}.
ENDIF.
ENDIF.
ENDFOR.
Tatsächlich ist das Merkmal 0ARTICLE für die Formel überflüssig, da die Werte des Merkmals nicht geändert werden. Bei der Berechnung des geplanten Erlöses zeigt sich, dass auf beiden Seiten des Zuweisungsoperators jeweils auf denselben Artikel verwiesen wird.
Wir empfehlen, in einem solchen Fall das Merkmal nicht in die Menge der zu verändernden Merkmale aufzunehmen, da es für die Berechnung nicht benötigt wird, aber beim Zugriff auf die Werte Performance kostet. Ein weiteres Mittel, um die Formel zu beschleunigen, besteht darin, den Wert des Elementes {PREIS,2,#,#} in einer Hilfsvariablen zu speichern und dann mit dieser zu arbeiten. Falls der Wert eines Merkmals benötigt wird, um Fehlermeldungen auszugeben oder um Attributwerte zu ermitteln, kann mit der Funktion OBJV() der Wert gelesen werden.
Die Formel kann noch kürzer aufgeschrieben werden, wenn auf die Referenzdaten explizite zugegriffen wird. Es gibt dann außer Kennzahlname keine zu verändernden Merkmale. Die Formel wird je Datensatz durchlaufen. Eine FOREACH-Schleife über zu verändernde Merkmale ist damit überflüssig.
DATA ARTICLE TYPE 0ARTICLE.
IF {PREIS | 0VERSION = 2,0GJAHR = #,0CUSTOMER = #} = 0.
ARTICLE = OBJV( ).
MESSAGE I001(/SEM/003) WITH ARTICLE.
ELSE.
ERLOS = MENGE * { PREIS | 0VERSION = 2,0GJAHR = #,0CUSTOMER = #}.
ENDIF.
Wie sieht die Preisplanung aus, wenn der Preis in den Stammdaten abgelegt ist? Mit Hilfe der Funktion OBJV holen wir uns den Wert des Artikels. Mit Hilfe der Funktion ATRV wird der Wert des Attributes 0PRICEgelesen. Die Funktion ATRV hat im einfachen Fall zwei Argumente. Das erste Argument muss der Name eines Stammdatenattributes sein, das zweite Argument eine Variable. Mit Hilfe des Variablenwertes wird in der Stammdatentabelle der Wert des Attributs gelesen. Bei geklammerten Merkmalen sind folgende Fälle zu unterscheiden:
● Wenn die übergeordneten Merkmale zu verändernde Felder sind, müssen die Werte dieser Merkmale der Funktion in Form von Variablen mitgegeben werden. Die Zahl der Argumente der Funktion richtet sich in diesem Fall danach, wie viele Felder mitgegeben werden müssen.
● Wenn die übergeordneten Merkmale nicht in der Menge der zu verändernden Felder enthalten sind, werden die Werte automatisch aus den Werten des aktuellen Päckchens versorgt. Im folgenden Beispiel ist nur der Kennzahlname ein zu veränderndes Merkmal.
DATA ARTICLE TYPE 0ARTICLE.
ARTICLE = OBJV().
ERLOS = ATRV( '0PRICE', ARTICLE ) * MENGE.
Zu verändernde Merkmale sind Kennzahlname, Version (0VERSION) und Kunde (0CUSTOMER).
DATA GESERLOS TYPE F.
DATA GESMENGE TYPE F.
DATA CUSTOMER TYPE 0CUSTOMER.
FOREACH CUSTOMER.
GESERLOS = GESERL0S + {ERLOS,2,CUSTOMER}.
GESMENGE = GESMENGE + {MENGE,2,CUSTOMER}.
ENDFOR.
FOREACH CUSTOMER.
{ERLOS,1,CUSTOMER} = {MENGE,1,CUSTOMER} * GESERLOS / GESMENGE.
ENDFOR.
Zu veränderndes Merkmal ist Version. Als Merkmal für Bedingungen ist der Kennzahlname ausgewählt worden. Als Wert für den Kennzahlnamen wurde ERLOS ausgewählt. Die folgende Formel kopiert den Erlös von Version 1 nach Version 2, falls der Erlös in Version 1 größer als 500 ist. In diesem Beispiel können wir nicht die Planungsfunktion vom Typ Kopieren einsetzen, da hier keine Bedingungen auf Kennzahlwerten formuliert werden können. In der Regel ist es vorteilhafter, anstelle von Formeln die speziellen Planungsfunktionen zu verwenden, da diese effizienter implementiert sind.
IF {1} > 500.
{2} = {1}.
ENDIF.
Zu verändernde Merkmale sind Kennzahlname und Version. Im Gegensatz zum obigen Beispiel werden jetzt alle Kennzahlen nach Version 2 kopiert, falls der Erlös größer als 500 ist. Um die Zuweisung nicht für alle Kennzahlen schreiben zu müssen, definieren wir eine Variable RATIO vom Typ KEYFIGURE_NAME und iterieren mit Hilfe des FOREACH-Konstruktes über alle Kennzahlen der Planungsebene.
DATA RATIO TYPE KEYFIGURE_NAME.
IF { ERLOS, 1 } > 500.
FOREACH RATIO.
{ RATIO, 2 } = { RATIO, 1 }.
ENDFOR.
ENDIF.
Zu verändernde Merkmale sind Kennzahlname, Version und Artikel. Wir überprüfen, ob der geplante Erlös mindestens 90 Prozent des Erlöses der Version 1 erreicht. Wenn die Grenze unterschritten wird, gibt das System eine Warnmeldung aus.
DATA ARTICLE TYPE 0ARTICLE.
DATA MINERLOS TYPE F.
FOREACH ARTICLE.
MINERLOS = { ERLOS, 1, ARTICLE } * 0.9.
IF { ERLOS, 2, ARTICLE } < MINERLOS.
* Der geplante Erlös für Artikel &1 unterschreitet den vorgegebenen Mindesterlös
MESSAGE I034(ZSEM) WITH ARTICLE.
ENDIF.
ENDFOR.
Zu verändernde Merkmale sind Version und Geschäftsjahr/Periode. Die Ist-Daten der aktuellen Periode werden in die Planversion kopiert. Die Differenz wird auf die restlichen Perioden verteilt. Die aktuelle Periode wird aus einer Variablen ermittelt.
DATA ACTPER TYPE FISCPER.
DATA FISCPER TYPE FISCPER.
DATA SUM TYPE F.
DATA DELTA TYPE F.
* Periode aus der Variablen mit dem technischen Namen PERIODE lesen
ACTPER = VARV( 'PERIODE' ).
* Summe zum Gewichten besorgen
FOREACH FISCPER.
IF FISCPER > ACTPER.
SUM = SUM + { 1, FISCPER }.
ENDIF.
ENDFOR.
* Delta zwischen Planwert und Istwert bestimmen
DELTA = {1, ACTPER} - {0,ACTPER}.
* Planwert auf Istwert setzen
{1,ACTPER} = {0, ACTPER}.
* Delta gewichtet verteilen
FOREACH FISCPER.
IF FISCPER > ACTPER.
{1,FISCPER} = {1,FISCPER} + DELTA * {1,FISCPER} / SUM.
ENDIF.
ENDFOR.
Zu verändernde Merkmale sind Kennzahlname und Geschäftsjahr. Es wird der Wert der Kennzahl 0AMOUNT für fünf Jahre ermittelt. Anschaffungspreis ist 1000. Restwert ist 100. Abschreibungsprozentsatz ist 20 Prozent. Es wird linear abgeschrieben. Bei diesem Beispiel steht nicht die Funktion DECL(lineare Abschreibung) im Mittelpunkt des Interesses, sondern die Funktion TMVL. Diese Funktion hat als erstes Argument den Wert eines Zeitmerkmales und als zweites Argument einen Offset. Der Offset gibt an, den wievielten nächstgrößeren Wert die Funktion liefern soll. Es ist auch möglich, negative Offsets zu übergeben. Dann werden die entsprechenden kleineren Werte geliefert. Es wäre nicht möglich, mit einer FOREACH-Schleife den gleichen Effekt zu erzielen, da in den Bewegungsdaten nicht alle Jahre vorhanden sein müssen.
DATA JAHRE TYPE I.
DATA GJAHR TYPE 0FISCYEAR.
GJAHR = VARV( 'ACTYEAR' ).
DO.
JAHRE = JAHRE + 1.
GJAHR = TMVL( GJAHR, 1 ).
{0AMOUNT, GJAHR} = DECL( 1000, 100, 20, JAHRE).
IF JAHRE = 5.
EXIT.
ENDIF.
ENDDO.
Es ist auch möglich, mit dem Datentyp 'D' Berechnungen durchzuführen. Im folgenden ist ein kleines Beispiel aufgeführt. In der FOREACH- Schleife werden in D1 das Datum des ersten Tages in FISPCER und in D2 der letzte Tag in FISCPERermittelt. Daraufhin wird in I1 die Differenz zwischen D2 und D1 gebildet und zwei Tage subtrahiert. I1 ist vom Typ I. Wenn die Datumsangaben in D1 und D2 ungültig sind, kommt als Resultat 0 heraus. Wenn mit Feldern vom Typ D gerechnet wird, werden die konstanten Operanden daraufhin überprüft, ob es sich um gültige Datumsangaben handelt. Deshalb konnten wir nicht I1 = D2 - D1 - 2. schreiben, sondern mussten eine Hilfsvariable I2 verwenden.
DATA D1 TYPE D.
DATA D2 TYPE D.
DATA I1 TYPE I.
DATA I2 TYPE I.
DATA FISCPER TYPE 0FISCPER.
FOREACH FISCPER.
* Calculate 1st day of FISCPER
D1 = C2DATE( FISCPER, S ).
* Calculate last day of FISCPER
D2 = C2DATE( FISCPER, E ).
* Calculate the difference between last and 1st day minus two days
I2 = 2.
I1 = D2 - D1 - I2.
MESSAGE I001(UPF) WITH 'DIFFERENCE' I1.
ENDFOR.
Im folgenden Beispiel wird geprüft, ob die Merkmale Geschäftsjahr/Periode (0FISCPER), Geschäftsjahr (0FISCYEAR) und dreistellige Buchungsperiode (0FISCPER3) zueinander konsistent gefüllt sind. Geschäftsjahr/Periode ist sieben Zeichen lang; in den ersten vier Zeichen steht das Geschäftsjahr, in den Zeichen fünf bis sieben ist die Buchungsperiode abgelegt. Mit Hilfe der Funktion SUBSTR (Merkmalswert, Offset, Länge) werden aus dem Wert von Geschäftsjahr/Periode die entsprechenden Werte ausgelesen. Falls der Merkmalswert von Geschäftsjahr/Periode initial ist, wird er mit dem verketteten Wert von Geschäftsjahr und Buchungsperiode gefüllt. Dazu wird die Funktion CONCAT benutzt.
DATA FISCPER TYPE 0FISCPER.
DATA FISCPER_CMP TYPE 0FISCPER.
DATA YEAR TYPE 0FISCYEAR.
DATA PER TYPE 0FISCPER3.
DATA PER_CMP TYPE 0FISCPER3.
DATA YEAR_CMP TYPE 0FISCYEAR.
DATA KYFNM TYPE KEYFIGURE_NAME.
YEAR = OBJV( ).
PER = OBJV( ).
FISCPER_CMP = CONCAT( YEAR, PER3 ).
FOREACH KYFNM, FISCPER.
IF FISCPER IS INITIAL.
{KYFNM,FISCPER_CMP} = {KYFNM,FISCPER}.
ELSE.
PER_CMP = SUBSTR( FISCPER, 4, 3 ).
YEAR_CMP = SUBSTR( FISCPER, 0, 4 ).
IF YEAR <> YEAR_CMP OR PER <> PER_CMP.
* Fehlermeldung
MESSAGE E021(/SEM/003) WITH YEAR YEAR_CMP PER PER_CMP.
ENDIF.
ENDIF.
ENDFOR.