Compare commits
393 commits
office-ale
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 97a6e86a11 | |||
| f2bd7210e6 | |||
| 3c5e5b0546 | |||
| f06adc290c | |||
| 6721c2de9b | |||
| 2d3f98c15c | |||
| cfe1edb294 | |||
| f96d1af5e7 | |||
| 8309be5b39 | |||
| e85840695c | |||
| b6782448f9 | |||
| f942231066 | |||
| 99e138e685 | |||
| 44df91da9d | |||
| 8afb45271f | |||
| 7bca17dcca | |||
| fe4ca105df | |||
| 202fe2f3a0 | |||
| 3d322152e5 | |||
| 01e0e89e14 | |||
| e14af8449f | |||
| b8d0660526 | |||
| aeba05cc19 | |||
| 020498eee7 | |||
| 6a66fd1852 | |||
| 0a459e4b48 | |||
| 49c8ea0db9 | |||
| bd0500beef | |||
| b6e56958ec | |||
| 3f15b3a11b | |||
| f758c4a6ac | |||
| 0d9c9d8615 | |||
| 2b997da394 | |||
| 092aa40ceb | |||
| 8d9de4a16a | |||
| 1086466822 | |||
| a3df1a0a77 | |||
| 68acd25778 | |||
| 4e24e6e7b4 | |||
| 53703cdf9b | |||
| 394297b31c | |||
| 6a22dc29af | |||
| 38b60d7621 | |||
| 944d72b2cf | |||
| f6fb26dcf0 | |||
| 4203572a8f | |||
| 049bf8fea9 | |||
| 69456a28a0 | |||
| 111527b407 | |||
| ba40d05c9d | |||
| 190aa023c0 | |||
| 907455fe9b | |||
| 99dd910520 | |||
| be2f8c08ac | |||
| 26114ae35c | |||
| 97935680bf | |||
| 5491c04da4 | |||
| a272c8bdb4 | |||
| f72ef5cce6 | |||
| 5b4401bb82 | |||
| 6afd6856c2 | |||
| c15efc106c | |||
| a65ae59950 | |||
| 1d91e7f809 | |||
| 0e86783324 | |||
| 7d426a0dab | |||
| 6f76b367e7 | |||
| edacbbdd6d | |||
| 04acdb4ff3 | |||
| f8c13c5b2b | |||
| 47fc7e151e | |||
| ae11393c8c | |||
| 9884a3cd00 | |||
| d11099e8a3 | |||
| 6bee49b917 | |||
| 3ebd619df4 | |||
| d7619a7c21 | |||
| 4894d11f83 | |||
| 9a3e6146ea | |||
| 28b17e957f | |||
| 2bfa7cd7e1 | |||
| d7c9682bfd | |||
| 676310ae38 | |||
| 1d7fb83710 | |||
| 1a614564a8 | |||
| fc69af8bd5 | |||
| 38b755d5c1 | |||
| d59f9f3718 | |||
| dd96aa84d0 | |||
| e2c1d9a47e | |||
| cdf6d36f8b | |||
| f90afb959a | |||
| 851519dbbd | |||
| 5f4de3e432 | |||
| 82b3771fc8 | |||
| 5b445adee0 | |||
| b3c935132b | |||
| 600f6980bd | |||
| 15b8a54360 | |||
| 5f20bc458b | |||
| e09e25766a | |||
| 78739d3517 | |||
| fecb9e8813 | |||
| 96477feb74 | |||
| a1621420e2 | |||
| e4347046b4 | |||
| 3e1e7ccef0 | |||
| 459f7808cf | |||
| 9024ee2e38 | |||
| 082f0f609d | |||
| 1ee7c82805 | |||
| 909c3f195d | |||
| dd70091057 | |||
| 6b6957e1ab | |||
| 6e65ed4468 | |||
| cca28e9414 | |||
| 616765aa0a | |||
| 53b5f69329 | |||
| c232841ed3 | |||
| f61c7feca5 | |||
| fb3f086192 | |||
| b986f8615a | |||
| 7b421e0a37 | |||
| 1897377eb3 | |||
| 1f2d3b4cd5 | |||
| 6c4e72fe82 | |||
| 1bce7db64e | |||
| cfd974ecd2 | |||
| 6d7d47772c | |||
| 1b31712ac7 | |||
| bb058306f0 | |||
| 11b28ef9c3 | |||
| 26b08eb507 | |||
| 5ead936783 | |||
| 9f6d86d328 | |||
| 7fe009c23c | |||
| e76a8dc668 | |||
| 278880a6b0 | |||
| 5e4698025a | |||
| ed3444890d | |||
| 3e96df6e9c | |||
| e322acbd0e | |||
| af03c22dd7 | |||
| 6f15bbd21f | |||
| 7ae22da078 | |||
| 62435591d7 | |||
| e50a923347 | |||
| ca630aec03 | |||
| 5aa9fba8f8 | |||
| 54fe24e8c7 | |||
| 9fa5217d59 | |||
| 98d46de37c | |||
| c7ec908f4e | |||
| 988a831200 | |||
| 15e37ff2c8 | |||
| 6c1fa2c094 | |||
| d7f2b0bc92 | |||
| 51730e3d39 | |||
| 513782b303 | |||
| 75ef221181 | |||
| 8b463d3acb | |||
| 3764a265f9 | |||
| 3df24a7bd8 | |||
| f986a9d1ba | |||
| 5d1434fa7d | |||
| d1b816d1e6 | |||
| 7e1c0e91b8 | |||
| 5a4ac8a1e6 | |||
| fef55be481 | |||
| 5e483d5517 | |||
| 863dc67603 | |||
| 4143468ea0 | |||
| d4dc59b60b | |||
| 106515d25a | |||
| 6c67a81b6f | |||
| 0ef5fff446 | |||
| e0e5bbd8f3 | |||
| c6205b9c43 | |||
| c14e1e41b3 | |||
| fbf5bf2962 | |||
| fe23ba4050 | |||
| 734fe57d09 | |||
| 3a08e83581 | |||
| 5c16f68a43 | |||
| 81db869ccd | |||
| 6f9727c4d1 | |||
| 98ad08b052 | |||
| 52ac50f204 | |||
| 6620f7ce7c | |||
| 4ae91b527c | |||
| e1145e9348 | |||
| 79504dc80a | |||
| c6e73ac111 | |||
| a44424fcf1 | |||
| b666ffdbb7 | |||
| c2c3b6e798 | |||
| 4fb35d252b | |||
| 58745c32da | |||
| 15ce9fc9bb | |||
| fce3559463 | |||
| 03e0ac275f | |||
| 7f437904c9 | |||
| 686a112c22 | |||
| c9b25c9f5e | |||
| c0073dadd7 | |||
| 550323b72f | |||
| ea5bc8d1e5 | |||
| 8fcdaa3b69 | |||
| 0d73f0f7e0 | |||
| 18ffca90fb | |||
| 22d23226e4 | |||
| 73dd3c37a5 | |||
| 291b9d4a0a | |||
| db815dea23 | |||
| 8ddf44515e | |||
| 29d584d12f | |||
| bf1d9fd37b | |||
| a152fdd461 | |||
| 9cefd51ccb | |||
| 22c1c8793b | |||
| 2725b08cf7 | |||
| 52412a7678 | |||
| 6545f76f43 | |||
| 259373053f | |||
| fd668439c8 | |||
| 60d2d90114 | |||
| 67affba4d7 | |||
| 1e698fc8bf | |||
| 04eb6ddc18 | |||
| c9c9f69bed | |||
| eb6d3d2c00 | |||
| 2bc72c0940 | |||
| 8796759bb2 | |||
| caae20029e | |||
| 049df51b89 | |||
| e81be7996e | |||
| 2cbd5d66bc | |||
| 87ef39ece4 | |||
| 22c2791fa1 | |||
| e350ece8f3 | |||
| ffb0942737 | |||
| cce4b9a6e4 | |||
| 7b283e5b03 | |||
| 7204fc43c8 | |||
| fe65ae16a4 | |||
| 9de6a9fe23 | |||
| 177d75c13a | |||
| 5105d20783 | |||
| cc7e081c78 | |||
| d4f1bd318e | |||
| 8d236df375 | |||
| f294d64e8c | |||
| ea5a43e259 | |||
| 87cd3204c2 | |||
| 93c902ab4a | |||
| f695bc63a3 | |||
| 9556c419ca | |||
| 830394c7a3 | |||
| 001787e018 | |||
| 5c7cdde0fe | |||
| 981ccfc41b | |||
| 73731c89ea | |||
| 1a82da08d5 | |||
| d4d57797a3 | |||
| 5c7f7746d6 | |||
| 7535fa975e | |||
| b8879fc300 | |||
| e987a30053 | |||
| 65a1d4f2b7 | |||
| 584d59cfbe | |||
| 6cfea74397 | |||
| 303448d766 | |||
| d948742963 | |||
| 174b230509 | |||
| 372c7887fb | |||
| db478a5b4e | |||
| c2e4df0379 | |||
| 6cd3d5d258 | |||
| 919ad796de | |||
| c1f123215a | |||
| d47518224f | |||
| 4b9da4d98a | |||
| 0f7627419a | |||
| be064fb965 | |||
| f30cc8e8fe | |||
| 72a10ddcf5 | |||
| 1ea9564e55 | |||
| 9511d7fd95 | |||
| 3a103e9a1e | |||
| 112de7e8ad | |||
| 81fb527029 | |||
| aa5f000715 | |||
| ac4127e353 | |||
| 5aa7113d7f | |||
| 595e77fc63 | |||
| 27698becf5 | |||
| 7ba7967a92 | |||
| bdf3c8ba01 | |||
| d6ba785002 | |||
| 633363aa3c | |||
| c1c1d8b520 | |||
| cbe256a962 | |||
| 27f7b2b4f6 | |||
| 39099700fe | |||
| c47a6ed4ac | |||
| a756997247 | |||
| 628d10bae9 | |||
| 703995f959 | |||
| f623ea33ff | |||
| 2c6636bfbc | |||
| d99aad1322 | |||
| 3b7742ee07 | |||
| b9084965e0 | |||
| 1db1cd756c | |||
| 84a2e87eb6 | |||
| 93263280dc | |||
| 02f24df8a3 | |||
| 042fd7bdcf | |||
| f52e76374e | |||
| 56a60a990d | |||
| 0d5aa41e4d | |||
| 0b20c10c0a | |||
| 47d90c8655 | |||
| 5da7fc866f | |||
| 216589537c | |||
| 2aa5501b03 | |||
| 647f2e9af8 | |||
| 09572730e5 | |||
| f8df34586c | |||
| bcbb60fc20 | |||
| 15fe8e14e6 | |||
| d33fed4707 | |||
| 021e7cec34 | |||
| 632f674bfa | |||
| 1acd22f334 | |||
| 90d624d585 | |||
| ccc4584f91 | |||
| 4f0f4aefd8 | |||
| dfa089ba31 | |||
| 90166229bd | |||
| 017ef6a752 | |||
| 51ccd40f18 | |||
| cde1b2a2eb | |||
| 302e4e5b08 | |||
| 73cd9a28f7 | |||
| 9a932d0f54 | |||
| d2a2d506d2 | |||
| 66b674afaf | |||
| eb6808da78 | |||
| 50f44b851f | |||
| 1cd4980ce0 | |||
| 831ace7b42 | |||
| 74ef6e17a7 | |||
| 8db4320348 | |||
| 8fad186e39 | |||
| 01cec74af6 | |||
| 947bed1ede | |||
| 07ed3a30d0 | |||
| 2fe0f4ef69 | |||
| 2e61ef39e3 | |||
| 7bdf108532 | |||
| f4b783f8af | |||
| 32d731fadd | |||
| ff832f327f | |||
| 3b5bb12c32 | |||
| a715e00a1d | |||
| 61a7fa8399 | |||
| 633bcdd3d6 | |||
| d5d4b21434 | |||
| 03d4fe241a | |||
| 11ccddb529 | |||
| a18a365898 | |||
| c34ed64445 | |||
| 6c538355d7 | |||
| 8e6f97ffa4 | |||
| ca2e72bc37 | |||
| 20c3410489 | |||
| 2e66c68e40 | |||
| aabb7ab04d | |||
| 2a12ecaf3c | |||
| 8790248d88 | |||
| 1bb65234fa | |||
| 47b925e71b | |||
| 3eecb7e90d | |||
| 4d2ce3527a | |||
| 566c32c94a | |||
| a1c3330cd3 | |||
| 8b22337548 | |||
| a6f4b68fba | |||
| 81549ab4e0 | |||
| 89865fcde1 | |||
| b7011a5cf8 | |||
| 1762c5c878 |
779 changed files with 560152 additions and 429910 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -13,9 +13,11 @@ target/
|
|||
.metadata/
|
||||
.project
|
||||
.classpath
|
||||
.env
|
||||
|
||||
# ignore docker deployments
|
||||
docker/deployments/
|
||||
docker/keys/imixs-llm.xml
|
||||
|
||||
# Sepa Report
|
||||
reports/sepa/result_sepa*
|
||||
|
|
|
|||
5
.vscode/settings.json
vendored
5
.vscode/settings.json
vendored
|
|
@ -8,8 +8,5 @@
|
|||
"editor.codeActionsOnSave": {
|
||||
"source.organizeImports": "explicit"
|
||||
},
|
||||
"java.checkstyle.version": "8.44",
|
||||
"java.checkstyle.autocheck": true,
|
||||
"java.checkstyle.configuration": "https://raw.githubusercontent.com/imixs/imixs-workflow/master/imixs-checkstyle-8.44.xml",
|
||||
"java.configuration.updateBuildConfiguration": "automatic"
|
||||
"java.format.settings.url": "https://raw.githubusercontent.com/imixs/imixs-workflow/refs/heads/master/imixs-code-style.xml"
|
||||
}
|
||||
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
|
||||
10
Dockerfile
10
Dockerfile
|
|
@ -1,9 +1,7 @@
|
|||
FROM imixs/imixs-office-workflow:5.0.3-SNAPSHOT
|
||||
|
||||
|
||||
# Setup debug configuration
|
||||
# COPY ./docker/configuration/standalone-debug.xml /opt/jboss/wildfly/standalone/configuration/
|
||||
FROM imixs/imixs-office-workflow:5.1.5-wildfly-29.0.1.Final-jdk17
|
||||
|
||||
# Deploy artefact
|
||||
RUN rm -r /opt/jboss/wildfly/standalone/deployments/*
|
||||
COPY ./*-app/target/*.war /opt/jboss/wildfly/standalone/deployments/
|
||||
# Deploy artefact
|
||||
COPY ./target/*.war /opt/jboss/wildfly/standalone/deployments/
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,8 @@
|
|||
FROM imixs/imixs-office-workflow:5.0.3-SNAPSHOT
|
||||
FROM imixs/imixs-office-workflow:5.1.5-wildfly-29.0.1.Final-jdk17
|
||||
|
||||
# Deploy artefact
|
||||
RUN rm -r /opt/jboss/wildfly/standalone/deployments/*
|
||||
COPY ./*-app/target/*.war /opt/jboss/wildfly/standalone/deployments/
|
||||
COPY ./target/*.war /opt/jboss/wildfly/standalone/deployments/
|
||||
|
||||
# Run in Debug Mode
|
||||
CMD ["/opt/jboss/wildfly/bin/standalone.sh", "-b", "0.0.0.0", "-bmanagement", "0.0.0.0", "--debug", "*:8787"]
|
||||
|
||||
|
|
|
|||
148
RELEASENOTES.md
148
RELEASENOTES.md
|
|
@ -1,8 +1,112 @@
|
|||
# Versionen
|
||||
|
||||
## 1.4.0 (Development)
|
||||
|
||||
- neuer AGLAIInvoiceAdapter
|
||||
der Adapter `com.alexanderlogistics.AGLAIInvoiceAdapter` muss künftig in das Import Event der Rechnungseingangs Modelle. Dieser Adapter Findet den Space und den Mandanten.
|
||||
|
||||
### 1.3.0 (Development - Office-Workflow 5.0.2 )
|
||||
Neue Modelle:
|
||||
|
||||
- Posteingang
|
||||
- posteingang-de-3.0
|
||||
- AMS
|
||||
- rechnungseingang-ams-1.1.0.bpmn
|
||||
|
||||
## 1.3.6 (Development)
|
||||
|
||||
**KSeF Produktiname II.**
|
||||
|
||||
Neues ksef.xml als Template einspielen
|
||||
Neue version deployen.
|
||||
|
||||
**KSeF Produktiname I.**
|
||||
|
||||
Wir bekommen von Majcie einen neuen Prod - Token für KSeF. Dieser muss in das Kubernetes Deployment file eintegragen werden. Auch der Enpunkt muss geändert werden!
|
||||
|
||||
- name: KSEF_API_NIP
|
||||
value: "9552521552"
|
||||
- name: KSEF_API_TOKEN
|
||||
value: "2025??????????????????2|nip-9552521552|f?????????????????????????????????????????"
|
||||
- name: KSEF_API_ENDPOINT
|
||||
value: "https://api.ksef.mf.gov.pl/v2"
|
||||
|
||||
Im Worklfow Modell 'rechnungsausgang' muss das das Partner Mail im Schritt 4200.10 aktiviert werden.
|
||||
jhendzel@alexander-logistics.com in CC
|
||||
ralph.soika@imixs.com in BCC
|
||||
Derzeit fehlen meistens die Mailadressen so dass vermutlich häufig keine Mails rausgehen.
|
||||
Im Dokument Import 'CARGOSOFT_INVOCIE_XML' muss die Task ID von 5001 auf 4000 geändert werden!!
|
||||
|
||||
## 1.3.5
|
||||
|
||||
- Verbesserter Cargosoft Export (Eingangsrechnungen)
|
||||
- Polen KSeF Schnittstelle
|
||||
- E-Rechnungs Adapter
|
||||
|
||||
## 1.3.4
|
||||
|
||||
- Finalisierung Business Partner Interface
|
||||
|- Neue Plugin Logik (Aktualisierung der BP Nummer und Aktivierung von BP Objekten falls diese archiviert waren)
|
||||
- Zoho Schnittstelle
|
||||
- Neues DataView und DataGroups Konzept implementiert
|
||||
|
||||
### Migration
|
||||
|
||||
- Encoding für CSV Import aus cargosoft muss auf `encoding=UTF-8` stehen!
|
||||
- Neues Businesspartner BPMN Modell einspielen
|
||||
- Lucene Index neu berechnene wegen 'partner.id'
|
||||
|
||||
#### Daten Synchronisation BUsiness Parnter
|
||||
|
||||
- Erstmal nach Dubletten suchen:
|
||||
- https://alexander-logistics-xxx.office-workflow.de/api/cargosoft/remove-dubletten?maxcount=5000
|
||||
ACHTUNG kann sehr lange laufen (1 Stunde)
|
||||
|
||||
- Jetzt die Daten syncen
|
||||
https://alexander-logistics-xxx.office-workflow.de/api/cargosoft/bp-sync?maxcount=25000
|
||||
ACHTUNG kann sehr sehr sehr!! lange laufen (3 Stunde)
|
||||
kann aber auch dann mehrfach aufgerufen werden so dass sich das alles zum guten wendet
|
||||
|
||||
#### Modelle Anpassen
|
||||
|
||||
in verschiedenen müssen die alten form parts `alexander/cdtreingabe` und `alexander/dbtreingabe` mit dem neuen `alexander/businesspartner_search` ausgetauscht werden.
|
||||
Der `BusinessPartnerController` bzw. das `InvoicePlugin` bzw. `InvoiceOutgoingPlugin` kümmert sich automatisch um die Migration
|
||||
|
||||
Betroffen sind:
|
||||
|
||||
- rechnungseingang-\*
|
||||
- rechnugnseingang-sachrechnung\*
|
||||
- rechnungsausgang-\*
|
||||
- zahlungseingang-\*
|
||||
- Analyse-debitor-\*
|
||||
|
||||
Mahnlauf
|
||||
|
||||
- dieser müsste so modelliert werden wie `rechnungsausgang-dwc-1.0.3` zu sehen ist!!!!!!
|
||||
|
||||
## 1.3.3
|
||||
|
||||
- Imixs-Archive 3.1.1. Compactor Service
|
||||
|
||||
Migration:
|
||||
|
||||
set ARCHIVE_SNAPSHOT_GRACE_PERIOD= 5
|
||||
set ARCHIVE_SNAPSHOT_COMPACTOR= enabled
|
||||
|
||||
## 1.3.2
|
||||
|
||||
- Posteingang Worklfow - timeout logic
|
||||
- added lucene client to docker image
|
||||
- added optional oidc profile
|
||||
|
||||
## 1.3.1
|
||||
|
||||
- Imixs-Office-Workflow 5.0.4
|
||||
- Mulit Currecy Feature für Ausgangsrechnungen
|
||||
- Neue Analyse Boards
|
||||
- Neue SOA
|
||||
- Neues Mahnwesen
|
||||
|
||||
## 1.3.0
|
||||
|
||||
- Migration auf Imixs-Office-Workflow 5.0.2
|
||||
- Upgrade Imixs-Workflow 6.7
|
||||
|
|
@ -27,15 +131,11 @@
|
|||
|
||||
3. Alle Workflow Modelle erneuern
|
||||
|
||||
|
||||
|
||||
|
||||
### 1.2.21 (Draft)
|
||||
## 1.2.21 (Draft)
|
||||
|
||||
- Beim XML Invoice Import wird nun auch die Sprache für das Mahnwesen ermittelt (fehlte)
|
||||
- Währungsunabhängigkeit
|
||||
|
||||
|
||||
**Migration**
|
||||
|
||||
1. Paramter Pflegen
|
||||
|
|
@ -49,28 +149,27 @@
|
|||
|
||||
3. Alle Workflow Modelle erneuern
|
||||
|
||||
### 1.2.20 (Development)
|
||||
## 1.2.20 (Development)
|
||||
|
||||
- Optimierung OP-Liste nach KW
|
||||
- Fix Fälligkeit in maske
|
||||
- Fix XML Schnittstelle Cargosoft Sammelgutschrift
|
||||
|
||||
### 1.2.19
|
||||
## 1.2.19
|
||||
|
||||
- Neue XML Invoice Schnittstelle
|
||||
- Mahnwesen englisch
|
||||
|
||||
|
||||
### 1.2.18
|
||||
## 1.2.18
|
||||
|
||||
- Fix in Archiv Suche CustomSearchController.java - requestscoped
|
||||
|
||||
### 1.2.17
|
||||
## 1.2.17
|
||||
|
||||
- neue Archive suche
|
||||
- invoice.exchangerate Input ersetzt nun . durch , und locale='de' damit der Wert richtig gespeichert wird!!
|
||||
|
||||
### 1.2.16
|
||||
## 1.2.16
|
||||
|
||||
- Upgrade Imixs-Archive auf 2.4.2 - verbesserter IMAP Import
|
||||
- Upgarde Imixs-Adapters 2.3.3-SNAPSHOT
|
||||
|
|
@ -83,10 +182,10 @@
|
|||
- sepa-export-manual-3.0.0
|
||||
- sepa-export-manual-pl-3.0.1
|
||||
|
||||
|
||||
**Achtung**: Kubernetes Deploymets müssen angepasst werden (siehe AGL Polen)
|
||||
|
||||
### 1.2.15
|
||||
## 1.2.15
|
||||
|
||||
- kleinere Layout Anpassungen in den Formualren und input Feldern (Positionstabelle, Sachbearbeiter Auswahl...)
|
||||
- invoice.exchangerate Input ersetzt nun , durch . damit der Wert richtig gespeichert wird.
|
||||
- Fix Cargosoft DATEV Import - Korektur des Rechnungsdatums / Jahr
|
||||
|
|
@ -94,32 +193,28 @@
|
|||
|
||||
https://alexander-logistics.office-workflow.de/api/cargosoft/fix/100
|
||||
|
||||
### 1.2.14
|
||||
## 1.2.14
|
||||
|
||||
- Internationalisierung
|
||||
|
||||
|
||||
### 1.2.13
|
||||
## 1.2.13
|
||||
|
||||
- Payment Statistik
|
||||
- Neue Indexfelder 'invoice.date' 'payment.date'
|
||||
|
||||
**WICHTIG:** Es muss nach dem Update einmal der Index neu berechnet werden.
|
||||
|
||||
### 1.2.12
|
||||
## 1.2.12
|
||||
|
||||
- Neue Debitoren/Kreditoren Verwaltung - Zusätzliche E-Mail
|
||||
Realisiert über neue Custom Feld 'textlist'
|
||||
- validierung e-mail erfolgt über Adapter und Workflow Rule
|
||||
|
||||
|
||||
|
||||
### 1.2.10
|
||||
## 1.2.10
|
||||
|
||||
Inkasso Workflow
|
||||
|
||||
|
||||
### 1.2.8
|
||||
## 1.2.8
|
||||
|
||||
Neue KI Version
|
||||
|
||||
|
|
@ -127,19 +222,18 @@
|
|||
|
||||
Zalungsavis für SEPA Rechnungen freigeschaltet
|
||||
|
||||
|
||||
### 1.2.7
|
||||
## 1.2.7
|
||||
|
||||
Erweiterte Kreditoren Verwaltung. Es können bis zu 4 IBAN/BIC Kombinationen pro Kreditor erfasst werden.
|
||||
|
||||
Wenn vom Benutezr bei der Rechnungserfassugn eine Kombination eingegeben wird die noch nicht gespeichert war,
|
||||
wird diese aufgenomen und die anderen rutschen nach unten.
|
||||
|
||||
### 1.2.6
|
||||
## 1.2.6
|
||||
|
||||
Übernahme von IBAN BIC aus kreditoren verwaltung
|
||||
|
||||
### 1.1.1
|
||||
## 1.1.1
|
||||
|
||||
- Cargosoft Splitbuchungen - Es können zu einer Rechnung mehrere Cargosoft Exporte erzeugt werden. Die Sub Rechnungsnummern stehen im Feld numsequencenumber_sub
|
||||
- Neue Modellversion rechnungseingnag-de-1.2.0 und posteingang-de-1.0.4
|
||||
|
|
|
|||
204
backup/README.md
Normal file
204
backup/README.md
Normal file
|
|
@ -0,0 +1,204 @@
|
|||
# Eigenes Backup-System (Backup-Mirror)
|
||||
## Architektur, Einrichtung und Disaster-Recovery-Konzept
|
||||
|
||||
---
|
||||
|
||||
## 1. Idee und Architektur
|
||||
|
||||
### 1.1 Ausgangslage
|
||||
|
||||
Imixs-Office-Workflow wird von uns als eine transaktionale, hochverfügbare
|
||||
Geschäftsprozessmanagement-Suite betrieben. Die Basis ist ein Open Source Kernel,
|
||||
der frei zugänglich ist ([https://github.com/imixs/](https://github.com/imixs/)).
|
||||
Unabhängig vom gewählten Betriebsmodell (SaaS, Public Cloud, Private Cloud, On
|
||||
Premise) sind und bleiben Sie Eigentümer Ihrer Geschäftsdaten. Über den
|
||||
Backup-Service haben Sie die Möglichkeit, jederzeit eigenständig auf eine
|
||||
vollständige Kopie Ihrer Daten zuzugreifen – unabhängig davon, wie und wo Ihre
|
||||
Instanz aktuell betrieben wird.
|
||||
|
||||
### 1.2 Architektur – Own your Data
|
||||
|
||||
Auch wenn wir den Betrieb Ihrer Instanz übernehmen, bedeutet das nicht, dass Sie
|
||||
von uns abhängig sind. Über den Backup-Mirror betreiben Sie bei sich einen eigenen,
|
||||
unabhängigen Backup-Dienst. Dieser Dienst wird von Ihnen selbst eingerichtet,
|
||||
verwaltet und überwacht und läuft vollständig autark – wir müssen ihn technisch
|
||||
weder kennen noch verwalten. Dadurch gilt:
|
||||
|
||||
> **Sie verfügen über eine eigenständige, vollständige Kopie Ihrer
|
||||
> Geschäftsdaten – unabhängig von unserer Infrastruktur. Mit dieser Kopie kann
|
||||
> Ihr System bei Bedarf komplett neu aufgebaut werden.**
|
||||
|
||||
Das ist ein bewusst einfaches und robustes Prinzip: Es kommt nicht darauf an, *wo*
|
||||
Ihre Daten zusätzlich liegen, sondern *wer* die Kontrolle über diesen zusätzlichen
|
||||
Sicherungsort hat. Nur wenn diese Kontrolle bei Ihnen liegt, sind Sie wirklich
|
||||
unabhängig.
|
||||
|
||||
### 1.3 Wie es funktioniert
|
||||
|
||||
Technisch basiert das Konzept auf dem Open-Source-Projekt
|
||||
[Imixs-Archive](https://github.com/imixs/imixs-archive), konkret auf dem Baustein
|
||||
*Imixs-Archive-Backup*. Der Ablauf im Überblick:
|
||||
|
||||
1. Bei jeder Änderung an einem Geschäftsvorgang erzeugt Ihre Workflow-Instanz
|
||||
automatisch einen unveränderlichen Snapshot (eine vollständige Kopie des
|
||||
Vorgangs inkl. aller angehängten Dokumente).
|
||||
2. Diese Snapshots werden über die REST-Schnittstelle Ihrer Workflow-Instanz
|
||||
bereitgestellt.
|
||||
3. Ein bei Ihnen installierter Backup-Dienst (siehe Abschnitt 2) ruft diese
|
||||
Snapshots eigenständig ab und speichert sie auf einem Speicherort Ihrer Wahl
|
||||
(z. B. eigener FTP-/Storage-Server).
|
||||
|
||||
Wichtig: Die Verbindung erfolgt **von Ihrem System zu unserer Workflow-Instanz**
|
||||
(„Pull-Prinzip"). Sie benötigen dafür lediglich einen Netzwerkzugriff auf die
|
||||
REST-Schnittstelle Ihrer Instanz – wir müssen keinen Zugriff auf Ihre Infrastruktur
|
||||
haben und erhalten auch keinen.
|
||||
|
||||
---
|
||||
|
||||
## 2. Technische Einrichtung
|
||||
|
||||
Der Backup-Dienst kann als Docker-Container in unterschiedlichen Umgebungen betrieben werden:
|
||||
|
||||
- **Local**: lokal über Docker oder Docker Compose,
|
||||
- **Private Cloud**: in einer Private Cloud (z.b. Kubernetes, OpenShift)
|
||||
- **Public Cloud**: in einer Public Cloud Umgebung (z.b. AWS, Microsoft Azure)
|
||||
|
||||
|
||||
### 2.1 Voraussetzungen
|
||||
|
||||
- Eine eigene Server- bzw. Container-Umgebung (Docker) auf Ihrer Seite
|
||||
- Ein eigener Speicherort für die Backup-Daten (z. B. FTP-Storage, NAS mit
|
||||
FTP-Anbindung)
|
||||
- Eine sogenannte **Mirror-ID**, die wir Ihnen bereitstellen
|
||||
|
||||
### 2.2 Mirror-ID anfragen
|
||||
|
||||
Die Mirror-ID ist eine organisatorische Kennung, mit der wir Ihre eigene
|
||||
Backup-Verbindung für Ihre Instanz freischalten. Sie ist kein Sicherheitsmerkmal im
|
||||
engeren Sinn, sondern eine Vereinbarung zwischen uns: *„Kunde X betreibt ein eigenes
|
||||
Backup."* Bitte fordern Sie diese ID formlos bei uns an.
|
||||
|
||||
### 2.3 Backup-Nutzer in Ihrer eigenen Instanz anlegen
|
||||
|
||||
Ein zentraler Punkt für die Autarkie des Systems: **Sie legen den technischen
|
||||
Benutzer für den Backup-Zugriff selbst in Ihrer Imixs-Instanz an.** Dieser Nutzer
|
||||
gehört ausschließlich Ihnen – wir kennen weder das Passwort noch verwalten wir
|
||||
dieses Konto. Vergeben Sie dem Nutzer ausreichende Leserechte, damit er alle
|
||||
relevanten Vorgänge und Dokumente sichern kann.
|
||||
|
||||
### 2.4 Docker-Compose Beispielkonfiguration
|
||||
|
||||
Das folgende Beispiel zeigt eine Docker Compose Konfiguraiton für den Betrieb des Backup-Dienstes:
|
||||
|
||||
```yaml
|
||||
version: "3.6"
|
||||
services:
|
||||
backup:
|
||||
image: imixs/imixs-archive-backup:latest
|
||||
environment:
|
||||
TZ: "Europe/Berlin"
|
||||
WORKFLOW_SERVICE_ENDPOINT: "https://<ihre-instanz>.office-workflow.de/api/"
|
||||
WORKFLOW_SERVICE_USER: "<ihr-backup-nutzer>"
|
||||
WORKFLOW_SERVICE_PASSWORD: "<ihr-passwort>"
|
||||
WORKFLOW_SERVICE_AUTHMETHOD: "form"
|
||||
BACKUP_FTP_HOST: "<ihr-storage-host>"
|
||||
BACKUP_FTP_PATH: "<ihr-zielverzeichnis>"
|
||||
BACKUP_FTP_PORT: "21"
|
||||
BACKUP_FTP_USER: "<ihr-ftp-nutzer>"
|
||||
BACKUP_FTP_PASSWORD: "<ihr-ftp-passwort>"
|
||||
BACKUP_MIRROR_ID: "<ihre-mirror-id>"
|
||||
ports:
|
||||
- "8084:8080"
|
||||
- "9990:9990"
|
||||
```
|
||||
|
||||
**Erläuterung der wichtigsten Parameter:**
|
||||
|
||||
| Parameter | Bedeutung |
|
||||
|---|---|
|
||||
| `WORKFLOW_SERVICE_ENDPOINT` | Die REST-API-Adresse Ihrer bei uns gehosteten Workflow-Instanz |
|
||||
| `WORKFLOW_SERVICE_USER/PASSWORD` | Der von Ihnen selbst angelegte Backup-Nutzer |
|
||||
| `BACKUP_FTP_*` | Ihr eigener Speicherort für die Backup-Daten |
|
||||
| `BACKUP_MIRROR_ID` | Die von uns bereitgestellte Freischalt-ID |
|
||||
|
||||
Nach dem Start prüft der Dienst regelmäßig auf neue zu sichernde Vorgänge und
|
||||
überträgt diese automatisch auf Ihren Speicherort.
|
||||
|
||||
### 2.5 Monitoring des eigenen Backup-Dienstes
|
||||
|
||||
Da der Dienst vollständig in Ihrer Verantwortung läuft, sollten Sie ihn aktiv
|
||||
überwachen. Ein einfacher Ping-Check zeigt zwar, dass der Container erreichbar
|
||||
ist – sagt aber nichts darüber aus, ob der Dienst tatsächlich funktionsfähig ist
|
||||
und Backups erfolgreich durchführt.
|
||||
|
||||
Der Imixs-Archive-Backup-Service stellt hierfür standardisierte **MicroProfile-Endpunkte** mit, die auf Port `9990`
|
||||
bereitgestellt werden:
|
||||
|
||||
| Endpunkt | Beschreibung |
|
||||
|---|---|
|
||||
| `/health` | Liefert den Health-Status des Dienstes nach dem MicroProfile-Health-Standard – inklusive Readiness (ist der Dienst betriebsbereit, z. B. Verbindung zur Workflow-API und zum FTP-Storage vorhanden?) und Liveness (läuft der Prozess korrekt?) |
|
||||
| `/metrics` | Liefert Betriebskennzahlen im MicroProfile-Metrics-Format (Prometheus-kompatibel), z. B. Anzahl verarbeiteter Backups, Fehlerzähler, Laufzeiten |
|
||||
|
||||
Damit lässt sich der Dienst professionell überwachen:
|
||||
|
||||
- **Health-Checks** binden Sie direkt in gängige Monitoring-Systeme ein (z. B.
|
||||
Kubernetes Liveness-/Readiness-Probes, Uptime-Kuma, Nagios, Icinga) und erkennen
|
||||
so nicht nur einen abgestürzten Container, sondern auch einen Dienst, der zwar
|
||||
läuft, aber z. B. keine Verbindung mehr zu Ihrer Workflow-Instanz oder zum
|
||||
FTP-Ziel herstellen kann.
|
||||
- **Metrics** lassen sich direkt von Prometheus abgegriffen und in Grafana
|
||||
visualisiert werden – so erkennen Sie auf einen Blick, ob regelmäßig Backups
|
||||
durchgeführt werden, oder ob z. B. die Fehlerrate ansteigt.
|
||||
|
||||
**Voraussetzung:** Sie müssen Port `9990` in Ihrer Docker-Umgebung entsprechend
|
||||
freigeben bzw. mappen, damit Ihr Monitoring-System auf die Endpunkte zugreifen kann
|
||||
(siehe Port-Mapping im Beispiel aus Abschnitt 2.4).
|
||||
|
||||
Ein Backup, das unbemerkt seit Wochen nicht mehr funktioniert, bietet keinen Schutz.
|
||||
Die Überwachung über Health- und Metrics-Endpunkte ist daher ein integraler
|
||||
Bestandteil des Konzepts, nicht optional.
|
||||
|
||||
---
|
||||
|
||||
## 3. Notfall- und Wiederherstellungsfall (Disaster Recovery)
|
||||
|
||||
Im Falle eines Disaster-Recovery-Prozesses stellen Sie uns Ihr Backup zur Verfügung, damit Ihr System auf dessen Basis wiederhergestellt werden kann. Dieser Abschnitt beschreibt das Vorgehen nur in Stichpunkten.
|
||||
Die vollständige technische Dokumentation der
|
||||
Imixs-Workflow-Architektur ist Open Source und öffentlich einsehbar unter
|
||||
[github.com/imixs](https://github.com/imixs).
|
||||
|
||||
**Grundprinzip der Wiederherstellung:**
|
||||
|
||||
- Ihre gesicherten Snapshot-Daten liegen vollständig und unverändert in Ihrem
|
||||
eigenen Speicher (FTP/Storage) vor.
|
||||
- Diese Daten liegen in einem offenen, plattformunabhängigen XML-Format vor und
|
||||
sind nicht an unsere konkrete Infrastruktur gebunden.
|
||||
- Auf Basis dieser Daten kann eine neue Imixs-Workflow-Instanz (bei Ihnen oder bei
|
||||
einem anderen Dienstleister) aufgesetzt werden.
|
||||
- Über die Restore-Funktion der Imixs-Archive-Komponenten werden die Snapshots in
|
||||
die neue Instanz zurückgespielt – jeder Geschäftsvorgang wird dabei inklusive
|
||||
seiner Historie und aller Dokumente wiederhergestellt.
|
||||
|
||||
**Wichtige Stichpunkte für den Ernstfall:**
|
||||
|
||||
- Backup-Daten sind vollständig bei Ihnen vorhanden → keine Abhängigkeit von uns
|
||||
- Wiederherstellung erfordert eine lauffähige Imixs-Workflow-Umgebung (Open Source,
|
||||
frei verfügbar)
|
||||
- Die technische Vorgehensweise zum Restore ist Teil der öffentlichen
|
||||
Imixs-Archive-Dokumentation
|
||||
- Wir unterstützen Sie im Ernstfall selbstverständlich gerne beim Wiederaufbau –
|
||||
diese Unterstützung ist jedoch **keine Voraussetzung**, da die Daten und das
|
||||
Wiederherstellungsverfahren vollständig unabhängig von uns nutzbar sind
|
||||
|
||||
---
|
||||
|
||||
## 4. Zusammenfassung
|
||||
|
||||
Mit dem Backup-Mirror bleiben Sie jederzeit Eigentümer Ihrer Geschäftsdaten – unabhängig
|
||||
davon, wie und wo Ihre Instanz betrieben wird. Sie richten den Dienst selbst ein, verwalten
|
||||
ihn eigenständig und behalten so die volle Kontrolle über Ihre zusätzliche Datenkopie. Genau
|
||||
diese Unabhängigkeit ist es, die Ihnen im Bedarfsfall den vollständigen Wiederaufbau Ihres
|
||||
Systems ermöglicht.
|
||||
|
||||
Bei Fragen zur Einrichtung oder zur Anforderung Ihrer Mirror-ID kontaktieren Sie uns
|
||||
gerne.
|
||||
22
backup/docker-compose.yaml
Normal file
22
backup/docker-compose.yaml
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
version: "3.6"
|
||||
services:
|
||||
###############################################
|
||||
# Backup Service
|
||||
###############################################
|
||||
backup:
|
||||
image: imixs/imixs-archive-backup:latest
|
||||
environment:
|
||||
TZ: "Europe/Berlin"
|
||||
WORKFLOW_SERVICE_ENDPOINT: "https://alexander-logistics-ams.office-workflow.de/api/"
|
||||
WORKFLOW_SERVICE_USER: "kutzner-backup-service"
|
||||
WORKFLOW_SERVICE_PASSWORD: "16e-7ede-4c1c-bdeb-e16ce"
|
||||
WORKFLOW_SERVICE_AUTHMETHOD: "form"
|
||||
BACKUP_FTP_HOST: "u248962.your-storagebox.de"
|
||||
BACKUP_FTP_PATH: "/test/agl/ams-test"
|
||||
BACKUP_FTP_PORT: "21"
|
||||
BACKUP_FTP_USER: "u248962"
|
||||
BACKUP_FTP_PASSWORD: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
|
||||
BACKUP_MIRROR_ID: "backup-mirror-local"
|
||||
WORKFLOW_REST_JPQL_DOUBLEDECODE_WORKAROUND: "true"
|
||||
ports:
|
||||
- "8084:8080"
|
||||
9
devi
9
devi
|
|
@ -30,13 +30,13 @@ if [[ "$(strip_dash $1)" == "setup" ]]; then
|
|||
echo " starting dev enrvionment..."
|
||||
mvn clean install -Pdebug
|
||||
cp ./*-app/target/*.war ./docker/deployments/
|
||||
docker-compose -f docker-compose.yml up
|
||||
docker compose -f docker-compose.yml up
|
||||
fi
|
||||
|
||||
|
||||
if [[ "$(strip_dash $1)" == "start" ]]; then
|
||||
echo " Start Dev Environment..."
|
||||
docker-compose -f docker-compose.yml up
|
||||
docker compose -f docker-compose.yml up
|
||||
fi
|
||||
|
||||
if [[ "$(strip_dash $1)" == "build" ]]; then
|
||||
|
|
@ -53,18 +53,17 @@ fi
|
|||
|
||||
if [[ "$(strip_dash $1)" == "hot" ]]; then
|
||||
echo "* Hotdeploy..."
|
||||
cd *-app
|
||||
mvn manik-hotdeploy:hotdeploy
|
||||
cd ..
|
||||
fi
|
||||
|
||||
if [[ "$(strip_dash $1)" == "deploy" ]]; then
|
||||
echo " Deploy to Imixs-Cloud..."
|
||||
|
||||
mvn clean install -Pkubernetes
|
||||
mvn clean install -Pimixs-cloud -DskipTests
|
||||
fi
|
||||
|
||||
|
||||
|
||||
# Überprüfen, ob keine Parameter übergeben wurden - standard build
|
||||
if [[ $# -eq 0 ]]; then
|
||||
|
||||
|
|
|
|||
97
doc/BUSINESSPARTNER.md
Normal file
97
doc/BUSINESSPARTNER.md
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
# BusinessPartner
|
||||
|
||||
Wir haben einen Workflow für die Verwaltung von BusinessPartner.
|
||||
Ein BusinessPartner wird über die bestehende Cargosoft Schnittstelle aus den Debitoren/Kreditoren automatisch importiert und synchronisiert.
|
||||
|
||||
In Imixs ist es dann aber möglich zusätzliche Attribute zu einem Businesspartner zu speichern. Beispielsweise:
|
||||
|
||||
- Zahlungsziel
|
||||
- Bankverbindungen
|
||||
- Emailadressen für Mahnwesen
|
||||
|
||||
Die Businessparnter werden für jedes System separat importiert und verwaltet.
|
||||
|
||||
Folgende zentrale Stati werden über das BusinessPartner Modell festgelegt:
|
||||
|
||||
- TASK_ACTIVE = 1100
|
||||
- TASK_VERIFICATION = 1300
|
||||
- TASK_INACTIVE = 1700
|
||||
- TASK_LOCKED = 1800
|
||||
|
||||
Die Invoice Plugins aktualisierne automatisch die BusinessPartner Attribute `partner.id` und `partner.name`. Zusätzlich unterbinden die Plugins eine Verarbeitung falls das Business Objekt im Satus LOCKED oder VERIFICATION ist!
|
||||
|
||||
## BusinessPartner Suche
|
||||
|
||||
Es gibt einen Controller und ein widget um nach Business Partnern zu suchen.
|
||||
|
||||
<img src="images/businesspartner-widget.png" />
|
||||
|
||||
Z.b. kann das als Custom Part in eine Form eingebunden werden:
|
||||
|
||||
```xml
|
||||
<item name="bpid" type="custom" path="alexander/businesspartner_search" required="true" label="Businesspartner:" />
|
||||
```
|
||||
|
||||
Der name ist heirbei irrelevant, da immer die Items `partner.id` und `partner.name` ausgefüllt werden.
|
||||
Zusätzlich kann man mit den Options angeben ob die Maske komplett neu gerendert werden soll. Das ist z.b. bei dem Modell `analyse-debitor.bpmn` der Fall
|
||||
|
||||
```xml
|
||||
<item name="dbtr.number" type="custom" path="alexander/businesspartner_search" required="true" label="Debtor:" options="rerender" />
|
||||
```
|
||||
|
||||
Man kann auch noch über die options eine regular Expression mitgeben wodurch die Filterliste eingeschränkt werden kann:
|
||||
|
||||
```xml
|
||||
<item name="dbtr.number" type="custom" path="alexander/businesspartner_search" required="true" label="Debtor:" options="rerender;regexPattern=(ABC)" />
|
||||
```
|
||||
|
||||
Alternativ kann im Backend über die EJB BusinessPartnerService nach bpid gesucht werden:
|
||||
|
||||
```java
|
||||
List<ItemCollection> resultList = businessPartnerService.search(phrase);
|
||||
// oder
|
||||
ItemCollection bp= businessPartnerService.getBusinessPartnerByID("BP0001");
|
||||
```
|
||||
|
||||
## Invoice Plugins
|
||||
|
||||
Die Invoice Plugins aktualisieren automatisch partner.id und partner.name falls diese Items noch nicht exiistieren
|
||||
|
||||
# Daten Migration
|
||||
|
||||
Der `BusinessPartnerImportService` hängt sich über ein CDI Observer Pattern an den standard CSVImport Service
|
||||
der die Cargosoft Stammdaten aktualisiert. Der BusinessPartnerImportService
|
||||
prüft ob der Workflow schon existiert oder ggf. aktualisiert werden muss.
|
||||
|
||||
Der Service migriert auch die alten zusätzlichen IBAN/BIC felder wenn der Business partner erstmals neu angelegt wird. Falls bei der ersten Migration erkannt wird, dass die IBAN Nummern nicht eindeutig sind wir der BusinessParter mit dem Event 300 angelegt.
|
||||
|
||||
-
|
||||
|
||||
\_vendor_zip_code
|
||||
|
||||
\_vendor_fax
|
||||
|
||||
(type:cargosoftkreditor) AND ($modified:[20010101 TO 20250215])
|
||||
|
||||
## Anmerkungen zu seltsamen Daten
|
||||
|
||||
BP4641 existier jetzt 3 mal mit der Debitoren nummer D14641
|
||||
|
||||
Feldmühle
|
||||
|
||||
- D14169
|
||||
K74169
|
||||
|
||||
K76233 HSH Papier GmbH & Co. KG
|
||||
|
||||
D16233 Manfred Ziegler Transport GmbH
|
||||
|
||||
Problemkind: https://alexander-logistics-dwc.office-workflow.de/pages/workitems/workitem.xhtml?id=9dd64b0a-cfe1-4174-aea4-0e8af45b823f
|
||||
|
||||
# Business Parter Serach Widget
|
||||
|
||||
wir müssten eigentlich nach Auswahl des Partner
|
||||
|
||||
execute="#{customFormComponents.clientId}" render="#{customFormComponents.clientId}"
|
||||
|
||||
machnen, aber das hat einen blöden effekt
|
||||
|
|
@ -1,13 +1,10 @@
|
|||
# Cargosoft Schnittstelle
|
||||
|
||||
Für den Austausch von Daten mit Cargosoft verwenden wir verschiedene Subaccounts auf unseren FTP Servern.
|
||||
|
||||
# Cargosoft Schnittstelle (Bremen - Mandant 001)
|
||||
## Server Verbindungsdaten
|
||||
|
||||
Für den Austasuch von Daten mit Cargosoft verwenden wir einen Subaccount `u248962-sub2` der auf das Verzeichnis `/office-alexander-logistics/cargosoft` zeigt:
|
||||
|
||||
Server: u248962.your-storagebox.de
|
||||
Pfad: /office-alexander-logistics/cargosoft
|
||||
Benutzername: u248962-sub2
|
||||
Passwort: aXa61n9Un3jDNQlL
|
||||
Details siehe [FTP Server](FTP.md)
|
||||
|
||||
## Ausgangsrechnungen
|
||||
|
||||
|
|
@ -21,48 +18,3 @@ Technisch wird das über die CDI Bean `com.alexanderlogistics.xml.CargosoftXMLIn
|
|||
|
||||
Die Kreditoren/Debitoren Stammdaten werden von Cargosoft im Verzeichnis `/fromCargosoft/stammdaten/` über die Datei `Vendors.csv` bereitgestellt
|
||||
Über den Document Importer `CSV` werden die Dokumente regelmäßig importiert bzw. aktualisert
|
||||
|
||||
|
||||
# Cargosoft Schnittstelle (Bremen Mandant 001)
|
||||
|
||||
Server: u248962.your-storagebox.de
|
||||
Pfad: /office-alexander-logistics/cargosoft
|
||||
Benutzername: u248962-sub2
|
||||
Passwort: aXa61n9Un3jDNQlL
|
||||
|
||||
|
||||
# Cargosoft Schnittstelle (Bremerhaven Mandant 005)
|
||||
|
||||
Server: u248962.your-storagebox.de
|
||||
Pfad: /office-alexander-logistics/cargosoft-bhv
|
||||
Benutzername: u248962-sub5
|
||||
Passwort: 5hKKzv6TFCKRrAdR
|
||||
|
||||
|
||||
# Cargosoft Schnittstelle (Polen Mandant 003)
|
||||
|
||||
Server: u248962.your-storagebox.de
|
||||
Pfad: /office-alexander-logistics/cargosoft-pl
|
||||
Benutzername: u248962-sub7
|
||||
Passwort: PGPzzqmtZ8BSxkbs
|
||||
|
||||
# Cargosoft Schnittstelle (Dubai Mandant 006)
|
||||
|
||||
Server: u248962.your-storagebox.de
|
||||
Pfad: /office-alexander-logistics/cargosoft-dwc
|
||||
Benutzername: u248962-sub3
|
||||
Passwort: enHjxs9h4nJ6EgsZ
|
||||
|
||||
# Cargosoft Schnittstelle (USA Mandant 004)
|
||||
|
||||
Server: u248962.your-storagebox.de
|
||||
Pfad: /office-alexander-logistics/cargosoft-usa
|
||||
Benutzername: u248962-sub9
|
||||
Passwort: GMk7NgDBrmb2QqXg
|
||||
|
||||
# Cargosoft Schnittstelle (China Mandant 007)
|
||||
|
||||
Server: u248962.your-storagebox.de
|
||||
Pfad: /office-alexander-logistics/cargosoft-chn
|
||||
Benutzername: u248962-sub10
|
||||
Passwort: yswBeN83jMqkMqJa
|
||||
BIN
doc/KSeF/Feld-Mapping Cargo Soft zu KSeF (DE).pdf
Normal file
BIN
doc/KSeF/Feld-Mapping Cargo Soft zu KSeF (DE).pdf
Normal file
Binary file not shown.
314
doc/KSeF/README.md
Normal file
314
doc/KSeF/README.md
Normal file
|
|
@ -0,0 +1,314 @@
|
|||
# KSeF API Integration
|
||||
|
||||
Java integration for the Polish **Krajowy System e-Faktur (KSeF)** - the national e-invoicing system for Poland.
|
||||
|
||||
## Overview
|
||||
|
||||
This integration provides secure communication with the KSeF API to upload electronic invoices. It handles the complex multi-step authentication flow and encryption requirements mandated by the Polish tax authorities.
|
||||
|
||||
- [Environment Endpoints](https://github.com/CIRFMF/ksef-docs/blob/main/srodowiska.md)
|
||||
- [KSeF Official Documentation](https://www.gov.pl/web/kas/ksef)
|
||||
- [KSeF API Specification](https://api-test.ksef.mf.gov.pl/docs/v2/index.html)
|
||||
- [Upload Invoice](https://api-test.ksef.mf.gov.pl/docs/v2/index.html#tag/Wysylka-interaktywna/paths/~1api~1v2~1sessions~1online~1%7BreferenceNumber%7D~1invoices/post)
|
||||
- [Facture Details](https://github.com/CIRFMF/ksef-docs/blob/main/sesja-interaktywna.md#2-wys%C5%82anie-faktury)
|
||||
- [XML Invoice Example](https://github.com/CIRFMF/ksef-docs/blob/main/faktury/weryfikacja-faktury.md)
|
||||
- [QR Code](https://github.com/CIRFMF/ksef-docs/blob/main/kody-qr.md)
|
||||
|
||||
- [Github Discussions](https://github.com/CIRFMF/ksef-docs/issues/351#issuecomment-3538013805)
|
||||
- [Github Discussions](https://github.com/CIRFMF/ksef-docs/issues/399)
|
||||
|
||||
Test environment endpoint:
|
||||
|
||||
```
|
||||
https://api-test.ksef.mf.gov.pl/api/v2
|
||||
```
|
||||
|
||||
Production endpoint:
|
||||
|
||||
```
|
||||
https://api.ksef.mf.gov.pl/api/v2
|
||||
```
|
||||
|
||||
## Components
|
||||
|
||||
### 1. KSeFAuthManager
|
||||
|
||||
Manages authentication and session lifecycle for the KSeF API.
|
||||
|
||||
**Key Responsibilities:**
|
||||
|
||||
- Multi-step authentication flow
|
||||
- RSA certificate management
|
||||
- Session key generation and encryption
|
||||
- Access token lifecycle management
|
||||
- Session reuse and validation
|
||||
|
||||
### 2. KSeFAPIService
|
||||
|
||||
Provides business-level methods for invoice operations.
|
||||
|
||||
**Key Responsibilities:**
|
||||
|
||||
- Invoice encryption (AES-256-CBC)
|
||||
- Invoice upload to KSeF
|
||||
- Hash calculation and validation
|
||||
- Error handling and reporting
|
||||
|
||||
## Authentication Flow
|
||||
|
||||
The KSeF API requires a sophisticated multi-step authentication process:
|
||||
|
||||
```
|
||||
1. Load Public Keys
|
||||
└─> GET /security/public-key-certificates
|
||||
|
||||
2. Challenge Request
|
||||
└─> POST /auth/challenge
|
||||
└─> Returns: challenge + timestamp
|
||||
|
||||
3. Token Authentication
|
||||
└─> POST /auth/ksef-token
|
||||
└─> Encrypts: token|timestamp with RSA-OAEP SHA-256
|
||||
└─> Returns: authToken + referenceNumber
|
||||
|
||||
4. Token Redemption
|
||||
└─> POST /auth/token/redeem
|
||||
└─> Returns: accessToken
|
||||
|
||||
5. Open Interactive Session
|
||||
└─> POST /sessions/online
|
||||
└─> Generates AES-256 key + IV
|
||||
└─> Encrypts session key with RSA
|
||||
└─> Returns: sessionRefNumber + validUntil
|
||||
```
|
||||
|
||||
## Invoice Upload Flow
|
||||
|
||||
Once authenticated, invoices can be uploaded:
|
||||
|
||||
```
|
||||
1. Reuse or Create Session
|
||||
└─> Validates existing session or creates new one
|
||||
|
||||
2. Encrypt Invoice
|
||||
└─> AES-256-CBC encryption using session key
|
||||
|
||||
3. Calculate Hashes
|
||||
└─> SHA-256 of original XML
|
||||
└─> SHA-256 of encrypted XML
|
||||
|
||||
4. Upload Invoice
|
||||
└─> POST /sessions/online/{sessionRef}/invoices
|
||||
└─> Returns: referenceNumber
|
||||
```
|
||||
|
||||
## Security Features
|
||||
|
||||
### Multi-Layer Encryption
|
||||
|
||||
- **RSA-OAEP SHA-256**: Token encryption with timestamp binding
|
||||
- **RSA-OAEP SHA-1**: Session key encryption
|
||||
- **AES-256-CBC**: Invoice content encryption
|
||||
|
||||
### Security Mechanisms
|
||||
|
||||
- **Replay Attack Protection**: Timestamp-bound tokens
|
||||
- **Session Management**: Automatic session reuse and validation
|
||||
- **Certificate Validation**: Dynamic X.509 certificate loading
|
||||
- **UTC Timezone Handling**: Prevents timezone-related vulnerabilities
|
||||
|
||||
## Usage Example
|
||||
|
||||
```java
|
||||
// Initialize Auth Manager
|
||||
KSeFAuthManager authManager = new KSeFAuthManager();
|
||||
authManager.setKsefToken("your-ksef-token");
|
||||
authManager.setKsefNip("1234567890");
|
||||
authManager.setKsefEndpoint("https://ksef-test.mf.gov.pl/api/v2");
|
||||
authManager.init();
|
||||
|
||||
// Initialize API Service
|
||||
KSeFAPIService apiService = new KSeFAPIService();
|
||||
apiService.kseFAuthManager = authManager;
|
||||
|
||||
// Upload Invoice
|
||||
ItemCollection workitem = new ItemCollection();
|
||||
FileData fileData = new FileData("invoice.xml", xmlBytes, null, null);
|
||||
workitem.addFileData(fileData);
|
||||
|
||||
String referenceNumber = apiService.uploadInvoice(workitem, "invoice.xml");
|
||||
System.out.println("Invoice uploaded: " + referenceNumber);
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
Required environment variables:
|
||||
|
||||
```properties
|
||||
ksef.api.token=your-ksef-authentication-token
|
||||
ksef.api.nip=your-company-nip-number
|
||||
ksef.api.endpoint=https://ksef-test.mf.gov.pl/api/v2
|
||||
ksef.api.debug=false
|
||||
```
|
||||
|
||||
## Session Management
|
||||
|
||||
The `KSeFAuthManager` automatically handles session lifecycle:
|
||||
|
||||
- **Session Reuse**: Validates `sessionValidUntil` timestamp (UTC)
|
||||
- **Auto-Renewal**: Opens new session if current one expired
|
||||
- **Thread-Safe**: Uses `@Lock(LockType.WRITE)` for concurrent access
|
||||
|
||||
## Testing
|
||||
|
||||
Test environment endpoint:
|
||||
|
||||
```
|
||||
https://ksef-test.mf.gov.pl/api/v2
|
||||
```
|
||||
|
||||
Production endpoint:
|
||||
|
||||
```
|
||||
https://ksef.mf.gov.pl/api/v2
|
||||
```
|
||||
|
||||
See `KSeFAPIServiceTest.java` for complete test examples.
|
||||
|
||||
## Error Handling
|
||||
|
||||
The implementation uses `PluginException` for error handling with two error types:
|
||||
|
||||
- `CONFIG_ERROR`: Configuration or setup issues
|
||||
- `API_ERROR`: API communication or response errors
|
||||
|
||||
## Dependencies
|
||||
|
||||
- Jakarta EE (EJB, JSON-B)
|
||||
- Java 11+ (HttpClient, Crypto APIs)
|
||||
- Imixs Workflow (for document management)
|
||||
|
||||
# Validate XML
|
||||
|
||||
To validate XML results use xmllint. To install run:
|
||||
|
||||
```bash
|
||||
$ sudo apt install libxml2-utils
|
||||
```
|
||||
|
||||
With the bash script `src/test/resources/ksef/validate_xml.sh` you can test a xml file:
|
||||
|
||||
```bash
|
||||
$ ./validate_xml.sh example-invoice-01.xml
|
||||
```
|
||||
|
||||
or to manual test a xml run:
|
||||
|
||||
```bash
|
||||
$ xmllint --noout --schema 'schemat-FA(3)-v1-0E.xsd' example-invoice-01.xml
|
||||
example-invoice-01.xml validates
|
||||
```
|
||||
|
||||
# KSeF FA(3) Invoice Types: VAT vs. KOR
|
||||
|
||||
This section explains the key differences between regular invoices (VAT) and correction invoices (KOR) in the Polish KSeF system using FA(3) structure.
|
||||
|
||||
## Invoice Types
|
||||
|
||||
### VAT - Regular Invoice
|
||||
|
||||
Standard invoice documenting a sale or service delivery.
|
||||
|
||||
### KOR - Correction Invoice
|
||||
|
||||
Invoice that corrects a previously issued invoice (VAT, ZAL, or ROZ).
|
||||
|
||||
---
|
||||
|
||||
## Key Differences
|
||||
|
||||
| Element | VAT Invoice | KOR Invoice |
|
||||
| ------------------------- | -------------------------- | --------------------------------------------- |
|
||||
| **RodzajFaktury** | `VAT` | `KOR` |
|
||||
| **P_2 (Invoice Number)** | `216525` | `216525-KOR` (with suffix) |
|
||||
| **P_1 (Invoice Date)** | Original date (2024-04-03) | Correction date (2024-04-15) |
|
||||
| **Amount Fields** | Absolute values | **Difference values** (negative or positive) |
|
||||
| **DaneFaKorygowanej** | ❌ Not present | ✅ **Required** - references original invoice |
|
||||
| **FaWiersz (Line Items)** | Original values | **New/corrected values** |
|
||||
|
||||
---
|
||||
|
||||
## Critical: Amount Fields in KOR
|
||||
|
||||
**KOR invoices show DIFFERENCES, not absolute amounts!**
|
||||
|
||||
### Example: Correction from 4128.00 → 3500.00 EUR
|
||||
|
||||
```xml
|
||||
<!-- VAT Invoice -->
|
||||
<P_13_1>4128.00</P_13_1> <!-- Total Net -->
|
||||
<P_14_1>0.00</P_14_1> <!-- Total VAT -->
|
||||
<P_15>4128.00</P_15> <!-- Total Gross -->
|
||||
```
|
||||
|
||||
```xml
|
||||
<!-- KOR Invoice -->
|
||||
<P_13_6_1>-628.00</P_13_6_1> <!-- Difference: 3500 - 4128 = -628 -->
|
||||
<P_15>-628.00</P_15> <!-- Difference in Total -->
|
||||
```
|
||||
|
||||
## DaneFaKorygowanej Element
|
||||
|
||||
**Required in KOR invoices** - Must appear AFTER `<RodzajFaktury>KOR</RodzajFaktury>`
|
||||
|
||||
```xml
|
||||
<DaneFaKorygowanej>
|
||||
<DataWystFaKorygowanej>2024-04-03</DataWystFaKorygowanej>
|
||||
<NrFaKorygowanej>216525</NrFaKorygowanej>
|
||||
<NrKSeF>1</NrKSeF>
|
||||
<NrKSeFFaKorygowanej>9552521552-20240403-ABCDEF-123456-AB</NrKSeFFaKorygowanej>
|
||||
</DaneFaKorygowanej>
|
||||
```
|
||||
|
||||
| Field | Description |
|
||||
| ----------------------- | --------------------------------------------------------- |
|
||||
| `DataWystFaKorygowanej` | Date of **original** invoice |
|
||||
| `NrFaKorygowanej` | Number of **original** invoice |
|
||||
| `NrKSeF` | Flag: `1` = original was in KSeF |
|
||||
| `NrKSeFFaKorygowanej` | KSeF number of original invoice (mandatory if `NrKSeF=1`) |
|
||||
|
||||
⚠️ **Critical:** The KSeF number must be saved when uploading the original VAT invoice!
|
||||
|
||||
---
|
||||
|
||||
## FaWiersz in KOR
|
||||
|
||||
**Line items show the NEW/CORRECTED values**, not differences:
|
||||
|
||||
```xml
|
||||
<!-- VAT Invoice -->
|
||||
<FaWiersz>
|
||||
<P_9A>4128.00</P_9A> <!-- Unit price -->
|
||||
<P_11>4128.00</P_11> <!-- Net value -->
|
||||
</FaWiersz>
|
||||
```
|
||||
|
||||
```xml
|
||||
<!-- KOR Invoice -->
|
||||
<FaWiersz>
|
||||
<P_9A>3500.00</P_9A> <!-- NEW unit price -->
|
||||
<P_11>3500.00</P_11> <!-- NEW net value -->
|
||||
<P_12>0 KR</P_12> <!-- Tax rate (0% for exempted) -->
|
||||
</FaWiersz>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
# Testdaten
|
||||
|
||||
Um Testdaten in die lokale Dev Umgebung zu importieren:
|
||||
|
||||
1. aus dem Produktiv Archiv System das XML eines Rechnungs-Snapshots unter /docker/transfer speichern
|
||||
2. per api Call importieren:
|
||||
|
||||
http://localhost:8080/api/cargosoft/import?file=/opt/jboss/wildfly/transfer/f28bf914-04de-4843-9809-54c724bdc9bf-1764111735524.xml
|
||||
26
doc/KSeF/TEST.md
Normal file
26
doc/KSeF/TEST.md
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
# Test Cases
|
||||
|
||||
Invoice
|
||||
|
||||
| No | currency | Tax % | Netto | Brutto | Imixs | TAXMAN |
|
||||
| ---- | -------- | ----- | ---------- | ---------- | --------- | ------ |
|
||||
| 6562 | EUR | 0 | 964,16 | 964,16 | OK |
|
||||
| 6555 | PLN | 23 | 31820,10 | 40894,7 | OK |
|
||||
| 6586 | PLN | 23 | 110.146,50 | 141.820,90 | OK |
|
||||
| 6467 | USD | 0 | 1540,00 | 1540,00 | OK |
|
||||
| 6567 | EUR | 0 | 9940,96 | 9940,96 | NIP Fehlt |
|
||||
|
||||
# Neuer Testlauf
|
||||
|
||||
6602 – correction invoice where just description was changed, without changing of amounts (price, VAT..)
|
||||
6816 - correction invoice where amounts where changed (before correction 180 USD, after correction 0 USD)
|
||||
6811 – invoice with more positions, incl. positions with different VAT rate
|
||||
|
||||
| No | currency | Tax % | Netto | Brutto | Imixs | TAXMAN |
|
||||
| ---- | -------- | ----- | ----- | ------ | ----- | ------ |
|
||||
| 6602 | | 0 | | | | OK |
|
||||
| 6816 | | 0 | | | | OK |
|
||||
| 6811 | | 0 | | | | OK |
|
||||
| | | 0 | | | | |
|
||||
| | | 0 | | | | |
|
||||
| | | 0 | | | | |
|
||||
BIN
doc/KSeF/information-sheet-on-the-fa-3-logical-structure.pdf
Normal file
BIN
doc/KSeF/information-sheet-on-the-fa-3-logical-structure.pdf
Normal file
Binary file not shown.
11183
doc/KSeF/openapi.json
Normal file
11183
doc/KSeF/openapi.json
Normal file
File diff suppressed because it is too large
Load diff
3950
doc/KSeF/schemat-FA(3)-v1-0E.xsd
Normal file
3950
doc/KSeF/schemat-FA(3)-v1-0E.xsd
Normal file
File diff suppressed because it is too large
Load diff
75
doc/KSeF/test.xml
Normal file
75
doc/KSeF/test.xml
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Potwierdzenie xmlns="http://upo.schematy.mf.gov.pl/KSeF/v4-2">
|
||||
<NazwaPodmiotuPrzyjmujacego>Ministerstwo Finansów</NazwaPodmiotuPrzyjmujacego>
|
||||
<NumerReferencyjnySesji>20251128-SO-1DA83DC000-9430B11465-93</NumerReferencyjnySesji>
|
||||
<Uwierzytelnienie>
|
||||
<IdKontekstu>
|
||||
<Nip>9552521552</Nip>
|
||||
</IdKontekstu>
|
||||
<NumerReferencyjnyTokenaKSeF>20251113-EC-2751AC3000-5C5466924B-62</NumerReferencyjnyTokenaKSeF>
|
||||
</Uwierzytelnienie>
|
||||
<NazwaStrukturyLogicznej>1-0E</NazwaStrukturyLogicznej>
|
||||
<KodFormularza>FA (3)</KodFormularza>
|
||||
<Dokument>
|
||||
<NipSprzedawcy>9552521552</NipSprzedawcy>
|
||||
<NumerKSeFDokumentu>9552521552-20251128-010000AA503B-FE</NumerKSeFDokumentu>
|
||||
<NumerFaktury>216577</NumerFaktury>
|
||||
<DataWystawieniaFaktury>2024-04-03</DataWystawieniaFaktury>
|
||||
<DataPrzeslaniaDokumentu>2025-11-28T09:38:18.096+01:00</DataPrzeslaniaDokumentu>
|
||||
<DataNadaniaNumeruKSeF>2025-11-28T09:38:18.192+01:00</DataNadaniaNumeruKSeF>
|
||||
<SkrotDokumentu>wk2TorojBbyNYtDODL1l/KCxQi/rlb3Yss/OEmf5HpE=</SkrotDokumentu>
|
||||
</Dokument>
|
||||
<Signature Id="Signature" xmlns="http://www.w3.org/2000/09/xmldsig#">
|
||||
<SignedInfo>
|
||||
<CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315" />
|
||||
<SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256" />
|
||||
<Reference URI="">
|
||||
<Transforms>
|
||||
<Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" />
|
||||
</Transforms>
|
||||
<DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" />
|
||||
<DigestValue>N/EazXugPjJtobeCSm/ShxeSafdffzHFeRo/BLsngR4=</DigestValue>
|
||||
</Reference>
|
||||
<Reference URI="#SignedProperties" Type="http://uri.etsi.org/01903#SignedProperties">
|
||||
<Transforms>
|
||||
<Transform Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315" />
|
||||
</Transforms>
|
||||
<DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" />
|
||||
<DigestValue>7OYxftjJC1QhSKcWd/oeu7jJaLiO1kFvDCLja8xmNqk=</DigestValue>
|
||||
</Reference>
|
||||
</SignedInfo>
|
||||
<SignatureValue>
|
||||
c87dKdbK3Wf2QpeKEEC0H2LMG92YBH95EbKL6wJTqozOzPq6wqj+06CIPX6bIEz8Szup9xWJlJHX+/xzO4NyMxeiXMQOCAiQ4ZnhPLG2EChopNZYGDbVgOMvfSQBSkHODobG8HH+q4fqueya0V+41CnCSzF8f68fcfVTrV8DfAuw3faKYVg4ddfkvFT+AkBCAZ/JPdYzVVN28np33bd1lHNFJ5wNSpILy9h0FF9iJIiB5RMyvJwxx0HlutrhIMUoId5vUW2XLJKAOLJSSntTJf2S4qjMJcgZr/ZVP9GSaBZPBX09nPWrXOfOwIOuakVfq9N2n+ONZ29ivHpZelMWlA==</SignatureValue>
|
||||
<KeyInfo>
|
||||
<X509Data>
|
||||
<X509Certificate>
|
||||
MIIGWDCCBECgAwIBAgIQY1FHALBG7qGuhTJ/Z7W+yjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJQTDEhMB8GA1UECgwYQXNzZWNvIERhdGEgU3lzdGVtcyBTLkEuMRwwGgYDVQQDDBNDZXJ0dW0gU01JTUUgUlNBIENBMB4XDTI1MDkyOTA2MTEzM1oXDTI3MDkyOTA2MTEzMlowgb4xGTAXBgNVBGETEFZBVFBMLTUyNjAyNTAyNzQxCzAJBgNVBAYTAlBMMRQwEgYDVQQIDAttYXpvd2llY2tpZTERMA8GA1UEBwwIV2Fyc3phd2ExHzAdBgNVBAoMFk1pbmlzdGVyc3R3byBGaW5hbnPDs3cxHzAdBgNVBAMMFk1pbmlzdGVyc3R3byBGaW5hbnPDs3cxKTAnBgkqhkiG9w0BCQEWGmtvbnN1bHRhY2plLmtzZWZAbWYuZ292LnBsMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtL+kpQU8d16im5Z3wIEzo7GqfQF8zWEYZqN5JroiX2ePVACR3znmoo4zx0krVEyhtKKB2/oE3Ql2M5sxaRWC/hnBMLj8r7uAJ/v3lQqzGYAf0ImwRy1H+nF4OS0B1U0m7wD2dGXOSQdbPNVru8SZ9Nw6IcsuAsHezy8EagEIffl+zA/GWtAG6Mp8Bxj3K8LkUdZp70Faaeiv25kOuvT7vThePW+qNFhpdktYQT56lGOmWJqKsm0QtdMzAy1o7bfWeAFLfP7DU3Okk/oz9NqUJc8Swih2ligWN/+g/nwFxcEMrQ4GWE3FDQogNz6kySZ7OIqN//kY1SXXb1nQ1MVAXQIDAQABo4IBvzCCAbswDAYDVR0TAQH/BAIwADBBBgNVHR8EOjA4MDagNKAyhjBodHRwOi8vY3NtaW1lcnNhY2EuY3JsLmNlcnR1bS5wbC9jc21pbWVyc2FjYS5jcmwwgYMGCCsGAQUFBwEBBHcwdTAuBggrBgEFBQcwAYYiaHR0cDovL2NzbWltZXJzYWNhLm9jc3AtY2VydHVtLmNvbTBDBggrBgEFBQcwAoY3aHR0cDovL2NzbWltZXJzYWNhLnJlcG9zaXRvcnkuY2VydHVtLnBsL2NzbWltZXJzYWNhLmNlcjAfBgNVHSMEGDAWgBRm+8MPvvS/4JzJq03eRxm9wMqmaDAdBgNVHQ4EFgQUGwFEj1u0JETJoPhJu2cKjErLsUwwTAYDVR0gBEUwQzAJBgdngQwBBQICMDYGCyqEaAGG9ncCZAMBMCcwJQYIKwYBBQUHAgEWGWh0dHBzOi8vd3d3LmNlcnR1bS5wbC9DUFMwHQYDVR0lBBYwFAYIKwYBBQUHAwQGCCsGAQUFBwMCMA4GA1UdDwEB/wQEAwIE8DAlBgNVHREEHjAcgRprb25zdWx0YWNqZS5rc2VmQG1mLmdvdi5wbDANBgkqhkiG9w0BAQsFAAOCAgEAOfiPMXAeftxKk6fMiRud/VZnQixhHqBakVx11ToO7m8qGW3gj2NJDkIoIWVuRIDpz6bg7vRoyPE0mSjYkjxXfb/gaAHVM1e9vGd5cN5esvJVc9wAbLY/e1ZAg7K8IHE+SQYjLsm0ykCQcnnamzEjSD6CArGUmvwJr33OnlNusVdSZ6ar+EexAEbwBUYL+8aeKYwXn+M928h4W831LxYoVv1WaNFfgUJHjFrIUNeSuXHLG0BslrJwJuy26UQaxiM0FSNJQyeSF5Xt3K+V7EuzX4jf3yfOcTwUrt/4Lq6AEH+konMj5OZurS75aA06NbR6L4hUWfdCFRIx561Y2sHeNlggONsvvQ//z0P9IVk65RqDz21DPt688SRJ5BL5wGo9CDn29+G8VEECPRuhe+UAoQOL/9iQ2mReybunuliarQCLGya/+Ig9QRZe9BWhlN7im1B+7kaMmTbGqzmUkiFoabH+hIqqh72o5B05H9U8R0o7PpI9oJZ95edst1y9fCXw5fbly5Y3N3lR78Ui3AkUf6NN6ZtsMixVHZS8qD/QTaXDX4ez8Kz1PkMGrPWYC0L64PZzyWGZmm3RNtvv/uqx4X/L0Kyu5Dp5+H5BJyQAGh+wHJ5TadGuzASThvuB+fXEhwO3Y+bS41G2czc1vf3s9DXSqMZykYVzRbPQ2XUWkzQ=</X509Certificate>
|
||||
</X509Data>
|
||||
</KeyInfo>
|
||||
<Object>
|
||||
<xades:QualifyingProperties Target="#Signature"
|
||||
xmlns:xades="http://uri.etsi.org/01903/v1.3.2#"
|
||||
xmlns="http://www.w3.org/2000/09/xmldsig#">
|
||||
<xades:SignedProperties Id="SignedProperties">
|
||||
<xades:SignedSignatureProperties>
|
||||
<xades:SigningTime>2025-11-28T08:38:18.2360956+00:00</xades:SigningTime>
|
||||
<xades:SigningCertificate>
|
||||
<xades:Cert>
|
||||
<xades:CertDigest>
|
||||
<DigestMethod
|
||||
Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" />
|
||||
<DigestValue>IFnqTIVQHeVNK0sYY9kn/o3hT2FGIV6U7keiW0zj/Ig=</DigestValue>
|
||||
</xades:CertDigest>
|
||||
<xades:IssuerSerial>
|
||||
<X509IssuerName>CN=Certum SMIME RSA CA, O=Asseco Data Systems
|
||||
S.A., C=PL</X509IssuerName>
|
||||
<X509SerialNumber>132015587733884965165641957463135993546</X509SerialNumber>
|
||||
</xades:IssuerSerial>
|
||||
</xades:Cert>
|
||||
</xades:SigningCertificate>
|
||||
</xades:SignedSignatureProperties>
|
||||
</xades:SignedProperties>
|
||||
</xades:QualifyingProperties>
|
||||
</Object>
|
||||
</Signature>
|
||||
</Potwierdzenie>
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
|
||||
|
||||
|
||||
https://techcommunity.microsoft.com/t5/exchange/javamail-connecting-to-office-365-xoauth2-for-imap/m-p/1505026
|
||||
|
||||
|
||||
47
doc/METRICS.md
Normal file
47
doc/METRICS.md
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
# Metrics
|
||||
|
||||
**Konzept Verworfen!**
|
||||
|
||||
## Background:
|
||||
|
||||
https://blog.imixs.org/2025/02/02/business-intelligence-built-on-metrics-part-ii/
|
||||
|
||||
**Die Implementierung war Teil von Version 1.3.1!**
|
||||
|
||||
## Testing
|
||||
|
||||
Curl
|
||||
|
||||
$ curl -s http://localhost:9990/metrics
|
||||
|
||||
|
||||
$ curl -s http://localhost:9990/metrics | grep BP4218
|
||||
|
||||
```
|
||||
|
||||
application_dbtr_balance{country="", currency="EUR",department="Import Zellulose/Holz",id="BP4218",name="Rayonier Advanced Materials",type="dbtr"} 60911.28
|
||||
application_dbtr_balance{country="US",currency="EUR",department="Import Zellulose/Holz",id="BP4218",name="Rayonier Advanced Materials",type="dbtr"} 257955.41
|
||||
|
||||
|
||||
application_dbtr_sales{country="", currency="EUR",department="Import Zellulose/Holz",id="BP4218",name="Rayonier Advanced Materials",type="dbtr"} 60911.28
|
||||
application_dbtr_sales{country="US", currency="EUR",department="Import Zellulose/Holz",id="BP4218",name="Rayonier Advanced Materials",type="dbtr"} 279028.91
|
||||
|
||||
|
||||
```
|
||||
|
||||
Rayonier Advanced Materials
|
||||
|
||||
Debitor 74218
|
||||
|
||||
293.535,19 EUR
|
||||
|
||||
Metric saldo: 318866.69
|
||||
|
||||
# Jetzt berechnen wir neu...
|
||||
|
||||
https://alexander-logistics.office-workflow.de/api/metrics/dbtr/rebuild
|
||||
|
||||
application_dbtr_balance{country="", currency="EUR",department="Import Zellulose/Holz",id="BP4218",name="Rayonier Advanced Materials",type="dbtr"} 60911.28
|
||||
application_dbtr_balance{country="US",currency="EUR",department="Import Zellulose/Holz",id="BP4218",name="Rayonier Advanced Materials",type="dbtr"} 364457.85
|
||||
application_dbtr_sales{country="", currency="EUR",department="Import Zellulose/Holz",id="BP4218",name="Rayonier Advanced Materials",type="dbtr"} 60911.28
|
||||
application_dbtr_sales{country="US", currency="EUR",department="Import Zellulose/Holz",id="BP4218",name="Rayonier Advanced Materials",type="dbtr"} 364457.85
|
||||
BIN
doc/images/businesspartner-widget.png
Normal file
BIN
doc/images/businesspartner-widget.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 7.5 KiB |
BIN
doc/images/zoho-001.png
Normal file
BIN
doc/images/zoho-001.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 106 KiB |
BIN
doc/images/zoho-002.png
Normal file
BIN
doc/images/zoho-002.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 42 KiB |
94
doc/zoho/README.md
Normal file
94
doc/zoho/README.md
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
# Zoho Web API
|
||||
|
||||
AGL Dubai nutzt Zoho als Platform zusammen mit einer lokalen Steuerkanzlei
|
||||
|
||||
https://books.zoho.com/
|
||||
|
||||
Testaccount - siehe [SECRETS.md](SECRETS.md)
|
||||
|
||||
# API Dokumentation
|
||||
|
||||
- API Docu: https://www.zoho.com/books/api/v3/introduction/
|
||||
- Authentication: https://www.zoho.com/books/api/v3/oauth/
|
||||
|
||||
# Testumgebung
|
||||
|
||||
https://books.zoho.eu/app/20105697367
|
||||
https://accounts.zoho.eu/home#
|
||||
|
||||
Base API URI= https://accounts.zoho.eu/
|
||||
|
||||
## 1. Client Einrichten
|
||||
|
||||
https://api-console.zoho.eu/
|
||||
|
||||
## 2. Generating Grant Token
|
||||
|
||||
https://accounts.zoho.com/oauth/v2/auth?scope=ZohoBooks.invoices.CREATE,ZohoBooks.invoices.READ,ZohoBooks.invoices.UPDATE,ZohoBooks.invoices.DELETE&client_id=1000.NLTM2KUEHI696MSLGEIANATVGGX7IN&state=testing&response_type=code&redirect_uri=https://alexander-logistics-dwc.office-workflow.de/api/zoho/grant
|
||||
|
||||
1000.NLTM2KUEHI696MSLGEIANATVGGX7IN
|
||||
ee9ba49f16e77c64abb89cea13542d2326d8d03ce8
|
||||
|
||||
## 3. Generate Access and Refresh Token
|
||||
|
||||
https://accounts.zoho.com/oauth/v2/token?code=1000.dd7exxxxxxxxxxxxxxxxxxxxxxxx9bb8.b6c0xxxxxxxxxxxxxxxxxxxxxxxxdca4&client_id=1000.NLTM2KUEHI696MSLGEIANATVGGX7IN&client_secret=ee9ba49f16e77c64abb89cea13542d2326d8d03ce8&redirect_uri=http://www.zoho.com/books&grant_type=authorization_code
|
||||
|
||||
# Self Client
|
||||
|
||||
Man kann bei zoho mit einem sogenannten 'Self Client' arbeiten. Dieser erlaubt es ohne Redirect auf die Zoho Webseite einen Code anzufordern:
|
||||
|
||||
## 1. Self Client einrichten
|
||||
|
||||
Auf die API COnsole von Zoho zugreifen:
|
||||
|
||||
https://api-console.zoho.eu/client/1000.GR5FTPZYB06HEWSFSSX4DJU3OBD4EJ
|
||||
|
||||
<img src="../images/zoho-001.png" width="800">
|
||||
|
||||
Es kann maximal ein Client eingerichtet werden
|
||||
|
||||
Unter Scope trägt man dann den gewünschten Scope ein. Z.B.:
|
||||
|
||||
ZohoBooks.invoices.CREATE,ZohoBooks.invoices.READ,ZohoBooks.invoices.UPDATE,ZohoBooks.invoices.DELETE
|
||||
|
||||
und eine Description
|
||||
|
||||
<img src="../images/zoho-002.png">
|
||||
|
||||
Den generierten Code nun in Anwendung übertragen und innerhalb (!!) der 'Time Duration' den Access und Refresh Token generieren!
|
||||
|
||||
Siehe Junit Test `TestUpdateTokens`
|
||||
|
||||
Find details also [here](https://www.zoho.com/writer/help/api/v1/oauth-step2.html#self-client)
|
||||
|
||||
## Example for JUnit Test
|
||||
|
||||
Der Junit Test `TestUpdateTokens` zeigt das Prinzip
|
||||
|
||||
```
|
||||
client ID= 1000.GR5FTPZYB06HEWSFSSX4DJU3OBD4EJ
|
||||
client secret= 3f3e74c5212bbc924a7ebf77f887c6296db1106c47
|
||||
```
|
||||
|
||||
In der Web GUi einen neuen Code generieren:
|
||||
|
||||
Scope=ZohoBooks.invoices.CREATE,ZohoBooks.invoices.READ,ZohoBooks.invoices.UPDATE,ZohoBooks.invoices.DELETE
|
||||
|
||||
Danach den Code token kopieren:
|
||||
|
||||
1000.7fe6315e8848b92a2f281b885677d37a.428c02dc2309606c86271842f1f67de4
|
||||
|
||||
**Note:** Der Code muss für Test immer wieder neu erstellt werden, da er nur für einige Minuten gültig ist!
|
||||
|
||||
# Disable auto-generated invoice number
|
||||
|
||||
Um die Automatische Vergabe von Rechnungsnummern in Zoho zu deaktivieren kann wie folgt vorgegangen werden:
|
||||
|
||||
1. Unter 'Invoices' eine neue Rechnung anlegen#
|
||||
2. Im Feld 'Invoice#' das Zahnrad anklicken:
|
||||
|
||||
<img src="disable-auto-generated-number-01.png" />
|
||||
|
||||
3. Und dort die Option "Enter invoice numbers manually" auswählen
|
||||
|
||||
<img src="disable-auto-generated-number-02.png" />
|
||||
167
doc/zoho/bill-create-example.json
Normal file
167
doc/zoho/bill-create-example.json
Normal file
|
|
@ -0,0 +1,167 @@
|
|||
{
|
||||
"code": 0,
|
||||
"message": "The bill has been created.",
|
||||
"bill": {
|
||||
"bill_id": "6206847000000103003",
|
||||
"vendor_id": "6206847000000100015",
|
||||
"vendor_name": "Feldmuehle GmbH",
|
||||
"source": "Api",
|
||||
"contact_category": "",
|
||||
"tax_treatment": "",
|
||||
"unused_credits_payable_amount": 0.00,
|
||||
"status": "paid",
|
||||
"color_code": "",
|
||||
"current_sub_status_id": "",
|
||||
"current_sub_status": "paid",
|
||||
"sub_statuses": [],
|
||||
"bill_number": "28195",
|
||||
"date": "2024-07-26",
|
||||
"due_date": "2024-07-26",
|
||||
"discount_setting": "flat",
|
||||
"tds_calculation_type": "tds_item_level",
|
||||
"payment_terms": 0,
|
||||
"payment_terms_label": "Due on Receipt",
|
||||
"payment_expected_date": "",
|
||||
"reference_number": "",
|
||||
"scanned_po_number": "",
|
||||
"recurring_bill_id": "",
|
||||
"due_by_days": 286,
|
||||
"due_in_days": "",
|
||||
"currency_id": "6206847000000000109",
|
||||
"currency_code": "EUR",
|
||||
"currency_symbol": "€",
|
||||
"currency_name_formatted": "EUR- Euro",
|
||||
"documents": [],
|
||||
"subject_content": "",
|
||||
"price_precision": 2,
|
||||
"exchange_rate": 1.00,
|
||||
"custom_fields": [],
|
||||
"custom_field_hash": {},
|
||||
"is_viewed_by_client": false,
|
||||
"client_viewed_time": "",
|
||||
"is_item_level_tax_calc": false,
|
||||
"is_inclusive_tax": false,
|
||||
"tax_rounding": "entity_level",
|
||||
"is_uber_bill": false,
|
||||
"is_tally_bill": false,
|
||||
"track_discount_in_account": true,
|
||||
"is_bill_reconciliation_violated": false,
|
||||
"bill_order_type": "",
|
||||
"line_items": [
|
||||
{
|
||||
"purchaseorder_id": "",
|
||||
"purchaseorder_item_id": "",
|
||||
"receive_id": "",
|
||||
"line_item_id": "6206847000000103013",
|
||||
"item_id": "",
|
||||
"name": "AB-DEFGHI-1234-567",
|
||||
"account_id": "6206847000000092271",
|
||||
"account_name": "TEst",
|
||||
"description": "",
|
||||
"bcy_rate": 0.00,
|
||||
"rate": 0.00,
|
||||
"sales_rate": "",
|
||||
"pricebook_id": "",
|
||||
"header_id": "",
|
||||
"header_name": "",
|
||||
"tags": [],
|
||||
"quantity": 1.00,
|
||||
"discount": 0.00,
|
||||
"discounts": [],
|
||||
"discount_account_id": "",
|
||||
"discount_account_name": "",
|
||||
"markup_percent": 0.00,
|
||||
"tax_id": "",
|
||||
"tax_name": "",
|
||||
"tax_type": "tax",
|
||||
"tax_percentage": 0,
|
||||
"line_item_taxes": [],
|
||||
"item_total": 0.00,
|
||||
"item_order": 1,
|
||||
"unit": "",
|
||||
"item_type": "",
|
||||
"image_name": "",
|
||||
"image_type": "",
|
||||
"is_billable": false,
|
||||
"customer_id": "",
|
||||
"receipt_line_item_id": "",
|
||||
"customer_name": "",
|
||||
"project_id": "",
|
||||
"project_name": "",
|
||||
"invoice_id": "",
|
||||
"invoice_number": "",
|
||||
"item_custom_fields": [],
|
||||
"purchase_request_items": [],
|
||||
"item_matching_type": ""
|
||||
}
|
||||
],
|
||||
"submitted_date": "",
|
||||
"submitted_by": "",
|
||||
"submitted_by_name": "",
|
||||
"submitted_by_email": "",
|
||||
"submitted_by_photo_url": "",
|
||||
"submitter_id": "",
|
||||
"approver_id": "",
|
||||
"adjustment": 0.00,
|
||||
"adjustment_description": "",
|
||||
"discount_amount": 0.00,
|
||||
"discount": 0.00,
|
||||
"discount_applied_on_amount": 0.00,
|
||||
"is_discount_before_tax": true,
|
||||
"discount_account_id": "",
|
||||
"discount_account_name": "",
|
||||
"discount_type": "entity_level",
|
||||
"sub_total": 0.00,
|
||||
"sub_total_inclusive_of_tax": 0.00,
|
||||
"tax_total": 0.00,
|
||||
"discount_total": 0.00,
|
||||
"discount_percent": 0.00,
|
||||
"total": 0.00,
|
||||
"payment_made": 0.00,
|
||||
"vendor_credits_applied": 0.00,
|
||||
"is_line_item_invoiced": false,
|
||||
"purchaseorders": [],
|
||||
"taxes": [],
|
||||
"computation_type": "basic",
|
||||
"tax_override_preference": "no_override",
|
||||
"tds_override_preference": "no_override",
|
||||
"balance": 0.00,
|
||||
"unprocessed_payment_amount": 0.00,
|
||||
"billing_address_id": "6206847000000100017",
|
||||
"billing_address": {
|
||||
"address": "",
|
||||
"street2": "",
|
||||
"city": "",
|
||||
"state": "",
|
||||
"zip": "",
|
||||
"country": "",
|
||||
"fax": "",
|
||||
"phone": "",
|
||||
"attention": ""
|
||||
},
|
||||
"payments": [],
|
||||
"vendor_credits": [],
|
||||
"created_time": "2025-05-08T21:36:04+0100",
|
||||
"created_by_id": "6206847000000092001",
|
||||
"last_modified_id": "6206847000000092001",
|
||||
"last_modified_time": "2025-05-08T21:36:04+0100",
|
||||
"reference_id": "",
|
||||
"notes": "",
|
||||
"terms": "",
|
||||
"attachment_name": "",
|
||||
"template_id": "6206847000000031017",
|
||||
"template_name": "Standard Template",
|
||||
"page_width": "8.27in",
|
||||
"page_height": "11.69in",
|
||||
"orientation": "portrait",
|
||||
"template_type": "standard",
|
||||
"is_approval_required": false,
|
||||
"allocated_landed_costs": [],
|
||||
"unallocated_landed_costs": [],
|
||||
"entity_type": "bill",
|
||||
"total_retention_amount": 0.00,
|
||||
"retention_items": [],
|
||||
"can_send_in_mail": false,
|
||||
"approvers_list": []
|
||||
}
|
||||
}
|
||||
177
doc/zoho/contact-create-example.json
Normal file
177
doc/zoho/contact-create-example.json
Normal file
|
|
@ -0,0 +1,177 @@
|
|||
{
|
||||
"code": 0,
|
||||
"message": "The contact has been added.",
|
||||
"contact": {
|
||||
"contact_id": "777249000000077029",
|
||||
"contact_name": "HQ Recyclers Network e.K.",
|
||||
"company_name": "HQ Recyclers Network e.K.",
|
||||
"contact_number": "CUS-00008",
|
||||
"contact_tax_information": "",
|
||||
"first_name": "",
|
||||
"last_name": "",
|
||||
"designation": "",
|
||||
"department": "",
|
||||
"website": "",
|
||||
"is_bcy_only_contact": true,
|
||||
"is_credit_limit_migration_completed": true,
|
||||
"language_code": "",
|
||||
"language_code_formatted": "",
|
||||
"contact_salutation": "",
|
||||
"email": "",
|
||||
"phone": "",
|
||||
"mobile": "",
|
||||
"invited_by": "",
|
||||
"portal_status": "disabled",
|
||||
"is_client_review_asked": false,
|
||||
"has_transaction": false,
|
||||
"contact_type": "customer",
|
||||
"customer_sub_type": "business",
|
||||
"owner_id": "",
|
||||
"owner_name": "",
|
||||
"source": "api",
|
||||
"documents": [],
|
||||
"twitter": "",
|
||||
"facebook": "",
|
||||
"is_crm_customer": false,
|
||||
"is_linked_with_zohocrm": false,
|
||||
"primary_contact_id": "",
|
||||
"zcrm_account_id": "",
|
||||
"zcrm_contact_id": "",
|
||||
"crm_owner_id": "",
|
||||
"payment_terms": 0,
|
||||
"payment_terms_label": "Due on Receipt",
|
||||
"payment_terms_id": "",
|
||||
"credit_limit_exceeded_amount": 0.00,
|
||||
"currency_id": "777249000000000071",
|
||||
"currency_code": "EUR",
|
||||
"currency_symbol": "€",
|
||||
"price_precision": 2,
|
||||
"exchange_rate": "",
|
||||
"can_show_customer_ob": true,
|
||||
"can_show_vendor_ob": true,
|
||||
"opening_balance_amount": 0.00,
|
||||
"opening_balance_amount_bcy": "",
|
||||
"outstanding_ob_receivable_amount": 0.00,
|
||||
"outstanding_ob_payable_amount": 0.00,
|
||||
"outstanding_receivable_amount": 0.00,
|
||||
"outstanding_receivable_amount_bcy": 0.00,
|
||||
"outstanding_payable_amount": 0.00,
|
||||
"outstanding_payable_amount_bcy": 0.00,
|
||||
"unused_credits_receivable_amount": 0.00,
|
||||
"unused_credits_receivable_amount_bcy": 0.00,
|
||||
"unused_credits_payable_amount": 0.00,
|
||||
"unused_credits_payable_amount_bcy": 0.00,
|
||||
"unused_retainer_payments": 0.00,
|
||||
"status": "active",
|
||||
"payment_reminder_enabled": true,
|
||||
"is_sms_enabled": true,
|
||||
"is_consent_agreed": false,
|
||||
"consent_date": "",
|
||||
"is_client_review_settings_enabled": false,
|
||||
"custom_fields": [],
|
||||
"custom_field_hash": {},
|
||||
"tax_reg_label": "",
|
||||
"contact_category": "",
|
||||
"sales_channel": "direct_sales",
|
||||
"ach_supported": false,
|
||||
"portal_receipt_count": 0,
|
||||
"opening_balances": [],
|
||||
"entity_address_id": "777249000000077035",
|
||||
"billing_address": {
|
||||
"address_id": "777249000000077031",
|
||||
"attention": "",
|
||||
"address": "",
|
||||
"street2": "",
|
||||
"city": "",
|
||||
"state_code": "",
|
||||
"state": "",
|
||||
"zip": "",
|
||||
"country": "",
|
||||
"county": "",
|
||||
"country_code": "",
|
||||
"phone": "",
|
||||
"fax": ""
|
||||
},
|
||||
"shipping_address": {
|
||||
"address_id": "777249000000077033",
|
||||
"attention": "",
|
||||
"address": "",
|
||||
"street2": "",
|
||||
"city": "",
|
||||
"state_code": "",
|
||||
"state": "",
|
||||
"zip": "",
|
||||
"country": "",
|
||||
"county": "",
|
||||
"country_code": "",
|
||||
"phone": "",
|
||||
"fax": "",
|
||||
"latitude": "",
|
||||
"longitude": ""
|
||||
},
|
||||
"contact_persons": [],
|
||||
"addresses": [],
|
||||
"pricebook_id": "",
|
||||
"pricebook_name": "",
|
||||
"default_templates": {
|
||||
"statement_template_id": "",
|
||||
"statement_template_name": "",
|
||||
"invoice_template_id": "",
|
||||
"invoice_template_name": "",
|
||||
"bill_template_id": "",
|
||||
"bill_template_name": "",
|
||||
"estimate_template_id": "",
|
||||
"estimate_template_name": "",
|
||||
"creditnote_template_id": "",
|
||||
"creditnote_template_name": "",
|
||||
"paymentthankyou_template_id": "",
|
||||
"paymentthankyou_template_name": "",
|
||||
"invoice_email_template_id": "",
|
||||
"invoice_email_template_name": "",
|
||||
"estimate_email_template_id": "",
|
||||
"estimate_email_template_name": "",
|
||||
"creditnote_email_template_id": "",
|
||||
"creditnote_email_template_name": "",
|
||||
"paymentthankyou_email_template_id": "",
|
||||
"paymentthankyou_email_template_name": "",
|
||||
"payment_remittance_email_template_id": "",
|
||||
"payment_remittance_email_template_name": ""
|
||||
},
|
||||
"associated_with_square": false,
|
||||
"cards": [],
|
||||
"checks": [],
|
||||
"bank_accounts": [],
|
||||
"vpa_list": [],
|
||||
"notes": "",
|
||||
"created_time": "2025-04-30T11:14:42+0200",
|
||||
"created_date": "2025-04-30",
|
||||
"created_by_name": "Ralph Soika",
|
||||
"last_modified_time": "2025-04-30T11:14:42+0200",
|
||||
"tags": [],
|
||||
"zohopeople_client_id": "",
|
||||
"customer_currency_summaries": [
|
||||
{
|
||||
"currency_id": "777249000000000071",
|
||||
"currency_code": "EUR",
|
||||
"currency_symbol": "€",
|
||||
"price_precision": 2,
|
||||
"is_base_currency": true,
|
||||
"currency_name_formatted": "EUR- Euro",
|
||||
"outstanding_receivable_amount": 0.00,
|
||||
"unused_credits_receivable_amount": 0.00
|
||||
}
|
||||
],
|
||||
"is_valid_trn": false,
|
||||
"trn_last_validated_time": "",
|
||||
"trn_last_validated_time_formatted": "",
|
||||
"approvers_list": [],
|
||||
"submitted_date": "",
|
||||
"submitted_by": "",
|
||||
"submitted_by_name": "",
|
||||
"submitted_by_email": "",
|
||||
"submitted_by_photo_url": "",
|
||||
"submitter_id": "",
|
||||
"approver_id": "",
|
||||
"integration_references": []
|
||||
}
|
||||
}
|
||||
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 |
BIN
doc/zoho/image.png
Normal file
BIN
doc/zoho/image.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 105 KiB |
273
doc/zoho/invoice-create-example.json
Normal file
273
doc/zoho/invoice-create-example.json
Normal file
|
|
@ -0,0 +1,273 @@
|
|||
{
|
||||
"code": 0,
|
||||
"message": "The invoice has been created.",
|
||||
"invoice": {
|
||||
"invoice_id": "777249000000082026",
|
||||
"invoice_number": "INV-000018",
|
||||
"date": "2024-04-03",
|
||||
"due_date": "2024-05-03",
|
||||
"offline_created_date_with_time": "",
|
||||
"customer_id": "777249000000075016",
|
||||
"contact_number": "CUS-00005",
|
||||
"customer_name": "Action Agenciamento de Cargas LTDA",
|
||||
"customer_custom_fields": [],
|
||||
"customer_custom_field_hash": {},
|
||||
"email": "",
|
||||
"currency_id": "777249000000000071",
|
||||
"invoice_source": "Api",
|
||||
"currency_code": "EUR",
|
||||
"currency_symbol": "€",
|
||||
"currency_name_formatted": "EUR- Euro",
|
||||
"status": "draft",
|
||||
"unprocessed_payment_amount": 0.00,
|
||||
"custom_fields": [],
|
||||
"custom_field_hash": {},
|
||||
"recurring_invoice_id": "",
|
||||
"is_last_child_invoice": false,
|
||||
"payment_mode": "",
|
||||
"bank_account_id": "",
|
||||
"payment_terms": 30,
|
||||
"payment_terms_label": "Net 30",
|
||||
"early_payment_discount_percentage": 0.00,
|
||||
"early_payment_discount_due_days": "",
|
||||
"early_payment_discount_amount": 0.00,
|
||||
"payment_reminder_enabled": true,
|
||||
"payment_made": 0.00,
|
||||
"zcrm_potential_id": "",
|
||||
"zcrm_potential_name": "",
|
||||
"reference_number": "",
|
||||
"preceding_invoice_id": "",
|
||||
"is_early_payment_discount_applicable": false,
|
||||
"lock_details": {},
|
||||
"is_progress_invoice": false,
|
||||
"can_show_kit_return": false,
|
||||
"is_kit_partial_return": false,
|
||||
"line_items": [
|
||||
{
|
||||
"line_item_id": "777249000000082036",
|
||||
"item_id": "",
|
||||
"item_order": 1,
|
||||
"name": "R IM-GCA-2403-110",
|
||||
"internal_name": "",
|
||||
"description": "",
|
||||
"discount_account_id": "",
|
||||
"discount_account_name": "",
|
||||
"unit": "",
|
||||
"quantity": 1.00,
|
||||
"discount_amount": 0.00,
|
||||
"discount": 0.00,
|
||||
"discounts": [],
|
||||
"bcy_rate": 1995.00,
|
||||
"rate": 1995.00,
|
||||
"account_id": "777249000000000376",
|
||||
"account_name": "Sales",
|
||||
"header_id": "",
|
||||
"header_name": "",
|
||||
"pricebook_id": "",
|
||||
"tax_id": "",
|
||||
"tax_name": "",
|
||||
"tax_type": "tax",
|
||||
"tax_percentage": 0,
|
||||
"item_total": 1995.00,
|
||||
"item_custom_fields": [],
|
||||
"pricing_scheme": "unit",
|
||||
"tags": [],
|
||||
"documents": [],
|
||||
"line_item_taxes": [],
|
||||
"bill_id": "",
|
||||
"bill_item_id": "",
|
||||
"project_id": "",
|
||||
"time_entry_ids": [],
|
||||
"expense_id": "",
|
||||
"item_type": "",
|
||||
"expense_receipt_name": "",
|
||||
"sales_rate": "",
|
||||
"purchase_rate": "",
|
||||
"salesorder_item_id": "",
|
||||
"cost_amount": 0,
|
||||
"markup_percent": 0,
|
||||
"mapped_items": []
|
||||
}
|
||||
],
|
||||
"total_retention_amount": 0.00,
|
||||
"retention_items": [],
|
||||
"retention_override_preference": "no_override",
|
||||
"exchange_rate": 1.00,
|
||||
"is_autobill_enabled": false,
|
||||
"inprocess_transaction_present": false,
|
||||
"allow_partial_payments": false,
|
||||
"price_precision": 2,
|
||||
"sub_total": 1995.00,
|
||||
"tax_total": 0.00,
|
||||
"discount_total": 0.00,
|
||||
"discount_percent": 0.00,
|
||||
"discount": 0.00,
|
||||
"discount_applied_on_amount": 0.00,
|
||||
"discount_type": "item_level",
|
||||
"discount_account_id": "",
|
||||
"discount_account_name": "",
|
||||
"is_discount_before_tax": true,
|
||||
"adjustment": 0.00,
|
||||
"adjustment_description": "",
|
||||
"shipping_charge_tax_id": "",
|
||||
"shipping_charge_tax_name": "",
|
||||
"shipping_charge_tax_type": "",
|
||||
"shipping_charge_tax_percentage": "",
|
||||
"shipping_charge_tax_exemption_id": "",
|
||||
"shipping_charge_tax_exemption_code": "",
|
||||
"shipping_charge_tax": "",
|
||||
"bcy_shipping_charge_tax": "",
|
||||
"shipping_charge_exclusive_of_tax": 0.000,
|
||||
"shipping_charge_inclusive_of_tax": 0.000,
|
||||
"shipping_charge_tax_formatted": "",
|
||||
"shipping_charge_exclusive_of_tax_formatted": "€0,00",
|
||||
"shipping_charge_inclusive_of_tax_formatted": "€0,00",
|
||||
"shipping_charge_account_id": "",
|
||||
"shipping_charge_account_name": "",
|
||||
"shipping_charge": 0.00,
|
||||
"bcy_shipping_charge": 0.00,
|
||||
"bcy_adjustment": 0.00,
|
||||
"bcy_sub_total": 1995.00,
|
||||
"bcy_discount_total": 0.00,
|
||||
"bcy_tax_total": 0.00,
|
||||
"bcy_total": 1995.000,
|
||||
"total": 1995.00,
|
||||
"balance": 1995.00,
|
||||
"write_off_amount": 0.00,
|
||||
"roundoff_value": 0.00,
|
||||
"transaction_rounding_type": "no_rounding",
|
||||
"is_inclusive_tax": false,
|
||||
"sub_total_inclusive_of_tax": 0.00,
|
||||
"contact_category": "",
|
||||
"tax_rounding": "entity_level",
|
||||
"taxes": [],
|
||||
"tds_calculation_type": "tds_item_level",
|
||||
"can_send_invoice_sms": true,
|
||||
"payment_expected_date": "",
|
||||
"payment_discount": 0.00,
|
||||
"stop_reminder_until_payment_expected_date": false,
|
||||
"last_payment_date": "",
|
||||
"ach_supported": false,
|
||||
"ach_payment_initiated": false,
|
||||
"payment_options": {
|
||||
"payment_gateways": []
|
||||
},
|
||||
"reader_offline_payment_initiated": false,
|
||||
"contact_persons": [],
|
||||
"contact_persons_associated": [],
|
||||
"bank_account_details": {
|
||||
"bank_account_id": "777249000000000376",
|
||||
"bank_account_name": "Sales",
|
||||
"bank_account_number": "",
|
||||
"is_active": false,
|
||||
"iban_number": "",
|
||||
"swift_code": ""
|
||||
},
|
||||
"attachment_name": "",
|
||||
"documents": [],
|
||||
"computation_type": "basic",
|
||||
"deliverychallans": [],
|
||||
"merchant_id": "",
|
||||
"merchant_name": "",
|
||||
"ecomm_operator_id": "",
|
||||
"ecomm_operator_name": "",
|
||||
"salesorder_id": "",
|
||||
"salesorder_number": "",
|
||||
"salesorders": [],
|
||||
"shipping_bills": [],
|
||||
"contact_persons_details": [],
|
||||
"contact": {
|
||||
"customer_balance": 0.00,
|
||||
"credit_limit": 0.00,
|
||||
"unused_customer_credits": 0.00,
|
||||
"is_credit_limit_migration_completed": true
|
||||
},
|
||||
"salesperson_id": "",
|
||||
"salesperson_name": "",
|
||||
"is_emailed": false,
|
||||
"reminders_sent": 0,
|
||||
"last_reminder_sent_date": "",
|
||||
"next_reminder_date_formatted": "",
|
||||
"is_viewed_by_client": false,
|
||||
"client_viewed_time": "",
|
||||
"submitter_id": "",
|
||||
"approver_id": "",
|
||||
"submitted_date": "",
|
||||
"submitted_by": "",
|
||||
"submitted_by_name": "",
|
||||
"submitted_by_email": "",
|
||||
"submitted_by_photo_url": "",
|
||||
"template_id": "777249000000000103",
|
||||
"template_name": "Standard Template",
|
||||
"template_type": "standard",
|
||||
"notes": "Thanks for your business.",
|
||||
"terms": "",
|
||||
"billing_address": {
|
||||
"street": "",
|
||||
"address": "",
|
||||
"street2": "",
|
||||
"city": "",
|
||||
"state": "",
|
||||
"zip": "",
|
||||
"country": "",
|
||||
"fax": "",
|
||||
"phone": "",
|
||||
"attention": ""
|
||||
},
|
||||
"shipping_address": {
|
||||
"street": "",
|
||||
"address": "",
|
||||
"street2": "",
|
||||
"city": "",
|
||||
"state": "",
|
||||
"zip": "",
|
||||
"country": "",
|
||||
"fax": "",
|
||||
"phone": "",
|
||||
"attention": ""
|
||||
},
|
||||
"invoice_url": "https://zohosecurepay.eu/books/imixs/secure?CInvoiceID=2-64277fbd3cd8bc868d9e57c3085f4f428b1f66a1d5e3f3a32fc159e6879f623863183b0ac4651a08fdcce7621ddf18bf61770563d9fd2832f987dda624d4f11579820a40c3f55870 ",
|
||||
"subject_content": "",
|
||||
"can_send_in_mail": false,
|
||||
"created_time": "2025-05-02T10:23:49+0200",
|
||||
"last_modified_time": "2025-05-02T10:23:49+0200",
|
||||
"created_date": "2025-05-02",
|
||||
"created_by_id": "777249000000055227",
|
||||
"created_by_name": "Ralph Soika",
|
||||
"last_modified_by_id": "777249000000055227",
|
||||
"page_width": "8.27in",
|
||||
"page_height": "11.69in",
|
||||
"orientation": "portrait",
|
||||
"is_backorder": "",
|
||||
"sales_channel": "direct_sales",
|
||||
"color_code": "",
|
||||
"current_sub_status_id": "",
|
||||
"current_sub_status": "draft",
|
||||
"sub_statuses": [],
|
||||
"estimate_id": "",
|
||||
"is_client_review_settings_enabled": false,
|
||||
"unused_retainer_payments": 0.00,
|
||||
"credits_applied": 0.00,
|
||||
"tax_amount_withheld": 0.00,
|
||||
"schedule_time": "",
|
||||
"customer_default_billing_address": {
|
||||
"zip": "",
|
||||
"country": "",
|
||||
"address": "",
|
||||
"city": "",
|
||||
"phone": "",
|
||||
"street2": "",
|
||||
"state": "",
|
||||
"fax": "",
|
||||
"state_code": ""
|
||||
},
|
||||
"includes_package_tracking_info": false,
|
||||
"approvers_list": [],
|
||||
"qr_code": {
|
||||
"qr_source": "invoice_url",
|
||||
"is_qr_enabled": false,
|
||||
"qr_value": "",
|
||||
"qr_description": "Scan the QR code to view the configured information."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,5 @@
|
|||
version: '3.6'
|
||||
version: "3.6"
|
||||
services:
|
||||
|
||||
###############################################
|
||||
# Postgres DB
|
||||
###############################################
|
||||
|
|
@ -26,7 +25,7 @@ services:
|
|||
POSTGRES_CONNECTION: "jdbc:postgresql://db/office-alexander-logistics"
|
||||
TZ: "CET"
|
||||
LANG: "en_US.UTF-8"
|
||||
MAILGATEWAY: "mailgateway"
|
||||
MAILGATEWAY: "mailpit"
|
||||
|
||||
ASYNCEVENT_PROCESSOR_ENABLED: "true"
|
||||
ASYNCEVENT_PROCESSOR_INITIALDELAY: "10000"
|
||||
|
|
@ -37,8 +36,20 @@ services:
|
|||
#OCR_PDF_MODE: "OCR_ONLY | TEXT_ONLY | TEXT_AND_OCR (default)"
|
||||
OCR_PDF_MODE: "OCR_ONLY"
|
||||
|
||||
LLM_SERVICE_ENDPOINT_USER: "admin"
|
||||
LLM_SERVICE_ENDPOINT_PASSWORD: "imixs4.null"
|
||||
# Rest Service BusinessPartner API
|
||||
WORKFLOW_SERVICE_ENDPOINT: "http://app:8080/api"
|
||||
WORKFLOW_SERVICE_USER: "admin"
|
||||
WORKFLOW_SERVICE_PASSWORD: "adminadmin"
|
||||
|
||||
# LLM Integration
|
||||
LLM_CONFIG_FILE: /opt/jboss/imixs-llm.xml
|
||||
|
||||
# KSeF - Polen Test
|
||||
KSEF_API_NIP: "9552521552"
|
||||
KSEF_API_TOKEN: "20251113-EC-2751AC3000-5C5466924B-62|nip-9552521552|fc0c95d020dc45d4af491fb0aa755f3f3f674b33ecbf4250a88ea6e36fa8340b"
|
||||
KSEF_API_ENDPOINT: "https://ksef-test.mf.gov.pl/api/v2"
|
||||
|
||||
METRICS_ENABLED: "false"
|
||||
|
||||
ports:
|
||||
- "8080:8080"
|
||||
|
|
@ -46,21 +57,40 @@ services:
|
|||
- "8787:8787"
|
||||
volumes:
|
||||
- ./docker/deployments:/opt/jboss/wildfly/standalone/deployments/
|
||||
|
||||
- ./docker/keys/imixs-llm.xml:/opt/jboss/imixs-llm.xml
|
||||
- ./docker/transfer:/opt/jboss/wildfly/transfer/
|
||||
|
||||
###############################################
|
||||
# Tika OCR Service
|
||||
###############################################
|
||||
tika:
|
||||
#image: apache/tika:latest
|
||||
#image: apache/tika:1.24.1-full
|
||||
image: apache/tika:2.4.1-full
|
||||
image: apache/tika:3.2.0.0-full
|
||||
environment:
|
||||
TZ: "Europe/Berlin"
|
||||
ports:
|
||||
- "9998:9998"
|
||||
|
||||
|
||||
##################
|
||||
# Exporter Service
|
||||
##################
|
||||
# imixsexporter-app:
|
||||
# image: imixs/imixs-archive-exporter
|
||||
# environment:
|
||||
# # EXAMPLE SETUP
|
||||
# WORKFLOW_SERVICE_ENDPOINT: "http://app:8080/api"
|
||||
# WORKFLOW_SERVICE_USER: "admin"
|
||||
# WORKFLOW_SERVICE_PASSWORD: "adminadmin"
|
||||
# WORKFLOW_SERVICE_AUTHMETHOD: "form"
|
||||
# METRICS_ENDPOINT: "http://localhost:9991/metrics"
|
||||
# HEALTH_ENDPOINT: "http://localhost:9991/health"
|
||||
# EXPORT_PATH: "/agl/dwc-test"
|
||||
# EXPORT_FTP_HOST: "u248962.your-storagebox.de"
|
||||
# EXPORT_FTP_PORT: "21"
|
||||
# EXPORT_FTP_USER: "u248962-sub4"
|
||||
# EXPORT_FTP_PASSWORD: "en4g3f1Jw0WlQ9Yb"
|
||||
# ports:
|
||||
# - "8081:8080"
|
||||
# - "8788:8787"
|
||||
|
||||
###############################################
|
||||
# Imixs-Admin
|
||||
|
|
@ -73,18 +103,29 @@ services:
|
|||
###############################################
|
||||
# Mailgateway
|
||||
###############################################
|
||||
mailgateway:
|
||||
image: imixs/exim4
|
||||
mailpit:
|
||||
image: axllent/mailpit:latest
|
||||
container_name: mailpit
|
||||
environment:
|
||||
EXIM_SMARTHOST: "www149.your-server.de:25"
|
||||
EXIM_PASSWORD: "www149.your-server.de:webmaster@imixs.com:$MAILPASSWORD"
|
||||
EXIM_ALLOWED_SENDERS: "10.0.0.0/8:172.18.0.0/12:192.168.0.0/16"
|
||||
MP_SMTP_BIND_ADDR: "0.0.0.0:25"
|
||||
ports:
|
||||
- "1025:25" # Host:1025 -> Container:25 (SMTP)
|
||||
- "8025:8025" # Web UI
|
||||
restart: unless-stopped
|
||||
|
||||
# prometheus:
|
||||
# image: prom/prometheus:latest
|
||||
# ports:
|
||||
# - "9090:9090"
|
||||
# volumes:
|
||||
# - ./docker/prometheus/prometheus.yml:/etc/prometheus/prometheus.yml
|
||||
# - prometheusdata:/prometheus/
|
||||
|
||||
# grafana:
|
||||
# image: grafana/grafana:latest
|
||||
# ports:
|
||||
# - "3000:3000"
|
||||
|
||||
volumes:
|
||||
dbdata:
|
||||
|
||||
|
||||
|
||||
|
||||
prometheusdata:
|
||||
|
|
|
|||
4
docker/.env
Normal file
4
docker/.env
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
# LLM Config
|
||||
|
||||
LLM_API_ENDPOINT=https://api.llama.cpp.imixs.com/
|
||||
LLM_API_KEY=7fdb663fa87ea16731c1e0ece8ad3214e358423eabf2403188110c731ce07321
|
||||
220
docker/grafana/agl-dashboard.json
Normal file
220
docker/grafana/agl-dashboard.json
Normal file
|
|
@ -0,0 +1,220 @@
|
|||
{
|
||||
"annotations": {
|
||||
"list": [
|
||||
{
|
||||
"builtIn": 1,
|
||||
"datasource": {
|
||||
"type": "grafana",
|
||||
"uid": "-- Grafana --"
|
||||
},
|
||||
"enable": true,
|
||||
"hide": true,
|
||||
"iconColor": "rgba(0, 211, 255, 1)",
|
||||
"name": "Annotations & Alerts",
|
||||
"type": "dashboard"
|
||||
}
|
||||
]
|
||||
},
|
||||
"editable": true,
|
||||
"fiscalYearStartMonth": 0,
|
||||
"graphTooltip": 0,
|
||||
"id": 1,
|
||||
"links": [],
|
||||
"panels": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "ee5zvwsdjb400f"
|
||||
},
|
||||
"description": "",
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"fixedColor": "green",
|
||||
"mode": "fixed"
|
||||
},
|
||||
"decimals": 0,
|
||||
"mappings": [],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green"
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 80
|
||||
}
|
||||
]
|
||||
},
|
||||
"unit": "locale"
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 4,
|
||||
"w": 23,
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
"id": 2,
|
||||
"options": {
|
||||
"colorMode": "value",
|
||||
"graphMode": "none",
|
||||
"justifyMode": "auto",
|
||||
"orientation": "auto",
|
||||
"percentChangeColorMode": "standard",
|
||||
"reduceOptions": {
|
||||
"calcs": [
|
||||
"lastNotNull"
|
||||
],
|
||||
"fields": "",
|
||||
"values": false
|
||||
},
|
||||
"showPercentChange": false,
|
||||
"text": {
|
||||
"titleSize": 16,
|
||||
"valueSize": 30
|
||||
},
|
||||
"textMode": "value_and_name",
|
||||
"wideLayout": true
|
||||
},
|
||||
"pluginVersion": "11.3.2",
|
||||
"targets": [
|
||||
{
|
||||
"disableTextWrap": false,
|
||||
"editorMode": "code",
|
||||
"exemplar": false,
|
||||
"expr": "sum by(department, currency) (application_dbtr_balance{department=~\".+\"})",
|
||||
"fullMetaSearch": false,
|
||||
"hide": false,
|
||||
"includeNullMetadata": true,
|
||||
"instant": false,
|
||||
"interval": "",
|
||||
"legendFormat": "{{department}} {{currency}}",
|
||||
"range": true,
|
||||
"refId": "A",
|
||||
"useBackend": false
|
||||
}
|
||||
],
|
||||
"title": "Debitoren - Saldo",
|
||||
"type": "stat"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "ee5zvwsdjb400f"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "palette-classic"
|
||||
},
|
||||
"custom": {
|
||||
"axisBorderShow": false,
|
||||
"axisCenteredZero": false,
|
||||
"axisColorMode": "text",
|
||||
"axisLabel": "",
|
||||
"axisPlacement": "auto",
|
||||
"barAlignment": 0,
|
||||
"barWidthFactor": 0.6,
|
||||
"drawStyle": "line",
|
||||
"fillOpacity": 0,
|
||||
"gradientMode": "none",
|
||||
"hideFrom": {
|
||||
"legend": false,
|
||||
"tooltip": false,
|
||||
"viz": false
|
||||
},
|
||||
"insertNulls": false,
|
||||
"lineInterpolation": "linear",
|
||||
"lineWidth": 2,
|
||||
"pointSize": 5,
|
||||
"scaleDistribution": {
|
||||
"type": "linear"
|
||||
},
|
||||
"showPoints": "auto",
|
||||
"spanNulls": false,
|
||||
"stacking": {
|
||||
"group": "A",
|
||||
"mode": "none"
|
||||
},
|
||||
"thresholdsStyle": {
|
||||
"mode": "off"
|
||||
}
|
||||
},
|
||||
"mappings": [],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green"
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 80
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 9,
|
||||
"w": 24,
|
||||
"x": 0,
|
||||
"y": 4
|
||||
},
|
||||
"id": 1,
|
||||
"options": {
|
||||
"legend": {
|
||||
"calcs": [],
|
||||
"displayMode": "list",
|
||||
"placement": "bottom",
|
||||
"showLegend": true
|
||||
},
|
||||
"tooltip": {
|
||||
"mode": "single",
|
||||
"sort": "none"
|
||||
}
|
||||
},
|
||||
"pluginVersion": "11.3.2",
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "ee5zvwsdjb400f"
|
||||
},
|
||||
"disableTextWrap": false,
|
||||
"editorMode": "code",
|
||||
"exemplar": false,
|
||||
"expr": "sum by(department) (application_dbtr_balance{department=~\".+\"})",
|
||||
"fullMetaSearch": false,
|
||||
"includeNullMetadata": true,
|
||||
"legendFormat": "__auto",
|
||||
"range": true,
|
||||
"refId": "A",
|
||||
"useBackend": false
|
||||
}
|
||||
],
|
||||
"title": "Kreditor",
|
||||
"type": "timeseries"
|
||||
}
|
||||
],
|
||||
"preload": false,
|
||||
"schemaVersion": 40,
|
||||
"tags": [],
|
||||
"templating": {
|
||||
"list": []
|
||||
},
|
||||
"time": {
|
||||
"from": "now-6h",
|
||||
"to": "now"
|
||||
},
|
||||
"timepicker": {},
|
||||
"timezone": "browser",
|
||||
"title": "AGL",
|
||||
"uid": "ce5zwc5vzt5hce",
|
||||
"version": 14,
|
||||
"weekStart": ""
|
||||
}
|
||||
658
docker/grafana/debitoren-001.json
Normal file
658
docker/grafana/debitoren-001.json
Normal file
|
|
@ -0,0 +1,658 @@
|
|||
{
|
||||
"annotations": {
|
||||
"list": [
|
||||
{
|
||||
"builtIn": 1,
|
||||
"datasource": {
|
||||
"type": "grafana",
|
||||
"uid": "-- Grafana --"
|
||||
},
|
||||
"enable": true,
|
||||
"hide": true,
|
||||
"iconColor": "rgba(0, 211, 255, 1)",
|
||||
"name": "Annotations & Alerts",
|
||||
"type": "dashboard"
|
||||
}
|
||||
]
|
||||
},
|
||||
"editable": true,
|
||||
"fiscalYearStartMonth": 0,
|
||||
"graphTooltip": 0,
|
||||
"id": 5,
|
||||
"links": [],
|
||||
"panels": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "P1809F7CD0C75ACF3"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "fixed"
|
||||
},
|
||||
"custom": {
|
||||
"hideFrom": {
|
||||
"legend": false,
|
||||
"tooltip": false,
|
||||
"viz": false
|
||||
}
|
||||
},
|
||||
"mappings": [],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 80
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
"id": 8,
|
||||
"options": {
|
||||
"basemap": {
|
||||
"config": {
|
||||
"server": "streets",
|
||||
"showLabels": true,
|
||||
"theme": "auto"
|
||||
},
|
||||
"name": "Layer 0",
|
||||
"opacity": 1,
|
||||
"tooltip": false,
|
||||
"type": "esri-xyz"
|
||||
},
|
||||
"controls": {
|
||||
"mouseWheelZoom": true,
|
||||
"showAttribution": true,
|
||||
"showDebug": false,
|
||||
"showMeasure": false,
|
||||
"showScale": false,
|
||||
"showZoom": true
|
||||
},
|
||||
"layers": [
|
||||
{
|
||||
"config": {
|
||||
"showLegend": true,
|
||||
"style": {
|
||||
"color": {
|
||||
"fixed": "dark-green"
|
||||
},
|
||||
"opacity": 0.4,
|
||||
"rotation": {
|
||||
"fixed": 0,
|
||||
"max": 360,
|
||||
"min": -360,
|
||||
"mode": "mod"
|
||||
},
|
||||
"size": {
|
||||
"field": "Value",
|
||||
"fixed": 5,
|
||||
"max": 50,
|
||||
"min": 10
|
||||
},
|
||||
"symbol": {
|
||||
"fixed": "img/icons/marker/circle.svg",
|
||||
"mode": "fixed"
|
||||
},
|
||||
"symbolAlign": {
|
||||
"horizontal": "center",
|
||||
"vertical": "center"
|
||||
},
|
||||
"textConfig": {
|
||||
"fontSize": 12,
|
||||
"offsetX": 0,
|
||||
"offsetY": 0,
|
||||
"textAlign": "center",
|
||||
"textBaseline": "middle"
|
||||
}
|
||||
}
|
||||
},
|
||||
"filterData": {
|
||||
"id": "byRefId",
|
||||
"options": "A"
|
||||
},
|
||||
"location": {
|
||||
"mode": "lookup"
|
||||
},
|
||||
"name": "Layer 1",
|
||||
"tooltip": true,
|
||||
"type": "markers"
|
||||
}
|
||||
],
|
||||
"tooltip": {
|
||||
"mode": "details"
|
||||
},
|
||||
"view": {
|
||||
"allLayers": true,
|
||||
"id": "europe",
|
||||
"lat": 46,
|
||||
"lon": 14,
|
||||
"zoom": 4
|
||||
}
|
||||
},
|
||||
"pluginVersion": "11.4.0",
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "P1809F7CD0C75ACF3"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"expr": "sum(application_dbtr_balance) by (country)",
|
||||
"format": "table",
|
||||
"instant": false,
|
||||
"legendFormat": "__auto",
|
||||
"range": true,
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "",
|
||||
"transparent": true,
|
||||
"type": "geomap"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "P1809F7CD0C75ACF3"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"fixedColor": "yellow",
|
||||
"mode": "palette-classic"
|
||||
},
|
||||
"custom": {
|
||||
"hideFrom": {
|
||||
"legend": false,
|
||||
"tooltip": false,
|
||||
"viz": false
|
||||
}
|
||||
},
|
||||
"mappings": [],
|
||||
"unit": "locale"
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 8,
|
||||
"w": 5,
|
||||
"x": 12,
|
||||
"y": 0
|
||||
},
|
||||
"id": 9,
|
||||
"options": {
|
||||
"displayLabels": [],
|
||||
"legend": {
|
||||
"displayMode": "list",
|
||||
"placement": "bottom",
|
||||
"showLegend": true
|
||||
},
|
||||
"pieType": "pie",
|
||||
"reduceOptions": {
|
||||
"calcs": [
|
||||
"lastNotNull"
|
||||
],
|
||||
"fields": "",
|
||||
"values": false
|
||||
},
|
||||
"tooltip": {
|
||||
"mode": "single",
|
||||
"sort": "none"
|
||||
}
|
||||
},
|
||||
"pluginVersion": "11.4.0",
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "P1809F7CD0C75ACF3"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"expr": "sum(application_dbtr_balance{currency=\"EUR\"}) by (department)",
|
||||
"instant": false,
|
||||
"legendFormat": "__auto",
|
||||
"range": true,
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "EUR Abteilung",
|
||||
"type": "piechart"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "P1809F7CD0C75ACF3"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "palette-classic"
|
||||
},
|
||||
"custom": {
|
||||
"hideFrom": {
|
||||
"legend": false,
|
||||
"tooltip": false,
|
||||
"viz": false
|
||||
}
|
||||
},
|
||||
"mappings": []
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 8,
|
||||
"w": 5,
|
||||
"x": 17,
|
||||
"y": 0
|
||||
},
|
||||
"id": 2,
|
||||
"options": {
|
||||
"legend": {
|
||||
"displayMode": "list",
|
||||
"placement": "bottom",
|
||||
"showLegend": true
|
||||
},
|
||||
"pieType": "pie",
|
||||
"reduceOptions": {
|
||||
"calcs": [
|
||||
"lastNotNull"
|
||||
],
|
||||
"fields": "",
|
||||
"values": false
|
||||
},
|
||||
"tooltip": {
|
||||
"mode": "single",
|
||||
"sort": "none"
|
||||
}
|
||||
},
|
||||
"pluginVersion": "11.4.0",
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "P1809F7CD0C75ACF3"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"expr": "sum(application_dbtr_balance) by (currency)",
|
||||
"instant": false,
|
||||
"legendFormat": "__auto",
|
||||
"range": true,
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Verteilung nach Währung",
|
||||
"type": "piechart"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "P1809F7CD0C75ACF3"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "palette-classic"
|
||||
},
|
||||
"custom": {
|
||||
"axisBorderShow": true,
|
||||
"axisCenteredZero": false,
|
||||
"axisColorMode": "text",
|
||||
"axisLabel": "",
|
||||
"axisPlacement": "auto",
|
||||
"barAlignment": 0,
|
||||
"barWidthFactor": 0.6,
|
||||
"drawStyle": "line",
|
||||
"fillOpacity": 0,
|
||||
"gradientMode": "opacity",
|
||||
"hideFrom": {
|
||||
"legend": false,
|
||||
"tooltip": false,
|
||||
"viz": false
|
||||
},
|
||||
"insertNulls": false,
|
||||
"lineInterpolation": "linear",
|
||||
"lineWidth": 1,
|
||||
"pointSize": 5,
|
||||
"scaleDistribution": {
|
||||
"type": "linear"
|
||||
},
|
||||
"showPoints": "auto",
|
||||
"spanNulls": false,
|
||||
"stacking": {
|
||||
"group": "A",
|
||||
"mode": "none"
|
||||
},
|
||||
"thresholdsStyle": {
|
||||
"mode": "off"
|
||||
}
|
||||
},
|
||||
"mappings": [],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 80
|
||||
}
|
||||
]
|
||||
},
|
||||
"unit": "locale"
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 0,
|
||||
"y": 8
|
||||
},
|
||||
"id": 1,
|
||||
"options": {
|
||||
"legend": {
|
||||
"calcs": [],
|
||||
"displayMode": "list",
|
||||
"placement": "right",
|
||||
"showLegend": true
|
||||
},
|
||||
"tooltip": {
|
||||
"mode": "single",
|
||||
"sort": "none"
|
||||
}
|
||||
},
|
||||
"pluginVersion": "11.4.0",
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "P1809F7CD0C75ACF3"
|
||||
},
|
||||
"editorMode": "builder",
|
||||
"exemplar": false,
|
||||
"expr": "sum(application_dbtr_balance) by (department)",
|
||||
"format": "time_series",
|
||||
"hide": false,
|
||||
"instant": false,
|
||||
"interval": "",
|
||||
"legendFormat": "__auto",
|
||||
"range": true,
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Gesamtsaldo pro Abteilung",
|
||||
"type": "timeseries"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "P1809F7CD0C75ACF3"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "thresholds"
|
||||
},
|
||||
"mappings": [],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 80
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 8,
|
||||
"w": 5,
|
||||
"x": 17,
|
||||
"y": 8
|
||||
},
|
||||
"id": 4,
|
||||
"options": {
|
||||
"colorMode": "value",
|
||||
"graphMode": "area",
|
||||
"justifyMode": "auto",
|
||||
"orientation": "auto",
|
||||
"percentChangeColorMode": "standard",
|
||||
"reduceOptions": {
|
||||
"calcs": [
|
||||
"lastNotNull"
|
||||
],
|
||||
"fields": "",
|
||||
"values": false
|
||||
},
|
||||
"showPercentChange": false,
|
||||
"textMode": "auto",
|
||||
"wideLayout": true
|
||||
},
|
||||
"pluginVersion": "11.4.0",
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "P1809F7CD0C75ACF3"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"expr": "count(application_dbtr_balance)",
|
||||
"instant": false,
|
||||
"legendFormat": "__auto",
|
||||
"range": true,
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Anzahl der Debitoren",
|
||||
"type": "stat"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "P1809F7CD0C75ACF3"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "thresholds"
|
||||
},
|
||||
"custom": {
|
||||
"align": "auto",
|
||||
"cellOptions": {
|
||||
"type": "auto"
|
||||
},
|
||||
"inspect": false
|
||||
},
|
||||
"mappings": [],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 80
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"overrides": [
|
||||
{
|
||||
"matcher": {
|
||||
"id": "byName",
|
||||
"options": "Value (sum)"
|
||||
},
|
||||
"properties": [
|
||||
{
|
||||
"id": "unit",
|
||||
"value": "locale"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"matcher": {
|
||||
"id": "byName",
|
||||
"options": "currency"
|
||||
},
|
||||
"properties": [
|
||||
{
|
||||
"id": "custom.width",
|
||||
"value": 87
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"matcher": {
|
||||
"id": "byName",
|
||||
"options": "department"
|
||||
},
|
||||
"properties": [
|
||||
{
|
||||
"id": "custom.width",
|
||||
"value": 188
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"matcher": {
|
||||
"id": "byName",
|
||||
"options": "id"
|
||||
},
|
||||
"properties": [
|
||||
{
|
||||
"id": "custom.width",
|
||||
"value": 93
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 0,
|
||||
"y": 16
|
||||
},
|
||||
"id": 6,
|
||||
"options": {
|
||||
"cellHeight": "sm",
|
||||
"footer": {
|
||||
"countRows": false,
|
||||
"fields": "",
|
||||
"reducer": [
|
||||
"sum"
|
||||
],
|
||||
"show": false
|
||||
},
|
||||
"showHeader": true,
|
||||
"sortBy": []
|
||||
},
|
||||
"pluginVersion": "11.4.0",
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "P1809F7CD0C75ACF3"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"exemplar": false,
|
||||
"expr": "topk(5, application_dbtr_balance) ",
|
||||
"format": "table",
|
||||
"hide": false,
|
||||
"instant": false,
|
||||
"legendFormat": "__auto",
|
||||
"range": true,
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Panel Title",
|
||||
"transformations": [
|
||||
{
|
||||
"id": "groupBy",
|
||||
"options": {
|
||||
"fields": {
|
||||
"Value": {
|
||||
"aggregations": [
|
||||
"sum"
|
||||
],
|
||||
"operation": "aggregate"
|
||||
},
|
||||
"country": {
|
||||
"aggregations": [],
|
||||
"operation": "groupby"
|
||||
},
|
||||
"currency": {
|
||||
"aggregations": [],
|
||||
"operation": "groupby"
|
||||
},
|
||||
"department": {
|
||||
"aggregations": [],
|
||||
"operation": "groupby"
|
||||
},
|
||||
"id": {
|
||||
"aggregations": [],
|
||||
"operation": "groupby"
|
||||
},
|
||||
"name": {
|
||||
"aggregations": [],
|
||||
"operation": "groupby"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "sortBy",
|
||||
"options": {
|
||||
"fields": {},
|
||||
"sort": [
|
||||
{
|
||||
"desc": true,
|
||||
"field": "Value (sum)"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"type": "table"
|
||||
}
|
||||
],
|
||||
"preload": false,
|
||||
"schemaVersion": 40,
|
||||
"tags": [],
|
||||
"templating": {
|
||||
"list": []
|
||||
},
|
||||
"time": {
|
||||
"from": "now-6h",
|
||||
"to": "now"
|
||||
},
|
||||
"timepicker": {},
|
||||
"timezone": "browser",
|
||||
"title": "Übersicht Debitoren",
|
||||
"uid": "deb9z4knfuxhcc",
|
||||
"version": 10,
|
||||
"weekStart": ""
|
||||
}
|
||||
896
docker/grafana/debitoren-002.json
Normal file
896
docker/grafana/debitoren-002.json
Normal file
|
|
@ -0,0 +1,896 @@
|
|||
{
|
||||
"__inputs": [
|
||||
{
|
||||
"name": "DS_PROMETHEUS",
|
||||
"label": "prometheus",
|
||||
"description": "",
|
||||
"type": "datasource",
|
||||
"pluginId": "prometheus",
|
||||
"pluginName": "Prometheus"
|
||||
}
|
||||
],
|
||||
"__elements": {},
|
||||
"__requires": [
|
||||
{
|
||||
"type": "panel",
|
||||
"id": "bargauge",
|
||||
"name": "Bar gauge",
|
||||
"version": ""
|
||||
},
|
||||
{
|
||||
"type": "panel",
|
||||
"id": "geomap",
|
||||
"name": "Geomap",
|
||||
"version": ""
|
||||
},
|
||||
{
|
||||
"type": "grafana",
|
||||
"id": "grafana",
|
||||
"name": "Grafana",
|
||||
"version": "11.4.0"
|
||||
},
|
||||
{
|
||||
"type": "panel",
|
||||
"id": "piechart",
|
||||
"name": "Pie chart",
|
||||
"version": ""
|
||||
},
|
||||
{
|
||||
"type": "datasource",
|
||||
"id": "prometheus",
|
||||
"name": "Prometheus",
|
||||
"version": "1.0.0"
|
||||
},
|
||||
{
|
||||
"type": "panel",
|
||||
"id": "stat",
|
||||
"name": "Stat",
|
||||
"version": ""
|
||||
},
|
||||
{
|
||||
"type": "panel",
|
||||
"id": "table",
|
||||
"name": "Table",
|
||||
"version": ""
|
||||
},
|
||||
{
|
||||
"type": "panel",
|
||||
"id": "timeseries",
|
||||
"name": "Time series",
|
||||
"version": ""
|
||||
}
|
||||
],
|
||||
"annotations": {
|
||||
"list": [
|
||||
{
|
||||
"builtIn": 1,
|
||||
"datasource": {
|
||||
"type": "grafana",
|
||||
"uid": "-- Grafana --"
|
||||
},
|
||||
"enable": true,
|
||||
"hide": true,
|
||||
"iconColor": "rgba(0, 211, 255, 1)",
|
||||
"name": "Annotations & Alerts",
|
||||
"type": "dashboard"
|
||||
}
|
||||
]
|
||||
},
|
||||
"editable": true,
|
||||
"fiscalYearStartMonth": 0,
|
||||
"graphTooltip": 0,
|
||||
"id": null,
|
||||
"links": [],
|
||||
"panels": [
|
||||
{
|
||||
"collapsed": false,
|
||||
"gridPos": {
|
||||
"h": 1,
|
||||
"w": 24,
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
"id": 14,
|
||||
"panels": [],
|
||||
"title": "Salden Übersicht",
|
||||
"type": "row"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "${DS_PROMETHEUS}"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "fixed"
|
||||
},
|
||||
"custom": {
|
||||
"hideFrom": {
|
||||
"legend": false,
|
||||
"tooltip": false,
|
||||
"viz": false
|
||||
}
|
||||
},
|
||||
"mappings": [],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 80
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 8,
|
||||
"w": 15,
|
||||
"x": 0,
|
||||
"y": 1
|
||||
},
|
||||
"id": 8,
|
||||
"options": {
|
||||
"basemap": {
|
||||
"config": {
|
||||
"server": "streets",
|
||||
"showLabels": true,
|
||||
"theme": "auto"
|
||||
},
|
||||
"name": "Layer 0",
|
||||
"opacity": 1,
|
||||
"tooltip": false,
|
||||
"type": "esri-xyz"
|
||||
},
|
||||
"controls": {
|
||||
"mouseWheelZoom": true,
|
||||
"showAttribution": true,
|
||||
"showDebug": false,
|
||||
"showMeasure": false,
|
||||
"showScale": false,
|
||||
"showZoom": true
|
||||
},
|
||||
"layers": [
|
||||
{
|
||||
"config": {
|
||||
"showLegend": true,
|
||||
"style": {
|
||||
"color": {
|
||||
"fixed": "dark-green"
|
||||
},
|
||||
"opacity": 0.4,
|
||||
"rotation": {
|
||||
"fixed": 0,
|
||||
"max": 360,
|
||||
"min": -360,
|
||||
"mode": "mod"
|
||||
},
|
||||
"size": {
|
||||
"field": "Value",
|
||||
"fixed": 5,
|
||||
"max": 50,
|
||||
"min": 10
|
||||
},
|
||||
"symbol": {
|
||||
"fixed": "img/icons/marker/circle.svg",
|
||||
"mode": "fixed"
|
||||
},
|
||||
"symbolAlign": {
|
||||
"horizontal": "center",
|
||||
"vertical": "center"
|
||||
},
|
||||
"textConfig": {
|
||||
"fontSize": 12,
|
||||
"offsetX": 0,
|
||||
"offsetY": 0,
|
||||
"textAlign": "center",
|
||||
"textBaseline": "middle"
|
||||
}
|
||||
}
|
||||
},
|
||||
"filterData": {
|
||||
"id": "byRefId",
|
||||
"options": "A"
|
||||
},
|
||||
"location": {
|
||||
"mode": "lookup"
|
||||
},
|
||||
"name": "Layer 1",
|
||||
"tooltip": true,
|
||||
"type": "markers"
|
||||
}
|
||||
],
|
||||
"tooltip": {
|
||||
"mode": "details"
|
||||
},
|
||||
"view": {
|
||||
"allLayers": true,
|
||||
"id": "europe",
|
||||
"lat": 46,
|
||||
"lon": 14,
|
||||
"zoom": 4
|
||||
}
|
||||
},
|
||||
"pluginVersion": "11.4.0",
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "${DS_PROMETHEUS}"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"expr": "sum(application_dbtr_balance) by (country)",
|
||||
"format": "table",
|
||||
"instant": false,
|
||||
"legendFormat": "__auto",
|
||||
"range": true,
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"transparent": true,
|
||||
"type": "geomap"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "${DS_PROMETHEUS}"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"fixedColor": "yellow",
|
||||
"mode": "palette-classic"
|
||||
},
|
||||
"custom": {
|
||||
"hideFrom": {
|
||||
"legend": false,
|
||||
"tooltip": false,
|
||||
"viz": false
|
||||
}
|
||||
},
|
||||
"mappings": [],
|
||||
"unit": "locale"
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 8,
|
||||
"w": 5,
|
||||
"x": 15,
|
||||
"y": 1
|
||||
},
|
||||
"id": 9,
|
||||
"options": {
|
||||
"displayLabels": [],
|
||||
"legend": {
|
||||
"displayMode": "list",
|
||||
"placement": "bottom",
|
||||
"showLegend": true
|
||||
},
|
||||
"pieType": "pie",
|
||||
"reduceOptions": {
|
||||
"calcs": [
|
||||
"lastNotNull"
|
||||
],
|
||||
"fields": "",
|
||||
"values": false
|
||||
},
|
||||
"tooltip": {
|
||||
"mode": "single",
|
||||
"sort": "none"
|
||||
}
|
||||
},
|
||||
"pluginVersion": "11.4.0",
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "${DS_PROMETHEUS}"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"expr": "sum(application_dbtr_balance{currency=~\"$currency\"}) by (department)",
|
||||
"instant": false,
|
||||
"legendFormat": "__auto",
|
||||
"range": true,
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "$currency nach Abteilung",
|
||||
"type": "piechart"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "${DS_PROMETHEUS}"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "palette-classic"
|
||||
},
|
||||
"custom": {
|
||||
"hideFrom": {
|
||||
"legend": false,
|
||||
"tooltip": false,
|
||||
"viz": false
|
||||
}
|
||||
},
|
||||
"mappings": []
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 8,
|
||||
"w": 4,
|
||||
"x": 20,
|
||||
"y": 1
|
||||
},
|
||||
"id": 2,
|
||||
"options": {
|
||||
"legend": {
|
||||
"displayMode": "list",
|
||||
"placement": "bottom",
|
||||
"showLegend": true
|
||||
},
|
||||
"pieType": "pie",
|
||||
"reduceOptions": {
|
||||
"calcs": [
|
||||
"lastNotNull"
|
||||
],
|
||||
"fields": "",
|
||||
"values": false
|
||||
},
|
||||
"tooltip": {
|
||||
"mode": "single",
|
||||
"sort": "none"
|
||||
}
|
||||
},
|
||||
"pluginVersion": "11.4.0",
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "${DS_PROMETHEUS}"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"expr": "sum(application_dbtr_balance) by (currency)",
|
||||
"instant": false,
|
||||
"legendFormat": "__auto",
|
||||
"range": true,
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Verteilung nach Währung",
|
||||
"type": "piechart"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "${DS_PROMETHEUS}"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "palette-classic-by-name"
|
||||
},
|
||||
"mappings": [],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 80
|
||||
}
|
||||
]
|
||||
},
|
||||
"unit": "locale"
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 6,
|
||||
"w": 20,
|
||||
"x": 0,
|
||||
"y": 9
|
||||
},
|
||||
"id": 11,
|
||||
"options": {
|
||||
"displayMode": "basic",
|
||||
"legend": {
|
||||
"calcs": [],
|
||||
"displayMode": "list",
|
||||
"placement": "bottom",
|
||||
"showLegend": false
|
||||
},
|
||||
"maxVizHeight": 300,
|
||||
"minVizHeight": 16,
|
||||
"minVizWidth": 8,
|
||||
"namePlacement": "auto",
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
"calcs": [
|
||||
"lastNotNull"
|
||||
],
|
||||
"fields": "",
|
||||
"values": false
|
||||
},
|
||||
"showUnfilled": true,
|
||||
"sizing": "auto",
|
||||
"text": {
|
||||
"titleSize": 10,
|
||||
"valueSize": 10
|
||||
},
|
||||
"valueMode": "color"
|
||||
},
|
||||
"pluginVersion": "11.4.0",
|
||||
"targets": [
|
||||
{
|
||||
"editorMode": "code",
|
||||
"expr": "sum by (department) (application_cdtr_balance{currency=~\"$currency\"})",
|
||||
"legendFormat": "__auto",
|
||||
"range": true,
|
||||
"refId": "A",
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "${DS_PROMETHEUS}"
|
||||
}
|
||||
}
|
||||
],
|
||||
"title": "Saldo in $currency nach Abteilung",
|
||||
"type": "bargauge"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "${DS_PROMETHEUS}"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "thresholds"
|
||||
},
|
||||
"mappings": [],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 80
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 6,
|
||||
"w": 4,
|
||||
"x": 20,
|
||||
"y": 9
|
||||
},
|
||||
"id": 4,
|
||||
"options": {
|
||||
"colorMode": "value",
|
||||
"graphMode": "area",
|
||||
"justifyMode": "auto",
|
||||
"orientation": "auto",
|
||||
"percentChangeColorMode": "standard",
|
||||
"reduceOptions": {
|
||||
"calcs": [
|
||||
"lastNotNull"
|
||||
],
|
||||
"fields": "",
|
||||
"values": false
|
||||
},
|
||||
"showPercentChange": false,
|
||||
"textMode": "auto",
|
||||
"wideLayout": true
|
||||
},
|
||||
"pluginVersion": "11.4.0",
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "${DS_PROMETHEUS}"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"expr": "count(application_dbtr_balance)",
|
||||
"instant": false,
|
||||
"legendFormat": "__auto",
|
||||
"range": true,
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Anzahl der Debitoren",
|
||||
"type": "stat"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "${DS_PROMETHEUS}"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "palette-classic"
|
||||
},
|
||||
"custom": {
|
||||
"axisBorderShow": true,
|
||||
"axisCenteredZero": false,
|
||||
"axisColorMode": "text",
|
||||
"axisLabel": "",
|
||||
"axisPlacement": "auto",
|
||||
"barAlignment": 0,
|
||||
"barWidthFactor": 0.6,
|
||||
"drawStyle": "line",
|
||||
"fillOpacity": 30,
|
||||
"gradientMode": "opacity",
|
||||
"hideFrom": {
|
||||
"legend": false,
|
||||
"tooltip": false,
|
||||
"viz": false
|
||||
},
|
||||
"insertNulls": false,
|
||||
"lineInterpolation": "smooth",
|
||||
"lineStyle": {
|
||||
"fill": "solid"
|
||||
},
|
||||
"lineWidth": 3,
|
||||
"pointSize": 9,
|
||||
"scaleDistribution": {
|
||||
"type": "linear"
|
||||
},
|
||||
"showPoints": "auto",
|
||||
"spanNulls": true,
|
||||
"stacking": {
|
||||
"group": "A",
|
||||
"mode": "none"
|
||||
},
|
||||
"thresholdsStyle": {
|
||||
"mode": "off"
|
||||
}
|
||||
},
|
||||
"mappings": [],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 80
|
||||
}
|
||||
]
|
||||
},
|
||||
"unit": "locale"
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 0,
|
||||
"y": 15
|
||||
},
|
||||
"id": 1,
|
||||
"options": {
|
||||
"legend": {
|
||||
"calcs": [],
|
||||
"displayMode": "list",
|
||||
"placement": "right",
|
||||
"showLegend": false
|
||||
},
|
||||
"tooltip": {
|
||||
"mode": "single",
|
||||
"sort": "none"
|
||||
}
|
||||
},
|
||||
"pluginVersion": "11.4.0",
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "${DS_PROMETHEUS}"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"exemplar": false,
|
||||
"expr": "sum(application_dbtr_balance{currency=~\"$currency\", department=~\"$department\"}) ",
|
||||
"format": "time_series",
|
||||
"hide": false,
|
||||
"instant": false,
|
||||
"interval": "",
|
||||
"legendFormat": "__auto",
|
||||
"range": true,
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "$department - Saldo in $currency",
|
||||
"type": "timeseries"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "${DS_PROMETHEUS}"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "thresholds"
|
||||
},
|
||||
"custom": {
|
||||
"align": "auto",
|
||||
"cellOptions": {
|
||||
"type": "auto"
|
||||
},
|
||||
"inspect": false
|
||||
},
|
||||
"mappings": [],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 80
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"overrides": [
|
||||
{
|
||||
"matcher": {
|
||||
"id": "byName",
|
||||
"options": "Value (sum)"
|
||||
},
|
||||
"properties": [
|
||||
{
|
||||
"id": "unit",
|
||||
"value": "locale"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"matcher": {
|
||||
"id": "byName",
|
||||
"options": "currency"
|
||||
},
|
||||
"properties": [
|
||||
{
|
||||
"id": "custom.width",
|
||||
"value": 81
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"matcher": {
|
||||
"id": "byName",
|
||||
"options": "department"
|
||||
},
|
||||
"properties": [
|
||||
{
|
||||
"id": "custom.width",
|
||||
"value": 188
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"matcher": {
|
||||
"id": "byName",
|
||||
"options": "id"
|
||||
},
|
||||
"properties": [
|
||||
{
|
||||
"id": "custom.width",
|
||||
"value": 93
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"matcher": {
|
||||
"id": "byName",
|
||||
"options": "country"
|
||||
},
|
||||
"properties": [
|
||||
{
|
||||
"id": "custom.width",
|
||||
"value": 81
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"matcher": {
|
||||
"id": "byName",
|
||||
"options": "Kunde"
|
||||
},
|
||||
"properties": [
|
||||
{
|
||||
"id": "custom.width",
|
||||
"value": 308
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 12,
|
||||
"y": 15
|
||||
},
|
||||
"id": 6,
|
||||
"options": {
|
||||
"cellHeight": "sm",
|
||||
"footer": {
|
||||
"countRows": false,
|
||||
"fields": "",
|
||||
"reducer": [
|
||||
"sum"
|
||||
],
|
||||
"show": false
|
||||
},
|
||||
"showHeader": true,
|
||||
"sortBy": []
|
||||
},
|
||||
"pluginVersion": "11.4.0",
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "${DS_PROMETHEUS}"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"exemplar": false,
|
||||
"expr": "topk(5,application_dbtr_balance{currency=~\"$currency\", department=~\"$department\"}) ",
|
||||
"format": "table",
|
||||
"hide": false,
|
||||
"instant": false,
|
||||
"legendFormat": "__auto",
|
||||
"range": true,
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Top 5",
|
||||
"transformations": [
|
||||
{
|
||||
"id": "groupBy",
|
||||
"options": {
|
||||
"fields": {
|
||||
"Value": {
|
||||
"aggregations": [
|
||||
"sum"
|
||||
],
|
||||
"operation": "aggregate"
|
||||
},
|
||||
"country": {
|
||||
"aggregations": [],
|
||||
"operation": "groupby"
|
||||
},
|
||||
"currency": {
|
||||
"aggregations": [],
|
||||
"operation": "groupby"
|
||||
},
|
||||
"department": {
|
||||
"aggregations": []
|
||||
},
|
||||
"id": {
|
||||
"aggregations": [],
|
||||
"operation": "groupby"
|
||||
},
|
||||
"name": {
|
||||
"aggregations": [],
|
||||
"operation": "groupby"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "sortBy",
|
||||
"options": {
|
||||
"fields": {},
|
||||
"sort": [
|
||||
{
|
||||
"desc": true,
|
||||
"field": "Value (sum)"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "organize",
|
||||
"options": {
|
||||
"excludeByName": {},
|
||||
"includeByName": {},
|
||||
"indexByName": {
|
||||
"Value (sum)": 3,
|
||||
"country": 2,
|
||||
"currency": 4,
|
||||
"id": 1,
|
||||
"name": 0
|
||||
},
|
||||
"renameByName": {
|
||||
"Value (sum)": "Saldo Aktuell",
|
||||
"country": "Land",
|
||||
"currency": " ",
|
||||
"id": "Nummer",
|
||||
"name": "Kunde"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"type": "table"
|
||||
}
|
||||
],
|
||||
"schemaVersion": 40,
|
||||
"tags": [],
|
||||
"templating": {
|
||||
"list": [
|
||||
{
|
||||
"current": {},
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "${DS_PROMETHEUS}"
|
||||
},
|
||||
"definition": "label_values(currency)",
|
||||
"label": "Währung",
|
||||
"name": "currency",
|
||||
"options": [],
|
||||
"query": {
|
||||
"qryType": 1,
|
||||
"query": "label_values(currency)",
|
||||
"refId": "PrometheusVariableQueryEditor-VariableQuery"
|
||||
},
|
||||
"refresh": 1,
|
||||
"regex": "",
|
||||
"type": "query"
|
||||
},
|
||||
{
|
||||
"current": {},
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "${DS_PROMETHEUS}"
|
||||
},
|
||||
"definition": "label_values(department)",
|
||||
"label": "Abteilung",
|
||||
"name": "department",
|
||||
"options": [],
|
||||
"query": {
|
||||
"qryType": 1,
|
||||
"query": "label_values(department)",
|
||||
"refId": "PrometheusVariableQueryEditor-VariableQuery"
|
||||
},
|
||||
"refresh": 1,
|
||||
"regex": "",
|
||||
"type": "query"
|
||||
}
|
||||
]
|
||||
},
|
||||
"time": {
|
||||
"from": "now-12h",
|
||||
"to": "now"
|
||||
},
|
||||
"timepicker": {},
|
||||
"timezone": "browser",
|
||||
"title": "Übersicht Debitoren",
|
||||
"uid": "deb9z4knfuxhcc",
|
||||
"version": 20,
|
||||
"weekStart": ""
|
||||
}
|
||||
888
docker/grafana/debitoren-003.json
Normal file
888
docker/grafana/debitoren-003.json
Normal file
|
|
@ -0,0 +1,888 @@
|
|||
{
|
||||
"__inputs": [
|
||||
{
|
||||
"name": "DS_PROMETHEUS",
|
||||
"label": "prometheus",
|
||||
"description": "",
|
||||
"type": "datasource",
|
||||
"pluginId": "prometheus",
|
||||
"pluginName": "Prometheus"
|
||||
}
|
||||
],
|
||||
"__elements": {},
|
||||
"__requires": [
|
||||
{
|
||||
"type": "panel",
|
||||
"id": "bargauge",
|
||||
"name": "Bar gauge",
|
||||
"version": ""
|
||||
},
|
||||
{
|
||||
"type": "panel",
|
||||
"id": "geomap",
|
||||
"name": "Geomap",
|
||||
"version": ""
|
||||
},
|
||||
{
|
||||
"type": "grafana",
|
||||
"id": "grafana",
|
||||
"name": "Grafana",
|
||||
"version": "11.4.0"
|
||||
},
|
||||
{
|
||||
"type": "panel",
|
||||
"id": "piechart",
|
||||
"name": "Pie chart",
|
||||
"version": ""
|
||||
},
|
||||
{
|
||||
"type": "datasource",
|
||||
"id": "prometheus",
|
||||
"name": "Prometheus",
|
||||
"version": "1.0.0"
|
||||
},
|
||||
{
|
||||
"type": "panel",
|
||||
"id": "stat",
|
||||
"name": "Stat",
|
||||
"version": ""
|
||||
},
|
||||
{
|
||||
"type": "panel",
|
||||
"id": "table",
|
||||
"name": "Table",
|
||||
"version": ""
|
||||
},
|
||||
{
|
||||
"type": "panel",
|
||||
"id": "timeseries",
|
||||
"name": "Time series",
|
||||
"version": ""
|
||||
}
|
||||
],
|
||||
"annotations": {
|
||||
"list": [
|
||||
{
|
||||
"builtIn": 1,
|
||||
"datasource": {
|
||||
"type": "grafana",
|
||||
"uid": "-- Grafana --"
|
||||
},
|
||||
"enable": true,
|
||||
"hide": true,
|
||||
"iconColor": "rgba(0, 211, 255, 1)",
|
||||
"name": "Annotations & Alerts",
|
||||
"type": "dashboard"
|
||||
}
|
||||
]
|
||||
},
|
||||
"editable": true,
|
||||
"fiscalYearStartMonth": 0,
|
||||
"graphTooltip": 0,
|
||||
"id": null,
|
||||
"links": [],
|
||||
"panels": [
|
||||
{
|
||||
"collapsed": false,
|
||||
"gridPos": {
|
||||
"h": 1,
|
||||
"w": 24,
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
"id": 14,
|
||||
"panels": [],
|
||||
"title": "Salden Übersicht Debitoren",
|
||||
"type": "row"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "${DS_PROMETHEUS}"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "fixed"
|
||||
},
|
||||
"custom": {
|
||||
"hideFrom": {
|
||||
"legend": false,
|
||||
"tooltip": false,
|
||||
"viz": false
|
||||
}
|
||||
},
|
||||
"mappings": [],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 80
|
||||
}
|
||||
]
|
||||
},
|
||||
"unit": "locale"
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 9,
|
||||
"w": 15,
|
||||
"x": 0,
|
||||
"y": 1
|
||||
},
|
||||
"id": 8,
|
||||
"options": {
|
||||
"basemap": {
|
||||
"config": {
|
||||
"server": "streets",
|
||||
"showLabels": true,
|
||||
"theme": "auto"
|
||||
},
|
||||
"name": "Layer 0",
|
||||
"opacity": 1,
|
||||
"tooltip": false,
|
||||
"type": "esri-xyz"
|
||||
},
|
||||
"controls": {
|
||||
"mouseWheelZoom": true,
|
||||
"showAttribution": true,
|
||||
"showDebug": false,
|
||||
"showMeasure": false,
|
||||
"showScale": false,
|
||||
"showZoom": true
|
||||
},
|
||||
"layers": [
|
||||
{
|
||||
"config": {
|
||||
"showLegend": false,
|
||||
"style": {
|
||||
"color": {
|
||||
"fixed": "blue"
|
||||
},
|
||||
"opacity": 0.4,
|
||||
"rotation": {
|
||||
"fixed": 0,
|
||||
"max": 360,
|
||||
"min": -360,
|
||||
"mode": "mod"
|
||||
},
|
||||
"size": {
|
||||
"field": "Value",
|
||||
"fixed": 5,
|
||||
"max": 60,
|
||||
"min": 10
|
||||
},
|
||||
"symbol": {
|
||||
"fixed": "img/icons/marker/circle.svg",
|
||||
"mode": "fixed"
|
||||
},
|
||||
"symbolAlign": {
|
||||
"horizontal": "center",
|
||||
"vertical": "center"
|
||||
},
|
||||
"textConfig": {
|
||||
"fontSize": 12,
|
||||
"offsetX": 0,
|
||||
"offsetY": 0,
|
||||
"textAlign": "center",
|
||||
"textBaseline": "middle"
|
||||
}
|
||||
}
|
||||
},
|
||||
"filterData": {
|
||||
"id": "byRefId",
|
||||
"options": "A"
|
||||
},
|
||||
"location": {
|
||||
"lookup": "country",
|
||||
"mode": "lookup"
|
||||
},
|
||||
"name": "Saldo",
|
||||
"tooltip": true,
|
||||
"type": "markers"
|
||||
}
|
||||
],
|
||||
"tooltip": {
|
||||
"mode": "details"
|
||||
},
|
||||
"view": {
|
||||
"allLayers": true,
|
||||
"id": "europe",
|
||||
"lat": 46,
|
||||
"lon": 14,
|
||||
"zoom": 4
|
||||
}
|
||||
},
|
||||
"pluginVersion": "11.4.0",
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "${DS_PROMETHEUS}"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"exemplar": false,
|
||||
"expr": "sum(last_over_time(application_dbtr_balance{currency=~\"$currency\"}[24h])) by (country, currency)",
|
||||
"format": "table",
|
||||
"instant": true,
|
||||
"legendFormat": "__auto",
|
||||
"range": false,
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"type": "geomap"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "${DS_PROMETHEUS}"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"fixedColor": "yellow",
|
||||
"mode": "palette-classic"
|
||||
},
|
||||
"custom": {
|
||||
"hideFrom": {
|
||||
"legend": false,
|
||||
"tooltip": false,
|
||||
"viz": false
|
||||
}
|
||||
},
|
||||
"mappings": [],
|
||||
"unit": "locale"
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 9,
|
||||
"w": 5,
|
||||
"x": 15,
|
||||
"y": 1
|
||||
},
|
||||
"id": 9,
|
||||
"options": {
|
||||
"displayLabels": [],
|
||||
"legend": {
|
||||
"displayMode": "list",
|
||||
"placement": "bottom",
|
||||
"showLegend": true
|
||||
},
|
||||
"pieType": "pie",
|
||||
"reduceOptions": {
|
||||
"calcs": [
|
||||
"lastNotNull"
|
||||
],
|
||||
"fields": "",
|
||||
"values": false
|
||||
},
|
||||
"tooltip": {
|
||||
"mode": "single",
|
||||
"sort": "none"
|
||||
}
|
||||
},
|
||||
"pluginVersion": "11.4.0",
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "${DS_PROMETHEUS}"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"exemplar": false,
|
||||
"expr": "sum(application_dbtr_balance{currency=~\"$currency\"}) by (department)",
|
||||
"format": "time_series",
|
||||
"instant": true,
|
||||
"legendFormat": "__auto",
|
||||
"range": true,
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "$currency nach Abteilung",
|
||||
"type": "piechart"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "${DS_PROMETHEUS}"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "palette-classic"
|
||||
},
|
||||
"custom": {
|
||||
"hideFrom": {
|
||||
"legend": false,
|
||||
"tooltip": false,
|
||||
"viz": false
|
||||
}
|
||||
},
|
||||
"mappings": []
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 9,
|
||||
"w": 4,
|
||||
"x": 20,
|
||||
"y": 1
|
||||
},
|
||||
"id": 2,
|
||||
"options": {
|
||||
"legend": {
|
||||
"displayMode": "list",
|
||||
"placement": "bottom",
|
||||
"showLegend": true
|
||||
},
|
||||
"pieType": "pie",
|
||||
"reduceOptions": {
|
||||
"calcs": [
|
||||
"lastNotNull"
|
||||
],
|
||||
"fields": "",
|
||||
"values": false
|
||||
},
|
||||
"tooltip": {
|
||||
"mode": "single",
|
||||
"sort": "none"
|
||||
}
|
||||
},
|
||||
"pluginVersion": "11.4.0",
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "${DS_PROMETHEUS}"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"expr": "sum(application_dbtr_balance) by (currency)",
|
||||
"instant": false,
|
||||
"legendFormat": "__auto",
|
||||
"range": true,
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Verteilung nach Währung",
|
||||
"type": "piechart"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "${DS_PROMETHEUS}"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "palette-classic-by-name"
|
||||
},
|
||||
"mappings": [],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 80
|
||||
}
|
||||
]
|
||||
},
|
||||
"unit": "locale"
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 6,
|
||||
"w": 20,
|
||||
"x": 0,
|
||||
"y": 10
|
||||
},
|
||||
"id": 11,
|
||||
"options": {
|
||||
"displayMode": "basic",
|
||||
"legend": {
|
||||
"calcs": [],
|
||||
"displayMode": "list",
|
||||
"placement": "bottom",
|
||||
"showLegend": false
|
||||
},
|
||||
"maxVizHeight": 300,
|
||||
"minVizHeight": 16,
|
||||
"minVizWidth": 8,
|
||||
"namePlacement": "auto",
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
"calcs": [
|
||||
"lastNotNull"
|
||||
],
|
||||
"fields": "",
|
||||
"values": false
|
||||
},
|
||||
"showUnfilled": true,
|
||||
"sizing": "auto",
|
||||
"text": {
|
||||
"titleSize": 10,
|
||||
"valueSize": 10
|
||||
},
|
||||
"valueMode": "color"
|
||||
},
|
||||
"pluginVersion": "11.4.0",
|
||||
"targets": [
|
||||
{
|
||||
"editorMode": "code",
|
||||
"expr": "sum by (department) (application_dbtr_balance{currency=~\"$currency\"})",
|
||||
"legendFormat": "__auto",
|
||||
"range": true,
|
||||
"refId": "A",
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "${DS_PROMETHEUS}"
|
||||
}
|
||||
}
|
||||
],
|
||||
"title": "Saldo in $currency nach Abteilung",
|
||||
"type": "bargauge"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "${DS_PROMETHEUS}"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "thresholds"
|
||||
},
|
||||
"mappings": [],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 80
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 6,
|
||||
"w": 4,
|
||||
"x": 20,
|
||||
"y": 10
|
||||
},
|
||||
"id": 4,
|
||||
"options": {
|
||||
"colorMode": "value",
|
||||
"graphMode": "area",
|
||||
"justifyMode": "auto",
|
||||
"orientation": "auto",
|
||||
"percentChangeColorMode": "standard",
|
||||
"reduceOptions": {
|
||||
"calcs": [
|
||||
"lastNotNull"
|
||||
],
|
||||
"fields": "",
|
||||
"values": false
|
||||
},
|
||||
"showPercentChange": false,
|
||||
"textMode": "auto",
|
||||
"wideLayout": true
|
||||
},
|
||||
"pluginVersion": "11.4.0",
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "${DS_PROMETHEUS}"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"expr": "count(last_over_time(application_dbtr_balance[2h]))",
|
||||
"hide": false,
|
||||
"instant": false,
|
||||
"legendFormat": "__auto",
|
||||
"range": true,
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Anzahl der Debitoren",
|
||||
"type": "stat"
|
||||
},
|
||||
{
|
||||
"collapsed": false,
|
||||
"gridPos": {
|
||||
"h": 1,
|
||||
"w": 24,
|
||||
"x": 0,
|
||||
"y": 16
|
||||
},
|
||||
"id": 16,
|
||||
"panels": [],
|
||||
"title": "Salden Übersicht Debitoren - nach Abteilung",
|
||||
"type": "row"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "${DS_PROMETHEUS}"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "palette-classic"
|
||||
},
|
||||
"custom": {
|
||||
"axisBorderShow": true,
|
||||
"axisCenteredZero": false,
|
||||
"axisColorMode": "text",
|
||||
"axisLabel": "",
|
||||
"axisPlacement": "auto",
|
||||
"barAlignment": 0,
|
||||
"barWidthFactor": 0.6,
|
||||
"drawStyle": "line",
|
||||
"fillOpacity": 30,
|
||||
"gradientMode": "opacity",
|
||||
"hideFrom": {
|
||||
"legend": false,
|
||||
"tooltip": false,
|
||||
"viz": false
|
||||
},
|
||||
"insertNulls": false,
|
||||
"lineInterpolation": "smooth",
|
||||
"lineStyle": {
|
||||
"fill": "solid"
|
||||
},
|
||||
"lineWidth": 3,
|
||||
"pointSize": 9,
|
||||
"scaleDistribution": {
|
||||
"type": "linear"
|
||||
},
|
||||
"showPoints": "auto",
|
||||
"spanNulls": true,
|
||||
"stacking": {
|
||||
"group": "A",
|
||||
"mode": "none"
|
||||
},
|
||||
"thresholdsStyle": {
|
||||
"mode": "off"
|
||||
}
|
||||
},
|
||||
"mappings": [],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 80
|
||||
}
|
||||
]
|
||||
},
|
||||
"unit": "locale"
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 9,
|
||||
"w": 12,
|
||||
"x": 0,
|
||||
"y": 17
|
||||
},
|
||||
"id": 1,
|
||||
"options": {
|
||||
"legend": {
|
||||
"calcs": [],
|
||||
"displayMode": "list",
|
||||
"placement": "right",
|
||||
"showLegend": false
|
||||
},
|
||||
"tooltip": {
|
||||
"mode": "single",
|
||||
"sort": "none"
|
||||
}
|
||||
},
|
||||
"pluginVersion": "11.4.0",
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "${DS_PROMETHEUS}"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"exemplar": false,
|
||||
"expr": "sum(application_dbtr_balance{currency=~\"$currency\", department=~\"$department\"}) ",
|
||||
"format": "time_series",
|
||||
"hide": false,
|
||||
"instant": false,
|
||||
"interval": "",
|
||||
"legendFormat": "__auto",
|
||||
"range": true,
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "$department - Saldo in $currency",
|
||||
"type": "timeseries"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "${DS_PROMETHEUS}"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "thresholds"
|
||||
},
|
||||
"custom": {
|
||||
"align": "auto",
|
||||
"cellOptions": {
|
||||
"type": "auto"
|
||||
},
|
||||
"inspect": false
|
||||
},
|
||||
"decimals": 2,
|
||||
"fieldMinMax": false,
|
||||
"mappings": [],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 80
|
||||
}
|
||||
]
|
||||
},
|
||||
"unit": "locale"
|
||||
},
|
||||
"overrides": [
|
||||
{
|
||||
"matcher": {
|
||||
"id": "byName",
|
||||
"options": "name"
|
||||
},
|
||||
"properties": [
|
||||
{
|
||||
"id": "custom.width",
|
||||
"value": 558
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"matcher": {
|
||||
"id": "byName",
|
||||
"options": "currency"
|
||||
},
|
||||
"properties": [
|
||||
{
|
||||
"id": "custom.width",
|
||||
"value": 97
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"matcher": {
|
||||
"id": "byName",
|
||||
"options": "id"
|
||||
},
|
||||
"properties": [
|
||||
{
|
||||
"id": "custom.width",
|
||||
"value": 81
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"matcher": {
|
||||
"id": "byName",
|
||||
"options": "Lieferant"
|
||||
},
|
||||
"properties": [
|
||||
{
|
||||
"id": "custom.width",
|
||||
"value": 515
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"matcher": {
|
||||
"id": "byName",
|
||||
"options": "Saldo"
|
||||
},
|
||||
"properties": [
|
||||
{
|
||||
"id": "decimals",
|
||||
"value": 2
|
||||
},
|
||||
{
|
||||
"id": "unit",
|
||||
"value": "none"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 9,
|
||||
"w": 12,
|
||||
"x": 12,
|
||||
"y": 17
|
||||
},
|
||||
"id": 15,
|
||||
"options": {
|
||||
"cellHeight": "sm",
|
||||
"footer": {
|
||||
"countRows": false,
|
||||
"fields": "",
|
||||
"reducer": [
|
||||
"sum"
|
||||
],
|
||||
"show": false
|
||||
},
|
||||
"showHeader": true,
|
||||
"sortBy": []
|
||||
},
|
||||
"pluginVersion": "11.4.0",
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "${DS_PROMETHEUS}"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"exemplar": false,
|
||||
"expr": "sum(last_over_time(application_dbtr_balance{currency=~\"$currency\", department=~\"$department\"}[2h]))\n by (name, id,department, currency)",
|
||||
"format": "table",
|
||||
"instant": true,
|
||||
"legendFormat": "__auto",
|
||||
"range": false,
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Saldo By Debitor",
|
||||
"transformations": [
|
||||
{
|
||||
"id": "organize",
|
||||
"options": {
|
||||
"excludeByName": {
|
||||
"Time": true,
|
||||
"department": true
|
||||
},
|
||||
"includeByName": {},
|
||||
"indexByName": {
|
||||
"Time": 0,
|
||||
"Value": 5,
|
||||
"currency": 3,
|
||||
"department": 4,
|
||||
"id": 2,
|
||||
"name": 1
|
||||
},
|
||||
"renameByName": {
|
||||
"Value": "Saldo",
|
||||
"currency": " ",
|
||||
"department": "",
|
||||
"name": "Lieferant"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "sortBy",
|
||||
"options": {
|
||||
"fields": {},
|
||||
"sort": [
|
||||
{
|
||||
"desc": true,
|
||||
"field": "Saldo"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"type": "table"
|
||||
}
|
||||
],
|
||||
"schemaVersion": 40,
|
||||
"tags": [],
|
||||
"templating": {
|
||||
"list": [
|
||||
{
|
||||
"current": {},
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "${DS_PROMETHEUS}"
|
||||
},
|
||||
"definition": "label_values(currency)",
|
||||
"label": "Währung",
|
||||
"name": "currency",
|
||||
"options": [],
|
||||
"query": {
|
||||
"qryType": 1,
|
||||
"query": "label_values(currency)",
|
||||
"refId": "PrometheusVariableQueryEditor-VariableQuery"
|
||||
},
|
||||
"refresh": 1,
|
||||
"regex": "",
|
||||
"type": "query"
|
||||
},
|
||||
{
|
||||
"current": {},
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "${DS_PROMETHEUS}"
|
||||
},
|
||||
"definition": "label_values(department)",
|
||||
"label": "Abteilung",
|
||||
"name": "department",
|
||||
"options": [],
|
||||
"query": {
|
||||
"qryType": 1,
|
||||
"query": "label_values(department)",
|
||||
"refId": "PrometheusVariableQueryEditor-VariableQuery"
|
||||
},
|
||||
"refresh": 1,
|
||||
"regex": "",
|
||||
"type": "query"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "P1809F7CD0C75ACF3"
|
||||
},
|
||||
"filters": [],
|
||||
"name": "Filters",
|
||||
"type": "adhoc"
|
||||
}
|
||||
]
|
||||
},
|
||||
"time": {
|
||||
"from": "now-24h",
|
||||
"to": "now"
|
||||
},
|
||||
"timepicker": {},
|
||||
"timezone": "browser",
|
||||
"title": "Übersicht Debitoren",
|
||||
"uid": "deb9z4knfuxhcc",
|
||||
"version": 31,
|
||||
"weekStart": ""
|
||||
}
|
||||
55
docker/keys/imixs-llm.xml
Normal file
55
docker/keys/imixs-llm.xml
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
imixs-llm.xml - LLM Model Registry
|
||||
======================================
|
||||
Place this file in your deployment so it is available on the classpath,
|
||||
e.g. in src/main/resources/ for a Maven project.
|
||||
|
||||
Each <model> element defines one logical LLM service endpoint.
|
||||
A model is either a completion model OR an embedding model - never both.
|
||||
The BPMN configuration references them separately by their id:
|
||||
|
||||
<imixs-ai name="CONDITION">
|
||||
<endpoint>my-llm</endpoint>
|
||||
...
|
||||
</imixs-ai>
|
||||
|
||||
<imixs-ai name="RAG_INDEX">
|
||||
<endpoint-completion>my-llm</endpoint-completion>
|
||||
<endpoint-embeddings>my-embeddings</endpoint-embeddings>
|
||||
...
|
||||
</imixs-ai>
|
||||
|
||||
Environment variable placeholders are supported via ${env.VAR_NAME}.
|
||||
-->
|
||||
<imixs-llm>
|
||||
|
||||
<!--
|
||||
Completion model – used for chat completions, conditions, analysis etc.
|
||||
This example connects to a local llama.cpp server.
|
||||
-->
|
||||
<endpoint id="api.llama.cpp.imixs.com">
|
||||
<url>https://api.llama.cpp.imixs.com/</url>
|
||||
<apikey>7fdb663fa87ea16731c1e0ece8ad3214e358423eabf2403188110c731ce07321</apikey>
|
||||
<options>{
|
||||
"temperature": 0.2,
|
||||
"max_tokens": 1024
|
||||
}
|
||||
</options>
|
||||
</endpoint>
|
||||
|
||||
<!--
|
||||
Embedding model – used for RAG indexing and retrieval.
|
||||
This example connects to a separate embedding server.
|
||||
No apikey needed for a locally hosted instance.
|
||||
-->
|
||||
<endpoint id="embeddings.llama.cpp.imixs.com">
|
||||
<url>https://embeddings.llama.cpp.imixs.com/</url>
|
||||
<apikey>7fdb663fa87ea16731c1e0ece8ad3214e358423eabf2403188110c731ce07321</apikey>
|
||||
<options>{
|
||||
"max_tokens": 512
|
||||
}
|
||||
</options>
|
||||
</endpoint>
|
||||
|
||||
</imixs-llm>
|
||||
15
docker/prometheus/prometheus.yml
Normal file
15
docker/prometheus/prometheus.yml
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
global:
|
||||
scrape_interval: 15s # By default, scrape targets every 15 seconds.
|
||||
|
||||
# Attach these labels to any time series or alerts when communicating with
|
||||
# external systems (federation, remote storage, Alertmanager).
|
||||
external_labels:
|
||||
monitor: "imixs-monitor"
|
||||
|
||||
scrape_configs:
|
||||
# Imixs-Office-Workflow Job (Wildfly Metrics)
|
||||
- job_name: "imixs"
|
||||
scrape_interval: 3600s
|
||||
metrics_path: /metrics
|
||||
static_configs:
|
||||
- targets: ["app:9990"]
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
11
hotdeploy.sh
11
hotdeploy.sh
|
|
@ -1,11 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
############################################################
|
||||
# Setup hotdeploy
|
||||
#
|
||||
############################################################
|
||||
|
||||
cd office-alexander-logistics-app
|
||||
mvn manik-hotdeploy:hotdeploy
|
||||
|
||||
cd ..
|
||||
|
|
@ -1,53 +0,0 @@
|
|||
# ML Models
|
||||
|
||||
Wir verwenden bei Alexander-Global Logistics ein standard Invoice ML Modell. Dieses basiert im Grund auf unserem offizielen spacy modell 'invoice-de-0.1.0'.
|
||||
|
||||
|
||||
|
||||
## Modell Nachtrainieren
|
||||
|
||||
Das Modell bei Alexander Logistics läst sich in der Dev Umggebung bei Bedarf nachtrainieren. Dazu geht man wie folgt vor:
|
||||
|
||||
**1.)** Aktuelles Modell auf Tikal Cloud Server sichern:
|
||||
|
||||
$ ssh imixs@master-1.tikal.imixs.com
|
||||
$ cd tikal-cloud/
|
||||
$ ./apps/alexander-logistics.office-workflow.de/ml_model_backup.sh
|
||||
|
||||
# Falls es zu einem io/error kommt, muss der spacy ml pod neu gestartet werden!
|
||||
|
||||
|
||||
**2.)** Die Tikal-Cloud Pullen
|
||||
|
||||
**3.)** Um auf dem aktuellen Modell weiter zu trainierne, den Inhalt des invoice-de-0.1.0 Folders aus dem Backup directory in die lokale Dev Umgebung kopieren /
|
||||
um ein neues Modell zu genereiren einfach den localen ordner 'invoice-de-0.1.0' umbenennen oder leeren.
|
||||
|
||||
**4.)** Jetzt lokal den Trainingsserver aufrufen
|
||||
|
||||
http://localhost:8081/api/openapi-ui/index.html
|
||||
|
||||
und das training beginnen mit der datei 'training-config-prod.xml'. Man kann das training 3-4 mal durchführen.
|
||||
|
||||
|
||||
**5.)** Nun kann man die Inhalte des invoice-de-0.1.0 Folders zurück auf den Tikal in den modell folder /invoice-de-0.1.0 einspielen
|
||||
|
||||
**6.)** Nun die änderungen nach Git Puschen.
|
||||
|
||||
**7.)** auf dem Tikal Sever nun das aktuellisete Modell wieder einspielen
|
||||
|
||||
$ git pull
|
||||
$ ./apps/alexander-logistics.office-workflow.de/ml_model_deploy.sh invoice-de-0.1.0/
|
||||
|
||||
|
||||
|
||||
|
||||
## 22.05.2021 - invoice-de-0.1.0
|
||||
|
||||
NER=2.1948
|
||||
|
||||
|
||||
## 17.02.2020 - invoice-de-0.1.0
|
||||
|
||||
Modell trainiert anhand der alexander-logistics Produtiv daten
|
||||
|
||||
|
||||
|
|
@ -1,491 +0,0 @@
|
|||
# Test Protokoll Alexander Logistic invoice-de-0.1.0
|
||||
|
||||
|
||||
**Validierung**
|
||||
f4eaceda-f28a-4394-928e-1a05daaf2760
|
||||
a5d1e7fe-d74a-4fa2-9b06-3221865759fa
|
||||
c0290497-f613-4492-81b6-4ae1e1680029
|
||||
d8e3fce4-d11c-46a4-8ba0-369b4c6e902f
|
||||
8b766f35-828a-41f1-be04-00b4b62da4d0
|
||||
|
||||
|
||||
|
||||
**********************************************************************
|
||||
** invoice-de-0.1.0-falsemodell
|
||||
**12.10.2021 15:50** (sort order created)
|
||||
**********************************************************************
|
||||
workflow.query ($workflowgroup:"Rechnungseingang" OR $workflowgroup:"Sachrechnung") AND ($taskid:5900)
|
||||
workflow.pagesize 500
|
||||
ml.training.filepattern .pdf
|
||||
ml.training.iterations 10
|
||||
ml.training.dropoutrate 0,25
|
||||
multiOccurrence false
|
||||
ml.training.quality LOW
|
||||
min_losses 0
|
||||
|
||||
RESULT
|
||||
-----------------------------------------------------------------------
|
||||
imixs-ml-training_1 | ......documents trained in total = 375
|
||||
imixs-ml-training_1 | ...... quality level GOOD = 53.33% (200)
|
||||
imixs-ml-training_1 | ...... quality level LOW = 31.47% (118)
|
||||
imixs-ml-training_1 | ...... quality level BAD = 15.2% (57)
|
||||
imixs-ml-training_1 | ...... average NER = 17.195895012525614
|
||||
imixs-ml-training_1 |
|
||||
imixs-ml-training_1 | ......documents trained in total = 375
|
||||
imixs-ml-training_1 | ...... quality level GOOD = 51.73% (194)
|
||||
imixs-ml-training_1 | ...... quality level LOW = 32.8% (123)
|
||||
imixs-ml-training_1 | ...... quality level BAD = 15.47% (58)
|
||||
imixs-ml-training_1 | ...... average NER = 6.50170386961344
|
||||
imixs-ml-training_1 |
|
||||
imixs-ml-training_1 | ......documents trained in total = 375
|
||||
imixs-ml-training_1 | ...... quality level GOOD = 53.87% (202)
|
||||
imixs-ml-training_1 | ...... quality level LOW = 31.73% (119)
|
||||
imixs-ml-training_1 | ...... quality level BAD = 14.4% (54)
|
||||
imixs-ml-training_1 | ...... average NER = 4.8940276912225
|
||||
imixs-ml-training_1 |
|
||||
imixs-ml-training_1 | ......documents trained in total = 375
|
||||
imixs-ml-training_1 | ...... quality level GOOD = 52.8% (198)
|
||||
imixs-ml-training_1 | ...... quality level LOW = 32% (120)
|
||||
imixs-ml-training_1 | ...... quality level BAD = 15.2% (57)
|
||||
imixs-ml-training_1 | ...... average NER = 3.9605563888416824
|
||||
imixs-ml-training_1 |
|
||||
imixs-ml-training_1 | ......documents trained in total = 375
|
||||
imixs-ml-training_1 | ...... quality level GOOD = 54.13% (203)
|
||||
imixs-ml-training_1 | ...... quality level LOW = 29.6% (111)
|
||||
imixs-ml-training_1 | ...... quality level BAD = 16.27% (61)
|
||||
imixs-ml-training_1 | ...... average NER = 3.744507591826106
|
||||
imixs-ml-training_1 |
|
||||
imixs-ml-training_1 | ......documents trained in total = 375
|
||||
imixs-ml-training_1 | ...... quality level GOOD = 53.07% (199)
|
||||
imixs-ml-training_1 | ...... quality level LOW = 31.2% (117)
|
||||
imixs-ml-training_1 | ...... quality level BAD = 15.73% (59)
|
||||
imixs-ml-training_1 | ...... average NER = 2.8395576715820736
|
||||
imixs-ml-training_1 |
|
||||
imixs-ml-training_1 | ......documents trained in total = 375
|
||||
imixs-ml-training_1 | ...... quality level GOOD = 53.87% (202)
|
||||
imixs-ml-training_1 | ...... quality level LOW = 32% (120)
|
||||
imixs-ml-training_1 | ...... quality level BAD = 14.13% (53)
|
||||
imixs-ml-training_1 | ...... average NER = 2.6799682681142363
|
||||
imixs-ml-training_1 |
|
||||
imixs-ml-training_1 | ......documents trained in total = 375
|
||||
imixs-ml-training_1 | ...... quality level GOOD = 53.6% (201)
|
||||
imixs-ml-training_1 | ...... quality level LOW = 31.47% (118)
|
||||
imixs-ml-training_1 | ...... quality level BAD = 14.93% (56)
|
||||
imixs-ml-training_1 | ...... average NER = 2.520244211218683
|
||||
imixs-ml-training_1 |
|
||||
imixs-ml-training_1 | ......documents trained in total = 375
|
||||
imixs-ml-training_1 | ...... quality level GOOD = 49.33% (185)
|
||||
imixs-ml-training_1 | ...... quality level LOW = 34.93% (131)
|
||||
imixs-ml-training_1 | ...... quality level BAD = 15.73% (59)
|
||||
imixs-ml-training_1 | ...... average NER = 2.1511980661715193
|
||||
imixs-ml-training_1 |
|
||||
imixs-ml-training_1 | ......documents trained in total = 375
|
||||
imixs-ml-training_1 | ...... quality level GOOD = 53.87% (202)
|
||||
imixs-ml-training_1 | ...... quality level LOW = 31.2% (117)
|
||||
imixs-ml-training_1 | ...... quality level BAD = 14.93% (56)
|
||||
imixs-ml-training_1 | ...... average NER = 2.2739690429824475
|
||||
|
||||
|
||||
|
||||
**13.10.2021 12:00**
|
||||
workflow.query ($workflowgroup:"Rechnungseingang" OR $workflowgroup:"Sachrechnung") AND ($taskid:5900)
|
||||
workflow.pagesize 500
|
||||
ml.training.filepattern .pdf|.PDF
|
||||
ml.training.iterations 10
|
||||
ml.training.dropoutrate 0,25
|
||||
multiOccurrence false
|
||||
ml.training.quality LOW
|
||||
min_losses 0
|
||||
|
||||
imixs-ml-training_1 | ......documents trained in total = 375
|
||||
imixs-ml-training_1 | ...... quality level GOOD = 61.33% (230)
|
||||
imixs-ml-training_1 | ...... quality level LOW = 38.67% (145)
|
||||
imixs-ml-training_1 | ...... quality level BAD = 0% (0)
|
||||
imixs-ml-training_1 | ...... average NER = 3.790466332166552
|
||||
imixs-ml-training_1 |
|
||||
imixs-ml-training_1 | ......documents trained in total = 375
|
||||
imixs-ml-training_1 | ...... quality level GOOD = 61.07% (229)
|
||||
imixs-ml-training_1 | ...... quality level LOW = 38.93% (146)
|
||||
imixs-ml-training_1 | ...... quality level BAD = 0% (0)
|
||||
imixs-ml-training_1 | ...... average NER = 3.160620521438082
|
||||
imixs-ml-training_1 |
|
||||
imixs-ml-training_1 | ......documents trained in total = 375
|
||||
imixs-ml-training_1 | ...... quality level GOOD = 58.13% (218)
|
||||
imixs-ml-training_1 | ...... quality level LOW = 41.87% (157)
|
||||
imixs-ml-training_1 | ...... quality level BAD = 0% (0)
|
||||
imixs-ml-training_1 | ...... average NER = 2.636420357788331
|
||||
imixs-ml-training_1 |
|
||||
imixs-ml-training_1 | ......documents trained in total = 375
|
||||
imixs-ml-training_1 | ...... quality level GOOD = 58.13% (218)
|
||||
imixs-ml-training_1 | ...... quality level LOW = 41.87% (157)
|
||||
imixs-ml-training_1 | ...... quality level BAD = 0% (0)
|
||||
imixs-ml-training_1 | ...... average NER = 2.506552163520219
|
||||
imixs-ml-training_1 |
|
||||
imixs-ml-training_1 | ......documents trained in total = 375
|
||||
imixs-ml-training_1 | ...... quality level GOOD = 58.93% (221)
|
||||
imixs-ml-training_1 | ...... quality level LOW = 41.07% (154)
|
||||
imixs-ml-training_1 | ...... quality level BAD = 0% (0)
|
||||
imixs-ml-training_1 | ...... average NER = 2.3495061575286793
|
||||
imixs-ml-training_1 |
|
||||
imixs-ml-training_1 | ......documents trained in total = 375
|
||||
imixs-ml-training_1 | ...... quality level GOOD = 59.47% (223)
|
||||
imixs-ml-training_1 | ...... quality level LOW = 40.53% (152)
|
||||
imixs-ml-training_1 | ...... quality level BAD = 0% (0)
|
||||
imixs-ml-training_1 | ...... average NER = 1.9351332692220107
|
||||
imixs-ml-training_1 |
|
||||
imixs-ml-training_1 | ......documents trained in total = 375
|
||||
imixs-ml-training_1 | ...... quality level GOOD = 61.33% (230)
|
||||
imixs-ml-training_1 | ...... quality level LOW = 38.67% (145)
|
||||
imixs-ml-training_1 | ...... quality level BAD = 0% (0)
|
||||
imixs-ml-training_1 | ...... average NER = 1.8881396005118698
|
||||
imixs-ml-training_1 |
|
||||
imixs-ml-training_1 | ......documents trained in total = 375
|
||||
imixs-ml-training_1 | ...... quality level GOOD = 57.87% (217)
|
||||
imixs-ml-training_1 | ...... quality level LOW = 42.13% (158)
|
||||
imixs-ml-training_1 | ...... quality level BAD = 0% (0)
|
||||
imixs-ml-training_1 | ...... average NER = 1.9754112840739593
|
||||
imixs-ml-training_1 |
|
||||
imixs-ml-training_1 | ......documents trained in total = 375
|
||||
imixs-ml-training_1 | ...... quality level GOOD = 59.73% (224)
|
||||
imixs-ml-training_1 | ...... quality level LOW = 40.27% (151)
|
||||
imixs-ml-training_1 | ...... quality level BAD = 0% (0)
|
||||
imixs-ml-training_1 | ...... average NER = 1.7839739270522237
|
||||
imixs-ml-training_1 |
|
||||
imixs-ml-training_1 | ......documents trained in total = 375
|
||||
imixs-ml-training_1 | ...... quality level GOOD = 59.73% (224)
|
||||
imixs-ml-training_1 | ...... quality level LOW = 40.27% (151)
|
||||
imixs-ml-training_1 | ...... quality level BAD = 0% (0)
|
||||
imixs-ml-training_1 | ...... average NER = 1.6024293913431429
|
||||
|
||||
|
||||
|
||||
|
||||
**********************************************************************
|
||||
** invoice-de-0.1.0
|
||||
**12.10.2021 15:50** (sort order created)
|
||||
**********************************************************************
|
||||
workflow.query ($workflowgroup:"Rechnungseingang" OR $workflowgroup:"Sachrechnung") AND ($taskid:5900)
|
||||
workflow.pagesize 500
|
||||
ml.training.filepattern .pdf|.PDF
|
||||
ml.training.iterations 10
|
||||
ml.training.dropoutrate 0,25
|
||||
multiOccurrence true
|
||||
ml.training.quality LOW
|
||||
min_losses 0
|
||||
|
||||
|
||||
|
||||
imixs-ml-training_1 |
|
||||
imixs-ml-training_1 | ......documents trained in total = 375
|
||||
imixs-ml-training_1 | ...... quality level GOOD = 68.27% (256)
|
||||
imixs-ml-training_1 | ...... quality level LOW = 31.47% (118)
|
||||
imixs-ml-training_1 | ...... quality level BAD = 0.27% (1)
|
||||
imixs-ml-training_1 | ...... average NER = 21.57255353509432
|
||||
imixs-ml-training_1 |
|
||||
imixs-ml-training_1 | ......documents trained in total = 375
|
||||
imixs-ml-training_1 | ...... quality level GOOD = 67.73% (254)
|
||||
imixs-ml-training_1 | ...... quality level LOW = 32.27% (121)
|
||||
imixs-ml-training_1 | ...... quality level BAD = 0% (0)
|
||||
imixs-ml-training_1 | ...... average NER = 8.249835149395697
|
||||
imixs-ml-training_1 |
|
||||
imixs-ml-training_1 | ......documents trained in total = 375
|
||||
imixs-ml-training_1 | ...... quality level GOOD = 68.53% (257)
|
||||
imixs-ml-training_1 | ...... quality level LOW = 31.2% (117)
|
||||
imixs-ml-training_1 | ...... quality level BAD = 0.27% (1)
|
||||
imixs-ml-training_1 | ...... average NER = 5.892598287488733
|
||||
imixs-ml-training_1 |
|
||||
imixs-ml-training_1 | ......documents trained in total = 375
|
||||
imixs-ml-training_1 | ...... quality level GOOD = 68.53% (257)
|
||||
imixs-ml-training_1 | ...... quality level LOW = 31.2% (117)
|
||||
imixs-ml-training_1 | ...... quality level BAD = 0.27% (1)
|
||||
imixs-ml-training_1 | ...... average NER = 4.964129124089013
|
||||
imixs-ml-training_1 |
|
||||
imixs-ml-training_1 | ......documents trained in total = 375
|
||||
imixs-ml-training_1 | ...... quality level GOOD = 68.53% (257)
|
||||
imixs-ml-training_1 | ...... quality level LOW = 31.2% (117)
|
||||
imixs-ml-training_1 | ...... quality level BAD = 0.27% (1)
|
||||
imixs-ml-training_1 | ...... average NER = 3.5603186705177947
|
||||
imixs-ml-training_1 |
|
||||
imixs-ml-training_1 | ......documents trained in total = 375
|
||||
imixs-ml-training_1 | ...... quality level GOOD = 67.2% (252)
|
||||
imixs-ml-training_1 | ...... quality level LOW = 32.53% (122)
|
||||
imixs-ml-training_1 | ...... quality level BAD = 0.27% (1)
|
||||
imixs-ml-training_1 | ...... average NER = 2.692053828307031
|
||||
imixs-ml-training_1 |
|
||||
imixs-ml-training_1 | ......documents trained in total = 375
|
||||
imixs-ml-training_1 | ...... quality level GOOD = 68% (255)
|
||||
imixs-ml-training_1 | ...... quality level LOW = 31.73% (119)
|
||||
imixs-ml-training_1 | ...... quality level BAD = 0.27% (1)
|
||||
imixs-ml-training_1 | ...... average NER = 2.3509401762802873
|
||||
imixs-ml-training_1 |
|
||||
imixs-ml-training_1 | ......documents trained in total = 375
|
||||
imixs-ml-training_1 | ...... quality level GOOD = 65.87% (247)
|
||||
imixs-ml-training_1 | ...... quality level LOW = 34.13% (128)
|
||||
imixs-ml-training_1 | ...... quality level BAD = 0% (0)
|
||||
imixs-ml-training_1 | ...... average NER = 2.2695994889458104
|
||||
imixs-ml-training_1 |
|
||||
imixs-ml-training_1 | ......documents trained in total = 375
|
||||
imixs-ml-training_1 | ...... quality level GOOD = 68.27% (256)
|
||||
imixs-ml-training_1 | ...... quality level LOW = 31.47% (118)
|
||||
imixs-ml-training_1 | ...... quality level BAD = 0.27% (1)
|
||||
imixs-ml-training_1 | ...... average NER = 1.844410364015416
|
||||
imixs-ml-training_1 |
|
||||
imixs-ml-training_1 | ......documents trained in total = 375
|
||||
imixs-ml-training_1 | ...... quality level GOOD = 70.67% (265)
|
||||
imixs-ml-training_1 | ...... quality level LOW = 29.07% (109)
|
||||
imixs-ml-training_1 | ...... quality level BAD = 0.27% (1)
|
||||
imixs-ml-training_1 | ...... average NER = 1.6153951610034658
|
||||
|
||||
|
||||
page=1 (count=500)
|
||||
--------------------------------
|
||||
imixs-ml-training_1 | ......documents trained in total = 375
|
||||
imixs-ml-training_1 | ...... quality level GOOD = 69.6% (261)
|
||||
imixs-ml-training_1 | ...... quality level LOW = 30.4% (114)
|
||||
imixs-ml-training_1 | ...... quality level BAD = 0% (0)
|
||||
imixs-ml-training_1 | ...... average NER = 7.093659738880595
|
||||
imixs-ml-training_1 |
|
||||
imixs-ml-training_1 | ......documents trained in total = 375
|
||||
imixs-ml-training_1 | ...... quality level GOOD = 66.4% (249)
|
||||
imixs-ml-training_1 | ...... quality level LOW = 33.6% (126)
|
||||
imixs-ml-training_1 | ...... quality level BAD = 0% (0)
|
||||
imixs-ml-training_1 | ...... average NER = 5.201780406598962
|
||||
imixs-ml-training_1 |
|
||||
imixs-ml-training_1 | ......documents trained in total = 375
|
||||
imixs-ml-training_1 | ...... quality level GOOD = 68.27% (256)
|
||||
imixs-ml-training_1 | ...... quality level LOW = 31.73% (119)
|
||||
imixs-ml-training_1 | ...... quality level BAD = 0% (0)
|
||||
imixs-ml-training_1 | ...... average NER = 3.8116329003426204
|
||||
imixs-ml-training_1 |
|
||||
imixs-ml-training_1 | ......documents trained in total = 375
|
||||
imixs-ml-training_1 | ...... quality level GOOD = 66.67% (250)
|
||||
imixs-ml-training_1 | ...... quality level LOW = 33.33% (125)
|
||||
imixs-ml-training_1 | ...... quality level BAD = 0% (0)
|
||||
imixs-ml-training_1 | ...... average NER = 3.3164488404836154
|
||||
imixs-ml-training_1 |
|
||||
imixs-ml-training_1 | ......documents trained in total = 375
|
||||
imixs-ml-training_1 | ...... quality level GOOD = 66.93% (251)
|
||||
imixs-ml-training_1 | ...... quality level LOW = 33.07% (124)
|
||||
imixs-ml-training_1 | ...... quality level BAD = 0% (0)
|
||||
imixs-ml-training_1 | ...... average NER = 2.7822570929398576
|
||||
imixs-ml-training_1 |
|
||||
imixs-ml-training_1 | ......documents trained in total = 375
|
||||
imixs-ml-training_1 | ...... quality level GOOD = 69.07% (259)
|
||||
imixs-ml-training_1 | ...... quality level LOW = 30.93% (116)
|
||||
imixs-ml-training_1 | ...... quality level BAD = 0% (0)
|
||||
imixs-ml-training_1 | ...... average NER = 2.31773083524846
|
||||
imixs-ml-training_1 |
|
||||
imixs-ml-training_1 | ......documents trained in total = 375
|
||||
imixs-ml-training_1 | ...... quality level GOOD = 68.8% (258)
|
||||
imixs-ml-training_1 | ...... quality level LOW = 31.2% (117)
|
||||
imixs-ml-training_1 | ...... quality level BAD = 0% (0)
|
||||
imixs-ml-training_1 | ...... average NER = 2.165804551920185
|
||||
imixs-ml-training_1 |
|
||||
imixs-ml-training_1 | ......documents trained in total = 375
|
||||
imixs-ml-training_1 | ...... quality level GOOD = 66.4% (249)
|
||||
imixs-ml-training_1 | ...... quality level LOW = 33.6% (126)
|
||||
imixs-ml-training_1 | ...... quality level BAD = 0% (0)
|
||||
imixs-ml-training_1 | ...... average NER = 1.9591955652007715
|
||||
imixs-ml-training_1 |
|
||||
imixs-ml-training_1 | ......documents trained in total = 375
|
||||
imixs-ml-training_1 | ...... quality level GOOD = 66.4% (249)
|
||||
imixs-ml-training_1 | ...... quality level LOW = 33.6% (126)
|
||||
imixs-ml-training_1 | ...... quality level BAD = 0% (0)
|
||||
imixs-ml-training_1 | ...... average NER = 1.5473874007025803
|
||||
imixs-ml-training_1 |
|
||||
imixs-ml-training_1 | ......documents trained in total = 375
|
||||
imixs-ml-training_1 | ...... quality level GOOD = 65.87% (247)
|
||||
imixs-ml-training_1 | ...... quality level LOW = 34.13% (128)
|
||||
imixs-ml-training_1 | ...... quality level BAD = 0% (0)
|
||||
imixs-ml-training_1 | ...... average NER = 1.705957084193204
|
||||
imixs-ml-training_1 | |#]
|
||||
imixs-ml-training_1 |
|
||||
|
||||
page=0 (count=1000)
|
||||
--------------------------------
|
||||
imixs-ml-training_1 |
|
||||
imixs-ml-training_1 | ......documents trained in total = 750
|
||||
imixs-ml-training_1 | ...... quality level GOOD = 67.47% (506)
|
||||
imixs-ml-training_1 | ...... quality level LOW = 32.53% (244)
|
||||
imixs-ml-training_1 | ...... quality level BAD = 0% (0)
|
||||
imixs-ml-training_1 | ...... average NER = 3.2147245242951565
|
||||
imixs-ml-training_1 |
|
||||
imixs-ml-training_1 | ......documents trained in total = 750
|
||||
imixs-ml-training_1 | ...... quality level GOOD = 68.8% (516)
|
||||
imixs-ml-training_1 | ...... quality level LOW = 31.07% (233)
|
||||
imixs-ml-training_1 | ...... quality level BAD = 0.13% (1)
|
||||
imixs-ml-training_1 | ...... average NER = 2.2084385109690565
|
||||
imixs-ml-training_1 |
|
||||
imixs-ml-training_1 | ......documents trained in total = 750
|
||||
imixs-ml-training_1 | ...... quality level GOOD = 67.73% (508)
|
||||
imixs-ml-training_1 | ...... quality level LOW = 32.27% (242)
|
||||
imixs-ml-training_1 | ...... quality level BAD = 0% (0)
|
||||
imixs-ml-training_1 | ...... average NER = 2.1797281610496464
|
||||
imixs-ml-training_1 |
|
||||
imixs-ml-training_1 | ......documents trained in total = 750
|
||||
imixs-ml-training_1 | ...... quality level GOOD = 67.2% (504)
|
||||
imixs-ml-training_1 | ...... quality level LOW = 32.67% (245)
|
||||
imixs-ml-training_1 | ...... quality level BAD = 0.13% (1)
|
||||
imixs-ml-training_1 | ...... average NER = 1.8908819163368502
|
||||
imixs-ml-training_1 |
|
||||
imixs-ml-training_1 | ......documents trained in total = 750
|
||||
imixs-ml-training_1 | ...... quality level GOOD = 66% (495)
|
||||
imixs-ml-training_1 | ...... quality level LOW = 33.87% (254)
|
||||
imixs-ml-training_1 | ...... quality level BAD = 0.13% (1)
|
||||
imixs-ml-training_1 | ...... average NER = 1.7774978150912477
|
||||
imixs-ml-training_1 |
|
||||
imixs-ml-training_1 | ......documents trained in total = 750
|
||||
imixs-ml-training_1 | ...... quality level GOOD = 67.6% (507)
|
||||
imixs-ml-training_1 | ...... quality level LOW = 32.27% (242)
|
||||
imixs-ml-training_1 | ...... quality level BAD = 0.13% (1)
|
||||
imixs-ml-training_1 | ...... average NER = 1.669098427922433
|
||||
imixs-ml-training_1 |
|
||||
imixs-ml-training_1 | ......documents trained in total = 750
|
||||
imixs-ml-training_1 | ...... quality level GOOD = 67.33% (505)
|
||||
imixs-ml-training_1 | ...... quality level LOW = 32.53% (244)
|
||||
imixs-ml-training_1 | ...... quality level BAD = 0.13% (1)
|
||||
imixs-ml-training_1 | ...... average NER = 1.6048149396167861
|
||||
imixs-ml-training_1 |
|
||||
imixs-ml-training_1 | ......documents trained in total = 750
|
||||
imixs-ml-training_1 | ...... quality level GOOD = 67.6% (507)
|
||||
imixs-ml-training_1 | ...... quality level LOW = 32.27% (242)
|
||||
imixs-ml-training_1 | ...... quality level BAD = 0.13% (1)
|
||||
imixs-ml-training_1 | ...... average NER = 1.4026393956412981
|
||||
imixs-ml-training_1 |
|
||||
imixs-ml-training_1 | ......documents trained in total = 750
|
||||
imixs-ml-training_1 | ...... quality level GOOD = 67.87% (509)
|
||||
imixs-ml-training_1 | ...... quality level LOW = 32% (240)
|
||||
imixs-ml-training_1 | ...... quality level BAD = 0.13% (1)
|
||||
imixs-ml-training_1 | ...... average NER = 1.1139796046407426
|
||||
imixs-ml-training_1 |
|
||||
imixs-ml-training_1 | ......documents trained in total = 750
|
||||
imixs-ml-training_1 | ...... quality level GOOD = 65.87% (494)
|
||||
imixs-ml-training_1 | ...... quality level LOW = 34% (255)
|
||||
imixs-ml-training_1 | ...... quality level BAD = 0.13% (1)
|
||||
imixs-ml-training_1 | ...... average NER = 1.2621875029460226
|
||||
|
||||
|
||||
|
||||
page=1 (count=1000)
|
||||
--------------------------------
|
||||
imixs-ml-training_1 | ......documents trained in total = 750
|
||||
imixs-ml-training_1 | ...... quality level GOOD = 63.47% (476)
|
||||
imixs-ml-training_1 | ...... quality level LOW = 36.4% (273)
|
||||
imixs-ml-training_1 | ...... quality level BAD = 0.13% (1)
|
||||
imixs-ml-training_1 | ...... average NER = 3.7501272727903876
|
||||
imixs-ml-training_1 |
|
||||
imixs-ml-training_1 | ......documents trained in total = 750
|
||||
imixs-ml-training_1 | ...... quality level GOOD = 64% (480)
|
||||
imixs-ml-training_1 | ...... quality level LOW = 35.87% (269)
|
||||
imixs-ml-training_1 | ...... quality level BAD = 0.13% (1)
|
||||
imixs-ml-training_1 | ...... average NER = 2.7749715296165482
|
||||
imixs-ml-training_1 |
|
||||
imixs-ml-training_1 | ......documents trained in total = 750
|
||||
imixs-ml-training_1 | ...... quality level GOOD = 65.47% (491)
|
||||
imixs-ml-training_1 | ...... quality level LOW = 34.27% (257)
|
||||
imixs-ml-training_1 | ...... quality level BAD = 0.27% (2)
|
||||
imixs-ml-training_1 | ...... average NER = 2.191986221088383
|
||||
imixs-ml-training_1 |
|
||||
imixs-ml-training_1 | ......documents trained in total = 750
|
||||
imixs-ml-training_1 | ...... quality level GOOD = 63.2% (474)
|
||||
imixs-ml-training_1 | ...... quality level LOW = 36.53% (274)
|
||||
imixs-ml-training_1 | ...... quality level BAD = 0.27% (2)
|
||||
imixs-ml-training_1 | ...... average NER = 1.836000005105162
|
||||
imixs-ml-training_1 |
|
||||
imixs-ml-training_1 | ......documents trained in total = 750
|
||||
imixs-ml-training_1 | ...... quality level GOOD = 64.8% (486)
|
||||
imixs-ml-training_1 | ...... quality level LOW = 34.93% (262)
|
||||
imixs-ml-training_1 | ...... quality level BAD = 0.27% (2)
|
||||
imixs-ml-training_1 | ...... average NER = 1.629252182245437
|
||||
imixs-ml-training_1 |
|
||||
imixs-ml-training_1 | ......documents trained in total = 750
|
||||
imixs-ml-training_1 | ...... quality level GOOD = 64.27% (482)
|
||||
imixs-ml-training_1 | ...... quality level LOW = 35.47% (266)
|
||||
imixs-ml-training_1 | ...... quality level BAD = 0.27% (2)
|
||||
imixs-ml-training_1 | ...... average NER = 1.5023185259959349
|
||||
imixs-ml-training_1 |
|
||||
imixs-ml-training_1 | ......documents trained in total = 750
|
||||
imixs-ml-training_1 | ...... quality level GOOD = 63.6% (477)
|
||||
imixs-ml-training_1 | ...... quality level LOW = 36.13% (271)
|
||||
imixs-ml-training_1 | ...... quality level BAD = 0.27% (2)
|
||||
imixs-ml-training_1 | ...... average NER = 1.1618358977500587
|
||||
imixs-ml-training_1 |
|
||||
imixs-ml-training_1 | ......documents trained in total = 750
|
||||
imixs-ml-training_1 | ...... quality level GOOD = 64.93% (487)
|
||||
imixs-ml-training_1 | ...... quality level LOW = 34.93% (262)
|
||||
imixs-ml-training_1 | ...... quality level BAD = 0.13% (1)
|
||||
imixs-ml-training_1 | ...... average NER = 1.1362052688492958
|
||||
imixs-ml-training_1 |
|
||||
imixs-ml-training_1 | ......documents trained in total = 750
|
||||
imixs-ml-training_1 | ...... quality level GOOD = 64.4% (483)
|
||||
imixs-ml-training_1 | ...... quality level LOW = 35.33% (265)
|
||||
imixs-ml-training_1 | ...... quality level BAD = 0.27% (2)
|
||||
imixs-ml-training_1 | ...... average NER = 1.0497074333838767
|
||||
imixs-ml-training_1 |
|
||||
imixs-ml-training_1 | ......documents trained in total = 750
|
||||
imixs-ml-training_1 | ...... quality level GOOD = 65.33% (490)
|
||||
imixs-ml-training_1 | ...... quality level LOW = 34.4% (258)
|
||||
imixs-ml-training_1 | ...... quality level BAD = 0.27% (2)
|
||||
imixs-ml-training_1 | ...... average NER = 0.8865013575787167
|
||||
|
||||
page=1 (count=1000)
|
||||
--------------------------------
|
||||
imixs-ml-training_1 | ......documents trained in total = 750
|
||||
imixs-ml-training_1 | ...... quality level GOOD = 63.33% (475)
|
||||
imixs-ml-training_1 | ...... quality level LOW = 36.4% (273)
|
||||
imixs-ml-training_1 | ...... quality level BAD = 0.27% (2)
|
||||
imixs-ml-training_1 | ...... average NER = 1.6325150460009787
|
||||
imixs-ml-training_1 |
|
||||
imixs-ml-training_1 | ......documents trained in total = 750
|
||||
imixs-ml-training_1 | ...... quality level GOOD = 61.73% (463)
|
||||
imixs-ml-training_1 | ...... quality level LOW = 38% (285)
|
||||
imixs-ml-training_1 | ...... quality level BAD = 0.27% (2)
|
||||
imixs-ml-training_1 | ...... average NER = 1.5385085364524884
|
||||
imixs-ml-training_1 |
|
||||
imixs-ml-training_1 | ......documents trained in total = 750
|
||||
imixs-ml-training_1 | ...... quality level GOOD = 63.6% (477)
|
||||
imixs-ml-training_1 | ...... quality level LOW = 36.13% (271)
|
||||
imixs-ml-training_1 | ...... quality level BAD = 0.27% (2)
|
||||
imixs-ml-training_1 | ...... average NER = 1.343965340697668
|
||||
imixs-ml-training_1 |
|
||||
imixs-ml-training_1 | ......documents trained in total = 750
|
||||
imixs-ml-training_1 | ...... quality level GOOD = 64.13% (481)
|
||||
imixs-ml-training_1 | ...... quality level LOW = 35.73% (268)
|
||||
imixs-ml-training_1 | ...... quality level BAD = 0.13% (1)
|
||||
imixs-ml-training_1 | ...... average NER = 1.1842750119930687
|
||||
imixs-ml-training_1 |
|
||||
imixs-ml-training_1 | ......documents trained in total = 750
|
||||
imixs-ml-training_1 | ...... quality level GOOD = 63.73% (478)
|
||||
imixs-ml-training_1 | ...... quality level LOW = 36% (270)
|
||||
imixs-ml-training_1 | ...... quality level BAD = 0.27% (2)
|
||||
imixs-ml-training_1 | ...... average NER = 1.112559219903824
|
||||
imixs-ml-training_1 |
|
||||
imixs-ml-training_1 | ......documents trained in total = 750
|
||||
imixs-ml-training_1 | ...... quality level GOOD = 62.8% (471)
|
||||
imixs-ml-training_1 | ...... quality level LOW = 36.93% (277)
|
||||
imixs-ml-training_1 | ...... quality level BAD = 0.27% (2)
|
||||
imixs-ml-training_1 | ...... average NER = 0.9444137586901881
|
||||
imixs-ml-training_1 |
|
||||
imixs-ml-training_1 | ......documents trained in total = 750
|
||||
imixs-ml-training_1 | ...... quality level GOOD = 64% (480)
|
||||
imixs-ml-training_1 | ...... quality level LOW = 35.73% (268)
|
||||
imixs-ml-training_1 | ...... quality level BAD = 0.27% (2)
|
||||
imixs-ml-training_1 | ...... average NER = 0.9175624525798468
|
||||
imixs-ml-training_1 |
|
||||
imixs-ml-training_1 | ......documents trained in total = 750
|
||||
imixs-ml-training_1 | ...... quality level GOOD = 63.47% (476)
|
||||
imixs-ml-training_1 | ...... quality level LOW = 36.27% (272)
|
||||
imixs-ml-training_1 | ...... quality level BAD = 0.27% (2)
|
||||
imixs-ml-training_1 | ...... average NER = 0.8877949306723629
|
||||
imixs-ml-training_1 |
|
||||
imixs-ml-training_1 | ......documents trained in total = 750
|
||||
imixs-ml-training_1 | ...... quality level GOOD = 62.53% (469)
|
||||
imixs-ml-training_1 | ...... quality level LOW = 37.2% (279)
|
||||
imixs-ml-training_1 | ...... quality level BAD = 0.27% (2)
|
||||
imixs-ml-training_1 | ...... average NER = 0.7669201996298972
|
||||
imixs-ml-training_1 |
|
||||
imixs-ml-training_1 | ......documents trained in total = 750
|
||||
imixs-ml-training_1 | ...... quality level GOOD = 62.8% (471)
|
||||
imixs-ml-training_1 | ...... quality level LOW = 37.07% (278)
|
||||
imixs-ml-training_1 | ...... quality level BAD = 0.13% (1)
|
||||
imixs-ml-training_1 | ...... average NER = 0.7161310708827515
|
||||
|
|
@ -1,128 +0,0 @@
|
|||
[paths]
|
||||
train = null
|
||||
dev = null
|
||||
vectors = null
|
||||
init_tok2vec = null
|
||||
|
||||
[system]
|
||||
seed = 0
|
||||
gpu_allocator = null
|
||||
|
||||
[nlp]
|
||||
lang = "de"
|
||||
pipeline = ["ner"]
|
||||
disabled = []
|
||||
before_creation = null
|
||||
after_creation = null
|
||||
after_pipeline_creation = null
|
||||
batch_size = 1000
|
||||
tokenizer = {"@tokenizers":"spacy.Tokenizer.v1"}
|
||||
|
||||
[components]
|
||||
|
||||
[components.ner]
|
||||
factory = "ner"
|
||||
incorrect_spans_key = null
|
||||
moves = null
|
||||
scorer = {"@scorers":"spacy.ner_scorer.v1"}
|
||||
update_with_oracle_cut_size = 100
|
||||
|
||||
[components.ner.model]
|
||||
@architectures = "spacy.TransitionBasedParser.v2"
|
||||
state_type = "ner"
|
||||
extra_state_tokens = false
|
||||
hidden_width = 64
|
||||
maxout_pieces = 2
|
||||
use_upper = true
|
||||
nO = null
|
||||
|
||||
[components.ner.model.tok2vec]
|
||||
@architectures = "spacy.HashEmbedCNN.v2"
|
||||
pretrained_vectors = null
|
||||
width = 96
|
||||
depth = 4
|
||||
embed_size = 2000
|
||||
window_size = 1
|
||||
maxout_pieces = 3
|
||||
subword_features = true
|
||||
|
||||
[corpora]
|
||||
|
||||
[corpora.dev]
|
||||
@readers = "spacy.Corpus.v1"
|
||||
path = ${paths.dev}
|
||||
gold_preproc = false
|
||||
max_length = 0
|
||||
limit = 0
|
||||
augmenter = null
|
||||
|
||||
[corpora.train]
|
||||
@readers = "spacy.Corpus.v1"
|
||||
path = ${paths.train}
|
||||
gold_preproc = false
|
||||
max_length = 0
|
||||
limit = 0
|
||||
augmenter = null
|
||||
|
||||
[training]
|
||||
seed = ${system.seed}
|
||||
gpu_allocator = ${system.gpu_allocator}
|
||||
dropout = 0.1
|
||||
accumulate_gradient = 1
|
||||
patience = 1600
|
||||
max_epochs = 0
|
||||
max_steps = 20000
|
||||
eval_frequency = 200
|
||||
frozen_components = []
|
||||
annotating_components = []
|
||||
dev_corpus = "corpora.dev"
|
||||
train_corpus = "corpora.train"
|
||||
before_to_disk = null
|
||||
|
||||
[training.batcher]
|
||||
@batchers = "spacy.batch_by_words.v1"
|
||||
discard_oversize = false
|
||||
tolerance = 0.2
|
||||
get_length = null
|
||||
|
||||
[training.batcher.size]
|
||||
@schedules = "compounding.v1"
|
||||
start = 100
|
||||
stop = 1000
|
||||
compound = 1.001
|
||||
t = 0.0
|
||||
|
||||
[training.logger]
|
||||
@loggers = "spacy.ConsoleLogger.v1"
|
||||
progress_bar = false
|
||||
|
||||
[training.optimizer]
|
||||
@optimizers = "Adam.v1"
|
||||
beta1 = 0.9
|
||||
beta2 = 0.999
|
||||
L2_is_weight_decay = true
|
||||
L2 = 0.01
|
||||
grad_clip = 1.0
|
||||
use_averages = false
|
||||
eps = 0.00000001
|
||||
learn_rate = 0.001
|
||||
|
||||
[training.score_weights]
|
||||
ents_f = 1.0
|
||||
ents_p = 0.0
|
||||
ents_r = 0.0
|
||||
ents_per_type = null
|
||||
|
||||
[pretraining]
|
||||
|
||||
[initialize]
|
||||
vectors = ${paths.vectors}
|
||||
init_tok2vec = ${paths.init_tok2vec}
|
||||
vocab_data = null
|
||||
lookups = null
|
||||
before_init = null
|
||||
after_init = null
|
||||
|
||||
[initialize.components]
|
||||
|
||||
[initialize.tokenizer]
|
||||
|
|
@ -1,38 +0,0 @@
|
|||
{
|
||||
"lang":"de",
|
||||
"name":"pipeline",
|
||||
"version":"0.0.0",
|
||||
"spacy_version":">=3.4.1,<3.5.0",
|
||||
"description":"",
|
||||
"author":"",
|
||||
"email":"",
|
||||
"url":"",
|
||||
"license":"",
|
||||
"spacy_git_version":"Unknown",
|
||||
"vectors":{
|
||||
"width":0,
|
||||
"vectors":0,
|
||||
"keys":0,
|
||||
"name":null,
|
||||
"mode":"default"
|
||||
},
|
||||
"labels":{
|
||||
"ner":[
|
||||
"cdtr.bic",
|
||||
"cdtr.iban",
|
||||
"cdtr.name",
|
||||
"invoice.date",
|
||||
"invoice.number",
|
||||
"invoice.total"
|
||||
]
|
||||
},
|
||||
"pipeline":[
|
||||
"ner"
|
||||
],
|
||||
"components":[
|
||||
"ner"
|
||||
],
|
||||
"disabled":[
|
||||
|
||||
]
|
||||
}
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
{
|
||||
"moves":null,
|
||||
"update_with_oracle_cut_size":100,
|
||||
"multitasks":[
|
||||
|
||||
],
|
||||
"min_action_freq":1,
|
||||
"learn_tokens":false,
|
||||
"beam_width":1,
|
||||
"beam_density":0.0,
|
||||
"beam_update_prob":0.0,
|
||||
"incorrect_spans_key":null
|
||||
}
|
||||
Binary file not shown.
|
|
@ -1 +0,0 @@
|
|||
‚¥movesÚÄ{"0":{},"1":{"invoice.total":-1,"invoice.number":-2,"cdtr.name":-3,"invoice.date":-4,"cdtr.iban":-5,"cdtr.bic":-6},"2":{"invoice.total":-1,"invoice.number":-2,"cdtr.name":-3,"invoice.date":-4,"cdtr.iban":-5,"cdtr.bic":-6},"3":{"invoice.total":-1,"invoice.number":-2,"cdtr.name":-3,"invoice.date":-4,"cdtr.iban":-5,"cdtr.bic":-6},"4":{"":1,"invoice.total":-1,"invoice.number":-2,"cdtr.name":-3,"invoice.date":-4,"cdtr.iban":-5,"cdtr.bic":-6},"5":{"":1}}£cfg<66>§neg_keyÀ
|
||||
File diff suppressed because one or more lines are too long
|
|
@ -1 +0,0 @@
|
|||
<EFBFBD>
|
||||
|
|
@ -1 +0,0 @@
|
|||
<EFBFBD>
|
||||
File diff suppressed because it is too large
Load diff
Binary file not shown.
|
|
@ -1,3 +0,0 @@
|
|||
{
|
||||
"mode":"default"
|
||||
}
|
||||
|
|
@ -1,127 +0,0 @@
|
|||
[paths]
|
||||
train = null
|
||||
dev = null
|
||||
vectors = null
|
||||
init_tok2vec = null
|
||||
|
||||
[system]
|
||||
seed = 0
|
||||
gpu_allocator = null
|
||||
|
||||
[nlp]
|
||||
lang = "de"
|
||||
pipeline = ["ner"]
|
||||
disabled = []
|
||||
before_creation = null
|
||||
after_creation = null
|
||||
after_pipeline_creation = null
|
||||
batch_size = 1000
|
||||
tokenizer = {"@tokenizers":"spacy.Tokenizer.v1"}
|
||||
|
||||
[components]
|
||||
|
||||
[components.ner]
|
||||
factory = "ner"
|
||||
incorrect_spans_key = null
|
||||
moves = null
|
||||
update_with_oracle_cut_size = 100
|
||||
|
||||
[components.ner.model]
|
||||
@architectures = "spacy.TransitionBasedParser.v2"
|
||||
state_type = "ner"
|
||||
extra_state_tokens = false
|
||||
hidden_width = 64
|
||||
maxout_pieces = 2
|
||||
use_upper = true
|
||||
nO = null
|
||||
|
||||
[components.ner.model.tok2vec]
|
||||
@architectures = "spacy.HashEmbedCNN.v2"
|
||||
pretrained_vectors = null
|
||||
width = 96
|
||||
depth = 4
|
||||
embed_size = 2000
|
||||
window_size = 1
|
||||
maxout_pieces = 3
|
||||
subword_features = true
|
||||
|
||||
[corpora]
|
||||
|
||||
[corpora.dev]
|
||||
@readers = "spacy.Corpus.v1"
|
||||
path = ${paths.dev}
|
||||
gold_preproc = false
|
||||
max_length = 0
|
||||
limit = 0
|
||||
augmenter = null
|
||||
|
||||
[corpora.train]
|
||||
@readers = "spacy.Corpus.v1"
|
||||
path = ${paths.train}
|
||||
gold_preproc = false
|
||||
max_length = 0
|
||||
limit = 0
|
||||
augmenter = null
|
||||
|
||||
[training]
|
||||
seed = ${system.seed}
|
||||
gpu_allocator = ${system.gpu_allocator}
|
||||
dropout = 0.1
|
||||
accumulate_gradient = 1
|
||||
patience = 1600
|
||||
max_epochs = 0
|
||||
max_steps = 20000
|
||||
eval_frequency = 200
|
||||
frozen_components = []
|
||||
annotating_components = []
|
||||
dev_corpus = "corpora.dev"
|
||||
train_corpus = "corpora.train"
|
||||
before_to_disk = null
|
||||
|
||||
[training.batcher]
|
||||
@batchers = "spacy.batch_by_words.v1"
|
||||
discard_oversize = false
|
||||
tolerance = 0.2
|
||||
get_length = null
|
||||
|
||||
[training.batcher.size]
|
||||
@schedules = "compounding.v1"
|
||||
start = 100
|
||||
stop = 1000
|
||||
compound = 1.001
|
||||
t = 0.0
|
||||
|
||||
[training.logger]
|
||||
@loggers = "spacy.ConsoleLogger.v1"
|
||||
progress_bar = false
|
||||
|
||||
[training.optimizer]
|
||||
@optimizers = "Adam.v1"
|
||||
beta1 = 0.9
|
||||
beta2 = 0.999
|
||||
L2_is_weight_decay = true
|
||||
L2 = 0.01
|
||||
grad_clip = 1.0
|
||||
use_averages = false
|
||||
eps = 0.00000001
|
||||
learn_rate = 0.001
|
||||
|
||||
[training.score_weights]
|
||||
ents_f = 1.0
|
||||
ents_p = 0.0
|
||||
ents_r = 0.0
|
||||
ents_per_type = null
|
||||
|
||||
[pretraining]
|
||||
|
||||
[initialize]
|
||||
vectors = ${paths.vectors}
|
||||
init_tok2vec = ${paths.init_tok2vec}
|
||||
vocab_data = null
|
||||
lookups = null
|
||||
before_init = null
|
||||
after_init = null
|
||||
|
||||
[initialize.components]
|
||||
|
||||
[initialize.tokenizer]
|
||||
|
|
@ -1,40 +0,0 @@
|
|||
{
|
||||
"lang":"de",
|
||||
"name":"pipeline",
|
||||
"version":"0.0.0",
|
||||
"spacy_version":">=3.1.1,<3.2.0",
|
||||
"description":"",
|
||||
"author":"",
|
||||
"email":"",
|
||||
"url":"",
|
||||
"license":"",
|
||||
"spacy_git_version":"ffaead8fe",
|
||||
"vectors":{
|
||||
"width":0,
|
||||
"vectors":0,
|
||||
"keys":0,
|
||||
"name":null
|
||||
},
|
||||
"labels":{
|
||||
"ner":[
|
||||
"cdtr.bic",
|
||||
"cdtr.iban",
|
||||
"cdtr.name",
|
||||
"invoice.date",
|
||||
"invoice.number",
|
||||
"invoice.total"
|
||||
]
|
||||
},
|
||||
"pipeline":[
|
||||
"ner"
|
||||
],
|
||||
"components":[
|
||||
"ner"
|
||||
],
|
||||
"disabled":[
|
||||
|
||||
],
|
||||
"_sourced_vectors_hashes":{
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
{
|
||||
"moves":null,
|
||||
"update_with_oracle_cut_size":100,
|
||||
"multitasks":[
|
||||
|
||||
],
|
||||
"min_action_freq":1,
|
||||
"learn_tokens":false,
|
||||
"beam_width":1,
|
||||
"beam_density":0.0,
|
||||
"beam_update_prob":0.0,
|
||||
"incorrect_spans_key":null
|
||||
}
|
||||
Binary file not shown.
|
|
@ -1 +0,0 @@
|
|||
‚¥movesÚÄ{"0":{},"1":{"cdtr.name":-1,"cdtr.iban":-2,"cdtr.bic":-3,"invoice.total":-4,"invoice.date":-5,"invoice.number":-6},"2":{"cdtr.name":-1,"cdtr.iban":-2,"cdtr.bic":-3,"invoice.total":-4,"invoice.date":-5,"invoice.number":-6},"3":{"cdtr.name":-1,"cdtr.iban":-2,"cdtr.bic":-3,"invoice.total":-4,"invoice.date":-5,"invoice.number":-6},"4":{"":1,"cdtr.name":-1,"cdtr.iban":-2,"cdtr.bic":-3,"invoice.total":-4,"invoice.date":-5,"invoice.number":-6},"5":{"":1}}£cfg<66>§neg_keyÀ
|
||||
File diff suppressed because one or more lines are too long
|
|
@ -1 +0,0 @@
|
|||
<EFBFBD>
|
||||
|
|
@ -1 +0,0 @@
|
|||
<EFBFBD>
|
||||
File diff suppressed because it is too large
Load diff
Binary file not shown.
|
|
@ -1,128 +0,0 @@
|
|||
[paths]
|
||||
train = null
|
||||
dev = null
|
||||
vectors = null
|
||||
init_tok2vec = null
|
||||
|
||||
[system]
|
||||
seed = 0
|
||||
gpu_allocator = null
|
||||
|
||||
[nlp]
|
||||
lang = "de"
|
||||
pipeline = ["ner"]
|
||||
disabled = []
|
||||
before_creation = null
|
||||
after_creation = null
|
||||
after_pipeline_creation = null
|
||||
batch_size = 1000
|
||||
tokenizer = {"@tokenizers":"spacy.Tokenizer.v1"}
|
||||
|
||||
[components]
|
||||
|
||||
[components.ner]
|
||||
factory = "ner"
|
||||
incorrect_spans_key = null
|
||||
moves = null
|
||||
scorer = {"@scorers":"spacy.ner_scorer.v1"}
|
||||
update_with_oracle_cut_size = 100
|
||||
|
||||
[components.ner.model]
|
||||
@architectures = "spacy.TransitionBasedParser.v2"
|
||||
state_type = "ner"
|
||||
extra_state_tokens = false
|
||||
hidden_width = 64
|
||||
maxout_pieces = 2
|
||||
use_upper = true
|
||||
nO = null
|
||||
|
||||
[components.ner.model.tok2vec]
|
||||
@architectures = "spacy.HashEmbedCNN.v2"
|
||||
pretrained_vectors = null
|
||||
width = 96
|
||||
depth = 4
|
||||
embed_size = 2000
|
||||
window_size = 1
|
||||
maxout_pieces = 3
|
||||
subword_features = true
|
||||
|
||||
[corpora]
|
||||
|
||||
[corpora.dev]
|
||||
@readers = "spacy.Corpus.v1"
|
||||
path = ${paths.dev}
|
||||
gold_preproc = false
|
||||
max_length = 0
|
||||
limit = 0
|
||||
augmenter = null
|
||||
|
||||
[corpora.train]
|
||||
@readers = "spacy.Corpus.v1"
|
||||
path = ${paths.train}
|
||||
gold_preproc = false
|
||||
max_length = 0
|
||||
limit = 0
|
||||
augmenter = null
|
||||
|
||||
[training]
|
||||
seed = ${system.seed}
|
||||
gpu_allocator = ${system.gpu_allocator}
|
||||
dropout = 0.1
|
||||
accumulate_gradient = 1
|
||||
patience = 1600
|
||||
max_epochs = 0
|
||||
max_steps = 20000
|
||||
eval_frequency = 200
|
||||
frozen_components = []
|
||||
annotating_components = []
|
||||
dev_corpus = "corpora.dev"
|
||||
train_corpus = "corpora.train"
|
||||
before_to_disk = null
|
||||
|
||||
[training.batcher]
|
||||
@batchers = "spacy.batch_by_words.v1"
|
||||
discard_oversize = false
|
||||
tolerance = 0.2
|
||||
get_length = null
|
||||
|
||||
[training.batcher.size]
|
||||
@schedules = "compounding.v1"
|
||||
start = 100
|
||||
stop = 1000
|
||||
compound = 1.001
|
||||
t = 0.0
|
||||
|
||||
[training.logger]
|
||||
@loggers = "spacy.ConsoleLogger.v1"
|
||||
progress_bar = false
|
||||
|
||||
[training.optimizer]
|
||||
@optimizers = "Adam.v1"
|
||||
beta1 = 0.9
|
||||
beta2 = 0.999
|
||||
L2_is_weight_decay = true
|
||||
L2 = 0.01
|
||||
grad_clip = 1.0
|
||||
use_averages = false
|
||||
eps = 0.00000001
|
||||
learn_rate = 0.001
|
||||
|
||||
[training.score_weights]
|
||||
ents_f = 1.0
|
||||
ents_p = 0.0
|
||||
ents_r = 0.0
|
||||
ents_per_type = null
|
||||
|
||||
[pretraining]
|
||||
|
||||
[initialize]
|
||||
vectors = ${paths.vectors}
|
||||
init_tok2vec = ${paths.init_tok2vec}
|
||||
vocab_data = null
|
||||
lookups = null
|
||||
before_init = null
|
||||
after_init = null
|
||||
|
||||
[initialize.components]
|
||||
|
||||
[initialize.tokenizer]
|
||||
|
|
@ -1,38 +0,0 @@
|
|||
{
|
||||
"lang":"de",
|
||||
"name":"pipeline",
|
||||
"version":"0.0.0",
|
||||
"spacy_version":">=3.4.1,<3.5.0",
|
||||
"description":"",
|
||||
"author":"",
|
||||
"email":"",
|
||||
"url":"",
|
||||
"license":"",
|
||||
"spacy_git_version":"Unknown",
|
||||
"vectors":{
|
||||
"width":0,
|
||||
"vectors":0,
|
||||
"keys":0,
|
||||
"name":null,
|
||||
"mode":"default"
|
||||
},
|
||||
"labels":{
|
||||
"ner":[
|
||||
"cdtr.bic",
|
||||
"cdtr.iban",
|
||||
"cdtr.name",
|
||||
"invoice.date",
|
||||
"invoice.number",
|
||||
"invoice.total"
|
||||
]
|
||||
},
|
||||
"pipeline":[
|
||||
"ner"
|
||||
],
|
||||
"components":[
|
||||
"ner"
|
||||
],
|
||||
"disabled":[
|
||||
|
||||
]
|
||||
}
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
{
|
||||
"moves":null,
|
||||
"update_with_oracle_cut_size":100,
|
||||
"multitasks":[
|
||||
|
||||
],
|
||||
"min_action_freq":1,
|
||||
"learn_tokens":false,
|
||||
"beam_width":1,
|
||||
"beam_density":0.0,
|
||||
"beam_update_prob":0.0,
|
||||
"incorrect_spans_key":null
|
||||
}
|
||||
Binary file not shown.
|
|
@ -1 +0,0 @@
|
|||
‚¥movesÚÄ{"0":{},"1":{"invoice.total":-1,"invoice.number":-2,"invoice.date":-3,"cdtr.name":-4,"cdtr.iban":-5,"cdtr.bic":-6},"2":{"invoice.total":-1,"invoice.number":-2,"invoice.date":-3,"cdtr.name":-4,"cdtr.iban":-5,"cdtr.bic":-6},"3":{"invoice.total":-1,"invoice.number":-2,"invoice.date":-3,"cdtr.name":-4,"cdtr.iban":-5,"cdtr.bic":-6},"4":{"":1,"invoice.total":-1,"invoice.number":-2,"invoice.date":-3,"cdtr.name":-4,"cdtr.iban":-5,"cdtr.bic":-6},"5":{"":1}}£cfg<66>§neg_keyÀ
|
||||
File diff suppressed because one or more lines are too long
|
|
@ -1 +0,0 @@
|
|||
<EFBFBD>
|
||||
|
|
@ -1 +0,0 @@
|
|||
<EFBFBD>
|
||||
File diff suppressed because it is too large
Load diff
Binary file not shown.
|
|
@ -1,3 +0,0 @@
|
|||
{
|
||||
"mode":"default"
|
||||
}
|
||||
|
|
@ -1,44 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<document xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:xs="http://www.w3.org/2001/XMLSchema">
|
||||
|
||||
<!-- Workflow Instance -->
|
||||
<item name="workflow.endpoint"><value xsi:type="xs:string">https://alexander-logistics.office-workflow.de/api/</value></item>
|
||||
<item name="workflow.userid"><value xsi:type="xs:string">admin</value></item>
|
||||
<item name="workflow.password"><value xsi:type="xs:string">imixs4.null</value></item>
|
||||
|
||||
<!-- -->
|
||||
<item name="workflow.query"><value xsi:type="xs:string">($workflowgroup:"Rechnungseingang" OR $workflowgroup:"Sachrechnung") AND ($taskid:5900)</value></item>
|
||||
|
||||
<item name="workflow.pagesize"><value xsi:type="xs:int">100</value></item>
|
||||
<item name="workflow.pageindex"><value xsi:type="xs:int">30</value></item>
|
||||
<item name="workflow.entities">
|
||||
<value xsi:type="xs:string">cdtr.name</value>
|
||||
<value xsi:type="xs:string">cdtr.iban</value>
|
||||
<value xsi:type="xs:string">cdtr.bic</value>
|
||||
<value xsi:type="xs:string">invoice.total</value>
|
||||
<value xsi:type="xs:string">invoice.date</value>
|
||||
<value xsi:type="xs:string">invoice.number</value>
|
||||
</item>
|
||||
<item name="workflow.locale">
|
||||
<value xsi:type="xs:string">en_GB</value>
|
||||
<value xsi:type="xs:string">en_US</value>
|
||||
<value xsi:type="xs:string">de_DE</value>
|
||||
</item>
|
||||
|
||||
<!-- Tika OCR Server -->
|
||||
<item name="tika.ocrmode"><value xsi:type="xs:string">OCR_ONLY</value></item>
|
||||
<item name="tika.options">
|
||||
<value xsi:type="xs:string">X-Tika-OCRLanguage=eng+deu</value>
|
||||
<value xsi:type="xs:string">X-Tika-PDFocrStrategy=OCR_ONLY</value>
|
||||
</item>
|
||||
|
||||
<!-- ML spaCy Server -->
|
||||
<item name="ml.validation.endpoint"><value xsi:type="xs:string">http://imixs-ml-spacy:8000/</value></item>
|
||||
<item name="ml.validation.model"><value xsi:type="xs:string">invoice-de-0.1.0</value></item>
|
||||
<item name="ml.validation.filepattern"><value xsi:type="xs:string">.pdf|.PDF</value></item>
|
||||
|
||||
</document>
|
||||
|
||||
|
||||
|
||||
|
|
@ -1,53 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<document xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:xs="http://www.w3.org/2001/XMLSchema">
|
||||
|
||||
<!-- Workflow Instance -->
|
||||
<item name="workflow.endpoint"><value xsi:type="xs:string">https://alexander-logistics.office-workflow.de/api/</value></item>
|
||||
<item name="workflow.userid"><value xsi:type="xs:string">admin</value></item>
|
||||
<item name="workflow.password"><value xsi:type="xs:string">imixs4.null</value></item>
|
||||
|
||||
<item name="workflow.entities">
|
||||
<value xsi:type="xs:string">cdtr.name</value>
|
||||
<value xsi:type="xs:string">cdtr.iban</value>
|
||||
<value xsi:type="xs:string">cdtr.bic</value>
|
||||
<value xsi:type="xs:string">invoice.total</value>
|
||||
<value xsi:type="xs:string">invoice.date</value>
|
||||
<value xsi:type="xs:string">invoice.number</value>
|
||||
</item>
|
||||
<item name="workflow.locale">
|
||||
<value xsi:type="xs:string">en_GB</value>
|
||||
<value xsi:type="xs:string">en_US</value>
|
||||
<value xsi:type="xs:string">de_DE</value>
|
||||
</item>
|
||||
|
||||
<!-- Tika OCR Server -->
|
||||
<item name="tika.ocrmode"><value xsi:type="xs:string">OCR_ONLY</value></item>
|
||||
<item name="tika.options">
|
||||
<value xsi:type="xs:string">X-Tika-OCRLanguage=eng+deu</value>
|
||||
<value xsi:type="xs:string">X-Tika-PDFocrStrategy=OCR_ONLY</value>
|
||||
</item>
|
||||
|
||||
<!-- ML spaCy Server -->
|
||||
<item name="ml.training.endpoint"><value xsi:type="xs:string">http://imixs-ml-spacy:8000/</value></item>
|
||||
<item name="ml.training.model"><value xsi:type="xs:string">invoice-de-0.2.0</value></item>
|
||||
<item name="ml.training.filepattern"><value xsi:type="xs:string">.pdf|.PDF</value></item>
|
||||
<!-- LOW | GOOD -->
|
||||
<item name="ml.training.quality"><value xsi:type="xs:string">LOW</value></item>
|
||||
|
||||
|
||||
<!-- Define the training set and taining mode -->
|
||||
<item name="workflow.query"><value xsi:type="xs:string">($workflowgroup:"Rechnungseingang" OR $workflowgroup:"Sachrechnung") AND ($taskid:5900)</value></item>
|
||||
<item name="workflow.pagesize"><value xsi:type="xs:int">1000</value></item>
|
||||
<item name="workflow.pageindex"><value xsi:type="xs:int">0</value></item>
|
||||
<item name="ml.training.iterations"><value xsi:type="xs:string">5</value></item>
|
||||
<item name="ml.training.dropoutrate"><value xsi:type="xs:string">0.0</value></item>
|
||||
<item name="ml.options">
|
||||
<value xsi:type="xs:string">min_losses=0.0&retrain_rate=100</value>
|
||||
</item>
|
||||
|
||||
|
||||
</document>
|
||||
|
||||
|
||||
|
||||
|
|
@ -1,48 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<document xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:xs="http://www.w3.org/2001/XMLSchema">
|
||||
|
||||
<!-- Workflow Instance -->
|
||||
<item name="workflow.endpoint"><value xsi:type="xs:string">https://alexander-logistics.office-workflow.de/api/</value></item>
|
||||
<item name="workflow.userid"><value xsi:type="xs:string">admin</value></item>
|
||||
<item name="workflow.password"><value xsi:type="xs:string">imixs4.null</value></item>
|
||||
|
||||
<item name="workflow.entities">
|
||||
<value xsi:type="xs:string">cdtr.name</value>
|
||||
<value xsi:type="xs:string">cdtr.iban</value>
|
||||
<value xsi:type="xs:string">cdtr.bic</value>
|
||||
<value xsi:type="xs:string">invoice.total</value>
|
||||
<value xsi:type="xs:string">invoice.date</value>
|
||||
<value xsi:type="xs:string">invoice.number</value>
|
||||
</item>
|
||||
<item name="workflow.locale">
|
||||
<value xsi:type="xs:string">en_GB</value>
|
||||
<value xsi:type="xs:string">en_US</value>
|
||||
<value xsi:type="xs:string">de_DE</value>
|
||||
</item>
|
||||
|
||||
<!-- Tika OCR Server -->
|
||||
<item name="tika.ocrmode"><value xsi:type="xs:string">OCR_ONLY</value></item>
|
||||
<item name="tika.options">
|
||||
<value xsi:type="xs:string">X-Tika-OCRLanguage=eng+deu</value>
|
||||
<value xsi:type="xs:string">X-Tika-PDFocrStrategy=OCR_ONLY</value>
|
||||
</item>
|
||||
|
||||
<!-- ML spaCy Server -->
|
||||
<item name="ml.training.endpoint"><value xsi:type="xs:string">http://imixs-ml-spacy:8000/</value></item>
|
||||
<item name="ml.training.model"><value xsi:type="xs:string">invoice-de-0.2.0</value></item>
|
||||
<item name="ml.training.filepattern"><value xsi:type="xs:string">.pdf|.PDF</value></item>
|
||||
<!-- LOW | GOOD -->
|
||||
<item name="ml.training.quality"><value xsi:type="xs:string">LOW</value></item>
|
||||
|
||||
|
||||
<!-- Define the training set and taining mode -->
|
||||
<item name="workflow.query"><value xsi:type="xs:string">($workflowgroup:"Rechnungseingang" OR $workflowgroup:"Sachrechnung") AND ($taskid:5900)</value></item>
|
||||
<item name="workflow.pagesize"><value xsi:type="xs:int">100</value></item>
|
||||
<item name="workflow.pageindex"><value xsi:type="xs:int">40</value></item>
|
||||
|
||||
|
||||
</document>
|
||||
|
||||
|
||||
|
||||
1
office-alexander-logistics-app/.gitignore
vendored
1
office-alexander-logistics-app/.gitignore
vendored
|
|
@ -1 +0,0 @@
|
|||
/target/
|
||||
|
|
@ -1,395 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<artifactId>office-alexander-logistics</artifactId>
|
||||
<groupId>com.alexander-logistics</groupId>
|
||||
<version>1.3.0</version>
|
||||
</parent>
|
||||
<artifactId>office-alexander-logistics-app</artifactId>
|
||||
<packaging>war</packaging>
|
||||
<name>Imixs Office Workflow App</name>
|
||||
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>docker</id>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-antrun-plugin</artifactId>
|
||||
<version>1.8</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>install</phase>
|
||||
<configuration>
|
||||
<target>
|
||||
<exec executable="docker">
|
||||
<arg value="build" />
|
||||
<arg value="-t" />
|
||||
<arg value="imixs/${imixs-office.applicationname}" />
|
||||
<arg value="../." />
|
||||
</exec>
|
||||
</target>
|
||||
</configuration>
|
||||
<goals>
|
||||
<goal>run</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
|
||||
<profile>
|
||||
<id>debug</id>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-antrun-plugin</artifactId>
|
||||
<version>1.8</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>install</phase>
|
||||
<configuration>
|
||||
<target>
|
||||
<exec executable="docker">
|
||||
<arg value="build" />
|
||||
<arg value="-f" />
|
||||
<arg value="../Dockerfile-wildfly-debug" />
|
||||
<arg value="-t" />
|
||||
<arg value="imixs/${imixs-office.applicationname}" />
|
||||
<arg value="../." />
|
||||
</exec>
|
||||
</target>
|
||||
</configuration>
|
||||
<goals>
|
||||
<goal>run</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
|
||||
<profile>
|
||||
<id>kubernetes</id>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-antrun-plugin</artifactId>
|
||||
<version>1.8</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>install</phase>
|
||||
<configuration>
|
||||
<target>
|
||||
<exec executable="docker">
|
||||
<arg value="build" />
|
||||
<arg value="-t" />
|
||||
<arg
|
||||
value="imixs/${imixs-office.applicationname}:${project.version}" />
|
||||
<arg value="../." />
|
||||
</exec>
|
||||
<exec executable="docker">
|
||||
<arg value="tag" />
|
||||
<arg
|
||||
value="imixs/${imixs-office.applicationname}:${project.version}" />
|
||||
<arg
|
||||
value="${org.imixs.kubernetes.registry}/imixs/${imixs-office.applicationname}:${project.version}" />
|
||||
</exec>
|
||||
<exec executable="docker">
|
||||
<arg value="push" />
|
||||
<arg
|
||||
value="${org.imixs.kubernetes.registry}/imixs/${imixs-office.applicationname}:${project.version}" />
|
||||
</exec>
|
||||
</target>
|
||||
</configuration>
|
||||
<goals>
|
||||
<goal>run</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
|
||||
</profiles>
|
||||
<build>
|
||||
<testResources>
|
||||
<testResource>
|
||||
<directory>${basedir}/../reports</directory>
|
||||
</testResource>
|
||||
<testResource>
|
||||
<directory>${basedir}/src/test/resources</directory>
|
||||
</testResource>
|
||||
</testResources>
|
||||
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-war-plugin</artifactId>
|
||||
<version>3.3.2</version>
|
||||
<configuration>
|
||||
<failOnMissingWebXml>false</failOnMissingWebXml>
|
||||
<webResources>
|
||||
<resource>
|
||||
<filtering>true</filtering>
|
||||
<!-- this is relative to the pom.xml directory -->
|
||||
<directory>${custom.webResources}</directory>
|
||||
<includes>
|
||||
<include>**/WEB-INF/*</include>
|
||||
<!-- include any other file types you want to filter -->
|
||||
</includes>
|
||||
</resource>
|
||||
</webResources>
|
||||
<workDirectory>target/overlay-war-folder</workDirectory>
|
||||
<!-- We exclude libs form the parent WAR artifact -->
|
||||
<overlays>
|
||||
<overlay>
|
||||
<groupId>org.imixs.workflow</groupId>
|
||||
<artifactId>imixs-office-workflow-app</artifactId>
|
||||
<excludes>
|
||||
<exclude>WEB-INF/lib/*.jar</exclude>
|
||||
</excludes>
|
||||
</overlay>
|
||||
</overlays>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.imixs.maven</groupId>
|
||||
<artifactId>manik-hotdeploy-maven-plugin</artifactId>
|
||||
<version>2.0.0</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>install</phase>
|
||||
<goals>
|
||||
<goal>deploy</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<!-- List Source and Target folders for Autodeploy and Hotdeploy -->
|
||||
<autodeployments>
|
||||
<deployment>
|
||||
<!-- wildcard deployment -->
|
||||
<source>target/*.{war,ear,jar}</source>
|
||||
<target>../docker/deployments/</target>
|
||||
<unpack>true</unpack>
|
||||
</deployment>
|
||||
</autodeployments>
|
||||
<hotdeployments>
|
||||
<deployment>
|
||||
<source>src/main/webapp</source>
|
||||
<target>../docker/deployments/office-alexander-logistics.war</target>
|
||||
</deployment>
|
||||
</hotdeployments>
|
||||
|
||||
</configuration>
|
||||
|
||||
</plugin>
|
||||
|
||||
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
|
||||
<dependencies>
|
||||
<!-- Imixs Workflow -->
|
||||
<dependency>
|
||||
<groupId>org.imixs.workflow</groupId>
|
||||
<artifactId>imixs-workflow-core</artifactId>
|
||||
<type>jar</type>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.imixs.workflow</groupId>
|
||||
<artifactId>imixs-workflow-engine</artifactId>
|
||||
<type>jar</type>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.imixs.workflow</groupId>
|
||||
<artifactId>imixs-workflow-jax-rs</artifactId>
|
||||
<type>jar</type>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.imixs.workflow</groupId>
|
||||
<artifactId>imixs-workflow-faces</artifactId>
|
||||
<type>jar</type>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.imixs.workflow</groupId>
|
||||
<artifactId>imixs-workflow-index-lucene</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Marty -->
|
||||
<dependency>
|
||||
<groupId>org.imixs.workflow</groupId>
|
||||
<artifactId>imixs-marty</artifactId>
|
||||
<type>jar</type>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Imixs-Office-Workflow -->
|
||||
<dependency>
|
||||
<groupId>org.imixs.workflow</groupId>
|
||||
<artifactId>imixs-office-workflow-app</artifactId>
|
||||
<type>war</type>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.imixs.workflow</groupId>
|
||||
<artifactId>imixs-office-workflow-util</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Imixs-Archive -->
|
||||
<dependency>
|
||||
<groupId>org.imixs.workflow</groupId>
|
||||
<artifactId>imixs-archive-api</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Imixs-Archive Documents -->
|
||||
<dependency>
|
||||
<groupId>org.imixs.workflow</groupId>
|
||||
<artifactId>imixs-archive-documents</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Imixs-Archive Importer -->
|
||||
<dependency>
|
||||
<groupId>org.imixs.workflow</groupId>
|
||||
<artifactId>imixs-archive-importer</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- SEPA Adapter -->
|
||||
<dependency>
|
||||
<groupId>org.imixs.workflow</groupId>
|
||||
<artifactId>imixs-adapters-sepa</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<!-- DATEV Adapter -->
|
||||
<dependency>
|
||||
<groupId>org.imixs.workflow</groupId>
|
||||
<artifactId>imixs-adapters-datev</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<!-- QR Code -->
|
||||
<dependency>
|
||||
<groupId>org.imixs.workflow</groupId>
|
||||
<artifactId>imixs-adapters-qrcode</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<!-- POI Adapter -->
|
||||
<dependency>
|
||||
<groupId>org.imixs.workflow</groupId>
|
||||
<artifactId>imixs-adapters-poi</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.imixs.workflow</groupId>
|
||||
<artifactId>imixs-ai-workflow</artifactId>
|
||||
<version>${org.imixs.ai.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- xsl 2.0 support for Reporting / Chart Diagrams -->
|
||||
<dependency>
|
||||
<groupId>net.sf.saxon</groupId>
|
||||
<artifactId>Saxon-HE</artifactId>
|
||||
</dependency>
|
||||
<!-- Apache PDFBox -->
|
||||
<dependency>
|
||||
<groupId>org.apache.pdfbox</groupId>
|
||||
<artifactId>pdfbox</artifactId>
|
||||
<version>${apache.pdfbox.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Apache Commons FTP Client -->
|
||||
<dependency>
|
||||
<groupId>commons-net</groupId>
|
||||
<artifactId>commons-net</artifactId>
|
||||
<version>3.6</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Microsoft oauth token -->
|
||||
<dependency>
|
||||
<groupId>com.sun.mail</groupId>
|
||||
<artifactId>javax.mail</artifactId>
|
||||
<version>1.6.2</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.httpcomponents</groupId>
|
||||
<artifactId>httpclient</artifactId>
|
||||
<version>4.5.10</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
<version>2.13.3</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- JUnit Tests
|
||||
<dependency>
|
||||
<groupId>javax.json</groupId>
|
||||
<artifactId>javax.json-api</artifactId>
|
||||
<version>1.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.glassfish</groupId>
|
||||
<artifactId>javax.json</artifactId>
|
||||
<version>1.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
-->
|
||||
<!-- JAX-RS 2.0 Test dependencies -->
|
||||
<dependency>
|
||||
<groupId>org.glassfish.jersey.core</groupId>
|
||||
<artifactId>jersey-client</artifactId>
|
||||
<version>3.1.2</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.cxf</groupId>
|
||||
<artifactId>cxf-rt-rs-client</artifactId>
|
||||
<version>3.3.6</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.glassfish.jersey.inject</groupId>
|
||||
<artifactId>jersey-hk2</artifactId>
|
||||
<version>3.1.2</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>jakarta.ws.rs</groupId>
|
||||
<artifactId>jakarta.ws.rs-api</artifactId>
|
||||
<version>3.1.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
</project>
|
||||
|
|
@ -1,636 +0,0 @@
|
|||
package com.alexanderlogistics;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.text.DecimalFormat;
|
||||
import java.text.DecimalFormatSymbols;
|
||||
import java.text.ParseException;
|
||||
import java.time.LocalDate;
|
||||
import java.time.YearMonth;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.imixs.marty.team.TeamService;
|
||||
import org.imixs.workflow.ItemCollection;
|
||||
import org.imixs.workflow.engine.DocumentService;
|
||||
import org.imixs.workflow.exceptions.QueryException;
|
||||
import org.imixs.workflow.faces.data.WorkflowController;
|
||||
import org.imixs.workflow.office.forms.AnalyticController;
|
||||
import org.imixs.workflow.office.forms.AnalyticEvent;
|
||||
|
||||
import jakarta.enterprise.context.ConversationScoped;
|
||||
import jakarta.enterprise.event.Observes;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.inject.Named;
|
||||
|
||||
/**
|
||||
* Der AGLAnalyticControllerDebitor berechnet verschiedene Analyse Daten von
|
||||
* Ausgangsrechnungen
|
||||
*
|
||||
* @author rsoika
|
||||
*
|
||||
*/
|
||||
@Named
|
||||
@ConversationScoped
|
||||
public class AGLAnalyticControllerDebitor implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static Logger logger = Logger.getLogger(AnalyticController.class.getName());
|
||||
|
||||
@Inject
|
||||
protected DocumentService documentService;
|
||||
|
||||
@Inject
|
||||
protected AGLConfigController aglConfigController;
|
||||
|
||||
@Inject
|
||||
protected WorkflowController workflowController;
|
||||
|
||||
@Inject
|
||||
TeamService teamService;
|
||||
|
||||
TreeMap<String, DebitorStatistikData> stats = null;
|
||||
|
||||
List<ItemCollection> invoices = null;
|
||||
int countAll = 0;
|
||||
int countOpen = 0;
|
||||
int countDue = 0;
|
||||
int countDunning = 0;
|
||||
|
||||
double totalAllCurrency1 = 0;
|
||||
double totalAllCurrency2 = 0;
|
||||
|
||||
double totalOpenCurrency1 = 0;
|
||||
double totalOpenCurrency2 = 0;
|
||||
|
||||
double totalDueCurrency1 = 0;
|
||||
double totalDueCurrency2 = 0;
|
||||
|
||||
double totalDunningCurrency1 = 0;
|
||||
double totalDunningCurrency2 = 0;
|
||||
|
||||
double averagePaymentDue = 0;
|
||||
double averagePaymentDays = 0;
|
||||
|
||||
String chartData = "";
|
||||
|
||||
public void onEvent(@Observes AnalyticEvent event) {
|
||||
|
||||
if (!"workitem".equals(event.getWorkitem().getType())) {
|
||||
// no op
|
||||
return;
|
||||
}
|
||||
String dbtrNumber = event.getWorkitem().getItemValueString("dbtr.number");
|
||||
String dbtrNumberLast = event.getWorkitem().getItemValueString("dbtr.number.last");
|
||||
|
||||
// Recompute only if last dbtr.number has changed or no values yet computed
|
||||
|
||||
// load all invoices?
|
||||
if (invoices == null || (!dbtrNumber.isEmpty() && !dbtrNumber.equals(dbtrNumberLast))) {
|
||||
resetStats();
|
||||
event.getWorkitem().setItemValue("dbtr.number.last", dbtrNumber);
|
||||
logger.info("Analyse new debitor data for : " + dbtrNumber);
|
||||
loadRechnungen();
|
||||
chartData = buildChartData();
|
||||
}
|
||||
|
||||
String link = "/pages/workitems/worklist.xhtml" + "?phrase=" + getDbtNr();
|
||||
logger.fine("process ref=" + workflowController.getWorkitem().getItemValueString("process.ref"));
|
||||
ItemCollection process = documentService
|
||||
.load(workflowController.getWorkitem().getItemValueString("process.ref"));
|
||||
if (process != null) {
|
||||
link = link + "&processref=" + process.getUniqueID()
|
||||
+ "&phrase=" + getDbtNr();
|
||||
}
|
||||
if ("analytic.invoices.count.all".equals(event.getKey())) {
|
||||
event.setValue("" + countAll);
|
||||
event.setLabel(formatTotals(totalAllCurrency1, totalAllCurrency2));
|
||||
event.setDescription("Total invoices");
|
||||
event.getWorkitem().setItemValue("invoices.total", event.getValue());
|
||||
event.setLink(link);
|
||||
}
|
||||
|
||||
if ("analytic.invoices.count.open".equals(event.getKey())) {
|
||||
event.setValue("" + countOpen);
|
||||
event.setLabel(formatTotals(totalOpenCurrency1, totalOpenCurrency2));
|
||||
event.setDescription("Total invoices not yet in due");
|
||||
event.getWorkitem().setItemValue("invoices.total.open", event.getValue());
|
||||
event.setLink(link);
|
||||
}
|
||||
|
||||
if ("analytic.invoices.count.due".equals(event.getKey())) {
|
||||
event.setValue("" + countDue);
|
||||
event.setLabel(formatTotals(totalDueCurrency1, totalDueCurrency2));
|
||||
event.setDescription("Total invoices in due");
|
||||
event.getWorkitem().setItemValue("invoices.total.due", event.getValue());
|
||||
event.setLink(link);
|
||||
}
|
||||
if ("analytic.invoices.count.dunning".equals(event.getKey())) {
|
||||
event.setValue("" + countDunning);
|
||||
event.setLabel(formatTotals(totalDunningCurrency1, totalDunningCurrency2));
|
||||
event.setDescription("Total invoices in dunning");
|
||||
event.getWorkitem().setItemValue("invoices.total.dunning", event.getValue());
|
||||
event.setLink(link);
|
||||
}
|
||||
|
||||
if ("analytic.payment.avg.due".equals(event.getKey())) {
|
||||
event.setValue("" + averagePaymentDue);
|
||||
event.setLabel("days");
|
||||
event.setDescription("Average terms of credit in the last 12 months.");
|
||||
event.getWorkitem().setItemValue("payment.avg.due", event.getValue());
|
||||
event.setLink(link);
|
||||
}
|
||||
if ("analytic.payment.avg.days".equals(event.getKey())) {
|
||||
event.setValue("" + averagePaymentDays);
|
||||
event.setLabel("days");
|
||||
event.setDescription("Average duration for payment during the last 12 months.");
|
||||
event.getWorkitem().setItemValue("payment.avg.days", event.getValue());
|
||||
event.setLink(link);
|
||||
}
|
||||
|
||||
if ("analytic.invoices.trend".equals(event.getKey())) {
|
||||
event.setValue(chartData);
|
||||
event.setLabel("Payment duration in days");
|
||||
event.setDescription("Payment practice by week");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Formatiert zwei währungen untereinander
|
||||
*
|
||||
* @param totalCurrency1
|
||||
* @param totalCurrency2
|
||||
* @return
|
||||
*/
|
||||
private String formatTotals(double totalCurrency1, double totalCurrency2) {
|
||||
|
||||
List<String> currencies = aglConfigController.getWorkitem().getItemValueList("currency.out", String.class);
|
||||
if (currencies.size() < 2) {
|
||||
currencies.add(currencies.get(0));
|
||||
}
|
||||
String label = "<span class=\"pull-right\">" + formatCurrency(totalCurrency1) + " " + currencies.get(0)
|
||||
+ "</span>";
|
||||
label = label + "</br><span class=\"pull-right\">" +
|
||||
formatCurrency(totalCurrency2) + " " + currencies.get(1) + "</span>";
|
||||
|
||||
return label;
|
||||
}
|
||||
|
||||
private void loadRechnungen() {
|
||||
if (getDbtNr().isEmpty()) {
|
||||
invoices = new ArrayList();
|
||||
stats = null;
|
||||
} else {
|
||||
logger.info(" ├──load invoices for " + getDbtNr() + "....");
|
||||
String query = "(type:workitem) AND dbtr.number:" + getDbtNr()
|
||||
+ " AND $modelversion:rechnungsausgang-*";
|
||||
try {
|
||||
logger.info(" ├──refresh invoice stats for " + getDbtNr() + "....");
|
||||
invoices = documentService.find(query, 999, 0, "$created", false);
|
||||
calculateStats();
|
||||
} catch (QueryException e) {
|
||||
logger.warning("Failed to query invoices: " + query + " - Error: " + e.getMessage());
|
||||
invoices = new ArrayList();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Läd die statistik daten zu einem debitor aus den aktuellen Rechnungen
|
||||
*/
|
||||
private void calculateStats() {
|
||||
countAll = 0;
|
||||
countOpen = 0;
|
||||
countDue = 0;
|
||||
countDunning = 0;
|
||||
logger.info(" ├──calculate stats for " + getDbtNr() + "....");
|
||||
// do we have data?
|
||||
if (invoices != null && invoices.size() > 0) {
|
||||
countAll = invoices.size();
|
||||
|
||||
for (ItemCollection invoice : invoices) {
|
||||
|
||||
// währung 1 oder 2?
|
||||
if (invoice.getItemValueDouble("invoice.rate") == 0) {
|
||||
totalAllCurrency1 = totalAllCurrency1 + invoice.getItemValueDouble("invoice.saldo");
|
||||
} else {
|
||||
totalAllCurrency2 = totalAllCurrency2 + invoice.getItemValueDouble("invoice.saldo");
|
||||
}
|
||||
|
||||
int task = invoice.getTaskID();
|
||||
|
||||
// Open
|
||||
if (task >= 5000 && task <= 5099) {
|
||||
countOpen++;
|
||||
// währung 1 oder 2?
|
||||
if (invoice.getItemValueDouble("invoice.rate") == 0) {
|
||||
totalOpenCurrency1 = totalOpenCurrency1 + invoice.getItemValueDouble("invoice.saldo");
|
||||
} else {
|
||||
totalOpenCurrency2 = totalOpenCurrency2 + invoice.getItemValueDouble("invoice.saldo");
|
||||
}
|
||||
}
|
||||
|
||||
// Due
|
||||
if (task >= 5100 && task <= 5199) {
|
||||
countDue++;
|
||||
// währung 1 oder 2?
|
||||
if (invoice.getItemValueDouble("invoice.rate") == 0) {
|
||||
totalDueCurrency1 = totalDueCurrency1 + invoice.getItemValueDouble("invoice.saldo");
|
||||
} else {
|
||||
totalDueCurrency2 = totalDueCurrency2 + invoice.getItemValueDouble("invoice.saldo");
|
||||
}
|
||||
}
|
||||
|
||||
// Dunning
|
||||
if (task >= 5200) {
|
||||
countDunning++;
|
||||
// währung 1 oder 2?
|
||||
if (invoice.getItemValueDouble("invoice.rate") == 0) {
|
||||
totalDunningCurrency1 = totalDunningCurrency1 + invoice.getItemValueDouble("invoice.saldo");
|
||||
} else {
|
||||
totalDunningCurrency2 = totalDunningCurrency2 + invoice.getItemValueDouble("invoice.saldo");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
totalAllCurrency1 = InvoiceUtil.round(totalAllCurrency1);
|
||||
totalAllCurrency2 = InvoiceUtil.round(totalAllCurrency2);
|
||||
totalOpenCurrency1 = InvoiceUtil.round(totalOpenCurrency1);
|
||||
totalOpenCurrency2 = InvoiceUtil.round(totalOpenCurrency2);
|
||||
totalDueCurrency1 = InvoiceUtil.round(totalDueCurrency1);
|
||||
totalDueCurrency2 = InvoiceUtil.round(totalDueCurrency2);
|
||||
totalDunningCurrency1 = InvoiceUtil.round(totalDunningCurrency1);
|
||||
totalDunningCurrency2 = InvoiceUtil.round(totalDunningCurrency2);
|
||||
|
||||
} else {
|
||||
// reset data because no invoices are available ...
|
||||
resetStats();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Setzt alle Statistikwerte zurück
|
||||
*/
|
||||
private void resetStats() {
|
||||
logger.info(" ├──reset stats for " + getDbtNr() + "....");
|
||||
stats = null;
|
||||
|
||||
totalAllCurrency1 = 0;
|
||||
totalAllCurrency2 = 0;
|
||||
totalOpenCurrency1 = 0;
|
||||
totalOpenCurrency2 = 0;
|
||||
totalDueCurrency1 = 0;
|
||||
totalDueCurrency2 = 0;
|
||||
totalDunningCurrency1 = 0;
|
||||
totalDunningCurrency2 = 0;
|
||||
|
||||
// chartData = null;
|
||||
chartData = "{}";
|
||||
|
||||
averagePaymentDue = 0;
|
||||
averagePaymentDays = 0;
|
||||
}
|
||||
|
||||
private void getDurchschnittZahlungsziel() {
|
||||
if (stats == null) {
|
||||
averagePaymentDue = 0;
|
||||
return;
|
||||
}
|
||||
int count = 0;
|
||||
long gesamt = 0;
|
||||
for (Map.Entry<String, DebitorStatistikData> entry : stats.entrySet()) {
|
||||
DebitorStatistikData statData = entry.getValue();
|
||||
if (statData.count > 0) {
|
||||
gesamt = gesamt + statData.getAverageDueDays();
|
||||
count++;
|
||||
}
|
||||
}
|
||||
averagePaymentDue = Math.round((double) gesamt / count);
|
||||
}
|
||||
|
||||
private void getDurchschnittZahlungsdauer() {
|
||||
if (stats == null) {
|
||||
averagePaymentDays = 0;
|
||||
return;
|
||||
}
|
||||
int count = 0;
|
||||
long gesamt = 0;
|
||||
for (Map.Entry<String, DebitorStatistikData> entry : stats.entrySet()) {
|
||||
DebitorStatistikData statData = entry.getValue();
|
||||
if (statData.count > 0) {
|
||||
gesamt = gesamt + statData.getAveragePaymentDays();
|
||||
count++;
|
||||
}
|
||||
}
|
||||
averagePaymentDays = Math.round((double) gesamt / count);
|
||||
}
|
||||
|
||||
private String formatCurrency(Double value) {
|
||||
|
||||
DecimalFormatSymbols symbols = new DecimalFormatSymbols(Locale.getDefault());
|
||||
symbols.setGroupingSeparator('.');
|
||||
symbols.setDecimalSeparator(',');
|
||||
DecimalFormat formatter = new DecimalFormat("#,##0.00", symbols);
|
||||
|
||||
return formatter.format(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Hilfsmethode die das fuehrende K/D aus der Debitorennummer entfernt
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private String getDbtNr() {
|
||||
String dbtNr = workflowController.getWorkitem().getItemValueString("dbtr.number");
|
||||
if (dbtNr.startsWith("D") || dbtNr.startsWith("K")) {
|
||||
dbtNr = dbtNr.substring(1);
|
||||
}
|
||||
return dbtNr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sucht alle Rechnugnen aus einem Zeitraum und sammelt Zahlungsziel und
|
||||
* Zahlungszeitspanne gruppiert nach monaten
|
||||
*
|
||||
*/
|
||||
public Map<String, DebitorStatistikData> loadStats() {
|
||||
|
||||
if (stats != null) {
|
||||
return stats;
|
||||
}
|
||||
|
||||
logger.info(" ├──load stats for " + getDbtNr() + "....");
|
||||
// recompute
|
||||
stats = new TreeMap<String, DebitorStatistikData>();
|
||||
if (getDbtNr().isEmpty()) {
|
||||
return stats;
|
||||
}
|
||||
|
||||
// Letzen 12 Monate
|
||||
LocalDate endDate = LocalDate.now();
|
||||
LocalDate startDate = endDate.minusMonths(12);
|
||||
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd");
|
||||
String startDateStr = startDate.format(formatter);
|
||||
String endDateStr = endDate.format(formatter);
|
||||
|
||||
String query = "(type:workitemarchive) AND "
|
||||
+ " invoice.date:[" + startDateStr + " TO " + endDateStr + "] AND "
|
||||
+ "dbtr.number:" + getDbtNr()
|
||||
+ " AND $modelversion:rechnungsausgang-* AND ($taskid:[5900 TO 5999])";
|
||||
|
||||
logger.fine("query = " + query);
|
||||
try {
|
||||
List<ItemCollection> invoices = documentService
|
||||
.findStubs(query, 9999, 0, "$created", false);
|
||||
|
||||
for (ItemCollection invoice : invoices) {
|
||||
try {
|
||||
|
||||
logger.fine("Rechnung: " + invoice.getUniqueID());
|
||||
Date invoiceDate = invoice.getItemValueDate("invoice.date");
|
||||
Date invoiceDueDate = invoice.getItemValueDate("invoice.duedate");
|
||||
Date paymentDate = findPaymentDateByWorkitem(invoice);
|
||||
if (paymentDate == null) {
|
||||
logger.fine("Es wurde kein Zahlungseingang gefunden");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (invoiceDate != null && paymentDate != null && invoiceDueDate != null) {
|
||||
// do we have a stats object?
|
||||
DebitorStatistikData statData = stats.get(getYearMonth(invoiceDate));
|
||||
if (statData == null) {
|
||||
// create a new one
|
||||
statData = new DebitorStatistikData(invoiceDate);
|
||||
}
|
||||
// jetzt irgendwas ausrechnen
|
||||
statData.compute(invoiceDate, invoiceDueDate, paymentDate);
|
||||
// .. und wieder speichern
|
||||
stats.put(statData.toString(), statData);
|
||||
|
||||
} else {
|
||||
logger.warning("No payment Date found for invoice " + invoice.getUniqueID());
|
||||
}
|
||||
|
||||
} catch (ParseException e) {
|
||||
logger.warning("Unable to parse payment Date for invoice " + invoice.getUniqueID());
|
||||
}
|
||||
}
|
||||
|
||||
} catch (QueryException e) {
|
||||
logger.severe("Failed to get statistic: " + e.getMessage());
|
||||
}
|
||||
// Step 2: Sort the list based on the alphanumeric order of the keys
|
||||
completeMissingMonths();
|
||||
|
||||
// berechne zahluntsziel durchscnitt
|
||||
getDurchschnittZahlungsziel();
|
||||
getDurchschnittZahlungsdauer();
|
||||
return stats;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the payment.date for a invoice.
|
||||
*
|
||||
* Wir suchen alle zugeordneten Zahlungseingägne und nehmen den letzten.
|
||||
*
|
||||
* WICHTIG: Es muss ggf. der index neu aufgebaut werden, da payment.date nun ein
|
||||
* index feld ist
|
||||
*
|
||||
* @param invoice
|
||||
* @return
|
||||
* @throws ParseException
|
||||
*/
|
||||
public Date findPaymentDateByWorkitem(ItemCollection invoice) throws ParseException {
|
||||
|
||||
// Wir selektieren alle Zahlungseingänge interessieren uns aber nur für den
|
||||
// letzten
|
||||
String sQuery = " (type:\"workitem\" OR type:\"workitemarchive\") " + //
|
||||
" AND ($modelversion:zahlungseingang-*) AND ($workitemref:\""
|
||||
+ invoice.getUniqueID() + "\" )";
|
||||
|
||||
List<ItemCollection> workitems = null;
|
||||
|
||||
try {
|
||||
workitems = documentService.findStubs(sQuery, 99, 0,
|
||||
"payment.date", true);
|
||||
if (workitems.size() > 0) {
|
||||
return workitems.get(0).getItemValueDate("payment.date");
|
||||
}
|
||||
} catch (QueryException e) {
|
||||
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
// no date found!
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Diese Methode baut die Datenstruktur für das Chart Diagram zusammen
|
||||
*
|
||||
*
|
||||
* <pre>
|
||||
{
|
||||
labels: ["January", "February", "March", "April", "May", "June", "July"],
|
||||
datasets: [{
|
||||
label: 'Dataset 1',
|
||||
//backgroundColor: color(window.chartColors.red).alpha(0.5).rgbString(),
|
||||
//borderColor: window.chartColors.red,
|
||||
borderWidth: 1,
|
||||
data: [
|
||||
70, 70, 70, 70, 79, 50, 50
|
||||
]
|
||||
}, {
|
||||
label: 'Dataset 2',
|
||||
//backgroundColor: color(window.chartColors.blue).alpha(0.5).rgbString(),
|
||||
//borderColor: window.chartColors.blue,
|
||||
borderWidth: 1,
|
||||
data: [
|
||||
70, 70, 170, 7, 79, 50, 50
|
||||
]
|
||||
}]
|
||||
}
|
||||
* </pre>
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public String buildChartData() {
|
||||
|
||||
loadStats();
|
||||
logger.info(" ├──build chart for " + getDbtNr() + "....");
|
||||
// build a list of all lables....
|
||||
List<String> statusLabels = new ArrayList<String>();
|
||||
|
||||
Set<String> keys = stats.keySet();
|
||||
for (String _key : keys) {
|
||||
statusLabels.add(_key);
|
||||
}
|
||||
|
||||
String result = "{\n \"type\": \"bar\",\n \"data\": { ";
|
||||
|
||||
// Lables
|
||||
result = result + "\"labels\" : [ ";
|
||||
result = result + statusLabels.stream().collect(Collectors.joining("\",\"", "\"", "\""));
|
||||
result = result + "],";
|
||||
result = result + "\"datasets\": [";
|
||||
|
||||
// Datasets 1
|
||||
result = result + "{\"label\": \"Days for payment\",\"borderWidth\": 1,";
|
||||
result = result + " \"borderColor\": [\"#3B6B82\"],";
|
||||
result = result + " \"backgroundColor\" : [\"#CFE9F5\"], \"fill\": true,\"tension\": 0.5,";
|
||||
|
||||
result = result + "\"data\": [";
|
||||
for (Map.Entry<String, DebitorStatistikData> entry : stats.entrySet()) {
|
||||
result = result + entry.getValue().getAverageDueDays() + ",";
|
||||
}
|
||||
// cut last comma
|
||||
if (result.endsWith(",")) {
|
||||
result = result.substring(0, result.length() - 1);
|
||||
}
|
||||
result = result + "]";
|
||||
result = result + "}, ";
|
||||
|
||||
// Datasets 2
|
||||
result = result + "{\"label\": \"Payment duration\",\"borderWidth\": 1,";
|
||||
result = result
|
||||
+ " \"borderColor\": [\"#E73B65\"],\"backgroundColor\" : [\"#70B088\" ], \"tension\": 0.5,\"fill\": true,";
|
||||
|
||||
result = result
|
||||
+ " \"trendlineLinear\": { \"colorMin\": \"red\", \"colorMax\": \"green\", \"lineStyle\": \"dotted\", \"width\": 2 , \"projection\": true },";
|
||||
|
||||
result = result + "\"data\": [";
|
||||
for (Map.Entry<String, DebitorStatistikData> entry : stats.entrySet()) {
|
||||
result = result + entry.getValue().getAveragePaymentDays() + ",";
|
||||
}
|
||||
// cut last comma
|
||||
if (result.endsWith(",")) {
|
||||
result = result.substring(0, result.length() - 1);
|
||||
}
|
||||
result = result + "]";
|
||||
result = result + "} ";
|
||||
|
||||
// ende
|
||||
result = result + "] }";
|
||||
|
||||
result = result + "}";
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hilfsmethode ergänzt die fehlenden Monate
|
||||
*
|
||||
* @param yearMonths
|
||||
* @return
|
||||
*/
|
||||
private void completeMissingMonths() {
|
||||
if (stats == null || stats.size() < 3) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Convert the list of strings to a list of LocalDate objects
|
||||
List<LocalDate> dates = new ArrayList<>();
|
||||
Set<String> yearMonths = this.stats.keySet();
|
||||
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMM");
|
||||
for (String yearMonth : yearMonths) {
|
||||
dates.add(YearMonth.parse(yearMonth, formatter).atDay(1));
|
||||
}
|
||||
|
||||
// Find the lowest and highest dates
|
||||
LocalDate lowestDate = Collections.min(dates);
|
||||
LocalDate highestDate = Collections.max(dates);
|
||||
|
||||
LocalDate current = lowestDate;
|
||||
current = current.plusMonths(1);
|
||||
while (!current.isAfter(highestDate)) {
|
||||
|
||||
// existiert der monat?
|
||||
String formattedDate = current.format(formatter);
|
||||
DebitorStatistikData entry = stats.get(formattedDate);
|
||||
if (entry == null) {
|
||||
// add missing entry
|
||||
stats.put(formattedDate, new DebitorStatistikData(current.getYear(), current.getMonthValue()));
|
||||
}
|
||||
current = current.plusMonths(1);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* returns
|
||||
*
|
||||
* 202304 from a given date
|
||||
*/
|
||||
public String getYearMonth(Date date) {
|
||||
|
||||
// Create a Calendar instance and set the date
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
calendar.setTime(date);
|
||||
|
||||
// Get the year from the Calendar object
|
||||
int year = calendar.get(Calendar.YEAR);
|
||||
// Get the month from the Calendar object
|
||||
int month = calendar.get(Calendar.MONTH);
|
||||
// Increment the month by 1 since Calendar months are zero-based
|
||||
month++;
|
||||
// Convert the month to a String with leading "0" if necessary
|
||||
return "" + year + (month < 10 ? "0" + month : "" + month);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,526 +0,0 @@
|
|||
package com.alexanderlogistics;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.imixs.marty.team.TeamService;
|
||||
import org.imixs.workflow.ItemCollection;
|
||||
import org.imixs.workflow.engine.DocumentService;
|
||||
import org.imixs.workflow.exceptions.QueryException;
|
||||
import org.imixs.workflow.faces.data.WorkflowController;
|
||||
import org.imixs.workflow.office.forms.AnalyticController;
|
||||
import org.imixs.workflow.office.forms.AnalyticEvent;
|
||||
|
||||
import jakarta.enterprise.context.RequestScoped;
|
||||
import jakarta.enterprise.event.Observes;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.inject.Named;
|
||||
import jakarta.json.Json;
|
||||
import jakarta.json.JsonArrayBuilder;
|
||||
import jakarta.json.JsonObject;
|
||||
import jakarta.json.JsonObjectBuilder;
|
||||
|
||||
/**
|
||||
* Der AGLAnalyticController berechnet verschiedene Analyse Daten
|
||||
*
|
||||
* @author rsoika
|
||||
*
|
||||
*/
|
||||
@Named
|
||||
@RequestScoped
|
||||
public class AGLAnalyticControllerSteuer implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static Logger logger = Logger.getLogger(AnalyticController.class.getName());
|
||||
|
||||
@Inject
|
||||
protected DocumentService documentService;
|
||||
|
||||
@Inject
|
||||
TeamService teamService;
|
||||
|
||||
@Inject
|
||||
protected WorkflowController workflowController;
|
||||
|
||||
@Inject
|
||||
|
||||
protected DebitorStatistikController debitorStatistikController;
|
||||
|
||||
List<ItemCollection> steuerbescheide = null;
|
||||
|
||||
public void onEvent(@Observes AnalyticEvent event) {
|
||||
|
||||
ItemCollection process = documentService
|
||||
.load(workflowController.getWorkitem().getItemValueString("process.ref"));
|
||||
String link = "/pages/workitems/worklist.xhtml";
|
||||
if (process != null) {
|
||||
link = link + "?processref=" + process.getUniqueID()
|
||||
+ "&workflowgroup=Steuerbescheid";
|
||||
}
|
||||
if ("analytic.steuer.eust".equals(event.getKey())) {
|
||||
event.setValue(computeSteuerbescheideEUST());
|
||||
event.setLabel("EUR");
|
||||
event.setDescription("Gesamt Einfuhrumsatzsteuer (EUSt)");
|
||||
event.getWorkitem().setItemValue("eust.total", event.getValue());
|
||||
event.setLink(link);
|
||||
}
|
||||
if ("analytic.steuer.zoll".equals(event.getKey())) {
|
||||
event.setValue(computeSteuerbescheideZoll());
|
||||
event.setLabel("EUR");
|
||||
event.setDescription("Gesamt Zölle (ZOLLEU)");
|
||||
event.setLink(link);
|
||||
}
|
||||
|
||||
if ("analytic.steuer.total".equals(event.getKey())) {
|
||||
event.setValue(computeSteuerbescheideTotal());
|
||||
event.setLabel("EUR");
|
||||
event.setDescription("Alle Steuerbescheide die noch nicht abgerechnet wurden.");
|
||||
event.setLink(link);
|
||||
}
|
||||
|
||||
if ("analytic.steuer.saldo".equals(event.getKey())) {
|
||||
event.setValue(computeSteuerbescheideSaldo());
|
||||
event.setLabel("EUR");
|
||||
event.setDescription("Saldo aller Steuerbescheide die noch nicht abgerechnet wurden.");
|
||||
event.setLink(link);
|
||||
}
|
||||
|
||||
if ("analytic.steuer.due".equals(event.getKey())) {
|
||||
event.setValue(computeSteuerbescheideSaldoDue());
|
||||
event.setLabel("EUR");
|
||||
event.setDescription("Saldo aller überfälligen Steuerbescheide die noch nicht abgerechnet wurden.");
|
||||
// event.setLink(link + "&task=Überfällig");
|
||||
event.setLink(link + "&task=1200");
|
||||
}
|
||||
|
||||
// Charts
|
||||
|
||||
if ("analytic.steuer.trend".equals(event.getKey())) {
|
||||
event.setValue(accumulateSteuerbescheideByWeek());
|
||||
event.setLabel("Zoll & EUST");
|
||||
event.setDescription("Fälligkeiten nach KW");
|
||||
}
|
||||
|
||||
if ("analytic.steuer.trend.abteilung".equals(event.getKey())) {
|
||||
event.setValue(accumulateSteuerbescheideAbteilungByWeek());
|
||||
event.setLabel("Nach Abteilungen");
|
||||
event.setDescription("Offene Salden nach KW pro Abteilung");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Berechnet die Summe aller offenen EUST Beträge
|
||||
* // tax.code=[0], amount=[3885.16], activity.type=[EUST],
|
||||
* // filenumber=[LA-PAP-2408-024]}
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private double computeSteuerbescheideEUST() {
|
||||
logger.fine("compute EUST...");
|
||||
List<ItemCollection> list = getSteuerbescheide();
|
||||
double result = 0;
|
||||
|
||||
for (ItemCollection steuerItemCol : list) {
|
||||
result = result + getZollBySteuerBeleg(steuerItemCol, "EUST");
|
||||
|
||||
}
|
||||
return InvoiceUtil.round(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Berechnet die Summe aller offenen Zoll Beträge
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private double computeSteuerbescheideZoll() {
|
||||
logger.fine("compute Zoll...");
|
||||
List<ItemCollection> list = getSteuerbescheide();
|
||||
double result = 0;
|
||||
for (ItemCollection steuerItemCol : list) {
|
||||
result = result + getZollBySteuerBeleg(steuerItemCol, "ZOLL");
|
||||
}
|
||||
return InvoiceUtil.round(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Berechnet die Summe aller überfälligen steuer Beträge $taskID=1200
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private double computeSteuerbescheideSaldo() {
|
||||
logger.fine("compute saldo...");
|
||||
List<ItemCollection> list = getSteuerbescheide();
|
||||
double result = 0;
|
||||
for (ItemCollection steuerItemCol : list) {
|
||||
result = result + steuerItemCol.getItemValueDouble("invoice.saldo");
|
||||
}
|
||||
return InvoiceUtil.round(result);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Berechnet die Summe aller überfälligen steuer Beträge $taskID=1200
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private double computeSteuerbescheideTotal() {
|
||||
logger.fine("compute total...");
|
||||
List<ItemCollection> list = getSteuerbescheide();
|
||||
double result = 0;
|
||||
for (ItemCollection steuerItemCol : list) {
|
||||
result = result + steuerItemCol.getItemValueDouble("invoice.total.net");
|
||||
}
|
||||
return InvoiceUtil.round(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Berechnet die Summe aller überfälligen steuer Beträge $taskID=1200
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private double computeSteuerbescheideSaldoDue() {
|
||||
logger.fine("compute EUST...");
|
||||
List<ItemCollection> list = getSteuerbescheide();
|
||||
double result = 0;
|
||||
for (ItemCollection steuerItemCol : list) {
|
||||
if (steuerItemCol.getTaskID() == 1200) {
|
||||
result = result + steuerItemCol.getItemValueDouble("invoice.saldo");
|
||||
}
|
||||
}
|
||||
return InvoiceUtil.round(result);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Berechnet die summ zoll/eust für einen Beleg
|
||||
*
|
||||
* @param steuerItemCol
|
||||
* @return
|
||||
*/
|
||||
private double getZollBySteuerBeleg(ItemCollection steuerItemCol, String type) {
|
||||
double result = 0;
|
||||
List<ItemCollection> positionsTabelle = InvoiceUtil.explodeChildList(steuerItemCol);
|
||||
for (ItemCollection pos : positionsTabelle) {
|
||||
if (type.equalsIgnoreCase(pos.getItemValueString("activity.type"))) {
|
||||
result = result + pos.getItemValueDouble("amount");
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private List<ItemCollection> getSteuerbescheide() {
|
||||
if (steuerbescheide != null) {
|
||||
return steuerbescheide;
|
||||
}
|
||||
// compute steuerbescheide....
|
||||
logger.info("Load Steuerbescheide for analytics....");
|
||||
String query = "(type:workitem ) AND ($workflowgroup:\"Steuerbescheid\")";
|
||||
try {
|
||||
steuerbescheide = documentService.find(query, 999, 0, "$created", false);
|
||||
return steuerbescheide;
|
||||
} catch (QueryException e) {
|
||||
logger.severe("Failed to get invoices: " + e.getMessage());
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Berechnet Chart daten aller Steuerbescheide bei KW
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
chartCfg = {
|
||||
type: 'bar',
|
||||
data: {
|
||||
datasets: [{
|
||||
data: [20, 10],
|
||||
}],
|
||||
labels: ['1', '2']
|
||||
}
|
||||
}
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private String accumulateSteuerbescheideByWeek() {
|
||||
logger.fine("accumulate steuer by week...");
|
||||
|
||||
List<ItemCollection> list = getSteuerbescheide();
|
||||
Map<Integer, SteuerData> saldoByWeek = new HashMap<>();
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
int earliestWeek = Integer.MAX_VALUE;
|
||||
int latestWeek = Integer.MIN_VALUE;
|
||||
|
||||
// Step 1: Group saldo by week
|
||||
for (ItemCollection steuerItemCol : list) {
|
||||
double saldo = steuerItemCol.getItemValueDouble("invoice.saldo");
|
||||
double total = steuerItemCol.getItemValueDouble("invoice.total.net");
|
||||
Date date = steuerItemCol.getItemValueDate("invoice.date");
|
||||
|
||||
// Get the week number and year from the date
|
||||
calendar.setTime(date);
|
||||
int weekNumber = calendar.get(Calendar.WEEK_OF_YEAR);
|
||||
int year = calendar.get(Calendar.YEAR);
|
||||
int yearWeek = year * 100 + weekNumber; // Unique key for each year + week combination
|
||||
|
||||
// Accumulate the saldo per week
|
||||
SteuerData steuerDataByWeek = saldoByWeek.getOrDefault(yearWeek, new SteuerData());
|
||||
double eust = getZollBySteuerBeleg(steuerItemCol, "EUST");
|
||||
double zoll = getZollBySteuerBeleg(steuerItemCol, "ZOLL");
|
||||
steuerDataByWeek.add(eust, zoll, total, saldo, "");
|
||||
|
||||
saldoByWeek.put(yearWeek, steuerDataByWeek);
|
||||
|
||||
// Track the earliest and latest weeks
|
||||
earliestWeek = Math.min(earliestWeek, yearWeek);
|
||||
latestWeek = Math.max(latestWeek, yearWeek);
|
||||
}
|
||||
|
||||
// Step 2: Prepare the JSON structure and ensure we have all weeks from earliest
|
||||
// to latest
|
||||
JsonArrayBuilder dataBuilderSaldo = Json.createArrayBuilder();
|
||||
JsonArrayBuilder dataBuilderEust = Json.createArrayBuilder();
|
||||
JsonArrayBuilder dataBuilderZoll = Json.createArrayBuilder();
|
||||
JsonArrayBuilder labelsBuilder = Json.createArrayBuilder();
|
||||
|
||||
Calendar startCal = Calendar.getInstance();
|
||||
startCal.set(Calendar.YEAR, earliestWeek / 100);
|
||||
startCal.set(Calendar.WEEK_OF_YEAR, earliestWeek % 100);
|
||||
|
||||
Calendar endCal = Calendar.getInstance();
|
||||
endCal.set(Calendar.YEAR, latestWeek / 100);
|
||||
endCal.set(Calendar.WEEK_OF_YEAR, latestWeek % 100);
|
||||
|
||||
while (!startCal.after(endCal)) {
|
||||
int weekNumber = startCal.get(Calendar.WEEK_OF_YEAR);
|
||||
int year = startCal.get(Calendar.YEAR);
|
||||
int yearWeek = year * 100 + weekNumber;
|
||||
|
||||
// Add the saldo for the week or 0.0 if no data
|
||||
SteuerData steuerData = saldoByWeek.getOrDefault(yearWeek, new SteuerData());
|
||||
dataBuilderSaldo.add(steuerData.saldo);
|
||||
dataBuilderEust.add(steuerData.eust);
|
||||
dataBuilderZoll.add(steuerData.zoll);
|
||||
labelsBuilder.add(weekNumber + "/" + year); // Label as 'week/year'
|
||||
|
||||
// Move to the next week
|
||||
startCal.add(Calendar.WEEK_OF_YEAR, 1);
|
||||
}
|
||||
|
||||
// Step 3: Prepare the JSON structure
|
||||
JsonObjectBuilder jsonBuilder = Json.createObjectBuilder()
|
||||
.add("type", "bar")
|
||||
.add("data", Json.createObjectBuilder()
|
||||
.add("datasets", Json.createArrayBuilder()
|
||||
|
||||
.add(Json.createObjectBuilder() // First dataset for 'tax'
|
||||
.add("label", "Zoll")
|
||||
.add("backgroundColor", "#96f")
|
||||
.add("borderWidth", 1)
|
||||
.add("data", dataBuilderZoll))
|
||||
.add(Json.createObjectBuilder() // Second dataset for 'eust'
|
||||
.add("label", "EUSt")
|
||||
.add("backgroundColor", "#36a2eb")
|
||||
.add("borderWidth", 1)
|
||||
.add("data", dataBuilderEust))
|
||||
.add(Json.createObjectBuilder() // Third dataset for 'Saldo'
|
||||
.add("label", "Saldo")
|
||||
.add("backgroundColor", "#ff6384")
|
||||
.add("borderWidth", 1)
|
||||
.add("data", dataBuilderSaldo)))
|
||||
|
||||
.add("labels", labelsBuilder));
|
||||
|
||||
// Step 4: Return the JSON structure as a string
|
||||
JsonObject chartCfg = jsonBuilder.build();
|
||||
return chartCfg.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Berechnet Chart daten aller Steuerbescheide bei KW
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
chartCfg = {
|
||||
type: 'bar',
|
||||
data: {
|
||||
datasets: [{
|
||||
data: [20, 10],
|
||||
}],
|
||||
labels: ['1', '2']
|
||||
}
|
||||
}
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private String accumulateSteuerbescheideAbteilungByWeek() {
|
||||
logger.fine("accumulate steuer by Abteilung week...");
|
||||
|
||||
String[] colors = {
|
||||
"#36a2eb",
|
||||
"#ff6384",
|
||||
"#4bc0c0",
|
||||
"#ff9f40",
|
||||
"#96f",
|
||||
"#ffcd56",
|
||||
"#c9cbcf"
|
||||
};
|
||||
|
||||
List<ItemCollection> list = getSteuerbescheide();
|
||||
Map<String, SteuerData> totalByWeek = new HashMap<>();
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
int earliestWeek = Integer.MAX_VALUE;
|
||||
int latestWeek = Integer.MIN_VALUE;
|
||||
|
||||
List<String> abteilungsListe = new ArrayList<>();
|
||||
|
||||
// Step 1: Group total by week
|
||||
for (ItemCollection steuerItemCol : list) {
|
||||
String abteilung = steuerItemCol.getItemValueString("space.name");
|
||||
if (abteilung.isEmpty()) {
|
||||
abteilung = "Keine Zuordnung";
|
||||
}
|
||||
if (!abteilungsListe.contains(abteilung)) {
|
||||
abteilungsListe.add(abteilung);
|
||||
}
|
||||
double saldo = steuerItemCol.getItemValueDouble("invoice.saldo");
|
||||
double total = steuerItemCol.getItemValueDouble("invoice.total.net");
|
||||
Date date = steuerItemCol.getItemValueDate("invoice.date");
|
||||
|
||||
logger.fine(".... " + steuerItemCol.getItemValueString("$workflowSummary") + " = " + total);
|
||||
// Get the week number and year from the date
|
||||
calendar.setTime(date);
|
||||
int weekNumber = calendar.get(Calendar.WEEK_OF_YEAR);
|
||||
int year = calendar.get(Calendar.YEAR);
|
||||
int yearWeek = year * 100 + weekNumber;
|
||||
String key = abteilung + "~" + yearWeek;// Unique key Import Forest~202405
|
||||
|
||||
// Accumulate the total per week
|
||||
SteuerData steuerDataByWeek = totalByWeek.getOrDefault(key, new SteuerData());
|
||||
double eust = getZollBySteuerBeleg(steuerItemCol, "EUST");
|
||||
double zoll = getZollBySteuerBeleg(steuerItemCol, "ZOLL");
|
||||
steuerDataByWeek.add(eust, zoll, total, saldo, abteilung);
|
||||
|
||||
totalByWeek.put(key, steuerDataByWeek);
|
||||
|
||||
// Track the earliest and latest weeks
|
||||
earliestWeek = Math.min(earliestWeek, yearWeek);
|
||||
latestWeek = Math.max(latestWeek, yearWeek);
|
||||
}
|
||||
|
||||
// Step 2: Prepare the JSON structure and ensure we have all weeks from earliest
|
||||
// to latest
|
||||
JsonArrayBuilder labelsBuilder = Json.createArrayBuilder();
|
||||
Calendar startCal = Calendar.getInstance();
|
||||
startCal.set(Calendar.YEAR, earliestWeek / 100);
|
||||
startCal.set(Calendar.WEEK_OF_YEAR, earliestWeek % 100);
|
||||
|
||||
Calendar endCal = Calendar.getInstance();
|
||||
endCal.set(Calendar.YEAR, latestWeek / 100);
|
||||
endCal.set(Calendar.WEEK_OF_YEAR, latestWeek % 100);
|
||||
|
||||
// Build labels - je eines pro woche
|
||||
while (!startCal.after(endCal)) {
|
||||
int weekNumber = startCal.get(Calendar.WEEK_OF_YEAR);
|
||||
int year = startCal.get(Calendar.YEAR);
|
||||
labelsBuilder.add(weekNumber + "/" + year); // Label as 'week/year'
|
||||
// Move to the next week
|
||||
startCal.add(Calendar.WEEK_OF_YEAR, 1);
|
||||
}
|
||||
|
||||
// Step 3: Baue die Balken pro abrteilung
|
||||
JsonArrayBuilder datasets = Json.createArrayBuilder();
|
||||
|
||||
JsonObjectBuilder jsonBuilder = Json.createObjectBuilder()
|
||||
.add("type", "bar");
|
||||
|
||||
JsonObjectBuilder dataDing = Json.createObjectBuilder();
|
||||
int iColor = 0;
|
||||
for (String _abteilung : abteilungsListe) {
|
||||
JsonArrayBuilder dataBuilderTotals = Json.createArrayBuilder();
|
||||
|
||||
startCal = Calendar.getInstance();
|
||||
startCal.set(Calendar.YEAR, earliestWeek / 100);
|
||||
startCal.set(Calendar.WEEK_OF_YEAR, earliestWeek % 100);
|
||||
|
||||
endCal = Calendar.getInstance();
|
||||
endCal.set(Calendar.YEAR, latestWeek / 100);
|
||||
endCal.set(Calendar.WEEK_OF_YEAR, latestWeek % 100);
|
||||
|
||||
while (!startCal.after(endCal)) {
|
||||
int weekNumber = startCal.get(Calendar.WEEK_OF_YEAR);
|
||||
int year = startCal.get(Calendar.YEAR);
|
||||
int yearWeek = year * 100 + weekNumber;
|
||||
String key = _abteilung + "~" + yearWeek;// Unique key Import Forest~202405
|
||||
// Add the total for the week or 0.0 if no data
|
||||
SteuerData steuerData = totalByWeek.getOrDefault(key, new SteuerData());
|
||||
logger.fine(" " + yearWeek + "=" + steuerData.total);
|
||||
dataBuilderTotals.add(steuerData.total);
|
||||
// Move to the next week
|
||||
startCal.add(Calendar.WEEK_OF_YEAR, 1);
|
||||
}
|
||||
|
||||
datasets.add(Json.createObjectBuilder() // First dataset for 'tax'
|
||||
.add("label", _abteilung)
|
||||
.add("backgroundColor", colors[iColor])
|
||||
.add("borderWidth", 1)
|
||||
.add("data", dataBuilderTotals));
|
||||
|
||||
iColor++;
|
||||
if (iColor > colors.length) {
|
||||
iColor = 0;
|
||||
}
|
||||
}
|
||||
|
||||
dataDing.add("datasets", datasets);
|
||||
dataDing.add("labels", labelsBuilder);
|
||||
|
||||
jsonBuilder.add("data", dataDing);
|
||||
|
||||
// Step 4: Return the JSON structure as a string
|
||||
JsonObject chartCfg = jsonBuilder.build();
|
||||
return chartCfg.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to hold zoll and eust totals in an object. Needed to build
|
||||
* totals per week.
|
||||
*/
|
||||
class SteuerData {
|
||||
double total = 0.0;
|
||||
double zoll = 0.0;
|
||||
double eust = 0.0;
|
||||
double saldo = 0.0;
|
||||
String abteilung = "";
|
||||
|
||||
public SteuerData() {
|
||||
// default constructor
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds new zoll and eust values and updates the total
|
||||
*
|
||||
* @param eustNew eust value to be added
|
||||
* @param zollNew zoll value to be added
|
||||
*/
|
||||
public void add(double eustNew, double zollNew, double totalNew, double saldoNew, String abteilungNew) {
|
||||
eust = eust + eustNew;
|
||||
zoll = zoll + zollNew;
|
||||
saldo = saldo + saldoNew;
|
||||
total = total + totalNew;
|
||||
abteilung = abteilungNew;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -1,315 +0,0 @@
|
|||
package com.alexanderlogistics;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.apache.poi.ss.usermodel.CellCopyPolicy;
|
||||
import org.apache.poi.ss.usermodel.Row.MissingCellPolicy;
|
||||
import org.apache.poi.ss.util.CellReference;
|
||||
import org.apache.poi.xssf.usermodel.XSSFRow;
|
||||
import org.apache.poi.xssf.usermodel.XSSFSheet;
|
||||
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
|
||||
import org.imixs.workflow.FileData;
|
||||
import org.imixs.workflow.ItemCollection;
|
||||
import org.imixs.workflow.engine.DocumentService;
|
||||
import org.imixs.workflow.engine.WorkflowService;
|
||||
import org.imixs.workflow.exceptions.AdapterException;
|
||||
import org.imixs.workflow.exceptions.PluginException;
|
||||
import org.imixs.workflow.exceptions.QueryException;
|
||||
import org.imixs.workflow.office.config.ConfigService;
|
||||
import org.imixs.workflow.poi.POIFindReplaceAdapter;
|
||||
import org.imixs.workflow.util.XMLParser;
|
||||
|
||||
import jakarta.inject.Inject;
|
||||
|
||||
/**
|
||||
* Der AGLAnalyticExcelAdapterDebitor exportiert eine Excel Datei aus einem
|
||||
* Textblock und fügt die offenen Recnungen ein
|
||||
*
|
||||
* Der Adapter wird im Modell wie folgt konfiguriert
|
||||
*
|
||||
* <pre>
|
||||
* {@code
|
||||
<soa name="excel-export">
|
||||
<textblock>textblock-ref</textblock>
|
||||
<template>filename</template>
|
||||
<targetname>filename</targetname>
|
||||
</soa>
|
||||
}
|
||||
* </pre>
|
||||
*
|
||||
* <p>
|
||||
* Der Adapter erweitert den POIAdapter somit können Felder aktualisiert werden
|
||||
* (siehe POIFineReplaceAdapter).
|
||||
*
|
||||
* <p>
|
||||
* Der Adapter kopiert die ausgangsrechnungen in neue Zeilen, welche ab
|
||||
* Zeilennummer
|
||||
* 16 eingefügt werden.
|
||||
* <p>
|
||||
*
|
||||
* Abschliessend wird die Zelle 'TOTAL' noch aktualisiert.
|
||||
*
|
||||
*
|
||||
* @version 1.0
|
||||
* @author rsoika
|
||||
*/
|
||||
public class AGLAnalyticExcelAdapterDebitor extends POIFindReplaceAdapter {
|
||||
|
||||
private static Logger logger = Logger.getLogger(AGLAnalyticExcelAdapter.class.getName());
|
||||
|
||||
@Inject
|
||||
WorkflowService workflowService;
|
||||
|
||||
@Inject
|
||||
OPListExportService opListExportService;
|
||||
|
||||
@Inject
|
||||
DocumentService documentService;
|
||||
|
||||
@Inject
|
||||
ConfigService configService;
|
||||
|
||||
/**
|
||||
* This method
|
||||
*
|
||||
* @throws PluginException
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public ItemCollection execute(ItemCollection document, ItemCollection event)
|
||||
throws AdapterException, PluginException {
|
||||
|
||||
// ermittle die Hauptwährungen
|
||||
ItemCollection configItemCollection = configService.loadConfiguration("AGL_CONFIGURATION");
|
||||
List<String> currencyList = configItemCollection.getItemValue("currency.out");
|
||||
if (currencyList == null || currencyList.size() < 2) {
|
||||
throw new PluginException(AGLAnalyticExcelAdapter.class.getSimpleName(),
|
||||
OPListExportService.ERROR_CONFIG,
|
||||
"missing Currency configuration - please check parameters");
|
||||
}
|
||||
|
||||
// read the Steuerbescheide options
|
||||
ItemCollection ausgangsrechnungConfig = workflowService.evalWorkflowResult(event, "soa",
|
||||
document,
|
||||
false);
|
||||
if (ausgangsrechnungConfig == null || !ausgangsrechnungConfig.hasItem("excel-export")) {
|
||||
throw new PluginException(AGLAnalyticExcelAdapterDebitor.class.getSimpleName(), CONFIG_ERROR,
|
||||
"missing soa configuration in model event - please check model configuration");
|
||||
}
|
||||
List<String> excelDefList = ausgangsrechnungConfig.getItemValue("excel-export");
|
||||
ItemCollection excelDefCollection = XMLParser.parseItemStructure(excelDefList.get(0));
|
||||
|
||||
String textblock = excelDefCollection.getItemValueString("textblock");
|
||||
String template = excelDefCollection.getItemValueString("template");
|
||||
String targetName = excelDefCollection.getItemValueString("target-name");
|
||||
|
||||
// adapt text....
|
||||
targetName = workflowService.adaptText(targetName, document);
|
||||
|
||||
try {
|
||||
appendExcelTemplate(document, textblock, template, targetName);
|
||||
insertInvoiceRows(document, targetName);
|
||||
|
||||
logger.info("... loading poi configuration..");
|
||||
// Process POI instructions
|
||||
// read the config
|
||||
ItemCollection poiConfig = workflowService.evalWorkflowResult(event, "poi-update", document,
|
||||
false);
|
||||
if (poiConfig == null || !poiConfig.hasItem("findreplace")) {
|
||||
throw new PluginException(POIFindReplaceAdapter.class.getSimpleName(), CONFIG_ERROR,
|
||||
"missing poi configuration");
|
||||
}
|
||||
List<String> replaceDevList = poiConfig.getItemValue("findreplace");
|
||||
String eval = poiConfig.getItemValueString("eval");
|
||||
|
||||
logger.info("... update template with normal poi information..");
|
||||
this.updateFileData(document.getFileData(targetName), document, replaceDevList, eval);
|
||||
|
||||
} catch (PluginException | IOException | QueryException e) {
|
||||
throw new PluginException(AGLAnalyticExcelAdapter.class.getSimpleName(),
|
||||
OPListExportService.ERROR_CONFIG,
|
||||
"failed to update steuerbescheide: " + e.getMessage());
|
||||
}
|
||||
logger.info("... completed!");
|
||||
return document;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hilfsmethode die das fuehrende K/D aus der Debitorennummer entfernt
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private String getDbtNr(ItemCollection workitem) {
|
||||
String dbtNr = workitem.getItemValueString("dbtr.number");
|
||||
if (dbtNr.startsWith("D") || dbtNr.startsWith("K")) {
|
||||
dbtNr = dbtNr.substring(1);
|
||||
}
|
||||
return dbtNr;
|
||||
}
|
||||
|
||||
/**
|
||||
* This helper method inserts a row for each invoice at row 16
|
||||
* into the excel template file
|
||||
* <p>
|
||||
* The method copies the Row A16 as a reference row
|
||||
* <p>
|
||||
* The named cell 'TOTAL' should contain the summary formula. It will be
|
||||
* evaluated at the end.
|
||||
*
|
||||
* @throws PluginException
|
||||
* @throws QueryException
|
||||
*/
|
||||
private void insertInvoiceRows(ItemCollection document, String fileName)
|
||||
throws PluginException, QueryException {
|
||||
|
||||
// load dummy rechnungen
|
||||
List<ItemCollection> invoices = loadInvoices(getDbtNr(document));
|
||||
|
||||
FileData fileData = document.getFileData(fileName);
|
||||
|
||||
// load XSSFWorkbook
|
||||
XSSFWorkbook doc = null;
|
||||
try (InputStream imputStream = new ByteArrayInputStream(fileData.getContent())) {
|
||||
doc = new XSSFWorkbook(imputStream);
|
||||
// NOTE: we only take the first sheet !
|
||||
XSSFSheet sheet = doc.getSheetAt(0);
|
||||
CellReference invoiceRefCell = new CellReference("A11");
|
||||
XSSFRow referenceRowInvoice = sheet.getRow(invoiceRefCell.getRow());
|
||||
int referenceRowPos = 10;
|
||||
int rowPos = referenceRowPos;
|
||||
int lastRow = 2999;
|
||||
logger.finest("Last rownum=" + lastRow);
|
||||
|
||||
// jetzt füge alle Rechnungen an.
|
||||
int totalRowCount = invoices.size();
|
||||
sheet.shiftRows(referenceRowPos, lastRow, totalRowCount, true, true);
|
||||
for (ItemCollection invoice : invoices) {
|
||||
logger.fine("......add invoice " + invoice.getUniqueID());
|
||||
// now create a new line..
|
||||
XSSFRow row = sheet.createRow(rowPos);
|
||||
row.copyRowFrom(referenceRowInvoice, new CellCopyPolicy());
|
||||
// insert values
|
||||
row.getCell(0)
|
||||
.setCellValue(invoice.getItemValueDate("$created"));
|
||||
row.getCell(1, MissingCellPolicy.CREATE_NULL_AS_BLANK)
|
||||
.setCellValue(invoice.getItemValueString("invoice.number"));
|
||||
row.getCell(2, MissingCellPolicy.CREATE_NULL_AS_BLANK)
|
||||
.setCellValue(invoice.getItemValueDate("invoice.date"));
|
||||
row.getCell(3, MissingCellPolicy.CREATE_NULL_AS_BLANK)
|
||||
.setCellValue(invoice.getItemValueDate("invoice.duedate"));
|
||||
row.getCell(4, MissingCellPolicy.CREATE_NULL_AS_BLANK)
|
||||
.setCellValue(invoice.getItemValueString("space.name"));
|
||||
row.getCell(5, MissingCellPolicy.CREATE_NULL_AS_BLANK)
|
||||
.setCellValue(invoice.getItemValueString("invoice.text"));
|
||||
|
||||
// Waehrung?
|
||||
if (invoice.getItemValueDouble("invoice.rate") == 0) {
|
||||
row.getCell(6, MissingCellPolicy.CREATE_NULL_AS_BLANK)
|
||||
.setCellValue(invoice.getItemValueDouble("invoice.total"));
|
||||
row.getCell(7, MissingCellPolicy.CREATE_NULL_AS_BLANK)
|
||||
.setCellValue(invoice.getItemValueDouble("invoice.saldo"));
|
||||
} else {
|
||||
row.getCell(8, MissingCellPolicy.CREATE_NULL_AS_BLANK)
|
||||
.setCellValue(invoice.getItemValueDouble("invoice.total"));
|
||||
row.getCell(9, MissingCellPolicy.CREATE_NULL_AS_BLANK)
|
||||
.setCellValue(invoice.getItemValueDouble("invoice.saldo"));
|
||||
}
|
||||
row.getCell(10, MissingCellPolicy.CREATE_NULL_AS_BLANK)
|
||||
.setCellValue(invoice.getItemValueString("$workflowstatus"));
|
||||
|
||||
rowPos++;
|
||||
}
|
||||
|
||||
// Leerzeile
|
||||
// categoryRow = sheet.createRow(rowPos);
|
||||
rowPos++;
|
||||
|
||||
// write back the file
|
||||
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
|
||||
doc.write(byteArrayOutputStream);
|
||||
|
||||
byte[] newContent = byteArrayOutputStream.toByteArray();
|
||||
FileData fileDataNew = new FileData(fileData.getName(), newContent, fileData.getContentType(),
|
||||
null);
|
||||
// update the fileData
|
||||
document.addFileData(fileDataNew);
|
||||
|
||||
logger.finest("......new document added");
|
||||
|
||||
} catch (IOException e) {
|
||||
throw new PluginException(AGLAnalyticExcelAdapter.class.getSimpleName(),
|
||||
OPListExportService.ERROR_CONFIG,
|
||||
"failed to update opliste: " + e.getMessage());
|
||||
} finally {
|
||||
if (doc != null) {
|
||||
try {
|
||||
doc.close();
|
||||
} catch (IOException e) {
|
||||
logger.severe("Failed to close workbook: " + e.getMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method loads a text-block for a specified ref and appends the named
|
||||
* fileData object of this document.
|
||||
*
|
||||
* @param document
|
||||
* @throws PluginException
|
||||
*/
|
||||
private void appendExcelTemplate(ItemCollection document, String textblockRef, String template,
|
||||
String targetName)
|
||||
throws PluginException {
|
||||
|
||||
if ((template == null || template.isEmpty()) || (textblockRef == null || textblockRef.isEmpty())) {
|
||||
throw new PluginException(AGLAnalyticExcelAdapter.class.getSimpleName(),
|
||||
OPListExportService.ERROR_CONFIG,
|
||||
"invalid SOA configuration in model event - textblock/template reference not defined!");
|
||||
}
|
||||
|
||||
// load the text block
|
||||
FileData fileData = opListExportService.loadTextBlockFileData(textblockRef, template);
|
||||
|
||||
// do we found the document?
|
||||
if (fileData == null) {
|
||||
throw new PluginException(AGLAnalyticExcelAdapter.class.getSimpleName(),
|
||||
OPListExportService.ERROR_CONFIG,
|
||||
"invalid SOA configuration in model event - template=" + template
|
||||
+ " not found!");
|
||||
}
|
||||
fileData.setName(targetName);
|
||||
// append document
|
||||
logger.info("...append new SOA Template: " + targetName);
|
||||
document.addFileData(fileData);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Diese Methode läd alle offenen Steuerbescheide
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private List<ItemCollection> loadInvoices(String dbtrNumber) {
|
||||
List<ItemCollection> result = new ArrayList<>();
|
||||
|
||||
String query = "(type:workitem) AND dbtr.number:" + dbtrNumber
|
||||
+ " AND $modelversion:rechnungsausgang-*";
|
||||
try {
|
||||
result = documentService.find(
|
||||
query, 9999, 0,
|
||||
"invoice.number", false);
|
||||
} catch (QueryException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,585 +0,0 @@
|
|||
package com.alexanderlogistics;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.text.DateFormat;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.time.LocalDate;
|
||||
import java.time.YearMonth;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.imixs.workflow.ItemCollection;
|
||||
import org.imixs.workflow.engine.DocumentService;
|
||||
import org.imixs.workflow.exceptions.PluginException;
|
||||
import org.imixs.workflow.exceptions.QueryException;
|
||||
import org.imixs.workflow.faces.data.WorkflowController;
|
||||
import org.imixs.workflow.office.views.SearchController;
|
||||
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import jakarta.enterprise.context.ConversationScoped;
|
||||
import jakarta.faces.context.FacesContext;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.inject.Named;
|
||||
|
||||
/**
|
||||
* Der InvoiceAnalyseController dient zur Auswertung der Sachprüfungs WOrklfow
|
||||
* Schritte. Die Analyse Seite ist büer das Admin Menü erreichbar.
|
||||
*
|
||||
* @author rsoika
|
||||
*
|
||||
*/
|
||||
@Named
|
||||
@ConversationScoped
|
||||
// @SessionScoped
|
||||
public class DebitorStatistikController implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static Logger logger = Logger.getLogger(DebitorStatistikController.class.getName());
|
||||
|
||||
@Inject
|
||||
protected DocumentService documentService;
|
||||
|
||||
TreeMap<String, DebitorStatistikData> stats = null;
|
||||
|
||||
@Inject
|
||||
protected WorkflowController workflowController;
|
||||
|
||||
@Inject
|
||||
protected SearchController searchController;
|
||||
|
||||
@Inject
|
||||
protected KreditorDebitorService kreditorDebitorService;
|
||||
|
||||
/**
|
||||
* Initialize default behavior initialize an opitonal id from the query string
|
||||
*
|
||||
*/
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
// extract the processref and page from the query string
|
||||
FacesContext fc = FacesContext.getCurrentInstance();
|
||||
Map<String, String> paramMap = fc.getExternalContext().getRequestParameterMap();
|
||||
|
||||
String id = paramMap.get("dbtr.number");
|
||||
if (id != null && !id.isEmpty()) {
|
||||
workflowController.getWorkitem().setItemValue("dbtr.number", id);
|
||||
try {
|
||||
ItemCollection dbtr = kreditorDebitorService.findDebitor(id);
|
||||
if (dbtr != null) {
|
||||
workflowController.getWorkitem().setItemValue("dbtr.name", dbtr.getItemValueString("_vendor_name"));
|
||||
}
|
||||
} catch (PluginException e) {
|
||||
// e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public ItemCollection getWorkitem() {
|
||||
return workflowController.getWorkitem();
|
||||
}
|
||||
|
||||
public int getZahlungsmoral() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gibt eine bookmarkable url zurück.
|
||||
* Wir vom Aktualisieren button in der Page genutzt
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public String getBookmark() {
|
||||
return "/pages/dbtr-stats.xhtml?dbtr.number=" + getDbtNr() + "&faces-redirect=true";
|
||||
}
|
||||
|
||||
/*
|
||||
* Gesamt
|
||||
*/
|
||||
public String getQueryRechnungen() {
|
||||
String query = "(type:workitem OR type:workitemarchive) AND dbtr.number:" + getDbtNr()
|
||||
+ " AND $workflowgroup:\"Rechnungsausgang\"";
|
||||
return "/pages/workitems/worklist?title=Rechnungen " + getDbtNr() + " gesamt&query=" + query;
|
||||
}
|
||||
|
||||
public int getRechnungen() {
|
||||
int result = 0;
|
||||
if (getDbtNr().isEmpty()) {
|
||||
return 0;
|
||||
}
|
||||
try {
|
||||
result = documentService
|
||||
.count("(type:workitem OR type:workitemarchive) AND dbtr.number:" + getDbtNr()
|
||||
+ " AND $workflowgroup:\"Rechnungsausgang\"");
|
||||
} catch (QueryException e) {
|
||||
logger.severe("Failed to get statistic: " + e.getMessage());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Bezahlt
|
||||
*/
|
||||
public String getQueryRechnungenBezahlt() {
|
||||
String query = "(type:workitem OR type:workitemarchive) AND dbtr.number:" + getDbtNr()
|
||||
+ " AND $workflowgroup:\"Rechnungsausgang\" AND ($taskid:[5900 TO 5999])";
|
||||
return "/pages/workitems/worklist?title=Rechnungen " + getDbtNr() + " bezahlt&query=" + query;
|
||||
}
|
||||
|
||||
public int getRechnungenBezahlt() {
|
||||
int result = 0;
|
||||
if (getDbtNr().isEmpty()) {
|
||||
return 0;
|
||||
}
|
||||
try {
|
||||
result = documentService
|
||||
.count("(type:workitem OR type:workitemarchive) AND dbtr.number:" + getDbtNr()
|
||||
+ " AND $workflowgroup:\"Rechnungsausgang\" AND ($taskid:[5900 TO 5999])");
|
||||
} catch (QueryException e) {
|
||||
logger.severe("Failed to get statistic: " + e.getMessage());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Offen
|
||||
*/
|
||||
public String getQueryRechnungenOffen() {
|
||||
String query = "(type:workitem) AND dbtr.number:" + getDbtNr()
|
||||
+ " AND $workflowgroup:\"Rechnungsausgang\" AND ($taskid:[5000 TO 5099])";
|
||||
return "/pages/workitems/worklist?title=Rechnungen " + getDbtNr() + " offen&query=" + query;
|
||||
}
|
||||
|
||||
public int getRechnungenOffen() {
|
||||
int result = 0;
|
||||
if (getDbtNr().isEmpty()) {
|
||||
return 0;
|
||||
}
|
||||
try {
|
||||
result = documentService
|
||||
.count("(type:workitem) AND dbtr.number:" + getDbtNr()
|
||||
+ " AND $workflowgroup:\"Rechnungsausgang\" AND ($taskid:[5000 TO 5099])");
|
||||
} catch (QueryException e) {
|
||||
logger.severe("Failed to get statistic: " + e.getMessage());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Fällig
|
||||
*/
|
||||
public String getQueryRechnungenFaellig() {
|
||||
String query = "(type:workitem) AND dbtr.number:" + getDbtNr()
|
||||
+ " AND $workflowgroup:\"Rechnungsausgang\" AND ($taskid:[5100 TO 5199])";
|
||||
return "/pages/workitems/worklist?title=Rechnungen " + getDbtNr() + " fällig&query=" + query;
|
||||
}
|
||||
|
||||
public int getRechnungenFaellig() {
|
||||
int result = 0;
|
||||
if (getDbtNr().isEmpty()) {
|
||||
return 0;
|
||||
}
|
||||
try {
|
||||
result = documentService
|
||||
.count("(type:workitem) AND dbtr.number:" + getDbtNr()
|
||||
+ " AND $workflowgroup:\"Rechnungsausgang\" AND ($taskid:[5100 TO 5199])");
|
||||
} catch (QueryException e) {
|
||||
logger.severe("Failed to get statistic: " + e.getMessage());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* In Mahnung
|
||||
*/
|
||||
public String getQueryRechnungenGemahnt() {
|
||||
String query = "(type:workitem) AND dbtr.number:" + getDbtNr()
|
||||
+ " AND $workflowgroup:\"Rechnungsausgang\" AND ($taskid:[5200 TO 5299])";
|
||||
return "/pages/workitems/worklist?title=Rechnungen " + getDbtNr() + " in Mahnung&query=" + query;
|
||||
}
|
||||
|
||||
public int getRechnungenGemahnt() {
|
||||
int result = 0;
|
||||
if (getDbtNr().isEmpty()) {
|
||||
return 0;
|
||||
}
|
||||
try {
|
||||
result = documentService
|
||||
.count("(type:workitem ) AND dbtr.number:" + getDbtNr()
|
||||
+ " AND $workflowgroup:\"Rechnungsausgang\" AND ($taskid:[5200 TO 5299])");
|
||||
} catch (QueryException e) {
|
||||
logger.severe("Failed to get statistic: " + e.getMessage());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Inkasso
|
||||
*/
|
||||
public String getQueryRechnungenInkasso() {
|
||||
String query = "(type:workitem) AND dbtr.number:" + getDbtNr()
|
||||
+ " AND $workflowgroup:\"Rechnungsausgang\" AND ($taskid:[5300 TO 5399])";
|
||||
return "/pages/workitems/worklist?title=Rechnungen " + getDbtNr() + " in Inkasso&query=" + query;
|
||||
}
|
||||
|
||||
public int getRechnungenInkasso() {
|
||||
int result = 0;
|
||||
if (getDbtNr().isEmpty()) {
|
||||
return 0;
|
||||
}
|
||||
try {
|
||||
result = documentService
|
||||
.count("(type:workitem OR type:workitemarchive) AND dbtr.number:" + getDbtNr()
|
||||
+ " AND $workflowgroup:\"Rechnungsausgang\" AND ($taskid:[5300 TO 5399])");
|
||||
} catch (QueryException e) {
|
||||
logger.severe("Failed to get statistic: " + e.getMessage());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hilfsmethode die das fuehrende K/D aus der Debitorennummer entfernt
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public String getDbtNr() {
|
||||
String dbtNr = getWorkitem().getItemValueString("dbtr.number");
|
||||
if (dbtNr.startsWith("D") || dbtNr.startsWith("K")) {
|
||||
dbtNr = dbtNr.substring(1);
|
||||
}
|
||||
return dbtNr;
|
||||
}
|
||||
|
||||
public long getDurchschnittZahlungsziel() {
|
||||
getStats();
|
||||
int count = 0;
|
||||
long gesamt = 0;
|
||||
for (Map.Entry<String, DebitorStatistikData> entry : stats.entrySet()) {
|
||||
DebitorStatistikData statData = entry.getValue();
|
||||
if (statData.count > 0) {
|
||||
gesamt = gesamt + statData.getAverageDueDays();
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return Math.round((double) gesamt / count);
|
||||
}
|
||||
|
||||
public long getDurchschnittZahlungsdauer() {
|
||||
getStats();
|
||||
int count = 0;
|
||||
long gesamt = 0;
|
||||
for (Map.Entry<String, DebitorStatistikData> entry : stats.entrySet()) {
|
||||
DebitorStatistikData statData = entry.getValue();
|
||||
if (statData.count > 0) {
|
||||
gesamt = gesamt + statData.getAveragePaymentDays();
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return Math.round((double) gesamt / count);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sucht alle Rechnugnen aus einem Zeitraum und sammelt Zahlungsziel und
|
||||
* Zahlungszeitspanne gruppiert nach monaten
|
||||
*
|
||||
*/
|
||||
public Map<String, DebitorStatistikData> getStats() {
|
||||
|
||||
if (stats != null) {
|
||||
return stats;
|
||||
}
|
||||
|
||||
// recompute
|
||||
stats = new TreeMap<String, DebitorStatistikData>();
|
||||
if (getDbtNr().isEmpty()) {
|
||||
return stats;
|
||||
}
|
||||
// invoice.date:[20210101 TO 20210201]
|
||||
DateFormat df = new SimpleDateFormat("yyyymmdd");
|
||||
|
||||
String query = "(type:workitemarchive) AND invoice.date:[20221201 TO 20500101] AND dbtr.number:" + getDbtNr()
|
||||
+ " AND $workflowgroup:\"Rechnungsausgang\" AND ($taskid:[5900 TO 5999])";
|
||||
|
||||
// query = query + " AND (invoice.date:[" + df.format(from) + " TO " +
|
||||
// df.format(to) + "])";
|
||||
logger.fine("query = " + query);
|
||||
try {
|
||||
List<ItemCollection> invoices = documentService
|
||||
.findStubs(query, 9999, 0, "$created", false);
|
||||
|
||||
for (ItemCollection invoice : invoices) {
|
||||
try {
|
||||
|
||||
logger.fine("Rechnung: " + invoice.getUniqueID());
|
||||
Date invoiceDate = invoice.getItemValueDate("invoice.date");
|
||||
Date invoiceDueDate = invoice.getItemValueDate("invoice.duedate");
|
||||
Date paymentDate = findPaymentDateByWorkitem(invoice);
|
||||
if (paymentDate == null) {
|
||||
logger.warning("Es wurde kein Zahlungseingang gefunden");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (invoiceDate != null && paymentDate != null && invoiceDueDate != null) {
|
||||
// do we have a stats object?
|
||||
DebitorStatistikData statData = stats.get(getYearMonth(invoiceDate));
|
||||
if (statData == null) {
|
||||
// create a new one
|
||||
statData = new DebitorStatistikData(invoiceDate);
|
||||
}
|
||||
// jetzt irgendwas ausrechnen
|
||||
statData.compute(invoiceDate, invoiceDueDate, paymentDate);
|
||||
// .. und wieder speichern
|
||||
stats.put(statData.toString(), statData);
|
||||
|
||||
} else {
|
||||
logger.warning("No payment Date found for invoice " + invoice.getUniqueID());
|
||||
}
|
||||
|
||||
} catch (ParseException e) {
|
||||
logger.warning("Unable to parse payment Date for invoice " + invoice.getUniqueID());
|
||||
}
|
||||
}
|
||||
|
||||
} catch (QueryException e) {
|
||||
logger.severe("Failed to get statistic: " + e.getMessage());
|
||||
}
|
||||
// Step 2: Sort the list based on the alphanumeric order of the keys
|
||||
completeMissingMonths();
|
||||
return stats;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Hilfsmethode ergänzt die fehlenden Monate
|
||||
*
|
||||
* @param yearMonths
|
||||
* @return
|
||||
*/
|
||||
private void completeMissingMonths() {
|
||||
if (stats == null || stats.size() < 3) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Convert the list of strings to a list of LocalDate objects
|
||||
List<LocalDate> dates = new ArrayList<>();
|
||||
Set<String> yearMonths = this.stats.keySet();
|
||||
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMM");
|
||||
for (String yearMonth : yearMonths) {
|
||||
dates.add(YearMonth.parse(yearMonth, formatter).atDay(1));
|
||||
}
|
||||
|
||||
// Find the lowest and highest dates
|
||||
LocalDate lowestDate = Collections.min(dates);
|
||||
LocalDate highestDate = Collections.max(dates);
|
||||
|
||||
LocalDate current = lowestDate;
|
||||
current = current.plusMonths(1);
|
||||
while (!current.isAfter(highestDate)) {
|
||||
|
||||
// existiert der monat?
|
||||
String formattedDate = current.format(formatter);
|
||||
DebitorStatistikData entry = stats.get(formattedDate);
|
||||
if (entry == null) {
|
||||
// add missing entry
|
||||
stats.put(formattedDate, new DebitorStatistikData(current.getYear(), current.getMonthValue()));
|
||||
}
|
||||
current = current.plusMonths(1);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* returns
|
||||
*
|
||||
* 202304 from a given date
|
||||
*/
|
||||
public String getYearMonth(Date date) {
|
||||
|
||||
// Create a Calendar instance and set the date
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
calendar.setTime(date);
|
||||
|
||||
// Get the year from the Calendar object
|
||||
int year = calendar.get(Calendar.YEAR);
|
||||
// Get the month from the Calendar object
|
||||
int month = calendar.get(Calendar.MONTH);
|
||||
// Increment the month by 1 since Calendar months are zero-based
|
||||
month++;
|
||||
// Convert the month to a String with leading "0" if necessary
|
||||
return "" + year + (month < 10 ? "0" + month : "" + month);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the payment.date for a invoice.
|
||||
*
|
||||
* Wir suchen alle zugeordneten Zahlungseingägne und nehmen den letzten.
|
||||
*
|
||||
* WICHTIG: Es muss ggf. der index neu aufgebaut werden, da payment.date nun ein
|
||||
* index feld ist
|
||||
*
|
||||
* @param invoice
|
||||
* @return
|
||||
* @throws ParseException
|
||||
*/
|
||||
public Date findPaymentDateByWorkitem(ItemCollection invoice) throws ParseException {
|
||||
|
||||
// Wir selektieren alle Zahlungseingänge interessieren usn aber nur für den
|
||||
// letzten
|
||||
String sQuery = " (type:\"workitem\" OR type:\"workitemarchive\") " + //
|
||||
" AND ($workflowgroup:Zahlungseingang) AND ($workitemref:\""
|
||||
+ invoice.getUniqueID() + "\" )";
|
||||
|
||||
List<ItemCollection> workitems = null;
|
||||
|
||||
try {
|
||||
workitems = documentService.findStubs(sQuery, 99, 0,
|
||||
"payment.date", true);
|
||||
if (workitems.size() > 0) {
|
||||
return workitems.get(0).getItemValueDate("payment.date");
|
||||
}
|
||||
} catch (QueryException e) {
|
||||
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
// no date found!
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the date when a workitem last reached the current task 5900 by reading
|
||||
* the eventLog
|
||||
*
|
||||
* This method is not so save as the method findPaymentDateByWorkitem that is
|
||||
* searching the payment workitem.
|
||||
*
|
||||
* 2023-06-28T12:40:17.437|rechnungsausgang-de-1.0|5001.50|5900|
|
||||
*
|
||||
* @param invoice
|
||||
* @return
|
||||
* @throws ParseException
|
||||
*/
|
||||
public Date findPaymentDateByLog(ItemCollection invoice) throws ParseException {
|
||||
|
||||
// Create a SimpleDateFormat instance with the desired format
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS");
|
||||
List<String> logEntries = invoice.getItemValue("$eventlog");
|
||||
|
||||
// Iterate through the List from the last element to the first
|
||||
for (int i = logEntries.size() - 1; i >= 0; i--) {
|
||||
String entry = logEntries.get(i);
|
||||
|
||||
if (entry.endsWith(invoice.getTaskID() + "|")) {
|
||||
// found!
|
||||
String dateString = entry.substring(0, entry.indexOf("|") - 1);
|
||||
// Parse the date string into a Date object
|
||||
Date date = sdf.parse(dateString);
|
||||
// Print the Date object
|
||||
System.out.println("Date: " + date);
|
||||
return date;
|
||||
}
|
||||
}
|
||||
|
||||
// no date found!
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Diese Methode baut die Datenstruktur für das Chart Diagram zusammen
|
||||
*
|
||||
*
|
||||
* <pre>
|
||||
{
|
||||
labels: ["January", "February", "March", "April", "May", "June", "July"],
|
||||
datasets: [{
|
||||
label: 'Dataset 1',
|
||||
//backgroundColor: color(window.chartColors.red).alpha(0.5).rgbString(),
|
||||
//borderColor: window.chartColors.red,
|
||||
borderWidth: 1,
|
||||
data: [
|
||||
70, 70, 70, 70, 79, 50, 50
|
||||
]
|
||||
}, {
|
||||
label: 'Dataset 2',
|
||||
//backgroundColor: color(window.chartColors.blue).alpha(0.5).rgbString(),
|
||||
//borderColor: window.chartColors.blue,
|
||||
borderWidth: 1,
|
||||
data: [
|
||||
70, 70, 170, 7, 79, 50, 50
|
||||
]
|
||||
}]
|
||||
}
|
||||
* </pre>
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public String buildChartData() {
|
||||
|
||||
getStats();
|
||||
|
||||
// build a list of all lables....
|
||||
List<String> statusLabels = new ArrayList<String>();
|
||||
|
||||
Set<String> keys = stats.keySet();
|
||||
for (String _key : keys) {
|
||||
statusLabels.add(_key);
|
||||
}
|
||||
|
||||
String result = "{";
|
||||
|
||||
// Lables
|
||||
result = result + "labels : [ ";
|
||||
result = result + statusLabels.stream().collect(Collectors.joining("','", "'", "'"));
|
||||
result = result + "],";
|
||||
result = result + "datasets: [";
|
||||
|
||||
// Datasets 1
|
||||
result = result + "{label: 'Zahlungsziel',borderWidth: 1,";
|
||||
result = result + " borderColor: [\"#3B6B82\"],";
|
||||
result = result + " \"backgroundColor\" : [\"#CFE9F5\"], fill: true,tension: 0.5,";
|
||||
|
||||
result = result + "data: [";
|
||||
for (Map.Entry<String, DebitorStatistikData> entry : stats.entrySet()) {
|
||||
result = result + entry.getValue().getAverageDueDays() + ",";
|
||||
}
|
||||
// cut last comma
|
||||
result = result.substring(0, result.length() - 1);
|
||||
result = result + "]";
|
||||
result = result + "}, ";
|
||||
|
||||
// Datasets 2
|
||||
result = result + "{label: 'Zahldauer',borderWidth: 1,";
|
||||
result = result + " borderColor: [\"#E73B65\"],\"backgroundColor\" : [\"#70B088\" ], tension: 0.5,fill: true,";
|
||||
|
||||
result = result
|
||||
+ " trendlineLinear: { colorMin: \"red\", colorMax: \"green\", lineStyle: \"dotted\", width: 2 , projection: true },";
|
||||
|
||||
result = result + "data: [";
|
||||
for (Map.Entry<String, DebitorStatistikData> entry : stats.entrySet()) {
|
||||
result = result + entry.getValue().getAveragePaymentDays() + ",";
|
||||
}
|
||||
// cut last comma
|
||||
result = result.substring(0, result.length() - 1);
|
||||
result = result + "]";
|
||||
result = result + "} ";
|
||||
|
||||
// ende
|
||||
result = result + "] }";
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,167 +0,0 @@
|
|||
package com.alexanderlogistics;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.time.YearMonth;
|
||||
import java.time.ZoneId;
|
||||
import java.util.Calendar;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.imixs.workflow.ItemCollection;
|
||||
import org.imixs.workflow.engine.DocumentService;
|
||||
import org.imixs.workflow.engine.index.Category;
|
||||
import org.imixs.workflow.engine.index.SearchService;
|
||||
|
||||
import jakarta.enterprise.context.ConversationScoped;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.inject.Named;
|
||||
|
||||
/**
|
||||
* Der InvoiceAnalyseController dient zur Auswertung der Sachprüfungs WOrklfow
|
||||
* Schritte. Die Analyse Seite ist büer das Admin Menü erreichbar.
|
||||
*
|
||||
* @author rsoika
|
||||
*
|
||||
*/
|
||||
@Named
|
||||
@ConversationScoped
|
||||
public class InvoiceAnalyseController implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static Logger logger = Logger.getLogger(InvoiceAnalyseController.class.getName());
|
||||
|
||||
@Inject
|
||||
protected DocumentService documentService;
|
||||
|
||||
@Inject
|
||||
SearchService searchService;
|
||||
|
||||
Category sachpruefung;
|
||||
Category verteilung;
|
||||
Category buchhaltung;
|
||||
|
||||
private ItemCollection filter;
|
||||
|
||||
public ItemCollection getFilter() {
|
||||
if (filter == null) {
|
||||
filter = new ItemCollection();
|
||||
// compute start stop based on current month
|
||||
YearMonth startYearMonth = YearMonth.now();
|
||||
java.time.LocalDate startOfMonthDate = startYearMonth.atDay(1);
|
||||
java.time.LocalDate endOfMonthDate = startYearMonth.atEndOfMonth();
|
||||
filter.setItemValue("start",
|
||||
java.util.Date.from(startOfMonthDate.atStartOfDay().atZone(ZoneId.systemDefault()).toInstant()));
|
||||
filter.setItemValue("stop",
|
||||
java.util.Date.from(endOfMonthDate.atStartOfDay().atZone(ZoneId.systemDefault()).toInstant()));
|
||||
}
|
||||
return filter;
|
||||
}
|
||||
|
||||
public void setFilter(ItemCollection filter) {
|
||||
this.filter = filter;
|
||||
}
|
||||
|
||||
public Category getSachpruefung() {
|
||||
return sachpruefung;
|
||||
}
|
||||
|
||||
public Category getVerteilung() {
|
||||
return verteilung;
|
||||
}
|
||||
|
||||
public Category getBuchhaltung() {
|
||||
return buchhaltung;
|
||||
}
|
||||
|
||||
public int totalCountByCategory(Category cat) {
|
||||
int result = 0;
|
||||
|
||||
Collection<Integer> allCounts = cat.getLabels().values();
|
||||
result = allCounts.stream().reduce(0, Integer::sum);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fuert verschiedene Queries aus um eine Analyse der Sachprufung durchzuführen.
|
||||
*/
|
||||
public void analyse() {
|
||||
|
||||
logger.info("start analyse....");
|
||||
verteilung = null;
|
||||
sachpruefung = null;
|
||||
Date start = filter.getItemValueDate("start");
|
||||
Date stop = filter.getItemValueDate("stop");
|
||||
|
||||
logger.info("...daterange=" + start + " - " + stop);
|
||||
|
||||
// serach date range?
|
||||
String sDateFrom = "191401070000"; // because * did not work here
|
||||
String sDateTo = "211401070000";
|
||||
SimpleDateFormat dateformat = new SimpleDateFormat("yyyyMMddHHmm");
|
||||
|
||||
if (start != null) {
|
||||
Calendar cal = Calendar.getInstance();
|
||||
cal.setTime(start);
|
||||
sDateFrom = dateformat.format(cal.getTime());
|
||||
}
|
||||
if (stop != null) {
|
||||
Calendar cal = Calendar.getInstance();
|
||||
cal.setTime(stop);
|
||||
cal.add(Calendar.DATE, 1);
|
||||
sDateTo = dateformat.format(cal.getTime());
|
||||
}
|
||||
|
||||
// query Verteilung
|
||||
String query = "(type:workitem OR type:workitemarchive) ";
|
||||
if (start != null || stop != null) {
|
||||
query += "AND (taxonomy.verteilung.stop:[" + sDateFrom + " TO " + sDateTo + "]) ";
|
||||
}
|
||||
logger.info(query);
|
||||
List<Category> taxResult = searchService.getTaxonomyByQuery(query, "taxonomy.verteilung.stop.by");
|
||||
if (taxResult.size() > 0) {
|
||||
verteilung = taxResult.get(0);
|
||||
|
||||
}
|
||||
|
||||
// query Sachprüfung
|
||||
query = "(type:workitem OR type:workitemarchive) ";
|
||||
if (start != null || stop != null) {
|
||||
query += "AND (taxonomy.sachpruefung.stop:[" + sDateFrom + " TO " + sDateTo + "]) ";
|
||||
}
|
||||
logger.info(query);
|
||||
taxResult = searchService.getTaxonomyByQuery(query, "taxonomy.sachpruefung.stop.by");
|
||||
if (taxResult.size() > 0) {
|
||||
sachpruefung = taxResult.get(0);
|
||||
|
||||
}
|
||||
|
||||
// query Buchhaltung
|
||||
query = "(type:workitem OR type:workitemarchive) ";
|
||||
if (start != null || stop != null) {
|
||||
query += "AND (taxonomy.buchhaltung.stop:[" + sDateFrom + " TO " + sDateTo + "]) ";
|
||||
}
|
||||
logger.info(query);
|
||||
taxResult = searchService.getTaxonomyByQuery(query, "taxonomy.buchhaltung.stop.by");
|
||||
if (taxResult.size() > 0) {
|
||||
buchhaltung = taxResult.get(0);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* This method reset the search and input state.
|
||||
*/
|
||||
public void reset() {
|
||||
filter = new ItemCollection();
|
||||
sachpruefung = null;
|
||||
verteilung = null;
|
||||
buchhaltung = null;
|
||||
logger.fine("reset");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,50 +0,0 @@
|
|||
package com.alexanderlogistics;
|
||||
|
||||
import org.imixs.workflow.ItemCollection;
|
||||
import org.imixs.workflow.engine.plugins.AbstractPlugin;
|
||||
import org.imixs.workflow.exceptions.PluginException;
|
||||
|
||||
import jakarta.inject.Inject;
|
||||
|
||||
/**
|
||||
* Das InvoiceOutgoingPlugin aktualisiert die Debitor E-Mail Adresse
|
||||
*
|
||||
* Auch das feld _img wird in Abhängigkeit vom item 'invoice.protest' gesetzt
|
||||
*
|
||||
* @author rsoika
|
||||
* @version 1.0
|
||||
*
|
||||
*/
|
||||
public class InvoiceOutgoingPlugin extends AbstractPlugin {
|
||||
|
||||
@Inject
|
||||
KreditorDebitorService kreditorService;
|
||||
|
||||
/**
|
||||
*
|
||||
* @throws PluginException - if data is missing
|
||||
*
|
||||
**/
|
||||
@Override
|
||||
public ItemCollection run(ItemCollection workitem, ItemCollection event) throws PluginException {
|
||||
|
||||
// Update Invoice.positions
|
||||
InvoiceUtil.updateInvoicePositions(workitem);
|
||||
|
||||
String dbtrNumber = workitem.getItemValueString("dbtr.number");
|
||||
ItemCollection debitor = kreditorService.findDebitor(dbtrNumber);
|
||||
if (debitor != null) {
|
||||
// update mail
|
||||
workitem.setItemValue("dbtr.mail", debitor.getItemValueString("cdtr.mail"));
|
||||
}
|
||||
|
||||
String img = "";
|
||||
if (workitem.getItemValueBoolean("invoice.protest")) {
|
||||
img = img + "<img title='Reklamiert' src=\"/layout/icons/icon106.png\">";
|
||||
|
||||
}
|
||||
workitem.setItemValue("_img", img);
|
||||
return workitem;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,442 +0,0 @@
|
|||
package com.alexanderlogistics;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.eclipse.microprofile.config.inject.ConfigProperty;
|
||||
import org.imixs.workflow.ItemCollection;
|
||||
import org.imixs.workflow.engine.plugins.AbstractPlugin;
|
||||
import org.imixs.workflow.exceptions.PluginException;
|
||||
import org.imixs.workflow.exceptions.QueryException;
|
||||
import org.imixs.workflow.faces.util.ResourceBundleHandler;
|
||||
|
||||
import jakarta.ejb.EJB;
|
||||
import jakarta.inject.Inject;
|
||||
|
||||
/**
|
||||
* Das InvoicePlugin prüft die Eingaben auf Gültigkeit, so dass diese problemlos
|
||||
* nach Cargosoft exportiert werden können.
|
||||
* <p>
|
||||
* Konkret geht es darum, das im Status 5200 in den ChildItems keine leeren
|
||||
* Zeilen vorkommen dürfen.
|
||||
* <p>
|
||||
* Im Status 5000 muss immer der payment.type ausgewählt werden. Dies wird vom
|
||||
* Plugin explizit geprüft
|
||||
* <p>
|
||||
* Das Plugin prüft auch auf doppelte Rechnungsnummern. Dabei wird Systemweit
|
||||
* geprüft ob die Rechnungsnummer schon einmal vorkam. Falls ja, wird eine
|
||||
* Warnung ausgegeben. Der Benutzer kann diese dann skippen.
|
||||
* <p>
|
||||
* Zusätzlich berechnet das Plugin das Feld invoice.positions mit einer Value
|
||||
* liste der Positionsnummern. Dieses Feld wird indiziert, so dass gezielt nach
|
||||
* Positionsnummern gesucht werden kann.
|
||||
* <p>
|
||||
* 2.2.22 - Das Plugin erzeugt auch das Feld _img welches die Images von
|
||||
* Sofortüberweisung, Mahnung und Ablehnung anzeigt.
|
||||
*
|
||||
*
|
||||
* @author rsoika
|
||||
* @version 1.0
|
||||
*
|
||||
*/
|
||||
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 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());
|
||||
|
||||
// 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
|
||||
@EJB
|
||||
KreditorDebitorService kreditorService;
|
||||
|
||||
@Inject
|
||||
ResourceBundleHandler resourceBundleHandler;
|
||||
|
||||
/**
|
||||
* Test childworkitems for empty lines
|
||||
*
|
||||
* @throws PluginException - if data is missing
|
||||
*
|
||||
**/
|
||||
@Override
|
||||
public ItemCollection run(ItemCollection workitem, ItemCollection event) throws PluginException {
|
||||
|
||||
updateImg(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;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
// 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("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);
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return 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\">";
|
||||
|
||||
}
|
||||
// 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 {
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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");
|
||||
|
||||
// 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 {
|
||||
|
||||
// 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 {
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
// wenn bereits eine Überneahme angedroht wurde dann übernehemen!
|
||||
if (!overtakeIBAN.isEmpty()) {
|
||||
kreditorService.addNewIBANBIC(cdtrNumber, iban, bic);
|
||||
workitem.setItemValue("ibanbic.overtake", "");
|
||||
return;
|
||||
}
|
||||
|
||||
// search the kreditor
|
||||
ItemCollection cdtr = kreditorService.findCreditorDebitor(cdtrNumber);
|
||||
if (cdtr != null) {
|
||||
// Prüfen ob wir die IBAN schon kennen
|
||||
if (iban.equals(cdtr.getItemValueString("cdtr.iban")) && bic.equals(cdtr.getItemValueString("cdtr.bic"))) {
|
||||
return;
|
||||
}
|
||||
if (iban.equals(cdtr.getItemValueString("cdtr.iban2"))
|
||||
&& bic.equals(cdtr.getItemValueString("cdtr.bic2"))) {
|
||||
return;
|
||||
}
|
||||
if (iban.equals(cdtr.getItemValueString("cdtr.iban3"))
|
||||
&& bic.equals(cdtr.getItemValueString("cdtr.bic3"))) {
|
||||
return;
|
||||
}
|
||||
if (iban.equals(cdtr.getItemValueString("cdtr.iban4"))
|
||||
&& bic.equals(cdtr.getItemValueString("cdtr.bic4"))) {
|
||||
return;
|
||||
}
|
||||
// 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");
|
||||
|
||||
// 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) {
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 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();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,148 +0,0 @@
|
|||
package com.alexanderlogistics;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.imixs.workflow.ItemCollection;
|
||||
|
||||
/**
|
||||
* Hilfsmethoden für die Berechnung und Validierung von Ein und
|
||||
* Ausgangsrechnugnen
|
||||
*
|
||||
* - Rundungs Methode
|
||||
* - Berechnung der Positionsnummern
|
||||
* - Explode Childitems
|
||||
*
|
||||
* See:
|
||||
* https://stackoverflow.com/questions/2808535/round-a-double-to-2-decimal-places
|
||||
*
|
||||
* @author rsoika
|
||||
*
|
||||
*/
|
||||
public class InvoiceUtil {
|
||||
|
||||
public static final String CHILD_ITEM_PROPERTY = "_ChildItems";
|
||||
public static final String ITEM_INVOICE_PERIOD = "invoice.period";
|
||||
public static final String ITEM_INVOICE_POSITIONS = "invoice.positions";
|
||||
public static final String ITEM_CDTR_NUMBER = "cdtr.number";
|
||||
public static final String ITEM_CDTR_NAME = "cdtr.name";
|
||||
public static final String ITEM_CDTR_NAME_CARGOSOFT = "cdtr.name.cargosoft";
|
||||
|
||||
public static double round(double value) {
|
||||
BigDecimal bd = BigDecimal.valueOf(value);
|
||||
bd = bd.setScale(2, RoundingMode.HALF_UP);
|
||||
return bd.doubleValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Hilfsmethode zum validieren der Mailadresse
|
||||
*
|
||||
* @param emailAddress
|
||||
* @return
|
||||
*/
|
||||
public static boolean validateEmail(String emailAddress) {
|
||||
// String regexPattern = "^(.+)@(\\S+)$";
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static double roundConservative(double value) {
|
||||
value = value * 100;
|
||||
long tmp = Math.round(value);
|
||||
return (double) tmp / 100;
|
||||
}
|
||||
|
||||
/**
|
||||
* converts the Map List of a workitem into a List of ItemCollectons
|
||||
*/
|
||||
public static List<ItemCollection> explodeChildList(ItemCollection workitem) {
|
||||
return explodeChildList(workitem, CHILD_ITEM_PROPERTY);
|
||||
}
|
||||
|
||||
/**
|
||||
* converts the Map List of a workitem into a List of ItemCollectons
|
||||
*/
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
public static List<ItemCollection> explodeChildList(ItemCollection workitem, String childItemName) {
|
||||
// convert current list of childItems into ItemCollection elements
|
||||
ArrayList<ItemCollection> childItems = new ArrayList<ItemCollection>();
|
||||
|
||||
List<Object> mapOrderItems = workitem.getItemValue(childItemName);
|
||||
for (Object mapOderItem : mapOrderItems) {
|
||||
if (mapOderItem instanceof Map) {
|
||||
ItemCollection itemCol = new ItemCollection((Map) mapOderItem);
|
||||
childItems.add(itemCol);
|
||||
}
|
||||
}
|
||||
return childItems;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the List of ItemCollections back into a List of Map elements
|
||||
*
|
||||
* @param workitem
|
||||
*/
|
||||
public static void implodeChildList(ItemCollection workitem, List<ItemCollection> childItems) {
|
||||
implodeChildList(workitem, childItems, CHILD_ITEM_PROPERTY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the List of ItemCollections back into a List of Map elements
|
||||
*
|
||||
* @param workitem
|
||||
*/
|
||||
@SuppressWarnings({ "rawtypes" })
|
||||
public static void implodeChildList(ItemCollection workitem, List<ItemCollection> childItems,
|
||||
String childItemName) {
|
||||
List<Map> mapOrderItems = new ArrayList<Map>();
|
||||
// convert the child ItemCollection elements into a List of Map
|
||||
if (childItems != null) {
|
||||
// iterate over all order items..
|
||||
for (ItemCollection orderItem : childItems) {
|
||||
mapOrderItems.add(orderItem.getAllItems());
|
||||
}
|
||||
workitem.replaceItemValue(childItemName, mapOrderItems);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @param workitem
|
||||
*/
|
||||
public static void updateInvoicePositions(ItemCollection workitem) {
|
||||
|
||||
List<String> posList = new ArrayList<String>();
|
||||
List<ItemCollection> childs = InvoiceUtil.explodeChildList(workitem);
|
||||
for (ItemCollection posItem : childs) {
|
||||
String posName = "";
|
||||
// Ausgangsrechnung - item=datev.text
|
||||
// Eingangsrechnugn - item=name
|
||||
if (posItem.hasItem("datev.text")) {
|
||||
posName = posItem.getItemValueString("datev.text").trim();
|
||||
} else {
|
||||
posName = posItem.getItemValueString("name").trim();
|
||||
}
|
||||
if (!posName.isEmpty()) {
|
||||
posList.add(posName);
|
||||
}
|
||||
}
|
||||
// update invoice.positions
|
||||
workitem.setItemValue(ITEM_INVOICE_POSITIONS, posList);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,382 +0,0 @@
|
|||
package com.alexanderlogistics;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.apache.poi.ss.usermodel.CellCopyPolicy;
|
||||
import org.apache.poi.ss.util.CellReference;
|
||||
import org.apache.poi.xssf.usermodel.XSSFCell;
|
||||
import org.apache.poi.xssf.usermodel.XSSFRow;
|
||||
import org.apache.poi.xssf.usermodel.XSSFSheet;
|
||||
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
|
||||
import org.imixs.workflow.FileData;
|
||||
import org.imixs.workflow.ItemCollection;
|
||||
import org.imixs.workflow.engine.DocumentService;
|
||||
import org.imixs.workflow.engine.WorkflowService;
|
||||
import org.imixs.workflow.exceptions.AdapterException;
|
||||
import org.imixs.workflow.exceptions.PluginException;
|
||||
import org.imixs.workflow.exceptions.QueryException;
|
||||
import org.imixs.workflow.office.config.ConfigService;
|
||||
import org.imixs.workflow.poi.POIFindReplaceAdapter;
|
||||
|
||||
import jakarta.inject.Inject;
|
||||
|
||||
/**
|
||||
* Der OPListExportAdapter importiert eine Excel Datei aus einem Textblock
|
||||
*
|
||||
* <pre>
|
||||
* {@code
|
||||
<opliste name="textblock">textblock-ref</opliste>
|
||||
<opliste name="template">filename</opliste>
|
||||
<opliste name="targetname">filename</opliste>
|
||||
}
|
||||
* </pre>
|
||||
* <p>
|
||||
* Der Adapter erweitert den POIAdapter somit können Felder aktualisiert werden
|
||||
* (siehe POIFineReplaceAdapter).
|
||||
*
|
||||
* <p>
|
||||
* Der Adapter kopiert die Rechnungsdaten in neue Zeilen, welche ab Zeilennummer
|
||||
* 16 eingefügt werden.
|
||||
* <p>
|
||||
*
|
||||
* Abschliessend wird die Zelle 'TOTAL' noch aktualisiert.
|
||||
*
|
||||
* Der Fälligkeitszeitrum von 21 Tagen kann über den Parameter
|
||||
*
|
||||
* @version 1.0
|
||||
* @author rsoika
|
||||
*/
|
||||
public class OPListExportAdapter extends POIFindReplaceAdapter {
|
||||
|
||||
private static Logger logger = Logger.getLogger(OPListExportAdapter.class.getName());
|
||||
|
||||
@Inject
|
||||
WorkflowService workflowService;
|
||||
|
||||
@Inject
|
||||
OPListExportService opListExportService;
|
||||
|
||||
@Inject
|
||||
DocumentService documentService;
|
||||
|
||||
@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 {
|
||||
|
||||
// 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(OPListExportAdapter.class.getSimpleName(), OPListExportService.ERROR_CONFIG,
|
||||
"missing Currency configuration - please check parameters");
|
||||
}
|
||||
String currency1 = currencyList.get(0);
|
||||
String currency2 = currencyList.get(1);
|
||||
|
||||
// read the zahlungsavis options
|
||||
ItemCollection evalItemCollection = workflowService.evalWorkflowResult(event, "opliste", document, false);
|
||||
if (evalItemCollection == null) {
|
||||
throw new PluginException(OPListExportAdapter.class.getSimpleName(), OPListExportService.ERROR_CONFIG,
|
||||
"missing op-list configuration in model event - please check model configuration");
|
||||
}
|
||||
String textblock = evalItemCollection.getItemValueString("textblock");
|
||||
String template = evalItemCollection.getItemValueString("template");
|
||||
String targetName = evalItemCollection.getItemValueString("target-name");
|
||||
boolean filter = evalItemCollection.getItemValueBoolean("filter");
|
||||
// adapt text....
|
||||
targetName = workflowService.adaptText(targetName, document);
|
||||
|
||||
appendExcelTemplate(document, textblock, template, 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");
|
||||
try {
|
||||
logger.info("... update template with normal poi information..");
|
||||
this.updateFileData(document.getFileData(targetName), document, replaceDevList, eval);
|
||||
|
||||
// now we add separate lines for each invoice....
|
||||
logger.info("... insert invoices - filter=" + filter);
|
||||
document.setItemValue("space.currency1", currency1);
|
||||
document.setItemValue("space.currency2", currency2);
|
||||
|
||||
insertInvoiceRows(document, targetName, filter, currency1, currency2);
|
||||
} catch (PluginException | IOException | QueryException e) {
|
||||
throw new PluginException(OPListExportAdapter.class.getSimpleName(), OPListExportService.ERROR_CONFIG,
|
||||
"failed to update op-liste: " + e.getMessage());
|
||||
}
|
||||
logger.info("... completed!");
|
||||
return document;
|
||||
}
|
||||
|
||||
/**
|
||||
* This helper method inserts a row for each invoice of the OPListe 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, boolean filter, String currency1,
|
||||
String currency2)
|
||||
throws PluginException, QueryException {
|
||||
|
||||
double saldo1 = 0;
|
||||
double saldo2 = 0;
|
||||
// load dummy rechnungen
|
||||
String spaceID = document.getItemValueString("space.ref");
|
||||
|
||||
logger.info("... space.ref=" + spaceID + " ...grouping invoices by spaceid....");
|
||||
Map<String, List<ItemCollection>> invoiceMap = groupInvoicesBySpaceID(spaceID, filter);
|
||||
|
||||
FileData fileData = document.getFileData(fileName);
|
||||
|
||||
// load XSSFWorkbook
|
||||
XSSFWorkbook doc = null;
|
||||
try (InputStream imputStream = new ByteArrayInputStream(fileData.getContent())) {
|
||||
doc = new XSSFWorkbook(imputStream);
|
||||
// NOTE: we only take the first sheet !
|
||||
XSSFSheet sheet = doc.getSheetAt(0);
|
||||
// Währungsüberschriften setzten
|
||||
sheet.getRow(10).getCell(6).setCellValue(currency1);
|
||||
sheet.getRow(10).getCell(8).setCellValue(currency2);
|
||||
|
||||
CellReference categoryRefCell = new CellReference("A12");
|
||||
XSSFRow referenceRowCategory = sheet.getRow(categoryRefCell.getRow());
|
||||
CellReference invoiceRefCell = new CellReference("A13");
|
||||
XSSFRow referenceRowInvoice = sheet.getRow(invoiceRefCell.getRow());
|
||||
|
||||
int referenceRowPos = 12;
|
||||
int rowPos = 12;
|
||||
int lastRow = 2999;
|
||||
logger.finest("Last rownum=" + lastRow);
|
||||
|
||||
int totalRowCount = invoiceMap.size() * 2;
|
||||
for (List<?> list : invoiceMap.values()) {
|
||||
totalRowCount = totalRowCount + list.size();
|
||||
}
|
||||
if (totalRowCount == 0) {
|
||||
logger.warning("No Invoices found - skip update workbook!");
|
||||
return;
|
||||
}
|
||||
sheet.shiftRows(rowPos, lastRow, totalRowCount, true, true);
|
||||
for (Map.Entry<String, List<ItemCollection>> entry : invoiceMap.entrySet()) {
|
||||
String dbtrNumber = entry.getKey();
|
||||
List<ItemCollection> invoices = entry.getValue();
|
||||
|
||||
// erzeuge eine Zwischenüberschrift für den Debitor....
|
||||
XSSFRow categoryRow = sheet.createRow(rowPos);
|
||||
categoryRow.copyRowFrom(referenceRowCategory, new CellCopyPolicy());
|
||||
// insert values
|
||||
categoryRow.getCell(0).setCellValue(dbtrNumber);
|
||||
String debitorName = invoices.get(0).getItemValueString("dbtr.name");
|
||||
categoryRow.getCell(1).setCellValue(debitorName);
|
||||
|
||||
// calculate summ of all invoices
|
||||
double catSumEUR = 0;
|
||||
double catSumUSD = 0;
|
||||
for (ItemCollection invoice : invoices) {
|
||||
if (currency1.equals(invoice.getItemValueString("invoice.currency"))) {
|
||||
catSumEUR = catSumEUR + invoice.getItemValueDouble("invoice.saldo");
|
||||
} else {
|
||||
catSumUSD = catSumUSD + invoice.getItemValueDouble("invoice.saldo");
|
||||
}
|
||||
}
|
||||
categoryRow.getCell(6).setCellValue(catSumEUR);
|
||||
categoryRow.getCell(8).setCellValue(catSumUSD);
|
||||
|
||||
rowPos++;
|
||||
|
||||
// jetzt füge alle Rechnungen an.
|
||||
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
|
||||
if (invoice.getItemValueBoolean("invoice.protest")) {
|
||||
row.getCell(2).setCellValue(invoice.getItemValueString("invoice.number") + " (R)");
|
||||
} else {
|
||||
row.getCell(2).setCellValue(invoice.getItemValueString("invoice.number"));
|
||||
}
|
||||
row.getCell(3).setCellValue(invoice.getItemValueString("invoice.text"));
|
||||
row.getCell(4).setCellValue(invoice.getItemValueDate("invoice.date"));
|
||||
row.getCell(5).setCellValue(invoice.getItemValueDate("invoice.duedate"));
|
||||
double total = invoice.getItemValueDouble("invoice.saldo");
|
||||
String currency = invoice.getItemValueString("invoice.currency");
|
||||
if (currency1.equals(currency)) {
|
||||
// EUR
|
||||
row.getCell(6).setCellValue(total);
|
||||
row.getCell(7).setCellValue(currency);
|
||||
saldo1 = InvoiceUtil.round(saldo1 + total);
|
||||
} else {
|
||||
// USD
|
||||
row.getCell(8).setCellValue(total);
|
||||
row.getCell(9).setCellValue(currency);
|
||||
saldo2 = InvoiceUtil.round(saldo2 + total);
|
||||
}
|
||||
row.getCell(10).setCellValue(invoice.getItemValueString("$workflowstatus"));
|
||||
|
||||
rowPos++;
|
||||
}
|
||||
|
||||
// Leerzeile
|
||||
categoryRow = sheet.createRow(rowPos);
|
||||
rowPos++;
|
||||
}
|
||||
// delete reference row 12
|
||||
sheet.shiftRows(referenceRowPos, lastRow + totalRowCount, -1, true, true);
|
||||
|
||||
// finally update the total formula...
|
||||
XSSFCell cTotal1 = getCellByRef(doc, sheet, "TOTAL1");
|
||||
XSSFCell cTotal2 = getCellByRef(doc, sheet, "TOTAL2");
|
||||
cTotal1.setCellValue(saldo1);
|
||||
cTotal2.setCellValue(saldo2);
|
||||
// Set währung
|
||||
XSSFCell cTotalCurrency1 = getCellByRef(doc, sheet, "TOTAL_CURRENCY1");
|
||||
XSSFCell cTotalCurrency2 = getCellByRef(doc, sheet, "TOTAL_CURRENCY2");
|
||||
cTotalCurrency1.setCellValue(currency1);
|
||||
cTotalCurrency2.setCellValue(currency2);
|
||||
|
||||
// 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);
|
||||
document.setItemValue("space.saldo.currency1", saldo1);
|
||||
document.setItemValue("space.saldo.currency2", saldo2);
|
||||
logger.finest("......new document added");
|
||||
|
||||
} catch (IOException e) {
|
||||
throw new PluginException(OPListExportAdapter.class.getSimpleName(), OPListExportService.ERROR_CONFIG,
|
||||
"failed to update opliste: " + e.getMessage());
|
||||
} finally {
|
||||
if (doc != null) {
|
||||
try {
|
||||
doc.close();
|
||||
} catch (IOException e) {
|
||||
logger.severe("Failed to close workbook: " + e.getMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method loads a text-block for a specified ref and appends the named
|
||||
* fileData object of this document.
|
||||
*
|
||||
* @param document
|
||||
* @throws PluginException
|
||||
*/
|
||||
private void appendExcelTemplate(ItemCollection document, String textblockRef, String template, String targetName)
|
||||
throws PluginException {
|
||||
|
||||
if ((template == null || template.isEmpty()) || (textblockRef == null || textblockRef.isEmpty())) {
|
||||
throw new PluginException(OPListExportAdapter.class.getSimpleName(), OPListExportService.ERROR_CONFIG,
|
||||
"invalid op-list 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(OPListExportAdapter.class.getSimpleName(), OPListExportService.ERROR_CONFIG,
|
||||
"invalid op-list configuration in model event - template=" + template + " not found!");
|
||||
}
|
||||
fileData.setName(targetName);
|
||||
// append document
|
||||
logger.info("...append new op-list Template: " + targetName);
|
||||
|
||||
document.addFileData(fileData);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Diese Methode gruppiert eine Rechnungsliste nach Debitorennummern
|
||||
*
|
||||
* Falls 'filter==true' werden nur Rechnungen ab der 2. Mahnung oder mit einer
|
||||
* Fälligkeit >10 Tage ausgegeben. Dieses Flag wird im Workflowmodell gesetzt
|
||||
*
|
||||
* @param spaceID
|
||||
* @return
|
||||
*/
|
||||
private Map<String, List<ItemCollection>> groupInvoicesBySpaceID(String spaceID, boolean filter) {
|
||||
|
||||
Map<String, List<ItemCollection>> result = new HashMap<>();
|
||||
|
||||
try {
|
||||
List<ItemCollection> invoices = documentService.find(
|
||||
"$modelversion:rechnungsausgang-* AND type:workitem AND $uniqueidref:" + spaceID, 9999, 0,
|
||||
"invoice.number", false);
|
||||
|
||||
for (ItemCollection invoice : invoices) {
|
||||
|
||||
String dbtrNumber = invoice.getItemValueString("dbtr.number");
|
||||
// haben wir shon ein listchen?
|
||||
List<ItemCollection> invoiceList = result.get(dbtrNumber);
|
||||
if (invoiceList == null) {
|
||||
// erzeuge eine neue liste
|
||||
invoiceList = new ArrayList<ItemCollection>();
|
||||
}
|
||||
|
||||
if (filter) {
|
||||
Date date = invoice.getItemValueDate("invoice.duedate");
|
||||
if (opListExportService.isOverdue(date, invoice.getTaskID())) {
|
||||
// logger.info("...invoice - " +invoice.getUniqueID() + " is in overdue");
|
||||
invoiceList.add(invoice);
|
||||
}
|
||||
} else {
|
||||
// jede Rechnung zählt (manuelle OPListe)
|
||||
invoiceList.add(invoice);
|
||||
}
|
||||
|
||||
// speicher wieder die neue liste wenn es mindestens eine Rechnung gab
|
||||
if (invoiceList.size() > 0) {
|
||||
result.put(dbtrNumber, invoiceList);
|
||||
}
|
||||
}
|
||||
|
||||
} catch (QueryException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,640 +0,0 @@
|
|||
package com.alexanderlogistics;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.time.LocalDate;
|
||||
import java.time.ZoneId;
|
||||
import java.time.temporal.IsoFields;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.apache.poi.ss.usermodel.CellCopyPolicy;
|
||||
import org.apache.poi.ss.usermodel.CellStyle;
|
||||
import org.apache.poi.ss.usermodel.FillPatternType;
|
||||
import org.apache.poi.ss.usermodel.IndexedColors;
|
||||
import org.apache.poi.ss.usermodel.Row.MissingCellPolicy;
|
||||
import org.apache.poi.xssf.usermodel.XSSFCell;
|
||||
import org.apache.poi.xssf.usermodel.XSSFRow;
|
||||
import org.apache.poi.xssf.usermodel.XSSFSheet;
|
||||
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
|
||||
import org.imixs.marty.team.TeamService;
|
||||
import org.imixs.workflow.FileData;
|
||||
import org.imixs.workflow.ItemCollection;
|
||||
import org.imixs.workflow.ItemCollectionComparator;
|
||||
import org.imixs.workflow.engine.DocumentService;
|
||||
import org.imixs.workflow.engine.WorkflowService;
|
||||
import org.imixs.workflow.exceptions.AdapterException;
|
||||
import org.imixs.workflow.exceptions.PluginException;
|
||||
import org.imixs.workflow.exceptions.QueryException;
|
||||
import org.imixs.workflow.office.config.ConfigService;
|
||||
import org.imixs.workflow.poi.POIFindReplaceAdapter;
|
||||
|
||||
import jakarta.inject.Inject;
|
||||
|
||||
/**
|
||||
* Der OPListExportAdapterByWeek ist ählnlich dem Der OPListExportAdapter. Er
|
||||
* erzeugt eine Excel tabelle mit allen offenen Rechnungen und gruppiert diese
|
||||
* nach Abteilungen und KW
|
||||
*
|
||||
* Der OPListExportAdapterByWeek importiert eine Excel Datei aus einem Textblock
|
||||
*
|
||||
* <pre>
|
||||
* {@code
|
||||
<opliste name="textblock">textblock-ref</opliste>
|
||||
<opliste name="template">filename</opliste>
|
||||
<opliste name="targetname">filename</opliste>
|
||||
}
|
||||
* </pre>
|
||||
* <p>
|
||||
* Der Adapter erweitert den POIAdapter somit können felder aktualisiert werden
|
||||
* (siehe POIFineReplaceAdapter).
|
||||
*
|
||||
* <p>
|
||||
* Der Adapter kopiert die Rechnungsdaten in neue Zeilen, welche ab Zeilnenummer
|
||||
* 16 eingefügt werden.
|
||||
* <p>
|
||||
*
|
||||
* Abschliessend wird die Zelle 'TOTAL' noch aktualisiert.
|
||||
*
|
||||
* @version 1.0
|
||||
* @author rsoika
|
||||
*/
|
||||
public class OPListExportAdapterByWeek extends POIFindReplaceAdapter {
|
||||
|
||||
private static Logger logger = Logger.getLogger(OPListExportAdapterByWeek.class.getName());
|
||||
|
||||
final String TYPE_TEXTBLOCK = "textblock";
|
||||
|
||||
@Inject
|
||||
WorkflowService workflowService;
|
||||
|
||||
@Inject
|
||||
DocumentService documentService;
|
||||
|
||||
@Inject
|
||||
TeamService teamService;
|
||||
|
||||
@Inject
|
||||
ConfigService configService;
|
||||
|
||||
@Inject
|
||||
OPListExportService opListExportService;
|
||||
|
||||
// cache for all invoices grouped by week
|
||||
Map<String, List<ItemCollection>> invoiceMap = null;
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
|
||||
// read the opliste options
|
||||
ItemCollection evalItemCollection = workflowService.evalWorkflowResult(event, "opliste", document, false);
|
||||
if (evalItemCollection == null) {
|
||||
throw new PluginException(OPListExportAdapterByWeek.class.getSimpleName(), OPListExportService.ERROR_CONFIG,
|
||||
"missing op-list configuration in model event - please check model configuration");
|
||||
}
|
||||
|
||||
// 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(OPListExportAdapter.class.getSimpleName(), OPListExportService.ERROR_CONFIG,
|
||||
"missing Currency configuration - please check parameters");
|
||||
}
|
||||
String currency1 = currencyList.get(0);
|
||||
String currency2 = currencyList.get(1);
|
||||
|
||||
String textblock = evalItemCollection.getItemValueString("textblock");
|
||||
String template = evalItemCollection.getItemValueString("template");
|
||||
String targetName = evalItemCollection.getItemValueString("target-name");
|
||||
// adapt text....
|
||||
targetName = workflowService.adaptText(targetName, document);
|
||||
appendExcelTemplate(document, textblock, template, 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");
|
||||
try {
|
||||
logger.info("... update template with normal poi information..");
|
||||
this.updateFileData(document.getFileData(targetName), document, replaceDevList, eval);
|
||||
|
||||
insertInvoiceRows(document, targetName, currency1, currency2);
|
||||
} catch (PluginException | IOException | QueryException e) {
|
||||
throw new PluginException(OPListExportAdapterByWeek.class.getSimpleName(), OPListExportService.ERROR_CONFIG,
|
||||
"failed to update op-liste: " + e.getMessage());
|
||||
}
|
||||
logger.info("... completed!");
|
||||
return document;
|
||||
}
|
||||
|
||||
/**
|
||||
* This helper method inserts a row for each invoice of the OPListe at row 16
|
||||
* into the excel template file
|
||||
* <p>
|
||||
* First the method computes all Departments and insert them at C10
|
||||
* <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, String currency1,
|
||||
String currency2)
|
||||
throws PluginException, QueryException {
|
||||
|
||||
Map<String, Double> totalsUeberfaelligCurrency1 = new HashMap<String, Double>();
|
||||
Map<String, Double> totalsFaelligCurrency1 = new HashMap<String, Double>();
|
||||
Map<String, Double> totalsUeberfaelligCurrency2 = new HashMap<String, Double>();
|
||||
Map<String, Double> totalsFaelligCurrency2 = new HashMap<String, Double>();
|
||||
List<String> spaceNames = new ArrayList<String>();
|
||||
|
||||
// compute all departments
|
||||
List<ItemCollection> spaces = teamService.getSpaces();
|
||||
// sort by space.name
|
||||
Collections.sort(spaces, new ItemCollectionComparator("space.name", true));
|
||||
|
||||
Map<String, WeekInvoiceData> weekDataMap = new HashMap<String, WeekInvoiceData>();
|
||||
FileData fileData = document.getFileData(fileName);
|
||||
|
||||
// load XSSFWorkbook
|
||||
XSSFWorkbook doc = null;
|
||||
try (InputStream imputStream = new ByteArrayInputStream(fileData.getContent())) {
|
||||
doc = new XSSFWorkbook(imputStream);
|
||||
|
||||
// compute current week
|
||||
Calendar calendar = new GregorianCalendar();
|
||||
calendar.setTime(new Date());
|
||||
int weekNumber = calendar.get(Calendar.WEEK_OF_YEAR);
|
||||
int year = calendar.get(Calendar.YEAR);
|
||||
String currentWeek = year + "/";
|
||||
if (weekNumber < 10) {
|
||||
currentWeek = currentWeek + "0" + weekNumber;
|
||||
} else {
|
||||
currentWeek = currentWeek + weekNumber;
|
||||
}
|
||||
|
||||
CellStyle headerCellStyle = doc.createCellStyle();
|
||||
// fill foreground color ...
|
||||
headerCellStyle.setFillForegroundColor(IndexedColors.GREY_50_PERCENT.index);
|
||||
// and solid fill pattern produces solid grey cell fill
|
||||
headerCellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
|
||||
|
||||
// NOTE: we only take the first sheet !
|
||||
XSSFSheet sheet = doc.getSheetAt(0);
|
||||
|
||||
// First we create a column for each Space.....
|
||||
XSSFRow rowSpacesLabels = sheet.getRow(9);
|
||||
XSSFRow referenceRowSpacesCurrencies = sheet.getRow(10);
|
||||
XSSFRow referenceRowValues = sheet.getRow(11);
|
||||
XSSFRow referenceRowCurrentWeek = sheet.getRow(12);
|
||||
|
||||
XSSFRow referenceRowTotal = sheet.getRow(15);
|
||||
|
||||
// Aktuelle KW berechnen
|
||||
calendar.setTime(new Date());
|
||||
int currentWeekNumber = calendar.get(Calendar.WEEK_OF_YEAR);
|
||||
int currentYear = calendar.get(Calendar.YEAR);
|
||||
String currentWeekCategory = currentYear + "/";
|
||||
if (currentWeekNumber < 10) {
|
||||
currentWeekCategory = currentWeekCategory + "0" + currentWeekNumber;
|
||||
} else {
|
||||
currentWeekCategory = currentWeekCategory + currentWeekNumber;
|
||||
}
|
||||
|
||||
/*
|
||||
* --- Phase 1 -------------------------------------------------------
|
||||
* Im folgenden fügen wir erst einmal in der Kopfzeile zusätzlich
|
||||
* Spaltenüberschriften für jede Abteilung ein
|
||||
*/
|
||||
XSSFCell cellSpaceLabelReference = rowSpacesLabels.getCell(2);
|
||||
XSSFCell cellSpaceCurrencyReference = referenceRowSpacesCurrencies.getCell(1);
|
||||
// XSSFCell cellKWTotalReference = referenceRowCurrentWeek.getCell(1);
|
||||
XSSFCell cellKWTotalReference = referenceRowTotal.getCell(14);
|
||||
int column = 1; // beginn in der 2. Spalte!
|
||||
for (ItemCollection space : spaces) {
|
||||
XSSFCell cell = null;
|
||||
String spaceName = space.getItemValueString("space.name");
|
||||
String spaceID = space.getUniqueID();
|
||||
spaceNames.add(spaceName);
|
||||
|
||||
// Space currency EUR
|
||||
cell = referenceRowSpacesCurrencies.getCell(column);
|
||||
cell.copyCellFrom(cellSpaceCurrencyReference, new CellCopyPolicy());
|
||||
cell.setCellValue(currency1);
|
||||
|
||||
// Space currency USD
|
||||
column++;
|
||||
cell = referenceRowSpacesCurrencies.getCell(column);
|
||||
cell.copyCellFrom(cellSpaceCurrencyReference, new CellCopyPolicy());
|
||||
cell.setCellValue(currency2);
|
||||
|
||||
// Space Label
|
||||
cell = rowSpacesLabels.getCell(column);
|
||||
cell.setCellValue(spaceName);
|
||||
|
||||
// create two new cells...
|
||||
column++;
|
||||
cell = rowSpacesLabels.createCell(column);
|
||||
cell.copyCellFrom(cellSpaceLabelReference, new CellCopyPolicy());
|
||||
cell.setCellValue("");
|
||||
|
||||
cell = rowSpacesLabels.createCell(column);
|
||||
cell.copyCellFrom(cellSpaceLabelReference, new CellCopyPolicy());
|
||||
cell.setCellValue("");
|
||||
|
||||
logger.info("...grouping invoices by week...");
|
||||
// collect all invoices for this space grouped by week....
|
||||
groupInvoicesByWeek(spaceID, spaceName, weekDataMap, currency1);
|
||||
|
||||
// init totals
|
||||
for (String name : spaceNames) {
|
||||
totalsUeberfaelligCurrency1.put(name, 0.0);
|
||||
totalsFaelligCurrency1.put(name, 0.0);
|
||||
totalsUeberfaelligCurrency2.put(name, 0.0);
|
||||
totalsFaelligCurrency2.put(name, 0.0);
|
||||
}
|
||||
}
|
||||
totalsUeberfaelligCurrency1.put("TOTAL", 0.0);
|
||||
totalsFaelligCurrency1.put("TOTAL", 0.0);
|
||||
totalsUeberfaelligCurrency2.put("TOTAL", 0.0);
|
||||
totalsFaelligCurrency2.put("TOTAL", 0.0);
|
||||
/*
|
||||
* --- Phase 2 -------------------------------------------------------
|
||||
* Nun bilden wir nochmal 2 weitere Spalten am Ende um eine Summenbildung in
|
||||
* EUR/USD pro KW zu ermöglichen
|
||||
*/
|
||||
XSSFCell cell = null;
|
||||
// column++;
|
||||
// Space currency EUR
|
||||
cell = referenceRowSpacesCurrencies.getCell(column, MissingCellPolicy.CREATE_NULL_AS_BLANK);
|
||||
cell.copyCellFrom(cellKWTotalReference, new CellCopyPolicy());
|
||||
cell.setCellValue(currency1);
|
||||
cell = rowSpacesLabels.getCell(column, MissingCellPolicy.CREATE_NULL_AS_BLANK);
|
||||
cell.copyCellFrom(cellKWTotalReference, new CellCopyPolicy());
|
||||
cell.setCellValue("");
|
||||
|
||||
// Space currency USD
|
||||
column++;
|
||||
cell = referenceRowSpacesCurrencies.getCell(column, MissingCellPolicy.CREATE_NULL_AS_BLANK);
|
||||
cell.copyCellFrom(cellKWTotalReference, new CellCopyPolicy());
|
||||
cell.setCellValue(currency2);
|
||||
|
||||
// Space Label
|
||||
cell = rowSpacesLabels.getCell(column, MissingCellPolicy.CREATE_NULL_AS_BLANK);
|
||||
cell.copyCellFrom(cellKWTotalReference, new CellCopyPolicy());
|
||||
cell.setCellValue("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....
|
||||
*/
|
||||
List<String> sortedWeekList = new ArrayList<String>();
|
||||
Iterator<Map.Entry<String, WeekInvoiceData>> iterator = weekDataMap.entrySet().iterator();
|
||||
while (iterator.hasNext()) {
|
||||
Map.Entry<String, WeekInvoiceData> entry = iterator.next();
|
||||
WeekInvoiceData weekInvoiceData = entry.getValue();
|
||||
if (!sortedWeekList.contains(weekInvoiceData.week)) {
|
||||
sortedWeekList.add(weekInvoiceData.week);
|
||||
}
|
||||
}
|
||||
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
|
||||
* errechnen....
|
||||
*/
|
||||
int rowPos = 11;
|
||||
int insertCount = sortedWeekList.size();
|
||||
sheet.shiftRows(rowPos + 1, 2999, insertCount, true, true);
|
||||
|
||||
/*
|
||||
* --- Phase 5 -------------------------------------------------------
|
||||
* Jetzt Zahlen Zeile für Zeile einfügen....
|
||||
*/
|
||||
boolean ueberFaellig = true;
|
||||
for (String week : sortedWeekList) {
|
||||
// now create a new line..
|
||||
rowPos++;
|
||||
logger.fine("--> Zeile " + rowPos + " Week=" + week);
|
||||
XSSFRow row = sheet.createRow(rowPos);
|
||||
|
||||
if (week.equals(currentWeekCategory)) {
|
||||
row.copyRowFrom(referenceRowCurrentWeek, new CellCopyPolicy());
|
||||
ueberFaellig = false;
|
||||
} else {
|
||||
row.copyRowFrom(referenceRowValues, new CellCopyPolicy());
|
||||
}
|
||||
|
||||
// insert values
|
||||
row.getCell(0).setCellValue(week);
|
||||
|
||||
// iterate over all spaceNames and test if we have any data to put it into the
|
||||
// row cells....
|
||||
column = 1;
|
||||
double kwTotalEUR = 0;
|
||||
double kwTotalUSD = 0;
|
||||
|
||||
for (String name : spaceNames) {
|
||||
String key = name + "/" + week;
|
||||
logger.fine("search WeekInvoiceData for " + key);
|
||||
// list of invoices
|
||||
WeekInvoiceData weekData = weekDataMap.get(key);
|
||||
if (weekData != null) {
|
||||
logger.fine(" " + currency1 + "=" + weekData.totalCurrency1 + " " + currency2 + "="
|
||||
+ weekData.totalCurrency2);
|
||||
row.getCell(column).setCellValue(weekData.totalCurrency1);
|
||||
column++;
|
||||
row.getCell(column).setCellValue(weekData.totalCurrency2);
|
||||
if (ueberFaellig) {
|
||||
double eur = totalsUeberfaelligCurrency1.get(name);
|
||||
eur = InvoiceUtil.round(eur + weekData.totalCurrency1);
|
||||
totalsUeberfaelligCurrency1.put(name, eur);
|
||||
double usd = totalsUeberfaelligCurrency2.get(name);
|
||||
usd = InvoiceUtil.round(usd + weekData.totalCurrency2);
|
||||
totalsUeberfaelligCurrency2.put(name, usd);
|
||||
// saldoEUR1 = InvoiceUtil.round(saldoEUR1 + weekData.totalEUR);
|
||||
// saldoUSD1 = InvoiceUtil.round(saldoUSD1 + weekData.totalUSD);
|
||||
} else {
|
||||
double eur = totalsFaelligCurrency1.get(name);
|
||||
eur = InvoiceUtil.round(eur + weekData.totalCurrency1);
|
||||
totalsFaelligCurrency1.put(name, eur);
|
||||
double usd = totalsFaelligCurrency2.get(name);
|
||||
usd = InvoiceUtil.round(usd + weekData.totalCurrency2);
|
||||
totalsFaelligCurrency2.put(name, usd);
|
||||
// saldoEUR2 = InvoiceUtil.round(saldoEUR2 + weekData.totalEUR);
|
||||
// saldoUSD2 = InvoiceUtil.round(saldoUSD2 + weekData.totalUSD);
|
||||
}
|
||||
kwTotalEUR = kwTotalEUR + weekData.totalCurrency1;
|
||||
kwTotalUSD = kwTotalUSD + weekData.totalCurrency2;
|
||||
column++;
|
||||
} else {
|
||||
logger.fine("...... NOT FOUND");
|
||||
// skip columns
|
||||
column = column + 2;
|
||||
}
|
||||
}
|
||||
// KW Summe anzeigen
|
||||
if (week.equals(currentWeekCategory)) {
|
||||
XSSFCell kwTotalCell = row.getCell(column);
|
||||
// kwTotalCell.copyCellFrom(cellKWTotalReference, new CellCopyPolicy());
|
||||
kwTotalCell.setCellValue(kwTotalEUR);
|
||||
|
||||
column++;
|
||||
// row.getCell(column).setCellValue(kwTotalUSD);
|
||||
kwTotalCell = row.getCell(column);
|
||||
// kwTotalCell.copyCellFrom(cellKWTotalReference, new CellCopyPolicy());
|
||||
kwTotalCell.setCellValue(kwTotalUSD);
|
||||
|
||||
} else {
|
||||
XSSFCell kwTotalCell = row.getCell(column);
|
||||
kwTotalCell.copyCellFrom(cellKWTotalReference, new CellCopyPolicy());
|
||||
kwTotalCell.setCellValue(kwTotalEUR);
|
||||
|
||||
column++;
|
||||
// row.getCell(column).setCellValue(kwTotalUSD);
|
||||
kwTotalCell = row.getCell(column);
|
||||
kwTotalCell.copyCellFrom(cellKWTotalReference, new CellCopyPolicy());
|
||||
kwTotalCell.setCellValue(kwTotalUSD);
|
||||
|
||||
}
|
||||
|
||||
// store totals
|
||||
if (ueberFaellig) {
|
||||
double eur = totalsUeberfaelligCurrency1.get("TOTAL");
|
||||
eur = InvoiceUtil.round(eur + kwTotalEUR);
|
||||
totalsUeberfaelligCurrency1.put("TOTAL", eur);
|
||||
double usd = totalsUeberfaelligCurrency2.get("TOTAL");
|
||||
usd = InvoiceUtil.round(usd + kwTotalUSD);
|
||||
totalsUeberfaelligCurrency2.put("TOTAL", usd);
|
||||
} else {
|
||||
double eur = totalsFaelligCurrency1.get("TOTAL");
|
||||
eur = InvoiceUtil.round(eur + kwTotalEUR);
|
||||
totalsFaelligCurrency1.put("TOTAL", eur);
|
||||
double usd = totalsFaelligCurrency2.get("TOTAL");
|
||||
usd = InvoiceUtil.round(usd + kwTotalUSD);
|
||||
totalsFaelligCurrency2.put("TOTAL", usd);
|
||||
}
|
||||
|
||||
}
|
||||
// delete reference rows
|
||||
logger.finest("..shift 12 to " + rowPos);
|
||||
sheet.shiftRows(12, rowPos, -1, true, true);
|
||||
sheet.shiftRows(rowPos + 2, rowPos + 6, -3, true, true);
|
||||
|
||||
/*
|
||||
* --- Phase 6 -------------------------------------------------------
|
||||
* now lets update the totals...
|
||||
* Überfällig
|
||||
*/
|
||||
int _rowNo = sortedWeekList.size() + 11;
|
||||
XSSFRow rowUeberFaellig = sheet.getRow(_rowNo);
|
||||
XSSFRow rowFaellig = sheet.getRow(_rowNo + 1);
|
||||
XSSFRow rowTotal = sheet.getRow(_rowNo + 2);
|
||||
column = 1;
|
||||
XSSFCell totalCell = null;
|
||||
for (String name : spaceNames) {
|
||||
totalCell = rowUeberFaellig.getCell(column);
|
||||
totalCell.setCellValue(totalsUeberfaelligCurrency1.get(name));
|
||||
totalCell = rowFaellig.getCell(column);
|
||||
totalCell.setCellValue(totalsFaelligCurrency1.get(name));
|
||||
totalCell = rowTotal.getCell(column);
|
||||
totalCell.setCellValue(totalsUeberfaelligCurrency1.get(name) + totalsFaelligCurrency1.get(name));
|
||||
column++;
|
||||
totalCell = rowUeberFaellig.getCell(column);
|
||||
totalCell.setCellValue(totalsUeberfaelligCurrency2.get(name));
|
||||
totalCell = rowFaellig.getCell(column);
|
||||
totalCell.setCellValue(totalsFaelligCurrency2.get(name));
|
||||
totalCell = rowTotal.getCell(column);
|
||||
totalCell.setCellValue(totalsUeberfaelligCurrency2.get(name) + totalsFaelligCurrency2.get(name));
|
||||
column++;
|
||||
}
|
||||
// totals
|
||||
totalCell = rowUeberFaellig.getCell(column);
|
||||
totalCell.setCellValue(totalsUeberfaelligCurrency1.get("TOTAL"));
|
||||
totalCell = rowFaellig.getCell(column);
|
||||
totalCell.setCellValue(totalsFaelligCurrency1.get("TOTAL"));
|
||||
totalCell = rowTotal.getCell(column);
|
||||
totalCell.setCellValue(totalsUeberfaelligCurrency1.get("TOTAL") + totalsFaelligCurrency1.get("TOTAL"));
|
||||
column++;
|
||||
totalCell = rowUeberFaellig.getCell(column);
|
||||
totalCell.setCellValue(totalsUeberfaelligCurrency2.get("TOTAL"));
|
||||
totalCell = rowFaellig.getCell(column);
|
||||
totalCell.setCellValue(totalsFaelligCurrency2.get("TOTAL"));
|
||||
totalCell = rowTotal.getCell(column);
|
||||
totalCell.setCellValue(totalsUeberfaelligCurrency2.get("TOTAL") + totalsFaelligCurrency2.get("TOTAL"));
|
||||
|
||||
// delete placeholder row
|
||||
sheet.shiftRows(_rowNo, _rowNo + 3, -1);
|
||||
|
||||
// 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(OPListExportAdapterByWeek.class.getSimpleName(), OPListExportService.ERROR_CONFIG,
|
||||
"failed to update opliste: " + e.getMessage());
|
||||
} finally {
|
||||
if (doc != null) {
|
||||
try {
|
||||
doc.close();
|
||||
} catch (IOException e) {
|
||||
logger.severe("Failed to close workbook: " + e.getMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method loads a text-block for a specified ref and appends the named
|
||||
* fileData object of this document.
|
||||
*
|
||||
* @param document
|
||||
* @throws PluginException
|
||||
*/
|
||||
private void appendExcelTemplate(ItemCollection document, String textblockRef, String template, String targetName)
|
||||
throws PluginException {
|
||||
|
||||
if ((template == null || template.isEmpty()) || (textblockRef == null || textblockRef.isEmpty())) {
|
||||
throw new PluginException(OPListExportAdapterByWeek.class.getSimpleName(), OPListExportService.ERROR_CONFIG,
|
||||
"invalid op-list 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(OPListExportAdapterByWeek.class.getSimpleName(), OPListExportService.ERROR_CONFIG,
|
||||
"invalid op-list configuration in model event - template=" + template + " not found!");
|
||||
}
|
||||
fileData.setName(targetName);
|
||||
// append document
|
||||
logger.info("...append new op-list Template: " + targetName);
|
||||
|
||||
document.addFileData(fileData);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Diese Methode gruppiert eine Rechnungsliste nach Kalenderwoche
|
||||
*
|
||||
* @param spaceID - Space Ref to select a list of invoices associated with a
|
||||
* space
|
||||
* @param cache - a local cache storing all invoices by week
|
||||
*
|
||||
*
|
||||
*/
|
||||
private void groupInvoicesByWeek(String spaceID, String spaceName,
|
||||
Map<String, WeekInvoiceData> cache, String currency1) {
|
||||
|
||||
logger.info("...group invoices (DEBUG) for " + spaceName + "/" + spaceID);
|
||||
try {
|
||||
List<ItemCollection> invoices = documentService.find(
|
||||
"$modelversion:rechnungsausgang-* AND type:workitem AND $uniqueidref:" + spaceID, 9999, 0,
|
||||
"invoice.number", false);
|
||||
|
||||
logger.fine(" found " + invoices.size() + " for space " + spaceName);
|
||||
for (ItemCollection invoice : invoices) {
|
||||
// compute Week
|
||||
Date dueDate = invoice.getItemValueDate("invoice.duedate");
|
||||
|
||||
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);
|
||||
if ("2024/01".equals(weekCategory)) {
|
||||
logger.warning("--> Invoice found with 2024/01: " + invoice.getUniqueID());
|
||||
}
|
||||
// haben wir schon ein listchen?
|
||||
|
||||
String key = spaceName + "/" + weekCategory;
|
||||
logger.fine(" ....building weekInvoiceData object for " + key);
|
||||
|
||||
WeekInvoiceData weekData = cache.get(key);
|
||||
if (weekData == null) {
|
||||
weekData = new WeekInvoiceData(spaceName, weekCategory);
|
||||
}
|
||||
// Jetzt Rechnung addieren
|
||||
weekData.add(invoice, currency1);
|
||||
cache.put(key, weekData);
|
||||
}
|
||||
|
||||
} catch (
|
||||
|
||||
QueryException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Data Element for invoice totals per week and space
|
||||
*/
|
||||
class WeekInvoiceData {
|
||||
|
||||
String week;
|
||||
String spaceName;
|
||||
double totalCurrency1;
|
||||
double totalCurrency2;
|
||||
|
||||
public WeekInvoiceData(String spaceName, String week) {
|
||||
this.spaceName = spaceName;
|
||||
this.week = week;
|
||||
}
|
||||
|
||||
public void add(ItemCollection invoice, String currency1) {
|
||||
String spaceName = invoice.getItemValueString("space.name");
|
||||
String currency = invoice.getItemValueString("invoice.currency");
|
||||
// Double total = invoice.getItemValueDouble("invoice.total");
|
||||
Double total = invoice.getItemValueDouble("invoice.saldo");
|
||||
if (currency1.equals(currency)) {
|
||||
totalCurrency1 = totalCurrency1 + total;
|
||||
} else {
|
||||
totalCurrency2 = totalCurrency2 + total;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,182 +0,0 @@
|
|||
package com.alexanderlogistics;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.imixs.workflow.ItemCollection;
|
||||
import org.imixs.workflow.engine.DocumentService;
|
||||
import org.imixs.workflow.engine.plugins.AbstractPlugin;
|
||||
import org.imixs.workflow.exceptions.PluginException;
|
||||
import org.imixs.workflow.exceptions.QueryException;
|
||||
|
||||
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 ???
|
||||
*
|
||||
*
|
||||
* @author rsoika
|
||||
* @version 1.0
|
||||
*
|
||||
*/
|
||||
public class SteuerbescheidPlugin extends AbstractPlugin {
|
||||
|
||||
private static Logger logger = Logger.getLogger(SteuerbescheidPlugin.class.getName());
|
||||
|
||||
@Inject
|
||||
protected DocumentService documentService;
|
||||
|
||||
@Inject
|
||||
KreditorDebitorService kreditorService;
|
||||
|
||||
/**
|
||||
* Prüft ob der Steuerbetrag abgerechnet ist.
|
||||
*
|
||||
*
|
||||
**/
|
||||
@Override
|
||||
public ItemCollection run(ItemCollection workitem, ItemCollection event) throws PluginException {
|
||||
|
||||
// Update Fälligkeit
|
||||
updateFaelligkeit(workitem);
|
||||
|
||||
// Update Salden
|
||||
updateTotalEustZoll(workitem);
|
||||
updateInvoiceSaldo(workitem);
|
||||
|
||||
return 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");
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
|
||||
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());
|
||||
|
||||
// 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));
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,724 +0,0 @@
|
|||
/*******************************************************************************
|
||||
* Imixs Workflow
|
||||
* Copyright (C) 2001, 2011 Imixs Software Solutions GmbH,
|
||||
* http://www.imixs.com
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You can receive a copy of the GNU General Public
|
||||
* License at http://www.gnu.org/licenses/gpl.html
|
||||
*
|
||||
* Project:
|
||||
* http://www.imixs.org
|
||||
* http://java.net/projects/imixs-workflow
|
||||
*
|
||||
* Contributors:
|
||||
* Imixs Software Solutions GmbH - initial API and implementation
|
||||
* Ralph Soika - Software Developer
|
||||
*******************************************************************************/
|
||||
|
||||
package com.alexanderlogistics.api;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.Serializable;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.TimeZone;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import javax.xml.xpath.XPath;
|
||||
import javax.xml.xpath.XPathConstants;
|
||||
import javax.xml.xpath.XPathExpression;
|
||||
import javax.xml.xpath.XPathExpressionException;
|
||||
import javax.xml.xpath.XPathFactory;
|
||||
|
||||
import org.imixs.marty.team.TeamService;
|
||||
import org.imixs.workflow.FileData;
|
||||
import org.imixs.workflow.ItemCollection;
|
||||
import org.imixs.workflow.engine.DocumentService;
|
||||
import org.imixs.workflow.engine.WorkflowService;
|
||||
import org.imixs.workflow.exceptions.AccessDeniedException;
|
||||
import org.imixs.workflow.exceptions.ModelException;
|
||||
import org.imixs.workflow.exceptions.PluginException;
|
||||
import org.imixs.workflow.exceptions.ProcessingErrorException;
|
||||
import org.imixs.workflow.exceptions.QueryException;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Node;
|
||||
import org.xml.sax.InputSource;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
import com.alexanderlogistics.InvoiceUtil;
|
||||
import com.alexanderlogistics.mahnlauf.MahnlaufService;
|
||||
import com.alexanderlogistics.xml.CargosoftXMLInvoiceImportService;
|
||||
|
||||
import jakarta.ejb.Stateless;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.ws.rs.GET;
|
||||
import jakarta.ws.rs.Path;
|
||||
import jakarta.ws.rs.PathParam;
|
||||
import jakarta.ws.rs.Produces;
|
||||
import jakarta.ws.rs.core.MediaType;
|
||||
|
||||
/**
|
||||
** Dieser Service korrigiert falsch importierte Cargosoft daten.
|
||||
* Ausgangsrechnungen die ein falsches Jahr haben.
|
||||
*
|
||||
* Oder DAten die über die XML Schnittstelle falsch reinkamen...
|
||||
*
|
||||
* @author rsoika
|
||||
* @version 1.1
|
||||
*/
|
||||
@Stateless
|
||||
@Produces({ MediaType.TEXT_HTML, MediaType.APPLICATION_XHTML_XML, MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON,
|
||||
MediaType.TEXT_XML })
|
||||
@Path("/cargosoft")
|
||||
public class CargosoftMigrationRestService implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
String log = "";
|
||||
int errors = 0;
|
||||
int count = 0;
|
||||
public static String _QUERY = "($modelversion:rechnungsausgang-de-1.0)\n" +
|
||||
"AND $created:[20240604 TO 20240701]";
|
||||
// public static String _QUERY = "($modelversion:rechnungsausgang-dwc-1.0)\n" +
|
||||
// //
|
||||
// "AND $created:[20240604 TO 20240619]";
|
||||
|
||||
@Inject
|
||||
DocumentService documentService;
|
||||
|
||||
@Inject
|
||||
WorkflowService workflowService;
|
||||
|
||||
@Inject
|
||||
MahnlaufService mahnlaufService;
|
||||
|
||||
@Inject
|
||||
TeamService teamService;
|
||||
|
||||
private static Logger logger = Logger.getLogger(CargosoftMigrationRestService.class.getName());
|
||||
|
||||
public CargosoftMigrationRestService() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Dieser Endpunkt akutalisiert alle ausgehenden noch offenen Rechnungen in
|
||||
* Bezug auf die Abteilungszugehörigkeit.
|
||||
*
|
||||
*
|
||||
* @return
|
||||
* @throws QueryException
|
||||
* @throws AccessDeniedException
|
||||
* @throws ProcessingErrorException
|
||||
* @throws PluginException
|
||||
* @throws ModelException
|
||||
*/
|
||||
@GET
|
||||
@Path("/invoices/fix/spaces")
|
||||
@Produces({ MediaType.TEXT_PLAIN })
|
||||
public String updateInvoiceSpacesAssignment()
|
||||
throws QueryException, AccessDeniedException, ProcessingErrorException, PluginException, ModelException {
|
||||
count = 0;
|
||||
String query = "($modelversion:rechnungsausgang-de-1.0) AND (type:workitem)";
|
||||
// "AND $taskid:[20240604 TO 20240701]";
|
||||
logger.info("query=" + query);
|
||||
log = "Update Space Assignment in Outgoing Invoices\n\n" + query;
|
||||
|
||||
List<ItemCollection> result = documentService.find(query, 9999, 0);
|
||||
log = log + " " + new Date() + "\n\n";
|
||||
log = log + "\n\nFound " + result.size() + " open invoices.";
|
||||
|
||||
// load spaces Pos Expressions
|
||||
Map<String, List<String>> spacePosMappings = mahnlaufService.loadSpacePosMappings();
|
||||
|
||||
for (ItemCollection invoice : result) {
|
||||
|
||||
String oldSpaceRef = invoice.getItemValueString("space.ref");
|
||||
mahnlaufService.mapInvoiceTextToSpace(invoice, spacePosMappings);
|
||||
String newSpaceRef = invoice.getItemValueString("space.ref");
|
||||
if (newSpaceRef.isEmpty()) {
|
||||
// wir dürfen die space.ref nicht löschen!
|
||||
continue;
|
||||
}
|
||||
// change?
|
||||
if (!oldSpaceRef.equals(newSpaceRef)) {
|
||||
count++;
|
||||
logger.info("...fix invoice: " + invoice.getUniqueID());
|
||||
// lookup space
|
||||
ItemCollection space = documentService.load(newSpaceRef);
|
||||
invoice.setItemValue("space.name", space.getItemValueString("name"));
|
||||
invoice.setItemValue("migration.space.ref", oldSpaceRef);
|
||||
documentService.save(invoice);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
log = log + "\n\n=== Completed! " + count + " fixes! ===\n\n";
|
||||
return log;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dieser Endpunkt akutalisiert alle ausgehenden noch offenen Rechnungen in
|
||||
* Bezug auf die Abteilungszugehörigkeit.
|
||||
*
|
||||
*
|
||||
* @return
|
||||
* @throws QueryException
|
||||
* @throws AccessDeniedException
|
||||
* @throws ProcessingErrorException
|
||||
* @throws PluginException
|
||||
* @throws ModelException
|
||||
*/
|
||||
@GET
|
||||
@Path("/invoices/fix/index/{page}")
|
||||
@Produces({ MediaType.TEXT_PLAIN })
|
||||
public String updateInvoiceIndex(@PathParam("page") int page)
|
||||
throws QueryException, AccessDeniedException, ProcessingErrorException, PluginException, ModelException {
|
||||
count = 0;
|
||||
String query = "($modelversion:rechnungsausgang-de-1.0) AND (type:workitem)";
|
||||
|
||||
logger.info("query=" + query);
|
||||
log = "Update index Invoices\n\n" + query;
|
||||
|
||||
List<ItemCollection> result = documentService.find(query, 100, page);
|
||||
log = log + " " + new Date() + "\n\n";
|
||||
log = log + " size= 500 page=" + page + "\n\n";
|
||||
log = log + "\n\nFound " + result.size() + " open invoices.";
|
||||
|
||||
logger.info("Found " + result.size() + " open invoices.");
|
||||
for (ItemCollection invoice : result) {
|
||||
|
||||
documentService.save(invoice);
|
||||
|
||||
count++;
|
||||
logger.info("... update index " + invoice.getUniqueID());
|
||||
|
||||
}
|
||||
|
||||
log = log + "\n\n=== Completed! " + count + " fixes! ===\n\n";
|
||||
return log;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dieser Endpunkt akutalisiert alle ausgehenden noch offenen Rechnungen in
|
||||
* Bezug auf die Abteilungszugehörigkeit.
|
||||
*
|
||||
*
|
||||
* @return
|
||||
* @throws QueryException
|
||||
* @throws AccessDeniedException
|
||||
* @throws ProcessingErrorException
|
||||
* @throws PluginException
|
||||
* @throws ModelException
|
||||
*/
|
||||
@GET
|
||||
@Path("/steuerbescheide/fix/spaces")
|
||||
@Produces({ MediaType.TEXT_PLAIN })
|
||||
public String updateSteuerbescheideSpacesAssignment()
|
||||
throws QueryException, AccessDeniedException, ProcessingErrorException, PluginException, ModelException {
|
||||
count = 0;
|
||||
String query = "($modelversion:steuerbescheid-de-1.0) AND (type:workitem)";
|
||||
// "AND $taskid:[20240604 TO 20240701]";
|
||||
logger.info("query=" + query);
|
||||
log = "Update Space Assignment in Steuerbescheide\n\n" + query;
|
||||
|
||||
List<ItemCollection> result = documentService.find(query, 9999, 0);
|
||||
|
||||
log = log + " " + new Date() + "\n\n";
|
||||
log = log + "\n\nFound " + result.size() + " open steuerbescheide.";
|
||||
|
||||
// load spaces Pos Expressions
|
||||
Map<String, List<String>> spacePosMappings = mahnlaufService.loadSpacePosMappings();
|
||||
|
||||
for (ItemCollection invoice : result) {
|
||||
|
||||
String oldSpaceRef = invoice.getItemValueString("space.ref");
|
||||
mahnlaufService.mapInvoiceTextToSpace(invoice, spacePosMappings);
|
||||
String newSpaceRef = invoice.getItemValueString("space.ref");
|
||||
if (newSpaceRef.isEmpty()) {
|
||||
// wir dürfen die space.ref nicht löschen!
|
||||
continue;
|
||||
}
|
||||
// change?
|
||||
if (!oldSpaceRef.equals(newSpaceRef)) {
|
||||
count++;
|
||||
logger.info("...fix invoice: " + invoice.getUniqueID());
|
||||
// lookup space
|
||||
ItemCollection space = documentService.load(newSpaceRef);
|
||||
invoice.setItemValue("space.name", space.getItemValueString("name"));
|
||||
invoice.setItemValue("migration.space.ref", oldSpaceRef);
|
||||
documentService.save(invoice);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
log = log + "\n\n=== Completed! " + count + " fixes! ===\n\n";
|
||||
return log;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method loads taxonomy data for a workflow group within a given process
|
||||
* and builds a ChartJS data structure in JSON format
|
||||
*
|
||||
* @param workflowgroup
|
||||
* @param task
|
||||
* @return
|
||||
* @throws QueryException
|
||||
*/
|
||||
@GET
|
||||
@Path("/test")
|
||||
@Produces({ MediaType.TEXT_PLAIN })
|
||||
public String testeFehlerhafteCargosoftDaten() throws QueryException {
|
||||
int falsch = 0;
|
||||
logger.info("query=" + _QUERY);
|
||||
log = "Query\n" + _QUERY;
|
||||
List<ItemCollection> result = documentService.find(_QUERY, 9999, 0);
|
||||
|
||||
log = log + "\n\nCount=" + result.size();
|
||||
|
||||
if (result.size() > 9999) {
|
||||
log = log + "\n\nACHTUNG ES GIBT MEHR ALS 10000 RECHNUNGEN !";
|
||||
}
|
||||
|
||||
for (ItemCollection workitem : result) {
|
||||
String type = workitem.getItemValueString("invoice.type");
|
||||
if ("G".equals(type) || "SR".equals(type)) {
|
||||
double total = workitem.getItemValueDouble("invoice.saldo");
|
||||
if (total >= 0) {
|
||||
logger.info("---Falsch: " + workitem.getUniqueID());
|
||||
falsch++;
|
||||
workitem.setItemValue("invoice.saldo", -total);
|
||||
// documentService.save(workitem);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
log = log + "\n\n";
|
||||
log = log + "" + result.size() + " rechnungen geprüft";
|
||||
log = log + "" + falsch + " davon falsch";
|
||||
log = log + "\n\n";
|
||||
return log;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method fixes the wrong amount of a imported xml invoice.
|
||||
*
|
||||
* @param workflowgroup
|
||||
* @param task
|
||||
* @return
|
||||
* @throws QueryException
|
||||
* @throws ModelException
|
||||
* @throws PluginException
|
||||
* @throws ProcessingErrorException
|
||||
* @throws AccessDeniedException
|
||||
*/
|
||||
public String fixMissingDueDate()
|
||||
throws QueryException, AccessDeniedException, ProcessingErrorException, PluginException, ModelException {
|
||||
|
||||
logger.info("query=" + _QUERY);
|
||||
log = "Query\n\n" + _QUERY;
|
||||
|
||||
List<ItemCollection> result = documentService.find(_QUERY, 9999, 0);
|
||||
|
||||
log = log + "\n\nSelection Count=" + result.size();
|
||||
|
||||
log = log + "\n\nFixes\n\n";
|
||||
|
||||
for (ItemCollection workitem : result) {
|
||||
|
||||
if (!workitem.hasItem("invoice.reminder")) {
|
||||
Date dueDate = workitem.getItemValueDate("invoice.duedate");
|
||||
workitem.setItemValue("invoice.reminder", dueDate);
|
||||
count++;
|
||||
// save only
|
||||
documentService.save(workitem);
|
||||
}
|
||||
}
|
||||
|
||||
log = log + "\n\n=== Completed! " + count + " fixes! ===\n\n";
|
||||
return log;
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("/fix")
|
||||
@Produces({ MediaType.TEXT_PLAIN })
|
||||
public String fixMissingRate()
|
||||
throws QueryException, AccessDeniedException, ProcessingErrorException, PluginException, ModelException {
|
||||
|
||||
logger.info("query=" + _QUERY);
|
||||
log = "Query\n\n" + _QUERY;
|
||||
|
||||
List<ItemCollection> result = documentService.find(_QUERY, 9999, 0);
|
||||
|
||||
log = log + "\n\nSelection Count=" + result.size();
|
||||
|
||||
log = log + "\n\nFixes\n\n";
|
||||
|
||||
for (ItemCollection workitem : result) {
|
||||
|
||||
if (!workitem.hasItem("invoice.rate")) {
|
||||
// Fetch frist datev.kurs von _childitems
|
||||
|
||||
List<ItemCollection> childs = InvoiceUtil.explodeChildList(workitem);
|
||||
if (childs != null && childs.size() > 0) {
|
||||
ItemCollection child = childs.get(0);
|
||||
double rate = child.getItemValueDouble("datev.kurs");
|
||||
logger.info("..fix missing rate = " + rate);
|
||||
workitem.setItemValue("invoice.rate", rate);
|
||||
// save only
|
||||
documentService.save(workitem);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
log = log + "\n\n=== Completed! " + count + " fixes! ===\n\n";
|
||||
return log;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dieser agent prüft die Rechnungen der letzten 2 Wochen auf einen Billingtext
|
||||
* der mit "24DE" beginnt und übernimmt dann diesen Text als neue ATC number
|
||||
*
|
||||
* @return
|
||||
* @throws QueryException
|
||||
* @throws AccessDeniedException
|
||||
* @throws ProcessingErrorException
|
||||
* @throws PluginException
|
||||
* @throws ModelException
|
||||
*/
|
||||
@GET
|
||||
@Path("/fix-atc")
|
||||
@Produces({ MediaType.TEXT_PLAIN })
|
||||
public String fixATCNumber()
|
||||
throws QueryException, AccessDeniedException, ProcessingErrorException, PluginException, ModelException {
|
||||
String query = "($modelversion:rechnungsausgang-de-1.0) " +
|
||||
"AND $created:[20241001 TO 20241201]";
|
||||
logger.info("query=" + query);
|
||||
log = "Query\n\n" + query;
|
||||
|
||||
List<ItemCollection> result = documentService.find(query, 9999, 0);
|
||||
|
||||
log = log + "\n\nSelection Count=" + result.size();
|
||||
log = log + "\n\nFixes:\n\n";
|
||||
|
||||
for (ItemCollection workitem : result) {
|
||||
logger.info("verify: " + workitem.getUniqueID());
|
||||
|
||||
if (!workitem.hasItem("invoice.atc.number")) {
|
||||
// Fetch _childitems and check billingText
|
||||
List<ItemCollection> childs = InvoiceUtil.explodeChildList(workitem);
|
||||
for (ItemCollection child : childs) {
|
||||
List<String> billingTexts = child.getItemValueList("billingtext", String.class);
|
||||
boolean contains24DE = false;
|
||||
String atcNumber = "";
|
||||
for (String str : billingTexts) {
|
||||
if (str.startsWith("24DE")) {
|
||||
contains24DE = true;
|
||||
atcNumber = str;
|
||||
logger.info(" found in " + workitem.getUniqueID());
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (contains24DE) {
|
||||
count++;
|
||||
workitem.setItemValue("invoice.atc.number", atcNumber);
|
||||
// save only
|
||||
logger.info(" update: " + workitem.getUniqueID());
|
||||
log = log + "\n - " + workitem.getUniqueID();
|
||||
documentService.save(workitem);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
log = log + "\n\n=== Completed! " + count + " fixes! ===\n\n";
|
||||
return log;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dieser agent prüft die Rechnungen der letzten 2 Wochen auf einen Billingtext
|
||||
* der mit "24DE" beginnt und übernimmt dann diesen Text als neue ATC number
|
||||
*
|
||||
* @return
|
||||
* @throws QueryException
|
||||
* @throws AccessDeniedException
|
||||
* @throws ProcessingErrorException
|
||||
* @throws PluginException
|
||||
* @throws ModelException
|
||||
*/
|
||||
@GET
|
||||
@Path("/fix-atc2")
|
||||
@Produces({ MediaType.TEXT_PLAIN })
|
||||
public String fixATCNumber2()
|
||||
throws QueryException, AccessDeniedException, ProcessingErrorException, PluginException, ModelException {
|
||||
String query = "($modelversion:rechnungsausgang-de-1.0) " +
|
||||
"AND $created:[20241001 TO 20241201]";
|
||||
logger.info("query=" + query);
|
||||
log = "Query\n\n" + query;
|
||||
|
||||
List<ItemCollection> result = documentService.find(query, 9999, 0);
|
||||
|
||||
log = log + "\n\nSelection Count=" + result.size();
|
||||
log = log + "\n\nFixes:\n\n";
|
||||
|
||||
for (ItemCollection workitem : result) {
|
||||
logger.info("verify: " + workitem.getUniqueID());
|
||||
|
||||
if (workitem.hasItem("invoice.atc.number")) {
|
||||
// Fetch _childitems and check billingText
|
||||
List<ItemCollection> childs = InvoiceUtil.explodeChildList(workitem);
|
||||
for (ItemCollection child : childs) {
|
||||
List<String> billingTexts = child.getItemValueList("billingtext", String.class);
|
||||
boolean contains24DE = false;
|
||||
String atcNumber = "";
|
||||
for (String str : billingTexts) {
|
||||
if (str.startsWith("24DE")) {
|
||||
contains24DE = true;
|
||||
atcNumber = str;
|
||||
logger.info(" found in " + workitem.getUniqueID());
|
||||
child.setItemValue("atc.number", atcNumber);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (contains24DE) {
|
||||
count++;
|
||||
|
||||
InvoiceUtil.implodeChildList(workitem, childs);
|
||||
// save only
|
||||
logger.info(" update: " + workitem.getUniqueID());
|
||||
log = log + "\n - " + workitem.getUniqueID();
|
||||
documentService.save(workitem);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
log = log + "\n\n=== Completed! " + count + " fixes! ===\n\n";
|
||||
return log;
|
||||
}
|
||||
|
||||
public String fixFehlerhafteCargosoftDatenMitSnapshot()
|
||||
throws QueryException, AccessDeniedException, ProcessingErrorException, PluginException, ModelException {
|
||||
|
||||
logger.info("query=" + _QUERY);
|
||||
log = "Query\n\n" + _QUERY;
|
||||
|
||||
List<ItemCollection> result = documentService.find(_QUERY, 9999, 0);
|
||||
|
||||
log = log + "\n\nSelection Count=" + result.size();
|
||||
|
||||
log = log + "\n\nFixes\n\n";
|
||||
|
||||
for (ItemCollection workitem : result) {
|
||||
ItemCollection snapshot = null;
|
||||
// load snapshot
|
||||
String snapshotID = workitem.getItemValueString("$snapshotid");
|
||||
if (!snapshotID.isEmpty()) {
|
||||
snapshot = documentService.load(snapshotID);
|
||||
}
|
||||
|
||||
if (snapshot == null) {
|
||||
logger.warning("Unable to load snapshot for document " + workitem.getUniqueID());
|
||||
log = log + "Unable to load snapshot for document " + workitem.getUniqueID() + " \n";
|
||||
errors++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get raw data....
|
||||
// find the XML Attachment
|
||||
String xmlFileName = null;
|
||||
List<String> fileNames = snapshot.getFileNames();
|
||||
for (String fileName : fileNames) {
|
||||
if (fileName.endsWith(".xml")) {
|
||||
xmlFileName = fileName;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (xmlFileName == null) {
|
||||
logger.warning("Unable to load XML from document " + workitem.getUniqueID());
|
||||
log = log + "Unable to load XML from document " + workitem.getUniqueID() + " \n";
|
||||
errors++;
|
||||
continue;
|
||||
}
|
||||
|
||||
FileData xmlFileData = snapshot.getFileData(xmlFileName);
|
||||
Document xmlDoc = createXMLTree(xmlFileData.getContent());
|
||||
|
||||
migrateDocument(workitem, xmlDoc);
|
||||
}
|
||||
|
||||
log = log + "\n\n=== Completed! " + count + " fixes! ===\n\n";
|
||||
return log;
|
||||
}
|
||||
|
||||
/**
|
||||
* Diese Methode korrigiert den Saldo um die Netto summe....
|
||||
*
|
||||
* @param workitem
|
||||
* @param xmlDoc
|
||||
* @throws ModelException
|
||||
* @throws PluginException
|
||||
* @throws ProcessingErrorException
|
||||
* @throws AccessDeniedException
|
||||
*/
|
||||
private void migrateDocument(ItemCollection workitem, Document doc)
|
||||
throws AccessDeniedException, ProcessingErrorException, PluginException, ModelException {
|
||||
|
||||
// Haben wir schon das neue Feld 'invoice.total.net' mit dem Netto Betrag?
|
||||
if (workitem.hasItem("invoice.total.tax")) {
|
||||
// no migration needed
|
||||
return;
|
||||
}
|
||||
|
||||
// Net und Tax ermitteln
|
||||
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);
|
||||
|
||||
// Der Total entspricht nun dem Net Amount.
|
||||
// Wenn wir eine Tax haben, dann müssen wir den Total sowie den Saldo um
|
||||
// diese Tax erhöhen.
|
||||
// Damit ist dann die Migration abgeschlossen.
|
||||
double tax = workitem.getItemValueDouble("invoice.total.tax");
|
||||
if (tax > 0) {
|
||||
log = log + "...Migriere " + workitem.getItemValueString("invoice.number") + " Korrektur Betrag " +
|
||||
tax + "\n";
|
||||
double total = workitem.getItemValueDouble("invoice.total");
|
||||
double saldo = workitem.getItemValueDouble("invoice.saldo");
|
||||
// Gutschrift?
|
||||
if (total < 0) {
|
||||
total = total - tax;
|
||||
saldo = saldo - tax;
|
||||
|
||||
} else {
|
||||
// Rechnung
|
||||
total = total + tax;
|
||||
saldo = saldo + tax;
|
||||
}
|
||||
workitem.setItemValue("invoice.total", total);
|
||||
workitem.setItemValue("invoice.saldo", saldo);
|
||||
workitem.setItemValue("cargosoft.fix.xmlerror", tax);
|
||||
log = log + "....... total neu=" + total + " saldo neu=" + saldo + "\n";
|
||||
|
||||
if (5900 == workitem.getTaskID()) {
|
||||
workitem.setEventID(942);
|
||||
workflowService.processWorkItem(workitem);
|
||||
|
||||
} else {
|
||||
// save only
|
||||
documentService.save(workitem);
|
||||
}
|
||||
count++;
|
||||
} else {
|
||||
log = log + "...Keine Migration notwendig " + workitem.getItemValueString("invoice.number") +
|
||||
" tax=" + tax + "\n";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Erzeugt einen XML Baum aus dem XML Raw Daten
|
||||
*
|
||||
* @param snapshot
|
||||
* @return
|
||||
*/
|
||||
private Document createXMLTree(byte[] rawData) {
|
||||
Document doc = null;
|
||||
InputStream inputStream = new ByteArrayInputStream(rawData);
|
||||
InputSource inputSource = new InputSource(inputStream);
|
||||
|
||||
DocumentBuilder documentBuilder;
|
||||
try {
|
||||
documentBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
|
||||
doc = documentBuilder.parse(inputSource);
|
||||
} catch (ParserConfigurationException | SAXException | IOException e) {
|
||||
log = log + "Unable to load XML tree: " + e.getMessage() + " \n";
|
||||
return null;
|
||||
}
|
||||
|
||||
return doc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a tag value from the xml tree and set the value into the given
|
||||
* workitem.
|
||||
*
|
||||
* /Invoices/Invoice/InvoiceHeader/Client/Code
|
||||
*
|
||||
* Beispiel Datum:
|
||||
* <InvoiceDate>2024-05-13T00:00:00+02:00</InvoiceDate>
|
||||
*
|
||||
* @param doc - xml doc
|
||||
* @param expression - xpath expression
|
||||
* @param workitem
|
||||
* @param itemName
|
||||
* @param itemType
|
||||
*/
|
||||
private <T> void readXMLValue(Document doc, String expression, ItemCollection workitem, String itemName,
|
||||
Class<T> itemType) {
|
||||
// create XPath...
|
||||
XPathFactory xpathFactory = XPathFactory.newInstance();
|
||||
XPath xpath = xpathFactory.newXPath();
|
||||
XPathExpression xPathExpression;
|
||||
try {
|
||||
xPathExpression = xpath.compile(expression);
|
||||
|
||||
// extract node value
|
||||
Node valueNode = (Node) xPathExpression.evaluate(doc, XPathConstants.NODE);
|
||||
if (valueNode != null) {
|
||||
String value = valueNode.getTextContent();
|
||||
|
||||
if (itemType == Date.class) {
|
||||
// 2024-05-13T00:00:00+02:00
|
||||
SimpleDateFormat formatter = new SimpleDateFormat(CargosoftXMLInvoiceImportService.DATE_FORMAT);
|
||||
formatter.setTimeZone(TimeZone.getTimeZone("CET"));
|
||||
try {
|
||||
workitem.setItemValue(itemName, formatter.parse(value));
|
||||
} catch (ParseException e) {
|
||||
logger.warning("Invalid Date Format");
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (itemType == Double.class && value != null && !value.isEmpty()) {
|
||||
workitem.setItemValue(itemName, Double.parseDouble(value));
|
||||
return;
|
||||
}
|
||||
if (itemType == Integer.class && value != null && !value.isEmpty()) {
|
||||
workitem.setItemValue(itemName, Integer.parseInt(value));
|
||||
return;
|
||||
}
|
||||
// Default String format
|
||||
workitem.setItemValue(itemName, value);
|
||||
|
||||
}
|
||||
} catch (XPathExpressionException e) {
|
||||
logger.warning("Unable to read data field '" + expression + "' : " + e.getMessage());
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,179 +0,0 @@
|
|||
package com.alexanderlogistics.mahnlauf;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.imixs.workflow.ItemCollection;
|
||||
import org.imixs.workflow.Model;
|
||||
import org.imixs.workflow.SignalAdapter;
|
||||
import org.imixs.workflow.WorkflowKernel;
|
||||
import org.imixs.workflow.engine.ModelService;
|
||||
import org.imixs.workflow.engine.WorkflowService;
|
||||
import org.imixs.workflow.exceptions.AdapterException;
|
||||
import org.imixs.workflow.exceptions.ModelException;
|
||||
import org.imixs.workflow.exceptions.PluginException;
|
||||
import org.imixs.workflow.exceptions.QueryException;
|
||||
import org.imixs.workflow.sepa.services.SepaWorkflowService;
|
||||
|
||||
import com.alexanderlogistics.KreditorDebitorService;
|
||||
|
||||
import jakarta.ejb.EJB;
|
||||
import jakarta.inject.Inject;
|
||||
|
||||
/**
|
||||
* The MahnlaufRefAddAdapter links an invoice with a Mahnlauf for the
|
||||
* dbtr.number item . If there is currently no open Mahnlauf for this key, the
|
||||
* adapter automatically creates a new process instance. If a mahnlauf for this
|
||||
* dbt.number is found, the invoice is just added.
|
||||
* <p>
|
||||
* If the invoice has already been linked to a Mahnlauf nothing happens.
|
||||
* <p>
|
||||
*
|
||||
* @version 1.0
|
||||
* @author rsoika
|
||||
*/
|
||||
public class MahnlaufRefAddAdapter implements SignalAdapter {
|
||||
|
||||
private static Logger logger = Logger.getLogger(MahnlaufRefAddAdapter.class.getName());
|
||||
|
||||
@EJB
|
||||
ModelService modelService;
|
||||
|
||||
@EJB
|
||||
KreditorDebitorService kreditorDebitorService;
|
||||
|
||||
@EJB
|
||||
WorkflowService workflowService = null;
|
||||
|
||||
@Inject
|
||||
SepaWorkflowService sepaWorkflowService;
|
||||
|
||||
/**
|
||||
* 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.");
|
||||
}
|
||||
|
||||
String dbtrNumber = invoice.getItemValueString(MahnlaufService.ITEM_DBTR_NUMBER);
|
||||
ItemCollection mahnLaufWorkitem;
|
||||
try {
|
||||
mahnLaufWorkitem = findMahnlauf(dbtrNumber);
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
// set event 100 and process
|
||||
ItemCollection mahnlaufConfig = workflowService.evalWorkflowResult(event, "mahnlauf", invoice, true);
|
||||
int eventID = mahnlaufConfig.getItemValueInteger("event");
|
||||
|
||||
mahnLaufWorkitem.event(eventID);
|
||||
workflowService.processWorkItem(mahnLaufWorkitem);
|
||||
|
||||
} 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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());
|
||||
|
||||
// copy dbtr_iban
|
||||
mahnlaufWorkitem.setItemValue(MahnlaufService.ITEM_DBTR_NAME,
|
||||
invoice.getItemValue(MahnlaufService.ITEM_DBTR_NAME));
|
||||
|
||||
// lookup email....
|
||||
String dbtrNumber = invoice.getItemValueString("dbtr.number");
|
||||
ItemCollection dbtrItemCol = kreditorDebitorService.findDebitor("D" + dbtrNumber);
|
||||
if (dbtrItemCol != null) {
|
||||
mahnlaufWorkitem.setItemValue(MahnlaufService.ITEM_DBTR_EMAIL, dbtrItemCol.getItemValue("cdtr.mail"));// dbtr.mail
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
logger.info("...created new mahnlauf " + key + "...");
|
||||
|
||||
return mahnlaufWorkitem;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,186 +0,0 @@
|
|||
package org.imixs.workflow.office.forms;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.imixs.workflow.ItemCollection;
|
||||
import org.imixs.workflow.faces.data.WorkflowController;
|
||||
|
||||
import jakarta.enterprise.context.ConversationScoped;
|
||||
import jakarta.enterprise.event.Event;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.inject.Named;
|
||||
|
||||
/**
|
||||
* The AnalyticController is a conversationScoped controller that provides
|
||||
* values for the analytic-custom parts.
|
||||
* <p>
|
||||
* A custom implementation can react on AnalyticEvent to compute values and
|
||||
* datasets.
|
||||
* <p>
|
||||
* The controller implements a caching mechanism to avoid repeated calls for new
|
||||
* analytic values. If the analytic value is already stored in the current
|
||||
* workitem, no new value will be fired.
|
||||
*
|
||||
*
|
||||
* @author rsoika
|
||||
*
|
||||
*/
|
||||
@Named
|
||||
@ConversationScoped
|
||||
public class AnalyticController implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static Logger logger = Logger.getLogger(AnalyticController.class.getName());
|
||||
|
||||
@Inject
|
||||
protected Event<AnalyticEvent> analyticEvents;
|
||||
|
||||
@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 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 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 description for a given key
|
||||
*
|
||||
* @param key
|
||||
* @return
|
||||
*/
|
||||
public String getDescription(String key) {
|
||||
ItemCollection analyticData = computeValue(key);
|
||||
return analyticData.getItemValueString("description");
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes am analytic value. The method cache the value in the item
|
||||
* 'analytic.KEY' to avoid feierring repeated AnalyticEvents.
|
||||
*
|
||||
* @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());
|
||||
implodeDetails(key, details);
|
||||
}
|
||||
}
|
||||
|
||||
// try loading from cache
|
||||
ItemCollection details = explodeDetails(key);
|
||||
if (details == null) {
|
||||
// set dummy value
|
||||
details = new ItemCollection();
|
||||
details.setItemValue("value", "");
|
||||
details.setItemValue("label", "");
|
||||
details.setItemValue("description", "No data available");
|
||||
implodeDetails(key, details);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
return new ItemCollection();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,66 +0,0 @@
|
|||
package org.imixs.workflow.office.forms;
|
||||
|
||||
import org.imixs.workflow.ItemCollection;
|
||||
|
||||
/**
|
||||
* An AnalyticEvent is send by the AnalyticController during initialization
|
||||
*/
|
||||
public class AnalyticEvent {
|
||||
|
||||
private String key;
|
||||
private Object value = null;
|
||||
private String label = "";
|
||||
private String description = "";
|
||||
private String link = "";
|
||||
private ItemCollection workitem = null;
|
||||
|
||||
public AnalyticEvent(String key, ItemCollection workitem) {
|
||||
this.key = key;
|
||||
this.workitem = workitem;
|
||||
}
|
||||
|
||||
public String getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
public void setKey(String key) {
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
public String getLink() {
|
||||
return link;
|
||||
}
|
||||
|
||||
public void setLink(String link) {
|
||||
this.link = link;
|
||||
}
|
||||
|
||||
public ItemCollection getWorkitem() {
|
||||
return workitem;
|
||||
}
|
||||
|
||||
public Object getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public void setValue(Object value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public String getLabel() {
|
||||
return label;
|
||||
}
|
||||
|
||||
public void setLabel(String label) {
|
||||
this.label = label;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue