optimize and clean up

This commit is contained in:
lelo 2025-05-28 15:32:52 +00:00
parent 491eb038ca
commit 5333f111dd

View File

@ -302,27 +302,24 @@ def get_merged_df(table_name):
for i, row in result.iterrows(): for i, row in result.iterrows():
if (pd.isna(row.get('norm_email')) or row.get('norm_email') == '') and pd.notna(row.get('E-Mail-Adresse')): if (pd.isna(row.get('norm_email')) or row.get('norm_email') == '') and pd.notna(row.get('E-Mail-Adresse')):
result.at[i, 'norm_email'] = f"{row.get('E-Mail-Adresse')}".strip() result.at[i, 'norm_email'] = f"{row.get('E-Mail-Adresse')}".strip()
# only keep required columns
result = result[[
'norm_name', 'norm_date', 'norm_email', 'norm_amount','norm_currency', 'norm_zweck'
]]
# rename columns to match CAMT format # rename columns
result = result.rename(columns={ result = result.rename(columns={
'norm_name': 'name', 'norm_name': 'name',
'norm_date': 'booking_date', 'norm_date': 'booking_date',
'norm_email': 'E-Mail', 'norm_email': 'email',
'norm_amount': 'amount', 'norm_amount': 'amount',
'norm_currency': 'currency', 'norm_currency': 'currency',
'norm_zweck': 'remittance' 'norm_zweck': 'reference'
}) })
# copy booking_date to value_date # add sign column based on amount
result['value_date'] = result['booking_date'] result['sign'] = result['amount'].apply(lambda x: 'CRDT' if x >= 0 else 'DBIT')
# sort columns
result['credit_debit'] = result['amount'].apply(lambda x: 'CRDT' if x >= 0 else 'DBIT') result = result[[
'booking_date', 'name', 'email', 'amount', 'currency', 'sign', 'reference'
]]
else: else:
raise ValueError(f"Unknown table_name '{table_name}'") raise ValueError(f"Unknown table_name '{table_name}'")
@ -486,11 +483,10 @@ def generate_mt940(df: pd.DataFrame,
df : pd.DataFrame df : pd.DataFrame
Columns required: Columns required:
- 'booking_date' (datetime or str YYYY-MM-DD) - 'booking_date' (datetime or str YYYY-MM-DD)
- 'value_date' (datetime or str YYYY-MM-DD)
- 'amount' (float) - 'amount' (float)
- 'currency' (str, e.g. 'EUR') - 'currency' (str, e.g. 'EUR')
- 'credit_debit' (str, 'CRDT' or 'DBIT') - 'sign' (str, 'CRDT' or 'DBIT')
- 'remittance' (str, used inside your info_prefix section) - 'reference' (str, used inside your info_prefix section)
- 'name' (str, appended after ?32 in tag 86) - 'name' (str, appended after ?32 in tag 86)
account_iban : str account_iban : str
Goes into tag 25 exactly as you want it (e.g. "11223344/55667788"). Goes into tag 25 exactly as you want it (e.g. "11223344/55667788").
@ -507,8 +503,8 @@ def generate_mt940(df: pd.DataFrame,
The literal reference after that code (default "NONREF") The literal reference after that code (default "NONREF")
info_prefix : str, optional info_prefix : str, optional
If you set e.g. "169?00RAISENOW??20", your tag 86 lines become If you set e.g. "169?00RAISENOW??20", your tag 86 lines become
169?00RAISENOW??20<remittance> ?32<name> 169?00RAISENOW??20<reference> ?32<name>
If you leave it `None`, we fall back to a simple `<name> <remittance>` join. If you leave it `None`, we fall back to a simple `<name> <reference>` join.
Returns Returns
------- -------
@ -516,9 +512,8 @@ def generate_mt940(df: pd.DataFrame,
""" """
# normalize & sort # normalize & sort
df2 = df.copy() df2 = df.copy()
df2['value_date'] = pd.to_datetime(df2['value_date'])
df2['booking_date'] = pd.to_datetime(df2['booking_date']) df2['booking_date'] = pd.to_datetime(df2['booking_date'])
df2.sort_values('value_date', inplace=True) df2.sort_values('booking_date', inplace=True)
# constant currency # constant currency
currency = df2['currency'].iat[0] currency = df2['currency'].iat[0]
@ -533,7 +528,7 @@ def generate_mt940(df: pd.DataFrame,
lines.append(f":28C:{statement_number}") lines.append(f":28C:{statement_number}")
# opening balance # opening balance
first_dt = df2['value_date'].iat[0] first_dt = df2['booking_date'].iat[0]
ob_sign = 'C' if opening_balance >= 0 else 'D' ob_sign = 'C' if opening_balance >= 0 else 'D'
ob_amt = abs(opening_balance) ob_amt = abs(opening_balance)
ob_str = f"{ob_amt:.2f}".replace('.', ',') ob_str = f"{ob_amt:.2f}".replace('.', ',')
@ -541,44 +536,43 @@ def generate_mt940(df: pd.DataFrame,
# transactions # transactions
for _, row in df2.iterrows(): for _, row in df2.iterrows():
vd = row['value_date']
bd = row['booking_date'] bd = row['booking_date']
sign = 'C' if row['credit_debit']=='CRDT' else 'D' sign = 'C' if row['sign']=='CRDT' else 'D'
amt = abs(row['amount']) amt = abs(row['amount'])
amt_str = f"{amt:.2f}".replace('.', ',') amt_str = f"{amt:.2f}".replace('.', ',')
# :61:YYMMDDMMDD[C|D]amount<txn_code><txn_ref> # :61:YYMMDDMMDD[C|D]amount<txn_code><txn_ref>
lines.append( lines.append(
f":61:{vd.strftime('%y%m%d')}" f":61:{bd.strftime('%y%m%d')}"
f"{bd.strftime('%m%d')}" f"{bd.strftime('%m%d')}"
f"{sign}{amt_str}" f"{sign}{amt_str}"
f"{txn_code}{txn_ref}" f"{txn_code}{txn_ref}"
) )
# :86: either structured or simple fallback # :86: either structured or simple fallback
raw_rem = row.get('remittance', '') raw_rem = row.get('reference', '')
raw_name = row.get('name', '') raw_name = row.get('name', '')
rem = '' if pd.isna(raw_rem) else str(raw_rem) rem = '' if pd.isna(raw_rem) else str(raw_rem)
name = '' if pd.isna(raw_name) else str(raw_name) name = '' if pd.isna(raw_name) else str(raw_name)
if info_prefix: if info_prefix:
# your “169?00RAISENOW??20<remittance> ?32<name>” # your “169?00RAISENOW??20<reference> ?32<name>”
lines.append(f":86:{info_prefix}{rem} ?32{name}") lines.append(f":86:{info_prefix}{rem} ?32{name}")
else: else:
# old-style "<name> <remittance>" # old-style "<name> <reference>"
info = " ".join(filter(None, [name, rem])) info = " ".join(filter(None, [name, rem]))
lines.append(f":86:{info}") lines.append(f":86:{info}")
# closing balance # closing balance
net_mv = sum( net_mv = sum(
row['amount'] if row['credit_debit']=='CRDT' else -row['amount'] row['amount'] if row['sign']=='CRDT' else -row['amount']
for _, row in df2.iterrows() for _, row in df2.iterrows()
) )
closing = opening_balance + net_mv closing = opening_balance + net_mv
cb_sign = 'C' if closing >= 0 else 'D' cb_sign = 'C' if closing >= 0 else 'D'
cb_amt = abs(closing) cb_amt = abs(closing)
cb_str = f"{cb_amt:.2f}".replace('.', ',') cb_str = f"{cb_amt:.2f}".replace('.', ',')
last_dt = df2['value_date'].iat[-1] last_dt = df2['booking_date'].iat[-1]
lines.append(f":62F:{cb_sign}{last_dt.strftime('%y%m%d')}{currency}{cb_str}") lines.append(f":62F:{cb_sign}{last_dt.strftime('%y%m%d')}{currency}{cb_str}")
file_str = "\r\n".join(lines) file_str = "\r\n".join(lines)