major: edit database and finish check_items

New:
- Removed the connection between tables 'receipt_item' and 'item'.
Instead the position on the receipt will be stored as a primary key
with the receipt.id.
- Uploading a receipt and checking items for invoice is now working.
- Uploading a receipt now redirects directly to the form where the
items on the receipt can be marked for invoice.
- Added pagination for candidates-page.

Refactoring:
- Added _rencer_field_errors.html for centralized error display.
- Added edeka_parser.py for better management of different parsers.

Known Bugs:
- Uploading a receipt without any fields results in an error.

Todo:
- Generate a general form if no fields are recognized on the uploaded
receipt.
- Create form where Admin can confirm receipt invoices.
- Display Notification for admin when users upload receipt.
- Display Notification for admin on new candidate.
This commit is contained in:
Lunaresk 2023-11-12 16:05:09 +01:00
parent 6c0fa5a58b
commit 4d1e7eb944
24 changed files with 725 additions and 414 deletions

5
.gitignore vendored
View File

@ -341,6 +341,7 @@ config.yaml
scans.json scans.json
test_*.* test_*.*
test.* test.*
tests*
*.db *.db
.vscode .vscode
*.tar *.tar
@ -350,4 +351,6 @@ test.*
!.env.project !.env.project
!.env.vault !.env.vault
*.ps1 *.ps1
*.pdf *.pdf
*.backup
Dockerfile.*

View File

@ -22,6 +22,7 @@ pymupdf = "*"
requests = "*" requests = "*"
sqlalchemy-utils = "*" sqlalchemy-utils = "*"
wtforms-sqlalchemy = "*" wtforms-sqlalchemy = "*"
pytest = "*"
[dev-packages] [dev-packages]

721
backend/Pipfile.lock generated
View File

