Skip to content

Commit

Permalink
Merge branch 'fix_retransfer' into develop
Browse files Browse the repository at this point in the history
  • Loading branch information
FestplattenSchnitzel committed Nov 14, 2024
2 parents f24c7ce + 45a0cdb commit 13fa3f6
Show file tree
Hide file tree
Showing 11 changed files with 130 additions and 9 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 = "b64618e97415"
down_revision = "5234d7ac2b4a"
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="33200",
),
)
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 ~= 4.2.5", # 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
12 changes: 12 additions & 0 deletions requirements.dev.txt

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 12 additions & 0 deletions requirements.prod.txt

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 12 additions & 0 deletions requirements.txt

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

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 @@ -77,6 +77,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 @@ -751,12 +752,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 13fa3f6

Please sign in to comment.