Compare commits
2 Commits
2b8d7c9865
...
491eb038ca
| Author | SHA1 | Date | |
|---|---|---|---|
| 491eb038ca | |||
| f5f1bae719 |
264
app/app.py
264
app/app.py
@ -76,10 +76,14 @@ def get_merged_df(table_name):
|
|||||||
stripe_adjustment['norm_date'] = pd.to_datetime(stripe_adjustment['Created'], format='%Y-%m-%d %H:%M')
|
stripe_adjustment['norm_date'] = pd.to_datetime(stripe_adjustment['Created'], format='%Y-%m-%d %H:%M')
|
||||||
stripe_adjustment['norm_amount'] = stripe_adjustment['Amount'].astype(str).str.replace(',', '.').astype(float)
|
stripe_adjustment['norm_amount'] = stripe_adjustment['Amount'].astype(str).str.replace(',', '.').astype(float)
|
||||||
stripe_adjustment['norm_zweck'] = "Korrekturen"
|
stripe_adjustment['norm_zweck'] = "Korrekturen"
|
||||||
|
stripe_adjustment['norm_name'] = "Verrechnung Korrekturen"
|
||||||
|
stripe_adjustment['norm_currency'] = stripe_adjustment['Currency'].astype(str).str.upper()
|
||||||
|
|
||||||
stripe_stripeFee['norm_date'] = pd.to_datetime(stripe_stripeFee['Created'], format='%Y-%m-%d %H:%M')
|
stripe_stripeFee['norm_date'] = pd.to_datetime(stripe_stripeFee['Created'], format='%Y-%m-%d %H:%M')
|
||||||
stripe_stripeFee['norm_amount'] = stripe_stripeFee['Amount'].astype(str).str.replace(',', '.').astype(float)
|
stripe_stripeFee['norm_amount'] = stripe_stripeFee['Amount'].astype(str).str.replace(',', '.').astype(float)
|
||||||
stripe_stripeFee['norm_zweck'] = "Stripe"
|
stripe_stripeFee['norm_zweck'] = "Stripe"
|
||||||
|
stripe_stripeFee['norm_name'] = "Verrechnung Stripe"
|
||||||
|
stripe_stripeFee['norm_currency'] = stripe_stripeFee['Currency'].astype(str).str.upper()
|
||||||
|
|
||||||
# Extract the “py_…” token from stripe_refund description
|
# Extract the “py_…” token from stripe_refund description
|
||||||
stripe_refund['norm_payment_id'] = stripe_refund['Description'].str.extract(r'(py_[A-Za-z0-9]+)')
|
stripe_refund['norm_payment_id'] = stripe_refund['Description'].str.extract(r'(py_[A-Za-z0-9]+)')
|
||||||
@ -92,6 +96,7 @@ def get_merged_df(table_name):
|
|||||||
stripe_charge['norm_date'] = pd.to_datetime(stripe_charge['Created'], format='%Y-%m-%d %H:%M')
|
stripe_charge['norm_date'] = pd.to_datetime(stripe_charge['Created'], format='%Y-%m-%d %H:%M')
|
||||||
stripe_charge['norm_amount'] = stripe_charge['Amount'].astype(str).str.replace(',', '.').astype(float)
|
stripe_charge['norm_amount'] = stripe_charge['Amount'].astype(str).str.replace(',', '.').astype(float)
|
||||||
stripe_charge['norm_email'] = stripe_charge['Customer Email'].fillna('').astype(str)
|
stripe_charge['norm_email'] = stripe_charge['Customer Email'].fillna('').astype(str)
|
||||||
|
stripe_charge['norm_currency'] = stripe_charge['Currency'].astype(str).str.upper()
|
||||||
stripe_charge['norm_name'] = stripe_charge.apply(
|
stripe_charge['norm_name'] = stripe_charge.apply(
|
||||||
lambda r: r['Customer Name'] or r['Details'], axis=1
|
lambda r: r['Customer Name'] or r['Details'], axis=1
|
||||||
)
|
)
|
||||||
@ -110,6 +115,7 @@ def get_merged_df(table_name):
|
|||||||
raisenow['norm_amount'] = raisenow['Betrag'].astype(float)
|
raisenow['norm_amount'] = raisenow['Betrag'].astype(float)
|
||||||
raisenow['norm_email'] = raisenow['E-Mail-Adresse'].astype(str)
|
raisenow['norm_email'] = raisenow['E-Mail-Adresse'].astype(str)
|
||||||
raisenow['norm_name'] = raisenow['Vorname'].astype(str) + ' ' + raisenow['Nachname'].astype(str)
|
raisenow['norm_name'] = raisenow['Vorname'].astype(str) + ' ' + raisenow['Nachname'].astype(str)
|
||||||
|
raisenow['norm_currency'] = raisenow['Währung'].astype(str).str.upper()
|
||||||
|
|
||||||
# start with two‐step assignment
|
# start with two‐step assignment
|
||||||
raisenow['norm_zweck'] = raisenow.apply(
|
raisenow['norm_zweck'] = raisenow.apply(
|
||||||
@ -244,7 +250,7 @@ def get_merged_df(table_name):
|
|||||||
srow = stripe_charge.loc[s_idx].to_dict()
|
srow = stripe_charge.loc[s_idx].to_dict()
|
||||||
rrow = raisenow.loc[r_idx].to_dict()
|
rrow = raisenow.loc[r_idx].to_dict()
|
||||||
# drop any overlapping keys so we never get suffixes
|
# drop any overlapping keys so we never get suffixes
|
||||||
for k in ['norm_amount','norm_name','norm_date','norm_email','idx_stripe']:
|
for k in ['norm_name','norm_date','norm_email','norm_amount','norm_currency','idx_stripe']:
|
||||||
rrow.pop(k, None)
|
rrow.pop(k, None)
|
||||||
# now combine so stripe values win for those keys, and raisenow adds its own columns
|
# now combine so stripe values win for those keys, and raisenow adds its own columns
|
||||||
merged = {**srow, **rrow}
|
merged = {**srow, **rrow}
|
||||||
@ -252,7 +258,7 @@ def get_merged_df(table_name):
|
|||||||
|
|
||||||
combined = pd.DataFrame(merged_rows)
|
combined = pd.DataFrame(merged_rows)
|
||||||
|
|
||||||
starting_columns = ['norm_name', 'norm_date', 'norm_email', 'norm_amount', 'norm_zweck']
|
starting_columns = ['norm_name', 'norm_date', 'norm_email', 'norm_amount', 'norm_currency', 'norm_zweck']
|
||||||
# reorder columns to put the most important ones first
|
# reorder columns to put the most important ones first
|
||||||
combined = pd.concat([
|
combined = pd.concat([
|
||||||
combined[starting_columns],
|
combined[starting_columns],
|
||||||
@ -274,11 +280,15 @@ def get_merged_df(table_name):
|
|||||||
stripe_only = stripe_charge[~stripe_charge['idx_stripe'].isin(used)]
|
stripe_only = stripe_charge[~stripe_charge['idx_stripe'].isin(used)]
|
||||||
result = pd.concat([combined, stripe_only, stripe_adjustment, stripe_stripeFee], ignore_index=True)
|
result = pd.concat([combined, stripe_only, stripe_adjustment, stripe_stripeFee], ignore_index=True)
|
||||||
# add the Stripe fees to the end of the table
|
# add the Stripe fees to the end of the table
|
||||||
|
# Set the timestamp to the last day of the month used by the dataset
|
||||||
|
latest_date = pd.to_datetime(result['norm_date']).max()
|
||||||
|
total_timestamp = pd.Timestamp(year=latest_date.year, month=latest_date.month, day=1) + pd.offsets.MonthEnd(0)
|
||||||
|
total_timestamp = total_timestamp.replace(hour=23, minute=59, second=59, microsecond=0)
|
||||||
new_rows = [
|
new_rows = [
|
||||||
{'norm_zweck': 'Buchungsgebühren', 'norm_amount': total_stripe_charge_fees * (-1)},
|
{'norm_name': 'Verrechnung Gebühren', 'norm_currency': 'EUR', 'norm_date': total_timestamp, 'norm_zweck': 'Buchungsgebühren', 'norm_amount': total_stripe_charge_fees * (-1)},
|
||||||
{'norm_zweck': 'Rückbuchungsgebühren', 'norm_amount': total_stripe_refund_fees * (-1)},
|
{'norm_name': 'Verrechnung Gebühren', 'norm_currency': 'EUR', 'norm_date': total_timestamp, 'norm_zweck': 'Rückbuchungsgebühren', 'norm_amount': total_stripe_refund_fees * (-1)},
|
||||||
{'norm_zweck': 'Korrekturgebühren', 'norm_amount': total_stripe_adjustment_fees * (-1)},
|
{'norm_name': 'Verrechnung Gebühren', 'norm_currency': 'EUR', 'norm_date': total_timestamp, 'norm_zweck': 'Korrekturgebühren', 'norm_amount': total_stripe_adjustment_fees * (-1)},
|
||||||
{'norm_zweck': 'Stripe Gebühren', 'norm_amount': total_stripe_stripeFee_fees * (-1)}
|
{'norm_name': 'Verrechnung Gebühren', 'norm_currency': 'EUR', 'norm_date': total_timestamp, 'norm_zweck': 'Stripe Gebühren', 'norm_amount': total_stripe_stripeFee_fees * (-1)}
|
||||||
]
|
]
|
||||||
new_rows_df = pd.DataFrame(new_rows)
|
new_rows_df = pd.DataFrame(new_rows)
|
||||||
result = pd.concat([result, new_rows_df], ignore_index=True)
|
result = pd.concat([result, new_rows_df], ignore_index=True)
|
||||||
@ -293,6 +303,27 @@ def get_merged_df(table_name):
|
|||||||
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
|
||||||
|
result = result.rename(columns={
|
||||||
|
'norm_name': 'name',
|
||||||
|
'norm_date': 'booking_date',
|
||||||
|
'norm_email': 'E-Mail',
|
||||||
|
'norm_amount': 'amount',
|
||||||
|
'norm_currency': 'currency',
|
||||||
|
'norm_zweck': 'remittance'
|
||||||
|
})
|
||||||
|
|
||||||
|
# copy booking_date to value_date
|
||||||
|
result['value_date'] = result['booking_date']
|
||||||
|
|
||||||
|
|
||||||
|
result['credit_debit'] = result['amount'].apply(lambda x: 'CRDT' if x >= 0 else 'DBIT')
|
||||||
|
|
||||||
else:
|
else:
|
||||||
raise ValueError(f"Unknown table_name '{table_name}'")
|
raise ValueError(f"Unknown table_name '{table_name}'")
|
||||||
|
|
||||||
@ -349,8 +380,8 @@ def get_table():
|
|||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
@app.route('/download')
|
@app.route('/download_xlsx')
|
||||||
def download():
|
def download_xlsx():
|
||||||
sheets = {
|
sheets = {
|
||||||
name: get_merged_df(name)
|
name: get_merged_df(name)
|
||||||
for name in [
|
for name in [
|
||||||
@ -390,6 +421,33 @@ def download():
|
|||||||
mimetype='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
|
mimetype='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/download_mt940')
|
||||||
|
def download_mt940():
|
||||||
|
df = get_merged_df('export')
|
||||||
|
|
||||||
|
mt940_string = generate_mt940(
|
||||||
|
df,
|
||||||
|
account_iban = "11223344/55667788",
|
||||||
|
transaction_ref = "REFEXCELEXPORT",
|
||||||
|
statement_number= "00000",
|
||||||
|
opening_balance = 0.0,
|
||||||
|
txn_code = "NMSC",
|
||||||
|
txn_ref = "NONREF",
|
||||||
|
info_prefix = "169?00RAISENOW??20"
|
||||||
|
)
|
||||||
|
|
||||||
|
output = BytesIO()
|
||||||
|
output.write(mt940_string.encode('utf-8'))
|
||||||
|
output.seek(0)
|
||||||
|
|
||||||
|
return send_file(
|
||||||
|
output,
|
||||||
|
as_attachment=True,
|
||||||
|
download_name='export_mt940.txt',
|
||||||
|
mimetype='text/plain'
|
||||||
|
)
|
||||||
|
|
||||||
@app.route('/clear_session', methods=['POST'])
|
@app.route('/clear_session', methods=['POST'])
|
||||||
def clear_session():
|
def clear_session():
|
||||||
"""
|
"""
|
||||||
@ -398,98 +456,134 @@ def clear_session():
|
|||||||
session.clear()
|
session.clear()
|
||||||
return jsonify({'status': 'session cleared'})
|
return jsonify({'status': 'session cleared'})
|
||||||
|
|
||||||
def export_to_special_format(
|
def wrap_string(text: str, max_length: int = 65) -> str:
|
||||||
df: pd.DataFrame,
|
|
||||||
reference: str,
|
|
||||||
account: str,
|
|
||||||
statement_number: int,
|
|
||||||
opening_date: datetime,
|
|
||||||
opening_balance: float,
|
|
||||||
currency: str,
|
|
||||||
closing_date: datetime = None,
|
|
||||||
closing_balance: float = None
|
|
||||||
) -> str:
|
|
||||||
"""
|
"""
|
||||||
Convert a DataFrame of transactions into the special SWIFT-like file format.
|
Wraps `text` at exactly `max_length` characters, inserting "\r\n" every max_length chars.
|
||||||
|
Existing line breaks are preserved (each line is wrapped separately).
|
||||||
|
"""
|
||||||
|
wrapped_lines = []
|
||||||
|
# split on any existing newline (handles "\n", "\r\n", etc.)
|
||||||
|
for line in text.splitlines():
|
||||||
|
# chop each line into max_length pieces
|
||||||
|
for i in range(0, len(line), max_length):
|
||||||
|
wrapped_lines.append(line[i : i + max_length])
|
||||||
|
# re-join with Windows-style breaks
|
||||||
|
return "\r\n".join(wrapped_lines)
|
||||||
|
|
||||||
|
def generate_mt940(df: pd.DataFrame,
|
||||||
|
account_iban: str,
|
||||||
|
transaction_ref: str,
|
||||||
|
statement_number: str = None,
|
||||||
|
opening_balance: float = 0.0,
|
||||||
|
txn_code: str = 'NMSC',
|
||||||
|
txn_ref: str = 'NONREF',
|
||||||
|
info_prefix: str = None) -> str:
|
||||||
|
"""
|
||||||
|
Generate an MT940 text statement in the “custom” style shown above.
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
df : pd.DataFrame
|
df : pd.DataFrame
|
||||||
Must contain columns:
|
Columns required:
|
||||||
- 'value_date' (datetime)
|
- 'booking_date' (datetime or str YYYY-MM-DD)
|
||||||
- 'booking_date' (datetime)
|
- 'value_date' (datetime or str YYYY-MM-DD)
|
||||||
- 'dc' (str): 'C' for credit, 'D' for debit
|
- 'amount' (float)
|
||||||
- 'amount' (float)
|
- 'currency' (str, e.g. 'EUR')
|
||||||
- optional 'transaction_code' (str)
|
- 'credit_debit' (str, 'CRDT' or 'DBIT')
|
||||||
- optional 'bank_reference' (str)
|
- 'remittance' (str, used inside your info_prefix section)
|
||||||
- 'narrative' (str)
|
- 'name' (str, appended after “?32” in tag 86)
|
||||||
reference : str
|
account_iban : str
|
||||||
Message reference for :20:
|
Goes into tag 25 exactly as you want it (e.g. "11223344/55667788").
|
||||||
account : str
|
transaction_ref : str
|
||||||
Account number for :25:
|
Tag 20 (e.g. "REFEXCELEXPORT")
|
||||||
statement_number : int
|
statement_number : str, optional
|
||||||
Statement sequence for :28C: (will be zero-padded to 5 digits)
|
If given, used verbatim for tag 28C (e.g. "00000"); otherwise falls back to
|
||||||
opening_date : datetime
|
"{transaction_ref}/1"
|
||||||
Opening balance date
|
opening_balance : float, optional
|
||||||
opening_balance : float
|
Starting balance for tag 60F
|
||||||
Opening balance amount (positive)
|
txn_code : str, optional
|
||||||
currency : str
|
The 3-letter code in your :61: line (default "NMSC")
|
||||||
Three-letter currency code (e.g. 'EUR')
|
txn_ref : str, optional
|
||||||
closing_date : datetime, optional
|
The literal reference after that code (default "NONREF")
|
||||||
Closing balance date
|
info_prefix : str, optional
|
||||||
closing_balance : float, optional
|
If you set e.g. "169?00RAISENOW??20", your tag 86 lines become
|
||||||
Closing balance amount (positive)
|
169?00RAISENOW??20<remittance> ?32<name>
|
||||||
|
If you leave it `None`, we fall back to a simple `<name> <remittance>` join.
|
||||||
|
|
||||||
Returns
|
Returns
|
||||||
-------
|
-------
|
||||||
str
|
A single string with CRLF line endings.
|
||||||
The formatted file content.
|
|
||||||
"""
|
"""
|
||||||
|
# normalize & sort
|
||||||
|
df2 = df.copy()
|
||||||
|
df2['value_date'] = pd.to_datetime(df2['value_date'])
|
||||||
|
df2['booking_date'] = pd.to_datetime(df2['booking_date'])
|
||||||
|
df2.sort_values('value_date', inplace=True)
|
||||||
|
|
||||||
|
# constant currency
|
||||||
|
currency = df2['currency'].iat[0]
|
||||||
|
|
||||||
lines = []
|
lines = []
|
||||||
# Header
|
# header
|
||||||
lines.append(f":20:{reference}")
|
lines.append(f":20:{transaction_ref}")
|
||||||
lines.append(f":25:{account}")
|
lines.append(f":25:{account_iban}")
|
||||||
lines.append(f":28C:{statement_number:05d}")
|
if statement_number is None:
|
||||||
|
lines.append(f":28C:{transaction_ref}/1")
|
||||||
|
else:
|
||||||
|
lines.append(f":28C:{statement_number}")
|
||||||
|
|
||||||
# Opening balance :60F:
|
# opening balance
|
||||||
od = opening_date.strftime('%y%m%d')
|
first_dt = df2['value_date'].iat[0]
|
||||||
ob = f"{opening_balance:,.2f}".replace(',', 'X').replace('.', ',').replace('X', '')
|
ob_sign = 'C' if opening_balance >= 0 else 'D'
|
||||||
lines.append(f":60F:C{od}{currency}{ob}")
|
ob_amt = abs(opening_balance)
|
||||||
|
ob_str = f"{ob_amt:.2f}".replace('.', ',')
|
||||||
|
lines.append(f":60F:{ob_sign}{first_dt.strftime('%y%m%d')}{currency}{ob_str}")
|
||||||
|
|
||||||
# Transactions
|
# transactions
|
||||||
for _, row in df.iterrows():
|
for _, row in df2.iterrows():
|
||||||
vd = row['value_date'].strftime('%y%m%d')
|
vd = row['value_date']
|
||||||
bd = row['booking_date'].strftime('%m%d')
|
bd = row['booking_date']
|
||||||
dc = row['dc']
|
sign = 'C' if row['credit_debit']=='CRDT' else 'D'
|
||||||
amt = f"{row['amount']:,.2f}".replace(',', 'X').replace('.', ',').replace('X', '')
|
amt = abs(row['amount'])
|
||||||
tcode = row.get('transaction_code', '')
|
amt_str = f"{amt:.2f}".replace('.', ',')
|
||||||
bref = row.get('bank_reference', '')
|
|
||||||
lines.append(f":61:{vd}{bd}{dc}{amt}{tcode}{bref}")
|
|
||||||
lines.append(f":86:{row['narrative']}")
|
|
||||||
|
|
||||||
# Closing balance :62F:
|
# :61:YYMMDDMMDD[C|D]amount<txn_code><txn_ref>
|
||||||
if closing_date and closing_balance is not None:
|
lines.append(
|
||||||
cd = closing_date.strftime('%y%m%d')
|
f":61:{vd.strftime('%y%m%d')}"
|
||||||
cb = f"{closing_balance:,.2f}".replace(',', 'X').replace('.', ',').replace('X', '')
|
f"{bd.strftime('%m%d')}"
|
||||||
lines.append(f":62F:C{cd}{currency}{cb}")
|
f"{sign}{amt_str}"
|
||||||
|
f"{txn_code}{txn_ref}"
|
||||||
|
)
|
||||||
|
|
||||||
return "\n".join(lines)
|
# :86: either structured or simple fallback
|
||||||
|
raw_rem = row.get('remittance', '')
|
||||||
|
raw_name = row.get('name', '')
|
||||||
|
rem = '' if pd.isna(raw_rem) else str(raw_rem)
|
||||||
|
name = '' if pd.isna(raw_name) else str(raw_name)
|
||||||
|
|
||||||
# Example usage:
|
if info_prefix:
|
||||||
# df = pd.DataFrame([...])
|
# your “169?00RAISENOW??20<remittance> ?32<name>”
|
||||||
# content = export_to_special_format(
|
lines.append(f":86:{info_prefix}{rem} ?32{name}")
|
||||||
# df,
|
else:
|
||||||
# reference='REFEXCELEXPORT',
|
# old-style "<name> <remittance>"
|
||||||
# account='11223344/55667788',
|
info = " ".join(filter(None, [name, rem]))
|
||||||
# statement_number=0,
|
lines.append(f":86:{info}")
|
||||||
# opening_date=datetime(2025,3,6),
|
|
||||||
# opening_balance=0.00,
|
# closing balance
|
||||||
# currency='EUR',
|
net_mv = sum(
|
||||||
# closing_date=datetime(2025,3,6),
|
row['amount'] if row['credit_debit']=='CRDT' else -row['amount']
|
||||||
# closing_balance=12048.71
|
for _, row in df2.iterrows()
|
||||||
# )
|
)
|
||||||
# with open('statement.txt', 'w') as f:
|
closing = opening_balance + net_mv
|
||||||
# f.write(content)
|
cb_sign = 'C' if closing >= 0 else 'D'
|
||||||
|
cb_amt = abs(closing)
|
||||||
|
cb_str = f"{cb_amt:.2f}".replace('.', ',')
|
||||||
|
last_dt = df2['value_date'].iat[-1]
|
||||||
|
lines.append(f":62F:{cb_sign}{last_dt.strftime('%y%m%d')}{currency}{cb_str}")
|
||||||
|
|
||||||
|
file_str = "\r\n".join(lines)
|
||||||
|
|
||||||
|
return wrap_string(file_str)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|||||||
46
app/projects.json
Normal file
46
app/projects.json
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
{
|
||||||
|
"Allgemein": {"project_ID": "000"},
|
||||||
|
"Hilfe für Waisen und Witwen": {"project_ID": "001", "description": "HILFE FÜR WAISEN UND WITWEN - Hilfsaktion für bedürftige Waisen und Witwen. Projektleiter: Wall Nikolaus, 1. Vorsitzender Mobil. 01794740945, CDH-Stephanus e. V., speyer@cdh-stephanus.de, Verwendungszweck: „Hilfe für Waisen und Witwen“"},
|
||||||
|
"Hilfe für Behinderte": {"project_ID": "002", "description": "HILFE FÜR BEHINDERTE - Das Projekt unterstützt Kranke, Behinderte und in Not geratene Menschen. Projektleiter: Andreas und Larissa Stebner Mobil 0151/26602643, Verwendungszweck: „Hilfe für Behinderte“, Infoquelle: Wird meist unproblematisch gleich auf Anfrage zugeschickt oder telefonisch durchgegeben. Projektleitung: Stebner Andrej und Larissa"},
|
||||||
|
"Evangelisation": {"project_ID": "006", "description": "Evangelisation (weltweiter Projekt), Projektleiter: Wall Nikolaus, 1. Vorsitzender Mobil. 01794740945, CDH-Stephanus e. V., speyer@cdh-stephanus.de, Verwendungszweck: Evangelisation"},
|
||||||
|
"Stephanus-Nachrichten": {"project_ID": "008", "description": "MISSIONS – GEMEINDENACHRICHTEN - Seit der Gründung des Hilfswerks „Stephanus“ werden unsere Spender durch die Zeitschrift „Gemeinde- und Missionsnachrichten“ über die Missionsarbeit informiert. Diese Zeitschrift wird durch ehrenamtliche Mitarbeiter von freien Evangeliums-Christengemeinden herausgegeben, Projektleiter: Siegfried Wentland, Tel. +49 421 608274, Verw. Zweck: „Missions-Nachrichten“"},
|
||||||
|
"Hilfe für Äthiopien": {"project_ID": "013", "description": "HILFE FÜR ÄTHIOPIEN - Dieses Projekt soll dazu dienen, der äthiopischen Bevölkerung Zugang zum Trinkwasser, sowie zum Wasser des Lebens Jesus Christus ermöglichen. Projektleiter: Waldemar Schulz (Gem. Buchholz), Mobil 0178/7579350, waldemar-schulz@hotmail.de, Verwendungszweck: „Äthiopien“"},
|
||||||
|
"Hilfe für Verfolgte Christen": {"project_ID": "014", "description": "HILFE FÜR VERFOLGTE CHRISTEN - Dieses Projekt ist für die Unterstützung der verfolgten Christen, für finanzielle und materielle Hilfe, Schulungen von Pastoren und Ausstattung der Gemeinden gedacht. Projektleiter: Alexander Siebert, Mobil 0172/1474429, siebertalexander82@gmail.com, Verwendungszweck: „Verfolgte Christen“"},
|
||||||
|
"Hilfe für Hoffnung für Kinder": {"project_ID": "015", "description": "HILFE FÜR HOFFNUNG FÜR KINDER - Das Projekt „Hoffnung für Kinder Belzy“ wurde für Kinder in der Not in Moldau eröffnet weil viele Familien nicht in der Lage sind, ihren Kindern einen ordentlichen Lebensstandard zu bieten. Projektleiter: Johannes Wiens, Mobil 0176/47086666, jo.bet@web.de, Verwendungszweck: „Hoffnung für Kinder Belzy“, Unterstutzt durch die FECG Mettenheim e.V."},
|
||||||
|
"Hilfe für Mädchenheim Arudpani Sri Lanka": {"project_ID": "016", "description": "HILFE FÜR MÄDCHENHEIM ARUDPANI, SRI LANKA - Seit 2005 unterstützen wir das Mädchenheim „Arudpani“. Im Moment befinden sich ca. 25 Mädchen im Heim wo sie christlich erzogen werden und eine Schulbildung bekommen. Projektleiter: Wall Reinhold, Mobil 0176/29262775, Verwendungszweck: „SL-Arudpani“"},
|
||||||
|
"Hilfe für Kinderheim in Rumänien": {"description": "Mission „Stephanus“ Arbeit in Rumänien durch Hilfsgütern und Finanzen für das Kinderheim „Debora“ in der Stadt Arad, die von den Gemeinden in Molbergen und Pforzheim unterstütz werden. Projektleiter: Ovidio Tiran Mobil 0151/27631582 htt-info@web.de, Verwendungszweck: „Rumänien Hilfe“"},
|
||||||
|
"Hilfe für Uganda": {"project_ID": "018", "description": "HILFE FÜR UGANDA - Im Oktober 2010 wurde durch A. Konradi eine Partnerorganisation (Tochtergesellschaft) von CDH-Stephanus e. V. „Stephanus Uganda“ im Dorf Seeta-Lukinga (Kyewanise) ins Leben gerufen. Dafür wurde ein Grundstück (12,5 Acre) für die Missionsstation gekauft. Das Hauptziel des Projektes ist es, die Lebensbedingungen der Bevölkerungsgruppe der Region (Mpigi District) im Sinne von Armutsbewältigung; sowie „geistlicher“ und körperlicher Gesundheit nachhaltig zu verbessern. Im März 2011 wurde dort ein Wasserbrunnen zur Versorgung von sauberem Wasser gebohrt. Im Jahr 2013 wurde ein Kinderheim errichtet, das zurzeit 35 waise bzw. benachteiligte Kinder beherbergt. Darüber hinaus wurde dort eine Schule errichtet. Durch unser Angebot von ‚Erziehung und Bildung’ ermöglichen wir es den jungen Menschen, beruflichen Beschränkungen auszuweichen. Projektleiter: Albert Hiller Mobil. 0163/6114900, Jack David Kayindu Mobil 0157/30656004, Verwendungszweck: „Uganda“"},
|
||||||
|
"Hilfe für Reha Zentrum Chasara Lechaim in Israel": {"project_ID": "019", "description": "HILFE REHA-ZENTRUM CHASARA LECHAIM IN ISRAEL - Die Mission Stephanus unterstützt in Israel ein Rehabilitationszentrum für Alkohol- und Drogenabhängige. Im Rehabilitationszentrum leben durchschnittlich 10 Personen. Projektleiter: Erich Dojan, Mobil 0172/1390640, erichdojan@gmx.de, Verwendungszweck: „Chasara-Lechaim“, Infoquelle: Infos werden direkt von Eduard Betiev aus Israel geschickt."},
|
||||||
|
"Hilfe für Kinder Pateschaften in Uganda": {"project_ID": "020", "description": "KIINDER PATENSCHAFTEN IN UGANDA - Patenschaften in Form von Heimpatenschaften und Schulpatenschaften möglich! Projektleiter: Alexander Penkowski Mobil. 0177/4756150, Jack David Kayindu Mobil 0157/30656004, Verwendungszweck: „Kinderpatenschaft Uganda“"},
|
||||||
|
"Hilfe für Gemeinde in Israel": {"project_ID": "021", "description": "HILFE FÜR GEMEINDE IN ISRAEL - Die Mission Stephanus unterstützt in Israel eine Gemeinde und dadurch die Evangelisation und ein Rehabilitationszentrum für Alkohol- und Drogenabhängige. Im Rehabilitationszentrum leben durchschnittlich 5 Personen. Infoquelle: Infos werden direkt aus Israel von Valentin Negura zugeschickt. Projektleiter: Viktor Folz, Mobil 0175/2400696, viktor.folz58@gmail.com, Verwendungszweck: „Israel“, Verantwortliche in Israel: Kisselyov Valery, Leiter der Mission „Teiwat apachamim“, Maalot, Str. Snir 5 / 3 Box 7314, Israel, E-Mail maalot98@yandex.ru und Valentin Negura, der Gemeindeverantwortliche in Maalot"},
|
||||||
|
"Missionar Kellinger": {"project_ID": "022", "description": "Im Januar 2022 reiste das junge Ehepaar Samuel und Eva Kellinger mit ihrem kleinen Sohn nach Uganda. Vor Ort betreuten sie das Stephanus-Projekt. Er leistet zusammen mit einem Pastor Gemeinde und Jugendarbeit. Projektleiter: Matthias Krüger, Verwendungszweck: „Missionar in Afrika“"},
|
||||||
|
"Liebe drängt uns... (Buch": {"project_ID": "023"},
|
||||||
|
"Konferen": {"project_ID": "024"},
|
||||||
|
"Hilfe für Togo": {"project_ID": "025", "description": "PROJEKT TOGO – Hilfe für WESTAFRIKA - Togo (Westafrika) – Hilfe zur Selbsthilfe (Getreideanbau, Viehzucht), Die Gemeinde Ulmen unterstützt das Projekt in Togo in Zusammenarbeit mit dem einheimischen Pastor Williams. Ziel dieses Projekts sind der Gemeindeaufbau und die Evangelisation. Außerdem werden Waisenkinder oder Halbwaisen unterstützt. Projektleiter: Paul Altmann, Tel. 0176 46046914, paulaltmann65@gmail.com, Verwendungszweck: „TOGO“"},
|
||||||
|
"Missionar Hense": {"project_ID": "026"},
|
||||||
|
"Hilfe für Kurzfristige Projekte - div. Gemeinden": {"project_ID": "034", "description": "Kurzfristige Projekte - Hilfsaktion für bedürftige, kranke oder in Not geratene Menschen, Projektleiter: Wall Nikolaus, 1. Vorsitzender Mobil. 01794740945, CDH-Stephanus e. V., speyer@cdh-stephanus.de, Verwendungszweck: Aktuelle Not, z. B. Hausbrandt Fam. XY"},
|
||||||
|
"Hilfe für Katastrophen und Kriege": {"project_ID": "035", "description": "HILFE FÜR KATASTROPHEN & KRIEGE - Eine Katastrophe ist immer ein unerwartetes Ereignis, bei dem zahlreiche Menschen getötet oder verletzt werden, oder aber ihr Eigentum beschädigt oder zerstört wird. Es gibt Hilfseinsätze nach Naturkatastrophen, technischen Unfällen (Brand, Explosionen), terroristischen Anschlägen und kriegerischen Ereignissen. Es muss sofort gehandelt werden, daher ist eine Rücklage für dieses Projekt notwendig. Projektleiter: Mission Stephanus e. V., speyer@cdh-stephanus.de Tel. 06232-9191555, Verwendungszweck: „Katastrophen & Kriege“ mit einem aktuellen Hinweis z.B. Hochwasser"},
|
||||||
|
"Erdbeben Türkei/Syrien": {"project_ID": "036", "description": "ERDBEBEN IN DER TÜRKEI / SYRIEN - Eine Katastrophe ist immer ein unerwartetes Ereignis, bei dem zahlreiche Menschen getötet oder verletzt werden, oder aber ihr Eigentum beschädigt oder zerstört wird. Es muss sofort gehandelt werden, daher ist eine Rücklage für dieses Projekt notwendig. Projektleiter: Mission Stephanus e. V., speyer@cdh-stephanus.de Tel. 06232-9191555, Verwendungszweck: „Erdbeben Türkei“"},
|
||||||
|
"Hilfe für Weihnachtsaktion": {"project_ID": "044", "description": "HILFE FÜR WEIHNACHTSAKTION - Projektleiter: Mission Stephanus e. V., speyer@cdh-stephanus.de Tel. 06232-9191555, Verwendungszweck: „Weihnachtsaktion"},
|
||||||
|
"Hilfe für Freizeit an Gehörlose": {"project_ID": "045", "description": "Freizeit für Gehörlose, Projektleiter: Wall Nikolaus, 1. Vorsitzender Mobil. 01794740945, CDH-Stephanus e. V., speyer@cdh-stephanus.de, Verwendungszweck: Verwendungszweck: Freizeit Gehörlose"},
|
||||||
|
"Hilfe für Kirgisien": {"project_ID": "050", "description": "Hilfe für Kirgisien, Projektleiter: Wall Nikolaus, 1. Vorsitzender Mobil. 01794740945, CDH-Stephanus e. V., speyer@cdh-stephanus.de, Verwendungszweck: Verwendungszweck: Kirgisien"},
|
||||||
|
"Hilfe für Rybnitza": {"project_ID": "050", "description": "Hilfe für Rybniza/Projektleiter vor Ort Panchina, Projektleiter: Wall Nikolaus, 1. Vorsitzender Mobil. 01794740945, CDH-Stephanus e. V., speyer@cdh-stephanus.de, Verwendungszweck: Verwendungszweck: Panchina"},
|
||||||
|
"Hilfe für Chisinau / Altenheim": {"project_ID": "053", "description": "HILFE FÜR CHISINAU IN MOLDAU - Projektleiter: Wassiljew Jakob Mob. 0162/1077390, wassiljew@icloud.com, Verwendungszweck: „Altenheim Sarepta“"},
|
||||||
|
"Hilfe Save Haus Talita (Äthiopien)": {"description": "Projektstart gescheitert und wird gelöscht"},
|
||||||
|
"Hilfe für Nischnij Novgorod (Russischeföderation)": {},
|
||||||
|
"Hilfe für Rehazentrum und neue Gemeinde in Nischni Novgorod (Baschmakov Andrej": {"project_ID": "050", "description": "Hilfe für Nischnij Novgorod (Russische Föderation), Projektleiter: Wall Nikolaus, 1. Vorsitzender Mobil. 01794740945, CDH-Stephanus e. V., speyer@cdh-stephanus.de, Verwendungszweck: Nischnij Novgorod"},
|
||||||
|
"Hilfe für Kurzfristige Kranke": {"project_ID": "069", "description": "Hilfe für Kranke (Sofothilfe für Kranke (Medikamente, Prothesen, OPs), Projektleiter: Wall Nikolaus, 1. Vorsitzender Mobil. 01794740945, CDH-Stephanus e. V., speyer@cdh-stephanus.de, Verwendungszweck: Sofothilfe für Kranke (Medikamente, Prothesen, OPs)"},
|
||||||
|
"Hilfe für Haus der Barmerzigkeut „Phildelphia“": {"project_ID": "071", "description": "Haus der Barmherzigkeit „PHiladelphia“ in Krivoj Rog, Ukraine, Projektleiter: Waldemar Just, Mobil. 0152 21554953 oder 06232/98668, CDH-Stephanus e. V., speyer@cdh-stephanus.de, Verwendungszweck: Philadelphia"},
|
||||||
|
"Hilfe für Fond Notleidende kinder": {"project_ID": "072", "description": "HILFE FÜR FOND NOTLEIDENDE KINDER - Fond Notleidenden Kinder ist seit 2000 tätig. Der Fond hat 16 Stammpunkte in Schulen, Gebetshäusern und christlichen Familien in denen insgesamt ca. 500 Kinder versorgt werden. Bei einem Stammpunkt bekommen die Kinder fünf Mal pro Woche geistige Nahrung und eine warme Mahlzeit (3 Gänge Menü). Projektleiter: Oleg Bogun, Tel. 0571/3988488, Mobil 0160/1232013, Spendenkonto: Stephanus e. V., Sparkasse Binden-Lübbecke, IBAN: DE56490501010040104671, BIC: WELADED1MI"},
|
||||||
|
"Hilfe für Kinder Patenschaften in Indien": {"project_ID": "075", "description": "KINDERPATENSCHAFTEN IN INDIEN - Seit der Gründung des CDH-Stephanus e. V. werden die Kinderpatenschaften in Indien in Zusammenarbeit mit der Inter-Mission im Hannover übernommen. Projektleiter: Witali Holstein, Tel. 04475/928366, witali.holstein@ewetel.net, Spendenkonto: Stephanus e. V., Old. Land. Bank, IBAN: DE25 2802 0050 3223 8396 00, BIC: OLBODEH2XXX"},
|
||||||
|
"Hilfe für Kinderheim in Philiphinen": {"project_ID": "076", "description": "Hilfe für Kinderheim in Philiphinen, Projektleiter: Markus Rutz, Tel. 01743214617, Verwendungszweck: „Philippinen Kinderheim“, Infos auf Anfrage"},
|
||||||
|
"Schule Manipur": {"project_ID": "077", "description": "Christliche Schule in Manipur Indien für Volksstämme der Tankul Bevölkerung. Projektleiter: Leo Altmann Ulmen"},
|
||||||
|
"Hilfe für Strahl der Hoffnung in Lrttland & UK": {"project_ID": "080", "description": "STRAHL DER HOFFNUNG IN LETTLAND & UKRAINE - Seit 2014 wird in Liepāja, Lettland in einem Haus Arbeit unter Straßenkindern geführt. Seit 2015 unterstützt „Strahl der Hoffnung“ die Arbeit in der Gebiet Cherson, Ukraine. In 5 Dörfern einmal in der Woche werden insgesamt bis zu 80 Kinder mit den warmen Essen versorgt. Projektleiter: Viktor Dalinger, Mobil 0178/4372310, v.f.dali@googlemail.com, Willi Krüger, Mobil 0176/84527187, willikrueger@gmx.de, Verwendungszweck: „Strahl der Hoffnung"},
|
||||||
|
"Hilfe für Bulgarien": {"project_ID": "085", "description": "HILFE FÜR BULGARIEN /Betreuung Gemeinde Speyer/Das Projekt „Jesus für Bulgarien“. Mit Hilfe der Gemeinde in Speyer werden seit 2012 Sachspenden und Lebensmittel sowie finanziell Hilfebedürftige unterstützt. Ziel ist der Aufbau von Gemeinden im Land und weiterhin diakonische Unterstützung von Bedürftigen. Projektleiter: Betz Reinhold, Mobil 0176/63399968, reinholdbetz@web.de, Gesswein Walter, Mobil 0176/70138468, w.gesswein@hotmail.de, Verwendungszweck:"},
|
||||||
|
"Brüderkasse": {"project_ID": "090", "description": "Projektleiter: Wall Nikolaus, 1. Vorsitzender Mobil. 01794740945, CDH-Stephanus e. V., speyer@cdh-stephanus.de"},
|
||||||
|
"Missionsreise": {"project_ID": "095", "description": "Alle Reisen die nicht mit einem bestimmten Projekt verbunden sind."},
|
||||||
|
"Reisen Projekt Verfolgte Christen": {"project_ID": "205", "description": "HILFE FÜR VERFOLGTE CHRISTEN - Dieses Projekt ist für die Unterstützung der verfolgten Christen, für finanzielle und materielle Hilfe, Schulungen von Pastoren und Ausstattung der Gemeinden gedacht. Projektleiter: Alexander Siebert, Mobil 0172/1474429, siebertalexander82@gmail.com, Verwendungszweck: „Verfolgte Christen“"},
|
||||||
|
"Reisen Äthiopie": {"project_ID": "213"},
|
||||||
|
"Reisen Sri Lanka": {"project_ID": "216", "description": "Missions-Reisegruppen nach Sri Lanka, Projektleiter: Irina Jähger Tel. 0172/1474429, Verwendungszweck: Namen_Vorname_Sri Lanka"},
|
||||||
|
"Reisen Uganda": {"project_ID": "218", "description": "Missions-Reisegruppen nach Uganda, Projektleiter: Irina Jähger Tel. 0172/1474429, Verwendungszweck: Namen_Vorname_Ugandareise"}
|
||||||
|
}
|
||||||
@ -40,16 +40,17 @@
|
|||||||
<button type="submit" class="btn btn-primary btn-sm">Upload</button>
|
<button type="submit" class="btn btn-primary btn-sm">Upload</button>
|
||||||
</form>
|
</form>
|
||||||
<button id="download-excel" class="btn btn-success btn-sm me-3">Excel Download</button>
|
<button id="download-excel" class="btn btn-success btn-sm me-3">Excel Download</button>
|
||||||
|
<button id="download-mt940" class="btn btn-info btn-sm me-3">MT940 Download</button>
|
||||||
<button id="clear-session" class="btn btn-warning btn-sm me-3">Daten löschen</button>
|
<button id="clear-session" class="btn btn-warning btn-sm me-3">Daten löschen</button>
|
||||||
<div class="d-flex align-items-center">
|
<div class="d-flex align-items-center">
|
||||||
<label for="table-select" class="form-label me-2 mb-0">Table:</label>
|
<label for="table-select" class="form-label me-2 mb-0">Table:</label>
|
||||||
<select id="table-select" class="form-select form-select-sm">
|
<select id="table-select" class="form-select form-select-sm">
|
||||||
|
<option value="export">Export</option>
|
||||||
<option value="stripe_import">Stripe Import</option>
|
<option value="stripe_import">Stripe Import</option>
|
||||||
<option value="raiseNow_import">RaiseNow Import</option>
|
<option value="raisenow_import">RaiseNow Import</option>
|
||||||
<option value="merged">Merged</option>
|
<option value="merged">Merged</option>
|
||||||
<option value="stripe_only">Stripe Only</option>
|
<option value="stripe_only">Stripe Only</option>
|
||||||
<option value="raisenow_only">RaiseNow Only</option>
|
<option value="raisenow_only">RaiseNow Only</option>
|
||||||
<option value="export">Export</option>
|
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -73,7 +74,9 @@
|
|||||||
<script>
|
<script>
|
||||||
const uploadForm = document.getElementById('upload-form');
|
const uploadForm = document.getElementById('upload-form');
|
||||||
const tableSelect = document.getElementById('table-select');
|
const tableSelect = document.getElementById('table-select');
|
||||||
const downloadBtn = document.getElementById('download-excel');
|
const download_xlsx_btn = document.getElementById('download-excel');
|
||||||
|
const download_camt_btn = document.getElementById('download-camt');
|
||||||
|
const download_mt940_btn = document.getElementById('download-mt940');
|
||||||
const clearBtn = document.getElementById('clear-session');
|
const clearBtn = document.getElementById('clear-session');
|
||||||
const loadingOverlay = document.getElementById('loadingOverlay');
|
const loadingOverlay = document.getElementById('loadingOverlay');
|
||||||
let table;
|
let table;
|
||||||
@ -96,10 +99,10 @@
|
|||||||
|
|
||||||
tableSelect.addEventListener('change', () => loadTable(tableSelect.value));
|
tableSelect.addEventListener('change', () => loadTable(tableSelect.value));
|
||||||
|
|
||||||
downloadBtn.addEventListener('click', async () => {
|
download_xlsx_btn.addEventListener('click', async () => {
|
||||||
showLoading();
|
showLoading();
|
||||||
try {
|
try {
|
||||||
const resp = await fetch('/download');
|
const resp = await fetch('/download_xlsx');
|
||||||
if (!resp.ok) throw new Error('Download failed');
|
if (!resp.ok) throw new Error('Download failed');
|
||||||
const blob = await resp.blob();
|
const blob = await resp.blob();
|
||||||
const url = URL.createObjectURL(blob);
|
const url = URL.createObjectURL(blob);
|
||||||
@ -117,6 +120,27 @@
|
|||||||
} finally { hideLoading(); }
|
} finally { hideLoading(); }
|
||||||
});
|
});
|
||||||
|
|
||||||
|
download_mt940_btn.addEventListener('click', async () => {
|
||||||
|
showLoading();
|
||||||
|
try {
|
||||||
|
const resp = await fetch('/download_mt940');
|
||||||
|
if (!resp.ok) throw new Error('Download failed');
|
||||||
|
const blob = await resp.blob();
|
||||||
|
const url = URL.createObjectURL(blob);
|
||||||
|
const a = document.createElement('a');
|
||||||
|
a.href = url;
|
||||||
|
const disposition = resp.headers.get('Content-Disposition') || '';
|
||||||
|
const match = disposition.match(/filename="?([^";]+)"?/);
|
||||||
|
a.download = match ? match[1] : 'mt940.txt';
|
||||||
|
document.body.appendChild(a);
|
||||||
|
a.click();
|
||||||
|
a.remove();
|
||||||
|
URL.revokeObjectURL(url);
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err); alert(err.message);
|
||||||
|
} finally { hideLoading(); }
|
||||||
|
});
|
||||||
|
|
||||||
clearBtn.addEventListener('click', async () => {
|
clearBtn.addEventListener('click', async () => {
|
||||||
if (!confirm('Are you sure you want to clear the server session? This will reset all loaded data.')) return;
|
if (!confirm('Are you sure you want to clear the server session? This will reset all loaded data.')) return;
|
||||||
showLoading();
|
showLoading();
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user