Die Beschreibung der Helper wurde aus allgemein\muster_qr_code.jrxml entnommen.
iReport = Java 7
Kalenderwoche aus Timestamp errechnen
und das immer für die vorige Woche, als vom Stichtag = Timestamp den Wochentag abzuziehen, um auf den Sonntag davor zu kommen
com.lp.util.HelperReport.berechneKWJahr(
new java.sql.Date(
$P{P_STICHTAG}.getTime() -
$P{P_STICHTAG}.getDay()*1000*3600*24
)
)
SQL Abfragen für einen Return-Wert
$P{P_SQLEXEC}.execute( SQL Query String)
SQL Abfragen für mehrere Werte
$P{P_SQLEXEC}.executes( SQL Query String)
Beispiel:
Variable Werte 
$P{P_SQLEXEC}.executes(
"select c_nr, f_gewichtkg, f_materialgewicht from ww_artikel " +
"where i_id = (select i_id from ww_artikel where c_nr='"+$F{Artikelnummer}+"');"
)
liefert ein Object in dem im Element 0 die Artikelnummer, im Element 1 das Gewicht usw. enthalten ist.
Die direkte Verwendung in den Feldern könnte wie folgt aussehen:
((Object[])$V{Werte})[0]
((Object[])$V{Werte})[1]
((Object[])$V{Werte})[2]
Gerne auch Variablen verwenden. Dabei muss darauf geachtet werden, dass die Variablen Klasse dem tatsächlichen Wert entspricht. Z.B. String für die c_nr und Double für das Gewicht.
Beachte nur mehr is null gültig
Mit den aktuell verwendeten Postgres-Datenbankservern ist ein Vergleich auf einen NULL Wert nur mehr mit is null zulässig. Die in sehr alten Postgresserver mögliche Form von = null wird nicht mehr unterstützt.
Werte aus der Datenbank
- Bigint aus DB = Long im Jasper Report
- sum() aus der DB liefert immer BigDecimal
Werte aus dem Report anders zusammenstellen und eigenständig sortieren
Manchmal will man einen Teil eines Reports anders sortieren, verschiedene Zwischensummen darstellen und ähnliches. Hier sei als Beispiel der Report ../eingangsrechnung/er_eingangsrechnung_alle.jrxml genannt. Auf diesem sieht man am Ende des Reports eine Zusammenfassung der verschiedenen Steuersätze. Dafür wird der Inhalt, den man an den Subreport übergeben will, in einer Array-List gesammelt (siehe Variable LISTE_UST_SAETZE bzw. LISTE_UST_SAETZE_ADD). Mit dieser Arraylist wird über einen Helper ein Sub-Report aufgerufen (im Summary er_eingangsrechnung_kontierung_summary). Das besondere an dem Helper ist, dass nach dem ersten Element sortiert wird. Dafür muss dieses ein String sein. Nicht zuletzt deshalb gibt es für diesen Helper zwei Ausführungen.
- HelperReport.sortList wird diesem Helper im Sort ein Null-Wert übergeben, wird mit einer Fehlermeldung abgebrochen
- HelperReport.sortListNoNull dieser Helper akzeptiert auch null in der Sortierung
Array zusammenfügen
Manchmal hat man auch die Aufgabe dass man mehrere Arrays zusammenfügen muss. Ein Beispiel dafür ist der Report ..\eingangsrechnung\er_eingangsrechnung_alle.jrxml in dem man in die Variable LISTE_UST_SAETZE auch die Werte aus den Splittbuchungen mit aufführen will.
Ein Beispiel dazu findest du im Detail 3

