neue Code Formatierung
This commit is contained in:
parent
be064fb965
commit
0f7627419a
93 changed files with 6864 additions and 6078 deletions
210
BPMN-KI-Test/prompt1.txt
Normal file
210
BPMN-KI-Test/prompt1.txt
Normal file
|
|
@ -0,0 +1,210 @@
|
|||
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>
|
||||
11
BPMN-KI-Test/prompt2.txt
Normal file
11
BPMN-KI-Test/prompt2.txt
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
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.
|
||||
389
BPMN-KI-Test/rechnung-ai-test.bpmn
Normal file
389
BPMN-KI-Test/rechnung-ai-test.bpmn
Normal file
|
|
@ -0,0 +1,389 @@
|
|||
<?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>
|
||||
207
BPMN-KI-Test/rechnung-ai-test_plain.bpmn
Normal file
207
BPMN-KI-Test/rechnung-ai-test_plain.bpmn
Normal file
|
|
@ -0,0 +1,207 @@
|
|||
<?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>
|
||||
17
BPMN-KI-Test/schema-1.txt
Normal file
17
BPMN-KI-Test/schema-1.txt
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
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)
|
||||
46
BPMN-KI-Test/schema-2.txt
Normal file
46
BPMN-KI-Test/schema-2.txt
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
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
|
||||
|
|
@ -8,9 +8,15 @@ https://api-console.zoho.eu/
|
|||
https://api-console.zoho.eu/client/1000.NLTM2KUEHI696MSLGEIANATVGGX7IN
|
||||
|
||||
```
|
||||
OrganizationID=20105697367
|
||||
client ID= 1000.NLTM2KUEHI696MSLGEIANATVGGX7IN
|
||||
client secret= ee9ba49f16e77c64abb89cea13542d2326d8d03ce8
|
||||
zoho.accesstoken 1000.18f5fbeaf572425b8062d015d541aad5.a704efa994774ef33d7af75106468a13
|
||||
zoho.apidomain https://www.zohoapis.eu
|
||||
zoho.clientid 1000.GR5FTPZYB06HEWSFSSX4DJU3OBD4EJ
|
||||
zoho.clientsecret 3f3e74c5212bbc924a7ebf77f887c6296db1106c47
|
||||
zoho.code 1000.c184c7592a218fee58f7b7855b56eb77.7b533ff9f570fd6ab3296784caeec072
|
||||
zoho.organization 20105697367
|
||||
zoho.refreshtoken 1000.98fe4d0c4f676237b400bf8a3dc219f3.03d6bacf5b988d339eb788c4ecff440e
|
||||
zoho.scope ZohoBooks.contacts.ALL ZohoBooks.invoices.CREATE ZohoBooks.invoices.READ ZohoBooks.invoices.UPDATE
|
||||
|
||||
```
|
||||
|
||||
# API Dokumentation
|
||||
|
|
@ -86,3 +92,16 @@ 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" />
|
||||
|
|
|
|||
26
doc/zoho/SECRETS.md
Normal file
26
doc/zoho/SECRETS.md
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
# Zoho Web API
|
||||
|
||||
AGL Dubai nutzt Zoho als Platform zusammen mit einer lokalen Steuerkanzlei
|
||||
|
||||
## Test/Prod Account Imixs
|
||||
|
||||
https://api-console.zoho.eu/
|
||||
https://api-console.zoho.eu/client/1000.NLTM2KUEHI696MSLGEIANATVGGX7IN
|
||||
|
||||
```
|
||||
OrganizationID=20105697367
|
||||
client ID= 1000.NLTM2KUEHI696MSLGEIANATVGGX7IN
|
||||
client secret= ee9ba49f16e77c64abb89cea13542d2326d8d03ce8
|
||||
```
|
||||
|
||||
# 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/
|
||||
BIN
doc/zoho/disable-auto-generated-number-01.png
Normal file
BIN
doc/zoho/disable-auto-generated-number-01.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 32 KiB |
BIN
doc/zoho/disable-auto-generated-number-02.png
Normal file
BIN
doc/zoho/disable-auto-generated-number-02.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 21 KiB |
File diff suppressed because it is too large
Load diff
|
|
@ -23,8 +23,7 @@ import jakarta.inject.Named;
|
|||
|
||||
/**
|
||||
* Der AGLAnalyticControllerOPListe berechnet Analyse Daten über alle offenen
|
||||
* Rechnungen
|
||||
* und bietet im Workflow noch eine Excel-Export Funktion
|
||||
* Rechnungen und bietet im Workflow noch eine Excel-Export Funktion
|
||||
*
|
||||
* @author rsoika
|
||||
*
|
||||
|
|
@ -33,176 +32,173 @@ import jakarta.inject.Named;
|
|||
@ConversationScoped
|
||||
public class AGLAnalyticControllerOPListe implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static Logger logger = Logger.getLogger(AnalyticController.class.getName());
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static Logger logger = Logger.getLogger(AnalyticController.class.getName());
|
||||
|
||||
@Inject
|
||||
protected DocumentService documentService;
|
||||
@Inject
|
||||
protected DocumentService documentService;
|
||||
|
||||
@Inject
|
||||
protected AGLConfigController aglConfigController;
|
||||
@Inject
|
||||
protected AGLConfigController aglConfigController;
|
||||
|
||||
@Inject
|
||||
protected WorkflowController workflowController;
|
||||
@Inject
|
||||
protected WorkflowController workflowController;
|
||||
|
||||
@Inject
|
||||
TeamService teamService;
|
||||
@Inject
|
||||
TeamService teamService;
|
||||
|
||||
@Inject
|
||||
ResourceBundleHandler resourceBundleHandler;
|
||||
@Inject
|
||||
ResourceBundleHandler resourceBundleHandler;
|
||||
|
||||
TreeMap<String, DebitorStatistikData> stats = null;
|
||||
TreeMap<String, DebitorStatistikData> stats = null;
|
||||
|
||||
String departmentID;
|
||||
String departmentIDLast = null;
|
||||
// String departmentName;
|
||||
ItemCollection department;
|
||||
String departmentID;
|
||||
String departmentIDLast = null;
|
||||
// String departmentName;
|
||||
ItemCollection department;
|
||||
|
||||
int countAll = 0;
|
||||
int countOpen = 0;
|
||||
int countDue = 0;
|
||||
int countDunning = 0;
|
||||
boolean refreshCalculation = false;
|
||||
int countAll = 0;
|
||||
int countOpen = 0;
|
||||
int countDue = 0;
|
||||
int countDunning = 0;
|
||||
boolean refreshCalculation = false;
|
||||
|
||||
public void onEvent(@Observes AnalyticEvent event) {
|
||||
public void onEvent(@Observes AnalyticEvent event) {
|
||||
|
||||
if (!event.getWorkitem().getModelVersion().contains("analyse-opliste-")) {
|
||||
// no op
|
||||
return;
|
||||
}
|
||||
if (!event.getWorkitem().getModelVersion().contains("analyse-opliste-")) {
|
||||
// no op
|
||||
return;
|
||||
}
|
||||
|
||||
department = null;
|
||||
departmentID = event.getWorkitem().getItemValueString("space.ref");
|
||||
if (departmentIDLast == null || !departmentID.equals(departmentIDLast)) {
|
||||
department = documentService.load(departmentID);
|
||||
if (department != null) {
|
||||
event.getWorkitem().setItemValue("space.name", department.getItemValueString("name"));
|
||||
}
|
||||
departmentIDLast = departmentID;
|
||||
resetStats(event);
|
||||
calculateStats();
|
||||
refreshCalculation = true;
|
||||
}
|
||||
department = null;
|
||||
departmentID = event.getWorkitem().getItemValueString("space.ref");
|
||||
if (departmentIDLast == null || !departmentID.equals(departmentIDLast)) {
|
||||
department = documentService.load(departmentID);
|
||||
if (department != null) {
|
||||
event.getWorkitem().setItemValue("space.name", department.getItemValueString("name"));
|
||||
}
|
||||
departmentIDLast = departmentID;
|
||||
resetStats(event);
|
||||
calculateStats();
|
||||
refreshCalculation = true;
|
||||
}
|
||||
|
||||
// use cache?
|
||||
if (event.getWorkitem().hasItem(event.getKey())) {
|
||||
// logger.info(" use cache for " + event.getKey());
|
||||
// no op
|
||||
return;
|
||||
}
|
||||
String link = "/pages/workitems/worklist.xhtml";
|
||||
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() // + "&modelversion=rechnungsausgang*"
|
||||
+ "&spaceref=" + departmentID;
|
||||
}
|
||||
if ("analytic.invoices.count.all".equals(event.getKey())) {
|
||||
event.setValue("" + countAll);
|
||||
event.setLabel(resourceBundleHandler.findMessage("oplist.invoices"));
|
||||
event.setDescription(resourceBundleHandler.findMessage("oplist.invoices.description.all"));
|
||||
event.getWorkitem().setItemValue("invoices.total", event.getValue());
|
||||
event.setLink(link);
|
||||
}
|
||||
// use cache?
|
||||
if (event.getWorkitem().hasItem(event.getKey())) {
|
||||
// logger.info(" use cache for " + event.getKey());
|
||||
// no op
|
||||
return;
|
||||
}
|
||||
String link = "/pages/workitems/worklist.xhtml";
|
||||
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() // + "&modelversion=rechnungsausgang*"
|
||||
+ "&spaceref=" + departmentID;
|
||||
}
|
||||
if ("analytic.invoices.count.all".equals(event.getKey())) {
|
||||
event.setValue("" + countAll);
|
||||
event.setLabel(resourceBundleHandler.findMessage("oplist.invoices"));
|
||||
event.setDescription(resourceBundleHandler.findMessage("oplist.invoices.description.all"));
|
||||
event.getWorkitem().setItemValue("invoices.total", event.getValue());
|
||||
event.setLink(link);
|
||||
}
|
||||
|
||||
if ("analytic.invoices.count.open".equals(event.getKey())) {
|
||||
event.setValue("" + (countOpen));
|
||||
event.setLabel(resourceBundleHandler.findMessage("oplist.invoices"));
|
||||
event.setDescription(resourceBundleHandler.findMessage("oplist.invoices.description.open"));
|
||||
event.getWorkitem().setItemValue("invoices.total.open", event.getValue());
|
||||
event.setLink(link);
|
||||
}
|
||||
if ("analytic.invoices.count.open".equals(event.getKey())) {
|
||||
event.setValue("" + (countOpen));
|
||||
event.setLabel(resourceBundleHandler.findMessage("oplist.invoices"));
|
||||
event.setDescription(resourceBundleHandler.findMessage("oplist.invoices.description.open"));
|
||||
event.getWorkitem().setItemValue("invoices.total.open", event.getValue());
|
||||
event.setLink(link);
|
||||
}
|
||||
|
||||
if ("analytic.invoices.count.due".equals(event.getKey())) {
|
||||
event.setValue("" + countDue);
|
||||
event.setLabel(resourceBundleHandler.findMessage("oplist.invoices"));
|
||||
event.setDescription(resourceBundleHandler.findMessage("oplist.invoices.description.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(resourceBundleHandler.findMessage("oplist.invoices"));
|
||||
event.setDescription(resourceBundleHandler.findMessage("oplist.invoices.description.dunning"));
|
||||
event.getWorkitem().setItemValue("invoices.total.dunning", event.getValue());
|
||||
event.setLink(link);
|
||||
}
|
||||
if ("analytic.invoices.count.due".equals(event.getKey())) {
|
||||
event.setValue("" + countDue);
|
||||
event.setLabel(resourceBundleHandler.findMessage("oplist.invoices"));
|
||||
event.setDescription(resourceBundleHandler.findMessage("oplist.invoices.description.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(resourceBundleHandler.findMessage("oplist.invoices"));
|
||||
event.setDescription(resourceBundleHandler.findMessage("oplist.invoices.description.dunning"));
|
||||
event.getWorkitem().setItemValue("invoices.total.dunning", event.getValue());
|
||||
event.setLink(link);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset cached analytic keys
|
||||
*/
|
||||
private void resetStats(AnalyticEvent event) {
|
||||
event.getWorkitem().removeItem("analytic.invoices.count.all");
|
||||
event.getWorkitem().removeItem("analytic.invoices.count.open");
|
||||
event.getWorkitem().removeItem("analytic.invoices.count.due");
|
||||
event.getWorkitem().removeItem("analytic.invoices.count.dunning");
|
||||
/**
|
||||
* Reset cached analytic keys
|
||||
*/
|
||||
private void resetStats(AnalyticEvent event) {
|
||||
event.getWorkitem().removeItem("analytic.invoices.count.all");
|
||||
event.getWorkitem().removeItem("analytic.invoices.count.open");
|
||||
event.getWorkitem().removeItem("analytic.invoices.count.due");
|
||||
event.getWorkitem().removeItem("analytic.invoices.count.dunning");
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Läd die statistik daten zu einem department die Anzahl an aktuellen
|
||||
* Rechnungen zu ermitteln
|
||||
*
|
||||
* int countAll = 0;
|
||||
* int countOpen = 0;
|
||||
* int countDue = 0;
|
||||
* int countDunning = 0;
|
||||
*
|
||||
*/
|
||||
private void calculateStats() {
|
||||
long l = System.currentTimeMillis();
|
||||
/**
|
||||
* Läd die statistik daten zu einem department die Anzahl an aktuellen
|
||||
* Rechnungen zu ermitteln
|
||||
*
|
||||
* int countAll = 0; int countOpen = 0; int countDue = 0; int countDunning = 0;
|
||||
*
|
||||
*/
|
||||
private void calculateStats() {
|
||||
long l = System.currentTimeMillis();
|
||||
|
||||
countAll = 0;
|
||||
countDue = 0;
|
||||
countDunning = 0;
|
||||
logger.info(" ├──calculate stats for " + departmentID + "....");
|
||||
countAll = 0;
|
||||
countDue = 0;
|
||||
countDunning = 0;
|
||||
logger.info(" ├──calculate stats for " + departmentID + "....");
|
||||
|
||||
try {
|
||||
try {
|
||||
|
||||
if (departmentID == null || !departmentID.isEmpty()) {
|
||||
countAll = documentService.count("(type:workitem) AND $uniqueidref:" + departmentID
|
||||
+ " AND $modelversion:rechnungsausgang-*");
|
||||
if (departmentID == null || !departmentID.isEmpty()) {
|
||||
countAll = documentService.count(
|
||||
"(type:workitem) AND $uniqueidref:" + departmentID + " AND $modelversion:rechnungsausgang-*");
|
||||
|
||||
countDue = documentService.count("(type:workitem) AND $uniqueidref:" + departmentID
|
||||
+ " AND $modelversion:rechnungsausgang-* AND $taskid:[5100 TO 5199]");
|
||||
countDunning = documentService.count("(type:workitem) AND $uniqueidref:" + departmentID
|
||||
+ " AND $modelversion:rechnungsausgang-* AND $taskid:[5200 TO 5399]");
|
||||
countDue = documentService.count("(type:workitem) AND $uniqueidref:" + departmentID
|
||||
+ " AND $modelversion:rechnungsausgang-* AND $taskid:[5100 TO 5199]");
|
||||
countDunning = documentService.count("(type:workitem) AND $uniqueidref:" + departmentID
|
||||
+ " AND $modelversion:rechnungsausgang-* AND $taskid:[5200 TO 5399]");
|
||||
|
||||
countOpen = countAll - countDue - countDunning;
|
||||
} else {
|
||||
countOpen = countAll - countDue - countDunning;
|
||||
} else {
|
||||
|
||||
// countAll=documentService.count("(type:workitem OR type:workitemarchive) AND
|
||||
// $modelversion:rechnungsausgang-*")
|
||||
// countAll=documentService.count("(type:workitem OR type:workitemarchive) AND
|
||||
// $modelversion:rechnungsausgang-*")
|
||||
|
||||
countAll = documentService.count("(type:workitem) AND $modelversion:rechnungsausgang-*");
|
||||
countAll = documentService.count("(type:workitem) AND $modelversion:rechnungsausgang-*");
|
||||
|
||||
countDue = documentService
|
||||
.count("(type:workitem) AND $modelversion:rechnungsausgang-* AND $taskid:[5100 TO 5199]");
|
||||
countDue = documentService
|
||||
.count("(type:workitem) AND $modelversion:rechnungsausgang-* AND $taskid:[5100 TO 5199]");
|
||||
|
||||
countDunning = documentService
|
||||
.count("(type:workitem) AND $modelversion:rechnungsausgang-* AND $taskid:[5200 TO 5399]");
|
||||
countOpen = countAll - countDue - countDunning;
|
||||
}
|
||||
countDunning = documentService
|
||||
.count("(type:workitem) AND $modelversion:rechnungsausgang-* AND $taskid:[5200 TO 5399]");
|
||||
countOpen = countAll - countDue - countDunning;
|
||||
}
|
||||
|
||||
} catch (QueryException e) {
|
||||
logger.warning("Failed to query invoices: " + e.getMessage());
|
||||
} catch (QueryException e) {
|
||||
logger.warning("Failed to query invoices: " + e.getMessage());
|
||||
|
||||
}
|
||||
logger.info(" ├──calculate stats took " + (System.currentTimeMillis() - l) + "ms");
|
||||
}
|
||||
logger.info(" ├──calculate stats took " + (System.currentTimeMillis() - l) + "ms");
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private String formatCurrency(Double value) {
|
||||
private String formatCurrency(Double value) {
|
||||
|
||||
DecimalFormatSymbols symbols = new DecimalFormatSymbols(Locale.getDefault());
|
||||
symbols.setGroupingSeparator('.');
|
||||
symbols.setDecimalSeparator(',');
|
||||
DecimalFormat formatter = new DecimalFormat("#,##0.00", symbols);
|
||||
DecimalFormatSymbols symbols = new DecimalFormatSymbols(Locale.getDefault());
|
||||
symbols.setGroupingSeparator('.');
|
||||
symbols.setDecimalSeparator(',');
|
||||
DecimalFormat formatter = new DecimalFormat("#,##0.00", symbols);
|
||||
|
||||
return formatter.format(value);
|
||||
}
|
||||
return formatter.format(value);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,497 +36,477 @@ import jakarta.json.JsonObjectBuilder;
|
|||
@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) {
|
||||
|
||||
if (!"workitem".equals(event.getWorkitem().getType())
|
||||
|| !event.getWorkitem().getModelVersion().startsWith("analyse-steuer")) {
|
||||
// no op
|
||||
return;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
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) {
|
||||
|
||||
if (!"workitem".equals(event.getWorkitem().getType())
|
||||
|| !event.getWorkitem().getModelVersion().startsWith("analyse-steuer")) {
|
||||
// no op
|
||||
return;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,8 +49,7 @@ import jakarta.inject.Inject;
|
|||
*
|
||||
* <p>
|
||||
* Der Adapter kopiert die Steuerbescheiddaten in neue Zeilen, welche ab
|
||||
* Zeilennummer
|
||||
* 16 eingefügt werden.
|
||||
* Zeilennummer 16 eingefügt werden.
|
||||
* <p>
|
||||
*
|
||||
* Abschliessend wird die Zelle 'TOTAL' noch aktualisiert.
|
||||
|
|
@ -61,245 +60,232 @@ import jakarta.inject.Inject;
|
|||
*/
|
||||
public class AGLAnalyticExcelAdapter extends POIFindReplaceAdapter {
|
||||
|
||||
private static Logger logger = Logger.getLogger(AGLAnalyticExcelAdapter.class.getName());
|
||||
private static Logger logger = Logger.getLogger(AGLAnalyticExcelAdapter.class.getName());
|
||||
|
||||
@Inject
|
||||
WorkflowService workflowService;
|
||||
@Inject
|
||||
WorkflowService workflowService;
|
||||
|
||||
@Inject
|
||||
InvoiceService opListExportService;
|
||||
@Inject
|
||||
InvoiceService opListExportService;
|
||||
|
||||
@Inject
|
||||
DocumentService documentService;
|
||||
@Inject
|
||||
DocumentService documentService;
|
||||
|
||||
@Inject
|
||||
ConfigService configService;
|
||||
@Inject
|
||||
ConfigService configService;
|
||||
|
||||
/**
|
||||
* This method finds or create the Zahlungsavis and adds a reference
|
||||
* ($workitemref) to the current invoice.
|
||||
*
|
||||
* @throws PluginException
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public ItemCollection execute(ItemCollection document, ItemCollection event)
|
||||
throws AdapterException, PluginException {
|
||||
/**
|
||||
* This method finds or create the Zahlungsavis and adds a reference
|
||||
* ($workitemref) to the current invoice.
|
||||
*
|
||||
* @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(),
|
||||
InvoiceService.ERROR_CONFIG,
|
||||
"missing Currency configuration - please check parameters");
|
||||
}
|
||||
|
||||
// read the Steuerbescheide options
|
||||
ItemCollection steuerbescheideConfig = workflowService.evalWorkflowResult(event, "steuerbescheide",
|
||||
document,
|
||||
false);
|
||||
if (steuerbescheideConfig == null || !steuerbescheideConfig.hasItem("excel-export")) {
|
||||
throw new PluginException(AGLAnalyticExcelAdapter.class.getSimpleName(), CONFIG_ERROR,
|
||||
"missing Steuerbescheide configuration in model event - please check model configuration");
|
||||
}
|
||||
List<String> excelDefList = steuerbescheideConfig.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(),
|
||||
InvoiceService.ERROR_CONFIG,
|
||||
"failed to update steuerbescheide: " + e.getMessage());
|
||||
}
|
||||
logger.info("... completed!");
|
||||
return document;
|
||||
// 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(), InvoiceService.ERROR_CONFIG,
|
||||
"missing Currency configuration - please check parameters");
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
// read the Steuerbescheide options
|
||||
ItemCollection steuerbescheideConfig = workflowService.evalWorkflowResult(event, "steuerbescheide", document,
|
||||
false);
|
||||
if (steuerbescheideConfig == null || !steuerbescheideConfig.hasItem("excel-export")) {
|
||||
throw new PluginException(AGLAnalyticExcelAdapter.class.getSimpleName(), CONFIG_ERROR,
|
||||
"missing Steuerbescheide configuration in model event - please check model configuration");
|
||||
}
|
||||
List<String> excelDefList = steuerbescheideConfig.getItemValue("excel-export");
|
||||
ItemCollection excelDefCollection = XMLParser.parseItemStructure(excelDefList.get(0));
|
||||
|
||||
// load dummy rechnungen
|
||||
List<ItemCollection> invoices = loadSteuerbescheide();
|
||||
String textblock = excelDefCollection.getItemValueString("textblock");
|
||||
String template = excelDefCollection.getItemValueString("template");
|
||||
String targetName = excelDefCollection.getItemValueString("target-name");
|
||||
|
||||
FileData fileData = document.getFileData(fileName);
|
||||
// adapt text....
|
||||
targetName = workflowService.adaptText(targetName, document);
|
||||
|
||||
// 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);
|
||||
try {
|
||||
appendExcelTemplate(document, textblock, template, targetName);
|
||||
insertInvoiceRows(document, targetName);
|
||||
|
||||
// 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.booking_date"));
|
||||
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");
|
||||
|
||||
// Ä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)
|
||||
.setCellValue(invoice.getItemValueString("steuer.anmelder"));
|
||||
logger.info("... update template with normal poi information..");
|
||||
this.updateFileData(document.getFileData(targetName), document, replaceDevList, eval);
|
||||
|
||||
row.getCell(5, MissingCellPolicy.CREATE_NULL_AS_BLANK)
|
||||
.setCellValue(invoice.getItemValueString("invoice.text"));
|
||||
row.getCell(6, MissingCellPolicy.CREATE_NULL_AS_BLANK)
|
||||
.setCellValue(invoice.getItemValueString("invoice.atc.number"));
|
||||
row.getCell(7, MissingCellPolicy.CREATE_NULL_AS_BLANK)
|
||||
.setCellValue(invoice.getItemValueDouble("invoice.total.net"));
|
||||
row.getCell(8, MissingCellPolicy.CREATE_NULL_AS_BLANK)
|
||||
.setCellValue(invoice.getItemValueDouble("invoice.saldo"));
|
||||
row.getCell(9, MissingCellPolicy.CREATE_NULL_AS_BLANK)
|
||||
.setCellValue(invoice.getItemValueDouble("steuer.eust"));
|
||||
row.getCell(10, MissingCellPolicy.CREATE_NULL_AS_BLANK)
|
||||
.setCellValue(invoice.getItemValueDate("steuer.eust.due"));
|
||||
row.getCell(11, MissingCellPolicy.CREATE_NULL_AS_BLANK)
|
||||
.setCellValue(invoice.getItemValueDouble("steuer.zoll"));
|
||||
row.getCell(12, MissingCellPolicy.CREATE_NULL_AS_BLANK)
|
||||
.setCellValue(invoice.getItemValueDate("steuer.zoll.due"));
|
||||
} catch (PluginException | IOException | QueryException e) {
|
||||
throw new PluginException(AGLAnalyticExcelAdapter.class.getSimpleName(), InvoiceService.ERROR_CONFIG,
|
||||
"failed to update steuerbescheide: " + e.getMessage());
|
||||
}
|
||||
logger.info("... completed!");
|
||||
return document;
|
||||
}
|
||||
|
||||
rowPos++;
|
||||
}
|
||||
/**
|
||||
* 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 {
|
||||
|
||||
// Leerzeile
|
||||
// categoryRow = sheet.createRow(rowPos);
|
||||
rowPos++;
|
||||
// load dummy rechnungen
|
||||
List<ItemCollection> invoices = loadSteuerbescheide();
|
||||
|
||||
// write back the file
|
||||
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
|
||||
doc.write(byteArrayOutputStream);
|
||||
FileData fileData = document.getFileData(fileName);
|
||||
|
||||
byte[] newContent = byteArrayOutputStream.toByteArray();
|
||||
FileData fileDataNew = new FileData(fileData.getName(), newContent, fileData.getContentType(),
|
||||
null);
|
||||
// update the fileData
|
||||
document.addFileData(fileDataNew);
|
||||
// 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);
|
||||
|
||||
logger.finest("......new document added");
|
||||
// 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.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)
|
||||
.setCellValue(invoice.getItemValueString("steuer.anmelder"));
|
||||
|
||||
row.getCell(5, MissingCellPolicy.CREATE_NULL_AS_BLANK)
|
||||
.setCellValue(invoice.getItemValueString("invoice.text"));
|
||||
row.getCell(6, MissingCellPolicy.CREATE_NULL_AS_BLANK)
|
||||
.setCellValue(invoice.getItemValueString("invoice.atc.number"));
|
||||
row.getCell(7, MissingCellPolicy.CREATE_NULL_AS_BLANK)
|
||||
.setCellValue(invoice.getItemValueDouble("invoice.total.net"));
|
||||
row.getCell(8, MissingCellPolicy.CREATE_NULL_AS_BLANK)
|
||||
.setCellValue(invoice.getItemValueDouble("invoice.saldo"));
|
||||
row.getCell(9, MissingCellPolicy.CREATE_NULL_AS_BLANK)
|
||||
.setCellValue(invoice.getItemValueDouble("steuer.eust"));
|
||||
row.getCell(10, MissingCellPolicy.CREATE_NULL_AS_BLANK)
|
||||
.setCellValue(invoice.getItemValueDate("steuer.eust.due"));
|
||||
row.getCell(11, MissingCellPolicy.CREATE_NULL_AS_BLANK)
|
||||
.setCellValue(invoice.getItemValueDouble("steuer.zoll"));
|
||||
row.getCell(12, MissingCellPolicy.CREATE_NULL_AS_BLANK)
|
||||
.setCellValue(invoice.getItemValueDate("steuer.zoll.due"));
|
||||
|
||||
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(), InvoiceService.ERROR_CONFIG,
|
||||
"failed to update opliste: " + e.getMessage());
|
||||
} finally {
|
||||
if (doc != null) {
|
||||
try {
|
||||
doc.close();
|
||||
} catch (IOException e) {
|
||||
throw new PluginException(AGLAnalyticExcelAdapter.class.getSimpleName(),
|
||||
InvoiceService.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();
|
||||
}
|
||||
}
|
||||
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(), InvoiceService.ERROR_CONFIG,
|
||||
"invalid steuerbescheide configuration in model event - textblock/template reference not defined!");
|
||||
}
|
||||
|
||||
/**
|
||||
* 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(),
|
||||
InvoiceService.ERROR_CONFIG,
|
||||
"invalid steuerbescheide 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(),
|
||||
InvoiceService.ERROR_CONFIG,
|
||||
"invalid steuerbescheide configuration in model event - template=" + template
|
||||
+ " not found!");
|
||||
}
|
||||
fileData.setName(targetName);
|
||||
// append document
|
||||
logger.info("...append new steuerbescheide Template: " + targetName);
|
||||
document.addFileData(fileData);
|
||||
// load the text block
|
||||
FileData fileData = opListExportService.loadTextBlockFileData(textblockRef, template);
|
||||
|
||||
// do we found the document?
|
||||
if (fileData == null) {
|
||||
throw new PluginException(AGLAnalyticExcelAdapter.class.getSimpleName(), InvoiceService.ERROR_CONFIG,
|
||||
"invalid steuerbescheide configuration in model event - template=" + template + " not found!");
|
||||
}
|
||||
fileData.setName(targetName);
|
||||
// append document
|
||||
logger.info("...append new steuerbescheide Template: " + targetName);
|
||||
document.addFileData(fileData);
|
||||
|
||||
/**
|
||||
* Diese Methode läd alle offenen Steuerbescheide
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private List<ItemCollection> loadSteuerbescheide() {
|
||||
List<ItemCollection> result = new ArrayList<>();
|
||||
try {
|
||||
result = documentService.find(
|
||||
"$modelversion:steuerbescheid-* AND type:workitem", 9999, 0,
|
||||
"invoice.number", false);
|
||||
} catch (QueryException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Diese Methode läd alle offenen Steuerbescheide
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private List<ItemCollection> loadSteuerbescheide() {
|
||||
List<ItemCollection> result = new ArrayList<>();
|
||||
try {
|
||||
result = documentService.find("$modelversion:steuerbescheid-* AND type:workitem", 9999, 0, "invoice.number",
|
||||
false);
|
||||
} catch (QueryException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -52,8 +52,7 @@ import jakarta.inject.Inject;
|
|||
*
|
||||
* <p>
|
||||
* Der Adapter kopiert die ausgangsrechnungen in neue Zeilen, welche ab
|
||||
* Zeilennummer
|
||||
* 16 eingefügt werden.
|
||||
* Zeilennummer 16 eingefügt werden.
|
||||
* <p>
|
||||
*
|
||||
* Abschliessend wird die Zelle 'TOTAL' noch aktualisiert.
|
||||
|
|
@ -92,9 +91,7 @@ public class AGLAnalyticExcelAdapterDebitor extends POIFindReplaceAdapter {
|
|||
List<String> currencyList = invoiceService.getCurrenciesOut();
|
||||
|
||||
// read the options
|
||||
ItemCollection ausgangsrechnungConfig = workflowService.evalWorkflowResult(event, "soa",
|
||||
document,
|
||||
false);
|
||||
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");
|
||||
|
|
@ -129,14 +126,12 @@ public class AGLAnalyticExcelAdapterDebitor extends POIFindReplaceAdapter {
|
|||
doc.write(byteArrayOutputStream);
|
||||
|
||||
byte[] newContent = byteArrayOutputStream.toByteArray();
|
||||
FileData fileDataNew = new FileData(fileData.getName(), newContent, fileData.getContentType(),
|
||||
null);
|
||||
FileData fileDataNew = new FileData(fileData.getName(), newContent, fileData.getContentType(), null);
|
||||
document.addFileData(fileDataNew);
|
||||
logger.finest("......new document added");
|
||||
|
||||
} catch (IOException | QueryException e) {
|
||||
throw new PluginException(AGLAnalyticExcelAdapter.class.getSimpleName(),
|
||||
InvoiceService.ERROR_CONFIG,
|
||||
throw new PluginException(AGLAnalyticExcelAdapter.class.getSimpleName(), InvoiceService.ERROR_CONFIG,
|
||||
"failed to update opliste: " + e.getMessage());
|
||||
} finally {
|
||||
if (doc != null) {
|
||||
|
|
@ -153,8 +148,7 @@ public class AGLAnalyticExcelAdapterDebitor extends POIFindReplaceAdapter {
|
|||
processPOIUpdate(document, event, targetName);
|
||||
|
||||
} catch (PluginException e) {
|
||||
throw new PluginException(AGLAnalyticExcelAdapter.class.getSimpleName(),
|
||||
InvoiceService.ERROR_CONFIG,
|
||||
throw new PluginException(AGLAnalyticExcelAdapter.class.getSimpleName(), InvoiceService.ERROR_CONFIG,
|
||||
"failed to update steuerbescheide: " + e.getMessage());
|
||||
}
|
||||
logger.info("... completed!");
|
||||
|
|
@ -213,8 +207,8 @@ public class AGLAnalyticExcelAdapterDebitor extends POIFindReplaceAdapter {
|
|||
}
|
||||
|
||||
/**
|
||||
* This helper method inserts a row for each invoice at row 16
|
||||
* into the excel template file
|
||||
* 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>
|
||||
|
|
@ -249,8 +243,7 @@ public class AGLAnalyticExcelAdapterDebitor extends POIFindReplaceAdapter {
|
|||
XSSFRow row = sheet.createRow(rowPos);
|
||||
row.copyRowFrom(referenceRowInvoice, new CellCopyPolicy());
|
||||
// insert values
|
||||
row.getCell(0)
|
||||
.setCellValue(invoice.getItemValueDate("$created"));
|
||||
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)
|
||||
|
|
@ -318,12 +311,10 @@ public class AGLAnalyticExcelAdapterDebitor extends POIFindReplaceAdapter {
|
|||
* @throws PluginException
|
||||
*/
|
||||
private FileData appendExcelTemplate(ItemCollection document, String textblockRef, String template,
|
||||
String targetName)
|
||||
throws PluginException {
|
||||
String targetName) throws PluginException {
|
||||
|
||||
if ((template == null || template.isEmpty()) || (textblockRef == null || textblockRef.isEmpty())) {
|
||||
throw new PluginException(AGLAnalyticExcelAdapter.class.getSimpleName(),
|
||||
InvoiceService.ERROR_CONFIG,
|
||||
throw new PluginException(AGLAnalyticExcelAdapter.class.getSimpleName(), InvoiceService.ERROR_CONFIG,
|
||||
"invalid SOA configuration in model event - textblock/template reference not defined!");
|
||||
}
|
||||
|
||||
|
|
@ -332,10 +323,8 @@ public class AGLAnalyticExcelAdapterDebitor extends POIFindReplaceAdapter {
|
|||
|
||||
// do we found the document?
|
||||
if (fileData == null) {
|
||||
throw new PluginException(AGLAnalyticExcelAdapter.class.getSimpleName(),
|
||||
InvoiceService.ERROR_CONFIG,
|
||||
"invalid SOA configuration in model event - template=" + template
|
||||
+ " not found!");
|
||||
throw new PluginException(AGLAnalyticExcelAdapter.class.getSimpleName(), InvoiceService.ERROR_CONFIG,
|
||||
"invalid SOA configuration in model event - template=" + template + " not found!");
|
||||
}
|
||||
fileData.setName(targetName);
|
||||
// append document
|
||||
|
|
@ -352,12 +341,9 @@ public class AGLAnalyticExcelAdapterDebitor extends POIFindReplaceAdapter {
|
|||
private List<ItemCollection> loadInvoices(String dbtrNumber) {
|
||||
List<ItemCollection> result = new ArrayList<>();
|
||||
|
||||
String query = "(type:workitem) AND dbtr.number:" + dbtrNumber
|
||||
+ " AND $modelversion:rechnungsausgang-*";
|
||||
String query = "(type:workitem) AND dbtr.number:" + dbtrNumber + " AND $modelversion:rechnungsausgang-*";
|
||||
try {
|
||||
result = documentService.find(
|
||||
query, 9999, 0,
|
||||
"invoice.number", false);
|
||||
result = documentService.find(query, 9999, 0, "invoice.number", false);
|
||||
} catch (QueryException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -109,9 +109,8 @@ public class BusinessPartnerController implements Serializable {
|
|||
*
|
||||
* {@code
|
||||
<h:commandScript name="datevSearch" action=
|
||||
* "#{datevSearchController.searchCdtr()}"
|
||||
* render="autocomplete-resultlist-datev" onevent="autocompleteShowResult" />
|
||||
* }
|
||||
* "#{datevSearchController.searchCdtr()}" render=
|
||||
* "autocomplete-resultlist-datev" onevent="autocompleteShowResult" /> }
|
||||
*/
|
||||
public void search(String options) {
|
||||
List<ItemCollection> resultList = null;
|
||||
|
|
@ -160,10 +159,9 @@ public class BusinessPartnerController implements Serializable {
|
|||
|
||||
/**
|
||||
* Diese Helper Method liefert true wenn in den Options von Form Part 'reRender'
|
||||
* angegeben wurde.
|
||||
* Damit löst die Suchmaske businesspartner_search.xhtml eine komplette rerender
|
||||
* Phase der Form aus.
|
||||
* Dies ist z.b. für den workflow 'analyse-debitor.bpmn' nützlich
|
||||
* angegeben wurde. Damit löst die Suchmaske businesspartner_search.xhtml eine
|
||||
* komplette rerender Phase der Form aus. Dies ist z.b. für den workflow
|
||||
* 'analyse-debitor.bpmn' nützlich
|
||||
*
|
||||
* @param options
|
||||
* @return
|
||||
|
|
@ -277,16 +275,16 @@ public class BusinessPartnerController implements Serializable {
|
|||
if (!dbtrNumber.isEmpty()) {
|
||||
invoicesOut = businessPartnerService.findOutgoingInvoices(dbtrNumber);
|
||||
// Mahnungen
|
||||
String query = "(type:workitem) AND ($modelversion:mahnlauf-*) "
|
||||
+ " AND (dbtr.number:" + dbtrNumber + ")";
|
||||
String query = "(type:workitem) AND ($modelversion:mahnlauf-*) " + " AND (dbtr.number:" + dbtrNumber
|
||||
+ ")";
|
||||
dunnings = documentService.findStubs(query, 999, 0, "invoice.number", false);
|
||||
}
|
||||
|
||||
// Eingangsrechnungen
|
||||
String cdtrNumber = workitem.getItemValueString("cdtr.number");
|
||||
if (!cdtrNumber.isEmpty()) {
|
||||
String query = "(type:workitem) AND ($modelversion:rechnungseingang-*) "
|
||||
+ " AND (cdtr.number:" + cdtrNumber + ")";
|
||||
String query = "(type:workitem) AND ($modelversion:rechnungseingang-*) " + " AND (cdtr.number:"
|
||||
+ cdtrNumber + ")";
|
||||
invoicesIn = documentService.findStubs(query, 999, 0, "invoice.number", false);
|
||||
}
|
||||
|
||||
|
|
@ -329,8 +327,8 @@ public class BusinessPartnerController implements Serializable {
|
|||
* user has selected a new businesspartner.
|
||||
* <p>
|
||||
* The method lookups the given BusinessPartner and updates the metadata for
|
||||
* dbtr/cdtr depending on the workflow type.
|
||||
* A form will than rerender the opList section.
|
||||
* dbtr/cdtr depending on the workflow type. A form will than rerender the
|
||||
* opList section.
|
||||
*/
|
||||
public void updateMetaData() {
|
||||
FacesContext fc = FacesContext.getCurrentInstance();
|
||||
|
|
@ -345,8 +343,7 @@ public class BusinessPartnerController implements Serializable {
|
|||
businessPartner.getItemValueString("cdtr.number"));
|
||||
workflowController.getWorkitem().setItemValue("cdtr.name",
|
||||
businessPartner.getItemValueString("partner.name"));
|
||||
workflowController.getWorkitem().setItemValue("cdtr.mail",
|
||||
businessPartner.getItemValue("cdtr.mail"));
|
||||
workflowController.getWorkitem().setItemValue("cdtr.mail", businessPartner.getItemValue("cdtr.mail"));
|
||||
}
|
||||
|
||||
// Ausgangsrechnung
|
||||
|
|
@ -355,8 +352,7 @@ public class BusinessPartnerController implements Serializable {
|
|||
businessPartner.getItemValueString("dbtr.number"));
|
||||
workflowController.getWorkitem().setItemValue("dbtr.name",
|
||||
businessPartner.getItemValueString("partner.name"));
|
||||
workflowController.getWorkitem().setItemValue("dbtr.mail",
|
||||
businessPartner.getItemValue("dbtr.mail"));
|
||||
workflowController.getWorkitem().setItemValue("dbtr.mail", businessPartner.getItemValue("dbtr.mail"));
|
||||
}
|
||||
|
||||
// Zahlungseingang
|
||||
|
|
@ -365,8 +361,7 @@ public class BusinessPartnerController implements Serializable {
|
|||
businessPartner.getItemValueString("dbtr.number"));
|
||||
workflowController.getWorkitem().setItemValue("dbtr.name",
|
||||
businessPartner.getItemValueString("partner.name"));
|
||||
workflowController.getWorkitem().setItemValue("dbtr.mail",
|
||||
businessPartner.getItemValue("dbtr.mail"));
|
||||
workflowController.getWorkitem().setItemValue("dbtr.mail", businessPartner.getItemValue("dbtr.mail"));
|
||||
}
|
||||
|
||||
// Analyse Debitor
|
||||
|
|
@ -375,8 +370,7 @@ public class BusinessPartnerController implements Serializable {
|
|||
businessPartner.getItemValueString("dbtr.number"));
|
||||
workflowController.getWorkitem().setItemValue("dbtr.name",
|
||||
businessPartner.getItemValueString("partner.name"));
|
||||
workflowController.getWorkitem().setItemValue("dbtr.mail",
|
||||
businessPartner.getItemValue("dbtr.mail"));
|
||||
workflowController.getWorkitem().setItemValue("dbtr.mail", businessPartner.getItemValue("dbtr.mail"));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,38 +11,38 @@ package com.alexanderlogistics;
|
|||
*/
|
||||
public class BusinessPartnerSearchEntry {
|
||||
|
||||
private String key;
|
||||
private String display;
|
||||
private String data;
|
||||
private String key;
|
||||
private String display;
|
||||
private String data;
|
||||
|
||||
public BusinessPartnerSearchEntry(String key, String display, String data) {
|
||||
super();
|
||||
this.key = key;
|
||||
this.display = display;
|
||||
this.data = data;
|
||||
}
|
||||
public BusinessPartnerSearchEntry(String key, String display, String data) {
|
||||
super();
|
||||
this.key = key;
|
||||
this.display = display;
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
public String getKey() {
|
||||
return key;
|
||||
}
|
||||
public String getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
public void setKey(String key) {
|
||||
this.key = key;
|
||||
}
|
||||
public void setKey(String key) {
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
public String getDisplay() {
|
||||
return display;
|
||||
}
|
||||
public String getDisplay() {
|
||||
return display;
|
||||
}
|
||||
|
||||
public void setDisplay(String display) {
|
||||
this.display = display;
|
||||
}
|
||||
public void setDisplay(String display) {
|
||||
this.display = display;
|
||||
}
|
||||
|
||||
public String getData() {
|
||||
return data;
|
||||
}
|
||||
public String getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
public void setData(String data) {
|
||||
this.data = data;
|
||||
}
|
||||
public void setData(String data) {
|
||||
this.data = data;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ import jakarta.annotation.PostConstruct;
|
|||
import jakarta.annotation.security.DeclareRoles;
|
||||
import jakarta.annotation.security.RolesAllowed;
|
||||
import jakarta.annotation.security.RunAs;
|
||||
import jakarta.ejb.Singleton;
|
||||
import jakarta.ejb.Stateless;
|
||||
import jakarta.inject.Inject;
|
||||
|
||||
/**
|
||||
|
|
@ -68,7 +68,7 @@ import jakarta.inject.Inject;
|
|||
@RolesAllowed({ "org.imixs.ACCESSLEVEL.NOACCESS", "org.imixs.ACCESSLEVEL.READERACCESS",
|
||||
"org.imixs.ACCESSLEVEL.AUTHORACCESS", "org.imixs.ACCESSLEVEL.EDITORACCESS",
|
||||
"org.imixs.ACCESSLEVEL.MANAGERACCESS" })
|
||||
@Singleton
|
||||
@Stateless
|
||||
@RunAs("org.imixs.ACCESSLEVEL.MANAGERACCESS")
|
||||
public class BusinessPartnerService {
|
||||
|
||||
|
|
@ -121,9 +121,8 @@ public class BusinessPartnerService {
|
|||
|
||||
/**
|
||||
* Diese Methode aktualisiert das business Partner object. Sie wird von den
|
||||
* Invoice Plugins genutzt.
|
||||
* Die Methode wirft eine PluginException falls das BusinessPartner Objekt
|
||||
* gesperrt oder in verification ist!
|
||||
* Invoice Plugins genutzt. Die Methode wirft eine PluginException falls das
|
||||
* BusinessPartner Objekt gesperrt oder in verification ist!
|
||||
*
|
||||
* Gleichzeitig wird bei Rechnungen in Abhängigkeit der Rechnungsart die
|
||||
* dbtr./cdtr. items sowie mail und country aktualisiert.
|
||||
|
|
@ -145,8 +144,18 @@ public class BusinessPartnerService {
|
|||
workitem.setItemValue("partner.id", partnerID);
|
||||
}
|
||||
|
||||
if (partnerID == null || partnerID.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
// load Business Partner
|
||||
ItemCollection businessPartner = getBusinessPartnerByID(partnerID);
|
||||
if (businessPartner == null) {
|
||||
return;
|
||||
}
|
||||
// because the method can be called multiple times within one worklfow
|
||||
// processing cycle
|
||||
// we need to load the object within the current transaction context
|
||||
businessPartner = documentService.load(businessPartner.getUniqueID());
|
||||
if (businessPartner != null) {
|
||||
workitem.setItemValue("partner.name", businessPartner.getItemValueString("partner.name"));
|
||||
|
||||
|
|
@ -166,13 +175,11 @@ public class BusinessPartnerService {
|
|||
|
||||
// Validate Business Partner Status!
|
||||
if (businessPartner.getTaskID() == TASK_VERIFICATION) {
|
||||
throw new PluginException(InvoicePlugin.class.getName(),
|
||||
ERROR_BUSINESSPARTNER_VERIFICATION,
|
||||
throw new PluginException(InvoicePlugin.class.getName(), ERROR_BUSINESSPARTNER_VERIFICATION,
|
||||
"Businesspartner is in verification. Invoice can't be processed!");
|
||||
}
|
||||
if (businessPartner.getTaskID() == TASK_LOCKED) {
|
||||
throw new PluginException(InvoicePlugin.class.getName(),
|
||||
ERROR_BUSINESSPARTNER_LOCKED,
|
||||
throw new PluginException(InvoicePlugin.class.getName(), ERROR_BUSINESSPARTNER_LOCKED,
|
||||
"Businesspartner is locked. Invoice can't be processed!");
|
||||
}
|
||||
// update business partner status...
|
||||
|
|
@ -225,8 +232,7 @@ public class BusinessPartnerService {
|
|||
/**
|
||||
* Diese Methode sucht einen Business Partner anhand seiner BPID
|
||||
*
|
||||
* @param bpid
|
||||
* - business partner id phrase
|
||||
* @param bpid - business partner id phrase
|
||||
* @return - matching business partner
|
||||
*/
|
||||
public ItemCollection getBusinessPartnerByID(String bpid) {
|
||||
|
|
@ -251,8 +257,7 @@ public class BusinessPartnerService {
|
|||
/**
|
||||
* Diese Methode sucht Business Partner anhand einer Suchphrase
|
||||
*
|
||||
* @param phrase
|
||||
* - search phrase
|
||||
* @param phrase - search phrase
|
||||
* @return - list of matching business partners
|
||||
*/
|
||||
public List<ItemCollection> search(String phrase) {
|
||||
|
|
@ -386,8 +391,7 @@ public class BusinessPartnerService {
|
|||
|
||||
List<ItemCollection> bankenListe = explodeBanks(businessPartner);
|
||||
for (ItemCollection bank : bankenListe) {
|
||||
if (iban.equals(bank.getItemValueString("iban"))
|
||||
&& bic.equals(bank.getItemValueString("bic"))) {
|
||||
if (iban.equals(bank.getItemValueString("iban")) && bic.equals(bank.getItemValueString("bic"))) {
|
||||
// known!
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -113,8 +113,8 @@ public class CargosoftExportAdapter implements SignalAdapter {
|
|||
// finally append the success event id
|
||||
document.event(EVENT_SUCCESS);
|
||||
|
||||
} catch (PluginException | IOException
|
||||
| jakarta.xml.bind.JAXBException | javax.xml.transform.TransformerException e) {
|
||||
} catch (PluginException | IOException | jakarta.xml.bind.JAXBException
|
||||
| javax.xml.transform.TransformerException e) {
|
||||
logger.severe("cargosoft export failed: " + e.getMessage());
|
||||
document.setItemValue("cargosoft.error", e.getMessage());
|
||||
document.event(EVENT_FAILURE);
|
||||
|
|
|
|||
|
|
@ -246,8 +246,7 @@ public class CustomSearchController implements Serializable {
|
|||
|
||||
Date endDate = endCalendar.getTime();
|
||||
SimpleDateFormat dateformat = new SimpleDateFormat("yyyyMMddHHmm");
|
||||
String dateRange = "[" + dateformat.format(startDate) + " TO "
|
||||
+ dateformat.format(endDate) + "]";
|
||||
String dateRange = "[" + dateformat.format(startDate) + " TO " + dateformat.format(endDate) + "]";
|
||||
|
||||
return dateRange;
|
||||
}
|
||||
|
|
@ -277,8 +276,7 @@ public class CustomSearchController implements Serializable {
|
|||
|
||||
Date endDate = endCalendar.getTime();
|
||||
SimpleDateFormat dateformat = new SimpleDateFormat("yyyyMMddHHmm");
|
||||
String dateRange = "[" + dateformat.format(startDate) + " TO "
|
||||
+ dateformat.format(endDate) + "]";
|
||||
String dateRange = "[" + dateformat.format(startDate) + " TO " + dateformat.format(endDate) + "]";
|
||||
|
||||
return dateRange;
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -30,138 +30,138 @@ import jakarta.inject.Named;
|
|||
@ConversationScoped
|
||||
public class InvoiceAnalyseController implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static Logger logger = Logger.getLogger(InvoiceAnalyseController.class.getName());
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static Logger logger = Logger.getLogger(InvoiceAnalyseController.class.getName());
|
||||
|
||||
@Inject
|
||||
protected DocumentService documentService;
|
||||
@Inject
|
||||
protected DocumentService documentService;
|
||||
|
||||
@Inject
|
||||
SearchService searchService;
|
||||
@Inject
|
||||
SearchService searchService;
|
||||
|
||||
Category sachpruefung;
|
||||
Category verteilung;
|
||||
Category buchhaltung;
|
||||
Category sachpruefung;
|
||||
Category verteilung;
|
||||
Category buchhaltung;
|
||||
|
||||
private ItemCollection filter;
|
||||
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 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 void setFilter(ItemCollection filter) {
|
||||
this.filter = filter;
|
||||
}
|
||||
|
||||
public Category getSachpruefung() {
|
||||
return sachpruefung;
|
||||
}
|
||||
public Category getSachpruefung() {
|
||||
return sachpruefung;
|
||||
}
|
||||
|
||||
public Category getVerteilung() {
|
||||
return verteilung;
|
||||
}
|
||||
public Category getVerteilung() {
|
||||
return verteilung;
|
||||
}
|
||||
|
||||
public Category getBuchhaltung() {
|
||||
return buchhaltung;
|
||||
}
|
||||
public Category getBuchhaltung() {
|
||||
return buchhaltung;
|
||||
}
|
||||
|
||||
public int totalCountByCategory(Category cat) {
|
||||
int result = 0;
|
||||
public int totalCountByCategory(Category cat) {
|
||||
int result = 0;
|
||||
|
||||
Collection<Integer> allCounts = cat.getLabels().values();
|
||||
result = allCounts.stream().reduce(0, Integer::sum);
|
||||
Collection<Integer> allCounts = cat.getLabels().values();
|
||||
result = allCounts.stream().reduce(0, Integer::sum);
|
||||
|
||||
return result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fuert verschiedene Queries aus um eine Analyse der Sachprufung durchzuführen.
|
||||
*/
|
||||
public void analyse() {
|
||||
/**
|
||||
* 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("start analyse....");
|
||||
verteilung = null;
|
||||
sachpruefung = null;
|
||||
Date start = filter.getItemValueDate("start");
|
||||
Date stop = filter.getItemValueDate("stop");
|
||||
|
||||
logger.info("...daterange=" + start + " - " + 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");
|
||||
// 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());
|
||||
}
|
||||
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 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 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);
|
||||
// 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");
|
||||
}
|
||||
/**
|
||||
* This method reset the search and input state.
|
||||
*/
|
||||
public void reset() {
|
||||
filter = new ItemCollection();
|
||||
sachpruefung = null;
|
||||
verteilung = null;
|
||||
buchhaltung = null;
|
||||
logger.fine("reset");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,31 +17,31 @@ import jakarta.inject.Inject;
|
|||
*/
|
||||
public class InvoiceOutgoingPlugin extends AbstractPlugin {
|
||||
|
||||
@Inject
|
||||
BusinessPartnerService businessPartnerService;
|
||||
@Inject
|
||||
BusinessPartnerService businessPartnerService;
|
||||
|
||||
/**
|
||||
*
|
||||
* @throws PluginException - if data is missing
|
||||
*
|
||||
**/
|
||||
@Override
|
||||
public ItemCollection run(ItemCollection workitem, ItemCollection event) throws PluginException {
|
||||
/**
|
||||
*
|
||||
* @throws PluginException - if data is missing
|
||||
*
|
||||
**/
|
||||
@Override
|
||||
public ItemCollection run(ItemCollection workitem, ItemCollection event) throws PluginException {
|
||||
|
||||
// Update BUsiness Partner Data
|
||||
businessPartnerService.updateBusinessPartnerData(workitem);
|
||||
// Update BUsiness Partner Data
|
||||
businessPartnerService.updateBusinessPartnerData(workitem);
|
||||
|
||||
// Update Invoice.positions
|
||||
InvoiceUtil.updateInvoicePositions(workitem);
|
||||
// Update Invoice.positions
|
||||
InvoiceUtil.updateInvoicePositions(workitem);
|
||||
|
||||
String img = "";
|
||||
if (workitem.getItemValueBoolean("invoice.protest")) {
|
||||
img = img + "<img title='Reklamiert' src=\"/layout/icons/icon106.png\">";
|
||||
String img = "";
|
||||
if (workitem.getItemValueBoolean("invoice.protest")) {
|
||||
img = img + "<img title='Reklamiert' src=\"/layout/icons/icon106.png\">";
|
||||
|
||||
}
|
||||
workitem.setItemValue("_img", img);
|
||||
}
|
||||
workitem.setItemValue("_img", img);
|
||||
|
||||
return workitem;
|
||||
}
|
||||
return workitem;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,8 +36,8 @@ import jakarta.inject.Inject;
|
|||
* 2.2.22 - Das Plugin erzeugt auch das Feld _img welches die Images von
|
||||
* Sofortüberweisung, Mahnung und Ablehnung anzeigt.
|
||||
*
|
||||
* 26.4.25 - Das Plugin setzt nun auch partner.name und partner.id
|
||||
* zusätzlich processed es das BP Workitem
|
||||
* 26.4.25 - Das Plugin setzt nun auch partner.name und partner.id zusätzlich
|
||||
* processed es das BP Workitem
|
||||
*
|
||||
* @author rsoika
|
||||
* @version 1.0
|
||||
|
|
@ -45,393 +45,392 @@ import jakarta.inject.Inject;
|
|||
*/
|
||||
public class InvoicePlugin extends AbstractPlugin {
|
||||
|
||||
public static final int TASK_ERFASSUNG = 5001;
|
||||
public static final int TASK_SACHPRUEFUNG = 5200;
|
||||
public static final int TASK_SACHPRUEFUNG_DELEGATION = 5210;
|
||||
public static final int EVENT_FREIGEBEN = 20;
|
||||
public static final int TASK_ERFASSUNG = 5001;
|
||||
public static final int TASK_SACHPRUEFUNG = 5200;
|
||||
public static final int TASK_SACHPRUEFUNG_DELEGATION = 5210;
|
||||
public static final int EVENT_FREIGEBEN = 20;
|
||||
|
||||
public static final String ERROR_MISSING_DATA = "MISSING_DATA";
|
||||
public static final String ERROR_DUPPLICATE_INVOICE_NUMBER = "DUPPLICATE_INVOICE_NUMBER";
|
||||
public static final String ERROR_NEW_IBANBIC = "NEW_IBANBIC";
|
||||
public static final String ERROR_MISSING_DATA = "MISSING_DATA";
|
||||
public static final String ERROR_DUPPLICATE_INVOICE_NUMBER = "DUPPLICATE_INVOICE_NUMBER";
|
||||
public static final String ERROR_NEW_IBANBIC = "NEW_IBANBIC";
|
||||
|
||||
private static Logger logger = Logger.getLogger(InvoicePlugin.class.getName());
|
||||
private static Logger logger = Logger.getLogger(InvoicePlugin.class.getName());
|
||||
|
||||
// Positions Pattern - kann überschrieben werden
|
||||
// XX-YYY-####-### oder XX-YYYZZZ-####-###
|
||||
// Default = ([A-Z]{2}-[A-Z]{3}-[0-9]{4}-[0-9]{3})
|
||||
// Optional = ([A-Z]{2}-(?:[A-Z]{3}|[A-Z]{6})-[0-9]{4}-[0-9]{3})
|
||||
// Nur 6- Stellig = ([A-Z]{2}-(?:[A-Z]{6})-[0-9]{4}-[0-9]{3})
|
||||
public final static String INVOICE_POSITIONS_PATTERN_DEFAULT = "([A-Z]{2}-(?:[A-Z]{3}|[A-Z]{6})-[0-9]{4}-[0-9]{3})";
|
||||
// Positions Pattern - kann überschrieben werden
|
||||
// XX-YYY-####-### oder XX-YYYZZZ-####-###
|
||||
// Default = ([A-Z]{2}-[A-Z]{3}-[0-9]{4}-[0-9]{3})
|
||||
// Optional = ([A-Z]{2}-(?:[A-Z]{3}|[A-Z]{6})-[0-9]{4}-[0-9]{3})
|
||||
// Nur 6- Stellig = ([A-Z]{2}-(?:[A-Z]{6})-[0-9]{4}-[0-9]{3})
|
||||
public final static String INVOICE_POSITIONS_PATTERN_DEFAULT = "([A-Z]{2}-(?:[A-Z]{3}|[A-Z]{6})-[0-9]{4}-[0-9]{3})";
|
||||
|
||||
@Inject
|
||||
@ConfigProperty(name = "invoice.position.pattern", defaultValue = INVOICE_POSITIONS_PATTERN_DEFAULT)
|
||||
String invoicePositionsPattern;
|
||||
@Inject
|
||||
@ConfigProperty(name = "invoice.position.pattern", defaultValue = INVOICE_POSITIONS_PATTERN_DEFAULT)
|
||||
String invoicePositionsPattern;
|
||||
|
||||
@Inject
|
||||
BusinessPartnerService businessPartnerService;
|
||||
@Inject
|
||||
BusinessPartnerService businessPartnerService;
|
||||
|
||||
@Inject
|
||||
ResourceBundleHandler resourceBundleHandler;
|
||||
@Inject
|
||||
ResourceBundleHandler resourceBundleHandler;
|
||||
|
||||
/**
|
||||
* Test childworkitems for empty lines
|
||||
*
|
||||
* @throws PluginException - if data is missing
|
||||
*
|
||||
**/
|
||||
@Override
|
||||
public ItemCollection run(ItemCollection workitem, ItemCollection event) throws PluginException {
|
||||
/**
|
||||
* Test childworkitems for empty lines
|
||||
*
|
||||
* @throws PluginException - if data is missing
|
||||
*
|
||||
**/
|
||||
@Override
|
||||
public ItemCollection run(ItemCollection workitem, ItemCollection event) throws PluginException {
|
||||
|
||||
// Update BUsiness Partner Data
|
||||
businessPartnerService.updateBusinessPartnerData(workitem);
|
||||
// Update BUsiness Partner Data
|
||||
businessPartnerService.updateBusinessPartnerData(workitem);
|
||||
|
||||
updateImg(workitem);
|
||||
updateImg(workitem);
|
||||
|
||||
// Update Invoice.positions
|
||||
InvoiceUtil.updateInvoicePositions(workitem);
|
||||
// Update Invoice.positions
|
||||
InvoiceUtil.updateInvoicePositions(workitem);
|
||||
|
||||
// skip if validaten tag is required=false
|
||||
ItemCollection evalItemCollection = this.getWorkflowService().evalWorkflowResult(event, "validation", workitem);
|
||||
if (evalItemCollection != null) {
|
||||
// evaluate the validation rules...
|
||||
if ("false".equalsIgnoreCase(evalItemCollection.getItemValueString("required"))) {
|
||||
return workitem;
|
||||
}
|
||||
}
|
||||
// skip if validaten tag is required=false
|
||||
ItemCollection evalItemCollection = this.getWorkflowService().evalWorkflowResult(event, "validation", workitem);
|
||||
if (evalItemCollection != null) {
|
||||
// evaluate the validation rules...
|
||||
if ("false".equalsIgnoreCase(evalItemCollection.getItemValueString("required"))) {
|
||||
return workitem;
|
||||
}
|
||||
}
|
||||
|
||||
boolean isPublicEvent = !("0".equals(event.getItemValueString("keypublicresult")));
|
||||
boolean isPublicEvent = !("0".equals(event.getItemValueString("keypublicresult")));
|
||||
|
||||
// Payment.type muss immer eingetragne werden!
|
||||
if (isPublicEvent && workitem.getTaskID() >= TASK_ERFASSUNG && workitem.getEventID() < 900) {
|
||||
if (workitem.getItemValueString("payment.type").trim().isEmpty()) {
|
||||
// throw a plugin exception!
|
||||
String message = resourceBundleHandler.findMessage("ERROR_MISSING_PAYMENT");
|
||||
throw new PluginException(InvoicePlugin.class.getName(), ERROR_MISSING_DATA, message);
|
||||
}
|
||||
// doppelte Rechnungsnummer prüfen
|
||||
if (workitem.getTaskID() == TASK_ERFASSUNG) {
|
||||
validateInvoiceNumber(workitem);
|
||||
checkIBANNumber(workitem);
|
||||
}
|
||||
// Payment.type muss immer eingetragne werden!
|
||||
if (isPublicEvent && workitem.getTaskID() >= TASK_ERFASSUNG && workitem.getEventID() < 900) {
|
||||
if (workitem.getItemValueString("payment.type").trim().isEmpty()) {
|
||||
// throw a plugin exception!
|
||||
String message = resourceBundleHandler.findMessage("ERROR_MISSING_PAYMENT");
|
||||
throw new PluginException(InvoicePlugin.class.getName(), ERROR_MISSING_DATA, message);
|
||||
}
|
||||
// doppelte Rechnungsnummer prüfen
|
||||
if (workitem.getTaskID() == TASK_ERFASSUNG) {
|
||||
validateInvoiceNumber(workitem);
|
||||
checkIBANNumber(workitem);
|
||||
}
|
||||
|
||||
if (workitem.getTaskID() == TASK_ERFASSUNG || ((workitem.getTaskID() == TASK_SACHPRUEFUNG
|
||||
|| workitem.getTaskID() == TASK_SACHPRUEFUNG_DELEGATION)
|
||||
&& workitem.getEventID() == EVENT_FREIGEBEN)) {
|
||||
// Buchungsperiode auf plausi prüfen
|
||||
if (isCargoRechnung(workitem) && "workitem".equals(workitem.getType())) {
|
||||
validateBuchungsperiode(workitem.getItemValueString(InvoiceUtil.ITEM_INVOICE_PERIOD));
|
||||
}
|
||||
// Cargosoft Kreditorennnummer prüfen
|
||||
if (isCargoRechnung(workitem)) {
|
||||
validateCargosoftCdtrNumber(workitem);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (workitem.getTaskID() == TASK_ERFASSUNG || ((workitem.getTaskID() == TASK_SACHPRUEFUNG
|
||||
|| workitem.getTaskID() == TASK_SACHPRUEFUNG_DELEGATION)
|
||||
&& workitem.getEventID() == EVENT_FREIGEBEN)) {
|
||||
// Buchungsperiode auf plausi prüfen
|
||||
if (isCargoRechnung(workitem) && "workitem".equals(workitem.getType())) {
|
||||
validateBuchungsperiode(workitem.getItemValueString(InvoiceUtil.ITEM_INVOICE_PERIOD));
|
||||
}
|
||||
// Cargosoft Kreditorennnummer prüfen
|
||||
if (isCargoRechnung(workitem)) {
|
||||
validateCargosoftCdtrNumber(workitem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// die prüfung der positionsnummern und Category erfolgt nur im Status
|
||||
// Sachprüfung (5200) und nur beim Freigeben (20)!
|
||||
if (isCargoRechnung(workitem)
|
||||
&& ((workitem.getTaskID() == TASK_SACHPRUEFUNG || workitem.getTaskID() == TASK_SACHPRUEFUNG_DELEGATION)
|
||||
&& workitem.getEventID() == EVENT_FREIGEBEN)) {
|
||||
List<ItemCollection> childs = InvoiceUtil.explodeChildList(workitem);
|
||||
for (ItemCollection posItem : childs) {
|
||||
if (posItem.getItemValueString("name").trim().isEmpty()) {
|
||||
// throw a plugin exception - because name is missing!
|
||||
String message = resourceBundleHandler.findMessage("ERROR_MISSING_POSNO");
|
||||
message = message.replace("{1}", posItem.getItemValueString("numpos"));
|
||||
throw new PluginException(InvoicePlugin.class.getName(), ERROR_MISSING_DATA, message);
|
||||
}
|
||||
// die prüfung der positionsnummern und Category erfolgt nur im Status
|
||||
// Sachprüfung (5200) und nur beim Freigeben (20)!
|
||||
if (isCargoRechnung(workitem)
|
||||
&& ((workitem.getTaskID() == TASK_SACHPRUEFUNG || workitem.getTaskID() == TASK_SACHPRUEFUNG_DELEGATION)
|
||||
&& workitem.getEventID() == EVENT_FREIGEBEN)) {
|
||||
List<ItemCollection> childs = InvoiceUtil.explodeChildList(workitem);
|
||||
for (ItemCollection posItem : childs) {
|
||||
if (posItem.getItemValueString("name").trim().isEmpty()) {
|
||||
// throw a plugin exception - because name is missing!
|
||||
String message = resourceBundleHandler.findMessage("ERROR_MISSING_POSNO");
|
||||
message = message.replace("{1}", posItem.getItemValueString("numpos"));
|
||||
throw new PluginException(InvoicePlugin.class.getName(), ERROR_MISSING_DATA, message);
|
||||
}
|
||||
|
||||
// validate pos for regex pattern 'XX-YYY-####-###'
|
||||
if (!posItem.getItemValueString("name").matches(invoicePositionsPattern)) {
|
||||
// throw a plugin exception - because name is missing!
|
||||
String message = resourceBundleHandler.findMessage("ERROR_FORMAT_POSNO");
|
||||
message = message.replace("{1}", posItem.getItemValueString("numpos"));
|
||||
throw new PluginException(InvoicePlugin.class.getName(), ERROR_MISSING_DATA, message);
|
||||
}
|
||||
// validate pos for regex pattern 'XX-YYY-####-###'
|
||||
if (!posItem.getItemValueString("name").matches(invoicePositionsPattern)) {
|
||||
// throw a plugin exception - because name is missing!
|
||||
String message = resourceBundleHandler.findMessage("ERROR_FORMAT_POSNO");
|
||||
message = message.replace("{1}", posItem.getItemValueString("numpos"));
|
||||
throw new PluginException(InvoicePlugin.class.getName(), ERROR_MISSING_DATA, message);
|
||||
}
|
||||
|
||||
if (posItem.getItemValueString("category").trim().isEmpty()) {
|
||||
// throw a plugin exception - because name is missing!
|
||||
String message = resourceBundleHandler.findMessage("ERROR_MISSING_CATEGORY");
|
||||
message = message.replace("{1}", posItem.getItemValueString("numpos"));
|
||||
throw new PluginException(InvoicePlugin.class.getName(), ERROR_MISSING_DATA,
|
||||
"Eingabefehler - Die Leistungsart in Zeile " + posItem.getItemValueString("numpos")
|
||||
+ " muss ausgefüllt sein!");
|
||||
}
|
||||
if (posItem.getItemValueString("category").trim().isEmpty()) {
|
||||
// throw a plugin exception - because name is missing!
|
||||
String message = resourceBundleHandler.findMessage("ERROR_MISSING_CATEGORY");
|
||||
message = message.replace("{1}", posItem.getItemValueString("numpos"));
|
||||
throw new PluginException(InvoicePlugin.class.getName(), ERROR_MISSING_DATA,
|
||||
"Eingabefehler - Die Leistungsart in Zeile " + posItem.getItemValueString("numpos")
|
||||
+ " muss ausgefüllt sein!");
|
||||
}
|
||||
|
||||
if (posItem.getItemValueString("tax").trim().isEmpty()) {
|
||||
// throw a plugin exception - because name is missing!
|
||||
String message = resourceBundleHandler.findMessage("ERROR_MISSING_TAX");
|
||||
message = message.replace("{1}", posItem.getItemValueString("numpos"));
|
||||
throw new PluginException(InvoicePlugin.class.getName(), ERROR_MISSING_DATA, message);
|
||||
}
|
||||
if (posItem.getItemValueString("tax").trim().isEmpty()) {
|
||||
// throw a plugin exception - because name is missing!
|
||||
String message = resourceBundleHandler.findMessage("ERROR_MISSING_TAX");
|
||||
message = message.replace("{1}", posItem.getItemValueString("numpos"));
|
||||
throw new PluginException(InvoicePlugin.class.getName(), ERROR_MISSING_DATA, message);
|
||||
}
|
||||
|
||||
if (posItem.getItemValueFloat("amount") == 0) {
|
||||
// throw a plugin exception - because name is missing!
|
||||
String message = resourceBundleHandler.findMessage("ERROR_MISSING_NET");
|
||||
message = message.replace("{1}", posItem.getItemValueString("numpos"));
|
||||
throw new PluginException(InvoicePlugin.class.getName(), ERROR_MISSING_DATA, message);
|
||||
}
|
||||
if (posItem.getItemValueFloat("amount") == 0) {
|
||||
// throw a plugin exception - because name is missing!
|
||||
String message = resourceBundleHandler.findMessage("ERROR_MISSING_NET");
|
||||
message = message.replace("{1}", posItem.getItemValueString("numpos"));
|
||||
throw new PluginException(InvoicePlugin.class.getName(), ERROR_MISSING_DATA, message);
|
||||
}
|
||||
|
||||
// Buchunsperiode
|
||||
if (!posItem.getItemValueString(InvoiceUtil.ITEM_INVOICE_PERIOD).trim().isEmpty()) {
|
||||
validateBuchungsperiode(posItem.getItemValueString(InvoiceUtil.ITEM_INVOICE_PERIOD));
|
||||
// Buchunsperiode
|
||||
if (!posItem.getItemValueString(InvoiceUtil.ITEM_INVOICE_PERIOD).trim().isEmpty()) {
|
||||
validateBuchungsperiode(posItem.getItemValueString(InvoiceUtil.ITEM_INVOICE_PERIOD));
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Ergaenzung 18.05.2021:
|
||||
// es kann vorkommen, das die Anwender abweichende Buchungsperioden eingeben so
|
||||
// das die Hauptbuchungsperiode gar ncht merh vorkommt. Das darf aber nicht der
|
||||
// fall sein.
|
||||
// Im folgenden überprüfen wir ob eine Buchungszeile vorkommt in der keine oder
|
||||
// die Hauptbuchunsperiode ausgewählt wurde. Ist das nicht der Fal gibt es eine
|
||||
// Fehlermeldung für den Anwendere
|
||||
if (isCargoRechnung(workitem) && childs.size() > 0) {
|
||||
String hauptBuchungsperiode = workitem.getItemValueString("invoice.period");
|
||||
boolean buchungsperiodenValid = false;
|
||||
for (ItemCollection posItem : childs) {
|
||||
String posBuchungsperiode = posItem.getItemValueString("invoice.period");
|
||||
if (posBuchungsperiode.isEmpty() || posBuchungsperiode.equals(hauptBuchungsperiode)) {
|
||||
// alles fein!
|
||||
buchungsperiodenValid = true;
|
||||
}
|
||||
}
|
||||
if (buchungsperiodenValid == false) {
|
||||
// fehlerhafte Buchungsperioden.
|
||||
String message = resourceBundleHandler.findMessage("ERROR_MAIN_BOOKING_PERIOD");
|
||||
throw new PluginException(InvoicePlugin.class.getName(), ERROR_MISSING_DATA, message);
|
||||
}
|
||||
}
|
||||
// Ergaenzung 18.05.2021:
|
||||
// es kann vorkommen, das die Anwender abweichende Buchungsperioden eingeben so
|
||||
// das die Hauptbuchungsperiode gar ncht merh vorkommt. Das darf aber nicht der
|
||||
// fall sein.
|
||||
// Im folgenden überprüfen wir ob eine Buchungszeile vorkommt in der keine oder
|
||||
// die Hauptbuchunsperiode ausgewählt wurde. Ist das nicht der Fal gibt es eine
|
||||
// Fehlermeldung für den Anwendere
|
||||
if (isCargoRechnung(workitem) && childs.size() > 0) {
|
||||
String hauptBuchungsperiode = workitem.getItemValueString("invoice.period");
|
||||
boolean buchungsperiodenValid = false;
|
||||
for (ItemCollection posItem : childs) {
|
||||
String posBuchungsperiode = posItem.getItemValueString("invoice.period");
|
||||
if (posBuchungsperiode.isEmpty() || posBuchungsperiode.equals(hauptBuchungsperiode)) {
|
||||
// alles fein!
|
||||
buchungsperiodenValid = true;
|
||||
}
|
||||
}
|
||||
if (buchungsperiodenValid == false) {
|
||||
// fehlerhafte Buchungsperioden.
|
||||
String message = resourceBundleHandler.findMessage("ERROR_MAIN_BOOKING_PERIOD");
|
||||
throw new PluginException(InvoicePlugin.class.getName(), ERROR_MISSING_DATA, message);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return workitem;
|
||||
}
|
||||
return workitem;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hilfsroutine die das _img item aktualisiert.
|
||||
*/
|
||||
private void updateImg(ItemCollection workitem) {
|
||||
/**
|
||||
* Hilfsroutine die das _img item aktualisiert.
|
||||
*/
|
||||
private void updateImg(ItemCollection workitem) {
|
||||
|
||||
// Update _img icon list
|
||||
String img = workitem.getItemValueString("_img");
|
||||
// 031=ablehnen
|
||||
// 100=sofortüberweichung
|
||||
// 074=mahnen
|
||||
// sofortüberweisung
|
||||
if (workitem.getEventID() == 96 && !img.contains("100.png")) {
|
||||
img = img + "<img title='Sofortüberweisung' src=\"/layout/icons/icon100.png\">";
|
||||
}
|
||||
// mahnen
|
||||
if (workitem.getEventID() == 95 && !img.contains("103.png")) {
|
||||
img = img + "<img title='Mahnen' src=\"/layout/icons/icon103.png\">";
|
||||
// Update _img icon list
|
||||
String img = workitem.getItemValueString("_img");
|
||||
// 031=ablehnen
|
||||
// 100=sofortüberweichung
|
||||
// 074=mahnen
|
||||
// sofortüberweisung
|
||||
if (workitem.getEventID() == 96 && !img.contains("100.png")) {
|
||||
img = img + "<img title='Sofortüberweisung' src=\"/layout/icons/icon100.png\">";
|
||||
}
|
||||
// mahnen
|
||||
if (workitem.getEventID() == 95 && !img.contains("103.png")) {
|
||||
img = img + "<img title='Mahnen' src=\"/layout/icons/icon103.png\">";
|
||||
|
||||
}
|
||||
// ablehnen
|
||||
if (workitem.getTaskID() == 5100 && workitem.getEventID() == 90 && !img.contains("028.png")) {
|
||||
img = img + "<img title='Abgelehnt' src=\"/layout/icons/icon028.png\">";
|
||||
}
|
||||
if (workitem.getTaskID() == 5200 && workitem.getEventID() == 90 && !img.contains("028.png")) {
|
||||
img = img + "<img title='Abgelehnt' src=\"/layout/icons/icon028.png\">";
|
||||
}
|
||||
workitem.setItemValue("_img", img);
|
||||
}
|
||||
// ablehnen
|
||||
if (workitem.getTaskID() == 5100 && workitem.getEventID() == 90 && !img.contains("028.png")) {
|
||||
img = img + "<img title='Abgelehnt' src=\"/layout/icons/icon028.png\">";
|
||||
}
|
||||
if (workitem.getTaskID() == 5200 && workitem.getEventID() == 90 && !img.contains("028.png")) {
|
||||
img = img + "<img title='Abgelehnt' src=\"/layout/icons/icon028.png\">";
|
||||
}
|
||||
workitem.setItemValue("_img", img);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Diese Method prüft die Buchungsperiode auf Plausibilität
|
||||
*
|
||||
* YYYY(+1)01-12
|
||||
*
|
||||
* z.b. 202110 oder 202107 oder 202201
|
||||
*
|
||||
* @param workitem
|
||||
* @throws PluginException
|
||||
*/
|
||||
private void validateBuchungsperiode(String period) throws PluginException {
|
||||
/**
|
||||
* Diese Method prüft die Buchungsperiode auf Plausibilität
|
||||
*
|
||||
* YYYY(+1)01-12
|
||||
*
|
||||
* z.b. 202110 oder 202107 oder 202201
|
||||
*
|
||||
* @param workitem
|
||||
* @throws PluginException
|
||||
*/
|
||||
private void validateBuchungsperiode(String period) throws PluginException {
|
||||
|
||||
// buchungsperionde nur prüfen wenn noch nicht archiviert
|
||||
if (!period.isEmpty()) {
|
||||
LocalDate localDate = LocalDate.now();
|
||||
int year = localDate.getYear();
|
||||
// build regex....
|
||||
String regex = "(" + year + "|" + (year + 1) + "|" + (year - 1) + ")(1[0-2]|0[1-9])";
|
||||
// buchungsperionde nur prüfen wenn noch nicht archiviert
|
||||
if (!period.isEmpty()) {
|
||||
LocalDate localDate = LocalDate.now();
|
||||
int year = localDate.getYear();
|
||||
// build regex....
|
||||
String regex = "(" + year + "|" + (year + 1) + "|" + (year - 1) + ")(1[0-2]|0[1-9])";
|
||||
|
||||
if (!period.matches(regex)) {
|
||||
// throw a plugin exception - because name is missing!
|
||||
String message = resourceBundleHandler.findMessage("ERROR_BOOKING_PERIOD");
|
||||
throw new PluginException(InvoicePlugin.class.getName(), ERROR_MISSING_DATA, message);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!period.matches(regex)) {
|
||||
// throw a plugin exception - because name is missing!
|
||||
String message = resourceBundleHandler.findMessage("ERROR_BOOKING_PERIOD");
|
||||
throw new PluginException(InvoicePlugin.class.getName(), ERROR_MISSING_DATA, message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Diese Method prüft ob die "invoice.number" bereits einmal im
|
||||
* Rechnugnsworkflow vergeben wurde. Falls ja wird eine PluginExcpetion
|
||||
* ausgelöst.
|
||||
* <p>
|
||||
* Query Example:
|
||||
* <p>
|
||||
* <code>NOT $uniqueid:"9f72fa50-4845-41ea-b6b9-ccd518c353be" AND
|
||||
txtcooperatespace:"9dba107e-f8ef-4150-a832-040d75a6eda7" AND invoice.number:"45"</code>
|
||||
*
|
||||
* <p>
|
||||
* in case a duplicate invoice was detected the item invoice.number.duplicate is
|
||||
* filled. This item is used for a conditional event. The case is displayed as a
|
||||
* warning in the form.
|
||||
*
|
||||
* @throws PluginException
|
||||
* @throws QueryException
|
||||
*
|
||||
*/
|
||||
private void validateInvoiceNumber(ItemCollection workitem) throws PluginException {
|
||||
/**
|
||||
* Diese Method prüft ob die "invoice.number" bereits einmal im
|
||||
* Rechnugnsworkflow vergeben wurde. Falls ja wird eine PluginExcpetion
|
||||
* ausgelöst.
|
||||
* <p>
|
||||
* Query Example:
|
||||
* <p>
|
||||
* <code>NOT $uniqueid:"9f72fa50-4845-41ea-b6b9-ccd518c353be" AND
|
||||
txtcooperatespace:"9dba107e-f8ef-4150-a832-040d75a6eda7" AND invoice.number:"45"</code>
|
||||
*
|
||||
* <p>
|
||||
* in case a duplicate invoice was detected the item invoice.number.duplicate is
|
||||
* filled. This item is used for a conditional event. The case is displayed as a
|
||||
* warning in the form.
|
||||
*
|
||||
* @throws PluginException
|
||||
* @throws QueryException
|
||||
*
|
||||
*/
|
||||
private void validateInvoiceNumber(ItemCollection workitem) throws PluginException {
|
||||
|
||||
String invoiceNumber = workitem.getItemValueString("invoice.number");
|
||||
// strip
|
||||
String invoiceNumberStripped = invoiceNumber.replace(" ", "");
|
||||
workitem.setItemValue("invoice.number.stripped", invoiceNumberStripped);
|
||||
String invoiceNumberDuplicate = workitem.getItemValueString("invoice.number.duplicate");
|
||||
String invoiceNumber = workitem.getItemValueString("invoice.number");
|
||||
// strip
|
||||
String invoiceNumberStripped = invoiceNumber.replace(" ", "");
|
||||
workitem.setItemValue("invoice.number.stripped", invoiceNumberStripped);
|
||||
String invoiceNumberDuplicate = workitem.getItemValueString("invoice.number.duplicate");
|
||||
|
||||
// wenn keine Rechnungsnummer eingegeben wurde gehts weiter!
|
||||
if (invoiceNumber.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
// wenn keine Rechnungsnummer eingegeben wurde gehts weiter!
|
||||
if (invoiceNumber.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// rechnungseingang only workitems...
|
||||
// Change 11.4.22 - we have now an additional field: invoice.number.stripped
|
||||
String query = "(type:workitem OR type:workitemarchive) AND ($modelversion:rechnungseingang*) AND NOT ($uniqueid:\""
|
||||
+ workitem.getUniqueID() + "\") AND ((invoice.number:\"" + invoiceNumberStripped
|
||||
+ "\") OR (invoice.number.stripped:\"" + invoiceNumberStripped + "\"))";
|
||||
try {
|
||||
int result = this.getWorkflowService().getDocumentService().count(query, 1);
|
||||
if (result > 0) {
|
||||
// wenn _invoicenumber_duplicate bereits gesetzt ist - dann geht es ohne prüfung
|
||||
// weiter
|
||||
if (!invoiceNumberDuplicate.isEmpty()) {
|
||||
logger.warning("...validateion skipped by user with duplicate invoice number: " + invoiceNumber);
|
||||
} else {
|
||||
// rechnungseingang only workitems...
|
||||
// Change 11.4.22 - we have now an additional field: invoice.number.stripped
|
||||
String query = "(type:workitem OR type:workitemarchive) AND ($modelversion:rechnungseingang*) AND NOT ($uniqueid:\""
|
||||
+ workitem.getUniqueID() + "\") AND ((invoice.number:\"" + invoiceNumberStripped
|
||||
+ "\") OR (invoice.number.stripped:\"" + invoiceNumberStripped + "\"))";
|
||||
try {
|
||||
int result = this.getWorkflowService().getDocumentService().count(query, 1);
|
||||
if (result > 0) {
|
||||
// wenn _invoicenumber_duplicate bereits gesetzt ist - dann geht es ohne prüfung
|
||||
// weiter
|
||||
if (!invoiceNumberDuplicate.isEmpty()) {
|
||||
logger.warning("...validateion skipped by user with duplicate invoice number: " + invoiceNumber);
|
||||
} else {
|
||||
|
||||
// set _invoicenumber_duplicate - dadurch wird die warnmeldung ausgegeben und
|
||||
// der Vorgang nicht weitergeleitet
|
||||
workitem.replaceItemValue("invoice.number.duplicate", invoiceNumber);
|
||||
String message = resourceBundleHandler.findMessage("ERROR_INVOICENO");
|
||||
throw new PluginException(InvoicePlugin.class.getName(), ERROR_DUPPLICATE_INVOICE_NUMBER, message);
|
||||
}
|
||||
} else {
|
||||
// clear !
|
||||
workitem.appendItemValue("invoice.number.duplicate.history",
|
||||
workitem.getItemValueString("invoice.number.duplicate"));
|
||||
workitem.replaceItemValue("invoice.number.duplicate", "");
|
||||
}
|
||||
} catch (QueryException e) {
|
||||
throw new PluginException(PluginException.class.getName(), "QUERY ERROR", e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
// set _invoicenumber_duplicate - dadurch wird die warnmeldung ausgegeben und
|
||||
// der Vorgang nicht weitergeleitet
|
||||
workitem.replaceItemValue("invoice.number.duplicate", invoiceNumber);
|
||||
String message = resourceBundleHandler.findMessage("ERROR_INVOICENO");
|
||||
throw new PluginException(InvoicePlugin.class.getName(), ERROR_DUPPLICATE_INVOICE_NUMBER, message);
|
||||
}
|
||||
} else {
|
||||
// clear !
|
||||
workitem.appendItemValue("invoice.number.duplicate.history",
|
||||
workitem.getItemValueString("invoice.number.duplicate"));
|
||||
workitem.replaceItemValue("invoice.number.duplicate", "");
|
||||
}
|
||||
} catch (QueryException e) {
|
||||
throw new PluginException(PluginException.class.getName(), "QUERY ERROR", e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Diese Method prüft ob die eingegebene IBAN nummer bereits in dem ausgewälten
|
||||
* Kreditor bekannt ist. Fallst nicht wird diese schnell mal in den Kreditoren
|
||||
* Datensatz übertragen. Dadurch muss man nicht extra die Kreditoren Verwaltung
|
||||
* aufrufen. Es ist ein art selbst-lernendes System.
|
||||
* <p>
|
||||
* Die Mehtode ruft eine Plugin Exception aus um den User zu fragen ob er das
|
||||
* möchte.
|
||||
*
|
||||
* @throws PluginException
|
||||
* @throws QueryException
|
||||
*
|
||||
*/
|
||||
private void checkIBANNumber(ItemCollection workitem) throws PluginException {
|
||||
/**
|
||||
* Diese Method prüft ob die eingegebene IBAN nummer bereits in dem ausgewälten
|
||||
* Kreditor bekannt ist. Fallst nicht wird diese schnell mal in den Kreditoren
|
||||
* Datensatz übertragen. Dadurch muss man nicht extra die Kreditoren Verwaltung
|
||||
* aufrufen. Es ist ein art selbst-lernendes System.
|
||||
* <p>
|
||||
* Die Mehtode ruft eine Plugin Exception aus um den User zu fragen ob er das
|
||||
* möchte.
|
||||
*
|
||||
* @throws PluginException
|
||||
* @throws QueryException
|
||||
*
|
||||
*/
|
||||
private void checkIBANNumber(ItemCollection workitem) throws PluginException {
|
||||
|
||||
String cdtrNumber = workitem.getItemValueString("cdtr.number");
|
||||
String iban = workitem.getItemValueString("cdtr.iban");
|
||||
String bic = workitem.getItemValueString("cdtr.bic");
|
||||
String overtakeIBAN = workitem.getItemValueString("ibanbic.overtake");
|
||||
String cdtrNumber = workitem.getItemValueString("cdtr.number");
|
||||
String iban = workitem.getItemValueString("cdtr.iban");
|
||||
String bic = workitem.getItemValueString("cdtr.bic");
|
||||
String overtakeIBAN = workitem.getItemValueString("ibanbic.overtake");
|
||||
|
||||
if (cdtrNumber.isEmpty() || iban.isEmpty() || bic.isEmpty()) {
|
||||
// no op
|
||||
return;
|
||||
}
|
||||
if (cdtrNumber.isEmpty() || iban.isEmpty() || bic.isEmpty()) {
|
||||
// no op
|
||||
return;
|
||||
}
|
||||
|
||||
ItemCollection businessPartner = businessPartnerService
|
||||
.getBusinessPartnerByID(InvoiceUtil.buildBPID(cdtrNumber));
|
||||
if (businessPartner != null) {
|
||||
// update country
|
||||
workitem.setItemValue("invoice.country", businessPartner.getItemValueString("partner.country"));
|
||||
ItemCollection businessPartner = businessPartnerService
|
||||
.getBusinessPartnerByID(InvoiceUtil.buildBPID(cdtrNumber));
|
||||
if (businessPartner != null) {
|
||||
// update country
|
||||
workitem.setItemValue("invoice.country", businessPartner.getItemValueString("partner.country"));
|
||||
|
||||
// wenn bereits eine Übernahme angedroht wurde, dann übernehmen wir die neue
|
||||
// IBAN/BIC!
|
||||
if (!overtakeIBAN.isEmpty()) {
|
||||
businessPartnerService.addNewIBANBIC(businessPartner, iban, bic);
|
||||
workitem.setItemValue("ibanbic.overtake", "");
|
||||
return;
|
||||
}
|
||||
// wenn bereits eine Übernahme angedroht wurde, dann übernehmen wir die neue
|
||||
// IBAN/BIC!
|
||||
if (!overtakeIBAN.isEmpty()) {
|
||||
businessPartnerService.addNewIBANBIC(businessPartner, iban, bic);
|
||||
workitem.setItemValue("ibanbic.overtake", "");
|
||||
return;
|
||||
}
|
||||
|
||||
// Prüfen ob wir die IBAN schon kennen
|
||||
if (!businessPartnerService.isIBANBICKnown(businessPartner, iban, bic)) {
|
||||
// OK - scheinbar ist diese IBAN/BIC nicht bekannt. Also fragen wir mal nach....
|
||||
workitem.setItemValue("ibanbic.overtake", iban + bic);
|
||||
String message = resourceBundleHandler.findMessage("ERROR_IBAN_UNKNOWN");
|
||||
throw new PluginException(InvoicePlugin.class.getName(), ERROR_NEW_IBANBIC, message);
|
||||
}
|
||||
// Prüfen ob wir die IBAN schon kennen
|
||||
if (!businessPartnerService.isIBANBICKnown(businessPartner, iban, bic)) {
|
||||
// OK - scheinbar ist diese IBAN/BIC nicht bekannt. Also fragen wir mal nach....
|
||||
workitem.setItemValue("ibanbic.overtake", iban + bic);
|
||||
String message = resourceBundleHandler.findMessage("ERROR_IBAN_UNKNOWN");
|
||||
throw new PluginException(InvoicePlugin.class.getName(), ERROR_NEW_IBANBIC, message);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Hilfsmethod prüft ob die cdtr.nummer mit einer nummer aus der Cargosoft
|
||||
* Import Datei übereinstimmt.
|
||||
*
|
||||
* @param workitem
|
||||
* @throws PluginException
|
||||
*/
|
||||
private void validateCargosoftCdtrNumber(ItemCollection workitem) throws PluginException {
|
||||
String crdtrNumber = workitem.getItemValueString("cdtr.number");
|
||||
/**
|
||||
* Hilfsmethod prüft ob die cdtr.nummer mit einer nummer aus der Cargosoft
|
||||
* Import Datei übereinstimmt.
|
||||
*
|
||||
* @param workitem
|
||||
* @throws PluginException
|
||||
*/
|
||||
private void validateCargosoftCdtrNumber(ItemCollection workitem) throws PluginException {
|
||||
String crdtrNumber = workitem.getItemValueString("cdtr.number");
|
||||
|
||||
// wenn keine Nummer eingegeben wurde gehts weiter!
|
||||
if (crdtrNumber.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
// wenn keine Nummer eingegeben wurde gehts weiter!
|
||||
if (crdtrNumber.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// search creditor number in cargosoft...
|
||||
// die cargosoft Kreditornummer beginnt seltsamerweise mit einem K.....
|
||||
try {
|
||||
String query = "(type:cargosoftkreditor) AND (name:K" + crdtrNumber + " OR name:" + crdtrNumber + ")";
|
||||
List<ItemCollection> result = this.getWorkflowService().getDocumentService().find(query, 1, 0);
|
||||
if (result == null || result.size() == 0) {
|
||||
// search creditor number in cargosoft...
|
||||
// die cargosoft Kreditornummer beginnt seltsamerweise mit einem K.....
|
||||
try {
|
||||
String query = "(type:cargosoftkreditor) AND (name:K" + crdtrNumber + " OR name:" + crdtrNumber + ")";
|
||||
List<ItemCollection> result = this.getWorkflowService().getDocumentService().find(query, 1, 0);
|
||||
if (result == null || result.size() == 0) {
|
||||
|
||||
String message = resourceBundleHandler.findMessage("ERROR_CDTR_INVALID");
|
||||
throw new PluginException(InvoicePlugin.class.getName(), ERROR_MISSING_DATA,
|
||||
message);
|
||||
String message = resourceBundleHandler.findMessage("ERROR_CDTR_INVALID");
|
||||
throw new PluginException(InvoicePlugin.class.getName(), ERROR_MISSING_DATA, message);
|
||||
|
||||
} else {
|
||||
// update cargosoft crediotr name
|
||||
ItemCollection cargo = result.get(0);
|
||||
workitem.setItemValue("cdtr.name.cargosoft", cargo.getItemValueString("_VENDOR_Name"));
|
||||
}
|
||||
} catch (QueryException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
} else {
|
||||
// update cargosoft crediotr name
|
||||
ItemCollection cargo = result.get(0);
|
||||
workitem.setItemValue("cdtr.name.cargosoft", cargo.getItemValueString("_VENDOR_Name"));
|
||||
}
|
||||
} catch (QueryException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns true if the current workitem is a Cargosoft Invoice.
|
||||
*
|
||||
* This can be based on different model versions e.g. rechnungseingang-de-1.2,
|
||||
* rechnungseingang-pl-1.0, rechnungseingang-dwc-1.0, ...
|
||||
*
|
||||
* @param workitem
|
||||
* @return
|
||||
*/
|
||||
public static boolean isCargoRechnung(ItemCollection workitem) {
|
||||
String REGEX_PATTERN = "rechnungseingang-([a-z]{2}|[a-z]{3})-\\d.\\d";
|
||||
// Erstellen Sie ein Pattern-Objekt
|
||||
Pattern pattern = Pattern.compile(REGEX_PATTERN);
|
||||
Matcher matcher = pattern.matcher(workitem.getModelVersion());
|
||||
// Überprüfen, ob das Muster übereinstimmt
|
||||
return matcher.matches();
|
||||
}
|
||||
/**
|
||||
* This method returns true if the current workitem is a Cargosoft Invoice.
|
||||
*
|
||||
* This can be based on different model versions e.g. rechnungseingang-de-1.2,
|
||||
* rechnungseingang-pl-1.0, rechnungseingang-dwc-1.0, ...
|
||||
*
|
||||
* @param workitem
|
||||
* @return
|
||||
*/
|
||||
public static boolean isCargoRechnung(ItemCollection workitem) {
|
||||
String REGEX_PATTERN = "rechnungseingang-([a-z]{2}|[a-z]{3})-\\d.\\d";
|
||||
// Erstellen Sie ein Pattern-Objekt
|
||||
Pattern pattern = Pattern.compile(REGEX_PATTERN);
|
||||
Matcher matcher = pattern.matcher(workitem.getModelVersion());
|
||||
// Überprüfen, ob das Muster übereinstimmt
|
||||
return matcher.matches();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -89,8 +89,7 @@ public class InvoiceService {
|
|||
ItemCollection configItemCollection = configService.loadConfiguration("AGL_CONFIGURATION");
|
||||
List<String> currencyList = configItemCollection.getItemValue("currency.out");
|
||||
if (currencyList == null || currencyList.size() < 1) {
|
||||
throw new PluginException(AGLAnalyticExcelAdapter.class.getSimpleName(),
|
||||
InvoiceService.ERROR_CONFIG,
|
||||
throw new PluginException(AGLAnalyticExcelAdapter.class.getSimpleName(), InvoiceService.ERROR_CONFIG,
|
||||
"missing Currency configuration - please check parameters");
|
||||
}
|
||||
return currencyList;
|
||||
|
|
@ -108,8 +107,7 @@ public class InvoiceService {
|
|||
ItemCollection configItemCollection = configService.loadConfiguration("AGL_CONFIGURATION");
|
||||
List<String> currencyList = configItemCollection.getItemValue("currency.out");
|
||||
if (currencyList == null || currencyList.size() < 1) {
|
||||
throw new PluginException(AGLAnalyticExcelAdapter.class.getSimpleName(),
|
||||
InvoiceService.ERROR_CONFIG,
|
||||
throw new PluginException(AGLAnalyticExcelAdapter.class.getSimpleName(), InvoiceService.ERROR_CONFIG,
|
||||
"missing Currency configuration - please check parameters");
|
||||
}
|
||||
return currencyList.get(0);
|
||||
|
|
@ -127,16 +125,14 @@ public class InvoiceService {
|
|||
ItemCollection configItemCollection = configService.loadConfiguration("AGL_CONFIGURATION");
|
||||
List<String> currencyList = configItemCollection.getItemValue("currency.in");
|
||||
if (currencyList == null || currencyList.size() < 1) {
|
||||
throw new PluginException(AGLAnalyticExcelAdapter.class.getSimpleName(),
|
||||
InvoiceService.ERROR_CONFIG,
|
||||
throw new PluginException(AGLAnalyticExcelAdapter.class.getSimpleName(), InvoiceService.ERROR_CONFIG,
|
||||
"missing Currency configuration - please check parameters");
|
||||
}
|
||||
return currencyList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prüft ob der Vorgang überflällig ist.
|
||||
* Default ist 21 tage.
|
||||
* Prüft ob der Vorgang überflällig ist. Default ist 21 tage.
|
||||
*/
|
||||
public boolean isOverdue(Date date, int taskid) {
|
||||
Date now = new Date();
|
||||
|
|
|
|||
|
|
@ -13,9 +13,7 @@ import org.imixs.workflow.ItemCollection;
|
|||
* Hilfsmethoden für die Berechnung und Validierung von Ein und
|
||||
* Ausgangsrechnugnen
|
||||
*
|
||||
* - Rundungs Methode
|
||||
* - Berechnung der Positionsnummern
|
||||
* - Explode Childitems
|
||||
* - Rundungs Methode - Berechnung der Positionsnummern - Explode Childitems
|
||||
*
|
||||
* See:
|
||||
* https://stackoverflow.com/questions/2808535/round-a-double-to-2-decimal-places
|
||||
|
|
@ -63,9 +61,7 @@ public class InvoiceUtil {
|
|||
|
||||
String regexPattern = "^(?=.{1,64}@)[A-Za-z0-9_-]+(\\.[A-Za-z0-9_-]+)*@"
|
||||
+ "[^-][A-Za-z0-9-]+(\\.[A-Za-z0-9-]+)*(\\.[A-Za-z]{2,})$";
|
||||
return Pattern.compile(regexPattern)
|
||||
.matcher(emailAddress)
|
||||
.matches();
|
||||
return Pattern.compile(regexPattern).matcher(emailAddress).matches();
|
||||
}
|
||||
|
||||
// @Deprecated
|
||||
|
|
@ -130,10 +126,9 @@ public class InvoiceUtil {
|
|||
|
||||
/**
|
||||
* Diese Methode berechnet das feld 'invoice.positions' welches eine Valueliste
|
||||
* mit allen Positionsnummern aus dem Childliste enthält.
|
||||
* Es wird sowohl für Ausgangs wie Eingangsrechnungen genutzt.
|
||||
* Das feld wird indiziert, so dass eine gezielte Suche nach positiosnummern
|
||||
* möglich ist.
|
||||
* mit allen Positionsnummern aus dem Childliste enthält. Es wird sowohl für
|
||||
* Ausgangs wie Eingangsrechnungen genutzt. Das feld wird indiziert, so dass
|
||||
* eine gezielte Suche nach positiosnummern möglich ist.
|
||||
*
|
||||
* @param workitem
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -74,8 +74,7 @@ public class OPListController implements Serializable {
|
|||
* Diese Methode wird für Zahlungseingänge und Mahnläufe verwendet.
|
||||
* <p>
|
||||
* Die Methode liefert die Rechnungen zur gegebenen dbtrNumber. Die Methode
|
||||
* nutzt
|
||||
* einen lokalen cache um die Zugriffe zu beschleunigen.
|
||||
* nutzt einen lokalen cache um die Zugriffe zu beschleunigen.
|
||||
* <p>
|
||||
* Befindet sich ein Zahlungseingang in Erstellung (Task=1000) werden alle
|
||||
* offenen Rechnungen geholt.
|
||||
|
|
@ -185,8 +184,7 @@ public class OPListController implements Serializable {
|
|||
// einer Rechnung mit dem Event 100 (Mahnlauf erstellen) kommen, oder
|
||||
// wenn der Mahnlauf von außen gerate eben neu erzeugt wurde
|
||||
if (workflowController.getWorkitem().getItemValueInteger("$lastevent") == 100
|
||||
||
|
||||
workflowController.getWorkitem().getItemValueInteger("$lastevent") == 0) {
|
||||
|| workflowController.getWorkitem().getItemValueInteger("$lastevent") == 0) {
|
||||
List<String> intialSelection = new ArrayList<String>();
|
||||
for (ItemCollection invoice : invoiceList) {
|
||||
// ist die Rechnung fällig?
|
||||
|
|
@ -323,9 +321,9 @@ public class OPListController implements Serializable {
|
|||
}
|
||||
|
||||
/**
|
||||
* Berechnet die Summer aller Rechnungen zu einer Währung.
|
||||
* Es werden nur Rechnungen berücksichtigt, deren Haupt Währung der übergebenen
|
||||
* Währung entspricht.
|
||||
* Berechnet die Summer aller Rechnungen zu einer Währung. Es werden nur
|
||||
* Rechnungen berücksichtigt, deren Haupt Währung der übergebenen Währung
|
||||
* entspricht.
|
||||
*
|
||||
* @param currency
|
||||
* @return
|
||||
|
|
|
|||
|
|
@ -95,9 +95,7 @@ public class OPListExportAdapter extends POIFindReplaceAdapter {
|
|||
}
|
||||
|
||||
// read the template options
|
||||
ItemCollection evalItemCollection = workflowService.evalWorkflowResult(event, "opliste",
|
||||
document,
|
||||
false);
|
||||
ItemCollection evalItemCollection = workflowService.evalWorkflowResult(event, "opliste", document, false);
|
||||
if (evalItemCollection == null || !evalItemCollection.hasItem("excel-export")) {
|
||||
throw new PluginException(OPListExportAdapter.class.getSimpleName(), CONFIG_ERROR,
|
||||
"missing opliste configuration in model event - please check model configuration");
|
||||
|
|
@ -132,13 +130,11 @@ public class OPListExportAdapter extends POIFindReplaceAdapter {
|
|||
doc.write(byteArrayOutputStream);
|
||||
|
||||
byte[] newContent = byteArrayOutputStream.toByteArray();
|
||||
FileData fileDataNew = new FileData(fileData.getName(), newContent, fileData.getContentType(),
|
||||
null);
|
||||
FileData fileDataNew = new FileData(fileData.getName(), newContent, fileData.getContentType(), null);
|
||||
document.addFileData(fileDataNew);
|
||||
logger.finest("......new document added");
|
||||
} catch (IOException | QueryException e) {
|
||||
throw new PluginException(OPListExportAdapter.class.getSimpleName(),
|
||||
InvoiceService.ERROR_CONFIG,
|
||||
throw new PluginException(OPListExportAdapter.class.getSimpleName(), InvoiceService.ERROR_CONFIG,
|
||||
"failed to update opliste: " + e.getMessage());
|
||||
} finally {
|
||||
if (doc != null) {
|
||||
|
|
@ -157,8 +153,7 @@ public class OPListExportAdapter extends POIFindReplaceAdapter {
|
|||
} catch (
|
||||
|
||||
PluginException e) {
|
||||
throw new PluginException(OPListExportAdapter.class.getSimpleName(),
|
||||
InvoiceService.ERROR_CONFIG,
|
||||
throw new PluginException(OPListExportAdapter.class.getSimpleName(), InvoiceService.ERROR_CONFIG,
|
||||
"failed to update op-liste: " + e.getMessage());
|
||||
}
|
||||
logger.fine("... completed!");
|
||||
|
|
@ -211,8 +206,7 @@ public class OPListExportAdapter extends POIFindReplaceAdapter {
|
|||
* @throws QueryException
|
||||
*/
|
||||
private void insertInvoiceRows(XSSFSheet sheet, ItemCollection document, String fileName, boolean filter,
|
||||
List<String> currencyList)
|
||||
throws PluginException, QueryException {
|
||||
List<String> currencyList) throws PluginException, QueryException {
|
||||
|
||||
String spaceID = document.getItemValueString("space.ref");
|
||||
logger.fine("... space.ref=" + spaceID + " ...grouping invoices by spaceid....");
|
||||
|
|
@ -349,12 +343,10 @@ public class OPListExportAdapter extends POIFindReplaceAdapter {
|
|||
* @throws PluginException
|
||||
*/
|
||||
private FileData appendExcelTemplate(ItemCollection document, String textblockRef, String template,
|
||||
String targetName)
|
||||
throws PluginException {
|
||||
String targetName) throws PluginException {
|
||||
|
||||
if ((template == null || template.isEmpty()) || (textblockRef == null || textblockRef.isEmpty())) {
|
||||
throw new PluginException(OPListExportAdapter.class.getSimpleName(),
|
||||
InvoiceService.ERROR_CONFIG,
|
||||
throw new PluginException(OPListExportAdapter.class.getSimpleName(), InvoiceService.ERROR_CONFIG,
|
||||
"invalid POI configuration in model event - textblock/template reference not defined!");
|
||||
}
|
||||
|
||||
|
|
@ -363,10 +355,8 @@ public class OPListExportAdapter extends POIFindReplaceAdapter {
|
|||
|
||||
// do we found the document?
|
||||
if (fileData == null) {
|
||||
throw new PluginException(OPListExportAdapter.class.getSimpleName(),
|
||||
InvoiceService.ERROR_CONFIG,
|
||||
"invalid POI configuration in model event - template=" + template
|
||||
+ " not found!");
|
||||
throw new PluginException(OPListExportAdapter.class.getSimpleName(), InvoiceService.ERROR_CONFIG,
|
||||
"invalid POI configuration in model event - template=" + template + " not found!");
|
||||
}
|
||||
fileData.setName(targetName);
|
||||
// append document
|
||||
|
|
|
|||
|
|
@ -119,9 +119,7 @@ public class OPListExportAdapterByWeek extends POIFindReplaceAdapter {
|
|||
Collections.sort(spaces, new ItemCollectionComparator("space.name", true));
|
||||
|
||||
// read the template options
|
||||
ItemCollection evalItemCollection = workflowService.evalWorkflowResult(event, "opliste",
|
||||
document,
|
||||
false);
|
||||
ItemCollection evalItemCollection = workflowService.evalWorkflowResult(event, "opliste", document, false);
|
||||
if (evalItemCollection == null || !evalItemCollection.hasItem("excel-export")) {
|
||||
throw new PluginException(OPListExportAdapter.class.getSimpleName(), CONFIG_ERROR,
|
||||
"missing opliste configuration in model event - please check model configuration");
|
||||
|
|
@ -155,14 +153,12 @@ public class OPListExportAdapterByWeek extends POIFindReplaceAdapter {
|
|||
doc.write(byteArrayOutputStream);
|
||||
|
||||
byte[] newContent = byteArrayOutputStream.toByteArray();
|
||||
FileData fileDataNew = new FileData(fileData.getName(), newContent, fileData.getContentType(),
|
||||
null);
|
||||
FileData fileDataNew = new FileData(fileData.getName(), newContent, fileData.getContentType(), null);
|
||||
document.addFileData(fileDataNew);
|
||||
logger.finest("......new document added");
|
||||
|
||||
} catch (IOException | QueryException e) {
|
||||
throw new PluginException(OPListExportAdapter.class.getSimpleName(),
|
||||
InvoiceService.ERROR_CONFIG,
|
||||
throw new PluginException(OPListExportAdapter.class.getSimpleName(), InvoiceService.ERROR_CONFIG,
|
||||
"failed to update opliste: " + e.getMessage());
|
||||
} finally {
|
||||
if (doc != null) {
|
||||
|
|
@ -180,8 +176,7 @@ public class OPListExportAdapterByWeek extends POIFindReplaceAdapter {
|
|||
} catch (
|
||||
|
||||
PluginException e) {
|
||||
throw new PluginException(OPListExportAdapter.class.getSimpleName(),
|
||||
InvoiceService.ERROR_CONFIG,
|
||||
throw new PluginException(OPListExportAdapter.class.getSimpleName(), InvoiceService.ERROR_CONFIG,
|
||||
"failed to update op-liste: " + e.getMessage());
|
||||
}
|
||||
logger.fine("... completed!");
|
||||
|
|
@ -254,8 +249,7 @@ public class OPListExportAdapterByWeek extends POIFindReplaceAdapter {
|
|||
* @throws QueryException
|
||||
*/
|
||||
private void insertInvoiceRows(XSSFWorkbook doc, XSSFSheet sheet, List<String> currencyList,
|
||||
List<ItemCollection> spaces)
|
||||
throws PluginException, QueryException {
|
||||
List<ItemCollection> spaces) throws PluginException, QueryException {
|
||||
|
||||
List<String> spaceNames = new ArrayList<String>();
|
||||
|
||||
|
|
@ -285,8 +279,8 @@ public class OPListExportAdapterByWeek extends POIFindReplaceAdapter {
|
|||
}
|
||||
|
||||
/*
|
||||
* --- Phase 1 -------------------------------------------------------
|
||||
* Im folgenden gruppieren wir die Rechnungen nach Woche
|
||||
* --- Phase 1 ------------------------------------------------------- Im
|
||||
* folgenden gruppieren wir die Rechnungen nach Woche
|
||||
*/
|
||||
|
||||
// XSSFCell cellKWTotalReference = referenceRowTotal.getCell(14);
|
||||
|
|
@ -306,10 +300,10 @@ public class OPListExportAdapterByWeek extends POIFindReplaceAdapter {
|
|||
totalDataMapUeberFaellig.put("TOTAL", new TotalInvoiceData("TOTAL"));
|
||||
|
||||
/*
|
||||
* --- Phase 3 -------------------------------------------------------
|
||||
* now build a new row for each week and print out the collected invoice data
|
||||
* first iterate over all objects and collect all known weeks and sort them into
|
||||
* a ordered list....
|
||||
* --- Phase 3 ------------------------------------------------------- now build
|
||||
* a new row for each week and print out the collected invoice data first
|
||||
* iterate over all objects and collect all known weeks and sort them into a
|
||||
* ordered list....
|
||||
*/
|
||||
List<String> sortedWeekList = new ArrayList<String>();
|
||||
Iterator<Map.Entry<String, WeekInvoiceData>> iterator = weekDataMap.entrySet().iterator();
|
||||
|
|
@ -323,9 +317,9 @@ public class OPListExportAdapterByWeek extends POIFindReplaceAdapter {
|
|||
Collections.sort(sortedWeekList);
|
||||
|
||||
/*
|
||||
* --- Phase 4 -------------------------------------------------------
|
||||
* Nun müssen wir so viele Zeilen nach unten schieben wie wir gleich einfügen.
|
||||
* Dazu müssen wir kurz einen Probelauf machen um die geplante Anzahl zu
|
||||
* --- Phase 4 ------------------------------------------------------- Nun
|
||||
* müssen wir so viele Zeilen nach unten schieben wie wir gleich einfügen. Dazu
|
||||
* müssen wir kurz einen Probelauf machen um die geplante Anzahl zu
|
||||
* errechnen....
|
||||
*/
|
||||
int rowPos = 11;
|
||||
|
|
@ -333,8 +327,8 @@ public class OPListExportAdapterByWeek extends POIFindReplaceAdapter {
|
|||
sheet.shiftRows(rowPos + 1, 2999, insertCount, true, true);
|
||||
|
||||
/*
|
||||
* --- Phase 5 -------------------------------------------------------
|
||||
* Jetzt Zahlen Zeile für Zeile einfügen....
|
||||
* --- Phase 5 ------------------------------------------------------- Jetzt
|
||||
* Zahlen Zeile für Zeile einfügen....
|
||||
*/
|
||||
boolean ueberFaellig = true;
|
||||
for (String week : sortedWeekList) {
|
||||
|
|
@ -399,9 +393,8 @@ public class OPListExportAdapterByWeek extends POIFindReplaceAdapter {
|
|||
}
|
||||
|
||||
/*
|
||||
* --- Phase 6 -------------------------------------------------------
|
||||
* now lets update the totals...
|
||||
* Überfällig
|
||||
* --- Phase 6 ------------------------------------------------------- now lets
|
||||
* update the totals... Überfällig
|
||||
*/
|
||||
int _rowNo = sortedWeekList.size() + 14;
|
||||
XSSFRow rowUeberFaellig = sheet.getRow(_rowNo);
|
||||
|
|
@ -462,14 +455,12 @@ public class OPListExportAdapterByWeek extends POIFindReplaceAdapter {
|
|||
* Diese Methode gruppiert eine Rechnungsliste nach Kalenderwoche
|
||||
*
|
||||
* @param spaceID - Space Ref to select a list of invoices associated with
|
||||
* a
|
||||
* space
|
||||
* a space
|
||||
* @param weekDataCache - a local cache storing all invoices by week
|
||||
*
|
||||
*
|
||||
*/
|
||||
private void groupInvoicesByWeek(String spaceID, String spaceName,
|
||||
Map<String, WeekInvoiceData> weekDataCache) {
|
||||
private void groupInvoicesByWeek(String spaceID, String spaceName, Map<String, WeekInvoiceData> weekDataCache) {
|
||||
|
||||
logger.info("...group invoices for " + spaceName + "/" + spaceID);
|
||||
try {
|
||||
|
|
@ -482,9 +473,7 @@ public class OPListExportAdapterByWeek extends POIFindReplaceAdapter {
|
|||
// compute Week
|
||||
Date dueDate = invoice.getItemValueDate("invoice.duedate");
|
||||
|
||||
LocalDate localDate = dueDate.toInstant()
|
||||
.atZone(ZoneId.systemDefault())
|
||||
.toLocalDate();
|
||||
LocalDate localDate = dueDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
|
||||
int weekNumber = localDate.get(IsoFields.WEEK_OF_WEEK_BASED_YEAR);
|
||||
int weekBasedYear = localDate.get(IsoFields.WEEK_BASED_YEAR);
|
||||
String weekCategory = weekBasedYear + "/" + String.format("%02d", weekNumber);
|
||||
|
|
@ -526,12 +515,10 @@ public class OPListExportAdapterByWeek extends POIFindReplaceAdapter {
|
|||
* @throws PluginException
|
||||
*/
|
||||
private FileData appendExcelTemplate(ItemCollection document, String textblockRef, String template,
|
||||
String targetName)
|
||||
throws PluginException {
|
||||
String targetName) throws PluginException {
|
||||
|
||||
if ((template == null || template.isEmpty()) || (textblockRef == null || textblockRef.isEmpty())) {
|
||||
throw new PluginException(OPListExportAdapter.class.getSimpleName(),
|
||||
InvoiceService.ERROR_CONFIG,
|
||||
throw new PluginException(OPListExportAdapter.class.getSimpleName(), InvoiceService.ERROR_CONFIG,
|
||||
"invalid POI configuration in model event - textblock/template reference not defined!");
|
||||
}
|
||||
|
||||
|
|
@ -540,10 +527,8 @@ public class OPListExportAdapterByWeek extends POIFindReplaceAdapter {
|
|||
|
||||
// do we found the document?
|
||||
if (fileData == null) {
|
||||
throw new PluginException(OPListExportAdapter.class.getSimpleName(),
|
||||
InvoiceService.ERROR_CONFIG,
|
||||
"invalid POI configuration in model event - template=" + template
|
||||
+ " not found!");
|
||||
throw new PluginException(OPListExportAdapter.class.getSimpleName(), InvoiceService.ERROR_CONFIG,
|
||||
"invalid POI configuration in model event - template=" + template + " not found!");
|
||||
}
|
||||
fileData.setName(targetName);
|
||||
// append document
|
||||
|
|
@ -555,8 +540,8 @@ public class OPListExportAdapterByWeek extends POIFindReplaceAdapter {
|
|||
}
|
||||
|
||||
/**
|
||||
* Data Element for invoice totals per week and space.
|
||||
* The object holds multiple currencies.
|
||||
* Data Element for invoice totals per week and space. The object holds multiple
|
||||
* currencies.
|
||||
*/
|
||||
class WeekInvoiceData {
|
||||
|
||||
|
|
@ -601,8 +586,8 @@ class WeekInvoiceData {
|
|||
}
|
||||
|
||||
/**
|
||||
* Data Element for invoice totals per space.
|
||||
* The object holds multiple currencies.
|
||||
* Data Element for invoice totals per space. The object holds multiple
|
||||
* currencies.
|
||||
*/
|
||||
class TotalInvoiceData {
|
||||
|
||||
|
|
|
|||
|
|
@ -34,8 +34,7 @@ import jakarta.inject.Named;
|
|||
|
||||
/**
|
||||
* The OPListExportController is used to configure the OpListeExporterService.
|
||||
* This service is
|
||||
* used to export workitems.
|
||||
* This service is used to export workitems.
|
||||
* <p>
|
||||
* The Controller creates a configuration entity "type=configuration;
|
||||
* txtname=OPLIST_EXPORT_CONFIGURATION".
|
||||
|
|
@ -48,30 +47,30 @@ import jakarta.inject.Named;
|
|||
@RequestScoped
|
||||
public class OPListExportController extends SchedulerController {
|
||||
|
||||
public static final String OPLIST_EXPORT_CONFIGURATION = "OPLIST_EXPORT_CONFIGURATION";
|
||||
public static final String OPLIST_EXPORT_CONFIGURATION = "OPLIST_EXPORT_CONFIGURATION";
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static Logger logger = Logger.getLogger(OPListExportController.class.getName());
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static Logger logger = Logger.getLogger(OPListExportController.class.getName());
|
||||
|
||||
@Inject
|
||||
OPListExportScheduler opListExportScheduler;
|
||||
@Inject
|
||||
OPListExportScheduler opListExportScheduler;
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return OPLIST_EXPORT_CONFIGURATION;
|
||||
}
|
||||
@Override
|
||||
public String getName() {
|
||||
return OPLIST_EXPORT_CONFIGURATION;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the sepa scheduler class name. This name depends on the _export_type.
|
||||
*
|
||||
* There are two export interfaces available - csv and XML
|
||||
*
|
||||
*/
|
||||
@Override
|
||||
public String getSchedulerClass() {
|
||||
String schedulerClass = OPListExportScheduler.class.getName();
|
||||
logger.finest("...... scheduler: " + schedulerClass);
|
||||
return schedulerClass;
|
||||
}
|
||||
/**
|
||||
* Returns the sepa scheduler class name. This name depends on the _export_type.
|
||||
*
|
||||
* There are two export interfaces available - csv and XML
|
||||
*
|
||||
*/
|
||||
@Override
|
||||
public String getSchedulerClass() {
|
||||
String schedulerClass = OPListExportScheduler.class.getName();
|
||||
logger.finest("...... scheduler: " + schedulerClass);
|
||||
return schedulerClass;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -139,8 +139,8 @@ public class OPListExportScheduler implements Scheduler {
|
|||
List<ItemCollection> invoices = new ArrayList<ItemCollection>();
|
||||
try {
|
||||
invoices = documentService.find(
|
||||
"$modelversion:rechnungsausgang-* AND type:workitem AND $uniqueidref:" + space.getUniqueID(),
|
||||
999, 0);
|
||||
"$modelversion:rechnungsausgang-* AND type:workitem AND $uniqueidref:" + space.getUniqueID(), 999,
|
||||
0);
|
||||
} catch (QueryException e) {
|
||||
logger.warning("Failed to compute invoice list: " + e.getMessage());
|
||||
e.printStackTrace();
|
||||
|
|
|
|||
|
|
@ -28,8 +28,8 @@ import jakarta.inject.Inject;
|
|||
*
|
||||
* Bei Sachrechnungen
|
||||
*
|
||||
* sequencenumber + "_" + invoice.number.stripped + ".pdf"
|
||||
* wird das Rechnungsdatum verwendet um die Buchungsperiode zu berechnen.
|
||||
* sequencenumber + "_" + invoice.number.stripped + ".pdf" wird das
|
||||
* Rechnungsdatum verwendet um die Buchungsperiode zu berechnen.
|
||||
*
|
||||
*
|
||||
*
|
||||
|
|
@ -39,101 +39,100 @@ import jakarta.inject.Inject;
|
|||
*/
|
||||
public class RenameFilenamesAdapter implements SignalAdapter {
|
||||
|
||||
private static Logger logger = Logger.getLogger(RenameFilenamesAdapter.class.getName());
|
||||
private static Logger logger = Logger.getLogger(RenameFilenamesAdapter.class.getName());
|
||||
|
||||
@Inject
|
||||
SnapshotService snapshotService;
|
||||
@Inject
|
||||
SnapshotService snapshotService;
|
||||
|
||||
/**
|
||||
* Rename Filenames
|
||||
*
|
||||
* @throws PluginException
|
||||
*
|
||||
**/
|
||||
@Override
|
||||
public ItemCollection execute(ItemCollection workitem, ItemCollection event)
|
||||
throws AdapterException, PluginException {
|
||||
/**
|
||||
* Rename Filenames
|
||||
*
|
||||
* @throws PluginException
|
||||
*
|
||||
**/
|
||||
@Override
|
||||
public ItemCollection execute(ItemCollection workitem, ItemCollection event)
|
||||
throws AdapterException, PluginException {
|
||||
|
||||
int fileNameCounter = 0; // for multiple files
|
||||
List<FileData> fileDataSet = workitem.getFileData();
|
||||
for (FileData fileData : fileDataSet) {
|
||||
String fileName = fileData.getName();
|
||||
// only PDF files and X-Rechnung
|
||||
if ((fileName.toLowerCase().endsWith(".pdf")
|
||||
|| fileName.toLowerCase().endsWith(".xml"))) {
|
||||
int fileNameCounter = 0; // for multiple files
|
||||
List<FileData> fileDataSet = workitem.getFileData();
|
||||
for (FileData fileData : fileDataSet) {
|
||||
String fileName = fileData.getName();
|
||||
// only PDF files and X-Rechnung
|
||||
if ((fileName.toLowerCase().endsWith(".pdf") || fileName.toLowerCase().endsWith(".xml"))) {
|
||||
|
||||
// Build new Filename
|
||||
String newFileName = buildFileName(fileName, workitem, fileNameCounter);
|
||||
if (!newFileName.equals(fileName)) {
|
||||
logger.info("Rename file name " + fileName + " -> " + newFileName);
|
||||
// do we have content
|
||||
if (fileData.getContent().length < 10) {
|
||||
// fetch snaphot data
|
||||
FileData snapShotFileData = snapshotService.getWorkItemFile(workitem.getUniqueID(), fileName);
|
||||
// remove old data
|
||||
workitem.removeFile(fileName);
|
||||
snapShotFileData.setName(newFileName);
|
||||
workitem.addFileData(snapShotFileData);
|
||||
} else {
|
||||
fileData.setName(newFileName);
|
||||
}
|
||||
fileNameCounter++;
|
||||
}
|
||||
// Build new Filename
|
||||
String newFileName = buildFileName(fileName, workitem, fileNameCounter);
|
||||
if (!newFileName.equals(fileName)) {
|
||||
logger.info("Rename file name " + fileName + " -> " + newFileName);
|
||||
// do we have content
|
||||
if (fileData.getContent().length < 10) {
|
||||
// fetch snaphot data
|
||||
FileData snapShotFileData = snapshotService.getWorkItemFile(workitem.getUniqueID(), fileName);
|
||||
// remove old data
|
||||
workitem.removeFile(fileName);
|
||||
snapShotFileData.setName(newFileName);
|
||||
workitem.addFileData(snapShotFileData);
|
||||
} else {
|
||||
fileData.setName(newFileName);
|
||||
}
|
||||
fileNameCounter++;
|
||||
}
|
||||
|
||||
// Update FTP Target path information
|
||||
String targetPath = "";
|
||||
if (InvoiceUtil.isCreditorInvoice(workitem)) {
|
||||
targetPath = "invoice-in/";
|
||||
String bookingPath = workitem.getItemValueString("invoice.period");
|
||||
// Sachrechnung
|
||||
if (bookingPath.isEmpty()) {
|
||||
// build period from invoice.date
|
||||
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMM");
|
||||
LocalDate invoiceDate = workitem.getItemValueLocalDate("invoice.date");
|
||||
bookingPath = invoiceDate.format(formatter);
|
||||
}
|
||||
if (bookingPath.length() > 4) {
|
||||
targetPath = targetPath + bookingPath.substring(0, 4) + "/" + bookingPath.substring(4);
|
||||
}
|
||||
} else {
|
||||
targetPath = "invoice-out/";
|
||||
String bookingPath = workitem.getItemValueString("invoice.bookingperiod");
|
||||
targetPath = targetPath + bookingPath.substring(0, 4) + "/" + bookingPath.substring(4);
|
||||
}
|
||||
// Update FTP Target path information
|
||||
String targetPath = "";
|
||||
if (InvoiceUtil.isCreditorInvoice(workitem)) {
|
||||
targetPath = "invoice-in/";
|
||||
String bookingPath = workitem.getItemValueString("invoice.period");
|
||||
// Sachrechnung
|
||||
if (bookingPath.isEmpty()) {
|
||||
// build period from invoice.date
|
||||
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMM");
|
||||
LocalDate invoiceDate = workitem.getItemValueLocalDate("invoice.date");
|
||||
bookingPath = invoiceDate.format(formatter);
|
||||
}
|
||||
if (bookingPath.length() > 4) {
|
||||
targetPath = targetPath + bookingPath.substring(0, 4) + "/" + bookingPath.substring(4);
|
||||
}
|
||||
} else {
|
||||
targetPath = "invoice-out/";
|
||||
String bookingPath = workitem.getItemValueString("invoice.bookingperiod");
|
||||
targetPath = targetPath + bookingPath.substring(0, 4) + "/" + bookingPath.substring(4);
|
||||
}
|
||||
|
||||
workitem.setItemValue("ftp.target.path", targetPath + "/");
|
||||
}
|
||||
workitem.setItemValue("ftp.target.path", targetPath + "/");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return workitem;
|
||||
}
|
||||
return workitem;
|
||||
}
|
||||
|
||||
/**
|
||||
* Baut einen Filenamen aus verschiedenen Attributen zusammen.
|
||||
*
|
||||
*
|
||||
* @param workitem
|
||||
* @return
|
||||
*/
|
||||
private String buildFileName(String fileName, ItemCollection workitem, int counter) {
|
||||
String result = workitem.getItemValueString("sequencenumber") + "_";
|
||||
/**
|
||||
* Baut einen Filenamen aus verschiedenen Attributen zusammen.
|
||||
*
|
||||
*
|
||||
* @param workitem
|
||||
* @return
|
||||
*/
|
||||
private String buildFileName(String fileName, ItemCollection workitem, int counter) {
|
||||
String result = workitem.getItemValueString("sequencenumber") + "_";
|
||||
|
||||
if (InvoiceUtil.isSachrechnung(workitem)) {
|
||||
result = result + workitem.getItemValueString("invoice.number.stripped");
|
||||
} else {
|
||||
// für ausgangsrechnungen skippen wir die Cargosoft XML Datei
|
||||
if (fileName.toLowerCase().endsWith(".xml")) {
|
||||
return fileName;
|
||||
}
|
||||
// für die PDF Datei bauen wir einen neuen Namen
|
||||
result = result + workitem.getItemValueString("invoice.positions");
|
||||
}
|
||||
if (counter > 0) {
|
||||
result = result + "_" + counter;
|
||||
}
|
||||
result = result + fileName.substring(fileName.lastIndexOf("."));
|
||||
if (InvoiceUtil.isSachrechnung(workitem)) {
|
||||
result = result + workitem.getItemValueString("invoice.number.stripped");
|
||||
} else {
|
||||
// für ausgangsrechnungen skippen wir die Cargosoft XML Datei
|
||||
if (fileName.toLowerCase().endsWith(".xml")) {
|
||||
return fileName;
|
||||
}
|
||||
// für die PDF Datei bauen wir einen neuen Namen
|
||||
result = result + workitem.getItemValueString("invoice.positions");
|
||||
}
|
||||
if (counter > 0) {
|
||||
result = result + "_" + counter;
|
||||
}
|
||||
result = result + fileName.substring(fileName.lastIndexOf("."));
|
||||
|
||||
return result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,9 +14,9 @@ import jakarta.inject.Inject;
|
|||
import jakarta.inject.Named;
|
||||
|
||||
/**
|
||||
* Der SEPAExportControllerAGL dient dazu die IBAN/BIC einstellungen in
|
||||
* einem SEPA Export zu aktualiseren. Er wird von der Form
|
||||
* sepa_export.xhtml aus per Ajax angesteuert.
|
||||
* Der SEPAExportControllerAGL dient dazu die IBAN/BIC einstellungen in einem
|
||||
* SEPA Export zu aktualiseren. Er wird von der Form sepa_export.xhtml aus per
|
||||
* Ajax angesteuert.
|
||||
*
|
||||
* @author rsoika
|
||||
*
|
||||
|
|
|
|||
|
|
@ -12,8 +12,8 @@ import jakarta.inject.Inject;
|
|||
import jakarta.inject.Named;
|
||||
|
||||
/**
|
||||
* Der SteuerListController dient dazu in einem Stuerbescheid
|
||||
* die einzelnen Zeilen auszugeben.
|
||||
* Der SteuerListController dient dazu in einem Stuerbescheid die einzelnen
|
||||
* Zeilen auszugeben.
|
||||
*
|
||||
* @author rsoika
|
||||
*
|
||||
|
|
|
|||
|
|
@ -17,11 +17,8 @@ import jakarta.inject.Inject;
|
|||
* Das SteuerbescheidPlugin prüft ob
|
||||
*
|
||||
* - die ATC Nummer aus dem Steuerbescheid in einer Ausgangsrechnung gefunden
|
||||
* wird ($taskID<5990)
|
||||
* - invoice.atc.number
|
||||
* - der Betrag "invoice.total.net"
|
||||
* - die Währung???
|
||||
* - die Positionsnummer ???
|
||||
* wird ($taskID<5990) - invoice.atc.number - der Betrag "invoice.total.net" -
|
||||
* die Währung??? - die Positionsnummer ???
|
||||
*
|
||||
*
|
||||
* @author rsoika
|
||||
|
|
@ -30,150 +27,149 @@ import jakarta.inject.Inject;
|
|||
*/
|
||||
public class SteuerbescheidPlugin extends AbstractPlugin {
|
||||
|
||||
private static Logger logger = Logger.getLogger(SteuerbescheidPlugin.class.getName());
|
||||
private static Logger logger = Logger.getLogger(SteuerbescheidPlugin.class.getName());
|
||||
|
||||
@Inject
|
||||
protected DocumentService documentService;
|
||||
@Inject
|
||||
protected DocumentService documentService;
|
||||
|
||||
/**
|
||||
* Prüft ob der Steuerbetrag abgerechnet ist.
|
||||
*
|
||||
*
|
||||
**/
|
||||
@Override
|
||||
public ItemCollection run(ItemCollection workitem, ItemCollection event) throws PluginException {
|
||||
/**
|
||||
* Prüft ob der Steuerbetrag abgerechnet ist.
|
||||
*
|
||||
*
|
||||
**/
|
||||
@Override
|
||||
public ItemCollection run(ItemCollection workitem, ItemCollection event) throws PluginException {
|
||||
|
||||
// Update Fälligkeit
|
||||
updateFaelligkeit(workitem);
|
||||
// Update Fälligkeit
|
||||
updateFaelligkeit(workitem);
|
||||
|
||||
// Update Salden
|
||||
updateTotalEustZoll(workitem);
|
||||
updateInvoiceSaldo(workitem);
|
||||
// Update Salden
|
||||
updateTotalEustZoll(workitem);
|
||||
updateInvoiceSaldo(workitem);
|
||||
|
||||
return workitem;
|
||||
}
|
||||
return workitem;
|
||||
}
|
||||
|
||||
/**
|
||||
* Aktualisiert die EUST/ZOLL Summen
|
||||
*
|
||||
*/
|
||||
protected void updateTotalEustZoll(ItemCollection workitem) {
|
||||
/**
|
||||
* Aktualisiert die EUST/ZOLL Summen
|
||||
*
|
||||
*/
|
||||
protected void updateTotalEustZoll(ItemCollection workitem) {
|
||||
|
||||
double saldoEust = 0;
|
||||
double saldoZoll = 0;
|
||||
List<ItemCollection> positionsTabelle = InvoiceUtil.explodeChildList(workitem);
|
||||
for (ItemCollection pos : positionsTabelle) {
|
||||
if ("EUST".equalsIgnoreCase(pos.getItemValueString("activity.type"))) {
|
||||
saldoEust = saldoEust + pos.getItemValueDouble("amount");
|
||||
}
|
||||
if ("ZOLL".equalsIgnoreCase(pos.getItemValueString("activity.type"))) {
|
||||
saldoZoll = saldoZoll + pos.getItemValueDouble("amount");
|
||||
}
|
||||
}
|
||||
double saldoEust = 0;
|
||||
double saldoZoll = 0;
|
||||
List<ItemCollection> positionsTabelle = InvoiceUtil.explodeChildList(workitem);
|
||||
for (ItemCollection pos : positionsTabelle) {
|
||||
if ("EUST".equalsIgnoreCase(pos.getItemValueString("activity.type"))) {
|
||||
saldoEust = saldoEust + pos.getItemValueDouble("amount");
|
||||
}
|
||||
if ("ZOLL".equalsIgnoreCase(pos.getItemValueString("activity.type"))) {
|
||||
saldoZoll = saldoZoll + pos.getItemValueDouble("amount");
|
||||
}
|
||||
}
|
||||
|
||||
workitem.setItemValue("steuer.eust", saldoEust);
|
||||
workitem.setItemValue("steuer.zoll", saldoZoll);
|
||||
workitem.setItemValue("steuer.eust", saldoEust);
|
||||
workitem.setItemValue("steuer.zoll", saldoZoll);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Aktualisiert die EUST/ZOLL Fälligkeiten in den Detailtabellen
|
||||
* Die Daten kommen von der KI und werden auf die Positionsnummern gemappt.
|
||||
*
|
||||
*/
|
||||
protected void updateFaelligkeit(ItemCollection workitem) {
|
||||
/**
|
||||
* Aktualisiert die EUST/ZOLL Fälligkeiten in den Detailtabellen Die Daten
|
||||
* kommen von der KI und werden auf die Positionsnummern gemappt.
|
||||
*
|
||||
*/
|
||||
protected void updateFaelligkeit(ItemCollection workitem) {
|
||||
|
||||
boolean foundZoll = false;
|
||||
boolean foundEust = false;
|
||||
Date datEust = null;
|
||||
Date datZoll = null;
|
||||
// resolve datEust und datZoll from steuerbescheid.positionen ChildItems....
|
||||
List<ItemCollection> steuerPositionen = InvoiceUtil.explodeChildList(workitem, "steuerbescheid.position");
|
||||
for (ItemCollection steuerPos : steuerPositionen) {
|
||||
if (steuerPos.getItemValueString("key").startsWith("A")) {
|
||||
datZoll = steuerPos.getItemValueDate("duedate");
|
||||
}
|
||||
if (steuerPos.getItemValueString("key").startsWith("B")) {
|
||||
datEust = steuerPos.getItemValueDate("duedate");
|
||||
}
|
||||
}
|
||||
boolean foundZoll = false;
|
||||
boolean foundEust = false;
|
||||
Date datEust = null;
|
||||
Date datZoll = null;
|
||||
// resolve datEust und datZoll from steuerbescheid.positionen ChildItems....
|
||||
List<ItemCollection> steuerPositionen = InvoiceUtil.explodeChildList(workitem, "steuerbescheid.position");
|
||||
for (ItemCollection steuerPos : steuerPositionen) {
|
||||
if (steuerPos.getItemValueString("key").startsWith("A")) {
|
||||
datZoll = steuerPos.getItemValueDate("duedate");
|
||||
}
|
||||
if (steuerPos.getItemValueString("key").startsWith("B")) {
|
||||
datEust = steuerPos.getItemValueDate("duedate");
|
||||
}
|
||||
}
|
||||
|
||||
// Map fälligkeit auf die Cargosoft Positionen
|
||||
List<ItemCollection> rows = InvoiceUtil.explodeChildList(workitem);
|
||||
for (ItemCollection pos : rows) {
|
||||
if (datZoll != null && "ZOLL".equalsIgnoreCase(pos.getItemValueString("activity.type"))) {
|
||||
pos.setItemValue("duedate", datZoll);
|
||||
foundZoll = true;
|
||||
}
|
||||
if (datEust != null && "EUST".equalsIgnoreCase(pos.getItemValueString("activity.type"))) {
|
||||
pos.setItemValue("duedate", datEust);
|
||||
foundEust = true;
|
||||
}
|
||||
}
|
||||
// Map fälligkeit auf die Cargosoft Positionen
|
||||
List<ItemCollection> rows = InvoiceUtil.explodeChildList(workitem);
|
||||
for (ItemCollection pos : rows) {
|
||||
if (datZoll != null && "ZOLL".equalsIgnoreCase(pos.getItemValueString("activity.type"))) {
|
||||
pos.setItemValue("duedate", datZoll);
|
||||
foundZoll = true;
|
||||
}
|
||||
if (datEust != null && "EUST".equalsIgnoreCase(pos.getItemValueString("activity.type"))) {
|
||||
pos.setItemValue("duedate", datEust);
|
||||
foundEust = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (foundEust) {
|
||||
workitem.setItemValue("steuer.eust.due", datEust);
|
||||
} else {
|
||||
workitem.removeItem("steuer.eust.due");
|
||||
}
|
||||
if (foundZoll) {
|
||||
workitem.setItemValue("steuer.zoll.due", datZoll);
|
||||
} else {
|
||||
workitem.removeItem("steuer.zoll.due");
|
||||
}
|
||||
InvoiceUtil.implodeChildList(workitem, rows);
|
||||
}
|
||||
if (foundEust) {
|
||||
workitem.setItemValue("steuer.eust.due", datEust);
|
||||
} else {
|
||||
workitem.removeItem("steuer.eust.due");
|
||||
}
|
||||
if (foundZoll) {
|
||||
workitem.setItemValue("steuer.zoll.due", datZoll);
|
||||
} else {
|
||||
workitem.removeItem("steuer.zoll.due");
|
||||
}
|
||||
InvoiceUtil.implodeChildList(workitem, rows);
|
||||
}
|
||||
|
||||
/**
|
||||
* Aktualisiert den invoice.saldo anhand der ausgehenden Rechnungen zu einer ATC
|
||||
* Nummer
|
||||
*
|
||||
*/
|
||||
protected void updateInvoiceSaldo(ItemCollection workitem) {
|
||||
/**
|
||||
* Aktualisiert den invoice.saldo anhand der ausgehenden Rechnungen zu einer ATC
|
||||
* Nummer
|
||||
*
|
||||
*/
|
||||
protected void updateInvoiceSaldo(ItemCollection workitem) {
|
||||
|
||||
String atcNummer = workitem.getItemValueString("invoice.atc.number");
|
||||
logger.fine("Verify ATC-Nr.: " + atcNummer);
|
||||
double amount = workitem.getItemValueDouble("invoice.total.net");
|
||||
List<ItemCollection> invoices = findInvoices(atcNummer);
|
||||
String atcNummer = workitem.getItemValueString("invoice.atc.number");
|
||||
logger.fine("Verify ATC-Nr.: " + atcNummer);
|
||||
double amount = workitem.getItemValueDouble("invoice.total.net");
|
||||
List<ItemCollection> invoices = findInvoices(atcNummer);
|
||||
|
||||
// Beträge subtrahieren....
|
||||
double saldo = amount;
|
||||
logger.info("Found " + invoices.size() + " matching invoices...");
|
||||
for (ItemCollection invoice : invoices) {
|
||||
workitem.setItemValueUnique("$workitemRef", invoice.getUniqueID());
|
||||
// Beträge subtrahieren....
|
||||
double saldo = amount;
|
||||
logger.info("Found " + invoices.size() + " matching invoices...");
|
||||
for (ItemCollection invoice : invoices) {
|
||||
workitem.setItemValueUnique("$workitemRef", invoice.getUniqueID());
|
||||
|
||||
// suche die Zeile in der die ATC Nummer vorkommt.
|
||||
List<ItemCollection> positionen = InvoiceUtil.explodeChildList(invoice);
|
||||
for (ItemCollection pos : positionen) {
|
||||
if (atcNummer.equals(pos.getItemValueString("atc.number"))) {
|
||||
double umsatz = pos.getItemValueDouble("datev.umsatz");
|
||||
logger.info("...Umsatz=" + umsatz);
|
||||
saldo = InvoiceUtil.round(saldo - umsatz);
|
||||
}
|
||||
}
|
||||
}
|
||||
// suche die Zeile in der die ATC Nummer vorkommt.
|
||||
List<ItemCollection> positionen = InvoiceUtil.explodeChildList(invoice);
|
||||
for (ItemCollection pos : positionen) {
|
||||
if (atcNummer.equals(pos.getItemValueString("atc.number"))) {
|
||||
double umsatz = pos.getItemValueDouble("datev.umsatz");
|
||||
logger.info("...Umsatz=" + umsatz);
|
||||
saldo = InvoiceUtil.round(saldo - umsatz);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Update Saldo
|
||||
workitem.setItemValue("invoice.saldo", InvoiceUtil.round(saldo));
|
||||
// Update Saldo
|
||||
workitem.setItemValue("invoice.saldo", InvoiceUtil.round(saldo));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Sucht alle Ausgansrechnungen zu einer ATC Nummer
|
||||
*/
|
||||
protected List<ItemCollection> findInvoices(String atcNumber) {
|
||||
List<ItemCollection> result = new ArrayList<ItemCollection>();
|
||||
String query = "(type:workitem OR type:workitemarchive) AND ($taskid:[5000 TO 5990])"
|
||||
+ " AND invoice.atc.number:\"" + atcNumber + "\" "
|
||||
+ " AND $workflowgroup:\"Rechnungsausgang\" ";
|
||||
try {
|
||||
result = documentService.find(query, 999, 0, "$created", false);
|
||||
return result;
|
||||
} catch (QueryException e) {
|
||||
logger.severe("Failed to get invoices: " + e.getMessage());
|
||||
}
|
||||
/*
|
||||
* Sucht alle Ausgansrechnungen zu einer ATC Nummer
|
||||
*/
|
||||
protected List<ItemCollection> findInvoices(String atcNumber) {
|
||||
List<ItemCollection> result = new ArrayList<ItemCollection>();
|
||||
String query = "(type:workitem OR type:workitemarchive) AND ($taskid:[5000 TO 5990])"
|
||||
+ " AND invoice.atc.number:\"" + atcNumber + "\" " + " AND $workflowgroup:\"Rechnungsausgang\" ";
|
||||
try {
|
||||
result = documentService.find(query, 999, 0, "$created", false);
|
||||
return result;
|
||||
} catch (QueryException e) {
|
||||
logger.severe("Failed to get invoices: " + e.getMessage());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -127,13 +127,11 @@ public class ZahlungseingangSaldoAdapter implements SignalAdapter {
|
|||
|
||||
String mainCurrency = invoiceService.getCurrenciesOutMain();
|
||||
if ((!invoiceCurrency.equals(paymentCurrency))
|
||||
&& (!invoiceCurrency.equals(mainCurrency) &&
|
||||
!paymentCurrency.equals(mainCurrency))) {
|
||||
&& (!invoiceCurrency.equals(mainCurrency) && !paymentCurrency.equals(mainCurrency))) {
|
||||
String message = resourceBundleHandler.findMessage("ERROR_PAYMENT4");
|
||||
message = message.replace("{1}", mainCurrency);
|
||||
throw new PluginException(PluginException.class.getName(),
|
||||
ZahlungseingangService.ERROR_PAYMENT_BOOKING_FAILED,
|
||||
message);
|
||||
ZahlungseingangService.ERROR_PAYMENT_BOOKING_FAILED, message);
|
||||
}
|
||||
|
||||
if (!invoiceCurrency.equals(paymentCurrency)) {
|
||||
|
|
@ -142,8 +140,7 @@ public class ZahlungseingangSaldoAdapter implements SignalAdapter {
|
|||
message = message.replace("{1}", paymentCurrency);
|
||||
message = message.replace("{2}", invoiceNumber);
|
||||
throw new PluginException(PluginException.class.getName(),
|
||||
ZahlungseingangService.ERROR_PAYMENT_BOOKING_FAILED,
|
||||
message);
|
||||
ZahlungseingangService.ERROR_PAYMENT_BOOKING_FAILED, message);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -151,8 +148,7 @@ public class ZahlungseingangSaldoAdapter implements SignalAdapter {
|
|||
* Falls die Währung der Rechnung von der Währung der Zahlung abweicht, dann
|
||||
* rechnen wir den PaymentAmmout mit der Rate aus.
|
||||
*/
|
||||
if ("EUR".equals(paymentCurrency) &&
|
||||
!invoiceCurrency.equals(paymentCurrency) && invoiceRate != 0) {
|
||||
if ("EUR".equals(paymentCurrency) && !invoiceCurrency.equals(paymentCurrency) && invoiceRate != 0) {
|
||||
invoicePaymentAmount = invoicePaymentAmount * invoiceRate;
|
||||
// runde auf 2 Stellen
|
||||
invoicePaymentAmount = (float) InvoiceUtil.round(invoicePaymentAmount);
|
||||
|
|
|
|||
|
|
@ -15,8 +15,8 @@ import jakarta.enterprise.event.Observes;
|
|||
import jakarta.inject.Inject;
|
||||
|
||||
/**
|
||||
* The PromptExampleAdapterXML is a CDI bean that creates XML examples based
|
||||
* on the last 3 invoices.
|
||||
* The PromptExampleAdapterXML is a CDI bean that creates XML examples based on
|
||||
* the last 3 invoices.
|
||||
*
|
||||
* The adapter only runs if the prompt template contains
|
||||
*
|
||||
|
|
@ -79,8 +79,7 @@ public class PromptExampleAdapterXML {
|
|||
if (invoices != null && invoices.size() > 0) {
|
||||
// Build an example for each invoice
|
||||
for (ItemCollection invoice : invoices) {
|
||||
promptExamples = promptExamples + buildExampleDE(invoice, exampleHeaderData,
|
||||
exampleHeaderXML);
|
||||
promptExamples = promptExamples + buildExampleDE(invoice, exampleHeaderData, exampleHeaderXML);
|
||||
}
|
||||
}
|
||||
prompt = prompt.replace("<<EXAMPLES_XML>>", "" + promptExamples);
|
||||
|
|
@ -126,14 +125,12 @@ public class PromptExampleAdapterXML {
|
|||
example.append(
|
||||
" <invoice.number>" + invoice.getItemValueString("invoice.number") + "</invoice.number>\n");
|
||||
if (invoice.getItemValueDate("invoice.date") != null) {
|
||||
example.append(
|
||||
" <invoice.date>" + dateFormat.format(invoice.getItemValueDate("invoice.date"))
|
||||
+ "</invoice.date>\n");
|
||||
example.append(" <invoice.date>" + dateFormat.format(invoice.getItemValueDate("invoice.date"))
|
||||
+ "</invoice.date>\n");
|
||||
}
|
||||
if (invoice.getItemValueDate("invoice.duedate") != null) {
|
||||
example.append(
|
||||
" <invoice.duedate>" + dateFormat.format(invoice.getItemValueDate("invoice.duedate"))
|
||||
+ "</invoice.duedate>\n");
|
||||
example.append(" <invoice.duedate>" + dateFormat.format(invoice.getItemValueDate("invoice.duedate"))
|
||||
+ "</invoice.duedate>\n");
|
||||
}
|
||||
example.append(" <invoice.total type=\"double\">" + invoice.getItemValueDouble("invoice.total")
|
||||
+ "</invoice.total>\n");
|
||||
|
|
@ -154,8 +151,7 @@ public class PromptExampleAdapterXML {
|
|||
List<ItemCollection> result = new ArrayList<>();
|
||||
|
||||
String searchTerm = "(type:workitemarchive) AND ($modelversion:rechnungseingang*) AND ($taskid:5900) AND NOT ($uniqueid:"
|
||||
+ currentID + ") AND (document.company:\""
|
||||
+ companyName + "\")";
|
||||
+ currentID + ") AND (document.company:\"" + companyName + "\")";
|
||||
try {
|
||||
result = documentService.find(searchTerm, 3, 0, "$modified", true);
|
||||
} catch (QueryException e) {
|
||||
|
|
|
|||
|
|
@ -145,8 +145,7 @@ public class CargosoftMigrationRestService implements Serializable {
|
|||
isRunning = true;
|
||||
|
||||
int totalCount = documentService.count(query);
|
||||
log("│ ├── found " + totalCount + " cargosoft entries",
|
||||
messageBuffer);
|
||||
log("│ ├── found " + totalCount + " cargosoft entries", messageBuffer);
|
||||
|
||||
// Berechne Anzahl der benötigten Pages
|
||||
int totalPages = (int) Math.ceil((double) totalCount / batchSize);
|
||||
|
|
@ -169,8 +168,8 @@ public class CargosoftMigrationRestService implements Serializable {
|
|||
}
|
||||
|
||||
// Fortschritt loggen
|
||||
log("│ ├── Processed page " + (pageIndex + 1) + " of " + totalPages +
|
||||
" (" + totalObjects + " objects read, " + syncs + " total syncs)", messageBuffer);
|
||||
log("│ ├── Processed page " + (pageIndex + 1) + " of " + totalPages + " (" + totalObjects
|
||||
+ " objects read, " + syncs + " total syncs)", messageBuffer);
|
||||
// Optional: Kurze Pause nach jedem 5. Batch
|
||||
try {
|
||||
Thread.sleep(100);
|
||||
|
|
@ -185,8 +184,8 @@ public class CargosoftMigrationRestService implements Serializable {
|
|||
}
|
||||
long duration = System.currentTimeMillis() - l;
|
||||
double objectsPerSecond = totalObjects / (duration / 1000.0);
|
||||
log("├── Successfully " + syncs + " business partner objects synced in " +
|
||||
duration + "ms (" + String.format("%.1f", objectsPerSecond) + " objects/sec)", messageBuffer);
|
||||
log("├── Successfully " + syncs + " business partner objects synced in " + duration + "ms ("
|
||||
+ String.format("%.1f", objectsPerSecond) + " objects/sec)", messageBuffer);
|
||||
|
||||
isRunning = false;
|
||||
return messageBuffer.toString();
|
||||
|
|
@ -273,8 +272,8 @@ public class CargosoftMigrationRestService implements Serializable {
|
|||
|
||||
// Fortschritt loggen
|
||||
iterations++;
|
||||
log("│ ├── Processed page " + (iterations) + " of " + totalPages +
|
||||
" (" + deletions + " total deletions)", messageBuffer);
|
||||
log("│ ├── Processed page " + (iterations) + " of " + totalPages + " (" + deletions + " total deletions)",
|
||||
messageBuffer);
|
||||
|
||||
// Optional: Kurze Pause nach jedem 5. Batch
|
||||
try {
|
||||
|
|
@ -290,8 +289,8 @@ public class CargosoftMigrationRestService implements Serializable {
|
|||
}
|
||||
long duration = System.currentTimeMillis() - l;
|
||||
double objectsPerSecond = totalObjects / (duration / 1000.0);
|
||||
log("├── Successfully " + deletions + " business partner objects deleted in " +
|
||||
duration + "ms (" + String.format("%.1f", objectsPerSecond) + " objects/sec)", messageBuffer);
|
||||
log("├── Successfully " + deletions + " business partner objects deleted in " + duration + "ms ("
|
||||
+ String.format("%.1f", objectsPerSecond) + " objects/sec)", messageBuffer);
|
||||
|
||||
isRunning = false;
|
||||
return messageBuffer.toString();
|
||||
|
|
@ -373,8 +372,8 @@ public class CargosoftMigrationRestService implements Serializable {
|
|||
|
||||
// Fortschritt loggen
|
||||
// Fortschritt loggen
|
||||
log("│ ├── Processed page " + (pageIndex + 1) + " of " + totalPages +
|
||||
" (" + deletions + " total deletions)", messageBuffer);
|
||||
log("│ ├── Processed page " + (pageIndex + 1) + " of " + totalPages + " (" + deletions
|
||||
+ " total deletions)", messageBuffer);
|
||||
// Optional: Kurze Pause nach jedem 5. Batch
|
||||
try {
|
||||
Thread.sleep(100);
|
||||
|
|
@ -389,8 +388,8 @@ public class CargosoftMigrationRestService implements Serializable {
|
|||
}
|
||||
long duration = System.currentTimeMillis() - l;
|
||||
double objectsPerSecond = totalObjects / (duration / 1000.0);
|
||||
log("├── Successfully " + deletions + " duplicated cargosoft objects deleted in " +
|
||||
duration + "ms (" + String.format("%.1f", objectsPerSecond) + " objects/sec)", messageBuffer);
|
||||
log("├── Successfully " + deletions + " duplicated cargosoft objects deleted in " + duration + "ms ("
|
||||
+ String.format("%.1f", objectsPerSecond) + " objects/sec)", messageBuffer);
|
||||
|
||||
isRunning = false;
|
||||
return messageBuffer.toString();
|
||||
|
|
|
|||
|
|
@ -139,9 +139,7 @@ public class DataRestService {
|
|||
protected Client createClient(String serviceAPI, String sessionID) {
|
||||
|
||||
// Create a Cookie object with a name and a value
|
||||
Cookie cookie = new Cookie.Builder("JSESSIONID")
|
||||
.value(sessionID)
|
||||
.path("/")
|
||||
Cookie cookie = new Cookie.Builder("JSESSIONID").value(sessionID).path("/")
|
||||
// .domain("domain.com")
|
||||
.build();
|
||||
|
||||
|
|
|
|||
|
|
@ -55,27 +55,27 @@ import jakarta.inject.Named;
|
|||
@RequestScoped
|
||||
public class CargosoftExportController extends SchedulerController {
|
||||
|
||||
public static final String CARGOSOFT_EXPORT_CONFIGURATION = "CARGOSOFT_EXPORT_CONFIGURATION";
|
||||
public static final String CARGOSOFT_EXPORT_CONFIGURATION = "CARGOSOFT_EXPORT_CONFIGURATION";
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static Logger logger = Logger.getLogger(CargosoftExportController.class.getName());
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static Logger logger = Logger.getLogger(CargosoftExportController.class.getName());
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return CARGOSOFT_EXPORT_CONFIGURATION;
|
||||
}
|
||||
@Override
|
||||
public String getName() {
|
||||
return CARGOSOFT_EXPORT_CONFIGURATION;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the sepa scheduler class name. This name depends on the _export_type.
|
||||
*
|
||||
* There are two export interfaces available - csv and XML
|
||||
*
|
||||
*/
|
||||
@Override
|
||||
public String getSchedulerClass() {
|
||||
String schedulerClass = CargosoftExportScheduler.class.getName();
|
||||
logger.finest("...... scheduler: " + schedulerClass);
|
||||
return schedulerClass;
|
||||
}
|
||||
/**
|
||||
* Returns the sepa scheduler class name. This name depends on the _export_type.
|
||||
*
|
||||
* There are two export interfaces available - csv and XML
|
||||
*
|
||||
*/
|
||||
@Override
|
||||
public String getSchedulerClass() {
|
||||
String schedulerClass = CargosoftExportScheduler.class.getName();
|
||||
logger.finest("...... scheduler: " + schedulerClass);
|
||||
return schedulerClass;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -54,291 +54,290 @@ import jakarta.inject.Named;
|
|||
@ConversationScoped
|
||||
public class ExcelExportController implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static Logger logger = Logger.getLogger(ExcelExportController.class.getName());
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static Logger logger = Logger.getLogger(ExcelExportController.class.getName());
|
||||
|
||||
public static final String ERROR_CONFIG = "CONFIG_ERROR";
|
||||
final String TYPE_TEXTBLOCK = "textblock";
|
||||
public static final String ERROR_CONFIG = "CONFIG_ERROR";
|
||||
final String TYPE_TEXTBLOCK = "textblock";
|
||||
|
||||
public static final int MAX_ROWS = 3000;
|
||||
@Inject
|
||||
protected DocumentService documentService;
|
||||
public static final int MAX_ROWS = 3000;
|
||||
@Inject
|
||||
protected DocumentService documentService;
|
||||
|
||||
@Inject
|
||||
WorkflowController workflowController;
|
||||
@Inject
|
||||
WorkflowController workflowController;
|
||||
|
||||
@Inject
|
||||
DocumentController documentController;
|
||||
@Inject
|
||||
DocumentController documentController;
|
||||
|
||||
@Inject
|
||||
SnapshotService snapshotService;
|
||||
@Inject
|
||||
SnapshotService snapshotService;
|
||||
|
||||
private ItemCollection filter;
|
||||
private CustomFormItem dbtrItem;
|
||||
private ItemCollection filter;
|
||||
private CustomFormItem dbtrItem;
|
||||
|
||||
public ExcelExportController() {
|
||||
}
|
||||
public ExcelExportController() {
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
reset();
|
||||
}
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
reset();
|
||||
}
|
||||
|
||||
public ItemCollection getFilter() {
|
||||
return filter;
|
||||
}
|
||||
public ItemCollection getFilter() {
|
||||
return filter;
|
||||
}
|
||||
|
||||
public void setFilter(ItemCollection filter) {
|
||||
this.filter = filter;
|
||||
}
|
||||
public void setFilter(ItemCollection filter) {
|
||||
this.filter = filter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fuert verschiedene Queries aus um eine Analyse der Sachprufung durchzuführen.
|
||||
*
|
||||
* @throws PluginException
|
||||
*/
|
||||
public String export() throws PluginException {
|
||||
/**
|
||||
* Fuert verschiedene Queries aus um eine Analyse der Sachprufung durchzuführen.
|
||||
*
|
||||
* @throws PluginException
|
||||
*/
|
||||
public String export() throws PluginException {
|
||||
|
||||
logger.info("start export....");
|
||||
Date start = filter.getItemValueDate("start");
|
||||
Date stop = filter.getItemValueDate("stop");
|
||||
logger.info("...daterange=" + start + " - " + stop);
|
||||
logger.info("start export....");
|
||||
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");
|
||||
// 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());
|
||||
}
|
||||
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 zeit
|
||||
String query = "(type:workitem OR type:workitemarchive) AND ($workflowgroup:Rechnungsausgang) ";
|
||||
if (start != null && stop != null) {
|
||||
query += "AND (invoice.date:[" + sDateFrom + " TO " + sDateTo + "]) ";
|
||||
} else {
|
||||
throw new PluginException("ERROR", "Bitte geben Sie einen Zeitraum an", null);
|
||||
}
|
||||
logger.info(query);
|
||||
// query zeit
|
||||
String query = "(type:workitem OR type:workitemarchive) AND ($workflowgroup:Rechnungsausgang) ";
|
||||
if (start != null && stop != null) {
|
||||
query += "AND (invoice.date:[" + sDateFrom + " TO " + sDateTo + "]) ";
|
||||
} else {
|
||||
throw new PluginException("ERROR", "Bitte geben Sie einen Zeitraum an", null);
|
||||
}
|
||||
logger.info(query);
|
||||
|
||||
// query Sachprüfung
|
||||
// query Sachprüfung
|
||||
|
||||
if (!filter.getItemValueString("space.ref").isEmpty()
|
||||
&& !"-".equals(filter.getItemValueString("space.ref"))) {
|
||||
query += " AND ($uniqueidref:" + filter.getItemValueString("space.ref") + ")";
|
||||
}
|
||||
if (workflowController.getWorkitem() != null
|
||||
&& !workflowController.getWorkitem().getItemValueString("dbtr.number").isEmpty()) {
|
||||
query += " AND (dbtr.number:" + workflowController.getWorkitem().getItemValueString("dbtr.number") + ")";
|
||||
}
|
||||
if (!filter.getItemValueString("invoice.text").isEmpty()) {
|
||||
query += " AND (invoice.positions:" + filter.getItemValueString("invoice.text") + ")";
|
||||
}
|
||||
if (!filter.getItemValueString("space.ref").isEmpty() && !"-".equals(filter.getItemValueString("space.ref"))) {
|
||||
query += " AND ($uniqueidref:" + filter.getItemValueString("space.ref") + ")";
|
||||
}
|
||||
if (workflowController.getWorkitem() != null
|
||||
&& !workflowController.getWorkitem().getItemValueString("dbtr.number").isEmpty()) {
|
||||
query += " AND (dbtr.number:" + workflowController.getWorkitem().getItemValueString("dbtr.number") + ")";
|
||||
}
|
||||
if (!filter.getItemValueString("invoice.text").isEmpty()) {
|
||||
query += " AND (invoice.positions:" + filter.getItemValueString("invoice.text") + ")";
|
||||
}
|
||||
|
||||
// load the text block
|
||||
String template = "ausgangsrechnungen-export_template.xlsx";
|
||||
FileData fileData = loadTextBlockFileData("Excel-Export Template", template);
|
||||
// load the text block
|
||||
String template = "ausgangsrechnungen-export_template.xlsx";
|
||||
FileData fileData = loadTextBlockFileData("Excel-Export Template", template);
|
||||
|
||||
// do we found the document?
|
||||
if (fileData == null) {
|
||||
throw new PluginException(InkassoExportAdapter.class.getSimpleName(), ERROR_CONFIG,
|
||||
"Missing Excel Export Template - template=" + template + " not found!");
|
||||
}
|
||||
String targetName = "ausgangsrechnungen-export_" + dateformat.format(new Date()) + ".xlsx";
|
||||
try {
|
||||
List<ItemCollection> invoices = documentService.find(query, MAX_ROWS, 0, "invoice.date", true);
|
||||
if (invoices.size() > 0) {
|
||||
insertInvoiceRows(invoices, fileData);
|
||||
}
|
||||
fileData.setName(targetName);
|
||||
// do we found the document?
|
||||
if (fileData == null) {
|
||||
throw new PluginException(InkassoExportAdapter.class.getSimpleName(), ERROR_CONFIG,
|
||||
"Missing Excel Export Template - template=" + template + " not found!");
|
||||
}
|
||||
String targetName = "ausgangsrechnungen-export_" + dateformat.format(new Date()) + ".xlsx";
|
||||
try {
|
||||
List<ItemCollection> invoices = documentService.find(query, MAX_ROWS, 0, "invoice.date", true);
|
||||
if (invoices.size() > 0) {
|
||||
insertInvoiceRows(invoices, fileData);
|
||||
}
|
||||
fileData.setName(targetName);
|
||||
|
||||
// See:
|
||||
// https://stackoverflow.com/questions/9391838/how-to-provide-a-file-download-from-a-jsf-backing-bean
|
||||
download(fileData);
|
||||
} catch (IOException | QueryException e) {
|
||||
throw new PluginException(InkassoExportAdapter.class.getSimpleName(), ERROR_CONFIG,
|
||||
"Failed to generate Excel Export: " + e.getMessage());
|
||||
}
|
||||
// See:
|
||||
// https://stackoverflow.com/questions/9391838/how-to-provide-a-file-download-from-a-jsf-backing-bean
|
||||
download(fileData);
|
||||
} catch (IOException | QueryException e) {
|
||||
throw new PluginException(InkassoExportAdapter.class.getSimpleName(), ERROR_CONFIG,
|
||||
"Failed to generate Excel Export: " + e.getMessage());
|
||||
}
|
||||
|
||||
logger.info("Query=" + query);
|
||||
return "/pages/admin/excel_export_rechnungsausgang.jsf?faces-redirect=true";
|
||||
}
|
||||
logger.info("Query=" + query);
|
||||
return "/pages/admin/excel_export_rechnungsausgang.jsf?faces-redirect=true";
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to initialize a download
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
public void download(FileData fileData) throws IOException {
|
||||
/**
|
||||
* Helper method to initialize a download
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
public void download(FileData fileData) throws IOException {
|
||||
|
||||
FacesContext facesContext = FacesContext.getCurrentInstance();
|
||||
ExternalContext externalContext = facesContext.getExternalContext();
|
||||
FacesContext facesContext = FacesContext.getCurrentInstance();
|
||||
ExternalContext externalContext = facesContext.getExternalContext();
|
||||
|
||||
externalContext.responseReset();
|
||||
externalContext.setResponseContentType("application/vnd.ms-excel");
|
||||
externalContext.setResponseContentLength(fileData.getContent().length);
|
||||
externalContext.setResponseHeader("Content-Disposition", "attachment; filename=\"" + fileData.getName() + "\"");
|
||||
externalContext.responseReset();
|
||||
externalContext.setResponseContentType("application/vnd.ms-excel");
|
||||
externalContext.setResponseContentLength(fileData.getContent().length);
|
||||
externalContext.setResponseHeader("Content-Disposition", "attachment; filename=\"" + fileData.getName() + "\"");
|
||||
|
||||
OutputStream output = externalContext.getResponseOutputStream();
|
||||
OutputStream output = externalContext.getResponseOutputStream();
|
||||
|
||||
// Now you can write the InputStream of the file to the above OutputStream the
|
||||
// usual way.
|
||||
output.write(fileData.getContent());
|
||||
// Now you can write the InputStream of the file to the above OutputStream the
|
||||
// usual way.
|
||||
output.write(fileData.getContent());
|
||||
|
||||
facesContext.responseComplete(); // Important! Otherwise Faces will attempt to render the response which
|
||||
// obviously will fail since it's already written with a file and closed.
|
||||
}
|
||||
facesContext.responseComplete(); // Important! Otherwise Faces will attempt to render the response which
|
||||
// obviously will fail since it's already written with a file and closed.
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns a text-block ItemCollection for a specified name.
|
||||
*
|
||||
* @param name in attribute txtname
|
||||
*
|
||||
*
|
||||
*/
|
||||
private FileData loadTextBlockFileData(String name, String fileName) {
|
||||
ItemCollection textBlockItemCollection = null;
|
||||
/**
|
||||
* This method returns a text-block ItemCollection for a specified name.
|
||||
*
|
||||
* @param name in attribute txtname
|
||||
*
|
||||
*
|
||||
*/
|
||||
private FileData loadTextBlockFileData(String name, String fileName) {
|
||||
ItemCollection textBlockItemCollection = null;
|
||||
|
||||
// load text-block by name....
|
||||
String sQuery = "(type:\"" + TYPE_TEXTBLOCK + "\" AND txtname:\"" + name + "\")";
|
||||
Collection<ItemCollection> col;
|
||||
try {
|
||||
// find the textblock...
|
||||
col = documentService.find(sQuery, 1, 0);
|
||||
if (col.size() > 0) {
|
||||
textBlockItemCollection = col.iterator().next();
|
||||
// fetch the fileData...
|
||||
return snapshotService.getWorkItemFile(textBlockItemCollection.getUniqueID(), fileName);
|
||||
// load text-block by name....
|
||||
String sQuery = "(type:\"" + TYPE_TEXTBLOCK + "\" AND txtname:\"" + name + "\")";
|
||||
Collection<ItemCollection> col;
|
||||
try {
|
||||
// find the textblock...
|
||||
col = documentService.find(sQuery, 1, 0);
|
||||
if (col.size() > 0) {
|
||||
textBlockItemCollection = col.iterator().next();
|
||||
// fetch the fileData...
|
||||
return snapshotService.getWorkItemFile(textBlockItemCollection.getUniqueID(), fileName);
|
||||
|
||||
} else {
|
||||
logger.warning("Missing text-block : '" + name + "'");
|
||||
}
|
||||
} catch (QueryException e) {
|
||||
logger.warning("getTextBlock - invalid query: " + e.getMessage());
|
||||
}
|
||||
} else {
|
||||
logger.warning("Missing text-block : '" + name + "'");
|
||||
}
|
||||
} catch (QueryException e) {
|
||||
logger.warning("getTextBlock - invalid query: " + e.getMessage());
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method reset the search and input state.
|
||||
*/
|
||||
public void reset() {
|
||||
filter = new ItemCollection();
|
||||
/**
|
||||
* This method reset the search and input state.
|
||||
*/
|
||||
public void reset() {
|
||||
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()));
|
||||
workflowController.setWorkitem(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()));
|
||||
workflowController.setWorkitem(new ItemCollection());
|
||||
|
||||
// debtr item
|
||||
dbtrItem = new CustomFormItem("dbtr.number", "text", "", false, false, false, "", null, false, 0);
|
||||
// debtr item
|
||||
dbtrItem = new CustomFormItem("dbtr.number", "text", "", false, false, false, "", null, false, 0);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public CustomFormItem getItem() {
|
||||
// dbtrItem.setName("dbtr.number");
|
||||
return dbtrItem;
|
||||
}
|
||||
public CustomFormItem getItem() {
|
||||
// dbtrItem.setName("dbtr.number");
|
||||
return dbtrItem;
|
||||
}
|
||||
|
||||
/**
|
||||
* This helper method inserts a row for each invoice
|
||||
*
|
||||
* @throws PluginException
|
||||
*/
|
||||
private void insertInvoiceRows(List<ItemCollection> invoices, FileData fileData) throws PluginException {
|
||||
// load XSSFWorkbook
|
||||
try (InputStream imputStream = new ByteArrayInputStream(fileData.getContent())) {
|
||||
XSSFWorkbook doc = new XSSFWorkbook(imputStream);
|
||||
// NOTE: we only take the first sheet !
|
||||
XSSFSheet sheet = doc.getSheetAt(0);
|
||||
/**
|
||||
* This helper method inserts a row for each invoice
|
||||
*
|
||||
* @throws PluginException
|
||||
*/
|
||||
private void insertInvoiceRows(List<ItemCollection> invoices, FileData fileData) throws PluginException {
|
||||
// load XSSFWorkbook
|
||||
try (InputStream imputStream = new ByteArrayInputStream(fileData.getContent())) {
|
||||
XSSFWorkbook doc = new XSSFWorkbook(imputStream);
|
||||
// NOTE: we only take the first sheet !
|
||||
XSSFSheet sheet = doc.getSheetAt(0);
|
||||
|
||||
XSSFCell standCell = getCellByRef(doc, sheet, "F6");
|
||||
standCell.setCellValue(new Date());
|
||||
XSSFCell standCell = getCellByRef(doc, sheet, "F6");
|
||||
standCell.setCellValue(new Date());
|
||||
|
||||
CellReference cr = new CellReference("A11");
|
||||
XSSFRow referenceRow = sheet.getRow(cr.getRow());
|
||||
int referenceRowPos = referenceRow.getRowNum() + 1;
|
||||
int rowPos = referenceRowPos;
|
||||
// int lastRow = sheet.getLastRowNum();
|
||||
int lastRow = 999;
|
||||
logger.finest("Last rownum=" + lastRow);
|
||||
sheet.shiftRows(rowPos, lastRow, invoices.size(), true, true);
|
||||
CellReference cr = new CellReference("A11");
|
||||
XSSFRow referenceRow = sheet.getRow(cr.getRow());
|
||||
int referenceRowPos = referenceRow.getRowNum() + 1;
|
||||
int rowPos = referenceRowPos;
|
||||
// int lastRow = sheet.getLastRowNum();
|
||||
int lastRow = 999;
|
||||
logger.finest("Last rownum=" + lastRow);
|
||||
sheet.shiftRows(rowPos, lastRow, invoices.size(), true, true);
|
||||
|
||||
for (ItemCollection invoice : invoices) {
|
||||
logger.finest("......copy row...");
|
||||
for (ItemCollection invoice : invoices) {
|
||||
logger.finest("......copy row...");
|
||||
|
||||
// now create a new line..
|
||||
XSSFRow row = sheet.createRow(rowPos);
|
||||
row.copyRowFrom(referenceRow, new CellCopyPolicy());
|
||||
// insert values
|
||||
row.getCell(0).setCellValue(invoice.getItemValueString("invoice.number"));
|
||||
row.getCell(1).setCellValue(invoice.getItemValueString("dbtr.number"));
|
||||
row.getCell(2).setCellValue(invoice.getItemValueString("space.name"));
|
||||
row.getCell(3).setCellValue(invoice.getItemValueString("invoice.text"));
|
||||
row.getCell(4).setCellValue(invoice.getItemValueDate("invoice.date"));
|
||||
row.getCell(5).setCellValue(invoice.getItemValueDate("invoice.duedate"));
|
||||
row.getCell(6).setCellValue(invoice.getItemValueDouble("invoice.total"));
|
||||
// now create a new line..
|
||||
XSSFRow row = sheet.createRow(rowPos);
|
||||
row.copyRowFrom(referenceRow, new CellCopyPolicy());
|
||||
// insert values
|
||||
row.getCell(0).setCellValue(invoice.getItemValueString("invoice.number"));
|
||||
row.getCell(1).setCellValue(invoice.getItemValueString("dbtr.number"));
|
||||
row.getCell(2).setCellValue(invoice.getItemValueString("space.name"));
|
||||
row.getCell(3).setCellValue(invoice.getItemValueString("invoice.text"));
|
||||
row.getCell(4).setCellValue(invoice.getItemValueDate("invoice.date"));
|
||||
row.getCell(5).setCellValue(invoice.getItemValueDate("invoice.duedate"));
|
||||
row.getCell(6).setCellValue(invoice.getItemValueDouble("invoice.total"));
|
||||
|
||||
rowPos++;
|
||||
}
|
||||
// delete reference row
|
||||
sheet.shiftRows(referenceRowPos, lastRow + invoices.size(), -1, true, true);
|
||||
rowPos++;
|
||||
}
|
||||
// delete reference row
|
||||
sheet.shiftRows(referenceRowPos, lastRow + invoices.size(), -1, true, true);
|
||||
|
||||
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
|
||||
// write back the file
|
||||
doc.write(byteArrayOutputStream);
|
||||
doc.close();
|
||||
byte[] newContent = byteArrayOutputStream.toByteArray();
|
||||
fileData.setContent(newContent);
|
||||
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
|
||||
// write back the file
|
||||
doc.write(byteArrayOutputStream);
|
||||
doc.close();
|
||||
byte[] newContent = byteArrayOutputStream.toByteArray();
|
||||
fileData.setContent(newContent);
|
||||
|
||||
} catch (IOException e) {
|
||||
throw new PluginException(ZahlungsavisExportAdapter.class.getSimpleName(), ERROR_CONFIG,
|
||||
"failed to update excel export: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new PluginException(ZahlungsavisExportAdapter.class.getSimpleName(), ERROR_CONFIG,
|
||||
"failed to update excel export: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a Cell by name or an optional absolute cell postion
|
||||
* <p>
|
||||
* Examples for refs are 'A1', 'AB3', 'MyCell' where 'MyCell' is a named cell.
|
||||
* <p>
|
||||
*
|
||||
*/
|
||||
public static XSSFCell getCellByRef(XSSFWorkbook doc, XSSFSheet sheet, String cellReference) {
|
||||
XSSFCell cell = null;
|
||||
/**
|
||||
* Returns a Cell by name or an optional absolute cell postion
|
||||
* <p>
|
||||
* Examples for refs are 'A1', 'AB3', 'MyCell' where 'MyCell' is a named cell.
|
||||
* <p>
|
||||
*
|
||||
*/
|
||||
public static XSSFCell getCellByRef(XSSFWorkbook doc, XSSFSheet sheet, String cellReference) {
|
||||
XSSFCell cell = null;
|
||||
|
||||
// first we test if the cellName is a named cell
|
||||
Name aNamedCell = doc.getName(cellReference);
|
||||
if (aNamedCell != null) {
|
||||
// yes its a named cell so we need to get the referrer Formula
|
||||
logger.finest("...resolving named cell = " + aNamedCell.getNameName());
|
||||
cellReference = aNamedCell.getRefersToFormula();
|
||||
// now we can find the cell by its ref
|
||||
}
|
||||
// first we test if the cellName is a named cell
|
||||
Name aNamedCell = doc.getName(cellReference);
|
||||
if (aNamedCell != null) {
|
||||
// yes its a named cell so we need to get the referrer Formula
|
||||
logger.finest("...resolving named cell = " + aNamedCell.getNameName());
|
||||
cellReference = aNamedCell.getRefersToFormula();
|
||||
// now we can find the cell by its ref
|
||||
}
|
||||
|
||||
CellReference cr = new CellReference(cellReference);
|
||||
XSSFRow row = sheet.getRow(cr.getRow());
|
||||
if (row == null) {
|
||||
logger.severe("Unable to resolve cell ref '" + cellReference + "'!");
|
||||
return null;
|
||||
}
|
||||
cell = row.getCell(cr.getCol());
|
||||
return cell;
|
||||
}
|
||||
CellReference cr = new CellReference(cellReference);
|
||||
XSSFRow row = sheet.getRow(cr.getRow());
|
||||
if (row == null) {
|
||||
logger.severe("Unable to resolve cell ref '" + cellReference + "'!");
|
||||
return null;
|
||||
}
|
||||
cell = row.getCell(cr.getCol());
|
||||
return cell;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,8 +17,8 @@ import jakarta.inject.Inject;
|
|||
|
||||
/**
|
||||
* Der InkassoAppendAdapter verknüpft eine Rechnung mit einem Inkasso Workflow
|
||||
* zum aktuellen Debitor. Existiert aktuell kein Inkasso für diesen
|
||||
* Debitor erzeugt der Adapter automatisch eine neue Prozessinstanz.
|
||||
* zum aktuellen Debitor. Existiert aktuell kein Inkasso für diesen Debitor
|
||||
* erzeugt der Adapter automatisch eine neue Prozessinstanz.
|
||||
* <p>
|
||||
* Wurde die Rechnung bereits einem Inkasso zugeordnet passiert nichts.
|
||||
*
|
||||
|
|
@ -41,8 +41,8 @@ public class InkassoAppendAdapter implements SignalAdapter {
|
|||
WorkflowService workflowService;
|
||||
|
||||
/**
|
||||
* This method finds or create the Inkasso and adds a reference
|
||||
* ($workitemref) to the current invoice.
|
||||
* This method finds or create the Inkasso and adds a reference ($workitemref)
|
||||
* to the current invoice.
|
||||
*
|
||||
* @throws PluginException
|
||||
*/
|
||||
|
|
@ -59,8 +59,8 @@ public class InkassoAppendAdapter implements SignalAdapter {
|
|||
|
||||
/**
|
||||
* Diese method hängt eine referenz der aktuellen Rechnung an den Inkasso
|
||||
* Workflow an. Gibt es noch keinen, wird einer erzeugt.
|
||||
* Die method liefert das Inkasso Workitem zurück.
|
||||
* Workflow an. Gibt es noch keinen, wird einer erzeugt. Die method liefert das
|
||||
* Inkasso Workitem zurück.
|
||||
*
|
||||
* @param document
|
||||
* @throws PluginException
|
||||
|
|
|
|||
|
|
@ -15,8 +15,8 @@ import jakarta.inject.Inject;
|
|||
import jakarta.inject.Named;
|
||||
|
||||
/**
|
||||
* Der InkassoController dient dazu eine bereits zugewiesene Rechnung
|
||||
* wieder aus dem Inkasso zu entfernen.
|
||||
* Der InkassoController dient dazu eine bereits zugewiesene Rechnung wieder aus
|
||||
* dem Inkasso zu entfernen.
|
||||
* <p>
|
||||
* Zusätzlich bietet er die Summenberechnung an, bei der die Gutschriften
|
||||
* abgezogen werden.
|
||||
|
|
|
|||
|
|
@ -29,8 +29,8 @@ import jakarta.inject.Inject;
|
|||
* processed invoices. This item is used in the Workflow Model to construct a
|
||||
* HTML Table wen sending the mail.
|
||||
* <p>
|
||||
* The Adapter also splits the item 'dbtr.mail' into a multi value field if
|
||||
* the value contains email addresses separated with new lines.
|
||||
* The Adapter also splits the item 'dbtr.mail' into a multi value field if the
|
||||
* value contains email addresses separated with new lines.
|
||||
*
|
||||
*
|
||||
* @version 1.0
|
||||
|
|
@ -125,24 +125,24 @@ public class MahnlaufExecuteAdapter implements SignalAdapter {
|
|||
}
|
||||
|
||||
switch (invoice.getTaskID()) {
|
||||
case 5200:
|
||||
case 5201:
|
||||
if (dunningLevel < 1)
|
||||
dunningLevel = 1;
|
||||
break;
|
||||
case 5210:
|
||||
case 5211:
|
||||
if (dunningLevel < 2)
|
||||
dunningLevel = 2;
|
||||
break;
|
||||
case 5220:
|
||||
if (dunningLevel < 3)
|
||||
dunningLevel = 3;
|
||||
break;
|
||||
default:
|
||||
if (dunningLevel < 1)
|
||||
dunningLevel = 1;
|
||||
break;
|
||||
case 5200:
|
||||
case 5201:
|
||||
if (dunningLevel < 1)
|
||||
dunningLevel = 1;
|
||||
break;
|
||||
case 5210:
|
||||
case 5211:
|
||||
if (dunningLevel < 2)
|
||||
dunningLevel = 2;
|
||||
break;
|
||||
case 5220:
|
||||
if (dunningLevel < 3)
|
||||
dunningLevel = 3;
|
||||
break;
|
||||
default:
|
||||
if (dunningLevel < 1)
|
||||
dunningLevel = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
// create a workitem stub for the mail message
|
||||
|
|
@ -179,18 +179,18 @@ public class MahnlaufExecuteAdapter implements SignalAdapter {
|
|||
// compute subject
|
||||
switch (dunningLevel) {
|
||||
|
||||
case 2:
|
||||
mahnLaufWorkitem.setItemValue("mail.subject_de", "2. MAHNUNG");
|
||||
mahnLaufWorkitem.setItemValue("mail.subject_en", "2. REMINDER");
|
||||
break;
|
||||
case 3:
|
||||
mahnLaufWorkitem.setItemValue("mail.subject_de", "LETZTE AUSSERGERICHTLICHE MAHNUNG");
|
||||
mahnLaufWorkitem.setItemValue("mail.subject_en", "LAST REMINDER");
|
||||
break;
|
||||
default:
|
||||
mahnLaufWorkitem.setItemValue("mail.subject_de", "1. MAHNUNG");
|
||||
mahnLaufWorkitem.setItemValue("mail.subject_en", "1. REMINDER");
|
||||
break;
|
||||
case 2:
|
||||
mahnLaufWorkitem.setItemValue("mail.subject_de", "2. MAHNUNG");
|
||||
mahnLaufWorkitem.setItemValue("mail.subject_en", "2. REMINDER");
|
||||
break;
|
||||
case 3:
|
||||
mahnLaufWorkitem.setItemValue("mail.subject_de", "LETZTE AUSSERGERICHTLICHE MAHNUNG");
|
||||
mahnLaufWorkitem.setItemValue("mail.subject_en", "LAST REMINDER");
|
||||
break;
|
||||
default:
|
||||
mahnLaufWorkitem.setItemValue("mail.subject_de", "1. MAHNUNG");
|
||||
mahnLaufWorkitem.setItemValue("mail.subject_en", "1. REMINDER");
|
||||
break;
|
||||
}
|
||||
|
||||
// Verify the dbtr.mail item (split into multi value)
|
||||
|
|
@ -198,8 +198,7 @@ public class MahnlaufExecuteAdapter implements SignalAdapter {
|
|||
for (String mail : mailListe) {
|
||||
logger.fine(" test mail address:'" + mail + "'");
|
||||
if (!InvoiceUtil.validateEmail(mail)) {
|
||||
throw new PluginException(MahnlaufExecuteAdapter.class.getName(),
|
||||
"INVALID_EMAIL",
|
||||
throw new PluginException(MahnlaufExecuteAdapter.class.getName(), "INVALID_EMAIL",
|
||||
"Die Daten konnten nicht aktualisiert werden! Bitte geben Sie eine gültige E-Mail Adresse ein!");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,146 +36,145 @@ import jakarta.inject.Inject;
|
|||
*/
|
||||
public class MahnlaufRefAddAdapter implements SignalAdapter {
|
||||
|
||||
private static Logger logger = Logger.getLogger(MahnlaufRefAddAdapter.class.getName());
|
||||
private static Logger logger = Logger.getLogger(MahnlaufRefAddAdapter.class.getName());
|
||||
|
||||
@EJB
|
||||
ModelService modelService;
|
||||
@EJB
|
||||
ModelService modelService;
|
||||
|
||||
@EJB
|
||||
WorkflowService workflowService = null;
|
||||
@EJB
|
||||
WorkflowService workflowService = null;
|
||||
|
||||
@Inject
|
||||
SepaWorkflowService sepaWorkflowService;
|
||||
@Inject
|
||||
SepaWorkflowService sepaWorkflowService;
|
||||
|
||||
@Inject
|
||||
BusinessPartnerService businessPartnerService;
|
||||
@Inject
|
||||
BusinessPartnerService businessPartnerService;
|
||||
|
||||
/**
|
||||
* This method finds or create the Mahnlauf and adds a reference ($workitemref)
|
||||
* to the current invoice.
|
||||
*
|
||||
* @throws PluginException
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public ItemCollection execute(ItemCollection invoice, ItemCollection event)
|
||||
throws AdapterException, PluginException {
|
||||
/**
|
||||
* This method finds or create the Mahnlauf and adds a reference ($workitemref)
|
||||
* to the current invoice.
|
||||
*
|
||||
* @throws PluginException
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public ItemCollection execute(ItemCollection invoice, ItemCollection event)
|
||||
throws AdapterException, PluginException {
|
||||
|
||||
if (invoice.getTaskID() < MahnlaufService.TASK_MAHNLAUF_START
|
||||
|| invoice.getTaskID() > MahnlaufService.TASK_MAHNLAUF_END) {
|
||||
throw new PluginException(MahnlaufRefAddAdapter.class.getName(),
|
||||
MahnlaufService.ERROR_CONFIG,
|
||||
"Der Mahnlauf kann nur für Rechnungen erstellt werden die bereits die Fälligkeit erreicht haben.");
|
||||
}
|
||||
if (invoice.getTaskID() < MahnlaufService.TASK_MAHNLAUF_START
|
||||
|| invoice.getTaskID() > MahnlaufService.TASK_MAHNLAUF_END) {
|
||||
throw new PluginException(MahnlaufRefAddAdapter.class.getName(), MahnlaufService.ERROR_CONFIG,
|
||||
"Der Mahnlauf kann nur für Rechnungen erstellt werden die bereits die Fälligkeit erreicht haben.");
|
||||
}
|
||||
|
||||
String dbtrNumber = invoice.getItemValueString(MahnlaufService.ITEM_DBTR_NUMBER);
|
||||
ItemCollection mahnLaufWorkitem;
|
||||
try {
|
||||
mahnLaufWorkitem = findMahnlauf(dbtrNumber);
|
||||
String dbtrNumber = invoice.getItemValueString(MahnlaufService.ITEM_DBTR_NUMBER);
|
||||
ItemCollection mahnLaufWorkitem;
|
||||
try {
|
||||
mahnLaufWorkitem = findMahnlauf(dbtrNumber);
|
||||
|
||||
if (mahnLaufWorkitem == null) {
|
||||
// create one...
|
||||
mahnLaufWorkitem = createNewMahnlauf(dbtrNumber, invoice, event);
|
||||
}
|
||||
if (mahnLaufWorkitem == null) {
|
||||
// create one...
|
||||
mahnLaufWorkitem = createNewMahnlauf(dbtrNumber, invoice, event);
|
||||
}
|
||||
|
||||
// add Invoice to Mahnlauf
|
||||
List<String> refList = mahnLaufWorkitem.getItemValue("$workitemref");
|
||||
if (!refList.contains(invoice.getUniqueID())) {
|
||||
mahnLaufWorkitem.appendItemValueUnique("$workitemref", invoice.getUniqueID());
|
||||
}
|
||||
// add Invoice to Mahnlauf
|
||||
List<String> refList = mahnLaufWorkitem.getItemValue("$workitemref");
|
||||
if (!refList.contains(invoice.getUniqueID())) {
|
||||
mahnLaufWorkitem.appendItemValueUnique("$workitemref", invoice.getUniqueID());
|
||||
}
|
||||
|
||||
// set event 100 and process
|
||||
ItemCollection mahnlaufConfig = workflowService.evalWorkflowResult(event, "mahnlauf", invoice, true);
|
||||
int eventID = mahnlaufConfig.getItemValueInteger("event");
|
||||
// set event 100 and process
|
||||
ItemCollection mahnlaufConfig = workflowService.evalWorkflowResult(event, "mahnlauf", invoice, true);
|
||||
int eventID = mahnlaufConfig.getItemValueInteger("event");
|
||||
|
||||
mahnLaufWorkitem.event(eventID);
|
||||
workflowService.processWorkItem(mahnLaufWorkitem);
|
||||
mahnLaufWorkitem.event(eventID);
|
||||
workflowService.processWorkItem(mahnLaufWorkitem);
|
||||
|
||||
} catch (QueryException | ModelException e) {
|
||||
throw new PluginException(MahnlaufRefAddAdapter.class.getName(),
|
||||
MahnlaufService.ERROR_CONFIG, "Unable to create Mahnlauf", e);
|
||||
}
|
||||
} catch (QueryException | ModelException e) {
|
||||
throw new PluginException(MahnlaufRefAddAdapter.class.getName(), MahnlaufService.ERROR_CONFIG,
|
||||
"Unable to create Mahnlauf", e);
|
||||
}
|
||||
|
||||
// set mahnlauf ref
|
||||
invoice.setItemValue("dunning.ref", mahnLaufWorkitem.getUniqueID());
|
||||
return invoice;
|
||||
}
|
||||
// set mahnlauf ref
|
||||
invoice.setItemValue("dunning.ref", mahnLaufWorkitem.getUniqueID());
|
||||
return invoice;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method finds an open mahnlauf for a debtr.numbre (name)
|
||||
*
|
||||
* @param key
|
||||
* @return
|
||||
* @throws QueryException
|
||||
*/
|
||||
public ItemCollection findMahnlauf(String key) throws QueryException {
|
||||
String query = "(type:workitem) AND ($modelversion:mahnlauf*) AND (name:\"" + key + "\")";
|
||||
List<ItemCollection> resultList = workflowService.getDocumentService().find(query, 1, 0, "$modified", true);
|
||||
/**
|
||||
* Helper method finds an open mahnlauf for a debtr.numbre (name)
|
||||
*
|
||||
* @param key
|
||||
* @return
|
||||
* @throws QueryException
|
||||
*/
|
||||
public ItemCollection findMahnlauf(String key) throws QueryException {
|
||||
String query = "(type:workitem) AND ($modelversion:mahnlauf*) AND (name:\"" + key + "\")";
|
||||
List<ItemCollection> resultList = workflowService.getDocumentService().find(query, 1, 0, "$modified", true);
|
||||
|
||||
if (resultList.size() > 0) {
|
||||
return resultList.get(0);
|
||||
}
|
||||
// no mahnaluffound
|
||||
return null;
|
||||
}
|
||||
if (resultList.size() > 0) {
|
||||
return resultList.get(0);
|
||||
}
|
||||
// no mahnaluffound
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to create a new Mahnlauf workitem
|
||||
*
|
||||
* @param key
|
||||
* @param invoice
|
||||
* @return
|
||||
* @throws ModelException
|
||||
* @throws PluginException
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public ItemCollection createNewMahnlauf(String key, ItemCollection invoice, ItemCollection event)
|
||||
throws ModelException, PluginException {
|
||||
String modelVersion = null;
|
||||
int taskID = -1;
|
||||
int eventID = -1;
|
||||
// test if the event provides a sepa export configuration
|
||||
ItemCollection mahnlaufConfig = workflowService.evalWorkflowResult(event, "mahnlauf", invoice, true);
|
||||
if (mahnlaufConfig != null && mahnlaufConfig.hasItem("modelversion") && mahnlaufConfig.hasItem("task")) {
|
||||
logger.fine("read model information from event");
|
||||
modelVersion = mahnlaufConfig.getItemValueString("modelVersion");
|
||||
taskID = mahnlaufConfig.getItemValueInteger("task");
|
||||
eventID = mahnlaufConfig.getItemValueInteger("event");
|
||||
}
|
||||
/**
|
||||
* Helper method to create a new Mahnlauf workitem
|
||||
*
|
||||
* @param key
|
||||
* @param invoice
|
||||
* @return
|
||||
* @throws ModelException
|
||||
* @throws PluginException
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public ItemCollection createNewMahnlauf(String key, ItemCollection invoice, ItemCollection event)
|
||||
throws ModelException, PluginException {
|
||||
String modelVersion = null;
|
||||
int taskID = -1;
|
||||
int eventID = -1;
|
||||
// test if the event provides a sepa export configuration
|
||||
ItemCollection mahnlaufConfig = workflowService.evalWorkflowResult(event, "mahnlauf", invoice, true);
|
||||
if (mahnlaufConfig != null && mahnlaufConfig.hasItem("modelversion") && mahnlaufConfig.hasItem("task")) {
|
||||
logger.fine("read model information from event");
|
||||
modelVersion = mahnlaufConfig.getItemValueString("modelVersion");
|
||||
taskID = mahnlaufConfig.getItemValueInteger("task");
|
||||
eventID = mahnlaufConfig.getItemValueInteger("event");
|
||||
}
|
||||
|
||||
// build the sepa export workitem....
|
||||
ItemCollection mahnlaufWorkitem = new ItemCollection().model(modelVersion).task(taskID);
|
||||
mahnlaufWorkitem.replaceItemValue("name", key);
|
||||
mahnlaufWorkitem.replaceItemValue(WorkflowKernel.CREATED, new Date());
|
||||
mahnlaufWorkitem.replaceItemValue(WorkflowKernel.MODIFIED, new Date());
|
||||
// set unqiueid
|
||||
mahnlaufWorkitem.setItemValue(WorkflowKernel.UNIQUEID, WorkflowKernel.generateUniqueID());
|
||||
// build the sepa export workitem....
|
||||
ItemCollection mahnlaufWorkitem = new ItemCollection().model(modelVersion).task(taskID);
|
||||
mahnlaufWorkitem.replaceItemValue("name", key);
|
||||
mahnlaufWorkitem.replaceItemValue(WorkflowKernel.CREATED, new Date());
|
||||
mahnlaufWorkitem.replaceItemValue(WorkflowKernel.MODIFIED, new Date());
|
||||
// set unqiueid
|
||||
mahnlaufWorkitem.setItemValue(WorkflowKernel.UNIQUEID, WorkflowKernel.generateUniqueID());
|
||||
|
||||
// copy dbtr_iban
|
||||
mahnlaufWorkitem.setItemValue(MahnlaufService.ITEM_DBTR_NAME,
|
||||
invoice.getItemValue(MahnlaufService.ITEM_DBTR_NAME));
|
||||
// copy dbtr_iban
|
||||
mahnlaufWorkitem.setItemValue(MahnlaufService.ITEM_DBTR_NAME,
|
||||
invoice.getItemValue(MahnlaufService.ITEM_DBTR_NAME));
|
||||
|
||||
// lookup email....
|
||||
String dbtrNumber = invoice.getItemValueString("dbtr.number");
|
||||
ItemCollection businessPartner = businessPartnerService
|
||||
.getBusinessPartnerByID(InvoiceUtil.buildBPID(dbtrNumber));
|
||||
if (businessPartner != null) {
|
||||
mahnlaufWorkitem.setItemValue(MahnlaufService.ITEM_DBTR_EMAIL, businessPartner.getItemValue("dbtr.mail"));// dbtr.mail
|
||||
}
|
||||
// lookup email....
|
||||
String dbtrNumber = invoice.getItemValueString("dbtr.number");
|
||||
ItemCollection businessPartner = businessPartnerService
|
||||
.getBusinessPartnerByID(InvoiceUtil.buildBPID(dbtrNumber));
|
||||
if (businessPartner != null) {
|
||||
mahnlaufWorkitem.setItemValue(MahnlaufService.ITEM_DBTR_EMAIL, businessPartner.getItemValue("dbtr.mail"));// dbtr.mail
|
||||
}
|
||||
|
||||
mahnlaufWorkitem.setItemValue(MahnlaufService.ITEM_DBTR_NUMBER,
|
||||
invoice.getItemValue(MahnlaufService.ITEM_DBTR_NUMBER));
|
||||
mahnlaufWorkitem.setItemValue("invoice.language", invoice.getItemValue("invoice.language"));
|
||||
mahnlaufWorkitem.setItemValue(MahnlaufService.ITEM_DBTR_NUMBER,
|
||||
invoice.getItemValue(MahnlaufService.ITEM_DBTR_NUMBER));
|
||||
mahnlaufWorkitem.setItemValue("invoice.language", invoice.getItemValue("invoice.language"));
|
||||
|
||||
// set workflow group name from the Task Element to identify document in xslt
|
||||
Model model = modelService.getModel(modelVersion);
|
||||
ItemCollection task = model.getTask(taskID);
|
||||
String modelTaskGroupName = task.getItemValueString("txtworkflowgroup"); // DO NOT CHANGE!
|
||||
mahnlaufWorkitem.setItemValue(WorkflowKernel.WORKFLOWGROUP, modelTaskGroupName);
|
||||
// set workflow group name from the Task Element to identify document in xslt
|
||||
Model model = modelService.getModel(modelVersion);
|
||||
ItemCollection task = model.getTask(taskID);
|
||||
String modelTaskGroupName = task.getItemValueString("txtworkflowgroup"); // DO NOT CHANGE!
|
||||
mahnlaufWorkitem.setItemValue(WorkflowKernel.WORKFLOWGROUP, modelTaskGroupName);
|
||||
|
||||
logger.info("...created new mahnlauf " + key + "...");
|
||||
logger.info("...created new mahnlauf " + key + "...");
|
||||
|
||||
return mahnlaufWorkitem;
|
||||
}
|
||||
return mahnlaufWorkitem;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -49,8 +49,8 @@ import jakarta.ejb.Singleton;
|
|||
import jakarta.inject.Inject;
|
||||
|
||||
/**
|
||||
* Der MahnlaufService wird vom MahnlaufExecuteAdapter um
|
||||
* Ausgangsrechnungen zu akutalisieren.
|
||||
* Der MahnlaufService wird vom MahnlaufExecuteAdapter um Ausgangsrechnungen zu
|
||||
* akutalisieren.
|
||||
*
|
||||
* @author rsoika
|
||||
*
|
||||
|
|
|
|||
|
|
@ -59,11 +59,10 @@ import jakarta.enterprise.event.Observes;
|
|||
|
||||
/**
|
||||
* Der BusinessPartnerImportService hängt sich an den standard CSVImport Service
|
||||
* der die Cargosoft Stammdaten aktualisiert.
|
||||
* Es ist ein simples Observer Pattern das auf das Document Event
|
||||
* "ON_DOCUMENT_SAVE" reagiert. Hier hängt sich der BusinessPartnerImportService
|
||||
* ein und prüft ob der Workflow schon existiert oder ggf. aktualisiert werden
|
||||
* muss.
|
||||
* der die Cargosoft Stammdaten aktualisiert. Es ist ein simples Observer
|
||||
* Pattern das auf das Document Event "ON_DOCUMENT_SAVE" reagiert. Hier hängt
|
||||
* sich der BusinessPartnerImportService ein und prüft ob der Workflow schon
|
||||
* existiert oder ggf. aktualisiert werden muss.
|
||||
* <p>
|
||||
* Der Service migriert auch die alten zusätzlichen IBAN/BIC felder wenn der
|
||||
* Business partner erstmals neu angelegt wird.
|
||||
|
|
|
|||
|
|
@ -89,17 +89,16 @@ import jakarta.enterprise.event.Observes;
|
|||
import jakarta.inject.Inject;
|
||||
|
||||
/**
|
||||
* Der CargosoftXMLEAkteImportService erweitert den FTPImportService und
|
||||
* kann XML EAkten (Steuerbescheide) von Cargosoft importieren.
|
||||
* Der Service reagiert auf DocumentImportEvents und kann über das Options Feld
|
||||
* konfiguriert werden.
|
||||
* Der CargosoftXMLEAkteImportService erweitert den FTPImportService und kann
|
||||
* XML EAkten (Steuerbescheide) von Cargosoft importieren. Der Service reagiert
|
||||
* auf DocumentImportEvents und kann über das Options Feld konfiguriert werden.
|
||||
* <p>
|
||||
* Im Gegensatz zum FTPImportService werden die XML Dateien nach einem
|
||||
* speziellen Verfahren geparsed und dann als Steuerbescheid importiert.
|
||||
* <p>
|
||||
* In den Optionen muss die option "mandant.id" hinterlegt sein. Stimmt
|
||||
* diese beim Import nicht mit der Mandanten Nummer in der XML Datei überein,
|
||||
* wird das XML Dokument gelöscht und nicht importiert.
|
||||
* In den Optionen muss die option "mandant.id" hinterlegt sein. Stimmt diese
|
||||
* beim Import nicht mit der Mandanten Nummer in der XML Datei überein, wird das
|
||||
* XML Dokument gelöscht und nicht importiert.
|
||||
*
|
||||
*
|
||||
*
|
||||
|
|
@ -162,8 +161,7 @@ public class CargosoftXMLEAkteImportService {
|
|||
return;
|
||||
}
|
||||
|
||||
documentImportService.logMessage("...CARGOSOFT_EAKTE_XML Import started: mandant.id=" + mandantID,
|
||||
event);
|
||||
documentImportService.logMessage("...CARGOSOFT_EAKTE_XML Import started: mandant.id=" + mandantID, event);
|
||||
String ftpServer = event.getSource().getItemValueString(DocumentImportService.SOURCE_ITEM_SERVER);
|
||||
String ftpPort = event.getSource().getItemValueString(DocumentImportService.SOURCE_ITEM_PORT);
|
||||
String ftpUser = event.getSource().getItemValueString(DocumentImportService.SOURCE_ITEM_USER);
|
||||
|
|
@ -216,8 +214,8 @@ public class CargosoftXMLEAkteImportService {
|
|||
ftpClient.connect(ftpServer, ftpPort);
|
||||
|
||||
if (ftpClient.login(ftpUser, ftpPassword) == false) {
|
||||
throw new PluginException(CargosoftXMLEAkteImportService.class.getName(),
|
||||
"FTP_ERROR", "FTP file transfer failed: login failed!");
|
||||
throw new PluginException(CargosoftXMLEAkteImportService.class.getName(), "FTP_ERROR",
|
||||
"FTP file transfer failed: login failed!");
|
||||
}
|
||||
ftpClient.enterLocalPassiveMode();
|
||||
logger.finest("...... FileType=" + FTP.BINARY_FILE_TYPE);
|
||||
|
|
@ -225,8 +223,7 @@ public class CargosoftXMLEAkteImportService {
|
|||
ftpClient.setControlEncoding("UTF-8");
|
||||
|
||||
} catch (IOException e) {
|
||||
throw new PluginException(CargosoftXMLEAkteImportService.class.getName(),
|
||||
"FTP_ERROR", e.getMessage());
|
||||
throw new PluginException(CargosoftXMLEAkteImportService.class.getName(), "FTP_ERROR", e.getMessage());
|
||||
}
|
||||
|
||||
return ftpClient;
|
||||
|
|
@ -250,8 +247,8 @@ public class CargosoftXMLEAkteImportService {
|
|||
// try to enter the working directory and read all files...
|
||||
boolean bWorkingDir = ftpClient.changeWorkingDirectory(ftpPath);
|
||||
if (bWorkingDir == false) {
|
||||
throw new PluginException(CargosoftXMLEAkteImportService.class.getName(),
|
||||
"FTP_ERROR", "...failed to change into working directory: ");
|
||||
throw new PluginException(CargosoftXMLEAkteImportService.class.getName(), "FTP_ERROR",
|
||||
"...failed to change into working directory: ");
|
||||
}
|
||||
|
||||
FTPFile[] allFiles = ftpClient.listFiles(ftpPath);
|
||||
|
|
@ -299,10 +296,10 @@ public class CargosoftXMLEAkteImportService {
|
|||
// "processed/");
|
||||
// }
|
||||
|
||||
} catch (AccessDeniedException | ProcessingErrorException | PluginException
|
||||
| ModelException | XPathExpressionException | TransformerException e) {
|
||||
throw new PluginException(CargosoftXMLEAkteImportService.class.getName(),
|
||||
"FTP_ERROR", e.getMessage());
|
||||
} catch (AccessDeniedException | ProcessingErrorException | PluginException | ModelException
|
||||
| XPathExpressionException | TransformerException e) {
|
||||
throw new PluginException(CargosoftXMLEAkteImportService.class.getName(), "FTP_ERROR",
|
||||
e.getMessage());
|
||||
}
|
||||
}
|
||||
documentImportService.logMessage("..." + count + " new files imported.", event);
|
||||
|
|
@ -313,8 +310,7 @@ public class CargosoftXMLEAkteImportService {
|
|||
int r = ftpClient.getReplyCode();
|
||||
logger.severe("FTP ReplyCode=" + r);
|
||||
|
||||
throw new PluginException(CargosoftXMLEAkteImportService.class.getName(),
|
||||
"FTP_ERROR", e.getMessage());
|
||||
throw new PluginException(CargosoftXMLEAkteImportService.class.getName(), "FTP_ERROR", e.getMessage());
|
||||
|
||||
} finally {
|
||||
// do logout....
|
||||
|
|
@ -324,8 +320,7 @@ public class CargosoftXMLEAkteImportService {
|
|||
ftpClient.disconnect();
|
||||
} catch (IOException e) {
|
||||
documentImportService.logMessage("...FTP file transfer failed: " + e.getMessage(), event);
|
||||
throw new PluginException(CargosoftXMLEAkteImportService.class.getName(),
|
||||
"FTP_ERROR", e.getMessage());
|
||||
throw new PluginException(CargosoftXMLEAkteImportService.class.getName(), "FTP_ERROR", e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -344,9 +339,8 @@ public class CargosoftXMLEAkteImportService {
|
|||
* @throws XPathExpressionException
|
||||
*/
|
||||
public ItemCollection createWorkitem(ItemCollection source, String fileName, byte[] rawData,
|
||||
Map<String, List<String>> spacePosMappings)
|
||||
throws AccessDeniedException, ProcessingErrorException, PluginException, ModelException,
|
||||
XPathExpressionException, TransformerException {
|
||||
Map<String, List<String>> spacePosMappings) throws AccessDeniedException, ProcessingErrorException,
|
||||
PluginException, ModelException, XPathExpressionException, TransformerException {
|
||||
ItemCollection workitem = new ItemCollection();
|
||||
workitem.model(source.getItemValueString(DocumentImportService.SOURCE_ITEM_MODELVERSION));
|
||||
workitem.task(source.getItemValueInteger(DocumentImportService.SOURCE_ITEM_TASK));
|
||||
|
|
@ -375,37 +369,37 @@ public class CargosoftXMLEAkteImportService {
|
|||
// invoice.rate
|
||||
// invoice.base.amount
|
||||
|
||||
readXMLValue(doc, "/CargoSoftEFile/EFile/References/Reference[@type='client']", workitem,
|
||||
"mandant.id", String.class);
|
||||
readXMLValue(doc, "/CargoSoftEFile/EFile/References/Reference[@type='client']", workitem, "mandant.id",
|
||||
String.class);
|
||||
|
||||
readXMLValue(doc, "/CargoSoftEFile/EFile/References/Reference[@type='cs_voucher_number']",
|
||||
workitem, "invoice.number", String.class);
|
||||
readXMLValue(doc, "/CargoSoftEFile/EFile/References/Reference[@type='cs_voucher_number']", workitem,
|
||||
"invoice.number", String.class);
|
||||
|
||||
readXMLValue(doc, "/CargoSoftEFile/EFile/References/Reference[@type='cs_address_number']",
|
||||
workitem, "cdtr.number", String.class);
|
||||
readXMLValue(doc, "/CargoSoftEFile/EFile/References/Reference[@type='cs_address_number']", workitem,
|
||||
"cdtr.number", String.class);
|
||||
|
||||
readXMLValue(doc, "/CargoSoftEFile/EFile/References/Reference[@type='voucherdate']",
|
||||
workitem, "invoice.date", Date.class);
|
||||
readXMLValue(doc, "/CargoSoftEFile/EFile/References/Reference[@type='voucherdate']", workitem,
|
||||
"invoice.date", Date.class);
|
||||
|
||||
readXMLValue(doc, "/CargoSoftEFile/EFile/References/Reference[@type='currency']",
|
||||
workitem, "invoice.currency", String.class);
|
||||
readXMLValue(doc, "/CargoSoftEFile/EFile/References/Reference[@type='currency']", workitem,
|
||||
"invoice.currency", String.class);
|
||||
|
||||
readXMLValue(doc, "/CargoSoftEFile/EFile/References/Reference[@type='currency_rate']",
|
||||
workitem, "invoice.rate", Double.class);
|
||||
readXMLValue(doc, "/CargoSoftEFile/EFile/References/Reference[@type='currency_rate']", workitem,
|
||||
"invoice.rate", Double.class);
|
||||
|
||||
readXMLValue(doc, "/CargoSoftEFile/EFile/References/Reference[@type='total_net_amount']",
|
||||
workitem, "invoice.total.net", Double.class);
|
||||
readXMLValue(doc, "/CargoSoftEFile/EFile/References/Reference[@type='total_tax_amount']",
|
||||
workitem, "invoice.total.tax", Double.class);
|
||||
readXMLValue(doc, "/CargoSoftEFile/EFile/References/Reference[@type='reference']",
|
||||
workitem, "invoice.atc.number", String.class);
|
||||
readXMLValue(doc, "/CargoSoftEFile/EFile/References/Reference[@type='booking_period']",
|
||||
workitem, "invoice.booking_period", String.class);
|
||||
readXMLValue(doc, "/CargoSoftEFile/EFile/References/Reference[@type='total_net_amount']", workitem,
|
||||
"invoice.total.net", Double.class);
|
||||
readXMLValue(doc, "/CargoSoftEFile/EFile/References/Reference[@type='total_tax_amount']", workitem,
|
||||
"invoice.total.tax", Double.class);
|
||||
readXMLValue(doc, "/CargoSoftEFile/EFile/References/Reference[@type='reference']", workitem,
|
||||
"invoice.atc.number", String.class);
|
||||
readXMLValue(doc, "/CargoSoftEFile/EFile/References/Reference[@type='booking_period']", workitem,
|
||||
"invoice.booking_period", String.class);
|
||||
|
||||
readXMLValue(doc, "/CargoSoftEFile/EFile/References/Reference[@type='booking_date']",
|
||||
workitem, "invoice.booking_date", Date.class);
|
||||
readXMLValue(doc, "/CargoSoftEFile/EFile/References/Reference[@type='booking_text']",
|
||||
workitem, "invoice.booking_text", String.class);
|
||||
readXMLValue(doc, "/CargoSoftEFile/EFile/References/Reference[@type='booking_date']", workitem,
|
||||
"invoice.booking_date", Date.class);
|
||||
readXMLValue(doc, "/CargoSoftEFile/EFile/References/Reference[@type='booking_text']", workitem,
|
||||
"invoice.booking_text", String.class);
|
||||
|
||||
// verify if invoice is already imported.
|
||||
if (alreadyImported(workitem.getItemValueString("invoice.number"))) {
|
||||
|
|
@ -440,8 +434,7 @@ public class CargosoftXMLEAkteImportService {
|
|||
attacheFiles(doc, workitem);
|
||||
}
|
||||
} catch (ParserConfigurationException | SAXException | IOException e) {
|
||||
throw new PluginException(CargosoftXMLEAkteImportService.class.getName(),
|
||||
"XML_ERROR", e.getMessage());
|
||||
throw new PluginException(CargosoftXMLEAkteImportService.class.getName(), "XML_ERROR", e.getMessage());
|
||||
}
|
||||
return workitem;
|
||||
}
|
||||
|
|
@ -452,8 +445,7 @@ public class CargosoftXMLEAkteImportService {
|
|||
*
|
||||
* /Invoices/Invoice/InvoiceHeader/Client/Code
|
||||
*
|
||||
* Beispiel Datum:
|
||||
* <InvoiceDate>2024-05-13T00:00:00+02:00</InvoiceDate>
|
||||
* Beispiel Datum: <InvoiceDate>2024-05-13T00:00:00+02:00</InvoiceDate>
|
||||
*
|
||||
* @param doc - xml doc
|
||||
* @param expression - xpath expression
|
||||
|
|
@ -513,9 +505,9 @@ public class CargosoftXMLEAkteImportService {
|
|||
}
|
||||
|
||||
/**
|
||||
* This method attache the pdf file and the XML file to the workitem.
|
||||
* The method removes the file content first form the xml tree and attache the
|
||||
* XML without the pdf data.
|
||||
* This method attache the pdf file and the XML file to the workitem. The method
|
||||
* removes the file content first form the xml tree and attache the XML without
|
||||
* the pdf data.
|
||||
*
|
||||
* @throws XPathExpressionException
|
||||
* @throws TransformerException
|
||||
|
|
@ -526,24 +518,23 @@ public class CargosoftXMLEAkteImportService {
|
|||
XPathFactory xpathFactory = XPathFactory.newInstance();
|
||||
XPath xpath = xpathFactory.newXPath();
|
||||
// read filename and content....
|
||||
readXMLValue(doc, "/CargoSoftEFile/EFile/Attachments/Attachment/Filename",
|
||||
workitem, "import.filename", String.class);
|
||||
readXMLValue(doc, "/CargoSoftEFile/EFile/Attachments/Attachment/Content",
|
||||
workitem, "import.filedata", String.class);
|
||||
readXMLValue(doc, "/CargoSoftEFile/EFile/Attachments/Attachment/Filename", workitem, "import.filename",
|
||||
String.class);
|
||||
readXMLValue(doc, "/CargoSoftEFile/EFile/Attachments/Attachment/Content", workitem, "import.filedata",
|
||||
String.class);
|
||||
|
||||
// attache the PDF file content
|
||||
String fileDataString = workitem.getItemValueString("import.filedata");
|
||||
byte[] decodedPDFData = java.util.Base64.getDecoder().decode(fileDataString);
|
||||
FileData fileData = new FileData(workitem.getItemValueString("import.filename"),
|
||||
decodedPDFData, "application/pdf", null);
|
||||
FileData fileData = new FileData(workitem.getItemValueString("import.filename"), decodedPDFData,
|
||||
"application/pdf", null);
|
||||
workitem.addFileData(fileData);
|
||||
// remove the temp items..
|
||||
workitem.removeItem("import.filename");
|
||||
workitem.removeItem("import.filedata");
|
||||
|
||||
// next remove the Attachments/AttachmentContent from the dom tree
|
||||
XPathExpression attachmentsExpr = xpath
|
||||
.compile("/CargoSoftEFile/EFile/Attachments/Attachment/Content");
|
||||
XPathExpression attachmentsExpr = xpath.compile("/CargoSoftEFile/EFile/Attachments/Attachment/Content");
|
||||
NodeList contentNodes = (NodeList) attachmentsExpr.evaluate(doc, XPathConstants.NODESET);
|
||||
// Remove the matching nodes
|
||||
for (int i = 0; i < contentNodes.getLength(); i++) {
|
||||
|
|
@ -594,8 +585,7 @@ public class CargosoftXMLEAkteImportService {
|
|||
* child Workitem for each row.
|
||||
*
|
||||
* The method assumes that the rows are starting with the type 'row_n_' where
|
||||
* 'n' is the row number.
|
||||
* We start with row 1 and read until we found more rows.
|
||||
* 'n' is the row number. We start with row 1 and read until we found more rows.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
|
|
|
|||
|
|
@ -89,19 +89,18 @@ import jakarta.inject.Inject;
|
|||
|
||||
/**
|
||||
* Der CargosoftXMLInvoiceImportImportService erweitert den FTPImportService und
|
||||
* kann XML Invoice Dokumente von Cargosoft importieren.
|
||||
* Der Service reagiert auf DocumentImportEvents und kann über das Options Feld
|
||||
* konfiguriert werden.
|
||||
* kann XML Invoice Dokumente von Cargosoft importieren. Der Service reagiert
|
||||
* auf DocumentImportEvents und kann über das Options Feld konfiguriert werden.
|
||||
* <p>
|
||||
* Im Gegensatz zum FTPImportService werden die XML Dateien nach einem
|
||||
* speziellen Verfahren geparsed und dann als Ausgangsrechnungen importiert.
|
||||
* Der Service ersetzt den alten DATEV Import. Falls eine Rechnung schon
|
||||
* existiert (Rechnungsnummer) wird der Datensatz vom FTP Laufwerk gelöscht und
|
||||
* nicht importiert.
|
||||
* speziellen Verfahren geparsed und dann als Ausgangsrechnungen importiert. Der
|
||||
* Service ersetzt den alten DATEV Import. Falls eine Rechnung schon existiert
|
||||
* (Rechnungsnummer) wird der Datensatz vom FTP Laufwerk gelöscht und nicht
|
||||
* importiert.
|
||||
* <p>
|
||||
* In den Optionen muss die option "mandant.id" hinterlegt sein. Stimmt
|
||||
* diese beim Import nicht mit der Mandanten Nummer in der XML Datei überein,
|
||||
* wird das XML Dokument gelöscht und nicht importiert.
|
||||
* In den Optionen muss die option "mandant.id" hinterlegt sein. Stimmt diese
|
||||
* beim Import nicht mit der Mandanten Nummer in der XML Datei überein, wird das
|
||||
* XML Dokument gelöscht und nicht importiert.
|
||||
*
|
||||
*
|
||||
*
|
||||
|
|
@ -164,8 +163,7 @@ public class CargosoftXMLInvoiceImportService {
|
|||
return;
|
||||
}
|
||||
|
||||
documentImportService.logMessage("...CARGOSOFT_INVOICE_XML Import started: mandant.id=" + mandantID,
|
||||
event);
|
||||
documentImportService.logMessage("...CARGOSOFT_INVOICE_XML Import started: mandant.id=" + mandantID, event);
|
||||
String ftpServer = event.getSource().getItemValueString(DocumentImportService.SOURCE_ITEM_SERVER);
|
||||
String ftpPort = event.getSource().getItemValueString(DocumentImportService.SOURCE_ITEM_PORT);
|
||||
String ftpUser = event.getSource().getItemValueString(DocumentImportService.SOURCE_ITEM_USER);
|
||||
|
|
@ -218,8 +216,8 @@ public class CargosoftXMLInvoiceImportService {
|
|||
ftpClient.connect(ftpServer, ftpPort);
|
||||
|
||||
if (ftpClient.login(ftpUser, ftpPassword) == false) {
|
||||
throw new PluginException(CargosoftXMLInvoiceImportService.class.getName(),
|
||||
"FTP_ERROR", "FTP file transfer failed: login failed!");
|
||||
throw new PluginException(CargosoftXMLInvoiceImportService.class.getName(), "FTP_ERROR",
|
||||
"FTP file transfer failed: login failed!");
|
||||
}
|
||||
ftpClient.enterLocalPassiveMode();
|
||||
logger.finest("...... FileType=" + FTP.BINARY_FILE_TYPE);
|
||||
|
|
@ -227,8 +225,7 @@ public class CargosoftXMLInvoiceImportService {
|
|||
ftpClient.setControlEncoding("UTF-8");
|
||||
|
||||
} catch (IOException e) {
|
||||
throw new PluginException(CargosoftXMLInvoiceImportService.class.getName(),
|
||||
"FTP_ERROR", e.getMessage());
|
||||
throw new PluginException(CargosoftXMLInvoiceImportService.class.getName(), "FTP_ERROR", e.getMessage());
|
||||
}
|
||||
|
||||
return ftpClient;
|
||||
|
|
@ -252,8 +249,8 @@ public class CargosoftXMLInvoiceImportService {
|
|||
// try to enter the working directory and read all files...
|
||||
boolean bWorkingDir = ftpClient.changeWorkingDirectory(ftpPath);
|
||||
if (bWorkingDir == false) {
|
||||
throw new PluginException(CargosoftXMLInvoiceImportService.class.getName(),
|
||||
"FTP_ERROR", "...failed to change into working directory: ");
|
||||
throw new PluginException(CargosoftXMLInvoiceImportService.class.getName(), "FTP_ERROR",
|
||||
"...failed to change into working directory: ");
|
||||
}
|
||||
|
||||
FTPFile[] allFiles = ftpClient.listFiles(ftpPath);
|
||||
|
|
@ -301,10 +298,10 @@ public class CargosoftXMLInvoiceImportService {
|
|||
// "processed/");
|
||||
// }
|
||||
|
||||
} catch (AccessDeniedException | ProcessingErrorException | PluginException
|
||||
| ModelException | XPathExpressionException | TransformerException e) {
|
||||
throw new PluginException(CargosoftXMLInvoiceImportService.class.getName(),
|
||||
"FTP_ERROR", e.getMessage());
|
||||
} catch (AccessDeniedException | ProcessingErrorException | PluginException | ModelException
|
||||
| XPathExpressionException | TransformerException e) {
|
||||
throw new PluginException(CargosoftXMLInvoiceImportService.class.getName(), "FTP_ERROR",
|
||||
e.getMessage());
|
||||
}
|
||||
}
|
||||
documentImportService.logMessage("..." + count + " new files imported.", event);
|
||||
|
|
@ -315,8 +312,7 @@ public class CargosoftXMLInvoiceImportService {
|
|||
int r = ftpClient.getReplyCode();
|
||||
logger.severe("FTP ReplyCode=" + r);
|
||||
|
||||
throw new PluginException(CargosoftXMLInvoiceImportService.class.getName(),
|
||||
"FTP_ERROR", e.getMessage());
|
||||
throw new PluginException(CargosoftXMLInvoiceImportService.class.getName(), "FTP_ERROR", e.getMessage());
|
||||
|
||||
} finally {
|
||||
// do logout....
|
||||
|
|
@ -326,8 +322,8 @@ public class CargosoftXMLInvoiceImportService {
|
|||
ftpClient.disconnect();
|
||||
} catch (IOException e) {
|
||||
documentImportService.logMessage("...FTP file transfer failed: " + e.getMessage(), event);
|
||||
throw new PluginException(CargosoftXMLInvoiceImportService.class.getName(),
|
||||
"FTP_ERROR", e.getMessage());
|
||||
throw new PluginException(CargosoftXMLInvoiceImportService.class.getName(), "FTP_ERROR",
|
||||
e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -346,9 +342,8 @@ public class CargosoftXMLInvoiceImportService {
|
|||
* @throws XPathExpressionException
|
||||
*/
|
||||
public ItemCollection createWorkitem(ItemCollection source, String fileName, byte[] rawData,
|
||||
Map<String, List<String>> spacePosMappings)
|
||||
throws AccessDeniedException, ProcessingErrorException, PluginException, ModelException,
|
||||
XPathExpressionException, TransformerException {
|
||||
Map<String, List<String>> spacePosMappings) throws AccessDeniedException, ProcessingErrorException,
|
||||
PluginException, ModelException, XPathExpressionException, TransformerException {
|
||||
ItemCollection workitem = new ItemCollection();
|
||||
workitem.model(source.getItemValueString(DocumentImportService.SOURCE_ITEM_MODELVERSION));
|
||||
workitem.task(source.getItemValueInteger(DocumentImportService.SOURCE_ITEM_TASK));
|
||||
|
|
@ -377,11 +372,11 @@ public class CargosoftXMLInvoiceImportService {
|
|||
// invoice.rate
|
||||
// invoice.base.amount
|
||||
|
||||
readXMLValue(doc, "/Invoices/Invoice/InvoiceHeader/Client/Codes/Code", workitem,
|
||||
"mandant.id", String.class);
|
||||
readXMLValue(doc, "/Invoices/Invoice/InvoiceHeader/Client/Codes/Code", workitem, "mandant.id",
|
||||
String.class);
|
||||
|
||||
readXMLValue(doc, "/Invoices/Invoice/InvoiceHeader/InvoiceNumber",
|
||||
workitem, "invoice.number", String.class);
|
||||
readXMLValue(doc, "/Invoices/Invoice/InvoiceHeader/InvoiceNumber", workitem, "invoice.number",
|
||||
String.class);
|
||||
|
||||
// verify if invoice is already imported.
|
||||
if (alreadyImported(workitem.getItemValueString("invoice.number"))) {
|
||||
|
|
@ -389,14 +384,14 @@ public class CargosoftXMLInvoiceImportService {
|
|||
return null;
|
||||
}
|
||||
|
||||
readXMLValue(doc, "/Invoices/Invoice/InvoiceHeader/InvoiceType/Codes/Code",
|
||||
workitem, "invoice.type", String.class);
|
||||
readXMLValue(doc, "/Invoices/Invoice/InvoiceHeader/InvoiceType/Description",
|
||||
workitem, "invoice.type.description", String.class);
|
||||
readXMLValue(doc, "/Invoices/Invoice/InvoiceHeader/InvoiceType/Codes/Code", workitem, "invoice.type",
|
||||
String.class);
|
||||
readXMLValue(doc, "/Invoices/Invoice/InvoiceHeader/InvoiceType/Description", workitem,
|
||||
"invoice.type.description", String.class);
|
||||
|
||||
// Rechnungssumme errechnen.....
|
||||
readXMLValue(doc, "/Invoices/Invoice/InvoiceHeader/InvoiceAmount/NetAmount/Amount/Value",
|
||||
workitem, "invoice.total.net", Double.class);
|
||||
readXMLValue(doc, "/Invoices/Invoice/InvoiceHeader/InvoiceAmount/NetAmount/Amount/Value", workitem,
|
||||
"invoice.total.net", Double.class);
|
||||
readXMLValue(doc, "/Invoices/Invoice/InvoiceHeader/InvoiceAmount/VATInformation/VATAmount/Amount/Value",
|
||||
workitem, "invoice.total.tax", Double.class);
|
||||
if (!workitem.hasItem("invoice.total.tax")) {
|
||||
|
|
@ -416,34 +411,33 @@ public class CargosoftXMLInvoiceImportService {
|
|||
}
|
||||
|
||||
// Steuer
|
||||
readXMLValue(doc, "/Invoices/Invoice/InvoiceHeader/InvoiceAmount/VATInformation/VAT/VATRate",
|
||||
workitem, "invoice.vatrate", Double.class);
|
||||
readXMLValue(doc, "/Invoices/Invoice/InvoiceHeader/InvoiceAmount/VATInformation/VAT/VATRate", workitem,
|
||||
"invoice.vatrate", Double.class);
|
||||
|
||||
// Booking Period
|
||||
readXMLValue(doc, "/Invoices/Invoice/InvoiceHeader/BookingPeriod",
|
||||
workitem, "invoice.bookingperiod", String.class);
|
||||
readXMLValue(doc, "/Invoices/Invoice/InvoiceHeader/BookingPeriod", workitem, "invoice.bookingperiod",
|
||||
String.class);
|
||||
|
||||
readXMLValue(doc, "/Invoices/Invoice/InvoiceHeader/InvoiceCurrency/Codes/Code",
|
||||
workitem, "invoice.currency", String.class);
|
||||
readXMLValue(doc, "/Invoices/Invoice/InvoiceHeader/InvoiceCurrency/Codes/Code", workitem,
|
||||
"invoice.currency", String.class);
|
||||
|
||||
readXMLValue(doc, "/Invoices/Invoice/InvoiceHeader/InvoiceDate",
|
||||
workitem, "invoice.date", Date.class);
|
||||
readXMLValue(doc, "/Invoices/Invoice/InvoiceHeader/InvoiceDate", workitem, "invoice.date", Date.class);
|
||||
|
||||
readXMLValue(doc,
|
||||
"/Invoices/Invoice/InvoiceHeader/PaymentConditions/PaymentCondition/Codes/Code[@Type='cs']",
|
||||
workitem, "payment.term", String.class);
|
||||
|
||||
// kostenstelle
|
||||
readXMLValue(doc, "/Invoices/Invoice/InvoiceHeader/CostUnit/Description",
|
||||
workitem, "invoice.CostUnit", String.class);
|
||||
readXMLValue(doc, "/Invoices/Invoice/InvoiceHeader/CostUnit/Description", workitem, "invoice.CostUnit",
|
||||
String.class);
|
||||
|
||||
readXMLValue(doc, "/Invoices/Invoice/InvoiceHeader/PaymentConditions/DueDate",
|
||||
workitem, "invoice.duedate", Date.class);
|
||||
readXMLValue(doc, "/Invoices/Invoice/InvoiceHeader/PaymentConditions/DueDate",
|
||||
workitem, "invoice.reminder", Date.class);
|
||||
readXMLValue(doc, "/Invoices/Invoice/InvoiceHeader/PaymentConditions/DueDate", workitem, "invoice.duedate",
|
||||
Date.class);
|
||||
readXMLValue(doc, "/Invoices/Invoice/InvoiceHeader/PaymentConditions/DueDate", workitem, "invoice.reminder",
|
||||
Date.class);
|
||||
|
||||
readXMLValue(doc, "/Invoices/Invoice/InvoiceHeader/InvoiceAddress/Codes/Code",
|
||||
workitem, "dbtr.number", String.class);
|
||||
readXMLValue(doc, "/Invoices/Invoice/InvoiceHeader/InvoiceAddress/Codes/Code", workitem, "dbtr.number",
|
||||
String.class);
|
||||
String dbtrNumber = workitem.getItemValueString("dbtr.number");
|
||||
if (dbtrNumber.startsWith("K") || dbtrNumber.startsWith("D")) {
|
||||
workitem.setItemValue("dbtr.number", dbtrNumber.substring(1));
|
||||
|
|
@ -487,8 +481,7 @@ public class CargosoftXMLInvoiceImportService {
|
|||
attacheFiles(doc, workitem);
|
||||
|
||||
} catch (ParserConfigurationException | SAXException | IOException e) {
|
||||
throw new PluginException(CargosoftXMLInvoiceImportService.class.getName(),
|
||||
"XML_ERROR", e.getMessage());
|
||||
throw new PluginException(CargosoftXMLInvoiceImportService.class.getName(), "XML_ERROR", e.getMessage());
|
||||
}
|
||||
return workitem;
|
||||
}
|
||||
|
|
@ -512,8 +505,7 @@ public class CargosoftXMLInvoiceImportService {
|
|||
*
|
||||
* /Invoices/Invoice/InvoiceHeader/Client/Code
|
||||
*
|
||||
* Beispiel Datum:
|
||||
* <InvoiceDate>2024-05-13T00:00:00+02:00</InvoiceDate>
|
||||
* Beispiel Datum: <InvoiceDate>2024-05-13T00:00:00+02:00</InvoiceDate>
|
||||
*
|
||||
* @param doc - xml doc
|
||||
* @param expression - xpath expression
|
||||
|
|
@ -566,11 +558,9 @@ public class CargosoftXMLInvoiceImportService {
|
|||
|
||||
/**
|
||||
* Hilfsmethode die die ATC Nummer sucht und in das workitem feld
|
||||
* invoice.atc.number einträgt.
|
||||
* Wir gehen davon aus, das wir über die ChildItems diese aus dem billingtexts
|
||||
* schon ermittel haben.
|
||||
* Es können mehrere ATC nummern existieren. Diese werden in einer Liste
|
||||
* gespeichert
|
||||
* invoice.atc.number einträgt. Wir gehen davon aus, das wir über die ChildItems
|
||||
* diese aus dem billingtexts schon ermittel haben. Es können mehrere ATC
|
||||
* nummern existieren. Diese werden in einer Liste gespeichert
|
||||
*
|
||||
* @param doc
|
||||
* @param workitem
|
||||
|
|
@ -595,15 +585,9 @@ public class CargosoftXMLInvoiceImportService {
|
|||
*
|
||||
* InvoiceRows/InvoiceRow
|
||||
*
|
||||
* Each row has the following items:
|
||||
* _childitems {
|
||||
* datev.shzeichen=[H],
|
||||
* datev.kurs=[0.0],
|
||||
* datev.basisumsatz=[0.0],
|
||||
* datev.text=[R LA-PAP-2405-051],
|
||||
* datev.konto=[3851],
|
||||
* datev.umsatz=[3307.81],
|
||||
* datev.wkz=[EUR]}}
|
||||
* Each row has the following items: _childitems { datev.shzeichen=[H],
|
||||
* datev.kurs=[0.0], datev.basisumsatz=[0.0], datev.text=[R LA-PAP-2405-051],
|
||||
* datev.konto=[3851], datev.umsatz=[3307.81], datev.wkz=[EUR]}}
|
||||
*
|
||||
* @param doc - xml doc
|
||||
* @param workitem
|
||||
|
|
@ -622,8 +606,7 @@ public class CargosoftXMLInvoiceImportService {
|
|||
XPathExpression netAmountExchangeRateExpr = xPath
|
||||
.compile("InvoiceAmount/NetAmount/Amount/ExchangeRate/text()");
|
||||
|
||||
XPathExpression netActivityTypeExpr = xPath
|
||||
.compile("ActivityType/Codes/Code[@Type='cs']/text()");
|
||||
XPathExpression netActivityTypeExpr = xPath.compile("ActivityType/Codes/Code[@Type='cs']/text()");
|
||||
|
||||
NodeList rowList = doc.getElementsByTagName("InvoiceRow");
|
||||
double _kurs = 0.0;
|
||||
|
|
@ -732,13 +715,10 @@ public class CargosoftXMLInvoiceImportService {
|
|||
}
|
||||
|
||||
/**
|
||||
* G = Gutschrift
|
||||
* SR = Stornorechnung
|
||||
* GK = Sammelgutschrift
|
||||
* SS = Sammelrechnung Storno
|
||||
* G = Gutschrift SR = Stornorechnung GK = Sammelgutschrift SS = Sammelrechnung
|
||||
* Storno
|
||||
*
|
||||
* müssen wir das vorzeichen ändern
|
||||
* dies wird über den Invoice.Type geprüft
|
||||
* müssen wir das vorzeichen ändern dies wird über den Invoice.Type geprüft
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
|
|
@ -748,9 +728,9 @@ public class CargosoftXMLInvoiceImportService {
|
|||
}
|
||||
|
||||
/**
|
||||
* This method attache the pdf file and the XML file to the workitem.
|
||||
* The method removes the file content first form the xml tree and attache the
|
||||
* XML without the pdf data.
|
||||
* This method attache the pdf file and the XML file to the workitem. The method
|
||||
* removes the file content first form the xml tree and attache the XML without
|
||||
* the pdf data.
|
||||
*
|
||||
* @throws XPathExpressionException
|
||||
* @throws TransformerException
|
||||
|
|
@ -761,16 +741,16 @@ public class CargosoftXMLInvoiceImportService {
|
|||
XPathFactory xpathFactory = XPathFactory.newInstance();
|
||||
XPath xpath = xpathFactory.newXPath();
|
||||
// read filename and content....
|
||||
readXMLValue(doc, "/Invoices/Invoice/InvoiceHeader/Attachments/Attachment/Filename",
|
||||
workitem, "import.filename", String.class);
|
||||
readXMLValue(doc, "/Invoices/Invoice/InvoiceHeader/Attachments/Attachment/Content",
|
||||
workitem, "import.filedata", String.class);
|
||||
readXMLValue(doc, "/Invoices/Invoice/InvoiceHeader/Attachments/Attachment/Filename", workitem,
|
||||
"import.filename", String.class);
|
||||
readXMLValue(doc, "/Invoices/Invoice/InvoiceHeader/Attachments/Attachment/Content", workitem, "import.filedata",
|
||||
String.class);
|
||||
|
||||
// attache the PDF file content
|
||||
String fileDataString = workitem.getItemValueString("import.filedata");
|
||||
byte[] decodedPDFData = java.util.Base64.getDecoder().decode(fileDataString);
|
||||
FileData fileData = new FileData(workitem.getItemValueString("import.filename"),
|
||||
decodedPDFData, "application/pdf", null);
|
||||
FileData fileData = new FileData(workitem.getItemValueString("import.filename"), decodedPDFData,
|
||||
"application/pdf", null);
|
||||
workitem.addFileData(fileData);
|
||||
// remove the temp items..
|
||||
workitem.removeItem("import.filename");
|
||||
|
|
|
|||
|
|
@ -42,336 +42,306 @@ import jakarta.json.bind.JsonbConfig;
|
|||
* Der ZohoAPIService stellt methoden für den Zugriff auf die Zoho API bereit.
|
||||
*/
|
||||
@DeclareRoles({ "org.imixs.ACCESSLEVEL.NOACCESS", "org.imixs.ACCESSLEVEL.READERACCESS",
|
||||
"org.imixs.ACCESSLEVEL.AUTHORACCESS", "org.imixs.ACCESSLEVEL.EDITORACCESS",
|
||||
"org.imixs.ACCESSLEVEL.MANAGERACCESS" })
|
||||
"org.imixs.ACCESSLEVEL.AUTHORACCESS", "org.imixs.ACCESSLEVEL.EDITORACCESS",
|
||||
"org.imixs.ACCESSLEVEL.MANAGERACCESS" })
|
||||
@RolesAllowed({ "org.imixs.ACCESSLEVEL.NOACCESS", "org.imixs.ACCESSLEVEL.READERACCESS",
|
||||
"org.imixs.ACCESSLEVEL.AUTHORACCESS", "org.imixs.ACCESSLEVEL.EDITORACCESS",
|
||||
"org.imixs.ACCESSLEVEL.MANAGERACCESS" })
|
||||
"org.imixs.ACCESSLEVEL.AUTHORACCESS", "org.imixs.ACCESSLEVEL.EDITORACCESS",
|
||||
"org.imixs.ACCESSLEVEL.MANAGERACCESS" })
|
||||
@Singleton
|
||||
@RunAs("org.imixs.ACCESSLEVEL.MANAGERACCESS")
|
||||
public class ZohoAPIService {
|
||||
|
||||
private static Logger logger = Logger.getLogger(ZohoAPIService.class.getName());
|
||||
private static final String ZOHO_API_BASE_URL = "https://www.zohoapis.eu/books/v3/";
|
||||
private static Logger logger = Logger.getLogger(ZohoAPIService.class.getName());
|
||||
|
||||
@Inject
|
||||
ZohoOAuthManager zohoOAuthManager;
|
||||
@Inject
|
||||
ZohoOAuthManager zohoOAuthManager;
|
||||
|
||||
private HttpClient httpClient;
|
||||
private Jsonb jsonb;
|
||||
private HttpClient httpClient;
|
||||
private Jsonb jsonb;
|
||||
|
||||
@PostConstruct
|
||||
void init() {
|
||||
this.httpClient = HttpClient.newBuilder()
|
||||
.connectTimeout(Duration.ofSeconds(10))
|
||||
.build();
|
||||
@PostConstruct
|
||||
void init() {
|
||||
this.httpClient = HttpClient.newBuilder().connectTimeout(Duration.ofSeconds(10)).build();
|
||||
|
||||
JsonbConfig config = new JsonbConfig()
|
||||
.withDateFormat("yyyy-MM-dd", Locale.getDefault())
|
||||
.setProperty("jsonb.fail-on-unknown-properties", false); // Ignoriert unbekannte Felder
|
||||
this.jsonb = JsonbBuilder.create(config);
|
||||
JsonbConfig config = new JsonbConfig().withDateFormat("yyyy-MM-dd", Locale.getDefault())
|
||||
.setProperty("jsonb.fail-on-unknown-properties", false); // Ignoriert unbekannte Felder
|
||||
this.jsonb = JsonbBuilder.create(config);
|
||||
}
|
||||
|
||||
public String findContactIDByCompanyName(String companyName, String accessToken) throws PluginException {
|
||||
|
||||
// Print JSON to console for verification
|
||||
logger.info("├── Zoho lookup contact '" + companyName + "'...");
|
||||
try {
|
||||
// https://www.zohoapis.com/books/v3/contacts?organization_id=10234695&company_name=xxx'
|
||||
String uri = zohoOAuthManager.getBaseURI() + "contacts?organization_id="
|
||||
+ zohoOAuthManager.getOrganization() + "&company_name="
|
||||
+ URLEncoder.encode(companyName, StandardCharsets.UTF_8);
|
||||
logger.fine("│ ├── uri= " + uri);
|
||||
logger.fine("│ ├── accessToken=" + accessToken);
|
||||
HttpRequest request = HttpRequest.newBuilder().uri(URI.create(uri))
|
||||
.header("Authorization", "Zoho-oauthtoken " + accessToken)
|
||||
.header("Content-Type", "application/json").GET().build();
|
||||
|
||||
HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
|
||||
|
||||
// Print response details to console
|
||||
logger.fine("├── Zoho Response:");
|
||||
logger.fine("│ ├── Status Code: " + response.statusCode());
|
||||
logger.fine("│ ├── Response Body: " + response.body());
|
||||
if (response.statusCode() >= 300) {
|
||||
throw new PluginException(this.getClass().getName(), "Zoho API error",
|
||||
"Failed to find Contacts - Status code: " + response.statusCode() + ", Response: "
|
||||
+ response.body());
|
||||
}
|
||||
|
||||
ZohoContactFindResponse contactsResponse = jsonb.fromJson(response.body(), ZohoContactFindResponse.class);
|
||||
|
||||
if (contactsResponse != null && contactsResponse.getContacts() != null) {
|
||||
// Durchsuche die Ergebnisse nach exakter Übereinstimmung
|
||||
for (ZohoContact contact : contactsResponse.getContacts()) {
|
||||
if (companyName.equalsIgnoreCase(contact.getCompanyName())) {
|
||||
logger.info("│ ├── contactID= " + contact.getContactId());
|
||||
return contact.getContactId();
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
} catch (Exception e) {
|
||||
throw new PluginException(this.getClass().getName(), "Zoho API error", "Failed to find contacts", e);
|
||||
}
|
||||
|
||||
public String findContactIDByCompanyName(String companyName, String accessToken) throws PluginException {
|
||||
}
|
||||
|
||||
// Print JSON to console for verification
|
||||
logger.info("├── Zoho lookup contact '" + companyName + "'...");
|
||||
try {
|
||||
// https://www.zohoapis.com/books/v3/contacts?organization_id=10234695&company_name=xxx'
|
||||
String uri = ZOHO_API_BASE_URL + "contacts?organization_id="
|
||||
+ zohoOAuthManager.getOrganization() + "&company_name="
|
||||
+ URLEncoder.encode(companyName, StandardCharsets.UTF_8);
|
||||
logger.fine("│ ├── uri= " + uri);
|
||||
logger.fine("│ ├── accessToken=" + accessToken);
|
||||
HttpRequest request = HttpRequest.newBuilder()
|
||||
.uri(URI.create(uri))
|
||||
.header("Authorization", "Zoho-oauthtoken " + accessToken)
|
||||
.header("Content-Type", "application/json")
|
||||
.GET()
|
||||
.build();
|
||||
|
||||
HttpResponse<String> response = httpClient.send(
|
||||
request, HttpResponse.BodyHandlers.ofString());
|
||||
|
||||
// Print response details to console
|
||||
logger.fine("├── Zoho Response:");
|
||||
logger.fine("│ ├── Status Code: " + response.statusCode());
|
||||
logger.fine("│ ├── Response Body: " + response.body());
|
||||
if (response.statusCode() >= 300) {
|
||||
throw new PluginException(this.getClass().getName(), "Zoho API error",
|
||||
"Failed to find Contacts - Status code: " + response.statusCode() +
|
||||
", Response: " + response.body());
|
||||
}
|
||||
|
||||
ZohoContactFindResponse contactsResponse = jsonb.fromJson(response.body(),
|
||||
ZohoContactFindResponse.class);
|
||||
|
||||
if (contactsResponse != null && contactsResponse.getContacts() != null) {
|
||||
// Durchsuche die Ergebnisse nach exakter Übereinstimmung
|
||||
for (ZohoContact contact : contactsResponse.getContacts()) {
|
||||
if (companyName.equalsIgnoreCase(contact.getCompanyName())) {
|
||||
logger.info("│ ├── contactID= " + contact.getContactId());
|
||||
return contact.getContactId();
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
} catch (Exception e) {
|
||||
throw new PluginException(this.getClass().getName(), "Zoho API error",
|
||||
"Failed to find contacts", e);
|
||||
}
|
||||
/**
|
||||
* Exports an invocie document
|
||||
*
|
||||
* @see https://www.zoho.com/books/api/v3/invoices/#create-an-invoice
|
||||
*
|
||||
* @param invoice
|
||||
* @throws PluginException
|
||||
*/
|
||||
public ZohoInvoice exportInvoice(ItemCollection invoice, List<FileData> files) throws PluginException {
|
||||
String accessToken = zohoOAuthManager.getValidAccessToken();
|
||||
logger.info("├── Zoho Export Invoice " + invoice.getItemValueString("invoice.number") + "...");
|
||||
|
||||
// first lookup contact!
|
||||
String contactID = "";
|
||||
contactID = findContactIDByCompanyName(invoice.getItemValueString("dbtr.name"), accessToken);
|
||||
if (contactID == null) {
|
||||
logger.info("│ ├── contact not found");
|
||||
ZohoContact contact = createContact(invoice.getItemValueString("dbtr.name"), accessToken);
|
||||
contactID = contact.getContactId();
|
||||
}
|
||||
|
||||
/**
|
||||
* Exports an invocie document
|
||||
*
|
||||
* @see https://www.zoho.com/books/api/v3/invoices/#create-an-invoice
|
||||
*
|
||||
* @param invoice
|
||||
* @throws PluginException
|
||||
*/
|
||||
public ZohoInvoice exportInvoice(ItemCollection invoice, List<FileData> files) throws PluginException {
|
||||
String accessToken = zohoOAuthManager.getValidAccessToken();
|
||||
logger.info("├── Zoho Export Invoice " + invoice.getItemValueString("invoice.number") + "...");
|
||||
// Konvertiere ItemCollection zu ZohoInvoiceDTO
|
||||
ZohoInvoice zohoInvoice = convertToZohoInvoice(invoice, contactID, accessToken);
|
||||
|
||||
// first lookup contact!
|
||||
String contactID = "";
|
||||
contactID = findContactIDByCompanyName(invoice.getItemValueString("dbtr.name"), accessToken);
|
||||
if (contactID == null) {
|
||||
logger.info("│ ├── contact not found");
|
||||
ZohoContact contact = createContact(invoice.getItemValueString("dbtr.name"), accessToken);
|
||||
contactID = contact.getContactId();
|
||||
try {
|
||||
String requestBody = jsonb.toJson(zohoInvoice);
|
||||
|
||||
// Print JSON to console for verification
|
||||
logger.fine("├── Zoho Invoice JSON Request...");
|
||||
logger.fine("│ ├── " + requestBody);
|
||||
|
||||
// https://www.zohoapis.com/books/v3/invoices?organization_id=10234695'
|
||||
String uri = zohoOAuthManager.getBaseURI() + "invoices?organization_id="
|
||||
+ zohoOAuthManager.getOrganization();
|
||||
logger.fine("│ ├── uri= " + uri);
|
||||
logger.fine("│ ├── accessToken=" + accessToken);
|
||||
HttpRequest request = HttpRequest.newBuilder().uri(URI.create(uri))
|
||||
.header("Authorization", "Zoho-oauthtoken " + accessToken)
|
||||
.header("Content-Type", "application/json").POST(HttpRequest.BodyPublishers.ofString(requestBody))
|
||||
.build();
|
||||
|
||||
HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
|
||||
|
||||
// Print response details to console
|
||||
logger.fine("├── Zoho Response:");
|
||||
logger.fine("│ ├── Status Code: " + response.statusCode());
|
||||
|
||||
if (response.statusCode() >= 300) {
|
||||
throw new PluginException(this.getClass().getName(), "Zoho API error",
|
||||
"Failed to create invoice. Status code: " + response.statusCode() + ", Response: "
|
||||
+ response.body());
|
||||
}
|
||||
|
||||
// Erfolgreiche Erstellung
|
||||
String bodyContent = response.body();
|
||||
logger.fine("│ ├── Response Body: " + bodyContent);
|
||||
|
||||
System.out.print(bodyContent);
|
||||
ZohoInvoiceCreateResponse createResponse = jsonb.fromJson(bodyContent, ZohoInvoiceCreateResponse.class);
|
||||
|
||||
logger.fine("│ ├── OK - customerID=" + createResponse.getInvoice().getCustomerId());
|
||||
logger.info("│ ├── OK - invoiceID=" + createResponse.getInvoice().getInvoiceId());
|
||||
|
||||
if (createResponse != null) {
|
||||
zohoInvoice = createResponse.getInvoice();
|
||||
|
||||
// now add attachments (optional)
|
||||
if (files != null) {
|
||||
for (FileData file : files) {
|
||||
attacheFileData(zohoInvoice.getInvoiceId(), file, "invoices", accessToken);
|
||||
}
|
||||
}
|
||||
|
||||
// Konvertiere ItemCollection zu ZohoInvoiceDTO
|
||||
ZohoInvoice zohoInvoice = convertToZohoInvoice(invoice, contactID, accessToken);
|
||||
|
||||
try {
|
||||
String requestBody = jsonb.toJson(zohoInvoice);
|
||||
|
||||
// Print JSON to console for verification
|
||||
logger.fine("├── Zoho Invoice JSON Request...");
|
||||
logger.fine("│ ├── " + requestBody);
|
||||
|
||||
// https://www.zohoapis.com/books/v3/invoices?organization_id=10234695'
|
||||
String uri = ZOHO_API_BASE_URL + "invoices?organization_id="
|
||||
+ zohoOAuthManager.getOrganization();
|
||||
logger.fine("│ ├── uri= " + uri);
|
||||
logger.fine("│ ├── accessToken=" + accessToken);
|
||||
HttpRequest request = HttpRequest.newBuilder()
|
||||
.uri(URI.create(uri))
|
||||
.header("Authorization", "Zoho-oauthtoken " + accessToken)
|
||||
.header("Content-Type", "application/json")
|
||||
.POST(HttpRequest.BodyPublishers.ofString(requestBody))
|
||||
.build();
|
||||
|
||||
HttpResponse<String> response = httpClient.send(
|
||||
request, HttpResponse.BodyHandlers.ofString());
|
||||
|
||||
// Print response details to console
|
||||
logger.fine("├── Zoho Response:");
|
||||
logger.fine("│ ├── Status Code: " + response.statusCode());
|
||||
|
||||
if (response.statusCode() >= 300) {
|
||||
throw new PluginException(this.getClass().getName(), "Zoho API error",
|
||||
"Failed to create invoice. Status code: " + response.statusCode() +
|
||||
", Response: " + response.body());
|
||||
}
|
||||
|
||||
// Erfolgreiche Erstellung
|
||||
String bodyContent = response.body();
|
||||
logger.fine("│ ├── Response Body: " + bodyContent);
|
||||
|
||||
System.out.print(bodyContent);
|
||||
ZohoInvoiceCreateResponse createResponse = jsonb.fromJson(bodyContent,
|
||||
ZohoInvoiceCreateResponse.class);
|
||||
|
||||
logger.fine("│ ├── OK - customerID=" + createResponse.getInvoice().getCustomerId());
|
||||
logger.info("│ ├── OK - invoiceID=" + createResponse.getInvoice().getInvoiceId());
|
||||
|
||||
if (createResponse != null) {
|
||||
zohoInvoice = createResponse.getInvoice();
|
||||
|
||||
// now add attachments (optional)
|
||||
if (files != null) {
|
||||
for (FileData file : files) {
|
||||
attacheFileData(zohoInvoice.getInvoiceId(), file, "invoices",
|
||||
accessToken);
|
||||
}
|
||||
}
|
||||
|
||||
logger.info("│ ├── Invoice Export successful.");
|
||||
return zohoInvoice;
|
||||
} else {
|
||||
throw new PluginException(this.getClass().getName(), "Zoho API error",
|
||||
"Failed to export invoice to Zoho: unable to resolve response");
|
||||
}
|
||||
|
||||
} catch (IOException | InterruptedException e) {
|
||||
throw new PluginException(this.getClass().getName(), "Zoho API error",
|
||||
"Failed to export invoice to Zoho: " + e.getMessage(), e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Erstellt einen neuen Contact in Zoho Books
|
||||
*
|
||||
* @param companyName Der Firmenname für den neuen Contact
|
||||
* @return Der erstellte ZohoContact mit contact_id
|
||||
* @throws PluginException Wenn der API-Aufruf fehlschlägt
|
||||
*/
|
||||
public ZohoContact createContact(String companyName, String accessToken) throws PluginException {
|
||||
logger.info("├── Zoho create contact '" + companyName + "'...");
|
||||
try {
|
||||
// Contact-DTO vorbereiten
|
||||
ZohoContact newContact = new ZohoContact();
|
||||
newContact.setContactName(companyName); // Wir verwenden den Firmennamen auch als Contact Name
|
||||
newContact.setCompanyName(companyName);
|
||||
|
||||
// JSON serialisieren
|
||||
String requestBody = jsonb.toJson(newContact);
|
||||
logger.fine("│ ├── " + requestBody);
|
||||
String uri = ZOHO_API_BASE_URL + "contacts?organization_id="
|
||||
+ zohoOAuthManager.getOrganization();
|
||||
|
||||
HttpRequest request = HttpRequest.newBuilder()
|
||||
.uri(URI.create(uri))
|
||||
.header("Authorization", "Zoho-oauthtoken " + accessToken)
|
||||
.header("Content-Type", "application/json")
|
||||
.POST(HttpRequest.BodyPublishers.ofString(requestBody))
|
||||
.build();
|
||||
|
||||
HttpResponse<String> response = httpClient.send(
|
||||
request, HttpResponse.BodyHandlers.ofString());
|
||||
logger.fine("├── Zoho Response:");
|
||||
logger.fine("│ ├── Status Code: " + response.statusCode());
|
||||
logger.fine("│ ├── Response Body: " + response.body());
|
||||
if (response.statusCode() >= 300) {
|
||||
throw new PluginException(this.getClass().getName(), "Zoho API error",
|
||||
"Failed to create invoice. Status code: " + response.statusCode() +
|
||||
", Response: " + response.body());
|
||||
}
|
||||
|
||||
// Erfolgreiche Erstellung
|
||||
ZohoContactCreateResponse createResponse = jsonb.fromJson(response.body(),
|
||||
ZohoContactCreateResponse.class);
|
||||
if (createResponse != null) {
|
||||
logger.info("│ ├── OK - contactID=" + createResponse.getContact().getContactId());
|
||||
return createResponse.getContact();
|
||||
} else {
|
||||
throw new PluginException(this.getClass().getName(), "Zoho API error",
|
||||
"Response could not be resolved!");
|
||||
}
|
||||
|
||||
} catch (IOException | InterruptedException e) {
|
||||
throw new PluginException(this.getClass().getName(), "Zoho API error",
|
||||
"Failed to create contact: " + e.getMessage(), e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private ZohoInvoice convertToZohoInvoice(ItemCollection invoice, String contactID, String accessToken)
|
||||
throws PluginException {
|
||||
|
||||
ZohoInvoice zohoInvoice = new ZohoInvoice();
|
||||
// Basisinformationen
|
||||
logger.fine("invoice.date=" + invoice.getItemValueDate("invoice.date"));
|
||||
logger.fine("invoice.duedate=" + invoice.getItemValueDate("invoice.duedate"));
|
||||
|
||||
// LocalDate.ofInstant(date.toInstant(), ZoneId.systemDefault())
|
||||
zohoInvoice.setDate(
|
||||
LocalDate.ofInstant(invoice.getItemValueDate("invoice.date").toInstant(),
|
||||
ZoneId.systemDefault()));
|
||||
|
||||
zohoInvoice.setDueDate(
|
||||
LocalDate.ofInstant(invoice.getItemValueDate("invoice.duedate").toInstant(),
|
||||
ZoneId.systemDefault()));
|
||||
|
||||
zohoInvoice.setTotal(invoice.getItemValueDouble("invoice.total"));
|
||||
// Kunden-ID (muss angepasst werden je nachdem wie du sie speicherst)
|
||||
zohoInvoice.setCustomerId(contactID);
|
||||
List<ItemCollection> positionen = InvoiceUtil.explodeChildList(invoice);
|
||||
|
||||
List<ZohoInvoiceItem> lineItems = positionen.stream()
|
||||
.map(item -> {
|
||||
ItemCollection itemCol = (ItemCollection) item;
|
||||
ZohoInvoiceItem lineItem = new ZohoInvoiceItem();
|
||||
lineItem.setName(itemCol.getItemValueString("datev.text"));
|
||||
lineItem.setDescription(itemCol.getItemValueString("billingtext"));
|
||||
lineItem.setRate(itemCol.getItemValueDouble("datev.umsatz"));
|
||||
lineItem.setQuantity(1);
|
||||
return lineItem;
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
|
||||
zohoInvoice.setLineItems(lineItems);
|
||||
logger.info("│ ├── Invoice Export successful.");
|
||||
return zohoInvoice;
|
||||
} else {
|
||||
throw new PluginException(this.getClass().getName(), "Zoho API error",
|
||||
"Failed to export invoice to Zoho: unable to resolve response");
|
||||
}
|
||||
|
||||
} catch (IOException | InterruptedException e) {
|
||||
throw new PluginException(this.getClass().getName(), "Zoho API error",
|
||||
"Failed to export invoice to Zoho: " + e.getMessage(), e);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method adds an attachment to an invoice
|
||||
*
|
||||
* @param invoiceId The Zoho invoice ID
|
||||
* @param file The FileData object containing the attachment
|
||||
* @param uriPattern The API endpoint pattern (e.g., "invoices")
|
||||
* @param accessToken The OAuth access token
|
||||
* @throws PluginException If the API call fails
|
||||
*/
|
||||
public void attacheFileData(String invoiceId, FileData file, String uriPattern, String accessToken)
|
||||
throws PluginException {
|
||||
String uri = ZOHO_API_BASE_URL + uriPattern + "/" + invoiceId + "/attachment" +
|
||||
"?organization_id=" + zohoOAuthManager.getOrganization();
|
||||
}
|
||||
|
||||
logger.info("│ ├── add attachment '" + file.getName() + "'...");
|
||||
logger.fine("│ ├── ...uri: " + uri + "...");
|
||||
/**
|
||||
* Erstellt einen neuen Contact in Zoho Books
|
||||
*
|
||||
* @param companyName Der Firmenname für den neuen Contact
|
||||
* @return Der erstellte ZohoContact mit contact_id
|
||||
* @throws PluginException Wenn der API-Aufruf fehlschlägt
|
||||
*/
|
||||
public ZohoContact createContact(String companyName, String accessToken) throws PluginException {
|
||||
logger.info("├── Zoho create contact '" + companyName + "'...");
|
||||
try {
|
||||
// Contact-DTO vorbereiten
|
||||
ZohoContact newContact = new ZohoContact();
|
||||
newContact.setContactName(companyName); // Wir verwenden den Firmennamen auch als Contact Name
|
||||
newContact.setCompanyName(companyName);
|
||||
|
||||
try {
|
||||
// Generate a unique boundary
|
||||
String boundary = "----WebKitFormBoundary" + System.currentTimeMillis();
|
||||
// JSON serialisieren
|
||||
String requestBody = jsonb.toJson(newContact);
|
||||
logger.fine("│ ├── " + requestBody);
|
||||
String uri = zohoOAuthManager.getBaseURI() + "contacts?organization_id="
|
||||
+ zohoOAuthManager.getOrganization();
|
||||
|
||||
// Build multipart request body
|
||||
byte[] header = ("--" + boundary + "\r\n" +
|
||||
"Content-Disposition: form-data; name=\"attachment\"; filename=\""
|
||||
+ file.getName() + "\"\r\n" +
|
||||
"Content-Type: " + file.getContentType() + "\r\n\r\n")
|
||||
.getBytes(StandardCharsets.UTF_8);
|
||||
HttpRequest request = HttpRequest.newBuilder().uri(URI.create(uri))
|
||||
.header("Authorization", "Zoho-oauthtoken " + accessToken)
|
||||
.header("Content-Type", "application/json").POST(HttpRequest.BodyPublishers.ofString(requestBody))
|
||||
.build();
|
||||
|
||||
byte[] footer = ("\r\n--" + boundary + "--\r\n").getBytes(StandardCharsets.UTF_8);
|
||||
HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
|
||||
logger.fine("├── Zoho Response:");
|
||||
logger.fine("│ ├── Status Code: " + response.statusCode());
|
||||
logger.fine("│ ├── Response Body: " + response.body());
|
||||
if (response.statusCode() >= 300) {
|
||||
throw new PluginException(this.getClass().getName(), "Zoho API error",
|
||||
"Failed to create invoice. Status code: " + response.statusCode() + ", Response: "
|
||||
+ response.body());
|
||||
}
|
||||
|
||||
logger.fine("│ ├── content size=" + file.getContent().length);
|
||||
HttpRequest.BodyPublisher bodyPublisher = HttpRequest.BodyPublishers.ofByteArrays(
|
||||
Arrays.asList(header, file.getContent(), footer));
|
||||
// Erfolgreiche Erstellung
|
||||
ZohoContactCreateResponse createResponse = jsonb.fromJson(response.body(), ZohoContactCreateResponse.class);
|
||||
if (createResponse != null) {
|
||||
logger.info("│ ├── OK - contactID=" + createResponse.getContact().getContactId());
|
||||
return createResponse.getContact();
|
||||
} else {
|
||||
throw new PluginException(this.getClass().getName(), "Zoho API error",
|
||||
"Response could not be resolved!");
|
||||
}
|
||||
|
||||
// Create and send the request
|
||||
HttpRequest request = HttpRequest.newBuilder()
|
||||
.uri(URI.create(uri))
|
||||
.header("Authorization", "Zoho-oauthtoken " + accessToken)
|
||||
.header("Content-Type", "multipart/form-data; boundary=" + boundary)
|
||||
.POST(bodyPublisher)
|
||||
.build();
|
||||
|
||||
HttpResponse<String> response = httpClient.send(
|
||||
request,
|
||||
HttpResponse.BodyHandlers.ofString());
|
||||
|
||||
logger.fine("├── Zoho Response:");
|
||||
logger.fine("│ ├── Status Code: " + response.statusCode());
|
||||
logger.fine("│ ├── Response Body: " + response.body());
|
||||
|
||||
if (response.statusCode() >= 300) {
|
||||
throw new PluginException(this.getClass().getName(), "Zoho API error",
|
||||
"Failed to add attachment. Status code: " + response.statusCode() +
|
||||
", Response: " + response.body());
|
||||
}
|
||||
|
||||
logger.info("│ ├── OK - Attachment added successfully");
|
||||
|
||||
} catch (IOException | InterruptedException e) {
|
||||
throw new PluginException(this.getClass().getName(), "Zoho API error",
|
||||
"Failed to add attachment: " + e.getMessage(), e);
|
||||
}
|
||||
} catch (IOException | InterruptedException e) {
|
||||
throw new PluginException(this.getClass().getName(), "Zoho API error",
|
||||
"Failed to create contact: " + e.getMessage(), e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private ZohoInvoice convertToZohoInvoice(ItemCollection invoice, String contactID, String accessToken)
|
||||
throws PluginException {
|
||||
|
||||
ZohoInvoice zohoInvoice = new ZohoInvoice();
|
||||
// Basisinformationen
|
||||
|
||||
zohoInvoice.setInvoiceNumber(invoice.getItemValueString("invoice.number"));
|
||||
zohoInvoice.setDate(
|
||||
LocalDate.ofInstant(invoice.getItemValueDate("invoice.date").toInstant(), ZoneId.systemDefault()));
|
||||
|
||||
zohoInvoice.setDueDate(
|
||||
LocalDate.ofInstant(invoice.getItemValueDate("invoice.duedate").toInstant(), ZoneId.systemDefault()));
|
||||
|
||||
zohoInvoice.setTotal(invoice.getItemValueDouble("invoice.total"));
|
||||
// Kunden-ID (muss angepasst werden je nachdem wie du sie speicherst)
|
||||
zohoInvoice.setCustomerId(contactID);
|
||||
List<ItemCollection> positionen = InvoiceUtil.explodeChildList(invoice);
|
||||
|
||||
List<ZohoInvoiceItem> lineItems = positionen.stream().map(item -> {
|
||||
ItemCollection itemCol = (ItemCollection) item;
|
||||
ZohoInvoiceItem lineItem = new ZohoInvoiceItem();
|
||||
lineItem.setName(itemCol.getItemValueString("datev.text"));
|
||||
lineItem.setDescription(itemCol.getItemValueString("billingtext"));
|
||||
lineItem.setRate(itemCol.getItemValueDouble("datev.umsatz"));
|
||||
lineItem.setQuantity(1);
|
||||
return lineItem;
|
||||
}).collect(Collectors.toList());
|
||||
|
||||
zohoInvoice.setLineItems(lineItems);
|
||||
return zohoInvoice;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method adds an attachment to an invoice
|
||||
*
|
||||
* @param invoiceId The Zoho invoice ID
|
||||
* @param file The FileData object containing the attachment
|
||||
* @param uriPattern The API endpoint pattern (e.g., "invoices")
|
||||
* @param accessToken The OAuth access token
|
||||
* @throws PluginException If the API call fails
|
||||
*/
|
||||
public void attacheFileData(String invoiceId, FileData file, String uriPattern, String accessToken)
|
||||
throws PluginException {
|
||||
String uri = zohoOAuthManager.getBaseURI() + uriPattern + "/" + //
|
||||
invoiceId + //
|
||||
"/attachment" + //
|
||||
"?organization_id=" + zohoOAuthManager.getOrganization();
|
||||
|
||||
logger.info("│ ├── add attachment '" + file.getName() + "'...");
|
||||
logger.fine("│ ├── ...uri: " + uri + "...");
|
||||
|
||||
try {
|
||||
// Generate a unique boundary
|
||||
String boundary = "----WebKitFormBoundary" + System.currentTimeMillis();
|
||||
|
||||
// Build multipart request body
|
||||
byte[] header = ("--" + boundary + "\r\n"
|
||||
+ "Content-Disposition: form-data; name=\"attachment\"; filename=\"" + file.getName() + "\"\r\n"
|
||||
+ "Content-Type: " + file.getContentType() + "\r\n\r\n").getBytes(StandardCharsets.UTF_8);
|
||||
|
||||
byte[] footer = ("\r\n--" + boundary + "--\r\n").getBytes(StandardCharsets.UTF_8);
|
||||
|
||||
logger.fine("│ ├── content size=" + file.getContent().length);
|
||||
HttpRequest.BodyPublisher bodyPublisher = HttpRequest.BodyPublishers
|
||||
.ofByteArrays(Arrays.asList(header, file.getContent(), footer));
|
||||
|
||||
// Create and send the request
|
||||
HttpRequest request = HttpRequest.newBuilder().uri(URI.create(uri))
|
||||
.header("Authorization", "Zoho-oauthtoken " + accessToken)
|
||||
.header("Content-Type", "multipart/form-data; boundary=" + boundary).POST(bodyPublisher).build();
|
||||
|
||||
HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
|
||||
|
||||
logger.fine("├── Zoho Response:");
|
||||
logger.fine("│ ├── Status Code: " + response.statusCode());
|
||||
logger.fine("│ ├── Response Body: " + response.body());
|
||||
|
||||
if (response.statusCode() >= 300) {
|
||||
throw new PluginException(this.getClass().getName(), "Zoho API error",
|
||||
"Failed to add attachment. Status code: " + response.statusCode() + ", Response: "
|
||||
+ response.body());
|
||||
}
|
||||
|
||||
logger.info("│ ├── OK - Attachment added successfully");
|
||||
|
||||
} catch (IOException | InterruptedException e) {
|
||||
throw new PluginException(this.getClass().getName(), "Zoho API error",
|
||||
"Failed to add attachment: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -45,44 +45,44 @@ import jakarta.inject.Named;
|
|||
@ApplicationScoped
|
||||
public class ZohoController extends ConfigController {
|
||||
|
||||
public static final String ZOHO_CONFIGURATION = "ZOHO_CONFIGURATION";
|
||||
public static final String ZOHO_CONFIGURATION = "ZOHO_CONFIGURATION";
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static Logger logger = Logger.getLogger(ZohoController.class.getName());
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static Logger logger = Logger.getLogger(ZohoController.class.getName());
|
||||
|
||||
@Inject
|
||||
ZohoOAuthManager zohoOAuthManager;
|
||||
@Inject
|
||||
ZohoOAuthManager zohoOAuthManager;
|
||||
|
||||
public ZohoController() {
|
||||
super();
|
||||
setName(ZOHO_CONFIGURATION);
|
||||
}
|
||||
public ZohoController() {
|
||||
super();
|
||||
setName(ZOHO_CONFIGURATION);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ruft zohoOAuhtManager.updateToken auf
|
||||
*/
|
||||
public void updateAccessToken() {
|
||||
//
|
||||
try {
|
||||
zohoOAuthManager.updateTokens(this.getWorkitem().getItemValueString("zoho.code"));
|
||||
} catch (PluginException e) {
|
||||
String message = "Failed to generate token: " + e.getMessage();
|
||||
logger.warning(message);
|
||||
this.getWorkitem().setItemValue("message", message);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Ruft zohoOAuhtManager.updateToken auf
|
||||
*/
|
||||
public void updateAccessToken() {
|
||||
//
|
||||
try {
|
||||
zohoOAuthManager.updateTokens(this.getWorkitem().getItemValueString("zoho.code"));
|
||||
} catch (PluginException e) {
|
||||
String message = "Failed to generate token: " + e.getMessage();
|
||||
logger.warning(message);
|
||||
this.getWorkitem().setItemValue("message", message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ruft zohoOAuhtManager.refreshToken auf
|
||||
*/
|
||||
public void refreshAccessToken() {
|
||||
//
|
||||
try {
|
||||
zohoOAuthManager.refreshAccessToken();
|
||||
} catch (PluginException e) {
|
||||
String message = "Failed to refresh token: " + e.getMessage();
|
||||
logger.warning(message);
|
||||
this.getWorkitem().setItemValue("message", message);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Ruft zohoOAuhtManager.refreshToken auf
|
||||
*/
|
||||
public void refreshAccessToken() {
|
||||
//
|
||||
try {
|
||||
zohoOAuthManager.refreshAccessToken();
|
||||
} catch (PluginException e) {
|
||||
String message = "Failed to refresh token: " + e.getMessage();
|
||||
logger.warning(message);
|
||||
this.getWorkitem().setItemValue("message", message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -52,8 +52,8 @@ import jakarta.ws.rs.core.MediaType;
|
|||
* verwenden!
|
||||
*
|
||||
* Der Service stellt im Grunde nur eine Callback URL für einen normalen Zoho
|
||||
* Client ein. Also wenn jemand einen solchen Token über den Browser
|
||||
* anfordert. Der URL muss dann odrt als CallBack URL angegeben sein!
|
||||
* Client ein. Also wenn jemand einen solchen Token über den Browser anfordert.
|
||||
* Der URL muss dann odrt als CallBack URL angegeben sein!
|
||||
*
|
||||
* Beispiel:
|
||||
*
|
||||
|
|
@ -90,8 +90,7 @@ public class ZohoOAuthCallbackService {
|
|||
*
|
||||
* state=testing
|
||||
* code=1000.c27802b99c007ad8db93a5a7291cb15a.8cb60b6a51df13ea627ef3ac7c2e4791
|
||||
* location=eu
|
||||
* accounts-server=https%3A%2F%2Faccounts.zoho.eu
|
||||
* location=eu accounts-server=https%3A%2F%2Faccounts.zoho.eu
|
||||
*
|
||||
*
|
||||
* @param workflowgroup
|
||||
|
|
@ -102,11 +101,8 @@ public class ZohoOAuthCallbackService {
|
|||
@GET
|
||||
@Path("/grant")
|
||||
@Produces({ MediaType.TEXT_HTML })
|
||||
public String getGrantToken(
|
||||
@QueryParam("state") String state,
|
||||
@QueryParam("code") String code,
|
||||
@QueryParam("location") String location,
|
||||
@QueryParam("accounts-server") String accountsServer)
|
||||
public String getGrantToken(@QueryParam("state") String state, @QueryParam("code") String code,
|
||||
@QueryParam("location") String location, @QueryParam("accounts-server") String accountsServer)
|
||||
throws QueryException {
|
||||
|
||||
logger.info("├── Receive Grant Token from Zoho");
|
||||
|
|
|
|||
|
|
@ -47,9 +47,7 @@ public class ZohoOAuthManager {
|
|||
|
||||
@PostConstruct
|
||||
void init() {
|
||||
this.httpClient = HttpClient.newBuilder()
|
||||
.connectTimeout(Duration.ofSeconds(10))
|
||||
.build();
|
||||
this.httpClient = HttpClient.newBuilder().connectTimeout(Duration.ofSeconds(10)).build();
|
||||
this.jsonb = JsonbBuilder.create();
|
||||
}
|
||||
|
||||
|
|
@ -87,6 +85,18 @@ public class ZohoOAuthManager {
|
|||
return null;
|
||||
}
|
||||
|
||||
public String getBaseURI() throws PluginException {
|
||||
String uri = "";
|
||||
ItemCollection zohoConfig = configService.loadConfiguration(ZohoController.ZOHO_CONFIGURATION, false);
|
||||
if (zohoConfig != null) {
|
||||
uri = zohoConfig.getItemValueString("zoho.uri");
|
||||
if (!uri.endsWith("/")) {
|
||||
uri = uri + "/";
|
||||
}
|
||||
}
|
||||
return uri;
|
||||
}
|
||||
|
||||
/**
|
||||
* Step 3: Generate Access and Refresh Token
|
||||
*
|
||||
|
|
@ -107,24 +117,21 @@ public class ZohoOAuthManager {
|
|||
|
||||
String clientID = zohoConfig.getItemValueString("zoho.clientid");
|
||||
String clientSecret = zohoConfig.getItemValueString("zoho.clientsecret");
|
||||
String requestUrl = "https://accounts.zoho.eu/oauth/v2/token" +
|
||||
"?code=" + URLEncoder.encode(code, StandardCharsets.UTF_8) +
|
||||
"&client_id=" + URLEncoder.encode(clientID, StandardCharsets.UTF_8) +
|
||||
"&client_secret=" + URLEncoder.encode(clientSecret, StandardCharsets.UTF_8) +
|
||||
"&redirect_uri=" + URLEncoder.encode(redirectURI, StandardCharsets.UTF_8) +
|
||||
"&grant_type=authorization_code";
|
||||
String requestUrl = "https://accounts.zoho.eu/oauth/v2/token" + "?code="
|
||||
+ URLEncoder.encode(code, StandardCharsets.UTF_8) + "&client_id="
|
||||
+ URLEncoder.encode(clientID, StandardCharsets.UTF_8) + "&client_secret="
|
||||
+ URLEncoder.encode(clientSecret, StandardCharsets.UTF_8) + "&redirect_uri="
|
||||
+ URLEncoder.encode(redirectURI, StandardCharsets.UTF_8) + "&grant_type=authorization_code";
|
||||
|
||||
logger.fine("│ ├── Request URI=" + requestUrl);
|
||||
|
||||
HttpRequest request = HttpRequest.newBuilder()
|
||||
.uri(URI.create(requestUrl))
|
||||
HttpRequest request = HttpRequest.newBuilder().uri(URI.create(requestUrl))
|
||||
.header("Content-Type", "application/x-www-form-urlencoded")
|
||||
.POST(HttpRequest.BodyPublishers.noBody()) // Wichtig: Kein Body!
|
||||
.build();
|
||||
|
||||
HttpResponse<String> response;
|
||||
response = httpClient.send(request,
|
||||
HttpResponse.BodyHandlers.ofString());
|
||||
response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
|
||||
|
||||
logger.fine("│ ├── Response statusCode=" + response.statusCode());
|
||||
if (response.statusCode() == 200) {
|
||||
|
|
@ -132,23 +139,20 @@ public class ZohoOAuthManager {
|
|||
logger.fine("│ ├── Response Body=" + response.body());
|
||||
|
||||
if (response.body().contains("error")) {
|
||||
throw new PluginException(ZohoOAuthManager.class.getSimpleName(),
|
||||
ZohoOAuthManager.ERROR_CONFIG,
|
||||
throw new PluginException(ZohoOAuthManager.class.getSimpleName(), ZohoOAuthManager.ERROR_CONFIG,
|
||||
"Ungültiger Access Code!");
|
||||
}
|
||||
|
||||
TokenResponse tokenResponse = jsonb.fromJson(response.body(),
|
||||
TokenResponse.class);
|
||||
TokenResponse tokenResponse = jsonb.fromJson(response.body(), TokenResponse.class);
|
||||
saveTokenData(zohoConfig, tokenResponse);
|
||||
|
||||
} else {
|
||||
throw new RuntimeException("Failed to get tokens: " +
|
||||
response.statusCode() + " - " + response.body());
|
||||
throw new RuntimeException("Failed to get tokens: " + response.statusCode() + " - " + response.body());
|
||||
}
|
||||
|
||||
} catch (IOException | InterruptedException e) {
|
||||
throw new PluginException(ZohoOAuthManager.class.getSimpleName(),
|
||||
ZohoOAuthManager.ERROR_CONFIG, "Unable to resolve access tokens: " + e.getMessage());
|
||||
throw new PluginException(ZohoOAuthManager.class.getSimpleName(), ZohoOAuthManager.ERROR_CONFIG,
|
||||
"Unable to resolve access tokens: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -168,26 +172,21 @@ public class ZohoOAuthManager {
|
|||
|
||||
String refreshToken = zohoConfig.getItemValueString("zoho.refreshToken");
|
||||
try {
|
||||
String requestUrl = "https://accounts.zoho.eu/oauth/v2/token" +
|
||||
"?refresh_token=" + URLEncoder.encode(refreshToken, StandardCharsets.UTF_8) +
|
||||
"&client_id=" + URLEncoder.encode(clientID, StandardCharsets.UTF_8) +
|
||||
"&client_secret=" + URLEncoder.encode(clientSecret,
|
||||
StandardCharsets.UTF_8)
|
||||
+
|
||||
"&grant_type=refresh_token";
|
||||
String requestUrl = "https://accounts.zoho.eu/oauth/v2/token" + "?refresh_token="
|
||||
+ URLEncoder.encode(refreshToken, StandardCharsets.UTF_8) + "&client_id="
|
||||
+ URLEncoder.encode(clientID, StandardCharsets.UTF_8) + "&client_secret="
|
||||
+ URLEncoder.encode(clientSecret, StandardCharsets.UTF_8) + "&grant_type=refresh_token";
|
||||
|
||||
logger.fine("│ ├── Request URI=" + requestUrl);
|
||||
|
||||
HttpRequest request = HttpRequest.newBuilder()
|
||||
.uri(URI.create(requestUrl))
|
||||
HttpRequest request = HttpRequest.newBuilder().uri(URI.create(requestUrl))
|
||||
.header("Content-Type", "application/x-www-form-urlencoded")
|
||||
.POST(HttpRequest.BodyPublishers.noBody()) // Wichtig: Kein Body!
|
||||
.build();
|
||||
|
||||
HttpResponse<String> response;
|
||||
|
||||
response = httpClient.send(request,
|
||||
HttpResponse.BodyHandlers.ofString());
|
||||
response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
|
||||
|
||||
logger.fine("│ ├── Response statusCode=" + response.statusCode());
|
||||
if (response.statusCode() == 200) {
|
||||
|
|
@ -195,19 +194,17 @@ public class ZohoOAuthManager {
|
|||
// 1. Response-Logging für Debugging
|
||||
logger.fine("│ ├── Response Body=" + response.body());
|
||||
|
||||
TokenResponse tokenResponse = jsonb.fromJson(response.body(),
|
||||
TokenResponse.class);
|
||||
TokenResponse tokenResponse = jsonb.fromJson(response.body(), TokenResponse.class);
|
||||
saveTokenData(zohoConfig, tokenResponse);
|
||||
return zohoConfig.getItemValueString("zoho.accessToken");
|
||||
|
||||
} else {
|
||||
throw new RuntimeException("Failed to get tokens: " +
|
||||
response.statusCode() + " - " + response.body());
|
||||
throw new RuntimeException("Failed to get tokens: " + response.statusCode() + " - " + response.body());
|
||||
}
|
||||
|
||||
} catch (IOException | InterruptedException e) {
|
||||
throw new PluginException(ZohoOAuthManager.class.getSimpleName(),
|
||||
ZohoOAuthManager.ERROR_CONFIG, "Unable to refresh access tokens: " + e.getMessage());
|
||||
throw new PluginException(ZohoOAuthManager.class.getSimpleName(), ZohoOAuthManager.ERROR_CONFIG,
|
||||
"Unable to refresh access tokens: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,42 +1,42 @@
|
|||
package com.alexanderlogistics.zoho.dto;
|
||||
|
||||
public class ZohoInvoiceItem {
|
||||
private String name;
|
||||
private String description;
|
||||
private double rate;
|
||||
private int quantity;
|
||||
private String name;
|
||||
private String description;
|
||||
private double rate;
|
||||
private int quantity;
|
||||
|
||||
// Getter und Setter
|
||||
// Getter und Setter
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public double getRate() {
|
||||
return rate;
|
||||
}
|
||||
public double getRate() {
|
||||
return rate;
|
||||
}
|
||||
|
||||
public void setRate(double rate) {
|
||||
this.rate = rate;
|
||||
}
|
||||
public void setRate(double rate) {
|
||||
this.rate = rate;
|
||||
}
|
||||
|
||||
public int getQuantity() {
|
||||
return quantity;
|
||||
}
|
||||
public int getQuantity() {
|
||||
return quantity;
|
||||
}
|
||||
|
||||
public void setQuantity(int quantity) {
|
||||
this.quantity = quantity;
|
||||
}
|
||||
public void setQuantity(int quantity) {
|
||||
this.quantity = quantity;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,150 +33,149 @@ import jakarta.inject.Named;
|
|||
@ConversationScoped
|
||||
public class AnalyticController implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static Logger logger = Logger.getLogger(AnalyticController.class.getName());
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static Logger logger = Logger.getLogger(AnalyticController.class.getName());
|
||||
|
||||
@Inject
|
||||
protected Event<AnalyticEvent> analyticEvents;
|
||||
@Inject
|
||||
protected Event<AnalyticEvent> analyticEvents;
|
||||
|
||||
@Inject
|
||||
protected WorkflowController workflowController;
|
||||
@Inject
|
||||
protected WorkflowController workflowController;
|
||||
|
||||
/**
|
||||
* Returns a analytic value as a String for a given key.
|
||||
*
|
||||
* @param key
|
||||
* @return
|
||||
*/
|
||||
public String getAsString(String key) {
|
||||
ItemCollection analyticData = computeValue(key);
|
||||
return analyticData.getItemValueString("value");
|
||||
}
|
||||
/**
|
||||
* Returns a analytic value as a String for a given key.
|
||||
*
|
||||
* @param key
|
||||
* @return
|
||||
*/
|
||||
public String getAsString(String key) {
|
||||
ItemCollection analyticData = computeValue(key);
|
||||
return analyticData.getItemValueString("value");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a analytic value as a Json String for a given key.
|
||||
*
|
||||
* @param key
|
||||
* @return
|
||||
*/
|
||||
public String getAsJson(String key) {
|
||||
ItemCollection analyticData = computeValue(key);
|
||||
String jsonval = analyticData.getItemValueString("value");
|
||||
if (jsonval == null || jsonval.isEmpty()) {
|
||||
return "null";
|
||||
} else {
|
||||
return jsonval;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Returns a analytic value as a Json String for a given key.
|
||||
*
|
||||
* @param key
|
||||
* @return
|
||||
*/
|
||||
public String getAsJson(String key) {
|
||||
ItemCollection analyticData = computeValue(key);
|
||||
String jsonval = analyticData.getItemValueString("value");
|
||||
if (jsonval == null || jsonval.isEmpty()) {
|
||||
return "null";
|
||||
} else {
|
||||
return jsonval;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a analytic value as a Double for a given key.
|
||||
*
|
||||
* @param key
|
||||
* @return
|
||||
*/
|
||||
public double getAsDouble(String key) {
|
||||
ItemCollection analyticData = computeValue(key);
|
||||
return analyticData.getItemValueDouble("value");
|
||||
}
|
||||
/**
|
||||
* Returns a analytic value as a Double for a given key.
|
||||
*
|
||||
* @param key
|
||||
* @return
|
||||
*/
|
||||
public double getAsDouble(String key) {
|
||||
ItemCollection analyticData = computeValue(key);
|
||||
return analyticData.getItemValueDouble("value");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the analytic label for a given key
|
||||
*
|
||||
* @param key
|
||||
* @return
|
||||
*/
|
||||
public String getLabel(String key) {
|
||||
ItemCollection analyticData = computeValue(key);
|
||||
return analyticData.getItemValueString("label");
|
||||
}
|
||||
/**
|
||||
* Returns the analytic label for a given key
|
||||
*
|
||||
* @param key
|
||||
* @return
|
||||
*/
|
||||
public String getLabel(String key) {
|
||||
ItemCollection analyticData = computeValue(key);
|
||||
return analyticData.getItemValueString("label");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the analytic optional link for a given key
|
||||
*
|
||||
* @param key
|
||||
* @return
|
||||
*/
|
||||
public String getLink(String key) {
|
||||
ItemCollection analyticData = computeValue(key);
|
||||
return analyticData.getItemValueString("link");
|
||||
}
|
||||
/**
|
||||
* Returns the analytic optional link for a given key
|
||||
*
|
||||
* @param key
|
||||
* @return
|
||||
*/
|
||||
public String getLink(String key) {
|
||||
ItemCollection analyticData = computeValue(key);
|
||||
return analyticData.getItemValueString("link");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the analytic description for a given key
|
||||
*
|
||||
* @param key
|
||||
* @return
|
||||
*/
|
||||
public String getDescription(String key) {
|
||||
ItemCollection analyticData = computeValue(key);
|
||||
return analyticData.getItemValueString("description");
|
||||
}
|
||||
/**
|
||||
* Returns the analytic description for a given key
|
||||
*
|
||||
* @param key
|
||||
* @return
|
||||
*/
|
||||
public String getDescription(String key) {
|
||||
ItemCollection analyticData = computeValue(key);
|
||||
return analyticData.getItemValueString("description");
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes an analytic value. The method cache the value in the
|
||||
* item key.
|
||||
*
|
||||
* An observer controller is responsible to cache or reset the cached values if
|
||||
* needed.
|
||||
*
|
||||
* @param key
|
||||
* @return
|
||||
*/
|
||||
protected ItemCollection computeValue(String key) {
|
||||
if (workflowController.getWorkitem() != null) {
|
||||
logger.fine("fire analytic event for key '" + key + "'");
|
||||
// Fire the Analytics Event for this key
|
||||
AnalyticEvent event = new AnalyticEvent(key, workflowController.getWorkitem());
|
||||
if (analyticEvents != null) {
|
||||
analyticEvents.fire(event);
|
||||
if (event.getValue() != null) {
|
||||
ItemCollection details = new ItemCollection();
|
||||
details.setItemValue("value", event.getValue());
|
||||
details.setItemValue("label", event.getLabel());
|
||||
details.setItemValue("description", event.getDescription());
|
||||
details.setItemValue("link", event.getLink());
|
||||
// cache result
|
||||
implodeDetails(key, details);
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Computes an analytic value. The method cache the value in the item key.
|
||||
*
|
||||
* An observer controller is responsible to cache or reset the cached values if
|
||||
* needed.
|
||||
*
|
||||
* @param key
|
||||
* @return
|
||||
*/
|
||||
protected ItemCollection computeValue(String key) {
|
||||
if (workflowController.getWorkitem() != null) {
|
||||
logger.fine("fire analytic event for key '" + key + "'");
|
||||
// Fire the Analytics Event for this key
|
||||
AnalyticEvent event = new AnalyticEvent(key, workflowController.getWorkitem());
|
||||
if (analyticEvents != null) {
|
||||
analyticEvents.fire(event);
|
||||
if (event.getValue() != null) {
|
||||
ItemCollection details = new ItemCollection();
|
||||
details.setItemValue("value", event.getValue());
|
||||
details.setItemValue("label", event.getLabel());
|
||||
details.setItemValue("description", event.getDescription());
|
||||
details.setItemValue("link", event.getLink());
|
||||
// cache result
|
||||
implodeDetails(key, details);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// analytic value is now already cached!
|
||||
return explodeDetails(key);
|
||||
}
|
||||
// analytic value is now already cached!
|
||||
return explodeDetails(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the List of ItemCollections back into a List of Map elements
|
||||
*
|
||||
* @param workitem
|
||||
*/
|
||||
@SuppressWarnings({ "rawtypes" })
|
||||
private void implodeDetails(String key, ItemCollection details) {
|
||||
// convert the child ItemCollection elements into a List of Map
|
||||
List<Map> detailsList = new ArrayList<Map>();
|
||||
detailsList.add(details.getAllItems());
|
||||
workflowController.getWorkitem().replaceItemValue(key, detailsList);
|
||||
}
|
||||
/**
|
||||
* Convert the List of ItemCollections back into a List of Map elements
|
||||
*
|
||||
* @param workitem
|
||||
*/
|
||||
@SuppressWarnings({ "rawtypes" })
|
||||
private void implodeDetails(String key, ItemCollection details) {
|
||||
// convert the child ItemCollection elements into a List of Map
|
||||
List<Map> detailsList = new ArrayList<Map>();
|
||||
detailsList.add(details.getAllItems());
|
||||
workflowController.getWorkitem().replaceItemValue(key, detailsList);
|
||||
}
|
||||
|
||||
/**
|
||||
* converts the Map List of a workitem into a List of ItemCollectons
|
||||
*/
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
private ItemCollection explodeDetails(String key) {
|
||||
// convert current list of childItems into ItemCollection elements
|
||||
List<Object> mapOrderItems = workflowController.getWorkitem().getItemValue(key);
|
||||
if (mapOrderItems != null && mapOrderItems.size() > 0) {
|
||||
ItemCollection itemCol = new ItemCollection((Map) mapOrderItems.get(0));
|
||||
return itemCol;
|
||||
}
|
||||
// return empty collection
|
||||
ItemCollection dummy = new ItemCollection();
|
||||
dummy.setItemValue("value", "");
|
||||
dummy.setItemValue("label", "");
|
||||
dummy.setItemValue("description", "No data available");
|
||||
/**
|
||||
* converts the Map List of a workitem into a List of ItemCollectons
|
||||
*/
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
private ItemCollection explodeDetails(String key) {
|
||||
// convert current list of childItems into ItemCollection elements
|
||||
List<Object> mapOrderItems = workflowController.getWorkitem().getItemValue(key);
|
||||
if (mapOrderItems != null && mapOrderItems.size() > 0) {
|
||||
ItemCollection itemCol = new ItemCollection((Map) mapOrderItems.get(0));
|
||||
return itemCol;
|
||||
}
|
||||
// return empty collection
|
||||
ItemCollection dummy = new ItemCollection();
|
||||
dummy.setItemValue("value", "");
|
||||
dummy.setItemValue("label", "");
|
||||
dummy.setItemValue("description", "No data available");
|
||||
|
||||
return dummy;
|
||||
}
|
||||
return dummy;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,12 +10,12 @@
|
|||
<ui:define name="scripts">
|
||||
<script type="text/javascript">
|
||||
/*<![CDATA[*/
|
||||
function handleSubmit(event) {
|
||||
// remove ajax kringel
|
||||
setTimeout(function() {
|
||||
document.body.classList.remove('loading');
|
||||
}, 5000);
|
||||
}
|
||||
function handleSubmit(event) {
|
||||
// remove ajax kringel
|
||||
setTimeout(function () {
|
||||
document.body.classList.remove('loading');
|
||||
}, 5000);
|
||||
}
|
||||
/*]]>*/
|
||||
</script>
|
||||
</ui:define>
|
||||
|
|
@ -32,7 +32,8 @@
|
|||
<h:panelGroup layout="block" styleClass="imixs-body" id="analyse_panel">
|
||||
<div class="imixs-form-panel">
|
||||
<div class="ui-state-highlight ui-corner-all" style="margin-bottom: 10px; padding: .5em;">
|
||||
<p>Der folgende Report exportiert <i>Ausgangsrechnungen</i>, in eine Excel Datei. Der Export ist auf maximal 3000 Einträge pro Tabelle beschränkt
|
||||
<p>Der folgende Report exportiert <i>Ausgangsrechnungen</i>, in eine Excel Datei. Der
|
||||
Export ist auf maximal 3000 Einträge pro Tabelle beschränkt
|
||||
</p>
|
||||
</div>
|
||||
<div class="imixs-form-section-2">
|
||||
|
|
@ -65,12 +66,14 @@
|
|||
Abteilung:
|
||||
</dt>
|
||||
<dd>
|
||||
<h:selectOneMenu noSelectionOption="true"
|
||||
<h:selectOneMenu noSelectionOption="true"
|
||||
value="#{excelExportController.filter.item['space.ref']}">
|
||||
<f:selectItem itemLabel=" - " itemValue="-" ></f:selectItem>
|
||||
<c:forEach items="#{spaceRefFormController.getSpaces(workflowController.workitem, options)}"
|
||||
<f:selectItem itemLabel=" - " itemValue="-"></f:selectItem>
|
||||
<c:forEach
|
||||
items="#{spaceRefFormController.getSpaces(workflowController.workitem, options)}"
|
||||
var="space">
|
||||
<f:selectItem itemLabel="#{space.item['name']}" itemValue="#{space.item['$UniqueID']}">
|
||||
<f:selectItem itemLabel="#{space.item['name']}"
|
||||
itemValue="#{space.item['$UniqueID']}">
|
||||
</f:selectItem>
|
||||
</c:forEach>
|
||||
</h:selectOneMenu>
|
||||
|
|
@ -82,10 +85,10 @@
|
|||
Debitor:
|
||||
</dt>
|
||||
<dd>
|
||||
<ui:include src="/pages/workitems/parts/alexander/debitor_search.xhtml" >
|
||||
<ui:include src="/pages/workitems/parts/alexander/businesspartner_search.xhtml">
|
||||
<ui:param name="workitem" value="#{workflowController.workitem}" />
|
||||
<ui:param name="item" value="#{excelExportController.item}" />
|
||||
</ui:include>
|
||||
</ui:include>
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
|
|
@ -94,15 +97,14 @@
|
|||
Positionsnummer:
|
||||
</dt>
|
||||
<dd>
|
||||
<h:inputText
|
||||
value="#{excelExportController.filter.item['invoice.text']}">
|
||||
<h:inputText value="#{excelExportController.filter.item['invoice.text']}">
|
||||
</h:inputText>
|
||||
</dd>
|
||||
</dl>
|
||||
</div>
|
||||
|
||||
<h:commandButton actionListener="#{excelExportController.export()}"
|
||||
value="Excel Export starten">
|
||||
value="Excel Export starten">
|
||||
</h:commandButton>
|
||||
<h:commandButton value="#{message.close}" action="notes" />
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -19,13 +19,13 @@
|
|||
/*]]>*/
|
||||
</script>
|
||||
|
||||
<h:form id="import_form_id">
|
||||
<h:form id="import_form_id" autocomplete="off">
|
||||
|
||||
<div class="imixs-form">
|
||||
<div class="imixs-header">
|
||||
<h1>ZOHO - API </h1>
|
||||
<!-- ########## Error ########## -->
|
||||
<ui:include src="/error_message.xhtml" />
|
||||
|
||||
</div>
|
||||
|
||||
<div class="imixs-body">
|
||||
|
|
@ -41,8 +41,27 @@
|
|||
|
||||
<!-- API Tokens -->
|
||||
<div class="imixs-form-section-2">
|
||||
|
||||
<dl>
|
||||
<dt>Client ID</dt>
|
||||
<dt>API Base URL <span class="imixs-required">*</span></dt>
|
||||
<dd>
|
||||
<h:inputText required="true"
|
||||
value="#{zohoController.workitem.item['zoho.uri']}">
|
||||
</h:inputText>
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
|
||||
<dl>
|
||||
<dt>Organization <span class="imixs-required">*</span></dt>
|
||||
<dd>
|
||||
<h:inputText required="true"
|
||||
value="#{zohoController.workitem.item['zoho.organization']}">
|
||||
</h:inputText>
|
||||
</dd>
|
||||
</dl>
|
||||
<dl>
|
||||
<dt>Client ID <span class="imixs-required">*</span></dt>
|
||||
<dd>
|
||||
<h:inputText required="false"
|
||||
value="#{zohoController.workitem.item['zoho.clientid']}">
|
||||
|
|
@ -51,27 +70,20 @@
|
|||
</dd>
|
||||
</dl>
|
||||
<dl>
|
||||
<dt>Client Secret</dt>
|
||||
<dt>Client Secret <span class="imixs-required">*</span></dt>
|
||||
<dd>
|
||||
<h:inputSecret required="false" redisplay="true"
|
||||
value="#{zohoController.workitem.item['zoho.clientsecret']}">
|
||||
</h:inputSecret>
|
||||
</dd>
|
||||
</dl>
|
||||
<dl>
|
||||
<dt>Organization</dt>
|
||||
<dd>
|
||||
<h:inputText required="false"
|
||||
value="#{zohoController.workitem.item['zoho.organization']}">
|
||||
</h:inputText>
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- Grant Token -->
|
||||
<div class="imixs-form-section-2">
|
||||
<dl>
|
||||
<dt>Access Code</dt>
|
||||
<dt>Access Code <span class="imixs-required">*</span> </dt>
|
||||
<dd>
|
||||
<h:inputSecret required="false" redisplay="true"
|
||||
value="#{zohoController.workitem.item['zoho.code']}">
|
||||
|
|
|
|||
|
|
@ -19,40 +19,40 @@ import org.junit.jupiter.api.Test;
|
|||
*/
|
||||
public class TestFTP {
|
||||
|
||||
final static String FILE = "/DTVF_SKBeschrift_21010.csv";
|
||||
final static String FILE = "/DTVF_SKBeschrift_21010.csv";
|
||||
|
||||
private final static Logger logger = Logger.getLogger(TestFTP.class.getName());
|
||||
private final static Logger logger = Logger.getLogger(TestFTP.class.getName());
|
||||
|
||||
@BeforeEach
|
||||
public void setUp() throws Exception {
|
||||
@BeforeEach
|
||||
public void setUp() throws Exception {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test Kreditoren import
|
||||
*/
|
||||
@Disabled
|
||||
@Test
|
||||
public void testPutFileToFTP() {
|
||||
/**
|
||||
* Test Kreditoren import
|
||||
*/
|
||||
@Disabled
|
||||
@Test
|
||||
public void testPutFileToFTP() {
|
||||
|
||||
FTPConnector ftpc = new FTPConnector();
|
||||
FTPConnector ftpc = new FTPConnector();
|
||||
|
||||
ftpc.ftpServer = Optional.ofNullable("u248962.your-storagebox.de");
|
||||
ftpc.ftpPort = Optional.ofNullable(21);
|
||||
ftpc.ftpUser = Optional.ofNullable("u248962-sub2");
|
||||
ftpc.ftpPassword = Optional.ofNullable("aXa61n9Un3jDNQlL");
|
||||
ftpc.ftpPath = Optional.ofNullable("/");
|
||||
ftpc.ftpServer = Optional.ofNullable("u248962.your-storagebox.de");
|
||||
ftpc.ftpPort = Optional.ofNullable(21);
|
||||
ftpc.ftpUser = Optional.ofNullable("u248962-sub2");
|
||||
ftpc.ftpPassword = Optional.ofNullable("aXa61n9Un3jDNQlL");
|
||||
ftpc.ftpPath = Optional.ofNullable("/");
|
||||
|
||||
FileData fileData = new FileData("test.txt", "some data...".getBytes(), "text", null);
|
||||
try {
|
||||
ftpc.put(fileData);
|
||||
logger.info("test finished...");
|
||||
} catch (PluginException e) {
|
||||
FileData fileData = new FileData("test.txt", "some data...".getBytes(), "text", null);
|
||||
try {
|
||||
ftpc.put(fileData);
|
||||
logger.info("test finished...");
|
||||
} catch (PluginException e) {
|
||||
|
||||
e.printStackTrace();
|
||||
fail();
|
||||
}
|
||||
e.printStackTrace();
|
||||
fail();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -59,8 +59,8 @@ public class TestIMAPOutlookOAuth {
|
|||
/*
|
||||
* Neue Daten
|
||||
*
|
||||
* Wert: zDL8Q~iEy8AX~dEmIOHrVv3aBTCZLrHIFmShibZ_
|
||||
* Geheime ID: bcaa558a-3300-4498-94e1-2267f418afd5
|
||||
* Wert: zDL8Q~iEy8AX~dEmIOHrVv3aBTCZLrHIFmShibZ_ Geheime ID:
|
||||
* bcaa558a-3300-4498-94e1-2267f418afd5
|
||||
*/
|
||||
|
||||
@Test
|
||||
|
|
|
|||
|
|
@ -13,18 +13,18 @@ import org.junit.jupiter.api.Test;
|
|||
*/
|
||||
public class TestPostionsnummernRegex {
|
||||
|
||||
/**
|
||||
* Test positionnummern 'XX-YYY-####-###'
|
||||
*/
|
||||
@Test
|
||||
public void testPutFileToFTP() {
|
||||
/**
|
||||
* Test positionnummern 'XX-YYY-####-###'
|
||||
*/
|
||||
@Test
|
||||
public void testPutFileToFTP() {
|
||||
|
||||
assertTrue("AA-BBC-1234-991".matches(InvoicePlugin.INVOICE_POSITIONS_PATTERN_DEFAULT));
|
||||
assertFalse("aa-BBC-1234-991".matches(InvoicePlugin.INVOICE_POSITIONS_PATTERN_DEFAULT));
|
||||
assertFalse("CC-BBC-1234-991 ".matches(InvoicePlugin.INVOICE_POSITIONS_PATTERN_DEFAULT));
|
||||
assertTrue("AA-BBC-1234-991".matches(InvoicePlugin.INVOICE_POSITIONS_PATTERN_DEFAULT));
|
||||
assertFalse("aa-BBC-1234-991".matches(InvoicePlugin.INVOICE_POSITIONS_PATTERN_DEFAULT));
|
||||
assertFalse("CC-BBC-1234-991 ".matches(InvoicePlugin.INVOICE_POSITIONS_PATTERN_DEFAULT));
|
||||
|
||||
assertTrue("IM-ZEL-2101-005".matches(InvoicePlugin.INVOICE_POSITIONS_PATTERN_DEFAULT));
|
||||
assertTrue("IM-ZEL-2101-005".matches(InvoicePlugin.INVOICE_POSITIONS_PATTERN_DEFAULT));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -66,34 +66,20 @@ public class DueDateBugfix {
|
|||
* Erledigte
|
||||
*
|
||||
*
|
||||
* EXTF_202301_202302030602_1295
|
||||
* EXTF_202301_202302060601_1296
|
||||
* EXTF_202301_202302070603_1297
|
||||
* EXTF_202301_202302080603_1298
|
||||
* EXTF_202301_202302090604_1299
|
||||
* EXTF_202301_202302100603_1300
|
||||
* EXTF_202301_202302130601_1301
|
||||
* EXTF_202301_202302140604_1302
|
||||
* EXTF_202301_202302141840_1303
|
||||
* EXTF_202301_202302160944_1304
|
||||
* EXTF_202302_202302020601_1294
|
||||
* EXTF_202302_202302030602_1295
|
||||
* EXTF_202302_202302060601_1296
|
||||
* EXTF_202302_202302070603_1297
|
||||
* EXTF_202302_202302080603_1298
|
||||
* EXTF_202302_202302090604_1299
|
||||
* EXTF_202302_202302100604_1300
|
||||
* EXTF_202302_202302130601_1301
|
||||
* EXTF_202302_202302140604_1302
|
||||
* EXTF_202302_202302141840_1303
|
||||
* EXTF_202302_202302160944_1304
|
||||
* EXTF_202303_202302070603_1297
|
||||
* EXTF_202303_202302080603_1298
|
||||
* EXTF_202303_202302090604_1299
|
||||
* EXTF_202303_202302100603_1300
|
||||
* EXTF_202303_202302130601_1301
|
||||
* EXTF_202303_202302140604_1302
|
||||
* EXTF_202303_202302141840_1303
|
||||
* EXTF_202301_202302030602_1295 EXTF_202301_202302060601_1296
|
||||
* EXTF_202301_202302070603_1297 EXTF_202301_202302080603_1298
|
||||
* EXTF_202301_202302090604_1299 EXTF_202301_202302100603_1300
|
||||
* EXTF_202301_202302130601_1301 EXTF_202301_202302140604_1302
|
||||
* EXTF_202301_202302141840_1303 EXTF_202301_202302160944_1304
|
||||
* EXTF_202302_202302020601_1294 EXTF_202302_202302030602_1295
|
||||
* EXTF_202302_202302060601_1296 EXTF_202302_202302070603_1297
|
||||
* EXTF_202302_202302080603_1298 EXTF_202302_202302090604_1299
|
||||
* EXTF_202302_202302100604_1300 EXTF_202302_202302130601_1301
|
||||
* EXTF_202302_202302140604_1302 EXTF_202302_202302141840_1303
|
||||
* EXTF_202302_202302160944_1304 EXTF_202303_202302070603_1297
|
||||
* EXTF_202303_202302080603_1298 EXTF_202303_202302090604_1299
|
||||
* EXTF_202303_202302100603_1300 EXTF_202303_202302130601_1301
|
||||
* EXTF_202303_202302140604_1302 EXTF_202303_202302141840_1303
|
||||
* EXTF_202303_202302160944_1304
|
||||
*
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -17,8 +17,8 @@ import jakarta.ws.rs.core.Cookie;
|
|||
import jakarta.ws.rs.core.Response;
|
||||
|
||||
/**
|
||||
* Test to request data via a JSESSIONID only....
|
||||
* This technique is used by the DataRestService
|
||||
* Test to request data via a JSESSIONID only.... This technique is used by the
|
||||
* DataRestService
|
||||
*
|
||||
*/
|
||||
@Ignore
|
||||
|
|
@ -36,11 +36,8 @@ public class TestDataClient {
|
|||
@BeforeEach
|
||||
public void setup() throws PluginException {
|
||||
// Create a Cookie object with a name and a value
|
||||
Cookie cookie = new Cookie.Builder("JSESSIONID")
|
||||
.value(sessionID)
|
||||
.path("/")
|
||||
.domain("alexander-logistics.office-workflow.de")
|
||||
.build();
|
||||
Cookie cookie = new Cookie.Builder("JSESSIONID").value(sessionID).path("/")
|
||||
.domain("alexander-logistics.office-workflow.de").build();
|
||||
|
||||
client = new DocumentClient(restAPI.trim());
|
||||
CookieAuthenticator aut = new CookieAuthenticator(cookie);
|
||||
|
|
|
|||
|
|
@ -18,65 +18,65 @@ import org.junit.jupiter.api.Test;
|
|||
*/
|
||||
public class TestSEPATransform {
|
||||
|
||||
final static String ENCODING = "UTF-8";
|
||||
final static String ENCODING = "UTF-8";
|
||||
|
||||
private static Logger logger = Logger.getLogger(TestSEPATransform.class.getName());
|
||||
private static Logger logger = Logger.getLogger(TestSEPATransform.class.getName());
|
||||
|
||||
@BeforeEach
|
||||
public void setup() throws PluginException, ModelException {
|
||||
logger.info("setup test environment ...");
|
||||
@BeforeEach
|
||||
public void setup() throws PluginException, ModelException {
|
||||
logger.info("setup test environment ...");
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* XSL Transformation for SEPA Standard file
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
@Test
|
||||
public void testDefault() throws IOException {
|
||||
String MODEL_PATH_XML = "sepa/beispiel-daten.xml";
|
||||
String MODEL_PATH_XSL = "sepa/sepa-2.0.5.xsl";
|
||||
try {
|
||||
XSLTester.transform(MODEL_PATH_XML, MODEL_PATH_XSL, "../reports/sepa/result_sepa01.xml");
|
||||
} catch (Exception e) {
|
||||
fail();
|
||||
}
|
||||
}
|
||||
/**
|
||||
* XSL Transformation for SEPA Standard file
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
@Test
|
||||
public void testDefault() throws IOException {
|
||||
String MODEL_PATH_XML = "sepa/beispiel-daten.xml";
|
||||
String MODEL_PATH_XSL = "sepa/sepa-2.0.5.xsl";
|
||||
try {
|
||||
XSLTester.transform(MODEL_PATH_XML, MODEL_PATH_XSL, "../reports/sepa/result_sepa01.xml");
|
||||
} catch (Exception e) {
|
||||
fail();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* XSL Transformation for SEPA file for Bank Polski
|
||||
*
|
||||
* We also test the two-digits case. 10,5 need to become 10,50
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
@Test
|
||||
public void testBankPolski() throws IOException {
|
||||
String MODEL_PATH_XML = "sepa/beispiel-daten.xml";
|
||||
String MODEL_PATH_XSL = "sepa/sepa-2.0.11-pl.xsl";
|
||||
try {
|
||||
XSLTester.transform(MODEL_PATH_XML, MODEL_PATH_XSL, "../reports/sepa/result_sepa-pl.xml");
|
||||
} catch (Exception e) {
|
||||
fail();
|
||||
}
|
||||
}
|
||||
/**
|
||||
* XSL Transformation for SEPA file for Bank Polski
|
||||
*
|
||||
* We also test the two-digits case. 10,5 need to become 10,50
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
@Test
|
||||
public void testBankPolski() throws IOException {
|
||||
String MODEL_PATH_XML = "sepa/beispiel-daten.xml";
|
||||
String MODEL_PATH_XSL = "sepa/sepa-2.0.11-pl.xsl";
|
||||
try {
|
||||
XSLTester.transform(MODEL_PATH_XML, MODEL_PATH_XSL, "../reports/sepa/result_sepa-pl.xml");
|
||||
} catch (Exception e) {
|
||||
fail();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* XSL Transformation for SEPA file for Bank Polski
|
||||
*
|
||||
* Neue Bank in Polen - bankmillennium
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
@Test
|
||||
public void testBankPolskibankmillennium() throws IOException {
|
||||
String MODEL_PATH_XML = "sepa/beispiel-daten.xml";
|
||||
String MODEL_PATH_XSL = "sepa/sepa-2.0.11-pl_bankmillennium.xsl";
|
||||
try {
|
||||
XSLTester.transform(MODEL_PATH_XML, MODEL_PATH_XSL, "../reports/sepa/result_sepa-pl_bankmillennium.xml");
|
||||
} catch (Exception e) {
|
||||
fail();
|
||||
}
|
||||
}
|
||||
/**
|
||||
* XSL Transformation for SEPA file for Bank Polski
|
||||
*
|
||||
* Neue Bank in Polen - bankmillennium
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
@Test
|
||||
public void testBankPolskibankmillennium() throws IOException {
|
||||
String MODEL_PATH_XML = "sepa/beispiel-daten.xml";
|
||||
String MODEL_PATH_XSL = "sepa/sepa-2.0.11-pl_bankmillennium.xsl";
|
||||
try {
|
||||
XSLTester.transform(MODEL_PATH_XML, MODEL_PATH_XSL, "../reports/sepa/result_sepa-pl_bankmillennium.xml");
|
||||
} catch (Exception e) {
|
||||
fail();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,59 +34,59 @@ import org.imixs.workflow.xml.XSLHandler;
|
|||
*/
|
||||
public class XSLTester {
|
||||
|
||||
final static String ENCODING = "UTF-8";
|
||||
final static String ENCODING = "UTF-8";
|
||||
|
||||
/**
|
||||
* XSL Transformation
|
||||
*
|
||||
* @throws IOException
|
||||
* @throws TransformerException
|
||||
*/
|
||||
public static void transform(String xmlSourcePath, String xslSourcePath, String outputPath)
|
||||
throws IOException, TransformerException {
|
||||
OutputStream outputStream = new FileOutputStream(outputPath);
|
||||
// Use the class loader to load the XML file as a resource
|
||||
ClassLoader classLoader = XSLTester.class.getClassLoader();
|
||||
InputStream xmlInputStream = classLoader.getResourceAsStream(xmlSourcePath);
|
||||
InputStream xslInputStream = classLoader.getResourceAsStream(xslSourcePath);
|
||||
/**
|
||||
* XSL Transformation
|
||||
*
|
||||
* @throws IOException
|
||||
* @throws TransformerException
|
||||
*/
|
||||
public static void transform(String xmlSourcePath, String xslSourcePath, String outputPath)
|
||||
throws IOException, TransformerException {
|
||||
OutputStream outputStream = new FileOutputStream(outputPath);
|
||||
// Use the class loader to load the XML file as a resource
|
||||
ClassLoader classLoader = XSLTester.class.getClassLoader();
|
||||
InputStream xmlInputStream = classLoader.getResourceAsStream(xmlSourcePath);
|
||||
InputStream xslInputStream = classLoader.getResourceAsStream(xslSourcePath);
|
||||
|
||||
try {
|
||||
try {
|
||||
|
||||
if (xmlInputStream == null) {
|
||||
throw new RuntimeException("XML file not found: " + xmlSourcePath);
|
||||
}
|
||||
if (xslInputStream == null) {
|
||||
throw new RuntimeException("XSL file not found: " + xslSourcePath);
|
||||
}
|
||||
if (xmlInputStream == null) {
|
||||
throw new RuntimeException("XML file not found: " + xmlSourcePath);
|
||||
}
|
||||
if (xslInputStream == null) {
|
||||
throw new RuntimeException("XSL file not found: " + xslSourcePath);
|
||||
}
|
||||
|
||||
String xmlSource = readXml(xmlInputStream);
|
||||
String xslSource = readXml(xslInputStream);
|
||||
XSLHandler.transform(xmlSource, xslSource, ENCODING, outputStream);
|
||||
String xmlSource = readXml(xmlInputStream);
|
||||
String xslSource = readXml(xslInputStream);
|
||||
XSLHandler.transform(xmlSource, xslSource, ENCODING, outputStream);
|
||||
|
||||
} finally {
|
||||
if (xmlInputStream != null)
|
||||
xmlInputStream.close();
|
||||
if (xslInputStream != null)
|
||||
xslInputStream.close();
|
||||
if (outputStream != null)
|
||||
outputStream.close();
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
if (xmlInputStream != null)
|
||||
xmlInputStream.close();
|
||||
if (xslInputStream != null)
|
||||
xslInputStream.close();
|
||||
if (outputStream != null)
|
||||
outputStream.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* read and return the XML content as a String
|
||||
*
|
||||
*/
|
||||
private static String readXml(InputStream inputStream) {
|
||||
try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) {
|
||||
StringBuilder xmlContent = new StringBuilder();
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
xmlContent.append(line).append("\n");
|
||||
}
|
||||
return xmlContent.toString();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("Error reading XML file", e);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* read and return the XML content as a String
|
||||
*
|
||||
*/
|
||||
private static String readXml(InputStream inputStream) {
|
||||
try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) {
|
||||
StringBuilder xmlContent = new StringBuilder();
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
xmlContent.append(line).append("\n");
|
||||
}
|
||||
return xmlContent.toString();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("Error reading XML file", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,77 +43,77 @@ import com.alexanderlogistics.mahnlauf.MahnlaufService;
|
|||
@MockitoSettings(strictness = Strictness.WARN)
|
||||
public class EAkteImportTester {
|
||||
|
||||
@Spy
|
||||
@InjectMocks
|
||||
private CargosoftXMLEAkteImportService service;
|
||||
@Spy
|
||||
@InjectMocks
|
||||
private CargosoftXMLEAkteImportService service;
|
||||
|
||||
@Mock
|
||||
private DocumentService documentService;
|
||||
@Mock
|
||||
private DocumentService documentService;
|
||||
|
||||
@Mock
|
||||
private BusinessPartnerService businessPartnerService;
|
||||
@Mock
|
||||
private BusinessPartnerService businessPartnerService;
|
||||
|
||||
@Mock
|
||||
private MahnlaufService mahnlaufService;
|
||||
@Mock
|
||||
private MahnlaufService mahnlaufService;
|
||||
|
||||
@BeforeEach
|
||||
public void setUp() {
|
||||
// Mock protected Methode 'alreadyImported' -> always false
|
||||
Mockito.when(service.alreadyImported(Mockito.anyString())).thenReturn(false);
|
||||
}
|
||||
@BeforeEach
|
||||
public void setUp() {
|
||||
// Mock protected Methode 'alreadyImported' -> always false
|
||||
Mockito.when(service.alreadyImported(Mockito.anyString())).thenReturn(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ein Einfacher test
|
||||
*
|
||||
* @throws TransformerException
|
||||
* @throws XPathExpressionException
|
||||
* @throws ModelException
|
||||
* @throws PluginException
|
||||
* @throws ProcessingErrorException
|
||||
* @throws AccessDeniedException
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void testEAkteBasic() throws Exception {
|
||||
/**
|
||||
* Ein Einfacher test
|
||||
*
|
||||
* @throws TransformerException
|
||||
* @throws XPathExpressionException
|
||||
* @throws ModelException
|
||||
* @throws PluginException
|
||||
* @throws ProcessingErrorException
|
||||
* @throws AccessDeniedException
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void testEAkteBasic() throws Exception {
|
||||
|
||||
ItemCollection source = new ItemCollection();
|
||||
String fileName = "Abgabenbescheid-IM-GCA-2408-116N-001-ATC400012650820242452-_20240806164256864_DEBUG.xml";
|
||||
byte[] xmlContent = readTestFile("cargosoft/" + fileName);
|
||||
assertNotNull(xmlContent);
|
||||
ItemCollection source = new ItemCollection();
|
||||
String fileName = "Abgabenbescheid-IM-GCA-2408-116N-001-ATC400012650820242452-_20240806164256864_DEBUG.xml";
|
||||
byte[] xmlContent = readTestFile("cargosoft/" + fileName);
|
||||
assertNotNull(xmlContent);
|
||||
|
||||
// Act
|
||||
ItemCollection result = service.createWorkitem(source, fileName, xmlContent, new HashMap<>());
|
||||
// Act
|
||||
ItemCollection result = service.createWorkitem(source, fileName, xmlContent, new HashMap<>());
|
||||
|
||||
// Assert
|
||||
assertNotNull(result);
|
||||
assertEquals("001", result.getItemValueString("mandant.id"));
|
||||
// Assert
|
||||
assertNotNull(result);
|
||||
assertEquals("001", result.getItemValueString("mandant.id"));
|
||||
|
||||
// test Rows
|
||||
List<ItemCollection> rows = InvoiceUtil.explodeChildList(result);
|
||||
assertNotNull(rows);
|
||||
assertEquals(2, rows.size());
|
||||
ItemCollection row1 = rows.get(0);
|
||||
ItemCollection row2 = rows.get(1);
|
||||
assertEquals("LA-ZEL-2403-004", row1.getItemValueString("filenumber"));
|
||||
assertEquals("LA-ZEL-2403-00", row2.getItemValueString("filenumber"));
|
||||
assertEquals("ZOLL", row1.getItemValueString("activity.type"));
|
||||
assertEquals("EUST", row2.getItemValueString("activity.type"));
|
||||
// test Rows
|
||||
List<ItemCollection> rows = InvoiceUtil.explodeChildList(result);
|
||||
assertNotNull(rows);
|
||||
assertEquals(2, rows.size());
|
||||
ItemCollection row1 = rows.get(0);
|
||||
ItemCollection row2 = rows.get(1);
|
||||
assertEquals("LA-ZEL-2403-004", row1.getItemValueString("filenumber"));
|
||||
assertEquals("LA-ZEL-2403-00", row2.getItemValueString("filenumber"));
|
||||
assertEquals("ZOLL", row1.getItemValueString("activity.type"));
|
||||
assertEquals("EUST", row2.getItemValueString("activity.type"));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Hilfsmethode zum einlesen einer xml test datei
|
||||
*
|
||||
* @return
|
||||
* @throws IOException
|
||||
*/
|
||||
private byte[] readTestFile(String filename) throws IOException {
|
||||
// Load the file from the resources folder
|
||||
ClassLoader classLoader = getClass().getClassLoader();
|
||||
InputStream inputStream = classLoader.getResourceAsStream(filename);
|
||||
byte[] data = inputStream.readAllBytes();
|
||||
inputStream.close();
|
||||
return data;
|
||||
}
|
||||
/**
|
||||
* Hilfsmethode zum einlesen einer xml test datei
|
||||
*
|
||||
* @return
|
||||
* @throws IOException
|
||||
*/
|
||||
private byte[] readTestFile(String filename) throws IOException {
|
||||
// Load the file from the resources folder
|
||||
ClassLoader classLoader = getClass().getClassLoader();
|
||||
InputStream inputStream = classLoader.getResourceAsStream(filename);
|
||||
byte[] data = inputStream.readAllBytes();
|
||||
inputStream.close();
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,122 +43,122 @@ import com.alexanderlogistics.mahnlauf.MahnlaufService;
|
|||
@MockitoSettings(strictness = Strictness.WARN)
|
||||
public class InvoiceImportTester {
|
||||
|
||||
@Spy
|
||||
@InjectMocks
|
||||
private CargosoftXMLInvoiceImportService service;
|
||||
@Spy
|
||||
@InjectMocks
|
||||
private CargosoftXMLInvoiceImportService service;
|
||||
|
||||
@Mock
|
||||
private DocumentService documentService;
|
||||
@Mock
|
||||
private DocumentService documentService;
|
||||
|
||||
@Mock
|
||||
private MahnlaufService mahnlaufService;
|
||||
@Mock
|
||||
private MahnlaufService mahnlaufService;
|
||||
|
||||
@Mock
|
||||
private BusinessPartnerService businessPartnerService;
|
||||
@Mock
|
||||
private BusinessPartnerService businessPartnerService;
|
||||
|
||||
@BeforeEach
|
||||
public void setUp() {
|
||||
// Mock protected Methode 'alreadyImported' -> always false
|
||||
Mockito.when(service.alreadyImported(Mockito.anyString())).thenReturn(false);
|
||||
}
|
||||
@BeforeEach
|
||||
public void setUp() {
|
||||
// Mock protected Methode 'alreadyImported' -> always false
|
||||
Mockito.when(service.alreadyImported(Mockito.anyString())).thenReturn(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ein Einfacher test
|
||||
*
|
||||
* @throws TransformerException
|
||||
* @throws XPathExpressionException
|
||||
* @throws ModelException
|
||||
* @throws PluginException
|
||||
* @throws ProcessingErrorException
|
||||
* @throws AccessDeniedException
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void testInvoiceBasic() throws Exception {
|
||||
/**
|
||||
* Ein Einfacher test
|
||||
*
|
||||
* @throws TransformerException
|
||||
* @throws XPathExpressionException
|
||||
* @throws ModelException
|
||||
* @throws PluginException
|
||||
* @throws ProcessingErrorException
|
||||
* @throws AccessDeniedException
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void testInvoiceBasic() throws Exception {
|
||||
|
||||
ItemCollection source = new ItemCollection();
|
||||
String fileName = "001_R_224380_110136787.xml";
|
||||
byte[] xmlContent = readTestFile("cargosoft/" + fileName);
|
||||
assertNotNull(xmlContent);
|
||||
ItemCollection source = new ItemCollection();
|
||||
String fileName = "001_R_224380_110136787.xml";
|
||||
byte[] xmlContent = readTestFile("cargosoft/" + fileName);
|
||||
assertNotNull(xmlContent);
|
||||
|
||||
// Act
|
||||
ItemCollection result = service.createWorkitem(source, fileName, xmlContent, new HashMap<>());
|
||||
// Act
|
||||
ItemCollection result = service.createWorkitem(source, fileName, xmlContent, new HashMap<>());
|
||||
|
||||
// Assert
|
||||
assertNotNull(result);
|
||||
assertEquals("001", result.getItemValueString("mandant.id"));
|
||||
// Assert
|
||||
assertNotNull(result);
|
||||
assertEquals("001", result.getItemValueString("mandant.id"));
|
||||
|
||||
// test Rows
|
||||
List<ItemCollection> rows = InvoiceUtil.explodeChildList(result);
|
||||
assertNotNull(rows);
|
||||
assertEquals(2, rows.size());
|
||||
ItemCollection row1 = rows.get(0);
|
||||
ItemCollection row2 = rows.get(1);
|
||||
assertEquals("EX-GCA-2408-042", row1.getItemValueString("datev.text"));
|
||||
assertEquals("EX-GCA-2408-042", row2.getItemValueString("datev.text"));
|
||||
// test Rows
|
||||
List<ItemCollection> rows = InvoiceUtil.explodeChildList(result);
|
||||
assertNotNull(rows);
|
||||
assertEquals(2, rows.size());
|
||||
ItemCollection row1 = rows.get(0);
|
||||
ItemCollection row2 = rows.get(1);
|
||||
assertEquals("EX-GCA-2408-042", row1.getItemValueString("datev.text"));
|
||||
assertEquals("EX-GCA-2408-042", row2.getItemValueString("datev.text"));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ein ATC test
|
||||
*
|
||||
* @throws IOException
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void testInvoiceATC() throws Exception {
|
||||
/**
|
||||
* Ein ATC test
|
||||
*
|
||||
* @throws IOException
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void testInvoiceATC() throws Exception {
|
||||
|
||||
ItemCollection source = new ItemCollection();
|
||||
String fileName = "001_R_224225_115103063.xml";
|
||||
byte[] xmlContent = readTestFile("cargosoft/" + fileName);
|
||||
assertNotNull(xmlContent);
|
||||
ItemCollection source = new ItemCollection();
|
||||
String fileName = "001_R_224225_115103063.xml";
|
||||
byte[] xmlContent = readTestFile("cargosoft/" + fileName);
|
||||
assertNotNull(xmlContent);
|
||||
|
||||
// Act
|
||||
ItemCollection result = service.createWorkitem(source, fileName, xmlContent, new HashMap<>());
|
||||
// Act
|
||||
ItemCollection result = service.createWorkitem(source, fileName, xmlContent, new HashMap<>());
|
||||
|
||||
// Assert
|
||||
assertNotNull(result);
|
||||
assertEquals("001", result.getItemValueString("mandant.id"));
|
||||
assertEquals("ATC400012650820242452", result.getItemValueString("invoice.atc.number"));
|
||||
assertEquals(3752.95, result.getItemValueDouble("invoice.total"), 0.0);
|
||||
// Assert
|
||||
assertNotNull(result);
|
||||
assertEquals("001", result.getItemValueString("mandant.id"));
|
||||
assertEquals("ATC400012650820242452", result.getItemValueString("invoice.atc.number"));
|
||||
assertEquals(3752.95, result.getItemValueDouble("invoice.total"), 0.0);
|
||||
|
||||
// test Rows
|
||||
List<ItemCollection> rows = InvoiceUtil.explodeChildList(result);
|
||||
assertNotNull(rows);
|
||||
assertEquals(2, rows.size());
|
||||
ItemCollection row1 = rows.get(0);
|
||||
assertEquals("IM-GCA-2408-116", row1.getItemValueString("datev.text"));
|
||||
assertEquals("EUST", row1.getItemValueString("category"));
|
||||
assertEquals("EUST", row1.getItemValueString("BillingCode"));
|
||||
// test BillingText
|
||||
List<String> billingTextList = row1.getItemValue("BillingText");
|
||||
assertEquals(2, billingTextList.size());
|
||||
// test ATC Number
|
||||
assertEquals("ATC400012650820242452", row1.getItemValueString("atc.number"));
|
||||
// Umsatz
|
||||
assertEquals(3591.34, row1.getItemValueDouble("datev.umsatz"), 0.0);
|
||||
// test Rows
|
||||
List<ItemCollection> rows = InvoiceUtil.explodeChildList(result);
|
||||
assertNotNull(rows);
|
||||
assertEquals(2, rows.size());
|
||||
ItemCollection row1 = rows.get(0);
|
||||
assertEquals("IM-GCA-2408-116", row1.getItemValueString("datev.text"));
|
||||
assertEquals("EUST", row1.getItemValueString("category"));
|
||||
assertEquals("EUST", row1.getItemValueString("BillingCode"));
|
||||
// test BillingText
|
||||
List<String> billingTextList = row1.getItemValue("BillingText");
|
||||
assertEquals(2, billingTextList.size());
|
||||
// test ATC Number
|
||||
assertEquals("ATC400012650820242452", row1.getItemValueString("atc.number"));
|
||||
// Umsatz
|
||||
assertEquals(3591.34, row1.getItemValueDouble("datev.umsatz"), 0.0);
|
||||
|
||||
ItemCollection row2 = rows.get(1);
|
||||
assertEquals("IM-GCA-2408-116", row2.getItemValueString("datev.text"));
|
||||
assertEquals("SONST", row2.getItemValueString("category"));
|
||||
// Umsatz
|
||||
assertEquals(161.61, row2.getItemValueDouble("datev.umsatz"), 0.0);
|
||||
}
|
||||
ItemCollection row2 = rows.get(1);
|
||||
assertEquals("IM-GCA-2408-116", row2.getItemValueString("datev.text"));
|
||||
assertEquals("SONST", row2.getItemValueString("category"));
|
||||
// Umsatz
|
||||
assertEquals(161.61, row2.getItemValueDouble("datev.umsatz"), 0.0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Hilfsmethode zum einlesen einer xml test datei
|
||||
*
|
||||
* @return
|
||||
* @throws IOException
|
||||
*/
|
||||
private byte[] readTestFile(String filename) throws IOException {
|
||||
// Load the file from the resources folder
|
||||
ClassLoader classLoader = getClass().getClassLoader();
|
||||
InputStream inputStream = classLoader.getResourceAsStream(filename);
|
||||
byte[] data = inputStream.readAllBytes();
|
||||
inputStream.close();
|
||||
return data;
|
||||
}
|
||||
/**
|
||||
* Hilfsmethode zum einlesen einer xml test datei
|
||||
*
|
||||
* @return
|
||||
* @throws IOException
|
||||
*/
|
||||
private byte[] readTestFile(String filename) throws IOException {
|
||||
// Load the file from the resources folder
|
||||
ClassLoader classLoader = getClass().getClassLoader();
|
||||
InputStream inputStream = classLoader.getResourceAsStream(filename);
|
||||
byte[] data = inputStream.readAllBytes();
|
||||
inputStream.close();
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,240 +33,218 @@ import jakarta.json.bind.JsonbBuilder;
|
|||
@Disabled
|
||||
public class TestUpdateTokens {
|
||||
|
||||
final static String ENCODING = "UTF-8";
|
||||
final static String ENCODING = "UTF-8";
|
||||
|
||||
private static Logger logger = Logger.getLogger(TestUpdateTokens.class.getName());
|
||||
private static Logger logger = Logger.getLogger(TestUpdateTokens.class.getName());
|
||||
|
||||
private HttpClient httpClient;
|
||||
private Jsonb jsonb;
|
||||
private HttpClient httpClient;
|
||||
private Jsonb jsonb;
|
||||
|
||||
private String redirectURI = "https://alexander-logistics-dwc.office-workflow.de/api/zoho/grant";
|
||||
private String redirectURI = "https://alexander-logistics-dwc.office-workflow.de/api/zoho/grant";
|
||||
|
||||
private String clientID = "1000.GR5FTPZYB06HEWSFSSX4DJU3OBD4EJ";
|
||||
private String clientSecret = "3f3e74c5212bbc924a7ebf77f887c6296db1106c47";
|
||||
private String clientID = "1000.GR5FTPZYB06HEWSFSSX4DJU3OBD4EJ";
|
||||
private String clientSecret = "3f3e74c5212bbc924a7ebf77f887c6296db1106c47";
|
||||
|
||||
private String code = null;
|
||||
private String accessToken = null;
|
||||
private String refreshToken = null;
|
||||
private String code = null;
|
||||
private String accessToken = null;
|
||||
private String refreshToken = null;
|
||||
|
||||
@BeforeEach
|
||||
public void setup() throws PluginException, ModelException {
|
||||
logger.info("setup test environment ...");
|
||||
this.httpClient = HttpClient.newBuilder()
|
||||
.connectTimeout(Duration.ofSeconds(10))
|
||||
.build();
|
||||
this.jsonb = JsonbBuilder.create();
|
||||
}
|
||||
@BeforeEach
|
||||
public void setup() throws PluginException, ModelException {
|
||||
logger.info("setup test environment ...");
|
||||
this.httpClient = HttpClient.newBuilder().connectTimeout(Duration.ofSeconds(10)).build();
|
||||
this.jsonb = JsonbBuilder.create();
|
||||
}
|
||||
|
||||
/**
|
||||
* Testet den Vorgang einen Access und Refresh Token zu generieren
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
@Test
|
||||
public void testUpdateTokens() throws IOException {
|
||||
/**
|
||||
* Testet den Vorgang einen Access und Refresh Token zu generieren
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
@Test
|
||||
public void testUpdateTokens() throws IOException {
|
||||
|
||||
logger.info("├── update Zoho tokens");
|
||||
refreshToken = null;
|
||||
accessToken = null;
|
||||
code = "1000.48bd85a3965cf724f4691757cfd8d93b.8ae5e3ee7d70f90d307da4d289a9b067";
|
||||
try {
|
||||
logger.info("├── update Zoho tokens");
|
||||
refreshToken = null;
|
||||
accessToken = null;
|
||||
code = "1000.48bd85a3965cf724f4691757cfd8d93b.8ae5e3ee7d70f90d307da4d289a9b067";
|
||||
try {
|
||||
|
||||
String requestUrl = "https://accounts.zoho.eu/oauth/v2/token" +
|
||||
"?code=" + URLEncoder.encode(code, StandardCharsets.UTF_8) +
|
||||
"&client_id=" + URLEncoder.encode(clientID, StandardCharsets.UTF_8) +
|
||||
"&client_secret=" + URLEncoder.encode(clientSecret, StandardCharsets.UTF_8) +
|
||||
"&redirect_uri=" + URLEncoder.encode(redirectURI, StandardCharsets.UTF_8) +
|
||||
"&grant_type=authorization_code";
|
||||
String requestUrl = "https://accounts.zoho.eu/oauth/v2/token" + "?code="
|
||||
+ URLEncoder.encode(code, StandardCharsets.UTF_8) + "&client_id="
|
||||
+ URLEncoder.encode(clientID, StandardCharsets.UTF_8) + "&client_secret="
|
||||
+ URLEncoder.encode(clientSecret, StandardCharsets.UTF_8) + "&redirect_uri="
|
||||
+ URLEncoder.encode(redirectURI, StandardCharsets.UTF_8) + "&grant_type=authorization_code";
|
||||
|
||||
logger.info("│ ├── Request URI=" + requestUrl);
|
||||
logger.info("│ ├── Request URI=" + requestUrl);
|
||||
|
||||
HttpRequest request = HttpRequest.newBuilder()
|
||||
.uri(URI.create(requestUrl))
|
||||
.header("Content-Type", "application/x-www-form-urlencoded")
|
||||
.POST(HttpRequest.BodyPublishers.noBody()) // Wichtig: Kein Body!
|
||||
.build();
|
||||
HttpRequest request = HttpRequest.newBuilder().uri(URI.create(requestUrl))
|
||||
.header("Content-Type", "application/x-www-form-urlencoded")
|
||||
.POST(HttpRequest.BodyPublishers.noBody()) // Wichtig: Kein Body!
|
||||
.build();
|
||||
|
||||
HttpResponse<String> response;
|
||||
HttpResponse<String> response;
|
||||
|
||||
response = httpClient.send(request,
|
||||
HttpResponse.BodyHandlers.ofString());
|
||||
response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
|
||||
|
||||
logger.info("│ ├── Response statusCode=" + response.statusCode());
|
||||
if (response.statusCode() == 200) {
|
||||
logger.info("│ ├── Response statusCode=" + response.statusCode());
|
||||
if (response.statusCode() == 200) {
|
||||
|
||||
// 1. Response-Logging für Debugging
|
||||
logger.info("│ ├── Response Body=" + response.body());
|
||||
// 1. Response-Logging für Debugging
|
||||
logger.info("│ ├── Response Body=" + response.body());
|
||||
|
||||
assertNotNull(response.body());
|
||||
assertFalse(response.body().contains("error"));
|
||||
assertNotNull(response.body());
|
||||
assertFalse(response.body().contains("error"));
|
||||
|
||||
TokenResponse tokenResponse = jsonb.fromJson(response.body(),
|
||||
TokenResponse.class);
|
||||
TokenResponse tokenResponse = jsonb.fromJson(response.body(), TokenResponse.class);
|
||||
|
||||
accessToken = tokenResponse.getAccess_token();
|
||||
assertNotNull(accessToken);
|
||||
logger.info("│ ├── accessToken=" + accessToken);
|
||||
refreshToken = tokenResponse.getRefresh_token();
|
||||
logger.info("│ ├── refreshToken=" + refreshToken);
|
||||
logger.info("│ ├── expires_in=" + tokenResponse.getExpires_in());
|
||||
} else {
|
||||
throw new RuntimeException("Failed to get tokens: " +
|
||||
response.statusCode() + " - " + response.body());
|
||||
}
|
||||
accessToken = tokenResponse.getAccess_token();
|
||||
assertNotNull(accessToken);
|
||||
logger.info("│ ├── accessToken=" + accessToken);
|
||||
refreshToken = tokenResponse.getRefresh_token();
|
||||
logger.info("│ ├── refreshToken=" + refreshToken);
|
||||
logger.info("│ ├── expires_in=" + tokenResponse.getExpires_in());
|
||||
} else {
|
||||
throw new RuntimeException("Failed to get tokens: " + response.statusCode() + " - " + response.body());
|
||||
}
|
||||
|
||||
} catch (IOException | InterruptedException e) {
|
||||
throw new InvalidAccessException("Unable to resolve access tokens: " + e.getMessage());
|
||||
}
|
||||
} catch (IOException | InterruptedException e) {
|
||||
throw new InvalidAccessException("Unable to resolve access tokens: " + e.getMessage());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Testet den Refresh Token
|
||||
*
|
||||
* POST:
|
||||
* {Accounts_URL}/oauth/v2/token?refresh_token={refresh_token}&client_id={client_id}&client_secret={client_secret}&grant_type=refresh_token
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
@Test
|
||||
public void testRefreshAccessToken() throws IOException {
|
||||
/**
|
||||
* Testet den Refresh Token
|
||||
*
|
||||
* POST:
|
||||
* {Accounts_URL}/oauth/v2/token?refresh_token={refresh_token}&client_id={client_id}&client_secret={client_secret}&grant_type=refresh_token
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
@Test
|
||||
public void testRefreshAccessToken() throws IOException {
|
||||
|
||||
logger.info("├── refresh Zoho access token");
|
||||
refreshToken = "1000.cf458816e97f848df8134ce1c7e923a1.5b9dbdee317e35d7f0c619e7648d55ff";
|
||||
try {
|
||||
logger.info("├── refresh Zoho access token");
|
||||
refreshToken = "1000.cf458816e97f848df8134ce1c7e923a1.5b9dbdee317e35d7f0c619e7648d55ff";
|
||||
try {
|
||||
|
||||
String requestUrl = "https://accounts.zoho.eu/oauth/v2/token" +
|
||||
"?refresh_token=" + URLEncoder.encode(refreshToken, StandardCharsets.UTF_8) +
|
||||
"&client_id=" + URLEncoder.encode(clientID, StandardCharsets.UTF_8) +
|
||||
"&client_secret=" + URLEncoder.encode(clientSecret, StandardCharsets.UTF_8) +
|
||||
"&grant_type=refresh_token";
|
||||
String requestUrl = "https://accounts.zoho.eu/oauth/v2/token" + "?refresh_token="
|
||||
+ URLEncoder.encode(refreshToken, StandardCharsets.UTF_8) + "&client_id="
|
||||
+ URLEncoder.encode(clientID, StandardCharsets.UTF_8) + "&client_secret="
|
||||
+ URLEncoder.encode(clientSecret, StandardCharsets.UTF_8) + "&grant_type=refresh_token";
|
||||
|
||||
logger.info("│ ├── Request URI=" + requestUrl);
|
||||
logger.info("│ ├── Request URI=" + requestUrl);
|
||||
|
||||
HttpRequest request = HttpRequest.newBuilder()
|
||||
.uri(URI.create(requestUrl))
|
||||
.header("Content-Type", "application/x-www-form-urlencoded")
|
||||
.POST(HttpRequest.BodyPublishers.noBody()) // Wichtig: Kein Body!
|
||||
.build();
|
||||
HttpRequest request = HttpRequest.newBuilder().uri(URI.create(requestUrl))
|
||||
.header("Content-Type", "application/x-www-form-urlencoded")
|
||||
.POST(HttpRequest.BodyPublishers.noBody()) // Wichtig: Kein Body!
|
||||
.build();
|
||||
|
||||
HttpResponse<String> response;
|
||||
HttpResponse<String> response;
|
||||
|
||||
response = httpClient.send(request,
|
||||
HttpResponse.BodyHandlers.ofString());
|
||||
response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
|
||||
|
||||
logger.info("│ ├── Response statusCode=" + response.statusCode());
|
||||
if (response.statusCode() == 200) {
|
||||
logger.info("│ ├── Response statusCode=" + response.statusCode());
|
||||
if (response.statusCode() == 200) {
|
||||
|
||||
// 1. Response-Logging für Debugging
|
||||
logger.info("│ ├── Response Body=" + response.body());
|
||||
// 1. Response-Logging für Debugging
|
||||
logger.info("│ ├── Response Body=" + response.body());
|
||||
|
||||
TokenResponse tokenResponse = jsonb.fromJson(response.body(),
|
||||
TokenResponse.class);
|
||||
TokenResponse tokenResponse = jsonb.fromJson(response.body(), TokenResponse.class);
|
||||
|
||||
String accessToken = tokenResponse.getAccess_token();
|
||||
logger.info("│ ├── accessToken=" + accessToken);
|
||||
logger.info("│ ├── expires_in=" + tokenResponse.getExpires_in());
|
||||
} else {
|
||||
throw new RuntimeException("Failed to get tokens: " +
|
||||
response.statusCode() + " - " + response.body());
|
||||
}
|
||||
String accessToken = tokenResponse.getAccess_token();
|
||||
logger.info("│ ├── accessToken=" + accessToken);
|
||||
logger.info("│ ├── expires_in=" + tokenResponse.getExpires_in());
|
||||
} else {
|
||||
throw new RuntimeException("Failed to get tokens: " + response.statusCode() + " - " + response.body());
|
||||
}
|
||||
|
||||
} catch (IOException | InterruptedException e) {
|
||||
throw new InvalidAccessException("Unable to resolve access tokens: " + e.getMessage());
|
||||
}
|
||||
} catch (IOException | InterruptedException e) {
|
||||
throw new InvalidAccessException("Unable to resolve access tokens: " + e.getMessage());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Testet den eigentlichen API Zugriff mit Hilfe des zuvor generieren Access
|
||||
* Token
|
||||
*
|
||||
* GET: https://{zohoapis_domain}/writer/api/v1/documents
|
||||
*
|
||||
* @see https://www.zoho.com/books/api/v3/introduction/#overview
|
||||
* @throws IOException
|
||||
*/
|
||||
@Test
|
||||
public void testGetOrganizations() throws IOException {
|
||||
/**
|
||||
* Testet den eigentlichen API Zugriff mit Hilfe des zuvor generieren Access
|
||||
* Token
|
||||
*
|
||||
* GET: https://{zohoapis_domain}/writer/api/v1/documents
|
||||
*
|
||||
* @see https://www.zoho.com/books/api/v3/introduction/#overview
|
||||
* @throws IOException
|
||||
*/
|
||||
@Test
|
||||
public void testGetOrganizations() throws IOException {
|
||||
|
||||
logger.info("├── get Zoho organizations");
|
||||
accessToken = "1000.21912dc6af0906707f51d336fd98ab61.eb153952d0d86a828fcb7e18426c2c1a";
|
||||
try {
|
||||
logger.info("├── get Zoho organizations");
|
||||
accessToken = "1000.21912dc6af0906707f51d336fd98ab61.eb153952d0d86a828fcb7e18426c2c1a";
|
||||
try {
|
||||
|
||||
String url = "https://www.zohoapis.eu/books/v3/organizations";
|
||||
String url = "https://www.zohoapis.eu/books/v3/organizations";
|
||||
|
||||
HttpRequest request = HttpRequest.newBuilder()
|
||||
.uri(URI.create(url))
|
||||
.GET()
|
||||
.header("Authorization", "Zoho-oauthtoken " + accessToken)
|
||||
.build();
|
||||
HttpRequest request = HttpRequest.newBuilder().uri(URI.create(url)).GET()
|
||||
.header("Authorization", "Zoho-oauthtoken " + accessToken).build();
|
||||
|
||||
HttpResponse<String> response = httpClient.send(
|
||||
request,
|
||||
HttpResponse.BodyHandlers.ofString());
|
||||
HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
|
||||
|
||||
logger.info("│ ├── Response statusCode=" + response.statusCode());
|
||||
logger.info("│ ├── Response statusCode=" + response.statusCode());
|
||||
|
||||
// 1. Response-Logging für Debugging
|
||||
logger.info("│ ├── Response Body=" + response.body());
|
||||
// 1. Response-Logging für Debugging
|
||||
logger.info("│ ├── Response Body=" + response.body());
|
||||
|
||||
if (response.statusCode() >= 300) {
|
||||
if (response.statusCode() >= 300) {
|
||||
|
||||
throw new RuntimeException("API request failed with status code: " + response.statusCode());
|
||||
}
|
||||
throw new RuntimeException("API request failed with status code: " + response.statusCode());
|
||||
}
|
||||
|
||||
} catch (IOException | InterruptedException e) {
|
||||
throw new InvalidAccessException("Unable to resolve access tokens: " + e.getMessage());
|
||||
}
|
||||
} catch (IOException | InterruptedException e) {
|
||||
throw new InvalidAccessException("Unable to resolve access tokens: " + e.getMessage());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Testet den eigentlichen API Zugriff mit Hilfe des zuvor generieren Access
|
||||
* Token
|
||||
*
|
||||
*
|
||||
* curl --request GET \
|
||||
* --url 'https://www.zohoapis.com/books/v3/invoices?organization_id=10234695' \
|
||||
* --header 'Authorization: Zoho-oauthtoken
|
||||
* 1000.41d9xxxxxxxxxxxxxxxxxxxxxxxxc2d1.8fccxxxxxxxxxxxxxxxxxxxxxxxx125f'
|
||||
*
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
@Test
|
||||
public void testGetInvoices() throws IOException {
|
||||
/**
|
||||
* Testet den eigentlichen API Zugriff mit Hilfe des zuvor generieren Access
|
||||
* Token
|
||||
*
|
||||
*
|
||||
* curl --request GET \ --url
|
||||
* 'https://www.zohoapis.com/books/v3/invoices?organization_id=10234695' \
|
||||
* --header 'Authorization: Zoho-oauthtoken
|
||||
* 1000.41d9xxxxxxxxxxxxxxxxxxxxxxxxc2d1.8fccxxxxxxxxxxxxxxxxxxxxxxxx125f'
|
||||
*
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
@Test
|
||||
public void testGetInvoices() throws IOException {
|
||||
|
||||
logger.info("├── get Zoho documents");
|
||||
accessToken = "1000.21912dc6af0906707f51d336fd98ab61.eb153952d0d86a828fcb7e18426c2c1a";
|
||||
try {
|
||||
logger.info("├── get Zoho documents");
|
||||
accessToken = "1000.21912dc6af0906707f51d336fd98ab61.eb153952d0d86a828fcb7e18426c2c1a";
|
||||
try {
|
||||
|
||||
String url = "https://www.zohoapis.eu/books/v3/invoices?organization_id=20105697367";
|
||||
String url = "https://www.zohoapis.eu/books/v3/invoices?organization_id=20105697367";
|
||||
|
||||
HttpRequest request = HttpRequest.newBuilder()
|
||||
.uri(URI.create(url))
|
||||
.GET()
|
||||
.header("Authorization", "Zoho-oauthtoken " + accessToken)
|
||||
.build();
|
||||
HttpRequest request = HttpRequest.newBuilder().uri(URI.create(url)).GET()
|
||||
.header("Authorization", "Zoho-oauthtoken " + accessToken).build();
|
||||
|
||||
HttpResponse<String> response = httpClient.send(
|
||||
request,
|
||||
HttpResponse.BodyHandlers.ofString());
|
||||
HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
|
||||
|
||||
logger.info("│ ├── Response statusCode=" + response.statusCode());
|
||||
logger.info("│ ├── Response statusCode=" + response.statusCode());
|
||||
|
||||
// 1. Response-Logging für Debugging
|
||||
logger.info("│ ├── Response Body=" + response.body());
|
||||
// 1. Response-Logging für Debugging
|
||||
logger.info("│ ├── Response Body=" + response.body());
|
||||
|
||||
if (response.statusCode() >= 300) {
|
||||
if (response.statusCode() >= 300) {
|
||||
|
||||
throw new RuntimeException("API request failed with status code: " + response.statusCode());
|
||||
}
|
||||
throw new RuntimeException("API request failed with status code: " + response.statusCode());
|
||||
}
|
||||
|
||||
} catch (IOException | InterruptedException e) {
|
||||
throw new InvalidAccessException("Unable to resolve access tokens: " + e.getMessage());
|
||||
}
|
||||
} catch (IOException | InterruptedException e) {
|
||||
throw new InvalidAccessException("Unable to resolve access tokens: " + e.getMessage());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,97 +1,97 @@
|
|||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"invoices": [
|
||||
"code" : 0,
|
||||
"message" : "success",
|
||||
"invoices" : [
|
||||
{
|
||||
"ach_payment_initiated": false,
|
||||
"invoice_id": "777249000000055583",
|
||||
"zcrm_potential_id": "",
|
||||
"customer_id": "777249000000055569",
|
||||
"zcrm_potential_name": "",
|
||||
"customer_name": "Mr. Foo",
|
||||
"company_name": "",
|
||||
"status": "overdue",
|
||||
"invoice_number": "INV-000001",
|
||||
"reference_number": "23452345",
|
||||
"date": "2025-04-21",
|
||||
"due_date": "2025-04-21",
|
||||
"due_days": "Overdue by 3 days",
|
||||
"email": "ralph.soika@imixs.com",
|
||||
"project_name": "",
|
||||
"billing_address": {
|
||||
"address": "",
|
||||
"street2": "",
|
||||
"city": "",
|
||||
"state": "",
|
||||
"zipcode": "",
|
||||
"country": "",
|
||||
"phone": "",
|
||||
"fax": "",
|
||||
"attention": ""
|
||||
"ach_payment_initiated" : false,
|
||||
"invoice_id" : "777249000000055583",
|
||||
"zcrm_potential_id" : "",
|
||||
"customer_id" : "777249000000055569",
|
||||
"zcrm_potential_name" : "",
|
||||
"customer_name" : "Mr. Foo",
|
||||
"company_name" : "",
|
||||
"status" : "overdue",
|
||||
"invoice_number" : "INV-000001",
|
||||
"reference_number" : "23452345",
|
||||
"date" : "2025-04-21",
|
||||
"due_date" : "2025-04-21",
|
||||
"due_days" : "Overdue by 3 days",
|
||||
"email" : "ralph.soika@imixs.com",
|
||||
"project_name" : "",
|
||||
"billing_address" : {
|
||||
"address" : "",
|
||||
"street2" : "",
|
||||
"city" : "",
|
||||
"state" : "",
|
||||
"zipcode" : "",
|
||||
"country" : "",
|
||||
"phone" : "",
|
||||
"fax" : "",
|
||||
"attention" : ""
|
||||
},
|
||||
"shipping_address": {
|
||||
"address": "",
|
||||
"street2": "",
|
||||
"city": "",
|
||||
"state": "",
|
||||
"zipcode": "",
|
||||
"country": "",
|
||||
"phone": "",
|
||||
"fax": "",
|
||||
"attention": ""
|
||||
"shipping_address" : {
|
||||
"address" : "",
|
||||
"street2" : "",
|
||||
"city" : "",
|
||||
"state" : "",
|
||||
"zipcode" : "",
|
||||
"country" : "",
|
||||
"phone" : "",
|
||||
"fax" : "",
|
||||
"attention" : ""
|
||||
},
|
||||
"country": "",
|
||||
"phone": "",
|
||||
"created_by": "Ralph Soika",
|
||||
"total": 50.00,
|
||||
"balance": 50.00,
|
||||
"payment_expected_date": "",
|
||||
"custom_fields": [],
|
||||
"custom_field_hash": {},
|
||||
"tags": [],
|
||||
"salesperson_name": "",
|
||||
"shipping_charge": 0.00,
|
||||
"adjustment": 0.00,
|
||||
"created_time": "2025-04-21T13:36:26+0200",
|
||||
"last_modified_time": "2025-04-21T13:42:56+0200",
|
||||
"updated_time": "2025-04-21T13:42:56+0200",
|
||||
"is_viewed_by_client": false,
|
||||
"has_attachment": true,
|
||||
"client_viewed_time": "",
|
||||
"is_viewed_in_mail": false,
|
||||
"is_emailed": true,
|
||||
"mail_first_viewed_time": "",
|
||||
"mail_last_viewed_time": "",
|
||||
"is_correction_invoice": false,
|
||||
"color_code": "",
|
||||
"current_sub_status_id": "",
|
||||
"current_sub_status": "overdue",
|
||||
"currency_id": "777249000000000071",
|
||||
"schedule_time": "",
|
||||
"currency_code": "EUR",
|
||||
"currency_symbol": "€",
|
||||
"template_type": "standard",
|
||||
"invoice_url": "https://zohosecurepay.eu/books/imixs/secure?CInvoiceID=2-64277fbd3cd8bc86f8e581a3a7e1544618c191c094de1ae938827291b0828c92b5f796a1ec94bfb1fdcce7621ddf18bf61770563d9fd283207b7fa0e24d232a416b0b5e010c61cd7 ",
|
||||
"transaction_type": "renewal",
|
||||
"reminders_sent": 0,
|
||||
"last_reminder_sent_date": "",
|
||||
"last_payment_date": "",
|
||||
"template_id": "777249000000000103",
|
||||
"documents": "",
|
||||
"salesperson_id": "",
|
||||
"write_off_amount": 0.00,
|
||||
"exchange_rate": 1.00,
|
||||
"unprocessed_payment_amount": 0.00
|
||||
"country" : "",
|
||||
"phone" : "",
|
||||
"created_by" : "Ralph Soika",
|
||||
"total" : 50.0,
|
||||
"balance" : 50.0,
|
||||
"payment_expected_date" : "",
|
||||
"custom_fields" : [ ],
|
||||
"custom_field_hash" : { },
|
||||
"tags" : [ ],
|
||||
"salesperson_name" : "",
|
||||
"shipping_charge" : 0.0,
|
||||
"adjustment" : 0.0,
|
||||
"created_time" : "2025-04-21T13:36:26+0200",
|
||||
"last_modified_time" : "2025-04-21T13:42:56+0200",
|
||||
"updated_time" : "2025-04-21T13:42:56+0200",
|
||||
"is_viewed_by_client" : false,
|
||||
"has_attachment" : true,
|
||||
"client_viewed_time" : "",
|
||||
"is_viewed_in_mail" : false,
|
||||
"is_emailed" : true,
|
||||
"mail_first_viewed_time" : "",
|
||||
"mail_last_viewed_time" : "",
|
||||
"is_correction_invoice" : false,
|
||||
"color_code" : "",
|
||||
"current_sub_status_id" : "",
|
||||
"current_sub_status" : "overdue",
|
||||
"currency_id" : "777249000000000071",
|
||||
"schedule_time" : "",
|
||||
"currency_code" : "EUR",
|
||||
"currency_symbol" : "€",
|
||||
"template_type" : "standard",
|
||||
"invoice_url" : "https://zohosecurepay.eu/books/imixs/secure?CInvoiceID=2-64277fbd3cd8bc86f8e581a3a7e1544618c191c094de1ae938827291b0828c92b5f796a1ec94bfb1fdcce7621ddf18bf61770563d9fd283207b7fa0e24d232a416b0b5e010c61cd7 ",
|
||||
"transaction_type" : "renewal",
|
||||
"reminders_sent" : 0,
|
||||
"last_reminder_sent_date" : "",
|
||||
"last_payment_date" : "",
|
||||
"template_id" : "777249000000000103",
|
||||
"documents" : "",
|
||||
"salesperson_id" : "",
|
||||
"write_off_amount" : 0.0,
|
||||
"exchange_rate" : 1.0,
|
||||
"unprocessed_payment_amount" : 0.0
|
||||
}
|
||||
],
|
||||
"page_context": {
|
||||
"page": 1,
|
||||
"per_page": 200,
|
||||
"has_more_page": false,
|
||||
"report_name": "Invoices",
|
||||
"applied_filter": "Status.All",
|
||||
"custom_fields": [],
|
||||
"sort_column": "created_time",
|
||||
"sort_order": "D"
|
||||
"page_context" : {
|
||||
"page" : 1,
|
||||
"per_page" : 200,
|
||||
"has_more_page" : false,
|
||||
"report_name" : "Invoices",
|
||||
"applied_filter" : "Status.All",
|
||||
"custom_fields" : [ ],
|
||||
"sort_column" : "created_time",
|
||||
"sort_order" : "D"
|
||||
}
|
||||
}
|
||||
39
pom.xml
39
pom.xml
|
|
@ -128,8 +128,45 @@
|
|||
<encoding>${project.build.sourceEncoding}</encoding>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
|
||||
<!-- Imixs Code Formatter and Checkstyle -->
|
||||
<plugin>
|
||||
<groupId>net.revelc.code.formatter</groupId>
|
||||
<artifactId>formatter-maven-plugin</artifactId>
|
||||
<version>2.26.0</version>
|
||||
<configuration>
|
||||
<configFile>
|
||||
https://raw.githubusercontent.com/imixs/imixs-workflow/refs/heads/master/imixs-code-style.xml</configFile>
|
||||
<lineEnding>LF</lineEnding>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>validate</phase>
|
||||
<goals>
|
||||
<goal>format</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-checkstyle-plugin</artifactId>
|
||||
<version>3.3.0</version>
|
||||
<configuration>
|
||||
<configLocation>
|
||||
https://raw.githubusercontent.com/imixs/imixs-workflow/master/imixs-checkstyle-8.44.xml</configLocation>
|
||||
<failOnViolation>true</failOnViolation>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>verify</phase>
|
||||
<goals>
|
||||
<goal>check</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
<finalName>office-alexander-logistics</finalName>
|
||||
</build>
|
||||
<dependencyManagement>
|
||||
|
|
|
|||
|
|
@ -74,6 +74,7 @@
|
|||
<bpmn2:flowNodeRef>event_kT136g</bpmn2:flowNodeRef>
|
||||
<bpmn2:flowNodeRef>event_jkHxJA</bpmn2:flowNodeRef>
|
||||
<bpmn2:flowNodeRef>event_zzWQSA</bpmn2:flowNodeRef>
|
||||
<bpmn2:flowNodeRef>event_k4Ms1Q</bpmn2:flowNodeRef>
|
||||
</bpmn2:lane>
|
||||
</bpmn2:laneSet>
|
||||
<bpmn2:task id="task_ToMZaQ" imixs:processid="1000" name="Neuanlage">
|
||||
|
|
@ -155,6 +156,7 @@
|
|||
<bpmn2:outgoing>sequenceFlow_03b60w</bpmn2:outgoing>
|
||||
<bpmn2:incoming>sequenceFlow_u8PLGw</bpmn2:incoming>
|
||||
<bpmn2:incoming>sequenceFlow_ZTiO7w</bpmn2:incoming>
|
||||
<bpmn2:incoming>sequenceFlow_gIdPow</bpmn2:incoming>
|
||||
</bpmn2:task>
|
||||
<bpmn2:task id="task_B8Pi7A" imixs:processid="1800" name="Locked">
|
||||
<bpmn2:extensionElements>
|
||||
|
|
@ -719,7 +721,40 @@
|
|||
<bpmn2:sequenceFlow id="sequenceFlow_ZTiO7w" sourceRef="event_zzWQSA" targetRef="task_Q80A1Q">
|
||||
<bpmn2:documentation id="documentation_S2i1Tg"/>
|
||||
</bpmn2:sequenceFlow>
|
||||
<bpmn2:intermediateCatchEvent id="event_k4Ms1Q" imixs:activityid="30" name="Excel Export">
|
||||
<bpmn2:extensionElements>
|
||||
<imixs:item name="rtfresultlog" type="xs:string">
|
||||
<imixs:value><![CDATA[Analysis data archived and Excel report generated]]></imixs:value>
|
||||
</imixs:item>
|
||||
<imixs:item name="keypublicresult" type="xs:string">
|
||||
<imixs:value><![CDATA[1]]></imixs:value>
|
||||
</imixs:item>
|
||||
<imixs:item name="txtactivityresult" type="xs:string">
|
||||
<imixs:value><![CDATA[<soa name="excel-export">
|
||||
<textblock>SOA Template</textblock>
|
||||
<template>soa_template.xlsx</template>
|
||||
<target-name>soa_<itemvalue>dbtr.number</itemvalue>_<itemvalue format="yyyy-MM-dd">$lasteventdate</itemvalue>.xlsx</target-name>
|
||||
</soa>
|
||||
<poi-update name="findreplace">
|
||||
<find>F6</find>
|
||||
<replace><itemvalue format="dd.MM.yyyy">$lasteventdate</itemvalue></replace>
|
||||
<type>date</type>
|
||||
</poi-update>
|
||||
<poi-update name="findreplace">
|
||||
<find>A7</find>
|
||||
<replace><itemvalue>dbtr.name</itemvalue></replace>
|
||||
</poi-update>]]></imixs:value>
|
||||
</imixs:item>
|
||||
</bpmn2:extensionElements>
|
||||
<bpmn2:documentation id="documentation_r37NEQ"/>
|
||||
<bpmn2:signalEventDefinition id="signalEventDefinition_rRKGpw" signalRef="signal_1"/>
|
||||
<bpmn2:outgoing>sequenceFlow_gIdPow</bpmn2:outgoing>
|
||||
</bpmn2:intermediateCatchEvent>
|
||||
<bpmn2:sequenceFlow id="sequenceFlow_gIdPow" sourceRef="event_k4Ms1Q" targetRef="task_Q80A1Q">
|
||||
<bpmn2:documentation id="documentation_q0cGQQ"/>
|
||||
</bpmn2:sequenceFlow>
|
||||
</bpmn2:process>
|
||||
<bpmn2:signal id="signal_1" name="com.alexanderlogistics.AGLAnalyticExcelAdapterDebitor"/>
|
||||
<bpmndi:BPMNDiagram id="BPMNDiagram_1" name="OpenBPMN Diagram">
|
||||
<bpmndi:BPMNPlane bpmnElement="collaboration_1" id="BPMNPlane_1">
|
||||
<bpmndi:BPMNShape bpmnElement="event_WmkBvw" id="BPMNShape_heefeQ">
|
||||
|
|
@ -1070,6 +1105,18 @@
|
|||
<di:waypoint x="714.0" y="465.0"/>
|
||||
<di:waypoint x="690.0" y="465.0"/>
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNShape bpmnElement="event_k4Ms1Q" id="BPMNShape_m0PeLw">
|
||||
<dc:Bounds height="36.0" width="36.0" x="827.0" y="357.0"/>
|
||||
<bpmndi:BPMNLabel id="BPMNLabel_fOaAtQ">
|
||||
<dc:Bounds height="20.0" width="100.0" x="795.0" y="396.0"/>
|
||||
</bpmndi:BPMNLabel>
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNEdge bpmnElement="sequenceFlow_gIdPow" id="BPMNEdge_QW8gQQ" sourceElement="BPMNShape_m0PeLw" targetElement="BPMNShape_7JA0nw">
|
||||
<di:waypoint x="827.0" y="375.0"/>
|
||||
<di:waypoint x="759.0" y="375.0"/>
|
||||
<di:waypoint x="759.0" y="465.0"/>
|
||||
<di:waypoint x="690.0" y="465.0"/>
|
||||
</bpmndi:BPMNEdge>
|
||||
</bpmndi:BPMNPlane>
|
||||
</bpmndi:BPMNDiagram>
|
||||
</bpmn2:definitions>
|
||||
|
|
|
|||
Loading…
Reference in a new issue