FEA: finished approve method in event_billig. Finished event billing module

This commit is contained in:
Keanu D?lle 2022-03-08 12:48:32 +01:00
parent 709dd54052
commit f72dab60a9
23 changed files with 783 additions and 172 deletions

491
Cargo.lock generated
View File

@ -56,6 +56,12 @@ dependencies = [
"opaque-debug 0.3.0",
]
[[package]]
name = "ahash"
version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "739f4a8db6605981345c5654f3a85b056ce52f37a39d34da03f25bf2151ea16e"
[[package]]
name = "aho-corasick"
version = "0.7.18"
@ -73,9 +79,9 @@ checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544"
[[package]]
name = "arrayvec"
version = "0.5.2"
version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b"
checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6"
[[package]]
name = "async-stream"
@ -147,6 +153,17 @@ version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd"
[[package]]
name = "bigdecimal"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1374191e2dd25f9ae02e3aa95041ed5d747fc77b3c102b49fe2dd9a8117a6244"
dependencies = [
"num-bigint",
"num-integer",
"num-traits",
]
[[package]]
name = "binascii"
version = "0.1.4"
@ -161,9 +178,9 @@ checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
[[package]]
name = "blake2b_simd"
version = "0.5.11"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "afa748e348ad3be8263be728124b24a24f268266f6f5d58af9d75f6a40b5c587"
checksum = "72936ee4afc7f8f736d1c38383b56480b5497b4617b4a77bdbf1d2ababc76127"
dependencies = [
"arrayref",
"arrayvec",
@ -250,8 +267,8 @@ checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73"
dependencies = [
"libc",
"num-integer",
"num-traits 0.2.14",
"serde 1.0.125",
"num-traits",
"serde",
"time 0.1.43",
"winapi 0.3.9",
]
@ -289,15 +306,18 @@ dependencies = [
[[package]]
name = "config"
version = "0.11.0"
version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b1b9d958c2b1368a663f05538fc1b5975adce1e19f435acceae987aceeeb369"
checksum = "54ad70579325f1a38ea4c13412b82241c5900700a69785d73e2736bd65a33f86"
dependencies = [
"async-trait",
"json5",
"lazy_static",
"nom",
"pathdiff",
"ron",
"rust-ini",
"serde 1.0.125",
"serde-hjson",
"serde",
"serde_json",
"toml",
"yaml-rust",
@ -348,6 +368,22 @@ dependencies = [
"version_check",
]
[[package]]
name = "core-foundation"
version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146"
dependencies = [
"core-foundation-sys",
"libc",
]
[[package]]
name = "core-foundation-sys"
version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc"
[[package]]
name = "cpufeatures"
version = "0.1.4"
@ -440,14 +476,18 @@ dependencies = [
[[package]]
name = "diesel"
version = "1.4.6"
version = "1.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "047bfc4d5c3bd2ef6ca6f981941046113524b9a9f9a7cbdfdd7ff40f58e6f542"
checksum = "b28135ecf6b7d446b43e27e225622a038cc4e2930a1022f51cdb97ada19b8e4d"
dependencies = [
"bigdecimal",
"bitflags",
"byteorder",
"chrono",
"diesel_derives",
"num-bigint",
"num-integer",
"num-traits",
"pq-sys",
"serde_json",
"uuid",
@ -498,6 +538,15 @@ version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0"
[[package]]
name = "dlv-list"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68df3f2b690c1b86e65ef7830956aededf3cb0a16f898f79b9a6f421a7b6211b"
dependencies = [
"rand",
]
[[package]]
name = "either"
version = "1.6.1"
@ -528,9 +577,9 @@ dependencies = [
[[package]]
name = "env_logger"
version = "0.8.3"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "17392a012ea30ef05a610aa97dfb49496e71c9f676b27879922ea5bdf60d9d3f"
checksum = "0b2cf0344971ee6c64c31be0d530793fba457d322dfec2810c453d0ef228f9c3"
dependencies = [
"atty",
"humantime",
@ -544,6 +593,7 @@ name = "errms"
version = "0.2.0"
dependencies = [
"base64",
"bigdecimal",
"chrono",
"chrono-tz",
"config",
@ -552,12 +602,13 @@ dependencies = [
"email-address-parser",
"env_logger",
"iban_validate",
"lettre",
"log",
"rand",
"rocket",
"rocket_dyn_templates",
"rust-argon2",
"serde 1.0.125",
"serde",
"serde_derive",
"serde_json",
"uuid",
@ -569,6 +620,15 @@ version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed"
[[package]]
name = "fastrand"
version = "1.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3fcf0cee53519c866c09b5de1f6c56ff9d647101f81c1964fa632e148896cdf"
dependencies = [
"instant",
]
[[package]]
name = "figment"
version = "0.10.5"
@ -577,7 +637,7 @@ checksum = "0ca029e813a72b7526d28273d25f3e4a2f365d1b7a1018a6f93ec9053a119763"
dependencies = [
"atomic",
"pear",
"serde 1.0.125",
"serde",
"toml",
"uncased",
"version_check",
@ -601,6 +661,21 @@ version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
[[package]]
name = "foreign-types"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
dependencies = [
"foreign-types-shared",
]
[[package]]
name = "foreign-types-shared"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
[[package]]
name = "fsevent"
version = "0.4.0"
@ -818,7 +893,7 @@ dependencies = [
"pest",
"pest_derive",
"quick-error",
"serde 1.0.125",
"serde",
"serde_json",
]
@ -827,6 +902,9 @@ name = "hashbrown"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04"
dependencies = [
"ahash",
]
[[package]]
name = "hermit-abi"
@ -857,6 +935,17 @@ dependencies = [
"digest 0.9.0",
]
[[package]]
name = "hostname"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c731c3e10504cc8ed35cfe2f1db4c9274c3d35fa486e3b31df46f068ef3e867"
dependencies = [
"libc",
"match_cfg",
"winapi 0.3.9",
]
[[package]]
name = "http"
version = "0.2.4"
@ -865,7 +954,7 @@ checksum = "527e8c9ac747e28542699a951517aa9a6945af506cd1f2e1b53a576c17b6cc11"
dependencies = [
"bytes",
"fnv",
"itoa",
"itoa 0.4.7",
]
[[package]]
@ -912,7 +1001,7 @@ dependencies = [
"http-body",
"httparse",
"httpdate",
"itoa",
"itoa 0.4.7",
"pin-project-lite",
"socket2",
"tokio",
@ -923,13 +1012,24 @@ dependencies = [
[[package]]
name = "iban_validate"
version = "4.0.0"
version = "4.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae1dbb2046534ff3eda29fa47148f3e28011cbaf063dd5893edf89f47c3fe115"
checksum = "cc1d358f7ae89819e8656f1b495c9d760a9ca315998b12d589dc516c9f81ed08"
dependencies = [
"arrayvec",
]
[[package]]
name = "idna"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8"
dependencies = [
"matches",
"unicode-bidi",
"unicode-normalization",
]
[[package]]
name = "indexmap"
version = "1.6.2"
@ -938,7 +1038,7 @@ checksum = "824845a0bf897a9042383849b02c1bc219c2383772efcd5c6f9766fa4b81aef3"
dependencies = [
"autocfg",
"hashbrown",
"serde 1.0.125",
"serde",
]
[[package]]
@ -991,6 +1091,23 @@ version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736"
[[package]]
name = "itoa"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35"
[[package]]
name = "json5"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96b0db21af676c1ce64250b5f40f3ce2cf27e4e47cb91ed91eb6fe9350b430c1"
dependencies = [
"pest",
"pest_derive",
"serde",
]
[[package]]
name = "kernel32-sys"
version = "0.2.2"
@ -1014,23 +1131,34 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
[[package]]
name = "lexical-core"
version = "0.7.6"
name = "lettre"
version = "0.10.0-rc.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6607c62aa161d23d17a9072cc5da0be67cdfc89d3afb1e8d9c842bebc2525ffe"
checksum = "71d8da8f34d086b081c9cc3b57d3bb3b51d16fc06b5c848a188e2f14d58ac2a5"
dependencies = [
"arrayvec",
"bitflags",
"cfg-if 1.0.0",
"ryu",
"static_assertions",
"async-trait",
"base64",
"fastrand",
"futures-io",
"futures-util",
"hostname",
"httpdate",
"idna",
"mime",
"native-tls",
"nom",
"once_cell",
"quoted_printable",
"regex",
"tokio",
"tokio-native-tls",
]
[[package]]
name = "libc"
version = "0.2.94"
version = "0.2.119"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "18794a8ad5b29321f790b55d93dfba91e125cb1a9edbd4f8e3150acc771c1a5e"
checksum = "1bf2e165bb3457c8e098ea76f3e3bc9db55f87aa90d52d0e6be741470916aaa4"
[[package]]
name = "linked-hash-map"
@ -1065,7 +1193,7 @@ dependencies = [
"cfg-if 1.0.0",
"generator",
"scoped-tls",
"serde 1.0.125",
"serde",
"serde_json",
]
@ -1075,6 +1203,18 @@ version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d"
[[package]]
name = "match_cfg"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4"
[[package]]
name = "matches"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f"
[[package]]
name = "memchr"
version = "2.4.0"
@ -1087,6 +1227,12 @@ version = "0.3.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d"
[[package]]
name = "minimal-lexical"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
[[package]]
name = "mio"
version = "0.6.23"
@ -1173,6 +1319,24 @@ dependencies = [
"version_check",
]
[[package]]
name = "native-tls"
version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "48ba9f7719b5a0f42f338907614285fb5fd70e53858141f69898a1fb7203b24d"
dependencies = [
"lazy_static",
"libc",
"log",
"openssl",
"openssl-probe",
"openssl-sys",
"schannel",
"security-framework",
"security-framework-sys",
"tempfile",
]
[[package]]
name = "net2"
version = "0.2.37"
@ -1186,12 +1350,12 @@ dependencies = [
[[package]]
name = "nom"
version = "5.1.2"
version = "7.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ffb4262d26ed83a1c0a33a38fe2bb15797329c85770da05e6b828ddb782627af"
checksum = "1b1d11e1ef389c76fe5b81bcaf2ea32cf88b62bc494e19f493d0b30e7a930109"
dependencies = [
"lexical-core",
"memchr",
"minimal-lexical",
"version_check",
]
@ -1231,6 +1395,17 @@ dependencies = [
"winapi 0.3.9",
]
[[package]]
name = "num-bigint"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "090c7f9998ee0ff65aa5b723e4009f7b217707f1fb5ea551329cc4d6231fb304"
dependencies = [
"autocfg",
"num-integer",
"num-traits",
]
[[package]]
name = "num-integer"
version = "0.1.44"
@ -1238,16 +1413,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db"
dependencies = [
"autocfg",
"num-traits 0.2.14",
]
[[package]]
name = "num-traits"
version = "0.1.43"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "92e5113e9fd4cc14ded8e499429f396a20f98c772a47cc8622a736e1ec843c31"
dependencies = [
"num-traits 0.2.14",
"num-traits",
]
[[package]]
@ -1287,6 +1453,49 @@ version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
[[package]]
name = "openssl"
version = "0.10.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c7ae222234c30df141154f159066c5093ff73b63204dcda7121eb082fc56a95"
dependencies = [
"bitflags",
"cfg-if 1.0.0",
"foreign-types",
"libc",
"once_cell",
"openssl-sys",
]
[[package]]
name = "openssl-probe"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
[[package]]
name = "openssl-sys"
version = "0.9.72"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7e46109c383602735fa0a2e48dd2b7c892b048e1bf69e5c3b1d804b7d9c203cb"
dependencies = [
"autocfg",
"cc",
"libc",
"pkg-config",
"vcpkg",
]
[[package]]
name = "ordered-multimap"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1c672c7ad9ec066e428c00eb917124a06f08db19e2584de982cc34b1f4c12485"
dependencies = [
"dlv-list",
"hashbrown",
]
[[package]]
name = "parking_lot"
version = "0.11.1"
@ -1321,6 +1530,12 @@ dependencies = [
"regex",
]
[[package]]
name = "pathdiff"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd"
[[package]]
name = "pear"
version = "0.2.3"
@ -1444,6 +1659,12 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
[[package]]
name = "pkg-config"
version = "0.3.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "58893f751c9b0412871a09abd62ecd2a00298c6c83befa223ef98c52aef40cbe"
[[package]]
name = "polyval"
version = "0.4.5"
@ -1529,15 +1750,20 @@ dependencies = [
]
[[package]]
name = "rand"
version = "0.8.3"
name = "quoted_printable"
version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ef9e7e66b4468674bfcb0c81af8b7fa0bb154fa9f28eb840da5c447baeb8d7e"
checksum = "3fee2dce59f7a43418e3382c766554c614e06a552d53a8f07ef499ea4b332c0f"
[[package]]
name = "rand"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
dependencies = [
"libc",
"rand_chacha",
"rand_core",
"rand_hc",
]
[[package]]
@ -1559,15 +1785,6 @@ dependencies = [
"getrandom",
]
[[package]]
name = "rand_hc"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3190ef7066a446f2e7f42e239d161e905420ccab01eb967c9eb27d21b2322a73"
dependencies = [
"rand_core",
]
[[package]]
name = "redox_syscall"
version = "0.2.7"
@ -1649,7 +1866,7 @@ dependencies = [
"ref-cast",
"rocket_codegen",
"rocket_http",
"serde 1.0.125",
"serde",
"serde_json",
"state",
"tempfile",
@ -1690,7 +1907,7 @@ dependencies = [
"normpath",
"notify",
"rocket",
"serde 1.0.125",
"serde",
"serde_json",
]
@ -1713,7 +1930,7 @@ dependencies = [
"percent-encoding",
"pin-project-lite",
"ref-cast",
"serde 1.0.125",
"serde",
"smallvec",
"stable-pattern",
"state",
@ -1724,10 +1941,21 @@ dependencies = [
]
[[package]]
name = "rust-argon2"
version = "0.8.3"
name = "ron"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4b18820d944b33caa75a71378964ac46f58517c92b6ae5f762636247c09e78fb"
checksum = "1b861ecaade43ac97886a512b360d01d66be9f41f3c61088b42cedf92e03d678"
dependencies = [
"base64",
"bitflags",
"serde",
]
[[package]]
name = "rust-argon2"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b50162d19404029c1ceca6f6980fe40d45c8b369f6f44446fa14bb39573b5bb9"
dependencies = [
"base64",
"blake2b_simd",
@ -1737,9 +1965,13 @@ dependencies = [
[[package]]
name = "rust-ini"
version = "0.13.0"
version = "0.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3e52c148ef37f8c375d49d5a73aa70713125b7f19095948a923f80afdeb22ec2"
checksum = "63471c4aa97a1cf8332a5f97709a79a4234698de6a1f5087faf66f2dae810e22"
dependencies = [
"cfg-if 1.0.0",
"ordered-multimap",
]
[[package]]
name = "rustc_version"
@ -1771,6 +2003,16 @@ dependencies = [
"winapi-util",
]
[[package]]
name = "schannel"
version = "0.1.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f05ba609c234e60bee0d547fe94a4c7e9da733d1c962cf6e59efa4cd9c8bc75"
dependencies = [
"lazy_static",
"winapi 0.3.9",
]
[[package]]
name = "scoped-tls"
version = "1.0.0"
@ -1783,6 +2025,29 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
[[package]]
name = "security-framework"
version = "2.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "23a2ac85147a3a11d77ecf1bc7166ec0b92febfa4461c37944e180f319ece467"
dependencies = [
"bitflags",
"core-foundation",
"core-foundation-sys",
"libc",
"security-framework-sys",
]
[[package]]
name = "security-framework-sys"
version = "2.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0160a13a177a45bfb43ce71c01580998474f556ad854dcbca936dd2841a5c556"
dependencies = [
"core-foundation-sys",
"libc",
]
[[package]]
name = "semver"
version = "0.9.0"
@ -1800,36 +2065,18 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
[[package]]
name = "serde"
version = "0.8.23"
version = "1.0.136"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9dad3f759919b92c3068c696c15c3d17238234498bbdcc80f2c469606f948ac8"
[[package]]
name = "serde"
version = "1.0.125"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "558dc50e1a5a5fa7112ca2ce4effcb321b0300c0d4ccf0776a9f60cd89031171"
checksum = "ce31e24b01e1e524df96f1c2fdd054405f8d7376249a5110886fb4b658484789"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde-hjson"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a3a4e0ea8a88553209f6cc6cfe8724ecad22e1acf372793c27d995290fe74f8"
dependencies = [
"lazy_static",
"num-traits 0.1.43",
"regex",
"serde 0.8.23",
]
[[package]]
name = "serde_derive"
version = "1.0.125"
version = "1.0.136"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b093b7a2bb58203b5da3056c05b4ec1fed827dcfdb37347a8841695263b3d06d"
checksum = "08597e7152fcd306f41838ed3e37be9eaeed2b61c42e2117266a554fab4662f9"
dependencies = [
"proc-macro2",
"quote",
@ -1838,13 +2085,13 @@ dependencies = [
[[package]]
name = "serde_json"
version = "1.0.64"
version = "1.0.79"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "799e97dc9fdae36a5c8b8f2cae9ce2ee9fdce2058c57a93e6099d919fd982f79"
checksum = "8e8d9fa5c3b304765ce1fd9c4c8a3de2c8db365a5b91be52f186efc675681d95"
dependencies = [
"itoa",
"itoa 1.0.1",
"ryu",
"serde 1.0.125",
"serde",
]
[[package]]
@ -1948,12 +2195,6 @@ dependencies = [
"loom",
]
[[package]]
name = "static_assertions"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
[[package]]
name = "stdweb"
version = "0.4.20"
@ -1976,7 +2217,7 @@ checksum = "c87a60a40fccc84bef0652345bbbbbe20a605bf5d0ce81719fc476f5c03b50ef"
dependencies = [
"proc-macro2",
"quote",
"serde 1.0.125",
"serde",
"serde_derive",
"syn",
]
@ -1990,7 +2231,7 @@ dependencies = [
"base-x",
"proc-macro2",
"quote",
"serde 1.0.125",
"serde",
"serde_derive",
"serde_json",
"sha1",
@ -2091,6 +2332,21 @@ dependencies = [
"syn",
]
[[package]]
name = "tinyvec"
version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2c1c1d5a42b6245520c249549ec267180beaffcc0615401ac8e31853d4b6d8d2"
dependencies = [
"tinyvec_macros",
]
[[package]]
name = "tinyvec_macros"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c"
[[package]]
name = "tokio"
version = "1.6.2"
@ -2121,6 +2377,16 @@ dependencies = [
"syn",
]
[[package]]
name = "tokio-native-tls"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f7d995660bd2b7f8c1568414c1126076c13fbb725c40112dc0120b78eb9b717b"
dependencies = [
"native-tls",
"tokio",
]
[[package]]
name = "tokio-stream"
version = "0.1.6"
@ -2152,7 +2418,7 @@ version = "0.5.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa"
dependencies = [
"serde 1.0.125",
"serde",
]
[[package]]
@ -2209,7 +2475,7 @@ version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42756bb9e708855de2f8a98195643dff31a97f0485d90d8467b39dc24be9e8fe"
dependencies = [
"serde 1.0.125",
"serde",
]
[[package]]
@ -2224,7 +2490,7 @@ version = "0.9.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5baeed7327e25054889b9bd4f975f32e5f4c5d434042d59ab6cd4142c0a76ed0"
dependencies = [
"serde 1.0.125",
"serde",
"version_check",
]
@ -2234,6 +2500,21 @@ version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eeba86d422ce181a719445e51872fa30f1f7413b62becb52e95ec91aa262d85c"
[[package]]
name = "unicode-bidi"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a01404663e3db436ed2746d9fefef640d868edae3cceb81c3b8d5732fda678f"
[[package]]
name = "unicode-normalization"
version = "0.1.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d54590932941a9e9266f0832deed84ebe1bf2e4c9e4a3554d393d18f5e854bf9"
dependencies = [
"tinyvec",
]
[[package]]
name = "unicode-xid"
version = "0.2.2"
@ -2257,7 +2538,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7"
dependencies = [
"getrandom",
"serde 1.0.125",
"serde",
]
[[package]]

View File

@ -35,6 +35,8 @@
{{#if organiser.phone}}<p><b>Telefon: </b>{{organiser.phone}}</p>{{/if}}
{{#if organiser.email}}<p><b>Email: </b>{{organiser.email}}</p>{{/if}}
{{#if organiser.other}}<p><b>Sonstiges: </b>{{organiser.other}}</p>{{/if}}
<h5>Abrechnung</h5>
<p><b>Status:</b> {{state_name}}</p>
</div>
</div>
</div>

View File

@ -16,7 +16,7 @@
<div class="form-group row eu_cast_instance_personal_position" data-instance-id="{{../instance_id}}"
data-position-id="{{position_id}}" data-member-name="{{member_name}}"
data-member-id="{{taken_by}}">
<label class="col-4 col-form-label" position_description}}title="{{position_description}}" {{{{#if/if}}>{{position_name}}</label>
<label class="col-4 col-form-label" position_description}}title="{{position_description}}" {{ {{#if/if}}>{{position_name}}</label>
<div class="input-group mb-3 col-8">
{{#if taken_by}}{{member_name}}{{else}}
<button class="btn btn-block btn-sm btn-secondary eu_cast_instance_self_register">Eintragen

View File

@ -121,15 +121,27 @@ EventListModule = ( function() {
}
let date = new Date(event.start);
event.timeframe = ('0' + date.getDate()).slice(-2) + '.' + ('0' + (date.getMonth()+1)).slice(-2) + '.' + date.getFullYear() + ' ' + ('0' + date.getHours()).slice(-2) + ':' + ('0' + date.getMinutes()).slice(-2) + ' - ';
event.timeframe = ('0' + date.getDate()).slice(-2) + '.' + ('0' + (date.getMonth() + 1)).slice(-2) + '.' + date.getFullYear() + ' ' + ('0' + date.getHours()).slice(-2) + ':' + ('0' + date.getMinutes()).slice(-2) + ' - ';
let date2 = new Date(event.end);
if(date.getDate() === date2.getDate()){
if (date.getDate() === date2.getDate()) {
event.timeframe += ('0' + date2.getHours()).slice(-2) + ':' + ('0' + date2.getMinutes()).slice(-2)
}else{
event.timeframe += event.timeframe = ('0' + date2.getDate()).slice(-2) + '.' + ('0' + (date2.getMonth()+1)).slice(-2) + '.' + date2.getFullYear() + ' ' + ('0' + date2.getHours()).slice(-2) + ':' + ('0' + date2.getMinutes()).slice(-2);
} else {
event.timeframe += event.timeframe = ('0' + date2.getDate()).slice(-2) + '.' + ('0' + (date2.getMonth() + 1)).slice(-2) + '.' + date2.getFullYear() + ' ' + ('0' + date2.getHours()).slice(-2) + ':' + ('0' + date2.getMinutes()).slice(-2);
}
event.cast_status = await load_event_cast_status(event.entity_id);
event.state_name = "unbekannt";
if (event.state === 2) {
event.state_name = "Einsatz geöffnet";
} else if (event.state === 4) {
event.state_name = "Einsatz geschlossen";
} else if (event.state === 6) {
event.state_name = "Einsatzzeiten bestätigt";
} else if (event.state === 7) {
event.state_name = "Personalabrechnung abgeschlossen";
} else if (event.state === 8) {
event.state_name = "Abrechnung abgeschlossen";
}
return event
}

View File

@ -724,12 +724,8 @@ EventBilling = (function () {
contentType: 'application/json',
timeout: 3000,
});
if ('error' in data) {
if (data.error.code === 404) {
return undefined;
} else {
show_error(data)
}
if (!is_ok(data)) {
show_error(data)
} else {
return data;
}

View File

@ -1 +1 @@
v0.2-84-g27295c7
v0.2-96-g136781c

View File

@ -1,5 +1,5 @@
use bigdecimal::BigDecimal;
use diesel::{ExpressionMethods, QueryDsl, RunQueryDsl};
use diesel::{ExpressionMethods, OptionalExtension, QueryDsl, RunQueryDsl};
use rocket::State;
use crate::database::controller::connector::establish_connection;
@ -45,10 +45,10 @@ pub fn create(settings: &State<Settings>, data: RawPersonnelBilling) -> Result<(
}
}
pub fn read(settings: &State<Settings>, position_instance_id: uuid::Uuid) -> Result<RawPersonnelBilling, diesel::result::Error> {
pub fn read(settings: &State<Settings>, position_instance_id: uuid::Uuid) -> Result<Option<RawPersonnelBilling>, diesel::result::Error> {
let connection = establish_connection(settings);
match personnel_billing::table.filter(personnel_billing::dsl::position_instance_id.eq(position_instance_id)).get_result(&connection) {
match personnel_billing::table.filter(personnel_billing::dsl::position_instance_id.eq(position_instance_id)).get_result(&connection).optional() {
Ok(res) => Ok(res),
Err(e) => {
error!("Couldn't get personnel billing details: {}", e);

View File

@ -10,7 +10,7 @@ pub struct BillingState {
entity_id: uuid::Uuid,
name: String,
description: Option<String>,
final_approve: bool,
pub(crate) final_approve: bool,
}
pub fn get_billing_states(settings: &State<Settings>) -> Result<Vec<BillingState>, diesel::result::Error> {
@ -27,6 +27,20 @@ pub fn get_billing_states(settings: &State<Settings>) -> Result<Vec<BillingState
}
}
pub fn get_billing_state(settings: &State<Settings>, state: uuid::Uuid) -> Result<BillingState, diesel::result::Error> {
use crate::schema::billing_states::dsl::*;
let connection = establish_connection(settings);
match billing_states.select((entity_id, name, description, final_approve)).filter(entity_id.eq(state)).get_result(&connection) {
Ok(bs) => Ok(bs),
Err(e) => {
error!("Couldn't get billing state: {}", e);
Err(e)
}
}
}
pub fn get_billing_states_for_event(settings: &State<Settings>, event: uuid::Uuid) -> Result<Vec<uuid::Uuid>, diesel::result::Error> {
use crate::schema::eu_instances::dsl::*;

View File

@ -98,6 +98,23 @@ pub fn approve_stage(settings: &State<Settings>, event_id2: uuid::Uuid, stage: u
}
}
/// Sets state for event from 7 to 8
/// Used in API endpoint for billing module
/// Returns an empty Ok result or an [diesel::result::Error].
pub fn finish_billing(settings: &State<Settings>, event_id: uuid::Uuid) -> Result<(), diesel::result::Error> {
use crate::schema::events::dsl::*;
let connection = establish_connection(settings);
match diesel::update(events.filter(entity_id.eq(event_id)).filter(state.eq(7))).set(state.eq(8)).execute(&connection) {
Ok(_) => Ok(()),
Err(e) => {
error!("Couldn't finish billing: {}", e);
Err(e)
}
}
}
pub fn change_event(settings: &State<Settings>, data: Event) -> Result<Event, diesel::result::Error> {
use crate::schema::events::dsl::*;
@ -510,7 +527,7 @@ pub fn get_instance_positions_name_description(settings: &State<Settings>, insta
}
}
pub fn get_instance_positions(settings: &State<Settings>, instance_id: uuid::Uuid) -> Result<Vec<RawPositionInstance>, diesel::result::Error> {
pub fn get_position_instances(settings: &State<Settings>, instance_id: uuid::Uuid) -> Result<Vec<RawPositionInstance>, diesel::result::Error> {
let connection = establish_connection(settings);
match eu_position_instances.filter(crate::schema::eu_position_instances::dsl::instance_id.eq(instance_id)).get_results(&connection) {

View File

@ -37,6 +37,20 @@ pub fn get_instances(settings: &State<Settings>, event: uuid::Uuid) -> Result<Ve
}
}
pub fn get_instance(settings: &State<Settings>, instance: uuid::Uuid) -> Result<RawEventUnitInstance, diesel::result::Error> {
use crate::schema::eu_instances::dsl::*;
let connection = establish_connection(settings);
match eu_instances.filter(instance_id.eq(instance)).get_result(&connection) {
Ok(instances) => Ok(instances),
Err(e) => {
error!("Couldn't get event unit instance: {}", e);
Err(e)
}
}
}
#[derive(Queryable, Clone, Deserialize, Serialize, AsChangeset, Insertable)]
#[table_name = "eu_instances"]
#[primary_key(entity_id)]

View File

@ -1,14 +1,15 @@
use diesel::{JoinOnDsl, QueryDsl, sql_query};
use diesel::pg::expression::array_comparison::any;
use diesel::pg::types::sql_types::{Array, Uuid};
use diesel::sql_types::{BigInt, Text};
use rocket::State;
use crate::database::controller::connector::establish_connection;
use crate::database::controller::groups::get_groups_for_member;
use crate::database::model::members::RawMember;
use crate::diesel::prelude::*;
use crate::helper::settings::Settings;
use crate::modules::member_management::model::member::Member;
use diesel::pg::expression::array_comparison::any;
use diesel::pg::types::sql_types::{Uuid, Array};
use diesel::sql_types::{BigInt, Text};
use diesel::{sql_query, JoinOnDsl, QueryDsl};
use rocket::State;
use crate::schema::groups_entities::dsl::groups_entities;
/*impl<DB> FromSql<SmallInt, DB> for Sex
@ -240,6 +241,7 @@ pub fn get_members_by_user_uuid(uuid: uuid::Uuid, settings: &State<Settings>) ->
/// * 'settings' - Settings, as managed State
/// #Returns
/// * 'Member'
//TODO: return Result not OPtion
pub fn get_member_by_uuid(uuid: uuid::Uuid, settings: &State<Settings>) -> Option<Member> {
let raw_member: RawMember = get_raw_member_by_uuid(uuid, &settings)?;

View File

@ -83,7 +83,7 @@ pub fn create_event(
other: ecd.other,
other_intern: ecd.other_intern,
related_request: None,
state: 0
state: 2
};
match add_event(settings, input){

View File

@ -68,7 +68,7 @@ pub fn create_instance(
};
let planned_start_time = match cid.planned_start_time {
Some(dt) => match datetime_str_to_utc(settings, &cookie, &dt) {
Some(dt) => match datetime_str_to_utc(settings, Some(&cookie), &dt) {
Ok(dt) => Some(dt),
Err(e) => {
warn!("Couldn't parse planned start time as DateTime: {}", e);
@ -82,7 +82,7 @@ pub fn create_instance(
};
let planned_end_time = match cid.planned_end_time {
Some(dt) => match datetime_str_to_utc(settings, &cookie, &dt) {
Some(dt) => match datetime_str_to_utc(settings, Some(&cookie), &dt) {
Ok(dt) => Some(dt),
Err(e) => {
warn!("Couldn't parse planned end time as DateTime: {}", e);
@ -177,7 +177,7 @@ pub fn add_position_instance(
}
//TODO: require extra permissions to set real start time & real end time
let real_start_time = match create_position_instance_data.real_start_time {
Some(dt) => match datetime_str_to_utc(settings, &cookie, &dt) {
Some(dt) => match datetime_str_to_utc(settings, Some(&cookie), &dt) {
Ok(dt) => Some(dt),
Err(e) => {
warn!("Couldn't parse real start time as DateTime: {}", e);
@ -190,7 +190,7 @@ pub fn add_position_instance(
None => None,
};
let real_end_time = match create_position_instance_data.real_end_time {
Some(dt) => match datetime_str_to_utc(settings, &cookie, &dt) {
Some(dt) => match datetime_str_to_utc(settings, Some(&cookie), &dt) {
Ok(end) => {
if let Some(start) = real_start_time {
if start.ge(&end) {

View File

@ -1,7 +1,7 @@
use rocket::serde::json::Json;
use rocket::State;
use crate::database::controller::events::{get_eu_position, get_instance_positions, get_instance_vehicle_positions};
use crate::database::controller::events::{get_eu_position, get_instance_vehicle_positions, get_position_instances};
use crate::database::controller::events::instances::instance_positions::RawPositionInstance;
use crate::database::controller::events::instances::instances::{get_instances, RawEventUnitInstance};
use crate::database::model::events::{EventUnitInstanceDeprecated, EventUnitInstancePosition, EventUnitInstanceVehiclePosition};
@ -33,19 +33,19 @@ impl EventUnitInstance {
/// Convert RawEventUnitInstance to EventUnitInstance by converting Utc DateTimes to timestamps with user specified timezone
pub fn from_raw(raw: RawEventUnitInstance, settings: &State<Settings>, cookie: &SessionCookie) -> EventUnitInstance {
let planned_start_time = match raw.planned_start_time {
Some(dt) => Some(utc_to_local_user_time(settings, cookie, dt)),
Some(dt) => Some(utc_to_local_user_time(settings, Some(cookie), dt)),
None => None
};
let planned_end_time = match raw.planned_end_time {
Some(dt) => Some(utc_to_local_user_time(settings, cookie, dt)),
Some(dt) => Some(utc_to_local_user_time(settings, Some(cookie), dt)),
None => None
};
let real_start_time = match raw.real_start_time {
Some(dt) => Some(utc_to_local_user_time(settings, cookie, dt)),
Some(dt) => Some(utc_to_local_user_time(settings, Some(cookie), dt)),
None => None
};
let real_end_time = match raw.real_end_time {
Some(dt) => Some(utc_to_local_user_time(settings, cookie, dt)),
Some(dt) => Some(utc_to_local_user_time(settings, Some(cookie), dt)),
None => None
};
@ -83,11 +83,11 @@ impl PositionInstance {
/// Convert RawPositionInstance to PositionInstance by converting Utc DateTimes to timestamps with user specified timezone
pub fn from_raw(raw: &RawPositionInstance, settings: &State<Settings>, cookie: &SessionCookie) -> Result<PositionInstance, ()> {
let real_start_time = match raw.real_start_time {
Some(dt) => Some(utc_to_local_user_time(settings, cookie, dt)),
Some(dt) => Some(utc_to_local_user_time(settings, Some(cookie), dt)),
None => None
};
let real_end_time = match raw.real_end_time {
Some(dt) => Some(utc_to_local_user_time(settings, cookie, dt)),
Some(dt) => Some(utc_to_local_user_time(settings, Some(cookie), dt)),
None => None
};
let position_data = match get_eu_position(settings, raw.position_id) {
@ -159,7 +159,7 @@ pub fn read_positions_for_instance(settings: &State<Settings>, cookie: SessionCo
return Err(Json(ApiError::new(403, "Keine Berechtigung Einsätze abzurufen!".to_string()).to_wrapper()));
}
match get_instance_positions(settings, parse_uuid_string(instance_id)?) {
match get_position_instances(settings, parse_uuid_string(instance_id)?) {
Ok(pos) => {
let mut res = vec![];
for position in pos {

View File

@ -5,7 +5,7 @@ use rocket::State;
use crate::database::controller::events::{change_position_instances, get_event};
use crate::database::controller::events::instances::instance_positions::RawPositionInstanceChangeset;
use crate::database::controller::events::instances::instances::{RawEventUnitInstanceChangeset, update_instance};
use crate::database::controller::events::instances::instances::{get_instance, get_instances, RawEventUnitInstanceChangeset, update_instance};
use crate::helper::serde_patch::Patch;
use crate::helper::session_cookies::model::SessionCookie;
use crate::helper::settings::Settings;
@ -28,11 +28,33 @@ pub fn put_entity_in_position(
let position_id = parse_uuid_string(position_id)?;
let entity_id = parse_uuid_string(entity_id)?;
let instance_id = parse_uuid_string(instance_id)?;
let instance = match get_instance(settings, instance_id) {
Ok(instance) => instance,
Err(e) =>
{
warn!("Instance not found: {}", e);
return Err(Json(ApiError::new(404, "instance not found!".to_string()).to_wrapper()));
}
};
let event = match get_event(settings, instance.event_id) {
Ok(event) => event,
Err(e) => {
warn!("Event not found: {}", e);
return Err(Json(
ApiError::new(404, "event for instance not found!".to_string()).to_wrapper()))
}
};
if event.state >= 4 {
return Err(Json(
ApiError::new(400, "Dieser Einsatz wurde bereits geschlossen!".to_string()).to_wrapper()))
}
if caller.entity_id == entity_id {
match check_position_requirements(settings, position_id, entity_id){
match check_position_requirements(settings, position_id, entity_id) {
Ok(res) => {
if !res{ //if member tries to add himself to a position, but don't fulfill the position requirements AND don't have the event edit permission (overwrite), abort
if !res { //if member tries to add himself to a position, but don't fulfill the position requirements AND don't have the event edit permission (overwrite), abort
if !caller.has_permission(crate::permissions::modules::event_management::events::EDIT.to_string()) {
return Err(Json(
ApiError::new(403, "Keine Berechtigung Einsätze zu bearbeiten!".to_string()).to_wrapper(),
@ -52,15 +74,13 @@ pub fn put_entity_in_position(
}
}
}
}else{
if !caller.has_permission(crate::permissions::modules::event_management::events::EDIT.to_string()) {
return Err(Json(
ApiError::new(403, "Keine Berechtigung Einsätze zu bearbeiten!".to_string()).to_wrapper(),
));
}
} else if !caller.has_permission(crate::permissions::modules::event_management::events::EDIT.to_string()) {
return Err(Json(
ApiError::new(403, "Keine Berechtigung Einsätze zu bearbeiten!".to_string()).to_wrapper(),
));
}
match change_position_instances(settings, parse_uuid_string(instance_id)?, position_id, Some(entity_id)){
match change_position_instances(settings, instance_id, position_id, Some(entity_id)) {
Ok(pos) => Ok(Json(pos)),
Err(e) => return Err(translate_diesel(e))
}
@ -80,7 +100,30 @@ pub fn remove_entity_from_position(
));
}
match change_position_instances(settings, parse_uuid_string(instance_id)?, parse_uuid_string(position_id)?, None) {
let instance_id = parse_uuid_string(instance_id)?;
let instance = match get_instance(settings, instance_id) {
Ok(instance) => instance,
Err(e) =>
{
warn!("Instance not found: {}", e);
return Err(Json(ApiError::new(404, "instance not found!".to_string()).to_wrapper()));
}
};
let event = match get_event(settings, instance.event_id) {
Ok(event) => event,
Err(e) => {
warn!("Event not found: {}", e);
return Err(Json(
ApiError::new(404, "event for instance not found!".to_string()).to_wrapper()))
}
};
if event.state >= 4 {
return Err(Json(
ApiError::new(400, "Dieser Einsatz wurde bereits geschlossen!".to_string()).to_wrapper()))
}
match change_position_instances(settings, instance_id, parse_uuid_string(position_id)?, None) {
Ok(pos) => Ok(Json(pos)),
Err(e) => return Err(translate_diesel(e))
}
@ -182,7 +225,7 @@ pub fn patch_instance(
Patch::Missing => None,
Patch::Null => Some(None),
Patch::Value(v) => {
match datetime_str_to_utc(settings, &cookie, &v) {
match datetime_str_to_utc(settings, Some(&cookie), &v) {
Ok(v) => Some(Some(v)),
Err(e) => {
warn!("Couldn't parse planned start time as DateTime: {}",e);
@ -197,7 +240,7 @@ pub fn patch_instance(
Patch::Missing => None,
Patch::Null => Some(None),
Patch::Value(v) => {
match datetime_str_to_utc(settings, &cookie, &v) {
match datetime_str_to_utc(settings, Some(&cookie), &v) {
Ok(v) => Some(Some(v)),
Err(e) => {
warn!("Couldn't parse planned end time as DateTime: {}",e);
@ -212,7 +255,7 @@ pub fn patch_instance(
Patch::Missing => None,
Patch::Null => Some(None),
Patch::Value(v) => {
match datetime_str_to_utc(settings, &cookie, &v) {
match datetime_str_to_utc(settings, Some(&cookie), &v) {
Ok(v) => Some(Some(v)),
Err(e) => {
warn!("Couldn't parse real start time as DateTime: {}",e);
@ -227,7 +270,7 @@ pub fn patch_instance(
Patch::Missing => None,
Patch::Null => Some(None),
Patch::Value(v) => {
match datetime_str_to_utc(settings, &cookie, &v) {
match datetime_str_to_utc(settings, Some(&cookie), &v) {
Ok(v) => Some(Some(v)),
Err(e) => {
warn!("Couldn't parse real end time as DateTime: {}",e);
@ -312,7 +355,7 @@ pub fn patch_position_instance(
Patch::Missing => None,
Patch::Null => Some(None),
Patch::Value(v) => {
match datetime_str_to_utc(settings, &cookie, &v) {
match datetime_str_to_utc(settings, Some(&cookie), &v) {
Ok(v) => Some(Some(v)),
Err(e) => {
warn!("Couldn't parse real start time as DateTime: {}",e);
@ -327,7 +370,7 @@ pub fn patch_position_instance(
Patch::Missing => None,
Patch::Null => Some(None),
Patch::Value(v) => {
match datetime_str_to_utc(settings, &cookie, &v) {
match datetime_str_to_utc(settings, Some(&cookie), &v) {
Ok(end) => {
match real_start_time {
Some(start) => match start {

View File

@ -3,7 +3,7 @@ use rocket::serde::json::Json;
use rocket::State;
use crate::database::controller::billing::states::{get_billing_states_for_event, get_min_billing_states_for_event};
use crate::database::controller::events::{get_event, get_event_count, get_events, get_events_for_member_in_future, get_instance_positions, get_instance_positions_name_description};
use crate::database::controller::events::{get_event, get_event_count, get_events, get_events_for_member_in_future, get_instance_positions_name_description, get_position_instances};
use crate::database::controller::events::instances::instances::get_instances;
use crate::database::model::events::Event;
use crate::helper::session_cookies::model::SessionCookie;

View File

@ -1,8 +1,15 @@
use std::sync::Arc;
use chrono::NaiveDateTime;
use diesel::expression::ops::Mul;
use lettre::{AsyncTransport, Message};
use lettre::message::{Attachment, MultiPart, SinglePart};
use lettre::message::header::ContentType;
use rocket::serde::json::Json;
use rocket::State;
use crate::database::controller::events::{change_event, get_event};
use crate::database::controller::billing::states::{get_billing_state, get_billing_states};
use crate::database::controller::events::{change_event, finish_billing, get_event};
use crate::database::controller::events::instances::instance_positions::RawPositionInstanceChangeset;
use crate::database::controller::events::instances::instances::get_instances;
use crate::database::controller::members::check_access_to_resource;
@ -10,9 +17,11 @@ use crate::database::model::events::Event;
use crate::helper::session_cookies::model::SessionCookie;
use crate::helper::settings::Settings;
use crate::helper::translate_diesel_error::translate_diesel;
use crate::MailQueue;
use crate::modules::api::events::create::CreateEventData;
use crate::modules::api::member_management::controller::parser::{parse_member_cookie, parse_option_uuid, parse_uuid_string};
use crate::modules::api::model::api_outcome::{ApiError, ApiErrorWrapper};
use crate::modules::event_billing::generate_billing_csv::{generate_billing_csv, save_billing_csv};
#[put("/api/events/<entity_id>", format = "json", data = "<update_event_data>")]
pub fn update_event(
@ -214,24 +223,57 @@ pub fn finish_personnel_billing(
}
#[put("/api/events/<entity_id>/approve?<stage>", format = "json")]
pub fn approve(
pub async fn approve(
settings: &State<Settings>,
cookie: SessionCookie,
entity_id: String,
stage: String,
mq: &State<Arc<MailQueue>>,
) -> Result<(), Json<ApiErrorWrapper>> {
let caller = parse_member_cookie(cookie.member)?;
let event_id = parse_uuid_string(entity_id)?;
let stage = parse_uuid_string(stage)?;
let billing_state = match get_billing_state(settings, stage) {
Ok(state) => state,
Err(e) => {
warn!("Couldn't find stage: {}", e);
return Err(Json(ApiError::new(404, "Stage not found.".to_string()).to_wrapper()));
}
};
if !check_access_to_resource(settings, caller.entity_id, stage, crate::permissions::modules::event_billing::APPROVE) {
return Err(Json(ApiError::new(403, "No permission to approve this billing state.".to_string()).to_wrapper()));
}
match crate::database::controller::events::approve_stage(settings, event_id, stage, caller.entity_id) {
Ok(_) => Ok(()),
Ok(_) => {
if billing_state.final_approve {
if let Err(e) = finish_billing(settings, event_id) {
return Err(translate_diesel(e));
}
let csv = match generate_billing_csv(settings, event_id) {
Ok(csv) => csv,
Err(e) => {
error!("Error generating CSV: {}", e); //TODO: report failure to user
return Ok(())
}
};
debug!("Generated CSV: {}", csv);
if settings.billing.send_personnel_billing_to_email {
let attachement = Attachment::new(String::from("Einsatzabrechnung.csv")).body(csv, ContentType::parse("text/csv").unwrap());
let msg = Message::builder()
.from(settings.mail.from.clone().parse().unwrap())
.reply_to(settings.mail.reply_to.clone().parse().unwrap())
.to(settings.billing.personnel_billing_email.parse().unwrap())
.subject("Einsatzabrechnung")
.multipart(MultiPart::mixed().singlepart(attachement).singlepart(SinglePart::plain(String::from("Es wurde eine Einsatzabrechnung freigegeben. Sie befindet sich im Anhang dieser E-Mail.")))).unwrap();
mq.add_mail(msg);
}
}
Ok(())
},
Err(e) => Err(translate_diesel(e))
}
}

View File

@ -4,7 +4,7 @@ use rocket::State;
use crate::database::controller::billing::personnel_billing::RawPersonnelBilling;
use crate::database::controller::billing::personnel_billing_rates::{get_billing_rate, get_billing_rates};
use crate::database::controller::events::{get_instance_positions, get_position_instance};
use crate::database::controller::events::{get_position_instance, get_position_instances};
use crate::helper::session_cookies::model::SessionCookie;
use crate::helper::translate_diesel_error::translate_diesel;
use crate::modules::api::member_management::controller::parser::{parse_member_cookie, parse_uuid_string};

View File

@ -26,7 +26,7 @@ pub fn get_personnel_billing(
settings: &State<Settings>,
cookie: SessionCookie,
position_instance_id: String,
) -> Result<Json<PersonnelBilling>, Json<ApiErrorWrapper>> {
) -> Result<Json<Option<PersonnelBilling>>, Json<ApiErrorWrapper>> {
let caller = parse_member_cookie(cookie.member.clone())?;
//TODO: allow member_responsible for event to bypass this permission
if !caller
@ -44,15 +44,20 @@ pub fn get_personnel_billing(
let pid = parse_uuid_string(position_instance_id)?;
match crate::database::controller::billing::personnel_billing::read(settings, pid) {
Ok(res) => {
Ok(Json(PersonnelBilling {
position_instance_id: res.position_instance_id,
member_id: res.member_id,
fulfilled_time: res.fulfilled_time,
money_for_time: res.money_for_time.to_string(),
money_from_lump_sum: res.money_from_lump_sum.to_string(),
total_money: res.total_money.to_string(),
Ok(Json(match res {
Some(res) => {
Some(PersonnelBilling {
position_instance_id: res.position_instance_id,
member_id: res.member_id,
fulfilled_time: res.fulfilled_time,
money_for_time: res.money_for_time.to_string(),
money_from_lump_sum: res.money_from_lump_sum.to_string(),
total_money: res.total_money.to_string(),
})
},
None => None
}))
}
},
Err(e) => Err(translate_diesel(e))
}
}

View File

@ -52,6 +52,12 @@ pub fn approve(cookie: SessionCookie, settings: &State<Settings>, event_id: Stri
}
};
//Do not allow editing times before event is closed
if event.state < 7 {
error!("User tried to approve before event was billed");
return Err(Status::BadRequest);
}
let header = Header {
html_language: "de".to_string(),
site_title: "Einsatzabrechnung".to_string(),

View File

@ -0,0 +1,173 @@
use std::fmt;
use std::fs::File;
use std::io::Write;
use std::path::{Path, PathBuf};
use rocket::State;
use crate::database::controller::billing::personnel_billing_rates::get_billing_rate;
use crate::database::controller::events::{get_event, get_position_instance, get_position_instances};
use crate::database::controller::events::instances::instances::get_instances;
use crate::database::controller::groups::get_group;
use crate::database::controller::members::get_member_by_uuid;
use crate::helper::time::utc_to_local_user_time;
use crate::modules::api::personnel_billing::read::get_personnel_billing;
use crate::Settings;
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub enum CSVGeneratorErrorKind {
MissingTimes,
MissingMember,
}
#[derive(Debug)]
pub enum CSVGeneratorError {
Database(diesel::result::Error),
Generator(CSVGeneratorErrorKind),
IoError(std::io::Error),
}
impl CSVGeneratorErrorKind {
pub fn as_str(&self) -> &str {
match *self {
CSVGeneratorErrorKind::MissingTimes => "Missing real start and/or real end times.",
CSVGeneratorErrorKind::MissingMember => "Missing member details. Maybe member got removed?",
}
}
}
impl fmt::Display for CSVGeneratorError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
CSVGeneratorError::Generator(ref err) => write!(f, "CSV Generator error: {:?}", err),
CSVGeneratorError::Database(ref err) => std::fmt::Display::fmt(&err, f),
CSVGeneratorError::IoError(ref err) => std::fmt::Display::fmt(&err, f),
}
}
}
impl From<diesel::result::Error> for CSVGeneratorError {
fn from(err: diesel::result::Error) -> CSVGeneratorError {
CSVGeneratorError::Database(err)
}
}
impl From<std::io::Error> for CSVGeneratorError {
fn from(err: std::io::Error) -> CSVGeneratorError {
CSVGeneratorError::IoError(err)
}
}
pub fn save_billing_csv(settings: &State<Settings>, csv: String, event_name: String) -> Result<String, std::io::Error> {
let mut path_draft = format!("data/personnel_billing_csv/csv_{}", event_name);
let mut path = Path::new(&path_draft);
if path.exists() {
let mut i = 1;
loop {
path_draft = format!("data/personnel_billing_csv/csv_{}_{}", event_name, i);
if !Path::new(&path_draft).exists() {
break;
} else {
i = i + 1;
}
}
path = Path::new(&path_draft);
}
let mut file = File::create(&path)?;
file.write_all(csv.as_bytes())?;
Ok(path_draft)
}
pub fn generate_billing_csv(settings: &State<Settings>, event_id: uuid::Uuid) -> Result<String, CSVGeneratorError> {
let mut res = String::new();
let event_data = get_event(settings, event_id)?;
res.push_str(&format!("{}, {}\n", sanitize(String::from("Einsatz: ")), sanitize(event_data.name.clone())));
if let Some(related_group) = event_data.related_group {
let group = get_group(settings, related_group)?;
res.push_str(&format!("{}, {}\n", sanitize(String::from("Gruppe:")), sanitize(group.name)));
}
if let Some(member_responsible) = event_data.member_responsible {
if let Some(member) = get_member_by_uuid(member_responsible, settings) {
res.push_str(&format!("{}, {}\n", sanitize(String::from("Verantwortliches Mitglied:")), sanitize(format!("{} {}", member.firstname, member.lastname))))
}
}
res.push_str("\n");
let instances = get_instances(settings, event_id)?;
for instance in instances {
res.push_str(&format!("Einheit:, {}\n", sanitize(instance.name)));
if let Some(billing_rate_id) = instance.billing_rate_id {
let billing_rate = get_billing_rate(settings, billing_rate_id)?;
res.push_str(&format!("Abrechnungssatz:, {}, {}, Pauschale:, {}, €/Stunde:, {}\n", sanitize(billing_rate.name), sanitize(billing_rate.description.unwrap_or(String::from(""))), sanitize(format!("{}", billing_rate.lump_sum)), sanitize(format!("{}", billing_rate.payment_per_hour))));
}
res.push_str(&format!("{}, {}, {}, {}, {}, {}, {}, {}, {}\n", String::from("Personalnummer"), String::from("Vorname"), String::from("Nachname"), String::from("Von"), String::from("Bis"), String::from("Stunden"), String::from("Pauschale"), String::from("Stundengeld"), String::from("Gesamt")));
let position_instances = get_position_instances(settings, instance.instance_id)?;
for position_instance in position_instances {
if let Some(personnel) = crate::database::controller::billing::personnel_billing::read(settings, position_instance.position_instance_id)? {
match get_member_by_uuid(personnel.member_id, settings) {
Some(member) => {
let begin = match position_instance.real_start_time {
Some(start) => utc_to_local_user_time(settings, None, start),
None => return Err(CSVGeneratorError::Generator(CSVGeneratorErrorKind::MissingTimes))
};
let end = match position_instance.real_end_time {
Some(end) => utc_to_local_user_time(settings, None, end),
None => return Err(CSVGeneratorError::Generator(CSVGeneratorErrorKind::MissingTimes))
};
res.push_str(&format!("{}, {}, {}, {}, {}, {}, {}, {}, {}\n", sanitize(member.personnel_number.unwrap_or(0).to_string()), sanitize(member.firstname), sanitize(member.lastname), sanitize(begin), sanitize(end), sanitize(personnel.fulfilled_time.to_string()), sanitize(personnel.money_from_lump_sum.to_string()), sanitize(personnel.money_for_time.to_string()), sanitize(personnel.total_money.to_string())));
}
None => {
return Err(CSVGeneratorError::Generator(CSVGeneratorErrorKind::MissingMember));
}
};
}
}
res.push_str("\n");
}
Ok(res)
}
fn sanitize(mut input: String) -> String {
input = input.replace("\"", "\"\"") //escape double quotes by another double quote
.replace("\r", "") //Remove carriage returns
.replace("\n", "") //Remove new lines
.replace("\t", ""); //Remove tabs
if input.starts_with("@") || input.starts_with("=") || input.starts_with("+") || input.starts_with("-") { //Add single quote if input starts with @ = + or -
input = format!("\'{}", input);
}
format!("\"{}\"", input)
}
#[cfg(test)]
mod tests {
use crate::modules::event_billing::generate_billing_csv::sanitize;
#[test]
fn csv_injection_test1() {
assert_eq!(sanitize(String::from("Tes\"t123")), String::from("\"Tes\"\"t123\""))
}
#[test]
fn csv_injection_test2() {
assert_eq!(sanitize(String::from("=1+2\";=1+2")), String::from("\"'=1+2\"\";=1+2\""))
}
#[test]
fn csv_injection_test3() {
assert_eq!(sanitize(String::from("=SUM(A1, A2)")), String::from("\"'=SUM(A1, A2)\""))
}
}

View File

@ -2,4 +2,5 @@ pub mod event;
pub mod close_event;
pub mod edit_times;
pub mod approve;
pub mod edit_personnel_billing;
pub mod edit_personnel_billing;
pub mod generate_billing_csv;

View File

@ -45,6 +45,9 @@ pub fn edit_event(cookie: SessionCookie, _settings: &State<Settings>, id: String
},
Script {
path: "/js/em_edit_event.js".to_string(),
},
Script {
path: "/js/search2.js".to_string(),
}],
};