im Feld F_TEXT Liste UST Sätze in dem an das Array noch die Details aus der Kontierungs-Splittbuchung dazugefügt werden.
Wo finde ich welches Feld
Oft steht man vor der Herausforderung, in welcher Tabelle welches Feld zu finden ist. Hat man nun eine Ahnung wie das Feld heißen könnte, kann man die Verwaltungstabellen des PostgresQL befragen. Also:
select * from information_schema.columns where column_name like '%herst%';
liefert z.B. eine Liste aller Tabellen die Spaltennamen mit herst beinhalten.
Strings in Zahlen wandeln
com.lp.util.HelperReport.toBigDecimal (String bigDecimal, Locale stringLocale) mit und ohne Local
com.lp.util.HelperReport.toInteger(String integer)
Datum aus Date/Timestamp
$V{LosEnde}.toLocaleString().substring(6,10)+"-"+
$V{LosEnde}.toLocaleString().substring(3,5)+"-"+
$V{LosEnde}.toLocaleString().substring(0,2)
/* $V{LosEnde}.toLocaleString() liefert DD.MM.JJJJ */
ACHTUNG: Liefert das Datum in Abhängigkeit des Report-Locales. Also bei italienisch die italienische Schreibweise (8-nov-2023), welche für SQL Abfragen dann nicht verwendbar ist. Für SQL Abfragen daher z.B. (new SimpleDateFormat(“yyyy-MM-dd”, Locale.GERMAN)).format($V{Datum}) verwenden. Siehe auch.
Zahlen in String wandeln
String.format("%1$,.2f" , $V{DBIIIam})
Die Bedeutungen
| Zeichen | Bedeutung |
|---|---|
| %1$ | das nachfolgende betrifft das Argument 1 (man kann auch mehrere Werte hintereinander ausgeben) |
| , | im Locale formatiert mit Tausendertrenner ACHTUNG: in AT ist der Tausendertrenner leider das Space |
| .2f | Vorkommastellen nicht definiert und dann 2 Nachkommastellen ausgegeben als Fließzahl |
Datum in String konvertieren
(new SimpleDateFormat("dd.MM.yyyy", Locale.GERMAN)).format($P{P_ANGEBOTSGUELTIGKEIT})
Locale.ENGLISH
bei den Schreibweisen auf 24 Std 12 Std achten, für Kalenderwoche auch auf die Java Definitionen (siehe Erfolgsrechnung bzw. Link oben)
Mögliche Beispiele:
(new SimpleDateFormat("yyyy-MM-dd", Locale.GERMAN)).format($V{DiesesMonat})+" 00:00:00"
(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.GERMAN)).format($F{Von})
(new SimpleDateFormat("dd.MM.yyyy", Locale.GERMAN)).format($V{V_HEUTE}) -- im in Deutsch lesbaren Format
String in Datum konvertieren
Wichtig Datum muss im Stringformat dd.MM.yyyy übergeben werden
com.lp.util.Helper.parseString2Date($F{F_REALISIERUNGSTERMIN})
Beginnzeitpunkt rechnen
Von Obigem bekommt man ein Date, welches mit .getTime() in ein Long verwandelt wird. Hier kann man nun ms (Millisekunden) als Long dazuzählen und mit new java.sql.Timestamp(long) in einen Timestamp verwandeln, mit dem man nun rechnen kann.
So will man z.B. für den jeweiligen Tag wissen, wieviele Stunden der Mitarbeiter vor 6:00 gearbeitet hat. Also:
- z.B. in die Variable Datum, welche ein Date ist:
com.lp.util.Helper.parseString2Date(
(new SimpleDateFormat("dd.MM.yyyy", Locale.GERMAN)).format($F{Zeit}) )
- und dann in die Variable Beginn
new java.sql.Timestamp($V{Datum}.getTime()+(6*3600*1000))
- somit erhält man als long
$V{Beginn}.getTime() - $F{Kommt}.getTime()
Stunden dazu oder abziehen
Siehe z.B. rech_rechnung_abrechnung_detail_zeitraum.jrxml
Variable bis
new java.sql.Timestamp (($F{t_zeit}.getTime() + (new Double ($F{n_stunden}.doubleValue()*3600*1000)).longValue()))
Wichtig: Man rechnet mit dem Long und wenn man dann wieder eine Uhrzeit braucht, die Konvertierung auf Timestamp
Tagesdifferenzen errechnen
Wenn man Tagesdifferenzen errechnen will, so hat sich folgende Herangehensweise bewährt:
(($V{V_HEUTE}.getTime() - $F{Liefertermin}.getTime()) / 3600 / 24 / 1000) -> liefert die entsprechenden Tage als Long
V_HEUTE = Calendar.getInstance(Locale.GERMAN).getTime()
Letzter des Monates
com.lp.util.HelperReport.getLetztenTagDesMonats($V{V_HEUTE}, 0)
Das ,0 ist der Monatsversatz, der dazugerechnet wird. Siehe z.B. auch fc_deltaliste_entwicklung.jrxml
Timestamp to Date
Bedeutet, dass die Zeit beim Datum, das auch ein Timeobjekt ist, auf 00:00:00 gesetzt wird.
new java.sql.Date($V{LosBeginn}.getTime())
Kalenderobjekt
Siehe: com.lp.util.HelperReport.asKalender
Dezimalstunden als hh:mm drucken
((String)(com.lp.util.HelperReport.konvertiereZeitDezimalInHHMMSS($V{V_SUMMEDAUER},2,false)))
wobei die Variable ein BigDecimal sein muss. Wenn hinten true, dann auch Sekunden
Date und Timestamp
Da es immer wieder mühsam ist (für den Report Schreibenden), wie man vom einen zum anderen kommt.
| von -> nach | Formel | Bemerkung |
|---|---|---|
| Date -> Timestamp | new java.sql.Timestamp($V{V_HEUTE}.getTime()) | Die resultierende Variable ist als Timestamp definiert |
| Timestamp -> Date | new java.sql.Date($V{LosBeginn}.getTime()) | Die resultierende Variable ist ein Date |
Zusatz: mit getTime() bekommt man ein long, was ein primitiver Java Typ ist. Wir brauchen in den Reports aber Objekte, darum eben das entsprechende new java.sql…..
Zahlen in String konvertieren
String.format("%05d", $F{F_ARBEITSGANG})
nur für integer Siehe auch
BigDecimal to String
String.format("%05.4f" , $V{Rabatt}.doubleValue()\*100).replace(",",".")
Je nachdem, was man damit machen muss, es kommt der String im default Locale, also ev. noch die Dezimaltrenner usw. bearbeiten.
Time in Double konvertieren
Manchmal muss man aus der Datenbank eine Time, z.B. die Sollzeit eines Zeitmodelles, in ein Double konvertieren, um damit weiterrechnen zu können.
$V{U_Sollzeit} == null ? 0.00 :
((new Double($V{U_Sollzeit}.getTime())).doubleValue() / 1000 / 3600 ) +1.0
Gerade oder ungerade
für ein int
$V{KW_int}.intValue()\%2 == 0 ? ist eine gerade Zahl
für ein double
xxx.doubleValue()\%2 == 0 ? ist eine gerade Zahl
Fremdsprachige Installationen
Bei fremdsprachigen Installationen, z.B. Konzernsprache in Englisch, müssen bereits die default Reports in der Mandantensprache, z.B. Englisch sein.
D.h. unter z.B. report/auftrag/anwender/ müssen bereits die englischsprachigen Reports für den Auftrag sein. Sollte dann ein Kunde eine deutsche AB benötigen,
ist diese unter 001/de zu hinterlegen.
Zugriff auf die Bezeichnung der intelligenten Zwischensumme
Da die intelligente Zwischensumme hierarchiefähig ist, ist der eigentliche Feldinhalt ein String[Array]. Das bedeutet, will man nun auf den Inhalt zugreifen, so muss das Array-Element angegeben werden. So erhält man z.B. mit $F{F_ZWSTEXTE}[0] eben die Bezeichnung der ersten Zeile des Textes der intelligenten Zwischensumme.
Zugriff auf weitere Infos der Lagerbewegungen
Manchmal benötigt man auch genauere Infos aus der Lagerbewegung.
Dafür gibt es in einigen wenigen Reports das Field F_I_ID_BUCHUNG. Damit kann man sich aus der Lagerbewegungstabelle weitere Details holen.
So z.B. mit nachfolgender Abfrage in einer Variable die Menge exakt dieser Lagerbewegung.
$P{P_SQLEXEC}.execute(
"select n_menge from ww_lagerbewegung where i_id_buchung="+$F{F_I_ID_BUCHUNG}+";"
)
Werte von Gruppen aufsummieren
Manchmal hat man die Situation, dass Werte sich aus Gruppensummen ergeben, anhand dessen ergeben sich verschiedene andere Werte mit denen man dann weiterrechnen sollte.
Ein gutes Beispiel dafür ist z.B. die Zusammenfassende Meldung (ZM) aus der Ausgangsrechnung.
Hier wird die Summe je UID Nummer errechnet und auf ganze Euro gerundet. Diese Werte sollten nun für die Kontrollsumme aufsummiert werden.
Siehe dazu das Formular rech_zusammenfassendemeldung, die Variable Leistung_Gesamt_gerundet.
Timestamp / Datum formatieren
von ist ein Timestamp
(new SimpleDateFormat("HH:mm", Locale.GERMAN)).format($F{Von}.getTime())
jetzt als String
new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new java.util.Date())
zwei Timestamps nur das Datum vergleichen
https://tableplus.com/blog/2018/07/postgresql-how-to-extract-date-from-timestamp.html
To extract a date (yyyy-mm-dd) from a timestamp value For example, you want to extract from ‘2018-07-25 10:30:30’ to ‘2018-07-25’
- Extract from a timestamp column: Use date() function: SELECT DATE(column_name) FROM table_name;
- Extract date from a specific timestamp value: Cast the timestamp to a date by adding ::date suffix: SELECT ‘2018-07-25 10:30:30’::TIMESTAMP::DATE; Or combine date() and substring() function: SELECT DATE(SUBSTRING(‘2018-07-25 10:30:30’ FROM 1 FOR 10));
im Query mit Monaten rechnen
(t_letztewartung+(i_wartungsintervall \* '1 month'::INTERVAL))
eine weitere interessante Variante ist
(start_date + (duration || ' month')::INTERVAL) < '2010-05-12'
siehe https://stackoverflow.com/questions/5909363/calculating-a-date-in-postgres-by-adding-months
oder auch
https://www.postgresqltutorial.com/postgresql-string-functions/postgresql-to_char/
TO_CHAR(n_min, '999999.99') || ' - ' || TO_CHAR(n_max,'999999.99')
aus ...\stueckliste\stk_gesamtkalkulation_konfigurationswerte.jrxml
Von Bis Zeiten aufsummieren
select sum(EXTRACT(EPOCH FROM (t_bis - t_von))) from pers_maschinenzeitdaten where ...
Istzeit einer Arbeitsgangposition
Bei der Reportgestaltung ergibt sich immer wieder die Forderung, dass man für eine Soll-Zeit-Position die Istzeit errechnen muss.
Aufgrund der Eigenschaft des Kieselstein ERP ist dies leider keine Kleinigkeit.
Der Trick liegt hier darin, dass man das Ende errechnet. Zusätzlich ist zu berücksichtigen, dass Zeitbuchungen der Mitarbeiter auch durch Pausen unterbrochen werden können.
$P{P_SQLEXEC}.execute(
"select sum(EXTRACT(EPOCH FROM (ende - beginn)))/3600 as iststunden from "+
"("+
"select t_zeit as beginn,"+
"(select t_zeit from pers_zeitdaten as danach where danach.personal_i_id=pers_zeitdaten.personal_i_id and danach.t_zeit > pers_zeitdaten.t_zeit "+
"order by t_zeit limit 1) as ende "+
"from pers_zeitdaten where c_belegartnr = 'Los' and i_belegartid="+$F{los_i_id}+" and i_belegartpositionid = "+$F{soll_i_id}+" "+
"order by t_zeit "+
") as foo;"
)
Hier fehlt noch die Berücksichtigung der Pausen.
Mehrere Felder in einen String
Manchmal benötigt man die verschiedenen Spaltenwerte einer Tabelle in einem String. So will man z.B. die verschiedenen möglichen Sperren in einer einzigen Variablen haben. Anstatt der Concat Funktion kann hier im PostgresQL das string_agg verwendet werden.
$P{P_SQLEXEC}.execute(
"select string_agg(ww_artikelsperren.c_grund, ', ') from ww_artikelsperren "+
"inner join ww_artikel ON ww_artikel.i_id = ww_artikelsperren.artikel_i_id "+
"and ww_artikel.c_nr='"+$F{F_IDENT}+"' "+
"and ww_artikel.mandant_c_nr='"+$P{P_MANDANT_OBJ}.getMandantCNr()+"';"
bzw. die Mengenstaffeln der Angebotsstückliste in einen String
select string_agg(cast (n_menge as varchar(255)), '| ') from as_agstklmengenstaffel
where agstkl_i_id=(select i_id from as_agstkl where c_nr='25/0000007' and mandant_c_nr='001')
Wenn du nur einen Wert haben willst, musst du distinct verwenden.
select string_agg(distinct personal_i_id,',') from pers_zeitdaten where c_belegartnr = 'Los' and i_belegartid=336420 and i_belegartpositionid = 192495
einen Subreport mit Tagen
com.lp.util.HelperReport.getSubreportKalendertage(
$P{P_VON},
$P{P_BIS},
$P{P_MANDANT_OBJ}.getTheClientDto())
Liefert einen Subreport mit Datum, Feiertag und Sollzeit (in Stunden) des Firmenzeitmodells
Beispiel siehe: proj_projekt_journal_offene_gantt_zeitachse.jrxml
Query, um eine Summe der jüngsten 10 Mengen zu erhalten
Der Trick liegt hier darin, dass man sich mit einem Select (dem inneren) die Werte holt, den man dann mit einem zweiten Select (dem äußeren) aufsummiert. Man könnte auch sagen, dass man damit einen zweistufigen Select macht. Also z.B. für die Aufträge:
select sum(n_menge) from (
select n_menge from auft_auftragposition
inner join auft_auftrag on auft_auftrag.i_id=auft_auftragposition.auftrag_i_id
where artikel_i_id in (select i_id from ww_artikel where c_nr like 'ABC%')
order by auft_auftrag.t_belegdatum desc
limit 10) as foo;
Für diverse SQL Querys
Siehe https://www.postgresql.org/docs/current/functions-formatting.html alleine schon das SQL kann jede Menge
X_TEXT direkt aus der Datenbank holen
Nachdem im Jasper üblicherweise mit Strings (und nicht mit String-Objekten) gearbeitet wird, aber in der Datenbank auch lange / große X_Texte abgelegt sind, müssen diese mittels CAST aus der Datenbank geholt werden. Z.B. für die Bemerkung aus einer Kostenstelle.
$P{P_SQLEXEC}.execute(
"select CAST(X_BEMERKUNG as VARCHAR(3000)) from LP_KOSTENSTELLE where C_NR = '10';"
)
Beliebiges Textmodul am Report andrucken
Dafür steht der Helper
com.lp.util.HelperReport.getMediastandardTextHtml("Name des Textmoduls", "001", $P{REPORT_LOCALE})
zur Verfügung.
Abfrage mit locale
Um das locale in den Querys verwenden zu können:
{REPORT_LOCALE}.toString().replace("_","")
z.B. Übersetzung der Bezeichnung der Mengeneinheiten
$P{P_SQLEXEC}.execute(
"select c_bez from lp_einheitspr where einheit_c_nr='"+$P{P_EINHEIT}+"' and locale_c_nr='"+$P{REPORT_LOCALE}.toString().replace("_","")+"';"
)
Datenreihen mit Datum generieren
Für PostgresQL (MS-SQL ist anderes und wird, da nicht OpenSource, von Kieselstein ERP nicht verwendet).
Tage zwischen Datumsbereich:
SELECT day::date
FROM generate_series(timestamp '2023-03-01', timestamp '2023-03-31', interval '1 day') day;
Ergebnis:
“2023-03-01”
“2023-03-02”
“2023-03-03”
…
“2023-03-28”
“2023-03-29”
“2023-03-30”
“2023-03-31”
Siehe z.B. …\personal\pers_maschinenproduktivitaet.jrxml
Siehe dazu auch, z.B. proj_projekt_journal_alle_detailliert_zugehoerige_belege_zeitachse.jrxml
com.lp.util.HelperReport.getSubreportKalendertage(
$V{VonBereich},
$V{BisBereich},
$P{P_MANDANT_OBJ}.getTheClientDto())
Stunden für Zeitbereich:
SELECT day::timestamp
FROM generate_series(timestamp '2023-03-01 12:00', timestamp '2023-03-02 18:00', interval '1 hour') day;
“2023-03-01 18:00:00”
“2023-03-01 19:00:00”
…
“2023-03-02 09:00:00”
“2023-03-02 10:00:00”
1. Tag im Monat:
SELECT date '2023-03-01' + interval '1' month \* s.a AS date
FROM generate_series(0,3,1) AS s(a);
Ergebnis:
“2023-03-01 00:00:00”
“2023-04-01 00:00:00”
“2023-05-01 00:00:00”
Raufzählen
SELECT * FROM generate_series(1,3);
Ergebnis:
1
2
3 als integer
Verfügbarkeiten laut Zeitmodell berechnen
Manchmal hat man das Problem, dass man die verfügbaren Stunden aus Zeitmodellen errechnen muss. Dies geht z.B. mit:
select sum(
(select l_verfuegbarkeit from pers_maschinenzmtagesart where tagesart_i_id=coalesce((select tagesart_i_id from pers_betriebskalender where mandant_c_nr='001' and t_datum = tage.day), extract(isodow from tage.day)+10)
and maschinenzm_i_id=(
select maschinenzm_i_id from pers_maschinemaschinenzm
where maschine_i_id=(select i_id from pers_maschine where c_identifikationsnr = '67' and mandant_c_nr='001')
and t_gueltigab <= tage.day
order by t_gueltigab desc limit 1
)
)
) / 1000 / 3600
from (
SELECT day::date
FROM generate_series(timestamp '2024-08-12', timestamp '2024-08-18', interval '1 day') day) as tage;
Siehe z.B. pers_maschinenproduktivitaet.jrxml
Konvertieren auf BigDecimal
Das Einfachste ist BigDecimal.valueOf(value) wobei value z.B. ein Double sein kann.
gerundet auf Nachkommastellen
BigDecimal.valueOf(value).setScale(2, BigDecimal.ROUND_HALF_UP)
Double runden
Manchmal muss man auch Double auf Nachkommastellen runden. Das geht eigentlich mit Math.round, wobei dieses einfach die Nachkommastellen wegrundet. D.h. der Wert ist vorher entsprechend umzurechnen. Z.B.:
Math.round($V{EchtesIst}.doubleValue() * 100)
Usecase ID wird nicht angedruckt
Macht man einen Druck der Auswahlliste (FLR Liste) muss rechts oben die UseCaseID angedruckt werden.
Diese wird nicht angedruckt, wenn im ../report/allgemein auch der flrdruck.jasper vorhanden ist.
Zusätzlich darf es den flrdruck.jrxml ausschließlich ein Mal im allgemein des Wildfly (LW:/kieselstein/dist/wildfly-26.1.2.Final/kieselstein/reports/allgemein) geben und in keinem anderen Verzeichnis.
Das führende Herr / Frau ersetzen
Manchmal will / muss man die förmlichen Anreden entfernen. Also aus Herr Mustermann nur Mustermann haben. Das macht man üblicherweise mit replace. Da es aber auch vorkommen kann, dass der Name des Ansprechpartners Herr enthält muss man das über .replaceAll("^Herr","") machen. D.h. es wird NUR das erste Herr durch den nachfolgenden (Leer-)String ersetzt. Ganz genau muss man dann auch noch auf den beginnenden String prüfen. Für die Ansprechpartner gehen wir hier davon aus, dass es immer eine entsprechende Anrede gibt.
Da man damit auch oft noch das Frau entsprechend herausfiltern will, heißt das dann:
.replaceAll("^Herr ","").trim().replaceAll("^Frau ","").trim()
Subreport overflowed on a band that does not support overflow
Wenn das nicht der Title, die Page Header / Footer betrifft, dann ist der Report, der den Subreport aufruft auf Horizontal gestellt. Er muss auf Vertikal gestellt sein. Passiert gerne, wenn man Reports umkopiert, z.B. mit mehreren Columns und dann gehts am Anfang und auf einmal nicht mehr (weil dann der Overflow kommt). D.h. wenn die Columns auf 1 (zurück-) gesetzt werden, dann auf die Richtung achten.
Zu Datum Tage dazuzuzählen
com.lp.util.Helper.addiereTageZuDatum(date Datum, int Tage)
Beispiel
com.lp.util.Helper.addiereTageZuDatum(com.lp.util.Helper.parseString2Date($P{Liefertermin}) , -2)
im Query zum Datum / Timestamp Tage dazuzählen
select (cast(fert_los.t_produktionsbeginn as date) + i_maschinenversatztage),
fert_los.t_produktionsbeginn, i_arbeitsgangnummer, i_unterarbeitsgang, i_maschinenversatztage, * from fert_lossollarbeitsplan
inner join fert_los on fert_los.i_id=fert_lossollarbeitsplan.los_i_id
where fert_los.c_nr='24/01622-993' and mandant_c_nr='001'
order by i_arbeitsgangnummer, i_unterarbeitsgang;
Wochentage / Wochentagsnamen andrucken
com.lp.util.HelperReport.getWochentag($P{REPORT_LOCALE}, <Timestamp>$F{Datum})
com.lp.util.HelperReport.getWochentag($P{REPORT_LOCALE}, new java.sql.Timestamp($F{BeginnDatum}.getTime()) ... wenn das ein Date ist
Daten anders sortieren
Üblicherweise werden die Daten des Reports anhand der gewählten Sortierung übergeben. Manchmal will man aber diese, z.B. in einer Reportvariante, anders sortieren. Um dies zu bewerkstelligen, kann direkt im jrxml das Sortierkriterium angegeben werden.
Es muss dies zwischen field name und variable eingefügt werden.
D.h. hier muss:
eingetragen werden. Damit werden die Daten vom Jasper nach diesem Feld sortiert. Beispiel siehe z.B.: ..\report\bestellung\bes_sammelmahnung.jrxml

Wichtig: Dies geht nur für original erhaltene Fields, leider nicht für Variablen.
Sortierung des Materials des Fertigungsbegleitscheines
So wie oben beschrieben, einfach nur zwischen den Zeilen field_name und variable die Sortfields einfügen.
\<sortField name="F_ARBEITSGANG"/><br>
\<sortField name="F_UNTERARBEITSGANG"/><br>
\<sortField name="F_MATERIAL_LAGERORT"/><br>
Dies ist leider nur im XML ersichtlich.
EMail Nachricht aus dem Report erzeugen
Mit folgendem Helper kann aus dem Report heraus eine Nachricht versandt werden. Z.B. wenn ein Wareneingang gebucht wurde und das Wareneingangsetikett gedruckt wird.
com.lp.util.HelperReport.emailSenden(
"wareneingang@kieselstein-erp.org",
"WE zu BS: "+$F{F_BESTELLNUMMER},
"Es wurde ein Wareneingang von "+$F{F_IDENT}+" "+$F{F_BEZ}+" gebucht",
$P{P_MANDANT_OBJ}.getTheClientDto())
- Empfänger
- Betrifft
- Nachricht
- Clientobjekt, um es versenden zu können.
Links hinterlegen
Manchmal ist es praktisch, wenn hinter einem Text, einem Bild ein Hyperlink hinterlegt wird. Damit braucht der Anwender nur auf den Link zu klicken und schon hat er die benötigte Information. Dafür muss dies ein Text Field sein. Dann mit der rechten Maustaste auf das Field und Hyperlink auswählen.
Dies nun auf

Hyperlink type Reference stellen und in den Reference Reiter den gewünschten Webaufruf als String (mit umschließenden Hochkomma “) eintragen.
Beispiel: artikel/ww_inventurstand.jrxml im Lastpagefooter.
Links als GoTo hinterlegen
Manchmal ist es auch praktisch aus dem Formular heraus einen Goto z.B. auf den Artikel oder einen Beleg zu machen. Dafür wird eine besondere Form des Hyperlinks verwendet. Idealerweise verwendest du die Artikelstatistik als Vorlage um dies in anderen Belegen einzubauen.

Der besondere Trick liegt im Reiter Link parameters mit den Parameter namen
- WhereToGoTo
- Key
In whereToGoTo kommt die Helperfunktion für den Aufruf des jeweiligen Modules rein
in Key kommt die Belegnummer oder die I_ID des anzuzeigenden Datensatzes rein.
Im Reiter Tooltip kannst du einen entsprechenden String hinterlegen. Leider werden keine Zeilenumbrüche unterstützt.
Aktuell gibt es folgende Helper:
| Helper | Bedeutung |
|---|---|
| com.lp.util.GotoHelper.goto_RECHNUNG_AUSWAHL() | Springe auf die Rechnung |
| com.lp.util.GotoHelper.goto_LIEFERSCHEIN_AUSWAHL() | Springe auf den Lieferschein |
| com.lp.util.GotoHelper.goto_GUTSCHRIFT_AUSWAHL() | Springe auf die Gutschrift |
| com.lp.util.GotoHelper.goto_BESTELLUNG_AUSWAHL() | Springe auf die Bestellung |
| com.lp.util.GotoHelper.goto_FERTIGUNG_AUSWAHL() | Springe auf das Los |
| com.lp.util.GotoHelper.goto_AUFTRAG_AUSWAHL() | Springe auf den Auftrag |
| com.lp.util.GotoHelper.goto_ANFRAGE_AUSWAHL() | Springe auf die Anfrage |
| com.lp.util.GotoHelper.goto_ARTIKEL_AUSWAHL() | Springe auf den Artikel |
| com.lp.util.GotoHelper.goto_ANGEBOT_AUSWAHL() | Springe auf das Angebot |
| com.lp.util.GotoHelper.goto_ANGEBOTSTKL_AUSWAHL() | Springe auf die Angebotsstückliste |
| com.lp.util.GotoHelper.goto_STUECKLISTE_AUSWAHL() | Springe auf die Stückliste |
| com.lp.util.GotoHelper.goto_PROJEKT_AUSWAHL() | Springe auf das Projekt |
| com.lp.util.GotoHelper.goto_ZEITERFASSUNG_ZEITDATEN() | hier muss das ZEITDATEN_I_ID übergeben werden, womit auf die Zeitbuchung gesprungen wird |
| com.lp.util.GotoHelper.goto_ZWISCHENABLAGE() | Kopiere den Inhalt in die Betriebssystem Zwischenablage. Siehe auch. |
| com.lp.util.GotoHelper.goto_REKLAMATION_AUSWAHL() | Springe auf die Reklamation |
| com.lp.util.GotoHelper.goto_PROFORMARECHNUNG_AUSWAHL() | Springe auf die Proformarechnung |
Beachte: Ein goto innerhalb des Moduls, wird unterstützt, führt aber immer dazu, dass der soeben angezeigte Report verlassen wird.
Weitere Helper siehe: …\kieselstein\kieselstein-ejb\src\main\java\com\lp\util\GotoHelper.java ca. ab Zeile 70.
Währung aus dem Mandantenobjekt holen
<string> $P{P_MANDANT_OBJ}.getMandantDto().getWaehrungCNr()
Ausdruckende Person aus dem Mandantenobjekt holen
<int> $P{P_MANDANT_OBJ}.getTheClientDto().getIDPersonal()
Also die Frage, wer druckt diesen Report aus.
Styles hinterlegen
Ein gutes Beispiel für Farbinformationen ist der Report
...\personal\pers_mitarbeiteruebersicht.jrxml.
Etwas einfachers, üblicheres ist z.B.
...\reports\fertigung\fert_gesamtkalkulation.jrxml
Zusätzlich: Wenn du nachträglich Fields von anderen Reports einkopierst, greift die Stylefarbe meistens nicht. Damit diese greift musst du die Farbinformation manuell entfernen. Also:

das forecolor und das backcolor über den Xml Editor manuell herauslöschen. Dann greifen die Farben.
weitere Helper
Du findest eine Aufstellung aller verfügbaren Report-Helper im Report
…/allgemein/muster_qr_code.jrxml
Hier gibt es den Parameter HelperReport
. Fügst du diesen in ein Textfield ein, so siehst du alle verfügbaren Helper.
Liste der Helper
Hinweis: Können jederzeit programmtechnisch erweitert werden. siehe dazu Source.
Der führende String ist:
com.lp.util.HelperReport.
toBigInteger( String, int ) java.math.BigInteger
toBigInteger( String ) java.math.BigInteger
toBigDecimal( String, java.util.Locale ) java.math.BigDecimal
toBigDecimal( String ) java.math.BigDecimal
getDauerEinerTaetigkeitEinesTages( String, String, java.util.Date, com.lp.server.system.service.TheClientDto ) java.math.BigDecimal
getSubreportPDFAusArtikelkommentar( String, String, String, java.util.Locale, int ) com.lp.util.LPDatenSubreport
getSubreportPDFAusArtikelkommentar( String, String, String, java.util.Locale, boolean, int ) com.lp.util.LPDatenSubreport
getMwstSummeAusListeMwstsaetze( String, java.util.Locale ) java.math.BigDecimal
getVerfuegbarkeitEinerMaschineInStunden( String, int, int, com.lp.server.system.service.TheClientDto ) java.math.BigDecimal
berechneOffenenWertEinerBestellung( String, com.lp.server.system.service.TheClientDto ) java.math.BigDecimal
berechneOffenenWertEinesAuftrags( String, com.lp.server.system.service.TheClientDto ) java.math.BigDecimal
konvertiereZeitDezimalInHHMMSS( java.math.BigDecimal, int, boolean ) String
getSubreportArtikelErsatztypen( String, com.lp.server.system.service.TheClientDto ) com.lp.util.LPDatenSubreport
getSubreportAusStringMitKommaGetrennt( String ) com.lp.util.LPDatenSubreport
getSubreportEnthaltenesLosIstMaterial( String, String, com.lp.server.system.service.TheClientDto ) com.lp.util.LPDatenSubreport
getWochentag( java.util.Locale, java.sql.Timestamp ) String
time2Double( java.sql.Time ) Double
getLief1Preis( String, java.math.BigDecimal, String, com.lp.server.system.service.TheClientDto ) java.math.BigDecimal
sortList( java.util.List ) java.util.List
double2Time( Number ) java.sql.Time
emailSenden( String, String, String, com.lp.server.system.service.TheClientDto ) boolean
haengeArrayAn( Object[], Object[] ) Object[]
getSSCC( Long, String ) String
joinStrings( String[], String ) String
zinsesZins( java.math.BigDecimal, java.math.BigDecimal, int ) java.math.BigDecimal
toInteger( String ) Integer
bildDrehen( java.awt.image.BufferedImage, int ) java.awt.image.BufferedImage
getArtikeltechnikeigenschaft( String, String, com.lp.server.system.service.TheClientDto ) String
getSubreportAllergene( String, com.lp.server.system.service.TheClientDto ) com.lp.util.LPDatenSubreport
ersetzeUmlaute( String ) String
ermittleTageEinesZeitraumes( java.util.Date, java.util.Date ) int
pruefeObCode128Konform( String ) boolean
getArtikelkommentarBild( String, String, String, java.util.Locale ) java.awt.image.BufferedImage
getSubreportAusPDFFile( String, int ) com.lp.util.LPDatenSubreport
getMonatVonJahrUndWoche( Integer, Integer, java.util.Locale ) String
ganzzahligerBetragInWorten( Integer ) String
getCalendarWeekOfDate( java.util.Date ) Integer
getCalendarWeekOfDate( String, java.util.Locale ) Integer
ersetzeUmlauteUndSchneideAb( String, int ) String
fuehreSQLQueryAus( String ) Object
getSubreportKalendertage( java.util.Date, java.util.Date, com.lp.server.system.service.TheClientDto ) com.lp.util.LPDatenSubreport
getCalendarOfTimestamp( java.sql.Timestamp, java.util.Locale ) Integer
updateLieferantBeurteilung( Integer, Integer, java.util.Date, String, com.lp.server.system.service.TheClientDto ) Integer
getArtikeleigenschaft( String, String, com.lp.server.system.service.TheClientDto ) String
wandleUmNachCode39( String ) String
wandleUmNachCode128( String ) String
pruefeObCode39Konform( String ) boolean
pruefeEndsumme( java.math.BigDecimal, java.math.BigDecimal, Double, String, java.util.Locale ) Boolean
pruefeEndsumme( java.math.BigDecimal, java.math.BigDecimal, Double ) Boolean
rundeKaufmaennisch( java.math.BigDecimal, int ) java.math.BigDecimal
getVDA4092Barcode( String ) String
berechneKWJahr( java.util.Date ) String
getLiquiditaetsKontostand( Integer, com.lp.server.system.service.TheClientDto ) java.math.BigDecimal
sortListNoNull( java.util.List ) java.util.List
getVDA4092Checksum( String ) Character
getMediastandardTextHtml( String, String, java.util.Locale ) String
getSummeIstZeitEinesBeleges( String, String, com.lp.server.system.service.TheClientDto ) Double
berechneUrlaubsAnspruch( String, java.util.Date, com.lp.server.system.service.TheClientDto ) com.lp.server.personal.service.UrlaubsabrechnungDto
sortListNoNullSprung( java.util.List, int, int ) java.util.List
entferneStyleInformation( String ) String
bildUm90GradDrehenWennNoetig( java.awt.image.BufferedImage ) java.awt.image.BufferedImage
seriennummerErzeugen( String, int ) String
berechneModulo10( String ) int
berechneModulo10Str( String ) String
addiereTageZuDatum( java.util.Date, int ) java.sql.Date
getLetztenTagDesMonats( java.util.Date, int ) java.util.Date
laenderartZweierLaender( String, String, String, java.sql.Timestamp ) String
getSubreportGeraeteseriennummernEinerLagerbewegung( String, Integer, String, com.lp.server.system.service.TheClientDto ) com.lp.util.LPDatenSubreport
Weitere Helper findest du unter ..\kieselstein\kieselstein-ejb\src\main\java\com\lp\util\Helper.java
Report Root
In den Reports steht mit dem Parameter REPORT_ROOT_DIRECTORY der Pfad auf das default Report Root Directory zur Verfügung.
Da alle deine Anwender-Spezifischen-Anpassungen im LW:\kieselstein\data\reports\ liegen müssen, musst du dir in der Regel den Pfad auf das Anwenderspezifische Reportverzeichnis errechnen. Z.B. mit:
$P{REPORT_ROOT_DIRECTORY}.substring(0,$P{REPORT_ROOT_DIRECTORY}.indexOf( "dist" ))+"/data/reports/allgemein"
Anmerkung:
Das P_LOGO_IMAGE ist nur dann dafür geeignet, wenn du auch tatsächlich ein Logo unter LW:\kieselstein\data\reports\allgemein\ abgelegt hast.
$P{REPORT_ROOT_DIRECTORY}.substring(0,$P{REPORT_ROOT_DIRECTORY}.indexOf( "dist" ))+"/data/reports/allgemein"
Datei vorhanden
Aus obigem ergibt sich auch immer wieder, dass man wissen muss, ob es z.B. das gewünschte PDF tatsächlich vorhanden ist.
Dafür stellt uns Java eine Funktionalität zur Verfügung.
D.h. du definierst dir z.B. die Variable filePathString als Boolean und mit Reset Type None
new java.io.File($V{filePathString}).exists()
Damit kannst du dann z.B. beim Drucken des PDF Files vorher darauf prüfen und gegebenenfalls ein, File ist nicht vorhanden andrucken.
Beliebiges PDF-File andrucken
Manchmal ergibt sich die Forderung, dass trotz allem in einem Report der Inhalt einer PDF Datei angedruckt werden muss. Verwende dafür:
com.lp.util.HelperReport.getSubreportAusPDFFile( String <Datei>, int <Auflösung in dpi> )
Hinweis:
Bitte prüfe immer zuerst, ob das spontant Gedachte: Das muss ich immer mitdrucken, wirklich stimmt. Wir haben schon oft erlebt, dass dies nur unter bestimmten Konstellationen zutreffen ist. Nutze daher die dafür vorgesehenen Funktionen wie z.B.:
| Modul | Beschreibung |
|---|---|
| Kunden | Kommentar |
| Lieferanten | Kommentar |
| Artikel | Kommentar |
| System, Mandant | AGB |
Unterscheide auch zwischen Textbausteinen und echten PDF Dateien. PDF Dateien sind als ganzseitige Informationen gedacht. D.h. der Vorteil von Textbausteinen ist, dass sich diese auch zwischen verschiedenen anderen Texten / Bildern einfügen lassen. PDF kommen immer als eigene Seite(n) / Anhang.
Achte bei den Ausdrucken der PDFs immer darauf, dass das PDF in dein Formular passt. Insbesondere wenn dies in den Page-Header / Footer, Title reinpassen sollte und du größere Daten erhältst, kann es sein, dass der Application Server (Wildfly) mit der Berechnung der Darstellung nicht mehr fertig wird und du deinen Kieselstein ERP Server neu starten musst.
Warning
Prüfe diese Reports daher mit möglichst echten Daten immer in einer Testumgebung.Siehe dazu auch: LW:\kieselstein\dist\wildfly-26.1.2.Final\kieselstein\reports\fertigung\muster\fert_produktionsinformation.jrxml
Bild aus Kundenkommentar andrucken
Es ergibt sich immer wieder die Aufgabe, dass z.B. beim Los ein Kundenspezifisches Logo angedruckt werden sollte. Selbstverständlich hat jeder Kunde sein Logo. Idealerweise kann man die Kunden davon überzeugen, dass wenigstens für alle die Größe der Etikette gleich ist.
Daher nachfolgend ein Beispiel wie man das im Los-Ablieferetikette einrichten kann:
- Ermitteln der Kunden_i_id anhand der Losnummer
Hier ist die Herausforderung, dass im Los manchmal nur der Kunde, manchmal nur der Auftrag und manschmal auch die Auftragsposition gegeben ist, wodurch dann, optisch, auch der Kunde definiert ist. Daher muss man alle drei möglichen Definitionen berücksichtigen.
Darum wird in der Variablen Kunden_I_ID, die ein Integer ist folgendes definiert:
$P{P_SQLEXEC}.execute(
"select coalesce(fert_los.kunde_i_id, "+
" (select kunde_i_id_auftragsadresse from auft_auftrag where auft_auftrag.i_id=fert_los.auftrag_i_id), "+
" (select kunde_i_id_auftragsadresse from auft_auftrag where auft_auftrag.i_id = (select auftrag_i_id from auft_auftragposition where i_id =("+
" select fert_los.auftragposition_i_id from fert_los where i_id=fert_los.i_id)"+
" )"+
" )"+
") from fert_los where c_nr='"+$P{P_LOSNUMMER}+"' and mandant_c_nr='"+$P{P_MANDANT_OBJ}.getMandantCNr()+"';"
)
- Ermitteln der partner_i_id aus dem Kunden In der Variablen Partner_I_ID, die ebenflas ein Integer ist, wird definiert:
$P{P_SQLEXEC}.execute(
"select partner_i_id from part_kunde where i_id="+$V{Kunden_I_ID}+";"
)
- Holen des Bild-Objektes
Z.B. als Variable Logo_Kunde, welche ein Object ist.

Hier wird davon ausgegangen, dass die verwendete Kommentarart Kundenlogo ist. Gegebenenfalls bitte entsprechend anpassen.
$P{P_SQLEXEC}.execute(
"select o_media from part_partnerkommentar "+
"inner join part_partnerkommentarart ON part_partnerkommentarart.i_id = part_partnerkommentar.partnerkommentarart_i_id "+
"where partner_i_id="+$V{Partner_I_ID}+" "+
"and part_partnerkommentarart.c_bez='Kundenlogo';"
)
- Drucken des Bildes
Siehe z.B. ww_artikelstammblatt, das Bild selbst und unter Image Expression wird die Variable Logo_Kunde gedruckt.
Gegebenenfalls mit der Bedingung, wenn kein Kundenlogo angegeben ist, wird ein eigenes Logo gedruckt:
$V{Logo_Kunde} == null ?
new java.io.File($P{REPORT_DIRECTORY}+"/../allgemein/Eti_Logo.png").toURL() :
$V{Logo_Kunde}
Inline IF
Im Report-Generator steht auch das sogenannte Inline IF-Statement zur Verfügung.
Das bedeutet wenn Bedingung = wahr dann mache das Eine und sonst das Andere.
Geschrieben wird das
Bedingung ? das Eine : das Andere
Wichtig: Beachte hier die Klammern.
So liefert z.B.
$V{Artikel_Referenznr} +
$V{Artikel_Revision}==null ? "" : "-"+$V{Artikel_Revision}
immer einen Leerstring, da die Abfrage ja lautet:
$V{Artikel_Referenznr} + $V{Artikel_Revision}==null
Vermutlich wolltest du aber nur auf $V{Artikel_Revision}==null prüfen und dann das Trennzeichen einfügen.
Daher muss dieser Ausdruck in Klammern gesetzt werden.
$V{Artikel_Referenznr} +
($V{Artikel_Revision}==null ? "" : "-"+$V{Artikel_Revision})
Womit immer die Referenznummer übergeben wird und je nach Inhalt der Revision kommt ein Leersting oder das Ternnzeichen(-) und danach die Revision.
Warum ist das so?
Es wird zuerst die (matehmatische) Operation ausgeführt und dann das Ergebnis geprüft. Durch die Klammernsetzung wird das wie von dir gedacht gesteuert.
Man könnte auch sagen, bitte hilf dem Compiler das so wie von dir gewünscht umzusetzen.
Bedingung, If, Else
Manchmal hat man die Aufgabe innerhalb des Querys Bedingungen zu errechnen. Dafür kann man im SQL-Query auch Case Konstrukte verwenden. So liefert nachfolgendes Beispiel je Chargennummer die lagernde Menge.
select Sum(case when b_abgang = 1 then n_menge * -1 else n_menge end) as Verbrauch, c_seriennrchargennr
from ww_lagerbewegung where artikel_i_id=(select i_id from ww_artikel where c_nr='11031')
and ww_lagerbewegung.b_vollstaendigverbraucht = 0
and b_historie = 0
and n_menge != 0
-- and b_abgang=0
group by c_seriennrchargennr
order by c_seriennrchargennr;