Skip to content

Commit

Permalink
Lookup missing BIC when returning bank account activities
Browse files Browse the repository at this point in the history
  • Loading branch information
FestplattenSchnitzel committed Sep 19, 2024
1 parent 968f2ad commit d856b6b
Show file tree
Hide file tree
Showing 11 changed files with 1,369 additions and 1,167 deletions.
3 changes: 2 additions & 1 deletion pycroft/lib/finance/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,9 @@
get_pid_csv,
)
from .retransfer import (
get_activities_to_return,
attribute_activities_as_returned,
generate_activities_return_sepaxml,
get_activities_to_return,
)
from .transaction_crud import (
simple_transaction,
Expand Down
31 changes: 29 additions & 2 deletions pycroft/lib/finance/retransfer.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
from collections.abc import Sequence
from datetime import datetime, timedelta

from schwifty import IBAN
from sepaxml import SepaTransfer
from sqlalchemy import select
from sqlalchemy.orm import joinedload, Session
from sqlalchemy.orm import Session, joinedload

from pycroft import config
from pycroft.helpers.utc import ensure_tz
from pycroft.model.finance import BankAccountActivity
from pycroft.model.user import User

from .transaction_crud import simple_transaction


def get_activities_to_return(session: Session) -> Sequence[BankAccountActivity]:
Expand All @@ -33,10 +37,11 @@ def generate_activities_return_sepaxml(activities: list[BankAccountActivity]) ->
sepa = SepaTransfer(transfer_config, clean=False)

for activity in activities:
bic = activity.other_routing_number or IBAN(activity.other_account_number).bic.compact
payment = {
"name": activity.other_name,
"IBAN": activity.other_account_number,
"BIC": activity.other_routing_number,
"BIC": bic,
"amount": int(activity.amount * 100),
"execution_date": datetime.now().date(),
"description": f"Rücküberweisung nicht zuordenbarer Überweisung vom {activity.posted_on} mit Referenz {activity.reference}"[
Expand All @@ -46,3 +51,25 @@ def generate_activities_return_sepaxml(activities: list[BankAccountActivity]) ->
sepa.add_payment(payment)

return sepa.export()


def attribute_activities_as_returned(
session: Session, activities: list[BankAccountActivity], author: User
) -> None:
for activity in activities:
debit_account = config.non_attributable_transactions_account
credit_account = activity.bank_account.account

transaction = simple_transaction(
description=activity.reference,
debit_account=debit_account,
credit_account=credit_account,
amount=activity.amount,
author=author,
valid_on=activity.valid_on,
confirmed=False,
)
activity.split = next(
split for split in transaction.splits if split.account_id == credit_account.id
)
session.add(activity)
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
"""add account for non-attributable transfers to config
Revision ID: 2d7e4df39a3b
Revises: bc0e0dd480d4
Create Date: 2024-06-06 20:21:16.972195
"""

import sqlalchemy as sa
from alembic import op

# revision identifiers, used by Alembic.
revision = "2d7e4df39a3b"
down_revision = "bc0e0dd480d4"
branch_labels = None
depends_on = None


def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.add_column(
"config",
sa.Column(
"non_attributable_transactions_account_id",
sa.Integer(),
nullable=False,
server_default="10",
),
)
op.create_foreign_key(
None, "config", "account", ["non_attributable_transactions_account_id"], ["id"]
)


def downgrade():
op.drop_constraint(None, "config", type_="foreignkey")
op.drop_column("config", "non_attributable_transactions_account_id")
op.create_index(
"bank_account_activity_imported_at", "bank_account_activity", ["imported_at"], unique=False
)
5 changes: 5 additions & 0 deletions pycroft/model/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,11 @@ class Config(IntegerIdModel):
foreign_keys=[membership_fee_bank_account_id]
)

non_attributable_transactions_account_id: Mapped[int] = col(ForeignKey(Account.id))
non_attributable_transactions_account: Mapped[Account] = relationship(
foreign_keys=[non_attributable_transactions_account_id]
)

fints_product_id: Mapped[str | None]

__table_args__ = (CheckConstraint("id = 1"),)
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ dependencies = [
"python-dotenv ~= 0.21.0",
"reportlab ~= 3.6.13", # usersheet generation
"rich ~= 13.8.0",
"schwifty ~= 2024.9.0",
"sentry-sdk[Flask] ~= 1.29.2",
"simplejson ~= 3.11.1", # decimal serialization
"SQLAlchemy >= 2.0.1",
Expand Down
1,342 changes: 699 additions & 643 deletions requirements.dev.txt

Large diffs are not rendered by default.

1,079 changes: 564 additions & 515 deletions requirements.prod.txt

Large diffs are not rendered by default.

12 changes: 12 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -838,6 +838,10 @@ pyasn1==0.6.0 \
--hash=sha256:3a35ab2c4b5ef98e17dfdec8ab074046fbda76e281c5a706ccd82328cfc8f64c \
--hash=sha256:cca4bb0f2df5504f02f6f8a775b6e416ff9b0b3b16f7ee80b5a3153d9b804473
# via ldap3
pycountry==24.6.1 \
--hash=sha256:b61b3faccea67f87d10c1f2b0fc0be714409e8fcdcc1315613174f6466c10221 \
--hash=sha256:f1a4fb391cd7214f8eefd39556d740adcc233c778a27f8942c8dca351d6ce06f
# via schwifty
pydantic==2.4.2 \
--hash=sha256:94f336138093a5d7f426aac732dcfe7ab4eb4da243c88f891d65deb4a2556ee7 \
--hash=sha256:bc3ddf669d234f4220e6e1c4d96b061abe0998185a8d7855c0126782b7abc8c1
Expand Down Expand Up @@ -1054,6 +1058,14 @@ rich==13.8.0 \
--hash=sha256:2e85306a063b9492dffc86278197a60cbece75bcb766022f3436f567cae11bdc \
--hash=sha256:a5ac1f1cd448ade0d59cc3356f7db7a7ccda2c8cbae9c7a90c28ff463d3e91f4
# via pycroft (pyproject.toml)
rstr==3.2.2 \
--hash=sha256:c4a564d4dfb4472d931d145c43d1cf1ad78c24592142e7755b8866179eeac012 \
--hash=sha256:f39195d38da1748331eeec52f1276e71eb6295e7949beea91a5e9af2340d7b3b
# via schwifty
schwifty==2024.9.0 \
--hash=sha256:88f5a73549c5e4acb627ca669d52f49368b00ed3c3dae3778068471d0f6f4f62 \
--hash=sha256:acee9f5021587c254fc5f77ebefcd62feb0c0c3a80fea4523d451307dd04f330
# via pycroft (pyproject.toml)
sentry-sdk==1.29.2 \
--hash=sha256:3e17215d8006612e2df02b0e73115eb8376c37e3f586d8436fa41644e605074d \
--hash=sha256:a99ee105384788c3f228726a88baf515fe7b5f1d2d0f215a03d194369f158df7
Expand Down
1 change: 1 addition & 0 deletions tests/factories/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,4 @@ class Meta:
# `Account`s
membership_fee_account = SubFactory(AccountFactory, type="REVENUE")
membership_fee_bank_account = SubFactory(BankAccountFactory)
non_attributable_transactions_account = SubFactory(AccountFactory, type="REVENUE")
20 changes: 15 additions & 5 deletions web/blueprints/finance/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@
match_activities,
get_activities_to_return,
generate_activities_return_sepaxml,
attribute_activities_as_returned,
get_all_bank_accounts,
get_unassigned_bank_account_activities,
get_all_mt940_errors,
Expand Down Expand Up @@ -602,12 +603,21 @@ def bank_account_activities_return_do() -> ResponseReturnValue:

form: t.Any = _create_form(field_list)()

if form.validate_on_submit():
selected_activities: list[BankAccountActivity] = [
activity for activity in activities_to_return if form[str(activity.id)].data
]
if not form.validate_on_submit():
return render_template(
"finance/bank_account_activities_return.html",
form=form(),
activities=activities_to_return,
)

sepa_xml: bytes = generate_activities_return_sepaxml(selected_activities)
selected_activities: list[BankAccountActivity] = [
activity for activity in activities_to_return if form[str(activity.id)].data
]

sepa_xml: bytes = generate_activities_return_sepaxml(selected_activities)

attribute_activities_as_returned(session, selected_activities, current_user)
session.commit()

return send_file(
BytesIO(sepa_xml),
Expand Down
2 changes: 1 addition & 1 deletion web/templates/finance/bank_account_activities_return.html
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@

<div class="row">
<div class="col-md-12">
<button type="submit" class="btn btn-primary">SEPA-XML generieren</button>
<button type="submit" class="btn btn-primary">Überweisungen unbestätigt als unzuordenbar buchen und SEPA-XML exportieren</button>
</div>
</div>
</form>
Expand Down

0 comments on commit d856b6b

Please sign in to comment.