From 4d1e7eb944e404d5d9ce6e068312976f4b78821b Mon Sep 17 00:00:00 2001 From: Lunaresk Date: Sun, 12 Nov 2023 16:05:09 +0100 Subject: [PATCH] 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. --- .gitignore | 5 +- backend/Pipfile | 1 + backend/Pipfile.lock | 721 ++++++++++-------- ...800705_remove_accepted_from_receiptitem.py | 32 + ...30_remove_item_receiptitem_relationship.py | 64 ++ backend/models/item.py | 2 - backend/models/receipt_item.py | 7 +- backend/models/schemas/receipt_item.py | 3 +- backend/requirements.txt | Bin 3634 -> 1729 bytes backend/src/auth/routes.py | 4 +- .../src/establishment/candidates/routes.py | 6 +- backend/src/receipts/check_items/forms.py | 66 +- backend/src/receipts/check_items/routes.py | 45 +- backend/src/receipts/check_items/utils.py | 57 ++ backend/src/receipts/upload/routes.py | 9 +- .../receipt_parser/edeka/edeka_parser.py | 0 .../receipt_parser/pdf_receipt_parser.py | 54 ++ .../establishment/candidates/candidates.html | 2 + .../web/templates/receipts/check_items.html | 15 +- .../utils/form/_render_field_errors.html | 8 + .../utils/form/_render_fieldlist.html | 9 +- .../utils/form/_render_generic_field.html | 9 +- .../utils/form/_render_hidden_field.html | 9 +- .../utils/form/_render_radio_button.html | 11 +- 24 files changed, 725 insertions(+), 414 deletions(-) create mode 100644 backend/migrations/versions/36f532800705_remove_accepted_from_receiptitem.py create mode 100644 backend/migrations/versions/cdbe3f5e3b30_remove_item_receiptitem_relationship.py create mode 100644 backend/src/receipts/check_items/utils.py create mode 100644 backend/src/utils/modules/receipt_parser/edeka/edeka_parser.py create mode 100644 backend/src/utils/modules/receipt_parser/pdf_receipt_parser.py create mode 100644 backend/web/templates/utils/form/_render_field_errors.html diff --git a/.gitignore b/.gitignore index 1d1cfe8..73d560d 100644 --- a/.gitignore +++ b/.gitignore @@ -341,6 +341,7 @@ config.yaml scans.json test_*.* test.* +tests* *.db .vscode *.tar @@ -350,4 +351,6 @@ test.* !.env.project !.env.vault *.ps1 -*.pdf \ No newline at end of file +*.pdf +*.backup +Dockerfile.* \ No newline at end of file diff --git a/backend/Pipfile b/backend/Pipfile index a84b1dc..21514f5 100644 --- a/backend/Pipfile +++ b/backend/Pipfile @@ -22,6 +22,7 @@ pymupdf = "*" requests = "*" sqlalchemy-utils = "*" wtforms-sqlalchemy = "*" +pytest = "*" [dev-packages] diff --git a/backend/Pipfile.lock b/backend/Pipfile.lock index aed324c..aa44bc4 100644 --- a/backend/Pipfile.lock +++ b/backend/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "5418d6b50788a542461e9a348ad0864d3e4d2046e48967df081cbaed9971ed0f" + "sha256": "6f12189a28bcfca261128bb19798f69649619d796466a01c69fe3a8df6457fbf" }, "pipfile-spec": 6, "requires": { @@ -19,19 +19,19 @@ "default": { "alembic": { "hashes": [ - "sha256:6a810a6b012c88b33458fceb869aef09ac75d6ace5291915ba7fae44de372c01", - "sha256:dc871798a601fab38332e38d6ddb38d5e734f60034baeb8e2db5b642fccd8ab8" + "sha256:47d52e3dfb03666ed945becb723d6482e52190917fdb47071440cfdba05d92cb", + "sha256:bca5877e9678b454706347bc10b97cb7d67f300320fa5c3a94423e8266e2823f" ], "markers": "python_version >= '3.7'", - "version": "==1.11.1" + "version": "==1.12.1" }, "blinker": { "hashes": [ - "sha256:4afd3de66ef3a9f8067559fb7a1cbe555c17dcbe15971b05d1b625c3e7abe213", - "sha256:c3d739772abb7bc2860abf5f2ec284223d9ad5c76da018234f6f50d6f31ab1f0" + "sha256:152090d27c1c5c722ee7e48504b02d76502811ce02e1523553b4cf8c8b3d3a8d", + "sha256:296320d6c28b006eb5e32d4712202dbcdcbf5dc482da298c2f44881c43884aaa" ], "markers": "python_version >= '3.7'", - "version": "==1.6.2" + "version": "==1.6.3" }, "certifi": { "hashes": [ @@ -43,92 +43,107 @@ }, "charset-normalizer": { "hashes": [ - "sha256:04e57ab9fbf9607b77f7d057974694b4f6b142da9ed4a199859d9d4d5c63fe96", - "sha256:09393e1b2a9461950b1c9a45d5fd251dc7c6f228acab64da1c9c0165d9c7765c", - "sha256:0b87549028f680ca955556e3bd57013ab47474c3124dc069faa0b6545b6c9710", - "sha256:1000fba1057b92a65daec275aec30586c3de2401ccdcd41f8a5c1e2c87078706", - "sha256:1249cbbf3d3b04902ff081ffbb33ce3377fa6e4c7356f759f3cd076cc138d020", - "sha256:1920d4ff15ce893210c1f0c0e9d19bfbecb7983c76b33f046c13a8ffbd570252", - "sha256:193cbc708ea3aca45e7221ae58f0fd63f933753a9bfb498a3b474878f12caaad", - "sha256:1a100c6d595a7f316f1b6f01d20815d916e75ff98c27a01ae817439ea7726329", - "sha256:1f30b48dd7fa1474554b0b0f3fdfdd4c13b5c737a3c6284d3cdc424ec0ffff3a", - "sha256:203f0c8871d5a7987be20c72442488a0b8cfd0f43b7973771640fc593f56321f", - "sha256:246de67b99b6851627d945db38147d1b209a899311b1305dd84916f2b88526c6", - "sha256:2dee8e57f052ef5353cf608e0b4c871aee320dd1b87d351c28764fc0ca55f9f4", - "sha256:2efb1bd13885392adfda4614c33d3b68dee4921fd0ac1d3988f8cbb7d589e72a", - "sha256:2f4ac36d8e2b4cc1aa71df3dd84ff8efbe3bfb97ac41242fbcfc053c67434f46", - "sha256:3170c9399da12c9dc66366e9d14da8bf7147e1e9d9ea566067bbce7bb74bd9c2", - "sha256:3b1613dd5aee995ec6d4c69f00378bbd07614702a315a2cf6c1d21461fe17c23", - "sha256:3bb3d25a8e6c0aedd251753a79ae98a093c7e7b471faa3aa9a93a81431987ace", - "sha256:3bb7fda7260735efe66d5107fb7e6af6a7c04c7fce9b2514e04b7a74b06bf5dd", - "sha256:41b25eaa7d15909cf3ac4c96088c1f266a9a93ec44f87f1d13d4a0e86c81b982", - "sha256:45de3f87179c1823e6d9e32156fb14c1927fcc9aba21433f088fdfb555b77c10", - "sha256:46fb8c61d794b78ec7134a715a3e564aafc8f6b5e338417cb19fe9f57a5a9bf2", - "sha256:48021783bdf96e3d6de03a6e39a1171ed5bd7e8bb93fc84cc649d11490f87cea", - "sha256:4957669ef390f0e6719db3613ab3a7631e68424604a7b448f079bee145da6e09", - "sha256:5e86d77b090dbddbe78867a0275cb4df08ea195e660f1f7f13435a4649e954e5", - "sha256:6339d047dab2780cc6220f46306628e04d9750f02f983ddb37439ca47ced7149", - "sha256:681eb3d7e02e3c3655d1b16059fbfb605ac464c834a0c629048a30fad2b27489", - "sha256:6c409c0deba34f147f77efaa67b8e4bb83d2f11c8806405f76397ae5b8c0d1c9", - "sha256:7095f6fbfaa55defb6b733cfeb14efaae7a29f0b59d8cf213be4e7ca0b857b80", - "sha256:70c610f6cbe4b9fce272c407dd9d07e33e6bf7b4aa1b7ffb6f6ded8e634e3592", - "sha256:72814c01533f51d68702802d74f77ea026b5ec52793c791e2da806a3844a46c3", - "sha256:7a4826ad2bd6b07ca615c74ab91f32f6c96d08f6fcc3902ceeedaec8cdc3bcd6", - "sha256:7c70087bfee18a42b4040bb9ec1ca15a08242cf5867c58726530bdf3945672ed", - "sha256:855eafa5d5a2034b4621c74925d89c5efef61418570e5ef9b37717d9c796419c", - "sha256:8700f06d0ce6f128de3ccdbc1acaea1ee264d2caa9ca05daaf492fde7c2a7200", - "sha256:89f1b185a01fe560bc8ae5f619e924407efca2191b56ce749ec84982fc59a32a", - "sha256:8b2c760cfc7042b27ebdb4a43a4453bd829a5742503599144d54a032c5dc7e9e", - "sha256:8c2f5e83493748286002f9369f3e6607c565a6a90425a3a1fef5ae32a36d749d", - "sha256:8e098148dd37b4ce3baca71fb394c81dc5d9c7728c95df695d2dca218edf40e6", - "sha256:94aea8eff76ee6d1cdacb07dd2123a68283cb5569e0250feab1240058f53b623", - "sha256:95eb302ff792e12aba9a8b8f8474ab229a83c103d74a750ec0bd1c1eea32e669", - "sha256:9bd9b3b31adcb054116447ea22caa61a285d92e94d710aa5ec97992ff5eb7cf3", - "sha256:9e608aafdb55eb9f255034709e20d5a83b6d60c054df0802fa9c9883d0a937aa", - "sha256:a103b3a7069b62f5d4890ae1b8f0597618f628b286b03d4bc9195230b154bfa9", - "sha256:a386ebe437176aab38c041de1260cd3ea459c6ce5263594399880bbc398225b2", - "sha256:a38856a971c602f98472050165cea2cdc97709240373041b69030be15047691f", - "sha256:a401b4598e5d3f4a9a811f3daf42ee2291790c7f9d74b18d75d6e21dda98a1a1", - "sha256:a7647ebdfb9682b7bb97e2a5e7cb6ae735b1c25008a70b906aecca294ee96cf4", - "sha256:aaf63899c94de41fe3cf934601b0f7ccb6b428c6e4eeb80da72c58eab077b19a", - "sha256:b0dac0ff919ba34d4df1b6131f59ce95b08b9065233446be7e459f95554c0dc8", - "sha256:baacc6aee0b2ef6f3d308e197b5d7a81c0e70b06beae1f1fcacffdbd124fe0e3", - "sha256:bf420121d4c8dce6b889f0e8e4ec0ca34b7f40186203f06a946fa0276ba54029", - "sha256:c04a46716adde8d927adb9457bbe39cf473e1e2c2f5d0a16ceb837e5d841ad4f", - "sha256:c0b21078a4b56965e2b12f247467b234734491897e99c1d51cee628da9786959", - "sha256:c1c76a1743432b4b60ab3358c937a3fe1341c828ae6194108a94c69028247f22", - "sha256:c4983bf937209c57240cff65906b18bb35e64ae872da6a0db937d7b4af845dd7", - "sha256:c4fb39a81950ec280984b3a44f5bd12819953dc5fa3a7e6fa7a80db5ee853952", - "sha256:c57921cda3a80d0f2b8aec7e25c8aa14479ea92b5b51b6876d975d925a2ea346", - "sha256:c8063cf17b19661471ecbdb3df1c84f24ad2e389e326ccaf89e3fb2484d8dd7e", - "sha256:ccd16eb18a849fd8dcb23e23380e2f0a354e8daa0c984b8a732d9cfaba3a776d", - "sha256:cd6dbe0238f7743d0efe563ab46294f54f9bc8f4b9bcf57c3c666cc5bc9d1299", - "sha256:d62e51710986674142526ab9f78663ca2b0726066ae26b78b22e0f5e571238dd", - "sha256:db901e2ac34c931d73054d9797383d0f8009991e723dab15109740a63e7f902a", - "sha256:e03b8895a6990c9ab2cdcd0f2fe44088ca1c65ae592b8f795c3294af00a461c3", - "sha256:e1c8a2f4c69e08e89632defbfabec2feb8a8d99edc9f89ce33c4b9e36ab63037", - "sha256:e4b749b9cc6ee664a3300bb3a273c1ca8068c46be705b6c31cf5d276f8628a94", - "sha256:e6a5bf2cba5ae1bb80b154ed68a3cfa2fa00fde979a7f50d6598d3e17d9ac20c", - "sha256:e857a2232ba53ae940d3456f7533ce6ca98b81917d47adc3c7fd55dad8fab858", - "sha256:ee4006268ed33370957f55bf2e6f4d263eaf4dc3cfc473d1d90baff6ed36ce4a", - "sha256:eef9df1eefada2c09a5e7a40991b9fc6ac6ef20b1372abd48d2794a316dc0449", - "sha256:f058f6963fd82eb143c692cecdc89e075fa0828db2e5b291070485390b2f1c9c", - "sha256:f25c229a6ba38a35ae6e25ca1264621cc25d4d38dca2942a7fce0b67a4efe918", - "sha256:f2a1d0fd4242bd8643ce6f98927cf9c04540af6efa92323e9d3124f57727bfc1", - "sha256:f7560358a6811e52e9c4d142d497f1a6e10103d3a6881f18d04dbce3729c0e2c", - "sha256:f779d3ad205f108d14e99bb3859aa7dd8e9c68874617c72354d7ecaec2a054ac", - "sha256:f87f746ee241d30d6ed93969de31e5ffd09a2961a051e60ae6bddde9ec3583aa" + "sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027", + "sha256:06a81e93cd441c56a9b65d8e1d043daeb97a3d0856d177d5c90ba85acb3db087", + "sha256:0a55554a2fa0d408816b3b5cedf0045f4b8e1a6065aec45849de2d6f3f8e9786", + "sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8", + "sha256:10955842570876604d404661fbccbc9c7e684caf432c09c715ec38fbae45ae09", + "sha256:122c7fa62b130ed55f8f285bfd56d5f4b4a5b503609d181f9ad85e55c89f4185", + "sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574", + "sha256:1d3193f4a680c64b4b6a9115943538edb896edc190f0b222e73761716519268e", + "sha256:1f79682fbe303db92bc2b1136016a38a42e835d932bab5b3b1bfcfbf0640e519", + "sha256:2127566c664442652f024c837091890cb1942c30937add288223dc895793f898", + "sha256:22afcb9f253dac0696b5a4be4a1c0f8762f8239e21b99680099abd9b2b1b2269", + "sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3", + "sha256:2e81c7b9c8979ce92ed306c249d46894776a909505d8f5a4ba55b14206e3222f", + "sha256:3287761bc4ee9e33561a7e058c72ac0938c4f57fe49a09eae428fd88aafe7bb6", + "sha256:34d1c8da1e78d2e001f363791c98a272bb734000fcef47a491c1e3b0505657a8", + "sha256:37e55c8e51c236f95b033f6fb391d7d7970ba5fe7ff453dad675e88cf303377a", + "sha256:3d47fa203a7bd9c5b6cee4736ee84ca03b8ef23193c0d1ca99b5089f72645c73", + "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc", + "sha256:42cb296636fcc8b0644486d15c12376cb9fa75443e00fb25de0b8602e64c1714", + "sha256:45485e01ff4d3630ec0d9617310448a8702f70e9c01906b0d0118bdf9d124cf2", + "sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc", + "sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce", + "sha256:4d0d1650369165a14e14e1e47b372cfcb31d6ab44e6e33cb2d4e57265290044d", + "sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e", + "sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6", + "sha256:572c3763a264ba47b3cf708a44ce965d98555f618ca42c926a9c1616d8f34269", + "sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96", + "sha256:5b4c145409bef602a690e7cfad0a15a55c13320ff7a3ad7ca59c13bb8ba4d45d", + "sha256:6463effa3186ea09411d50efc7d85360b38d5f09b870c48e4600f63af490e56a", + "sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4", + "sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77", + "sha256:6897af51655e3691ff853668779c7bad41579facacf5fd7253b0133308cf000d", + "sha256:68d1f8a9e9e37c1223b656399be5d6b448dea850bed7d0f87a8311f1ff3dabb0", + "sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed", + "sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068", + "sha256:6c4caeef8fa63d06bd437cd4bdcf3ffefe6738fb1b25951440d80dc7df8c03ac", + "sha256:6ef1d82a3af9d3eecdba2321dc1b3c238245d890843e040e41e470ffa64c3e25", + "sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8", + "sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab", + "sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26", + "sha256:7f04c839ed0b6b98b1a7501a002144b76c18fb1c1850c8b98d458ac269e26ed2", + "sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db", + "sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f", + "sha256:8465322196c8b4d7ab6d1e049e4c5cb460d0394da4a27d23cc242fbf0034b6b5", + "sha256:86216b5cee4b06df986d214f664305142d9c76df9b6512be2738aa72a2048f99", + "sha256:87d1351268731db79e0f8e745d92493ee2841c974128ef629dc518b937d9194c", + "sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d", + "sha256:8c622a5fe39a48f78944a87d4fb8a53ee07344641b0562c540d840748571b811", + "sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa", + "sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a", + "sha256:9063e24fdb1e498ab71cb7419e24622516c4a04476b17a2dab57e8baa30d6e03", + "sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b", + "sha256:923c0c831b7cfcb071580d3f46c4baf50f174be571576556269530f4bbd79d04", + "sha256:95f2a5796329323b8f0512e09dbb7a1860c46a39da62ecb2324f116fa8fdc85c", + "sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001", + "sha256:9f96df6923e21816da7e0ad3fd47dd8f94b2a5ce594e00677c0013018b813458", + "sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389", + "sha256:a50aebfa173e157099939b17f18600f72f84eed3049e743b68ad15bd69b6bf99", + "sha256:a981a536974bbc7a512cf44ed14938cf01030a99e9b3a06dd59578882f06f985", + "sha256:a9a8e9031d613fd2009c182b69c7b2c1ef8239a0efb1df3f7c8da66d5dd3d537", + "sha256:ae5f4161f18c61806f411a13b0310bea87f987c7d2ecdbdaad0e94eb2e404238", + "sha256:aed38f6e4fb3f5d6bf81bfa990a07806be9d83cf7bacef998ab1a9bd660a581f", + "sha256:b01b88d45a6fcb69667cd6d2f7a9aeb4bf53760d7fc536bf679ec94fe9f3ff3d", + "sha256:b261ccdec7821281dade748d088bb6e9b69e6d15b30652b74cbbac25e280b796", + "sha256:b2b0a0c0517616b6869869f8c581d4eb2dd83a4d79e0ebcb7d373ef9956aeb0a", + "sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143", + "sha256:bd8f7df7d12c2db9fab40bdd87a7c09b1530128315d047a086fa3ae3435cb3a8", + "sha256:beb58fe5cdb101e3a055192ac291b7a21e3b7ef4f67fa1d74e331a7f2124341c", + "sha256:c002b4ffc0be611f0d9da932eb0f704fe2602a9a949d1f738e4c34c75b0863d5", + "sha256:c083af607d2515612056a31f0a8d9e0fcb5876b7bfc0abad3ecd275bc4ebc2d5", + "sha256:c180f51afb394e165eafe4ac2936a14bee3eb10debc9d9e4db8958fe36afe711", + "sha256:c235ebd9baae02f1b77bcea61bce332cb4331dc3617d254df3323aa01ab47bd4", + "sha256:cd70574b12bb8a4d2aaa0094515df2463cb429d8536cfb6c7ce983246983e5a6", + "sha256:d0eccceffcb53201b5bfebb52600a5fb483a20b61da9dbc885f8b103cbe7598c", + "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'", - "version": "==3.2.0" + "version": "==3.3.2" }, "click": { "hashes": [ - "sha256:48ee849951919527a045bfe3bf7baa8a959c423134e1a5b98c05c20ba75a1cbd", - "sha256:fa244bb30b3b5ee2cae3da8f55c9e5e0c0e86093306301fb418eb9dc40fbded5" + "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28", + "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de" ], "markers": "python_version >= '3.7'", - "version": "==8.1.6" + "version": "==8.1.7" }, "colorama": { "hashes": [ @@ -140,11 +155,11 @@ }, "dnspython": { "hashes": [ - "sha256:5b7488477388b8c0b70a8ce93b227c5603bc7b77f1565afe8e729c36c51447d7", - "sha256:c33971c79af5be968bb897e95c2448e11a645ee84d93b265ce0b7aabe5dfdca8" + "sha256:57c6fbaaeaaf39c891292012060beb141791735dbb4004798328fc2c467402d8", + "sha256:8dcfae8c7460a2f84b4072e26f1c9f4101ca20c071649cb7c34e8b6a93d58984" ], "markers": "python_version >= '3.8' and python_version < '4.0'", - "version": "==2.4.1" + "version": "==2.4.2" }, "dominate": { "hashes": [ @@ -156,19 +171,19 @@ }, "email-validator": { "hashes": [ - "sha256:1ff6e86044200c56ae23595695c54e9614f4a9551e0e393614f764860b3d7900", - "sha256:2466ba57cda361fb7309fd3d5a225723c788ca4bbad32a0ebd5373b99730285c" + "sha256:a4b0bd1cf55f073b924258d19321b1f3aa74b4b5a71a42c305575dba920e1a44", + "sha256:c973053efbeddfef924dc0bd93f6e77a1ea7ee0fce935aea7103c7a3d6d2d637" ], "index": "pypi", - "version": "==2.0.0.post2" + "version": "==2.1.0.post1" }, "flask": { "hashes": [ - "sha256:77fd4e1249d8c9923de34907236b747ced06e5467ecac1a7bb7115ae0e9670b0", - "sha256:8c2f9abd47a9e8df7f0c3f091ce9497d011dc3b31effcf4c85a6e2b50f4114ef" + "sha256:21128f47e4e3b9d597a3e8521a329bf56909b690fcc3fa3e477725aa81367638", + "sha256:cfadcdb638b609361d29ec22360d6070a77d7463dcb3ab08d2c2f2f168845f58" ], "index": "pypi", - "version": "==2.3.2" + "version": "==3.0.0" }, "flask-bootstrap": { "hashes": [ @@ -187,11 +202,11 @@ }, "flask-login": { "hashes": [ - "sha256:1ef79843f5eddd0f143c2cd994c1b05ac83c0401dc6234c143495af9a939613f", - "sha256:c0a7baa9fdc448cdd3dd6f0939df72eec5177b2f7abe6cb82fc934d29caac9c3" + "sha256:5e23d14a607ef12806c699590b89d0f0e0d67baeec599d75947bf9c147330333", + "sha256:849b25b82a436bf830a054e74214074af59097171562ab10bfa999e6b78aae5d" ], "index": "pypi", - "version": "==0.6.2" + "version": "==0.6.3" }, "flask-mail": { "hashes": [ @@ -210,93 +225,90 @@ }, "flask-migrate": { "hashes": [ - "sha256:73293d40b10ac17736e715b377e7b7bde474cb8105165d77474df4c3619b10b3", - "sha256:77580f27ab39bc68be4906a43c56d7674b45075bc4f883b1d0b985db5164d58f" + "sha256:613a2df703998e78716cace68cd83972960834424457f5b67f56e74fff950aef", + "sha256:d3f437a8b5f3849d1bb1b60e1b818efc564c66e3fefe90b62e5db08db295e1b1" ], "index": "pypi", - "version": "==4.0.4" + "version": "==4.0.5" }, "flask-sqlalchemy": { "hashes": [ - "sha256:c5765e58ca145401b52106c0f46178569243c5da25556be2c231ecc60867c5b1", - "sha256:cabb6600ddd819a9f859f36515bb1bd8e7dbf30206cc679d2b081dff9e383283" + "sha256:4ba4be7f419dc72f4efd8802d69974803c37259dd42f3913b0dcf75c9447e0a0", + "sha256:e4b68bb881802dda1a7d878b2fc84c06d1ee57fb40b874d3dc97dabfa36b8312" ], "index": "pypi", - "version": "==3.0.5" + "version": "==3.1.1" }, "flask-wtf": { "hashes": [ - "sha256:41c4244e9ae626d63bed42ae4785b90667b885b1535d5a4095e1f63060d12aa9", - "sha256:7887d6f1ebb3e17bf648647422f0944c9a469d0fcf63e3b66fb9a83037e38b2c" + "sha256:8bb269eb9bb46b87e7c8233d7e7debdf1f8b74bf90cc1789988c29b37a97b695", + "sha256:fa6793f2fb7e812e0fe9743b282118e581fb1b6c45d414b8af05e659bd653287" ], "index": "pypi", - "version": "==1.1.1" + "version": "==1.2.1" }, "greenlet": { "hashes": [ - "sha256:03a8f4f3430c3b3ff8d10a2a86028c660355ab637cee9333d63d66b56f09d52a", - "sha256:0bf60faf0bc2468089bdc5edd10555bab6e85152191df713e2ab1fcc86382b5a", - "sha256:18a7f18b82b52ee85322d7a7874e676f34ab319b9f8cce5de06067384aa8ff43", - "sha256:18e98fb3de7dba1c0a852731c3070cf022d14f0d68b4c87a19cc1016f3bb8b33", - "sha256:1a819eef4b0e0b96bb0d98d797bef17dc1b4a10e8d7446be32d1da33e095dbb8", - "sha256:26fbfce90728d82bc9e6c38ea4d038cba20b7faf8a0ca53a9c07b67318d46088", - "sha256:2780572ec463d44c1d3ae850239508dbeb9fed38e294c68d19a24d925d9223ca", - "sha256:283737e0da3f08bd637b5ad058507e578dd462db259f7f6e4c5c365ba4ee9343", - "sha256:2d4686f195e32d36b4d7cf2d166857dbd0ee9f3d20ae349b6bf8afc8485b3645", - "sha256:2dd11f291565a81d71dab10b7033395b7a3a5456e637cf997a6f33ebdf06f8db", - "sha256:30bcf80dda7f15ac77ba5af2b961bdd9dbc77fd4ac6105cee85b0d0a5fcf74df", - "sha256:32e5b64b148966d9cccc2c8d35a671409e45f195864560829f395a54226408d3", - "sha256:36abbf031e1c0f79dd5d596bfaf8e921c41df2bdf54ee1eed921ce1f52999a86", - "sha256:3a06ad5312349fec0ab944664b01d26f8d1f05009566339ac6f63f56589bc1a2", - "sha256:3a51c9751078733d88e013587b108f1b7a1fb106d402fb390740f002b6f6551a", - "sha256:3c9b12575734155d0c09d6c3e10dbd81665d5c18e1a7c6597df72fd05990c8cf", - "sha256:3f6ea9bd35eb450837a3d80e77b517ea5bc56b4647f5502cd28de13675ee12f7", - "sha256:4b58adb399c4d61d912c4c331984d60eb66565175cdf4a34792cd9600f21b394", - "sha256:4d2e11331fc0c02b6e84b0d28ece3a36e0548ee1a1ce9ddde03752d9b79bba40", - "sha256:5454276c07d27a740c5892f4907c86327b632127dd9abec42ee62e12427ff7e3", - "sha256:561091a7be172ab497a3527602d467e2b3fbe75f9e783d8b8ce403fa414f71a6", - "sha256:6c3acb79b0bfd4fe733dff8bc62695283b57949ebcca05ae5c129eb606ff2d74", - "sha256:703f18f3fda276b9a916f0934d2fb6d989bf0b4fb5a64825260eb9bfd52d78f0", - "sha256:7492e2b7bd7c9b9916388d9df23fa49d9b88ac0640db0a5b4ecc2b653bf451e3", - "sha256:76ae285c8104046b3a7f06b42f29c7b73f77683df18c49ab5af7983994c2dd91", - "sha256:7cafd1208fdbe93b67c7086876f061f660cfddc44f404279c1585bbf3cdc64c5", - "sha256:7efde645ca1cc441d6dc4b48c0f7101e8d86b54c8530141b09fd31cef5149ec9", - "sha256:88d9ab96491d38a5ab7c56dd7a3cc37d83336ecc564e4e8816dbed12e5aaefc8", - "sha256:8eab883b3b2a38cc1e050819ef06a7e6344d4a990d24d45bc6f2cf959045a45b", - "sha256:910841381caba4f744a44bf81bfd573c94e10b3045ee00de0cbf436fe50673a6", - "sha256:9190f09060ea4debddd24665d6804b995a9c122ef5917ab26e1566dcc712ceeb", - "sha256:937e9020b514ceedb9c830c55d5c9872abc90f4b5862f89c0887033ae33c6f73", - "sha256:94c817e84245513926588caf1152e3b559ff794d505555211ca041f032abbb6b", - "sha256:971ce5e14dc5e73715755d0ca2975ac88cfdaefcaab078a284fea6cfabf866df", - "sha256:9d14b83fab60d5e8abe587d51c75b252bcc21683f24699ada8fb275d7712f5a9", - "sha256:9f35ec95538f50292f6d8f2c9c9f8a3c6540bbfec21c9e5b4b751e0a7c20864f", - "sha256:a1846f1b999e78e13837c93c778dcfc3365902cfb8d1bdb7dd73ead37059f0d0", - "sha256:acd2162a36d3de67ee896c43effcd5ee3de247eb00354db411feb025aa319857", - "sha256:b0ef99cdbe2b682b9ccbb964743a6aca37905fda5e0452e5ee239b1654d37f2a", - "sha256:b80f600eddddce72320dbbc8e3784d16bd3fb7b517e82476d8da921f27d4b249", - "sha256:b864ba53912b6c3ab6bcb2beb19f19edd01a6bfcbdfe1f37ddd1778abfe75a30", - "sha256:b9ec052b06a0524f0e35bd8790686a1da006bd911dd1ef7d50b77bfbad74e292", - "sha256:ba2956617f1c42598a308a84c6cf021a90ff3862eddafd20c3333d50f0edb45b", - "sha256:bdfea8c661e80d3c1c99ad7c3ff74e6e87184895bbaca6ee8cc61209f8b9b85d", - "sha256:be4ed120b52ae4d974aa40215fcdfde9194d63541c7ded40ee12eb4dda57b76b", - "sha256:c4302695ad8027363e96311df24ee28978162cdcdd2006476c43970b384a244c", - "sha256:c48f54ef8e05f04d6eff74b8233f6063cb1ed960243eacc474ee73a2ea8573ca", - "sha256:c9c59a2120b55788e800d82dfa99b9e156ff8f2227f07c5e3012a45a399620b7", - "sha256:cd021c754b162c0fb55ad5d6b9d960db667faad0fa2ff25bb6e1301b0b6e6a75", - "sha256:d27ec7509b9c18b6d73f2f5ede2622441de812e7b1a80bbd446cb0633bd3d5ae", - "sha256:d5508f0b173e6aa47273bdc0a0b5ba055b59662ba7c7ee5119528f466585526b", - "sha256:d75209eed723105f9596807495d58d10b3470fa6732dd6756595e89925ce2470", - "sha256:db1a39669102a1d8d12b57de2bb7e2ec9066a6f2b3da35ae511ff93b01b5d564", - "sha256:dbfcfc0218093a19c252ca8eb9aee3d29cfdcb586df21049b9d777fd32c14fd9", - "sha256:e0f72c9ddb8cd28532185f54cc1453f2c16fb417a08b53a855c4e6a418edd099", - "sha256:e7c8dc13af7db097bed64a051d2dd49e9f0af495c26995c00a9ee842690d34c0", - "sha256:ea9872c80c132f4663822dd2a08d404073a5a9b5ba6155bea72fb2a79d1093b5", - "sha256:eff4eb9b7eb3e4d0cae3d28c283dc16d9bed6b193c2e1ace3ed86ce48ea8df19", - "sha256:f82d4d717d8ef19188687aa32b8363e96062911e63ba22a0cff7802a8e58e5f1", - "sha256:fc3a569657468b6f3fb60587e48356fe512c1754ca05a564f11366ac9e306526" + "sha256:0a02d259510b3630f330c86557331a3b0e0c79dac3d166e449a39363beaae174", + "sha256:0b6f9f8ca7093fd4433472fd99b5650f8a26dcd8ba410e14094c1e44cd3ceddd", + "sha256:100f78a29707ca1525ea47388cec8a049405147719f47ebf3895e7509c6446aa", + "sha256:1757936efea16e3f03db20efd0cd50a1c86b06734f9f7338a90c4ba85ec2ad5a", + "sha256:19075157a10055759066854a973b3d1325d964d498a805bb68a1f9af4aaef8ec", + "sha256:19bbdf1cce0346ef7341705d71e2ecf6f41a35c311137f29b8a2dc2341374565", + "sha256:20107edf7c2c3644c67c12205dc60b1bb11d26b2610b276f97d666110d1b511d", + "sha256:22f79120a24aeeae2b4471c711dcf4f8c736a2bb2fabad2a67ac9a55ea72523c", + "sha256:2847e5d7beedb8d614186962c3d774d40d3374d580d2cbdab7f184580a39d234", + "sha256:28e89e232c7593d33cac35425b58950789962011cc274aa43ef8865f2e11f46d", + "sha256:329c5a2e5a0ee942f2992c5e3ff40be03e75f745f48847f118a3cfece7a28546", + "sha256:337322096d92808f76ad26061a8f5fccb22b0809bea39212cd6c406f6a7060d2", + "sha256:3fcc780ae8edbb1d050d920ab44790201f027d59fdbd21362340a85c79066a74", + "sha256:41bdeeb552d814bcd7fb52172b304898a35818107cc8778b5101423c9017b3de", + "sha256:4eddd98afc726f8aee1948858aed9e6feeb1758889dfd869072d4465973f6bfd", + "sha256:52e93b28db27ae7d208748f45d2db8a7b6a380e0d703f099c949d0f0d80b70e9", + "sha256:55d62807f1c5a1682075c62436702aaba941daa316e9161e4b6ccebbbf38bda3", + "sha256:5805e71e5b570d490938d55552f5a9e10f477c19400c38bf1d5190d760691846", + "sha256:599daf06ea59bfedbec564b1692b0166a0045f32b6f0933b0dd4df59a854caf2", + "sha256:60d5772e8195f4e9ebf74046a9121bbb90090f6550f81d8956a05387ba139353", + "sha256:696d8e7d82398e810f2b3622b24e87906763b6ebfd90e361e88eb85b0e554dc8", + "sha256:6e6061bf1e9565c29002e3c601cf68569c450be7fc3f7336671af7ddb4657166", + "sha256:80ac992f25d10aaebe1ee15df45ca0d7571d0f70b645c08ec68733fb7a020206", + "sha256:816bd9488a94cba78d93e1abb58000e8266fa9cc2aa9ccdd6eb0696acb24005b", + "sha256:85d2b77e7c9382f004b41d9c72c85537fac834fb141b0296942d52bf03fe4a3d", + "sha256:87c8ceb0cf8a5a51b8008b643844b7f4a8264a2c13fcbcd8a8316161725383fe", + "sha256:89ee2e967bd7ff85d84a2de09df10e021c9b38c7d91dead95b406ed6350c6997", + "sha256:8bef097455dea90ffe855286926ae02d8faa335ed8e4067326257cb571fc1445", + "sha256:8d11ebbd679e927593978aa44c10fc2092bc454b7d13fdc958d3e9d508aba7d0", + "sha256:91e6c7db42638dc45cf2e13c73be16bf83179f7859b07cfc139518941320be96", + "sha256:97e7ac860d64e2dcba5c5944cfc8fa9ea185cd84061c623536154d5a89237884", + "sha256:990066bff27c4fcf3b69382b86f4c99b3652bab2a7e685d968cd4d0cfc6f67c6", + "sha256:9fbc5b8f3dfe24784cee8ce0be3da2d8a79e46a276593db6868382d9c50d97b1", + "sha256:ac4a39d1abae48184d420aa8e5e63efd1b75c8444dd95daa3e03f6c6310e9619", + "sha256:b2c02d2ad98116e914d4f3155ffc905fd0c025d901ead3f6ed07385e19122c94", + "sha256:b2d3337dcfaa99698aa2377c81c9ca72fcd89c07e7eb62ece3f23a3fe89b2ce4", + "sha256:b489c36d1327868d207002391f662a1d163bdc8daf10ab2e5f6e41b9b96de3b1", + "sha256:b641161c302efbb860ae6b081f406839a8b7d5573f20a455539823802c655f63", + "sha256:b8ba29306c5de7717b5761b9ea74f9c72b9e2b834e24aa984da99cbfc70157fd", + "sha256:b9934adbd0f6e476f0ecff3c94626529f344f57b38c9a541f87098710b18af0a", + "sha256:ce85c43ae54845272f6f9cd8320d034d7a946e9773c693b27d620edec825e376", + "sha256:cf868e08690cb89360eebc73ba4be7fb461cfbc6168dd88e2fbbe6f31812cd57", + "sha256:d2905ce1df400360463c772b55d8e2518d0e488a87cdea13dd2c71dcb2a1fa16", + "sha256:d57e20ba591727da0c230ab2c3f200ac9d6d333860d85348816e1dca4cc4792e", + "sha256:d6a8c9d4f8692917a3dc7eb25a6fb337bff86909febe2f793ec1928cd97bedfc", + "sha256:d923ff276f1c1f9680d32832f8d6c040fe9306cbfb5d161b0911e9634be9ef0a", + "sha256:daa7197b43c707462f06d2c693ffdbb5991cbb8b80b5b984007de431493a319c", + "sha256:dbd4c177afb8a8d9ba348d925b0b67246147af806f0b104af4d24f144d461cd5", + "sha256:dc4d815b794fd8868c4d67602692c21bf5293a75e4b607bb92a11e821e2b859a", + "sha256:e9d21aaa84557d64209af04ff48e0ad5e28c5cca67ce43444e939579d085da72", + "sha256:ea6b8aa9e08eea388c5f7a276fabb1d4b6b9d6e4ceb12cc477c3d352001768a9", + "sha256:eabe7090db68c981fca689299c2d116400b553f4b713266b130cfc9e2aa9c5a9", + "sha256:f2f6d303f3dee132b322a14cd8765287b8f86cdc10d2cb6a6fae234ea488888e", + "sha256:f33f3258aae89da191c6ebaa3bc517c6c4cbc9b9f689e5d8452f7aedbb913fa8", + "sha256:f7bfb769f7efa0eefcd039dd19d843a4fbfbac52f1878b1da2ed5793ec9b1a65", + "sha256:f89e21afe925fcfa655965ca8ea10f24773a1791400989ff32f467badfe4a064", + "sha256:fa24255ae3c0ab67e613556375a4341af04a084bd58764731972bcbc8baeba36" ], "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": { "hashes": [ @@ -306,6 +318,14 @@ "markers": "python_version >= '3.5'", "version": "==3.4" }, + "iniconfig": { + "hashes": [ + "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3", + "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374" + ], + "markers": "python_version >= '3.7'", + "version": "==2.0.0" + }, "itsdangerous": { "hashes": [ "sha256:2c2349112351b88699d8d4b6b075022c0808887cb7ad10069318a8b0bc88db44", @@ -336,8 +356,11 @@ "sha256:0a4e4a1aff6c7ac4cd55792abf96c915634c2b97e3cc1c7129578aa68ebd754e", "sha256:10bbfe99883db80bdbaff2dcf681dfc6533a614f700da1287707e8a5d78a8431", "sha256:134da1eca9ec0ae528110ccc9e48041e0828d79f24121a1a146161103c76e686", + "sha256:14ff806850827afd6b07a5f32bd917fb7f45b046ba40c57abdb636674a8b559c", "sha256:1577735524cdad32f9f694208aa75e422adba74f1baee7551620e43a3141f559", "sha256:1b40069d487e7edb2676d3fbdb2b0829ffa2cd63a2ec26c4938b2d34391b4ecc", + "sha256:1b8dd8c3fd14349433c79fa8abeb573a55fc0fdd769133baac1f5e07abf54aeb", + "sha256:1f67c7038d560d92149c060157d623c542173016c4babc0c1913cca0564b9939", "sha256:282c2cb35b5b673bbcadb33a585408104df04f14b2d9b01d4c345a3b92861c2c", "sha256:2c1b19b3aaacc6e57b7e25710ff571c24d6c3613a45e905b1fde04d691b98ee0", "sha256:2ef12179d3a291be237280175b542c07a36e7f60718296278d8593d21ca937d4", @@ -345,6 +368,7 @@ "sha256:3c0fae6c3be832a0a0473ac912810b2877c8cb9d76ca48de1ed31e1c68386575", "sha256:3fd4abcb888d15a94f32b75d8fd18ee162ca0c064f35b11134be77050296d6ba", "sha256:42de32b22b6b804f42c5d98be4f7e5e977ecdd9ee9b660fda1a3edf03b11792d", + "sha256:47d4f1c5f80fc62fdd7777d0d40a2e9dda0a05883ab11374334f6c4de38adffd", "sha256:504b320cd4b7eff6f968eddf81127112db685e81f7e36e75f9f84f0df46041c3", "sha256:525808b8019e36eb524b8c68acdd63a37e75714eac50e988180b169d64480a00", "sha256:56d9f2ecac662ca1611d183feb03a3fa4406469dafe241673d521dd5ae92a155", @@ -353,6 +377,7 @@ "sha256:68e78619a61ecf91e76aa3e6e8e33fc4894a2bebe93410754bd28fce0a8a4f9f", "sha256:69c0f17e9f5a7afdf2cc9fb2d1ce6aabdb3bafb7f38017c0b77862bcec2bbad8", "sha256:6b2b56950d93e41f33b4223ead100ea0fe11f8e6ee5f641eb753ce4b77a7042b", + "sha256:715d3562f79d540f251b99ebd6d8baa547118974341db04f5ad06d5ea3eb8007", "sha256:787003c0ddb00500e49a10f2844fac87aa6ce977b90b0feaaf9de23c22508b24", "sha256:7ef3cb2ebbf91e330e3bb937efada0edd9003683db6b57bb108c4001f37a02ea", "sha256:8023faf4e01efadfa183e863fefde0046de576c6f14659e8782065bcece22198", @@ -360,9 +385,12 @@ "sha256:8afafd99945ead6e075b973fefa56379c5b5c53fd8937dad92c662da5d8fd5ee", "sha256:8c41976a29d078bb235fea9b2ecd3da465df42a562910f9022f1a03107bd02be", "sha256:8e254ae696c88d98da6555f5ace2279cf7cd5b3f52be2b5cf97feafe883b58d2", + "sha256:8f9293864fe09b8149f0cc42ce56e3f0e54de883a9de90cd427f191c346eb2e1", "sha256:9402b03f1a1b4dc4c19845e5c749e3ab82d5078d16a2a4c2cd2df62d57bb0707", "sha256:962f82a3086483f5e5f64dbad880d31038b698494799b097bc59c2edf392fce6", + "sha256:9aad3c1755095ce347e26488214ef77e0485a3c34a50c5a5e2471dff60b9dd9c", "sha256:9dcdfd0eaf283af041973bff14a2e143b8bd64e069f4c383416ecd79a81aab58", + "sha256:aa57bd9cf8ae831a362185ee444e15a93ecb2e344c8e52e4d721ea3ab6ef1823", "sha256:aa7bd130efab1c280bed0f45501b7c8795f9fdbeb02e965371bbef3523627779", "sha256:ab4a0df41e7c16a1392727727e7998a467472d0ad65f3ad5e6e765015df08636", "sha256:ad9e82fb8f09ade1c3e1b996a6337afac2b8b9e365f926f5a61aacc71adc5b3c", @@ -381,7 +409,9 @@ "sha256:df0be2b576a7abbf737b1575f048c23fb1d769f267ec4358296f31c2479db8f9", "sha256:e09031c87a1e51556fdcb46e5bd4f59dfb743061cf93c4d6831bf894f125eb57", "sha256:e4dd52d80b8c83fdce44e12478ad2e85c64ea965e75d66dbeafb0a3e77308fcc", - "sha256:fec21693218efe39aa7f8599346e90c705afa52c5b31ae019b2e57e8f6542bb2" + "sha256:f698de3fd0c4e6972b92290a45bd9b1536bffe8c6759c62471efaa8acb4c37bc", + "sha256:fec21693218efe39aa7f8599346e90c705afa52c5b31ae019b2e57e8f6542bb2", + "sha256:ffcc3f7c66b5f5b7931a5aa68fc9cecc51e685ef90282f4a82f0f5e9b704ad11" ], "markers": "python_version >= '3.7'", "version": "==2.1.3" @@ -404,79 +434,97 @@ }, "packaging": { "hashes": [ - "sha256:994793af429502c4ea2ebf6bf664629d07c1a9fe974af92966e4b8d2df7edc61", - "sha256:a392980d2b6cffa644431898be54b0045151319d1e7ec34f0cfed48767dd334f" + "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5", + "sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7" ], "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": { "hashes": [ - "sha256:02c0f3757a4300cf379eb49f543fb7ac527fb00144d39246ee40e1df684ab514", - "sha256:02c6e3cf3439e213e4ee930308dc122d6fb4d4bea9aef4a12535fbd605d1a2fe", - "sha256:0645376d399bfd64da57148694d78e1f431b1e1ee1054872a5713125681cf1be", - "sha256:0892ef645c2fabb0c75ec32d79f4252542d0caec1d5d949630e7d242ca4681a3", - "sha256:0d236c2825fa656a2d98bbb0e52370a2e852e5a0ec45fc4f402977313329174d", - "sha256:0e0f754d27fddcfd74006455b6e04e6705d6c31a612ec69ddc040a5468e44b4e", - "sha256:15e2ee79e7cf29582ef770de7dab3d286431b01c3bb598f8e05e09601b890081", - "sha256:1876843d8e31c89c399e31b97d4b9725a3575bb9c2af92038464231ec40f9edb", - "sha256:1f64dcfb8f6e0c014c7f55e51c9759f024f70ea572fbdef123f85318c297947c", - "sha256:2ab652e729ff4ad76d400df2624d223d6e265ef81bb8aa17fbd63607878ecbee", - "sha256:30637a20623e2a2eacc420059be11527f4458ef54352d870b8181a4c3020ae6b", - "sha256:34b9ccdf210cbbb1303c7c4db2905fa0319391bd5904d32689e6dd5c963d2ea8", - "sha256:38601cbbfe600362c43714482f43b7c110b20cb0f8172422c616b09b85a750c5", - "sha256:441cc2f8869a4f0f4bb408475e5ae0ee1f3b55b33f350406150277f7f35384fc", - "sha256:498807b927ca2510baea1b05cc91d7da4718a0f53cb766c154c417a39f1820a0", - "sha256:4ac30da8b4f57187dbf449294d23b808f8f53cad6b1fc3623fa8a6c11d176dd0", - "sha256:4c727b597c6444a16e9119386b59388f8a424223302d0c06c676ec8b4bc1f963", - "sha256:4d67fbdaf177da06374473ef6f7ed8cc0a9dc640b01abfe9e8a2ccb1b1402c1f", - "sha256:4dfb4be774c4436a4526d0c554af0cc2e02082c38303852a36f6456ece7b3503", - "sha256:4ea29fc3ad9d91162c52b578f211ff1c931d8a38e1f58e684c45aa470adf19e2", - "sha256:51537e3d299be0db9137b321dfb6a5022caaab275775680e0c3d281feefaca6b", - "sha256:61b047a0537bbc3afae10f134dc6393823882eb263088c271331602b672e52e9", - "sha256:6460c7a99fc939b849431f1e73e013d54aa54293f30f1109019c56a0b2b2ec2f", - "sha256:65bee1e49fa6f9cf327ce0e01c4c10f39165ee76d35c846ade7cb0ec6683e303", - "sha256:65c07febd1936d63bfde78948b76cd4c2a411572a44ac50719ead41947d0f26b", - "sha256:71f14375d6f73b62800530b581aed3ada394039877818b2d5f7fc77e3bb6894d", - "sha256:7a40c00dbe17c0af5bdd55aafd6ff6679f94a9be9513a4c7e071baf3d7d22a70", - "sha256:7e13a5a2c01151f1208d5207e42f33ba86d561b7a89fca67c700b9486a06d0e2", - "sha256:7f0438fa20fb6c7e202863e0d5ab02c246d35efb1d164e052f2f3bfe2b152bd0", - "sha256:8122cfc7cae0da9a3077216528b8bb3629c43b25053284cc868744bfe71eb141", - "sha256:8338a271cb71d8da40b023a35d9c1e919eba6cbd8fa20a54b748a332c355d896", - "sha256:84d2222e61f313c4848ff05353653bf5f5cf6ce34df540e4274516880d9c3763", - "sha256:8a6979cf527e2603d349a91060f428bcb135aea2be3201dff794813256c274f1", - "sha256:8a76e027f87753f9bd1ab5f7c9cb8c7628d1077ef927f5e2446477153a602f2c", - "sha256:964b4dfb7c1c1965ac4c1978b0f755cc4bd698e8aa2b7667c575fb5f04ebe06b", - "sha256:9972aad21f965599ed0106f65334230ce826e5ae69fda7cbd688d24fa922415e", - "sha256:a8c28fd40a4226b4a84bdf2d2b5b37d2c7bd49486b5adcc200e8c7ec991dfa7e", - "sha256:ae102a98c547ee2288637af07393dd33f440c25e5cd79556b04e3fca13325e5f", - "sha256:af335bac6b666cc6aea16f11d486c3b794029d9df029967f9938a4bed59b6a19", - "sha256:afe64e9b8ea66866a771996f6ff14447e8082ea26e675a295ad3bdbffdd72afb", - "sha256:b4b24f75d16a89cc6b4cdff0eb6a910a966ecd476d1e73f7ce5985ff1328e9a6", - "sha256:b6c8288bb8a84b47e07013bb4850f50538aa913d487579e1921724631d02ea1b", - "sha256:b83456c2d4979e08ff56180a76429263ea254c3f6552cd14ada95cff1dec9bb8", - "sha256:bfb13af3c5dd3a9588000910178de17010ebcccd37b4f9794b00595e3a8ddad3", - "sha256:c3dba7dab16709a33a847e5cd756767271697041fbe3fe97c215b1fc1f5c9848", - "sha256:c48d8f2db17f27d41fb0e2ecd703ea41984ee19362cbce52c097963b3a1b4365", - "sha256:c7e62ab8b332147a7593a385d4f368874d5fe4ad4e341770d4983442d89603e3", - "sha256:c83a74b68270028dc8ee74d38ecfaf9c90eed23c8959fca95bd703d25b82c88e", - "sha256:cacbdc5839bdff804dfebc058fe25684cae322987f7a38b0168bc1b2df703fb1", - "sha256:cf4499e0a83b7b7edcb8dabecbd8501d0d3a5ef66457200f77bde3d210d5debb", - "sha256:cfec476887aa231b8548ece2e06d28edc87c1397ebd83922299af2e051cf2827", - "sha256:d26e0342183c762de3276cca7a530d574d4e25121ca7d6e4a98e4f05cb8e4df7", - "sha256:d4e6036decf4b72d6425d5b29bbd3e8f0ff1059cda7ac7b96d6ac5ed34ffbacd", - "sha256:d57c3fd55d9058645d26ae37d76e61156a27722097229d32a9e73ed54819982a", - "sha256:dfa74c903a3c1f0d9b1c7e7b53ed2d929a4910e272add6700c38f365a6002820", - "sha256:e3ed340d2b858d6e6fb5083f87c09996506af483227735de6964a6100b4e6a54", - "sha256:e78e6e2a00c223e164c417628572a90093c031ed724492c763721c2e0bc2a8df", - "sha256:e9182eb20f41417ea1dd8e8f7888c4d7c6e805f8a7c98c1081778a3da2bee3e4", - "sha256:e99e34c82309dd78959ba3c1590975b5d3c862d6f279f843d47d26ff89d7d7e1", - "sha256:f6a88f384335bb27812293fdb11ac6aee2ca3f51d3c7820fe03de0a304ab6249", - "sha256:f81e65376e52f03422e1fb475c9514185669943798ed019ac50410fb4c4df232", - "sha256:ffe9dc0a884a8848075e576c1de0290d85a533a9f6e9c4e564f19adf8f6e54a7" + "sha256:03ef7df18daf2c4c07e2695e8cfd5ee7f748a1d54d802330985a78d2a5a6dca9", + "sha256:0a602ea5aff39bb9fac6308e9c9d82b9a35c2bf288e184a816002c9fae930b77", + "sha256:0c009475ee389757e6e34611d75f6e4f05f0cf5ebb76c6037508318e1a1e0d7e", + "sha256:0ef4854e82c09e84cc63084a9e4ccd6d9b154f1dbdd283efb92ecd0b5e2b8c84", + "sha256:1236ed0952fbd919c100bc839eaa4a39ebc397ed1c08a97fc45fee2a595aa1b3", + "sha256:143072318f793f53819048fdfe30c321890af0c3ec7cb1dfc9cc87aa88241de2", + "sha256:15208be1c50b99203fe88d15695f22a5bed95ab3f84354c494bcb1d08557df67", + "sha256:1873aade94b74715be2246321c8650cabf5a0d098a95bab81145ffffa4c13876", + "sha256:18d0ef97766055fec15b5de2c06dd8e7654705ce3e5e5eed3b6651a1d2a9a152", + "sha256:1ea665f8ce695bcc37a90ee52de7a7980be5161375d42a0b6c6abedbf0d81f0f", + "sha256:2293b001e319ab0d869d660a704942c9e2cce19745262a8aba2115ef41a0a42a", + "sha256:246b123cc54bb5361588acc54218c8c9fb73068bf227a4a531d8ed56fa3ca7d6", + "sha256:275ff571376626195ab95a746e6a04c7df8ea34638b99fc11160de91f2fef503", + "sha256:281309265596e388ef483250db3640e5f414168c5a67e9c665cafce9492eda2f", + "sha256:2d423c8d8a3c82d08fe8af900ad5b613ce3632a1249fd6a223941d0735fce493", + "sha256:2e5afae772c00980525f6d6ecf7cbca55676296b580c0e6abb407f15f3706996", + "sha256:30dcc86377618a4c8f3b72418df92e77be4254d8f89f14b8e8f57d6d43603c0f", + "sha256:31a34c508c003a4347d389a9e6fcc2307cc2150eb516462a7a17512130de109e", + "sha256:323ba25b92454adb36fa425dc5cf6f8f19f78948cbad2e7bc6cdf7b0d7982e59", + "sha256:34eccd14566f8fe14b2b95bb13b11572f7c7d5c36da61caf414d23b91fcc5d94", + "sha256:3a58c98a7e9c021f357348867f537017057c2ed7f77337fd914d0bedb35dace7", + "sha256:3f78fd71c4f43a13d342be74ebbc0666fe1f555b8837eb113cb7416856c79682", + "sha256:4154ad09dac630a0f13f37b583eae260c6aa885d67dfbccb5b02c33f31a6d420", + "sha256:420f9bbf47a02616e8554e825208cb947969451978dceb77f95ad09c37791dae", + "sha256:4686818798f9194d03c9129a4d9a702d9e113a89cb03bffe08c6cf799e053291", + "sha256:57fede879f08d23c85140a360c6a77709113efd1c993923c59fde17aa27599fe", + "sha256:60989127da422b74a04345096c10d416c2b41bd7bf2a380eb541059e4e999980", + "sha256:64cf30263844fa208851ebb13b0732ce674d8ec6a0c86a4e160495d299ba3c93", + "sha256:68fc1f1ba168724771e38bee37d940d2865cb0f562380a1fb1ffb428b75cb692", + "sha256:6e6f98446430fdf41bd36d4faa6cb409f5140c1c2cf58ce0bbdaf16af7d3f119", + "sha256:729177eaf0aefca0994ce4cffe96ad3c75e377c7b6f4efa59ebf003b6d398716", + "sha256:72dffbd8b4194858d0941062a9766f8297e8868e1dd07a7b36212aaa90f49472", + "sha256:75723c3c0fbbf34350b46a3199eb50638ab22a0228f93fb472ef4d9becc2382b", + "sha256:77853062a2c45be16fd6b8d6de2a99278ee1d985a7bd8b103e97e41c034006d2", + "sha256:78151aa3ec21dccd5cdef6c74c3e73386dcdfaf19bced944169697d7ac7482fc", + "sha256:7f01846810177d829c7692f1f5ada8096762d9172af1b1a28d4ab5b77c923c1c", + "sha256:804d99b24ad523a1fe18cc707bf741670332f7c7412e9d49cb5eab67e886b9b5", + "sha256:81ff62668af011f9a48787564ab7eded4e9fb17a4a6a74af5ffa6a457400d2ab", + "sha256:8359bf4791968c5a78c56103702000105501adb557f3cf772b2c207284273984", + "sha256:83791a65b51ad6ee6cf0845634859d69a038ea9b03d7b26e703f94c7e93dbcf9", + "sha256:8532fd6e6e2dc57bcb3bc90b079c60de896d2128c5d9d6f24a63875a95a088cf", + "sha256:876801744b0dee379e4e3c38b76fc89f88834bb15bf92ee07d94acd06ec890a0", + "sha256:8dbf6d1bc73f1d04ec1734bae3b4fb0ee3cb2a493d35ede9badbeb901fb40f6f", + "sha256:8f8544b092a29a6ddd72f3556a9fcf249ec412e10ad28be6a0c0d948924f2212", + "sha256:911dda9c487075abd54e644ccdf5e5c16773470a6a5d3826fda76699410066fb", + "sha256:977646e05232579d2e7b9c59e21dbe5261f403a88417f6a6512e70d3f8a046be", + "sha256:9dba73be7305b399924709b91682299794887cbbd88e38226ed9f6712eabee90", + "sha256:a148c5d507bb9b4f2030a2025c545fccb0e1ef317393eaba42e7eabd28eb6041", + "sha256:a6cdcc3ede532f4a4b96000b6362099591ab4a3e913d70bcbac2b56c872446f7", + "sha256:ac05fb791acf5e1a3e39402641827780fe44d27e72567a000412c648a85ba860", + "sha256:b0605eaed3eb239e87df0d5e3c6489daae3f7388d455d0c0b4df899519c6a38d", + "sha256:b58b4710c7f4161b5e9dcbe73bb7c62d65670a87df7bcce9e1faaad43e715245", + "sha256:b6356793b84728d9d50ead16ab43c187673831e9d4019013f1402c41b1db9b27", + "sha256:b76bedd166805480ab069612119ea636f5ab8f8771e640ae103e05a4aae3e417", + "sha256:bc7bb56d04601d443f24094e9e31ae6deec9ccb23581f75343feebaf30423359", + "sha256:c2470da5418b76232f02a2fcd2229537bb2d5a7096674ce61859c3229f2eb202", + "sha256:c332c8d69fb64979ebf76613c66b985414927a40f8defa16cf1bc028b7b0a7b0", + "sha256:c6af2a6d4b7ee9615cbb162b0738f6e1fd1f5c3eda7e5da17861eacf4c717ea7", + "sha256:c77e3d1862452565875eb31bdb45ac62502feabbd53429fdc39a1cc341d681ba", + "sha256:ca08decd2697fdea0aea364b370b1249d47336aec935f87b8bbfd7da5b2ee9c1", + "sha256:ca49a8119c6cbd77375ae303b0cfd8c11f011abbbd64601167ecca18a87e7cdd", + "sha256:cb16c65dcb648d0a43a2521f2f0a2300f40639f6f8c1ecbc662141e4e3e1ee07", + "sha256:d2997c458c690ec2bc6b0b7ecbafd02b029b7b4283078d3b32a852a7ce3ddd98", + "sha256:d3f82c171b4ccd83bbaf35aa05e44e690113bd4f3b7b6cc54d2219b132f3ae55", + "sha256:dc4926288b2a3e9fd7b50dc6a1909a13bbdadfc67d93f3374d984e56f885579d", + "sha256:ead20f7913a9c1e894aebe47cccf9dc834e1618b7aa96155d2091a626e59c972", + "sha256:ebdc36bea43063116f0486869652cb2ed7032dbc59fbcb4445c4862b5c1ecf7f", + "sha256:ed1184ab8f113e8d660ce49a56390ca181f2981066acc27cf637d5c1e10ce46e", + "sha256:ee825e70b1a209475622f7f7b776785bd68f34af6e7a46e2e42f27b659b5bc26", + "sha256:f7ae5d65ccfbebdfa761585228eb4d0df3a8b15cfb53bd953e713e09fbb12957", + "sha256:f7fc5a5acafb7d6ccca13bfa8c90f8c51f13d8fb87d95656d3950f0158d3ce53", + "sha256:f9b5571d33660d5009a8b3c25dc1db560206e2d2f89d3df1cb32d72c0d117d52" ], "index": "pypi", - "version": "==2.9.6" + "version": "==2.9.9" }, "pyjwt": { "hashes": [ @@ -488,39 +536,60 @@ }, "pymupdf": { "hashes": [ - "sha256:01119edb7e4c3dd8c154d237b8ac927bd359eea8d31468f9a89aa308b5bca04e", - "sha256:017aaba511526facfc928e9d95d2c10d28a2821b05b9039bf422031a7da8584e", - "sha256:0542178c3a399282903705a8cc298e7f33f4770605e0a9db344aff5d375bcf0b", - "sha256:17efbbf0e2d99d24cfc302fac512928eb294f10b7b67d597d04dafd012812e4e", - "sha256:2e74d766f79e41e10c51865233042ab2cc4612ca7942812dca0603f4d0f8f73d", - "sha256:30c55814bbf6461aef9b34cb524d1d14857d5ec6ccfbb78ecfb1d07dfc40eeb8", - "sha256:3d0fe749e648f5245059d5f771fb50c1a988a1d2e82268b56377b2176a9fee5d", - "sha256:3d71c47aa14b73f2df7d03be8c547a05df6c6898d8c63a0f752b26f206eefd3c", - "sha256:411fc35f6dae16ec940b6b0406e84be6ff29f93b30908ea1427e2a4bd594d4ba", - "sha256:42f59f4999d7f8b35c850050bd965e98c081a7d9b92d5f9dcf30203b30d06876", - "sha256:4bcad7ea4b3ab82c46fe8da27ec738d38c213ed9935ef67d98ed09574d9a234e", - "sha256:4fbc5bfe6ecc53929e3fd0db9846fb7da084ddb4b1fc1063857245fa783974d9", - "sha256:5ec8d5106752297529d0d68d46cfc4ce99914aabd99be843f1599a1842d63fe9", - "sha256:640b8e4cb116dd87a3c854e49808a4f63625e663a7bc5b1efc971db5b4775367", - "sha256:64ae9f81b8fe0a3e6386a24887a92736793479c5918ecac3b7deac2d02abf1f2", - "sha256:6fe5e44a14864d921fb96669a82f9635846806176f77f1d73c61feb84ebf4d84", - "sha256:7562436dadf8382e59ac3739fbbf9d5b2d807fafc7f28cb884863430e0de6505", - "sha256:7b04a83ddcb3f7c935c75a1f7f6050c85fe4062a2ea64c47ee6bda788d037761", - "sha256:7c8c0f686865e330de90b93d53b100f7f07c2f10f5449ceb721121f459f7cc4a", - "sha256:87b36e0797ab7fbb7ef594c7a6e0febc7ffb4101a42ea796726a8288391a3769", - "sha256:9bc9b9bf0f2beea3911750d2d66247608be8cbad33b7a050cacec9e4c105a1ca", - "sha256:add310c96df6933cfb4ce3821c9c7b5c133e8aa609a4c9416e1c7af546163488", - "sha256:c2fd70ca9961f7871810dce1b7d0a42a69eb8ff2d786621123952bd505a6867e", - "sha256:d02ee28663077f15d529b04d27588b174fa937daf73a294df279bbf70c468f5c", - "sha256:d0c22046e5f2cf0d72f9809a967340db1b238fefe58322896bc7c3f3d1d10b42", - "sha256:e7734a32a91eea4b502b8f9d2915cdba0a372226e14fb983876d763110dcefef", - "sha256:efa601dc4116c17a6b09255b031b5a1891e3ac18b50ec536452a725a6b75db8d", - "sha256:f8ca46a6987e14f58ec8dfda2d2376bacd113c1fec5f58bebf90838bb4408ab9", - "sha256:fde02fcb387863873b56730f4b9f65515d87c92c12299f0f0a74b3ccdfe35062", - "sha256:fe8175452fcc99a0af6429d8acd87682a3a70c5879d73532c7327f71ce508a35" + "sha256:264d5f6478d787c336520cf1a99e39bb6a0ef6d984550f925095c0e692dea7b5", + "sha256:29e1d82b16f7580280ae35a0ae78de55f15c92ec87b7f3a1372f40f37a053bf3", + "sha256:31405311c28fc8b3b2975a98b60bac388563748beaacb6da470f917678417e2d", + "sha256:332c1d5633c233458c4b65e6ad4a860391c507384bd2324a186b2702f8c64dfe", + "sha256:3400b582be3d71f1c0974701fcfda32f0c2ebb75a78c2aea430552b0c6896546", + "sha256:3a01c93c69e74068c1618631a750677fd088708d2b09b3c23809b099fa4ffa39", + "sha256:3f5fc705e8790217d23ab5e7ac2c05d82e050f6271b710300288adfe87a71072", + "sha256:435a108cf8b53302500b52adb2cccbf2afa51c94ab3c705b250245090b46f5da", + "sha256:4508ee04c46cac8356a9d04f0d9a63f845770d2abb54caf512b44d22f0e80300", + "sha256:460b47a1a17335d444ec441b68c083da5e51cdfcfa67a6638de69fe5e97f4ad2", + "sha256:4a53b2bf19be687160e4d18c27680e5326687aa39a7e31641d32a61edadbbfd9", + "sha256:4b1bd9a91dee18bc95d7af2c593a214857a03e4fcd9a1eb01588df432de24c58", + "sha256:53278c6a3d0a5dc8f221e0a77c065a61fd0598f9d8d9ef5be53de0c0a7d2df90", + "sha256:59755a600c25a282589b548ffa045aed59c2df7b76943978cabb1825f0c03ec4", + "sha256:64ab1097e3a077ae9db6a98d01e2e77087894ebd85b702edf5eb85d05ab8c0f1", + "sha256:693979ad4c8885729ac126b3202f1cb645f3392ad7e0964c2d924e61bc0e0a9d", + "sha256:705a7aed0a917c35bb5efa4d94a7e8092705b3395726f9770d2b888de775f437", + "sha256:9586bc98a322e546cf2e477309806aa4a3e1d18efc9b93fc2e2b3d8131e1b9f7", + "sha256:9bde3683e254661e6b0032006f0ef7025ade2a33d3e3045499e71b76ea99942c", + "sha256:b234805b615b2d45dcb1bfe5c2167dc4121e31d618ab557856a3153b94c1676b", + "sha256:bb345ef1120db4f78ec0f229514d333ea3e7d367875c1400423a9b3e2b48ffc0", + "sha256:c71b5e80a08272b9f3012314dc47ee2423270b30262d07ec7dd9709ae2bde1ac", + "sha256:d2e9cfa46193fab196c27cb07561e1bb0938450984c2f01b3739f254a31b639e", + "sha256:d3bef175707693a2f53fe0fe4e546e3187c7876aedabfe43d9a916060bac9073", + "sha256:da1b08b5348152f2940fa183d0265a6b6eb6f0292fae44b576eaf8e53723e336", + "sha256:dbce86df507f6bce118b12b33d893f1d3512013c898174211e903da78e1916aa", + "sha256:eafa1bce0860320ddbb7edb4ab5678e02051db5450251ba8e918713d9a70c03c", + "sha256:ee9e9ce1897eeac0fc33cf99084067c14250312a5dbc1372012c3d2f0e7a4af5", + "sha256:f7a8f91681b88ad216c36911e08ea25d2b3121350d52f4f8d76aeb0b7fcc6bef", + "sha256:fab599d23fa490725e5b5a70bfb6bc87acf5ceb70abe11ad2ef2b2f516961f31", + "sha256:faebdf8679706964f87617ee43b8d0107587d20b526892b538222146a4c32d43" ], "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": { "hashes": [ @@ -540,50 +609,58 @@ }, "sqlalchemy": { "hashes": [ - "sha256:024d2f67fb3ec697555e48caeb7147cfe2c08065a4f1a52d93c3d44fc8e6ad1c", - "sha256:0bf0fd65b50a330261ec7fe3d091dfc1c577483c96a9fa1e4323e932961aa1b5", - "sha256:16a310f5bc75a5b2ce7cb656d0e76eb13440b8354f927ff15cbaddd2523ee2d1", - "sha256:1d90ccc15ba1baa345796a8fb1965223ca7ded2d235ccbef80a47b85cea2d71a", - "sha256:22bafb1da60c24514c141a7ff852b52f9f573fb933b1e6b5263f0daa28ce6db9", - "sha256:2c69ce70047b801d2aba3e5ff3cba32014558966109fecab0c39d16c18510f15", - "sha256:2e7b69d9ced4b53310a87117824b23c509c6fc1f692aa7272d47561347e133b6", - "sha256:314145c1389b021a9ad5aa3a18bac6f5d939f9087d7fc5443be28cba19d2c972", - "sha256:3afa8a21a9046917b3a12ffe016ba7ebe7a55a6fc0c7d950beb303c735c3c3ad", - "sha256:430614f18443b58ceb9dedec323ecddc0abb2b34e79d03503b5a7579cd73a531", - "sha256:43699eb3f80920cc39a380c159ae21c8a8924fe071bccb68fc509e099420b148", - "sha256:539010665c90e60c4a1650afe4ab49ca100c74e6aef882466f1de6471d414be7", - "sha256:57d100a421d9ab4874f51285c059003292433c648df6abe6c9c904e5bd5b0828", - "sha256:5831138f0cc06b43edf5f99541c64adf0ab0d41f9a4471fd63b54ae18399e4de", - "sha256:584f66e5e1979a7a00f4935015840be627e31ca29ad13f49a6e51e97a3fb8cae", - "sha256:5d6afc41ca0ecf373366fd8e10aee2797128d3ae45eb8467b19da4899bcd1ee0", - "sha256:61ada5831db36d897e28eb95f0f81814525e0d7927fb51145526c4e63174920b", - "sha256:6b54d1ad7a162857bb7c8ef689049c7cd9eae2f38864fc096d62ae10bc100c7d", - "sha256:7351c05db355da112e056a7b731253cbeffab9dfdb3be1e895368513c7d70106", - "sha256:77a14fa20264af73ddcdb1e2b9c5a829b8cc6b8304d0f093271980e36c200a3f", - "sha256:851a37898a8a39783aab603c7348eb5b20d83c76a14766a43f56e6ad422d1ec8", - "sha256:89bc2b374ebee1a02fd2eae6fd0570b5ad897ee514e0f84c5c137c942772aa0c", - "sha256:8e712cfd2e07b801bc6b60fdf64853bc2bd0af33ca8fa46166a23fe11ce0dbb0", - "sha256:8f9eb4575bfa5afc4b066528302bf12083da3175f71b64a43a7c0badda2be365", - "sha256:8fc05b59142445a4efb9c1fd75c334b431d35c304b0e33f4fa0ff1ea4890f92e", - "sha256:96f0463573469579d32ad0c91929548d78314ef95c210a8115346271beeeaaa2", - "sha256:9deaae357edc2091a9ed5d25e9ee8bba98bcfae454b3911adeaf159c2e9ca9e3", - "sha256:a752b7a9aceb0ba173955d4f780c64ee15a1a991f1c52d307d6215c6c73b3a4c", - "sha256:ae7473a67cd82a41decfea58c0eac581209a0aa30f8bc9190926fbf628bb17f7", - "sha256:b15afbf5aa76f2241184c1d3b61af1a72ba31ce4161013d7cb5c4c2fca04fd6e", - "sha256:c896d4e6ab2eba2afa1d56be3d0b936c56d4666e789bfc59d6ae76e9fcf46145", - "sha256:cb4e688f6784427e5f9479d1a13617f573de8f7d4aa713ba82813bcd16e259d1", - "sha256:cda283700c984e699e8ef0fcc5c61f00c9d14b6f65a4f2767c97242513fcdd84", - "sha256:cf7b5e3856cbf1876da4e9d9715546fa26b6e0ba1a682d5ed2fc3ca4c7c3ec5b", - "sha256:d6894708eeb81f6d8193e996257223b6bb4041cb05a17cd5cf373ed836ef87a2", - "sha256:d8f2afd1aafded7362b397581772c670f20ea84d0a780b93a1a1529da7c3d369", - "sha256:dd4d410a76c3762511ae075d50f379ae09551d92525aa5bb307f8343bf7c2c12", - "sha256:eb60699de43ba1a1f77363f563bb2c652f7748127ba3a774f7cf2c7804aa0d3d", - "sha256:f469f15068cd8351826df4080ffe4cc6377c5bf7d29b5a07b0e717dddb4c7ea2", - "sha256:f82c310ddf97b04e1392c33cf9a70909e0ae10a7e2ddc1d64495e3abdc5d19fb", - "sha256:fa51ce4aea583b0c6b426f4b0563d3535c1c75986c4373a0987d84d22376585b" + "sha256:0b0b3f2686c3f162123adba3cb8b626ed7e9b8433ab528e36ed270b4f70d1cdb", + "sha256:0c1fea8c0abcb070ffe15311853abfda4e55bf7dc1d4889497b3403629f3bf00", + "sha256:0e1ce8ebd2e040357dde01a3fb7d30d9b5736b3e54a94002641dfd0aa12ae6ce", + "sha256:129415f89744b05741c6f0b04a84525f37fbabe5dc3774f7edf100e7458c48cd", + "sha256:13790cb42f917c45c9c850b39b9941539ca8ee7917dacf099cc0b569f3d40da7", + "sha256:14cd3bcbb853379fef2cd01e7c64a5d6f1d005406d877ed9509afb7a05ff40a5", + "sha256:154a32f3c7b00de3d090bc60ec8006a78149e221f1182e3edcf0376016be9396", + "sha256:19c6986cf2fb4bc8e0e846f97f4135a8e753b57d2aaaa87c50f9acbe606bd1db", + "sha256:2096d6b018d242a2bcc9e451618166f860bb0304f590d205173d317b69986c95", + "sha256:2c9bac865ee06d27a1533471405ad240a6f5d83195eca481f9fc4a71d8b87df8", + "sha256:3076740335e4aaadd7deb3fe6dcb96b3015f1613bd190a4e1634e1b99b02ec86", + "sha256:3940677d341f2b685a999bffe7078697b5848a40b5f6952794ffcf3af150c301", + "sha256:3aa1472bf44f61dd27987cd051f1c893b7d3b17238bff8c23fceaef4f1133868", + "sha256:40b1206a0d923e73aa54f0a6bd61419a96b914f1cd19900b6c8226899d9742ad", + "sha256:4bb062784f37b2d75fd9b074c8ec360ad5df71f933f927e9e95c50eb8e05323c", + "sha256:4e869a8ff7ee7a833b74868a0887e8462445ec462432d8cbeff5e85f475186da", + "sha256:4f6ff392b27a743c1ad346d215655503cec64405d3b694228b3454878bf21590", + "sha256:505f503763a767556fa4deae5194b2be056b64ecca72ac65224381a0acab7ebe", + "sha256:53a766cb0b468223cafdf63e2d37f14a4757476157927b09300c8c5832d88560", + "sha256:5434cc601aa17570d79e5377f5fd45ff92f9379e2abed0be5e8c2fba8d353d2b", + "sha256:54bcceaf4eebef07dadfde424f5c26b491e4a64e61761dea9459103ecd6ccc95", + "sha256:55914d45a631b81a8a2cb1a54f03eea265cf1783241ac55396ec6d735be14883", + "sha256:564e9f9e4e6466273dbfab0e0a2e5fe819eec480c57b53a2cdee8e4fdae3ad5f", + "sha256:56a7e2bb639df9263bf6418231bc2a92a773f57886d371ddb7a869a24919face", + "sha256:58a3aba1bfb32ae7af68da3f277ed91d9f57620cf7ce651db96636790a78b736", + "sha256:625b72d77ac8ac23da3b1622e2da88c4aedaee14df47c8432bf8f6495e655de2", + "sha256:69fd9e41cf9368afa034e1c81f3570afb96f30fcd2eb1ef29cb4d9371c6eece2", + "sha256:6ac28bd6888fe3c81fbe97584eb0b96804bd7032d6100b9701255d9441373ec1", + "sha256:7c6c3e9350f9fb16de5b5e5fbf17b578811a52d71bb784cc5ff71acb7de2a7f9", + "sha256:7ee7ccf47aa503033b6afd57efbac6b9e05180f492aeed9fcf70752556f95624", + "sha256:875de9414393e778b655a3d97d60465eb3fae7c919e88b70cc10b40b9f56042d", + "sha256:8db5ba8b7da759b727faebc4289a9e6a51edadc7fc32207a30f7c6203a181592", + "sha256:92e512a6af769e4725fa5b25981ba790335d42c5977e94ded07db7d641490a85", + "sha256:9886a72c8e6371280cb247c5d32c9c8fa141dc560124348762db8a8b236f8692", + "sha256:9e55dff5ec115316dd7a083cdc1a52de63693695aecf72bc53a8e1468ce429e5", + "sha256:a42c9fa3abcda0dcfad053e49c4f752eef71ecd8c155221e18b99d4224621176", + "sha256:a571bc8ac092a3175a1d994794a8e7a1f2f651e7c744de24a19b4f740fe95034", + "sha256:af66001d7b76a3fab0d5e4c1ec9339ac45748bc4a399cbc2baa48c1980d3c1f4", + "sha256:b39a6e21110204a8c08d40ff56a73ba542ec60bab701c36ce721e7990df49fb9", + "sha256:b560f075c151900587ade06706b0c51d04b3277c111151997ea0813455378ae0", + "sha256:c8f1792d20d2f4e875ce7a113f43c3561ad12b34ff796b84002a256f37ce9437", + "sha256:cb9a758ad973e795267da334a92dd82bb7555cb36a0960dcabcf724d26299db8", + "sha256:ccca778c0737a773a1ad86b68bda52a71ad5950b25e120b6eb1330f0df54c3d0", + "sha256:ccd87c25e4c8559e1b918d46b4fa90b37f459c9b4566f1dfbce0eb8122571547", + "sha256:d143c5a9dada696bcfdb96ba2de4a47d5a89168e71d05a076e88a01386872f97", + "sha256:d80eeb5189d7d4b1af519fc3f148fe7521b9dfce8f4d6a0820e8f5769b005051", + "sha256:e04ab55cf49daf1aeb8c622c54d23fa4bec91cb051a43cc24351ba97e1dd09f5", + "sha256:f146c61ae128ab43ea3a0955de1af7e1633942c2b2b4985ac51cc292daf33222", + "sha256:f776c2c30f0e5f4db45c3ee11a5f2a8d9de68e81eb73ec4237de1e32e04ae81c" ], "markers": "python_version >= '3.7'", - "version": "==2.0.19" + "version": "==2.0.22" }, "sqlalchemy-utils": { "hashes": [ @@ -595,19 +672,19 @@ }, "typing-extensions": { "hashes": [ - "sha256:440d5dd3af93b060174bf433bccd69b0babc3b15b1a8dca43789fd7f61514b36", - "sha256:b75ddc264f0ba5615db7ba217daeb99701ad295353c45f9e95963337ceeeffb2" + "sha256:8f92fc8806f9a6b641eaa5318da32b44d401efaac0f6678c9bc448ba3605faa0", + "sha256:df8e4339e9cb77357558cbdbceca33c303714cf861d1eef15e1070055ae8b7ef" ], - "markers": "python_version >= '3.7'", - "version": "==4.7.1" + "markers": "python_version >= '3.8'", + "version": "==4.8.0" }, "urllib3": { "hashes": [ - "sha256:8d22f86aae8ef5e410d4f539fde9ce6b2113a001bb4d189e0aed70642d602b11", - "sha256:de7df1803967d2c2a98e4b11bb7d6bd9210474c46e8a0401514e3a42a75ebde4" + "sha256:c97dfde1f7bd43a71c8d2a58e369e9b2bf692d1334ea9f9cae55add7d0dd0f84", + "sha256:fdb6d215c776278489906c2f8916e6e7d4f5a9b602ccbcfdf7f016fc8da0596e" ], "markers": "python_version >= '3.7'", - "version": "==2.0.4" + "version": "==2.0.7" }, "visitor": { "hashes": [ @@ -617,19 +694,19 @@ }, "werkzeug": { "hashes": [ - "sha256:935539fa1413afbb9195b24880778422ed620c0fc09670945185cce4d91a8890", - "sha256:98c774df2f91b05550078891dee5f0eb0cb797a522c757a2452b9cee5b202330" + "sha256:507e811ecea72b18a404947aded4b3390e1db8f826b494d76550ef45bb3b1dcc", + "sha256:90a285dc0e42ad56b34e696398b8122ee4c681833fb35b8334a095d82c56da10" ], "markers": "python_version >= '3.8'", - "version": "==2.3.6" + "version": "==3.0.1" }, "wtforms": { "hashes": [ - "sha256:6b351bbb12dd58af57ffef05bc78425d08d1914e0fd68ee14143b7ade023c5bc", - "sha256:837f2f0e0ca79481b92884962b914eba4e72b7a2daaf1f939c890ed0124b834b" + "sha256:5e51df8af9a60f6beead75efa10975e97768825a82146a65c7cbf5b915990620", + "sha256:ae7c54b29806c70f7bce8eb9f24afceb10ca5c32af3d9f04f74d2f66ccc5c7e0" ], - "markers": "python_version >= '3.7'", - "version": "==3.0.1" + "markers": "python_version >= '3.8'", + "version": "==3.1.1" }, "wtforms-sqlalchemy": { "hashes": [ diff --git a/backend/migrations/versions/36f532800705_remove_accepted_from_receiptitem.py b/backend/migrations/versions/36f532800705_remove_accepted_from_receiptitem.py new file mode 100644 index 0000000..d046778 --- /dev/null +++ b/backend/migrations/versions/36f532800705_remove_accepted_from_receiptitem.py @@ -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 ### diff --git a/backend/migrations/versions/cdbe3f5e3b30_remove_item_receiptitem_relationship.py b/backend/migrations/versions/cdbe3f5e3b30_remove_item_receiptitem_relationship.py new file mode 100644 index 0000000..20b2763 --- /dev/null +++ b/backend/migrations/versions/cdbe3f5e3b30_remove_item_receiptitem_relationship.py @@ -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 ### diff --git a/backend/models/item.py b/backend/models/item.py index 52d8b06..a3b9517 100644 --- a/backend/models/item.py +++ b/backend/models/item.py @@ -16,8 +16,6 @@ class Item(db.Model): "Category", secondary=item_category, lazy="dynamic", back_populates="Item") PriceChange = db.relationship( "PriceChange", backref='Item', lazy='dynamic') - ReceiptItem = db.relationship( - "ReceiptItem", backref='Item', lazy='dynamic') def __repr__(self) -> str: return f"" diff --git a/backend/models/receipt_item.py b/backend/models/receipt_item.py index 3f52322..8da5820 100644 --- a/backend/models/receipt_item.py +++ b/backend/models/receipt_item.py @@ -4,10 +4,9 @@ from src import db class ReceiptItem(db.Model): receipt = db.Column(db.ForeignKey("receipt.id"), primary_key=True, server_onupdate=db.FetchedValue()) - item = db.Column(db.ForeignKey("item.id"), primary_key=True, - server_onupdate=db.FetchedValue()) - amount = db.Column(db.SmallInteger, nullable=False) - accepted = db.Column(db.Boolean, nullable=False) + item = db.Column(db.SmallInteger, primary_key=True, nullable=False) + amount = db.Column(db.SmallInteger, nullable=False, default=str(1)) + price = db.Column(db.SmallInteger, nullable=False) def __repr__(self) -> str: return f"" diff --git a/backend/models/schemas/receipt_item.py b/backend/models/schemas/receipt_item.py index f2dae03..501061f 100644 --- a/backend/models/schemas/receipt_item.py +++ b/backend/models/schemas/receipt_item.py @@ -10,6 +10,5 @@ class ReceiptItemSchema(ma.SQLAlchemySchema): include_fk = True Receipt = ma.Nested(ReceiptSchema) - Item = ma.Nested(ItemSchema) + price = ma.auto_field() amount = ma.auto_field() - accepted = ma.auto_field() diff --git a/backend/requirements.txt b/backend/requirements.txt index 3a48cf01a2d14660de2815c2761e80d6b1a030db..c6897f7036d072433009a1669d9bd74b90c8e32b 100644 GIT binary patch literal 1729 zcmaJ>%Wm5+5WMRvbW;jcj2@2dv{iuuz4Xvta|~#Sk{I(9lCtA`eTS0sge4ygh@4%{ z?#yn=whc%1K_3{CjLpzSrvhz^vn1#XqY!Daj^@ zc7m%tvjMm!ZUy>zDTmTN<|_0%`x=)d4}V4YE0c&x%0+rW zmm2Cd`UJ5^MvQhok6J+;x`8;7O&{q_Ywx_JX6opMoKb15t*a_HC*z}js=IDH|GTIQBYC$OrFB~@YebK=-c2RkdHdcm=erS zyo2*z#F4b_xniR_l-jyquaa2X`066Un0mbuYyt7KUEeRJpt4!K|MmCx;{B1UvKR?m zWO(=IAFjWIU&I>)JC9etiJ?Sl`-fuG@>nS!=s-WQjp?=6&(;ueN8wBA#g zHFW0vmiRcJ;Ah0pb+8_o&Grw^8F#9+>56oRnYF+daQtm#P7g=eavWfM$iXy|Ya!3e z_ipSF4(5x&GGPvRHdrPl;=*1{8||4ogy1lMmOT!@jN+9ziryC;#Gl=sDDn-P4xS4n z!Ilf7=CR{dm$D~36_)ro?{mwjBxuB7h2Xm~)SN9X)B|^X+&)kdH65AVKeGXHgw?a4 VE5;sM7d*yYFyFE>?vwUq^dIz6BH;i4 literal 3634 zcmbuCOLG!Y5QTefmH&aAS|yr+gv4i+Rc>79Hp>*@o$xYDAo%0e^L5W<^1uj_nwmi1 z_PM7|pYFN*`CYe>)of_FuDLDjy}i{nx3%t(y|I~H*+8Ex^xs6EjjdPE7UITNgn2{pDi*LZJhITH7 zBkgtRJ12%M?boP?*m0y>sD0faHtaw*OpiQ|{g}3jygO2C`y~_FC`pMYeg@*t}~N>Y;C2abtOF zS-7g}wV)D7Nvg#?*FIFG;XT>28})ZjpW=IZcc7S=+&1^f==$AyDzpr?S;4I@R&DJU zE<}@XIrE_WuC6&V)0I23D@DZatmQt|ojKpzF?f=hLxxd7GQ5wBYX`0>>rfzO#Qk+i z!?fz%);(FpoN|)Ci6M*kOO`~*V0jm@8JW!3;XGsja8SS_s-h!(E;{H4a|iP( z<^cYt3#y(0F1$Jy!ftGMJ_V0{x)eWh4xIh-PF0E7bLq2rA>6)lPdyFxzIC~ayKSaX zrOcRw`#kw#Vn@xl&&#^1wSCIrvPQ8Zo|!98&M@s_h7XF2gIP6qa}Hh$btd$IcH`;8 zykoM*ti?rS-E!Y@g1FF>FDEEn5L2G-CSH;5tr^@9YMRuy&mVQUmZuyudAacfIR_f^ z`lrx(Vu;66b(`*;ShG+pCsfX;rLWMVYK{I?i}b9(0o9b=hFn*EoHfQpeq?{>`NdN! zm!kYOp||T&;-=7xUnrbU%IAHY3aT-?R;_t@k5v2SMrXKG?V_cy;FybLoVq}ZzQoBZ k<#Ht_bKbvJZe?xD6ZEdXsM17@CqMg53SGhn>|0HjzmG98<^TWy diff --git a/backend/src/auth/routes.py b/backend/src/auth/routes.py index ae396c8..f8540e9 100644 --- a/backend/src/auth/routes.py +++ b/backend/src/auth/routes.py @@ -6,7 +6,7 @@ from models.user import User from src.utils.routes_utils import render_custom_template as render_template from flask import flash, redirect, request, url_for 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']) def web_register(): @@ -34,7 +34,7 @@ def web_login(): return redirect(url_for('auth.web_login')) login_user(user, remember=form.remember_me.data) 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') return redirect(next_page) return render_template('auth/login.html', title='Sign In', form=form) diff --git a/backend/src/establishment/candidates/routes.py b/backend/src/establishment/candidates/routes.py index 9e8796c..a42e2cd 100644 --- a/backend/src/establishment/candidates/routes.py +++ b/backend/src/establishment/candidates/routes.py @@ -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 . import bp from .forms import EvaluateCandidateForm @@ -12,8 +12,10 @@ from src.utils.database_utils import generate_token def candidates(establishment_id): establishment = Establishment.query.get_or_404(establishment_id) if(current_user == establishment.User): + page = request.args.get('page', 1, type=int) 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.accept.data): login_token = LoginToken(Establishment = establishment, User = User.query.get(form.candidate_id.data), token = generate_token()) diff --git a/backend/src/receipts/check_items/forms.py b/backend/src/receipts/check_items/forms.py index c135330..9a58f03 100644 --- a/backend/src/receipts/check_items/forms.py +++ b/backend/src/receipts/check_items/forms.py @@ -1,48 +1,55 @@ from collections import namedtuple from flask_wtf import FlaskForm -from models import Brand, Item 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.validators import DataRequired, Optional, ValidationError +from wtforms import BooleanField, HiddenField, FieldList, Form, FormField, IntegerField, RadioField, StringField, SubmitField +from wtforms.validators import DataRequired, ValidationError 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): - # TODO Fertig machen x.x itemname = HiddenField('itemname', validators=[DataRequired()]) price = HiddenField('price', validators=[DataRequired()]) - requesting = BooleanField("", default=False, render_kw={ - "class": "form-check-input"}) - new_or_existing = RadioField("", choices=[ - (0, "New"), (1, "Existing")], render_kw={"class": "form-check-input", "style": "display:none"}, validate_choice=False) + requesting = BooleanField("", default=False, + render_kw={"class": "form-check-input"}) + new_or_existing = RadioField("", + choices=get_choices(), + render_kw={"class": "form-check form-check-inline form-check-input"}, + coerce=int, default=3) # Fields for new Item - new_description = StringField("Description", render_kw={"class": "form-control"}) - new_amount_change = IntegerField("Amount", render_kw={"class": "form-control"}) - new_brand = QuerySelectField("Brand", query_factory=all_brands, render_kw={"class": "form-control"}, allow_blank=True) + new_ean = IntegerField("EAN ID", render_kw={ + "class": "form-control"}, validators=[radio_validator(1)], + 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 - 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): if (self.requesting.data and not new_or_existing.data): raise ValidationError( "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): items = FieldList(FormField(CheckItemsEntryForm)) @@ -55,7 +62,8 @@ class CheckItemsForm(FlaskForm): CheckItems = namedtuple("CheckItems", ["items"]) check_items_entry = [] 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) form = cls(obj=check_items) diff --git a/backend/src/receipts/check_items/routes.py b/backend/src/receipts/check_items/routes.py index 2fd4653..99e2a17 100644 --- a/backend/src/receipts/check_items/routes.py +++ b/backend/src/receipts/check_items/routes.py @@ -1,10 +1,11 @@ +from datetime import date from flask import abort, request, url_for from flask_login import current_user, login_required 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 models.receipt import Receipt -from models.login_token import LoginToken +from models import AmountChange, Item, LoginToken, PriceChange, Receipt, ReceiptItem from src.utils.pdf_receipt_parser import PDFReceipt from src.utils.routes_utils import render_custom_template as render_template @@ -15,10 +16,10 @@ PDFDir = "./" def confirm_receipt_items(receipt_id: int): """Check items from a receipt if they should be accounted for payment. 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: - receipt = PDFReceipt.getPDFReceiptFromFile(PDFDir + f"{receipt_details.id}.pdf") - form = CheckItemsForm.new(receipt.items) + receipt: PDFReceipt = PDFReceipt.getPDFReceiptFromFile(PDFDir + f"{receipt_details.id}.pdf") + 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 # times and provide dropdown menu if necessary. If not, provide input field. # temp_choices = [] @@ -30,12 +31,34 @@ def confirm_receipt_items(receipt_id: int): # temp_choices.append((itemname.replace(" ", "_"), f"{itemname}, {price} * {amount}")) # form.choices = temp_choices # print(form.data) - for formitem in form.items: - # print(formitem.new_brand.__dict__) - print(formitem.data) + # for formitem in form.items: + # LOGGER.debug(formitem.data) if form.validate(): - print("valid") + LOGGER.debug("valid") + else: + LOGGER.debug(form.errors) 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) abort(403) \ No newline at end of file diff --git a/backend/src/receipts/check_items/utils.py b/backend/src/receipts/check_items/utils.py new file mode 100644 index 0000000..4a05834 --- /dev/null +++ b/backend/src/receipts/check_items/utils.py @@ -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] \ No newline at end of file diff --git a/backend/src/receipts/upload/routes.py b/backend/src/receipts/upload/routes.py index 00b8499..827e7b1 100644 --- a/backend/src/receipts/upload/routes.py +++ b/backend/src/receipts/upload/routes.py @@ -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 os import rename 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 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('/', methods=['GET', 'POST']) @login_required def upload_receipt(establishment: int): @@ -34,7 +30,8 @@ def upload_receipt(establishment: int): db.session.add(dbReceipt) db.session.commit() rename(f"{PDFDir}/temp.pdf", f"{PDFDir}{secure_filename(f'{dbReceipt.id}.pdf')}") - return receipt.text.replace("\n", "
") + LOGGER.debug(receipt.text) + return redirect(url_for("receipts.check_items.confirm_receipt_items", receipt_id = dbReceipt.id)) else: LOGGER.debug(form.errors) return render_template("receipts/upload.html", form = form) diff --git a/backend/src/utils/modules/receipt_parser/edeka/edeka_parser.py b/backend/src/utils/modules/receipt_parser/edeka/edeka_parser.py new file mode 100644 index 0000000..e69de29 diff --git a/backend/src/utils/modules/receipt_parser/pdf_receipt_parser.py b/backend/src/utils/modules/receipt_parser/pdf_receipt_parser.py new file mode 100644 index 0000000..319618b --- /dev/null +++ b/backend/src/utils/modules/receipt_parser/pdf_receipt_parser.py @@ -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) \ No newline at end of file diff --git a/backend/web/templates/establishment/candidates/candidates.html b/backend/web/templates/establishment/candidates/candidates.html index 54b4444..56d8262 100644 --- a/backend/web/templates/establishment/candidates/candidates.html +++ b/backend/web/templates/establishment/candidates/candidates.html @@ -11,5 +11,7 @@ {% endfor %} +{% with pagination_object=establishment_candidates %} {% include "utils/general/_page_navigation.html" %} +{% endwith %} {% endblock %} \ No newline at end of file diff --git a/backend/web/templates/receipts/check_items.html b/backend/web/templates/receipts/check_items.html index d137543..96bc8cf 100644 --- a/backend/web/templates/receipts/check_items.html +++ b/backend/web/templates/receipts/check_items.html @@ -13,6 +13,7 @@ {{ render_field(item.new_or_existing) }}