2018-01-11 18:54:42 +01:00
import csv
2018-03-03 18:57:54 +01:00
import os . path
2018-01-11 18:54:42 +01:00
import re
2018-01-13 13:05:49 +01:00
from datetime import datetime
2018-01-11 18:54:42 +01:00
from decimal import Decimal
2018-01-11 20:20:05 +01:00
from django . dispatch import receiver
2018-01-11 19:24:13 +01:00
from django . utils . timezone import now
2018-03-03 18:57:54 +01:00
from django . conf import settings
2018-01-11 18:54:42 +01:00
2018-01-13 13:05:49 +01:00
from byro . bookkeeping . models import (
Account , AccountCategory , RealTransaction ,
TransactionChannel , VirtualTransaction ,
)
from byro . bookkeeping . signals import (
derive_virtual_transactions , process_csv_upload ,
)
2018-01-11 19:24:13 +01:00
from byro . members . models import Member
2018-01-11 18:54:42 +01:00
2018-01-13 13:05:49 +01:00
@receiver ( process_csv_upload )
2018-01-13 12:38:49 +01:00
def process_bank_csv ( sender , signal , * * kwargs ) :
source = sender
2018-03-03 18:57:54 +01:00
filename = os . path . join ( settings . MEDIA_ROOT , source . source_file . name )
reader = csv . DictReader ( open ( filename , encoding = ' iso-8859-1 ' ) , delimiter = ' ; ' , quotechar = ' " ' )
2018-01-11 19:24:13 +01:00
booking_timestamp = now ( )
2018-01-11 18:54:42 +01:00
2018-01-11 19:24:13 +01:00
for line in reader :
if not line :
continue
reference = ' '
for key in line . keys ( ) :
if key . startswith ( ' VWZ ' ) :
2018-01-11 20:20:05 +01:00
reference + = line [ key ] + ' '
2018-01-11 18:54:42 +01:00
2018-01-13 13:52:59 +01:00
RealTransaction . objects . get_or_create (
2018-01-11 19:24:13 +01:00
channel = TransactionChannel . BANK ,
value_datetime = datetime . strptime ( line . get ( ' Buchungstag ' ) , ' %d . % m. % Y ' ) ,
amount = Decimal ( line . get ( ' Betrag ' ) . replace ( ' . ' , ' ' ) . replace ( ' , ' , ' . ' ) ) ,
purpose = reference ,
2018-01-11 20:20:05 +01:00
originator = line . get ( ' Auftraggeber/Empfänger ' , ' <leer> ' ) ,
2018-01-11 19:24:13 +01:00
importer = ' shack_bank_csv_importer ' ,
2018-01-13 19:14:00 +01:00
defaults = { ' source ' : source , ' booking_datetime ' : booking_timestamp , ' data ' : line } ,
2018-01-11 19:24:13 +01:00
)
2018-01-13 13:05:49 +01:00
return True
2018-01-11 18:54:42 +01:00
2018-01-11 20:20:16 +01:00
@receiver ( derive_virtual_transactions )
2018-01-13 12:38:49 +01:00
def match_transaction ( sender , signal , * * kwargs ) :
transaction = sender
2018-01-13 13:05:49 +01:00
uid , score = reference_parser ( reference = transaction . purpose )
2018-01-11 19:24:13 +01:00
member = None
try :
2018-01-11 20:20:16 +01:00
member = Member . objects . get ( number = uid )
2018-01-11 19:24:13 +01:00
except Member . DoesNotExist :
2018-01-11 20:20:16 +01:00
return
account = Account . objects . get ( account_category = AccountCategory . MEMBER_FEES )
data = {
' amount ' : transaction . amount ,
2018-01-13 13:05:49 +01:00
' destination_account ' : account ,
' value_datetime ' : transaction . value_datetime ,
2018-01-11 20:20:16 +01:00
' member ' : member ,
}
virtual_transaction = VirtualTransaction . objects . filter ( * * data ) . first ( )
if virtual_transaction and virtual_transaction . real_transaction != transaction :
raise Exception ( f ' RealTransaction { transaction . id } cannot be matched! There is already a VirtualTransaction ( { virtual_transaction . id } ) that is too similar. It is matched to RealTransaction { virtual_transaction . real_transaction . id } . ' )
if not virtual_transaction :
data [ ' real_transaction ' ] = transaction
virtual_transaction = VirtualTransaction . objects . create ( * * data )
return [ virtual_transaction ]
2018-01-11 18:54:42 +01:00
2018-01-13 13:05:49 +01:00
def reference_parser ( reference ) :
2018-01-11 19:24:13 +01:00
reference = reference . lower ( )
2018-01-11 18:54:42 +01:00
2018-01-11 19:24:13 +01:00
regexes = (
r ' .*mitgliedsbeitrag \ s+id \ s+(?P<ID> \ d { 1,4}) \ s.* ' ,
r ' .*id \ s+(?P<ID> \ d { 1,4}) \ smitgliedsbeitrag.* ' ,
# r'.*id\s+(?P<ID>\d{1,4})\s.*',
r ' .*mitgliedsbeitrag.*id \ s+(?P<ID> \ d { 1,4}) \ s.* ' ,
r ' .*mitgliedsbeitrag \ s+(?P<ID> \ d { 1,4}) \ s.* ' ,
r ' .*beitrag \ s+mitglied \ s+(?P<ID> \ d { 1,4}) \ s.* ' ,
r ' .*mitgliedsbeitrag.* \ s+(?P<ID> \ d { 1,4})[^ \ d].* ' ,
# r'.*id(?P<ID>\d{1,4})\s+zr\d+.*',
# r'.*id\s+(?P<ID>\d{1,4}),\s+zr\s+\d+.*',
r ' .*mitgliedsbeitrag \ s+id[.:-_](?P<ID> \ d { 1,4}) \ s.* ' ,
)
2018-01-11 18:54:42 +01:00
2018-01-11 19:24:13 +01:00
for score , regex in enumerate ( regexes , 1 ) :
hit = re . match ( regex , reference )
if hit :
return ( int ( hit . groupdict ( ) . get ( ' ID ' ) ) , score )
2018-01-11 18:54:42 +01:00
2018-01-11 19:24:13 +01:00
return ( False , 99 )