From 983b970219690428de0dcbc869d6f8f36a509880 Mon Sep 17 00:00:00 2001 From: Fritz Grimpen Date: Tue, 10 Dec 2024 18:45:25 +0100 Subject: [PATCH] newsletter script --- mail_templates/beitragserh24.eml | 29 ++++++++++++++++ tryton-scripts/mailings.py | 57 ++++++++++++++++++++++++++++---- 2 files changed, 79 insertions(+), 7 deletions(-) create mode 100644 mail_templates/beitragserh24.eml diff --git a/mail_templates/beitragserh24.eml b/mail_templates/beitragserh24.eml new file mode 100644 index 0000000..1b638a5 --- /dev/null +++ b/mail_templates/beitragserh24.eml @@ -0,0 +1,29 @@ +Ultrakurzfassung: +Du zahlst aktuell {{ fee_old|format_currency(currency='EUR') }} Beitrag im Monat beim CCC Bremen. {% if direct_debit -%} +Wenn du nichts machst, erhöht sich dein Beitrag ab dem 01.01.2025 auf {{ 20|format_currency(currency='EUR') }} und wir ziehen das entsprechend ein. +{%- else -%} +Wenn du uns nichts anderes mitteilst, fordern wir ab dem 01.01.2025 einen Beitrag von {{ 20|format_currency(currency='EUR') }} und du müsstest deine Überweisungen / Daueraufträge dementsprechend anpassen. +{%- endif %} Du kannst Einfluss nehmen auf die Höhe deines Beitrags, den Zahlungsturnus sowie -modus: https://wiki.ccchb.de/wiki/Beitrag + +Langfassung: + +Moin {{ name }}, + +die Mitgliederversammlung des Chaos Computer Club Bremen e.V. hat am 19.11.2024 eine neue Beitragsordnung beschlossen, die am 01.01.2025 in Kraft treten wird. Im Folgenden erläutern wir kurz, warum das getan wurde und gehen anschließend darauf ein, was das für dich konkret bedeutet und welche Optionen du hast. + +Wir haben aktuell durchschnittliche monatliche Einnahmen von circa {{ 770|format_currency(currency='EUR') }}; davon kommen {{ 250|format_currency(currency='EUR') }} vom überregionalen CCC e.V. und sollen für Projekte ausgegeben werden. Dem gegenüber stehen {{ 675|format_currency(currency='EUR') }} durchschnittliche monatliche Ausgaben. Wir geben also aktuell einen Teil der Projektmittel für z.B. Raummiete aus. + +Um in Zukunft mindestens {{ 250|format_currency(currency='EUR') }} im Monat für Projekte ausgeben zu können, und auch um die Möglichkeit zu haben, mit Hilfe eines Mietkostenzuschusses des CCC e.V. in neue Räume umziehen zu können, ist die Beitragserhöhung notwendig. + +Was bedeutet das für dich? + +Du zahlst aktuell {{ fee_old|format_currency(currency='EUR') }} Beitrag im Monat beim CCC Bremen. Falls wir von dir nicht hören, erhöht sich dein Beitrag ab dem 01.01.2025 automatisch auf {{ 20|format_currency(currency='EUR') }} im Monat. {% if direct_debit -%} +Da du uns Lastschrifteinzug erlaubt hast, ziehen wir das automatisch passend ein und du musst nichts machen. +{%- else -%} +Du zahlst aktuell per Überweisung, also müsstest du möglicherweise deinen Dauerauftrag anpassen, oder den neuen Betrag bei deinen Überweisungen berücksichtigen. +{%- endif %} + +Falls der Beitrag für dich zu hoch oder zu niedrig ist, oder du Zahlungsturnus und -modus ändern willst, folge bitte den Instruktionen auf https://wiki.ccchb.de/wiki/Beitrag + +Viele Grüße, +Fritz Grimpen und Nora Bruns für den Vorstand des CCC Bremen e.V. diff --git a/tryton-scripts/mailings.py b/tryton-scripts/mailings.py index 0a9a3f0..080e16c 100644 --- a/tryton-scripts/mailings.py +++ b/tryton-scripts/mailings.py @@ -144,6 +144,34 @@ def sepa_mandate(env: Env): mailfile.write(bytes(msg)) csvwriter.writerow(mandate) +def newsletter(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() + template = env.jinja2_env.get_template(env.args.template) + for member in csvreader: + email_address = member.get('email') + if not email_address: + continue + 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"] = env.args.subject + msg["Message-Id"] = member.get("message_id") or email.utils.make_msgid(domain="verein.ccchb.de") + member['message_id'] = msg["Message-Id"] + template_args = { + "name": member.get("name"), + "email": email_address, + "direct_debit": member.get("sepa_mandate"), + "fee_old": decimal.Decimal(member.get("monthly_fee") or '0.0'), + "member": member, + } + 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_build_pdf(env, sepa_mandate): with tempfile.TemporaryDirectory() as tempdir: tempdir_path = pathlib.Path(tempdir) @@ -188,7 +216,7 @@ def main(): 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") @@ -199,6 +227,7 @@ def main(): fee_invoice_parser.add_argument("-k", "--lookup-key", choices={'number', 'id'}, default='id', help='lookup key for invoice') fee_invoice_parser.add_argument("csvfile", type=argparse.FileType("r"), default="-", nargs="?") fee_invoice_parser.set_defaults(func=fee_invoice) + fee_invoice_parser.set_defaults(requires_tryton=True) sepa_mandate_parser = subparsers.add_parser('sepa-mandate') sepa_mandate_parser.add_argument('-o', '--output', type=argparse.FileType("w"), default='-') @@ -208,6 +237,16 @@ def main(): 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) + sepa_mandate_parser.set_defaults(requires_tryton=True) + + newsletter_parser = subparsers.add_parser('newsletter') + newsletter_parser.add_argument('-o', '--output', type=argparse.FileType("w"), default='-') + newsletter_parser.add_argument('-F', '--csv_fields', type=lambda f: f.split(','), help='csv fields') + newsletter_parser.add_argument("-s", "--subject", default="") + newsletter_parser.add_argument('template') + newsletter_parser.add_argument('csvfile', type=argparse.FileType('r'), default='-', nargs='?') + newsletter_parser.set_defaults(func=newsletter) + newsletter_parser.set_defaults(requires_tryton=False) args = parser.parse_args() @@ -236,17 +275,21 @@ def main(): if "from" in env.config["email"]: env.args.email_from = env.config["email"]["from"] - if not args.uri: + if not args.uri and args.requires_tryton: args.uri = input("URI for Tryton: ") - if not args.username: + if not args.username and args.requires_tryton: args.username = input("Username for Tryton: ") - if not args.password: + if not args.password and args.requires_tryton: 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 + if args.requires_tryton: + with triad.client.Session.start(args.uri, args.username, args.password) as session: + env.session = session + args.func(env) + else: args.func(env) -main() +if __name__ == '__main__': + main()