mailings
This commit is contained in:
parent
d5bd37adfa
commit
99a7997818
6 changed files with 271 additions and 112 deletions
31
mail_templates/beitrag.eml
Normal file
31
mail_templates/beitrag.eml
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
Hallo {{ invoice.party.name }},
|
||||||
|
|
||||||
|
für deine ordentliche Mitgliedschaft im Chaos Computer Club Bremen e.V. ist ein Mitgliedsbeitrag fällig. Für das Beitragsjahr {{ year.year }} beträgt der monatliche Beitrag {{ monthly_fee }} €. Dieser Beitrag ist jeweils zu Beginn des Monats fällig.
|
||||||
|
|
||||||
|
Wir berechnen dir daher die folgenden Mitgliedsbeiträge:
|
||||||
|
{% for line in invoice.lines %}
|
||||||
|
{{ line.description.ljust(50) }} {{ "{: >.2f}".format(line.unit_price) }} €
|
||||||
|
{%- endfor %}
|
||||||
|
|
||||||
|
{% if sepa_mandate -%}
|
||||||
|
Wir werden deine Mitgliedsbeiträge per SEPA-Lastschrift von deinem Konto mit der IBAN {{ sepa_mandate.account_number.number }} zu den folgenden Terminen einziehen:
|
||||||
|
|
||||||
|
{% for payment in invoice.lines_to_pay if not payment.reconiciliation and payment.payable_receivable_balance %}
|
||||||
|
{{ payment.maturity_date }} {{ "{: >.2f}".format(payment.amount) }} €
|
||||||
|
{%- endfor %}
|
||||||
|
{% else -%}
|
||||||
|
Bitte überweise deine Mitgliedsbeiträge fristgerecht auf unser Konto:
|
||||||
|
|
||||||
|
Kontoinhaber: Chaos Computer Club Bremen e.V.
|
||||||
|
IBAN: DE28 4306 0967 2027 5271 00
|
||||||
|
Bank: GLS Gemeinschaftsbank eG
|
||||||
|
BIC: GENODEM1GLS
|
||||||
|
Verwendungszweck: Beitrag {{ invoice.party.name }}
|
||||||
|
|
||||||
|
Du kannst den Beitrag für das gesamte Jahr {{ year.year }} im Voraus überweisen.
|
||||||
|
{%- endif %}
|
||||||
|
|
||||||
|
Viele Grüße,
|
||||||
|
der Vorstand
|
||||||
|
|
||||||
|
i.A. {{ sender }}
|
21
mail_templates/sepa_mandat.eml
Normal file
21
mail_templates/sepa_mandat.eml
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
Hallo {{ party.name }},
|
||||||
|
|
||||||
|
anbei erhälst du eine Abschrift des SEPA-Lastschriftmandats mit der Mandatsreferenz „{{ sepa_mandate.identification }}“, das zum Einzug deiner Mitgliedsbeiträge bei uns gespeichert ist.
|
||||||
|
|
||||||
|
Name des Zahlungsempfängers:
|
||||||
|
Chaos Computer Club Bremen e.V.
|
||||||
|
Anschrift des Zahlungsempfängers:
|
||||||
|
Konsul-Smidt-Straße 43, 28217 Bremen, Deutschland
|
||||||
|
Gläubiger-Identifikationsnummer:
|
||||||
|
DE20 CCC0 0000 9634 98
|
||||||
|
|
||||||
|
Kontoinhaber*in: {{ sepa_mandate.party.name }}
|
||||||
|
IBAN der Kontoinhaber*in: {{ sepa_mandate.account_number.number }}
|
||||||
|
Mandatsreferenz: {{ sepa_mandate.identification }}
|
||||||
|
Zahlungsart: Wiederkehrende Zahlung
|
||||||
|
Datum: {{ sepa_mandate.signature_date }}
|
||||||
|
|
||||||
|
Sollten Angaben in diesem Mandat fehlerhaft oder veraltet sein, so teil uns dies bitte per E-Mail an vorstand@ccchb.de mit.
|
||||||
|
|
||||||
|
Viele Grüße,
|
||||||
|
der Vorstand des Chaos Computer Club Bremen e.V.
|
|
@ -1,99 +0,0 @@
|
||||||
#!/bin/env python3
|
|
||||||
|
|
||||||
import csv
|
|
||||||
import subprocess
|
|
||||||
import email.message
|
|
||||||
import email.utils
|
|
||||||
import datetime
|
|
||||||
import argparse
|
|
||||||
import pathlib
|
|
||||||
import tempfile
|
|
||||||
import shutil
|
|
||||||
|
|
||||||
DEFAULT_CSV_FIELDLIST = ("creditor_name", "creditor_iban", "mandate", "recurrence", "date", "email")
|
|
||||||
|
|
||||||
def create_tex(mandate):
|
|
||||||
return f'''
|
|
||||||
\csdef{{sepa-m001}}{{{mandate['mandate']}}}
|
|
||||||
\csdef{{sepa-m006}}{{{mandate['recurrence']}}}
|
|
||||||
\csdef{{sepa-p001}}{{{mandate['creditor_name']}}}
|
|
||||||
\csdef{{sepa-d001}}{{{mandate['creditor_iban']}}}
|
|
||||||
\csdef{{sepa-m008}}{{{mandate['date']}}}
|
|
||||||
\csdef{{sepa-m009}}{{\emph{{entfällt}}}}
|
|
||||||
\csdef{{sepa-d002a}}{{}}
|
|
||||||
\csdef{{sepa-d002b}}{{}}
|
|
||||||
\csdef{{sepa-p005}}{{}}
|
|
||||||
\csdef{{sepa-remarks}}{{Dieses Mandat ist eine Abschrift des dem Zahlungsempfänger vorliegenden, originalen SEPA-Lastschriftmandats.\\\\
|
|
||||||
Erstellt am {datetime.date.today()}}}
|
|
||||||
'''
|
|
||||||
|
|
||||||
EMAIL_MESSAGE = """Liebes Mitglied,
|
|
||||||
|
|
||||||
anbei erhälst du eine Abschrift des SEPA-Lastschriftmandats mit der Mandatsreferenz "{mandate[mandate]}", das zum Einzug deiner Mitgliedsbeiträge bei uns gespeichert ist.
|
|
||||||
|
|
||||||
Sollten Angaben in diesem Mandat fehlerhaft oder veraltet sein, so teil uns dies bitte per E-Mail mit an vorstand@ccchb.de.
|
|
||||||
|
|
||||||
|
|
||||||
Viele Grüße,
|
|
||||||
Vorstand des Chaos Computer Club Bremen e.V.
|
|
||||||
"""
|
|
||||||
|
|
||||||
def create_email(mandate, pdfmandate):
|
|
||||||
msg = email.message.EmailMessage()
|
|
||||||
msg["To"] = f"{mandate['creditor_name']} <{mandate['email']}>"
|
|
||||||
msg["From"] = "Chaos Computer Club Bremen e.V. <vorstand@ccchb.de>"
|
|
||||||
msg["Subject"] = f"Dein SEPA-Lastschriftmandat (MREF: {mandate['mandate']})"
|
|
||||||
msg["Message-Id"] = email.utils.make_msgid(domain="verein.ccchb.de")
|
|
||||||
msg["Date"] = datetime.datetime.now()
|
|
||||||
msg.set_content(EMAIL_MESSAGE.format(mandate=mandate))
|
|
||||||
msg.add_attachment(pdfmandate, 'application', 'pdf', filename='Lastschriftmandat.pdf')
|
|
||||||
return msg
|
|
||||||
|
|
||||||
def main_reify_mandate(mandate, output_dir_path, tex_template_path, tempdir_path, debug):
|
|
||||||
tex_jobname = str(tempdir_path.joinpath(mandate['mandate']))
|
|
||||||
settings_file_path = tempdir_path.joinpath(f'{mandate['mandate']}-settings.tex')
|
|
||||||
with open(settings_file_path, "w") as texfile:
|
|
||||||
texfile.write(create_tex(mandate))
|
|
||||||
latexmk_args = ["latexmk", "-lualatex", str(tex_template_path), f"-jobname={tex_jobname}"]
|
|
||||||
if not debug:
|
|
||||||
latexmk_args.append("-silent")
|
|
||||||
subprocess.run(latexmk_args)
|
|
||||||
pdf_file_path = tempdir_path.joinpath(f'{mandate['mandate']}.pdf')
|
|
||||||
pdf_output_path = output_dir_path.joinpath(f'{mandate['mandate']}.pdf')
|
|
||||||
shutil.copy(pdf_file_path, pdf_output_path)
|
|
||||||
if mandate['email']:
|
|
||||||
mail_output_path = output_dir_path.joinpath(f'{mandate['mandate']}.eml')
|
|
||||||
with open(pdf_file_path, "rb") as pdffile:
|
|
||||||
msg = create_email(mandate, pdffile.read())
|
|
||||||
with open(mail_output_path, "wb") as mailfile:
|
|
||||||
mailfile.write(bytes(msg))
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
argparser = argparse.ArgumentParser()
|
|
||||||
argparser.add_argument("--csv-skip", default=1)
|
|
||||||
argparser.add_argument("--csv-fields", type=lambda s: s.split(","), default=DEFAULT_CSV_FIELDLIST)
|
|
||||||
argparser.add_argument("-O", "--output-dir", default="output/")
|
|
||||||
argparser.add_argument("--build-dir", default="build")
|
|
||||||
argparser.add_argument("--debug", default=False, action="store_true")
|
|
||||||
argparser.add_argument("tex_template")
|
|
||||||
argparser.add_argument("mandate_file")
|
|
||||||
args = argparser.parse_args()
|
|
||||||
|
|
||||||
output_dir_path = pathlib.Path(args.output_dir)
|
|
||||||
# Ensure that the output directory exists
|
|
||||||
output_dir_path.mkdir(parents=True, exist_ok=True)
|
|
||||||
tex_template_path = pathlib.Path(args.tex_template)
|
|
||||||
build_dir_path = pathlib.Path(args.build_dir)
|
|
||||||
# Ensure that the build directory exists
|
|
||||||
build_dir_path.mkdir(parents=True, exist_ok=True)
|
|
||||||
|
|
||||||
with open(args.mandate_file) as csvfile:
|
|
||||||
reader = csv.DictReader(csvfile, fieldnames=args.csv_fields)
|
|
||||||
for mandate in reader:
|
|
||||||
if not mandate.get('mandate'):
|
|
||||||
continue
|
|
||||||
main_reify_mandate(mandate, output_dir_path, tex_template_path, build_dir_path, args.debug)
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
main()
|
|
|
@ -72,6 +72,18 @@ class InvoicingClient(BaseClient):
|
||||||
self.PaymentTerm = self.get_model('account.invoice.payment_term', cls_name='PaymentTerm')
|
self.PaymentTerm = self.get_model('account.invoice.payment_term', cls_name='PaymentTerm')
|
||||||
self.PaymentTermLine = self.get_model('account.invoice.payment_term.line', cls_name='PaymentTermLine')
|
self.PaymentTermLine = self.get_model('account.invoice.payment_term.line', cls_name='PaymentTermLine')
|
||||||
|
|
||||||
|
def get_invoice_by_number(self, number):
|
||||||
|
try:
|
||||||
|
return self.Invoice.find([('number', '=', str(number))])[0]
|
||||||
|
except IndexError:
|
||||||
|
raise KeyError(number)
|
||||||
|
|
||||||
|
def get_invoice_by_id(self, _id):
|
||||||
|
try:
|
||||||
|
return self.Invoice.find([('id', '=', str(_id))])[0]
|
||||||
|
except IndexError:
|
||||||
|
raise KeyError(_id)
|
||||||
|
|
||||||
class PartyClient(BaseClient):
|
class PartyClient(BaseClient):
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
|
|
|
@ -17,8 +17,11 @@ argparser.add_argument('--reference-date', help='Referenzdatum für Zahlungsbedi
|
||||||
argparser.add_argument('--claims-account', help='Forderungskonto', default='12001')
|
argparser.add_argument('--claims-account', help='Forderungskonto', default='12001')
|
||||||
argparser.add_argument('--fee-account', help='Beitragskonto', default='40000')
|
argparser.add_argument('--fee-account', help='Beitragskonto', default='40000')
|
||||||
argparser.add_argument('--default-payment-term', default='1m')
|
argparser.add_argument('--default-payment-term', default='1m')
|
||||||
argparser.add_argument('--csv-format', type=lambda x: x.split(",") if isinstance(x, str) else list(x), default='party_id,monthly_fee,payment_term,yearly_fee', help='CSV format specification')
|
argparser.add_argument("-F", "--csv-fields", type=lambda f: f.split(","), help="csv fields")
|
||||||
argparser.add_argument('-n', '--dry-run', action='store_true')
|
argparser.add_argument('-n', '--dry-run', action='store_true')
|
||||||
|
argparser.add_argument("-o", "--output", help="output file", type=argparse.FileType("w"), default="-")
|
||||||
|
argparser.add_argument("--update", help="update invoices", action="store_true")
|
||||||
|
argparser.add_argument("--months", help="Beitragsmonate", type=lambda m: m.split(","), default="1,2,3,4,5,6,7,8,9,10,11,12")
|
||||||
argparser.add_argument('year', help='Beitragsjahr', type=lambda s: datetime.date(int(s), 1, 1))
|
argparser.add_argument('year', help='Beitragsjahr', type=lambda s: datetime.date(int(s), 1, 1))
|
||||||
argparser.add_argument('csvfile', nargs='?', type=argparse.FileType('r'), default='-')
|
argparser.add_argument('csvfile', nargs='?', type=argparse.FileType('r'), default='-')
|
||||||
|
|
||||||
|
@ -40,7 +43,11 @@ def calculate_reference_date(date):
|
||||||
if not args.reference_date:
|
if not args.reference_date:
|
||||||
args.reference_date = calculate_reference_date(args.year)
|
args.reference_date = calculate_reference_date(args.year)
|
||||||
|
|
||||||
csvreader = csv.DictReader(args.csvfile, fieldnames=args.csv_format)
|
args.months = [datetime.date(args.year.year, int(m), 1) for m in args.months]
|
||||||
|
|
||||||
|
csvreader = csv.DictReader(args.csvfile, fieldnames=args.csv_fields)
|
||||||
|
csvwriter = csv.DictWriter(args.output, fieldnames=csvreader.fieldnames + ["invoice_id"])
|
||||||
|
csvwriter.writeheader()
|
||||||
|
|
||||||
PAYMENT_TERMS_MAPPING = [
|
PAYMENT_TERMS_MAPPING = [
|
||||||
({'1m'}, 'Beitrag monatlich/jährlich'),
|
({'1m'}, 'Beitrag monatlich/jährlich'),
|
||||||
|
@ -57,7 +64,10 @@ def load_payment_terms(session, invoicing_client):
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
|
||||||
def create_invoice(party, payment_term, monthly_fee, yearly_fee, claims_account, fee_account, invoicing_client, reference_date, year):
|
def create_invoice(party, payment_term, monthly_fee, months, yearly_fee, claims_account, fee_account, invoicing_client, reference_date, year, invoice_id, update):
|
||||||
|
if update:
|
||||||
|
invoice = invoicing_client.Invoice(int(invoice_id))
|
||||||
|
else:
|
||||||
invoice = invoicing_client.Invoice()
|
invoice = invoicing_client.Invoice()
|
||||||
invoice.type = 'out'
|
invoice.type = 'out'
|
||||||
invoice.party = party
|
invoice.party = party
|
||||||
|
@ -65,11 +75,15 @@ def create_invoice(party, payment_term, monthly_fee, yearly_fee, claims_account,
|
||||||
invoice.account = claims_account
|
invoice.account = claims_account
|
||||||
invoice.payment_term = payment_term
|
invoice.payment_term = payment_term
|
||||||
invoice.payment_term_date = reference_date
|
invoice.payment_term_date = reference_date
|
||||||
|
if update:
|
||||||
|
for line in invoice.lines:
|
||||||
|
invoice.lines.remove(line)
|
||||||
if monthly_fee:
|
if monthly_fee:
|
||||||
|
for month in months:
|
||||||
invoice_line = invoicing_client.InvoiceLine()
|
invoice_line = invoicing_client.InvoiceLine()
|
||||||
invoice_line.description = f"Monatsbeiträge Januar--Dezember {year.year}"
|
invoice_line.description = f"Beitrag {month.year}-{month.month}"
|
||||||
invoice_line.account = fee_account
|
invoice_line.account = fee_account
|
||||||
invoice_line.quantity = decimal.Decimal(12) # Months
|
invoice_line.quantity = decimal.Decimal(1)
|
||||||
invoice_line.unit_price = decimal.Decimal(monthly_fee)
|
invoice_line.unit_price = decimal.Decimal(monthly_fee)
|
||||||
invoice.lines.append(invoice_line)
|
invoice.lines.append(invoice_line)
|
||||||
if yearly_fee:
|
if yearly_fee:
|
||||||
|
@ -118,11 +132,12 @@ with triad.client.Session.start(args.url, args.username, args.password) as sessi
|
||||||
yearly_fee = None
|
yearly_fee = None
|
||||||
else:
|
else:
|
||||||
print(f'\tYearly fee: {yearly_fee}', file=sys.stderr)
|
print(f'\tYearly fee: {yearly_fee}', file=sys.stderr)
|
||||||
invoice = create_invoice(party, payment_term, monthly_fee, yearly_fee, claims_account, fee_account, invoicing_client, args.reference_date, args.year)
|
invoice = create_invoice(party, payment_term, monthly_fee, args.months, yearly_fee, claims_account, fee_account, invoicing_client, args.reference_date, args.year, member.get('invoice_id'), args.update)
|
||||||
if not args.dry_run:
|
if not args.dry_run:
|
||||||
invoice.save()
|
invoice.save()
|
||||||
print(f'\tInvoice: {invoice.id} {invoice.description}', file=sys.stderr)
|
print(f'\tInvoice: {invoice.id} {invoice.description}', file=sys.stderr)
|
||||||
for line in invoice.lines:
|
for line in invoice.lines:
|
||||||
print(f'\tLine: {line.description} {line.quantity} * {line.unit_price}', file=sys.stderr)
|
print(f'\t\tLine: {line.description} {line.unit_price}', file=sys.stderr)
|
||||||
print(f'\tYearly fee: {invoice.total_amount}', file=sys.stderr)
|
print(f'\tYearly fee: {invoice.total_amount}', file=sys.stderr)
|
||||||
print(f"{member['party_id']},{invoice.id},{invoice.total_amount},{payment_term.name}")
|
member['invoice_id'] = invoice.id
|
||||||
|
csvwriter.writerow(member)
|
||||||
|
|
179
tryton-scripts/mailings.py
Normal file
179
tryton-scripts/mailings.py
Normal file
|
@ -0,0 +1,179 @@
|
||||||
|
#!/bin/env python3
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import csv
|
||||||
|
import datetime
|
||||||
|
import decimal
|
||||||
|
import email.message
|
||||||
|
import getpass
|
||||||
|
import pathlib
|
||||||
|
import subprocess
|
||||||
|
import tempfile
|
||||||
|
|
||||||
|
import jinja2
|
||||||
|
|
||||||
|
import triad.client
|
||||||
|
|
||||||
|
class Env(object):
|
||||||
|
jinja2_env: jinja2.Environment
|
||||||
|
args: argparse.Namespace
|
||||||
|
session: triad.client.Session
|
||||||
|
|
||||||
|
def fee_invoice(env: Env):
|
||||||
|
csvreader = csv.DictReader(env.args.csvfile, fieldnames=env.args.csv_fields)
|
||||||
|
csvwriter = csv.DictWriter(env.args.output, fieldnames=csvreader.fieldnames + ["message_id"])
|
||||||
|
csvwriter.writeheader()
|
||||||
|
invoicing_client = triad.client.InvoicingClient.from_session(env.session)
|
||||||
|
template = env.jinja2_env.get_template("beitrag.eml")
|
||||||
|
for member in csvreader:
|
||||||
|
invoice = invoicing_client.get_invoice_by_id(member['invoice_id'])
|
||||||
|
year = invoice.invoice_date or env.args.year
|
||||||
|
months = [datetime.date(year.year, month, 1) for month in range(1, 13)]
|
||||||
|
email_address = member.get('email') or invoice.party.email
|
||||||
|
try:
|
||||||
|
sepa_mandate = invoice.party.reception_direct_debits[0]
|
||||||
|
except IndexError:
|
||||||
|
sepa_mandate = None
|
||||||
|
else:
|
||||||
|
sepa_mandate = sepa_mandate.sepa_mandate
|
||||||
|
template_args = {
|
||||||
|
'monthly_fee': decimal.Decimal(member.get('monthly_fee') or '0.0'),
|
||||||
|
"yearly_fee": decimal.Decimal(member.get('yearly_fee') or '0.0'),
|
||||||
|
'invoice': invoice,
|
||||||
|
'sepa_mandate': sepa_mandate,
|
||||||
|
'payments': [],
|
||||||
|
'sender': env.args.email_sender,
|
||||||
|
"year": year,
|
||||||
|
"fee_months": [datetime.date(year.year, month, 1) for month in range(1, 13)]
|
||||||
|
}
|
||||||
|
msg = email.message.EmailMessage()
|
||||||
|
msg["From"] = env.args.email_from
|
||||||
|
msg["To"] = email_address
|
||||||
|
msg["Date"] = env.args.email_date or datetime.datetime.now()
|
||||||
|
msg["Subject"] = f"Beitragsrechnung {year.year} ({invoice.number})"
|
||||||
|
msg["Message-Id"] = email.utils.make_msgid(domain="verein.ccchb.de")
|
||||||
|
member['message_id'] = msg["Message-Id"]
|
||||||
|
msg.set_content(template.render(**template_args))
|
||||||
|
with (env.args.output_dir / member['message_id']).open("wb") as mailfile:
|
||||||
|
mailfile.write(bytes(msg))
|
||||||
|
csvwriter.writerow(member)
|
||||||
|
|
||||||
|
def sepa_mandate(env: Env):
|
||||||
|
csvreader = csv.DictReader(env.args.csvfile, fieldnames=env.args.csv_fields)
|
||||||
|
csvwriter = csv.DictWriter(env.args.output, fieldnames=csvreader.fieldnames + ["message_id"])
|
||||||
|
csvwriter.writeheader()
|
||||||
|
client = triad.client.BaseClient.from_session(env.session)
|
||||||
|
template = env.jinja2_env.get_template("sepa_mandat.eml")
|
||||||
|
for mandate in csvreader:
|
||||||
|
email_address= mandate.get('email')
|
||||||
|
if 'sepa_mandate_ref' in mandate:
|
||||||
|
sepa_mandate = client.get_model('account.payment.sepa.mandate').find([('identification', '=', mandate['sepa_mandate_ref'])])
|
||||||
|
party = sepa_mandate.party
|
||||||
|
elif 'party_id' in mandate:
|
||||||
|
party = client.get_model('party.party').find([('code', '=', mandate['party_id'])])[0]
|
||||||
|
email_address = email_address or party.email
|
||||||
|
sepa_mandate = party.reception_direct_debits[0].sepa_mandate
|
||||||
|
else:
|
||||||
|
continue
|
||||||
|
template_args = {
|
||||||
|
"party": party,
|
||||||
|
"sepa_mandate": sepa_mandate
|
||||||
|
}
|
||||||
|
msg = email.message.EmailMessage()
|
||||||
|
msg["From"] = env.args.email_from
|
||||||
|
msg["To"] = email_address
|
||||||
|
msg["Date"] = env.args.email_date or datetime.datetime.now()
|
||||||
|
msg["Subject"] = f"SEPA-Lastschriftmandat MREF: {sepa_mandate.identification}"
|
||||||
|
msg["Message-Id"] = email.utils.make_msgid(domain="verein.ccchb.de")
|
||||||
|
mandate['message_id'] = msg["Message-Id"]
|
||||||
|
msg.set_content(template.render(**template_args))
|
||||||
|
if env.args.pdf:
|
||||||
|
msg.add_attachment(sepa_mandate_build_pdf(env, sepa_mandate), 'application', 'pdf', filename='SEPA-Lastschriftmandat.pdf')
|
||||||
|
with (env.args.output_dir / mandate['message_id']).open("wb") as mailfile:
|
||||||
|
mailfile.write(bytes(msg))
|
||||||
|
csvwriter.writerow(mandate)
|
||||||
|
|
||||||
|
def sepa_mandate_build_pdf(env, sepa_mandate):
|
||||||
|
with tempfile.TemporaryDirectory() as tempdir:
|
||||||
|
tempdir_path = pathlib.Path(tempdir)
|
||||||
|
jobname = sepa_mandate.identification
|
||||||
|
with (tempdir_path / (jobname + "-settings.tex")).open("w") as fh:
|
||||||
|
fh.write(f'''
|
||||||
|
\\csdef{{sepa-m001}}{{{sepa_mandate.identification}}}
|
||||||
|
\\csdef{{sepa-m006}}{{Wiederkehrende Zahlung}}
|
||||||
|
\\csdef{{sepa-p001}}{{{sepa_mandate.party.name}}}
|
||||||
|
\\csdef{{sepa-d001}}{{{sepa_mandate.account_number.number}}}
|
||||||
|
\\csdef{{sepa-m008}}{{{sepa_mandate.signature_date}}}
|
||||||
|
\\csdef{{sepa-m009}}{{\\emph{{entfällt}}}}
|
||||||
|
\\csdef{{sepa-d002a}}{{}}
|
||||||
|
\\csdef{{sepa-d002b}}{{}}
|
||||||
|
\\csdef{{sepa-p005}}{{}}
|
||||||
|
\\csdef{{sepa-remarks}}{{Dieses Mandat ist eine Abschrift des dem Zahlungsempfänger vorliegenden, originalen SEPA-Lastschriftmandats.\\\\
|
||||||
|
Erstellt am {datetime.date.today()}}}
|
||||||
|
''')
|
||||||
|
compile_latex(jobname, env.args.latex_template, tempdir)
|
||||||
|
with (tempdir_path / (jobname + ".pdf")).open("rb") as fh:
|
||||||
|
return fh.read()
|
||||||
|
|
||||||
|
def compile_latex(jobname, texfile, directory, debug=True):
|
||||||
|
latexmk_args = ["latexmk", "-lualatex", str(texfile), f"-jobname={jobname}"]
|
||||||
|
if not debug:
|
||||||
|
latexmk_args.append("-silent")
|
||||||
|
subprocess.run(latexmk_args, cwd=directory)
|
||||||
|
|
||||||
|
def main():
|
||||||
|
parser = argparse.ArgumentParser()
|
||||||
|
|
||||||
|
parser.add_argument("-U", "--uri", help="Tryton URI")
|
||||||
|
parser.add_argument("-u", "--username", help="Tryton username")
|
||||||
|
parser.add_argument("-p", "--password", help="Tryton password")
|
||||||
|
|
||||||
|
parser.add_argument("-O", "--output-dir", help="email output directory", default=".", type=pathlib.Path)
|
||||||
|
parser.add_argument("-T", "--template-dir", help="email template directory", default="mail_templates")
|
||||||
|
|
||||||
|
# Email arguments
|
||||||
|
parser.add_argument('--email-sender', help='email signature sender')
|
||||||
|
parser.add_argument("--email-from", help="email from header")
|
||||||
|
parser.add_argument("--email-date", help="email date header")
|
||||||
|
|
||||||
|
subparsers = parser.add_subparsers()
|
||||||
|
|
||||||
|
fee_invoice_parser = subparsers.add_parser("fee-invoice")
|
||||||
|
fee_invoice_parser.add_argument("-o", "--output", type=argparse.FileType("w"), default='-')
|
||||||
|
fee_invoice_parser.add_argument("-F", "--csv-fields", type=lambda f: f.split(","), help="csv fields")
|
||||||
|
fee_invoice_parser.add_argument("-y", "--year", type=lambda y: datetime.date(int(y), 1, 1))
|
||||||
|
fee_invoice_parser.add_argument("--months", help="Beitragsmonate", type=lambda m: m.split(","), default="1,2,3,4,5,6,7,8,9,10,11,12")
|
||||||
|
fee_invoice_parser.add_argument("csvfile", type=argparse.FileType("r"), default="-", nargs="?")
|
||||||
|
fee_invoice_parser.set_defaults(func=fee_invoice)
|
||||||
|
|
||||||
|
sepa_mandate_parser = subparsers.add_parser('sepa-mandate')
|
||||||
|
sepa_mandate_parser.add_argument('-o', '--output', type=argparse.FileType("w"), default='-')
|
||||||
|
sepa_mandate_parser.add_argument('-F', '--csv-fields', type=lambda f: f.split(','), help='csv fields')
|
||||||
|
sepa_mandate_parser.add_argument('--pdf', action='store_true', help='build pdf attachment', default=False)
|
||||||
|
sepa_mandate_parser.add_argument('--no-pdf', action='store_false', dest='pdf', help='don\'t build pdf attachment')
|
||||||
|
sepa_mandate_parser.add_argument('--latex-template', help='latex template in $TEXINPUTS')
|
||||||
|
sepa_mandate_parser.add_argument('csvfile', type=argparse.FileType('r'), default='-', nargs='?')
|
||||||
|
sepa_mandate_parser.set_defaults(func=sepa_mandate)
|
||||||
|
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
env = Env()
|
||||||
|
env.jinja2_env = jinja2.Environment(
|
||||||
|
loader=jinja2.FileSystemLoader(args.template_dir)
|
||||||
|
)
|
||||||
|
env.args = args
|
||||||
|
|
||||||
|
if not args.uri:
|
||||||
|
args.uri = input("URI for Tryton: ")
|
||||||
|
|
||||||
|
if not args.username:
|
||||||
|
args.username = input("Username for Tryton: ")
|
||||||
|
|
||||||
|
if not args.password:
|
||||||
|
args.password = getpass.getpass(f"Password for Tryton user `{args.username}': ")
|
||||||
|
|
||||||
|
with triad.client.Session.start(args.uri, args.username, args.password) as session:
|
||||||
|
env.session = session
|
||||||
|
args.func(env)
|
||||||
|
|
||||||
|
main()
|
Loading…
Reference in a new issue