vereinsgwrschtl/tryton-scripts/beitragsrechnungen.py

128 lines
5.9 KiB
Python

#!/bin/env python3
import argparse
import csv
import datetime
import decimal
import getpass
import sys
import triad.client
argparser = argparse.ArgumentParser(description='Beitragsrechnungen für ein Jahr erzeugen')
argparser.add_argument('-u', '--username', help='Tryton-Benutzername', default='fgrimpen')
argparser.add_argument('-p', '--password', help='Tryton-Passwort')
argparser.add_argument('-U', '--url', help='Tryton-URL', default='https://kasse.verein.ccchb.de/tryton/')
argparser.add_argument('--reference-date', help='Referenzdatum für Zahlungsbedingung', type=datetime.date.fromisoformat)
argparser.add_argument('--claims-account', help='Forderungskonto', default='12001')
argparser.add_argument('--fee-account', help='Beitragskonto', default='40000')
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('-n', '--dry-run', action='store_true')
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='-')
args = argparser.parse_args()
if not args.password:
args.password = getpass.getpass(f"Password for {args.username}@{args.url}: ")
def calculate_reference_date(date):
today = datetime.date.today()
if today >= date:
date = today
while date.day >= 10:
date += datetime.timedelta(days=1)
while date.day != 15:
date += datetime.timedelta(days=1)
return date
if not args.reference_date:
args.reference_date = calculate_reference_date(args.year)
csvreader = csv.DictReader(args.csvfile, fieldnames=args.csv_format)
PAYMENT_TERMS_MAPPING = [
({'1m'}, 'Beitrag monatlich/jährlich'),
({'3m'}, 'Beitrag quartalsweise/jährlich'),
({'6m'}, 'Beitrag halbjährlich/jährlich'),
({'1y', '12m'}, 'Beitrag jährlich/jährlich')
]
def load_payment_terms(session, invoicing_client):
ret = {}
for keys, payment_term_name in PAYMENT_TERMS_MAPPING:
payment_term = invoicing_client.PaymentTerm.find([('name', '=', payment_term_name)])[0]
ret.update({key: payment_term for key in keys})
return ret
def create_invoice(party, payment_term, monthly_fee, yearly_fee, claims_account, fee_account, invoicing_client, reference_date, year):
invoice = invoicing_client.Invoice()
invoice.type = 'out'
invoice.party = party
invoice.description = f"Beiträge {year.year}"
invoice.account = claims_account
invoice.payment_term = payment_term
invoice.payment_term_date = reference_date
if monthly_fee:
invoice_line = invoicing_client.InvoiceLine()
invoice_line.description = f"Monatsbeiträge Januar--Dezember {year.year}"
invoice_line.account = fee_account
invoice_line.quantity = decimal.Decimal(12) # Months
invoice_line.unit_price = decimal.Decimal(monthly_fee)
invoice.lines.append(invoice_line)
if yearly_fee:
invoice_line = invoicing_client.InvoiceLine()
invoice_line.description = f"Jahresbeitrag {year.year}"
invoice_line.account = fee_account
invoice_line.quantity = decimal.Decimal(1)
invoice_line.unit_price = decimal.Decimal(yearly_fee)
invoice.lines.append(invoice_line)
invoice.state = 'draft'
return invoice
with triad.client.Session.start(args.url, args.username, args.password) as session:
party_client = triad.client.PartyClient.from_session(session)
invoicing_client = triad.client.InvoicingClient.from_session(session)
accounting_client = triad.client.AccountingClient.from_session(session)
claims_account = accounting_client.get_account_by_code(args.claims_account)
print(f"Claims account: {claims_account.code} {claims_account.name}", file=sys.stderr)
fee_account = accounting_client.get_account_by_code(args.fee_account)
print(f'Fee account: {fee_account.code} {fee_account.name}', file=sys.stderr)
payment_terms = load_payment_terms(invoicing_client, invoicing_client)
for key, payment_term in payment_terms.items():
print(f"Payment term {key}: {payment_term.name}", file=sys.stderr)
print(f'Fee year: {args.year}', file=sys.stderr)
print(f'Reference date: {args.reference_date}', file=sys.stderr)
for member in csvreader:
party = party_client.get_party_by_code(member['party_id'])
print(f"Party: {party.code} {party.name}", file=sys.stderr)
try:
payment_term = payment_terms[member['payment_term']]
except KeyError:
payment_term = payment_terms[args.default_payment_term]
print(f"\tPayment term: {payment_term.name}", file=sys.stderr)
try:
monthly_fee = decimal.Decimal(member['monthly_fee'])
except:
print(f"\tInvalid monthly fee: {member['monthly_fee']}", file=sys.stderr)
monthly_fee = None
else:
print(f"\tMonthly fee: {monthly_fee}", file=sys.stderr)
try:
yearly_fee = decimal.Decimal(member['yearly_fee'])
except:
print(f'\tInvalid yearly fee: {member['yearly_fee']}', file=sys.stderr)
yearly_fee = None
else:
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)
if not args.dry_run:
invoice.save()
print(f'\tInvoice: {invoice.id} {invoice.description}', file=sys.stderr)
for line in invoice.lines:
print(f'\tLine: {line.description} {line.quantity} * {line.unit_price}', 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}")