V2-Berichte mit JSON-Datenquelle erstellen¶
calServer V2 kann JasperReports-Vorlagen aus einem JSON-Datensatz mit lesbaren
API-Feldnamen fuellen -- statt aus in die Vorlage eingebettetem SQL gegen die
alten Metrologie-Codespalten (I4201, C2303, ...). Solche Vorlagen enthalten
kein SQL und funktionieren dadurch unabhaengig vom Datenbank-Backend
(MySQL, PostgreSQL, MS SQL Server).
Hintergrund und Grundsatzentscheidung: ADR-009.
Wann JSON, wann SQL?¶
- Bestehende V1-Vorlagen (JDBC + Codespalten) laufen unveraendert weiter -- sie muessen nicht umgestellt werden.
- Neue V2-Vorlagen sollten die JSON-Datenquelle nutzen: eine Namenswelt (Vorlagenfelder = API-Felder), DB-unabhaengig, Custom Fields inklusive.
Klassische SQL-Vorlage + reine V2-Daten = leerer Bericht
Eine V1-SQL-Vorlage liest die V1-Tabellen (calibration, inventory,
...). Datensaetze, die direkt in V2 angelegt wurden (oder aus dem
Demo-Seeder stammen), existieren nur in den V2-Tabellen -- die SQL-Query
findet dann keine Zeile und JasperReports rendert trotzdem "erfolgreich"
ein mehrseitiges, aber leeres PDF. calServer erkennt diese Situation
inzwischen vor dem Rendern und bricht mit einer verstaendlichen
Fehlermeldung ab (auch im Berichts-Laufprotokoll sichtbar), statt ein
leeres PDF auszuliefern. Abhilfe: die V2-JSON-Variante der Vorlage
verwenden (z. B. DAKKS-JSON-SAMPLE statt DAKKS-SAMPLE).
Eine Vorlage als V2-JSON-Bericht aktivieren¶
Das geschieht automatisch: Vorlage wie gewohnt unter
Administration > Berichtsverwaltung anlegen (Ordner, Dateiname, Format) und
das Bundle hochladen. Hat das Haupt-JRXML kein eingebettetes SQL (kein
<queryString> -- das Kennzeichen aller V2-Bundles), erkennt calServer das beim
Generieren und baut den JSON-Datensatz mit dem Standard-Contract des Grids:
| Grid | Standard-Contract |
|---|---|
| calibration | calibration-certificate |
| inventory | inventory-datasheet |
| booking | order-document |
| repair | repair-report |
| location | location-report |
Vorlagen mit eingebettetem SQL (klassische V1-Bundles) laufen unveraendert ueber JDBC.
Override (optional): Eine report-bezogene Report-Variable mit dem Namen
data_contract uebersteuert die Erkennung -- z. B. mit einem anderen
Contract-Namen, oder mit einem Nicht-Contract-Wert wie jdbc, um fuer diese
Vorlage explizit den klassischen SQL/JDBC-Pfad zu erzwingen.
Etiketten: dieselbe Vorlage druckt eines und vierzig¶
Eine Etikettenvorlage ist fuer einen Datensatz geschrieben -- ihre Felder lesen
device.asset_number oder calibration.calibration_date direkt von der
Dokumentwurzel, genau wie das Datenblatt oder das Zertifikat, dessen Contract sie
mitbenutzt. Ein Etikett bekommt also keinen eigenen Contract.
Fuer den Stapeldruck aus dem Grid schickt calServer trotzdem nur einen Lauf. Der Datensatz sieht dann so aus:
{
"meta": { "contract": "inventory-datasheet", "schema_version": "1.1", "count": 3 },
"stickers": [ { "meta": {}, "device": {}, "customer": {} }, "… je Zeile ein vollstaendiges Dokument" ]
}
Dazu bekommt der Runner die Angabe, dass er stickers durchlaufen soll. Weil
jedes Element ein vollstaendiges Dokument ist, loesen alle Feldpfade der
Vorlage unveraendert auf: Dieselbe Datei druckt ein Etikett, wenn sie einen
Datensatz an der Wurzel bekommt, und vierzig, wenn sie das Array bekommt. Eine
Stapel-Fassung der Vorlage ist nicht noetig und waere ein Wartungsfall mehr.
Fuer den Entwurf heisst das: Die Vorlage gegen sample-data.json bauen (ein
Datensatz, wie bisher). Der Stapel ergibt sich von selbst.
Den Stapel gibt es nur auf diesem Weg: Er ist das Array, das der Runner durchlaeuft. Ein klassisches SQL-Etikett fuellt sich aus der eigenen Abfrage und liest das Array gar nicht, weshalb calServer den Stapeldruck fuer einen solchen Bericht mit einer Meldung abweist, statt einen Stapel leerer Etiketten zu drucken. Einzeln druckt er unveraendert weiter; wer stapeln will, laedt ein V2-Buendel auf den Platzhalter.
Der Barcode kommt aus dem Datensatz, nicht aus der Vorlage¶
inventory-datasheet und calibration-certificate tragen einen Block
barcode:
type und field kommen aus den Grundeinstellungen (Barcode-Typ,
Barcode-Feld), value ist der bereits aufgeloeste Feldwert des Geraets.
Eine Etikettenvorlage sollte barcode.value codieren, nicht
device.asset_number. Der Unterschied faellt erst beim zweiten Kunden auf:
Wer eine Hausnummer aus einem Zusatzfeld codiert, braucht sonst eine eigene
Vorlage. Mit dem Block passt dieselbe Datei ueberall.
Fuer die Symbologie schaltet man die Barcode-Komponenten ueber
printWhenExpression gegen barcode.type — so macht es
STICKER-CAL-INV-ZEBRA-JSON-SAMPLE. Verfuegbar sind die Encoder, die der
Report-Runner mitbringt: qrcode (ZXing) sowie datamatrix, code128,
code39, codabar, ean13, ean8, upc, int25 (barcode4j).
In dasselbe printWhenExpression gehoert der Leertest. barcode.value ist
null, wenn das konfigurierte Feld am Geraet leer ist — ein Etikett ohne
Barcode, kein gescheiterter Bericht. Die barcode4j-Symbologien sehen das anders:
Sie verweigern eine leere Nachricht mit
NullPointerException: Parameter msg must not be empty, und ein Fuellfehler
bricht in JasperReports den ganzen Lauf ab, nicht die einzelne Seite. Im
Stapeldruck nimmt ein Geraet ohne Barcode-Wert damit alle anderen mit, und im
Druckdialog steht nur die Java-Meldung. Also:
<printWhenExpression><![CDATA[$V{symbology}.equals("datamatrix") && $V{hasCode}.booleanValue()]]></printWhenExpression>
qrcode braucht den Test nicht (ZXing rendert eine leere Nachricht klaglos) —
genau deshalb faellt der Fehler nur bei Mandanten auf, die auf DataMatrix
(Vorgabe), Code128 oder Code39 stehen. In calServer-reports haelt
scripts/check_barcode_guards.py die Regel fest.
Der QR-Code zeigt auf die Geraeteseite, nicht auf eine Nummer¶
calibration-certificate (ab v1.6) und inventory-datasheet (ab v1.4) tragen
zusaetzlich einen Block qr:
url ist der oeffentliche Deep-Link auf die Geraeteseite der QR-Code-Rolle:
scannen fuehrt ohne Anmeldung auf Stammdaten, Kalibrierstatus und Dokumente des
Geraets. Das ist der Unterschied zu barcode.value — der codiert eine
Inventarnummer, die ein Scanner als Text liest, waehrend qr.url eine Adresse
ist, die ein Telefon oeffnet.
Der Link steht je Datensatz im Dokument, nicht als Jasper-Parameter. Der
alte V1-Parameter QR_Code_Value gilt je Druckauftrag; auf der Titelseite eines
Kalibrierscheins reicht das, in einem Etikettenstapel zeigten damit alle vierzig
Aufkleber auf dasselbe Geraet.
url ist null, solange die QR-Links abgeschaltet sind (Administration >
Grundeinstellungen > Portal, Schalter QR-Links) oder die Kalibrierung kein
Geraet hat; enabled sagt, welcher der beiden Faelle vorliegt. Eine Vorlage
schaltet die QR-Komponente per printWhenExpression gegen qr.url — ein
Aufkleber ohne QR ist besser als einer, der ins Leere zeigt.
Die URL-Laenge entscheidet ueber die Etikettengroesse
Ein Deep-Link mit uuid ist rund 74 Zeichen lang, das ergibt QR-Version 5
mit 37 Modulen. Auf einem 203-dpi-Etikettendrucker braucht das Symbol
dadurch etwa 17 mm Kantenlaenge, um zuverlaessig gescannt zu werden. Auf
ein 18-mm-DAkkS-Etikett passt daneben nichts mehr — deshalb liegt der QR
im Bundle STICKER-DAKKS-40X30MM-QR-JSON-SAMPLE (Kalibrieraufkleber) bzw.
STICKER-INV-40X30MM-QR-JSON-SAMPLE (Geraeteetikett) und nicht in den
12/18-mm- oder Zebra-Bundles.
Den erzeugten Datensatz einer konkreten Kalibrierung kann man direkt abrufen (nuetzlich als Beispieldatei fuer den Entwurf):
Verfuegbare Contracts¶
| Contract | Berichtsfamilie | Beispiel-Datensatz |
|---|---|---|
calibration-certificate (v1.10) |
Kalibrierschein | DAKKS-JSON-SAMPLE/main_reports/sample-data.json |
inventory-datasheet (v1.4) |
Geraete-Datenblatt | INVENTORY-JSON-SAMPLE/main_reports/sample-data.json |
order-document (v1.0) |
Auftrag / Lieferschein | ORDER-JSON-SAMPLE bzw. DELIVERY-JSON-SAMPLE (main_reports/sample-data.json) |
repair-report (v1.0) |
Reparaturbericht | REPAIR-JSON-SAMPLE/main_reports/sample-data.json |
location-report (v1.2) |
Standort-/Leihbericht (Leihschein als Versanddokument) | LOCATION-JSON-SAMPLE/main_reports/sample-data.json |
free-delivery-note (v1.0) |
Freier Versandschein (Lieferpapier ohne Auftrag) | FREE-DELIVERY-JSON-SAMPLE/main_reports/sample-data.json |
price-list (v1.1) |
Kundenpreisliste | PRICE-LIST-JSON-SAMPLE/main_reports/sample-data.json |
Der Contract calibration-certificate liefert ein Wurzelobjekt mit den Bloecken
meta, laboratory, accreditation, calibration, device, barcode,
qr, customer, procedure, environment, report_variant, standards[],
results[], decision_rule, signatures[] und texts. Jeder
Entitaetsblock enthaelt zusaetzlich ein custom_fields-Objekt mit den
benutzerdefinierten Feldern unter ihrem api_name.
Jede Zeile in results[] traegt die Bewertung dreifach:
pass_fail-- die Entscheidung in MET/TEAM-Schreibweise (Pass,Fail,Pass Indeterminate,Fail Indeterminate). Das Backend normalisiert die Spalte fuer den Datensatz und liest dafuer zuersttest_status: die gespeicherte Spalte ist binaer, weil sie unveraendert an MET/TEAM zurueckgeht, der Datensatz traegt die Nuance. Zeilen aus MET/TRACK oder der V1-Laufzeit, die die Entscheidung nur intest_statushaben, kommen dadurch ueberhaupt erst mit Bewertung an. Unbekannte, kundeneigene Werte gehen unveraendert durch.test_status-- Klartext inkl. der Guard-Band-ZonenConditional/ConditionalFail.conformity-- Legendensymbol des Kalibrierscheins (leer,?,!?,!).
Fuer die Konformitaetsspalte einer neuen Vorlage gehoert conformity
gebunden -- der Klartext passt weder in die Spaltenbreite noch in die Legende.
Die aus V1 uebernommenen Bundles (DAKKS-JSON-SAMPLE) binden pass_fail,
weil sie byte-genaue Kopien des akkreditierten Originals sind; genau dafuer ist
die Normalisierung da. guardband_meth nennt die angewandte Entscheidungsregel.
Ab v1.8 traegt jede Zeile ausserdem das Budget der Messunsicherheit
(Messunsicherheit nach GUM):
uncert_method, cov_fac und deg_free als Text wie die uebrigen Spalten,
dazu budget mit Methode, k und seiner Herkunft (dof, plan, fixed), den
effektiven Freiheitsgraden, u, U, einer Anhebung auf die CMC, einem Ersatz aus
einem Unsicherheitsmodell, dem Grund eines fehlenden U und einer Zeile je
Beitrag. Damit laesst sich das Budget als Anhang drucken. budget ist null
fuer Zeilen ohne Methode (importiert oder vor GUM erfasst). texts.uncertainty
folgt dem tatsaechlichen k; bei k = 2 bleibt es der bisherige Satz. Jede
Beitragszeile nennt ihre Freiheitsgrade (degrees_of_freedom, null fuer
unendlich): N − 1 bei S1 und, wo das Unsicherheitsmodell sie angibt, die eines
Modellbeitrags (Nachtrag 6.2 des ADR, gleiche Form, kein neues Feld).
Ab v1.9 nennt der Block decision_rule die Entscheidungsregel der
Kalibrierung
(Entscheidungsregel,
ISO/IEC 17025:2017 7.8.6.2): key (non_binary, binary_guarded,
simple), reference und section in ILAC-G8:09/2019, guard_band
(w = U oder w = 0), binary, origin (lab, customer, manual,
points), agreement (wo die Regel vereinbart ist), points_decided und
points_without_uncertainty, dazu die drei Texte des Abschnitts
„Konformitaet“ in der Sprache des Scheins: statement, symbols, legend.
Dieselben Texte bekommen die JRXML-Vorlagen als Parameter
Conformity_description_1 bis _3, sobald calServer Punkte der Kalibrierung
bewertet hat; eine Berichtsvariable desselben Namens gewinnt. Berichtigt ist
der Vorgabewert von texts.conformity_legend: * nicht im
Akkreditierungsumfang. Vorher stand dort * im Akkreditierungsumfang, also
das Gegenteil dessen, was das Sternchen markiert; ein eigener Text des Labors
bleibt unangetastet.
Ab v1.10 nennt decision_rule.guard_band auch ein anderes Schutzband als
w = U, etwa w = 1,5 · U oder w für ein Risiko von höchstens 2,5 %, in der
Sprache des Scheins; decision_rule.guard traegt das Band als Daten: mode
(u, factor, risk), factor und risk in Prozent
(Das Schutzband w).
Jede Zeile in results[] traegt ausserdem accred_source, die Herkunft ihrer
Aussage zum Akkreditierungsumfang: derived (aus der Anlage, bei der
Erfassung eingefroren), plan (calScript accred no), manual, import
(MET/TEAM) oder leer fuer Zeilen von vor dieser Spalte
(Akkreditierungsumfang).
Geaendert hat sich die Bedeutung von results[].accred, nicht seine Form: Den
Wert schreibt jetzt die Erfassung aus der Anlage in den Qualitaetsvorgaben.
Vorher trug jede in calServer erfasste Zeile den Vorgabewert 1 der Datenbank
und behauptete damit, im Umfang zu liegen; ohne gepflegte Anlage bleibt die
Spalte jetzt leer (keine Aussage).
Vorlagen in Jaspersoft Studio entwerfen¶
- JSON-Data-Adapter anlegen und auf die Beispieldatei (
sample-data.jsonbzw. die Ausgabe desreport-dataset-Endpoints) zeigen lassen. - Felder ueber ihren JSON-Pfad binden, nicht ueber SQL. In der JRXML ist das
die
fieldDescription:
<field name="serial_number" class="java.lang.String">
<fieldDescription><![CDATA[device.serial_number]]></fieldDescription>
</field>
- Wiederkehrende Listen (Messergebnisse, verwendete Normale) ueber ein
Subreport mit
subDataSourcerendern -- keine Connection, kein eigenes SQL:
<subreport>
<dataSourceExpression><![CDATA[
((net.sf.jasperreports.engine.data.JsonDataSource)$P{REPORT_DATA_SOURCE})
.subDataSource("results")
]]></dataSourceExpression>
<subreportExpression><![CDATA[$P{Reportpath} + "/subreports/results.jasper"]]></subreportExpression>
</subreport>
- Custom Fields stehen unter ihrem
api_nameimcustom_fields-Block bereit, z. B.fieldDescription = device.custom_fields.customer_tag.
JasperReports-Version
Verbindlich bleibt JasperReports 6.20.6 (siehe robots.md im
Repository). Keine Features einsetzen, die eine neuere Version voraussetzen.
Parameter beschreiben
Ein V2-JSON-Bundle kann einen Parameter-Katalog mitliefern, damit calServer die konfigurierbaren Parameter beim Anlegen von Berichtsvariablen mit Beschreibung, Typ und Standardwert anbietet. Details: Parameter im Report-Paket beschreiben.
Referenzvorlage¶
Das Pilot-Bundle
DAKKS-JSON-SAMPLE
im Repository calhelp/calServer-reports
zeigt Haupt- und Subreports (Ergebnisse, Normale) vollstaendig auf JSON-Basis und
enthaelt die passende sample-data.json.
Code-zu-API-Namen-Zuordnung¶
Die Zuordnung der alten Codespalten zu den lesbaren api_names ist maszgeblich in
der Tabelle api_field_mappings hinterlegt und ueber den FIELD-NAMES-Report je
Sprache abrufbar. Auszug der Kernfelder:
| V1-Code | api_name | Bedeutung |
|---|---|---|
I4201 |
asset_number |
Inventar-/Geraetenummer |
I4202 |
serial_number |
Seriennummer |
C2301 |
calibration_date |
Kalibrierdatum |
C2303 |
next_calibration_date |
Naechster Kalibriertermin |
K4601 |
name |
Kundenname |