From ff34e907b6157b466aec1f393fb38b34ce920eda Mon Sep 17 00:00:00 2001 From: Jia Xu Date: Mon, 18 Mar 2024 12:50:54 -0700 Subject: [PATCH] 19875 - PAY Jobs - Disbursement Process handle Partial Refunds (#1428) --- jobs/payment-jobs/poetry.lock | 257 ++++++++++-------- jobs/payment-jobs/pyproject.toml | 2 +- jobs/payment-jobs/tasks/ap_task.py | 11 +- jobs/payment-jobs/tasks/eft_transfer_task.py | 12 +- .../tasks/ejv_partner_distribution_task.py | 115 ++++++-- jobs/payment-jobs/tasks/ejv_payment_task.py | 13 +- jobs/payment-jobs/tests/jobs/factory.py | 20 +- .../tests/jobs/test_eft_transfer_task.py | 6 +- .../test_ejv_partner_distribution_task.py | 4 +- ...artner_partial_refund_distribution_task.py | 86 ++++++ .../tests/jobs/test_ejv_payment_task.py | 11 +- ...024_03_06_04b8a7bed74e_ejv_link_generic.py | 39 +++ pay-api/poetry.lock | 116 ++++---- pay-api/src/pay_api/models/__init__.py | 2 +- .../{ejv_invoice_link.py => ejv_link.py} | 17 +- pay-api/src/pay_api/models/refunds_partial.py | 6 +- pay-api/src/pay_api/utils/enums.py | 7 + pay-queue/poetry.lock | 18 +- pay-queue/pyproject.toml | 2 +- .../pay_queue/services/cgi_reconciliations.py | 26 +- .../integration/test_cgi_reconciliations.py | 56 ++-- 21 files changed, 560 insertions(+), 266 deletions(-) create mode 100644 jobs/payment-jobs/tests/jobs/test_ejv_partner_partial_refund_distribution_task.py create mode 100644 pay-api/migrations/versions/2024_03_06_04b8a7bed74e_ejv_link_generic.py rename pay-api/src/pay_api/models/{ejv_invoice_link.py => ejv_link.py} (80%) diff --git a/jobs/payment-jobs/poetry.lock b/jobs/payment-jobs/poetry.lock index b71776aa8..b4942360b 100644 --- a/jobs/payment-jobs/poetry.lock +++ b/jobs/payment-jobs/poetry.lock @@ -119,17 +119,17 @@ tests-no-zope = ["attrs[tests-mypy]", "cloudpickle", "hypothesis", "pympler", "p [[package]] name = "autopep8" -version = "2.0.4" +version = "2.1.0" description = "A tool that automatically formats Python code to conform to the PEP 8 style guide" optional = false -python-versions = ">=3.6" +python-versions = ">=3.8" files = [ - {file = "autopep8-2.0.4-py2.py3-none-any.whl", hash = "sha256:067959ca4a07b24dbd5345efa8325f5f58da4298dab0dde0443d5ed765de80cb"}, - {file = "autopep8-2.0.4.tar.gz", hash = "sha256:2913064abd97b3419d1cc83ea71f042cb821f87e45b9c88cad5ad3c4ea87fe0c"}, + {file = "autopep8-2.1.0-py2.py3-none-any.whl", hash = "sha256:2bb76888c5edbcafe6aabab3c47ba534f5a2c2d245c2eddced4a30c4b4946357"}, + {file = "autopep8-2.1.0.tar.gz", hash = "sha256:1fa8964e4618929488f4ec36795c7ff12924a68b8bf01366c094fc52f770b6e7"}, ] [package.dependencies] -pycodestyle = ">=2.10.0" +pycodestyle = ">=2.11.0" [[package]] name = "bcrypt" @@ -184,13 +184,13 @@ files = [ [[package]] name = "cachelib" -version = "0.12.0" +version = "0.9.0" description = "A collection of cache libraries in the same API interface." optional = false -python-versions = ">=3.8" +python-versions = ">=3.7" files = [ - {file = "cachelib-0.12.0-py3-none-any.whl", hash = "sha256:038f4d855afc3eb8caab10458f6eac55c328911f9055824c22c2f259ef9ed3a3"}, - {file = "cachelib-0.12.0.tar.gz", hash = "sha256:8243029a028436fd23229113dee517c0700bb43a8a289ec5a963e4af9ca2b194"}, + {file = "cachelib-0.9.0-py3-none-any.whl", hash = "sha256:811ceeb1209d2fe51cd2b62810bd1eccf70feba5c52641532498be5c675493b3"}, + {file = "cachelib-0.9.0.tar.gz", hash = "sha256:38222cc7c1b79a23606de5c2607f4925779e37cdcea1c2ad21b8bae94b5425a5"}, ] [[package]] @@ -428,63 +428,63 @@ files = [ [[package]] name = "coverage" -version = "7.4.3" +version = "7.4.4" description = "Code coverage measurement for Python" optional = false python-versions = ">=3.8" files = [ - {file = "coverage-7.4.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:8580b827d4746d47294c0e0b92854c85a92c2227927433998f0d3320ae8a71b6"}, - {file = "coverage-7.4.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:718187eeb9849fc6cc23e0d9b092bc2348821c5e1a901c9f8975df0bc785bfd4"}, - {file = "coverage-7.4.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:767b35c3a246bcb55b8044fd3a43b8cd553dd1f9f2c1eeb87a302b1f8daa0524"}, - {file = "coverage-7.4.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ae7f19afe0cce50039e2c782bff379c7e347cba335429678450b8fe81c4ef96d"}, - {file = "coverage-7.4.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba3a8aaed13770e970b3df46980cb068d1c24af1a1968b7818b69af8c4347efb"}, - {file = "coverage-7.4.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:ee866acc0861caebb4f2ab79f0b94dbfbdbfadc19f82e6e9c93930f74e11d7a0"}, - {file = "coverage-7.4.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:506edb1dd49e13a2d4cac6a5173317b82a23c9d6e8df63efb4f0380de0fbccbc"}, - {file = "coverage-7.4.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fd6545d97c98a192c5ac995d21c894b581f1fd14cf389be90724d21808b657e2"}, - {file = "coverage-7.4.3-cp310-cp310-win32.whl", hash = "sha256:f6a09b360d67e589236a44f0c39218a8efba2593b6abdccc300a8862cffc2f94"}, - {file = "coverage-7.4.3-cp310-cp310-win_amd64.whl", hash = "sha256:18d90523ce7553dd0b7e23cbb28865db23cddfd683a38fb224115f7826de78d0"}, - {file = "coverage-7.4.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cbbe5e739d45a52f3200a771c6d2c7acf89eb2524890a4a3aa1a7fa0695d2a47"}, - {file = "coverage-7.4.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:489763b2d037b164846ebac0cbd368b8a4ca56385c4090807ff9fad817de4113"}, - {file = "coverage-7.4.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:451f433ad901b3bb00184d83fd83d135fb682d780b38af7944c9faeecb1e0bfe"}, - {file = "coverage-7.4.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fcc66e222cf4c719fe7722a403888b1f5e1682d1679bd780e2b26c18bb648cdc"}, - {file = "coverage-7.4.3-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b3ec74cfef2d985e145baae90d9b1b32f85e1741b04cd967aaf9cfa84c1334f3"}, - {file = "coverage-7.4.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:abbbd8093c5229c72d4c2926afaee0e6e3140de69d5dcd918b2921f2f0c8baba"}, - {file = "coverage-7.4.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:35eb581efdacf7b7422af677b92170da4ef34500467381e805944a3201df2079"}, - {file = "coverage-7.4.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:8249b1c7334be8f8c3abcaaa996e1e4927b0e5a23b65f5bf6cfe3180d8ca7840"}, - {file = "coverage-7.4.3-cp311-cp311-win32.whl", hash = "sha256:cf30900aa1ba595312ae41978b95e256e419d8a823af79ce670835409fc02ad3"}, - {file = "coverage-7.4.3-cp311-cp311-win_amd64.whl", hash = "sha256:18c7320695c949de11a351742ee001849912fd57e62a706d83dfc1581897fa2e"}, - {file = "coverage-7.4.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:b51bfc348925e92a9bd9b2e48dad13431b57011fd1038f08316e6bf1df107d10"}, - {file = "coverage-7.4.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d6cdecaedea1ea9e033d8adf6a0ab11107b49571bbb9737175444cea6eb72328"}, - {file = "coverage-7.4.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3b2eccb883368f9e972e216c7b4c7c06cabda925b5f06dde0650281cb7666a30"}, - {file = "coverage-7.4.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6c00cdc8fa4e50e1cc1f941a7f2e3e0f26cb2a1233c9696f26963ff58445bac7"}, - {file = "coverage-7.4.3-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b9a4a8dd3dcf4cbd3165737358e4d7dfbd9d59902ad11e3b15eebb6393b0446e"}, - {file = "coverage-7.4.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:062b0a75d9261e2f9c6d071753f7eef0fc9caf3a2c82d36d76667ba7b6470003"}, - {file = "coverage-7.4.3-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:ebe7c9e67a2d15fa97b77ea6571ce5e1e1f6b0db71d1d5e96f8d2bf134303c1d"}, - {file = "coverage-7.4.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:c0a120238dd71c68484f02562f6d446d736adcc6ca0993712289b102705a9a3a"}, - {file = "coverage-7.4.3-cp312-cp312-win32.whl", hash = "sha256:37389611ba54fd6d278fde86eb2c013c8e50232e38f5c68235d09d0a3f8aa352"}, - {file = "coverage-7.4.3-cp312-cp312-win_amd64.whl", hash = "sha256:d25b937a5d9ffa857d41be042b4238dd61db888533b53bc76dc082cb5a15e914"}, - {file = "coverage-7.4.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:28ca2098939eabab044ad68850aac8f8db6bf0b29bc7f2887d05889b17346454"}, - {file = "coverage-7.4.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:280459f0a03cecbe8800786cdc23067a8fc64c0bd51dc614008d9c36e1659d7e"}, - {file = "coverage-7.4.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6c0cdedd3500e0511eac1517bf560149764b7d8e65cb800d8bf1c63ebf39edd2"}, - {file = "coverage-7.4.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9a9babb9466fe1da12417a4aed923e90124a534736de6201794a3aea9d98484e"}, - {file = "coverage-7.4.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dec9de46a33cf2dd87a5254af095a409ea3bf952d85ad339751e7de6d962cde6"}, - {file = "coverage-7.4.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:16bae383a9cc5abab9bb05c10a3e5a52e0a788325dc9ba8499e821885928968c"}, - {file = "coverage-7.4.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:2c854ce44e1ee31bda4e318af1dbcfc929026d12c5ed030095ad98197eeeaed0"}, - {file = "coverage-7.4.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:ce8c50520f57ec57aa21a63ea4f325c7b657386b3f02ccaedeccf9ebe27686e1"}, - {file = "coverage-7.4.3-cp38-cp38-win32.whl", hash = "sha256:708a3369dcf055c00ddeeaa2b20f0dd1ce664eeabde6623e516c5228b753654f"}, - {file = "coverage-7.4.3-cp38-cp38-win_amd64.whl", hash = "sha256:1bf25fbca0c8d121a3e92a2a0555c7e5bc981aee5c3fdaf4bb7809f410f696b9"}, - {file = "coverage-7.4.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3b253094dbe1b431d3a4ac2f053b6d7ede2664ac559705a704f621742e034f1f"}, - {file = "coverage-7.4.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:77fbfc5720cceac9c200054b9fab50cb2a7d79660609200ab83f5db96162d20c"}, - {file = "coverage-7.4.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6679060424faa9c11808598504c3ab472de4531c571ab2befa32f4971835788e"}, - {file = "coverage-7.4.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4af154d617c875b52651dd8dd17a31270c495082f3d55f6128e7629658d63765"}, - {file = "coverage-7.4.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8640f1fde5e1b8e3439fe482cdc2b0bb6c329f4bb161927c28d2e8879c6029ee"}, - {file = "coverage-7.4.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:69b9f6f66c0af29642e73a520b6fed25ff9fd69a25975ebe6acb297234eda501"}, - {file = "coverage-7.4.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:0842571634f39016a6c03e9d4aba502be652a6e4455fadb73cd3a3a49173e38f"}, - {file = "coverage-7.4.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a78ed23b08e8ab524551f52953a8a05d61c3a760781762aac49f8de6eede8c45"}, - {file = "coverage-7.4.3-cp39-cp39-win32.whl", hash = "sha256:c0524de3ff096e15fcbfe8f056fdb4ea0bf497d584454f344d59fce069d3e6e9"}, - {file = "coverage-7.4.3-cp39-cp39-win_amd64.whl", hash = "sha256:0209a6369ccce576b43bb227dc8322d8ef9e323d089c6f3f26a597b09cb4d2aa"}, - {file = "coverage-7.4.3-pp38.pp39.pp310-none-any.whl", hash = "sha256:7cbde573904625509a3f37b6fecea974e363460b556a627c60dc2f47e2fffa51"}, - {file = "coverage-7.4.3.tar.gz", hash = "sha256:276f6077a5c61447a48d133ed13e759c09e62aff0dc84274a68dc18660104d52"}, + {file = "coverage-7.4.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e0be5efd5127542ef31f165de269f77560d6cdef525fffa446de6f7e9186cfb2"}, + {file = "coverage-7.4.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ccd341521be3d1b3daeb41960ae94a5e87abe2f46f17224ba5d6f2b8398016cf"}, + {file = "coverage-7.4.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:09fa497a8ab37784fbb20ab699c246053ac294d13fc7eb40ec007a5043ec91f8"}, + {file = "coverage-7.4.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b1a93009cb80730c9bca5d6d4665494b725b6e8e157c1cb7f2db5b4b122ea562"}, + {file = "coverage-7.4.4-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:690db6517f09336559dc0b5f55342df62370a48f5469fabf502db2c6d1cffcd2"}, + {file = "coverage-7.4.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:09c3255458533cb76ef55da8cc49ffab9e33f083739c8bd4f58e79fecfe288f7"}, + {file = "coverage-7.4.4-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:8ce1415194b4a6bd0cdcc3a1dfbf58b63f910dcb7330fe15bdff542c56949f87"}, + {file = "coverage-7.4.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b91cbc4b195444e7e258ba27ac33769c41b94967919f10037e6355e998af255c"}, + {file = "coverage-7.4.4-cp310-cp310-win32.whl", hash = "sha256:598825b51b81c808cb6f078dcb972f96af96b078faa47af7dfcdf282835baa8d"}, + {file = "coverage-7.4.4-cp310-cp310-win_amd64.whl", hash = "sha256:09ef9199ed6653989ebbcaacc9b62b514bb63ea2f90256e71fea3ed74bd8ff6f"}, + {file = "coverage-7.4.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0f9f50e7ef2a71e2fae92774c99170eb8304e3fdf9c8c3c7ae9bab3e7229c5cf"}, + {file = "coverage-7.4.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:623512f8ba53c422fcfb2ce68362c97945095b864cda94a92edbaf5994201083"}, + {file = "coverage-7.4.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0513b9508b93da4e1716744ef6ebc507aff016ba115ffe8ecff744d1322a7b63"}, + {file = "coverage-7.4.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:40209e141059b9370a2657c9b15607815359ab3ef9918f0196b6fccce8d3230f"}, + {file = "coverage-7.4.4-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8a2b2b78c78293782fd3767d53e6474582f62443d0504b1554370bde86cc8227"}, + {file = "coverage-7.4.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:73bfb9c09951125d06ee473bed216e2c3742f530fc5acc1383883125de76d9cd"}, + {file = "coverage-7.4.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:1f384c3cc76aeedce208643697fb3e8437604b512255de6d18dae3f27655a384"}, + {file = "coverage-7.4.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:54eb8d1bf7cacfbf2a3186019bcf01d11c666bd495ed18717162f7eb1e9dd00b"}, + {file = "coverage-7.4.4-cp311-cp311-win32.whl", hash = "sha256:cac99918c7bba15302a2d81f0312c08054a3359eaa1929c7e4b26ebe41e9b286"}, + {file = "coverage-7.4.4-cp311-cp311-win_amd64.whl", hash = "sha256:b14706df8b2de49869ae03a5ccbc211f4041750cd4a66f698df89d44f4bd30ec"}, + {file = "coverage-7.4.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:201bef2eea65e0e9c56343115ba3814e896afe6d36ffd37bab783261db430f76"}, + {file = "coverage-7.4.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:41c9c5f3de16b903b610d09650e5e27adbfa7f500302718c9ffd1c12cf9d6818"}, + {file = "coverage-7.4.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d898fe162d26929b5960e4e138651f7427048e72c853607f2b200909794ed978"}, + {file = "coverage-7.4.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3ea79bb50e805cd6ac058dfa3b5c8f6c040cb87fe83de10845857f5535d1db70"}, + {file = "coverage-7.4.4-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ce4b94265ca988c3f8e479e741693d143026632672e3ff924f25fab50518dd51"}, + {file = "coverage-7.4.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:00838a35b882694afda09f85e469c96367daa3f3f2b097d846a7216993d37f4c"}, + {file = "coverage-7.4.4-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:fdfafb32984684eb03c2d83e1e51f64f0906b11e64482df3c5db936ce3839d48"}, + {file = "coverage-7.4.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:69eb372f7e2ece89f14751fbcbe470295d73ed41ecd37ca36ed2eb47512a6ab9"}, + {file = "coverage-7.4.4-cp312-cp312-win32.whl", hash = "sha256:137eb07173141545e07403cca94ab625cc1cc6bc4c1e97b6e3846270e7e1fea0"}, + {file = "coverage-7.4.4-cp312-cp312-win_amd64.whl", hash = "sha256:d71eec7d83298f1af3326ce0ff1d0ea83c7cb98f72b577097f9083b20bdaf05e"}, + {file = "coverage-7.4.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d5ae728ff3b5401cc320d792866987e7e7e880e6ebd24433b70a33b643bb0384"}, + {file = "coverage-7.4.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:cc4f1358cb0c78edef3ed237ef2c86056206bb8d9140e73b6b89fbcfcbdd40e1"}, + {file = "coverage-7.4.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8130a2aa2acb8788e0b56938786c33c7c98562697bf9f4c7d6e8e5e3a0501e4a"}, + {file = "coverage-7.4.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cf271892d13e43bc2b51e6908ec9a6a5094a4df1d8af0bfc360088ee6c684409"}, + {file = "coverage-7.4.4-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a4cdc86d54b5da0df6d3d3a2f0b710949286094c3a6700c21e9015932b81447e"}, + {file = "coverage-7.4.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:ae71e7ddb7a413dd60052e90528f2f65270aad4b509563af6d03d53e979feafd"}, + {file = "coverage-7.4.4-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:38dd60d7bf242c4ed5b38e094baf6401faa114fc09e9e6632374388a404f98e7"}, + {file = "coverage-7.4.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:aa5b1c1bfc28384f1f53b69a023d789f72b2e0ab1b3787aae16992a7ca21056c"}, + {file = "coverage-7.4.4-cp38-cp38-win32.whl", hash = "sha256:dfa8fe35a0bb90382837b238fff375de15f0dcdb9ae68ff85f7a63649c98527e"}, + {file = "coverage-7.4.4-cp38-cp38-win_amd64.whl", hash = "sha256:b2991665420a803495e0b90a79233c1433d6ed77ef282e8e152a324bbbc5e0c8"}, + {file = "coverage-7.4.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3b799445b9f7ee8bf299cfaed6f5b226c0037b74886a4e11515e569b36fe310d"}, + {file = "coverage-7.4.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b4d33f418f46362995f1e9d4f3a35a1b6322cb959c31d88ae56b0298e1c22357"}, + {file = "coverage-7.4.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aadacf9a2f407a4688d700e4ebab33a7e2e408f2ca04dbf4aef17585389eff3e"}, + {file = "coverage-7.4.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7c95949560050d04d46b919301826525597f07b33beba6187d04fa64d47ac82e"}, + {file = "coverage-7.4.4-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ff7687ca3d7028d8a5f0ebae95a6e4827c5616b31a4ee1192bdfde697db110d4"}, + {file = "coverage-7.4.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:5fc1de20b2d4a061b3df27ab9b7c7111e9a710f10dc2b84d33a4ab25065994ec"}, + {file = "coverage-7.4.4-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:c74880fc64d4958159fbd537a091d2a585448a8f8508bf248d72112723974cbd"}, + {file = "coverage-7.4.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:742a76a12aa45b44d236815d282b03cfb1de3b4323f3e4ec933acfae08e54ade"}, + {file = "coverage-7.4.4-cp39-cp39-win32.whl", hash = "sha256:d89d7b2974cae412400e88f35d86af72208e1ede1a541954af5d944a8ba46c57"}, + {file = "coverage-7.4.4-cp39-cp39-win_amd64.whl", hash = "sha256:9ca28a302acb19b6af89e90f33ee3e1906961f94b54ea37de6737b7ca9d8827c"}, + {file = "coverage-7.4.4-pp38.pp39.pp310-none-any.whl", hash = "sha256:b2c5edc4ac10a7ef6605a966c58929ec6c1bd0917fb8c15cb3363f65aa40e677"}, + {file = "coverage-7.4.4.tar.gz", hash = "sha256:c901df83d097649e257e803be22592aedfd5182f07b3cc87d640bbb9afd50f49"}, ] [package.extras] @@ -784,17 +784,17 @@ dotenv = ["python-dotenv"] [[package]] name = "flask-caching" -version = "1.11.1" +version = "2.1.0" description = "Adds caching support to Flask applications." optional = false python-versions = ">=3.7" files = [ - {file = "Flask-Caching-1.11.1.tar.gz", hash = "sha256:28af189e97defb9e39b43ebe197b54a58aaee81bdeb759f46d969c26d7aa7810"}, - {file = "Flask_Caching-1.11.1-py3-none-any.whl", hash = "sha256:36592812eec6cba86eca48bcda74eff24bfd6c8eaf6056ca0184474bb78c0dc4"}, + {file = "Flask-Caching-2.1.0.tar.gz", hash = "sha256:b7500c145135836a952e3de3a80881d9654e327a29c852c9265607f5c449235c"}, + {file = "Flask_Caching-2.1.0-py3-none-any.whl", hash = "sha256:f02645a629a8c89800d96dc8f690a574a0d49dcd66c7536badc6d362ba46b716"}, ] [package.dependencies] -cachelib = "*" +cachelib = ">=0.9.0,<0.10.0" Flask = "*" [[package]] @@ -1602,52 +1602,97 @@ gssapi = ["gssapi (>=1.4.1)", "pyasn1 (>=0.1.7)", "pywin32 (>=2.1.8)"] invoke = ["invoke (>=2.0)"] [[package]] -name = "pay_api" -version = "0.0.0" -description = "A short description of the project" +name = "pay-api" +version = "0.1.0" +description = "" optional = false -python-versions = ">=3.12" +python-versions = "^3.12" files = [] develop = false [package.dependencies] -cattrs = "*" -croniter = "*" -cryptography = "*" -dpath = "*" -Flask = "*" -Flask-Caching = "*" -Flask-Cors = "*" -flask-jwt-oidc = "*" -flask-marshmallow = "*" -Flask-Migrate = "*" -Flask-Moment = "*" -Flask-Script = "*" -Flask-SQLAlchemy = "*" +alembic = "1.13.1" +attrs = "23.2.0" +blinker = "1.7.0" +cachelib = "0.9.0" +cachetools = "5.3.3" +cattrs = "23.2.3" +certifi = "2024.2.2" +cffi = "1.16.0" +charset-normalizer = "3.3.2" +click = "8.1.7" +croniter = "2.0.2" +cryptography = "42.0.5" +dpath = "2.1.6" +ecdsa = "0.18.0" +expiringdict = "1.2.2" +flask = "3.0.2" +flask-caching = "2.1.0" +flask-cors = "4.0.0" +flask-jwt-oidc = {git = "https://github.com/thorwolpert/flask-jwt-oidc.git"} +flask-marshmallow = "1.2.0" +flask-migrate = "4.0.7" +flask-moment = "1.0.5" +flask-script = "2.0.6" +flask-sqlalchemy = "3.1.1" +google-api-core = "2.17.1" google-auth = "2.28.1" google-cloud-pubsub = "2.20.0" -gunicorn = "*" +googleapis-common-protos = "1.63.0" +greenlet = "3.0.3" +grpc-google-iam-v1 = "0.13.0" +grpcio = "1.62.1" +grpcio-status = "1.62.1" +gunicorn = "21.2.0" holidays = "0.37" -itsdangerous = "*" -jaeger-client = "*" -Jinja2 = "*" +idna = "3.6" +itsdangerous = "2.1.2" +jaeger-client = "4.8.0" +jinja2 = "3.1.3" jsonschema = "4.17.3" -launchdarkly-server-sdk = "*" -marshmallow-sqlalchemy = "*" -psycopg2-binary = "*" -pyhumps = "*" -python-dotenv = "*" -requests = "*" -sentry-sdk = {version = "*", extras = ["flask"]} -sqlalchemy = "*" -sqlalchemy_utils = "*" -Werkzeug = "*" +launchdarkly-eventsource = "1.1.1" +launchdarkly-server-sdk = "9.2.2" +mako = "1.3.2" +markupsafe = "2.1.5" +marshmallow = "3.21.1" +marshmallow-sqlalchemy = "1.0.0" +opentracing = "2.4.0" +packaging = "24.0" +pg8000 = "^1.30.5" +proto-plus = "1.23.0" +protobuf = "4.25.3" +psycopg2-binary = "2.9.9" +pyasn1 = "0.5.1" +pyasn1-modules = "0.3.0" +pycparser = "2.21" +pyhumps = "3.8.0" +pyrfc3339 = "1.1" +pyrsistent = "0.20.0" +python-dateutil = "2.9.0.post0" +python-dotenv = "1.0.1" +python-jose = "3.3.0" +pytz = "2024.1" +requests = "2.31.0" +rsa = "4.9" +sbc-common-components = {git = "https://github.com/bcgov/sbc-common-components.git", subdirectory = "python"} +semver = "3.0.2" +sentry-sdk = "1.41.0" +simple-cloudevent = {git = "https://github.com/daxiom/simple-cloudevent.py.git"} +six = "1.16.0" +sqlalchemy = "2.0.28" +sqlalchemy-utils = "0.41.1" +threadloop = "1.0.2" +thrift = "0.16.0" +tornado = "6.4" +typing-extensions = "4.10.0" +urllib3 = "2.2.1" +werkzeug = "3.0.1" [package.source] type = "git" -url = "https://github.com/seeker25/sbc-pay.git" -reference = "18263" -resolved_reference = "fe42bf81c86c77946a1df238f69f12ad6b83d804" +url = "https://github.com/Jxio/sbc-pay.git" +reference = "19875" +resolved_reference = "62ceadd6e60f53cd8cf3781b5e2f6b99c968c6bf" subdirectory = "pay-api" [[package]] @@ -2334,20 +2379,17 @@ files = [ [[package]] name = "sentry-sdk" -version = "1.42.0" +version = "1.41.0" description = "Python client for Sentry (https://sentry.io)" optional = false python-versions = "*" files = [ - {file = "sentry-sdk-1.42.0.tar.gz", hash = "sha256:4a8364b8f7edbf47f95f7163e48334c96100d9c098f0ae6606e2e18183c223e6"}, - {file = "sentry_sdk-1.42.0-py2.py3-none-any.whl", hash = "sha256:a654ee7e497a3f5f6368b36d4f04baeab1fe92b3105f7f6965d6ef0de35a9ba4"}, + {file = "sentry-sdk-1.41.0.tar.gz", hash = "sha256:4f2d6c43c07925d8cd10dfbd0970ea7cb784f70e79523cca9dbcd72df38e5a46"}, + {file = "sentry_sdk-1.41.0-py2.py3-none-any.whl", hash = "sha256:be4f8f4b29a80b6a3b71f0f31487beb9e296391da20af8504498a328befed53f"}, ] [package.dependencies] -blinker = {version = ">=1.1", optional = true, markers = "extra == \"flask\""} certifi = "*" -flask = {version = ">=0.11", optional = true, markers = "extra == \"flask\""} -markupsafe = {version = "*", optional = true, markers = "extra == \"flask\""} urllib3 = {version = ">=1.26.11", markers = "python_version >= \"3.6\""} [package.extras] @@ -2367,7 +2409,6 @@ grpcio = ["grpcio (>=1.21.1)"] httpx = ["httpx (>=0.16.0)"] huey = ["huey (>=2)"] loguru = ["loguru (>=0.5)"] -openai = ["openai (>=1.0.0)", "tiktoken (>=0.3.0)"] opentelemetry = ["opentelemetry-distro (>=0.35b0)"] opentelemetry-experimental = ["opentelemetry-distro (>=0.40b0,<1.0)", "opentelemetry-instrumentation-aiohttp-client (>=0.40b0,<1.0)", "opentelemetry-instrumentation-django (>=0.40b0,<1.0)", "opentelemetry-instrumentation-fastapi (>=0.40b0,<1.0)", "opentelemetry-instrumentation-flask (>=0.40b0,<1.0)", "opentelemetry-instrumentation-requests (>=0.40b0,<1.0)", "opentelemetry-instrumentation-sqlite3 (>=0.40b0,<1.0)", "opentelemetry-instrumentation-urllib (>=0.40b0,<1.0)"] pure-eval = ["asttokens", "executing", "pure-eval"] @@ -2673,4 +2714,4 @@ watchdog = ["watchdog (>=2.3)"] [metadata] lock-version = "2.0" python-versions = "^3.12" -content-hash = "350c3fdfde2b9ef2aa795334a051e997a91eddd0e155897b958fd7f60492f4a5" +content-hash = "3f2c4e7b54827174e4fc8d638c5b3079df2f456376983184edef0fbfe91c5e9a" diff --git a/jobs/payment-jobs/pyproject.toml b/jobs/payment-jobs/pyproject.toml index a7f42bb90..dab1071b0 100644 --- a/jobs/payment-jobs/pyproject.toml +++ b/jobs/payment-jobs/pyproject.toml @@ -8,7 +8,7 @@ readme = "README.md" [tool.poetry.dependencies] python = "^3.12" sbc-common-components = {git = "https://github.com/bcgov/sbc-common-components.git", subdirectory = "python"} -pay-api = {git = "https://github.com/seeker25/sbc-pay.git", rev = "18263", subdirectory = "pay-api"} +pay-api = {git = "https://github.com/Jxio/sbc-pay.git", rev = "19875", subdirectory = "pay-api"} flask-jwt-oidc = {git = "https://github.com/thorwolpert/flask-jwt-oidc.git"} simple-cloudevent = {git = "https://github.com/daxiom/simple-cloudevent.py.git"} gunicorn = "^21.2.0" diff --git a/jobs/payment-jobs/tasks/ap_task.py b/jobs/payment-jobs/tasks/ap_task.py index 6506e8fab..0633a8c3b 100644 --- a/jobs/payment-jobs/tasks/ap_task.py +++ b/jobs/payment-jobs/tasks/ap_task.py @@ -23,12 +23,12 @@ from pay_api.models import DistributionCode as DistributionCodeModel from pay_api.models import EjvFile as EjvFileModel from pay_api.models import EjvHeader as EjvHeaderModel -from pay_api.models import EjvInvoiceLink as EjvInvoiceLinkModel +from pay_api.models import EjvLink as EjvLinkModel from pay_api.models import Invoice as InvoiceModel from pay_api.models import Refund as RefundModel from pay_api.models import RoutingSlip as RoutingSlipModel from pay_api.models import db -from pay_api.utils.enums import DisbursementStatus, EjvFileType, RoutingSlipStatus +from pay_api.utils.enums import DisbursementStatus, EjvFileType, EJVLinkType, RoutingSlipStatus from tasks.common.cgi_ap import CgiAP from tasks.common.dataclasses import APLine from tasks.ejv_partner_distribution_task import EjvPartnerDistributionTask @@ -156,9 +156,10 @@ def _create_non_gov_disbursement_file(cls): # pylint:disable=too-many-locals ap_content = f'{ap_content}{batch_trailer}' for inv in invoices: - db.session.add(EjvInvoiceLinkModel(invoice_id=inv.id, - ejv_header_id=ejv_header_model.id, - disbursement_status_code=DisbursementStatus.UPLOADED.value)) + db.session.add(EjvLinkModel(link_id=inv.id, + link_type=EJVLinkType.INVOICE.value, + ejv_header_id=ejv_header_model.id, + disbursement_status_code=DisbursementStatus.UPLOADED.value)) inv.disbursement_status_code = DisbursementStatus.UPLOADED.value db.session.flush() diff --git a/jobs/payment-jobs/tasks/eft_transfer_task.py b/jobs/payment-jobs/tasks/eft_transfer_task.py index d6f9bdfe9..c43bd7412 100644 --- a/jobs/payment-jobs/tasks/eft_transfer_task.py +++ b/jobs/payment-jobs/tasks/eft_transfer_task.py @@ -23,13 +23,14 @@ from pay_api.models import EFTShortnames as EFTShortnameModel from pay_api.models import EjvFile as EjvFileModel from pay_api.models import EjvHeader as EjvHeaderModel -from pay_api.models import EjvInvoiceLink as EjvInvoiceLinkModel +from pay_api.models import EjvLink as EjvLinkModel from pay_api.models import Invoice as InvoiceModel from pay_api.models import PaymentAccount as PaymentAccountModel from pay_api.models import PaymentLineItem as PaymentLineItemModel from pay_api.models import db from pay_api.services.flags import flags -from pay_api.utils.enums import DisbursementStatus, EFTGlTransferType, EjvFileType, InvoiceStatus, PaymentMethod +from pay_api.utils.enums import ( + DisbursementStatus, EFTGlTransferType, EjvFileType, EJVLinkType, InvoiceStatus, PaymentMethod) from sqlalchemy import exists, func from tasks.common.cgi_ejv import CgiEjv @@ -173,9 +174,10 @@ def process_invoice_ejv_links(invoices: List[InvoiceModel], ejv_header_model_id: for inv in invoices: current_app.logger.debug(f'Creating EJV Invoice Link for invoice id: {inv.id}') # Create Ejv file link and flush - ejv_invoice_link = EjvInvoiceLinkModel(invoice_id=inv.id, ejv_header_id=ejv_header_model_id, - disbursement_status_code=DisbursementStatus.UPLOADED.value, - sequence=sequence) + ejv_invoice_link = EjvLinkModel(link_id=inv.id, link_type=EJVLinkType.INVOICE.value, + ejv_header_id=ejv_header_model_id, + disbursement_status_code=DisbursementStatus.UPLOADED.value, + sequence=sequence) db.session.add(ejv_invoice_link) sequence += 1 diff --git a/jobs/payment-jobs/tasks/ejv_partner_distribution_task.py b/jobs/payment-jobs/tasks/ejv_partner_distribution_task.py index cdb0421b5..0ec8b13c1 100644 --- a/jobs/payment-jobs/tasks/ejv_partner_distribution_task.py +++ b/jobs/payment-jobs/tasks/ejv_partner_distribution_task.py @@ -23,13 +23,14 @@ from pay_api.models import DistributionCodeLink as DistributionCodeLinkModel from pay_api.models import EjvFile as EjvFileModel from pay_api.models import EjvHeader as EjvHeaderModel -from pay_api.models import EjvInvoiceLink as EjvInvoiceLinkModel +from pay_api.models import EjvLink as EjvLinkModel from pay_api.models import FeeSchedule as FeeScheduleModel from pay_api.models import Invoice as InvoiceModel from pay_api.models import PaymentLineItem as PaymentLineItemModel +from pay_api.models import RefundsPartial as RefundsPartialModel from pay_api.models import Receipt as ReceiptModel from pay_api.models import db -from pay_api.utils.enums import DisbursementStatus, EjvFileType, InvoiceStatus, PaymentMethod +from pay_api.utils.enums import DisbursementStatus, EjvFileType, EJVLinkType, InvoiceStatus, PaymentMethod from sqlalchemy import Date, cast from tasks.common.cgi_ejv import CgiEjv @@ -68,6 +69,21 @@ def get_invoices_for_disbursement(partner): current_app.logger.info(invoices) return invoices + @staticmethod + def get_refund_partial_payment_line_items_for_disbursement(partner) -> List[PaymentLineItemModel]: + """Return payment line items with partial refunds for disbursement.""" + payment_line_items: List[PaymentLineItemModel] = db.session.query(PaymentLineItemModel) \ + .join(InvoiceModel, PaymentLineItemModel.invoice_id == InvoiceModel.id) \ + .join(RefundsPartialModel, PaymentLineItemModel.id == RefundsPartialModel.payment_line_item_id) \ + .filter(InvoiceModel.invoice_status_code == InvoiceStatus.PAID.value) \ + .filter(InvoiceModel.payment_method_code.in_([PaymentMethod.DIRECT_PAY.value])) \ + .filter((RefundsPartialModel.disbursement_status_code.is_(None)) | + (RefundsPartialModel.disbursement_status_code == DisbursementStatus.ERRORED.value)) \ + .filter(InvoiceModel.corp_type_code == partner.code) \ + .all() + current_app.logger.info(payment_line_items) + return payment_line_items + @classmethod def get_invoices_for_refund_reversal(cls, partner): """Return invoices for refund reversal.""" @@ -113,12 +129,16 @@ def _create_ejv_file_for_partner(cls, batch_type: str): # pylint:disable=too-ma for partner in partners: # Find all invoices for the partner to disburse. - # This includes invoices which are not PAID and invoices which are refunded. + # This includes invoices which are not PAID and invoices which are refunded and partial refunded. payment_invoices = cls.get_invoices_for_disbursement(partner) refund_reversals = cls.get_invoices_for_refund_reversal(partner) invoices = payment_invoices + refund_reversals + + # Process partial refunds for each partner + refund_partial_items = cls.get_refund_partial_payment_line_items_for_disbursement(partner) + # If no invoices continue. - if not invoices: + if not invoices and not refund_partial_items: continue effective_date: str = cls.get_effective_date() @@ -134,11 +154,16 @@ def _create_ejv_file_for_partner(cls, batch_type: str): # pylint:disable=too-ma # and create one JV Header and detail for each. distribution_code_set = set() invoice_id_list = [] + partial_line_item_id_list = [] for inv in invoices: invoice_id_list.append(inv.id) for line_item in inv.payment_line_items: distribution_code_set.add(line_item.fee_distribution_id) + for line_item in refund_partial_items: + partial_line_item_id_list.append(line_item.id) + distribution_code_set.add(line_item.fee_distribution_id) + for distribution_code_id in list(distribution_code_set): distribution_code: DistributionCodeModel = DistributionCodeModel.find_by_id(distribution_code_id) credit_distribution_code: DistributionCodeModel = DistributionCodeModel.find_by_id( @@ -147,13 +172,22 @@ def _create_ejv_file_for_partner(cls, batch_type: str): # pylint:disable=too-ma if credit_distribution_code.stop_ejv: continue - line_items = cls._find_line_items_by_invoice_and_distribution(distribution_code_id, invoice_id_list) + line_items = cls._find_line_items_by_invoice_and_distribution( + distribution_code_id, invoice_id_list) + + refund_partial_items = cls._find_refund_partial_items_by_distribution( + distribution_code_id, partial_line_item_id_list) total: float = 0 for line in line_items: total += line.total + partial_refund_total: float = 0 + for refund_partial in refund_partial_items: + partial_refund_total += refund_partial.refund_amount + batch_total += total + batch_total += partial_refund_total debit_distribution = cls.get_distribution_string(distribution_code) # Debit from BCREG GL credit_distribution = cls.get_distribution_string(credit_distribution_code) # Credit to partner GL @@ -193,20 +227,39 @@ def _create_ejv_file_for_partner(cls, batch_type: str): # pylint:disable=too-ma control_total += 1 + partial_refund_number: int = 0 + for refund_partial in refund_partial_items: + # JV Details for partial refunds + partial_refund_number += 1 + # Flow Through add it as the refunds_partial id. + flow_through = f'{refund_partial.id:<110}' + refund_partial_number = f'#{refund_partial.id}' + description = disbursement_desc[:-len(refund_partial_number)] + refund_partial_number + description = f'{description[:100]:<100}' + + ejv_content = '{}{}'.format(ejv_content, # pylint:disable=consider-using-f-string + cls.get_jv_line(batch_type, credit_distribution, description, + effective_date, flow_through, journal_name, + refund_partial.refund_amount, + partial_refund_number, 'D')) + partial_refund_number += 1 + control_total += 1 + + # Add a line here for debit too + ejv_content = '{}{}'.format(ejv_content, # pylint:disable=consider-using-f-string + cls.get_jv_line(batch_type, debit_distribution, description, + effective_date, flow_through, journal_name, + refund_partial.refund_amount, + partial_refund_number, 'C')) + control_total += 1 + + # Update partial refund status + refund_partial.disbursement_status_code = DisbursementStatus.UPLOADED.value + + # Create ejv invoice/partial_refund link records and set invoice status sequence = 1 - # Create ejv invoice link records and set invoice status - for inv in invoices: - # Create Ejv file link and flush - link_model = EjvInvoiceLinkModel(invoice_id=inv.id, - ejv_header_id=ejv_header_model.id, - disbursement_status_code=DisbursementStatus.UPLOADED.value, - sequence=sequence) - # Set distribution status to invoice - db.session.add(link_model) - sequence += 1 - inv.disbursement_status_code = DisbursementStatus.UPLOADED.value - - db.session.flush() + sequence = cls._create_ejv_link(invoices, ejv_header_model, sequence, EJVLinkType.INVOICE.value) + cls._create_ejv_link(refund_partial_items, ejv_header_model, sequence, EJVLinkType.REFUND.value) if not ejv_content: db.session.rollback() @@ -238,6 +291,18 @@ def _find_line_items_by_invoice_and_distribution(cls, distribution_code_id, invo .filter(PaymentLineItemModel.fee_distribution_id == distribution_code_id) return line_items + @classmethod + def _find_refund_partial_items_by_distribution(cls, distribution_code_id, partial_line_item_id_list) \ + -> List[RefundsPartialModel]: + """Find and return all payment line items for this distribution.""" + line_items: List[RefundsPartialModel] = db.session.query(RefundsPartialModel) \ + .join(PaymentLineItemModel, PaymentLineItemModel.id == RefundsPartialModel.payment_line_item_id) \ + .filter(RefundsPartialModel.payment_line_item_id.in_(partial_line_item_id_list)) \ + .filter(RefundsPartialModel.refund_amount > 0) \ + .filter(PaymentLineItemModel.fee_distribution_id == distribution_code_id) \ + .all() + return line_items + @classmethod def _get_partners_by_batch_type(cls, batch_type) -> List[CorpTypeModel]: """Return partners by batch type.""" @@ -272,3 +337,17 @@ def _get_partners_by_batch_type(cls, batch_type) -> List[CorpTypeModel]: corp_type_codes: List[str] = db.session.scalars(corp_type_query).all() return db.session.query(CorpTypeModel).filter(CorpTypeModel.code.in_(corp_type_codes)).all() + + @classmethod + def _create_ejv_link(cls, items, ejv_header_model, sequence, link_type): + for item in items: + link_model = EjvLinkModel(link_id=item.id, + link_type=link_type, + ejv_header_id=ejv_header_model.id, + disbursement_status_code=DisbursementStatus.UPLOADED.value, + sequence=sequence) + db.session.add(link_model) + sequence += 1 + item.disbursement_status_code = DisbursementStatus.UPLOADED.value + db.session.flush() + return sequence diff --git a/jobs/payment-jobs/tasks/ejv_payment_task.py b/jobs/payment-jobs/tasks/ejv_payment_task.py index d53d2143b..22ae8a172 100644 --- a/jobs/payment-jobs/tasks/ejv_payment_task.py +++ b/jobs/payment-jobs/tasks/ejv_payment_task.py @@ -20,12 +20,13 @@ from pay_api.models import DistributionCode as DistributionCodeModel from pay_api.models import EjvFile as EjvFileModel from pay_api.models import EjvHeader as EjvHeaderModel -from pay_api.models import EjvInvoiceLink as EjvInvoiceLinkModel +from pay_api.models import EjvLink as EjvLinkModel from pay_api.models import Invoice as InvoiceModel from pay_api.models import InvoiceReference as InvoiceReferenceModel from pay_api.models import PaymentAccount as PaymentAccountModel from pay_api.models import db -from pay_api.utils.enums import DisbursementStatus, EjvFileType, InvoiceReferenceStatus, InvoiceStatus, PaymentMethod +from pay_api.utils.enums import ( + DisbursementStatus, EjvFileType, EJVLinkType, InvoiceReferenceStatus, InvoiceStatus, PaymentMethod) from pay_api.utils.util import generate_transaction_number from tasks.common.cgi_ejv import CgiEjv @@ -180,10 +181,10 @@ def _create_ejv_file_for_gov_account(cls, batch_type: str): # pylint:disable=to sequence = 1 for inv in invoices: current_app.logger.debug(f'Creating EJV Invoice Link for invoice id: {inv.id}') - # Create Ejv file link and flush - ejv_invoice_link = EjvInvoiceLinkModel(invoice_id=inv.id, ejv_header_id=ejv_header_model.id, - disbursement_status_code=DisbursementStatus.UPLOADED.value, - sequence=sequence) + ejv_invoice_link = EjvLinkModel(link_id=inv.id, link_type=EJVLinkType.INVOICE.value, + ejv_header_id=ejv_header_model.id, + disbursement_status_code=DisbursementStatus.UPLOADED.value, + sequence=sequence) db.session.add(ejv_invoice_link) sequence += 1 # Set distribution status to invoice diff --git a/jobs/payment-jobs/tests/jobs/factory.py b/jobs/payment-jobs/tests/jobs/factory.py index c91a69a30..6bf6fab04 100644 --- a/jobs/payment-jobs/tests/jobs/factory.py +++ b/jobs/payment-jobs/tests/jobs/factory.py @@ -21,7 +21,8 @@ from pay_api.models import ( CfsAccount, DistributionCode, DistributionCodeLink, EFTShortnames, Invoice, InvoiceReference, Payment, - PaymentAccount, PaymentLineItem, Receipt, Refund, RoutingSlip, StatementRecipients, StatementSettings) + PaymentAccount, PaymentLineItem, Receipt, Refund, RefundsPartial, RoutingSlip, StatementRecipients, + StatementSettings) from pay_api.utils.enums import ( CfsAccountStatus, InvoiceReferenceStatus, InvoiceStatus, LineItemStatus, PaymentMethod, PaymentStatus, PaymentSystem, RoutingSlipStatus) @@ -334,3 +335,20 @@ def factory_refund_invoice( requested_by='TEST', details=details ).save() + + +def factory_refund_partial( + payment_line_item_id: int, + refund_amount: float, + refund_type: str, + created_by='test', + created_on: datetime = datetime.now() +): + """Return Factory.""" + return RefundsPartial( + payment_line_item_id=payment_line_item_id, + refund_amount=refund_amount, + refund_type=refund_type, + created_by=created_by, + created_on=created_on + ).save() diff --git a/jobs/payment-jobs/tests/jobs/test_eft_transfer_task.py b/jobs/payment-jobs/tests/jobs/test_eft_transfer_task.py index 0cd14d431..27aaf3256 100644 --- a/jobs/payment-jobs/tests/jobs/test_eft_transfer_task.py +++ b/jobs/payment-jobs/tests/jobs/test_eft_transfer_task.py @@ -19,7 +19,7 @@ from datetime import datetime from typing import List -from pay_api.models import DistributionCode, EFTGLTransfer, EjvFile, EjvHeader, EjvInvoiceLink, FeeSchedule, Invoice, db +from pay_api.models import DistributionCode, EFTGLTransfer, EjvFile, EjvHeader, EjvLink, FeeSchedule, Invoice, db from pay_api.utils.enums import DisbursementStatus, EFTGlTransferType, EjvFileType, InvoiceStatus, PaymentMethod from tasks.eft_transfer_task import EftTransferTask @@ -89,8 +89,8 @@ def test_eft_transfer(app, session, monkeypatch): # Lookup invoice and assert disbursement status for invoice in invoices: - ejv_inv_link: EjvInvoiceLink = db.session.query(EjvInvoiceLink) \ - .filter(EjvInvoiceLink.invoice_id == invoice.id).first() + ejv_inv_link: EjvLink = db.session.query(EjvLink) \ + .filter(EjvLink.link_id == invoice.id).first() assert ejv_inv_link ejv_header = db.session.query(EjvHeader).filter(EjvHeader.id == ejv_inv_link.ejv_header_id).first() diff --git a/jobs/payment-jobs/tests/jobs/test_ejv_partner_distribution_task.py b/jobs/payment-jobs/tests/jobs/test_ejv_partner_distribution_task.py index 7dac7cd3a..8d1191db6 100644 --- a/jobs/payment-jobs/tests/jobs/test_ejv_partner_distribution_task.py +++ b/jobs/payment-jobs/tests/jobs/test_ejv_partner_distribution_task.py @@ -22,7 +22,7 @@ from flask import current_app from freezegun import freeze_time from pay_api.models import CorpType as CorpTypeModel -from pay_api.models import DistributionCode, EjvFile, EjvHeader, EjvInvoiceLink, FeeSchedule, Invoice, db +from pay_api.models import DistributionCode, EjvFile, EjvHeader, EjvLink, FeeSchedule, Invoice, db from pay_api.utils.enums import CfsAccountStatus, DisbursementStatus, InvoiceStatus, PaymentMethod from tasks.ejv_partner_distribution_task import EjvPartnerDistributionTask @@ -89,7 +89,7 @@ def test_disbursement_for_partners(session, monkeypatch, client_code, batch_type invoice = Invoice.find_by_id(invoice.id) assert invoice.disbursement_status_code == DisbursementStatus.UPLOADED.value - ejv_inv_link = db.session.query(EjvInvoiceLink).filter(EjvInvoiceLink.invoice_id == invoice.id).first() + ejv_inv_link = db.session.query(EjvLink).filter(EjvLink.link_id == invoice.id).first() assert ejv_inv_link ejv_header = db.session.query(EjvHeader).filter(EjvHeader.id == ejv_inv_link.ejv_header_id).first() diff --git a/jobs/payment-jobs/tests/jobs/test_ejv_partner_partial_refund_distribution_task.py b/jobs/payment-jobs/tests/jobs/test_ejv_partner_partial_refund_distribution_task.py new file mode 100644 index 000000000..7ab4cce30 --- /dev/null +++ b/jobs/payment-jobs/tests/jobs/test_ejv_partner_partial_refund_distribution_task.py @@ -0,0 +1,86 @@ +# Copyright © 2019 Province of British Columbia +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Tests to assure the CGI EJV Job. + +Test-Suite to ensure that the CgiEjvJob is working as expected. +""" +from datetime import datetime, timedelta + +from flask import current_app +from freezegun import freeze_time +from pay_api.models import CorpType as CorpTypeModel +from pay_api.models import DistributionCode, EjvFile, EjvHeader, EjvLink, FeeSchedule, db +from pay_api.utils.enums import DisbursementStatus, RefundsPartialType + +from tasks.ejv_partner_distribution_task import EjvPartnerDistributionTask + +from .factory import ( + factory_create_direct_pay_account, factory_distribution, factory_distribution_link, factory_invoice, + factory_invoice_reference, factory_payment, factory_payment_line_item, factory_refund_partial) + + +def test_partial_refund_disbursement(session, monkeypatch): + """Test partial refund disbursement.""" + monkeypatch.setattr('pysftp.Connection.put', lambda *args, **kwargs: None) + corp_type: CorpTypeModel = CorpTypeModel.find_by_code('VS') + + pay_account = factory_create_direct_pay_account() + + disbursement_distribution: DistributionCode = factory_distribution(name='VS Disbursement', client='112') + service_fee_distribution: DistributionCode = factory_distribution(name='VS Service Fee', client='112') + fee_distribution: DistributionCode = factory_distribution( + name='VS Fee distribution', client='112', service_fee_dist_id=service_fee_distribution.distribution_code_id, + disbursement_dist_id=disbursement_distribution.distribution_code_id + ) + fee_schedule: FeeSchedule = FeeSchedule.find_by_filing_type_and_corp_type(corp_type.code, 'WILLNOTICE') + factory_distribution_link(fee_distribution.distribution_code_id, fee_schedule.fee_schedule_id) + + invoice = factory_invoice(payment_account=pay_account, disbursement_status_code=DisbursementStatus.COMPLETED.value, + corp_type_code=corp_type.code, total=21.5, status_code='PAID') + pli = factory_payment_line_item(invoice_id=invoice.id, fee_schedule_id=fee_schedule.fee_schedule_id, + filing_fees=0, total=1.5, service_fees=1.5, + fee_dist_id=fee_distribution.distribution_code_id) + + inv_ref = factory_invoice_reference(invoice_id=invoice.id) + factory_payment(invoice_number=inv_ref.invoice_number, payment_status_code='COMPLETED') + + refund_partial = factory_refund_partial(pli.id, refund_amount=1.5, created_by='test', + refund_type=RefundsPartialType.SERVICE_FEES.value) + + assert refund_partial.disbursement_status_code is None + # Lookup refund_partial_link + refund_partial_link = EjvLink.find_ejv_link_by_link_id(refund_partial.id) + assert refund_partial_link is None + + day_after_time_delay = datetime.today() + timedelta(days=( + current_app.config.get('DISBURSEMENT_DELAY_IN_DAYS') + 1)) + + with freeze_time(day_after_time_delay): + EjvPartnerDistributionTask.create_ejv_file() + + ejv_link = db.session.query(EjvLink).filter(EjvLink.link_id == refund_partial.id).first() + assert ejv_link + + ejv_header = db.session.query(EjvHeader).filter(EjvHeader.id == ejv_link.ejv_header_id).first() + assert ejv_header.disbursement_status_code == DisbursementStatus.UPLOADED.value + assert ejv_header + + ejv_file = EjvFile.find_by_id(ejv_header.ejv_file_id) + assert ejv_file + assert ejv_file.disbursement_status_code == DisbursementStatus.UPLOADED.value + + refund_partial_link = EjvLink.find_ejv_link_by_link_id(refund_partial.id) + assert refund_partial_link.disbursement_status_code == DisbursementStatus.UPLOADED.value + assert refund_partial.disbursement_status_code == DisbursementStatus.UPLOADED.value diff --git a/jobs/payment-jobs/tests/jobs/test_ejv_payment_task.py b/jobs/payment-jobs/tests/jobs/test_ejv_payment_task.py index 5eae96032..9c1a67363 100644 --- a/jobs/payment-jobs/tests/jobs/test_ejv_payment_task.py +++ b/jobs/payment-jobs/tests/jobs/test_ejv_payment_task.py @@ -16,8 +16,7 @@ Test-Suite to ensure that the CgiEjvJob is working as expected. """ -from pay_api.models import ( - DistributionCode, EjvFile, EjvHeader, EjvInvoiceLink, FeeSchedule, Invoice, InvoiceReference, db) +from pay_api.models import DistributionCode, EjvFile, EjvHeader, EjvLink, FeeSchedule, Invoice, InvoiceReference, db from pay_api.utils.enums import DisbursementStatus, EjvFileType, InvoiceReferenceStatus, InvoiceStatus from tasks.ejv_payment_task import EjvPaymentTask @@ -87,8 +86,8 @@ def test_payments_for_gov_accounts(session, monkeypatch): InvoiceReferenceStatus.ACTIVE.value) assert invoice_ref - ejv_inv_link: EjvInvoiceLink = db.session.query(EjvInvoiceLink)\ - .filter(EjvInvoiceLink.invoice_id == inv_id).first() + ejv_inv_link: EjvLink = db.session.query(EjvLink)\ + .filter(EjvLink.link_id == inv_id).first() assert ejv_inv_link ejv_header = db.session.query(EjvHeader).filter(EjvHeader.id == ejv_inv_link.ejv_header_id).first() @@ -127,8 +126,8 @@ def test_payments_for_gov_accounts(session, monkeypatch): InvoiceReferenceStatus.ACTIVE.value) assert invoice_ref - ejv_inv_link = db.session.query(EjvInvoiceLink).filter(EjvInvoiceLink.invoice_id == inv_id)\ - .filter(EjvInvoiceLink.disbursement_status_code == DisbursementStatus.UPLOADED.value).first() + ejv_inv_link = db.session.query(EjvLink).filter(EjvLink.link_id == inv_id)\ + .filter(EjvLink.disbursement_status_code == DisbursementStatus.UPLOADED.value).first() assert ejv_inv_link ejv_header = db.session.query(EjvHeader).filter(EjvHeader.id == ejv_inv_link.ejv_header_id).first() diff --git a/pay-api/migrations/versions/2024_03_06_04b8a7bed74e_ejv_link_generic.py b/pay-api/migrations/versions/2024_03_06_04b8a7bed74e_ejv_link_generic.py new file mode 100644 index 000000000..eca30695c --- /dev/null +++ b/pay-api/migrations/versions/2024_03_06_04b8a7bed74e_ejv_link_generic.py @@ -0,0 +1,39 @@ +"""Rename ejv_invoice_links to ejv_links, alter invoice_id to link_id, removed foreign constraint, and added link_type column + +Revision ID: 04b8a7bed74e +Revises: bacb2b859d78 +Create Date: 2024-03-06 11:40:00.153387 + +""" +from alembic import op +import sqlalchemy as sa + +from pay_api.utils.enums import EJVLinkType + +# revision identifiers, used by Alembic. +revision = '04b8a7bed74e' +down_revision = 'bacb2b859d78' +branch_labels = None +depends_on = None + + +def upgrade(): + op.add_column('ejv_invoice_links', sa.Column('link_type', sa.String(length=20), nullable=True)) + op.drop_constraint('ejv_invoice_links_invoice_id_fkey', 'ejv_invoice_links', type_='foreignkey') + op.drop_index(op.f('ix_ejv_invoice_links_invoice_id'), table_name='ejv_invoice_links') + op.alter_column('ejv_invoice_links', 'invoice_id', new_column_name='link_id', + existing_type=sa.Integer(), nullable=True) + op.rename_table('ejv_invoice_links', 'ejv_links') + # as there is no data for partial refunds yet. + op.execute(f"UPDATE ejv_links set link_type='{EJVLinkType.INVOICE.value}'") + + op.create_index('ix_ejv_links_link_type_link_id', 'ejv_links', ['link_type', 'link_id'], unique=False) + +def downgrade(): + op.drop_index('ix_ejv_links_link_type_link_id', table_name='ejv_links') + op.rename_table('ejv_links', 'ejv_invoice_links') + op.alter_column('ejv_invoice_links', 'link_id', new_column_name='invoice_id', + existing_type=sa.Integer(), nullable=False) + op.create_index(op.f('ix_ejv_invoice_links_invoice_id'), 'ejv_invoice_links', ['invoice_id'], unique=False) + op.drop_column('ejv_invoice_links', 'link_type') + op.create_foreign_key('ejv_invoice_links_invoice_id_fkey', 'ejv_invoice_links', 'invoices', ['invoice_id'], ['id']) diff --git a/pay-api/poetry.lock b/pay-api/poetry.lock index 0a825ea22..adadbd2c3 100644 --- a/pay-api/poetry.lock +++ b/pay-api/poetry.lock @@ -62,17 +62,17 @@ tests-no-zope = ["attrs[tests-mypy]", "cloudpickle", "hypothesis", "pympler", "p [[package]] name = "autopep8" -version = "2.0.4" +version = "2.1.0" description = "A tool that automatically formats Python code to conform to the PEP 8 style guide" optional = false -python-versions = ">=3.6" +python-versions = ">=3.8" files = [ - {file = "autopep8-2.0.4-py2.py3-none-any.whl", hash = "sha256:067959ca4a07b24dbd5345efa8325f5f58da4298dab0dde0443d5ed765de80cb"}, - {file = "autopep8-2.0.4.tar.gz", hash = "sha256:2913064abd97b3419d1cc83ea71f042cb821f87e45b9c88cad5ad3c4ea87fe0c"}, + {file = "autopep8-2.1.0-py2.py3-none-any.whl", hash = "sha256:2bb76888c5edbcafe6aabab3c47ba534f5a2c2d245c2eddced4a30c4b4946357"}, + {file = "autopep8-2.1.0.tar.gz", hash = "sha256:1fa8964e4618929488f4ec36795c7ff12924a68b8bf01366c094fc52f770b6e7"}, ] [package.dependencies] -pycodestyle = ">=2.10.0" +pycodestyle = ">=2.11.0" [[package]] name = "blinker" @@ -331,63 +331,63 @@ files = [ [[package]] name = "coverage" -version = "7.4.3" +version = "7.4.4" description = "Code coverage measurement for Python" optional = false python-versions = ">=3.8" files = [ - {file = "coverage-7.4.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:8580b827d4746d47294c0e0b92854c85a92c2227927433998f0d3320ae8a71b6"}, - {file = "coverage-7.4.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:718187eeb9849fc6cc23e0d9b092bc2348821c5e1a901c9f8975df0bc785bfd4"}, - {file = "coverage-7.4.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:767b35c3a246bcb55b8044fd3a43b8cd553dd1f9f2c1eeb87a302b1f8daa0524"}, - {file = "coverage-7.4.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ae7f19afe0cce50039e2c782bff379c7e347cba335429678450b8fe81c4ef96d"}, - {file = "coverage-7.4.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba3a8aaed13770e970b3df46980cb068d1c24af1a1968b7818b69af8c4347efb"}, - {file = "coverage-7.4.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:ee866acc0861caebb4f2ab79f0b94dbfbdbfadc19f82e6e9c93930f74e11d7a0"}, - {file = "coverage-7.4.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:506edb1dd49e13a2d4cac6a5173317b82a23c9d6e8df63efb4f0380de0fbccbc"}, - {file = "coverage-7.4.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fd6545d97c98a192c5ac995d21c894b581f1fd14cf389be90724d21808b657e2"}, - {file = "coverage-7.4.3-cp310-cp310-win32.whl", hash = "sha256:f6a09b360d67e589236a44f0c39218a8efba2593b6abdccc300a8862cffc2f94"}, - {file = "coverage-7.4.3-cp310-cp310-win_amd64.whl", hash = "sha256:18d90523ce7553dd0b7e23cbb28865db23cddfd683a38fb224115f7826de78d0"}, - {file = "coverage-7.4.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cbbe5e739d45a52f3200a771c6d2c7acf89eb2524890a4a3aa1a7fa0695d2a47"}, - {file = "coverage-7.4.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:489763b2d037b164846ebac0cbd368b8a4ca56385c4090807ff9fad817de4113"}, - {file = "coverage-7.4.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:451f433ad901b3bb00184d83fd83d135fb682d780b38af7944c9faeecb1e0bfe"}, - {file = "coverage-7.4.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fcc66e222cf4c719fe7722a403888b1f5e1682d1679bd780e2b26c18bb648cdc"}, - {file = "coverage-7.4.3-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b3ec74cfef2d985e145baae90d9b1b32f85e1741b04cd967aaf9cfa84c1334f3"}, - {file = "coverage-7.4.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:abbbd8093c5229c72d4c2926afaee0e6e3140de69d5dcd918b2921f2f0c8baba"}, - {file = "coverage-7.4.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:35eb581efdacf7b7422af677b92170da4ef34500467381e805944a3201df2079"}, - {file = "coverage-7.4.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:8249b1c7334be8f8c3abcaaa996e1e4927b0e5a23b65f5bf6cfe3180d8ca7840"}, - {file = "coverage-7.4.3-cp311-cp311-win32.whl", hash = "sha256:cf30900aa1ba595312ae41978b95e256e419d8a823af79ce670835409fc02ad3"}, - {file = "coverage-7.4.3-cp311-cp311-win_amd64.whl", hash = "sha256:18c7320695c949de11a351742ee001849912fd57e62a706d83dfc1581897fa2e"}, - {file = "coverage-7.4.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:b51bfc348925e92a9bd9b2e48dad13431b57011fd1038f08316e6bf1df107d10"}, - {file = "coverage-7.4.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d6cdecaedea1ea9e033d8adf6a0ab11107b49571bbb9737175444cea6eb72328"}, - {file = "coverage-7.4.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3b2eccb883368f9e972e216c7b4c7c06cabda925b5f06dde0650281cb7666a30"}, - {file = "coverage-7.4.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6c00cdc8fa4e50e1cc1f941a7f2e3e0f26cb2a1233c9696f26963ff58445bac7"}, - {file = "coverage-7.4.3-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b9a4a8dd3dcf4cbd3165737358e4d7dfbd9d59902ad11e3b15eebb6393b0446e"}, - {file = "coverage-7.4.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:062b0a75d9261e2f9c6d071753f7eef0fc9caf3a2c82d36d76667ba7b6470003"}, - {file = "coverage-7.4.3-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:ebe7c9e67a2d15fa97b77ea6571ce5e1e1f6b0db71d1d5e96f8d2bf134303c1d"}, - {file = "coverage-7.4.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:c0a120238dd71c68484f02562f6d446d736adcc6ca0993712289b102705a9a3a"}, - {file = "coverage-7.4.3-cp312-cp312-win32.whl", hash = "sha256:37389611ba54fd6d278fde86eb2c013c8e50232e38f5c68235d09d0a3f8aa352"}, - {file = "coverage-7.4.3-cp312-cp312-win_amd64.whl", hash = "sha256:d25b937a5d9ffa857d41be042b4238dd61db888533b53bc76dc082cb5a15e914"}, - {file = "coverage-7.4.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:28ca2098939eabab044ad68850aac8f8db6bf0b29bc7f2887d05889b17346454"}, - {file = "coverage-7.4.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:280459f0a03cecbe8800786cdc23067a8fc64c0bd51dc614008d9c36e1659d7e"}, - {file = "coverage-7.4.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6c0cdedd3500e0511eac1517bf560149764b7d8e65cb800d8bf1c63ebf39edd2"}, - {file = "coverage-7.4.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9a9babb9466fe1da12417a4aed923e90124a534736de6201794a3aea9d98484e"}, - {file = "coverage-7.4.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dec9de46a33cf2dd87a5254af095a409ea3bf952d85ad339751e7de6d962cde6"}, - {file = "coverage-7.4.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:16bae383a9cc5abab9bb05c10a3e5a52e0a788325dc9ba8499e821885928968c"}, - {file = "coverage-7.4.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:2c854ce44e1ee31bda4e318af1dbcfc929026d12c5ed030095ad98197eeeaed0"}, - {file = "coverage-7.4.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:ce8c50520f57ec57aa21a63ea4f325c7b657386b3f02ccaedeccf9ebe27686e1"}, - {file = "coverage-7.4.3-cp38-cp38-win32.whl", hash = "sha256:708a3369dcf055c00ddeeaa2b20f0dd1ce664eeabde6623e516c5228b753654f"}, - {file = "coverage-7.4.3-cp38-cp38-win_amd64.whl", hash = "sha256:1bf25fbca0c8d121a3e92a2a0555c7e5bc981aee5c3fdaf4bb7809f410f696b9"}, - {file = "coverage-7.4.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3b253094dbe1b431d3a4ac2f053b6d7ede2664ac559705a704f621742e034f1f"}, - {file = "coverage-7.4.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:77fbfc5720cceac9c200054b9fab50cb2a7d79660609200ab83f5db96162d20c"}, - {file = "coverage-7.4.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6679060424faa9c11808598504c3ab472de4531c571ab2befa32f4971835788e"}, - {file = "coverage-7.4.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4af154d617c875b52651dd8dd17a31270c495082f3d55f6128e7629658d63765"}, - {file = "coverage-7.4.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8640f1fde5e1b8e3439fe482cdc2b0bb6c329f4bb161927c28d2e8879c6029ee"}, - {file = "coverage-7.4.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:69b9f6f66c0af29642e73a520b6fed25ff9fd69a25975ebe6acb297234eda501"}, - {file = "coverage-7.4.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:0842571634f39016a6c03e9d4aba502be652a6e4455fadb73cd3a3a49173e38f"}, - {file = "coverage-7.4.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a78ed23b08e8ab524551f52953a8a05d61c3a760781762aac49f8de6eede8c45"}, - {file = "coverage-7.4.3-cp39-cp39-win32.whl", hash = "sha256:c0524de3ff096e15fcbfe8f056fdb4ea0bf497d584454f344d59fce069d3e6e9"}, - {file = "coverage-7.4.3-cp39-cp39-win_amd64.whl", hash = "sha256:0209a6369ccce576b43bb227dc8322d8ef9e323d089c6f3f26a597b09cb4d2aa"}, - {file = "coverage-7.4.3-pp38.pp39.pp310-none-any.whl", hash = "sha256:7cbde573904625509a3f37b6fecea974e363460b556a627c60dc2f47e2fffa51"}, - {file = "coverage-7.4.3.tar.gz", hash = "sha256:276f6077a5c61447a48d133ed13e759c09e62aff0dc84274a68dc18660104d52"}, + {file = "coverage-7.4.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e0be5efd5127542ef31f165de269f77560d6cdef525fffa446de6f7e9186cfb2"}, + {file = "coverage-7.4.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ccd341521be3d1b3daeb41960ae94a5e87abe2f46f17224ba5d6f2b8398016cf"}, + {file = "coverage-7.4.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:09fa497a8ab37784fbb20ab699c246053ac294d13fc7eb40ec007a5043ec91f8"}, + {file = "coverage-7.4.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b1a93009cb80730c9bca5d6d4665494b725b6e8e157c1cb7f2db5b4b122ea562"}, + {file = "coverage-7.4.4-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:690db6517f09336559dc0b5f55342df62370a48f5469fabf502db2c6d1cffcd2"}, + {file = "coverage-7.4.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:09c3255458533cb76ef55da8cc49ffab9e33f083739c8bd4f58e79fecfe288f7"}, + {file = "coverage-7.4.4-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:8ce1415194b4a6bd0cdcc3a1dfbf58b63f910dcb7330fe15bdff542c56949f87"}, + {file = "coverage-7.4.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b91cbc4b195444e7e258ba27ac33769c41b94967919f10037e6355e998af255c"}, + {file = "coverage-7.4.4-cp310-cp310-win32.whl", hash = "sha256:598825b51b81c808cb6f078dcb972f96af96b078faa47af7dfcdf282835baa8d"}, + {file = "coverage-7.4.4-cp310-cp310-win_amd64.whl", hash = "sha256:09ef9199ed6653989ebbcaacc9b62b514bb63ea2f90256e71fea3ed74bd8ff6f"}, + {file = "coverage-7.4.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0f9f50e7ef2a71e2fae92774c99170eb8304e3fdf9c8c3c7ae9bab3e7229c5cf"}, + {file = "coverage-7.4.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:623512f8ba53c422fcfb2ce68362c97945095b864cda94a92edbaf5994201083"}, + {file = "coverage-7.4.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0513b9508b93da4e1716744ef6ebc507aff016ba115ffe8ecff744d1322a7b63"}, + {file = "coverage-7.4.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:40209e141059b9370a2657c9b15607815359ab3ef9918f0196b6fccce8d3230f"}, + {file = "coverage-7.4.4-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8a2b2b78c78293782fd3767d53e6474582f62443d0504b1554370bde86cc8227"}, + {file = "coverage-7.4.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:73bfb9c09951125d06ee473bed216e2c3742f530fc5acc1383883125de76d9cd"}, + {file = "coverage-7.4.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:1f384c3cc76aeedce208643697fb3e8437604b512255de6d18dae3f27655a384"}, + {file = "coverage-7.4.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:54eb8d1bf7cacfbf2a3186019bcf01d11c666bd495ed18717162f7eb1e9dd00b"}, + {file = "coverage-7.4.4-cp311-cp311-win32.whl", hash = "sha256:cac99918c7bba15302a2d81f0312c08054a3359eaa1929c7e4b26ebe41e9b286"}, + {file = "coverage-7.4.4-cp311-cp311-win_amd64.whl", hash = "sha256:b14706df8b2de49869ae03a5ccbc211f4041750cd4a66f698df89d44f4bd30ec"}, + {file = "coverage-7.4.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:201bef2eea65e0e9c56343115ba3814e896afe6d36ffd37bab783261db430f76"}, + {file = "coverage-7.4.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:41c9c5f3de16b903b610d09650e5e27adbfa7f500302718c9ffd1c12cf9d6818"}, + {file = "coverage-7.4.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d898fe162d26929b5960e4e138651f7427048e72c853607f2b200909794ed978"}, + {file = "coverage-7.4.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3ea79bb50e805cd6ac058dfa3b5c8f6c040cb87fe83de10845857f5535d1db70"}, + {file = "coverage-7.4.4-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ce4b94265ca988c3f8e479e741693d143026632672e3ff924f25fab50518dd51"}, + {file = "coverage-7.4.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:00838a35b882694afda09f85e469c96367daa3f3f2b097d846a7216993d37f4c"}, + {file = "coverage-7.4.4-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:fdfafb32984684eb03c2d83e1e51f64f0906b11e64482df3c5db936ce3839d48"}, + {file = "coverage-7.4.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:69eb372f7e2ece89f14751fbcbe470295d73ed41ecd37ca36ed2eb47512a6ab9"}, + {file = "coverage-7.4.4-cp312-cp312-win32.whl", hash = "sha256:137eb07173141545e07403cca94ab625cc1cc6bc4c1e97b6e3846270e7e1fea0"}, + {file = "coverage-7.4.4-cp312-cp312-win_amd64.whl", hash = "sha256:d71eec7d83298f1af3326ce0ff1d0ea83c7cb98f72b577097f9083b20bdaf05e"}, + {file = "coverage-7.4.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d5ae728ff3b5401cc320d792866987e7e7e880e6ebd24433b70a33b643bb0384"}, + {file = "coverage-7.4.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:cc4f1358cb0c78edef3ed237ef2c86056206bb8d9140e73b6b89fbcfcbdd40e1"}, + {file = "coverage-7.4.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8130a2aa2acb8788e0b56938786c33c7c98562697bf9f4c7d6e8e5e3a0501e4a"}, + {file = "coverage-7.4.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cf271892d13e43bc2b51e6908ec9a6a5094a4df1d8af0bfc360088ee6c684409"}, + {file = "coverage-7.4.4-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a4cdc86d54b5da0df6d3d3a2f0b710949286094c3a6700c21e9015932b81447e"}, + {file = "coverage-7.4.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:ae71e7ddb7a413dd60052e90528f2f65270aad4b509563af6d03d53e979feafd"}, + {file = "coverage-7.4.4-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:38dd60d7bf242c4ed5b38e094baf6401faa114fc09e9e6632374388a404f98e7"}, + {file = "coverage-7.4.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:aa5b1c1bfc28384f1f53b69a023d789f72b2e0ab1b3787aae16992a7ca21056c"}, + {file = "coverage-7.4.4-cp38-cp38-win32.whl", hash = "sha256:dfa8fe35a0bb90382837b238fff375de15f0dcdb9ae68ff85f7a63649c98527e"}, + {file = "coverage-7.4.4-cp38-cp38-win_amd64.whl", hash = "sha256:b2991665420a803495e0b90a79233c1433d6ed77ef282e8e152a324bbbc5e0c8"}, + {file = "coverage-7.4.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3b799445b9f7ee8bf299cfaed6f5b226c0037b74886a4e11515e569b36fe310d"}, + {file = "coverage-7.4.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b4d33f418f46362995f1e9d4f3a35a1b6322cb959c31d88ae56b0298e1c22357"}, + {file = "coverage-7.4.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aadacf9a2f407a4688d700e4ebab33a7e2e408f2ca04dbf4aef17585389eff3e"}, + {file = "coverage-7.4.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7c95949560050d04d46b919301826525597f07b33beba6187d04fa64d47ac82e"}, + {file = "coverage-7.4.4-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ff7687ca3d7028d8a5f0ebae95a6e4827c5616b31a4ee1192bdfde697db110d4"}, + {file = "coverage-7.4.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:5fc1de20b2d4a061b3df27ab9b7c7111e9a710f10dc2b84d33a4ab25065994ec"}, + {file = "coverage-7.4.4-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:c74880fc64d4958159fbd537a091d2a585448a8f8508bf248d72112723974cbd"}, + {file = "coverage-7.4.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:742a76a12aa45b44d236815d282b03cfb1de3b4323f3e4ec933acfae08e54ade"}, + {file = "coverage-7.4.4-cp39-cp39-win32.whl", hash = "sha256:d89d7b2974cae412400e88f35d86af72208e1ede1a541954af5d944a8ba46c57"}, + {file = "coverage-7.4.4-cp39-cp39-win_amd64.whl", hash = "sha256:9ca28a302acb19b6af89e90f33ee3e1906961f94b54ea37de6737b7ca9d8827c"}, + {file = "coverage-7.4.4-pp38.pp39.pp310-none-any.whl", hash = "sha256:b2c5edc4ac10a7ef6605a966c58929ec6c1bd0917fb8c15cb3363f65aa40e677"}, + {file = "coverage-7.4.4.tar.gz", hash = "sha256:c901df83d097649e257e803be22592aedfd5182f07b3cc87d640bbb9afd50f49"}, ] [package.extras] diff --git a/pay-api/src/pay_api/models/__init__.py b/pay-api/src/pay_api/models/__init__.py index c3a04b78f..9e119110f 100755 --- a/pay-api/src/pay_api/models/__init__.py +++ b/pay-api/src/pay_api/models/__init__.py @@ -36,7 +36,7 @@ from .eft_transaction import EFTTransaction, EFTTransactionSchema from .ejv_file import EjvFile from .ejv_header import EjvHeader -from .ejv_invoice_link import EjvInvoiceLink +from .ejv_link import EjvLink from .error_code import ErrorCode, ErrorCodeSchema from .fee_code import FeeCode, FeeCodeSchema # noqa: I001 from .fee_schedule import FeeSchedule, FeeScheduleSchema diff --git a/pay-api/src/pay_api/models/ejv_invoice_link.py b/pay-api/src/pay_api/models/ejv_link.py similarity index 80% rename from pay-api/src/pay_api/models/ejv_invoice_link.py rename to pay-api/src/pay_api/models/ejv_link.py index 7db67b761..4055df51d 100644 --- a/pay-api/src/pay_api/models/ejv_invoice_link.py +++ b/pay-api/src/pay_api/models/ejv_link.py @@ -19,10 +19,10 @@ from .db import db -class EjvInvoiceLink(BaseModel): # pylint: disable=too-few-public-methods +class EjvLink(BaseModel): # pylint: disable=too-few-public-methods """This class manages linkages between EJV and invoices.""" - __tablename__ = 'ejv_invoice_links' + __tablename__ = 'ejv_links' # this mapper is used so that new and old versions of the service can be run simultaneously, # making rolling upgrades easier # This is used by SQLAlchemy to explicitly define which fields we're interested @@ -38,15 +38,22 @@ class EjvInvoiceLink(BaseModel): # pylint: disable=too-few-public-methods 'id', 'disbursement_status_code', 'ejv_header_id', - 'invoice_id', + 'link_id', + 'link_type', 'message', 'sequence' ] } id = db.Column(db.Integer, primary_key=True, autoincrement=True) - invoice_id = db.Column(db.Integer, ForeignKey('invoices.id'), nullable=False, index=True) - ejv_header_id = db.Column(db.Integer, ForeignKey('ejv_headers.id'), nullable=False, index=True) disbursement_status_code = db.Column(db.String(20), ForeignKey('disbursement_status_codes.code'), nullable=True) + ejv_header_id = db.Column(db.Integer, ForeignKey('ejv_headers.id'), nullable=False, index=True) + link_id = db.Column(db.Integer, nullable=True, index=True) # Repurposed for generic linking + link_type = db.Column(db.String(50), nullable=True, index=True) message = db.Column('message', db.String, nullable=True, index=False) sequence = db.Column(db.Integer, nullable=True) + + @classmethod + def find_ejv_link_by_link_id(cls, link_id: str): + """Return any ejv link by link_id.""" + return cls.query.filter_by(link_id=link_id).first() diff --git a/pay-api/src/pay_api/models/refunds_partial.py b/pay-api/src/pay_api/models/refunds_partial.py index 9fda23d51..de85c361f 100644 --- a/pay-api/src/pay_api/models/refunds_partial.py +++ b/pay-api/src/pay_api/models/refunds_partial.py @@ -40,11 +40,13 @@ class RefundsPartial(Audit, VersionedModel): # pylint: disable=too-many-instanc __mapper_args__ = { 'include_properties': [ 'id', + 'created_by', + 'created_on', + 'disbursement_date', + 'disbursement_status_code', 'payment_line_item_id', 'refund_amount', 'refund_type', - 'disbursement_status_code', - 'disbursement_date' ] } diff --git a/pay-api/src/pay_api/utils/enums.py b/pay-api/src/pay_api/utils/enums.py index c7bc97b71..7b6e40c9a 100644 --- a/pay-api/src/pay_api/utils/enums.py +++ b/pay-api/src/pay_api/utils/enums.py @@ -375,3 +375,10 @@ class QueueSources(Enum): PAY_JOBS = 'pay-jobs' PAY_QUEUE = 'pay-queue' FTP_POLLER = 'ftp-poller' + + +class EJVLinkType(Enum): + """EJV link types for ejv_link table.""" + + INVOICE = 'invoice' + REFUND = 'refund' diff --git a/pay-queue/poetry.lock b/pay-queue/poetry.lock index d3d57005b..8bc2c6d99 100644 --- a/pay-queue/poetry.lock +++ b/pay-queue/poetry.lock @@ -119,17 +119,17 @@ tests-no-zope = ["attrs[tests-mypy]", "cloudpickle", "hypothesis", "pympler", "p [[package]] name = "autopep8" -version = "2.0.4" +version = "2.1.0" description = "A tool that automatically formats Python code to conform to the PEP 8 style guide" optional = false -python-versions = ">=3.6" +python-versions = ">=3.8" files = [ - {file = "autopep8-2.0.4-py2.py3-none-any.whl", hash = "sha256:067959ca4a07b24dbd5345efa8325f5f58da4298dab0dde0443d5ed765de80cb"}, - {file = "autopep8-2.0.4.tar.gz", hash = "sha256:2913064abd97b3419d1cc83ea71f042cb821f87e45b9c88cad5ad3c4ea87fe0c"}, + {file = "autopep8-2.1.0-py2.py3-none-any.whl", hash = "sha256:2bb76888c5edbcafe6aabab3c47ba534f5a2c2d245c2eddced4a30c4b4946357"}, + {file = "autopep8-2.1.0.tar.gz", hash = "sha256:1fa8964e4618929488f4ec36795c7ff12924a68b8bf01366c094fc52f770b6e7"}, ] [package.dependencies] -pycodestyle = ">=2.10.0" +pycodestyle = ">=2.11.0" [[package]] name = "blinker" @@ -1648,9 +1648,9 @@ werkzeug = "3.0.1" [package.source] type = "git" -url = "https://github.com/seeker25/sbc-pay.git" -reference = "pubsub_emulation" -resolved_reference = "e2c9d5fe0e51ce2be585b45ed26d40ba6e03ecbd" +url = "https://github.com/Jxio/sbc-pay.git" +reference = "19875" +resolved_reference = "62ceadd6e60f53cd8cf3781b5e2f6b99c968c6bf" subdirectory = "pay-api" [[package]] @@ -2647,4 +2647,4 @@ watchdog = ["watchdog (>=2.3)"] [metadata] lock-version = "2.0" python-versions = "^3.12" -content-hash = "bc1d52223cc3c9ae97947aeb1a795405091f9c1d771d0a088090cdfde97d9093" +content-hash = "b74265a904a8f0ea46d5e829d3643326ea5f204a805c8486c1782bf97d643c6f" diff --git a/pay-queue/pyproject.toml b/pay-queue/pyproject.toml index f2c245e7f..0ad74480b 100644 --- a/pay-queue/pyproject.toml +++ b/pay-queue/pyproject.toml @@ -22,7 +22,7 @@ protobuf = "4.25.3" launchdarkly-server-sdk = "^9.2.2" cachecontrol = "^0.14.0" sbc-common-components = {git = "https://github.com/bcgov/sbc-common-components.git", subdirectory = "python"} -pay-api = {git = "https://github.com/seeker25/sbc-pay.git", rev = "pubsub_emulation", subdirectory = "pay-api"} +pay-api = {git = "https://github.com/Jxio/sbc-pay.git", rev = "19875", subdirectory = "pay-api"} flask-jwt-oidc = {git = "https://github.com/thorwolpert/flask-jwt-oidc.git"} simple-cloudevent = {git = "https://github.com/daxiom/simple-cloudevent.py.git"} pg8000 = "^1.30.5" diff --git a/pay-queue/src/pay_queue/services/cgi_reconciliations.py b/pay-queue/src/pay_queue/services/cgi_reconciliations.py index d3040f9b9..9926acb86 100644 --- a/pay-queue/src/pay_queue/services/cgi_reconciliations.py +++ b/pay-queue/src/pay_queue/services/cgi_reconciliations.py @@ -20,7 +20,7 @@ from pay_api.models import DistributionCode as DistributionCodeModel from pay_api.models import EjvFile as EjvFileModel from pay_api.models import EjvHeader as EjvHeaderModel -from pay_api.models import EjvInvoiceLink as EjvInvoiceLinkModel +from pay_api.models import EjvLink as EjvLinkModel from pay_api.models import Invoice as InvoiceModel from pay_api.models import InvoiceReference as InvoiceReferenceModel from pay_api.models import Payment as PaymentModel @@ -32,8 +32,8 @@ from pay_api.services import gcp_queue_publisher from pay_api.services.gcp_queue_publisher import QueueMessage from pay_api.utils.enums import ( - DisbursementStatus, EjvFileType, InvoiceReferenceStatus, InvoiceStatus, MessageType, PaymentMethod, PaymentStatus, - PaymentSystem, QueueSources, RoutingSlipStatus) + DisbursementStatus, EjvFileType, EJVLinkType, InvoiceReferenceStatus, InvoiceStatus, MessageType, PaymentMethod, + PaymentStatus, PaymentSystem, QueueSources, RoutingSlipStatus) from sentry_sdk import capture_message from pay_queue import config @@ -78,10 +78,12 @@ def _update_acknowledgement(msg: Dict[str, any]): for ejv_header in ejv_headers: ejv_header.disbursement_status_code = DisbursementStatus.ACKNOWLEDGED.value if ejv_file.file_type == EjvFileType.DISBURSEMENT.value: - ejv_links: List[EjvInvoiceLinkModel] = db.session.query(EjvInvoiceLinkModel).filter( - EjvInvoiceLinkModel.ejv_header_id == ejv_header.id).all() + ejv_links: List[EjvLinkModel] = db.session.query(EjvLinkModel) \ + .filter(EjvLinkModel.ejv_header_id == ejv_header.id) \ + .filter(EjvLinkModel.link_type == EJVLinkType.INVOICE.value) \ + .all() for ejv_link in ejv_links: - invoice: InvoiceModel = InvoiceModel.find_by_id(ejv_link.invoice_id) + invoice: InvoiceModel = InvoiceModel.find_by_id(ejv_link.link_id) invoice.disbursement_status_code = DisbursementStatus.ACKNOWLEDGED.value db.session.commit() @@ -164,9 +166,10 @@ def _process_jv_details_feedback(ejv_file, has_errors, line, receipt_number): # invoice_id = int(line[205:315]) current_app.logger.info('Invoice id - %s', invoice_id) invoice: InvoiceModel = InvoiceModel.find_by_id(invoice_id) - invoice_link: EjvInvoiceLinkModel = db.session.query(EjvInvoiceLinkModel).filter( - EjvInvoiceLinkModel.ejv_header_id == ejv_header_model_id).filter( - EjvInvoiceLinkModel.invoice_id == invoice_id).one_or_none() + invoice_link: EjvLinkModel = db.session.query(EjvLinkModel).filter( + EjvLinkModel.ejv_header_id == ejv_header_model_id).filter( + EjvLinkModel.link_id == invoice_id).filter( + EjvLinkModel.link_type == EJVLinkType.INVOICE.value).one_or_none() invoice_return_code = line[315:319] invoice_return_message = line[319:469] # If the JV process failed, then mark the GL code against the invoice to be stopped @@ -385,10 +388,11 @@ def _process_ap_header_non_gov_disbursement(line, ejv_file: EjvFileModel) -> boo ap_header_return_code = line[414:418] ap_header_error_message = line[418:568] disbursement_status = _get_disbursement_status(ap_header_return_code) - invoice_link = db.session.query(EjvInvoiceLinkModel)\ + invoice_link = db.session.query(EjvLinkModel)\ .join(EjvHeaderModel).join(EjvFileModel)\ .filter(EjvFileModel.id == ejv_file.id)\ - .filter(EjvInvoiceLinkModel.invoice_id == invoice_id)\ + .filter(EjvLinkModel.link_id == invoice_id)\ + .filter(EjvLinkModel.link_type == EJVLinkType.INVOICE.value) \ .one_or_none() invoice_link.disbursement_status_code = disbursement_status invoice_link.message = ap_header_error_message diff --git a/pay-queue/tests/integration/test_cgi_reconciliations.py b/pay-queue/tests/integration/test_cgi_reconciliations.py index 8b3adaac9..f308d9f46 100644 --- a/pay-queue/tests/integration/test_cgi_reconciliations.py +++ b/pay-queue/tests/integration/test_cgi_reconciliations.py @@ -21,7 +21,7 @@ from pay_api.models import DistributionCode as DistributionCodeModel from pay_api.models import EjvFile as EjvFileModel from pay_api.models import EjvHeader as EjvHeaderModel -from pay_api.models import EjvInvoiceLink as EjvInvoiceLinkModel +from pay_api.models import EjvLink as EjvLinkModel from pay_api.models import FeeSchedule as FeeScheduleModel from pay_api.models import Invoice as InvoiceModel from pay_api.models import InvoiceReference as InvoiceReferenceModel @@ -33,7 +33,7 @@ from pay_api.models import RoutingSlip as RoutingSlipModel from pay_api.models import db from pay_api.utils.enums import ( - CfsAccountStatus, DisbursementStatus, EjvFileType, InvoiceReferenceStatus, InvoiceStatus, MessageType, + CfsAccountStatus, DisbursementStatus, EjvFileType, EJVLinkType, InvoiceReferenceStatus, InvoiceStatus, MessageType, PaymentMethod, PaymentStatus, RoutingSlipStatus) from tests.integration.utils import add_file_event_to_queue_and_process @@ -93,8 +93,9 @@ def test_successful_partner_ejv_reconciliations(client): partner_code=partner_code, payment_account_id=pay_account.id).save() ejv_header_id = ejv_header.id - EjvInvoiceLinkModel( - invoice_id=invoice.id, ejv_header_id=ejv_header.id, disbursement_status_code=DisbursementStatus.UPLOADED.value + EjvLinkModel( + link_id=invoice.id, link_type=EJVLinkType.INVOICE.value, + ejv_header_id=ejv_header.id, disbursement_status_code=DisbursementStatus.UPLOADED.value ).save() ack_file_name = f'ACK.{file_ref}' @@ -207,8 +208,10 @@ def test_failed_partner_ejv_reconciliations(client): partner_code=partner_code, payment_account_id=pay_account.id).save() ejv_header_id = ejv_header.id - EjvInvoiceLinkModel( - invoice_id=invoice.id, ejv_header_id=ejv_header.id, disbursement_status_code=DisbursementStatus.UPLOADED.value + EjvLinkModel( + link_id=invoice.id, + link_type=EJVLinkType.INVOICE.value, + ejv_header_id=ejv_header.id, disbursement_status_code=DisbursementStatus.UPLOADED.value ).save() ack_file_name = f'ACK.{file_ref}' @@ -325,8 +328,9 @@ def test_successful_partner_reversal_ejv_reconciliations(client): partner_code=partner_code, payment_account_id=pay_account.id).save() ejv_header_id = ejv_header.id - EjvInvoiceLinkModel( - invoice_id=invoice.id, ejv_header_id=ejv_header.id, disbursement_status_code=DisbursementStatus.UPLOADED.value + EjvLinkModel( + link_id=invoice.id, link_type=EJVLinkType.INVOICE.value, + ejv_header_id=ejv_header.id, disbursement_status_code=DisbursementStatus.UPLOADED.value ).save() ack_file_name = f'ACK.{file_ref}' @@ -457,8 +461,9 @@ def test_succesful_payment_ejv_reconciliations(client): ejv_header: EjvHeaderModel = EjvHeaderModel(disbursement_status_code=DisbursementStatus.UPLOADED.value, ejv_file_id=ejv_file.id, payment_account_id=jv_acc.id).save() - EjvInvoiceLinkModel( - invoice_id=inv.id, ejv_header_id=ejv_header.id, disbursement_status_code=DisbursementStatus.UPLOADED.value + EjvLinkModel( + link_id=inv.id, link_type=EJVLinkType.INVOICE.value, + ejv_header_id=ejv_header.id, disbursement_status_code=DisbursementStatus.UPLOADED.value ).save() inv_total = f'{inv.total:.2f}'.zfill(15) pay_line_amount = f'{line.total:.2f}'.zfill(15) @@ -615,8 +620,9 @@ def test_succesful_payment_reversal_ejv_reconciliations(client): ejv_header: EjvHeaderModel = EjvHeaderModel(disbursement_status_code=DisbursementStatus.UPLOADED.value, ejv_file_id=ejv_file.id, payment_account_id=jv_acc.id).save() - EjvInvoiceLinkModel( - invoice_id=inv.id, ejv_header_id=ejv_header.id, disbursement_status_code=DisbursementStatus.UPLOADED.value + EjvLinkModel( + link_id=inv.id, link_type=EJVLinkType.INVOICE.value, + ejv_header_id=ejv_header.id, disbursement_status_code=DisbursementStatus.UPLOADED.value ).save() inv_total = f'{inv.total:.2f}'.zfill(15) pay_line_amount = f'{line.total:.2f}'.zfill(15) @@ -1041,12 +1047,13 @@ def test_successful_ap_disbursement(client): ejv_header: EjvHeaderModel = EjvHeaderModel(disbursement_status_code=DisbursementStatus.UPLOADED.value, ejv_file_id=ejv_file.id, payment_account_id=account.id).save() - EjvInvoiceLinkModel( - invoice_id=invoice.id, ejv_header_id=ejv_header.id, disbursement_status_code=DisbursementStatus.UPLOADED.value + EjvLinkModel( + link_id=invoice.id, link_type=EJVLinkType.INVOICE.value, + ejv_header_id=ejv_header.id, disbursement_status_code=DisbursementStatus.UPLOADED.value ).save() - EjvInvoiceLinkModel( - invoice_id=refund_invoice.id, ejv_header_id=ejv_header.id, + EjvLinkModel( + link_id=refund_invoice.id, link_type=EJVLinkType.INVOICE.value, ejv_header_id=ejv_header.id, disbursement_status_code=DisbursementStatus.UPLOADED.value ).save() @@ -1187,12 +1194,13 @@ def test_failure_ap_disbursement(client): ejv_header: EjvHeaderModel = EjvHeaderModel(disbursement_status_code=DisbursementStatus.UPLOADED.value, ejv_file_id=ejv_file.id, payment_account_id=account.id).save() - EjvInvoiceLinkModel( - invoice_id=invoice.id, ejv_header_id=ejv_header.id, disbursement_status_code=DisbursementStatus.UPLOADED.value + EjvLinkModel( + link_id=invoice.id, link_type=EJVLinkType.INVOICE.value, + ejv_header_id=ejv_header.id, disbursement_status_code=DisbursementStatus.UPLOADED.value ).save() - EjvInvoiceLinkModel( - invoice_id=refund_invoice.id, ejv_header_id=ejv_header.id, + EjvLinkModel( + link_id=refund_invoice.id, link_type=EJVLinkType.INVOICE.value, ejv_header_id=ejv_header.id, disbursement_status_code=DisbursementStatus.UPLOADED.value ).save() @@ -1287,14 +1295,14 @@ def test_failure_ap_disbursement(client): invoice_1 = InvoiceModel.find_by_id(invoice_ids[0]) assert invoice_1.disbursement_status_code == DisbursementStatus.COMPLETED.value assert invoice_1.disbursement_date is not None - invoice_link = db.session.query(EjvInvoiceLinkModel)\ - .filter(EjvInvoiceLinkModel.invoice_id == invoice_ids[0])\ + invoice_link = db.session.query(EjvLinkModel)\ + .filter(EjvLinkModel.link_id == invoice_ids[0])\ .one_or_none() assert invoice_link.disbursement_status_code == DisbursementStatus.COMPLETED.value invoice_2 = InvoiceModel.find_by_id(invoice_ids[1]) assert invoice_2.disbursement_status_code == DisbursementStatus.ERRORED.value - invoice_link = db.session.query(EjvInvoiceLinkModel)\ - .filter(EjvInvoiceLinkModel.invoice_id == invoice_ids[1])\ + invoice_link = db.session.query(EjvLinkModel)\ + .filter(EjvLinkModel.link_id == invoice_ids[1])\ .one_or_none() assert invoice_link.disbursement_status_code == DisbursementStatus.ERRORED.value