Compare commits

..

No commits in common. "master" and "office-alexander-logistics-1.3.0" have entirely different histories.

779 changed files with 429914 additions and 560156 deletions

2
.gitignore vendored
View file

@ -13,11 +13,9 @@ target/
.metadata/ .metadata/
.project .project
.classpath .classpath
.env
# ignore docker deployments # ignore docker deployments
docker/deployments/ docker/deployments/
docker/keys/imixs-llm.xml
# Sepa Report # Sepa Report
reports/sepa/result_sepa* reports/sepa/result_sepa*

View file

@ -8,5 +8,8 @@
"editor.codeActionsOnSave": { "editor.codeActionsOnSave": {
"source.organizeImports": "explicit" "source.organizeImports": "explicit"
}, },
"java.format.settings.url": "https://raw.githubusercontent.com/imixs/imixs-workflow/refs/heads/master/imixs-code-style.xml" "java.checkstyle.version": "8.44",
"java.checkstyle.autocheck": true,
"java.checkstyle.configuration": "https://raw.githubusercontent.com/imixs/imixs-workflow/master/imixs-checkstyle-8.44.xml",
"java.configuration.updateBuildConfiguration": "automatic"
} }

View file

@ -1,210 +0,0 @@
Du bist Prozessberater und Spezialisiert auf die Analyse von BPMN Modellen.
Bitte beschreibe den im folgenden BPMN 2.0 Modell definierten Prozess und erstelle eine kurze Zusammenfassung:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<bpmn2:definitions xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI"
xmlns:dc="http://www.omg.org/spec/DD/20100524/DC"
xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:open-bpmn="http://open-bpmn.org/XMLSchema"
xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
exporter="org.openbpmn" exporterVersion="1.0.0" targetNamespace="http://open-bpmn.org"
xmlns:bpmn2="http://www.omg.org/spec/BPMN/20100524/MODEL">
<bpmn2:collaboration id="collaboration_1" name="Default Collaboration">
<bpmn2:participant id="participant_TgW2JA" name="Default Process" processRef="process_1" />
<bpmn2:participant id="participant_tgRhJQ" name="Rechnungseingang" processRef="process_lYaFpg">
<bpmn2:documentation id="documentation_wSfXcQ"><![CDATA[Dieser Workflow dient dazu eingehende Rechnungen zu prüfen und zur Bezahlung weiterzuleiten. Es wird unterschieden von Sachrechnungen, die vom Sekretariat bearbeitet werden können und Cargo-Rechnungen die durch die Logistikabteilung anhand von Logistikaufträgen geprüft werden.
Nachdem die Rechnung bezahlt wurde wird der Vorgang archiviert. ]]></bpmn2:documentation>
</bpmn2:participant>
</bpmn2:collaboration>
<bpmn2:extensionElements>
<open-bpmn:auto-align>true</open-bpmn:auto-align>
</bpmn2:extensionElements>
<bpmn2:process definitionalCollaborationRef="collaboration_1" id="process_1"
name="Default Process" processType="Public">
<bpmn2:documentation id="documentation_wXazVg" />
</bpmn2:process>
<bpmn2:process definitionalCollaborationRef="collaboration_1" id="process_lYaFpg"
isExecutable="true" name="Rechnungseingang" processType="Private">
<bpmn2:laneSet id="laneset_fDygyw" name="Lane Set">
<bpmn2:lane id="lane_BgoDFg" name="Sekretariat">
<bpmn2:documentation id="documentation_hIztzA" />
<bpmn2:flowNodeRef>task_7Y3UUA</bpmn2:flowNodeRef>
<bpmn2:flowNodeRef>event_bH7Wag</bpmn2:flowNodeRef>
<bpmn2:flowNodeRef>event_oNXxgg</bpmn2:flowNodeRef>
<bpmn2:flowNodeRef>event_GEqHhQ</bpmn2:flowNodeRef>
<bpmn2:flowNodeRef>event_VJXKGg</bpmn2:flowNodeRef>
<bpmn2:flowNodeRef>task_SP75zg</bpmn2:flowNodeRef>
<bpmn2:flowNodeRef>gateway_ASbu1A</bpmn2:flowNodeRef>
<bpmn2:flowNodeRef>gateway_Vyo0Zw</bpmn2:flowNodeRef>
<bpmn2:flowNodeRef>task_xAzhzw</bpmn2:flowNodeRef>
<bpmn2:flowNodeRef>event_YH3bnw</bpmn2:flowNodeRef>
<bpmn2:flowNodeRef>event_1qR49w</bpmn2:flowNodeRef>
<bpmn2:flowNodeRef>task_fHgZBg</bpmn2:flowNodeRef>
<bpmn2:flowNodeRef>event_YnFi7A</bpmn2:flowNodeRef>
</bpmn2:lane>
<bpmn2:lane id="lane_eMP9Xw" name="Fachbereich">
<bpmn2:documentation id="documentation_6ihnmQ" />
<bpmn2:flowNodeRef>event_A1J0OA</bpmn2:flowNodeRef>
<bpmn2:flowNodeRef>task_5lS3mw</bpmn2:flowNodeRef>
<bpmn2:flowNodeRef>gateway_Hn5ZhQ</bpmn2:flowNodeRef>
<bpmn2:flowNodeRef>event_dJ89xQ</bpmn2:flowNodeRef>
<bpmn2:flowNodeRef>event_30uUNA</bpmn2:flowNodeRef>
</bpmn2:lane>
</bpmn2:laneSet>
<bpmn2:startEvent id="event_bH7Wag" name="Start">
<bpmn2:documentation id="documentation_pguolw" />
<bpmn2:outgoing>sequenceFlow_8yitUQ</bpmn2:outgoing>
</bpmn2:startEvent>
<bpmn2:task id="task_7Y3UUA" name="Rechnungsprüfung">
<bpmn2:documentation id="documentation_oKsT5Q"><![CDATA[Inhaltliche Prüufng der Rechnung]]></bpmn2:documentation>
<bpmn2:incoming>sequenceFlow_BGVbSA</bpmn2:incoming>
<bpmn2:outgoing>sequenceFlow_FyAf3g</bpmn2:outgoing>
<bpmn2:incoming>sequenceFlow_hvQWmg</bpmn2:incoming>
<bpmn2:incoming>sequenceFlow_j4GDgg</bpmn2:incoming>
</bpmn2:task>
<bpmn2:endEvent id="event_oNXxgg" name="Ende">
<bpmn2:documentation id="documentation_1heF3g" />
<bpmn2:incoming>sequenceFlow_iVpj0g</bpmn2:incoming>
</bpmn2:endEvent>
<bpmn2:intermediateCatchEvent id="event_GEqHhQ" name="Import">
<bpmn2:documentation id="documentation_gR2xbw" />
<bpmn2:incoming>sequenceFlow_8yitUQ</bpmn2:incoming>
<bpmn2:outgoing>sequenceFlow_BGVbSA</bpmn2:outgoing>
</bpmn2:intermediateCatchEvent>
<bpmn2:sequenceFlow id="sequenceFlow_8yitUQ" sourceRef="event_bH7Wag" targetRef="event_GEqHhQ">
<bpmn2:documentation id="documentation_2Zd0Aw" />
</bpmn2:sequenceFlow>
<bpmn2:sequenceFlow id="sequenceFlow_BGVbSA" sourceRef="event_GEqHhQ" targetRef="task_7Y3UUA">
<bpmn2:documentation id="documentation_6k088A" />
</bpmn2:sequenceFlow>
<bpmn2:intermediateCatchEvent id="event_VJXKGg" name="Sachrechnung">
<bpmn2:documentation id="documentation_DaDN3w"><![CDATA[Weiterleiten zur Sachprüfung]]></bpmn2:documentation>
<bpmn2:incoming>sequenceFlow_rZXh6g</bpmn2:incoming>
<bpmn2:outgoing>sequenceFlow_sNlWkQ</bpmn2:outgoing>
</bpmn2:intermediateCatchEvent>
<bpmn2:task id="task_SP75zg" name="Budgetprüfung">
<bpmn2:documentation id="documentation_qP2Sew" />
<bpmn2:incoming>sequenceFlow_sNlWkQ</bpmn2:incoming>
<bpmn2:outgoing>sequenceFlow_nxZ9bA</bpmn2:outgoing>
</bpmn2:task>
<bpmn2:task id="task_5lS3mw" name="Prüfung Logistik Auftrag">
<bpmn2:documentation id="documentation_zweAkw"><![CDATA[Prüfung der Rechnung und Abgleich mit Logistikauftrag]]></bpmn2:documentation>
<bpmn2:incoming>sequenceFlow_DXGQrw</bpmn2:incoming>
<bpmn2:outgoing>sequenceFlow_UebylQ</bpmn2:outgoing>
</bpmn2:task>
<bpmn2:eventBasedGateway gatewayDirection="Diverging" id="gateway_ASbu1A" name="">
<bpmn2:documentation id="documentation_09gukg" />
<bpmn2:incoming>sequenceFlow_FyAf3g</bpmn2:incoming>
<bpmn2:outgoing>sequenceFlow_rZXh6g</bpmn2:outgoing>
<bpmn2:outgoing>sequenceFlow_i7cH2A</bpmn2:outgoing>
</bpmn2:eventBasedGateway>
<bpmn2:sequenceFlow id="sequenceFlow_FyAf3g" sourceRef="task_7Y3UUA" targetRef="gateway_ASbu1A">
<bpmn2:documentation id="documentation_tv00MQ" />
</bpmn2:sequenceFlow>
<bpmn2:sequenceFlow id="sequenceFlow_rZXh6g" sourceRef="gateway_ASbu1A" targetRef="event_VJXKGg">
<bpmn2:documentation id="documentation_EPAmhQ" />
</bpmn2:sequenceFlow>
<bpmn2:sequenceFlow id="sequenceFlow_sNlWkQ" sourceRef="event_VJXKGg" targetRef="task_SP75zg">
<bpmn2:documentation id="documentation_iXrfpg" />
</bpmn2:sequenceFlow>
<bpmn2:intermediateCatchEvent id="event_A1J0OA" name="Cargo Rechnung">
<bpmn2:documentation id="documentation_RWi6LA"><![CDATA[Weiterleitung zur Prüfung Logistikauftrag]]></bpmn2:documentation>
<bpmn2:incoming>sequenceFlow_i7cH2A</bpmn2:incoming>
<bpmn2:outgoing>sequenceFlow_DXGQrw</bpmn2:outgoing>
</bpmn2:intermediateCatchEvent>
<bpmn2:sequenceFlow id="sequenceFlow_i7cH2A" sourceRef="gateway_ASbu1A" targetRef="event_A1J0OA">
<bpmn2:documentation id="documentation_pz6J4g" />
</bpmn2:sequenceFlow>
<bpmn2:sequenceFlow id="sequenceFlow_DXGQrw" sourceRef="event_A1J0OA" targetRef="task_5lS3mw">
<bpmn2:documentation id="documentation_ngSLdQ" />
</bpmn2:sequenceFlow>
<bpmn2:exclusiveGateway gatewayDirection="Diverging" id="gateway_Vyo0Zw" name="">
<bpmn2:documentation id="documentation_Pm90XA" />
<bpmn2:incoming>sequenceFlow_nxZ9bA</bpmn2:incoming>
<bpmn2:outgoing>sequenceFlow_9tp42Q</bpmn2:outgoing>
<bpmn2:outgoing>sequenceFlow_h4SfiQ</bpmn2:outgoing>
</bpmn2:exclusiveGateway>
<bpmn2:intermediateCatchEvent id="event_dJ89xQ" name="Freigabe">
<bpmn2:documentation id="documentation_sB06Ag"><![CDATA[Rechnung in Ordnung und freigegeben zur Bezahlung]]></bpmn2:documentation>
<bpmn2:incoming>sequenceFlow_PLk0RA</bpmn2:incoming>
<bpmn2:outgoing>sequenceFlow_A0FQoA</bpmn2:outgoing>
</bpmn2:intermediateCatchEvent>
<bpmn2:exclusiveGateway gatewayDirection="Diverging" id="gateway_Hn5ZhQ" name="">
<bpmn2:documentation id="documentation_aLEQqQ" />
<bpmn2:incoming>sequenceFlow_UebylQ</bpmn2:incoming>
<bpmn2:outgoing>sequenceFlow_PLk0RA</bpmn2:outgoing>
<bpmn2:outgoing>sequenceFlow_xVEjcA</bpmn2:outgoing>
</bpmn2:exclusiveGateway>
<bpmn2:sequenceFlow id="sequenceFlow_UebylQ" sourceRef="task_5lS3mw" targetRef="gateway_Hn5ZhQ">
<bpmn2:documentation id="documentation_MZdr7Q" />
</bpmn2:sequenceFlow>
<bpmn2:task id="task_xAzhzw" name="Bezahlung">
<bpmn2:documentation id="documentation_zO3SRw" />
<bpmn2:incoming>sequenceFlow_9OrwEg</bpmn2:incoming>
<bpmn2:incoming>sequenceFlow_A0FQoA</bpmn2:incoming>
<bpmn2:outgoing>sequenceFlow_OfKNWA</bpmn2:outgoing>
</bpmn2:task>
<bpmn2:sequenceFlow id="sequenceFlow_nxZ9bA" sourceRef="task_SP75zg" targetRef="gateway_Vyo0Zw">
<bpmn2:documentation id="documentation_G4qmmA" />
</bpmn2:sequenceFlow>
<bpmn2:sequenceFlow id="sequenceFlow_PLk0RA" sourceRef="gateway_Hn5ZhQ" targetRef="event_dJ89xQ">
<bpmn2:documentation id="documentation_Y5qwSA" />
</bpmn2:sequenceFlow>
<bpmn2:intermediateCatchEvent id="event_YH3bnw" name="Freigeben">
<bpmn2:documentation id="documentation_C05Bhw"><![CDATA[Rechnung in Ordnung und freigegeben zur Bezahlung]]></bpmn2:documentation>
<bpmn2:incoming>sequenceFlow_9tp42Q</bpmn2:incoming>
<bpmn2:outgoing>sequenceFlow_9OrwEg</bpmn2:outgoing>
</bpmn2:intermediateCatchEvent>
<bpmn2:sequenceFlow id="sequenceFlow_9tp42Q" sourceRef="gateway_Vyo0Zw" targetRef="event_YH3bnw">
<bpmn2:documentation id="documentation_PIQaSg" />
</bpmn2:sequenceFlow>
<bpmn2:sequenceFlow id="sequenceFlow_9OrwEg" sourceRef="event_YH3bnw" targetRef="task_xAzhzw">
<bpmn2:documentation id="documentation_0eagTw" />
</bpmn2:sequenceFlow>
<bpmn2:intermediateCatchEvent id="event_1qR49w" name="Ablehnen">
<bpmn2:documentation id="documentation_cdpcXA" />
<bpmn2:incoming>sequenceFlow_h4SfiQ</bpmn2:incoming>
<bpmn2:outgoing>sequenceFlow_hvQWmg</bpmn2:outgoing>
</bpmn2:intermediateCatchEvent>
<bpmn2:intermediateCatchEvent id="event_30uUNA" name="Ablehnen">
<bpmn2:documentation id="documentation_VazNUA" />
<bpmn2:incoming>sequenceFlow_xVEjcA</bpmn2:incoming>
<bpmn2:outgoing>sequenceFlow_j4GDgg</bpmn2:outgoing>
</bpmn2:intermediateCatchEvent>
<bpmn2:sequenceFlow id="sequenceFlow_h4SfiQ" sourceRef="gateway_Vyo0Zw" targetRef="event_1qR49w">
<bpmn2:documentation id="documentation_Q2yPDw" />
</bpmn2:sequenceFlow>
<bpmn2:sequenceFlow id="sequenceFlow_hvQWmg" sourceRef="event_1qR49w" targetRef="task_7Y3UUA">
<bpmn2:documentation id="documentation_qkneSw" />
</bpmn2:sequenceFlow>
<bpmn2:sequenceFlow id="sequenceFlow_xVEjcA" sourceRef="gateway_Hn5ZhQ" targetRef="event_30uUNA">
<bpmn2:documentation id="documentation_l9waIg" />
</bpmn2:sequenceFlow>
<bpmn2:sequenceFlow id="sequenceFlow_j4GDgg" sourceRef="event_30uUNA" targetRef="task_7Y3UUA">
<bpmn2:documentation id="documentation_4vaLww" />
</bpmn2:sequenceFlow>
<bpmn2:sequenceFlow id="sequenceFlow_A0FQoA" sourceRef="event_dJ89xQ" targetRef="task_xAzhzw">
<bpmn2:documentation id="documentation_fAB90Q" />
</bpmn2:sequenceFlow>
<bpmn2:task id="task_fHgZBg" name="Archiviert">
<bpmn2:documentation id="documentation_Idessw"><![CDATA[Rechnungsprüfung abgeschlossen und Rechnung archiveirt.]]></bpmn2:documentation>
<bpmn2:incoming>sequenceFlow_A0FQoA</bpmn2:incoming>
<bpmn2:incoming>sequenceFlow_sUEtcA</bpmn2:incoming>
<bpmn2:outgoing>sequenceFlow_iVpj0g</bpmn2:outgoing>
</bpmn2:task>
<bpmn2:intermediateCatchEvent id="event_YnFi7A" name="Bezahlt">
<bpmn2:documentation id="documentation_Jz0LKg"><![CDATA[Rechnungsbetrag wurde überwiesen]]></bpmn2:documentation>
<bpmn2:incoming>sequenceFlow_OfKNWA</bpmn2:incoming>
<bpmn2:outgoing>sequenceFlow_sUEtcA</bpmn2:outgoing>
</bpmn2:intermediateCatchEvent>
<bpmn2:sequenceFlow id="sequenceFlow_OfKNWA" sourceRef="task_xAzhzw" targetRef="event_YnFi7A">
<bpmn2:documentation id="documentation_DdJpCg" />
</bpmn2:sequenceFlow>
<bpmn2:sequenceFlow id="sequenceFlow_sUEtcA" sourceRef="event_YnFi7A" targetRef="task_fHgZBg">
<bpmn2:documentation id="documentation_uG0SGg" />
</bpmn2:sequenceFlow>
<bpmn2:sequenceFlow id="sequenceFlow_iVpj0g" sourceRef="task_fHgZBg" targetRef="event_oNXxgg">
<bpmn2:documentation id="documentation_Is0LqQ" />
</bpmn2:sequenceFlow>
</bpmn2:process>
</bpmn2:definitions>

View file

@ -1,11 +0,0 @@
Wir haben einen Geschäftsprozess für die Eingangsrechnungsprüfung in einem Unternehmen.
Rechnungen werden importiert und dann zur "Rechnungsprüfung" geleitet. Dieser Zusstand ist in einem BPMN 2.0 Diagram als Task Element abgebildet.
Der Mitarbeiter hat nun über die beiden Aktionen "Sachrechnung" und "Cargorechnung" die Möglichkeit die Rechnung zu klassifizieren. Diese beiden Aktionen sind in einem
BPMN 2.0 Diagram als Event Elemente dargestellt. Das Event 'Sachrechnung' führt zum Status (Task) "Budgetprüfung" (die vom Sekretariat durchgeführt wird)
und das Event 'Cargorechnung' führt zum Status 'Prüfung Logistikauftrag' (die vom Fachbereich durchgeführt werden kann). In beiden Zuständen kann nun der Mitarbeiter die Rechnung
über das Event "Freigeben" zur Bezahlung freigeben (Task) oder mit "Ablehnen" zurück an die initiale "Rechnungsprüfung" zurücksenden. Nach der Bezahlung kann der Mitarbeiter
die Rechnung über die Aktion (Event) "Bezahlt" in den finalen Status (Task) 'Archiviert' senden.
In einem BPMN Diagram sind diese Verzweigungen bei den Entscheidungen mit Gateways dargestellt.
Erstelle für diesen Prozessablauf eine sehr kompakte Darstellungsform, die für ein KI Prompt Template geeignet ist.

View file

@ -1,389 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<bpmn2:definitions xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:open-bpmn="http://open-bpmn.org/XMLSchema" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" exporter="org.openbpmn" exporterVersion="1.0.0" targetNamespace="http://open-bpmn.org" xmlns:bpmn2="http://www.omg.org/spec/BPMN/20100524/MODEL">
<bpmn2:collaboration id="collaboration_1" name="Default Collaboration">
<bpmn2:participant id="participant_TgW2JA" name="Default Process" processRef="process_1"/>
<bpmn2:participant id="participant_tgRhJQ" name="Rechnungseingang" processRef="process_lYaFpg">
<bpmn2:documentation id="documentation_wSfXcQ"><![CDATA[Dieser Workflow dient dazu eingehende Rechnungen zu prüfen und zur Bezahlung weiterzuleiten. Es wird unterschieden von Sachrechnungen, die vom Sekretariat bearbeitet werden können und Cargo-Rechnungen die durch die Logistikabteilung anhand von Logistikaufträgen geprüft werden.
Nachdem die Rechnung bezahlt wurde wird der Vorgang archiviert. ]]></bpmn2:documentation>
</bpmn2:participant>
</bpmn2:collaboration>
<bpmn2:extensionElements>
<open-bpmn:auto-align>true</open-bpmn:auto-align>
</bpmn2:extensionElements>
<bpmn2:process definitionalCollaborationRef="collaboration_1" id="process_1" name="Default Process" processType="Public">
<bpmn2:documentation id="documentation_wXazVg"/>
</bpmn2:process>
<bpmn2:process definitionalCollaborationRef="collaboration_1" id="process_lYaFpg" isExecutable="true" name="Rechnungseingang" processType="Private">
<bpmn2:laneSet id="laneset_fDygyw" name="Lane Set">
<bpmn2:lane id="lane_BgoDFg" name="Sekretariat">
<bpmn2:documentation id="documentation_hIztzA"/>
<bpmn2:flowNodeRef>task_7Y3UUA</bpmn2:flowNodeRef>
<bpmn2:flowNodeRef>event_bH7Wag</bpmn2:flowNodeRef>
<bpmn2:flowNodeRef>event_oNXxgg</bpmn2:flowNodeRef>
<bpmn2:flowNodeRef>event_GEqHhQ</bpmn2:flowNodeRef>
<bpmn2:flowNodeRef>event_VJXKGg</bpmn2:flowNodeRef>
<bpmn2:flowNodeRef>task_SP75zg</bpmn2:flowNodeRef>
<bpmn2:flowNodeRef>gateway_ASbu1A</bpmn2:flowNodeRef>
<bpmn2:flowNodeRef>gateway_Vyo0Zw</bpmn2:flowNodeRef>
<bpmn2:flowNodeRef>task_xAzhzw</bpmn2:flowNodeRef>
<bpmn2:flowNodeRef>event_YH3bnw</bpmn2:flowNodeRef>
<bpmn2:flowNodeRef>event_1qR49w</bpmn2:flowNodeRef>
<bpmn2:flowNodeRef>task_fHgZBg</bpmn2:flowNodeRef>
<bpmn2:flowNodeRef>event_YnFi7A</bpmn2:flowNodeRef>
</bpmn2:lane>
<bpmn2:lane id="lane_eMP9Xw" name="Fachbereich">
<bpmn2:documentation id="documentation_6ihnmQ"/>
<bpmn2:flowNodeRef>event_A1J0OA</bpmn2:flowNodeRef>
<bpmn2:flowNodeRef>task_5lS3mw</bpmn2:flowNodeRef>
<bpmn2:flowNodeRef>gateway_Hn5ZhQ</bpmn2:flowNodeRef>
<bpmn2:flowNodeRef>event_dJ89xQ</bpmn2:flowNodeRef>
<bpmn2:flowNodeRef>event_30uUNA</bpmn2:flowNodeRef>
</bpmn2:lane>
</bpmn2:laneSet>
<bpmn2:startEvent id="event_bH7Wag" name="Start">
<bpmn2:documentation id="documentation_pguolw"/>
<bpmn2:outgoing>sequenceFlow_8yitUQ</bpmn2:outgoing>
</bpmn2:startEvent>
<bpmn2:task id="task_7Y3UUA" name="Rechnungsprüfung">
<bpmn2:documentation id="documentation_oKsT5Q"><![CDATA[Inhaltliche Prüufng der Rechnung]]></bpmn2:documentation>
<bpmn2:incoming>sequenceFlow_BGVbSA</bpmn2:incoming>
<bpmn2:outgoing>sequenceFlow_FyAf3g</bpmn2:outgoing>
<bpmn2:incoming>sequenceFlow_hvQWmg</bpmn2:incoming>
<bpmn2:incoming>sequenceFlow_j4GDgg</bpmn2:incoming>
</bpmn2:task>
<bpmn2:endEvent id="event_oNXxgg" name="Ende">
<bpmn2:documentation id="documentation_1heF3g"/>
<bpmn2:incoming>sequenceFlow_iVpj0g</bpmn2:incoming>
</bpmn2:endEvent>
<bpmn2:intermediateCatchEvent id="event_GEqHhQ" name="Import">
<bpmn2:documentation id="documentation_gR2xbw"/>
<bpmn2:incoming>sequenceFlow_8yitUQ</bpmn2:incoming>
<bpmn2:outgoing>sequenceFlow_BGVbSA</bpmn2:outgoing>
</bpmn2:intermediateCatchEvent>
<bpmn2:sequenceFlow id="sequenceFlow_8yitUQ" sourceRef="event_bH7Wag" targetRef="event_GEqHhQ">
<bpmn2:documentation id="documentation_2Zd0Aw"/>
</bpmn2:sequenceFlow>
<bpmn2:sequenceFlow id="sequenceFlow_BGVbSA" sourceRef="event_GEqHhQ" targetRef="task_7Y3UUA">
<bpmn2:documentation id="documentation_6k088A"/>
</bpmn2:sequenceFlow>
<bpmn2:intermediateCatchEvent id="event_VJXKGg" name="Sachrechnung">
<bpmn2:documentation id="documentation_DaDN3w"><![CDATA[Weiterleiten zur Sachprüfung]]></bpmn2:documentation>
<bpmn2:incoming>sequenceFlow_rZXh6g</bpmn2:incoming>
<bpmn2:outgoing>sequenceFlow_sNlWkQ</bpmn2:outgoing>
</bpmn2:intermediateCatchEvent>
<bpmn2:task id="task_SP75zg" name="Budgetprüfung">
<bpmn2:documentation id="documentation_qP2Sew"/>
<bpmn2:incoming>sequenceFlow_sNlWkQ</bpmn2:incoming>
<bpmn2:outgoing>sequenceFlow_nxZ9bA</bpmn2:outgoing>
</bpmn2:task>
<bpmn2:task id="task_5lS3mw" name="Prüfung Logistik Auftrag">
<bpmn2:documentation id="documentation_zweAkw"><![CDATA[Prüfung der Rechnung und Abgleich mit Logistikauftrag]]></bpmn2:documentation>
<bpmn2:incoming>sequenceFlow_DXGQrw</bpmn2:incoming>
<bpmn2:outgoing>sequenceFlow_UebylQ</bpmn2:outgoing>
</bpmn2:task>
<bpmn2:eventBasedGateway gatewayDirection="Diverging" id="gateway_ASbu1A" name="">
<bpmn2:documentation id="documentation_09gukg"/>
<bpmn2:incoming>sequenceFlow_FyAf3g</bpmn2:incoming>
<bpmn2:outgoing>sequenceFlow_rZXh6g</bpmn2:outgoing>
<bpmn2:outgoing>sequenceFlow_i7cH2A</bpmn2:outgoing>
</bpmn2:eventBasedGateway>
<bpmn2:sequenceFlow id="sequenceFlow_FyAf3g" sourceRef="task_7Y3UUA" targetRef="gateway_ASbu1A">
<bpmn2:documentation id="documentation_tv00MQ"/>
</bpmn2:sequenceFlow>
<bpmn2:sequenceFlow id="sequenceFlow_rZXh6g" sourceRef="gateway_ASbu1A" targetRef="event_VJXKGg">
<bpmn2:documentation id="documentation_EPAmhQ"/>
</bpmn2:sequenceFlow>
<bpmn2:sequenceFlow id="sequenceFlow_sNlWkQ" sourceRef="event_VJXKGg" targetRef="task_SP75zg">
<bpmn2:documentation id="documentation_iXrfpg"/>
</bpmn2:sequenceFlow>
<bpmn2:intermediateCatchEvent id="event_A1J0OA" name="Cargo Rechnung">
<bpmn2:documentation id="documentation_RWi6LA"><![CDATA[Weiterleitung zur Prüfung Logistikauftrag]]></bpmn2:documentation>
<bpmn2:incoming>sequenceFlow_i7cH2A</bpmn2:incoming>
<bpmn2:outgoing>sequenceFlow_DXGQrw</bpmn2:outgoing>
</bpmn2:intermediateCatchEvent>
<bpmn2:sequenceFlow id="sequenceFlow_i7cH2A" sourceRef="gateway_ASbu1A" targetRef="event_A1J0OA">
<bpmn2:documentation id="documentation_pz6J4g"/>
</bpmn2:sequenceFlow>
<bpmn2:sequenceFlow id="sequenceFlow_DXGQrw" sourceRef="event_A1J0OA" targetRef="task_5lS3mw">
<bpmn2:documentation id="documentation_ngSLdQ"/>
</bpmn2:sequenceFlow>
<bpmn2:exclusiveGateway gatewayDirection="Diverging" id="gateway_Vyo0Zw" name="">
<bpmn2:documentation id="documentation_Pm90XA"/>
<bpmn2:incoming>sequenceFlow_nxZ9bA</bpmn2:incoming>
<bpmn2:outgoing>sequenceFlow_9tp42Q</bpmn2:outgoing>
<bpmn2:outgoing>sequenceFlow_h4SfiQ</bpmn2:outgoing>
</bpmn2:exclusiveGateway>
<bpmn2:intermediateCatchEvent id="event_dJ89xQ" name="Freigabe">
<bpmn2:documentation id="documentation_sB06Ag"><![CDATA[Rechnung in Ordnung und freigegeben zur Bezahlung]]></bpmn2:documentation>
<bpmn2:incoming>sequenceFlow_PLk0RA</bpmn2:incoming>
<bpmn2:outgoing>sequenceFlow_A0FQoA</bpmn2:outgoing>
</bpmn2:intermediateCatchEvent>
<bpmn2:exclusiveGateway gatewayDirection="Diverging" id="gateway_Hn5ZhQ" name="">
<bpmn2:documentation id="documentation_aLEQqQ"/>
<bpmn2:incoming>sequenceFlow_UebylQ</bpmn2:incoming>
<bpmn2:outgoing>sequenceFlow_PLk0RA</bpmn2:outgoing>
<bpmn2:outgoing>sequenceFlow_xVEjcA</bpmn2:outgoing>
</bpmn2:exclusiveGateway>
<bpmn2:sequenceFlow id="sequenceFlow_UebylQ" sourceRef="task_5lS3mw" targetRef="gateway_Hn5ZhQ">
<bpmn2:documentation id="documentation_MZdr7Q"/>
</bpmn2:sequenceFlow>
<bpmn2:task id="task_xAzhzw" name="Bezahlung">
<bpmn2:documentation id="documentation_zO3SRw"/>
<bpmn2:incoming>sequenceFlow_9OrwEg</bpmn2:incoming>
<bpmn2:incoming>sequenceFlow_A0FQoA</bpmn2:incoming>
<bpmn2:outgoing>sequenceFlow_OfKNWA</bpmn2:outgoing>
</bpmn2:task>
<bpmn2:sequenceFlow id="sequenceFlow_nxZ9bA" sourceRef="task_SP75zg" targetRef="gateway_Vyo0Zw">
<bpmn2:documentation id="documentation_G4qmmA"/>
</bpmn2:sequenceFlow>
<bpmn2:sequenceFlow id="sequenceFlow_PLk0RA" sourceRef="gateway_Hn5ZhQ" targetRef="event_dJ89xQ">
<bpmn2:documentation id="documentation_Y5qwSA"/>
</bpmn2:sequenceFlow>
<bpmn2:intermediateCatchEvent id="event_YH3bnw" name="Freigeben">
<bpmn2:documentation id="documentation_C05Bhw"><![CDATA[Rechnung in Ordnung und freigegeben zur Bezahlung]]></bpmn2:documentation>
<bpmn2:incoming>sequenceFlow_9tp42Q</bpmn2:incoming>
<bpmn2:outgoing>sequenceFlow_9OrwEg</bpmn2:outgoing>
</bpmn2:intermediateCatchEvent>
<bpmn2:sequenceFlow id="sequenceFlow_9tp42Q" sourceRef="gateway_Vyo0Zw" targetRef="event_YH3bnw">
<bpmn2:documentation id="documentation_PIQaSg"/>
</bpmn2:sequenceFlow>
<bpmn2:sequenceFlow id="sequenceFlow_9OrwEg" sourceRef="event_YH3bnw" targetRef="task_xAzhzw">
<bpmn2:documentation id="documentation_0eagTw"/>
</bpmn2:sequenceFlow>
<bpmn2:intermediateCatchEvent id="event_1qR49w" name="Ablehnen">
<bpmn2:documentation id="documentation_cdpcXA"/>
<bpmn2:incoming>sequenceFlow_h4SfiQ</bpmn2:incoming>
<bpmn2:outgoing>sequenceFlow_hvQWmg</bpmn2:outgoing>
</bpmn2:intermediateCatchEvent>
<bpmn2:intermediateCatchEvent id="event_30uUNA" name="Ablehnen">
<bpmn2:documentation id="documentation_VazNUA"/>
<bpmn2:incoming>sequenceFlow_xVEjcA</bpmn2:incoming>
<bpmn2:outgoing>sequenceFlow_j4GDgg</bpmn2:outgoing>
</bpmn2:intermediateCatchEvent>
<bpmn2:sequenceFlow id="sequenceFlow_h4SfiQ" sourceRef="gateway_Vyo0Zw" targetRef="event_1qR49w">
<bpmn2:documentation id="documentation_Q2yPDw"/>
</bpmn2:sequenceFlow>
<bpmn2:sequenceFlow id="sequenceFlow_hvQWmg" sourceRef="event_1qR49w" targetRef="task_7Y3UUA">
<bpmn2:documentation id="documentation_qkneSw"/>
</bpmn2:sequenceFlow>
<bpmn2:sequenceFlow id="sequenceFlow_xVEjcA" sourceRef="gateway_Hn5ZhQ" targetRef="event_30uUNA">
<bpmn2:documentation id="documentation_l9waIg"/>
</bpmn2:sequenceFlow>
<bpmn2:sequenceFlow id="sequenceFlow_j4GDgg" sourceRef="event_30uUNA" targetRef="task_7Y3UUA">
<bpmn2:documentation id="documentation_4vaLww"/>
</bpmn2:sequenceFlow>
<bpmn2:sequenceFlow id="sequenceFlow_A0FQoA" sourceRef="event_dJ89xQ" targetRef="task_xAzhzw">
<bpmn2:documentation id="documentation_fAB90Q"/>
</bpmn2:sequenceFlow>
<bpmn2:task id="task_fHgZBg" name="Archiviert">
<bpmn2:documentation id="documentation_Idessw"><![CDATA[Rechnungsprüfung abgeschlossen und Rechnung archiveirt.]]></bpmn2:documentation>
<bpmn2:incoming>sequenceFlow_A0FQoA</bpmn2:incoming>
<bpmn2:incoming>sequenceFlow_sUEtcA</bpmn2:incoming>
<bpmn2:outgoing>sequenceFlow_iVpj0g</bpmn2:outgoing>
</bpmn2:task>
<bpmn2:intermediateCatchEvent id="event_YnFi7A" name="Bezahlt">
<bpmn2:documentation id="documentation_Jz0LKg"><![CDATA[Rechnungsbetrag wurde überwiesen]]></bpmn2:documentation>
<bpmn2:incoming>sequenceFlow_OfKNWA</bpmn2:incoming>
<bpmn2:outgoing>sequenceFlow_sUEtcA</bpmn2:outgoing>
</bpmn2:intermediateCatchEvent>
<bpmn2:sequenceFlow id="sequenceFlow_OfKNWA" sourceRef="task_xAzhzw" targetRef="event_YnFi7A">
<bpmn2:documentation id="documentation_DdJpCg"/>
</bpmn2:sequenceFlow>
<bpmn2:sequenceFlow id="sequenceFlow_sUEtcA" sourceRef="event_YnFi7A" targetRef="task_fHgZBg">
<bpmn2:documentation id="documentation_uG0SGg"/>
</bpmn2:sequenceFlow>
<bpmn2:sequenceFlow id="sequenceFlow_iVpj0g" sourceRef="task_fHgZBg" targetRef="event_oNXxgg">
<bpmn2:documentation id="documentation_Is0LqQ"/>
</bpmn2:sequenceFlow>
</bpmn2:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1" name="OpenBPMN Diagram">
<bpmndi:BPMNPlane bpmnElement="collaboration_1" id="BPMNPlane_1">
<bpmndi:BPMNShape bpmnElement="event_bH7Wag" id="BPMNShape_uh055A">
<dc:Bounds height="36.0" width="36.0" x="307.0" y="-233.0"/>
<bpmndi:BPMNLabel id="BPMNLabel_iQJHWQ">
<dc:Bounds height="20.0" width="100.0" x="275.0" y="-194.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="event_oNXxgg" id="BPMNShape_UInW7g">
<dc:Bounds height="36.0" width="36.0" x="1777.0" y="-233.0"/>
<bpmndi:BPMNLabel id="BPMNLabel_34qp2g">
<dc:Bounds height="20.0" width="100.0" x="1745.0" y="-194.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="task_7Y3UUA" id="BPMNShape_6O8H3A">
<dc:Bounds height="50.0" width="110.0" x="520.0" y="-240.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="participant_tgRhJQ" id="BPMNShape_nrps0Q">
<dc:Bounds height="630.0" width="1650.0" x="230.0" y="-370.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="lane_BgoDFg" id="BPMNShape_Lane_D1gWUg">
<dc:Bounds height="258.0" width="1620.0" x="260.0" y="-370.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="lane_eMP9Xw" id="BPMNShape_Lane_j8rKkg">
<dc:Bounds height="372.0" width="1620.0" x="260.0" y="-112.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="event_GEqHhQ" id="BPMNShape_NYeOlw">
<dc:Bounds height="36.0" width="36.0" x="397.0" y="-233.0"/>
<bpmndi:BPMNLabel id="BPMNLabel_u0gAdw">
<dc:Bounds height="20.0" width="100.0" x="365.0" y="-194.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge bpmnElement="sequenceFlow_8yitUQ" id="BPMNEdge_SKFqeQ" sourceElement="BPMNShape_uh055A" targetElement="BPMNShape_NYeOlw">
<di:waypoint x="343.0" y="-215.0"/>
<di:waypoint x="397.0" y="-215.0"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="sequenceFlow_BGVbSA" id="BPMNEdge_qcdmuA" sourceElement="BPMNShape_NYeOlw" targetElement="BPMNShape_6O8H3A">
<di:waypoint x="433.0" y="-215.0"/>
<di:waypoint x="520.0" y="-215.0"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNShape bpmnElement="event_VJXKGg" id="BPMNShape_QCvdOw">
<dc:Bounds height="36.0" width="36.0" x="797.0" y="-233.0"/>
<bpmndi:BPMNLabel id="BPMNLabel_6j9aVg">
<dc:Bounds height="20.0" width="100.0" x="765.0" y="-194.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="task_SP75zg" id="BPMNShape_dnAc8g">
<dc:Bounds height="50.0" width="110.0" x="930.0" y="-240.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="task_5lS3mw" id="BPMNShape_VFDbeg">
<dc:Bounds height="50.0" width="110.0" x="920.0" y="0.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="gateway_ASbu1A" id="BPMNShape_LIkiBA">
<dc:Bounds height="50.0" width="50.0" x="680.0" y="-240.0"/>
<bpmndi:BPMNLabel id="BPMNLabel_uZQpOQ">
<dc:Bounds height="20.0" width="100.0" x="655.0" y="-187.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge bpmnElement="sequenceFlow_FyAf3g" id="BPMNEdge_F0Y1Tw" sourceElement="BPMNShape_6O8H3A" targetElement="BPMNShape_LIkiBA">
<di:waypoint x="630.0" y="-215.0"/>
<di:waypoint x="680.0" y="-215.0"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="sequenceFlow_rZXh6g" id="BPMNEdge_luL2IA" sourceElement="BPMNShape_LIkiBA" targetElement="BPMNShape_QCvdOw">
<di:waypoint x="730.0" y="-215.0"/>
<di:waypoint x="797.0" y="-215.0"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="sequenceFlow_sNlWkQ" id="BPMNEdge_vB8usw" sourceElement="BPMNShape_QCvdOw" targetElement="BPMNShape_dnAc8g">
<di:waypoint x="833.0" y="-215.0"/>
<di:waypoint x="930.0" y="-215.0"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNShape bpmnElement="event_A1J0OA" id="BPMNShape_KJbgeQ">
<dc:Bounds height="36.0" width="36.0" x="787.0" y="7.0"/>
<bpmndi:BPMNLabel id="BPMNLabel_Rmen0A">
<dc:Bounds height="20.0" width="100.0" x="755.0" y="46.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge bpmnElement="sequenceFlow_i7cH2A" id="BPMNEdge_HBLd5A" sourceElement="BPMNShape_LIkiBA" targetElement="BPMNShape_KJbgeQ">
<di:waypoint x="703.0" y="-192.0"/>
<di:waypoint x="703.0" y="25.0"/>
<di:waypoint x="787.0" y="25.0"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="sequenceFlow_DXGQrw" id="BPMNEdge_s15wBA" sourceElement="BPMNShape_KJbgeQ" targetElement="BPMNShape_VFDbeg">
<di:waypoint x="823.0" y="25.0"/>
<di:waypoint x="920.0" y="25.0"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNShape bpmnElement="gateway_Vyo0Zw" id="BPMNShape_QihA6g">
<dc:Bounds height="50.0" width="50.0" x="1090.0" y="-240.0"/>
<bpmndi:BPMNLabel id="BPMNLabel_cyvcMA">
<dc:Bounds height="20.0" width="100.0" x="1065.0" y="-187.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="event_dJ89xQ" id="BPMNShape_4M1lNg">
<dc:Bounds height="36.0" width="36.0" x="1187.0" y="7.0"/>
<bpmndi:BPMNLabel id="BPMNLabel_gdYGpg">
<dc:Bounds height="20.0" width="100.0" x="1155.0" y="46.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="gateway_Hn5ZhQ" id="BPMNShape_mr0ibw">
<dc:Bounds height="50.0" width="50.0" x="1080.0" y="0.0"/>
<bpmndi:BPMNLabel id="BPMNLabel_5l4dRA">
<dc:Bounds height="20.0" width="100.0" x="1055.0" y="53.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge bpmnElement="sequenceFlow_UebylQ" id="BPMNEdge_U0wIKg" sourceElement="BPMNShape_VFDbeg" targetElement="BPMNShape_mr0ibw">
<di:waypoint x="1030.0" y="25.0"/>
<di:waypoint x="1080.0" y="25.0"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNShape bpmnElement="task_xAzhzw" id="BPMNShape_JrIJDQ">
<dc:Bounds height="50.0" width="110.0" x="1290.0" y="-240.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge bpmnElement="sequenceFlow_nxZ9bA" id="BPMNEdge_KKXvFg" sourceElement="BPMNShape_dnAc8g" targetElement="BPMNShape_QihA6g">
<di:waypoint x="1040.0" y="-215.0"/>
<di:waypoint x="1090.0" y="-215.0"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="sequenceFlow_PLk0RA" id="BPMNEdge_8UEsHA" sourceElement="BPMNShape_mr0ibw" targetElement="BPMNShape_4M1lNg">
<di:waypoint x="1130.0" y="25.0"/>
<di:waypoint x="1187.0" y="25.0"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNShape bpmnElement="event_YH3bnw" id="BPMNShape_GUBmSg">
<dc:Bounds height="36.0" width="36.0" x="1197.0" y="-233.0"/>
<bpmndi:BPMNLabel id="BPMNLabel_c48Mng">
<dc:Bounds height="20.0" width="100.0" x="1165.0" y="-194.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge bpmnElement="sequenceFlow_9tp42Q" id="BPMNEdge_0AkLow" sourceElement="BPMNShape_QihA6g" targetElement="BPMNShape_GUBmSg">
<di:waypoint x="1140.0" y="-215.0"/>
<di:waypoint x="1197.0" y="-215.0"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="sequenceFlow_9OrwEg" id="BPMNEdge_eqL00Q" sourceElement="BPMNShape_GUBmSg" targetElement="BPMNShape_JrIJDQ">
<di:waypoint x="1233.0" y="-215.0"/>
<di:waypoint x="1290.0" y="-215.0"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNShape bpmnElement="event_1qR49w" id="BPMNShape_rbG2Zg">
<dc:Bounds height="36.0" width="36.0" x="1097.0" y="-333.0"/>
<bpmndi:BPMNLabel id="BPMNLabel_2qmYIA">
<dc:Bounds height="20.0" width="100.0" x="1065.0" y="-294.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="event_30uUNA" id="BPMNShape_xUycJQ">
<dc:Bounds height="36.0" width="36.0" x="1087.0" y="127.0"/>
<bpmndi:BPMNLabel id="BPMNLabel_40xf3g">
<dc:Bounds height="20.0" width="100.0" x="1055.0" y="166.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge bpmnElement="sequenceFlow_h4SfiQ" id="BPMNEdge_7m0QHg" sourceElement="BPMNShape_QihA6g" targetElement="BPMNShape_rbG2Zg">
<di:waypoint x="1115.0" y="-240.0"/>
<di:waypoint x="1115.0" y="-297.0"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="sequenceFlow_hvQWmg" id="BPMNEdge_xx0UyQ" sourceElement="BPMNShape_rbG2Zg" targetElement="BPMNShape_6O8H3A">
<di:waypoint x="1097.0" y="-315.0"/>
<di:waypoint x="575.0" y="-315.0"/>
<di:waypoint x="575.0" y="-240.0"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="sequenceFlow_xVEjcA" id="BPMNEdge_5276Pw" sourceElement="BPMNShape_mr0ibw" targetElement="BPMNShape_xUycJQ">
<di:waypoint x="1105.0" y="50.0"/>
<di:waypoint x="1105.0" y="127.0"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="sequenceFlow_j4GDgg" id="BPMNEdge_3xc00w" sourceElement="BPMNShape_xUycJQ" targetElement="BPMNShape_6O8H3A">
<di:waypoint x="1087.0" y="145.0"/>
<di:waypoint x="575.0" y="145.0"/>
<di:waypoint x="575.0" y="-190.0"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="sequenceFlow_A0FQoA" id="BPMNEdge_vgxzvQ" sourceElement="BPMNShape_4M1lNg" targetElement="BPMNShape_JrIJDQ">
<di:waypoint x="1223.0" y="25.0"/>
<di:waypoint x="1345.0" y="25.0"/>
<di:waypoint x="1345.0" y="-190.0"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNShape bpmnElement="task_fHgZBg" id="BPMNShape_79up9g">
<dc:Bounds height="50.0" width="110.0" x="1600.0" y="-240.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="event_YnFi7A" id="BPMNShape_THdIqQ">
<dc:Bounds height="36.0" width="36.0" x="1457.0" y="-233.0"/>
<bpmndi:BPMNLabel id="BPMNLabel_P4dNKg">
<dc:Bounds height="20.0" width="100.0" x="1425.0" y="-194.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge bpmnElement="sequenceFlow_OfKNWA" id="BPMNEdge_p2wDpg" sourceElement="BPMNShape_JrIJDQ" targetElement="BPMNShape_THdIqQ">
<di:waypoint x="1400.0" y="-215.0"/>
<di:waypoint x="1457.0" y="-215.0"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="sequenceFlow_sUEtcA" id="BPMNEdge_lOlEPw" sourceElement="BPMNShape_THdIqQ" targetElement="BPMNShape_79up9g">
<di:waypoint x="1493.0" y="-215.0"/>
<di:waypoint x="1600.0" y="-215.0"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="sequenceFlow_iVpj0g" id="BPMNEdge_XmQNXg" sourceElement="BPMNShape_79up9g" targetElement="BPMNShape_UInW7g">
<di:waypoint x="1710.0" y="-215.0"/>
<di:waypoint x="1777.0" y="-215.0"/>
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn2:definitions>

View file

@ -1,207 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<bpmn2:definitions xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI"
xmlns:dc="http://www.omg.org/spec/DD/20100524/DC"
xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:open-bpmn="http://open-bpmn.org/XMLSchema"
xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
exporter="org.openbpmn" exporterVersion="1.0.0" targetNamespace="http://open-bpmn.org"
xmlns:bpmn2="http://www.omg.org/spec/BPMN/20100524/MODEL">
<bpmn2:collaboration id="collaboration_1" name="Default Collaboration">
<bpmn2:participant id="participant_TgW2JA" name="Default Process" processRef="process_1" />
<bpmn2:participant id="participant_tgRhJQ" name="Rechnungseingang" processRef="process_lYaFpg">
<bpmn2:documentation id="documentation_wSfXcQ"><![CDATA[Dieser Workflow dient dazu eingehende Rechnungen zu prüfen und zur Bezahlung weiterzuleiten. Es wird unterschieden von Sachrechnungen, die vom Sekretariat bearbeitet werden können und Cargo-Rechnungen die durch die Logistikabteilung anhand von Logistikaufträgen geprüft werden.
Nachdem die Rechnung bezahlt wurde wird der Vorgang archiviert. ]]></bpmn2:documentation>
</bpmn2:participant>
</bpmn2:collaboration>
<bpmn2:extensionElements>
<open-bpmn:auto-align>true</open-bpmn:auto-align>
</bpmn2:extensionElements>
<bpmn2:process definitionalCollaborationRef="collaboration_1" id="process_1"
name="Default Process" processType="Public">
<bpmn2:documentation id="documentation_wXazVg" />
</bpmn2:process>
<bpmn2:process definitionalCollaborationRef="collaboration_1" id="process_lYaFpg"
isExecutable="true" name="Rechnungseingang" processType="Private">
<bpmn2:laneSet id="laneset_fDygyw" name="Lane Set">
<bpmn2:lane id="lane_BgoDFg" name="Sekretariat">
<bpmn2:documentation id="documentation_hIztzA" />
<bpmn2:flowNodeRef>task_7Y3UUA</bpmn2:flowNodeRef>
<bpmn2:flowNodeRef>event_bH7Wag</bpmn2:flowNodeRef>
<bpmn2:flowNodeRef>event_oNXxgg</bpmn2:flowNodeRef>
<bpmn2:flowNodeRef>event_GEqHhQ</bpmn2:flowNodeRef>
<bpmn2:flowNodeRef>event_VJXKGg</bpmn2:flowNodeRef>
<bpmn2:flowNodeRef>task_SP75zg</bpmn2:flowNodeRef>
<bpmn2:flowNodeRef>gateway_ASbu1A</bpmn2:flowNodeRef>
<bpmn2:flowNodeRef>gateway_Vyo0Zw</bpmn2:flowNodeRef>
<bpmn2:flowNodeRef>task_xAzhzw</bpmn2:flowNodeRef>
<bpmn2:flowNodeRef>event_YH3bnw</bpmn2:flowNodeRef>
<bpmn2:flowNodeRef>event_1qR49w</bpmn2:flowNodeRef>
<bpmn2:flowNodeRef>task_fHgZBg</bpmn2:flowNodeRef>
<bpmn2:flowNodeRef>event_YnFi7A</bpmn2:flowNodeRef>
</bpmn2:lane>
<bpmn2:lane id="lane_eMP9Xw" name="Fachbereich">
<bpmn2:documentation id="documentation_6ihnmQ" />
<bpmn2:flowNodeRef>event_A1J0OA</bpmn2:flowNodeRef>
<bpmn2:flowNodeRef>task_5lS3mw</bpmn2:flowNodeRef>
<bpmn2:flowNodeRef>gateway_Hn5ZhQ</bpmn2:flowNodeRef>
<bpmn2:flowNodeRef>event_dJ89xQ</bpmn2:flowNodeRef>
<bpmn2:flowNodeRef>event_30uUNA</bpmn2:flowNodeRef>
</bpmn2:lane>
</bpmn2:laneSet>
<bpmn2:startEvent id="event_bH7Wag" name="Start">
<bpmn2:documentation id="documentation_pguolw" />
<bpmn2:outgoing>sequenceFlow_8yitUQ</bpmn2:outgoing>
</bpmn2:startEvent>
<bpmn2:task id="task_7Y3UUA" name="Rechnungsprüfung">
<bpmn2:documentation id="documentation_oKsT5Q"><![CDATA[Inhaltliche Prüufng der Rechnung]]></bpmn2:documentation>
<bpmn2:incoming>sequenceFlow_BGVbSA</bpmn2:incoming>
<bpmn2:outgoing>sequenceFlow_FyAf3g</bpmn2:outgoing>
<bpmn2:incoming>sequenceFlow_hvQWmg</bpmn2:incoming>
<bpmn2:incoming>sequenceFlow_j4GDgg</bpmn2:incoming>
</bpmn2:task>
<bpmn2:endEvent id="event_oNXxgg" name="Ende">
<bpmn2:documentation id="documentation_1heF3g" />
<bpmn2:incoming>sequenceFlow_iVpj0g</bpmn2:incoming>
</bpmn2:endEvent>
<bpmn2:intermediateCatchEvent id="event_GEqHhQ" name="Import">
<bpmn2:documentation id="documentation_gR2xbw" />
<bpmn2:incoming>sequenceFlow_8yitUQ</bpmn2:incoming>
<bpmn2:outgoing>sequenceFlow_BGVbSA</bpmn2:outgoing>
</bpmn2:intermediateCatchEvent>
<bpmn2:sequenceFlow id="sequenceFlow_8yitUQ" sourceRef="event_bH7Wag" targetRef="event_GEqHhQ">
<bpmn2:documentation id="documentation_2Zd0Aw" />
</bpmn2:sequenceFlow>
<bpmn2:sequenceFlow id="sequenceFlow_BGVbSA" sourceRef="event_GEqHhQ" targetRef="task_7Y3UUA">
<bpmn2:documentation id="documentation_6k088A" />
</bpmn2:sequenceFlow>
<bpmn2:intermediateCatchEvent id="event_VJXKGg" name="Sachrechnung">
<bpmn2:documentation id="documentation_DaDN3w"><![CDATA[Weiterleiten zur Sachprüfung]]></bpmn2:documentation>
<bpmn2:incoming>sequenceFlow_rZXh6g</bpmn2:incoming>
<bpmn2:outgoing>sequenceFlow_sNlWkQ</bpmn2:outgoing>
</bpmn2:intermediateCatchEvent>
<bpmn2:task id="task_SP75zg" name="Budgetprüfung">
<bpmn2:documentation id="documentation_qP2Sew" />
<bpmn2:incoming>sequenceFlow_sNlWkQ</bpmn2:incoming>
<bpmn2:outgoing>sequenceFlow_nxZ9bA</bpmn2:outgoing>
</bpmn2:task>
<bpmn2:task id="task_5lS3mw" name="Prüfung Logistik Auftrag">
<bpmn2:documentation id="documentation_zweAkw"><![CDATA[Prüfung der Rechnung und Abgleich mit Logistikauftrag]]></bpmn2:documentation>
<bpmn2:incoming>sequenceFlow_DXGQrw</bpmn2:incoming>
<bpmn2:outgoing>sequenceFlow_UebylQ</bpmn2:outgoing>
</bpmn2:task>
<bpmn2:eventBasedGateway gatewayDirection="Diverging" id="gateway_ASbu1A" name="">
<bpmn2:documentation id="documentation_09gukg" />
<bpmn2:incoming>sequenceFlow_FyAf3g</bpmn2:incoming>
<bpmn2:outgoing>sequenceFlow_rZXh6g</bpmn2:outgoing>
<bpmn2:outgoing>sequenceFlow_i7cH2A</bpmn2:outgoing>
</bpmn2:eventBasedGateway>
<bpmn2:sequenceFlow id="sequenceFlow_FyAf3g" sourceRef="task_7Y3UUA" targetRef="gateway_ASbu1A">
<bpmn2:documentation id="documentation_tv00MQ" />
</bpmn2:sequenceFlow>
<bpmn2:sequenceFlow id="sequenceFlow_rZXh6g" sourceRef="gateway_ASbu1A" targetRef="event_VJXKGg">
<bpmn2:documentation id="documentation_EPAmhQ" />
</bpmn2:sequenceFlow>
<bpmn2:sequenceFlow id="sequenceFlow_sNlWkQ" sourceRef="event_VJXKGg" targetRef="task_SP75zg">
<bpmn2:documentation id="documentation_iXrfpg" />
</bpmn2:sequenceFlow>
<bpmn2:intermediateCatchEvent id="event_A1J0OA" name="Cargo Rechnung">
<bpmn2:documentation id="documentation_RWi6LA"><![CDATA[Weiterleitung zur Prüfung Logistikauftrag]]></bpmn2:documentation>
<bpmn2:incoming>sequenceFlow_i7cH2A</bpmn2:incoming>
<bpmn2:outgoing>sequenceFlow_DXGQrw</bpmn2:outgoing>
</bpmn2:intermediateCatchEvent>
<bpmn2:sequenceFlow id="sequenceFlow_i7cH2A" sourceRef="gateway_ASbu1A" targetRef="event_A1J0OA">
<bpmn2:documentation id="documentation_pz6J4g" />
</bpmn2:sequenceFlow>
<bpmn2:sequenceFlow id="sequenceFlow_DXGQrw" sourceRef="event_A1J0OA" targetRef="task_5lS3mw">
<bpmn2:documentation id="documentation_ngSLdQ" />
</bpmn2:sequenceFlow>
<bpmn2:exclusiveGateway gatewayDirection="Diverging" id="gateway_Vyo0Zw" name="">
<bpmn2:documentation id="documentation_Pm90XA" />
<bpmn2:incoming>sequenceFlow_nxZ9bA</bpmn2:incoming>
<bpmn2:outgoing>sequenceFlow_9tp42Q</bpmn2:outgoing>
<bpmn2:outgoing>sequenceFlow_h4SfiQ</bpmn2:outgoing>
</bpmn2:exclusiveGateway>
<bpmn2:intermediateCatchEvent id="event_dJ89xQ" name="Freigabe">
<bpmn2:documentation id="documentation_sB06Ag"><![CDATA[Rechnung in Ordnung und freigegeben zur Bezahlung]]></bpmn2:documentation>
<bpmn2:incoming>sequenceFlow_PLk0RA</bpmn2:incoming>
<bpmn2:outgoing>sequenceFlow_A0FQoA</bpmn2:outgoing>
</bpmn2:intermediateCatchEvent>
<bpmn2:exclusiveGateway gatewayDirection="Diverging" id="gateway_Hn5ZhQ" name="">
<bpmn2:documentation id="documentation_aLEQqQ" />
<bpmn2:incoming>sequenceFlow_UebylQ</bpmn2:incoming>
<bpmn2:outgoing>sequenceFlow_PLk0RA</bpmn2:outgoing>
<bpmn2:outgoing>sequenceFlow_xVEjcA</bpmn2:outgoing>
</bpmn2:exclusiveGateway>
<bpmn2:sequenceFlow id="sequenceFlow_UebylQ" sourceRef="task_5lS3mw" targetRef="gateway_Hn5ZhQ">
<bpmn2:documentation id="documentation_MZdr7Q" />
</bpmn2:sequenceFlow>
<bpmn2:task id="task_xAzhzw" name="Bezahlung">
<bpmn2:documentation id="documentation_zO3SRw" />
<bpmn2:incoming>sequenceFlow_9OrwEg</bpmn2:incoming>
<bpmn2:incoming>sequenceFlow_A0FQoA</bpmn2:incoming>
<bpmn2:outgoing>sequenceFlow_OfKNWA</bpmn2:outgoing>
</bpmn2:task>
<bpmn2:sequenceFlow id="sequenceFlow_nxZ9bA" sourceRef="task_SP75zg" targetRef="gateway_Vyo0Zw">
<bpmn2:documentation id="documentation_G4qmmA" />
</bpmn2:sequenceFlow>
<bpmn2:sequenceFlow id="sequenceFlow_PLk0RA" sourceRef="gateway_Hn5ZhQ" targetRef="event_dJ89xQ">
<bpmn2:documentation id="documentation_Y5qwSA" />
</bpmn2:sequenceFlow>
<bpmn2:intermediateCatchEvent id="event_YH3bnw" name="Freigeben">
<bpmn2:documentation id="documentation_C05Bhw"><![CDATA[Rechnung in Ordnung und freigegeben zur Bezahlung]]></bpmn2:documentation>
<bpmn2:incoming>sequenceFlow_9tp42Q</bpmn2:incoming>
<bpmn2:outgoing>sequenceFlow_9OrwEg</bpmn2:outgoing>
</bpmn2:intermediateCatchEvent>
<bpmn2:sequenceFlow id="sequenceFlow_9tp42Q" sourceRef="gateway_Vyo0Zw" targetRef="event_YH3bnw">
<bpmn2:documentation id="documentation_PIQaSg" />
</bpmn2:sequenceFlow>
<bpmn2:sequenceFlow id="sequenceFlow_9OrwEg" sourceRef="event_YH3bnw" targetRef="task_xAzhzw">
<bpmn2:documentation id="documentation_0eagTw" />
</bpmn2:sequenceFlow>
<bpmn2:intermediateCatchEvent id="event_1qR49w" name="Ablehnen">
<bpmn2:documentation id="documentation_cdpcXA" />
<bpmn2:incoming>sequenceFlow_h4SfiQ</bpmn2:incoming>
<bpmn2:outgoing>sequenceFlow_hvQWmg</bpmn2:outgoing>
</bpmn2:intermediateCatchEvent>
<bpmn2:intermediateCatchEvent id="event_30uUNA" name="Ablehnen">
<bpmn2:documentation id="documentation_VazNUA" />
<bpmn2:incoming>sequenceFlow_xVEjcA</bpmn2:incoming>
<bpmn2:outgoing>sequenceFlow_j4GDgg</bpmn2:outgoing>
</bpmn2:intermediateCatchEvent>
<bpmn2:sequenceFlow id="sequenceFlow_h4SfiQ" sourceRef="gateway_Vyo0Zw" targetRef="event_1qR49w">
<bpmn2:documentation id="documentation_Q2yPDw" />
</bpmn2:sequenceFlow>
<bpmn2:sequenceFlow id="sequenceFlow_hvQWmg" sourceRef="event_1qR49w" targetRef="task_7Y3UUA">
<bpmn2:documentation id="documentation_qkneSw" />
</bpmn2:sequenceFlow>
<bpmn2:sequenceFlow id="sequenceFlow_xVEjcA" sourceRef="gateway_Hn5ZhQ" targetRef="event_30uUNA">
<bpmn2:documentation id="documentation_l9waIg" />
</bpmn2:sequenceFlow>
<bpmn2:sequenceFlow id="sequenceFlow_j4GDgg" sourceRef="event_30uUNA" targetRef="task_7Y3UUA">
<bpmn2:documentation id="documentation_4vaLww" />
</bpmn2:sequenceFlow>
<bpmn2:sequenceFlow id="sequenceFlow_A0FQoA" sourceRef="event_dJ89xQ" targetRef="task_xAzhzw">
<bpmn2:documentation id="documentation_fAB90Q" />
</bpmn2:sequenceFlow>
<bpmn2:task id="task_fHgZBg" name="Archiviert">
<bpmn2:documentation id="documentation_Idessw"><![CDATA[Rechnungsprüfung abgeschlossen und Rechnung archiveirt.]]></bpmn2:documentation>
<bpmn2:incoming>sequenceFlow_A0FQoA</bpmn2:incoming>
<bpmn2:incoming>sequenceFlow_sUEtcA</bpmn2:incoming>
<bpmn2:outgoing>sequenceFlow_iVpj0g</bpmn2:outgoing>
</bpmn2:task>
<bpmn2:intermediateCatchEvent id="event_YnFi7A" name="Bezahlt">
<bpmn2:documentation id="documentation_Jz0LKg"><![CDATA[Rechnungsbetrag wurde überwiesen]]></bpmn2:documentation>
<bpmn2:incoming>sequenceFlow_OfKNWA</bpmn2:incoming>
<bpmn2:outgoing>sequenceFlow_sUEtcA</bpmn2:outgoing>
</bpmn2:intermediateCatchEvent>
<bpmn2:sequenceFlow id="sequenceFlow_OfKNWA" sourceRef="task_xAzhzw" targetRef="event_YnFi7A">
<bpmn2:documentation id="documentation_DdJpCg" />
</bpmn2:sequenceFlow>
<bpmn2:sequenceFlow id="sequenceFlow_sUEtcA" sourceRef="event_YnFi7A" targetRef="task_fHgZBg">
<bpmn2:documentation id="documentation_uG0SGg" />
</bpmn2:sequenceFlow>
<bpmn2:sequenceFlow id="sequenceFlow_iVpj0g" sourceRef="task_fHgZBg" targetRef="event_oNXxgg">
<bpmn2:documentation id="documentation_Is0LqQ" />
</bpmn2:sequenceFlow>
</bpmn2:process>
</bpmn2:definitions>

View file

@ -1,17 +0,0 @@
Prozess: Eingangsrechnungsprüfung
START -> [Task] Rechnungsprüfung
|
|-- [Event] Sachrechnung --> [Task] Budgetprüfung (Sekretariat)
| |
| |-- [Event] Freigeben --> [Task] Bezahlung
| |-- [Event] Ablehnen --> [Task] Rechnungsprüfung
|
|-- [Event] Cargorechnung --> [Task] Prüfung Logistikauftrag (Fachbereich)
|
|-- [Event] Freigeben --> [Task] Bezahlung
|-- [Event] Ablehnen --> [Task] Rechnungsprüfung
[Task] Bezahlung
|
|-- [Event] Bezahlt --> [Task] Archiviert (ENDE)

View file

@ -1,46 +0,0 @@
prozess: Eingangsrechnungsprüfung
start_event: Rechnung importiert
tasks:
- name: Rechnungsprüfung
type: user_task
gateway:
name: Klassifikation
type: exclusive
paths:
- event: Sachrechnung
next_task: Budgetprüfung
role: Sekretariat
- event: Cargorechnung
next_task: Prüfung Logistikauftrag
role: Fachbereich
- name: Budgetprüfung
type: user_task
gateway:
name: Entscheidung
type: exclusive
paths:
- event: Freigeben
next_task: Bezahlung
- event: Ablehnen
next_task: Rechnungsprüfung
- name: Prüfung Logistikauftrag
type: user_task
gateway:
name: Entscheidung
type: exclusive
paths:
- event: Freigeben
next_task: Bezahlung
- event: Ablehnen
next_task: Rechnungsprüfung
- name: Bezahlung
type: service_task
event:
name: Bezahlt
next_task: Archiviert
- name: Archiviert
type: end_event

View file

@ -1,7 +1,9 @@
FROM imixs/imixs-office-workflow:5.1.5-wildfly-29.0.1.Final-jdk17 FROM imixs/imixs-office-workflow:5.0.3-SNAPSHOT
# Setup debug configuration
# COPY ./docker/configuration/standalone-debug.xml /opt/jboss/wildfly/standalone/configuration/
# Deploy artefact # Deploy artefact
RUN rm -r /opt/jboss/wildfly/standalone/deployments/* RUN rm -r /opt/jboss/wildfly/standalone/deployments/*
# Deploy artefact COPY ./*-app/target/*.war /opt/jboss/wildfly/standalone/deployments/
COPY ./target/*.war /opt/jboss/wildfly/standalone/deployments/

View file

@ -1,8 +1,9 @@
FROM imixs/imixs-office-workflow:5.1.5-wildfly-29.0.1.Final-jdk17 FROM imixs/imixs-office-workflow:5.0.3-SNAPSHOT
# Deploy artefact # Deploy artefact
RUN rm -r /opt/jboss/wildfly/standalone/deployments/* RUN rm -r /opt/jboss/wildfly/standalone/deployments/*
COPY ./target/*.war /opt/jboss/wildfly/standalone/deployments/ COPY ./*-app/target/*.war /opt/jboss/wildfly/standalone/deployments/
# Run in Debug Mode # Run in Debug Mode
CMD ["/opt/jboss/wildfly/bin/standalone.sh", "-b", "0.0.0.0", "-bmanagement", "0.0.0.0", "--debug", "*:8787"] CMD ["/opt/jboss/wildfly/bin/standalone.sh", "-b", "0.0.0.0", "-bmanagement", "0.0.0.0", "--debug", "*:8787"]

View file

@ -1,240 +1,146 @@
# Versionen # Versionen
## 1.4.0 (Development)
- neuer AGLAIInvoiceAdapter
der Adapter `com.alexanderlogistics.AGLAIInvoiceAdapter` muss künftig in das Import Event der Rechnungseingangs Modelle. Dieser Adapter Findet den Space und den Mandanten.
Neue Modelle: ### 1.3.0 (Development - Office-Workflow 5.0.2 )
- Posteingang - Migration auf Imixs-Office-Workflow 5.0.2
- posteingang-de-3.0 - Upgrade Imixs-Workflow 6.7
- AMS - Beim XML Invoice Import wird nun auch die Sprache für das Mahnwesen ermittelt (fehlte)
- rechnungseingang-ams-1.1.0.bpmn - Währungsunabhängigkeit
- Lucene Index: item 'cdtr.name' und 'document.company' wurde in den index aufgenommen wegen AI Examples Adapter
## 1.3.6 (Development) - Fix Fälligkeit in maske
- Fix XML Schnittstelle Cargosoft Sammelgutschrift
**KSeF Produktiname II.** - Zahlungseingang kann nun korrigiert werden. => modell update 'zahlungseingang-de-1.0.5' und 'rechnungsausgang-de-1.0.13'
- fix Zahlungseingangs Formular
Neues ksef.xml als Template einspielen
Neue version deployen.
**KSeF Produktiname I.**
Wir bekommen von Majcie einen neuen Prod - Token für KSeF. Dieser muss in das Kubernetes Deployment file eintegragen werden. Auch der Enpunkt muss geändert werden!
- name: KSEF_API_NIP
value: "9552521552"
- name: KSEF_API_TOKEN
value: "2025??????????????????2|nip-9552521552|f?????????????????????????????????????????"
- name: KSEF_API_ENDPOINT
value: "https://api.ksef.mf.gov.pl/v2"
Im Worklfow Modell 'rechnungsausgang' muss das das Partner Mail im Schritt 4200.10 aktiviert werden.
jhendzel@alexander-logistics.com in CC
ralph.soika@imixs.com in BCC
Derzeit fehlen meistens die Mailadressen so dass vermutlich häufig keine Mails rausgehen.
Im Dokument Import 'CARGOSOFT_INVOCIE_XML' muss die Task ID von 5001 auf 4000 geändert werden!!
## 1.3.5
- Verbesserter Cargosoft Export (Eingangsrechnungen)
- Polen KSeF Schnittstelle
- E-Rechnungs Adapter
## 1.3.4
- Finalisierung Business Partner Interface
|- Neue Plugin Logik (Aktualisierung der BP Nummer und Aktivierung von BP Objekten falls diese archiviert waren)
- Zoho Schnittstelle
- Neues DataView und DataGroups Konzept implementiert
### Migration
- Encoding für CSV Import aus cargosoft muss auf `encoding=UTF-8` stehen!
- Neues Businesspartner BPMN Modell einspielen
- Lucene Index neu berechnene wegen 'partner.id'
#### Daten Synchronisation BUsiness Parnter
- Erstmal nach Dubletten suchen:
- https://alexander-logistics-xxx.office-workflow.de/api/cargosoft/remove-dubletten?maxcount=5000
ACHTUNG kann sehr lange laufen (1 Stunde)
- Jetzt die Daten syncen
https://alexander-logistics-xxx.office-workflow.de/api/cargosoft/bp-sync?maxcount=25000
ACHTUNG kann sehr sehr sehr!! lange laufen (3 Stunde)
kann aber auch dann mehrfach aufgerufen werden so dass sich das alles zum guten wendet
#### Modelle Anpassen
in verschiedenen müssen die alten form parts `alexander/cdtreingabe` und `alexander/dbtreingabe` mit dem neuen `alexander/businesspartner_search` ausgetauscht werden.
Der `BusinessPartnerController` bzw. das `InvoicePlugin` bzw. `InvoiceOutgoingPlugin` kümmert sich automatisch um die Migration
Betroffen sind:
- rechnungseingang-\*
- rechnugnseingang-sachrechnung\*
- rechnungsausgang-\*
- zahlungseingang-\*
- Analyse-debitor-\*
Mahnlauf
- dieser müsste so modelliert werden wie `rechnungsausgang-dwc-1.0.3` zu sehen ist!!!!!!
## 1.3.3
- Imixs-Archive 3.1.1. Compactor Service
Migration:
set ARCHIVE_SNAPSHOT_GRACE_PERIOD= 5
set ARCHIVE_SNAPSHOT_COMPACTOR= enabled
## 1.3.2
- Posteingang Worklfow - timeout logic
- added lucene client to docker image
- added optional oidc profile
## 1.3.1
- Imixs-Office-Workflow 5.0.4
- Mulit Currecy Feature für Ausgangsrechnungen
- Neue Analyse Boards
- Neue SOA
- Neues Mahnwesen
## 1.3.0
- Migration auf Imixs-Office-Workflow 5.0.2
- Upgrade Imixs-Workflow 6.7
- Beim XML Invoice Import wird nun auch die Sprache für das Mahnwesen ermittelt (fehlte)
- Währungsunabhängigkeit
- Lucene Index: item 'cdtr.name' und 'document.company' wurde in den index aufgenommen wegen AI Examples Adapter
- Fix Fälligkeit in maske
- Fix XML Schnittstelle Cargosoft Sammelgutschrift
- Zahlungseingang kann nun korrigiert werden. => modell update 'zahlungseingang-de-1.0.5' und 'rechnungsausgang-de-1.0.13'
- fix Zahlungseingangs Formular
**Migration** **Migration**
1. Parameter Pflegen 1. Parameter Pflegen
a) Währungen pflegen a) Währungen pflegen
- DE = EUR;CHF;SEK;RUB;NOK;GBP;USD;CAD - DE = EUR;CHF;SEK;RUB;NOK;GBP;USD;CAD
- PL = PLN;EUR;CHF;SEK;RUB;NOK;GBP;USD;CAD - PL = PLN;EUR;CHF;SEK;RUB;NOK;GBP;USD;CAD
- DWC = AED; EUR;CHF;SEK;RUB;NOK;GBP;USD;CAD - DWC = AED; EUR;CHF;SEK;RUB;NOK;GBP;USD;CAD
b) Mandant ID b) Mandant ID
2. OP Listen Template im Textbaustein aktualisieren 2. OP Listen Template im Textbaustein aktualisieren
3. Alle Workflow Modelle erneuern 3. Alle Workflow Modelle erneuern
## 1.2.21 (Draft)
- Beim XML Invoice Import wird nun auch die Sprache für das Mahnwesen ermittelt (fehlte)
- Währungsunabhängigkeit
### 1.2.21 (Draft)
- Beim XML Invoice Import wird nun auch die Sprache für das Mahnwesen ermittelt (fehlte)
- Währungsunabhängigkeit
**Migration** **Migration**
1. Paramter Pflegen 1. Paramter Pflegen
a) Währungen pflegen a) Währungen pflegen
- DE = EUR;CHF;SEK;RUB;NOK;GBP;USD;CAD - DE = EUR;CHF;SEK;RUB;NOK;GBP;USD;CAD
- PL = PLN;EUR;CHF;SEK;RUB;NOK;GBP;USD;CAD - PL = PLN;EUR;CHF;SEK;RUB;NOK;GBP;USD;CAD
- DWC = AED; EUR;CHF;SEK;RUB;NOK;GBP;USD;CAD - DWC = AED; EUR;CHF;SEK;RUB;NOK;GBP;USD;CAD
b) Mandant ID b) Mandant ID
2. OP Listen Template im Textbausteein aktualisieren 2. OP Listen Template im Textbausteein aktualisieren
3. Alle Workflow Modelle erneuern 3. Alle Workflow Modelle erneuern
## 1.2.20 (Development) ### 1.2.20 (Development)
- Optimierung OP-Liste nach KW - Optimierung OP-Liste nach KW
- Fix Fälligkeit in maske - Fix Fälligkeit in maske
- Fix XML Schnittstelle Cargosoft Sammelgutschrift - Fix XML Schnittstelle Cargosoft Sammelgutschrift
## 1.2.19 ### 1.2.19
- Neue XML Invoice Schnittstelle - Neue XML Invoice Schnittstelle
- Mahnwesen englisch - Mahnwesen englisch
## 1.2.18
- Fix in Archiv Suche CustomSearchController.java - requestscoped ### 1.2.18
## 1.2.17 - Fix in Archiv Suche CustomSearchController.java - requestscoped
- neue Archive suche ### 1.2.17
- invoice.exchangerate Input ersetzt nun . durch , und locale='de' damit der Wert richtig gespeichert wird!!
## 1.2.16 - neue Archive suche
- invoice.exchangerate Input ersetzt nun . durch , und locale='de' damit der Wert richtig gespeichert wird!!
- Upgrade Imixs-Archive auf 2.4.2 - verbesserter IMAP Import ### 1.2.16
- Upgarde Imixs-Adapters 2.3.3-SNAPSHOT
- Umstellung auf neue Imixs-Archive Backup Technik - Upgrade Imixs-Archive auf 2.4.2 - verbesserter IMAP Import
- Upgarde Imixs-Adapters 2.3.3-SNAPSHOT
- Umstellung auf neue Imixs-Archive Backup Technik
- Neuer manueller SEPA Lauf mit version:
- rechnungseingang-de-1.2.35,
- rechnungseingang_sachrechnung-de-1.0.21,
- rechungseingang-sachrechnung-pl-1.0.1
- sepa-export-manual-3.0.0
- sepa-export-manual-pl-3.0.1
- Neuer manueller SEPA Lauf mit version:
- rechnungseingang-de-1.2.35,
- rechnungseingang_sachrechnung-de-1.0.21,
- rechungseingang-sachrechnung-pl-1.0.1
- sepa-export-manual-3.0.0
- sepa-export-manual-pl-3.0.1
**Achtung**: Kubernetes Deploymets müssen angepasst werden (siehe AGL Polen) **Achtung**: Kubernetes Deploymets müssen angepasst werden (siehe AGL Polen)
## 1.2.15 ### 1.2.15
- kleinere Layout Anpassungen in den Formualren und input Feldern (Positionstabelle, Sachbearbeiter Auswahl...)
- invoice.exchangerate Input ersetzt nun , durch . damit der Wert richtig gespeichert wird.
- Fix Cargosoft DATEV Import - Korektur des Rechnungsdatums / Jahr
- Neuer Rest Service für Korrektur von Cargsoft Ausgangsrechnungen
- kleinere Layout Anpassungen in den Formualren und input Feldern (Positionstabelle, Sachbearbeiter Auswahl...) https://alexander-logistics.office-workflow.de/api/cargosoft/fix/100
- invoice.exchangerate Input ersetzt nun , durch . damit der Wert richtig gespeichert wird.
- Fix Cargosoft DATEV Import - Korektur des Rechnungsdatums / Jahr
- Neuer Rest Service für Korrektur von Cargsoft Ausgangsrechnungen
https://alexander-logistics.office-workflow.de/api/cargosoft/fix/100 ### 1.2.14
## 1.2.14 - Internationalisierung
- Internationalisierung
### 1.2.13
## 1.2.13 - Payment Statistik
- Neue Indexfelder 'invoice.date' 'payment.date'
- Payment Statistik
- Neue Indexfelder 'invoice.date' 'payment.date'
**WICHTIG:** Es muss nach dem Update einmal der Index neu berechnet werden. **WICHTIG:** Es muss nach dem Update einmal der Index neu berechnet werden.
## 1.2.12 ### 1.2.12
- Neue Debitoren/Kreditoren Verwaltung - Zusätzliche E-Mail - Neue Debitoren/Kreditoren Verwaltung - Zusätzliche E-Mail
Realisiert über neue Custom Feld 'textlist' Realisiert über neue Custom Feld 'textlist'
- validierung e-mail erfolgt über Adapter und Workflow Rule - validierung e-mail erfolgt über Adapter und Workflow Rule
## 1.2.10
Inkasso Workflow
## 1.2.8 ### 1.2.10
Neue KI Version Inkasso Workflow
Rechnungasausgangsworkflow + Mahnwesen + OP ### 1.2.8
Zalungsavis für SEPA Rechnungen freigeschaltet Neue KI Version
Rechnungasausgangsworkflow + Mahnwesen + OP
Zalungsavis für SEPA Rechnungen freigeschaltet
## 1.2.7 ### 1.2.7
Erweiterte Kreditoren Verwaltung. Es können bis zu 4 IBAN/BIC Kombinationen pro Kreditor erfasst werden. Erweiterte Kreditoren Verwaltung. Es können bis zu 4 IBAN/BIC Kombinationen pro Kreditor erfasst werden.
Wenn vom Benutezr bei der Rechnungserfassugn eine Kombination eingegeben wird die noch nicht gespeichert war,
wird diese aufgenomen und die anderen rutschen nach unten.
Wenn vom Benutezr bei der Rechnungserfassugn eine Kombination eingegeben wird die noch nicht gespeichert war, ### 1.2.6
wird diese aufgenomen und die anderen rutschen nach unten.
## 1.2.6 Übernahme von IBAN BIC aus kreditoren verwaltung
Übernahme von IBAN BIC aus kreditoren verwaltung ### 1.1.1
## 1.1.1 - Cargosoft Splitbuchungen - Es können zu einer Rechnung mehrere Cargosoft Exporte erzeugt werden. Die Sub Rechnungsnummern stehen im Feld numsequencenumber_sub
- Neue Modellversion rechnungseingnag-de-1.2.0 und posteingang-de-1.0.4
- Cargosoft Splitbuchungen - Es können zu einer Rechnung mehrere Cargosoft Exporte erzeugt werden. Die Sub Rechnungsnummern stehen im Feld numsequencenumber_sub - Das Modell rechnungseingnag-de-1.1.3 kann nach einigen Wochen entfernt werden
- Neue Modellversion rechnungseingnag-de-1.2.0 und posteingang-de-1.0.4
- Das Modell rechnungseingnag-de-1.1.3 kann nach einigen Wochen entfernt werden

View file

@ -1,204 +0,0 @@
# Eigenes Backup-System (Backup-Mirror)
## Architektur, Einrichtung und Disaster-Recovery-Konzept
---
## 1. Idee und Architektur
### 1.1 Ausgangslage
Imixs-Office-Workflow wird von uns als eine transaktionale, hochverfügbare
Geschäftsprozessmanagement-Suite betrieben. Die Basis ist ein Open Source Kernel,
der frei zugänglich ist ([https://github.com/imixs/](https://github.com/imixs/)).
Unabhängig vom gewählten Betriebsmodell (SaaS, Public Cloud, Private Cloud, On
Premise) sind und bleiben Sie Eigentümer Ihrer Geschäftsdaten. Über den
Backup-Service haben Sie die Möglichkeit, jederzeit eigenständig auf eine
vollständige Kopie Ihrer Daten zuzugreifen unabhängig davon, wie und wo Ihre
Instanz aktuell betrieben wird.
### 1.2 Architektur Own your Data
Auch wenn wir den Betrieb Ihrer Instanz übernehmen, bedeutet das nicht, dass Sie
von uns abhängig sind. Über den Backup-Mirror betreiben Sie bei sich einen eigenen,
unabhängigen Backup-Dienst. Dieser Dienst wird von Ihnen selbst eingerichtet,
verwaltet und überwacht und läuft vollständig autark wir müssen ihn technisch
weder kennen noch verwalten. Dadurch gilt:
> **Sie verfügen über eine eigenständige, vollständige Kopie Ihrer
> Geschäftsdaten unabhängig von unserer Infrastruktur. Mit dieser Kopie kann
> Ihr System bei Bedarf komplett neu aufgebaut werden.**
Das ist ein bewusst einfaches und robustes Prinzip: Es kommt nicht darauf an, *wo*
Ihre Daten zusätzlich liegen, sondern *wer* die Kontrolle über diesen zusätzlichen
Sicherungsort hat. Nur wenn diese Kontrolle bei Ihnen liegt, sind Sie wirklich
unabhängig.
### 1.3 Wie es funktioniert
Technisch basiert das Konzept auf dem Open-Source-Projekt
[Imixs-Archive](https://github.com/imixs/imixs-archive), konkret auf dem Baustein
*Imixs-Archive-Backup*. Der Ablauf im Überblick:
1. Bei jeder Änderung an einem Geschäftsvorgang erzeugt Ihre Workflow-Instanz
automatisch einen unveränderlichen Snapshot (eine vollständige Kopie des
Vorgangs inkl. aller angehängten Dokumente).
2. Diese Snapshots werden über die REST-Schnittstelle Ihrer Workflow-Instanz
bereitgestellt.
3. Ein bei Ihnen installierter Backup-Dienst (siehe Abschnitt 2) ruft diese
Snapshots eigenständig ab und speichert sie auf einem Speicherort Ihrer Wahl
(z. B. eigener FTP-/Storage-Server).
Wichtig: Die Verbindung erfolgt **von Ihrem System zu unserer Workflow-Instanz**
(„Pull-Prinzip"). Sie benötigen dafür lediglich einen Netzwerkzugriff auf die
REST-Schnittstelle Ihrer Instanz wir müssen keinen Zugriff auf Ihre Infrastruktur
haben und erhalten auch keinen.
---
## 2. Technische Einrichtung
Der Backup-Dienst kann als Docker-Container in unterschiedlichen Umgebungen betrieben werden:
- **Local**: lokal über Docker oder Docker Compose,
- **Private Cloud**: in einer Private Cloud (z.b. Kubernetes, OpenShift)
- **Public Cloud**: in einer Public Cloud Umgebung (z.b. AWS, Microsoft Azure)
### 2.1 Voraussetzungen
- Eine eigene Server- bzw. Container-Umgebung (Docker) auf Ihrer Seite
- Ein eigener Speicherort für die Backup-Daten (z. B. FTP-Storage, NAS mit
FTP-Anbindung)
- Eine sogenannte **Mirror-ID**, die wir Ihnen bereitstellen
### 2.2 Mirror-ID anfragen
Die Mirror-ID ist eine organisatorische Kennung, mit der wir Ihre eigene
Backup-Verbindung für Ihre Instanz freischalten. Sie ist kein Sicherheitsmerkmal im
engeren Sinn, sondern eine Vereinbarung zwischen uns: *„Kunde X betreibt ein eigenes
Backup."* Bitte fordern Sie diese ID formlos bei uns an.
### 2.3 Backup-Nutzer in Ihrer eigenen Instanz anlegen
Ein zentraler Punkt für die Autarkie des Systems: **Sie legen den technischen
Benutzer für den Backup-Zugriff selbst in Ihrer Imixs-Instanz an.** Dieser Nutzer
gehört ausschließlich Ihnen wir kennen weder das Passwort noch verwalten wir
dieses Konto. Vergeben Sie dem Nutzer ausreichende Leserechte, damit er alle
relevanten Vorgänge und Dokumente sichern kann.
### 2.4 Docker-Compose Beispielkonfiguration
Das folgende Beispiel zeigt eine Docker Compose Konfiguraiton für den Betrieb des Backup-Dienstes:
```yaml
version: "3.6"
services:
backup:
image: imixs/imixs-archive-backup:latest
environment:
TZ: "Europe/Berlin"
WORKFLOW_SERVICE_ENDPOINT: "https://<ihre-instanz>.office-workflow.de/api/"
WORKFLOW_SERVICE_USER: "<ihr-backup-nutzer>"
WORKFLOW_SERVICE_PASSWORD: "<ihr-passwort>"
WORKFLOW_SERVICE_AUTHMETHOD: "form"
BACKUP_FTP_HOST: "<ihr-storage-host>"
BACKUP_FTP_PATH: "<ihr-zielverzeichnis>"
BACKUP_FTP_PORT: "21"
BACKUP_FTP_USER: "<ihr-ftp-nutzer>"
BACKUP_FTP_PASSWORD: "<ihr-ftp-passwort>"
BACKUP_MIRROR_ID: "<ihre-mirror-id>"
ports:
- "8084:8080"
- "9990:9990"
```
**Erläuterung der wichtigsten Parameter:**
| Parameter | Bedeutung |
|---|---|
| `WORKFLOW_SERVICE_ENDPOINT` | Die REST-API-Adresse Ihrer bei uns gehosteten Workflow-Instanz |
| `WORKFLOW_SERVICE_USER/PASSWORD` | Der von Ihnen selbst angelegte Backup-Nutzer |
| `BACKUP_FTP_*` | Ihr eigener Speicherort für die Backup-Daten |
| `BACKUP_MIRROR_ID` | Die von uns bereitgestellte Freischalt-ID |
Nach dem Start prüft der Dienst regelmäßig auf neue zu sichernde Vorgänge und
überträgt diese automatisch auf Ihren Speicherort.
### 2.5 Monitoring des eigenen Backup-Dienstes
Da der Dienst vollständig in Ihrer Verantwortung läuft, sollten Sie ihn aktiv
überwachen. Ein einfacher Ping-Check zeigt zwar, dass der Container erreichbar
ist sagt aber nichts darüber aus, ob der Dienst tatsächlich funktionsfähig ist
und Backups erfolgreich durchführt.
Der Imixs-Archive-Backup-Service stellt hierfür standardisierte **MicroProfile-Endpunkte** mit, die auf Port `9990`
bereitgestellt werden:
| Endpunkt | Beschreibung |
|---|---|
| `/health` | Liefert den Health-Status des Dienstes nach dem MicroProfile-Health-Standard inklusive Readiness (ist der Dienst betriebsbereit, z. B. Verbindung zur Workflow-API und zum FTP-Storage vorhanden?) und Liveness (läuft der Prozess korrekt?) |
| `/metrics` | Liefert Betriebskennzahlen im MicroProfile-Metrics-Format (Prometheus-kompatibel), z. B. Anzahl verarbeiteter Backups, Fehlerzähler, Laufzeiten |
Damit lässt sich der Dienst professionell überwachen:
- **Health-Checks** binden Sie direkt in gängige Monitoring-Systeme ein (z. B.
Kubernetes Liveness-/Readiness-Probes, Uptime-Kuma, Nagios, Icinga) und erkennen
so nicht nur einen abgestürzten Container, sondern auch einen Dienst, der zwar
läuft, aber z. B. keine Verbindung mehr zu Ihrer Workflow-Instanz oder zum
FTP-Ziel herstellen kann.
- **Metrics** lassen sich direkt von Prometheus abgegriffen und in Grafana
visualisiert werden so erkennen Sie auf einen Blick, ob regelmäßig Backups
durchgeführt werden, oder ob z. B. die Fehlerrate ansteigt.
**Voraussetzung:** Sie müssen Port `9990` in Ihrer Docker-Umgebung entsprechend
freigeben bzw. mappen, damit Ihr Monitoring-System auf die Endpunkte zugreifen kann
(siehe Port-Mapping im Beispiel aus Abschnitt 2.4).
Ein Backup, das unbemerkt seit Wochen nicht mehr funktioniert, bietet keinen Schutz.
Die Überwachung über Health- und Metrics-Endpunkte ist daher ein integraler
Bestandteil des Konzepts, nicht optional.
---
## 3. Notfall- und Wiederherstellungsfall (Disaster Recovery)
Im Falle eines Disaster-Recovery-Prozesses stellen Sie uns Ihr Backup zur Verfügung, damit Ihr System auf dessen Basis wiederhergestellt werden kann. Dieser Abschnitt beschreibt das Vorgehen nur in Stichpunkten.
Die vollständige technische Dokumentation der
Imixs-Workflow-Architektur ist Open Source und öffentlich einsehbar unter
[github.com/imixs](https://github.com/imixs).
**Grundprinzip der Wiederherstellung:**
- Ihre gesicherten Snapshot-Daten liegen vollständig und unverändert in Ihrem
eigenen Speicher (FTP/Storage) vor.
- Diese Daten liegen in einem offenen, plattformunabhängigen XML-Format vor und
sind nicht an unsere konkrete Infrastruktur gebunden.
- Auf Basis dieser Daten kann eine neue Imixs-Workflow-Instanz (bei Ihnen oder bei
einem anderen Dienstleister) aufgesetzt werden.
- Über die Restore-Funktion der Imixs-Archive-Komponenten werden die Snapshots in
die neue Instanz zurückgespielt jeder Geschäftsvorgang wird dabei inklusive
seiner Historie und aller Dokumente wiederhergestellt.
**Wichtige Stichpunkte für den Ernstfall:**
- Backup-Daten sind vollständig bei Ihnen vorhanden → keine Abhängigkeit von uns
- Wiederherstellung erfordert eine lauffähige Imixs-Workflow-Umgebung (Open Source,
frei verfügbar)
- Die technische Vorgehensweise zum Restore ist Teil der öffentlichen
Imixs-Archive-Dokumentation
- Wir unterstützen Sie im Ernstfall selbstverständlich gerne beim Wiederaufbau
diese Unterstützung ist jedoch **keine Voraussetzung**, da die Daten und das
Wiederherstellungsverfahren vollständig unabhängig von uns nutzbar sind
---
## 4. Zusammenfassung
Mit dem Backup-Mirror bleiben Sie jederzeit Eigentümer Ihrer Geschäftsdaten unabhängig
davon, wie und wo Ihre Instanz betrieben wird. Sie richten den Dienst selbst ein, verwalten
ihn eigenständig und behalten so die volle Kontrolle über Ihre zusätzliche Datenkopie. Genau
diese Unabhängigkeit ist es, die Ihnen im Bedarfsfall den vollständigen Wiederaufbau Ihres
Systems ermöglicht.
Bei Fragen zur Einrichtung oder zur Anforderung Ihrer Mirror-ID kontaktieren Sie uns
gerne.

View file

@ -1,22 +0,0 @@
version: "3.6"
services:
###############################################
# Backup Service
###############################################
backup:
image: imixs/imixs-archive-backup:latest
environment:
TZ: "Europe/Berlin"
WORKFLOW_SERVICE_ENDPOINT: "https://alexander-logistics-ams.office-workflow.de/api/"
WORKFLOW_SERVICE_USER: "kutzner-backup-service"
WORKFLOW_SERVICE_PASSWORD: "16e-7ede-4c1c-bdeb-e16ce"
WORKFLOW_SERVICE_AUTHMETHOD: "form"
BACKUP_FTP_HOST: "u248962.your-storagebox.de"
BACKUP_FTP_PATH: "/test/agl/ams-test"
BACKUP_FTP_PORT: "21"
BACKUP_FTP_USER: "u248962"
BACKUP_FTP_PASSWORD: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
BACKUP_MIRROR_ID: "backup-mirror-local"
WORKFLOW_REST_JPQL_DOUBLEDECODE_WORKAROUND: "true"
ports:
- "8084:8080"

9
devi
View file

@ -30,13 +30,13 @@ if [[ "$(strip_dash $1)" == "setup" ]]; then
echo " starting dev enrvionment..." echo " starting dev enrvionment..."
mvn clean install -Pdebug mvn clean install -Pdebug
cp ./*-app/target/*.war ./docker/deployments/ cp ./*-app/target/*.war ./docker/deployments/
docker compose -f docker-compose.yml up docker-compose -f docker-compose.yml up
fi fi
if [[ "$(strip_dash $1)" == "start" ]]; then if [[ "$(strip_dash $1)" == "start" ]]; then
echo " Start Dev Environment..." echo " Start Dev Environment..."
docker compose -f docker-compose.yml up docker-compose -f docker-compose.yml up
fi fi
if [[ "$(strip_dash $1)" == "build" ]]; then if [[ "$(strip_dash $1)" == "build" ]]; then
@ -53,17 +53,18 @@ fi
if [[ "$(strip_dash $1)" == "hot" ]]; then if [[ "$(strip_dash $1)" == "hot" ]]; then
echo "* Hotdeploy..." echo "* Hotdeploy..."
cd *-app
mvn manik-hotdeploy:hotdeploy mvn manik-hotdeploy:hotdeploy
cd ..
fi fi
if [[ "$(strip_dash $1)" == "deploy" ]]; then if [[ "$(strip_dash $1)" == "deploy" ]]; then
echo " Deploy to Imixs-Cloud..." echo " Deploy to Imixs-Cloud..."
mvn clean install -Pimixs-cloud -DskipTests mvn clean install -Pkubernetes
fi fi
# Überprüfen, ob keine Parameter übergeben wurden - standard build # Überprüfen, ob keine Parameter übergeben wurden - standard build
if [[ $# -eq 0 ]]; then if [[ $# -eq 0 ]]; then

View file

@ -1,97 +0,0 @@
# BusinessPartner
Wir haben einen Workflow für die Verwaltung von BusinessPartner.
Ein BusinessPartner wird über die bestehende Cargosoft Schnittstelle aus den Debitoren/Kreditoren automatisch importiert und synchronisiert.
In Imixs ist es dann aber möglich zusätzliche Attribute zu einem Businesspartner zu speichern. Beispielsweise:
- Zahlungsziel
- Bankverbindungen
- Emailadressen für Mahnwesen
Die Businessparnter werden für jedes System separat importiert und verwaltet.
Folgende zentrale Stati werden über das BusinessPartner Modell festgelegt:
- TASK_ACTIVE = 1100
- TASK_VERIFICATION = 1300
- TASK_INACTIVE = 1700
- TASK_LOCKED = 1800
Die Invoice Plugins aktualisierne automatisch die BusinessPartner Attribute `partner.id` und `partner.name`. Zusätzlich unterbinden die Plugins eine Verarbeitung falls das Business Objekt im Satus LOCKED oder VERIFICATION ist!
## BusinessPartner Suche
Es gibt einen Controller und ein widget um nach Business Partnern zu suchen.
<img src="images/businesspartner-widget.png" />
Z.b. kann das als Custom Part in eine Form eingebunden werden:
```xml
<item name="bpid" type="custom" path="alexander/businesspartner_search" required="true" label="Businesspartner:" />
```
Der name ist heirbei irrelevant, da immer die Items `partner.id` und `partner.name` ausgefüllt werden.
Zusätzlich kann man mit den Options angeben ob die Maske komplett neu gerendert werden soll. Das ist z.b. bei dem Modell `analyse-debitor.bpmn` der Fall
```xml
<item name="dbtr.number" type="custom" path="alexander/businesspartner_search" required="true" label="Debtor:" options="rerender" />
```
Man kann auch noch über die options eine regular Expression mitgeben wodurch die Filterliste eingeschränkt werden kann:
```xml
<item name="dbtr.number" type="custom" path="alexander/businesspartner_search" required="true" label="Debtor:" options="rerender;regexPattern=(ABC)" />
```
Alternativ kann im Backend über die EJB BusinessPartnerService nach bpid gesucht werden:
```java
List<ItemCollection> resultList = businessPartnerService.search(phrase);
// oder
ItemCollection bp= businessPartnerService.getBusinessPartnerByID("BP0001");
```
## Invoice Plugins
Die Invoice Plugins aktualisieren automatisch partner.id und partner.name falls diese Items noch nicht exiistieren
# Daten Migration
Der `BusinessPartnerImportService` hängt sich über ein CDI Observer Pattern an den standard CSVImport Service
der die Cargosoft Stammdaten aktualisiert. Der BusinessPartnerImportService
prüft ob der Workflow schon existiert oder ggf. aktualisiert werden muss.
Der Service migriert auch die alten zusätzlichen IBAN/BIC felder wenn der Business partner erstmals neu angelegt wird. Falls bei der ersten Migration erkannt wird, dass die IBAN Nummern nicht eindeutig sind wir der BusinessParter mit dem Event 300 angelegt.
-
\_vendor_zip_code
\_vendor_fax
(type:cargosoftkreditor) AND ($modified:[20010101 TO 20250215])
## Anmerkungen zu seltsamen Daten
BP4641 existier jetzt 3 mal mit der Debitoren nummer D14641
Feldmühle
- D14169
K74169
K76233 HSH Papier GmbH & Co. KG
D16233 Manfred Ziegler Transport GmbH
Problemkind: https://alexander-logistics-dwc.office-workflow.de/pages/workitems/workitem.xhtml?id=9dd64b0a-cfe1-4174-aea4-0e8af45b823f
# Business Parter Serach Widget
wir müssten eigentlich nach Auswahl des Partner
execute="#{customFormComponents.clientId}" render="#{customFormComponents.clientId}"
machnen, aber das hat einen blöden effekt

View file

@ -1,11 +1,14 @@
# Cargosoft Schnittstelle
Für den Austausch von Daten mit Cargosoft verwenden wir verschiedene Subaccounts auf unseren FTP Servern.
## Server Verbindungsdaten # Cargosoft Schnittstelle (Bremen - Mandant 001)
Details siehe [FTP Server](FTP.md) Für den Austasuch von Daten mit Cargosoft verwenden wir einen Subaccount `u248962-sub2` der auf das Verzeichnis `/office-alexander-logistics/cargosoft` zeigt:
Server: u248962.your-storagebox.de
Pfad: /office-alexander-logistics/cargosoft
Benutzername: u248962-sub2
Passwort: aXa61n9Un3jDNQlL
## Ausgangsrechnungen ## Ausgangsrechnungen
Ausgansrechnungen werden von Cargosoft im Verzeichnis `/fromCargosoft/imixs_invoices/` bereitgestellt Ausgansrechnungen werden von Cargosoft im Verzeichnis `/fromCargosoft/imixs_invoices/` bereitgestellt
@ -18,3 +21,48 @@ Technisch wird das über die CDI Bean `com.alexanderlogistics.xml.CargosoftXMLIn
Die Kreditoren/Debitoren Stammdaten werden von Cargosoft im Verzeichnis `/fromCargosoft/stammdaten/` über die Datei `Vendors.csv` bereitgestellt Die Kreditoren/Debitoren Stammdaten werden von Cargosoft im Verzeichnis `/fromCargosoft/stammdaten/` über die Datei `Vendors.csv` bereitgestellt
Über den Document Importer `CSV` werden die Dokumente regelmäßig importiert bzw. aktualisert Über den Document Importer `CSV` werden die Dokumente regelmäßig importiert bzw. aktualisert
# Cargosoft Schnittstelle (Bremen Mandant 001)
Server: u248962.your-storagebox.de
Pfad: /office-alexander-logistics/cargosoft
Benutzername: u248962-sub2
Passwort: aXa61n9Un3jDNQlL
# Cargosoft Schnittstelle (Bremerhaven Mandant 005)
Server: u248962.your-storagebox.de
Pfad: /office-alexander-logistics/cargosoft-bhv
Benutzername: u248962-sub5
Passwort: 5hKKzv6TFCKRrAdR
# Cargosoft Schnittstelle (Polen Mandant 003)
Server: u248962.your-storagebox.de
Pfad: /office-alexander-logistics/cargosoft-pl
Benutzername: u248962-sub7
Passwort: PGPzzqmtZ8BSxkbs
# Cargosoft Schnittstelle (Dubai Mandant 006)
Server: u248962.your-storagebox.de
Pfad: /office-alexander-logistics/cargosoft-dwc
Benutzername: u248962-sub3
Passwort: enHjxs9h4nJ6EgsZ
# Cargosoft Schnittstelle (USA Mandant 004)
Server: u248962.your-storagebox.de
Pfad: /office-alexander-logistics/cargosoft-usa
Benutzername: u248962-sub9
Passwort: GMk7NgDBrmb2QqXg
# Cargosoft Schnittstelle (China Mandant 007)
Server: u248962.your-storagebox.de
Pfad: /office-alexander-logistics/cargosoft-chn
Benutzername: u248962-sub10
Passwort: yswBeN83jMqkMqJa

View file

@ -1,314 +0,0 @@
# KSeF API Integration
Java integration for the Polish **Krajowy System e-Faktur (KSeF)** - the national e-invoicing system for Poland.
## Overview
This integration provides secure communication with the KSeF API to upload electronic invoices. It handles the complex multi-step authentication flow and encryption requirements mandated by the Polish tax authorities.
- [Environment Endpoints](https://github.com/CIRFMF/ksef-docs/blob/main/srodowiska.md)
- [KSeF Official Documentation](https://www.gov.pl/web/kas/ksef)
- [KSeF API Specification](https://api-test.ksef.mf.gov.pl/docs/v2/index.html)
- [Upload Invoice](https://api-test.ksef.mf.gov.pl/docs/v2/index.html#tag/Wysylka-interaktywna/paths/~1api~1v2~1sessions~1online~1%7BreferenceNumber%7D~1invoices/post)
- [Facture Details](https://github.com/CIRFMF/ksef-docs/blob/main/sesja-interaktywna.md#2-wys%C5%82anie-faktury)
- [XML Invoice Example](https://github.com/CIRFMF/ksef-docs/blob/main/faktury/weryfikacja-faktury.md)
- [QR Code](https://github.com/CIRFMF/ksef-docs/blob/main/kody-qr.md)
- [Github Discussions](https://github.com/CIRFMF/ksef-docs/issues/351#issuecomment-3538013805)
- [Github Discussions](https://github.com/CIRFMF/ksef-docs/issues/399)
Test environment endpoint:
```
https://api-test.ksef.mf.gov.pl/api/v2
```
Production endpoint:
```
https://api.ksef.mf.gov.pl/api/v2
```
## Components
### 1. KSeFAuthManager
Manages authentication and session lifecycle for the KSeF API.
**Key Responsibilities:**
- Multi-step authentication flow
- RSA certificate management
- Session key generation and encryption
- Access token lifecycle management
- Session reuse and validation
### 2. KSeFAPIService
Provides business-level methods for invoice operations.
**Key Responsibilities:**
- Invoice encryption (AES-256-CBC)
- Invoice upload to KSeF
- Hash calculation and validation
- Error handling and reporting
## Authentication Flow
The KSeF API requires a sophisticated multi-step authentication process:
```
1. Load Public Keys
└─> GET /security/public-key-certificates
2. Challenge Request
└─> POST /auth/challenge
└─> Returns: challenge + timestamp
3. Token Authentication
└─> POST /auth/ksef-token
└─> Encrypts: token|timestamp with RSA-OAEP SHA-256
└─> Returns: authToken + referenceNumber
4. Token Redemption
└─> POST /auth/token/redeem
└─> Returns: accessToken
5. Open Interactive Session
└─> POST /sessions/online
└─> Generates AES-256 key + IV
└─> Encrypts session key with RSA
└─> Returns: sessionRefNumber + validUntil
```
## Invoice Upload Flow
Once authenticated, invoices can be uploaded:
```
1. Reuse or Create Session
└─> Validates existing session or creates new one
2. Encrypt Invoice
└─> AES-256-CBC encryption using session key
3. Calculate Hashes
└─> SHA-256 of original XML
└─> SHA-256 of encrypted XML
4. Upload Invoice
└─> POST /sessions/online/{sessionRef}/invoices
└─> Returns: referenceNumber
```
## Security Features
### Multi-Layer Encryption
- **RSA-OAEP SHA-256**: Token encryption with timestamp binding
- **RSA-OAEP SHA-1**: Session key encryption
- **AES-256-CBC**: Invoice content encryption
### Security Mechanisms
- **Replay Attack Protection**: Timestamp-bound tokens
- **Session Management**: Automatic session reuse and validation
- **Certificate Validation**: Dynamic X.509 certificate loading
- **UTC Timezone Handling**: Prevents timezone-related vulnerabilities
## Usage Example
```java
// Initialize Auth Manager
KSeFAuthManager authManager = new KSeFAuthManager();
authManager.setKsefToken("your-ksef-token");
authManager.setKsefNip("1234567890");
authManager.setKsefEndpoint("https://ksef-test.mf.gov.pl/api/v2");
authManager.init();
// Initialize API Service
KSeFAPIService apiService = new KSeFAPIService();
apiService.kseFAuthManager = authManager;
// Upload Invoice
ItemCollection workitem = new ItemCollection();
FileData fileData = new FileData("invoice.xml", xmlBytes, null, null);
workitem.addFileData(fileData);
String referenceNumber = apiService.uploadInvoice(workitem, "invoice.xml");
System.out.println("Invoice uploaded: " + referenceNumber);
```
## Configuration
Required environment variables:
```properties
ksef.api.token=your-ksef-authentication-token
ksef.api.nip=your-company-nip-number
ksef.api.endpoint=https://ksef-test.mf.gov.pl/api/v2
ksef.api.debug=false
```
## Session Management
The `KSeFAuthManager` automatically handles session lifecycle:
- **Session Reuse**: Validates `sessionValidUntil` timestamp (UTC)
- **Auto-Renewal**: Opens new session if current one expired
- **Thread-Safe**: Uses `@Lock(LockType.WRITE)` for concurrent access
## Testing
Test environment endpoint:
```
https://ksef-test.mf.gov.pl/api/v2
```
Production endpoint:
```
https://ksef.mf.gov.pl/api/v2
```
See `KSeFAPIServiceTest.java` for complete test examples.
## Error Handling
The implementation uses `PluginException` for error handling with two error types:
- `CONFIG_ERROR`: Configuration or setup issues
- `API_ERROR`: API communication or response errors
## Dependencies
- Jakarta EE (EJB, JSON-B)
- Java 11+ (HttpClient, Crypto APIs)
- Imixs Workflow (for document management)
# Validate XML
To validate XML results use xmllint. To install run:
```bash
$ sudo apt install libxml2-utils
```
With the bash script `src/test/resources/ksef/validate_xml.sh` you can test a xml file:
```bash
$ ./validate_xml.sh example-invoice-01.xml
```
or to manual test a xml run:
```bash
$ xmllint --noout --schema 'schemat-FA(3)-v1-0E.xsd' example-invoice-01.xml
example-invoice-01.xml validates
```
# KSeF FA(3) Invoice Types: VAT vs. KOR
This section explains the key differences between regular invoices (VAT) and correction invoices (KOR) in the Polish KSeF system using FA(3) structure.
## Invoice Types
### VAT - Regular Invoice
Standard invoice documenting a sale or service delivery.
### KOR - Correction Invoice
Invoice that corrects a previously issued invoice (VAT, ZAL, or ROZ).
---
## Key Differences
| Element | VAT Invoice | KOR Invoice |
| ------------------------- | -------------------------- | --------------------------------------------- |
| **RodzajFaktury** | `VAT` | `KOR` |
| **P_2 (Invoice Number)** | `216525` | `216525-KOR` (with suffix) |
| **P_1 (Invoice Date)** | Original date (2024-04-03) | Correction date (2024-04-15) |
| **Amount Fields** | Absolute values | **Difference values** (negative or positive) |
| **DaneFaKorygowanej** | ❌ Not present | ✅ **Required** - references original invoice |
| **FaWiersz (Line Items)** | Original values | **New/corrected values** |
---
## Critical: Amount Fields in KOR
**KOR invoices show DIFFERENCES, not absolute amounts!**
### Example: Correction from 4128.00 → 3500.00 EUR
```xml
<!-- VAT Invoice -->
<P_13_1>4128.00</P_13_1> <!-- Total Net -->
<P_14_1>0.00</P_14_1> <!-- Total VAT -->
<P_15>4128.00</P_15> <!-- Total Gross -->
```
```xml
<!-- KOR Invoice -->
<P_13_6_1>-628.00</P_13_6_1> <!-- Difference: 3500 - 4128 = -628 -->
<P_15>-628.00</P_15> <!-- Difference in Total -->
```
## DaneFaKorygowanej Element
**Required in KOR invoices** - Must appear AFTER `<RodzajFaktury>KOR</RodzajFaktury>`
```xml
<DaneFaKorygowanej>
<DataWystFaKorygowanej>2024-04-03</DataWystFaKorygowanej>
<NrFaKorygowanej>216525</NrFaKorygowanej>
<NrKSeF>1</NrKSeF>
<NrKSeFFaKorygowanej>9552521552-20240403-ABCDEF-123456-AB</NrKSeFFaKorygowanej>
</DaneFaKorygowanej>
```
| Field | Description |
| ----------------------- | --------------------------------------------------------- |
| `DataWystFaKorygowanej` | Date of **original** invoice |
| `NrFaKorygowanej` | Number of **original** invoice |
| `NrKSeF` | Flag: `1` = original was in KSeF |
| `NrKSeFFaKorygowanej` | KSeF number of original invoice (mandatory if `NrKSeF=1`) |
⚠️ **Critical:** The KSeF number must be saved when uploading the original VAT invoice!
---
## FaWiersz in KOR
**Line items show the NEW/CORRECTED values**, not differences:
```xml
<!-- VAT Invoice -->
<FaWiersz>
<P_9A>4128.00</P_9A> <!-- Unit price -->
<P_11>4128.00</P_11> <!-- Net value -->
</FaWiersz>
```
```xml
<!-- KOR Invoice -->
<FaWiersz>
<P_9A>3500.00</P_9A> <!-- NEW unit price -->
<P_11>3500.00</P_11> <!-- NEW net value -->
<P_12>0 KR</P_12> <!-- Tax rate (0% for exempted) -->
</FaWiersz>
```
---
# Testdaten
Um Testdaten in die lokale Dev Umgebung zu importieren:
1. aus dem Produktiv Archiv System das XML eines Rechnungs-Snapshots unter /docker/transfer speichern
2. per api Call importieren:
http://localhost:8080/api/cargosoft/import?file=/opt/jboss/wildfly/transfer/f28bf914-04de-4843-9809-54c724bdc9bf-1764111735524.xml

View file

@ -1,26 +0,0 @@
# Test Cases
Invoice
| No | currency | Tax % | Netto | Brutto | Imixs | TAXMAN |
| ---- | -------- | ----- | ---------- | ---------- | --------- | ------ |
| 6562 | EUR | 0 | 964,16 | 964,16 | OK |
| 6555 | PLN | 23 | 31820,10 | 40894,7 | OK |
| 6586 | PLN | 23 | 110.146,50 | 141.820,90 | OK |
| 6467 | USD | 0 | 1540,00 | 1540,00 | OK |
| 6567 | EUR | 0 | 9940,96 | 9940,96 | NIP Fehlt |
# Neuer Testlauf
6602 correction invoice where just description was changed, without changing of amounts (price, VAT..)
6816 - correction invoice where amounts where changed (before correction 180 USD, after correction 0 USD)
6811 invoice with more positions, incl. positions with different VAT rate
| No | currency | Tax % | Netto | Brutto | Imixs | TAXMAN |
| ---- | -------- | ----- | ----- | ------ | ----- | ------ |
| 6602 | | 0 | | | | OK |
| 6816 | | 0 | | | | OK |
| 6811 | | 0 | | | | OK |
| | | 0 | | | | |
| | | 0 | | | | |
| | | 0 | | | | |

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,75 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Potwierdzenie xmlns="http://upo.schematy.mf.gov.pl/KSeF/v4-2">
<NazwaPodmiotuPrzyjmujacego>Ministerstwo Finansów</NazwaPodmiotuPrzyjmujacego>
<NumerReferencyjnySesji>20251128-SO-1DA83DC000-9430B11465-93</NumerReferencyjnySesji>
<Uwierzytelnienie>
<IdKontekstu>
<Nip>9552521552</Nip>
</IdKontekstu>
<NumerReferencyjnyTokenaKSeF>20251113-EC-2751AC3000-5C5466924B-62</NumerReferencyjnyTokenaKSeF>
</Uwierzytelnienie>
<NazwaStrukturyLogicznej>1-0E</NazwaStrukturyLogicznej>
<KodFormularza>FA (3)</KodFormularza>
<Dokument>
<NipSprzedawcy>9552521552</NipSprzedawcy>
<NumerKSeFDokumentu>9552521552-20251128-010000AA503B-FE</NumerKSeFDokumentu>
<NumerFaktury>216577</NumerFaktury>
<DataWystawieniaFaktury>2024-04-03</DataWystawieniaFaktury>
<DataPrzeslaniaDokumentu>2025-11-28T09:38:18.096+01:00</DataPrzeslaniaDokumentu>
<DataNadaniaNumeruKSeF>2025-11-28T09:38:18.192+01:00</DataNadaniaNumeruKSeF>
<SkrotDokumentu>wk2TorojBbyNYtDODL1l/KCxQi/rlb3Yss/OEmf5HpE=</SkrotDokumentu>
</Dokument>
<Signature Id="Signature" xmlns="http://www.w3.org/2000/09/xmldsig#">
<SignedInfo>
<CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315" />
<SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256" />
<Reference URI="">
<Transforms>
<Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" />
</Transforms>
<DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" />
<DigestValue>N/EazXugPjJtobeCSm/ShxeSafdffzHFeRo/BLsngR4=</DigestValue>
</Reference>
<Reference URI="#SignedProperties" Type="http://uri.etsi.org/01903#SignedProperties">
<Transforms>
<Transform Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315" />
</Transforms>
<DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" />
<DigestValue>7OYxftjJC1QhSKcWd/oeu7jJaLiO1kFvDCLja8xmNqk=</DigestValue>
</Reference>
</SignedInfo>
<SignatureValue>
c87dKdbK3Wf2QpeKEEC0H2LMG92YBH95EbKL6wJTqozOzPq6wqj+06CIPX6bIEz8Szup9xWJlJHX+/xzO4NyMxeiXMQOCAiQ4ZnhPLG2EChopNZYGDbVgOMvfSQBSkHODobG8HH+q4fqueya0V+41CnCSzF8f68fcfVTrV8DfAuw3faKYVg4ddfkvFT+AkBCAZ/JPdYzVVN28np33bd1lHNFJ5wNSpILy9h0FF9iJIiB5RMyvJwxx0HlutrhIMUoId5vUW2XLJKAOLJSSntTJf2S4qjMJcgZr/ZVP9GSaBZPBX09nPWrXOfOwIOuakVfq9N2n+ONZ29ivHpZelMWlA==</SignatureValue>
<KeyInfo>
<X509Data>
<X509Certificate>
MIIGWDCCBECgAwIBAgIQY1FHALBG7qGuhTJ/Z7W+yjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJQTDEhMB8GA1UECgwYQXNzZWNvIERhdGEgU3lzdGVtcyBTLkEuMRwwGgYDVQQDDBNDZXJ0dW0gU01JTUUgUlNBIENBMB4XDTI1MDkyOTA2MTEzM1oXDTI3MDkyOTA2MTEzMlowgb4xGTAXBgNVBGETEFZBVFBMLTUyNjAyNTAyNzQxCzAJBgNVBAYTAlBMMRQwEgYDVQQIDAttYXpvd2llY2tpZTERMA8GA1UEBwwIV2Fyc3phd2ExHzAdBgNVBAoMFk1pbmlzdGVyc3R3byBGaW5hbnPDs3cxHzAdBgNVBAMMFk1pbmlzdGVyc3R3byBGaW5hbnPDs3cxKTAnBgkqhkiG9w0BCQEWGmtvbnN1bHRhY2plLmtzZWZAbWYuZ292LnBsMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtL+kpQU8d16im5Z3wIEzo7GqfQF8zWEYZqN5JroiX2ePVACR3znmoo4zx0krVEyhtKKB2/oE3Ql2M5sxaRWC/hnBMLj8r7uAJ/v3lQqzGYAf0ImwRy1H+nF4OS0B1U0m7wD2dGXOSQdbPNVru8SZ9Nw6IcsuAsHezy8EagEIffl+zA/GWtAG6Mp8Bxj3K8LkUdZp70Faaeiv25kOuvT7vThePW+qNFhpdktYQT56lGOmWJqKsm0QtdMzAy1o7bfWeAFLfP7DU3Okk/oz9NqUJc8Swih2ligWN/+g/nwFxcEMrQ4GWE3FDQogNz6kySZ7OIqN//kY1SXXb1nQ1MVAXQIDAQABo4IBvzCCAbswDAYDVR0TAQH/BAIwADBBBgNVHR8EOjA4MDagNKAyhjBodHRwOi8vY3NtaW1lcnNhY2EuY3JsLmNlcnR1bS5wbC9jc21pbWVyc2FjYS5jcmwwgYMGCCsGAQUFBwEBBHcwdTAuBggrBgEFBQcwAYYiaHR0cDovL2NzbWltZXJzYWNhLm9jc3AtY2VydHVtLmNvbTBDBggrBgEFBQcwAoY3aHR0cDovL2NzbWltZXJzYWNhLnJlcG9zaXRvcnkuY2VydHVtLnBsL2NzbWltZXJzYWNhLmNlcjAfBgNVHSMEGDAWgBRm+8MPvvS/4JzJq03eRxm9wMqmaDAdBgNVHQ4EFgQUGwFEj1u0JETJoPhJu2cKjErLsUwwTAYDVR0gBEUwQzAJBgdngQwBBQICMDYGCyqEaAGG9ncCZAMBMCcwJQYIKwYBBQUHAgEWGWh0dHBzOi8vd3d3LmNlcnR1bS5wbC9DUFMwHQYDVR0lBBYwFAYIKwYBBQUHAwQGCCsGAQUFBwMCMA4GA1UdDwEB/wQEAwIE8DAlBgNVHREEHjAcgRprb25zdWx0YWNqZS5rc2VmQG1mLmdvdi5wbDANBgkqhkiG9w0BAQsFAAOCAgEAOfiPMXAeftxKk6fMiRud/VZnQixhHqBakVx11ToO7m8qGW3gj2NJDkIoIWVuRIDpz6bg7vRoyPE0mSjYkjxXfb/gaAHVM1e9vGd5cN5esvJVc9wAbLY/e1ZAg7K8IHE+SQYjLsm0ykCQcnnamzEjSD6CArGUmvwJr33OnlNusVdSZ6ar+EexAEbwBUYL+8aeKYwXn+M928h4W831LxYoVv1WaNFfgUJHjFrIUNeSuXHLG0BslrJwJuy26UQaxiM0FSNJQyeSF5Xt3K+V7EuzX4jf3yfOcTwUrt/4Lq6AEH+konMj5OZurS75aA06NbR6L4hUWfdCFRIx561Y2sHeNlggONsvvQ//z0P9IVk65RqDz21DPt688SRJ5BL5wGo9CDn29+G8VEECPRuhe+UAoQOL/9iQ2mReybunuliarQCLGya/+Ig9QRZe9BWhlN7im1B+7kaMmTbGqzmUkiFoabH+hIqqh72o5B05H9U8R0o7PpI9oJZ95edst1y9fCXw5fbly5Y3N3lR78Ui3AkUf6NN6ZtsMixVHZS8qD/QTaXDX4ez8Kz1PkMGrPWYC0L64PZzyWGZmm3RNtvv/uqx4X/L0Kyu5Dp5+H5BJyQAGh+wHJ5TadGuzASThvuB+fXEhwO3Y+bS41G2czc1vf3s9DXSqMZykYVzRbPQ2XUWkzQ=</X509Certificate>
</X509Data>
</KeyInfo>
<Object>
<xades:QualifyingProperties Target="#Signature"
xmlns:xades="http://uri.etsi.org/01903/v1.3.2#"
xmlns="http://www.w3.org/2000/09/xmldsig#">
<xades:SignedProperties Id="SignedProperties">
<xades:SignedSignatureProperties>
<xades:SigningTime>2025-11-28T08:38:18.2360956+00:00</xades:SigningTime>
<xades:SigningCertificate>
<xades:Cert>
<xades:CertDigest>
<DigestMethod
Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" />
<DigestValue>IFnqTIVQHeVNK0sYY9kn/o3hT2FGIV6U7keiW0zj/Ig=</DigestValue>
</xades:CertDigest>
<xades:IssuerSerial>
<X509IssuerName>CN=Certum SMIME RSA CA, O=Asseco Data Systems
S.A., C=PL</X509IssuerName>
<X509SerialNumber>132015587733884965165641957463135993546</X509SerialNumber>
</xades:IssuerSerial>
</xades:Cert>
</xades:SigningCertificate>
</xades:SignedSignatureProperties>
</xades:SignedProperties>
</xades:QualifyingProperties>
</Object>
</Signature>
</Potwierdzenie>

6
doc/MAIL_OAUTH2.md Normal file
View file

@ -0,0 +1,6 @@
https://techcommunity.microsoft.com/t5/exchange/javamail-connecting-to-office-365-xoauth2-for-imap/m-p/1505026

View file

@ -1,47 +0,0 @@
# Metrics
**Konzept Verworfen!**
## Background:
https://blog.imixs.org/2025/02/02/business-intelligence-built-on-metrics-part-ii/
**Die Implementierung war Teil von Version 1.3.1!**
## Testing
Curl
$ curl -s http://localhost:9990/metrics
$ curl -s http://localhost:9990/metrics | grep BP4218
```
application_dbtr_balance{country="", currency="EUR",department="Import Zellulose/Holz",id="BP4218",name="Rayonier Advanced Materials",type="dbtr"} 60911.28
application_dbtr_balance{country="US",currency="EUR",department="Import Zellulose/Holz",id="BP4218",name="Rayonier Advanced Materials",type="dbtr"} 257955.41
application_dbtr_sales{country="", currency="EUR",department="Import Zellulose/Holz",id="BP4218",name="Rayonier Advanced Materials",type="dbtr"} 60911.28
application_dbtr_sales{country="US", currency="EUR",department="Import Zellulose/Holz",id="BP4218",name="Rayonier Advanced Materials",type="dbtr"} 279028.91
```
Rayonier Advanced Materials
Debitor 74218
293.535,19 EUR
Metric saldo: 318866.69
# Jetzt berechnen wir neu...
https://alexander-logistics.office-workflow.de/api/metrics/dbtr/rebuild
application_dbtr_balance{country="", currency="EUR",department="Import Zellulose/Holz",id="BP4218",name="Rayonier Advanced Materials",type="dbtr"} 60911.28
application_dbtr_balance{country="US",currency="EUR",department="Import Zellulose/Holz",id="BP4218",name="Rayonier Advanced Materials",type="dbtr"} 364457.85
application_dbtr_sales{country="", currency="EUR",department="Import Zellulose/Holz",id="BP4218",name="Rayonier Advanced Materials",type="dbtr"} 60911.28
application_dbtr_sales{country="US", currency="EUR",department="Import Zellulose/Holz",id="BP4218",name="Rayonier Advanced Materials",type="dbtr"} 364457.85

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 106 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

View file

@ -1,94 +0,0 @@
# Zoho Web API
AGL Dubai nutzt Zoho als Platform zusammen mit einer lokalen Steuerkanzlei
https://books.zoho.com/
Testaccount - siehe [SECRETS.md](SECRETS.md)
# API Dokumentation
- API Docu: https://www.zoho.com/books/api/v3/introduction/
- Authentication: https://www.zoho.com/books/api/v3/oauth/
# Testumgebung
https://books.zoho.eu/app/20105697367
https://accounts.zoho.eu/home#
Base API URI= https://accounts.zoho.eu/
## 1. Client Einrichten
https://api-console.zoho.eu/
## 2. Generating Grant Token
https://accounts.zoho.com/oauth/v2/auth?scope=ZohoBooks.invoices.CREATE,ZohoBooks.invoices.READ,ZohoBooks.invoices.UPDATE,ZohoBooks.invoices.DELETE&client_id=1000.NLTM2KUEHI696MSLGEIANATVGGX7IN&state=testing&response_type=code&redirect_uri=https://alexander-logistics-dwc.office-workflow.de/api/zoho/grant
1000.NLTM2KUEHI696MSLGEIANATVGGX7IN
ee9ba49f16e77c64abb89cea13542d2326d8d03ce8
## 3. Generate Access and Refresh Token
https://accounts.zoho.com/oauth/v2/token?code=1000.dd7exxxxxxxxxxxxxxxxxxxxxxxx9bb8.b6c0xxxxxxxxxxxxxxxxxxxxxxxxdca4&client_id=1000.NLTM2KUEHI696MSLGEIANATVGGX7IN&client_secret=ee9ba49f16e77c64abb89cea13542d2326d8d03ce8&redirect_uri=http://www.zoho.com/books&grant_type=authorization_code
# Self Client
Man kann bei zoho mit einem sogenannten 'Self Client' arbeiten. Dieser erlaubt es ohne Redirect auf die Zoho Webseite einen Code anzufordern:
## 1. Self Client einrichten
Auf die API COnsole von Zoho zugreifen:
https://api-console.zoho.eu/client/1000.GR5FTPZYB06HEWSFSSX4DJU3OBD4EJ
<img src="../images/zoho-001.png" width="800">
Es kann maximal ein Client eingerichtet werden
Unter Scope trägt man dann den gewünschten Scope ein. Z.B.:
ZohoBooks.invoices.CREATE,ZohoBooks.invoices.READ,ZohoBooks.invoices.UPDATE,ZohoBooks.invoices.DELETE
und eine Description
<img src="../images/zoho-002.png">
Den generierten Code nun in Anwendung übertragen und innerhalb (!!) der 'Time Duration' den Access und Refresh Token generieren!
Siehe Junit Test `TestUpdateTokens`
Find details also [here](https://www.zoho.com/writer/help/api/v1/oauth-step2.html#self-client)
## Example for JUnit Test
Der Junit Test `TestUpdateTokens` zeigt das Prinzip
```
client ID= 1000.GR5FTPZYB06HEWSFSSX4DJU3OBD4EJ
client secret= 3f3e74c5212bbc924a7ebf77f887c6296db1106c47
```
In der Web GUi einen neuen Code generieren:
Scope=ZohoBooks.invoices.CREATE,ZohoBooks.invoices.READ,ZohoBooks.invoices.UPDATE,ZohoBooks.invoices.DELETE
Danach den Code token kopieren:
1000.7fe6315e8848b92a2f281b885677d37a.428c02dc2309606c86271842f1f67de4
**Note:** Der Code muss für Test immer wieder neu erstellt werden, da er nur für einige Minuten gültig ist!
# Disable auto-generated invoice number
Um die Automatische Vergabe von Rechnungsnummern in Zoho zu deaktivieren kann wie folgt vorgegangen werden:
1. Unter 'Invoices' eine neue Rechnung anlegen#
2. Im Feld 'Invoice#' das Zahnrad anklicken:
<img src="disable-auto-generated-number-01.png" />
3. Und dort die Option "Enter invoice numbers manually" auswählen
<img src="disable-auto-generated-number-02.png" />

View file

@ -1,167 +0,0 @@
{
"code": 0,
"message": "The bill has been created.",
"bill": {
"bill_id": "6206847000000103003",
"vendor_id": "6206847000000100015",
"vendor_name": "Feldmuehle GmbH",
"source": "Api",
"contact_category": "",
"tax_treatment": "",
"unused_credits_payable_amount": 0.00,
"status": "paid",
"color_code": "",
"current_sub_status_id": "",
"current_sub_status": "paid",
"sub_statuses": [],
"bill_number": "28195",
"date": "2024-07-26",
"due_date": "2024-07-26",
"discount_setting": "flat",
"tds_calculation_type": "tds_item_level",
"payment_terms": 0,
"payment_terms_label": "Due on Receipt",
"payment_expected_date": "",
"reference_number": "",
"scanned_po_number": "",
"recurring_bill_id": "",
"due_by_days": 286,
"due_in_days": "",
"currency_id": "6206847000000000109",
"currency_code": "EUR",
"currency_symbol": "€",
"currency_name_formatted": "EUR- Euro",
"documents": [],
"subject_content": "",
"price_precision": 2,
"exchange_rate": 1.00,
"custom_fields": [],
"custom_field_hash": {},
"is_viewed_by_client": false,
"client_viewed_time": "",
"is_item_level_tax_calc": false,
"is_inclusive_tax": false,
"tax_rounding": "entity_level",
"is_uber_bill": false,
"is_tally_bill": false,
"track_discount_in_account": true,
"is_bill_reconciliation_violated": false,
"bill_order_type": "",
"line_items": [
{
"purchaseorder_id": "",
"purchaseorder_item_id": "",
"receive_id": "",
"line_item_id": "6206847000000103013",
"item_id": "",
"name": "AB-DEFGHI-1234-567",
"account_id": "6206847000000092271",
"account_name": "TEst",
"description": "",
"bcy_rate": 0.00,
"rate": 0.00,
"sales_rate": "",
"pricebook_id": "",
"header_id": "",
"header_name": "",
"tags": [],
"quantity": 1.00,
"discount": 0.00,
"discounts": [],
"discount_account_id": "",
"discount_account_name": "",
"markup_percent": 0.00,
"tax_id": "",
"tax_name": "",
"tax_type": "tax",
"tax_percentage": 0,
"line_item_taxes": [],
"item_total": 0.00,
"item_order": 1,
"unit": "",
"item_type": "",
"image_name": "",
"image_type": "",
"is_billable": false,
"customer_id": "",
"receipt_line_item_id": "",
"customer_name": "",
"project_id": "",
"project_name": "",
"invoice_id": "",
"invoice_number": "",
"item_custom_fields": [],
"purchase_request_items": [],
"item_matching_type": ""
}
],
"submitted_date": "",
"submitted_by": "",
"submitted_by_name": "",
"submitted_by_email": "",
"submitted_by_photo_url": "",
"submitter_id": "",
"approver_id": "",
"adjustment": 0.00,
"adjustment_description": "",
"discount_amount": 0.00,
"discount": 0.00,
"discount_applied_on_amount": 0.00,
"is_discount_before_tax": true,
"discount_account_id": "",
"discount_account_name": "",
"discount_type": "entity_level",
"sub_total": 0.00,
"sub_total_inclusive_of_tax": 0.00,
"tax_total": 0.00,
"discount_total": 0.00,
"discount_percent": 0.00,
"total": 0.00,
"payment_made": 0.00,
"vendor_credits_applied": 0.00,
"is_line_item_invoiced": false,
"purchaseorders": [],
"taxes": [],
"computation_type": "basic",
"tax_override_preference": "no_override",
"tds_override_preference": "no_override",
"balance": 0.00,
"unprocessed_payment_amount": 0.00,
"billing_address_id": "6206847000000100017",
"billing_address": {
"address": "",
"street2": "",
"city": "",
"state": "",
"zip": "",
"country": "",
"fax": "",
"phone": "",
"attention": ""
},
"payments": [],
"vendor_credits": [],
"created_time": "2025-05-08T21:36:04+0100",
"created_by_id": "6206847000000092001",
"last_modified_id": "6206847000000092001",
"last_modified_time": "2025-05-08T21:36:04+0100",
"reference_id": "",
"notes": "",
"terms": "",
"attachment_name": "",
"template_id": "6206847000000031017",
"template_name": "Standard Template",
"page_width": "8.27in",
"page_height": "11.69in",
"orientation": "portrait",
"template_type": "standard",
"is_approval_required": false,
"allocated_landed_costs": [],
"unallocated_landed_costs": [],
"entity_type": "bill",
"total_retention_amount": 0.00,
"retention_items": [],
"can_send_in_mail": false,
"approvers_list": []
}
}

View file

@ -1,177 +0,0 @@
{
"code": 0,
"message": "The contact has been added.",
"contact": {
"contact_id": "777249000000077029",
"contact_name": "HQ Recyclers Network e.K.",
"company_name": "HQ Recyclers Network e.K.",
"contact_number": "CUS-00008",
"contact_tax_information": "",
"first_name": "",
"last_name": "",
"designation": "",
"department": "",
"website": "",
"is_bcy_only_contact": true,
"is_credit_limit_migration_completed": true,
"language_code": "",
"language_code_formatted": "",
"contact_salutation": "",
"email": "",
"phone": "",
"mobile": "",
"invited_by": "",
"portal_status": "disabled",
"is_client_review_asked": false,
"has_transaction": false,
"contact_type": "customer",
"customer_sub_type": "business",
"owner_id": "",
"owner_name": "",
"source": "api",
"documents": [],
"twitter": "",
"facebook": "",
"is_crm_customer": false,
"is_linked_with_zohocrm": false,
"primary_contact_id": "",
"zcrm_account_id": "",
"zcrm_contact_id": "",
"crm_owner_id": "",
"payment_terms": 0,
"payment_terms_label": "Due on Receipt",
"payment_terms_id": "",
"credit_limit_exceeded_amount": 0.00,
"currency_id": "777249000000000071",
"currency_code": "EUR",
"currency_symbol": "€",
"price_precision": 2,
"exchange_rate": "",
"can_show_customer_ob": true,
"can_show_vendor_ob": true,
"opening_balance_amount": 0.00,
"opening_balance_amount_bcy": "",
"outstanding_ob_receivable_amount": 0.00,
"outstanding_ob_payable_amount": 0.00,
"outstanding_receivable_amount": 0.00,
"outstanding_receivable_amount_bcy": 0.00,
"outstanding_payable_amount": 0.00,
"outstanding_payable_amount_bcy": 0.00,
"unused_credits_receivable_amount": 0.00,
"unused_credits_receivable_amount_bcy": 0.00,
"unused_credits_payable_amount": 0.00,
"unused_credits_payable_amount_bcy": 0.00,
"unused_retainer_payments": 0.00,
"status": "active",
"payment_reminder_enabled": true,
"is_sms_enabled": true,
"is_consent_agreed": false,
"consent_date": "",
"is_client_review_settings_enabled": false,
"custom_fields": [],
"custom_field_hash": {},
"tax_reg_label": "",
"contact_category": "",
"sales_channel": "direct_sales",
"ach_supported": false,
"portal_receipt_count": 0,
"opening_balances": [],
"entity_address_id": "777249000000077035",
"billing_address": {
"address_id": "777249000000077031",
"attention": "",
"address": "",
"street2": "",
"city": "",
"state_code": "",
"state": "",
"zip": "",
"country": "",
"county": "",
"country_code": "",
"phone": "",
"fax": ""
},
"shipping_address": {
"address_id": "777249000000077033",
"attention": "",
"address": "",
"street2": "",
"city": "",
"state_code": "",
"state": "",
"zip": "",
"country": "",
"county": "",
"country_code": "",
"phone": "",
"fax": "",
"latitude": "",
"longitude": ""
},
"contact_persons": [],
"addresses": [],
"pricebook_id": "",
"pricebook_name": "",
"default_templates": {
"statement_template_id": "",
"statement_template_name": "",
"invoice_template_id": "",
"invoice_template_name": "",
"bill_template_id": "",
"bill_template_name": "",
"estimate_template_id": "",
"estimate_template_name": "",
"creditnote_template_id": "",
"creditnote_template_name": "",
"paymentthankyou_template_id": "",
"paymentthankyou_template_name": "",
"invoice_email_template_id": "",
"invoice_email_template_name": "",
"estimate_email_template_id": "",
"estimate_email_template_name": "",
"creditnote_email_template_id": "",
"creditnote_email_template_name": "",
"paymentthankyou_email_template_id": "",
"paymentthankyou_email_template_name": "",
"payment_remittance_email_template_id": "",
"payment_remittance_email_template_name": ""
},
"associated_with_square": false,
"cards": [],
"checks": [],
"bank_accounts": [],
"vpa_list": [],
"notes": "",
"created_time": "2025-04-30T11:14:42+0200",
"created_date": "2025-04-30",
"created_by_name": "Ralph Soika",
"last_modified_time": "2025-04-30T11:14:42+0200",
"tags": [],
"zohopeople_client_id": "",
"customer_currency_summaries": [
{
"currency_id": "777249000000000071",
"currency_code": "EUR",
"currency_symbol": "€",
"price_precision": 2,
"is_base_currency": true,
"currency_name_formatted": "EUR- Euro",
"outstanding_receivable_amount": 0.00,
"unused_credits_receivable_amount": 0.00
}
],
"is_valid_trn": false,
"trn_last_validated_time": "",
"trn_last_validated_time_formatted": "",
"approvers_list": [],
"submitted_date": "",
"submitted_by": "",
"submitted_by_name": "",
"submitted_by_email": "",
"submitted_by_photo_url": "",
"submitter_id": "",
"approver_id": "",
"integration_references": []
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 105 KiB

View file

@ -1,273 +0,0 @@
{
"code": 0,
"message": "The invoice has been created.",
"invoice": {
"invoice_id": "777249000000082026",
"invoice_number": "INV-000018",
"date": "2024-04-03",
"due_date": "2024-05-03",
"offline_created_date_with_time": "",
"customer_id": "777249000000075016",
"contact_number": "CUS-00005",
"customer_name": "Action Agenciamento de Cargas LTDA",
"customer_custom_fields": [],
"customer_custom_field_hash": {},
"email": "",
"currency_id": "777249000000000071",
"invoice_source": "Api",
"currency_code": "EUR",
"currency_symbol": "€",
"currency_name_formatted": "EUR- Euro",
"status": "draft",
"unprocessed_payment_amount": 0.00,
"custom_fields": [],
"custom_field_hash": {},
"recurring_invoice_id": "",
"is_last_child_invoice": false,
"payment_mode": "",
"bank_account_id": "",
"payment_terms": 30,
"payment_terms_label": "Net 30",
"early_payment_discount_percentage": 0.00,
"early_payment_discount_due_days": "",
"early_payment_discount_amount": 0.00,
"payment_reminder_enabled": true,
"payment_made": 0.00,
"zcrm_potential_id": "",
"zcrm_potential_name": "",
"reference_number": "",
"preceding_invoice_id": "",
"is_early_payment_discount_applicable": false,
"lock_details": {},
"is_progress_invoice": false,
"can_show_kit_return": false,
"is_kit_partial_return": false,
"line_items": [
{
"line_item_id": "777249000000082036",
"item_id": "",
"item_order": 1,
"name": "R IM-GCA-2403-110",
"internal_name": "",
"description": "",
"discount_account_id": "",
"discount_account_name": "",
"unit": "",
"quantity": 1.00,
"discount_amount": 0.00,
"discount": 0.00,
"discounts": [],
"bcy_rate": 1995.00,
"rate": 1995.00,
"account_id": "777249000000000376",
"account_name": "Sales",
"header_id": "",
"header_name": "",
"pricebook_id": "",
"tax_id": "",
"tax_name": "",
"tax_type": "tax",
"tax_percentage": 0,
"item_total": 1995.00,
"item_custom_fields": [],
"pricing_scheme": "unit",
"tags": [],
"documents": [],
"line_item_taxes": [],
"bill_id": "",
"bill_item_id": "",
"project_id": "",
"time_entry_ids": [],
"expense_id": "",
"item_type": "",
"expense_receipt_name": "",
"sales_rate": "",
"purchase_rate": "",
"salesorder_item_id": "",
"cost_amount": 0,
"markup_percent": 0,
"mapped_items": []
}
],
"total_retention_amount": 0.00,
"retention_items": [],
"retention_override_preference": "no_override",
"exchange_rate": 1.00,
"is_autobill_enabled": false,
"inprocess_transaction_present": false,
"allow_partial_payments": false,
"price_precision": 2,
"sub_total": 1995.00,
"tax_total": 0.00,
"discount_total": 0.00,
"discount_percent": 0.00,
"discount": 0.00,
"discount_applied_on_amount": 0.00,
"discount_type": "item_level",
"discount_account_id": "",
"discount_account_name": "",
"is_discount_before_tax": true,
"adjustment": 0.00,
"adjustment_description": "",
"shipping_charge_tax_id": "",
"shipping_charge_tax_name": "",
"shipping_charge_tax_type": "",
"shipping_charge_tax_percentage": "",
"shipping_charge_tax_exemption_id": "",
"shipping_charge_tax_exemption_code": "",
"shipping_charge_tax": "",
"bcy_shipping_charge_tax": "",
"shipping_charge_exclusive_of_tax": 0.000,
"shipping_charge_inclusive_of_tax": 0.000,
"shipping_charge_tax_formatted": "",
"shipping_charge_exclusive_of_tax_formatted": "€0,00",
"shipping_charge_inclusive_of_tax_formatted": "€0,00",
"shipping_charge_account_id": "",
"shipping_charge_account_name": "",
"shipping_charge": 0.00,
"bcy_shipping_charge": 0.00,
"bcy_adjustment": 0.00,
"bcy_sub_total": 1995.00,
"bcy_discount_total": 0.00,
"bcy_tax_total": 0.00,
"bcy_total": 1995.000,
"total": 1995.00,
"balance": 1995.00,
"write_off_amount": 0.00,
"roundoff_value": 0.00,
"transaction_rounding_type": "no_rounding",
"is_inclusive_tax": false,
"sub_total_inclusive_of_tax": 0.00,
"contact_category": "",
"tax_rounding": "entity_level",
"taxes": [],
"tds_calculation_type": "tds_item_level",
"can_send_invoice_sms": true,
"payment_expected_date": "",
"payment_discount": 0.00,
"stop_reminder_until_payment_expected_date": false,
"last_payment_date": "",
"ach_supported": false,
"ach_payment_initiated": false,
"payment_options": {
"payment_gateways": []
},
"reader_offline_payment_initiated": false,
"contact_persons": [],
"contact_persons_associated": [],
"bank_account_details": {
"bank_account_id": "777249000000000376",
"bank_account_name": "Sales",
"bank_account_number": "",
"is_active": false,
"iban_number": "",
"swift_code": ""
},
"attachment_name": "",
"documents": [],
"computation_type": "basic",
"deliverychallans": [],
"merchant_id": "",
"merchant_name": "",
"ecomm_operator_id": "",
"ecomm_operator_name": "",
"salesorder_id": "",
"salesorder_number": "",
"salesorders": [],
"shipping_bills": [],
"contact_persons_details": [],
"contact": {
"customer_balance": 0.00,
"credit_limit": 0.00,
"unused_customer_credits": 0.00,
"is_credit_limit_migration_completed": true
},
"salesperson_id": "",
"salesperson_name": "",
"is_emailed": false,
"reminders_sent": 0,
"last_reminder_sent_date": "",
"next_reminder_date_formatted": "",
"is_viewed_by_client": false,
"client_viewed_time": "",
"submitter_id": "",
"approver_id": "",
"submitted_date": "",
"submitted_by": "",
"submitted_by_name": "",
"submitted_by_email": "",
"submitted_by_photo_url": "",
"template_id": "777249000000000103",
"template_name": "Standard Template",
"template_type": "standard",
"notes": "Thanks for your business.",
"terms": "",
"billing_address": {
"street": "",
"address": "",
"street2": "",
"city": "",
"state": "",
"zip": "",
"country": "",
"fax": "",
"phone": "",
"attention": ""
},
"shipping_address": {
"street": "",
"address": "",
"street2": "",
"city": "",
"state": "",
"zip": "",
"country": "",
"fax": "",
"phone": "",
"attention": ""
},
"invoice_url": "https://zohosecurepay.eu/books/imixs/secure?CInvoiceID=2-64277fbd3cd8bc868d9e57c3085f4f428b1f66a1d5e3f3a32fc159e6879f623863183b0ac4651a08fdcce7621ddf18bf61770563d9fd2832f987dda624d4f11579820a40c3f55870 ",
"subject_content": "",
"can_send_in_mail": false,
"created_time": "2025-05-02T10:23:49+0200",
"last_modified_time": "2025-05-02T10:23:49+0200",
"created_date": "2025-05-02",
"created_by_id": "777249000000055227",
"created_by_name": "Ralph Soika",
"last_modified_by_id": "777249000000055227",
"page_width": "8.27in",
"page_height": "11.69in",
"orientation": "portrait",
"is_backorder": "",
"sales_channel": "direct_sales",
"color_code": "",
"current_sub_status_id": "",
"current_sub_status": "draft",
"sub_statuses": [],
"estimate_id": "",
"is_client_review_settings_enabled": false,
"unused_retainer_payments": 0.00,
"credits_applied": 0.00,
"tax_amount_withheld": 0.00,
"schedule_time": "",
"customer_default_billing_address": {
"zip": "",
"country": "",
"address": "",
"city": "",
"phone": "",
"street2": "",
"state": "",
"fax": "",
"state_code": ""
},
"includes_package_tracking_info": false,
"approvers_list": [],
"qr_code": {
"qr_source": "invoice_url",
"is_qr_enabled": false,
"qr_value": "",
"qr_description": "Scan the QR code to view the configured information."
}
}
}

View file

@ -1,5 +1,6 @@
version: "3.6" version: '3.6'
services: services:
############################################### ###############################################
# Postgres DB # Postgres DB
############################################### ###############################################
@ -8,9 +9,9 @@ services:
environment: environment:
POSTGRES_PASSWORD: adminadmin POSTGRES_PASSWORD: adminadmin
POSTGRES_DB: office-alexander-logistics POSTGRES_DB: office-alexander-logistics
volumes: volumes:
- dbdata:/var/lib/postgresql/data - dbdata:/var/lib/postgresql/data
############################################### ###############################################
# Office # Office
############################################### ###############################################
@ -23,9 +24,9 @@ services:
POSTGRES_USER: "postgres" POSTGRES_USER: "postgres"
POSTGRES_PASSWORD: "adminadmin" POSTGRES_PASSWORD: "adminadmin"
POSTGRES_CONNECTION: "jdbc:postgresql://db/office-alexander-logistics" POSTGRES_CONNECTION: "jdbc:postgresql://db/office-alexander-logistics"
TZ: "CET" TZ: "CET"
LANG: "en_US.UTF-8" LANG: "en_US.UTF-8"
MAILGATEWAY: "mailpit" MAILGATEWAY: "mailgateway"
ASYNCEVENT_PROCESSOR_ENABLED: "true" ASYNCEVENT_PROCESSOR_ENABLED: "true"
ASYNCEVENT_PROCESSOR_INITIALDELAY: "10000" ASYNCEVENT_PROCESSOR_INITIALDELAY: "10000"
@ -33,23 +34,11 @@ services:
OCR_SERVICE_ENDPOINT: "http://tika:9998/tika" OCR_SERVICE_ENDPOINT: "http://tika:9998/tika"
OCR_SERVICE_MODE: "MODEL" OCR_SERVICE_MODE: "MODEL"
#OCR_SERVICE_MAXFILESIZE: "1048576" #OCR_SERVICE_MAXFILESIZE: "1048576"
#OCR_PDF_MODE: "OCR_ONLY | TEXT_ONLY | TEXT_AND_OCR (default)" #OCR_PDF_MODE: "OCR_ONLY | TEXT_ONLY | TEXT_AND_OCR (default)"
OCR_PDF_MODE: "OCR_ONLY" OCR_PDF_MODE: "OCR_ONLY"
# Rest Service BusinessPartner API LLM_SERVICE_ENDPOINT_USER: "admin"
WORKFLOW_SERVICE_ENDPOINT: "http://app:8080/api" LLM_SERVICE_ENDPOINT_PASSWORD: "imixs4.null"
WORKFLOW_SERVICE_USER: "admin"
WORKFLOW_SERVICE_PASSWORD: "adminadmin"
# LLM Integration
LLM_CONFIG_FILE: /opt/jboss/imixs-llm.xml
# KSeF - Polen Test
KSEF_API_NIP: "9552521552"
KSEF_API_TOKEN: "20251113-EC-2751AC3000-5C5466924B-62|nip-9552521552|fc0c95d020dc45d4af491fb0aa755f3f3f674b33ecbf4250a88ea6e36fa8340b"
KSEF_API_ENDPOINT: "https://ksef-test.mf.gov.pl/api/v2"
METRICS_ENABLED: "false"
ports: ports:
- "8080:8080" - "8080:8080"
@ -57,40 +46,21 @@ services:
- "8787:8787" - "8787:8787"
volumes: volumes:
- ./docker/deployments:/opt/jboss/wildfly/standalone/deployments/ - ./docker/deployments:/opt/jboss/wildfly/standalone/deployments/
- ./docker/keys/imixs-llm.xml:/opt/jboss/imixs-llm.xml
- ./docker/transfer:/opt/jboss/wildfly/transfer/
############################################### ###############################################
# Tika OCR Service # Tika OCR Service
############################################### ###############################################
tika: tika:
image: apache/tika:3.2.0.0-full #image: apache/tika:latest
#image: apache/tika:1.24.1-full
image: apache/tika:2.4.1-full
environment: environment:
TZ: "Europe/Berlin" TZ: "Europe/Berlin"
ports: ports:
- "9998:9998" - "9998:9998"
##################
# Exporter Service
##################
# imixsexporter-app:
# image: imixs/imixs-archive-exporter
# environment:
# # EXAMPLE SETUP
# WORKFLOW_SERVICE_ENDPOINT: "http://app:8080/api"
# WORKFLOW_SERVICE_USER: "admin"
# WORKFLOW_SERVICE_PASSWORD: "adminadmin"
# WORKFLOW_SERVICE_AUTHMETHOD: "form"
# METRICS_ENDPOINT: "http://localhost:9991/metrics"
# HEALTH_ENDPOINT: "http://localhost:9991/health"
# EXPORT_PATH: "/agl/dwc-test"
# EXPORT_FTP_HOST: "u248962.your-storagebox.de"
# EXPORT_FTP_PORT: "21"
# EXPORT_FTP_USER: "u248962-sub4"
# EXPORT_FTP_PASSWORD: "en4g3f1Jw0WlQ9Yb"
# ports:
# - "8081:8080"
# - "8788:8787"
############################################### ###############################################
# Imixs-Admin # Imixs-Admin
@ -103,29 +73,18 @@ services:
############################################### ###############################################
# Mailgateway # Mailgateway
############################################### ###############################################
mailpit: mailgateway:
image: axllent/mailpit:latest image: imixs/exim4
container_name: mailpit
environment: environment:
MP_SMTP_BIND_ADDR: "0.0.0.0:25" EXIM_SMARTHOST: "www149.your-server.de:25"
ports: EXIM_PASSWORD: "www149.your-server.de:webmaster@imixs.com:$MAILPASSWORD"
- "1025:25" # Host:1025 -> Container:25 (SMTP) EXIM_ALLOWED_SENDERS: "10.0.0.0/8:172.18.0.0/12:192.168.0.0/16"
- "8025:8025" # Web UI
restart: unless-stopped
# prometheus:
# image: prom/prometheus:latest
# ports:
# - "9090:9090"
# volumes:
# - ./docker/prometheus/prometheus.yml:/etc/prometheus/prometheus.yml
# - prometheusdata:/prometheus/
# grafana:
# image: grafana/grafana:latest
# ports:
# - "3000:3000"
volumes: volumes:
dbdata: dbdata:
prometheusdata:

View file

@ -1,4 +0,0 @@
# LLM Config
LLM_API_ENDPOINT=https://api.llama.cpp.imixs.com/
LLM_API_KEY=7fdb663fa87ea16731c1e0ece8ad3214e358423eabf2403188110c731ce07321

View file

@ -1,220 +0,0 @@
{
"annotations": {
"list": [
{
"builtIn": 1,
"datasource": {
"type": "grafana",
"uid": "-- Grafana --"
},
"enable": true,
"hide": true,
"iconColor": "rgba(0, 211, 255, 1)",
"name": "Annotations & Alerts",
"type": "dashboard"
}
]
},
"editable": true,
"fiscalYearStartMonth": 0,
"graphTooltip": 0,
"id": 1,
"links": [],
"panels": [
{
"datasource": {
"type": "prometheus",
"uid": "ee5zvwsdjb400f"
},
"description": "",
"fieldConfig": {
"defaults": {
"color": {
"fixedColor": "green",
"mode": "fixed"
},
"decimals": 0,
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green"
},
{
"color": "red",
"value": 80
}
]
},
"unit": "locale"
},
"overrides": []
},
"gridPos": {
"h": 4,
"w": 23,
"x": 0,
"y": 0
},
"id": 2,
"options": {
"colorMode": "value",
"graphMode": "none",
"justifyMode": "auto",
"orientation": "auto",
"percentChangeColorMode": "standard",
"reduceOptions": {
"calcs": [
"lastNotNull"
],
"fields": "",
"values": false
},
"showPercentChange": false,
"text": {
"titleSize": 16,
"valueSize": 30
},
"textMode": "value_and_name",
"wideLayout": true
},
"pluginVersion": "11.3.2",
"targets": [
{
"disableTextWrap": false,
"editorMode": "code",
"exemplar": false,
"expr": "sum by(department, currency) (application_dbtr_balance{department=~\".+\"})",
"fullMetaSearch": false,
"hide": false,
"includeNullMetadata": true,
"instant": false,
"interval": "",
"legendFormat": "{{department}} {{currency}}",
"range": true,
"refId": "A",
"useBackend": false
}
],
"title": "Debitoren - Saldo",
"type": "stat"
},
{
"datasource": {
"type": "prometheus",
"uid": "ee5zvwsdjb400f"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"custom": {
"axisBorderShow": false,
"axisCenteredZero": false,
"axisColorMode": "text",
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"barWidthFactor": 0.6,
"drawStyle": "line",
"fillOpacity": 0,
"gradientMode": "none",
"hideFrom": {
"legend": false,
"tooltip": false,
"viz": false
},
"insertNulls": false,
"lineInterpolation": "linear",
"lineWidth": 2,
"pointSize": 5,
"scaleDistribution": {
"type": "linear"
},
"showPoints": "auto",
"spanNulls": false,
"stacking": {
"group": "A",
"mode": "none"
},
"thresholdsStyle": {
"mode": "off"
}
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green"
},
{
"color": "red",
"value": 80
}
]
}
},
"overrides": []
},
"gridPos": {
"h": 9,
"w": 24,
"x": 0,
"y": 4
},
"id": 1,
"options": {
"legend": {
"calcs": [],
"displayMode": "list",
"placement": "bottom",
"showLegend": true
},
"tooltip": {
"mode": "single",
"sort": "none"
}
},
"pluginVersion": "11.3.2",
"targets": [
{
"datasource": {
"type": "prometheus",
"uid": "ee5zvwsdjb400f"
},
"disableTextWrap": false,
"editorMode": "code",
"exemplar": false,
"expr": "sum by(department) (application_dbtr_balance{department=~\".+\"})",
"fullMetaSearch": false,
"includeNullMetadata": true,
"legendFormat": "__auto",
"range": true,
"refId": "A",
"useBackend": false
}
],
"title": "Kreditor",
"type": "timeseries"
}
],
"preload": false,
"schemaVersion": 40,
"tags": [],
"templating": {
"list": []
},
"time": {
"from": "now-6h",
"to": "now"
},
"timepicker": {},
"timezone": "browser",
"title": "AGL",
"uid": "ce5zwc5vzt5hce",
"version": 14,
"weekStart": ""
}

View file

@ -1,658 +0,0 @@
{
"annotations": {
"list": [
{
"builtIn": 1,
"datasource": {
"type": "grafana",
"uid": "-- Grafana --"
},
"enable": true,
"hide": true,
"iconColor": "rgba(0, 211, 255, 1)",
"name": "Annotations & Alerts",
"type": "dashboard"
}
]
},
"editable": true,
"fiscalYearStartMonth": 0,
"graphTooltip": 0,
"id": 5,
"links": [],
"panels": [
{
"datasource": {
"type": "prometheus",
"uid": "P1809F7CD0C75ACF3"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "fixed"
},
"custom": {
"hideFrom": {
"legend": false,
"tooltip": false,
"viz": false
}
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
},
{
"color": "red",
"value": 80
}
]
}
},
"overrides": []
},
"gridPos": {
"h": 8,
"w": 12,
"x": 0,
"y": 0
},
"id": 8,
"options": {
"basemap": {
"config": {
"server": "streets",
"showLabels": true,
"theme": "auto"
},
"name": "Layer 0",
"opacity": 1,
"tooltip": false,
"type": "esri-xyz"
},
"controls": {
"mouseWheelZoom": true,
"showAttribution": true,
"showDebug": false,
"showMeasure": false,
"showScale": false,
"showZoom": true
},
"layers": [
{
"config": {
"showLegend": true,
"style": {
"color": {
"fixed": "dark-green"
},
"opacity": 0.4,
"rotation": {
"fixed": 0,
"max": 360,
"min": -360,
"mode": "mod"
},
"size": {
"field": "Value",
"fixed": 5,
"max": 50,
"min": 10
},
"symbol": {
"fixed": "img/icons/marker/circle.svg",
"mode": "fixed"
},
"symbolAlign": {
"horizontal": "center",
"vertical": "center"
},
"textConfig": {
"fontSize": 12,
"offsetX": 0,
"offsetY": 0,
"textAlign": "center",
"textBaseline": "middle"
}
}
},
"filterData": {
"id": "byRefId",
"options": "A"
},
"location": {
"mode": "lookup"
},
"name": "Layer 1",
"tooltip": true,
"type": "markers"
}
],
"tooltip": {
"mode": "details"
},
"view": {
"allLayers": true,
"id": "europe",
"lat": 46,
"lon": 14,
"zoom": 4
}
},
"pluginVersion": "11.4.0",
"targets": [
{
"datasource": {
"type": "prometheus",
"uid": "P1809F7CD0C75ACF3"
},
"editorMode": "code",
"expr": "sum(application_dbtr_balance) by (country)",
"format": "table",
"instant": false,
"legendFormat": "__auto",
"range": true,
"refId": "A"
}
],
"title": "",
"transparent": true,
"type": "geomap"
},
{
"datasource": {
"type": "prometheus",
"uid": "P1809F7CD0C75ACF3"
},
"fieldConfig": {
"defaults": {
"color": {
"fixedColor": "yellow",
"mode": "palette-classic"
},
"custom": {
"hideFrom": {
"legend": false,
"tooltip": false,
"viz": false
}
},
"mappings": [],
"unit": "locale"
},
"overrides": []
},
"gridPos": {
"h": 8,
"w": 5,
"x": 12,
"y": 0
},
"id": 9,
"options": {
"displayLabels": [],
"legend": {
"displayMode": "list",
"placement": "bottom",
"showLegend": true
},
"pieType": "pie",
"reduceOptions": {
"calcs": [
"lastNotNull"
],
"fields": "",
"values": false
},
"tooltip": {
"mode": "single",
"sort": "none"
}
},
"pluginVersion": "11.4.0",
"targets": [
{
"datasource": {
"type": "prometheus",
"uid": "P1809F7CD0C75ACF3"
},
"editorMode": "code",
"expr": "sum(application_dbtr_balance{currency=\"EUR\"}) by (department)",
"instant": false,
"legendFormat": "__auto",
"range": true,
"refId": "A"
}
],
"title": "EUR Abteilung",
"type": "piechart"
},
{
"datasource": {
"type": "prometheus",
"uid": "P1809F7CD0C75ACF3"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"custom": {
"hideFrom": {
"legend": false,
"tooltip": false,
"viz": false
}
},
"mappings": []
},
"overrides": []
},
"gridPos": {
"h": 8,
"w": 5,
"x": 17,
"y": 0
},
"id": 2,
"options": {
"legend": {
"displayMode": "list",
"placement": "bottom",
"showLegend": true
},
"pieType": "pie",
"reduceOptions": {
"calcs": [
"lastNotNull"
],
"fields": "",
"values": false
},
"tooltip": {
"mode": "single",
"sort": "none"
}
},
"pluginVersion": "11.4.0",
"targets": [
{
"datasource": {
"type": "prometheus",
"uid": "P1809F7CD0C75ACF3"
},
"editorMode": "code",
"expr": "sum(application_dbtr_balance) by (currency)",
"instant": false,
"legendFormat": "__auto",
"range": true,
"refId": "A"
}
],
"title": "Verteilung nach Währung",
"type": "piechart"
},
{
"datasource": {
"type": "prometheus",
"uid": "P1809F7CD0C75ACF3"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"custom": {
"axisBorderShow": true,
"axisCenteredZero": false,
"axisColorMode": "text",
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"barWidthFactor": 0.6,
"drawStyle": "line",
"fillOpacity": 0,
"gradientMode": "opacity",
"hideFrom": {
"legend": false,
"tooltip": false,
"viz": false
},
"insertNulls": false,
"lineInterpolation": "linear",
"lineWidth": 1,
"pointSize": 5,
"scaleDistribution": {
"type": "linear"
},
"showPoints": "auto",
"spanNulls": false,
"stacking": {
"group": "A",
"mode": "none"
},
"thresholdsStyle": {
"mode": "off"
}
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
},
{
"color": "red",
"value": 80
}
]
},
"unit": "locale"
},
"overrides": []
},
"gridPos": {
"h": 8,
"w": 12,
"x": 0,
"y": 8
},
"id": 1,
"options": {
"legend": {
"calcs": [],
"displayMode": "list",
"placement": "right",
"showLegend": true
},
"tooltip": {
"mode": "single",
"sort": "none"
}
},
"pluginVersion": "11.4.0",
"targets": [
{
"datasource": {
"type": "prometheus",
"uid": "P1809F7CD0C75ACF3"
},
"editorMode": "builder",
"exemplar": false,
"expr": "sum(application_dbtr_balance) by (department)",
"format": "time_series",
"hide": false,
"instant": false,
"interval": "",
"legendFormat": "__auto",
"range": true,
"refId": "A"
}
],
"title": "Gesamtsaldo pro Abteilung",
"type": "timeseries"
},
{
"datasource": {
"type": "prometheus",
"uid": "P1809F7CD0C75ACF3"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "thresholds"
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
},
{
"color": "red",
"value": 80
}
]
}
},
"overrides": []
},
"gridPos": {
"h": 8,
"w": 5,
"x": 17,
"y": 8
},
"id": 4,
"options": {
"colorMode": "value",
"graphMode": "area",
"justifyMode": "auto",
"orientation": "auto",
"percentChangeColorMode": "standard",
"reduceOptions": {
"calcs": [
"lastNotNull"
],
"fields": "",
"values": false
},
"showPercentChange": false,
"textMode": "auto",
"wideLayout": true
},
"pluginVersion": "11.4.0",
"targets": [
{
"datasource": {
"type": "prometheus",
"uid": "P1809F7CD0C75ACF3"
},
"editorMode": "code",
"expr": "count(application_dbtr_balance)",
"instant": false,
"legendFormat": "__auto",
"range": true,
"refId": "A"
}
],
"title": "Anzahl der Debitoren",
"type": "stat"
},
{
"datasource": {
"type": "prometheus",
"uid": "P1809F7CD0C75ACF3"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "thresholds"
},
"custom": {
"align": "auto",
"cellOptions": {
"type": "auto"
},
"inspect": false
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
},
{
"color": "red",
"value": 80
}
]
}
},
"overrides": [
{
"matcher": {
"id": "byName",
"options": "Value (sum)"
},
"properties": [
{
"id": "unit",
"value": "locale"
}
]
},
{
"matcher": {
"id": "byName",
"options": "currency"
},
"properties": [
{
"id": "custom.width",
"value": 87
}
]
},
{
"matcher": {
"id": "byName",
"options": "department"
},
"properties": [
{
"id": "custom.width",
"value": 188
}
]
},
{
"matcher": {
"id": "byName",
"options": "id"
},
"properties": [
{
"id": "custom.width",
"value": 93
}
]
}
]
},
"gridPos": {
"h": 8,
"w": 12,
"x": 0,
"y": 16
},
"id": 6,
"options": {
"cellHeight": "sm",
"footer": {
"countRows": false,
"fields": "",
"reducer": [
"sum"
],
"show": false
},
"showHeader": true,
"sortBy": []
},
"pluginVersion": "11.4.0",
"targets": [
{
"datasource": {
"type": "prometheus",
"uid": "P1809F7CD0C75ACF3"
},
"editorMode": "code",
"exemplar": false,
"expr": "topk(5, application_dbtr_balance) ",
"format": "table",
"hide": false,
"instant": false,
"legendFormat": "__auto",
"range": true,
"refId": "A"
}
],
"title": "Panel Title",
"transformations": [
{
"id": "groupBy",
"options": {
"fields": {
"Value": {
"aggregations": [
"sum"
],
"operation": "aggregate"
},
"country": {
"aggregations": [],
"operation": "groupby"
},
"currency": {
"aggregations": [],
"operation": "groupby"
},
"department": {
"aggregations": [],
"operation": "groupby"
},
"id": {
"aggregations": [],
"operation": "groupby"
},
"name": {
"aggregations": [],
"operation": "groupby"
}
}
}
},
{
"id": "sortBy",
"options": {
"fields": {},
"sort": [
{
"desc": true,
"field": "Value (sum)"
}
]
}
}
],
"type": "table"
}
],
"preload": false,
"schemaVersion": 40,
"tags": [],
"templating": {
"list": []
},
"time": {
"from": "now-6h",
"to": "now"
},
"timepicker": {},
"timezone": "browser",
"title": "Übersicht Debitoren",
"uid": "deb9z4knfuxhcc",
"version": 10,
"weekStart": ""
}

View file

@ -1,896 +0,0 @@
{
"__inputs": [
{
"name": "DS_PROMETHEUS",
"label": "prometheus",
"description": "",
"type": "datasource",
"pluginId": "prometheus",
"pluginName": "Prometheus"
}
],
"__elements": {},
"__requires": [
{
"type": "panel",
"id": "bargauge",
"name": "Bar gauge",
"version": ""
},
{
"type": "panel",
"id": "geomap",
"name": "Geomap",
"version": ""
},
{
"type": "grafana",
"id": "grafana",
"name": "Grafana",
"version": "11.4.0"
},
{
"type": "panel",
"id": "piechart",
"name": "Pie chart",
"version": ""
},
{
"type": "datasource",
"id": "prometheus",
"name": "Prometheus",
"version": "1.0.0"
},
{
"type": "panel",
"id": "stat",
"name": "Stat",
"version": ""
},
{
"type": "panel",
"id": "table",
"name": "Table",
"version": ""
},
{
"type": "panel",
"id": "timeseries",
"name": "Time series",
"version": ""
}
],
"annotations": {
"list": [
{
"builtIn": 1,
"datasource": {
"type": "grafana",
"uid": "-- Grafana --"
},
"enable": true,
"hide": true,
"iconColor": "rgba(0, 211, 255, 1)",
"name": "Annotations & Alerts",
"type": "dashboard"
}
]
},
"editable": true,
"fiscalYearStartMonth": 0,
"graphTooltip": 0,
"id": null,
"links": [],
"panels": [
{
"collapsed": false,
"gridPos": {
"h": 1,
"w": 24,
"x": 0,
"y": 0
},
"id": 14,
"panels": [],
"title": "Salden Übersicht",
"type": "row"
},
{
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "fixed"
},
"custom": {
"hideFrom": {
"legend": false,
"tooltip": false,
"viz": false
}
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
},
{
"color": "red",
"value": 80
}
]
}
},
"overrides": []
},
"gridPos": {
"h": 8,
"w": 15,
"x": 0,
"y": 1
},
"id": 8,
"options": {
"basemap": {
"config": {
"server": "streets",
"showLabels": true,
"theme": "auto"
},
"name": "Layer 0",
"opacity": 1,
"tooltip": false,
"type": "esri-xyz"
},
"controls": {
"mouseWheelZoom": true,
"showAttribution": true,
"showDebug": false,
"showMeasure": false,
"showScale": false,
"showZoom": true
},
"layers": [
{
"config": {
"showLegend": true,
"style": {
"color": {
"fixed": "dark-green"
},
"opacity": 0.4,
"rotation": {
"fixed": 0,
"max": 360,
"min": -360,
"mode": "mod"
},
"size": {
"field": "Value",
"fixed": 5,
"max": 50,
"min": 10
},
"symbol": {
"fixed": "img/icons/marker/circle.svg",
"mode": "fixed"
},
"symbolAlign": {
"horizontal": "center",
"vertical": "center"
},
"textConfig": {
"fontSize": 12,
"offsetX": 0,
"offsetY": 0,
"textAlign": "center",
"textBaseline": "middle"
}
}
},
"filterData": {
"id": "byRefId",
"options": "A"
},
"location": {
"mode": "lookup"
},
"name": "Layer 1",
"tooltip": true,
"type": "markers"
}
],
"tooltip": {
"mode": "details"
},
"view": {
"allLayers": true,
"id": "europe",
"lat": 46,
"lon": 14,
"zoom": 4
}
},
"pluginVersion": "11.4.0",
"targets": [
{
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"editorMode": "code",
"expr": "sum(application_dbtr_balance) by (country)",
"format": "table",
"instant": false,
"legendFormat": "__auto",
"range": true,
"refId": "A"
}
],
"transparent": true,
"type": "geomap"
},
{
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"fieldConfig": {
"defaults": {
"color": {
"fixedColor": "yellow",
"mode": "palette-classic"
},
"custom": {
"hideFrom": {
"legend": false,
"tooltip": false,
"viz": false
}
},
"mappings": [],
"unit": "locale"
},
"overrides": []
},
"gridPos": {
"h": 8,
"w": 5,
"x": 15,
"y": 1
},
"id": 9,
"options": {
"displayLabels": [],
"legend": {
"displayMode": "list",
"placement": "bottom",
"showLegend": true
},
"pieType": "pie",
"reduceOptions": {
"calcs": [
"lastNotNull"
],
"fields": "",
"values": false
},
"tooltip": {
"mode": "single",
"sort": "none"
}
},
"pluginVersion": "11.4.0",
"targets": [
{
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"editorMode": "code",
"expr": "sum(application_dbtr_balance{currency=~\"$currency\"}) by (department)",
"instant": false,
"legendFormat": "__auto",
"range": true,
"refId": "A"
}
],
"title": "$currency nach Abteilung",
"type": "piechart"
},
{
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"custom": {
"hideFrom": {
"legend": false,
"tooltip": false,
"viz": false
}
},
"mappings": []
},
"overrides": []
},
"gridPos": {
"h": 8,
"w": 4,
"x": 20,
"y": 1
},
"id": 2,
"options": {
"legend": {
"displayMode": "list",
"placement": "bottom",
"showLegend": true
},
"pieType": "pie",
"reduceOptions": {
"calcs": [
"lastNotNull"
],
"fields": "",
"values": false
},
"tooltip": {
"mode": "single",
"sort": "none"
}
},
"pluginVersion": "11.4.0",
"targets": [
{
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"editorMode": "code",
"expr": "sum(application_dbtr_balance) by (currency)",
"instant": false,
"legendFormat": "__auto",
"range": true,
"refId": "A"
}
],
"title": "Verteilung nach Währung",
"type": "piechart"
},
{
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic-by-name"
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
},
{
"color": "red",
"value": 80
}
]
},
"unit": "locale"
},
"overrides": []
},
"gridPos": {
"h": 6,
"w": 20,
"x": 0,
"y": 9
},
"id": 11,
"options": {
"displayMode": "basic",
"legend": {
"calcs": [],
"displayMode": "list",
"placement": "bottom",
"showLegend": false
},
"maxVizHeight": 300,
"minVizHeight": 16,
"minVizWidth": 8,
"namePlacement": "auto",
"orientation": "auto",
"reduceOptions": {
"calcs": [
"lastNotNull"
],
"fields": "",
"values": false
},
"showUnfilled": true,
"sizing": "auto",
"text": {
"titleSize": 10,
"valueSize": 10
},
"valueMode": "color"
},
"pluginVersion": "11.4.0",
"targets": [
{
"editorMode": "code",
"expr": "sum by (department) (application_cdtr_balance{currency=~\"$currency\"})",
"legendFormat": "__auto",
"range": true,
"refId": "A",
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
}
}
],
"title": "Saldo in $currency nach Abteilung",
"type": "bargauge"
},
{
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "thresholds"
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
},
{
"color": "red",
"value": 80
}
]
}
},
"overrides": []
},
"gridPos": {
"h": 6,
"w": 4,
"x": 20,
"y": 9
},
"id": 4,
"options": {
"colorMode": "value",
"graphMode": "area",
"justifyMode": "auto",
"orientation": "auto",
"percentChangeColorMode": "standard",
"reduceOptions": {
"calcs": [
"lastNotNull"
],
"fields": "",
"values": false
},
"showPercentChange": false,
"textMode": "auto",
"wideLayout": true
},
"pluginVersion": "11.4.0",
"targets": [
{
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"editorMode": "code",
"expr": "count(application_dbtr_balance)",
"instant": false,
"legendFormat": "__auto",
"range": true,
"refId": "A"
}
],
"title": "Anzahl der Debitoren",
"type": "stat"
},
{
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"custom": {
"axisBorderShow": true,
"axisCenteredZero": false,
"axisColorMode": "text",
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"barWidthFactor": 0.6,
"drawStyle": "line",
"fillOpacity": 30,
"gradientMode": "opacity",
"hideFrom": {
"legend": false,
"tooltip": false,
"viz": false
},
"insertNulls": false,
"lineInterpolation": "smooth",
"lineStyle": {
"fill": "solid"
},
"lineWidth": 3,
"pointSize": 9,
"scaleDistribution": {
"type": "linear"
},
"showPoints": "auto",
"spanNulls": true,
"stacking": {
"group": "A",
"mode": "none"
},
"thresholdsStyle": {
"mode": "off"
}
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
},
{
"color": "red",
"value": 80
}
]
},
"unit": "locale"
},
"overrides": []
},
"gridPos": {
"h": 8,
"w": 12,
"x": 0,
"y": 15
},
"id": 1,
"options": {
"legend": {
"calcs": [],
"displayMode": "list",
"placement": "right",
"showLegend": false
},
"tooltip": {
"mode": "single",
"sort": "none"
}
},
"pluginVersion": "11.4.0",
"targets": [
{
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"editorMode": "code",
"exemplar": false,
"expr": "sum(application_dbtr_balance{currency=~\"$currency\", department=~\"$department\"}) ",
"format": "time_series",
"hide": false,
"instant": false,
"interval": "",
"legendFormat": "__auto",
"range": true,
"refId": "A"
}
],
"title": "$department - Saldo in $currency",
"type": "timeseries"
},
{
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "thresholds"
},
"custom": {
"align": "auto",
"cellOptions": {
"type": "auto"
},
"inspect": false
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
},
{
"color": "red",
"value": 80
}
]
}
},
"overrides": [
{
"matcher": {
"id": "byName",
"options": "Value (sum)"
},
"properties": [
{
"id": "unit",
"value": "locale"
}
]
},
{
"matcher": {
"id": "byName",
"options": "currency"
},
"properties": [
{
"id": "custom.width",
"value": 81
}
]
},
{
"matcher": {
"id": "byName",
"options": "department"
},
"properties": [
{
"id": "custom.width",
"value": 188
}
]
},
{
"matcher": {
"id": "byName",
"options": "id"
},
"properties": [
{
"id": "custom.width",
"value": 93
}
]
},
{
"matcher": {
"id": "byName",
"options": "country"
},
"properties": [
{
"id": "custom.width",
"value": 81
}
]
},
{
"matcher": {
"id": "byName",
"options": "Kunde"
},
"properties": [
{
"id": "custom.width",
"value": 308
}
]
}
]
},
"gridPos": {
"h": 8,
"w": 12,
"x": 12,
"y": 15
},
"id": 6,
"options": {
"cellHeight": "sm",
"footer": {
"countRows": false,
"fields": "",
"reducer": [
"sum"
],
"show": false
},
"showHeader": true,
"sortBy": []
},
"pluginVersion": "11.4.0",
"targets": [
{
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"editorMode": "code",
"exemplar": false,
"expr": "topk(5,application_dbtr_balance{currency=~\"$currency\", department=~\"$department\"}) ",
"format": "table",
"hide": false,
"instant": false,
"legendFormat": "__auto",
"range": true,
"refId": "A"
}
],
"title": "Top 5",
"transformations": [
{
"id": "groupBy",
"options": {
"fields": {
"Value": {
"aggregations": [
"sum"
],
"operation": "aggregate"
},
"country": {
"aggregations": [],
"operation": "groupby"
},
"currency": {
"aggregations": [],
"operation": "groupby"
},
"department": {
"aggregations": []
},
"id": {
"aggregations": [],
"operation": "groupby"
},
"name": {
"aggregations": [],
"operation": "groupby"
}
}
}
},
{
"id": "sortBy",
"options": {
"fields": {},
"sort": [
{
"desc": true,
"field": "Value (sum)"
}
]
}
},
{
"id": "organize",
"options": {
"excludeByName": {},
"includeByName": {},
"indexByName": {
"Value (sum)": 3,
"country": 2,
"currency": 4,
"id": 1,
"name": 0
},
"renameByName": {
"Value (sum)": "Saldo Aktuell",
"country": "Land",
"currency": " ",
"id": "Nummer",
"name": "Kunde"
}
}
}
],
"type": "table"
}
],
"schemaVersion": 40,
"tags": [],
"templating": {
"list": [
{
"current": {},
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"definition": "label_values(currency)",
"label": "Währung",
"name": "currency",
"options": [],
"query": {
"qryType": 1,
"query": "label_values(currency)",
"refId": "PrometheusVariableQueryEditor-VariableQuery"
},
"refresh": 1,
"regex": "",
"type": "query"
},
{
"current": {},
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"definition": "label_values(department)",
"label": "Abteilung",
"name": "department",
"options": [],
"query": {
"qryType": 1,
"query": "label_values(department)",
"refId": "PrometheusVariableQueryEditor-VariableQuery"
},
"refresh": 1,
"regex": "",
"type": "query"
}
]
},
"time": {
"from": "now-12h",
"to": "now"
},
"timepicker": {},
"timezone": "browser",
"title": "Übersicht Debitoren",
"uid": "deb9z4knfuxhcc",
"version": 20,
"weekStart": ""
}

View file

@ -1,888 +0,0 @@
{
"__inputs": [
{
"name": "DS_PROMETHEUS",
"label": "prometheus",
"description": "",
"type": "datasource",
"pluginId": "prometheus",
"pluginName": "Prometheus"
}
],
"__elements": {},
"__requires": [
{
"type": "panel",
"id": "bargauge",
"name": "Bar gauge",
"version": ""
},
{
"type": "panel",
"id": "geomap",
"name": "Geomap",
"version": ""
},
{
"type": "grafana",
"id": "grafana",
"name": "Grafana",
"version": "11.4.0"
},
{
"type": "panel",
"id": "piechart",
"name": "Pie chart",
"version": ""
},
{
"type": "datasource",
"id": "prometheus",
"name": "Prometheus",
"version": "1.0.0"
},
{
"type": "panel",
"id": "stat",
"name": "Stat",
"version": ""
},
{
"type": "panel",
"id": "table",
"name": "Table",
"version": ""
},
{
"type": "panel",
"id": "timeseries",
"name": "Time series",
"version": ""
}
],
"annotations": {
"list": [
{
"builtIn": 1,
"datasource": {
"type": "grafana",
"uid": "-- Grafana --"
},
"enable": true,
"hide": true,
"iconColor": "rgba(0, 211, 255, 1)",
"name": "Annotations & Alerts",
"type": "dashboard"
}
]
},
"editable": true,
"fiscalYearStartMonth": 0,
"graphTooltip": 0,
"id": null,
"links": [],
"panels": [
{
"collapsed": false,
"gridPos": {
"h": 1,
"w": 24,
"x": 0,
"y": 0
},
"id": 14,
"panels": [],
"title": "Salden Übersicht Debitoren",
"type": "row"
},
{
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "fixed"
},
"custom": {
"hideFrom": {
"legend": false,
"tooltip": false,
"viz": false
}
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
},
{
"color": "red",
"value": 80
}
]
},
"unit": "locale"
},
"overrides": []
},
"gridPos": {
"h": 9,
"w": 15,
"x": 0,
"y": 1
},
"id": 8,
"options": {
"basemap": {
"config": {
"server": "streets",
"showLabels": true,
"theme": "auto"
},
"name": "Layer 0",
"opacity": 1,
"tooltip": false,
"type": "esri-xyz"
},
"controls": {
"mouseWheelZoom": true,
"showAttribution": true,
"showDebug": false,
"showMeasure": false,
"showScale": false,
"showZoom": true
},
"layers": [
{
"config": {
"showLegend": false,
"style": {
"color": {
"fixed": "blue"
},
"opacity": 0.4,
"rotation": {
"fixed": 0,
"max": 360,
"min": -360,
"mode": "mod"
},
"size": {
"field": "Value",
"fixed": 5,
"max": 60,
"min": 10
},
"symbol": {
"fixed": "img/icons/marker/circle.svg",
"mode": "fixed"
},
"symbolAlign": {
"horizontal": "center",
"vertical": "center"
},
"textConfig": {
"fontSize": 12,
"offsetX": 0,
"offsetY": 0,
"textAlign": "center",
"textBaseline": "middle"
}
}
},
"filterData": {
"id": "byRefId",
"options": "A"
},
"location": {
"lookup": "country",
"mode": "lookup"
},
"name": "Saldo",
"tooltip": true,
"type": "markers"
}
],
"tooltip": {
"mode": "details"
},
"view": {
"allLayers": true,
"id": "europe",
"lat": 46,
"lon": 14,
"zoom": 4
}
},
"pluginVersion": "11.4.0",
"targets": [
{
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"editorMode": "code",
"exemplar": false,
"expr": "sum(last_over_time(application_dbtr_balance{currency=~\"$currency\"}[24h])) by (country, currency)",
"format": "table",
"instant": true,
"legendFormat": "__auto",
"range": false,
"refId": "A"
}
],
"type": "geomap"
},
{
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"fieldConfig": {
"defaults": {
"color": {
"fixedColor": "yellow",
"mode": "palette-classic"
},
"custom": {
"hideFrom": {
"legend": false,
"tooltip": false,
"viz": false
}
},
"mappings": [],
"unit": "locale"
},
"overrides": []
},
"gridPos": {
"h": 9,
"w": 5,
"x": 15,
"y": 1
},
"id": 9,
"options": {
"displayLabels": [],
"legend": {
"displayMode": "list",
"placement": "bottom",
"showLegend": true
},
"pieType": "pie",
"reduceOptions": {
"calcs": [
"lastNotNull"
],
"fields": "",
"values": false
},
"tooltip": {
"mode": "single",
"sort": "none"
}
},
"pluginVersion": "11.4.0",
"targets": [
{
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"editorMode": "code",
"exemplar": false,
"expr": "sum(application_dbtr_balance{currency=~\"$currency\"}) by (department)",
"format": "time_series",
"instant": true,
"legendFormat": "__auto",
"range": true,
"refId": "A"
}
],
"title": "$currency nach Abteilung",
"type": "piechart"
},
{
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"custom": {
"hideFrom": {
"legend": false,
"tooltip": false,
"viz": false
}
},
"mappings": []
},
"overrides": []
},
"gridPos": {
"h": 9,
"w": 4,
"x": 20,
"y": 1
},
"id": 2,
"options": {
"legend": {
"displayMode": "list",
"placement": "bottom",
"showLegend": true
},
"pieType": "pie",
"reduceOptions": {
"calcs": [
"lastNotNull"
],
"fields": "",
"values": false
},
"tooltip": {
"mode": "single",
"sort": "none"
}
},
"pluginVersion": "11.4.0",
"targets": [
{
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"editorMode": "code",
"expr": "sum(application_dbtr_balance) by (currency)",
"instant": false,
"legendFormat": "__auto",
"range": true,
"refId": "A"
}
],
"title": "Verteilung nach Währung",
"type": "piechart"
},
{
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic-by-name"
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
},
{
"color": "red",
"value": 80
}
]
},
"unit": "locale"
},
"overrides": []
},
"gridPos": {
"h": 6,
"w": 20,
"x": 0,
"y": 10
},
"id": 11,
"options": {
"displayMode": "basic",
"legend": {
"calcs": [],
"displayMode": "list",
"placement": "bottom",
"showLegend": false
},
"maxVizHeight": 300,
"minVizHeight": 16,
"minVizWidth": 8,
"namePlacement": "auto",
"orientation": "auto",
"reduceOptions": {
"calcs": [
"lastNotNull"
],
"fields": "",
"values": false
},
"showUnfilled": true,
"sizing": "auto",
"text": {
"titleSize": 10,
"valueSize": 10
},
"valueMode": "color"
},
"pluginVersion": "11.4.0",
"targets": [
{
"editorMode": "code",
"expr": "sum by (department) (application_dbtr_balance{currency=~\"$currency\"})",
"legendFormat": "__auto",
"range": true,
"refId": "A",
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
}
}
],
"title": "Saldo in $currency nach Abteilung",
"type": "bargauge"
},
{
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "thresholds"
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
},
{
"color": "red",
"value": 80
}
]
}
},
"overrides": []
},
"gridPos": {
"h": 6,
"w": 4,
"x": 20,
"y": 10
},
"id": 4,
"options": {
"colorMode": "value",
"graphMode": "area",
"justifyMode": "auto",
"orientation": "auto",
"percentChangeColorMode": "standard",
"reduceOptions": {
"calcs": [
"lastNotNull"
],
"fields": "",
"values": false
},
"showPercentChange": false,
"textMode": "auto",
"wideLayout": true
},
"pluginVersion": "11.4.0",
"targets": [
{
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"editorMode": "code",
"expr": "count(last_over_time(application_dbtr_balance[2h]))",
"hide": false,
"instant": false,
"legendFormat": "__auto",
"range": true,
"refId": "A"
}
],
"title": "Anzahl der Debitoren",
"type": "stat"
},
{
"collapsed": false,
"gridPos": {
"h": 1,
"w": 24,
"x": 0,
"y": 16
},
"id": 16,
"panels": [],
"title": "Salden Übersicht Debitoren - nach Abteilung",
"type": "row"
},
{
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"custom": {
"axisBorderShow": true,
"axisCenteredZero": false,
"axisColorMode": "text",
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"barWidthFactor": 0.6,
"drawStyle": "line",
"fillOpacity": 30,
"gradientMode": "opacity",
"hideFrom": {
"legend": false,
"tooltip": false,
"viz": false
},
"insertNulls": false,
"lineInterpolation": "smooth",
"lineStyle": {
"fill": "solid"
},
"lineWidth": 3,
"pointSize": 9,
"scaleDistribution": {
"type": "linear"
},
"showPoints": "auto",
"spanNulls": true,
"stacking": {
"group": "A",
"mode": "none"
},
"thresholdsStyle": {
"mode": "off"
}
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
},
{
"color": "red",
"value": 80
}
]
},
"unit": "locale"
},
"overrides": []
},
"gridPos": {
"h": 9,
"w": 12,
"x": 0,
"y": 17
},
"id": 1,
"options": {
"legend": {
"calcs": [],
"displayMode": "list",
"placement": "right",
"showLegend": false
},
"tooltip": {
"mode": "single",
"sort": "none"
}
},
"pluginVersion": "11.4.0",
"targets": [
{
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"editorMode": "code",
"exemplar": false,
"expr": "sum(application_dbtr_balance{currency=~\"$currency\", department=~\"$department\"}) ",
"format": "time_series",
"hide": false,
"instant": false,
"interval": "",
"legendFormat": "__auto",
"range": true,
"refId": "A"
}
],
"title": "$department - Saldo in $currency",
"type": "timeseries"
},
{
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "thresholds"
},
"custom": {
"align": "auto",
"cellOptions": {
"type": "auto"
},
"inspect": false
},
"decimals": 2,
"fieldMinMax": false,
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
},
{
"color": "red",
"value": 80
}
]
},
"unit": "locale"
},
"overrides": [
{
"matcher": {
"id": "byName",
"options": "name"
},
"properties": [
{
"id": "custom.width",
"value": 558
}
]
},
{
"matcher": {
"id": "byName",
"options": "currency"
},
"properties": [
{
"id": "custom.width",
"value": 97
}
]
},
{
"matcher": {
"id": "byName",
"options": "id"
},
"properties": [
{
"id": "custom.width",
"value": 81
}
]
},
{
"matcher": {
"id": "byName",
"options": "Lieferant"
},
"properties": [
{
"id": "custom.width",
"value": 515
}
]
},
{
"matcher": {
"id": "byName",
"options": "Saldo"
},
"properties": [
{
"id": "decimals",
"value": 2
},
{
"id": "unit",
"value": "none"
}
]
}
]
},
"gridPos": {
"h": 9,
"w": 12,
"x": 12,
"y": 17
},
"id": 15,
"options": {
"cellHeight": "sm",
"footer": {
"countRows": false,
"fields": "",
"reducer": [
"sum"
],
"show": false
},
"showHeader": true,
"sortBy": []
},
"pluginVersion": "11.4.0",
"targets": [
{
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"editorMode": "code",
"exemplar": false,
"expr": "sum(last_over_time(application_dbtr_balance{currency=~\"$currency\", department=~\"$department\"}[2h]))\n by (name, id,department, currency)",
"format": "table",
"instant": true,
"legendFormat": "__auto",
"range": false,
"refId": "A"
}
],
"title": "Saldo By Debitor",
"transformations": [
{
"id": "organize",
"options": {
"excludeByName": {
"Time": true,
"department": true
},
"includeByName": {},
"indexByName": {
"Time": 0,
"Value": 5,
"currency": 3,
"department": 4,
"id": 2,
"name": 1
},
"renameByName": {
"Value": "Saldo",
"currency": " ",
"department": "",
"name": "Lieferant"
}
}
},
{
"id": "sortBy",
"options": {
"fields": {},
"sort": [
{
"desc": true,
"field": "Saldo"
}
]
}
}
],
"type": "table"
}
],
"schemaVersion": 40,
"tags": [],
"templating": {
"list": [
{
"current": {},
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"definition": "label_values(currency)",
"label": "Währung",
"name": "currency",
"options": [],
"query": {
"qryType": 1,
"query": "label_values(currency)",
"refId": "PrometheusVariableQueryEditor-VariableQuery"
},
"refresh": 1,
"regex": "",
"type": "query"
},
{
"current": {},
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"definition": "label_values(department)",
"label": "Abteilung",
"name": "department",
"options": [],
"query": {
"qryType": 1,
"query": "label_values(department)",
"refId": "PrometheusVariableQueryEditor-VariableQuery"
},
"refresh": 1,
"regex": "",
"type": "query"
},
{
"datasource": {
"type": "prometheus",
"uid": "P1809F7CD0C75ACF3"
},
"filters": [],
"name": "Filters",
"type": "adhoc"
}
]
},
"time": {
"from": "now-24h",
"to": "now"
},
"timepicker": {},
"timezone": "browser",
"title": "Übersicht Debitoren",
"uid": "deb9z4knfuxhcc",
"version": 31,
"weekStart": ""
}

View file

@ -1,55 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
imixs-llm.xml - LLM Model Registry
======================================
Place this file in your deployment so it is available on the classpath,
e.g. in src/main/resources/ for a Maven project.
Each <model> element defines one logical LLM service endpoint.
A model is either a completion model OR an embedding model - never both.
The BPMN configuration references them separately by their id:
<imixs-ai name="CONDITION">
<endpoint>my-llm</endpoint>
...
</imixs-ai>
<imixs-ai name="RAG_INDEX">
<endpoint-completion>my-llm</endpoint-completion>
<endpoint-embeddings>my-embeddings</endpoint-embeddings>
...
</imixs-ai>
Environment variable placeholders are supported via ${env.VAR_NAME}.
-->
<imixs-llm>
<!--
Completion model used for chat completions, conditions, analysis etc.
This example connects to a local llama.cpp server.
-->
<endpoint id="api.llama.cpp.imixs.com">
<url>https://api.llama.cpp.imixs.com/</url>
<apikey>7fdb663fa87ea16731c1e0ece8ad3214e358423eabf2403188110c731ce07321</apikey>
<options>{
"temperature": 0.2,
"max_tokens": 1024
}
</options>
</endpoint>
<!--
Embedding model used for RAG indexing and retrieval.
This example connects to a separate embedding server.
No apikey needed for a locally hosted instance.
-->
<endpoint id="embeddings.llama.cpp.imixs.com">
<url>https://embeddings.llama.cpp.imixs.com/</url>
<apikey>7fdb663fa87ea16731c1e0ece8ad3214e358423eabf2403188110c731ce07321</apikey>
<options>{
"max_tokens": 512
}
</options>
</endpoint>
</imixs-llm>

View file

@ -1,15 +0,0 @@
global:
scrape_interval: 15s # By default, scrape targets every 15 seconds.
# Attach these labels to any time series or alerts when communicating with
# external systems (federation, remote storage, Alertmanager).
external_labels:
monitor: "imixs-monitor"
scrape_configs:
# Imixs-Office-Workflow Job (Wildfly Metrics)
- job_name: "imixs"
scrape_interval: 3600s
metrics_path: /metrics
static_configs:
- targets: ["app:9990"]

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

11
hotdeploy.sh Executable file
View file

@ -0,0 +1,11 @@
#!/bin/bash
############################################################
# Setup hotdeploy
#
############################################################
cd office-alexander-logistics-app
mvn manik-hotdeploy:hotdeploy
cd ..

53
models/README.md Executable file
View file

@ -0,0 +1,53 @@
# ML Models
Wir verwenden bei Alexander-Global Logistics ein standard Invoice ML Modell. Dieses basiert im Grund auf unserem offizielen spacy modell 'invoice-de-0.1.0'.
## Modell Nachtrainieren
Das Modell bei Alexander Logistics läst sich in der Dev Umggebung bei Bedarf nachtrainieren. Dazu geht man wie folgt vor:
**1.)** Aktuelles Modell auf Tikal Cloud Server sichern:
$ ssh imixs@master-1.tikal.imixs.com
$ cd tikal-cloud/
$ ./apps/alexander-logistics.office-workflow.de/ml_model_backup.sh
# Falls es zu einem io/error kommt, muss der spacy ml pod neu gestartet werden!
**2.)** Die Tikal-Cloud Pullen
**3.)** Um auf dem aktuellen Modell weiter zu trainierne, den Inhalt des invoice-de-0.1.0 Folders aus dem Backup directory in die lokale Dev Umgebung kopieren /
um ein neues Modell zu genereiren einfach den localen ordner 'invoice-de-0.1.0' umbenennen oder leeren.
**4.)** Jetzt lokal den Trainingsserver aufrufen
http://localhost:8081/api/openapi-ui/index.html
und das training beginnen mit der datei 'training-config-prod.xml'. Man kann das training 3-4 mal durchführen.
**5.)** Nun kann man die Inhalte des invoice-de-0.1.0 Folders zurück auf den Tikal in den modell folder /invoice-de-0.1.0 einspielen
**6.)** Nun die änderungen nach Git Puschen.
**7.)** auf dem Tikal Sever nun das aktuellisete Modell wieder einspielen
$ git pull
$ ./apps/alexander-logistics.office-workflow.de/ml_model_deploy.sh invoice-de-0.1.0/
## 22.05.2021 - invoice-de-0.1.0
NER=2.1948
## 17.02.2020 - invoice-de-0.1.0
Modell trainiert anhand der alexander-logistics Produtiv daten

491
models/TEST_PROTOKOLL.md Normal file
View file

@ -0,0 +1,491 @@
# Test Protokoll Alexander Logistic invoice-de-0.1.0
**Validierung**
f4eaceda-f28a-4394-928e-1a05daaf2760
a5d1e7fe-d74a-4fa2-9b06-3221865759fa
c0290497-f613-4492-81b6-4ae1e1680029
d8e3fce4-d11c-46a4-8ba0-369b4c6e902f
8b766f35-828a-41f1-be04-00b4b62da4d0
**********************************************************************
** invoice-de-0.1.0-falsemodell
**12.10.2021 15:50** (sort order created)
**********************************************************************
workflow.query ($workflowgroup:"Rechnungseingang" OR $workflowgroup:"Sachrechnung") AND ($taskid:5900)
workflow.pagesize 500
ml.training.filepattern .pdf
ml.training.iterations 10
ml.training.dropoutrate 0,25
multiOccurrence false
ml.training.quality LOW
min_losses 0
RESULT
-----------------------------------------------------------------------
imixs-ml-training_1 | ......documents trained in total = 375
imixs-ml-training_1 | ...... quality level GOOD = 53.33% (200)
imixs-ml-training_1 | ...... quality level LOW = 31.47% (118)
imixs-ml-training_1 | ...... quality level BAD = 15.2% (57)
imixs-ml-training_1 | ...... average NER = 17.195895012525614
imixs-ml-training_1 |
imixs-ml-training_1 | ......documents trained in total = 375
imixs-ml-training_1 | ...... quality level GOOD = 51.73% (194)
imixs-ml-training_1 | ...... quality level LOW = 32.8% (123)
imixs-ml-training_1 | ...... quality level BAD = 15.47% (58)
imixs-ml-training_1 | ...... average NER = 6.50170386961344
imixs-ml-training_1 |
imixs-ml-training_1 | ......documents trained in total = 375
imixs-ml-training_1 | ...... quality level GOOD = 53.87% (202)
imixs-ml-training_1 | ...... quality level LOW = 31.73% (119)
imixs-ml-training_1 | ...... quality level BAD = 14.4% (54)
imixs-ml-training_1 | ...... average NER = 4.8940276912225
imixs-ml-training_1 |
imixs-ml-training_1 | ......documents trained in total = 375
imixs-ml-training_1 | ...... quality level GOOD = 52.8% (198)
imixs-ml-training_1 | ...... quality level LOW = 32% (120)
imixs-ml-training_1 | ...... quality level BAD = 15.2% (57)
imixs-ml-training_1 | ...... average NER = 3.9605563888416824
imixs-ml-training_1 |
imixs-ml-training_1 | ......documents trained in total = 375
imixs-ml-training_1 | ...... quality level GOOD = 54.13% (203)
imixs-ml-training_1 | ...... quality level LOW = 29.6% (111)
imixs-ml-training_1 | ...... quality level BAD = 16.27% (61)
imixs-ml-training_1 | ...... average NER = 3.744507591826106
imixs-ml-training_1 |
imixs-ml-training_1 | ......documents trained in total = 375
imixs-ml-training_1 | ...... quality level GOOD = 53.07% (199)
imixs-ml-training_1 | ...... quality level LOW = 31.2% (117)
imixs-ml-training_1 | ...... quality level BAD = 15.73% (59)
imixs-ml-training_1 | ...... average NER = 2.8395576715820736
imixs-ml-training_1 |
imixs-ml-training_1 | ......documents trained in total = 375
imixs-ml-training_1 | ...... quality level GOOD = 53.87% (202)
imixs-ml-training_1 | ...... quality level LOW = 32% (120)
imixs-ml-training_1 | ...... quality level BAD = 14.13% (53)
imixs-ml-training_1 | ...... average NER = 2.6799682681142363
imixs-ml-training_1 |
imixs-ml-training_1 | ......documents trained in total = 375
imixs-ml-training_1 | ...... quality level GOOD = 53.6% (201)
imixs-ml-training_1 | ...... quality level LOW = 31.47% (118)
imixs-ml-training_1 | ...... quality level BAD = 14.93% (56)
imixs-ml-training_1 | ...... average NER = 2.520244211218683
imixs-ml-training_1 |
imixs-ml-training_1 | ......documents trained in total = 375
imixs-ml-training_1 | ...... quality level GOOD = 49.33% (185)
imixs-ml-training_1 | ...... quality level LOW = 34.93% (131)
imixs-ml-training_1 | ...... quality level BAD = 15.73% (59)
imixs-ml-training_1 | ...... average NER = 2.1511980661715193
imixs-ml-training_1 |
imixs-ml-training_1 | ......documents trained in total = 375
imixs-ml-training_1 | ...... quality level GOOD = 53.87% (202)
imixs-ml-training_1 | ...... quality level LOW = 31.2% (117)
imixs-ml-training_1 | ...... quality level BAD = 14.93% (56)
imixs-ml-training_1 | ...... average NER = 2.2739690429824475
**13.10.2021 12:00**
workflow.query ($workflowgroup:"Rechnungseingang" OR $workflowgroup:"Sachrechnung") AND ($taskid:5900)
workflow.pagesize 500
ml.training.filepattern .pdf|.PDF
ml.training.iterations 10
ml.training.dropoutrate 0,25
multiOccurrence false
ml.training.quality LOW
min_losses 0
imixs-ml-training_1 | ......documents trained in total = 375
imixs-ml-training_1 | ...... quality level GOOD = 61.33% (230)
imixs-ml-training_1 | ...... quality level LOW = 38.67% (145)
imixs-ml-training_1 | ...... quality level BAD = 0% (0)
imixs-ml-training_1 | ...... average NER = 3.790466332166552
imixs-ml-training_1 |
imixs-ml-training_1 | ......documents trained in total = 375
imixs-ml-training_1 | ...... quality level GOOD = 61.07% (229)
imixs-ml-training_1 | ...... quality level LOW = 38.93% (146)
imixs-ml-training_1 | ...... quality level BAD = 0% (0)
imixs-ml-training_1 | ...... average NER = 3.160620521438082
imixs-ml-training_1 |
imixs-ml-training_1 | ......documents trained in total = 375
imixs-ml-training_1 | ...... quality level GOOD = 58.13% (218)
imixs-ml-training_1 | ...... quality level LOW = 41.87% (157)
imixs-ml-training_1 | ...... quality level BAD = 0% (0)
imixs-ml-training_1 | ...... average NER = 2.636420357788331
imixs-ml-training_1 |
imixs-ml-training_1 | ......documents trained in total = 375
imixs-ml-training_1 | ...... quality level GOOD = 58.13% (218)
imixs-ml-training_1 | ...... quality level LOW = 41.87% (157)
imixs-ml-training_1 | ...... quality level BAD = 0% (0)
imixs-ml-training_1 | ...... average NER = 2.506552163520219
imixs-ml-training_1 |
imixs-ml-training_1 | ......documents trained in total = 375
imixs-ml-training_1 | ...... quality level GOOD = 58.93% (221)
imixs-ml-training_1 | ...... quality level LOW = 41.07% (154)
imixs-ml-training_1 | ...... quality level BAD = 0% (0)
imixs-ml-training_1 | ...... average NER = 2.3495061575286793
imixs-ml-training_1 |
imixs-ml-training_1 | ......documents trained in total = 375
imixs-ml-training_1 | ...... quality level GOOD = 59.47% (223)
imixs-ml-training_1 | ...... quality level LOW = 40.53% (152)
imixs-ml-training_1 | ...... quality level BAD = 0% (0)
imixs-ml-training_1 | ...... average NER = 1.9351332692220107
imixs-ml-training_1 |
imixs-ml-training_1 | ......documents trained in total = 375
imixs-ml-training_1 | ...... quality level GOOD = 61.33% (230)
imixs-ml-training_1 | ...... quality level LOW = 38.67% (145)
imixs-ml-training_1 | ...... quality level BAD = 0% (0)
imixs-ml-training_1 | ...... average NER = 1.8881396005118698
imixs-ml-training_1 |
imixs-ml-training_1 | ......documents trained in total = 375
imixs-ml-training_1 | ...... quality level GOOD = 57.87% (217)
imixs-ml-training_1 | ...... quality level LOW = 42.13% (158)
imixs-ml-training_1 | ...... quality level BAD = 0% (0)
imixs-ml-training_1 | ...... average NER = 1.9754112840739593
imixs-ml-training_1 |
imixs-ml-training_1 | ......documents trained in total = 375
imixs-ml-training_1 | ...... quality level GOOD = 59.73% (224)
imixs-ml-training_1 | ...... quality level LOW = 40.27% (151)
imixs-ml-training_1 | ...... quality level BAD = 0% (0)
imixs-ml-training_1 | ...... average NER = 1.7839739270522237
imixs-ml-training_1 |
imixs-ml-training_1 | ......documents trained in total = 375
imixs-ml-training_1 | ...... quality level GOOD = 59.73% (224)
imixs-ml-training_1 | ...... quality level LOW = 40.27% (151)
imixs-ml-training_1 | ...... quality level BAD = 0% (0)
imixs-ml-training_1 | ...... average NER = 1.6024293913431429
**********************************************************************
** invoice-de-0.1.0
**12.10.2021 15:50** (sort order created)
**********************************************************************
workflow.query ($workflowgroup:"Rechnungseingang" OR $workflowgroup:"Sachrechnung") AND ($taskid:5900)
workflow.pagesize 500
ml.training.filepattern .pdf|.PDF
ml.training.iterations 10
ml.training.dropoutrate 0,25
multiOccurrence true
ml.training.quality LOW
min_losses 0
imixs-ml-training_1 |
imixs-ml-training_1 | ......documents trained in total = 375
imixs-ml-training_1 | ...... quality level GOOD = 68.27% (256)
imixs-ml-training_1 | ...... quality level LOW = 31.47% (118)
imixs-ml-training_1 | ...... quality level BAD = 0.27% (1)
imixs-ml-training_1 | ...... average NER = 21.57255353509432
imixs-ml-training_1 |
imixs-ml-training_1 | ......documents trained in total = 375
imixs-ml-training_1 | ...... quality level GOOD = 67.73% (254)
imixs-ml-training_1 | ...... quality level LOW = 32.27% (121)
imixs-ml-training_1 | ...... quality level BAD = 0% (0)
imixs-ml-training_1 | ...... average NER = 8.249835149395697
imixs-ml-training_1 |
imixs-ml-training_1 | ......documents trained in total = 375
imixs-ml-training_1 | ...... quality level GOOD = 68.53% (257)
imixs-ml-training_1 | ...... quality level LOW = 31.2% (117)
imixs-ml-training_1 | ...... quality level BAD = 0.27% (1)
imixs-ml-training_1 | ...... average NER = 5.892598287488733
imixs-ml-training_1 |
imixs-ml-training_1 | ......documents trained in total = 375
imixs-ml-training_1 | ...... quality level GOOD = 68.53% (257)
imixs-ml-training_1 | ...... quality level LOW = 31.2% (117)
imixs-ml-training_1 | ...... quality level BAD = 0.27% (1)
imixs-ml-training_1 | ...... average NER = 4.964129124089013
imixs-ml-training_1 |
imixs-ml-training_1 | ......documents trained in total = 375
imixs-ml-training_1 | ...... quality level GOOD = 68.53% (257)
imixs-ml-training_1 | ...... quality level LOW = 31.2% (117)
imixs-ml-training_1 | ...... quality level BAD = 0.27% (1)
imixs-ml-training_1 | ...... average NER = 3.5603186705177947
imixs-ml-training_1 |
imixs-ml-training_1 | ......documents trained in total = 375
imixs-ml-training_1 | ...... quality level GOOD = 67.2% (252)
imixs-ml-training_1 | ...... quality level LOW = 32.53% (122)
imixs-ml-training_1 | ...... quality level BAD = 0.27% (1)
imixs-ml-training_1 | ...... average NER = 2.692053828307031
imixs-ml-training_1 |
imixs-ml-training_1 | ......documents trained in total = 375
imixs-ml-training_1 | ...... quality level GOOD = 68% (255)
imixs-ml-training_1 | ...... quality level LOW = 31.73% (119)
imixs-ml-training_1 | ...... quality level BAD = 0.27% (1)
imixs-ml-training_1 | ...... average NER = 2.3509401762802873
imixs-ml-training_1 |
imixs-ml-training_1 | ......documents trained in total = 375
imixs-ml-training_1 | ...... quality level GOOD = 65.87% (247)
imixs-ml-training_1 | ...... quality level LOW = 34.13% (128)
imixs-ml-training_1 | ...... quality level BAD = 0% (0)
imixs-ml-training_1 | ...... average NER = 2.2695994889458104
imixs-ml-training_1 |
imixs-ml-training_1 | ......documents trained in total = 375
imixs-ml-training_1 | ...... quality level GOOD = 68.27% (256)
imixs-ml-training_1 | ...... quality level LOW = 31.47% (118)
imixs-ml-training_1 | ...... quality level BAD = 0.27% (1)
imixs-ml-training_1 | ...... average NER = 1.844410364015416
imixs-ml-training_1 |
imixs-ml-training_1 | ......documents trained in total = 375
imixs-ml-training_1 | ...... quality level GOOD = 70.67% (265)
imixs-ml-training_1 | ...... quality level LOW = 29.07% (109)
imixs-ml-training_1 | ...... quality level BAD = 0.27% (1)
imixs-ml-training_1 | ...... average NER = 1.6153951610034658
page=1 (count=500)
--------------------------------
imixs-ml-training_1 | ......documents trained in total = 375
imixs-ml-training_1 | ...... quality level GOOD = 69.6% (261)
imixs-ml-training_1 | ...... quality level LOW = 30.4% (114)
imixs-ml-training_1 | ...... quality level BAD = 0% (0)
imixs-ml-training_1 | ...... average NER = 7.093659738880595
imixs-ml-training_1 |
imixs-ml-training_1 | ......documents trained in total = 375
imixs-ml-training_1 | ...... quality level GOOD = 66.4% (249)
imixs-ml-training_1 | ...... quality level LOW = 33.6% (126)
imixs-ml-training_1 | ...... quality level BAD = 0% (0)
imixs-ml-training_1 | ...... average NER = 5.201780406598962
imixs-ml-training_1 |
imixs-ml-training_1 | ......documents trained in total = 375
imixs-ml-training_1 | ...... quality level GOOD = 68.27% (256)
imixs-ml-training_1 | ...... quality level LOW = 31.73% (119)
imixs-ml-training_1 | ...... quality level BAD = 0% (0)
imixs-ml-training_1 | ...... average NER = 3.8116329003426204
imixs-ml-training_1 |
imixs-ml-training_1 | ......documents trained in total = 375
imixs-ml-training_1 | ...... quality level GOOD = 66.67% (250)
imixs-ml-training_1 | ...... quality level LOW = 33.33% (125)
imixs-ml-training_1 | ...... quality level BAD = 0% (0)
imixs-ml-training_1 | ...... average NER = 3.3164488404836154
imixs-ml-training_1 |
imixs-ml-training_1 | ......documents trained in total = 375
imixs-ml-training_1 | ...... quality level GOOD = 66.93% (251)
imixs-ml-training_1 | ...... quality level LOW = 33.07% (124)
imixs-ml-training_1 | ...... quality level BAD = 0% (0)
imixs-ml-training_1 | ...... average NER = 2.7822570929398576
imixs-ml-training_1 |
imixs-ml-training_1 | ......documents trained in total = 375
imixs-ml-training_1 | ...... quality level GOOD = 69.07% (259)
imixs-ml-training_1 | ...... quality level LOW = 30.93% (116)
imixs-ml-training_1 | ...... quality level BAD = 0% (0)
imixs-ml-training_1 | ...... average NER = 2.31773083524846
imixs-ml-training_1 |
imixs-ml-training_1 | ......documents trained in total = 375
imixs-ml-training_1 | ...... quality level GOOD = 68.8% (258)
imixs-ml-training_1 | ...... quality level LOW = 31.2% (117)
imixs-ml-training_1 | ...... quality level BAD = 0% (0)
imixs-ml-training_1 | ...... average NER = 2.165804551920185
imixs-ml-training_1 |
imixs-ml-training_1 | ......documents trained in total = 375
imixs-ml-training_1 | ...... quality level GOOD = 66.4% (249)
imixs-ml-training_1 | ...... quality level LOW = 33.6% (126)
imixs-ml-training_1 | ...... quality level BAD = 0% (0)
imixs-ml-training_1 | ...... average NER = 1.9591955652007715
imixs-ml-training_1 |
imixs-ml-training_1 | ......documents trained in total = 375
imixs-ml-training_1 | ...... quality level GOOD = 66.4% (249)
imixs-ml-training_1 | ...... quality level LOW = 33.6% (126)
imixs-ml-training_1 | ...... quality level BAD = 0% (0)
imixs-ml-training_1 | ...... average NER = 1.5473874007025803
imixs-ml-training_1 |
imixs-ml-training_1 | ......documents trained in total = 375
imixs-ml-training_1 | ...... quality level GOOD = 65.87% (247)
imixs-ml-training_1 | ...... quality level LOW = 34.13% (128)
imixs-ml-training_1 | ...... quality level BAD = 0% (0)
imixs-ml-training_1 | ...... average NER = 1.705957084193204
imixs-ml-training_1 | |#]
imixs-ml-training_1 |
page=0 (count=1000)
--------------------------------
imixs-ml-training_1 |
imixs-ml-training_1 | ......documents trained in total = 750
imixs-ml-training_1 | ...... quality level GOOD = 67.47% (506)
imixs-ml-training_1 | ...... quality level LOW = 32.53% (244)
imixs-ml-training_1 | ...... quality level BAD = 0% (0)
imixs-ml-training_1 | ...... average NER = 3.2147245242951565
imixs-ml-training_1 |
imixs-ml-training_1 | ......documents trained in total = 750
imixs-ml-training_1 | ...... quality level GOOD = 68.8% (516)
imixs-ml-training_1 | ...... quality level LOW = 31.07% (233)
imixs-ml-training_1 | ...... quality level BAD = 0.13% (1)
imixs-ml-training_1 | ...... average NER = 2.2084385109690565
imixs-ml-training_1 |
imixs-ml-training_1 | ......documents trained in total = 750
imixs-ml-training_1 | ...... quality level GOOD = 67.73% (508)
imixs-ml-training_1 | ...... quality level LOW = 32.27% (242)
imixs-ml-training_1 | ...... quality level BAD = 0% (0)
imixs-ml-training_1 | ...... average NER = 2.1797281610496464
imixs-ml-training_1 |
imixs-ml-training_1 | ......documents trained in total = 750
imixs-ml-training_1 | ...... quality level GOOD = 67.2% (504)
imixs-ml-training_1 | ...... quality level LOW = 32.67% (245)
imixs-ml-training_1 | ...... quality level BAD = 0.13% (1)
imixs-ml-training_1 | ...... average NER = 1.8908819163368502
imixs-ml-training_1 |
imixs-ml-training_1 | ......documents trained in total = 750
imixs-ml-training_1 | ...... quality level GOOD = 66% (495)
imixs-ml-training_1 | ...... quality level LOW = 33.87% (254)
imixs-ml-training_1 | ...... quality level BAD = 0.13% (1)
imixs-ml-training_1 | ...... average NER = 1.7774978150912477
imixs-ml-training_1 |
imixs-ml-training_1 | ......documents trained in total = 750
imixs-ml-training_1 | ...... quality level GOOD = 67.6% (507)
imixs-ml-training_1 | ...... quality level LOW = 32.27% (242)
imixs-ml-training_1 | ...... quality level BAD = 0.13% (1)
imixs-ml-training_1 | ...... average NER = 1.669098427922433
imixs-ml-training_1 |
imixs-ml-training_1 | ......documents trained in total = 750
imixs-ml-training_1 | ...... quality level GOOD = 67.33% (505)
imixs-ml-training_1 | ...... quality level LOW = 32.53% (244)
imixs-ml-training_1 | ...... quality level BAD = 0.13% (1)
imixs-ml-training_1 | ...... average NER = 1.6048149396167861
imixs-ml-training_1 |
imixs-ml-training_1 | ......documents trained in total = 750
imixs-ml-training_1 | ...... quality level GOOD = 67.6% (507)
imixs-ml-training_1 | ...... quality level LOW = 32.27% (242)
imixs-ml-training_1 | ...... quality level BAD = 0.13% (1)
imixs-ml-training_1 | ...... average NER = 1.4026393956412981
imixs-ml-training_1 |
imixs-ml-training_1 | ......documents trained in total = 750
imixs-ml-training_1 | ...... quality level GOOD = 67.87% (509)
imixs-ml-training_1 | ...... quality level LOW = 32% (240)
imixs-ml-training_1 | ...... quality level BAD = 0.13% (1)
imixs-ml-training_1 | ...... average NER = 1.1139796046407426
imixs-ml-training_1 |
imixs-ml-training_1 | ......documents trained in total = 750
imixs-ml-training_1 | ...... quality level GOOD = 65.87% (494)
imixs-ml-training_1 | ...... quality level LOW = 34% (255)
imixs-ml-training_1 | ...... quality level BAD = 0.13% (1)
imixs-ml-training_1 | ...... average NER = 1.2621875029460226
page=1 (count=1000)
--------------------------------
imixs-ml-training_1 | ......documents trained in total = 750
imixs-ml-training_1 | ...... quality level GOOD = 63.47% (476)
imixs-ml-training_1 | ...... quality level LOW = 36.4% (273)
imixs-ml-training_1 | ...... quality level BAD = 0.13% (1)
imixs-ml-training_1 | ...... average NER = 3.7501272727903876
imixs-ml-training_1 |
imixs-ml-training_1 | ......documents trained in total = 750
imixs-ml-training_1 | ...... quality level GOOD = 64% (480)
imixs-ml-training_1 | ...... quality level LOW = 35.87% (269)
imixs-ml-training_1 | ...... quality level BAD = 0.13% (1)
imixs-ml-training_1 | ...... average NER = 2.7749715296165482
imixs-ml-training_1 |
imixs-ml-training_1 | ......documents trained in total = 750
imixs-ml-training_1 | ...... quality level GOOD = 65.47% (491)
imixs-ml-training_1 | ...... quality level LOW = 34.27% (257)
imixs-ml-training_1 | ...... quality level BAD = 0.27% (2)
imixs-ml-training_1 | ...... average NER = 2.191986221088383
imixs-ml-training_1 |
imixs-ml-training_1 | ......documents trained in total = 750
imixs-ml-training_1 | ...... quality level GOOD = 63.2% (474)
imixs-ml-training_1 | ...... quality level LOW = 36.53% (274)
imixs-ml-training_1 | ...... quality level BAD = 0.27% (2)
imixs-ml-training_1 | ...... average NER = 1.836000005105162
imixs-ml-training_1 |
imixs-ml-training_1 | ......documents trained in total = 750
imixs-ml-training_1 | ...... quality level GOOD = 64.8% (486)
imixs-ml-training_1 | ...... quality level LOW = 34.93% (262)
imixs-ml-training_1 | ...... quality level BAD = 0.27% (2)
imixs-ml-training_1 | ...... average NER = 1.629252182245437
imixs-ml-training_1 |
imixs-ml-training_1 | ......documents trained in total = 750
imixs-ml-training_1 | ...... quality level GOOD = 64.27% (482)
imixs-ml-training_1 | ...... quality level LOW = 35.47% (266)
imixs-ml-training_1 | ...... quality level BAD = 0.27% (2)
imixs-ml-training_1 | ...... average NER = 1.5023185259959349
imixs-ml-training_1 |
imixs-ml-training_1 | ......documents trained in total = 750
imixs-ml-training_1 | ...... quality level GOOD = 63.6% (477)
imixs-ml-training_1 | ...... quality level LOW = 36.13% (271)
imixs-ml-training_1 | ...... quality level BAD = 0.27% (2)
imixs-ml-training_1 | ...... average NER = 1.1618358977500587
imixs-ml-training_1 |
imixs-ml-training_1 | ......documents trained in total = 750
imixs-ml-training_1 | ...... quality level GOOD = 64.93% (487)
imixs-ml-training_1 | ...... quality level LOW = 34.93% (262)
imixs-ml-training_1 | ...... quality level BAD = 0.13% (1)
imixs-ml-training_1 | ...... average NER = 1.1362052688492958
imixs-ml-training_1 |
imixs-ml-training_1 | ......documents trained in total = 750
imixs-ml-training_1 | ...... quality level GOOD = 64.4% (483)
imixs-ml-training_1 | ...... quality level LOW = 35.33% (265)
imixs-ml-training_1 | ...... quality level BAD = 0.27% (2)
imixs-ml-training_1 | ...... average NER = 1.0497074333838767
imixs-ml-training_1 |
imixs-ml-training_1 | ......documents trained in total = 750
imixs-ml-training_1 | ...... quality level GOOD = 65.33% (490)
imixs-ml-training_1 | ...... quality level LOW = 34.4% (258)
imixs-ml-training_1 | ...... quality level BAD = 0.27% (2)
imixs-ml-training_1 | ...... average NER = 0.8865013575787167
page=1 (count=1000)
--------------------------------
imixs-ml-training_1 | ......documents trained in total = 750
imixs-ml-training_1 | ...... quality level GOOD = 63.33% (475)
imixs-ml-training_1 | ...... quality level LOW = 36.4% (273)
imixs-ml-training_1 | ...... quality level BAD = 0.27% (2)
imixs-ml-training_1 | ...... average NER = 1.6325150460009787
imixs-ml-training_1 |
imixs-ml-training_1 | ......documents trained in total = 750
imixs-ml-training_1 | ...... quality level GOOD = 61.73% (463)
imixs-ml-training_1 | ...... quality level LOW = 38% (285)
imixs-ml-training_1 | ...... quality level BAD = 0.27% (2)
imixs-ml-training_1 | ...... average NER = 1.5385085364524884
imixs-ml-training_1 |
imixs-ml-training_1 | ......documents trained in total = 750
imixs-ml-training_1 | ...... quality level GOOD = 63.6% (477)
imixs-ml-training_1 | ...... quality level LOW = 36.13% (271)
imixs-ml-training_1 | ...... quality level BAD = 0.27% (2)
imixs-ml-training_1 | ...... average NER = 1.343965340697668
imixs-ml-training_1 |
imixs-ml-training_1 | ......documents trained in total = 750
imixs-ml-training_1 | ...... quality level GOOD = 64.13% (481)
imixs-ml-training_1 | ...... quality level LOW = 35.73% (268)
imixs-ml-training_1 | ...... quality level BAD = 0.13% (1)
imixs-ml-training_1 | ...... average NER = 1.1842750119930687
imixs-ml-training_1 |
imixs-ml-training_1 | ......documents trained in total = 750
imixs-ml-training_1 | ...... quality level GOOD = 63.73% (478)
imixs-ml-training_1 | ...... quality level LOW = 36% (270)
imixs-ml-training_1 | ...... quality level BAD = 0.27% (2)
imixs-ml-training_1 | ...... average NER = 1.112559219903824
imixs-ml-training_1 |
imixs-ml-training_1 | ......documents trained in total = 750
imixs-ml-training_1 | ...... quality level GOOD = 62.8% (471)
imixs-ml-training_1 | ...... quality level LOW = 36.93% (277)
imixs-ml-training_1 | ...... quality level BAD = 0.27% (2)
imixs-ml-training_1 | ...... average NER = 0.9444137586901881
imixs-ml-training_1 |
imixs-ml-training_1 | ......documents trained in total = 750
imixs-ml-training_1 | ...... quality level GOOD = 64% (480)
imixs-ml-training_1 | ...... quality level LOW = 35.73% (268)
imixs-ml-training_1 | ...... quality level BAD = 0.27% (2)
imixs-ml-training_1 | ...... average NER = 0.9175624525798468
imixs-ml-training_1 |
imixs-ml-training_1 | ......documents trained in total = 750
imixs-ml-training_1 | ...... quality level GOOD = 63.47% (476)
imixs-ml-training_1 | ...... quality level LOW = 36.27% (272)
imixs-ml-training_1 | ...... quality level BAD = 0.27% (2)
imixs-ml-training_1 | ...... average NER = 0.8877949306723629
imixs-ml-training_1 |
imixs-ml-training_1 | ......documents trained in total = 750
imixs-ml-training_1 | ...... quality level GOOD = 62.53% (469)
imixs-ml-training_1 | ...... quality level LOW = 37.2% (279)
imixs-ml-training_1 | ...... quality level BAD = 0.27% (2)
imixs-ml-training_1 | ...... average NER = 0.7669201996298972
imixs-ml-training_1 |
imixs-ml-training_1 | ......documents trained in total = 750
imixs-ml-training_1 | ...... quality level GOOD = 62.8% (471)
imixs-ml-training_1 | ...... quality level LOW = 37.07% (278)
imixs-ml-training_1 | ...... quality level BAD = 0.13% (1)
imixs-ml-training_1 | ...... average NER = 0.7161310708827515

View file

@ -0,0 +1,128 @@
[paths]
train = null
dev = null
vectors = null
init_tok2vec = null
[system]
seed = 0
gpu_allocator = null
[nlp]
lang = "de"
pipeline = ["ner"]
disabled = []
before_creation = null
after_creation = null
after_pipeline_creation = null
batch_size = 1000
tokenizer = {"@tokenizers":"spacy.Tokenizer.v1"}
[components]
[components.ner]
factory = "ner"
incorrect_spans_key = null
moves = null
scorer = {"@scorers":"spacy.ner_scorer.v1"}
update_with_oracle_cut_size = 100
[components.ner.model]
@architectures = "spacy.TransitionBasedParser.v2"
state_type = "ner"
extra_state_tokens = false
hidden_width = 64
maxout_pieces = 2
use_upper = true
nO = null
[components.ner.model.tok2vec]
@architectures = "spacy.HashEmbedCNN.v2"
pretrained_vectors = null
width = 96
depth = 4
embed_size = 2000
window_size = 1
maxout_pieces = 3
subword_features = true
[corpora]
[corpora.dev]
@readers = "spacy.Corpus.v1"
path = ${paths.dev}
gold_preproc = false
max_length = 0
limit = 0
augmenter = null
[corpora.train]
@readers = "spacy.Corpus.v1"
path = ${paths.train}
gold_preproc = false
max_length = 0
limit = 0
augmenter = null
[training]
seed = ${system.seed}
gpu_allocator = ${system.gpu_allocator}
dropout = 0.1
accumulate_gradient = 1
patience = 1600
max_epochs = 0
max_steps = 20000
eval_frequency = 200
frozen_components = []
annotating_components = []
dev_corpus = "corpora.dev"
train_corpus = "corpora.train"
before_to_disk = null
[training.batcher]
@batchers = "spacy.batch_by_words.v1"
discard_oversize = false
tolerance = 0.2
get_length = null
[training.batcher.size]
@schedules = "compounding.v1"
start = 100
stop = 1000
compound = 1.001
t = 0.0
[training.logger]
@loggers = "spacy.ConsoleLogger.v1"
progress_bar = false
[training.optimizer]
@optimizers = "Adam.v1"
beta1 = 0.9
beta2 = 0.999
L2_is_weight_decay = true
L2 = 0.01
grad_clip = 1.0
use_averages = false
eps = 0.00000001
learn_rate = 0.001
[training.score_weights]
ents_f = 1.0
ents_p = 0.0
ents_r = 0.0
ents_per_type = null
[pretraining]
[initialize]
vectors = ${paths.vectors}
init_tok2vec = ${paths.init_tok2vec}
vocab_data = null
lookups = null
before_init = null
after_init = null
[initialize.components]
[initialize.tokenizer]

View file

@ -0,0 +1,38 @@
{
"lang":"de",
"name":"pipeline",
"version":"0.0.0",
"spacy_version":">=3.4.1,<3.5.0",
"description":"",
"author":"",
"email":"",
"url":"",
"license":"",
"spacy_git_version":"Unknown",
"vectors":{
"width":0,
"vectors":0,
"keys":0,
"name":null,
"mode":"default"
},
"labels":{
"ner":[
"cdtr.bic",
"cdtr.iban",
"cdtr.name",
"invoice.date",
"invoice.number",
"invoice.total"
]
},
"pipeline":[
"ner"
],
"components":[
"ner"
],
"disabled":[
]
}

View file

@ -0,0 +1,13 @@
{
"moves":null,
"update_with_oracle_cut_size":100,
"multitasks":[
],
"min_action_freq":1,
"learn_tokens":false,
"beam_width":1,
"beam_density":0.0,
"beam_update_prob":0.0,
"incorrect_spans_key":null
}

Binary file not shown.

View file

@ -0,0 +1 @@
¥movesÚÄ{"0":{},"1":{"invoice.total":-1,"invoice.number":-2,"cdtr.name":-3,"invoice.date":-4,"cdtr.iban":-5,"cdtr.bic":-6},"2":{"invoice.total":-1,"invoice.number":-2,"cdtr.name":-3,"invoice.date":-4,"cdtr.iban":-5,"cdtr.bic":-6},"3":{"invoice.total":-1,"invoice.number":-2,"cdtr.name":-3,"invoice.date":-4,"cdtr.iban":-5,"cdtr.bic":-6},"4":{"":1,"invoice.total":-1,"invoice.number":-2,"cdtr.name":-3,"invoice.date":-4,"cdtr.iban":-5,"cdtr.bic":-6},"5":{"":1}}£cfg<66>§neg_keyÀ

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1 @@
<EFBFBD>

View file

@ -0,0 +1 @@
<EFBFBD>

File diff suppressed because it is too large Load diff

Binary file not shown.

View file

@ -0,0 +1,3 @@
{
"mode":"default"
}

View file

@ -0,0 +1,127 @@
[paths]
train = null
dev = null
vectors = null
init_tok2vec = null
[system]
seed = 0
gpu_allocator = null
[nlp]
lang = "de"
pipeline = ["ner"]
disabled = []
before_creation = null
after_creation = null
after_pipeline_creation = null
batch_size = 1000
tokenizer = {"@tokenizers":"spacy.Tokenizer.v1"}
[components]
[components.ner]
factory = "ner"
incorrect_spans_key = null
moves = null
update_with_oracle_cut_size = 100
[components.ner.model]
@architectures = "spacy.TransitionBasedParser.v2"
state_type = "ner"
extra_state_tokens = false
hidden_width = 64
maxout_pieces = 2
use_upper = true
nO = null
[components.ner.model.tok2vec]
@architectures = "spacy.HashEmbedCNN.v2"
pretrained_vectors = null
width = 96
depth = 4
embed_size = 2000
window_size = 1
maxout_pieces = 3
subword_features = true
[corpora]
[corpora.dev]
@readers = "spacy.Corpus.v1"
path = ${paths.dev}
gold_preproc = false
max_length = 0
limit = 0
augmenter = null
[corpora.train]
@readers = "spacy.Corpus.v1"
path = ${paths.train}
gold_preproc = false
max_length = 0
limit = 0
augmenter = null
[training]
seed = ${system.seed}
gpu_allocator = ${system.gpu_allocator}
dropout = 0.1
accumulate_gradient = 1
patience = 1600
max_epochs = 0
max_steps = 20000
eval_frequency = 200
frozen_components = []
annotating_components = []
dev_corpus = "corpora.dev"
train_corpus = "corpora.train"
before_to_disk = null
[training.batcher]
@batchers = "spacy.batch_by_words.v1"
discard_oversize = false
tolerance = 0.2
get_length = null
[training.batcher.size]
@schedules = "compounding.v1"
start = 100
stop = 1000
compound = 1.001
t = 0.0
[training.logger]
@loggers = "spacy.ConsoleLogger.v1"
progress_bar = false
[training.optimizer]
@optimizers = "Adam.v1"
beta1 = 0.9
beta2 = 0.999
L2_is_weight_decay = true
L2 = 0.01
grad_clip = 1.0
use_averages = false
eps = 0.00000001
learn_rate = 0.001
[training.score_weights]
ents_f = 1.0
ents_p = 0.0
ents_r = 0.0
ents_per_type = null
[pretraining]
[initialize]
vectors = ${paths.vectors}
init_tok2vec = ${paths.init_tok2vec}
vocab_data = null
lookups = null
before_init = null
after_init = null
[initialize.components]
[initialize.tokenizer]

View file

@ -0,0 +1,40 @@
{
"lang":"de",
"name":"pipeline",
"version":"0.0.0",
"spacy_version":">=3.1.1,<3.2.0",
"description":"",
"author":"",
"email":"",
"url":"",
"license":"",
"spacy_git_version":"ffaead8fe",
"vectors":{
"width":0,
"vectors":0,
"keys":0,
"name":null
},
"labels":{
"ner":[
"cdtr.bic",
"cdtr.iban",
"cdtr.name",
"invoice.date",
"invoice.number",
"invoice.total"
]
},
"pipeline":[
"ner"
],
"components":[
"ner"
],
"disabled":[
],
"_sourced_vectors_hashes":{
}
}

View file

@ -0,0 +1,13 @@
{
"moves":null,
"update_with_oracle_cut_size":100,
"multitasks":[
],
"min_action_freq":1,
"learn_tokens":false,
"beam_width":1,
"beam_density":0.0,
"beam_update_prob":0.0,
"incorrect_spans_key":null
}

Binary file not shown.

View file

@ -0,0 +1 @@
¥movesÚÄ{"0":{},"1":{"cdtr.name":-1,"cdtr.iban":-2,"cdtr.bic":-3,"invoice.total":-4,"invoice.date":-5,"invoice.number":-6},"2":{"cdtr.name":-1,"cdtr.iban":-2,"cdtr.bic":-3,"invoice.total":-4,"invoice.date":-5,"invoice.number":-6},"3":{"cdtr.name":-1,"cdtr.iban":-2,"cdtr.bic":-3,"invoice.total":-4,"invoice.date":-5,"invoice.number":-6},"4":{"":1,"cdtr.name":-1,"cdtr.iban":-2,"cdtr.bic":-3,"invoice.total":-4,"invoice.date":-5,"invoice.number":-6},"5":{"":1}}£cfg<66>§neg_keyÀ

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1 @@
<EFBFBD>

View file

@ -0,0 +1 @@
<EFBFBD>

File diff suppressed because it is too large Load diff

Binary file not shown.

View file

@ -0,0 +1,128 @@
[paths]
train = null
dev = null
vectors = null
init_tok2vec = null
[system]
seed = 0
gpu_allocator = null
[nlp]
lang = "de"
pipeline = ["ner"]
disabled = []
before_creation = null
after_creation = null
after_pipeline_creation = null
batch_size = 1000
tokenizer = {"@tokenizers":"spacy.Tokenizer.v1"}
[components]
[components.ner]
factory = "ner"
incorrect_spans_key = null
moves = null
scorer = {"@scorers":"spacy.ner_scorer.v1"}
update_with_oracle_cut_size = 100
[components.ner.model]
@architectures = "spacy.TransitionBasedParser.v2"
state_type = "ner"
extra_state_tokens = false
hidden_width = 64
maxout_pieces = 2
use_upper = true
nO = null
[components.ner.model.tok2vec]
@architectures = "spacy.HashEmbedCNN.v2"
pretrained_vectors = null
width = 96
depth = 4
embed_size = 2000
window_size = 1
maxout_pieces = 3
subword_features = true
[corpora]
[corpora.dev]
@readers = "spacy.Corpus.v1"
path = ${paths.dev}
gold_preproc = false
max_length = 0
limit = 0
augmenter = null
[corpora.train]
@readers = "spacy.Corpus.v1"
path = ${paths.train}
gold_preproc = false
max_length = 0
limit = 0
augmenter = null
[training]
seed = ${system.seed}
gpu_allocator = ${system.gpu_allocator}
dropout = 0.1
accumulate_gradient = 1
patience = 1600
max_epochs = 0
max_steps = 20000
eval_frequency = 200
frozen_components = []
annotating_components = []
dev_corpus = "corpora.dev"
train_corpus = "corpora.train"
before_to_disk = null
[training.batcher]
@batchers = "spacy.batch_by_words.v1"
discard_oversize = false
tolerance = 0.2
get_length = null
[training.batcher.size]
@schedules = "compounding.v1"
start = 100
stop = 1000
compound = 1.001
t = 0.0
[training.logger]
@loggers = "spacy.ConsoleLogger.v1"
progress_bar = false
[training.optimizer]
@optimizers = "Adam.v1"
beta1 = 0.9
beta2 = 0.999
L2_is_weight_decay = true
L2 = 0.01
grad_clip = 1.0
use_averages = false
eps = 0.00000001
learn_rate = 0.001
[training.score_weights]
ents_f = 1.0
ents_p = 0.0
ents_r = 0.0
ents_per_type = null
[pretraining]
[initialize]
vectors = ${paths.vectors}
init_tok2vec = ${paths.init_tok2vec}
vocab_data = null
lookups = null
before_init = null
after_init = null
[initialize.components]
[initialize.tokenizer]

View file

@ -0,0 +1,38 @@
{
"lang":"de",
"name":"pipeline",
"version":"0.0.0",
"spacy_version":">=3.4.1,<3.5.0",
"description":"",
"author":"",
"email":"",
"url":"",
"license":"",
"spacy_git_version":"Unknown",
"vectors":{
"width":0,
"vectors":0,
"keys":0,
"name":null,
"mode":"default"
},
"labels":{
"ner":[
"cdtr.bic",
"cdtr.iban",
"cdtr.name",
"invoice.date",
"invoice.number",
"invoice.total"
]
},
"pipeline":[
"ner"
],
"components":[
"ner"
],
"disabled":[
]
}

View file

@ -0,0 +1,13 @@
{
"moves":null,
"update_with_oracle_cut_size":100,
"multitasks":[
],
"min_action_freq":1,
"learn_tokens":false,
"beam_width":1,
"beam_density":0.0,
"beam_update_prob":0.0,
"incorrect_spans_key":null
}

Binary file not shown.

View file

@ -0,0 +1 @@
¥movesÚÄ{"0":{},"1":{"invoice.total":-1,"invoice.number":-2,"invoice.date":-3,"cdtr.name":-4,"cdtr.iban":-5,"cdtr.bic":-6},"2":{"invoice.total":-1,"invoice.number":-2,"invoice.date":-3,"cdtr.name":-4,"cdtr.iban":-5,"cdtr.bic":-6},"3":{"invoice.total":-1,"invoice.number":-2,"invoice.date":-3,"cdtr.name":-4,"cdtr.iban":-5,"cdtr.bic":-6},"4":{"":1,"invoice.total":-1,"invoice.number":-2,"invoice.date":-3,"cdtr.name":-4,"cdtr.iban":-5,"cdtr.bic":-6},"5":{"":1}}£cfg<66>§neg_keyÀ

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1 @@
<EFBFBD>

View file

@ -0,0 +1 @@
<EFBFBD>

File diff suppressed because it is too large Load diff

Binary file not shown.

View file

@ -0,0 +1,3 @@
{
"mode":"default"
}

44
models/model-analyze-prod.xml Executable file
View file

@ -0,0 +1,44 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<document xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<!-- Workflow Instance -->
<item name="workflow.endpoint"><value xsi:type="xs:string">https://alexander-logistics.office-workflow.de/api/</value></item>
<item name="workflow.userid"><value xsi:type="xs:string">admin</value></item>
<item name="workflow.password"><value xsi:type="xs:string">imixs4.null</value></item>
<!-- -->
<item name="workflow.query"><value xsi:type="xs:string">($workflowgroup:"Rechnungseingang" OR $workflowgroup:"Sachrechnung") AND ($taskid:5900)</value></item>
<item name="workflow.pagesize"><value xsi:type="xs:int">100</value></item>
<item name="workflow.pageindex"><value xsi:type="xs:int">30</value></item>
<item name="workflow.entities">
<value xsi:type="xs:string">cdtr.name</value>
<value xsi:type="xs:string">cdtr.iban</value>
<value xsi:type="xs:string">cdtr.bic</value>
<value xsi:type="xs:string">invoice.total</value>
<value xsi:type="xs:string">invoice.date</value>
<value xsi:type="xs:string">invoice.number</value>
</item>
<item name="workflow.locale">
<value xsi:type="xs:string">en_GB</value>
<value xsi:type="xs:string">en_US</value>
<value xsi:type="xs:string">de_DE</value>
</item>
<!-- Tika OCR Server -->
<item name="tika.ocrmode"><value xsi:type="xs:string">OCR_ONLY</value></item>
<item name="tika.options">
<value xsi:type="xs:string">X-Tika-OCRLanguage=eng+deu</value>
<value xsi:type="xs:string">X-Tika-PDFocrStrategy=OCR_ONLY</value>
</item>
<!-- ML spaCy Server -->
<item name="ml.validation.endpoint"><value xsi:type="xs:string">http://imixs-ml-spacy:8000/</value></item>
<item name="ml.validation.model"><value xsi:type="xs:string">invoice-de-0.1.0</value></item>
<item name="ml.validation.filepattern"><value xsi:type="xs:string">.pdf|.PDF</value></item>
</document>

53
models/model-train-prod.xml Executable file
View file

@ -0,0 +1,53 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<document xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<!-- Workflow Instance -->
<item name="workflow.endpoint"><value xsi:type="xs:string">https://alexander-logistics.office-workflow.de/api/</value></item>
<item name="workflow.userid"><value xsi:type="xs:string">admin</value></item>
<item name="workflow.password"><value xsi:type="xs:string">imixs4.null</value></item>
<item name="workflow.entities">
<value xsi:type="xs:string">cdtr.name</value>
<value xsi:type="xs:string">cdtr.iban</value>
<value xsi:type="xs:string">cdtr.bic</value>
<value xsi:type="xs:string">invoice.total</value>
<value xsi:type="xs:string">invoice.date</value>
<value xsi:type="xs:string">invoice.number</value>
</item>
<item name="workflow.locale">
<value xsi:type="xs:string">en_GB</value>
<value xsi:type="xs:string">en_US</value>
<value xsi:type="xs:string">de_DE</value>
</item>
<!-- Tika OCR Server -->
<item name="tika.ocrmode"><value xsi:type="xs:string">OCR_ONLY</value></item>
<item name="tika.options">
<value xsi:type="xs:string">X-Tika-OCRLanguage=eng+deu</value>
<value xsi:type="xs:string">X-Tika-PDFocrStrategy=OCR_ONLY</value>
</item>
<!-- ML spaCy Server -->
<item name="ml.training.endpoint"><value xsi:type="xs:string">http://imixs-ml-spacy:8000/</value></item>
<item name="ml.training.model"><value xsi:type="xs:string">invoice-de-0.2.0</value></item>
<item name="ml.training.filepattern"><value xsi:type="xs:string">.pdf|.PDF</value></item>
<!-- LOW | GOOD -->
<item name="ml.training.quality"><value xsi:type="xs:string">LOW</value></item>
<!-- Define the training set and taining mode -->
<item name="workflow.query"><value xsi:type="xs:string">($workflowgroup:"Rechnungseingang" OR $workflowgroup:"Sachrechnung") AND ($taskid:5900)</value></item>
<item name="workflow.pagesize"><value xsi:type="xs:int">1000</value></item>
<item name="workflow.pageindex"><value xsi:type="xs:int">0</value></item>
<item name="ml.training.iterations"><value xsi:type="xs:string">5</value></item>
<item name="ml.training.dropoutrate"><value xsi:type="xs:string">0.0</value></item>
<item name="ml.options">
<value xsi:type="xs:string">min_losses=0.0&amp;retrain_rate=100</value>
</item>
</document>

48
models/model-valiate-prod.xml Executable file
View file

@ -0,0 +1,48 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<document xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<!-- Workflow Instance -->
<item name="workflow.endpoint"><value xsi:type="xs:string">https://alexander-logistics.office-workflow.de/api/</value></item>
<item name="workflow.userid"><value xsi:type="xs:string">admin</value></item>
<item name="workflow.password"><value xsi:type="xs:string">imixs4.null</value></item>
<item name="workflow.entities">
<value xsi:type="xs:string">cdtr.name</value>
<value xsi:type="xs:string">cdtr.iban</value>
<value xsi:type="xs:string">cdtr.bic</value>
<value xsi:type="xs:string">invoice.total</value>
<value xsi:type="xs:string">invoice.date</value>
<value xsi:type="xs:string">invoice.number</value>
</item>
<item name="workflow.locale">
<value xsi:type="xs:string">en_GB</value>
<value xsi:type="xs:string">en_US</value>
<value xsi:type="xs:string">de_DE</value>
</item>
<!-- Tika OCR Server -->
<item name="tika.ocrmode"><value xsi:type="xs:string">OCR_ONLY</value></item>
<item name="tika.options">
<value xsi:type="xs:string">X-Tika-OCRLanguage=eng+deu</value>
<value xsi:type="xs:string">X-Tika-PDFocrStrategy=OCR_ONLY</value>
</item>
<!-- ML spaCy Server -->
<item name="ml.training.endpoint"><value xsi:type="xs:string">http://imixs-ml-spacy:8000/</value></item>
<item name="ml.training.model"><value xsi:type="xs:string">invoice-de-0.2.0</value></item>
<item name="ml.training.filepattern"><value xsi:type="xs:string">.pdf|.PDF</value></item>
<!-- LOW | GOOD -->
<item name="ml.training.quality"><value xsi:type="xs:string">LOW</value></item>
<!-- Define the training set and taining mode -->
<item name="workflow.query"><value xsi:type="xs:string">($workflowgroup:"Rechnungseingang" OR $workflowgroup:"Sachrechnung") AND ($taskid:5900)</value></item>
<item name="workflow.pagesize"><value xsi:type="xs:int">100</value></item>
<item name="workflow.pageindex"><value xsi:type="xs:int">40</value></item>
</document>

View file

@ -0,0 +1 @@
/target/

View file

@ -0,0 +1,395 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>office-alexander-logistics</artifactId>
<groupId>com.alexander-logistics</groupId>
<version>1.3.0</version>
</parent>
<artifactId>office-alexander-logistics-app</artifactId>
<packaging>war</packaging>
<name>Imixs Office Workflow App</name>
<profiles>
<profile>
<id>docker</id>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.8</version>
<executions>
<execution>
<phase>install</phase>
<configuration>
<target>
<exec executable="docker">
<arg value="build" />
<arg value="-t" />
<arg value="imixs/${imixs-office.applicationname}" />
<arg value="../." />
</exec>
</target>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
<profile>
<id>debug</id>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.8</version>
<executions>
<execution>
<phase>install</phase>
<configuration>
<target>
<exec executable="docker">
<arg value="build" />
<arg value="-f" />
<arg value="../Dockerfile-wildfly-debug" />
<arg value="-t" />
<arg value="imixs/${imixs-office.applicationname}" />
<arg value="../." />
</exec>
</target>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
<profile>
<id>kubernetes</id>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.8</version>
<executions>
<execution>
<phase>install</phase>
<configuration>
<target>
<exec executable="docker">
<arg value="build" />
<arg value="-t" />
<arg
value="imixs/${imixs-office.applicationname}:${project.version}" />
<arg value="../." />
</exec>
<exec executable="docker">
<arg value="tag" />
<arg
value="imixs/${imixs-office.applicationname}:${project.version}" />
<arg
value="${org.imixs.kubernetes.registry}/imixs/${imixs-office.applicationname}:${project.version}" />
</exec>
<exec executable="docker">
<arg value="push" />
<arg
value="${org.imixs.kubernetes.registry}/imixs/${imixs-office.applicationname}:${project.version}" />
</exec>
</target>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
<build>
<testResources>
<testResource>
<directory>${basedir}/../reports</directory>
</testResource>
<testResource>
<directory>${basedir}/src/test/resources</directory>
</testResource>
</testResources>
<plugins>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>3.3.2</version>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
<webResources>
<resource>
<filtering>true</filtering>
<!-- this is relative to the pom.xml directory -->
<directory>${custom.webResources}</directory>
<includes>
<include>**/WEB-INF/*</include>
<!-- include any other file types you want to filter -->
</includes>
</resource>
</webResources>
<workDirectory>target/overlay-war-folder</workDirectory>
<!-- We exclude libs form the parent WAR artifact -->
<overlays>
<overlay>
<groupId>org.imixs.workflow</groupId>
<artifactId>imixs-office-workflow-app</artifactId>
<excludes>
<exclude>WEB-INF/lib/*.jar</exclude>
</excludes>
</overlay>
</overlays>
</configuration>
</plugin>
<plugin>
<groupId>org.imixs.maven</groupId>
<artifactId>manik-hotdeploy-maven-plugin</artifactId>
<version>2.0.0</version>
<executions>
<execution>
<phase>install</phase>
<goals>
<goal>deploy</goal>
</goals>
</execution>
</executions>
<configuration>
<!-- List Source and Target folders for Autodeploy and Hotdeploy -->
<autodeployments>
<deployment>
<!-- wildcard deployment -->
<source>target/*.{war,ear,jar}</source>
<target>../docker/deployments/</target>
<unpack>true</unpack>
</deployment>
</autodeployments>
<hotdeployments>
<deployment>
<source>src/main/webapp</source>
<target>../docker/deployments/office-alexander-logistics.war</target>
</deployment>
</hotdeployments>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<!-- Imixs Workflow -->
<dependency>
<groupId>org.imixs.workflow</groupId>
<artifactId>imixs-workflow-core</artifactId>
<type>jar</type>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.imixs.workflow</groupId>
<artifactId>imixs-workflow-engine</artifactId>
<type>jar</type>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.imixs.workflow</groupId>
<artifactId>imixs-workflow-jax-rs</artifactId>
<type>jar</type>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.imixs.workflow</groupId>
<artifactId>imixs-workflow-faces</artifactId>
<type>jar</type>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.imixs.workflow</groupId>
<artifactId>imixs-workflow-index-lucene</artifactId>
<scope>compile</scope>
</dependency>
<!-- Marty -->
<dependency>
<groupId>org.imixs.workflow</groupId>
<artifactId>imixs-marty</artifactId>
<type>jar</type>
<scope>compile</scope>
</dependency>
<!-- Imixs-Office-Workflow -->
<dependency>
<groupId>org.imixs.workflow</groupId>
<artifactId>imixs-office-workflow-app</artifactId>
<type>war</type>
</dependency>
<dependency>
<groupId>org.imixs.workflow</groupId>
<artifactId>imixs-office-workflow-util</artifactId>
<scope>compile</scope>
</dependency>
<!-- Imixs-Archive -->
<dependency>
<groupId>org.imixs.workflow</groupId>
<artifactId>imixs-archive-api</artifactId>
<scope>compile</scope>
</dependency>
<!-- Imixs-Archive Documents -->
<dependency>
<groupId>org.imixs.workflow</groupId>
<artifactId>imixs-archive-documents</artifactId>
<scope>compile</scope>
</dependency>
<!-- Imixs-Archive Importer -->
<dependency>
<groupId>org.imixs.workflow</groupId>
<artifactId>imixs-archive-importer</artifactId>
<scope>compile</scope>
</dependency>
<!-- SEPA Adapter -->
<dependency>
<groupId>org.imixs.workflow</groupId>
<artifactId>imixs-adapters-sepa</artifactId>
<scope>compile</scope>
</dependency>
<!-- DATEV Adapter -->
<dependency>
<groupId>org.imixs.workflow</groupId>
<artifactId>imixs-adapters-datev</artifactId>
<scope>compile</scope>
</dependency>
<!-- QR Code -->
<dependency>
<groupId>org.imixs.workflow</groupId>
<artifactId>imixs-adapters-qrcode</artifactId>
<scope>compile</scope>
</dependency>
<!-- POI Adapter -->
<dependency>
<groupId>org.imixs.workflow</groupId>
<artifactId>imixs-adapters-poi</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.imixs.workflow</groupId>
<artifactId>imixs-ai-workflow</artifactId>
<version>${org.imixs.ai.version}</version>
<scope>compile</scope>
</dependency>
<!-- xsl 2.0 support for Reporting / Chart Diagrams -->
<dependency>
<groupId>net.sf.saxon</groupId>
<artifactId>Saxon-HE</artifactId>
</dependency>
<!-- Apache PDFBox -->
<dependency>
<groupId>org.apache.pdfbox</groupId>
<artifactId>pdfbox</artifactId>
<version>${apache.pdfbox.version}</version>
<scope>compile</scope>
</dependency>
<!-- Apache Commons FTP Client -->
<dependency>
<groupId>commons-net</groupId>
<artifactId>commons-net</artifactId>
<version>3.6</version>
</dependency>
<!-- Microsoft oauth token -->
<dependency>
<groupId>com.sun.mail</groupId>
<artifactId>javax.mail</artifactId>
<version>1.6.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.10</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.13.3</version>
<scope>test</scope>
</dependency>
<!-- JUnit Tests
<dependency>
<groupId>javax.json</groupId>
<artifactId>javax.json-api</artifactId>
<version>1.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.glassfish</groupId>
<artifactId>javax.json</artifactId>
<version>1.1</version>
<scope>test</scope>
</dependency>
-->
<!-- JAX-RS 2.0 Test dependencies -->
<dependency>
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-client</artifactId>
<version>3.1.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-rs-client</artifactId>
<version>3.3.6</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.inject</groupId>
<artifactId>jersey-hk2</artifactId>
<version>3.1.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>jakarta.ws.rs</groupId>
<artifactId>jakarta.ws.rs-api</artifactId>
<version>3.1.0</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View file

@ -0,0 +1,636 @@
package com.alexanderlogistics;
import java.io.Serializable;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.text.ParseException;
import java.time.LocalDate;
import java.time.YearMonth;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.logging.Logger;
import java.util.stream.Collectors;
import org.imixs.marty.team.TeamService;
import org.imixs.workflow.ItemCollection;
import org.imixs.workflow.engine.DocumentService;
import org.imixs.workflow.exceptions.QueryException;
import org.imixs.workflow.faces.data.WorkflowController;
import org.imixs.workflow.office.forms.AnalyticController;
import org.imixs.workflow.office.forms.AnalyticEvent;
import jakarta.enterprise.context.ConversationScoped;
import jakarta.enterprise.event.Observes;
import jakarta.inject.Inject;
import jakarta.inject.Named;
/**
* Der AGLAnalyticControllerDebitor berechnet verschiedene Analyse Daten von
* Ausgangsrechnungen
*
* @author rsoika
*
*/
@Named
@ConversationScoped
public class AGLAnalyticControllerDebitor implements Serializable {
private static final long serialVersionUID = 1L;
private static Logger logger = Logger.getLogger(AnalyticController.class.getName());
@Inject
protected DocumentService documentService;
@Inject
protected AGLConfigController aglConfigController;
@Inject
protected WorkflowController workflowController;
@Inject
TeamService teamService;
TreeMap<String, DebitorStatistikData> stats = null;
List<ItemCollection> invoices = null;
int countAll = 0;
int countOpen = 0;
int countDue = 0;
int countDunning = 0;
double totalAllCurrency1 = 0;
double totalAllCurrency2 = 0;
double totalOpenCurrency1 = 0;
double totalOpenCurrency2 = 0;
double totalDueCurrency1 = 0;
double totalDueCurrency2 = 0;
double totalDunningCurrency1 = 0;
double totalDunningCurrency2 = 0;
double averagePaymentDue = 0;
double averagePaymentDays = 0;
String chartData = "";
public void onEvent(@Observes AnalyticEvent event) {
if (!"workitem".equals(event.getWorkitem().getType())) {
// no op
return;
}
String dbtrNumber = event.getWorkitem().getItemValueString("dbtr.number");
String dbtrNumberLast = event.getWorkitem().getItemValueString("dbtr.number.last");
// Recompute only if last dbtr.number has changed or no values yet computed
// load all invoices?
if (invoices == null || (!dbtrNumber.isEmpty() && !dbtrNumber.equals(dbtrNumberLast))) {
resetStats();
event.getWorkitem().setItemValue("dbtr.number.last", dbtrNumber);
logger.info("Analyse new debitor data for : " + dbtrNumber);
loadRechnungen();
chartData = buildChartData();
}
String link = "/pages/workitems/worklist.xhtml" + "?phrase=" + getDbtNr();
logger.fine("process ref=" + workflowController.getWorkitem().getItemValueString("process.ref"));
ItemCollection process = documentService
.load(workflowController.getWorkitem().getItemValueString("process.ref"));
if (process != null) {
link = link + "&processref=" + process.getUniqueID()
+ "&phrase=" + getDbtNr();
}
if ("analytic.invoices.count.all".equals(event.getKey())) {
event.setValue("" + countAll);
event.setLabel(formatTotals(totalAllCurrency1, totalAllCurrency2));
event.setDescription("Total invoices");
event.getWorkitem().setItemValue("invoices.total", event.getValue());
event.setLink(link);
}
if ("analytic.invoices.count.open".equals(event.getKey())) {
event.setValue("" + countOpen);
event.setLabel(formatTotals(totalOpenCurrency1, totalOpenCurrency2));
event.setDescription("Total invoices not yet in due");
event.getWorkitem().setItemValue("invoices.total.open", event.getValue());
event.setLink(link);
}
if ("analytic.invoices.count.due".equals(event.getKey())) {
event.setValue("" + countDue);
event.setLabel(formatTotals(totalDueCurrency1, totalDueCurrency2));
event.setDescription("Total invoices in due");
event.getWorkitem().setItemValue("invoices.total.due", event.getValue());
event.setLink(link);
}
if ("analytic.invoices.count.dunning".equals(event.getKey())) {
event.setValue("" + countDunning);
event.setLabel(formatTotals(totalDunningCurrency1, totalDunningCurrency2));
event.setDescription("Total invoices in dunning");
event.getWorkitem().setItemValue("invoices.total.dunning", event.getValue());
event.setLink(link);
}
if ("analytic.payment.avg.due".equals(event.getKey())) {
event.setValue("" + averagePaymentDue);
event.setLabel("days");
event.setDescription("Average terms of credit in the last 12 months.");
event.getWorkitem().setItemValue("payment.avg.due", event.getValue());
event.setLink(link);
}
if ("analytic.payment.avg.days".equals(event.getKey())) {
event.setValue("" + averagePaymentDays);
event.setLabel("days");
event.setDescription("Average duration for payment during the last 12 months.");
event.getWorkitem().setItemValue("payment.avg.days", event.getValue());
event.setLink(link);
}
if ("analytic.invoices.trend".equals(event.getKey())) {
event.setValue(chartData);
event.setLabel("Payment duration in days");
event.setDescription("Payment practice by week");
}
}
/**
* Formatiert zwei währungen untereinander
*
* @param totalCurrency1
* @param totalCurrency2
* @return
*/
private String formatTotals(double totalCurrency1, double totalCurrency2) {
List<String> currencies = aglConfigController.getWorkitem().getItemValueList("currency.out", String.class);
if (currencies.size() < 2) {
currencies.add(currencies.get(0));
}
String label = "<span class=\"pull-right\">" + formatCurrency(totalCurrency1) + " " + currencies.get(0)
+ "</span>";
label = label + "</br><span class=\"pull-right\">" +
formatCurrency(totalCurrency2) + " " + currencies.get(1) + "</span>";
return label;
}
private void loadRechnungen() {
if (getDbtNr().isEmpty()) {
invoices = new ArrayList();
stats = null;
} else {
logger.info(" ├──load invoices for " + getDbtNr() + "....");
String query = "(type:workitem) AND dbtr.number:" + getDbtNr()
+ " AND $modelversion:rechnungsausgang-*";
try {
logger.info(" ├──refresh invoice stats for " + getDbtNr() + "....");
invoices = documentService.find(query, 999, 0, "$created", false);
calculateStats();
} catch (QueryException e) {
logger.warning("Failed to query invoices: " + query + " - Error: " + e.getMessage());
invoices = new ArrayList();
}
}
}
/**
* Läd die statistik daten zu einem debitor aus den aktuellen Rechnungen
*/
private void calculateStats() {
countAll = 0;
countOpen = 0;
countDue = 0;
countDunning = 0;
logger.info(" ├──calculate stats for " + getDbtNr() + "....");
// do we have data?
if (invoices != null && invoices.size() > 0) {
countAll = invoices.size();
for (ItemCollection invoice : invoices) {
// währung 1 oder 2?
if (invoice.getItemValueDouble("invoice.rate") == 0) {
totalAllCurrency1 = totalAllCurrency1 + invoice.getItemValueDouble("invoice.saldo");
} else {
totalAllCurrency2 = totalAllCurrency2 + invoice.getItemValueDouble("invoice.saldo");
}
int task = invoice.getTaskID();
// Open
if (task >= 5000 && task <= 5099) {
countOpen++;
// währung 1 oder 2?
if (invoice.getItemValueDouble("invoice.rate") == 0) {
totalOpenCurrency1 = totalOpenCurrency1 + invoice.getItemValueDouble("invoice.saldo");
} else {
totalOpenCurrency2 = totalOpenCurrency2 + invoice.getItemValueDouble("invoice.saldo");
}
}
// Due
if (task >= 5100 && task <= 5199) {
countDue++;
// währung 1 oder 2?
if (invoice.getItemValueDouble("invoice.rate") == 0) {
totalDueCurrency1 = totalDueCurrency1 + invoice.getItemValueDouble("invoice.saldo");
} else {
totalDueCurrency2 = totalDueCurrency2 + invoice.getItemValueDouble("invoice.saldo");
}
}
// Dunning
if (task >= 5200) {
countDunning++;
// währung 1 oder 2?
if (invoice.getItemValueDouble("invoice.rate") == 0) {
totalDunningCurrency1 = totalDunningCurrency1 + invoice.getItemValueDouble("invoice.saldo");
} else {
totalDunningCurrency2 = totalDunningCurrency2 + invoice.getItemValueDouble("invoice.saldo");
}
}
}
totalAllCurrency1 = InvoiceUtil.round(totalAllCurrency1);
totalAllCurrency2 = InvoiceUtil.round(totalAllCurrency2);
totalOpenCurrency1 = InvoiceUtil.round(totalOpenCurrency1);
totalOpenCurrency2 = InvoiceUtil.round(totalOpenCurrency2);
totalDueCurrency1 = InvoiceUtil.round(totalDueCurrency1);
totalDueCurrency2 = InvoiceUtil.round(totalDueCurrency2);
totalDunningCurrency1 = InvoiceUtil.round(totalDunningCurrency1);
totalDunningCurrency2 = InvoiceUtil.round(totalDunningCurrency2);
} else {
// reset data because no invoices are available ...
resetStats();
}
}
/**
* Setzt alle Statistikwerte zurück
*/
private void resetStats() {
logger.info(" ├──reset stats for " + getDbtNr() + "....");
stats = null;
totalAllCurrency1 = 0;
totalAllCurrency2 = 0;
totalOpenCurrency1 = 0;
totalOpenCurrency2 = 0;
totalDueCurrency1 = 0;
totalDueCurrency2 = 0;
totalDunningCurrency1 = 0;
totalDunningCurrency2 = 0;
// chartData = null;
chartData = "{}";
averagePaymentDue = 0;
averagePaymentDays = 0;
}
private void getDurchschnittZahlungsziel() {
if (stats == null) {
averagePaymentDue = 0;
return;
}
int count = 0;
long gesamt = 0;
for (Map.Entry<String, DebitorStatistikData> entry : stats.entrySet()) {
DebitorStatistikData statData = entry.getValue();
if (statData.count > 0) {
gesamt = gesamt + statData.getAverageDueDays();
count++;
}
}
averagePaymentDue = Math.round((double) gesamt / count);
}
private void getDurchschnittZahlungsdauer() {
if (stats == null) {
averagePaymentDays = 0;
return;
}
int count = 0;
long gesamt = 0;
for (Map.Entry<String, DebitorStatistikData> entry : stats.entrySet()) {
DebitorStatistikData statData = entry.getValue();
if (statData.count > 0) {
gesamt = gesamt + statData.getAveragePaymentDays();
count++;
}
}
averagePaymentDays = Math.round((double) gesamt / count);
}
private String formatCurrency(Double value) {
DecimalFormatSymbols symbols = new DecimalFormatSymbols(Locale.getDefault());
symbols.setGroupingSeparator('.');
symbols.setDecimalSeparator(',');
DecimalFormat formatter = new DecimalFormat("#,##0.00", symbols);
return formatter.format(value);
}
/**
* Hilfsmethode die das fuehrende K/D aus der Debitorennummer entfernt
*
* @return
*/
private String getDbtNr() {
String dbtNr = workflowController.getWorkitem().getItemValueString("dbtr.number");
if (dbtNr.startsWith("D") || dbtNr.startsWith("K")) {
dbtNr = dbtNr.substring(1);
}
return dbtNr;
}
/**
* Sucht alle Rechnugnen aus einem Zeitraum und sammelt Zahlungsziel und
* Zahlungszeitspanne gruppiert nach monaten
*
*/
public Map<String, DebitorStatistikData> loadStats() {
if (stats != null) {
return stats;
}
logger.info(" ├──load stats for " + getDbtNr() + "....");
// recompute
stats = new TreeMap<String, DebitorStatistikData>();
if (getDbtNr().isEmpty()) {
return stats;
}
// Letzen 12 Monate
LocalDate endDate = LocalDate.now();
LocalDate startDate = endDate.minusMonths(12);
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd");
String startDateStr = startDate.format(formatter);
String endDateStr = endDate.format(formatter);
String query = "(type:workitemarchive) AND "
+ " invoice.date:[" + startDateStr + " TO " + endDateStr + "] AND "
+ "dbtr.number:" + getDbtNr()
+ " AND $modelversion:rechnungsausgang-* AND ($taskid:[5900 TO 5999])";
logger.fine("query = " + query);
try {
List<ItemCollection> invoices = documentService
.findStubs(query, 9999, 0, "$created", false);
for (ItemCollection invoice : invoices) {
try {
logger.fine("Rechnung: " + invoice.getUniqueID());
Date invoiceDate = invoice.getItemValueDate("invoice.date");
Date invoiceDueDate = invoice.getItemValueDate("invoice.duedate");
Date paymentDate = findPaymentDateByWorkitem(invoice);
if (paymentDate == null) {
logger.fine("Es wurde kein Zahlungseingang gefunden");
continue;
}
if (invoiceDate != null && paymentDate != null && invoiceDueDate != null) {
// do we have a stats object?
DebitorStatistikData statData = stats.get(getYearMonth(invoiceDate));
if (statData == null) {
// create a new one
statData = new DebitorStatistikData(invoiceDate);
}
// jetzt irgendwas ausrechnen
statData.compute(invoiceDate, invoiceDueDate, paymentDate);
// .. und wieder speichern
stats.put(statData.toString(), statData);
} else {
logger.warning("No payment Date found for invoice " + invoice.getUniqueID());
}
} catch (ParseException e) {
logger.warning("Unable to parse payment Date for invoice " + invoice.getUniqueID());
}
}
} catch (QueryException e) {
logger.severe("Failed to get statistic: " + e.getMessage());
}
// Step 2: Sort the list based on the alphanumeric order of the keys
completeMissingMonths();
// berechne zahluntsziel durchscnitt
getDurchschnittZahlungsziel();
getDurchschnittZahlungsdauer();
return stats;
}
/**
* Finds the payment.date for a invoice.
*
* Wir suchen alle zugeordneten Zahlungseingägne und nehmen den letzten.
*
* WICHTIG: Es muss ggf. der index neu aufgebaut werden, da payment.date nun ein
* index feld ist
*
* @param invoice
* @return
* @throws ParseException
*/
public Date findPaymentDateByWorkitem(ItemCollection invoice) throws ParseException {
// Wir selektieren alle Zahlungseingänge interessieren uns aber nur für den
// letzten
String sQuery = " (type:\"workitem\" OR type:\"workitemarchive\") " + //
" AND ($modelversion:zahlungseingang-*) AND ($workitemref:\""
+ invoice.getUniqueID() + "\" )";
List<ItemCollection> workitems = null;
try {
workitems = documentService.findStubs(sQuery, 99, 0,
"payment.date", true);
if (workitems.size() > 0) {
return workitems.get(0).getItemValueDate("payment.date");
}
} catch (QueryException e) {
e.printStackTrace();
}
// no date found!
return null;
}
/**
* Diese Methode baut die Datenstruktur für das Chart Diagram zusammen
*
*
* <pre>
{
labels: ["January", "February", "March", "April", "May", "June", "July"],
datasets: [{
label: 'Dataset 1',
//backgroundColor: color(window.chartColors.red).alpha(0.5).rgbString(),
//borderColor: window.chartColors.red,
borderWidth: 1,
data: [
70, 70, 70, 70, 79, 50, 50
]
}, {
label: 'Dataset 2',
//backgroundColor: color(window.chartColors.blue).alpha(0.5).rgbString(),
//borderColor: window.chartColors.blue,
borderWidth: 1,
data: [
70, 70, 170, 7, 79, 50, 50
]
}]
}
* </pre>
*
* @return
*/
public String buildChartData() {
loadStats();
logger.info(" ├──build chart for " + getDbtNr() + "....");
// build a list of all lables....
List<String> statusLabels = new ArrayList<String>();
Set<String> keys = stats.keySet();
for (String _key : keys) {
statusLabels.add(_key);
}
String result = "{\n \"type\": \"bar\",\n \"data\": { ";
// Lables
result = result + "\"labels\" : [ ";
result = result + statusLabels.stream().collect(Collectors.joining("\",\"", "\"", "\""));
result = result + "],";
result = result + "\"datasets\": [";
// Datasets 1
result = result + "{\"label\": \"Days for payment\",\"borderWidth\": 1,";
result = result + " \"borderColor\": [\"#3B6B82\"],";
result = result + " \"backgroundColor\" : [\"#CFE9F5\"], \"fill\": true,\"tension\": 0.5,";
result = result + "\"data\": [";
for (Map.Entry<String, DebitorStatistikData> entry : stats.entrySet()) {
result = result + entry.getValue().getAverageDueDays() + ",";
}
// cut last comma
if (result.endsWith(",")) {
result = result.substring(0, result.length() - 1);
}
result = result + "]";
result = result + "}, ";
// Datasets 2
result = result + "{\"label\": \"Payment duration\",\"borderWidth\": 1,";
result = result
+ " \"borderColor\": [\"#E73B65\"],\"backgroundColor\" : [\"#70B088\" ], \"tension\": 0.5,\"fill\": true,";
result = result
+ " \"trendlineLinear\": { \"colorMin\": \"red\", \"colorMax\": \"green\", \"lineStyle\": \"dotted\", \"width\": 2 , \"projection\": true },";
result = result + "\"data\": [";
for (Map.Entry<String, DebitorStatistikData> entry : stats.entrySet()) {
result = result + entry.getValue().getAveragePaymentDays() + ",";
}
// cut last comma
if (result.endsWith(",")) {
result = result.substring(0, result.length() - 1);
}
result = result + "]";
result = result + "} ";
// ende
result = result + "] }";
result = result + "}";
return result;
}
/**
* Hilfsmethode ergänzt die fehlenden Monate
*
* @param yearMonths
* @return
*/
private void completeMissingMonths() {
if (stats == null || stats.size() < 3) {
return;
}
// Convert the list of strings to a list of LocalDate objects
List<LocalDate> dates = new ArrayList<>();
Set<String> yearMonths = this.stats.keySet();
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMM");
for (String yearMonth : yearMonths) {
dates.add(YearMonth.parse(yearMonth, formatter).atDay(1));
}
// Find the lowest and highest dates
LocalDate lowestDate = Collections.min(dates);
LocalDate highestDate = Collections.max(dates);
LocalDate current = lowestDate;
current = current.plusMonths(1);
while (!current.isAfter(highestDate)) {
// existiert der monat?
String formattedDate = current.format(formatter);
DebitorStatistikData entry = stats.get(formattedDate);
if (entry == null) {
// add missing entry
stats.put(formattedDate, new DebitorStatistikData(current.getYear(), current.getMonthValue()));
}
current = current.plusMonths(1);
}
}
/**
* returns
*
* 202304 from a given date
*/
public String getYearMonth(Date date) {
// Create a Calendar instance and set the date
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
// Get the year from the Calendar object
int year = calendar.get(Calendar.YEAR);
// Get the month from the Calendar object
int month = calendar.get(Calendar.MONTH);
// Increment the month by 1 since Calendar months are zero-based
month++;
// Convert the month to a String with leading "0" if necessary
return "" + year + (month < 10 ? "0" + month : "" + month);
}
}

View file

@ -0,0 +1,526 @@
package com.alexanderlogistics;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;
import org.imixs.marty.team.TeamService;
import org.imixs.workflow.ItemCollection;
import org.imixs.workflow.engine.DocumentService;
import org.imixs.workflow.exceptions.QueryException;
import org.imixs.workflow.faces.data.WorkflowController;
import org.imixs.workflow.office.forms.AnalyticController;
import org.imixs.workflow.office.forms.AnalyticEvent;
import jakarta.enterprise.context.RequestScoped;
import jakarta.enterprise.event.Observes;
import jakarta.inject.Inject;
import jakarta.inject.Named;
import jakarta.json.Json;
import jakarta.json.JsonArrayBuilder;
import jakarta.json.JsonObject;
import jakarta.json.JsonObjectBuilder;
/**
* Der AGLAnalyticController berechnet verschiedene Analyse Daten
*
* @author rsoika
*
*/
@Named
@RequestScoped
public class AGLAnalyticControllerSteuer implements Serializable {
private static final long serialVersionUID = 1L;
private static Logger logger = Logger.getLogger(AnalyticController.class.getName());
@Inject
protected DocumentService documentService;
@Inject
TeamService teamService;
@Inject
protected WorkflowController workflowController;
@Inject
protected DebitorStatistikController debitorStatistikController;
List<ItemCollection> steuerbescheide = null;
public void onEvent(@Observes AnalyticEvent event) {
ItemCollection process = documentService
.load(workflowController.getWorkitem().getItemValueString("process.ref"));
String link = "/pages/workitems/worklist.xhtml";
if (process != null) {
link = link + "?processref=" + process.getUniqueID()
+ "&workflowgroup=Steuerbescheid";
}
if ("analytic.steuer.eust".equals(event.getKey())) {
event.setValue(computeSteuerbescheideEUST());
event.setLabel("EUR");
event.setDescription("Gesamt Einfuhrumsatzsteuer (EUSt)");
event.getWorkitem().setItemValue("eust.total", event.getValue());
event.setLink(link);
}
if ("analytic.steuer.zoll".equals(event.getKey())) {
event.setValue(computeSteuerbescheideZoll());
event.setLabel("EUR");
event.setDescription("Gesamt Zölle (ZOLLEU)");
event.setLink(link);
}
if ("analytic.steuer.total".equals(event.getKey())) {
event.setValue(computeSteuerbescheideTotal());
event.setLabel("EUR");
event.setDescription("Alle Steuerbescheide die noch nicht abgerechnet wurden.");
event.setLink(link);
}
if ("analytic.steuer.saldo".equals(event.getKey())) {
event.setValue(computeSteuerbescheideSaldo());
event.setLabel("EUR");
event.setDescription("Saldo aller Steuerbescheide die noch nicht abgerechnet wurden.");
event.setLink(link);
}
if ("analytic.steuer.due".equals(event.getKey())) {
event.setValue(computeSteuerbescheideSaldoDue());
event.setLabel("EUR");
event.setDescription("Saldo aller überfälligen Steuerbescheide die noch nicht abgerechnet wurden.");
// event.setLink(link + "&task=Überfällig");
event.setLink(link + "&task=1200");
}
// Charts
if ("analytic.steuer.trend".equals(event.getKey())) {
event.setValue(accumulateSteuerbescheideByWeek());
event.setLabel("Zoll & EUST");
event.setDescription("Fälligkeiten nach KW");
}
if ("analytic.steuer.trend.abteilung".equals(event.getKey())) {
event.setValue(accumulateSteuerbescheideAbteilungByWeek());
event.setLabel("Nach Abteilungen");
event.setDescription("Offene Salden nach KW pro Abteilung");
}
}
/**
* Berechnet die Summe aller offenen EUST Beträge
* // tax.code=[0], amount=[3885.16], activity.type=[EUST],
* // filenumber=[LA-PAP-2408-024]}
*
* @return
*/
private double computeSteuerbescheideEUST() {
logger.fine("compute EUST...");
List<ItemCollection> list = getSteuerbescheide();
double result = 0;
for (ItemCollection steuerItemCol : list) {
result = result + getZollBySteuerBeleg(steuerItemCol, "EUST");
}
return InvoiceUtil.round(result);
}
/**
* Berechnet die Summe aller offenen Zoll Beträge
*
* @return
*/
private double computeSteuerbescheideZoll() {
logger.fine("compute Zoll...");
List<ItemCollection> list = getSteuerbescheide();
double result = 0;
for (ItemCollection steuerItemCol : list) {
result = result + getZollBySteuerBeleg(steuerItemCol, "ZOLL");
}
return InvoiceUtil.round(result);
}
/**
* Berechnet die Summe aller überfälligen steuer Beträge $taskID=1200
*
* @return
*/
private double computeSteuerbescheideSaldo() {
logger.fine("compute saldo...");
List<ItemCollection> list = getSteuerbescheide();
double result = 0;
for (ItemCollection steuerItemCol : list) {
result = result + steuerItemCol.getItemValueDouble("invoice.saldo");
}
return InvoiceUtil.round(result);
}
/**
* Berechnet die Summe aller überfälligen steuer Beträge $taskID=1200
*
* @return
*/
private double computeSteuerbescheideTotal() {
logger.fine("compute total...");
List<ItemCollection> list = getSteuerbescheide();
double result = 0;
for (ItemCollection steuerItemCol : list) {
result = result + steuerItemCol.getItemValueDouble("invoice.total.net");
}
return InvoiceUtil.round(result);
}
/**
* Berechnet die Summe aller überfälligen steuer Beträge $taskID=1200
*
* @return
*/
private double computeSteuerbescheideSaldoDue() {
logger.fine("compute EUST...");
List<ItemCollection> list = getSteuerbescheide();
double result = 0;
for (ItemCollection steuerItemCol : list) {
if (steuerItemCol.getTaskID() == 1200) {
result = result + steuerItemCol.getItemValueDouble("invoice.saldo");
}
}
return InvoiceUtil.round(result);
}
/**
* Berechnet die summ zoll/eust für einen Beleg
*
* @param steuerItemCol
* @return
*/
private double getZollBySteuerBeleg(ItemCollection steuerItemCol, String type) {
double result = 0;
List<ItemCollection> positionsTabelle = InvoiceUtil.explodeChildList(steuerItemCol);
for (ItemCollection pos : positionsTabelle) {
if (type.equalsIgnoreCase(pos.getItemValueString("activity.type"))) {
result = result + pos.getItemValueDouble("amount");
}
}
return result;
}
private List<ItemCollection> getSteuerbescheide() {
if (steuerbescheide != null) {
return steuerbescheide;
}
// compute steuerbescheide....
logger.info("Load Steuerbescheide for analytics....");
String query = "(type:workitem ) AND ($workflowgroup:\"Steuerbescheid\")";
try {
steuerbescheide = documentService.find(query, 999, 0, "$created", false);
return steuerbescheide;
} catch (QueryException e) {
logger.severe("Failed to get invoices: " + e.getMessage());
}
return null;
}
/**
* Berechnet Chart daten aller Steuerbescheide bei KW
*
* <pre>
*
chartCfg = {
type: 'bar',
data: {
datasets: [{
data: [20, 10],
}],
labels: ['1', '2']
}
}
*
* </pre>
*
* @return
*/
private String accumulateSteuerbescheideByWeek() {
logger.fine("accumulate steuer by week...");
List<ItemCollection> list = getSteuerbescheide();
Map<Integer, SteuerData> saldoByWeek = new HashMap<>();
Calendar calendar = Calendar.getInstance();
int earliestWeek = Integer.MAX_VALUE;
int latestWeek = Integer.MIN_VALUE;
// Step 1: Group saldo by week
for (ItemCollection steuerItemCol : list) {
double saldo = steuerItemCol.getItemValueDouble("invoice.saldo");
double total = steuerItemCol.getItemValueDouble("invoice.total.net");
Date date = steuerItemCol.getItemValueDate("invoice.date");
// Get the week number and year from the date
calendar.setTime(date);
int weekNumber = calendar.get(Calendar.WEEK_OF_YEAR);
int year = calendar.get(Calendar.YEAR);
int yearWeek = year * 100 + weekNumber; // Unique key for each year + week combination
// Accumulate the saldo per week
SteuerData steuerDataByWeek = saldoByWeek.getOrDefault(yearWeek, new SteuerData());
double eust = getZollBySteuerBeleg(steuerItemCol, "EUST");
double zoll = getZollBySteuerBeleg(steuerItemCol, "ZOLL");
steuerDataByWeek.add(eust, zoll, total, saldo, "");
saldoByWeek.put(yearWeek, steuerDataByWeek);
// Track the earliest and latest weeks
earliestWeek = Math.min(earliestWeek, yearWeek);
latestWeek = Math.max(latestWeek, yearWeek);
}
// Step 2: Prepare the JSON structure and ensure we have all weeks from earliest
// to latest
JsonArrayBuilder dataBuilderSaldo = Json.createArrayBuilder();
JsonArrayBuilder dataBuilderEust = Json.createArrayBuilder();
JsonArrayBuilder dataBuilderZoll = Json.createArrayBuilder();
JsonArrayBuilder labelsBuilder = Json.createArrayBuilder();
Calendar startCal = Calendar.getInstance();
startCal.set(Calendar.YEAR, earliestWeek / 100);
startCal.set(Calendar.WEEK_OF_YEAR, earliestWeek % 100);
Calendar endCal = Calendar.getInstance();
endCal.set(Calendar.YEAR, latestWeek / 100);
endCal.set(Calendar.WEEK_OF_YEAR, latestWeek % 100);
while (!startCal.after(endCal)) {
int weekNumber = startCal.get(Calendar.WEEK_OF_YEAR);
int year = startCal.get(Calendar.YEAR);
int yearWeek = year * 100 + weekNumber;
// Add the saldo for the week or 0.0 if no data
SteuerData steuerData = saldoByWeek.getOrDefault(yearWeek, new SteuerData());
dataBuilderSaldo.add(steuerData.saldo);
dataBuilderEust.add(steuerData.eust);
dataBuilderZoll.add(steuerData.zoll);
labelsBuilder.add(weekNumber + "/" + year); // Label as 'week/year'
// Move to the next week
startCal.add(Calendar.WEEK_OF_YEAR, 1);
}
// Step 3: Prepare the JSON structure
JsonObjectBuilder jsonBuilder = Json.createObjectBuilder()
.add("type", "bar")
.add("data", Json.createObjectBuilder()
.add("datasets", Json.createArrayBuilder()
.add(Json.createObjectBuilder() // First dataset for 'tax'
.add("label", "Zoll")
.add("backgroundColor", "#96f")
.add("borderWidth", 1)
.add("data", dataBuilderZoll))
.add(Json.createObjectBuilder() // Second dataset for 'eust'
.add("label", "EUSt")
.add("backgroundColor", "#36a2eb")
.add("borderWidth", 1)
.add("data", dataBuilderEust))
.add(Json.createObjectBuilder() // Third dataset for 'Saldo'
.add("label", "Saldo")
.add("backgroundColor", "#ff6384")
.add("borderWidth", 1)
.add("data", dataBuilderSaldo)))
.add("labels", labelsBuilder));
// Step 4: Return the JSON structure as a string
JsonObject chartCfg = jsonBuilder.build();
return chartCfg.toString();
}
/**
* Berechnet Chart daten aller Steuerbescheide bei KW
*
* <pre>
*
chartCfg = {
type: 'bar',
data: {
datasets: [{
data: [20, 10],
}],
labels: ['1', '2']
}
}
*
* </pre>
*
* @return
*/
private String accumulateSteuerbescheideAbteilungByWeek() {
logger.fine("accumulate steuer by Abteilung week...");
String[] colors = {
"#36a2eb",
"#ff6384",
"#4bc0c0",
"#ff9f40",
"#96f",
"#ffcd56",
"#c9cbcf"
};
List<ItemCollection> list = getSteuerbescheide();
Map<String, SteuerData> totalByWeek = new HashMap<>();
Calendar calendar = Calendar.getInstance();
int earliestWeek = Integer.MAX_VALUE;
int latestWeek = Integer.MIN_VALUE;
List<String> abteilungsListe = new ArrayList<>();
// Step 1: Group total by week
for (ItemCollection steuerItemCol : list) {
String abteilung = steuerItemCol.getItemValueString("space.name");
if (abteilung.isEmpty()) {
abteilung = "Keine Zuordnung";
}
if (!abteilungsListe.contains(abteilung)) {
abteilungsListe.add(abteilung);
}
double saldo = steuerItemCol.getItemValueDouble("invoice.saldo");
double total = steuerItemCol.getItemValueDouble("invoice.total.net");
Date date = steuerItemCol.getItemValueDate("invoice.date");
logger.fine(".... " + steuerItemCol.getItemValueString("$workflowSummary") + " = " + total);
// Get the week number and year from the date
calendar.setTime(date);
int weekNumber = calendar.get(Calendar.WEEK_OF_YEAR);
int year = calendar.get(Calendar.YEAR);
int yearWeek = year * 100 + weekNumber;
String key = abteilung + "~" + yearWeek;// Unique key Import Forest~202405
// Accumulate the total per week
SteuerData steuerDataByWeek = totalByWeek.getOrDefault(key, new SteuerData());
double eust = getZollBySteuerBeleg(steuerItemCol, "EUST");
double zoll = getZollBySteuerBeleg(steuerItemCol, "ZOLL");
steuerDataByWeek.add(eust, zoll, total, saldo, abteilung);
totalByWeek.put(key, steuerDataByWeek);
// Track the earliest and latest weeks
earliestWeek = Math.min(earliestWeek, yearWeek);
latestWeek = Math.max(latestWeek, yearWeek);
}
// Step 2: Prepare the JSON structure and ensure we have all weeks from earliest
// to latest
JsonArrayBuilder labelsBuilder = Json.createArrayBuilder();
Calendar startCal = Calendar.getInstance();
startCal.set(Calendar.YEAR, earliestWeek / 100);
startCal.set(Calendar.WEEK_OF_YEAR, earliestWeek % 100);
Calendar endCal = Calendar.getInstance();
endCal.set(Calendar.YEAR, latestWeek / 100);
endCal.set(Calendar.WEEK_OF_YEAR, latestWeek % 100);
// Build labels - je eines pro woche
while (!startCal.after(endCal)) {
int weekNumber = startCal.get(Calendar.WEEK_OF_YEAR);
int year = startCal.get(Calendar.YEAR);
labelsBuilder.add(weekNumber + "/" + year); // Label as 'week/year'
// Move to the next week
startCal.add(Calendar.WEEK_OF_YEAR, 1);
}
// Step 3: Baue die Balken pro abrteilung
JsonArrayBuilder datasets = Json.createArrayBuilder();
JsonObjectBuilder jsonBuilder = Json.createObjectBuilder()
.add("type", "bar");
JsonObjectBuilder dataDing = Json.createObjectBuilder();
int iColor = 0;
for (String _abteilung : abteilungsListe) {
JsonArrayBuilder dataBuilderTotals = Json.createArrayBuilder();
startCal = Calendar.getInstance();
startCal.set(Calendar.YEAR, earliestWeek / 100);
startCal.set(Calendar.WEEK_OF_YEAR, earliestWeek % 100);
endCal = Calendar.getInstance();
endCal.set(Calendar.YEAR, latestWeek / 100);
endCal.set(Calendar.WEEK_OF_YEAR, latestWeek % 100);
while (!startCal.after(endCal)) {
int weekNumber = startCal.get(Calendar.WEEK_OF_YEAR);
int year = startCal.get(Calendar.YEAR);
int yearWeek = year * 100 + weekNumber;
String key = _abteilung + "~" + yearWeek;// Unique key Import Forest~202405
// Add the total for the week or 0.0 if no data
SteuerData steuerData = totalByWeek.getOrDefault(key, new SteuerData());
logger.fine(" " + yearWeek + "=" + steuerData.total);
dataBuilderTotals.add(steuerData.total);
// Move to the next week
startCal.add(Calendar.WEEK_OF_YEAR, 1);
}
datasets.add(Json.createObjectBuilder() // First dataset for 'tax'
.add("label", _abteilung)
.add("backgroundColor", colors[iColor])
.add("borderWidth", 1)
.add("data", dataBuilderTotals));
iColor++;
if (iColor > colors.length) {
iColor = 0;
}
}
dataDing.add("datasets", datasets);
dataDing.add("labels", labelsBuilder);
jsonBuilder.add("data", dataDing);
// Step 4: Return the JSON structure as a string
JsonObject chartCfg = jsonBuilder.build();
return chartCfg.toString();
}
/**
* Helper method to hold zoll and eust totals in an object. Needed to build
* totals per week.
*/
class SteuerData {
double total = 0.0;
double zoll = 0.0;
double eust = 0.0;
double saldo = 0.0;
String abteilung = "";
public SteuerData() {
// default constructor
}
/**
* Adds new zoll and eust values and updates the total
*
* @param eustNew eust value to be added
* @param zollNew zoll value to be added
*/
public void add(double eustNew, double zollNew, double totalNew, double saldoNew, String abteilungNew) {
eust = eust + eustNew;
zoll = zoll + zollNew;
saldo = saldo + saldoNew;
total = total + totalNew;
abteilung = abteilungNew;
}
}
}

View file

@ -32,29 +32,30 @@ import jakarta.inject.Inject;
* Textblock und fügt die offenen Steuerbescheid Daten ein * Textblock und fügt die offenen Steuerbescheid Daten ein
* *
* Der Adapter wird im Modell wie folgt konfiguriert * Der Adapter wird im Modell wie folgt konfiguriert
* *
* <pre> * <pre>
* {@code * {@code
<steuerbescheide name="excel-export"> <steuerbescheide name="excel-export">
<textblock>textblock-ref</textblock> <textblock>textblock-ref</textblock>
<template>filename</template> <template>filename</template>
<targetname>filename</targetname> <targetname>filename</targetname>
</steuerbescheide> </steuerbescheide>
} }
* </pre> * </pre>
* *
* <p> * <p>
* Der Adapter erweitert den POIAdapter somit können Felder aktualisiert werden * Der Adapter erweitert den POIAdapter somit können Felder aktualisiert werden
* (siehe POIFineReplaceAdapter). * (siehe POIFineReplaceAdapter).
* *
* <p> * <p>
* Der Adapter kopiert die Steuerbescheiddaten in neue Zeilen, welche ab * Der Adapter kopiert die Steuerbescheiddaten in neue Zeilen, welche ab
* Zeilennummer 16 eingefügt werden. * Zeilennummer
* 16 eingefügt werden.
* <p> * <p>
* *
* Abschliessend wird die Zelle 'TOTAL' noch aktualisiert. * Abschliessend wird die Zelle 'TOTAL' noch aktualisiert.
* *
* *
* @version 1.0 * @version 1.0
* @author rsoika * @author rsoika
*/ */
@ -66,7 +67,7 @@ public class AGLAnalyticExcelAdapter extends POIFindReplaceAdapter {
WorkflowService workflowService; WorkflowService workflowService;
@Inject @Inject
InvoiceService opListExportService; OPListExportService opListExportService;
@Inject @Inject
DocumentService documentService; DocumentService documentService;
@ -77,7 +78,7 @@ public class AGLAnalyticExcelAdapter extends POIFindReplaceAdapter {
/** /**
* This method finds or create the Zahlungsavis and adds a reference * This method finds or create the Zahlungsavis and adds a reference
* ($workitemref) to the current invoice. * ($workitemref) to the current invoice.
* *
* @throws PluginException * @throws PluginException
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@ -89,7 +90,7 @@ public class AGLAnalyticExcelAdapter extends POIFindReplaceAdapter {
ItemCollection configItemCollection = configService.loadConfiguration("AGL_CONFIGURATION"); ItemCollection configItemCollection = configService.loadConfiguration("AGL_CONFIGURATION");
List<String> currencyList = configItemCollection.getItemValue("currency.out"); List<String> currencyList = configItemCollection.getItemValue("currency.out");
if (currencyList == null || currencyList.size() < 2) { if (currencyList == null || currencyList.size() < 2) {
throw new PluginException(AGLAnalyticExcelAdapter.class.getSimpleName(), InvoiceService.ERROR_CONFIG, throw new PluginException(AGLAnalyticExcelAdapter.class.getSimpleName(), OPListExportService.ERROR_CONFIG,
"missing Currency configuration - please check parameters"); "missing Currency configuration - please check parameters");
} }
@ -129,7 +130,7 @@ public class AGLAnalyticExcelAdapter extends POIFindReplaceAdapter {
this.updateFileData(document.getFileData(targetName), document, replaceDevList, eval); this.updateFileData(document.getFileData(targetName), document, replaceDevList, eval);
} catch (PluginException | IOException | QueryException e) { } catch (PluginException | IOException | QueryException e) {
throw new PluginException(AGLAnalyticExcelAdapter.class.getSimpleName(), InvoiceService.ERROR_CONFIG, throw new PluginException(AGLAnalyticExcelAdapter.class.getSimpleName(), OPListExportService.ERROR_CONFIG,
"failed to update steuerbescheide: " + e.getMessage()); "failed to update steuerbescheide: " + e.getMessage());
} }
logger.info("... completed!"); logger.info("... completed!");
@ -137,18 +138,19 @@ public class AGLAnalyticExcelAdapter extends POIFindReplaceAdapter {
} }
/** /**
* This helper method inserts a row for each invoice at row 16 into the excel * This helper method inserts a row for each invoice at row 16
* template file * into the excel template file
* <p> * <p>
* The method copies the Row A16 as a reference row * The method copies the Row A16 as a reference row
* <p> * <p>
* The named cell 'TOTAL' should contain the summary formula. It will be * The named cell 'TOTAL' should contain the summary formula. It will be
* evaluated at the end. * evaluated at the end.
* *
* @throws PluginException * @throws PluginException
* @throws QueryException * @throws QueryException
*/ */
private void insertInvoiceRows(ItemCollection document, String fileName) throws PluginException, QueryException { private void insertInvoiceRows(ItemCollection document, String fileName)
throws PluginException, QueryException {
// load dummy rechnungen // load dummy rechnungen
List<ItemCollection> invoices = loadSteuerbescheide(); List<ItemCollection> invoices = loadSteuerbescheide();
@ -177,21 +179,16 @@ public class AGLAnalyticExcelAdapter extends POIFindReplaceAdapter {
XSSFRow row = sheet.createRow(rowPos); XSSFRow row = sheet.createRow(rowPos);
row.copyRowFrom(referenceRowInvoice, new CellCopyPolicy()); row.copyRowFrom(referenceRowInvoice, new CellCopyPolicy());
// insert values // insert values
row.getCell(0).setCellValue(invoice.getItemValueDate("$created")); row.getCell(0)
.setCellValue(invoice.getItemValueDate("$created"));
row.getCell(1, MissingCellPolicy.CREATE_NULL_AS_BLANK) row.getCell(1, MissingCellPolicy.CREATE_NULL_AS_BLANK)
.setCellValue(invoice.getItemValueString("invoice.number")); .setCellValue(invoice.getItemValueString("invoice.number"));
row.getCell(2, MissingCellPolicy.CREATE_NULL_AS_BLANK) row.getCell(2, MissingCellPolicy.CREATE_NULL_AS_BLANK)
.setCellValue(invoice.getItemValueDate("invoice.date")); .setCellValue(invoice.getItemValueDate("invoice.date"));
row.getCell(3, MissingCellPolicy.CREATE_NULL_AS_BLANK) row.getCell(3, MissingCellPolicy.CREATE_NULL_AS_BLANK)
.setCellValue(invoice.getItemValueDate("invoice.booking_date")); .setCellValue(invoice.getItemValueDate("invoice.booking_date"));
// Änderung Frau Mwangi am 5.12.2025
// Nun soll anstatt des Departments der Anmelder ausgegeben werden
// row.getCell(4, MissingCellPolicy.CREATE_NULL_AS_BLANK)
// .setCellValue(invoice.getItemValueString("space.name"));
row.getCell(4, MissingCellPolicy.CREATE_NULL_AS_BLANK) row.getCell(4, MissingCellPolicy.CREATE_NULL_AS_BLANK)
.setCellValue(invoice.getItemValueString("steuer.anmelder")); .setCellValue(invoice.getItemValueString("space.name"));
row.getCell(5, MissingCellPolicy.CREATE_NULL_AS_BLANK) row.getCell(5, MissingCellPolicy.CREATE_NULL_AS_BLANK)
.setCellValue(invoice.getItemValueString("invoice.text")); .setCellValue(invoice.getItemValueString("invoice.text"));
row.getCell(6, MissingCellPolicy.CREATE_NULL_AS_BLANK) row.getCell(6, MissingCellPolicy.CREATE_NULL_AS_BLANK)
@ -228,7 +225,7 @@ public class AGLAnalyticExcelAdapter extends POIFindReplaceAdapter {
logger.finest("......new document added"); logger.finest("......new document added");
} catch (IOException e) { } catch (IOException e) {
throw new PluginException(AGLAnalyticExcelAdapter.class.getSimpleName(), InvoiceService.ERROR_CONFIG, throw new PluginException(AGLAnalyticExcelAdapter.class.getSimpleName(), OPListExportService.ERROR_CONFIG,
"failed to update opliste: " + e.getMessage()); "failed to update opliste: " + e.getMessage());
} finally { } finally {
if (doc != null) { if (doc != null) {
@ -245,7 +242,7 @@ public class AGLAnalyticExcelAdapter extends POIFindReplaceAdapter {
/** /**
* This method loads a text-block for a specified ref and appends the named * This method loads a text-block for a specified ref and appends the named
* fileData object of this document. * fileData object of this document.
* *
* @param document * @param document
* @throws PluginException * @throws PluginException
*/ */
@ -253,7 +250,7 @@ public class AGLAnalyticExcelAdapter extends POIFindReplaceAdapter {
throws PluginException { throws PluginException {
if ((template == null || template.isEmpty()) || (textblockRef == null || textblockRef.isEmpty())) { if ((template == null || template.isEmpty()) || (textblockRef == null || textblockRef.isEmpty())) {
throw new PluginException(AGLAnalyticExcelAdapter.class.getSimpleName(), InvoiceService.ERROR_CONFIG, throw new PluginException(AGLAnalyticExcelAdapter.class.getSimpleName(), OPListExportService.ERROR_CONFIG,
"invalid steuerbescheide configuration in model event - textblock/template reference not defined!"); "invalid steuerbescheide configuration in model event - textblock/template reference not defined!");
} }
@ -262,7 +259,7 @@ public class AGLAnalyticExcelAdapter extends POIFindReplaceAdapter {
// do we found the document? // do we found the document?
if (fileData == null) { if (fileData == null) {
throw new PluginException(AGLAnalyticExcelAdapter.class.getSimpleName(), InvoiceService.ERROR_CONFIG, throw new PluginException(AGLAnalyticExcelAdapter.class.getSimpleName(), OPListExportService.ERROR_CONFIG,
"invalid steuerbescheide configuration in model event - template=" + template + " not found!"); "invalid steuerbescheide configuration in model event - template=" + template + " not found!");
} }
fileData.setName(targetName); fileData.setName(targetName);
@ -274,14 +271,15 @@ public class AGLAnalyticExcelAdapter extends POIFindReplaceAdapter {
/** /**
* Diese Methode läd alle offenen Steuerbescheide * Diese Methode läd alle offenen Steuerbescheide
* *
* @return * @return
*/ */
private List<ItemCollection> loadSteuerbescheide() { private List<ItemCollection> loadSteuerbescheide() {
List<ItemCollection> result = new ArrayList<>(); List<ItemCollection> result = new ArrayList<>();
try { try {
result = documentService.find("$modelversion:steuerbescheid-* AND type:workitem", 9999, 0, "invoice.number", result = documentService.find(
false); "$modelversion:steuerbescheid-* AND type:workitem", 9999, 0,
"invoice.number", false);
} catch (QueryException e) { } catch (QueryException e) {
e.printStackTrace(); e.printStackTrace();
} }

View file

@ -0,0 +1,315 @@
package com.alexanderlogistics;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;
import org.apache.poi.ss.usermodel.CellCopyPolicy;
import org.apache.poi.ss.usermodel.Row.MissingCellPolicy;
import org.apache.poi.ss.util.CellReference;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.imixs.workflow.FileData;
import org.imixs.workflow.ItemCollection;
import org.imixs.workflow.engine.DocumentService;
import org.imixs.workflow.engine.WorkflowService;
import org.imixs.workflow.exceptions.AdapterException;
import org.imixs.workflow.exceptions.PluginException;
import org.imixs.workflow.exceptions.QueryException;
import org.imixs.workflow.office.config.ConfigService;
import org.imixs.workflow.poi.POIFindReplaceAdapter;
import org.imixs.workflow.util.XMLParser;
import jakarta.inject.Inject;
/**
* Der AGLAnalyticExcelAdapterDebitor exportiert eine Excel Datei aus einem
* Textblock und fügt die offenen Recnungen ein
*
* Der Adapter wird im Modell wie folgt konfiguriert
*
* <pre>
* {@code
<soa name="excel-export">
<textblock>textblock-ref</textblock>
<template>filename</template>
<targetname>filename</targetname>
</soa>
}
* </pre>
*
* <p>
* Der Adapter erweitert den POIAdapter somit können Felder aktualisiert werden
* (siehe POIFineReplaceAdapter).
*
* <p>
* Der Adapter kopiert die ausgangsrechnungen in neue Zeilen, welche ab
* Zeilennummer
* 16 eingefügt werden.
* <p>
*
* Abschliessend wird die Zelle 'TOTAL' noch aktualisiert.
*
*
* @version 1.0
* @author rsoika
*/
public class AGLAnalyticExcelAdapterDebitor extends POIFindReplaceAdapter {
private static Logger logger = Logger.getLogger(AGLAnalyticExcelAdapter.class.getName());
@Inject
WorkflowService workflowService;
@Inject
OPListExportService opListExportService;
@Inject
DocumentService documentService;
@Inject
ConfigService configService;
/**
* This method
*
* @throws PluginException
*/
@SuppressWarnings("unchecked")
@Override
public ItemCollection execute(ItemCollection document, ItemCollection event)
throws AdapterException, PluginException {
// ermittle die Hauptwährungen
ItemCollection configItemCollection = configService.loadConfiguration("AGL_CONFIGURATION");
List<String> currencyList = configItemCollection.getItemValue("currency.out");
if (currencyList == null || currencyList.size() < 2) {
throw new PluginException(AGLAnalyticExcelAdapter.class.getSimpleName(),
OPListExportService.ERROR_CONFIG,
"missing Currency configuration - please check parameters");
}
// read the Steuerbescheide options
ItemCollection ausgangsrechnungConfig = workflowService.evalWorkflowResult(event, "soa",
document,
false);
if (ausgangsrechnungConfig == null || !ausgangsrechnungConfig.hasItem("excel-export")) {
throw new PluginException(AGLAnalyticExcelAdapterDebitor.class.getSimpleName(), CONFIG_ERROR,
"missing soa configuration in model event - please check model configuration");
}
List<String> excelDefList = ausgangsrechnungConfig.getItemValue("excel-export");
ItemCollection excelDefCollection = XMLParser.parseItemStructure(excelDefList.get(0));
String textblock = excelDefCollection.getItemValueString("textblock");
String template = excelDefCollection.getItemValueString("template");
String targetName = excelDefCollection.getItemValueString("target-name");
// adapt text....
targetName = workflowService.adaptText(targetName, document);
try {
appendExcelTemplate(document, textblock, template, targetName);
insertInvoiceRows(document, targetName);
logger.info("... loading poi configuration..");
// Process POI instructions
// read the config
ItemCollection poiConfig = workflowService.evalWorkflowResult(event, "poi-update", document,
false);
if (poiConfig == null || !poiConfig.hasItem("findreplace")) {
throw new PluginException(POIFindReplaceAdapter.class.getSimpleName(), CONFIG_ERROR,
"missing poi configuration");
}
List<String> replaceDevList = poiConfig.getItemValue("findreplace");
String eval = poiConfig.getItemValueString("eval");
logger.info("... update template with normal poi information..");
this.updateFileData(document.getFileData(targetName), document, replaceDevList, eval);
} catch (PluginException | IOException | QueryException e) {
throw new PluginException(AGLAnalyticExcelAdapter.class.getSimpleName(),
OPListExportService.ERROR_CONFIG,
"failed to update steuerbescheide: " + e.getMessage());
}
logger.info("... completed!");
return document;
}
/**
* Hilfsmethode die das fuehrende K/D aus der Debitorennummer entfernt
*
* @return
*/
private String getDbtNr(ItemCollection workitem) {
String dbtNr = workitem.getItemValueString("dbtr.number");
if (dbtNr.startsWith("D") || dbtNr.startsWith("K")) {
dbtNr = dbtNr.substring(1);
}
return dbtNr;
}
/**
* This helper method inserts a row for each invoice at row 16
* into the excel template file
* <p>
* The method copies the Row A16 as a reference row
* <p>
* The named cell 'TOTAL' should contain the summary formula. It will be
* evaluated at the end.
*
* @throws PluginException
* @throws QueryException
*/
private void insertInvoiceRows(ItemCollection document, String fileName)
throws PluginException, QueryException {
// load dummy rechnungen
List<ItemCollection> invoices = loadInvoices(getDbtNr(document));
FileData fileData = document.getFileData(fileName);
// load XSSFWorkbook
XSSFWorkbook doc = null;
try (InputStream imputStream = new ByteArrayInputStream(fileData.getContent())) {
doc = new XSSFWorkbook(imputStream);
// NOTE: we only take the first sheet !
XSSFSheet sheet = doc.getSheetAt(0);
CellReference invoiceRefCell = new CellReference("A11");
XSSFRow referenceRowInvoice = sheet.getRow(invoiceRefCell.getRow());
int referenceRowPos = 10;
int rowPos = referenceRowPos;
int lastRow = 2999;
logger.finest("Last rownum=" + lastRow);
// jetzt füge alle Rechnungen an.
int totalRowCount = invoices.size();
sheet.shiftRows(referenceRowPos, lastRow, totalRowCount, true, true);
for (ItemCollection invoice : invoices) {
logger.fine("......add invoice " + invoice.getUniqueID());
// now create a new line..
XSSFRow row = sheet.createRow(rowPos);
row.copyRowFrom(referenceRowInvoice, new CellCopyPolicy());
// insert values
row.getCell(0)
.setCellValue(invoice.getItemValueDate("$created"));
row.getCell(1, MissingCellPolicy.CREATE_NULL_AS_BLANK)
.setCellValue(invoice.getItemValueString("invoice.number"));
row.getCell(2, MissingCellPolicy.CREATE_NULL_AS_BLANK)
.setCellValue(invoice.getItemValueDate("invoice.date"));
row.getCell(3, MissingCellPolicy.CREATE_NULL_AS_BLANK)
.setCellValue(invoice.getItemValueDate("invoice.duedate"));
row.getCell(4, MissingCellPolicy.CREATE_NULL_AS_BLANK)
.setCellValue(invoice.getItemValueString("space.name"));
row.getCell(5, MissingCellPolicy.CREATE_NULL_AS_BLANK)
.setCellValue(invoice.getItemValueString("invoice.text"));
// Waehrung?
if (invoice.getItemValueDouble("invoice.rate") == 0) {
row.getCell(6, MissingCellPolicy.CREATE_NULL_AS_BLANK)
.setCellValue(invoice.getItemValueDouble("invoice.total"));
row.getCell(7, MissingCellPolicy.CREATE_NULL_AS_BLANK)
.setCellValue(invoice.getItemValueDouble("invoice.saldo"));
} else {
row.getCell(8, MissingCellPolicy.CREATE_NULL_AS_BLANK)
.setCellValue(invoice.getItemValueDouble("invoice.total"));
row.getCell(9, MissingCellPolicy.CREATE_NULL_AS_BLANK)
.setCellValue(invoice.getItemValueDouble("invoice.saldo"));
}
row.getCell(10, MissingCellPolicy.CREATE_NULL_AS_BLANK)
.setCellValue(invoice.getItemValueString("$workflowstatus"));
rowPos++;
}
// Leerzeile
// categoryRow = sheet.createRow(rowPos);
rowPos++;
// write back the file
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
doc.write(byteArrayOutputStream);
byte[] newContent = byteArrayOutputStream.toByteArray();
FileData fileDataNew = new FileData(fileData.getName(), newContent, fileData.getContentType(),
null);
// update the fileData
document.addFileData(fileDataNew);
logger.finest("......new document added");
} catch (IOException e) {
throw new PluginException(AGLAnalyticExcelAdapter.class.getSimpleName(),
OPListExportService.ERROR_CONFIG,
"failed to update opliste: " + e.getMessage());
} finally {
if (doc != null) {
try {
doc.close();
} catch (IOException e) {
logger.severe("Failed to close workbook: " + e.getMessage());
e.printStackTrace();
}
}
}
}
/**
* This method loads a text-block for a specified ref and appends the named
* fileData object of this document.
*
* @param document
* @throws PluginException
*/
private void appendExcelTemplate(ItemCollection document, String textblockRef, String template,
String targetName)
throws PluginException {
if ((template == null || template.isEmpty()) || (textblockRef == null || textblockRef.isEmpty())) {
throw new PluginException(AGLAnalyticExcelAdapter.class.getSimpleName(),
OPListExportService.ERROR_CONFIG,
"invalid SOA configuration in model event - textblock/template reference not defined!");
}
// load the text block
FileData fileData = opListExportService.loadTextBlockFileData(textblockRef, template);
// do we found the document?
if (fileData == null) {
throw new PluginException(AGLAnalyticExcelAdapter.class.getSimpleName(),
OPListExportService.ERROR_CONFIG,
"invalid SOA configuration in model event - template=" + template
+ " not found!");
}
fileData.setName(targetName);
// append document
logger.info("...append new SOA Template: " + targetName);
document.addFileData(fileData);
}
/**
* Diese Methode läd alle offenen Steuerbescheide
*
* @return
*/
private List<ItemCollection> loadInvoices(String dbtrNumber) {
List<ItemCollection> result = new ArrayList<>();
String query = "(type:workitem) AND dbtr.number:" + dbtrNumber
+ " AND $modelversion:rechnungsausgang-*";
try {
result = documentService.find(
query, 9999, 0,
"invoice.number", false);
} catch (QueryException e) {
e.printStackTrace();
}
return result;
}
}

View file

@ -1,51 +1,51 @@
/******************************************************************************* /*******************************************************************************
* Imixs Workflow Technology * Imixs Workflow Technology
* Copyright (C) 2003, 2008 Imixs Software Solutions GmbH, * Copyright (C) 2003, 2008 Imixs Software Solutions GmbH,
* http://www.imixs.com * http://www.imixs.com
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2 * as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version. * of the License, or (at your option) any later version.
* *
* This program is distributed in the hope that it will be useful, * This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details. * General Public License for more details.
* *
* You can receive a copy of the GNU General Public * You can receive a copy of the GNU General Public
* License at http://www.gnu.org/licenses/gpl.html * License at http://www.gnu.org/licenses/gpl.html
* *
* Contributors: * Contributors:
* Imixs Software Solutions GmbH - initial API and implementation * Imixs Software Solutions GmbH - initial API and implementation
* Ralph Soika * Ralph Soika
* *
*******************************************************************************/ *******************************************************************************/
package com.alexanderlogistics; package com.alexanderlogistics;
import org.imixs.workflow.office.config.ConfigController; import org.imixs.workflow.office.config.ConfigController;
import jakarta.enterprise.context.ApplicationScoped; import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Named; import jakarta.inject.Named;
/** /**
* The Custom Config Controller for TAXES and Invoice typs * The Custom Config Controller for TAXES and Invoice typs
* *
* *
* @author rsoika * @author rsoika
* @version 1.0 * @version 1.0
*/ */
@Named("aglConfigController") @Named("aglConfigController")
// @RequestScoped // @RequestScoped
@ApplicationScoped @ApplicationScoped
public class AGLConfigController extends ConfigController { public class AGLConfigController extends ConfigController {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
public AGLConfigController() { public AGLConfigController() {
super(); super();
setName("AGL_CONFIGURATION"); setName("AGL_CONFIGURATION");
} }
} }

View file

@ -25,18 +25,18 @@ import jakarta.inject.Inject;
* <p> * <p>
* report = report definition to transfers the workitem into the cargosoft xml * report = report definition to transfers the workitem into the cargosoft xml
* structure * structure
* *
* <pre> * <pre>
* {@code * {@code
<cargosoft name="report">cargosoft</cargosoft> <cargosoft name="report">cargosoft</cargosoft>
} }
* </pre> * </pre>
* <p> * <p>
* Because we also export the attachment data to cargosoft, the adaper lookups * Because we also export the attachment data to cargosoft, the adaper lookups
* the conente of the attachment in the snapshot of the origin workitem * the conente of the attachment in the snapshot of the origin workitem
* *
* *
* @version 1.0 * @version 1.0
* @author rsoika * @author rsoika
*/ */
@ -76,7 +76,7 @@ public class CargosoftExportAdapter implements SignalAdapter {
@Override @Override
public ItemCollection execute(ItemCollection document, ItemCollection event) throws AdapterException { public ItemCollection execute(ItemCollection document, ItemCollection event) throws AdapterException {
logger.info("├── 📤 Cargosoft export..."); logger.info("......starting export...");
try { try {
// read the cargosoft export options // read the cargosoft export options
@ -84,14 +84,14 @@ public class CargosoftExportAdapter implements SignalAdapter {
if (evalItemCollection == null) { if (evalItemCollection == null) {
throw new PluginException(CargosoftExportAdapter.class.getSimpleName(), CONFIG_ERROR, throw new PluginException(CargosoftExportAdapter.class.getSimpleName(), CONFIG_ERROR,
"missing cargosoft configuration in model event - please check model configuration"); "missign cargosoft configuration in model event - please check model configuration");
} }
String reportID = evalItemCollection.getItemValueString("report"); String reportID = evalItemCollection.getItemValueString("report");
ItemCollection report = reportService.findReport(reportID); ItemCollection report = reportService.findReport(reportID);
if (report == null) { if (report == null) {
throw new PluginException(CargosoftExportAdapter.class.getSimpleName(), CONFIG_ERROR, throw new PluginException(CargosoftExportAdapter.class.getSimpleName(), CONFIG_ERROR,
"missing cargosoft report '" + reportID + "' - please check model configuration"); "missign cargosoft report '" + reportID + "' - please check model configuration");
} }
List<ItemCollection> sourceData = new ArrayList<ItemCollection>(); List<ItemCollection> sourceData = new ArrayList<ItemCollection>();
@ -106,15 +106,16 @@ public class CargosoftExportAdapter implements SignalAdapter {
// transfer file via FTP... // transfer file via FTP...
if (ftpServer.isPresent()) { if (ftpServer.isPresent()) {
logger.info("ftp transfer...");
ftpConnector.put(exportFile); ftpConnector.put(exportFile);
} }
// finally append the success event id // finally append the success event id
document.event(EVENT_SUCCESS); document.event(EVENT_SUCCESS);
} catch (PluginException | IOException | jakarta.xml.bind.JAXBException } catch (PluginException | IOException
| javax.xml.transform.TransformerException e) { | jakarta.xml.bind.JAXBException | javax.xml.transform.TransformerException e) {
logger.severe("├── ⚠️ Cargosoft export failed: " + e.getMessage()); logger.severe("cargosoft export failed: " + e.getMessage());
document.setItemValue("cargosoft.error", e.getMessage()); document.setItemValue("cargosoft.error", e.getMessage());
document.event(EVENT_FAILURE); document.event(EVENT_FAILURE);
} }
@ -129,8 +130,8 @@ public class CargosoftExportAdapter implements SignalAdapter {
* Change 14.10.2021 - Wir senden maximal 5MB and Daten, da die Cargosoft * Change 14.10.2021 - Wir senden maximal 5MB and Daten, da die Cargosoft
* Schnittstelle größere Datensätze mit großen Dateianhängen einfach verschluckt * Schnittstelle größere Datensätze mit großen Dateianhängen einfach verschluckt
* ohne eine Fehlermeldugn zu liefern. * ohne eine Fehlermeldugn zu liefern.
* *
* *
* @param document * @param document
* @return * @return
*/ */

View file

@ -21,18 +21,18 @@ import org.imixs.workflow.office.util.SequenceService;
import jakarta.inject.Inject; import jakarta.inject.Inject;
/** /**
* Der CargosoftSplitAdapter erzeugt anhand der Positionstablelle * Der CargosoftSplitAdapter erezeugt anhand der Positionstablelle eignee
* cargosoft export workitems, getrennt für jede Buchungsperdiode. Dies ist * cargosoft export workitems, getrennt für jede Buchungsperdiode. Dies ist
* notwendig, da Cargosoft selbst nicht mit unterschiedlichen Buchungsperioden * notwendig, da Cargosoft selbst nicht mit unterschiedlichen Buchungsperioden
* in einer Rechnung umgehen kann. * in einer Rechnung umgehen kann.
* <p> * <p>
* Die Daten werden als XML Datei auf einem FTP Laufwerk abgelegt. Da * adapter exports the invoice data to a ftp server connected to cargosoft. Da
* auch eine fortlaufene Rechnungsnummer von Cargosoft zwingend vorgeschrieben * auch eine fortlaufene Rechnungsnummer von Cargosoft zwingend vorgeschrieben
* ist, erzeugt der adapter auch für jedes weiteres cargosoft export worktiem * ist, erzeugt der adapter auch für jedes weiteres cargosoft export worktiem
* ein neue Sequencenummer die im Hautpworkitem gespeichert wird. * ein neue Sequencenummer die im Hautpworkitem gespeichert wird.
* <p> * <p>
* Der Adapter wird im Modell wie folgt konfiguriert * Der Adapter wird im Modell wie folgt konfiguriert
* *
* <pre> * <pre>
* {@code * {@code
<cargosoft> <cargosoft>
@ -41,21 +41,14 @@ import jakarta.inject.Inject;
<event>100</event> <event>100</event>
<items>(?!txtworkflowhistory)(^[a-zA-Z]|^_)</items> <items>(?!txtworkflowhistory)(^[a-zA-Z]|^_)</items>
</cargosoft> </cargosoft>
} }
* </pre> * </pre>
* <p> * <p>
* Because we also export the attachment data to cargosoft, the adapter lookups * Because we also export the attachment data to cargosoft, the adaper lookups
* the conente of the attachment in the snapshot of the origin workitem * the conente of the attachment in the snapshot of the origin workitem
* *
* <p> *
* Der Adapter validiert zusätzlich ob die Kreditorennnummer cdtr.number gültig
* ist.
* <p>
* Es kann auch vorkommen das speziell Gutschriften auf ein alternatives
* Cargosoft Konto gebucht werden müssen. Dies prüfen wir und ändern ggf. das
* Konto ab (Anforderung Frau Mahner 18.9.2025)
*
* @version 1.0 * @version 1.0
* @author rsoika * @author rsoika
*/ */
@ -70,12 +63,9 @@ public class CargosoftSplitAdapter implements SignalAdapter {
@Inject @Inject
SequenceService sequenceService; SequenceService sequenceService;
@Inject
BusinessPartnerService businessPartnerService;
/** /**
* This method computes the cargosoft export data file * This method computes the cargosoft export data file
* *
* @throws PluginException * @throws PluginException
*/ */
@SuppressWarnings("rawtypes") @SuppressWarnings("rawtypes")
@ -86,28 +76,6 @@ public class CargosoftSplitAdapter implements SignalAdapter {
logger.info("......starting export..."); logger.info("......starting export...");
try { try {
// check cdtr.number
String cdtrNumber = workitem.getItemValueString("cdtr.number");
ItemCollection partner = businessPartnerService.getBusinessPartnerByID(InvoiceUtil.buildBPID(cdtrNumber));
if (partner == null) {
throw new PluginException(CargosoftSplitAdapter.class.getSimpleName(), CONFIG_ERROR,
"Missing or wrong Creditor Number, please check your data.");
}
/**
* Sonderfall:
* Es kann sein, das Frau Mahner oder Frau Mwangi für diesen Kreditor
* Gutschriften (NUR Gutschriften!!) auf ein alternatives Konto buchen will.
* In diesem Fall ändern wir JETZT das feld cdtr.number!!!!
*/
if ("credit".equals(workitem.getItemValueString("payment.type"))) {
// Haben wir ein alternative Konto im Business Partner hinterlegt?
String alternativKonto = partner.getItemValueString("cargosot.credit.cdtr.number").trim();
if (!alternativKonto.isBlank()) {
cdtrNumber = alternativKonto;
workitem.setItemValue("cdtr.number", alternativKonto);
}
}
// read the cargosoft split options // read the cargosoft split options
ItemCollection evalItemCollection = workflowService.evalWorkflowResult(event, "cargosoft", workitem, false); ItemCollection evalItemCollection = workflowService.evalWorkflowResult(event, "cargosoft", workitem, false);
@ -122,13 +90,13 @@ public class CargosoftSplitAdapter implements SignalAdapter {
if (model.isEmpty() || taskID == 0 || eventID == 0) { if (model.isEmpty() || taskID == 0 || eventID == 0) {
throw new PluginException(CargosoftSplitAdapter.class.getSimpleName(), CONFIG_ERROR, throw new PluginException(CargosoftSplitAdapter.class.getSimpleName(), CONFIG_ERROR,
"missing cargosoft configuration 'model', 'task', 'event' - please check model configuration"); "missign cargosoft configuration 'model', 'task', 'event' - please check model configuration");
} }
// Zunaechst müssen wir feststellen, ob es mehrere unterschiedliche // Zunaechst müssen wir festelstellen, ob es mehrere unterschiedliche
// Buchungsperioden in der Positionstabelle gibt. // Buchungsperioden in der Positionstabelle gibt.
List<String> buchungsPersioden = new ArrayList<String>(); List<String> buchungsPersioden = new ArrayList<String>();
// add Haupt-Buchungsperiode // add haupt buchungsperiode
buchungsPersioden.add(workitem.getItemValueString("invoice.period")); buchungsPersioden.add(workitem.getItemValueString("invoice.period"));
List<ItemCollection> positionsTabelle = InvoiceUtil.explodeChildList(workitem); List<ItemCollection> positionsTabelle = InvoiceUtil.explodeChildList(workitem);
for (ItemCollection posItem : positionsTabelle) { for (ItemCollection posItem : positionsTabelle) {
@ -221,21 +189,21 @@ public class CargosoftSplitAdapter implements SignalAdapter {
* <p> * <p>
* Example: {@code * Example: {@code
* txttitle,txtfirstname * txttitle,txtfirstname
* *
* txttitle|newitem1,txtfirstname|newitem2 * txttitle|newitem1,txtfirstname|newitem2
* *
* } * }
* *
* <p> * <p>
* Optional also reg expressions are supported. In this case mapping of the item * Optional also reg expressions are supported. In this case mapping of the item
* name is not supported. * name is not supported.
* <p> * <p>
* Example: {@code * Example: {@code
* (^artikel$|^invoice$),txtTitel|txtNewTitel * (^artikel$|^invoice$),txtTitel|txtNewTitel
* *
* *
* } A reg expression must be includes in brackets. * } A reg expression must be includes in brackets.
* *
*/ */
protected void copyItemList(String items, ItemCollection source, ItemCollection target) { protected void copyItemList(String items, ItemCollection source, ItemCollection target) {
// clone the field list... // clone the field list...

View file

@ -1,283 +1,279 @@
/******************************************************************************* /*******************************************************************************
* Imixs Workflow Technology * Imixs Workflow Technology
* Copyright (C) 2003, 2008 Imixs Software Solutions GmbH, * Copyright (C) 2003, 2008 Imixs Software Solutions GmbH,
* http://www.imixs.com * http://www.imixs.com
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2 * as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version. * of the License, or (at your option) any later version.
* *
* This program is distributed in the hope that it will be useful, * This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details. * General Public License for more details.
* *
* You can receive a copy of the GNU General Public * You can receive a copy of the GNU General Public
* License at http://www.gnu.org/licenses/gpl.html * License at http://www.gnu.org/licenses/gpl.html
* *
* Contributors: * Contributors:
* Imixs Software Solutions GmbH - initial API and implementation * Imixs Software Solutions GmbH - initial API and implementation
* Ralph Soika * Ralph Soika
* *
*******************************************************************************/ *******************************************************************************/
package com.alexanderlogistics; package com.alexanderlogistics;
import java.io.Serializable; import java.io.Serializable;
import java.text.DecimalFormat; import java.io.UnsupportedEncodingException;
import java.text.SimpleDateFormat; import java.net.URLEncoder;
import java.util.Calendar; import java.text.DecimalFormat;
import java.util.Date; import java.text.SimpleDateFormat;
import java.util.logging.Logger; import java.util.Calendar;
import java.util.Date;
import org.imixs.marty.team.TeamController; import java.util.logging.Logger;
import org.imixs.workflow.ItemCollection;
import org.imixs.workflow.office.views.SearchController; import org.imixs.marty.team.TeamController;
import org.imixs.workflow.office.views.SearchEvent; import org.imixs.workflow.ItemCollection;
import org.imixs.workflow.office.views.SearchController;
import jakarta.enterprise.context.SessionScoped; import org.imixs.workflow.office.views.SearchEvent;
import jakarta.enterprise.event.Observes;
import jakarta.inject.Inject; import jakarta.enterprise.context.RequestScoped;
import jakarta.inject.Named; import jakarta.enterprise.event.Observes;
import jakarta.inject.Inject;
/** import jakarta.inject.Named;
* Der CustomSearchController reagiert auf SeachEvents und erweitert das Search
* Query um Rechnungbetrag von-bis. /**
* * Der CustomSearchController reagiert auf SeachEvents und erweitert das Search
* @author rsoika * Query um Rechnungbetrag von-bis.
* @version 1.0 *
*/ * @author rsoika
* @version 1.0
@Named */
@SessionScoped
// @RequestScoped @Named
public class CustomSearchController implements Serializable { // @SessionScoped
@RequestScoped
private static final long serialVersionUID = 1L; public class CustomSearchController implements Serializable {
private static Logger logger = Logger.getLogger(CustomSearchController.class.getName()); private static final long serialVersionUID = 1L;
@Inject private static Logger logger = Logger.getLogger(CustomSearchController.class.getName());
SearchController searchController;
@Inject
@Inject SearchController searchController;
TeamController teamController;
@Inject
boolean isArchiveSearch = false; TeamController teamController;
public void init() { boolean isArchiveSearch = false;
isArchiveSearch = true;
} public void init() {
isArchiveSearch = true;
/** }
* Diese Suche schränkt immer auf Archive und Rechnugnscontrolling ein!!
* /**
* @param searchEvent * Diese Suche schränkt immer auf Archive und Rechnugnscontrolling ein!!
*/ *
public void onSearchEvent(@Observes SearchEvent searchEvent) { * @param searchEvent
*/
if (!isArchiveSearch) { public void onSearchEvent(@Observes SearchEvent searchEvent) {
// Keine Anpassung für andere Prozesse
return; if (!isArchiveSearch) {
} // Keine Anpassung für andere Prozesse
return;
String query = searchEvent.getQuery(); }
float invoiceTotal = searchEvent.getSearchFilter().getItemValueFloat("invoice.total");
Date invoiceDate = searchEvent.getSearchFilter().getItemValueDate("invoice.date"); String query = searchEvent.getQuery();
Date dueDate = searchEvent.getSearchFilter().getItemValueDate("invoice.duedate"); float invoiceTotal = searchEvent.getSearchFilter().getItemValueFloat("invoice.total");
Date closingDate = searchEvent.getSearchFilter().getItemValueDate("invoice.closingdate"); Date invoiceDate = searchEvent.getSearchFilter().getItemValueDate("invoice.date");
Date dueDate = searchEvent.getSearchFilter().getItemValueDate("invoice.duedate");
String cdtrNumber = searchEvent.getSearchFilter().getItemValueString("cdtr.number").trim(); Date closingDate = searchEvent.getSearchFilter().getItemValueDate("invoice.closingdate");
String invoiceType = searchEvent.getSearchFilter().getItemValueString("invoice.type");
String invoiceCurrency = searchEvent.getSearchFilter().getItemValueString("invoice.currency").trim(); String cdtrNumber = searchEvent.getSearchFilter().getItemValueString("cdtr.number").trim();
String invoiceType = searchEvent.getSearchFilter().getItemValueString("invoice.type");
String invoiceNumber = searchEvent.getSearchFilter().getItemValueString("invoice.number"); String invoiceCurrency = searchEvent.getSearchFilter().getItemValueString("invoice.currency").trim();
String paymentType = searchEvent.getSearchFilter().getItemValueString("payment.type").trim(); String invoiceNumber = searchEvent.getSearchFilter().getItemValueString("invoice.number");
String sequenceNumber = searchEvent.getSearchFilter().getItemValueString("sequencenumber").trim();
String paymentType = searchEvent.getSearchFilter().getItemValueString("payment.type").trim();
query += " (type:\"workitemarchive\") "; String sequenceNumber = searchEvent.getSearchFilter().getItemValueString("sequencenumber").trim();
// process ref= Rechnugnscontorling Prozess
ItemCollection process = teamController.getProcessByName("Rechnungscontrolling"); query += " (type:\"workitemarchive\") ";
if (process == null) { // process ref= Rechnugnscontorling Prozess
process = teamController.getProcessByName("Invoice Controlling"); ItemCollection process = teamController.getProcessByName("Rechnungscontrolling");
} if (process == null) {
if (process != null) { process = teamController.getProcessByName("Invoice Controlling");
query += " AND ($uniqueidref:\"" + process.getUniqueID() + "\") "; }
} if (process != null) {
query += " AND ($uniqueidref:\"" + process.getUniqueID() + "\") ";
// invoice.total }
if (invoiceTotal != 0) {
// format form and to with at least one digit // invoice.total
DecimalFormat decimalFormat = new DecimalFormat("#.00"); if (invoiceTotal != 0) {
query += " AND (invoice.total:" + decimalFormat.format(invoiceTotal) + ")"; // format form and to with at least one digit
DecimalFormat decimalFormat = new DecimalFormat("#.00");
} query += " AND (invoice.total:" + decimalFormat.format(invoiceTotal) + ")";
// invoice.date }
if (invoiceDate != null) {
query += " AND (invoice.date:" + CustomSearchController.getRangeDay(invoiceDate) + ")"; // invoice.date
if (invoiceDate != null) {
} query += " AND (invoice.date:" + CustomSearchController.getRangeDay(invoiceDate) + ")";
// invoice.duedate }
if (dueDate != null) {
query += " AND (invoice.duedate:" + CustomSearchController.getRangeDay(dueDate) + ")"; // invoice.duedate
if (dueDate != null) {
} query += " AND (invoice.duedate:" + CustomSearchController.getRangeDay(dueDate) + ")";
// invoice.closingdate }
if (closingDate != null) {
query += " AND ($lasteventdate:" + CustomSearchController.getRangeMonth(closingDate) + ")"; // invoice.closingdate
} if (closingDate != null) {
query += " AND ($lasteventdate:" + CustomSearchController.getRangeMonth(closingDate) + ")";
if (invoiceNumber != null && !invoiceNumber.isEmpty()) { }
query += " AND (invoice.number:" + invoiceNumber + ")";
} if (invoiceNumber != null && !invoiceNumber.isEmpty()) {
query += " AND (invoice.number:" + invoiceNumber + ")";
if (paymentType != null && !paymentType.isEmpty()) { }
query += " AND (payment.type:" + paymentType + ")";
} if (paymentType != null && !paymentType.isEmpty()) {
if (sequenceNumber != null && !sequenceNumber.isEmpty()) { query += " AND (payment.type:" + paymentType + ")";
query += " AND (sequencenumber:" + sequenceNumber + ")"; }
} if (sequenceNumber != null && !sequenceNumber.isEmpty()) {
query += " AND (sequencenumber:" + sequenceNumber + ")";
if (invoiceCurrency != null && !invoiceCurrency.isEmpty()) { }
query += " AND (invoice.currency:" + invoiceCurrency + ")";
} if (invoiceCurrency != null && !invoiceCurrency.isEmpty()) {
query += " AND (invoice.currency:" + invoiceCurrency + ")";
// Rechnungsart }
if (invoiceType != null && !"0".equals(invoiceType)) {
if ("1".equals(invoiceType)) { // Rechnungsart
query += " AND ($workflowgroup:\"Rechnungseingang\" AND NOT payment.type:credit)"; if (invoiceType != null && !"0".equals(invoiceType)) {
} if ("1".equals(invoiceType)) {
if ("2".equals(invoiceType)) { query += " AND ($workflowgroup:\"Rechnungseingang\" AND NOT payment.type:credit)";
query += " AND ($workflowgroup:Sachrechnung)"; }
} if ("2".equals(invoiceType)) {
if ("3".equals(invoiceType)) { query += " AND ($workflowgroup:Sachrechnung)";
query += " AND (($workflowgroup:Rechnungseingang) AND (payment.type:credit))"; }
} if ("3".equals(invoiceType)) {
if ("4".equals(invoiceType)) { query += " AND (($workflowgroup:Rechnungseingang) AND (payment.type:credit))";
query += " AND ($workflowgroup:\"Gutschrift Abgleich\")"; }
} if ("4".equals(invoiceType)) {
} query += " AND ($workflowgroup:\"Gutschrift Abgleich\")";
}
// dbtr.number }
if (cdtrNumber != null && !cdtrNumber.isEmpty()) {
cdtrNumber = cdtrNumber.trim().toUpperCase(); // dbtr.number
if (!cdtrNumber.startsWith("K") && !cdtrNumber.startsWith("D")) { if (cdtrNumber != null && !cdtrNumber.isEmpty()) {
query += " AND (cdtr.number:K" + cdtrNumber + " OR dbtr.number:" + cdtrNumber + ")"; cdtrNumber = cdtrNumber.trim().toUpperCase();
} else { if (!cdtrNumber.startsWith("K") && !cdtrNumber.startsWith("D")) {
if (cdtrNumber.startsWith("K")) { query += " AND (cdtr.number:K" + cdtrNumber + " OR dbtr.number:" + cdtrNumber + ")";
// suche nach Kreditor (Eingangsrechnung) } else {
query += " AND (cdtr.number:" + cdtrNumber + ")"; if (cdtrNumber.startsWith("K")) {
} else { // suche nach Kreditor (Eingangsrechnung)
// suche nach Debitor (Ausgangsrechnung) query += " AND (cdtr.number:" + cdtrNumber + ")";
if (cdtrNumber.startsWith("D")) { } else {
cdtrNumber = cdtrNumber.substring(1); // suche nach Debitor (Ausgangsrechnung)
} if (cdtrNumber.startsWith("D")) {
query += " AND (dbtr.number:" + cdtrNumber + ")"; cdtrNumber = cdtrNumber.substring(1);
} }
} query += " AND (dbtr.number:" + cdtrNumber + ")";
} }
}
logger.fine("Custom Query=" + query); }
// Udpate query
searchEvent.setQuery(query); logger.fine("Custom Query=" + query);
// Udpate query
} searchEvent.setQuery(query);
/** }
* Sonder AGL Lösung um im Archiv zu bleiben.
* /**
*/ * Sonder AGL Lösung um im Archiv zu bleiben.
public String refreshAGLArchive() { *
String phrase = searchController.getSearchFilter().getItemValueString("phrase"); */
searchController.refreshSearch(); public String refreshAGLArchive() {
searchController.getSearchFilter().setItemValue("type", "workitemarchive"); String phrase = searchController.getSearchFilter().getItemValueString("phrase");
String action = "/pages/workitems/agl_archive.xhtml?faces-redirect=true&phrase=" + phrase;
return action; searchController.getSearchFilter().setItemValue("Type", "workitemarchive");
try {
// String phrase = phrase = URLEncoder.encode(phrase, "UTF-8");
// searchController.getSearchFilter().getItemValueString("phrase"); } catch (UnsupportedEncodingException e) {
logger.severe("unable to encode search phrase!");
// searchController.getSearchFilter().setItemValue("type", "workitemarchive"); e.printStackTrace();
// try { }
// phrase = URLEncoder.encode(phrase, "UTF-8"); String action = "/pages/workitems/agl_archive.xhtml?faces-redirect=true&phrase=" + phrase;
// } catch (UnsupportedEncodingException e) { searchController.setPageIndex(0);
// logger.severe("unable to encode search phrase!"); return action;
// e.printStackTrace(); }
// }
// String action = /**
// "/pages/workitems/agl_archive.xhtml?faces-redirect=true&phrase=" + phrase; * This method reset the search filter and the search pageIndex and creates a
// searchController.setPageIndex(0); * new bookmarkable search link to the worklist including the current search
// return action; * phrase.
} *
*/
/** public String resetSearch() {
* This method reset the search filter and the search pageIndex and creates a searchController.reset();
* new bookmarkable search link to the worklist including the current search return refreshAGLArchive();
* phrase. }
*
*/ private static String getRangeDay(Date dueDate) {
public String resetSearch() { // Setze die Uhrzeit auf Mitternacht (00:00)
searchController.reset(); Calendar startCalendar = Calendar.getInstance();
return refreshAGLArchive(); startCalendar.setTime(dueDate);
} startCalendar.set(Calendar.HOUR_OF_DAY, 0);
startCalendar.set(Calendar.MINUTE, 0);
private static String getRangeDay(Date dueDate) { startCalendar.set(Calendar.SECOND, 0);
// Setze die Uhrzeit auf Mitternacht (00:00) startCalendar.set(Calendar.MILLISECOND, 0);
Calendar startCalendar = Calendar.getInstance();
startCalendar.setTime(dueDate); Date startDate = startCalendar.getTime();
startCalendar.set(Calendar.HOUR_OF_DAY, 0);
startCalendar.set(Calendar.MINUTE, 0); // Setze die Uhrzeit auf 23:59:59.999
startCalendar.set(Calendar.SECOND, 0); Calendar endCalendar = Calendar.getInstance();
startCalendar.set(Calendar.MILLISECOND, 0); endCalendar.setTime(dueDate);
endCalendar.set(Calendar.HOUR_OF_DAY, 23);
Date startDate = startCalendar.getTime(); endCalendar.set(Calendar.MINUTE, 59);
endCalendar.set(Calendar.SECOND, 59);
// Setze die Uhrzeit auf 23:59:59.999 endCalendar.set(Calendar.MILLISECOND, 999);
Calendar endCalendar = Calendar.getInstance();
endCalendar.setTime(dueDate); Date endDate = endCalendar.getTime();
endCalendar.set(Calendar.HOUR_OF_DAY, 23); SimpleDateFormat dateformat = new SimpleDateFormat("yyyyMMddHHmm");
endCalendar.set(Calendar.MINUTE, 59); String dateRange = "[" + dateformat.format(startDate) + " TO "
endCalendar.set(Calendar.SECOND, 59); + dateformat.format(endDate) + "]";
endCalendar.set(Calendar.MILLISECOND, 999);
return dateRange;
Date endDate = endCalendar.getTime(); }
SimpleDateFormat dateformat = new SimpleDateFormat("yyyyMMddHHmm");
String dateRange = "[" + dateformat.format(startDate) + " TO " + dateformat.format(endDate) + "]"; private static String getRangeMonth(Date dueDate) {
// Setze die Uhrzeit auf Mitternacht (00:00)
return dateRange; Calendar startCalendar = Calendar.getInstance();
} startCalendar.setTime(dueDate);
startCalendar.set(Calendar.HOUR_OF_DAY, 0);
private static String getRangeMonth(Date dueDate) { startCalendar.set(Calendar.MINUTE, 0);
// Setze die Uhrzeit auf Mitternacht (00:00) startCalendar.set(Calendar.SECOND, 0);
Calendar startCalendar = Calendar.getInstance(); startCalendar.set(Calendar.MILLISECOND, 0);
startCalendar.setTime(dueDate); startCalendar.set(Calendar.DAY_OF_MONTH, 1);
startCalendar.set(Calendar.HOUR_OF_DAY, 0);
startCalendar.set(Calendar.MINUTE, 0); Date startDate = startCalendar.getTime();
startCalendar.set(Calendar.SECOND, 0);
startCalendar.set(Calendar.MILLISECOND, 0); // Setze die Uhrzeit auf 23:59:59.999
startCalendar.set(Calendar.DAY_OF_MONTH, 1); Calendar endCalendar = Calendar.getInstance();
endCalendar.setTime(dueDate);
Date startDate = startCalendar.getTime(); endCalendar.set(Calendar.HOUR_OF_DAY, 23);
endCalendar.set(Calendar.MINUTE, 59);
// Setze die Uhrzeit auf 23:59:59.999 endCalendar.set(Calendar.SECOND, 59);
Calendar endCalendar = Calendar.getInstance(); endCalendar.set(Calendar.MILLISECOND, 999);
endCalendar.setTime(dueDate); endCalendar.set(Calendar.DAY_OF_MONTH, 1);
endCalendar.set(Calendar.HOUR_OF_DAY, 23); endCalendar.add(Calendar.MONTH, 1);
endCalendar.set(Calendar.MINUTE, 59); endCalendar.add(Calendar.DAY_OF_MONTH, -1);
endCalendar.set(Calendar.SECOND, 59);
endCalendar.set(Calendar.MILLISECOND, 999); Date endDate = endCalendar.getTime();
endCalendar.set(Calendar.DAY_OF_MONTH, 1); SimpleDateFormat dateformat = new SimpleDateFormat("yyyyMMddHHmm");
endCalendar.add(Calendar.MONTH, 1); String dateRange = "[" + dateformat.format(startDate) + " TO "
endCalendar.add(Calendar.DAY_OF_MONTH, -1); + dateformat.format(endDate) + "]";
Date endDate = endCalendar.getTime(); return dateRange;
SimpleDateFormat dateformat = new SimpleDateFormat("yyyyMMddHHmm"); }
String dateRange = "[" + dateformat.format(startDate) + " TO " + dateformat.format(endDate) + "]"; }
return dateRange;
}
}

View file

@ -0,0 +1,585 @@
package com.alexanderlogistics;
import java.io.Serializable;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.YearMonth;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.logging.Logger;
import java.util.stream.Collectors;
import org.imixs.workflow.ItemCollection;
import org.imixs.workflow.engine.DocumentService;
import org.imixs.workflow.exceptions.PluginException;
import org.imixs.workflow.exceptions.QueryException;
import org.imixs.workflow.faces.data.WorkflowController;
import org.imixs.workflow.office.views.SearchController;
import jakarta.annotation.PostConstruct;
import jakarta.enterprise.context.ConversationScoped;
import jakarta.faces.context.FacesContext;
import jakarta.inject.Inject;
import jakarta.inject.Named;
/**
* Der InvoiceAnalyseController dient zur Auswertung der Sachprüfungs WOrklfow
* Schritte. Die Analyse Seite ist büer das Admin Menü erreichbar.
*
* @author rsoika
*
*/
@Named
@ConversationScoped
// @SessionScoped
public class DebitorStatistikController implements Serializable {
private static final long serialVersionUID = 1L;
private static Logger logger = Logger.getLogger(DebitorStatistikController.class.getName());
@Inject
protected DocumentService documentService;
TreeMap<String, DebitorStatistikData> stats = null;
@Inject
protected WorkflowController workflowController;
@Inject
protected SearchController searchController;
@Inject
protected KreditorDebitorService kreditorDebitorService;
/**
* Initialize default behavior initialize an opitonal id from the query string
*
*/
@PostConstruct
public void init() {
// extract the processref and page from the query string
FacesContext fc = FacesContext.getCurrentInstance();
Map<String, String> paramMap = fc.getExternalContext().getRequestParameterMap();
String id = paramMap.get("dbtr.number");
if (id != null && !id.isEmpty()) {
workflowController.getWorkitem().setItemValue("dbtr.number", id);
try {
ItemCollection dbtr = kreditorDebitorService.findDebitor(id);
if (dbtr != null) {
workflowController.getWorkitem().setItemValue("dbtr.name", dbtr.getItemValueString("_vendor_name"));
}
} catch (PluginException e) {
// e.printStackTrace();
}
}
}
public ItemCollection getWorkitem() {
return workflowController.getWorkitem();
}
public int getZahlungsmoral() {
return 0;
}
/**
* Gibt eine bookmarkable url zurück.
* Wir vom Aktualisieren button in der Page genutzt
*
* @return
*/
public String getBookmark() {
return "/pages/dbtr-stats.xhtml?dbtr.number=" + getDbtNr() + "&faces-redirect=true";
}
/*
* Gesamt
*/
public String getQueryRechnungen() {
String query = "(type:workitem OR type:workitemarchive) AND dbtr.number:" + getDbtNr()
+ " AND $workflowgroup:\"Rechnungsausgang\"";
return "/pages/workitems/worklist?title=Rechnungen " + getDbtNr() + " gesamt&query=" + query;
}
public int getRechnungen() {
int result = 0;
if (getDbtNr().isEmpty()) {
return 0;
}
try {
result = documentService
.count("(type:workitem OR type:workitemarchive) AND dbtr.number:" + getDbtNr()
+ " AND $workflowgroup:\"Rechnungsausgang\"");
} catch (QueryException e) {
logger.severe("Failed to get statistic: " + e.getMessage());
}
return result;
}
/*
* Bezahlt
*/
public String getQueryRechnungenBezahlt() {
String query = "(type:workitem OR type:workitemarchive) AND dbtr.number:" + getDbtNr()
+ " AND $workflowgroup:\"Rechnungsausgang\" AND ($taskid:[5900 TO 5999])";
return "/pages/workitems/worklist?title=Rechnungen " + getDbtNr() + " bezahlt&query=" + query;
}
public int getRechnungenBezahlt() {
int result = 0;
if (getDbtNr().isEmpty()) {
return 0;
}
try {
result = documentService
.count("(type:workitem OR type:workitemarchive) AND dbtr.number:" + getDbtNr()
+ " AND $workflowgroup:\"Rechnungsausgang\" AND ($taskid:[5900 TO 5999])");
} catch (QueryException e) {
logger.severe("Failed to get statistic: " + e.getMessage());
}
return result;
}
/*
* Offen
*/
public String getQueryRechnungenOffen() {
String query = "(type:workitem) AND dbtr.number:" + getDbtNr()
+ " AND $workflowgroup:\"Rechnungsausgang\" AND ($taskid:[5000 TO 5099])";
return "/pages/workitems/worklist?title=Rechnungen " + getDbtNr() + " offen&query=" + query;
}
public int getRechnungenOffen() {
int result = 0;
if (getDbtNr().isEmpty()) {
return 0;
}
try {
result = documentService
.count("(type:workitem) AND dbtr.number:" + getDbtNr()
+ " AND $workflowgroup:\"Rechnungsausgang\" AND ($taskid:[5000 TO 5099])");
} catch (QueryException e) {
logger.severe("Failed to get statistic: " + e.getMessage());
}
return result;
}
/*
* Fällig
*/
public String getQueryRechnungenFaellig() {
String query = "(type:workitem) AND dbtr.number:" + getDbtNr()
+ " AND $workflowgroup:\"Rechnungsausgang\" AND ($taskid:[5100 TO 5199])";
return "/pages/workitems/worklist?title=Rechnungen " + getDbtNr() + " fällig&query=" + query;
}
public int getRechnungenFaellig() {
int result = 0;
if (getDbtNr().isEmpty()) {
return 0;
}
try {
result = documentService
.count("(type:workitem) AND dbtr.number:" + getDbtNr()
+ " AND $workflowgroup:\"Rechnungsausgang\" AND ($taskid:[5100 TO 5199])");
} catch (QueryException e) {
logger.severe("Failed to get statistic: " + e.getMessage());
}
return result;
}
/*
* In Mahnung
*/
public String getQueryRechnungenGemahnt() {
String query = "(type:workitem) AND dbtr.number:" + getDbtNr()
+ " AND $workflowgroup:\"Rechnungsausgang\" AND ($taskid:[5200 TO 5299])";
return "/pages/workitems/worklist?title=Rechnungen " + getDbtNr() + " in Mahnung&query=" + query;
}
public int getRechnungenGemahnt() {
int result = 0;
if (getDbtNr().isEmpty()) {
return 0;
}
try {
result = documentService
.count("(type:workitem ) AND dbtr.number:" + getDbtNr()
+ " AND $workflowgroup:\"Rechnungsausgang\" AND ($taskid:[5200 TO 5299])");
} catch (QueryException e) {
logger.severe("Failed to get statistic: " + e.getMessage());
}
return result;
}
/*
* Inkasso
*/
public String getQueryRechnungenInkasso() {
String query = "(type:workitem) AND dbtr.number:" + getDbtNr()
+ " AND $workflowgroup:\"Rechnungsausgang\" AND ($taskid:[5300 TO 5399])";
return "/pages/workitems/worklist?title=Rechnungen " + getDbtNr() + " in Inkasso&query=" + query;
}
public int getRechnungenInkasso() {
int result = 0;
if (getDbtNr().isEmpty()) {
return 0;
}
try {
result = documentService
.count("(type:workitem OR type:workitemarchive) AND dbtr.number:" + getDbtNr()
+ " AND $workflowgroup:\"Rechnungsausgang\" AND ($taskid:[5300 TO 5399])");
} catch (QueryException e) {
logger.severe("Failed to get statistic: " + e.getMessage());
}
return result;
}
/**
* Hilfsmethode die das fuehrende K/D aus der Debitorennummer entfernt
*
* @return
*/
public String getDbtNr() {
String dbtNr = getWorkitem().getItemValueString("dbtr.number");
if (dbtNr.startsWith("D") || dbtNr.startsWith("K")) {
dbtNr = dbtNr.substring(1);
}
return dbtNr;
}
public long getDurchschnittZahlungsziel() {
getStats();
int count = 0;
long gesamt = 0;
for (Map.Entry<String, DebitorStatistikData> entry : stats.entrySet()) {
DebitorStatistikData statData = entry.getValue();
if (statData.count > 0) {
gesamt = gesamt + statData.getAverageDueDays();
count++;
}
}
return Math.round((double) gesamt / count);
}
public long getDurchschnittZahlungsdauer() {
getStats();
int count = 0;
long gesamt = 0;
for (Map.Entry<String, DebitorStatistikData> entry : stats.entrySet()) {
DebitorStatistikData statData = entry.getValue();
if (statData.count > 0) {
gesamt = gesamt + statData.getAveragePaymentDays();
count++;
}
}
return Math.round((double) gesamt / count);
}
/**
* Sucht alle Rechnugnen aus einem Zeitraum und sammelt Zahlungsziel und
* Zahlungszeitspanne gruppiert nach monaten
*
*/
public Map<String, DebitorStatistikData> getStats() {
if (stats != null) {
return stats;
}
// recompute
stats = new TreeMap<String, DebitorStatistikData>();
if (getDbtNr().isEmpty()) {
return stats;
}
// invoice.date:[20210101 TO 20210201]
DateFormat df = new SimpleDateFormat("yyyymmdd");
String query = "(type:workitemarchive) AND invoice.date:[20221201 TO 20500101] AND dbtr.number:" + getDbtNr()
+ " AND $workflowgroup:\"Rechnungsausgang\" AND ($taskid:[5900 TO 5999])";
// query = query + " AND (invoice.date:[" + df.format(from) + " TO " +
// df.format(to) + "])";
logger.fine("query = " + query);
try {
List<ItemCollection> invoices = documentService
.findStubs(query, 9999, 0, "$created", false);
for (ItemCollection invoice : invoices) {
try {
logger.fine("Rechnung: " + invoice.getUniqueID());
Date invoiceDate = invoice.getItemValueDate("invoice.date");
Date invoiceDueDate = invoice.getItemValueDate("invoice.duedate");
Date paymentDate = findPaymentDateByWorkitem(invoice);
if (paymentDate == null) {
logger.warning("Es wurde kein Zahlungseingang gefunden");
continue;
}
if (invoiceDate != null && paymentDate != null && invoiceDueDate != null) {
// do we have a stats object?
DebitorStatistikData statData = stats.get(getYearMonth(invoiceDate));
if (statData == null) {
// create a new one
statData = new DebitorStatistikData(invoiceDate);
}
// jetzt irgendwas ausrechnen
statData.compute(invoiceDate, invoiceDueDate, paymentDate);
// .. und wieder speichern
stats.put(statData.toString(), statData);
} else {
logger.warning("No payment Date found for invoice " + invoice.getUniqueID());
}
} catch (ParseException e) {
logger.warning("Unable to parse payment Date for invoice " + invoice.getUniqueID());
}
}
} catch (QueryException e) {
logger.severe("Failed to get statistic: " + e.getMessage());
}
// Step 2: Sort the list based on the alphanumeric order of the keys
completeMissingMonths();
return stats;
}
/**
* Hilfsmethode ergänzt die fehlenden Monate
*
* @param yearMonths
* @return
*/
private void completeMissingMonths() {
if (stats == null || stats.size() < 3) {
return;
}
// Convert the list of strings to a list of LocalDate objects
List<LocalDate> dates = new ArrayList<>();
Set<String> yearMonths = this.stats.keySet();
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMM");
for (String yearMonth : yearMonths) {
dates.add(YearMonth.parse(yearMonth, formatter).atDay(1));
}
// Find the lowest and highest dates
LocalDate lowestDate = Collections.min(dates);
LocalDate highestDate = Collections.max(dates);
LocalDate current = lowestDate;
current = current.plusMonths(1);
while (!current.isAfter(highestDate)) {
// existiert der monat?
String formattedDate = current.format(formatter);
DebitorStatistikData entry = stats.get(formattedDate);
if (entry == null) {
// add missing entry
stats.put(formattedDate, new DebitorStatistikData(current.getYear(), current.getMonthValue()));
}
current = current.plusMonths(1);
}
}
/**
* returns
*
* 202304 from a given date
*/
public String getYearMonth(Date date) {
// Create a Calendar instance and set the date
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
// Get the year from the Calendar object
int year = calendar.get(Calendar.YEAR);
// Get the month from the Calendar object
int month = calendar.get(Calendar.MONTH);
// Increment the month by 1 since Calendar months are zero-based
month++;
// Convert the month to a String with leading "0" if necessary
return "" + year + (month < 10 ? "0" + month : "" + month);
}
/**
* Finds the payment.date for a invoice.
*
* Wir suchen alle zugeordneten Zahlungseingägne und nehmen den letzten.
*
* WICHTIG: Es muss ggf. der index neu aufgebaut werden, da payment.date nun ein
* index feld ist
*
* @param invoice
* @return
* @throws ParseException
*/
public Date findPaymentDateByWorkitem(ItemCollection invoice) throws ParseException {
// Wir selektieren alle Zahlungseingänge interessieren usn aber nur für den
// letzten
String sQuery = " (type:\"workitem\" OR type:\"workitemarchive\") " + //
" AND ($workflowgroup:Zahlungseingang) AND ($workitemref:\""
+ invoice.getUniqueID() + "\" )";
List<ItemCollection> workitems = null;
try {
workitems = documentService.findStubs(sQuery, 99, 0,
"payment.date", true);
if (workitems.size() > 0) {
return workitems.get(0).getItemValueDate("payment.date");
}
} catch (QueryException e) {
e.printStackTrace();
}
// no date found!
return null;
}
/**
* Finds the date when a workitem last reached the current task 5900 by reading
* the eventLog
*
* This method is not so save as the method findPaymentDateByWorkitem that is
* searching the payment workitem.
*
* 2023-06-28T12:40:17.437|rechnungsausgang-de-1.0|5001.50|5900|
*
* @param invoice
* @return
* @throws ParseException
*/
public Date findPaymentDateByLog(ItemCollection invoice) throws ParseException {
// Create a SimpleDateFormat instance with the desired format
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS");
List<String> logEntries = invoice.getItemValue("$eventlog");
// Iterate through the List from the last element to the first
for (int i = logEntries.size() - 1; i >= 0; i--) {
String entry = logEntries.get(i);
if (entry.endsWith(invoice.getTaskID() + "|")) {
// found!
String dateString = entry.substring(0, entry.indexOf("|") - 1);
// Parse the date string into a Date object
Date date = sdf.parse(dateString);
// Print the Date object
System.out.println("Date: " + date);
return date;
}
}
// no date found!
return null;
}
/**
* Diese Methode baut die Datenstruktur für das Chart Diagram zusammen
*
*
* <pre>
{
labels: ["January", "February", "March", "April", "May", "June", "July"],
datasets: [{
label: 'Dataset 1',
//backgroundColor: color(window.chartColors.red).alpha(0.5).rgbString(),
//borderColor: window.chartColors.red,
borderWidth: 1,
data: [
70, 70, 70, 70, 79, 50, 50
]
}, {
label: 'Dataset 2',
//backgroundColor: color(window.chartColors.blue).alpha(0.5).rgbString(),
//borderColor: window.chartColors.blue,
borderWidth: 1,
data: [
70, 70, 170, 7, 79, 50, 50
]
}]
}
* </pre>
*
* @return
*/
public String buildChartData() {
getStats();
// build a list of all lables....
List<String> statusLabels = new ArrayList<String>();
Set<String> keys = stats.keySet();
for (String _key : keys) {
statusLabels.add(_key);
}
String result = "{";
// Lables
result = result + "labels : [ ";
result = result + statusLabels.stream().collect(Collectors.joining("','", "'", "'"));
result = result + "],";
result = result + "datasets: [";
// Datasets 1
result = result + "{label: 'Zahlungsziel',borderWidth: 1,";
result = result + " borderColor: [\"#3B6B82\"],";
result = result + " \"backgroundColor\" : [\"#CFE9F5\"], fill: true,tension: 0.5,";
result = result + "data: [";
for (Map.Entry<String, DebitorStatistikData> entry : stats.entrySet()) {
result = result + entry.getValue().getAverageDueDays() + ",";
}
// cut last comma
result = result.substring(0, result.length() - 1);
result = result + "]";
result = result + "}, ";
// Datasets 2
result = result + "{label: 'Zahldauer',borderWidth: 1,";
result = result + " borderColor: [\"#E73B65\"],\"backgroundColor\" : [\"#70B088\" ], tension: 0.5,fill: true,";
result = result
+ " trendlineLinear: { colorMin: \"red\", colorMax: \"green\", lineStyle: \"dotted\", width: 2 , projection: true },";
result = result + "data: [";
for (Map.Entry<String, DebitorStatistikData> entry : stats.entrySet()) {
result = result + entry.getValue().getAveragePaymentDays() + ",";
}
// cut last comma
result = result.substring(0, result.length() - 1);
result = result + "]";
result = result + "} ";
// ende
result = result + "] }";
return result;
}
}

View file

@ -40,7 +40,7 @@ public class DebitorStatistikData {
/** /**
* Aktualisiert die statistischen werte * Aktualisiert die statistischen werte
* *
* @param invoiceDate * @param invoiceDate
* @param paymentDate * @param paymentDate
*/ */
@ -90,7 +90,7 @@ public class DebitorStatistikData {
/** /**
* returns * returns
* *
* 202304 * 202304
*/ */
public String toString() { public String toString() {

View file

@ -1,22 +1,22 @@
/******************************************************************************* /*******************************************************************************
* Imixs Workflow Technology * Imixs Workflow Technology
* Copyright (C) 2001, 2008 Imixs Software Solutions GmbH, * Copyright (C) 2001, 2008 Imixs Software Solutions GmbH,
* http://www.imixs.com * http://www.imixs.com
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2 * as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version. * of the License, or (at your option) any later version.
* *
* This program is distributed in the hope that it will be useful, * This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details. * General Public License for more details.
* *
* You can receive a copy of the GNU General Public * You can receive a copy of the GNU General Public
* License at http://www.gnu.org/licenses/gpl.html * License at http://www.gnu.org/licenses/gpl.html
* *
* Contributors: * Contributors:
* Imixs Software Solutions GmbH - initial API and implementation * Imixs Software Solutions GmbH - initial API and implementation
* Ralph Soika * Ralph Soika
*******************************************************************************/ *******************************************************************************/
@ -42,7 +42,7 @@ import jakarta.inject.Inject;
/** /**
* The FTPConnector service provides methods to push invoices to cargosoft * The FTPConnector service provides methods to push invoices to cargosoft
* *
* @version 1.0 * @version 1.0
* @author rsoika * @author rsoika
*/ */
@ -82,12 +82,10 @@ public class FTPConnector {
Optional<String> ftpPassword; Optional<String> ftpPassword;
/** /**
* This method transfers a file to a FTP server using atomic upload. * This method transfers a snapshot to a ftp server.
* The file is first uploaded with a temporary name and then renamed *
* to avoid race conditions with the receiver. * @param fileData object
* * @throws PluginException
* @param fileData object containing the file to upload
* @throws PluginException if the upload fails
*/ */
public void put(FileData fileData) throws PluginException { public void put(FileData fileData) throws PluginException {
@ -97,8 +95,6 @@ public class FTPConnector {
} }
String fileName = fileData.getName(); String fileName = fileData.getName();
// Create temporary filename to avoid race conditions
String tempFileName = fileName + ".part";
// Compute file path // Compute file path
String ftpWorkingPath = ftpPath.get(); String ftpWorkingPath = ftpPath.get();
@ -112,11 +108,7 @@ public class FTPConnector {
FTPClient ftpClient = null; FTPClient ftpClient = null;
try { try {
logger.info("├── 🔜 uploading " + fileName + " to FTP server: " + ftpServer + " ..."); logger.finest("......put " + fileName + " to FTP server: " + ftpServer + "...");
logger.info("│ ├── port=" + ftpPort.get().intValue());
logger.info("│ ├── working directory=" + ftpWorkingPath);
logger.info("│ ├── user=" + ftpUser.get());
// logger.info("│ ├── password=" + ftpPassword.get());
ftpClient = new FTPSClient("TLS", false); ftpClient = new FTPSClient("TLS", false);
ftpClient.setBufferSize(8192); ftpClient.setBufferSize(8192);
ftpClient.connect(ftpServer.get(), ftpPort.get().intValue()); ftpClient.connect(ftpServer.get(), ftpPort.get().intValue());
@ -128,61 +120,45 @@ public class FTPConnector {
ftpClient.setFileType(FTP.ASCII_FILE_TYPE); ftpClient.setFileType(FTP.ASCII_FILE_TYPE);
ftpClient.setControlEncoding("UTF-8"); ftpClient.setControlEncoding("UTF-8");
// Verify directories // verify directories
if (!ftpClient.changeWorkingDirectory(ftpWorkingPath)) { if (!ftpClient.changeWorkingDirectory(ftpWorkingPath)) {
throw new PluginException(CargosoftExportAdapter.class.getSimpleName(), FTP_ERROR, throw new PluginException(CargosoftExportAdapter.class.getSimpleName(), FTP_ERROR,
"FTP file transfer failed: missing working directory '" + ftpWorkingPath + "' : " "FTP file transfer failed: missing working directory '" + ftpWorkingPath + "' : "
+ ftpClient.getReplyString()); + ftpClient.getReplyString());
} }
// Upload file to FTP server with temporary name // upload file to FTP server.
writer = new ByteArrayInputStream(fileData.getContent()); writer = new ByteArrayInputStream(fileData.getContent());
if (!ftpClient.storeFile(tempFileName, writer)) { if (!ftpClient.storeFile(fileName, writer)) {
throw new PluginException(CargosoftExportAdapter.class.getSimpleName(), FTP_ERROR, throw new PluginException(CargosoftExportAdapter.class.getSimpleName(), FTP_ERROR,
"FTP file transfer failed: unable to write '" + ftpWorkingPath + tempFileName + "' : " "FTP file transfer failed: unable to write '" + ftpWorkingPath + fileName + "' : "
+ ftpClient.getReplyString()); + ftpClient.getReplyString());
} }
// Rename to final name - this is an atomic operation logger.finest("...." + ftpWorkingPath + fileName + " transfered successfull to " + ftpServer);
logger.info("│ ├── rename '" + tempFileName + "' to '" + fileName + " ...");
if (!ftpClient.rename(tempFileName, fileName)) {
throw new PluginException(CargosoftExportAdapter.class.getSimpleName(), FTP_ERROR,
"FTP file transfer failed: unable to rename '" + tempFileName + "' to '" + fileName + "' : "
+ ftpClient.getReplyString());
}
logger.info("│ └── ✓ ftp transfer completed."); } catch (IOException e) {
} catch (IOException | PluginException e) {
// Log the real cause immediately, before the finally block runs -
// otherwise a cleanup failure could overwrite/hide this exception.
logger.warning("│ ├── ⚠️ FTP connection error: " + e.getMessage());
if (e instanceof PluginException) {
throw (PluginException) e;
}
throw new PluginException(CargosoftExportAdapter.class.getSimpleName(), FTP_ERROR, throw new PluginException(CargosoftExportAdapter.class.getSimpleName(), FTP_ERROR,
"FTP file transfer failed: " + e.getMessage(), e); "FTP file transfer failed: " + e.getMessage(), e);
} finally { } finally {
// Cleanup - never let a cleanup failure mask the primary exception // do logout....
try { try {
if (writer != null) { if (writer != null) {
writer.close(); writer.close();
} }
if (ftpClient != null && ftpClient.isConnected()) { ftpClient.logout();
ftpClient.logout(); ftpClient.disconnect();
ftpClient.disconnect(); } catch (IOException e) {
}
} catch (IOException cleanupException) {
throw new PluginException(CargosoftExportAdapter.class.getSimpleName(), FTP_ERROR, throw new PluginException(CargosoftExportAdapter.class.getSimpleName(), FTP_ERROR,
"FTP file transfer failed during cleanup: " + cleanupException.getMessage(), "FTP file transfer failed: " + e.getMessage(), e);
cleanupException);
} }
} }
} }
/** /**
* This method reads data form the current working directory * This method reads data form the current working directory
* *
* @param snapshot * @param snapshot
* @throws ArchiveException * @throws ArchiveException
* @return data * @return data
@ -222,7 +198,7 @@ public class FTPConnector {
/** /**
* This method changes the current working sub-directy. If no corresponding * This method changes the current working sub-directy. If no corresponding
* directory exits the method creats one. * directory exits the method creats one.
* *
* @throws ArchiveException * @throws ArchiveException
*/ */
@SuppressWarnings("unused") @SuppressWarnings("unused")

View file

@ -0,0 +1,167 @@
package com.alexanderlogistics;
import java.io.Serializable;
import java.text.SimpleDateFormat;
import java.time.YearMonth;
import java.time.ZoneId;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.logging.Logger;
import org.imixs.workflow.ItemCollection;
import org.imixs.workflow.engine.DocumentService;
import org.imixs.workflow.engine.index.Category;
import org.imixs.workflow.engine.index.SearchService;
import jakarta.enterprise.context.ConversationScoped;
import jakarta.inject.Inject;
import jakarta.inject.Named;
/**
* Der InvoiceAnalyseController dient zur Auswertung der Sachprüfungs WOrklfow
* Schritte. Die Analyse Seite ist büer das Admin Menü erreichbar.
*
* @author rsoika
*
*/
@Named
@ConversationScoped
public class InvoiceAnalyseController implements Serializable {
private static final long serialVersionUID = 1L;
private static Logger logger = Logger.getLogger(InvoiceAnalyseController.class.getName());
@Inject
protected DocumentService documentService;
@Inject
SearchService searchService;
Category sachpruefung;
Category verteilung;
Category buchhaltung;
private ItemCollection filter;
public ItemCollection getFilter() {
if (filter == null) {
filter = new ItemCollection();
// compute start stop based on current month
YearMonth startYearMonth = YearMonth.now();
java.time.LocalDate startOfMonthDate = startYearMonth.atDay(1);
java.time.LocalDate endOfMonthDate = startYearMonth.atEndOfMonth();
filter.setItemValue("start",
java.util.Date.from(startOfMonthDate.atStartOfDay().atZone(ZoneId.systemDefault()).toInstant()));
filter.setItemValue("stop",
java.util.Date.from(endOfMonthDate.atStartOfDay().atZone(ZoneId.systemDefault()).toInstant()));
}
return filter;
}
public void setFilter(ItemCollection filter) {
this.filter = filter;
}
public Category getSachpruefung() {
return sachpruefung;
}
public Category getVerteilung() {
return verteilung;
}
public Category getBuchhaltung() {
return buchhaltung;
}
public int totalCountByCategory(Category cat) {
int result = 0;
Collection<Integer> allCounts = cat.getLabels().values();
result = allCounts.stream().reduce(0, Integer::sum);
return result;
}
/**
* Fuert verschiedene Queries aus um eine Analyse der Sachprufung durchzuführen.
*/
public void analyse() {
logger.info("start analyse....");
verteilung = null;
sachpruefung = null;
Date start = filter.getItemValueDate("start");
Date stop = filter.getItemValueDate("stop");
logger.info("...daterange=" + start + " - " + stop);
// serach date range?
String sDateFrom = "191401070000"; // because * did not work here
String sDateTo = "211401070000";
SimpleDateFormat dateformat = new SimpleDateFormat("yyyyMMddHHmm");
if (start != null) {
Calendar cal = Calendar.getInstance();
cal.setTime(start);
sDateFrom = dateformat.format(cal.getTime());
}
if (stop != null) {
Calendar cal = Calendar.getInstance();
cal.setTime(stop);
cal.add(Calendar.DATE, 1);
sDateTo = dateformat.format(cal.getTime());
}
// query Verteilung
String query = "(type:workitem OR type:workitemarchive) ";
if (start != null || stop != null) {
query += "AND (taxonomy.verteilung.stop:[" + sDateFrom + " TO " + sDateTo + "]) ";
}
logger.info(query);
List<Category> taxResult = searchService.getTaxonomyByQuery(query, "taxonomy.verteilung.stop.by");
if (taxResult.size() > 0) {
verteilung = taxResult.get(0);
}
// query Sachprüfung
query = "(type:workitem OR type:workitemarchive) ";
if (start != null || stop != null) {
query += "AND (taxonomy.sachpruefung.stop:[" + sDateFrom + " TO " + sDateTo + "]) ";
}
logger.info(query);
taxResult = searchService.getTaxonomyByQuery(query, "taxonomy.sachpruefung.stop.by");
if (taxResult.size() > 0) {
sachpruefung = taxResult.get(0);
}
// query Buchhaltung
query = "(type:workitem OR type:workitemarchive) ";
if (start != null || stop != null) {
query += "AND (taxonomy.buchhaltung.stop:[" + sDateFrom + " TO " + sDateTo + "]) ";
}
logger.info(query);
taxResult = searchService.getTaxonomyByQuery(query, "taxonomy.buchhaltung.stop.by");
if (taxResult.size() > 0) {
buchhaltung = taxResult.get(0);
}
}
/**
* This method reset the search and input state.
*/
public void reset() {
filter = new ItemCollection();
sachpruefung = null;
verteilung = null;
buchhaltung = null;
logger.fine("reset");
}
}

View file

@ -16,7 +16,7 @@ import jakarta.inject.Inject;
/** /**
* Der InvoiceDispatchAdapter verteilt die vom Abteilungsleiter ausgewählten * Der InvoiceDispatchAdapter verteilt die vom Abteilungsleiter ausgewählten
* Rechnungen * Rechnungen
* *
* @version 1.0 * @version 1.0
* @author rsoika * @author rsoika
*/ */
@ -29,7 +29,7 @@ public class InvoiceDispatchAdapter implements SignalAdapter {
/** /**
* This method computes the cargosoft export data file * This method computes the cargosoft export data file
* *
* @throws PluginException * @throws PluginException
*/ */
@Override @Override
@ -74,14 +74,8 @@ public class InvoiceDispatchAdapter implements SignalAdapter {
try { try {
workflowService.processWorkItem(invoice, 20); workflowService.processWorkItem(invoice, 20);
} catch (AccessDeniedException | ProcessingErrorException | PluginException | ModelException e) { } catch (AccessDeniedException | ProcessingErrorException | PluginException | ModelException e) {
// Hier werfen wir keine Exception mehr sondern geben nur eine Warning auf der throw new PluginException(InvoiceDispatchAdapter.class.getSimpleName(), "PROCESSING_ERROR",
// Console aus. "Failed to process invoice : " + invoice.getUniqueID());
// Der User merkt also nicht wenn eine Rechnung nicht zugewiesen werden konnte
// throw new PluginException(InvoiceDispatchAdapter.class.getSimpleName(),
// "PROCESSING_ERROR",
// "Failed to process invoice : " + invoice.getUniqueID());
logger.info("Failed to process invoice : " + invoice.getUniqueID());
} }
} }

View file

@ -16,7 +16,7 @@ import jakarta.inject.Named;
/** /**
* The InvoiceDispatchController loads open workitems for the current user * The InvoiceDispatchController loads open workitems for the current user
* *
* @author rsoika * @author rsoika
* *
*/ */
@ -50,7 +50,7 @@ public class InvoiceDispatchController implements Serializable {
* ($modelversion:rechnungseingang-de*) AND ($taskid:5100) AND * ($modelversion:rechnungseingang-de*) AND ($taskid:5100) AND
* ($owner:#{user})"></ui:param> <ui:param name="invoiceList" value= * ($owner:#{user})"></ui:param> <ui:param name="invoiceList" value=
* "#{workflowController.documentService.find(query,30,0)}"></ui:param> * "#{workflowController.documentService.find(query,30,0)}"></ui:param>
* *
*/ */
public void searchInvoices() { public void searchInvoices() {
long l = System.currentTimeMillis(); long l = System.currentTimeMillis();

Some files were not shown because too many files have changed in this diff Show more