@ -1,7 +1,7 @@
{ {
"_meta": { "_meta": {
"hash": { "hash": {
"sha256": "5418d6b50788a542461e9a348ad0864d3e4d2046e48967df081cbaed9971ed0f" "sha256": "6f12189a28bcfca261128bb19798f69649619d796466a01c69fe3a8df6457fbf"
}, },
"pipfile-spec": 6, "pipfile-spec": 6,
"requires": { "requires": {
@ -19,19 +19,19 @@
"default": { "default": {
"alembic": { "alembic": {
"hashes": [ "hashes": [
"sha256:6a810a6b012c88b33458fceb869aef09ac75d6ace5291915ba7fae44de372c01", "sha256:47d52e3dfb03666ed945becb723d6482e52190917fdb47071440cfdba05d92cb",
"sha256:dc871798a601fab38332e38d6ddb38d5e734f60034baeb8e2db5b642fccd8ab8" "sha256:bca5877e9678b454706347bc10b97cb7d67f300320fa5c3a94423e8266e2823f"
], ],
"markers": "python_version >= '3.7'", "markers": "python_version >= '3.7'",
"version": "==1.11.1" "version": "==1.12.1"
}, },
"blinker": { "blinker": {
"hashes": [ "hashes": [
"sha256:4afd3de66ef3a9f8067559fb7a1cbe555c17dcbe15971b05d1b625c3e7abe213", "sha256:152090d27c1c5c722ee7e48504b02d76502811ce02e1523553b4cf8c8b3d3a8d",
"sha256:c3d739772abb7bc2860abf5f2ec284223d9ad5c76da018234f6f50d6f31ab1f0" "sha256:296320d6c28b006eb5e32d4712202dbcdcbf5dc482da298c2f44881c43884aaa"
], ],
"markers": "python_version >= '3.7'", "markers": "python_version >= '3.7'",
"version": "==1.6.2" "version": "==1.6.3"
}, },
"certifi": { "certifi": {
"hashes": [ "hashes": [
@ -43,92 +43,107 @@
}, },
"charset-normalizer": { "charset-normalizer": {
"hashes": [ "hashes": [
"sha256:04e57ab9fbf9607b77f7d057974694b4f6b142da9ed4a199859d9d4d5c63fe96", "sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027",
"sha256:09393e1b2a9461950b1c9a45d5fd251dc7c6f228acab64da1c9c0165d9c7765c", "sha256:06a81e93cd441c56a9b65d8e1d043daeb97a3d0856d177d5c90ba85acb3db087",
"sha256:0b87549028f680ca955556e3bd57013ab47474c3124dc069faa0b6545b6c9710", "sha256:0a55554a2fa0d408816b3b5cedf0045f4b8e1a6065aec45849de2d6f3f8e9786",
"sha256:1000fba1057b92a65daec275aec30586c3de2401ccdcd41f8a5c1e2c87078706", "sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8",
"sha256:1249cbbf3d3b04902ff081ffbb33ce3377fa6e4c7356f759f3cd076cc138d020", "sha256:10955842570876604d404661fbccbc9c7e684caf432c09c715ec38fbae45ae09",
"sha256:1920d4ff15ce893210c1f0c0e9d19bfbecb7983c76b33f046c13a8ffbd570252", "sha256:122c7fa62b130ed55f8f285bfd56d5f4b4a5b503609d181f9ad85e55c89f4185",
"sha256:193cbc708ea3aca45e7221ae58f0fd63f933753a9bfb498a3b474878f12caaad", "sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574",
"sha256:1a100c6d595a7f316f1b6f01d20815d916e75ff98c27a01ae817439ea7726329", "sha256:1d3193f4a680c64b4b6a9115943538edb896edc190f0b222e73761716519268e",
"sha256:1f30b48dd7fa1474554b0b0f3fdfdd4c13b5c737a3c6284d3cdc424ec0ffff3a", "sha256:1f79682fbe303db92bc2b1136016a38a42e835d932bab5b3b1bfcfbf0640e519",
"sha256:203f0c8871d5a7987be20c72442488a0b8cfd0f43b7973771640fc593f56321f", "sha256:2127566c664442652f024c837091890cb1942c30937add288223dc895793f898",
"sha256:246de67b99b6851627d945db38147d1b209a899311b1305dd84916f2b88526c6", "sha256:22afcb9f253dac0696b5a4be4a1c0f8762f8239e21b99680099abd9b2b1b2269",
"sha256:2dee8e57f052ef5353cf608e0b4c871aee320dd1b87d351c28764fc0ca55f9f4", "sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3",
"sha256:2efb1bd13885392adfda4614c33d3b68dee4921fd0ac1d3988f8cbb7d589e72a", "sha256:2e81c7b9c8979ce92ed306c249d46894776a909505d8f5a4ba55b14206e3222f",
"sha256:2f4ac36d8e2b4cc1aa71df3dd84ff8efbe3bfb97ac41242fbcfc053c67434f46", "sha256:3287761bc4ee9e33561a7e058c72ac0938c4f57fe49a09eae428fd88aafe7bb6",
"sha256:3170c9399da12c9dc66366e9d14da8bf7147e1e9d9ea566067bbce7bb74bd9c2", "sha256:34d1c8da1e78d2e001f363791c98a272bb734000fcef47a491c1e3b0505657a8",
"sha256:3b1613dd5aee995ec6d4c69f00378bbd07614702a315a2cf6c1d21461fe17c23", "sha256:37e55c8e51c236f95b033f6fb391d7d7970ba5fe7ff453dad675e88cf303377a",
"sha256:3bb3d25a8e6c0aedd251753a79ae98a093c7e7b471faa3aa9a93a81431987ace", "sha256:3d47fa203a7bd9c5b6cee4736ee84ca03b8ef23193c0d1ca99b5089f72645c73",
"sha256:3bb7fda7260735efe66d5107fb7e6af6a7c04c7fce9b2514e04b7a74b06bf5dd", "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc",
"sha256:41b25eaa7d15909cf3ac4c96088c1f266a9a93ec44f87f1d13d4a0e86c81b982", "sha256:42cb296636fcc8b0644486d15c12376cb9fa75443e00fb25de0b8602e64c1714",
"sha256:45de3f87179c1823e6d9e32156fb14c1927fcc9aba21433f088fdfb555b77c10", "sha256:45485e01ff4d3630ec0d9617310448a8702f70e9c01906b0d0118bdf9d124cf2",
"sha256:46fb8c61d794b78ec7134a715a3e564aafc8f6b5e338417cb19fe9f57a5a9bf2", "sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc",
"sha256:48021783bdf96e3d6de03a6e39a1171ed5bd7e8bb93fc84cc649d11490f87cea", "sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce",
"sha256:4957669ef390f0e6719db3613ab3a7631e68424604a7b448f079bee145da6e09", "sha256:4d0d1650369165a14e14e1e47b372cfcb31d6ab44e6e33cb2d4e57265290044d",
"sha256:5e86d77b090dbddbe78867a0275cb4df08ea195e660f1f7f13435a4649e954e5", "sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e",
"sha256:6339d047dab2780cc6220f46306628e04d9750f02f983ddb37439ca47ced7149", "sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6",
"sha256:681eb3d7e02e3c3655d1b16059fbfb605ac464c834a0c629048a30fad2b27489", "sha256:572c3763a264ba47b3cf708a44ce965d98555f618ca42c926a9c1616d8f34269",
"sha256:6c409c0deba34f147f77efaa67b8e4bb83d2f11c8806405f76397ae5b8c0d1c9", "sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96",
"sha256:7095f6fbfaa55defb6b733cfeb14efaae7a29f0b59d8cf213be4e7ca0b857b80", "sha256:5b4c145409bef602a690e7cfad0a15a55c13320ff7a3ad7ca59c13bb8ba4d45d",
"sha256:70c610f6cbe4b9fce272c407dd9d07e33e6bf7b4aa1b7ffb6f6ded8e634e3592", "sha256:6463effa3186ea09411d50efc7d85360b38d5f09b870c48e4600f63af490e56a",
"sha256:72814c01533f51d68702802d74f77ea026b5ec52793c791e2da806a3844a46c3", "sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4",
"sha256:7a4826ad2bd6b07ca615c74ab91f32f6c96d08f6fcc3902ceeedaec8cdc3bcd6", "sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77",
"sha256:7c70087bfee18a42b4040bb9ec1ca15a08242cf5867c58726530bdf3945672ed", "sha256:6897af51655e3691ff853668779c7bad41579facacf5fd7253b0133308cf000d",
"sha256:855eafa5d5a2034b4621c74925d89c5efef61418570e5ef9b37717d9c796419c", "sha256:68d1f8a9e9e37c1223b656399be5d6b448dea850bed7d0f87a8311f1ff3dabb0",
"sha256:8700f06d0ce6f128de3ccdbc1acaea1ee264d2caa9ca05daaf492fde7c2a7200", "sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed",
"sha256:89f1b185a01fe560bc8ae5f619e924407efca2191b56ce749ec84982fc59a32a", "sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068",
"sha256:8b2c760cfc7042b27ebdb4a43a4453bd829a5742503599144d54a032c5dc7e9e", "sha256:6c4caeef8fa63d06bd437cd4bdcf3ffefe6738fb1b25951440d80dc7df8c03ac",
"sha256:8c2f5e83493748286002f9369f3e6607c565a6a90425a3a1fef5ae32a36d749d", "sha256:6ef1d82a3af9d3eecdba2321dc1b3c238245d890843e040e41e470ffa64c3e25",
"sha256:8e098148dd37b4ce3baca71fb394c81dc5d9c7728c95df695d2dca218edf40e6", "sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8",
"sha256:94aea8eff76ee6d1cdacb07dd2123a68283cb5569e0250feab1240058f53b623", "sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab",
"sha256:95eb302ff792e12aba9a8b8f8474ab229a83c103d74a750ec0bd1c1eea32e669", "sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26",
"sha256:9bd9b3b31adcb054116447ea22caa61a285d92e94d710aa5ec97992ff5eb7cf3", "sha256:7f04c839ed0b6b98b1a7501a002144b76c18fb1c1850c8b98d458ac269e26ed2",
"sha256:9e608aafdb55eb9f255034709e20d5a83b6d60c054df0802fa9c9883d0a937aa", "sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db",
"sha256:a103b3a7069b62f5d4890ae1b8f0597618f628b286b03d4bc9195230b154bfa9", "sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f",
"sha256:a386ebe437176aab38c041de1260cd3ea459c6ce5263594399880bbc398225b2", "sha256:8465322196c8b4d7ab6d1e049e4c5cb460d0394da4a27d23cc242fbf0034b6b5",
"sha256:a38856a971c602f98472050165cea2cdc97709240373041b69030be15047691f", "sha256:86216b5cee4b06df986d214f664305142d9c76df9b6512be2738aa72a2048f99",
"sha256:a401b4598e5d3f4a9a811f3daf42ee2291790c7f9d74b18d75d6e21dda98a1a1", "sha256:87d1351268731db79e0f8e745d92493ee2841c974128ef629dc518b937d9194c",
"sha256:a7647ebdfb9682b7bb97e2a5e7cb6ae735b1c25008a70b906aecca294ee96cf4", "sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d",
"sha256:aaf63899c94de41fe3cf934601b0f7ccb6b428c6e4eeb80da72c58eab077b19a", "sha256:8c622a5fe39a48f78944a87d4fb8a53ee07344641b0562c540d840748571b811",
"sha256:b0dac0ff919ba34d4df1b6131f59ce95b08b9065233446be7e459f95554c0dc8", "sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa",
"sha256:baacc6aee0b2ef6f3d308e197b5d7a81c0e70b06beae1f1fcacffdbd124fe0e3", "sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a",
"sha256:bf420121d4c8dce6b889f0e8e4ec0ca34b7f40186203f06a946fa0276ba54029", "sha256:9063e24fdb1e498ab71cb7419e24622516c4a04476b17a2dab57e8baa30d6e03",
"sha256:c04a46716adde8d927adb9457bbe39cf473e1e2c2f5d0a16ceb837e5d841ad4f", "sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b",
"sha256:c0b21078a4b56965e2b12f247467b234734491897e99c1d51cee628da9786959", "sha256:923c0c831b7cfcb071580d3f46c4baf50f174be571576556269530f4bbd79d04",
"sha256:c1c76a1743432b4b60ab3358c937a3fe1341c828ae6194108a94c69028247f22", "sha256:95f2a5796329323b8f0512e09dbb7a1860c46a39da62ecb2324f116fa8fdc85c",
"sha256:c4983bf937209c57240cff65906b18bb35e64ae872da6a0db937d7b4af845dd7", "sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001",
"sha256:c4fb39a81950ec280984b3a44f5bd12819953dc5fa3a7e6fa7a80db5ee853952", "sha256:9f96df6923e21816da7e0ad3fd47dd8f94b2a5ce594e00677c0013018b813458",
"sha256:c57921cda3a80d0f2b8aec7e25c8aa14479ea92b5b51b6876d975d925a2ea346", "sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389",
"sha256:c8063cf17b19661471ecbdb3df1c84f24ad2e389e326ccaf89e3fb2484d8dd7e", "sha256:a50aebfa173e157099939b17f18600f72f84eed3049e743b68ad15bd69b6bf99",
"sha256:ccd16eb18a849fd8dcb23e23380e2f0a354e8daa0c984b8a732d9cfaba3a776d", "sha256:a981a536974bbc7a512cf44ed14938cf01030a99e9b3a06dd59578882f06f985",
"sha256:cd6dbe0238f7743d0efe563ab46294f54f9bc8f4b9bcf57c3c666cc5bc9d1299", "sha256:a9a8e9031d613fd2009c182b69c7b2c1ef8239a0efb1df3f7c8da66d5dd3d537",
"sha256:d62e51710986674142526ab9f78663ca2b0726066ae26b78b22e0f5e571238dd", "sha256:ae5f4161f18c61806f411a13b0310bea87f987c7d2ecdbdaad0e94eb2e404238",
"sha256:db901e2ac34c931d73054d9797383d0f8009991e723dab15109740a63e7f902a", "sha256:aed38f6e4fb3f5d6bf81bfa990a07806be9d83cf7bacef998ab1a9bd660a581f",
"sha256:e03b8895a6990c9ab2cdcd0f2fe44088ca1c65ae592b8f795c3294af00a461c3", "sha256:b01b88d45a6fcb69667cd6d2f7a9aeb4bf53760d7fc536bf679ec94fe9f3ff3d",
"sha256:e1c8a2f4c69e08e89632defbfabec2feb8a8d99edc9f89ce33c4b9e36ab63037", "sha256:b261ccdec7821281dade748d088bb6e9b69e6d15b30652b74cbbac25e280b796",
"sha256:e4b749b9cc6ee664a3300bb3a273c1ca8068c46be705b6c31cf5d276f8628a94", "sha256:b2b0a0c0517616b6869869f8c581d4eb2dd83a4d79e0ebcb7d373ef9956aeb0a",
"sha256:e6a5bf2cba5ae1bb80b154ed68a3cfa2fa00fde979a7f50d6598d3e17d9ac20c", "sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143",
"sha256:e857a2232ba53ae940d3456f7533ce6ca98b81917d47adc3c7fd55dad8fab858", "sha256:bd8f7df7d12c2db9fab40bdd87a7c09b1530128315d047a086fa3ae3435cb3a8",
"sha256:ee4006268ed33370957f55bf2e6f4d263eaf4dc3cfc473d1d90baff6ed36ce4a", "sha256:beb58fe5cdb101e3a055192ac291b7a21e3b7ef4f67fa1d74e331a7f2124341c",
"sha256:eef9df1eefada2c09a5e7a40991b9fc6ac6ef20b1372abd48d2794a316dc0449", "sha256:c002b4ffc0be611f0d9da932eb0f704fe2602a9a949d1f738e4c34c75b0863d5",
"sha256:f058f6963fd82eb143c692cecdc89e075fa0828db2e5b291070485390b2f1c9c", "sha256:c083af607d2515612056a31f0a8d9e0fcb5876b7bfc0abad3ecd275bc4ebc2d5",
"sha256:f25c229a6ba38a35ae6e25ca1264621cc25d4d38dca2942a7fce0b67a4efe918", "sha256:c180f51afb394e165eafe4ac2936a14bee3eb10debc9d9e4db8958fe36afe711",
"sha256:f2a1d0fd4242bd8643ce6f98927cf9c04540af6efa92323e9d3124f57727bfc1", "sha256:c235ebd9baae02f1b77bcea61bce332cb4331dc3617d254df3323aa01ab47bd4",
"sha256:f7560358a6811e52e9c4d142d497f1a6e10103d3a6881f18d04dbce3729c0e2c", "sha256:cd70574b12bb8a4d2aaa0094515df2463cb429d8536cfb6c7ce983246983e5a6",
"sha256:f779d3ad205f108d14e99bb3859aa7dd8e9c68874617c72354d7ecaec2a054ac", "sha256:d0eccceffcb53201b5bfebb52600a5fb483a20b61da9dbc885f8b103cbe7598c",
"sha256:f87f746ee241d30d6ed93969de31e5ffd09a2961a051e60ae6bddde9ec3583aa" "sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7",
"sha256:db364eca23f876da6f9e16c9da0df51aa4f104a972735574842618b8c6d999d4",
"sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b",
"sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae",
"sha256:e06ed3eb3218bc64786f7db41917d4e686cc4856944f53d5bdf83a6884432e12",
"sha256:e27ad930a842b4c5eb8ac0016b0a54f5aebbe679340c26101df33424142c143c",
"sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae",
"sha256:eb00ed941194665c332bf8e078baf037d6c35d7c4f3102ea2d4f16ca94a26dc8",
"sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887",
"sha256:eb8821e09e916165e160797a6c17edda0679379a4be5c716c260e836e122f54b",
"sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4",
"sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f",
"sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5",
"sha256:fb69256e180cb6c8a894fee62b3afebae785babc1ee98b81cdf68bbca1987f33",
"sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519",
"sha256:ff8fa367d09b717b2a17a052544193ad76cd49979c805768879cb63d9ca50561"
], ],
"markers": "python_full_version >= '3.7.0'", "markers": "python_full_version >= '3.7.0'",
"version": "==3.2.0" "version": "==3.3.2"
}, },
"click": { "click": {
"hashes": [ "hashes": [
"sha256:48ee849951919527a045bfe3bf7baa8a959c423134e1a5b98c05c20ba75a1cbd", "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28",
"sha256:fa244bb30b3b5ee2cae3da8f55c9e5e0c0e86093306301fb418eb9dc40fbded5" "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"
], ],
"markers": "python_version >= '3.7'", "markers": "python_version >= '3.7'",
"version": "==8.1.6" "version": "==8.1.7"
}, },
"colorama": { "colorama": {
"hashes": [ "hashes": [
@ -140,11 +155,11 @@
}, },
"dnspython": { "dnspython": {
"hashes": [ "hashes": [
"sha256:5b7488477388b8c0b70a8ce93b227c5603bc7b77f1565afe8e729c36c51447d7", "sha256:57c6fbaaeaaf39c891292012060beb141791735dbb4004798328fc2c467402d8",
"sha256:c33971c79af5be968bb897e95c2448e11a645ee84d93b265ce0b7aabe5dfdca8" "sha256:8dcfae8c7460a2f84b4072e26f1c9f4101ca20c071649cb7c34e8b6a93d58984"
], ],
"markers": "python_version >= '3.8' and python_version < '4.0'", "markers": "python_version >= '3.8' and python_version < '4.0'",
"version": "==2.4.1" "version": "==2.4.2"
}, },
"dominate": { "dominate": {
"hashes": [ "hashes": [
@ -156,19 +171,19 @@
}, },
"email-validator": { "email-validator": {
"hashes": [ "hashes": [
"sha256:1ff6e86044200c56ae23595695c54e9614f4a9551e0e393614f764860b3d7900", "sha256:a4b0bd1cf55f073b924258d19321b1f3aa74b4b5a71a42c305575dba920e1a44",
"sha256:2466ba57cda361fb7309fd3d5a225723c788ca4bbad32a0ebd5373b99730285c" "sha256:c973053efbeddfef924dc0bd93f6e77a1ea7ee0fce935aea7103c7a3d6d2d637"
], ],
"index": "pypi", "index": "pypi",
"version": "==2.0.0.post2" "version": "==2.1.0.post1"
}, },
"flask": { "flask": {
"hashes": [ "hashes": [
"sha256:77fd4e1249d8c9923de34907236b747ced06e5467ecac1a7bb7115ae0e9670b0", "sha256:21128f47e4e3b9d597a3e8521a329bf56909b690fcc3fa3e477725aa81367638",
"sha256:8c2f9abd47a9e8df7f0c3f091ce9497d011dc3b31effcf4c85a6e2b50f4114ef" "sha256:cfadcdb638b609361d29ec22360d6070a77d7463dcb3ab08d2c2f2f168845f58"
], ],
"index": "pypi", "index": "pypi",
"version": "==2.3.2" "version": "==3.0.0"
}, },
"flask-bootstrap": { "flask-bootstrap": {
"hashes": [ "hashes": [
@ -187,11 +202,11 @@
}, },
"flask-login": { "flask-login": {
"hashes": [ "hashes": [
"sha256:1ef79843f5eddd0f143c2cd994c1b05ac83c0401dc6234c143495af9a939613f", "sha256:5e23d14a607ef12806c699590b89d0f0e0d67baeec599d75947bf9c147330333",
"sha256:c0a7baa9fdc448cdd3dd6f0939df72eec5177b2f7abe6cb82fc934d29caac9c3" "sha256:849b25b82a436bf830a054e74214074af59097171562ab10bfa999e6b78aae5d"
], ],
"index": "pypi", "index": "pypi",
"version": "==0.6.2" "version": "==0.6.3"
}, },
"flask-mail": { "flask-mail": {
"hashes": [ "hashes": [
@ -210,93 +225,90 @@
}, },
"flask-migrate": { "flask-migrate": {
"hashes": [ "hashes": [
"sha256:73293d40b10ac17736e715b377e7b7bde474cb8105165d77474df4c3619b10b3", "sha256:613a2df703998e78716cace68cd83972960834424457f5b67f56e74fff950aef",
"sha256:77580f27ab39bc68be4906a43c56d7674b45075bc4f883b1d0b985db5164d58f" "sha256:d3f437a8b5f3849d1bb1b60e1b818efc564c66e3fefe90b62e5db08db295e1b1"
], ],
"index": "pypi", "index": "pypi",
"version": "==4.0.4" "version": "==4.0.5"
}, },
"flask-sqlalchemy": { "flask-sqlalchemy": {
"hashes": [ "hashes": [
"sha256:c5765e58ca145401b52106c0f46178569243c5da25556be2c231ecc60867c5b1", "sha256:4ba4be7f419dc72f4efd8802d69974803c37259dd42f3913b0dcf75c9447e0a0",
"sha256:cabb6600ddd819a9f859f36515bb1bd8e7dbf30206cc679d2b081dff9e383283" "sha256:e4b68bb881802dda1a7d878b2fc84c06d1ee57fb40b874d3dc97dabfa36b8312"
], ],
"index": "pypi", "index": "pypi",
"version": "==3.0.5" "version": "==3.1.1"
}, },
"flask-wtf": { "flask-wtf": {
"hashes": [ "hashes": [
"sha256:41c4244e9ae626d63bed42ae4785b90667b885b1535d5a4095e1f63060d12aa9", "sha256:8bb269eb9bb46b87e7c8233d7e7debdf1f8b74bf90cc1789988c29b37a97b695",
"sha256:7887d6f1ebb3e17bf648647422f0944c9a469d0fcf63e3b66fb9a83037e38b2c" "sha256:fa6793f2fb7e812e0fe9743b282118e581fb1b6c45d414b8af05e659bd653287"
], ],
"index": "pypi", "index": "pypi",
"version": "==1.1.1" "version": "==1.2.1"
}, },
"greenlet": { "greenlet": {
"hashes": [ "hashes": [
"sha256:03a8f4f3430c3b3ff8d10a2a86028c660355ab637cee9333d63d66b56f09d52a", "sha256:0a02d259510b3630f330c86557331a3b0e0c79dac3d166e449a39363beaae174",
"sha256:0bf60faf0bc2468089bdc5edd10555bab6e85152191df713e2ab1fcc86382b5a", "sha256:0b6f9f8ca7093fd4433472fd99b5650f8a26dcd8ba410e14094c1e44cd3ceddd",
"sha256:18a7f18b82b52ee85322d7a7874e676f34ab319b9f8cce5de06067384aa8ff43", "sha256:100f78a29707ca1525ea47388cec8a049405147719f47ebf3895e7509c6446aa",
"sha256:18e98fb3de7dba1c0a852731c3070cf022d14f0d68b4c87a19cc1016f3bb8b33", "sha256:1757936efea16e3f03db20efd0cd50a1c86b06734f9f7338a90c4ba85ec2ad5a",
"sha256:1a819eef4b0e0b96bb0d98d797bef17dc1b4a10e8d7446be32d1da33e095dbb8", "sha256:19075157a10055759066854a973b3d1325d964d498a805bb68a1f9af4aaef8ec",
"sha256:26fbfce90728d82bc9e6c38ea4d038cba20b7faf8a0ca53a9c07b67318d46088", "sha256:19bbdf1cce0346ef7341705d71e2ecf6f41a35c311137f29b8a2dc2341374565",
"sha256:2780572ec463d44c1d3ae850239508dbeb9fed38e294c68d19a24d925d9223ca", "sha256:20107edf7c2c3644c67c12205dc60b1bb11d26b2610b276f97d666110d1b511d",
"sha256:283737e0da3f08bd637b5ad058507e578dd462db259f7f6e4c5c365ba4ee9343", "sha256:22f79120a24aeeae2b4471c711dcf4f8c736a2bb2fabad2a67ac9a55ea72523c",
"sha256:2d4686f195e32d36b4d7cf2d166857dbd0ee9f3d20ae349b6bf8afc8485b3645", "sha256:2847e5d7beedb8d614186962c3d774d40d3374d580d2cbdab7f184580a39d234",
"sha256:2dd11f291565a81d71dab10b7033395b7a3a5456e637cf997a6f33ebdf06f8db", "sha256:28e89e232c7593d33cac35425b58950789962011cc274aa43ef8865f2e11f46d",
"sha256:30bcf80dda7f15ac77ba5af2b961bdd9dbc77fd4ac6105cee85b0d0a5fcf74df", "sha256:329c5a2e5a0ee942f2992c5e3ff40be03e75f745f48847f118a3cfece7a28546",
"sha256:32e5b64b148966d9cccc2c8d35a671409e45f195864560829f395a54226408d3", "sha256:337322096d92808f76ad26061a8f5fccb22b0809bea39212cd6c406f6a7060d2",
"sha256:36abbf031e1c0f79dd5d596bfaf8e921c41df2bdf54ee1eed921ce1f52999a86", "sha256:3fcc780ae8edbb1d050d920ab44790201f027d59fdbd21362340a85c79066a74",
"sha256:3a06ad5312349fec0ab944664b01d26f8d1f05009566339ac6f63f56589bc1a2", "sha256:41bdeeb552d814bcd7fb52172b304898a35818107cc8778b5101423c9017b3de",
"sha256:3a51c9751078733d88e013587b108f1b7a1fb106d402fb390740f002b6f6551a", "sha256:4eddd98afc726f8aee1948858aed9e6feeb1758889dfd869072d4465973f6bfd",
"sha256:3c9b12575734155d0c09d6c3e10dbd81665d5c18e1a7c6597df72fd05990c8cf", "sha256:52e93b28db27ae7d208748f45d2db8a7b6a380e0d703f099c949d0f0d80b70e9",
"sha256:3f6ea9bd35eb450837a3d80e77b517ea5bc56b4647f5502cd28de13675ee12f7", "sha256:55d62807f1c5a1682075c62436702aaba941daa316e9161e4b6ccebbbf38bda3",
"sha256:4b58adb399c4d61d912c4c331984d60eb66565175cdf4a34792cd9600f21b394", "sha256:5805e71e5b570d490938d55552f5a9e10f477c19400c38bf1d5190d760691846",
"sha256:4d2e11331fc0c02b6e84b0d28ece3a36e0548ee1a1ce9ddde03752d9b79bba40", "sha256:599daf06ea59bfedbec564b1692b0166a0045f32b6f0933b0dd4df59a854caf2",
"sha256:5454276c07d27a740c5892f4907c86327b632127dd9abec42ee62e12427ff7e3", "sha256:60d5772e8195f4e9ebf74046a9121bbb90090f6550f81d8956a05387ba139353",
"sha256:561091a7be172ab497a3527602d467e2b3fbe75f9e783d8b8ce403fa414f71a6", "sha256:696d8e7d82398e810f2b3622b24e87906763b6ebfd90e361e88eb85b0e554dc8",
"sha256:6c3acb79b0bfd4fe733dff8bc62695283b57949ebcca05ae5c129eb606ff2d74", "sha256:6e6061bf1e9565c29002e3c601cf68569c450be7fc3f7336671af7ddb4657166",
"sha256:703f18f3fda276b9a916f0934d2fb6d989bf0b4fb5a64825260eb9bfd52d78f0", "sha256:80ac992f25d10aaebe1ee15df45ca0d7571d0f70b645c08ec68733fb7a020206",
"sha256:7492e2b7bd7c9b9916388d9df23fa49d9b88ac0640db0a5b4ecc2b653bf451e3", "sha256:816bd9488a94cba78d93e1abb58000e8266fa9cc2aa9ccdd6eb0696acb24005b",
"sha256:76ae285c8104046b3a7f06b42f29c7b73f77683df18c49ab5af7983994c2dd91", "sha256:85d2b77e7c9382f004b41d9c72c85537fac834fb141b0296942d52bf03fe4a3d",
"sha256:7cafd1208fdbe93b67c7086876f061f660cfddc44f404279c1585bbf3cdc64c5", "sha256:87c8ceb0cf8a5a51b8008b643844b7f4a8264a2c13fcbcd8a8316161725383fe",
"sha256:7efde645ca1cc441d6dc4b48c0f7101e8d86b54c8530141b09fd31cef5149ec9", "sha256:89ee2e967bd7ff85d84a2de09df10e021c9b38c7d91dead95b406ed6350c6997",
"sha256:88d9ab96491d38a5ab7c56dd7a3cc37d83336ecc564e4e8816dbed12e5aaefc8", "sha256:8bef097455dea90ffe855286926ae02d8faa335ed8e4067326257cb571fc1445",
"sha256:8eab883b3b2a38cc1e050819ef06a7e6344d4a990d24d45bc6f2cf959045a45b", "sha256:8d11ebbd679e927593978aa44c10fc2092bc454b7d13fdc958d3e9d508aba7d0",
"sha256:910841381caba4f744a44bf81bfd573c94e10b3045ee00de0cbf436fe50673a6", "sha256:91e6c7db42638dc45cf2e13c73be16bf83179f7859b07cfc139518941320be96",
"sha256:9190f09060ea4debddd24665d6804b995a9c122ef5917ab26e1566dcc712ceeb", "sha256:97e7ac860d64e2dcba5c5944cfc8fa9ea185cd84061c623536154d5a89237884",
"sha256:937e9020b514ceedb9c830c55d5c9872abc90f4b5862f89c0887033ae33c6f73", "sha256:990066bff27c4fcf3b69382b86f4c99b3652bab2a7e685d968cd4d0cfc6f67c6",
"sha256:94c817e84245513926588caf1152e3b559ff794d505555211ca041f032abbb6b", "sha256:9fbc5b8f3dfe24784cee8ce0be3da2d8a79e46a276593db6868382d9c50d97b1",
"sha256:971ce5e14dc5e73715755d0ca2975ac88cfdaefcaab078a284fea6cfabf866df", "sha256:ac4a39d1abae48184d420aa8e5e63efd1b75c8444dd95daa3e03f6c6310e9619",
"sha256:9d14b83fab60d5e8abe587d51c75b252bcc21683f24699ada8fb275d7712f5a9", "sha256:b2c02d2ad98116e914d4f3155ffc905fd0c025d901ead3f6ed07385e19122c94",
"sha256:9f35ec95538f50292f6d8f2c9c9f8a3c6540bbfec21c9e5b4b751e0a7c20864f", "sha256:b2d3337dcfaa99698aa2377c81c9ca72fcd89c07e7eb62ece3f23a3fe89b2ce4",
"sha256:a1846f1b999e78e13837c93c778dcfc3365902cfb8d1bdb7dd73ead37059f0d0", "sha256:b489c36d1327868d207002391f662a1d163bdc8daf10ab2e5f6e41b9b96de3b1",
"sha256:acd2162a36d3de67ee896c43effcd5ee3de247eb00354db411feb025aa319857", "sha256:b641161c302efbb860ae6b081f406839a8b7d5573f20a455539823802c655f63",
"sha256:b0ef99cdbe2b682b9ccbb964743a6aca37905fda5e0452e5ee239b1654d37f2a", "sha256:b8ba29306c5de7717b5761b9ea74f9c72b9e2b834e24aa984da99cbfc70157fd",
"sha256:b80f600eddddce72320dbbc8e3784d16bd3fb7b517e82476d8da921f27d4b249", "sha256:b9934adbd0f6e476f0ecff3c94626529f344f57b38c9a541f87098710b18af0a",
"sha256:b864ba53912b6c3ab6bcb2beb19f19edd01a6bfcbdfe1f37ddd1778abfe75a30", "sha256:ce85c43ae54845272f6f9cd8320d034d7a946e9773c693b27d620edec825e376",
"sha256:b9ec052b06a0524f0e35bd8790686a1da006bd911dd1ef7d50b77bfbad74e292", "sha256:cf868e08690cb89360eebc73ba4be7fb461cfbc6168dd88e2fbbe6f31812cd57",
"sha256:ba2956617f1c42598a308a84c6cf021a90ff3862eddafd20c3333d50f0edb45b", "sha256:d2905ce1df400360463c772b55d8e2518d0e488a87cdea13dd2c71dcb2a1fa16",
"sha256:bdfea8c661e80d3c1c99ad7c3ff74e6e87184895bbaca6ee8cc61209f8b9b85d", "sha256:d57e20ba591727da0c230ab2c3f200ac9d6d333860d85348816e1dca4cc4792e",
"sha256:be4ed120b52ae4d974aa40215fcdfde9194d63541c7ded40ee12eb4dda57b76b", "sha256:d6a8c9d4f8692917a3dc7eb25a6fb337bff86909febe2f793ec1928cd97bedfc",
"sha256:c4302695ad8027363e96311df24ee28978162cdcdd2006476c43970b384a244c", "sha256:d923ff276f1c1f9680d32832f8d6c040fe9306cbfb5d161b0911e9634be9ef0a",
"sha256:c48f54ef8e05f04d6eff74b8233f6063cb1ed960243eacc474ee73a2ea8573ca", "sha256:daa7197b43c707462f06d2c693ffdbb5991cbb8b80b5b984007de431493a319c",
"sha256:c9c59a2120b55788e800d82dfa99b9e156ff8f2227f07c5e3012a45a399620b7", "sha256:dbd4c177afb8a8d9ba348d925b0b67246147af806f0b104af4d24f144d461cd5",
"sha256:cd021c754b162c0fb55ad5d6b9d960db667faad0fa2ff25bb6e1301b0b6e6a75", "sha256:dc4d815b794fd8868c4d67602692c21bf5293a75e4b607bb92a11e821e2b859a",
"sha256:d27ec7509b9c18b6d73f2f5ede2622441de812e7b1a80bbd446cb0633bd3d5ae", "sha256:e9d21aaa84557d64209af04ff48e0ad5e28c5cca67ce43444e939579d085da72",
"sha256:d5508f0b173e6aa47273bdc0a0b5ba055b59662ba7c7ee5119528f466585526b", "sha256:ea6b8aa9e08eea388c5f7a276fabb1d4b6b9d6e4ceb12cc477c3d352001768a9",
"sha256:d75209eed723105f9596807495d58d10b3470fa6732dd6756595e89925ce2470", "sha256:eabe7090db68c981fca689299c2d116400b553f4b713266b130cfc9e2aa9c5a9",
"sha256:db1a39669102a1d8d12b57de2bb7e2ec9066a6f2b3da35ae511ff93b01b5d564", "sha256:f2f6d303f3dee132b322a14cd8765287b8f86cdc10d2cb6a6fae234ea488888e",
"sha256:dbfcfc0218093a19c252ca8eb9aee3d29cfdcb586df21049b9d777fd32c14fd9", "sha256:f33f3258aae89da191c6ebaa3bc517c6c4cbc9b9f689e5d8452f7aedbb913fa8",
"sha256:e0f72c9ddb8cd28532185f54cc1453f2c16fb417a08b53a855c4e6a418edd099", "sha256:f7bfb769f7efa0eefcd039dd19d843a4fbfbac52f1878b1da2ed5793ec9b1a65",
"sha256:e7c8dc13af7db097bed64a051d2dd49e9f0af495c26995c00a9ee842690d34c0", "sha256:f89e21afe925fcfa655965ca8ea10f24773a1791400989ff32f467badfe4a064",
"sha256:ea9872c80c132f4663822dd2a08d404073a5a9b5ba6155bea72fb2a79d1093b5", "sha256:fa24255ae3c0ab67e613556375a4341af04a084bd58764731972bcbc8baeba36"
"sha256:eff4eb9b7eb3e4d0cae3d28c283dc16d9bed6b193c2e1ace3ed86ce48ea8df19",
"sha256:f82d4d717d8ef19188687aa32b8363e96062911e63ba22a0cff7802a8e58e5f1",
"sha256:fc3a569657468b6f3fb60587e48356fe512c1754ca05a564f11366ac9e306526"
], ],
"markers": "platform_machine == 'aarch64' or (platform_machine == 'ppc64le' or (platform_machine == 'x86_64' or (platform_machine == 'amd64' or (platform_machine == 'AMD64' or (platform_machine == 'win32' or platform_machine == 'WIN32')))))", "markers": "platform_machine == 'aarch64' or (platform_machine == 'ppc64le' or (platform_machine == 'x86_64' or (platform_machine == 'amd64' or (platform_machine == 'AMD64' or (platform_machine == 'win32' or platform_machine == 'WIN32')))))",
"version": "==2.0.2" "version": "==3.0.1"
}, },
"idna": { "idna": {
"hashes": [ "hashes": [
@ -306,6 +318,14 @@
"markers": "python_version >= '3.5'", "markers": "python_version >= '3.5'",
"version": "==3.4" "version": "==3.4"
}, },
"iniconfig": {
"hashes": [
"sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3",
"sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"
],
"markers": "python_version >= '3.7'",
"version": "==2.0.0"
},
"itsdangerous": { "itsdangerous": {
"hashes": [ "hashes": [
"sha256:2c2349112351b88699d8d4b6b075022c0808887cb7ad10069318a8b0bc88db44", "sha256:2c2349112351b88699d8d4b6b075022c0808887cb7ad10069318a8b0bc88db44",
@ -336,8 +356,11 @@
"sha256:0a4e4a1aff6c7ac4cd55792abf96c915634c2b97e3cc1c7129578aa68ebd754e", "sha256:0a4e4a1aff6c7ac4cd55792abf96c915634c2b97e3cc1c7129578aa68ebd754e",
"sha256:10bbfe99883db80bdbaff2dcf681dfc6533a614f700da1287707e8a5d78a8431", "sha256:10bbfe99883db80bdbaff2dcf681dfc6533a614f700da1287707e8a5d78a8431",
"sha256:134da1eca9ec0ae528110ccc9e48041e0828d79f24121a1a146161103c76e686", "sha256:134da1eca9ec0ae528110ccc9e48041e0828d79f24121a1a146161103c76e686",
"sha256:14ff806850827afd6b07a5f32bd917fb7f45b046ba40c57abdb636674a8b559c",
"sha256:1577735524cdad32f9f694208aa75e422adba74f1baee7551620e43a3141f559", "sha256:1577735524cdad32f9f694208aa75e422adba74f1baee7551620e43a3141f559",
"sha256:1b40069d487e7edb2676d3fbdb2b0829ffa2cd63a2ec26c4938b2d34391b4ecc", "sha256:1b40069d487e7edb2676d3fbdb2b0829ffa2cd63a2ec26c4938b2d34391b4ecc",
"sha256:1b8dd8c3fd14349433c79fa8abeb573a55fc0fdd769133baac1f5e07abf54aeb",
"sha256:1f67c7038d560d92149c060157d623c542173016c4babc0c1913cca0564b9939",
"sha256:282c2cb35b5b673bbcadb33a585408104df04f14b2d9b01d4c345a3b92861c2c", "sha256:282c2cb35b5b673bbcadb33a585408104df04f14b2d9b01d4c345a3b92861c2c",
"sha256:2c1b19b3aaacc6e57b7e25710ff571c24d6c3613a45e905b1fde04d691b98ee0", "sha256:2c1b19b3aaacc6e57b7e25710ff571c24d6c3613a45e905b1fde04d691b98ee0",
"sha256:2ef12179d3a291be237280175b542c07a36e7f60718296278d8593d21ca937d4", "sha256:2ef12179d3a291be237280175b542c07a36e7f60718296278d8593d21ca937d4",
@ -345,6 +368,7 @@
"sha256:3c0fae6c3be832a0a0473ac912810b2877c8cb9d76ca48de1ed31e1c68386575", "sha256:3c0fae6c3be832a0a0473ac912810b2877c8cb9d76ca48de1ed31e1c68386575",
"sha256:3fd4abcb888d15a94f32b75d8fd18ee162ca0c064f35b11134be77050296d6ba", "sha256:3fd4abcb888d15a94f32b75d8fd18ee162ca0c064f35b11134be77050296d6ba",
"sha256:42de32b22b6b804f42c5d98be4f7e5e977ecdd9ee9b660fda1a3edf03b11792d", "sha256:42de32b22b6b804f42c5d98be4f7e5e977ecdd9ee9b660fda1a3edf03b11792d",
"sha256:47d4f1c5f80fc62fdd7777d0d40a2e9dda0a05883ab11374334f6c4de38adffd",
"sha256:504b320cd4b7eff6f968eddf81127112db685e81f7e36e75f9f84f0df46041c3", "sha256:504b320cd4b7eff6f968eddf81127112db685e81f7e36e75f9f84f0df46041c3",
"sha256:525808b8019e36eb524b8c68acdd63a37e75714eac50e988180b169d64480a00", "sha256:525808b8019e36eb524b8c68acdd63a37e75714eac50e988180b169d64480a00",
"sha256:56d9f2ecac662ca1611d183feb03a3fa4406469dafe241673d521dd5ae92a155", "sha256:56d9f2ecac662ca1611d183feb03a3fa4406469dafe241673d521dd5ae92a155",
@ -353,6 +377,7 @@
"sha256:68e78619a61ecf91e76aa3e6e8e33fc4894a2bebe93410754bd28fce0a8a4f9f", "sha256:68e78619a61ecf91e76aa3e6e8e33fc4894a2bebe93410754bd28fce0a8a4f9f",
"sha256:69c0f17e9f5a7afdf2cc9fb2d1ce6aabdb3bafb7f38017c0b77862bcec2bbad8", "sha256:69c0f17e9f5a7afdf2cc9fb2d1ce6aabdb3bafb7f38017c0b77862bcec2bbad8",
"sha256:6b2b56950d93e41f33b4223ead100ea0fe11f8e6ee5f641eb753ce4b77a7042b", "sha256:6b2b56950d93e41f33b4223ead100ea0fe11f8e6ee5f641eb753ce4b77a7042b",
"sha256:715d3562f79d540f251b99ebd6d8baa547118974341db04f5ad06d5ea3eb8007",
"sha256:787003c0ddb00500e49a10f2844fac87aa6ce977b90b0feaaf9de23c22508b24", "sha256:787003c0ddb00500e49a10f2844fac87aa6ce977b90b0feaaf9de23c22508b24",
"sha256:7ef3cb2ebbf91e330e3bb937efada0edd9003683db6b57bb108c4001f37a02ea", "sha256:7ef3cb2ebbf91e330e3bb937efada0edd9003683db6b57bb108c4001f37a02ea",
"sha256:8023faf4e01efadfa183e863fefde0046de576c6f14659e8782065bcece22198", "sha256:8023faf4e01efadfa183e863fefde0046de576c6f14659e8782065bcece22198",
@ -360,9 +385,12 @@
"sha256:8afafd99945ead6e075b973fefa56379c5b5c53fd8937dad92c662da5d8fd5ee", "sha256:8afafd99945ead6e075b973fefa56379c5b5c53fd8937dad92c662da5d8fd5ee",
"sha256:8c41976a29d078bb235fea9b2ecd3da465df42a562910f9022f1a03107bd02be", "sha256:8c41976a29d078bb235fea9b2ecd3da465df42a562910f9022f1a03107bd02be",
"sha256:8e254ae696c88d98da6555f5ace2279cf7cd5b3f52be2b5cf97feafe883b58d2", "sha256:8e254ae696c88d98da6555f5ace2279cf7cd5b3f52be2b5cf97feafe883b58d2",
"sha256:8f9293864fe09b8149f0cc42ce56e3f0e54de883a9de90cd427f191c346eb2e1",
"sha256:9402b03f1a1b4dc4c19845e5c749e3ab82d5078d16a2a4c2cd2df62d57bb0707", "sha256:9402b03f1a1b4dc4c19845e5c749e3ab82d5078d16a2a4c2cd2df62d57bb0707",
"sha256:962f82a3086483f5e5f64dbad880d31038b698494799b097bc59c2edf392fce6", "sha256:962f82a3086483f5e5f64dbad880d31038b698494799b097bc59c2edf392fce6",
"sha256:9aad3c1755095ce347e26488214ef77e0485a3c34a50c5a5e2471dff60b9dd9c",
"sha256:9dcdfd0eaf283af041973bff14a2e143b8bd64e069f4c383416ecd79a81aab58", "sha256:9dcdfd0eaf283af041973bff14a2e143b8bd64e069f4c383416ecd79a81aab58",
"sha256:aa57bd9cf8ae831a362185ee444e15a93ecb2e344c8e52e4d721ea3ab6ef1823",
"sha256:aa7bd130efab1c280bed0f45501b7c8795f9fdbeb02e965371bbef3523627779", "sha256:aa7bd130efab1c280bed0f45501b7c8795f9fdbeb02e965371bbef3523627779",
"sha256:ab4a0df41e7c16a1392727727e7998a467472d0ad65f3ad5e6e765015df08636", "sha256:ab4a0df41e7c16a1392727727e7998a467472d0ad65f3ad5e6e765015df08636",
"sha256:ad9e82fb8f09ade1c3e1b996a6337afac2b8b9e365f926f5a61aacc71adc5b3c", "sha256:ad9e82fb8f09ade1c3e1b996a6337afac2b8b9e365f926f5a61aacc71adc5b3c",
@ -381,7 +409,9 @@
"sha256:df0be2b576a7abbf737b1575f048c23fb1d769f267ec4358296f31c2479db8f9", "sha256:df0be2b576a7abbf737b1575f048c23fb1d769f267ec4358296f31c2479db8f9",
"sha256:e09031c87a1e51556fdcb46e5bd4f59dfb743061cf93c4d6831bf894f125eb57", "sha256:e09031c87a1e51556fdcb46e5bd4f59dfb743061cf93c4d6831bf894f125eb57",
"sha256:e4dd52d80b8c83fdce44e12478ad2e85c64ea965e75d66dbeafb0a3e77308fcc", "sha256:e4dd52d80b8c83fdce44e12478ad2e85c64ea965e75d66dbeafb0a3e77308fcc",
"sha256:fec21693218efe39aa7f8599346e90c705afa52c5b31ae019b2e57e8f6542bb2" "sha256:f698de3fd0c4e6972b92290a45bd9b1536bffe8c6759c62471efaa8acb4c37bc",
"sha256:fec21693218efe39aa7f8599346e90c705afa52c5b31ae019b2e57e8f6542bb2",
"sha256:ffcc3f7c66b5f5b7931a5aa68fc9cecc51e685ef90282f4a82f0f5e9b704ad11"
], ],
"markers": "python_version >= '3.7'", "markers": "python_version >= '3.7'",
"version": "==2.1.3" "version": "==2.1.3"
@ -404,79 +434,97 @@
}, },
"packaging": { "packaging": {
"hashes": [ "hashes": [
"sha256:994793af429502c4ea2ebf6bf664629d07c1a9fe974af92966e4b8d2df7edc61", "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5",
"sha256:a392980d2b6cffa644431898be54b0045151319d1e7ec34f0cfed48767dd334f" "sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7"
], ],
"markers": "python_version >= '3.7'", "markers": "python_version >= '3.7'",
"version": "==23.1" "version": "==23.2"
},
"pluggy": {
"hashes": [
"sha256:cf61ae8f126ac6f7c451172cf30e3e43d3ca77615509771b3a984a0730651e12",
"sha256:d89c696a773f8bd377d18e5ecda92b7a3793cbe66c87060a6fb58c7b6e1061f7"
],
"markers": "python_version >= '3.8'",
"version": "==1.3.0"
}, },
"psycopg2-binary": { "psycopg2-binary": {
"hashes": [ "hashes": [
"sha256:02c0f3757a4300cf379eb49f543fb7ac527fb00144d39246ee40e1df684ab514", "sha256:03ef7df18daf2c4c07e2695e8cfd5ee7f748a1d54d802330985a78d2a5a6dca9",
"sha256:02c6e3cf3439e213e4ee930308dc122d6fb4d4bea9aef4a12535fbd605d1a2fe", "sha256:0a602ea5aff39bb9fac6308e9c9d82b9a35c2bf288e184a816002c9fae930b77",
"sha256:0645376d399bfd64da57148694d78e1f431b1e1ee1054872a5713125681cf1be", "sha256:0c009475ee389757e6e34611d75f6e4f05f0cf5ebb76c6037508318e1a1e0d7e",
"sha256:0892ef645c2fabb0c75ec32d79f4252542d0caec1d5d949630e7d242ca4681a3", "sha256:0ef4854e82c09e84cc63084a9e4ccd6d9b154f1dbdd283efb92ecd0b5e2b8c84",
"sha256:0d236c2825fa656a2d98bbb0e52370a2e852e5a0ec45fc4f402977313329174d", "sha256:1236ed0952fbd919c100bc839eaa4a39ebc397ed1c08a97fc45fee2a595aa1b3",
"sha256:0e0f754d27fddcfd74006455b6e04e6705d6c31a612ec69ddc040a5468e44b4e", "sha256:143072318f793f53819048fdfe30c321890af0c3ec7cb1dfc9cc87aa88241de2",
"sha256:15e2ee79e7cf29582ef770de7dab3d286431b01c3bb598f8e05e09601b890081", "sha256:15208be1c50b99203fe88d15695f22a5bed95ab3f84354c494bcb1d08557df67",
"sha256:1876843d8e31c89c399e31b97d4b9725a3575bb9c2af92038464231ec40f9edb", "sha256:1873aade94b74715be2246321c8650cabf5a0d098a95bab81145ffffa4c13876",
"sha256:1f64dcfb8f6e0c014c7f55e51c9759f024f70ea572fbdef123f85318c297947c", "sha256:18d0ef97766055fec15b5de2c06dd8e7654705ce3e5e5eed3b6651a1d2a9a152",
"sha256:2ab652e729ff4ad76d400df2624d223d6e265ef81bb8aa17fbd63607878ecbee", "sha256:1ea665f8ce695bcc37a90ee52de7a7980be5161375d42a0b6c6abedbf0d81f0f",
"sha256:30637a20623e2a2eacc420059be11527f4458ef54352d870b8181a4c3020ae6b", "sha256:2293b001e319ab0d869d660a704942c9e2cce19745262a8aba2115ef41a0a42a",
"sha256:34b9ccdf210cbbb1303c7c4db2905fa0319391bd5904d32689e6dd5c963d2ea8", "sha256:246b123cc54bb5361588acc54218c8c9fb73068bf227a4a531d8ed56fa3ca7d6",
"sha256:38601cbbfe600362c43714482f43b7c110b20cb0f8172422c616b09b85a750c5", "sha256:275ff571376626195ab95a746e6a04c7df8ea34638b99fc11160de91f2fef503",
"sha256:441cc2f8869a4f0f4bb408475e5ae0ee1f3b55b33f350406150277f7f35384fc", "sha256:281309265596e388ef483250db3640e5f414168c5a67e9c665cafce9492eda2f",
"sha256:498807b927ca2510baea1b05cc91d7da4718a0f53cb766c154c417a39f1820a0", "sha256:2d423c8d8a3c82d08fe8af900ad5b613ce3632a1249fd6a223941d0735fce493",
"sha256:4ac30da8b4f57187dbf449294d23b808f8f53cad6b1fc3623fa8a6c11d176dd0", "sha256:2e5afae772c00980525f6d6ecf7cbca55676296b580c0e6abb407f15f3706996",
"sha256:4c727b597c6444a16e9119386b59388f8a424223302d0c06c676ec8b4bc1f963", "sha256:30dcc86377618a4c8f3b72418df92e77be4254d8f89f14b8e8f57d6d43603c0f",
"sha256:4d67fbdaf177da06374473ef6f7ed8cc0a9dc640b01abfe9e8a2ccb1b1402c1f", "sha256:31a34c508c003a4347d389a9e6fcc2307cc2150eb516462a7a17512130de109e",
"sha256:4dfb4be774c4436a4526d0c554af0cc2e02082c38303852a36f6456ece7b3503", "sha256:323ba25b92454adb36fa425dc5cf6f8f19f78948cbad2e7bc6cdf7b0d7982e59",
"sha256:4ea29fc3ad9d91162c52b578f211ff1c931d8a38e1f58e684c45aa470adf19e2", "sha256:34eccd14566f8fe14b2b95bb13b11572f7c7d5c36da61caf414d23b91fcc5d94",
"sha256:51537e3d299be0db9137b321dfb6a5022caaab275775680e0c3d281feefaca6b", "sha256:3a58c98a7e9c021f357348867f537017057c2ed7f77337fd914d0bedb35dace7",
"sha256:61b047a0537bbc3afae10f134dc6393823882eb263088c271331602b672e52e9", "sha256:3f78fd71c4f43a13d342be74ebbc0666fe1f555b8837eb113cb7416856c79682",
"sha256:6460c7a99fc939b849431f1e73e013d54aa54293f30f1109019c56a0b2b2ec2f", "sha256:4154ad09dac630a0f13f37b583eae260c6aa885d67dfbccb5b02c33f31a6d420",
"sha256:65bee1e49fa6f9cf327ce0e01c4c10f39165ee76d35c846ade7cb0ec6683e303", "sha256:420f9bbf47a02616e8554e825208cb947969451978dceb77f95ad09c37791dae",
"sha256:65c07febd1936d63bfde78948b76cd4c2a411572a44ac50719ead41947d0f26b", "sha256:4686818798f9194d03c9129a4d9a702d9e113a89cb03bffe08c6cf799e053291",
"sha256:71f14375d6f73b62800530b581aed3ada394039877818b2d5f7fc77e3bb6894d", "sha256:57fede879f08d23c85140a360c6a77709113efd1c993923c59fde17aa27599fe",
"sha256:7a40c00dbe17c0af5bdd55aafd6ff6679f94a9be9513a4c7e071baf3d7d22a70", "sha256:60989127da422b74a04345096c10d416c2b41bd7bf2a380eb541059e4e999980",
"sha256:7e13a5a2c01151f1208d5207e42f33ba86d561b7a89fca67c700b9486a06d0e2", "sha256:64cf30263844fa208851ebb13b0732ce674d8ec6a0c86a4e160495d299ba3c93",
"sha256:7f0438fa20fb6c7e202863e0d5ab02c246d35efb1d164e052f2f3bfe2b152bd0", "sha256:68fc1f1ba168724771e38bee37d940d2865cb0f562380a1fb1ffb428b75cb692",
"sha256:8122cfc7cae0da9a3077216528b8bb3629c43b25053284cc868744bfe71eb141", "sha256:6e6f98446430fdf41bd36d4faa6cb409f5140c1c2cf58ce0bbdaf16af7d3f119",
"sha256:8338a271cb71d8da40b023a35d9c1e919eba6cbd8fa20a54b748a332c355d896", "sha256:729177eaf0aefca0994ce4cffe96ad3c75e377c7b6f4efa59ebf003b6d398716",
"sha256:84d2222e61f313c4848ff05353653bf5f5cf6ce34df540e4274516880d9c3763", "sha256:72dffbd8b4194858d0941062a9766f8297e8868e1dd07a7b36212aaa90f49472",
"sha256:8a6979cf527e2603d349a91060f428bcb135aea2be3201dff794813256c274f1", "sha256:75723c3c0fbbf34350b46a3199eb50638ab22a0228f93fb472ef4d9becc2382b",
"sha256:8a76e027f87753f9bd1ab5f7c9cb8c7628d1077ef927f5e2446477153a602f2c", "sha256:77853062a2c45be16fd6b8d6de2a99278ee1d985a7bd8b103e97e41c034006d2",
"sha256:964b4dfb7c1c1965ac4c1978b0f755cc4bd698e8aa2b7667c575fb5f04ebe06b", "sha256:78151aa3ec21dccd5cdef6c74c3e73386dcdfaf19bced944169697d7ac7482fc",
"sha256:9972aad21f965599ed0106f65334230ce826e5ae69fda7cbd688d24fa922415e", "sha256:7f01846810177d829c7692f1f5ada8096762d9172af1b1a28d4ab5b77c923c1c",
"sha256:a8c28fd40a4226b4a84bdf2d2b5b37d2c7bd49486b5adcc200e8c7ec991dfa7e", "sha256:804d99b24ad523a1fe18cc707bf741670332f7c7412e9d49cb5eab67e886b9b5",
"sha256:ae102a98c547ee2288637af07393dd33f440c25e5cd79556b04e3fca13325e5f", "sha256:81ff62668af011f9a48787564ab7eded4e9fb17a4a6a74af5ffa6a457400d2ab",
"sha256:af335bac6b666cc6aea16f11d486c3b794029d9df029967f9938a4bed59b6a19", "sha256:8359bf4791968c5a78c56103702000105501adb557f3cf772b2c207284273984",
"sha256:afe64e9b8ea66866a771996f6ff14447e8082ea26e675a295ad3bdbffdd72afb", "sha256:83791a65b51ad6ee6cf0845634859d69a038ea9b03d7b26e703f94c7e93dbcf9",
"sha256:b4b24f75d16a89cc6b4cdff0eb6a910a966ecd476d1e73f7ce5985ff1328e9a6", "sha256:8532fd6e6e2dc57bcb3bc90b079c60de896d2128c5d9d6f24a63875a95a088cf",
"sha256:b6c8288bb8a84b47e07013bb4850f50538aa913d487579e1921724631d02ea1b", "sha256:876801744b0dee379e4e3c38b76fc89f88834bb15bf92ee07d94acd06ec890a0",
"sha256:b83456c2d4979e08ff56180a76429263ea254c3f6552cd14ada95cff1dec9bb8", "sha256:8dbf6d1bc73f1d04ec1734bae3b4fb0ee3cb2a493d35ede9badbeb901fb40f6f",
"sha256:bfb13af3c5dd3a9588000910178de17010ebcccd37b4f9794b00595e3a8ddad3", "sha256:8f8544b092a29a6ddd72f3556a9fcf249ec412e10ad28be6a0c0d948924f2212",
"sha256:c3dba7dab16709a33a847e5cd756767271697041fbe3fe97c215b1fc1f5c9848", "sha256:911dda9c487075abd54e644ccdf5e5c16773470a6a5d3826fda76699410066fb",
"sha256:c48d8f2db17f27d41fb0e2ecd703ea41984ee19362cbce52c097963b3a1b4365", "sha256:977646e05232579d2e7b9c59e21dbe5261f403a88417f6a6512e70d3f8a046be",
"sha256:c7e62ab8b332147a7593a385d4f368874d5fe4ad4e341770d4983442d89603e3", "sha256:9dba73be7305b399924709b91682299794887cbbd88e38226ed9f6712eabee90",
"sha256:c83a74b68270028dc8ee74d38ecfaf9c90eed23c8959fca95bd703d25b82c88e", "sha256:a148c5d507bb9b4f2030a2025c545fccb0e1ef317393eaba42e7eabd28eb6041",
"sha256:cacbdc5839bdff804dfebc058fe25684cae322987f7a38b0168bc1b2df703fb1", "sha256:a6cdcc3ede532f4a4b96000b6362099591ab4a3e913d70bcbac2b56c872446f7",
"sha256:cf4499e0a83b7b7edcb8dabecbd8501d0d3a5ef66457200f77bde3d210d5debb", "sha256:ac05fb791acf5e1a3e39402641827780fe44d27e72567a000412c648a85ba860",
"sha256:cfec476887aa231b8548ece2e06d28edc87c1397ebd83922299af2e051cf2827", "sha256:b0605eaed3eb239e87df0d5e3c6489daae3f7388d455d0c0b4df899519c6a38d",
"sha256:d26e0342183c762de3276cca7a530d574d4e25121ca7d6e4a98e4f05cb8e4df7", "sha256:b58b4710c7f4161b5e9dcbe73bb7c62d65670a87df7bcce9e1faaad43e715245",
"sha256:d4e6036decf4b72d6425d5b29bbd3e8f0ff1059cda7ac7b96d6ac5ed34ffbacd", "sha256:b6356793b84728d9d50ead16ab43c187673831e9d4019013f1402c41b1db9b27",
"sha256:d57c3fd55d9058645d26ae37d76e61156a27722097229d32a9e73ed54819982a", "sha256:b76bedd166805480ab069612119ea636f5ab8f8771e640ae103e05a4aae3e417",
"sha256:dfa74c903a3c1f0d9b1c7e7b53ed2d929a4910e272add6700c38f365a6002820", "sha256:bc7bb56d04601d443f24094e9e31ae6deec9ccb23581f75343feebaf30423359",
"sha256:e3ed340d2b858d6e6fb5083f87c09996506af483227735de6964a6100b4e6a54", "sha256:c2470da5418b76232f02a2fcd2229537bb2d5a7096674ce61859c3229f2eb202",
"sha256:e78e6e2a00c223e164c417628572a90093c031ed724492c763721c2e0bc2a8df", "sha256:c332c8d69fb64979ebf76613c66b985414927a40f8defa16cf1bc028b7b0a7b0",
"sha256:e9182eb20f41417ea1dd8e8f7888c4d7c6e805f8a7c98c1081778a3da2bee3e4", "sha256:c6af2a6d4b7ee9615cbb162b0738f6e1fd1f5c3eda7e5da17861eacf4c717ea7",
"sha256:e99e34c82309dd78959ba3c1590975b5d3c862d6f279f843d47d26ff89d7d7e1", "sha256:c77e3d1862452565875eb31bdb45ac62502feabbd53429fdc39a1cc341d681ba",
"sha256:f6a88f384335bb27812293fdb11ac6aee2ca3f51d3c7820fe03de0a304ab6249", "sha256:ca08decd2697fdea0aea364b370b1249d47336aec935f87b8bbfd7da5b2ee9c1",
"sha256:f81e65376e52f03422e1fb475c9514185669943798ed019ac50410fb4c4df232", "sha256:ca49a8119c6cbd77375ae303b0cfd8c11f011abbbd64601167ecca18a87e7cdd",
"sha256:ffe9dc0a884a8848075e576c1de0290d85a533a9f6e9c4e564f19adf8f6e54a7" "sha256:cb16c65dcb648d0a43a2521f2f0a2300f40639f6f8c1ecbc662141e4e3e1ee07",
"sha256:d2997c458c690ec2bc6b0b7ecbafd02b029b7b4283078d3b32a852a7ce3ddd98",
"sha256:d3f82c171b4ccd83bbaf35aa05e44e690113bd4f3b7b6cc54d2219b132f3ae55",
"sha256:dc4926288b2a3e9fd7b50dc6a1909a13bbdadfc67d93f3374d984e56f885579d",
"sha256:ead20f7913a9c1e894aebe47cccf9dc834e1618b7aa96155d2091a626e59c972",
"sha256:ebdc36bea43063116f0486869652cb2ed7032dbc59fbcb4445c4862b5c1ecf7f",
"sha256:ed1184ab8f113e8d660ce49a56390ca181f2981066acc27cf637d5c1e10ce46e",
"sha256:ee825e70b1a209475622f7f7b776785bd68f34af6e7a46e2e42f27b659b5bc26",
"sha256:f7ae5d65ccfbebdfa761585228eb4d0df3a8b15cfb53bd953e713e09fbb12957",
"sha256:f7fc5a5acafb7d6ccca13bfa8c90f8c51f13d8fb87d95656d3950f0158d3ce53",
"sha256:f9b5571d33660d5009a8b3c25dc1db560206e2d2f89d3df1cb32d72c0d117d52"
], ],
"index": "pypi", "index": "pypi",
"version": "==2.9.6" "version": "==2.9.9"
}, },
"pyjwt": { "pyjwt": {
"hashes": [ "hashes": [
@ -488,39 +536,60 @@
}, },
"pymupdf": { "pymupdf": {
"hashes": [ "hashes": [
"sha256:01119edb7e4c3dd8c154d237b8ac927bd359eea8d31468f9a89aa308b5bca04e", "sha256:264d5f6478d787c336520cf1a99e39bb6a0ef6d984550f925095c0e692dea7b5",
"sha256:017aaba511526facfc928e9d95d2c10d28a2821b05b9039bf422031a7da8584e", "sha256:29e1d82b16f7580280ae35a0ae78de55f15c92ec87b7f3a1372f40f37a053bf3",
"sha256:0542178c3a399282903705a8cc298e7f33f4770605e0a9db344aff5d375bcf0b", "sha256:31405311c28fc8b3b2975a98b60bac388563748beaacb6da470f917678417e2d",
"sha256:17efbbf0e2d99d24cfc302fac512928eb294f10b7b67d597d04dafd012812e4e", "sha256:332c1d5633c233458c4b65e6ad4a860391c507384bd2324a186b2702f8c64dfe",
"sha256:2e74d766f79e41e10c51865233042ab2cc4612ca7942812dca0603f4d0f8f73d", "sha256:3400b582be3d71f1c0974701fcfda32f0c2ebb75a78c2aea430552b0c6896546",
"sha256:30c55814bbf6461aef9b34cb524d1d14857d5ec6ccfbb78ecfb1d07dfc40eeb8", "sha256:3a01c93c69e74068c1618631a750677fd088708d2b09b3c23809b099fa4ffa39",
"sha256:3d0fe749e648f5245059d5f771fb50c1a988a1d2e82268b56377b2176a9fee5d", "sha256:3f5fc705e8790217d23ab5e7ac2c05d82e050f6271b710300288adfe87a71072",
"sha256:3d71c47aa14b73f2df7d03be8c547a05df6c6898d8c63a0f752b26f206eefd3c", "sha256:435a108cf8b53302500b52adb2cccbf2afa51c94ab3c705b250245090b46f5da",
"sha256:411fc35f6dae16ec940b6b0406e84be6ff29f93b30908ea1427e2a4bd594d4ba", "sha256:4508ee04c46cac8356a9d04f0d9a63f845770d2abb54caf512b44d22f0e80300",
"sha256:42f59f4999d7f8b35c850050bd965e98c081a7d9b92d5f9dcf30203b30d06876", "sha256:460b47a1a17335d444ec441b68c083da5e51cdfcfa67a6638de69fe5e97f4ad2",
"sha256:4bcad7ea4b3ab82c46fe8da27ec738d38c213ed9935ef67d98ed09574d9a234e", "sha256:4a53b2bf19be687160e4d18c27680e5326687aa39a7e31641d32a61edadbbfd9",
"sha256:4fbc5bfe6ecc53929e3fd0db9846fb7da084ddb4b1fc1063857245fa783974d9", "sha256:4b1bd9a91dee18bc95d7af2c593a214857a03e4fcd9a1eb01588df432de24c58",
"sha256:5ec8d5106752297529d0d68d46cfc4ce99914aabd99be843f1599a1842d63fe9", "sha256:53278c6a3d0a5dc8f221e0a77c065a61fd0598f9d8d9ef5be53de0c0a7d2df90",
"sha256:640b8e4cb116dd87a3c854e49808a4f63625e663a7bc5b1efc971db5b4775367", "sha256:59755a600c25a282589b548ffa045aed59c2df7b76943978cabb1825f0c03ec4",
"sha256:64ae9f81b8fe0a3e6386a24887a92736793479c5918ecac3b7deac2d02abf1f2", "sha256:64ab1097e3a077ae9db6a98d01e2e77087894ebd85b702edf5eb85d05ab8c0f1",
"sha256:6fe5e44a14864d921fb96669a82f9635846806176f77f1d73c61feb84ebf4d84", "sha256:693979ad4c8885729ac126b3202f1cb645f3392ad7e0964c2d924e61bc0e0a9d",
"sha256:7562436dadf8382e59ac3739fbbf9d5b2d807fafc7f28cb884863430e0de6505", "sha256:705a7aed0a917c35bb5efa4d94a7e8092705b3395726f9770d2b888de775f437",
"sha256:7b04a83ddcb3f7c935c75a1f7f6050c85fe4062a2ea64c47ee6bda788d037761", "sha256:9586bc98a322e546cf2e477309806aa4a3e1d18efc9b93fc2e2b3d8131e1b9f7",
"sha256:7c8c0f686865e330de90b93d53b100f7f07c2f10f5449ceb721121f459f7cc4a", "sha256:9bde3683e254661e6b0032006f0ef7025ade2a33d3e3045499e71b76ea99942c",
"sha256:87b36e0797ab7fbb7ef594c7a6e0febc7ffb4101a42ea796726a8288391a3769", "sha256:b234805b615b2d45dcb1bfe5c2167dc4121e31d618ab557856a3153b94c1676b",
"sha256:9bc9b9bf0f2beea3911750d2d66247608be8cbad33b7a050cacec9e4c105a1ca", "sha256:bb345ef1120db4f78ec0f229514d333ea3e7d367875c1400423a9b3e2b48ffc0",
"sha256:add310c96df6933cfb4ce3821c9c7b5c133e8aa609a4c9416e1c7af546163488", "sha256:c71b5e80a08272b9f3012314dc47ee2423270b30262d07ec7dd9709ae2bde1ac",
"sha256:c2fd70ca9961f7871810dce1b7d0a42a69eb8ff2d786621123952bd505a6867e", "sha256:d2e9cfa46193fab196c27cb07561e1bb0938450984c2f01b3739f254a31b639e",
"sha256:d02ee28663077f15d529b04d27588b174fa937daf73a294df279bbf70c468f5c", "sha256:d3bef175707693a2f53fe0fe4e546e3187c7876aedabfe43d9a916060bac9073",
"sha256:d0c22046e5f2cf0d72f9809a967340db1b238fefe58322896bc7c3f3d1d10b42", "sha256:da1b08b5348152f2940fa183d0265a6b6eb6f0292fae44b576eaf8e53723e336",
"sha256:e7734a32a91eea4b502b8f9d2915cdba0a372226e14fb983876d763110dcefef", "sha256:dbce86df507f6bce118b12b33d893f1d3512013c898174211e903da78e1916aa",
"sha256:efa601dc4116c17a6b09255b031b5a1891e3ac18b50ec536452a725a6b75db8d", "sha256:eafa1bce0860320ddbb7edb4ab5678e02051db5450251ba8e918713d9a70c03c",
"sha256:f8ca46a6987e14f58ec8dfda2d2376bacd113c1fec5f58bebf90838bb4408ab9", "sha256:ee9e9ce1897eeac0fc33cf99084067c14250312a5dbc1372012c3d2f0e7a4af5",
"sha256:fde02fcb387863873b56730f4b9f65515d87c92c12299f0f0a74b3ccdfe35062", "sha256:f7a8f91681b88ad216c36911e08ea25d2b3121350d52f4f8d76aeb0b7fcc6bef",
"sha256:fe8175452fcc99a0af6429d8acd87682a3a70c5879d73532c7327f71ce508a35" "sha256:fab599d23fa490725e5b5a70bfb6bc87acf5ceb70abe11ad2ef2b2f516961f31",
"sha256:faebdf8679706964f87617ee43b8d0107587d20b526892b538222146a4c32d43"
], ],
"index": "pypi", "index": "pypi",
"version": "==1.22.5" "version": "==1.23.5"
},
"pymupdfb": {
"hashes": [
"sha256:2b71b5b7987f2ebe9f6893544151ede2de74ec30651eef584039eb5f9c7c02aa",
"sha256:80137c37a4b0d5abeb988434c7d7eb3f9087afdd0754f4bf2f8840a788e691ae",
"sha256:85cbc308085a4ec794e0da790965985cc5ccb21b2abc09732e072f6eaf10150b",
"sha256:d0095f28b2bcd64ed8a9636dfba193108eeb6c24d0ec71fa3f88cb15aee67a30",
"sha256:e26705e1a4ea42926b70c5655f2509d555a4774d1d1382ecc7e76466695209e6",
"sha256:f269814bafdffd5558d44af3de63eaa531d498de640a79cf6c7072011fd4088f"
],
"markers": "python_version >= '3.8'",
"version": "==1.23.5"
},
"pytest": {
"hashes": [
"sha256:0d009c083ea859a71b76adf7c1d502e4bc170b80a8ef002da5806527b9591fac",
"sha256:d989d136982de4e3b29dabcc838ad581c64e8ed52c11fbe86ddebd9da0818cd5"
],
"index": "pypi",
"version": "==7.4.3"
}, },
"python-dotenv": { "python-dotenv": {
"hashes": [ "hashes": [
@ -540,50 +609,58 @@
}, },
"sqlalchemy": { "sqlalchemy": {
"hashes": [ "hashes": [
"sha256:024d2f67fb3ec697555e48caeb7147cfe2c08065a4f1a52d93c3d44fc8e6ad1c", "sha256:0b0b3f2686c3f162123adba3cb8b626ed7e9b8433ab528e36ed270b4f70d1cdb",
"sha256:0bf0fd65b50a330261ec7fe3d091dfc1c577483c96a9fa1e4323e932961aa1b5", "sha256:0c1fea8c0abcb070ffe15311853abfda4e55bf7dc1d4889497b3403629f3bf00",
"sha256:16a310f5bc75a5b2ce7cb656d0e76eb13440b8354f927ff15cbaddd2523ee2d1", "sha256:0e1ce8ebd2e040357dde01a3fb7d30d9b5736b3e54a94002641dfd0aa12ae6ce",
"sha256:1d90ccc15ba1baa345796a8fb1965223ca7ded2d235ccbef80a47b85cea2d71a", "sha256:129415f89744b05741c6f0b04a84525f37fbabe5dc3774f7edf100e7458c48cd",
"sha256:22bafb1da60c24514c141a7ff852b52f9f573fb933b1e6b5263f0daa28ce6db9", "sha256:13790cb42f917c45c9c850b39b9941539ca8ee7917dacf099cc0b569f3d40da7",
"sha256:2c69ce70047b801d2aba3e5ff3cba32014558966109fecab0c39d16c18510f15", "sha256:14cd3bcbb853379fef2cd01e7c64a5d6f1d005406d877ed9509afb7a05ff40a5",
"sha256:2e7b69d9ced4b53310a87117824b23c509c6fc1f692aa7272d47561347e133b6", "sha256:154a32f3c7b00de3d090bc60ec8006a78149e221f1182e3edcf0376016be9396",
"sha256:314145c1389b021a9ad5aa3a18bac6f5d939f9087d7fc5443be28cba19d2c972", "sha256:19c6986cf2fb4bc8e0e846f97f4135a8e753b57d2aaaa87c50f9acbe606bd1db",
"sha256:3afa8a21a9046917b3a12ffe016ba7ebe7a55a6fc0c7d950beb303c735c3c3ad", "sha256:2096d6b018d242a2bcc9e451618166f860bb0304f590d205173d317b69986c95",
"sha256:430614f18443b58ceb9dedec323ecddc0abb2b34e79d03503b5a7579cd73a531", "sha256:2c9bac865ee06d27a1533471405ad240a6f5d83195eca481f9fc4a71d8b87df8",
"sha256:43699eb3f80920cc39a380c159ae21c8a8924fe071bccb68fc509e099420b148", "sha256:3076740335e4aaadd7deb3fe6dcb96b3015f1613bd190a4e1634e1b99b02ec86",
"sha256:539010665c90e60c4a1650afe4ab49ca100c74e6aef882466f1de6471d414be7", "sha256:3940677d341f2b685a999bffe7078697b5848a40b5f6952794ffcf3af150c301",
"sha256:57d100a421d9ab4874f51285c059003292433c648df6abe6c9c904e5bd5b0828", "sha256:3aa1472bf44f61dd27987cd051f1c893b7d3b17238bff8c23fceaef4f1133868",
"sha256:5831138f0cc06b43edf5f99541c64adf0ab0d41f9a4471fd63b54ae18399e4de", "sha256:40b1206a0d923e73aa54f0a6bd61419a96b914f1cd19900b6c8226899d9742ad",
"sha256:584f66e5e1979a7a00f4935015840be627e31ca29ad13f49a6e51e97a3fb8cae", "sha256:4bb062784f37b2d75fd9b074c8ec360ad5df71f933f927e9e95c50eb8e05323c",
"sha256:5d6afc41ca0ecf373366fd8e10aee2797128d3ae45eb8467b19da4899bcd1ee0", "sha256:4e869a8ff7ee7a833b74868a0887e8462445ec462432d8cbeff5e85f475186da",
"sha256:61ada5831db36d897e28eb95f0f81814525e0d7927fb51145526c4e63174920b", "sha256:4f6ff392b27a743c1ad346d215655503cec64405d3b694228b3454878bf21590",
"sha256:6b54d1ad7a162857bb7c8ef689049c7cd9eae2f38864fc096d62ae10bc100c7d", "sha256:505f503763a767556fa4deae5194b2be056b64ecca72ac65224381a0acab7ebe",
"sha256:7351c05db355da112e056a7b731253cbeffab9dfdb3be1e895368513c7d70106", "sha256:53a766cb0b468223cafdf63e2d37f14a4757476157927b09300c8c5832d88560",
"sha256:77a14fa20264af73ddcdb1e2b9c5a829b8cc6b8304d0f093271980e36c200a3f", "sha256:5434cc601aa17570d79e5377f5fd45ff92f9379e2abed0be5e8c2fba8d353d2b",
"sha256:851a37898a8a39783aab603c7348eb5b20d83c76a14766a43f56e6ad422d1ec8", "sha256:54bcceaf4eebef07dadfde424f5c26b491e4a64e61761dea9459103ecd6ccc95",
"sha256:89bc2b374ebee1a02fd2eae6fd0570b5ad897ee514e0f84c5c137c942772aa0c", "sha256:55914d45a631b81a8a2cb1a54f03eea265cf1783241ac55396ec6d735be14883",
"sha256:8e712cfd2e07b801bc6b60fdf64853bc2bd0af33ca8fa46166a23fe11ce0dbb0", "sha256:564e9f9e4e6466273dbfab0e0a2e5fe819eec480c57b53a2cdee8e4fdae3ad5f",
"sha256:8f9eb4575bfa5afc4b066528302bf12083da3175f71b64a43a7c0badda2be365", "sha256:56a7e2bb639df9263bf6418231bc2a92a773f57886d371ddb7a869a24919face",
"sha256:8fc05b59142445a4efb9c1fd75c334b431d35c304b0e33f4fa0ff1ea4890f92e", "sha256:58a3aba1bfb32ae7af68da3f277ed91d9f57620cf7ce651db96636790a78b736",
"sha256:96f0463573469579d32ad0c91929548d78314ef95c210a8115346271beeeaaa2", "sha256:625b72d77ac8ac23da3b1622e2da88c4aedaee14df47c8432bf8f6495e655de2",
"sha256:9deaae357edc2091a9ed5d25e9ee8bba98bcfae454b3911adeaf159c2e9ca9e3", "sha256:69fd9e41cf9368afa034e1c81f3570afb96f30fcd2eb1ef29cb4d9371c6eece2",
"sha256:a752b7a9aceb0ba173955d4f780c64ee15a1a991f1c52d307d6215c6c73b3a4c", "sha256:6ac28bd6888fe3c81fbe97584eb0b96804bd7032d6100b9701255d9441373ec1",
"sha256:ae7473a67cd82a41decfea58c0eac581209a0aa30f8bc9190926fbf628bb17f7", "sha256:7c6c3e9350f9fb16de5b5e5fbf17b578811a52d71bb784cc5ff71acb7de2a7f9",
"sha256:b15afbf5aa76f2241184c1d3b61af1a72ba31ce4161013d7cb5c4c2fca04fd6e", "sha256:7ee7ccf47aa503033b6afd57efbac6b9e05180f492aeed9fcf70752556f95624",
"sha256:c896d4e6ab2eba2afa1d56be3d0b936c56d4666e789bfc59d6ae76e9fcf46145", "sha256:875de9414393e778b655a3d97d60465eb3fae7c919e88b70cc10b40b9f56042d",
"sha256:cb4e688f6784427e5f9479d1a13617f573de8f7d4aa713ba82813bcd16e259d1", "sha256:8db5ba8b7da759b727faebc4289a9e6a51edadc7fc32207a30f7c6203a181592",
"sha256:cda283700c984e699e8ef0fcc5c61f00c9d14b6f65a4f2767c97242513fcdd84", "sha256:92e512a6af769e4725fa5b25981ba790335d42c5977e94ded07db7d641490a85",
"sha256:cf7b5e3856cbf1876da4e9d9715546fa26b6e0ba1a682d5ed2fc3ca4c7c3ec5b", "sha256:9886a72c8e6371280cb247c5d32c9c8fa141dc560124348762db8a8b236f8692",
"sha256:d6894708eeb81f6d8193e996257223b6bb4041cb05a17cd5cf373ed836ef87a2", "sha256:9e55dff5ec115316dd7a083cdc1a52de63693695aecf72bc53a8e1468ce429e5",
"sha256:d8f2afd1aafded7362b397581772c670f20ea84d0a780b93a1a1529da7c3d369", "sha256:a42c9fa3abcda0dcfad053e49c4f752eef71ecd8c155221e18b99d4224621176",
"sha256:dd4d410a76c3762511ae075d50f379ae09551d92525aa5bb307f8343bf7c2c12", "sha256:a571bc8ac092a3175a1d994794a8e7a1f2f651e7c744de24a19b4f740fe95034",
"sha256:eb60699de43ba1a1f77363f563bb2c652f7748127ba3a774f7cf2c7804aa0d3d", "sha256:af66001d7b76a3fab0d5e4c1ec9339ac45748bc4a399cbc2baa48c1980d3c1f4",
"sha256:f469f15068cd8351826df4080ffe4cc6377c5bf7d29b5a07b0e717dddb4c7ea2", "sha256:b39a6e21110204a8c08d40ff56a73ba542ec60bab701c36ce721e7990df49fb9",
"sha256:f82c310ddf97b04e1392c33cf9a70909e0ae10a7e2ddc1d64495e3abdc5d19fb", "sha256:b560f075c151900587ade06706b0c51d04b3277c111151997ea0813455378ae0",
"sha256:fa51ce4aea583b0c6b426f4b0563d3535c1c75986c4373a0987d84d22376585b" "sha256:c8f1792d20d2f4e875ce7a113f43c3561ad12b34ff796b84002a256f37ce9437",
"sha256:cb9a758ad973e795267da334a92dd82bb7555cb36a0960dcabcf724d26299db8",
"sha256:ccca778c0737a773a1ad86b68bda52a71ad5950b25e120b6eb1330f0df54c3d0",
"sha256:ccd87c25e4c8559e1b918d46b4fa90b37f459c9b4566f1dfbce0eb8122571547",
"sha256:d143c5a9dada696bcfdb96ba2de4a47d5a89168e71d05a076e88a01386872f97",
"sha256:d80eeb5189d7d4b1af519fc3f148fe7521b9dfce8f4d6a0820e8f5769b005051",
"sha256:e04ab55cf49daf1aeb8c622c54d23fa4bec91cb051a43cc24351ba97e1dd09f5",
"sha256:f146c61ae128ab43ea3a0955de1af7e1633942c2b2b4985ac51cc292daf33222",
"sha256:f776c2c30f0e5f4db45c3ee11a5f2a8d9de68e81eb73ec4237de1e32e04ae81c"
], ],
"markers": "python_version >= '3.7'", "markers": "python_version >= '3.7'",
"version": "==2.0.19" "version": "==2.0.22"
}, },
"sqlalchemy-utils": { "sqlalchemy-utils": {
"hashes": [ "hashes": [
@ -595,19 +672,19 @@
}, },
"typing-extensions": { "typing-extensions": {
"hashes": [ "hashes": [
"sha256:440d5dd3af93b060174bf433bccd69b0babc3b15b1a8dca43789fd7f61514b36", "sha256:8f92fc8806f9a6b641eaa5318da32b44d401efaac0f6678c9bc448ba3605faa0",
"sha256:b75ddc264f0ba5615db7ba217daeb99701ad295353c45f9e95963337ceeeffb2" "sha256:df8e4339e9cb77357558cbdbceca33c303714cf861d1eef15e1070055ae8b7ef"
], ],
"markers": "python_version >= '3.7'", "markers": "python_version >= '3.8'",
"version": "==4.7.1" "version": "==4.8.0"
}, },
"urllib3": { "urllib3": {
"hashes": [ "hashes": [
"sha256:8d22f86aae8ef5e410d4f539fde9ce6b2113a001bb4d189e0aed70642d602b11", "sha256:c97dfde1f7bd43a71c8d2a58e369e9b2bf692d1334ea9f9cae55add7d0dd0f84",
"sha256:de7df1803967d2c2a98e4b11bb7d6bd9210474c46e8a0401514e3a42a75ebde4" "sha256:fdb6d215c776278489906c2f8916e6e7d4f5a9b602ccbcfdf7f016fc8da0596e"
], ],
"markers": "python_version >= '3.7'", "markers": "python_version >= '3.7'",
"version": "==2.0.4" "version": "==2.0.7"
}, },
"visitor": { "visitor": {
"hashes": [ "hashes": [
@ -617,19 +694,19 @@
}, },
"werkzeug": { "werkzeug": {
"hashes": [ "hashes": [
"sha256:935539fa1413afbb9195b24880778422ed620c0fc09670945185cce4d91a8890", "sha256:507e811ecea72b18a404947aded4b3390e1db8f826b494d76550ef45bb3b1dcc",
"sha256:98c774df2f91b05550078891dee5f0eb0cb797a522c757a2452b9cee5b202330" "sha256:90a285dc0e42ad56b34e696398b8122ee4c681833fb35b8334a095d82c56da10"
], ],
"markers": "python_version >= '3.8'", "markers": "python_version >= '3.8'",
"version": "==2.3.6" "version": "==3.0.1"
}, },
"wtforms": { "wtforms": {
"hashes": [ "hashes": [
"sha256:6b351bbb12dd58af57ffef05bc78425d08d1914e0fd68ee14143b7ade023c5bc", "sha256:5e51df8af9a60f6beead75efa10975e97768825a82146a65c7cbf5b915990620",
"sha256:837f2f0e0ca79481b92884962b914eba4e72b7a2daaf1f939c890ed0124b834b" "sha256:ae7c54b29806c70f7bce8eb9f24afceb10ca5c32af3d9f04f74d2f66ccc5c7e0"
], ],
"markers": "python_version >= '3.7'", "markers": "python_version >= '3.8'",
"version": "==3.0.1" "version": "==3.1.1"
}, },
"wtforms-sqlalchemy": { "wtforms-sqlalchemy": {
"hashes": [ "hashes": [

View File

@ -0,0 +1,32 @@
"""Remove accepted from receiptitem
Revision ID: 36f532800705
Revises: cdbe3f5e3b30
Create Date: 2023-11-11 10:45:44.652161
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = '36f532800705'
down_revision = 'cdbe3f5e3b30'
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
with op.batch_alter_table('receipt_item', schema=None) as batch_op:
batch_op.drop_column('accepted')
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
with op.batch_alter_table('receipt_item', schema=None) as batch_op:
batch_op.add_column(sa.Column('accepted', sa.BOOLEAN(), autoincrement=False, nullable=False))
# ### end Alembic commands ###

View File

@ -0,0 +1,64 @@
"""Remove item.receiptitem relationship
Revision ID: cdbe3f5e3b30
Revises: 0fa2ef37e440
Create Date: 2023-09-19 19:02:23.003034
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = 'cdbe3f5e3b30'
down_revision = '0fa2ef37e440'
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
with op.batch_alter_table('receipt', schema=None) as batch_op:
batch_op.alter_column('id',
existing_type=sa.INTEGER(),
type_=sa.BigInteger(),
existing_nullable=False,
autoincrement=True)
with op.batch_alter_table('receipt_item', schema=None) as batch_op:
batch_op.add_column(sa.Column('price', sa.SmallInteger(), nullable=False))
batch_op.alter_column('receipt',
existing_type=sa.INTEGER(),
type_=sa.BigInteger(),
existing_nullable=False)
batch_op.alter_column('item',
existing_type=sa.BIGINT(),
type_=sa.SmallInteger(),
existing_nullable=False)
batch_op.drop_constraint('item_receipt_item_fkey', type_='foreignkey')
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
with op.batch_alter_table('receipt_item', schema=None) as batch_op:
batch_op.create_foreign_key('item_receipt_item_fkey', 'item', ['item'], ['id'])
batch_op.alter_column('item',
existing_type=sa.SmallInteger(),
type_=sa.BIGINT(),
existing_nullable=False)
batch_op.alter_column('receipt',
existing_type=sa.BigInteger(),
type_=sa.INTEGER(),
existing_nullable=False)
batch_op.drop_column('price')
with op.batch_alter_table('receipt', schema=None) as batch_op:
batch_op.alter_column('id',
existing_type=sa.BigInteger(),
type_=sa.INTEGER(),
existing_nullable=False,
autoincrement=True)
# ### end Alembic commands ###

View File

@ -16,8 +16,6 @@ class Item(db.Model):
"Category", secondary=item_category, lazy="dynamic", back_populates="Item") "Category", secondary=item_category, lazy="dynamic", back_populates="Item")
PriceChange = db.relationship( PriceChange = db.relationship(
"PriceChange", backref='Item', lazy='dynamic') "PriceChange", backref='Item', lazy='dynamic')
ReceiptItem = db.relationship(
"ReceiptItem", backref='Item', lazy='dynamic')
def __repr__(self) -> str: def __repr__(self) -> str:
return f"<Item {self.id} ({self.name})>" return f"<Item {self.id} ({self.name})>"

View File

@ -4,10 +4,9 @@ from src import db
class ReceiptItem(db.Model): class ReceiptItem(db.Model):
receipt = db.Column(db.ForeignKey("receipt.id"), receipt = db.Column(db.ForeignKey("receipt.id"),
primary_key=True, server_onupdate=db.FetchedValue()) primary_key=True, server_onupdate=db.FetchedValue())
item = db.Column(db.ForeignKey("item.id"), primary_key=True, item = db.Column(db.SmallInteger, primary_key=True, nullable=False)
server_onupdate=db.FetchedValue()) amount = db.Column(db.SmallInteger, nullable=False, default=str(1))
amount = db.Column(db.SmallInteger, nullable=False) price = db.Column(db.SmallInteger, nullable=False)
accepted = db.Column(db.Boolean, nullable=False)
def __repr__(self) -> str: def __repr__(self) -> str:
return f"<ReceiptItem {self.receipt}: {self.item}>" return f"<ReceiptItem {self.receipt}: {self.item}>"

View File

@ -10,6 +10,5 @@ class ReceiptItemSchema(ma.SQLAlchemySchema):
include_fk = True include_fk = True
Receipt = ma.Nested(ReceiptSchema) Receipt = ma.Nested(ReceiptSchema)
Item = ma.Nested(ItemSchema) price = ma.auto_field()
amount = ma.auto_field() amount = ma.auto_field()
accepted = ma.auto_field()

Binary file not shown.

View File

@ -6,7 +6,7 @@ from models.user import User
from src.utils.routes_utils import render_custom_template as render_template from src.utils.routes_utils import render_custom_template as render_template
from flask import flash, redirect, request, url_for from flask import flash, redirect, request, url_for
from flask_login import current_user, login_user, logout_user from flask_login import current_user, login_user, logout_user
from werkzeug.urls import url_parse from urllib.parse import urlparse
@bp.route('/register', methods=['GET', 'POST']) @bp.route('/register', methods=['GET', 'POST'])
def web_register(): def web_register():
@ -34,7 +34,7 @@ def web_login():
return redirect(url_for('auth.web_login')) return redirect(url_for('auth.web_login'))
login_user(user, remember=form.remember_me.data) login_user(user, remember=form.remember_me.data)
next_page = request.args.get('next') next_page = request.args.get('next')
if not next_page or url_parse(next_page).netloc != '': if not next_page or urlparse(next_page).netloc != '':
next_page = url_for('main.index') next_page = url_for('main.index')
return redirect(next_page) return redirect(next_page)
return render_template('auth/login.html', title='Sign In', form=form) return render_template('auth/login.html', title='Sign In', form=form)

View File

@ -1,4 +1,4 @@
from flask import abort, redirect, url_for from flask import abort, current_app, redirect, request, url_for
from flask_login import current_user, login_required from flask_login import current_user, login_required
from . import bp from . import bp
from .forms import EvaluateCandidateForm from .forms import EvaluateCandidateForm
@ -12,8 +12,10 @@ from src.utils.database_utils import generate_token
def candidates(establishment_id): def candidates(establishment_id):
establishment = Establishment.query.get_or_404(establishment_id) establishment = Establishment.query.get_or_404(establishment_id)
if(current_user == establishment.User): if(current_user == establishment.User):
page = request.args.get('page', 1, type=int)
form = EvaluateCandidateForm() form = EvaluateCandidateForm()
establishment_candidates = EstablishmentCandidate.query.filter_by(establishment = establishment.id).all() establishment_candidates = EstablishmentCandidate.query.filter_by(establishment = establishment.id).order_by(EstablishmentCandidate.user.asc()).paginate(
page=page, per_page=current_app.config['POSTS_PER_PAGE'], error_out=False)
if(form.validate_on_submit()): if(form.validate_on_submit()):
if(form.accept.data): if(form.accept.data):
login_token = LoginToken(Establishment = establishment, User = User.query.get(form.candidate_id.data), token = generate_token()) login_token = LoginToken(Establishment = establishment, User = User.query.get(form.candidate_id.data), token = generate_token())

View File

@ -1,48 +1,55 @@
from collections import namedtuple from collections import namedtuple
from flask_wtf import FlaskForm from flask_wtf import FlaskForm
from models import Brand, Item
from src.utils.models.query_factories import all_brands, all_items from src.utils.models.query_factories import all_brands, all_items
from wtforms import BooleanField, HiddenField, FieldList, Form, FormField, IntegerField, RadioField, SelectField, StringField, SubmitField from wtforms import BooleanField, HiddenField, FieldList, Form, FormField, IntegerField, RadioField, StringField, SubmitField
from wtforms.validators import DataRequired, Optional, ValidationError from wtforms.validators import DataRequired, ValidationError
from wtforms_sqlalchemy.fields import QuerySelectField from wtforms_sqlalchemy.fields import QuerySelectField
def radio_validator(choice):
field_names = ["New", "Existing"]
def _radio_validator(form, field):
if (form.new_or_existing.data == choice and (not field.data)):
raise ValidationError(
f"Field is required if you choose '{field_names[choice-1]}'.")
return _radio_validator
def get_choices():
return [(1, "New"), (2, "Existing"), (3, "Not listed")]
class CheckItemsEntryForm(Form): class CheckItemsEntryForm(Form):
# TODO Fertig machen x.x
itemname = HiddenField('itemname', validators=[DataRequired()]) itemname = HiddenField('itemname', validators=[DataRequired()])
price = HiddenField('price', validators=[DataRequired()]) price = HiddenField('price', validators=[DataRequired()])
requesting = BooleanField("", default=False, render_kw={ requesting = BooleanField("", default=False,
"class": "form-check-input"}) render_kw={"class": "form-check-input"})
new_or_existing = RadioField("", choices=[ new_or_existing = RadioField("",
(0, "New"), (1, "Existing")], render_kw={"class": "form-check-input", "style": "display:none"}, validate_choice=False) choices=get_choices(),
render_kw={"class": "form-check form-check-inline form-check-input"},
coerce=int, default=3)
# Fields for new Item # Fields for new Item
new_description = StringField("Description", render_kw={"class": "form-control"}) new_ean = IntegerField("EAN ID", render_kw={
new_amount_change = IntegerField("Amount", render_kw={"class": "form-control"}) "class": "form-control"}, validators=[radio_validator(1)],
new_brand = QuerySelectField("Brand", query_factory=all_brands, render_kw={"class": "form-control"}, allow_blank=True) default=0)
new_description = StringField("Description", render_kw={
"class": "form-control"}, validators=[radio_validator(1)])
new_amount_change = IntegerField("Amount",
render_kw={"class": "form-control"},
validators=[radio_validator(1)],
default=0)
new_brand = QuerySelectField("Brand", query_factory=all_brands,
render_kw={"class": "form-control"},
allow_blank=True, validators=[radio_validator(1)])
# Fields for existing Item # Fields for existing Item
existing_item = QuerySelectField("Item", query_factory=all_items, render_kw={"class": "form-control"}, allow_blank=True) existing_item = QuerySelectField("Item", query_factory=all_items,
render_kw={"class": "form-control"},
allow_blank=True, validators=[radio_validator(2)])
def validate_new_or_existing(self, new_or_existing): def validate_new_or_existing(self, new_or_existing):
if (self.requesting.data and not new_or_existing.data): if (self.requesting.data and not new_or_existing.data):
raise ValidationError( raise ValidationError(
"Please choose if it's a new or existing Item.") "Please choose if it's a new or existing Item.")
def validate_existing_item(self, existing_item):
if (existing_item.data and self.new_or_existing.data == 0):
raise ValidationError("You shouldn't be able to enter this.")
def validate_new_description(self, new_description):
if (new_description.data and self.new_or_existing.data == 1):
raise ValidationError("You shouldn't be able to enter this.")
def validate_new_amount_change(self, new_amount_change):
if (new_amount_change.data and self.new_or_existing.data == 1):
raise ValidationError("You shouldn't be able to enter this.")
def validate_new_brand(self, new_brand):
if (new_brand.data and self.new_or_existing.data == 1):
raise ValidationError("You shouldn't be able to enter this.")
class CheckItemsForm(FlaskForm): class CheckItemsForm(FlaskForm):
items = FieldList(FormField(CheckItemsEntryForm)) items = FieldList(FormField(CheckItemsEntryForm))
@ -55,7 +62,8 @@ class CheckItemsForm(FlaskForm):
CheckItems = namedtuple("CheckItems", ["items"]) CheckItems = namedtuple("CheckItems", ["items"])
check_items_entry = [] check_items_entry = []
for item in itemarray: for item in itemarray:
check_items_entry.append(CheckItemsEntry(item['itemname'], item['price'], 0)) check_items_entry.append(CheckItemsEntry(
item['itemname'], item['price'], 0))
check_items = CheckItems(check_items_entry) check_items = CheckItems(check_items_entry)
form = cls(obj=check_items) form = cls(obj=check_items)

View File

@ -1,10 +1,11 @@
from datetime import date
from flask import abort, request, url_for from flask import abort, request, url_for
from flask_login import current_user, login_required from flask_login import current_user, login_required
from . import bp from . import bp
from .forms import CheckItemsForm from .forms import CheckItemsEntryForm, CheckItemsForm, get_choices
from .utils import insert_existing_item, insert_new_item, insert_item_to_receipt, clear_receipt_items
from src import db, LOGGER from src import db, LOGGER
from models.receipt import Receipt from models import AmountChange, Item, LoginToken, PriceChange, Receipt, ReceiptItem
from models.login_token import LoginToken
from src.utils.pdf_receipt_parser import PDFReceipt from src.utils.pdf_receipt_parser import PDFReceipt
from src.utils.routes_utils import render_custom_template as render_template from src.utils.routes_utils import render_custom_template as render_template
@ -15,10 +16,10 @@ PDFDir = "./"
def confirm_receipt_items(receipt_id: int): def confirm_receipt_items(receipt_id: int):
"""Check items from a receipt if they should be accounted for payment. """Check items from a receipt if they should be accounted for payment.
Get those items from the receipt PDF itself.""" Get those items from the receipt PDF itself."""
receipt_details = Receipt.query.get(receipt_id) receipt_details: Receipt = Receipt.query.get(receipt_id)
if current_user.is_authenticated and current_user.id == receipt_details.LoginToken.Establishment.owner: if current_user.is_authenticated and current_user.id == receipt_details.LoginToken.Establishment.owner:
receipt = PDFReceipt.getPDFReceiptFromFile(PDFDir + f"{receipt_details.id}.pdf") receipt: PDFReceipt = PDFReceipt.getPDFReceiptFromFile(PDFDir + f"{receipt_details.id}.pdf")
form = CheckItemsForm.new(receipt.items) form: CheckItemsForm = CheckItemsForm.new(receipt.items)
# TODO: Precheck if items are already in database. If yes, check if item is present only once or multiple # TODO: Precheck if items are already in database. If yes, check if item is present only once or multiple
# times and provide dropdown menu if necessary. If not, provide input field. # times and provide dropdown menu if necessary. If not, provide input field.
# temp_choices = [] # temp_choices = []
@ -30,12 +31,34 @@ def confirm_receipt_items(receipt_id: int):
# temp_choices.append((itemname.replace(" ", "_"), f"{itemname}, {price} * {amount}")) # temp_choices.append((itemname.replace(" ", "_"), f"{itemname}, {price} * {amount}"))
# form.choices = temp_choices # form.choices = temp_choices
# print(form.data) # print(form.data)
for formitem in form.items: # for formitem in form.items:
# print(formitem.new_brand.__dict__) # LOGGER.debug(formitem.data)
print(formitem.data)
if form.validate(): if form.validate():
print("valid") LOGGER.debug("valid")
else:
LOGGER.debug(form.errors)
if form.validate_on_submit(): if form.validate_on_submit():
return form.items.data LOGGER.debug("Validate on submit")
clear_receipt_items(receipt=receipt_details)
for itempos, formitem in enumerate(form.items):
LOGGER.debug("Iterating through form items")
formitemdata = formitem.data
if formitemdata.get('requesting'):
LOGGER.debug("Item requested")
LOGGER.debug(formitemdata)
insert_item_to_receipt(receipt=receipt_details, item_dict=receipt.items[itempos], item_index=itempos)
if formitemdata.get('new_or_existing') == get_choices()[0][0]: # New Item
LOGGER.debug("New Item catched")
insert_new_item(formitemdict=formitemdata)
elif formitemdata.get('new_or_existing') == get_choices()[1][0]: # Existing Item
LOGGER.debug("Existing Item catched")
insert_existing_item(formitemdict=formitemdata, receipt_date=receipt.date)
elif formitemdata.get('new_or_existing') == get_choices()[2][0]: # Item not for DB
LOGGER.debug("Not listed Item catched")
else:
LOGGER.debug("Cold catched")
abort(400)
LOGGER.debug("At this point form.items.data will be returned")
# return form.items.data
return render_template("receipts/check_items.html", form=form) return render_template("receipts/check_items.html", form=form)
abort(403) abort(403)

View File

@ -0,0 +1,57 @@
from datetime import date
from models import AmountChange, Item, PriceChange, Receipt, ReceiptItem
from src import db, LOGGER
def insert_new_item(formitemdict: dict[str: str]):
LOGGER.debug("Inserting new Item")
newitem = Item(id=formitemdict.get('new_ean'), name=formitemdict.get('itemname'), description=formitemdict.get('new_description'), Brand=formitemdict.get('new_brand'))
newamount = formitemdict.get('new_amount')
if(newamount and newamount not in [0, 1]):
newitem.AmountChange.append(AmountChange(amount=newamount))
newprice = int(formitemdict.get("price").replace(",", ""))
newitem.PriceChange.append(PriceChange(price=newprice))
db.session.add(newitem)
db.session.commit()
def insert_existing_item(formitemdict: dict[str: str], receipt_date: date = None):
if not receipt_date:
receipt_date = date.today()
LOGGER.debug("Updating existing Item")
itemobject: Item = formitemdict.get("existing_item")
LOGGER.debug("Retrieving and comparing old and new price")
# TODO compare the dates around the receipt date (before and after receipt date)
pricechange_list: list[PriceChange] = itemobject.PriceChange.order_by(PriceChange.date.desc()).all()
neighboring_prices: list[PriceChange] = get_neighboring_prices(pricechange_list, receipt_date)
newprice = int(formitemdict.get("price").replace(",", ""))
LOGGER.debug(neighboring_prices)
if newprice != neighboring_prices[1].price:
LOGGER.debug("New Price different from earlier price, inserting new price")
new_pricechange = PriceChange(Item=itemobject, date=str(receipt_date), price=newprice)
db.session.add(new_pricechange)
if newprice == neighboring_prices[0].price:
LOGGER.debug("New Price same as later price, removing later entry")
db.session.delete(neighboring_prices[0])
db.session.commit()
def insert_item_to_receipt(receipt: Receipt, item_dict: dict[str: str], item_index:int=0):
receipt.ReceiptItem.append(ReceiptItem(item=item_index, amount=item_dict.get('amount'), price=int(item_dict.get('price').replace(',',''))))
db.session.add(receipt)
db.session.commit()
def clear_receipt_items(receipt: Receipt):
receipt.registered = False
for receipt_item in receipt.ReceiptItem.all():
db.session.delete(receipt_item)
db.session.commit()
def get_neighboring_prices(pricechange_list: list[PriceChange], target_date: date):
upper_date, lower_date = None, None
for pricechange in pricechange_list:
if pricechange.date > target_date:
if (not upper_date) or (upper_date.date > pricechange.date):
upper_date = pricechange
elif pricechange.date < target_date:
if (not lower_date) or (lower_date.date < pricechange.date):
lower_date = pricechange
return [upper_date, lower_date]

View File

@ -1,4 +1,4 @@
from flask import abort, request, url_for from flask import abort, redirect, request, url_for
from flask_login import current_user, login_required from flask_login import current_user, login_required
from os import rename from os import rename
from werkzeug.utils import secure_filename from werkzeug.utils import secure_filename
@ -11,10 +11,6 @@ from src.utils.pdf_receipt_parser import PDFReceipt
from src.utils.routes_utils import render_custom_template as render_template from src.utils.routes_utils import render_custom_template as render_template
PDFDir = "./" PDFDir = "./"
# TODO überarbeiten. PDFs müssen in der Datenbank eine eigene ID bekommen.
# Quittungen haben eine gesonderte ID. Die muss als Unique Key in der Datenbank
# hinterlegt sein.
# Die laufende ID ist zum abspeichern der PDFs gedacht.
@bp.route('/<int:establishment>', methods=['GET', 'POST']) @bp.route('/<int:establishment>', methods=['GET', 'POST'])
@login_required @login_required
def upload_receipt(establishment: int): def upload_receipt(establishment: int):
@ -34,7 +30,8 @@ def upload_receipt(establishment: int):
db.session.add(dbReceipt) db.session.add(dbReceipt)
db.session.commit() db.session.commit()
rename(f"{PDFDir}/temp.pdf", f"{PDFDir}{secure_filename(f'{dbReceipt.id}.pdf')}") rename(f"{PDFDir}/temp.pdf", f"{PDFDir}{secure_filename(f'{dbReceipt.id}.pdf')}")
return receipt.text.replace("\n", "<br>") LOGGER.debug(receipt.text)
return redirect(url_for("receipts.check_items.confirm_receipt_items", receipt_id = dbReceipt.id))
else: else:
LOGGER.debug(form.errors) LOGGER.debug(form.errors)
return render_template("receipts/upload.html", form = form) return render_template("receipts/upload.html", form = form)

View File

@ -0,0 +1,54 @@
import fitz
from datetime import datetime
from re import search
class PDFReceipt:
"""Class to use a PDF-Receipt as an object.
Arguments:
strPDFFile -- The path to the PDF-File as a string.
parser -- A keyword in lowercase to tell how the receipt is formated.
Currently supported: 'edeka'
"""
def __init__(self, bPDFFile, parser: str = "edeka") -> None:
self.text = PDFReceipt._getTextFromPDF(bPDFFile)
self.id, self.date, self.items = PDFReceipt._getInfosFromText(self.text, parser)
def _getTextFromPDF(file):
with fitz.open(file, filetype="pdf") as doc:
text = ""
for page in doc:
text += page.get_text()
return text.strip()
def _getItemsTextFromText(text, start="", end=""):
return text[text.index(start)+len(start):text.index(end)].strip()
def _convertItemsTextToDict(text):
temp = text.split("\n")
resultsArr = []
i = 0
while i < len(temp):
if search("(\d+) x", temp[i]):
resultsArr.append({"itemname": temp[i+2], "price": temp[i+1], "amount": temp[i][:-2]})
i += 4
else:
resultsArr.append({"itemname": temp[i], "price": temp[i+1][:-2]})
i += 2
return resultsArr
def _getInfosFromText(text: str, parser: str = "edeka"):
if parser.lower() == "edeka":
items = PDFReceipt._convertItemsTextToDict(PDFReceipt._getItemsTextFromText(text, start="EUR", end="----------"))
strDate = text.split("\n")[-1].split(" ")[0]
date = datetime.strptime(strDate, "%d.%m.%y").date()
strReceiptNumber = text.split("\n")[-1].split(" ")[-1]
try:
intReceiptNumber = int(strReceiptNumber)
except:
raise ValueError("Receipt Number not an integer.")
return (intReceiptNumber, date, items)
def getPDFReceiptFromFile(strPDFFile: str, parser: str = "edeka"):
with open(strPDFFile) as doc:
return PDFReceipt(doc, parser)

View File

@ -11,5 +11,7 @@
{% endfor %} {% endfor %}
</tbody> </tbody>
</table> </table>
{% with pagination_object=establishment_candidates %}
{% include "utils/general/_page_navigation.html" %} {% include "utils/general/_page_navigation.html" %}
{% endwith %}
{% endblock %} {% endblock %}

View File

@ -13,6 +13,7 @@
{{ render_field(item.new_or_existing) }} {{ render_field(item.new_or_existing) }}
</div> </div>
<div class="{{ item.id }}_new" style="display: none;"> <div class="{{ item.id }}_new" style="display: none;">
{{ render_field(item.new_ean) }}
{{ render_field(item.new_description) }} {{ render_field(item.new_description) }}
{{ render_field(item.new_amount_change) }} {{ render_field(item.new_amount_change) }}
{{ render_field(item.new_brand) }} {{ render_field(item.new_brand) }}
@ -36,10 +37,10 @@
$("#{{ item.requesting.id }}").change(function () { $("#{{ item.requesting.id }}").change(function () {
if ($(this).prop("checked")) { if ($(this).prop("checked")) {
$(".{{ item.new_or_existing.id }}").show(); $(".{{ item.new_or_existing.id }}").show();
if ($("#{{ item.new_or_existing.id }}-0").prop("checked")) { if ($("#{{ item.new_or_existing.id }}-1").prop("checked")) {
$(".{{ item.id }}_new").show(); $(".{{ item.id }}_new").show();
} }
if ($("#{{ item.new_or_existing.id }}-1").prop("checked")) { if ($("#{{ item.new_or_existing.id }}-2").prop("checked")) {
$(".{{ item.id }}_existing").show(); $(".{{ item.id }}_existing").show();
} }
} }
@ -49,18 +50,24 @@
$(".{{ item.id }}_existing").hide(); $(".{{ item.id }}_existing").hide();
} }
}); });
$("#{{ item.new_or_existing.id }}-0").change(function () { $("#{{ item.new_or_existing.id }}-1").change(function () {
if ($(this).prop("checked")) { if ($(this).prop("checked")) {
$(".{{ item.id }}_new").show(); $(".{{ item.id }}_new").show();
$(".{{ item.id }}_existing").hide(); $(".{{ item.id }}_existing").hide();
} }
}); });
$("#{{ item.new_or_existing.id }}-1").change(function () { $("#{{ item.new_or_existing.id }}-2").change(function () {
if ($(this).prop("checked")) { if ($(this).prop("checked")) {
$(".{{ item.id }}_new").hide(); $(".{{ item.id }}_new").hide();
$(".{{ item.id }}_existing").show(); $(".{{ item.id }}_existing").show();
} }
}); });
$("#{{ item.new_or_existing.id }}-3").change(function () {
if ($(this).prop("checked")) {
$(".{{ item.id }}_new").hide();
$(".{{ item.id }}_existing").hide();
}
});
}); });
</script> </script>
{% endfor %} {% endfor %}

View File

@ -0,0 +1,8 @@
{% if field.errors %}
<ul class="errors">
{% for error in field.errors %}
<li>{{ error }}</li>
{% endfor %}
</ul>
{% endif %}

View File

@ -1,11 +1,6 @@
{% macro render_fieldlist(field) %} {% macro render_fieldlist(field) %}
<div class="form-group"> <div class="form-group">
{{ field.label }} {{ field(**kwargs)|safe }} {% if field.errors %} {{ field.label }} {{ field(**kwargs)|safe }}
<ul class="errors"> {% include "utils/form/_render_field_errors.html" %}
{% for error in field.errors %}
<li>{{ error }}</li>
{% endfor %}
</ul>
{% endif %}
</div> </div>
{% endmacro %} {% endmacro %}

View File

@ -1,11 +1,6 @@
{% macro render_field(field) %} {% macro render_field(field) %}
<div class="form-group"> <div class="form-group">
{{ field.label }} {{ field(**kwargs)|safe }} {% if field.errors %} {{ field.label }} {{ field(**kwargs)|safe }}
<ul class="errors"> {% include "utils/form/_render_field_errors.html" %}
{% for error in field.errors %}
<li>{{ error }}</li>
{% endfor %}
</ul>
{% endif %}
</div> </div>
{% endmacro %} {% endmacro %}

View File

@ -1,11 +1,6 @@
{% macro render_field(field) %} {% macro render_field(field) %}
<div class="form-group"> <div class="form-group">
{{ field(**kwargs)|safe }} {% if field.errors %} {{ field(**kwargs)|safe }}
<ul class="errors"> {% include "utils/form/_render_field_errors.html" %}
{% for error in field.errors %}
<li>{{ error }}</li>
{% endfor %}
</ul>
{% endif %}
</div> </div>
{% endmacro %} {% endmacro %}

View File

@ -2,15 +2,10 @@
{% for choice in field.choices %} {% for choice in field.choices %}
<div class="form-check form-check-inline"> <div class="form-check form-check-inline">
<input class="{{ field.render_kw['class'] }}" type="radio" name="{{ field.id }}" id="{{ field.id }}-{{ choice[0] }}" <input class="{{ field.render_kw['class'] }}" type="radio" name="{{ field.id }}" id="{{ field.id }}-{{ choice[0] }}"
value="{{ choice[0] }}"> value="{{ choice[0] }}" {% if field.default == choice[0] %} checked {% endif %}>
<label class="form-check-label" for="{{ field.id }}-{{ choice[0] }}">{{ choice[1] }}</label> <label class="form-check-label" for="{{ field.id }}-{{ choice[0] }}">{{ choice[1] }}</label>
</div> </div>
{% endfor %} {% endfor %}
{% if field.errors %} {# {{ field(**kwargs)|safe }} {{ field.label }} #}
<ul class="errors"> {% include "utils/form/_render_field_errors.html" %}
{% for error in field.errors %}
<li>{{ error }}</li>
{% endfor %}
</ul>
{% endif %}
{% endmacro %} {% endmacro %}