byro-leinelab/byro_shackspace/management/commands/import_shackbureau.py

163 lines
5.4 KiB
Python
Raw Normal View History

2017-10-13 19:25:31 +02:00
import json
from contextlib import suppress
from datetime import datetime, timedelta
from decimal import Decimal
from django.core.management.base import BaseCommand
from django.db import transaction
from django.utils.dateparse import parse_date
from byro.bookkeeping.models import TransactionChannel, RealTransaction, VirtualTransaction, Account, AccountCategory
from byro.members.models import Member, Membership
def _import_sepa(member_data, member):
sepa_keys = [
'iban', 'mandate_reason', 'zip_code', 'country',
'city', 'bic', 'address', 'fullname', 'issue_date',
'institute', 'mandate_reference',
]
for key in sepa_keys:
setattr(member.profile_sepa, key, member_data.get(f'sepa__{key}'))
member.profile_sepa.save()
def _get_main_accounts():
fee_account, _ = Account.objects.get_or_create(
account_category=AccountCategory.MEMBER_FEES,
)
donation_account, _ = Account.objects.get_or_create(
account_category=AccountCategory.MEMBER_DONATION,
)
liability_account, _ = Account.objects.get_or_create(
account_category=AccountCategory.LIABILITY,
)
return (
fee_account,
donation_account,
liability_account,
)
2017-10-13 19:25:31 +02:00
def _import_real_transactions(real_transactions):
2017-10-13 19:25:31 +02:00
transactions = []
2017-10-13 19:25:31 +02:00
for real_transaction in real_transactions:
transactions.append(RealTransaction(
channel=TransactionChannel.BANK,
value_datetime=parse_date(real_transaction['booking_date']),
amount=real_transaction['amount'],
purpose=real_transaction['reference'],
originator=real_transaction.get('transaction_owner') or 'imported',
# TODO: reverses?
importer='shackbureau',
))
ids = [rt.pk for rt in RealTransaction.objects.bulk_create(transactions)]
return RealTransaction.objects.filter(pk__in=ids)
2017-10-13 19:25:31 +02:00
def _import_fee_claims(member, virtual_transactions):
fee_account, donation_account, liability_account = _get_main_accounts()
claims = [v for v in virtual_transactions if v['booking_type'] == 'fee_claim']
2017-10-13 19:25:31 +02:00
transactions = []
2017-10-13 19:25:31 +02:00
for claim in claims:
transactions.append(VirtualTransaction(
source_account=fee_account,
destination_account=liability_account,
member=member,
amount=abs(Decimal(claim['amount'])),
value_datetime=claim['due_date'],
))
2017-10-13 19:25:31 +02:00
VirtualTransaction.objects.bulk_create(transactions)
def _import_inflows(member, virtual_transactions, real_transactions):
fee_account, donation_account, liability_account = _get_main_accounts()
inflows = [v for v in virtual_transactions if v['booking_type'] == 'deposit']
2017-10-13 19:25:31 +02:00
for inflow in inflows:
account = fee_account if inflow['transaction_type'] == 'membership fee' else donation_account
try:
real_transaction = real_transactions.get(
2017-10-13 19:25:31 +02:00
virtual_transactions__isnull=True,
amount=abs(Decimal(inflow['amount'])),
value_datetime=inflow['due_date'],
purpose=inflow['payment_reference'],
)
except RealTransaction.DoesNotExist:
real_transaction = None
VirtualTransaction.objects.create(
destination_account=account,
source_account=liability_account,
member=member,
amount=abs(Decimal(inflow['amount'])),
value_datetime=inflow['due_date'],
real_transaction=real_transaction,
)
def _import_transactions(member_data, member):
real_transactions = member_data.get('bank_transactions')
virtual_transactions = member_data.get('account_transactions')
real_transactions = _import_real_transactions(real_transactions)
_import_fee_claims(member, virtual_transactions)
_import_inflows(member, virtual_transactions, real_transactions)
2017-10-13 19:25:31 +02:00
def import_member(member_data):
member = Member.objects.create(
number=member_data['number'],
name=member_data['name'],
address=member_data['address'],
email=member_data['email'],
)
memberships = member_data.get('memberships')
last = None
for membership in sorted(memberships, key=lambda m: m['membership_start']):
obj = Membership.objects.create(
member=member,
start=parse_date(membership['membership_start']),
amount=Decimal(membership['membership_fee_monthly'])*membership['membership_fee_interval'],
interval=membership['membership_fee_interval'],
)
if last:
last.end = obj.start - timedelta(days=1)
last.save(update_fields=['end'])
last = obj
if member_data['payment_type'].lower() == 'sepa':
_import_sepa(member_data, member)
for key in ['birth_date', 'nick', 'phone_number']:
value = member_data.get(f'profile__{key}')
if value:
setattr(member.profile_profile, key, value)
member.profile_profile.save()
_import_transactions(member_data, member)
class Command(BaseCommand):
help = 'Imports a frab xml export'
def add_arguments(self, parser):
parser.add_argument('path', type=str)
@transaction.atomic
def handle(self, *args, **options):
path = options.get('path')
with open(path) as export:
data = json.load(export)
for member in data:
import_member(member)