# -* coding: utf8 *- import datetime class InvoiceImage(object): def __init__(self, pilimage, caption=None, dpi=80, alignment="left"): self.imagedata = pilimage self.alignment = alignment self.dpi = dpi self.caption = caption class InvoiceText(object): def __init__(self, content, urgent=False, headline=None, indent=None): self.paragraphs = [content] self.urgent = urgent self.headline = headline self.indent = indent self.fontsize = 0 # relative Schriftgröße ggü default def addParagraph(self, content): self.paragraphs.append(content) class InvoiceTable(object): def __init__(self, vatType='gross', tender=False, summary=True): self.entries = [] self.vat = {} self.sum = 0.0 self.payments = [] self.tender = tender self.summary = summary if vatType not in ['gross', 'net']: raise ValueError('vatType must be »gross« or »net«') self.vatType = vatType def validEntry(self, entry): """bekommt einen Eintrag und liefert einen Eintrag, wenn ok; wirft ansonsten ValueError. wird benutzt um z.B. die Summe auszurechnen oder ähnliches """ k = entry.keys() e = entry if not ('count' in k and 'unit' in k and 'subject' in k and 'price' in k and 'vat' in k): raise ValueError('Some data is missing!') ret = {'type': 'entry', 'count': e['count'], 'unit': e['unit'], 'subject': e['subject'], 'price': e['price'], 'total': (e['price'] * e['count']), 'vat': e['vat'], 'tender': False, } if ret['vat'] > 1: ret['vat'] = float(ret['vat']) / 100 if 'tender' in e.keys(): ret['tender'] = e['tender'] if 'desc' in k: ret['desc'] = e['desc'] if 'period_start' in k: ret['period_start'] = e['period_start'] if 'period_end' in k: ret['period_end'] = e['period_end'] return ret def addItem(self, data): """Fügt eine Zeile ein. data muss ein Dict mit passenden Keys und passenden Typen sein""" d = self.validEntry(data) if not d['vat'] in self.vat.keys(): self.vat[d['vat']] = [0, chr(65+len(self.vat))] if 'tender' not in data or not data['tender']: self.vat[d['vat']][0] += d['total'] self.sum += d['total'] self.entries.append(d) def addTitle(self, title): self.entries.append({'type': 'title', 'title': title, }) def addPayment(self, payment_type, amount, date): self.payments.append({"type": payment_type, "amount": amount, "date": date}) RECHNUNG = 380 ANGEBOT = 1 GUTSCHRIFT = 381 KORREKTUR = 384 VAT_REGULAR = 'S' VAT_KLEINUNTERNEHMER = 'E' VAT_INNERGEM = 'K' PAYMENT_LASTSCHRIFT = "59" PAYMENT_UEBERWEISUNG = "58" PAYMENT_BANKKONTO = "42" PAYMENT_ONLINE = "68" PAYMENT_BAR = "10" PAYMENT_KARTE = "48" UNITS = { # key = XML-Code, value = (Langform Einzahl, Langform Mehrzahl, Kurzform, [mögliche weitere Schreibweisen,...]) 'H87': ('Stück', 'Stück', 'Stk', 'pcs'), 'SEC': ('Sekunde', 'Sekunden', 's', 'Sek.', 'Sek'), 'MIN': ('Minute', 'Minuten', 'min', 'Min.', 'Min'), 'HUR': ('Stunde', 'Stunden', 'h', 'Std.', 'Std'), 'DAY': ('Tag', 'Tage', 'Tg', 'd'), 'WEE': ('Woche', 'Wochen', 'Woch.', 'Woch'), 'MON': ('Monat', 'Monate', 'Mon.', 'Mon'), 'ANN': ('Jahr', 'Jahre', 'J.', 'y'), 'LTR': ('Liter', 'Liter', 'l', 'Ltr'), 'MTQ': ('Kubikmeter', 'Kubikmeter', 'm³', 'cbm'), 'GRM': ('Gramm', 'Gramm', 'g', 'Gr', 'gr'), 'KGM': ('Kilogramm', 'Kilogramm', 'kg', 'Kilo'), 'TNE': ('Tonne', 'Tonnen', 't'), 'DTN': ('Dezitonne', 'Dezitonnen', 'dt'), 'MTR': ('Meter', 'Meter', 'm', 'Mtr'), 'MMT': ('Millimeter', 'Millimeter', 'mm'), 'KMT': ('Kilometer', 'Kilometer', 'km'), 'MTK': ('Quadratmeter', 'Quadratmeter', 'm²', 'qm'), 'KWT': ('Kilowatt', 'Kilowatt', 'kW'), 'MAW': ('Megawatt', 'Megawatt', 'MW'), 'KWH': ('Kilowattstunde', 'Kilowattstunden', 'kWh'), 'MWH': ('Megawattstunde', 'Megawattstunden', 'MWh'), 'D97': ('Palette', 'Paletten', 'Pal'), 'AD': ('Byte', 'Bytes', 'Byte', 'octet', 'octets'), '2P': ('Kilobyte', 'Kilobytes', 'KB'), '4L': ('Megabyte', 'Megabytes', 'MB'), 'E34': ('Gigabyte', 'Gigabytes', 'GB'), 'E35': ('Terabyte', 'Terabytes', 'TB'), 'E36': ('Petabyte', 'Petabytes', 'PB'), '1I': ('Pauschal', 'Pauschale', 'Psch.', 'Psch'), } class Invoice(object): def __init__(self, tender=False): self.customerno = None self.customer = { "id": None, "name": None, "address": { "postcode": None, "city_name": None, "line1": None, "line2": None, "line3": None, "country_id": None, }, "phone": None, "email": None, } self.buyer = self.customer self.seller = { "name": None, # juristischer Name "trade_name": None, # Firmenname "address": { "postcode": None, "city_name": None, "line1": None, "line2": None, "line3": None, "country_id": None, }, "phone": None, "email": None, "website": None, } self.seller_vat_id = None self.seller_bank_data = { 'kontoinhaber': None, 'iban': None, 'bic': None, 'bankname': None, } self.due_date = None self.debit = False self.payment_type = PAYMENT_UEBERWEISUNG self.leitweg_id = None self.buyer_reference = None self.order_number = None self.contract_number = None self.debit_mandate_id = None self.creditor_reference_id = None self.buyer_bank_data = { 'kontoinhaber': None, 'iban': None, 'bic': None, 'bankname': None, } self.vat_type = VAT_REGULAR self.salutation = 'Sehr geehrte Damen und Herren,' self.id = None self.cash = True self.type = RECHNUNG self.logo_image_file = None self.tender = tender self.title = 'Rechnung' if tender: self.title = 'Angebot' self.official = True self.parts = [] self.pagecount = 0 self.date = datetime.date.today() def setDate(self, date): if not isinstance(date, datetime.date): raise ValueError('date must be of type »datetime.date«') self.date = date