In eigenes GIT ausgelagert
Bernd Wurst

Bernd Wurst commited on 2024-02-14 08:44:20
Zeige 4 geänderte Dateien mit 25 Einfügungen und 623 Löschungen.

... ...
@@ -1,7 +1,8 @@
1 1
 # -* coding: utf8 *-
2 2
 
3 3
 from __future__ import division
4
-from Invoice import Text, Table, Image
4
+
5
+from .InvoiceObjects import Invoice, InvoiceTable, InvoiceText, InvoiceImage, PAYMENT_UEBERWEISUNG
5 6
 from utils import format_price, split_to_width
6 7
 
7 8
 
... ...
@@ -20,37 +21,46 @@ def _breakLine(text, width=72):
20 21
     return lines
21 22
 
22 23
 
23
-def InvoiceToText(iv, bankdata=True):
24
+def InvoiceToText(invoice : Invoice, bankdata=True):
24 25
     ret = []
25 26
     ret.append(u'Rechnungsempfänger:')
26
-    for line in iv.addresslines:
27
-        ret.append('  %s' % line)
27
+    addresslines = filter(None, [
28
+        invoice.customer['name'].strip(),
29
+        invoice.customer['address']['line1'] or '',
30
+        invoice.customer['address']['line2'] or '',
31
+        invoice.customer['address']['line3'] or '',
32
+        ((invoice.customer['address']['postcode'] or '') + ' ' + (
33
+                    invoice.customer['address']['city_name'] or '')).strip(),
34
+    ])
35
+    for line in addresslines:
36
+        ret.append(f'  {line}')
28 37
     ret.append('')
29
-    ret.append('Kundennummer:    %4i' % iv.customerno)
30
-    ret.append('Rechnungsnummer: %4i    Rechnungsdatum:  %s' % (iv.id, iv.date.strftime('%d.%m.%Y')))
38
+    ret.append(f'Kundennummer:    {invoice.customerno}')
39
+    ret.append(f'Rechnungsnummer: {invoice.id}')
40
+    ret.append(f'Rechnungsdatum:  {invoice.date.strftime("%d.%m.%Y")}')
31 41
 
32 42
     ret.append('')
33
-    for part in iv.parts:
34
-        if type(part) == Table:
43
+    for part in invoice.parts:
44
+        if type(part) == InvoiceTable:
35 45
             ret.append(InvoiceTableToText(part))
36
-        elif type(part) == Text:
46
+        elif type(part) == InvoiceText:
37 47
             ret.append(InvoiceTextToText(part))
38
-        elif type(part) == Image:
48
+        elif type(part) == InvoiceImage:
39 49
             # ignore images
40 50
             pass
41 51
         else:
42 52
             raise NotImplementedError("Cannot handle part of type %s" % type(part))
43 53
 
44
-    if bankdata:
54
+    if invoice.payment_type == PAYMENT_UEBERWEISUNG:
45 55
         ret.append('-' * 72)
46 56
         ret.append('Unsere Bankverbindung:')
47
-        ret.append('Volksbank Backnang, BLZ 602 911 20, Konto-Nr. 41512 006')
48
-        ret.append('IBAN: DE91602911200041512006, BIC: GENODES1VBK')
57
+        ret.append(f'{invoice.seller_bank_data["bankname"]}')
58
+        ret.append(f'IBAN: {invoice.seller_bank_data["iban"]}')
49 59
 
50 60
     return '\n'.join(ret)
51 61
 
52 62
 
53
-def InvoiceTableToText(invoiceTable):
63
+def InvoiceTableToText(invoiceTable : InvoiceTable):
54 64
     ret = []
55 65
     if len(invoiceTable.vat) < 2:
56 66
         ret.append(u'Anz       Beschreibung                                  Preis     Gesamt')
... ...
@@ -111,7 +121,7 @@ def InvoiceTableToText(invoiceTable):
111 121
     return '\n'.join(ret)
112 122
 
113 123
 
114
-def InvoiceTextToText(invoiceText):
124
+def InvoiceTextToText(invoiceText : InvoiceText):
115 125
     ret = []
116 126
     for par in invoiceText.paragraphs:
117 127
         for s in split_to_width(par, 72):
... ...
@@ -1,71 +0,0 @@
1
-# -* coding: utf8 *-
2
-from __future__ import division
3
-from .metrics import *
4
-
5
-
6
-address_header = 'schokokeks.org · Köchersberg 32 · 71540 Murrhardt'
7
-
8
-
9
-def FoldingMarkers(canvas):
10
-    """Setzt Falzmarken"""
11
-    from reportlab.lib.units import cm
12
-    canvas.setStrokeColorRGB(0, 0, 0)
13
-    canvas.setLineWidth(0.01 * cm)
14
-    canvas.lines(
15
-        [(0.3 * cm, page_height - 10.5 * cm, 0.65 * cm, page_height - 10.5 * cm),
16
-         (0.3 * cm, page_height - 21.0 * cm, 0.65 * cm, page_height - 21.0 * cm),
17
-            (0.3 * cm, page_height - 14.85 * cm, 0.7 * cm, page_height - 14.85 * cm)])
18
-
19
-
20
-def Footer(canvas):
21
-    canvas.line(leftcontent, bottomcontent, rightcontent, bottomcontent)
22
-    canvas.setFont(font, 7)
23
-    canvas.drawString(leftcontent, bottomcontent - 10, 'schokokeks.org GbR')
24
-    canvas.drawString(leftcontent, bottomcontent - 20, 'Bernd Wurst / Johannes Böck')
25
-    canvas.drawString(leftcontent, bottomcontent - 30, 'www.schokokeks.org')
26
-    canvas.drawString(leftcontent, bottomcontent - 40, 'root@schokokeks.org')
27
-
28
-    canvas.drawString(leftcontent + ((rightcontent - leftcontent) // 3), bottomcontent - 10, 'Steuernummer 51072/01109')
29
-    canvas.drawString(leftcontent + ((rightcontent - leftcontent) // 3), bottomcontent - 20, 'Finanzamt Backnang')
30
-    canvas.drawString(leftcontent + ((rightcontent - leftcontent) // 3), bottomcontent - 30, 'USt-ID: DE255720588')
31
-
32
-    canvas.setFont(font, 7)
33
-    canvas.drawString(leftcontent + ((rightcontent - leftcontent) // 3) * 2, bottomcontent - 10, 'Volksbank Backnang')
34
-    canvas.drawString(leftcontent + ((rightcontent - leftcontent) // 3) * 2, bottomcontent - 20, 'IBAN: DE91 6029 1120 0041 5120 06')
35
-    canvas.drawString(leftcontent + ((rightcontent - leftcontent) // 3) * 2, bottomcontent - 30, 'BIC: GENODES1VBK')
36
-    canvas.drawString(leftcontent + ((rightcontent - leftcontent) // 3) * 2, bottomcontent - 40, '(Kto: 41512 006 / BLZ: 602 911 20)')
37
-
38
-
39
-def basicPage(canvas):
40
-    FoldingMarkers(canvas)
41
-    Footer(canvas)
42
-    return topcontent
43
-
44
-
45
-def firstPage(canvas):
46
-    basicPage(canvas)
47
-
48
-    font_size = default_font_size
49
-    y = topcontent
50
-    canvas.drawInlineImage("logo.png", rightcolumn, topcontent - (3 * cm), width=4.08 * cm, height=3 * cm)
51
-    y -= (3.5 * cm)
52
-    canvas.setFont(font + "-Bold", font_size)
53
-    # canvas.drawString(rightcolumn, y, "schokokeks.org Webhosting")
54
-    # y -= (font_size + 5 + 0.2*cm)
55
-    canvas.drawString(rightcolumn, y, "schokokeks.org GbR")
56
-    y -= (font_size + 5)
57
-    canvas.setFont(font, font_size)
58
-    canvas.drawString(rightcolumn, y, "Bernd Wurst / Johannes Böck")
59
-    y -= (font_size + 5)
60
-    canvas.drawString(rightcolumn, y, "Köchersberg 32")
61
-    y -= (font_size + 5)
62
-    canvas.drawString(rightcolumn, y, "71540 Murrhardt")
63
-    y -= (font_size + 10)
64
-    canvas.drawString(rightcolumn, y, "Tel: 07192-936432")
65
-    y -= (font_size + 5)
66
-    canvas.drawString(rightcolumn, y, "Fax: 07192-936431")
67
-    y -= (font_size + 5)
68
-    canvas.drawString(rightcolumn, y, "E-Mail: root@schokokeks.org")
69
-    y -= (font_size + 10)
70
-
71
-    return topcontent - 7.5 * cm
... ...
@@ -1,39 +0,0 @@
1
-
2
-def setup():
3
-    from reportlab.lib.pagesizes import A4
4
-    from reportlab.lib.units import cm
5
-    from reportlab.pdfbase.ttfonts import TTFont
6
-    from reportlab.pdfbase import pdfmetrics
7
-
8
-    if 'DejaVuSans' not in pdfmetrics._fonts:
9
-        pdfmetrics.registerFont(TTFont("DejaVuSans", "DejaVuSans.ttf"))
10
-        pdfmetrics.registerFont(TTFont("DejaVuSans-Bold", "DejaVuSans-Bold.ttf"))
11
-        pdfmetrics.registerFont(TTFont("DejaVuSans-Oblique", "DejaVuSans-Oblique.ttf"))
12
-        pdfmetrics.registerFont(TTFont("DejaVuSans-BoldOblique", "DejaVuSans-BoldOblique.ttf"))
13
-
14
-    return (cm, A4)
15
-
16
-
17
-(cm, A4) = setup()
18
-
19
-(page_width, page_height) = A4
20
-font = 'DejaVuSans'
21
-# Set default font size
22
-default_font_size = 8
23
-
24
-
25
-# set margins
26
-topmargin = 2 * cm
27
-bottommargin = 2.5 * cm
28
-leftmargin = 2 * cm
29
-rightmargin = 2 * cm
30
-
31
-topcontent = page_height - topmargin
32
-leftcontent = leftmargin
33
-rightcontent = page_width - rightmargin
34
-bottomcontent = bottommargin
35
-
36
-rightcolumn = 13 * cm
37
-
38
-address_width = 8.5 * cm
39
-address_height = 5.0 * cm
... ...
@@ -1,498 +0,0 @@
1
-# -* coding: utf8 *-
2
-
3
-from __future__ import division
4
-import Invoice
5
-import re
6
-
7
-# our page size and margins
8
-from .metrics import *
9
-# our custom page style
10
-from .custom_elements import basicPage, firstPage, address_header
11
-
12
-# reportlab imports
13
-from reportlab.lib.units import cm, inch
14
-from reportlab.pdfgen import canvas as Canvas
15
-from reportlab.lib.colors import Color
16
-
17
-
18
-def _formatPrice(price, symbol='€'):
19
-    '''_formatPrice(price, symbol='€'):
20
-    Gets a floating point value and returns a formatted price, suffixed by 'symbol'. '''
21
-    s = ("%.2f" % price).replace('.', ',')
22
-    pat = re.compile(r'([0-9])([0-9]{3}[.,])')
23
-    while pat.search(s):
24
-        s = pat.sub(r'\1.\2', s)
25
-    return s + ' ' + symbol
26
-
27
-
28
-def _niceCount(value):
29
-    '''_niceCount(value):
30
-    Returns a tuple (integer , decimals) where decimals can be None'''
31
-    if type(value) == int:
32
-        return ('%i' % value, None)
33
-    if round(value, 2) == int(value):
34
-        return ('%i' % int(value), None)
35
-    s = '%.2f' % value
36
-    (integer, decimals) = s.split('.', 1)
37
-    if decimals[-1] == '0':
38
-        decimals = decimals[:-1]
39
-    return (integer, decimals)
40
-
41
-
42
-def _splitToWidth(canvas, text, width, font, size):
43
-    '''_splitToWidth(canvas, text, width, font, size)
44
-    Split a string to several lines of a given width.'''
45
-    lines = []
46
-    paras = text.split('\n')
47
-    for para in paras:
48
-        words = para.split(' ')
49
-        while len(words) > 0:
50
-            mywords = [words[0], ]
51
-            del words[0]
52
-            while len(words) > 0 and canvas.stringWidth(' '.join(mywords) + ' ' + words[0], font, size) <= width:
53
-                mywords.append(words[0])
54
-                del words[0]
55
-            lines.append(' '.join(mywords))
56
-    return lines
57
-
58
-
59
-def _drawJustifiedString(x, y, text, canvas, width, font, size):
60
-    text = text.strip()
61
-    if canvas.stringWidth(text, font, size) > width:
62
-        canvas.drawString(x, y, text)
63
-        # too long line, I cannot handle this
64
-        return
65
-    if ' ' not in text:
66
-        canvas.drawString(x, y, text)
67
-        # no space in there, nothing to justify
68
-        return
69
-
70
-    words = ['%s' % w for w in text.split(' ')]
71
-    words_width = 0.0
72
-    for word in words:
73
-        words_width += canvas.stringWidth(word, font, size)
74
-
75
-    available_space = width - words_width
76
-    available_each = available_space // float((len(words) - 1))
77
-
78
-    my_x = x
79
-    for idx in range(len(words)):
80
-        word = words[idx]
81
-        canvas.drawString(my_x, y, word)
82
-        my_x += canvas.stringWidth(word, font, size) + available_each
83
-    return
84
-
85
-
86
-def address(canvas, lines):
87
-    x = 2.0 * cm
88
-    y = page_height - 5.0 * cm
89
-    canvas.setFont(font, 8)
90
-    canvas.drawString(x + 0.5 * cm, y + 0.1 * cm, 'schokokeks.org · Köchersberg 32 · 71540 Murrhardt')
91
-    canvas.setLineWidth(1)
92
-    canvas.line(x + 0.4 * cm, y, x + address_width, y)
93
-    y = y - 0.2 * cm
94
-
95
-    line_height = 11 + 0.1 * cm
96
-    y -= line_height
97
-
98
-    fontsize = 11
99
-    for line in lines:
100
-        if canvas.stringWidth(line, font, fontsize) > address_width:
101
-            # Wenn es in zwei Zeilen passt, dann ist alles okay, ansonsten verkleinern
102
-            if len(lines) > 4 or canvas.stringWidth(line, font, fontsize) > 2 * address_width:
103
-                for candidate in [10.5, 10, 9.5, 9, 8.5, 8]:
104
-                    fontsize = candidate
105
-                    if (len(lines) <= 4 and canvas.stringWidth(line, font, fontsize) <= 2 * address_width) or canvas.stringWidth(line, font, fontsize) <= address_width:
106
-                        break
107
-    for line in lines:
108
-        if canvas.stringWidth(line, font, fontsize) > address_width:
109
-            mylines = _splitToWidth(canvas, line, address_width, font, fontsize)
110
-            for l in mylines:
111
-                canvas.setFont(font, fontsize)
112
-                canvas.drawString(x + 0.5 * cm, y, l)
113
-                y -= line_height
114
-        else:
115
-            canvas.setFont(font, fontsize)
116
-            canvas.drawString(x + 0.5 * cm, y, line)
117
-            y -= line_height
118
-
119
-
120
-def InvoiceToPDF(iv, bankdata=True):
121
-    from io import BytesIO
122
-    fd = BytesIO()
123
-    canvas = Canvas.Canvas(fd, pagesize=A4)
124
-
125
-    if iv.tender:
126
-        canvas.setTitle("Angebot von schokokeks.org")
127
-    else:
128
-        canvas.setTitle("Rechnung von schokokeks.org")
129
-
130
-    canvas.setFont(font, 12)
131
-
132
-    num_pages = 1
133
-    # Waehrungssysmbol
134
-    symbol = '€'
135
-    y = topcontent
136
-    font_size = default_font_size
137
-    font_height = 0.35 * cm
138
-    line_padding = 0.1 * cm
139
-    line_height = font_height + 0.1 * cm
140
-
141
-    def _partHeight(part):
142
-        height = 0
143
-        if type(part) == Invoice.Text:
144
-            left, right = leftcontent, rightcontent
145
-            if part.urgent:
146
-                left += 1.5 * cm
147
-                right -= 1.5 * cm
148
-                height += len(part.paragraphs) * 3 * line_padding
149
-                # Rechne eine Zeile mehr für den Rahmen
150
-                height += line_height
151
-            if part.headline:
152
-                height += (len(_splitToWidth(canvas, part.headline, right - left, font + '-Bold', default_font_size + 1)) * line_height) + line_padding
153
-            for para in part.paragraphs:
154
-                height += (len(_splitToWidth(canvas, para, right - left, font, default_font_size)) * line_height) + line_padding
155
-        elif type(part) == Invoice.Table:
156
-            # Eine Zeile plus 2 mal line_padding für Tabellenkopf
157
-            height = line_height + 2 * line_padding
158
-            # Wenn nur ein Element (plus Summen) hin passt, reicht uns das
159
-            el = part.entries[0]
160
-            # Die Abstände oben und unten
161
-            height += 2 * line_padding
162
-            # Die Breite ist konservativ
163
-            height += line_height * len(_splitToWidth(canvas, el['subject'], 9.3 * cm, font, font_size))
164
-            if 'desc' in el and el['desc'] != '':
165
-                height += line_height * len(_splitToWidth(canvas, el['desc'], 11 * cm, font, font_size))
166
-            if part.vatType == 'net':
167
-                # Eine Zeile mehr
168
-                height += line_height + line_padding
169
-            # Für die MwSt-Summen
170
-            height += (line_height + line_padding) * len(part.vat)
171
-            # Für den Rechnungsbetrag
172
-            height += line_height + line_padding
173
-        return height
174
-
175
-    def _tableHead(y):
176
-        canvas.setFont(font, font_size)
177
-        canvas.drawString(left + (0.1 * cm), y - line_height + line_padding, 'Anz.')
178
-        canvas.drawString(left + (2.6 * cm), y - line_height + line_padding, 'Beschreibung')
179
-        if len(part.vat) == 1:
180
-            canvas.drawRightString(left + (14.3 * cm), y - line_height + line_padding, 'Einzelpreis')
181
-        else:
182
-            canvas.drawRightString(left + (13.7 * cm), y - line_height + line_padding, 'Einzelpreis')
183
-        canvas.drawRightString(left + (16.8 * cm), y - line_height + line_padding, 'Gesamtpreis')
184
-        canvas.setLineWidth(0.01 * cm)
185
-        canvas.line(left, y - line_height, right, y - line_height)
186
-        y -= line_height + 0.02 * cm
187
-        return y
188
-
189
-    def _PageWrap(canvas):
190
-        '''Seitenumbruch'''
191
-        nonlocal num_pages
192
-        num_pages += 1
193
-        canvas.setFont(font, default_font_size - 2)
194
-        canvas.drawRightString(rightcontent, bottomcontent + line_padding, 'Fortsetzung auf Seite %i' % num_pages)
195
-        canvas.showPage()
196
-        basicPage(canvas)
197
-        y = topcontent - font_size
198
-        canvas.setFillColor((0, 0, 0))
199
-        canvas.setFont(font, font_size - 2)
200
-        canvas.drawCentredString(leftcontent + (rightcontent - leftcontent) // 2, y, '- Seite %i -' % num_pages)
201
-
202
-    address(canvas, iv.addresslines)
203
-
204
-    font_size = default_font_size
205
-    y = firstPage(canvas)
206
-    if not bankdata:
207
-        # Bankdaten überschreiben wenn Lastschrift
208
-        canvas.setFillColor(Color(255, 255, 255, alpha=0.8))
209
-        canvas.rect(leftcontent + ((rightcontent - leftcontent) // 3) * 2 - 2, bottomcontent - 2, (rightcontent - leftcontent) // 3, -40, fill=True, stroke=False)
210
-        canvas.setFillColor(Color(0, 0, 0, alpha=1))
211
-        canvas.saveState()
212
-        canvas.translate(leftcontent + ((rightcontent - leftcontent) // 3) * 2 + 2, bottomcontent - 40)
213
-        canvas.rotate(15)
214
-        canvas.drawString(0, 0, "Bitte nicht überweisen")
215
-        canvas.restoreState()
216
-        # canvas.drawString(leftcontent+((rightcontent-leftcontent)/3)*2 + 2, bottomcontent - 20, "Bitte nicht überweisen")
217
-
218
-    canvas.setFont(font + '-Bold', font_size + 3)
219
-    min_y = y
220
-    if iv.caption:
221
-        canvas.drawString(leftcontent, y, iv.caption)
222
-        min_y -= (font_size + 3) + 0.5 * cm
223
-
224
-    if type(iv) == Invoice.Tender:
225
-        canvas.setFont(font, font_size)
226
-        canvas.drawString(rightcolumn, y, "Erstellungsdatum:")
227
-        canvas.drawRightString(rightcontent, y, "%s" % iv.date.strftime('%d. %m. %Y'))
228
-        y -= (font_size + 0.1 * cm)
229
-    elif type(iv) == Invoice.Generic:
230
-        canvas.setFont(font, font_size)
231
-        canvas.drawString(rightcolumn, y, "Datum:")
232
-        canvas.drawRightString(rightcontent, y, "%s" % iv.date.strftime('%d. %m. %Y'))
233
-        y -= (font_size + 0.1 * cm)
234
-    elif type(iv) == Invoice.Invoice:
235
-        canvas.setFont(font + '-Bold', font_size)
236
-        canvas.drawString(rightcolumn, y, "Bei Fragen bitte immer angeben:")
237
-        y -= (font_size + 0.2 * cm)
238
-        canvas.setFont(font, font_size)
239
-        canvas.drawString(rightcolumn, y, "Rechnungsdatum:")
240
-        canvas.drawRightString(rightcontent, y, "%s" % iv.date.strftime('%d. %m. %Y'))
241
-        y -= (font_size + 0.1 * cm)
242
-        canvas.drawString(rightcolumn, y, "Rechnungsnummer:")
243
-        canvas.drawRightString(rightcontent, y, "%i" % iv.id)
244
-        y -= (font_size + 0.1 * cm)
245
-    if iv.customerno:
246
-        canvas.drawString(rightcolumn, y, "Kundennummer:")
247
-        canvas.drawRightString(rightcontent, y, "%s" % iv.customerno)
248
-        y -= (font_size + 0.5 * cm)
249
-    canvas.setFont(font, font_size)
250
-    y = min(min_y, y)
251
-
252
-    if iv.salutation:
253
-        canvas.drawString(leftcontent, y, iv.salutation)
254
-        y -= font_size + 0.2 * cm
255
-        if type(iv) in [Invoice.Tender, Invoice.Invoice]:
256
-            introText = 'hiermit stellen wir Ihnen die nachfolgend genannten Leistungen in Rechnung.'
257
-            if type(iv) == Invoice.Tender:
258
-                introText = 'hiermit unterbreiten wir Ihnen folgendes Angebot.'
259
-            intro = _splitToWidth(canvas, introText, rightcontent - leftcontent, font, font_size)
260
-            for line in intro:
261
-                canvas.drawString(leftcontent, y, line)
262
-                y -= font_size + 0.1 * cm
263
-            y -= font_size + 0.1 * cm
264
-
265
-    font_size = default_font_size
266
-    for part in iv.parts:
267
-        if y - _partHeight(part) < (bottomcontent + (0.5 * cm)):
268
-            _PageWrap(canvas)
269
-            y = topcontent - font_size - line_padding * 3
270
-        # Debug: Was hat die Höhenbestimmung für diesen Teil als Höhe herausgefunden?
271
-        # canvas.line(leftcontent, y-_partHeight(part), rightcontent, y-_partHeight(part))
272
-
273
-        if type(part) == Invoice.Table:
274
-
275
-            left = leftcontent
276
-            right = rightcontent
277
-            top = topcontent
278
-            bottom = bottomcontent
279
-            temp_sum = 0.0
280
-            y = _tableHead(y)
281
-            odd = True
282
-            for el in part.entries:
283
-                subject = []
284
-                if len(part.vat) == 1:
285
-                    subject = _splitToWidth(canvas, el['subject'], 10.3 * cm, font, font_size)
286
-                else:
287
-                    subject = _splitToWidth(canvas, el['subject'], 9.3 * cm, font, font_size)
288
-                desc = []
289
-                if 'desc' in el and el['desc'] != '':
290
-                    desc = _splitToWidth(canvas, el['desc'], 11 * cm, font, font_size)
291
-                need_lines = len(subject) + len(desc)
292
-
293
-                # need page wrap?
294
-                if y - (need_lines + 2 * font_size) < (bottomcontent + 2 * cm):
295
-                    canvas.setFont(font, font_size)
296
-                    # Zwischensumme
297
-                    canvas.drawRightString(left + 14.5 * cm, y - font_height, 'Zwischensumme:')
298
-                    canvas.drawRightString(left + 16.8 * cm, y - font_height, _formatPrice(temp_sum))
299
-                    # page wrap
300
-                    _PageWrap(canvas)
301
-                    y = topcontent - font_size - line_padding * 3
302
-                    # header
303
-                    y = _tableHead(y)
304
-                    odd = True
305
-                    # übertrag
306
-                    canvas.setFont(font, font_size)
307
-                    canvas.drawRightString(left + 14.5 * cm, y - font_height, 'Übertrag:')
308
-                    canvas.drawRightString(left + 16.8 * cm, y - font_height, _formatPrice(temp_sum))
309
-                    y -= font_height + line_padding
310
-
311
-                # Zwischensumme (inkl. aktueller Posten)
312
-                temp_sum += el['total']
313
-                # draw the background
314
-                if not odd:
315
-                    canvas.setFillColorRGB(0.9, 0.9, 0.9)
316
-                else:
317
-                    canvas.setFillColorRGB(1, 1, 1)
318
-                canvas.rect(left, y - (need_lines * line_height) - (2 * line_padding), height=(need_lines * line_height) + (2 * line_padding), width=right - left, fill=1, stroke=0)
319
-                canvas.setFillColorRGB(0, 0, 0)
320
-                y -= line_padding
321
-                (integer, decimals) = _niceCount(el['count'])
322
-                canvas.drawRightString(left + 0.8 * cm, y - font_height, integer)
323
-                suffix = ''
324
-                if decimals:
325
-                    suffix = ',%s' % decimals
326
-                if el['unit']:
327
-                    suffix = suffix + ' ' + el['unit']
328
-                if suffix:
329
-                    canvas.drawString(left + 0.8 * cm, y - font_height, '%s' % suffix)
330
-
331
-                if len(part.vat) < 2:
332
-                    canvas.drawString(left + 2.7 * cm, y - font_height, subject[0])
333
-                    canvas.drawRightString(left + 14.3 * cm, y - font_height, _formatPrice(el['price']))
334
-                    if el['tender']:
335
-                        canvas.drawRightString(left + 16.8 * cm, y - font_height, 'eventual')
336
-                    else:
337
-                        canvas.drawRightString(left + 16.8 * cm, y - font_height, _formatPrice(el['total']))
338
-                    subject = subject[1:]
339
-                    x = 1
340
-                    for line in subject:
341
-                        canvas.drawString(left + 2.7 * cm, y - (x * line_height) - font_height, line)
342
-                        x += 1
343
-                    for line in desc[:-1]:
344
-                        _drawJustifiedString(left + 2.7 * cm, y - (x * line_height) - font_height, line, canvas, 11 * cm, font, font_size)
345
-                        x += 1
346
-                    canvas.drawString(left + 2.7 * cm, y - (x * line_height) - font_height, desc[-1])
347
-                    x += 1
348
-                else:
349
-                    canvas.drawString(left + 2.7 * cm, y - font_height, subject[0])
350
-                    canvas.drawRightString(left + 13.3 * cm, y - font_height, _formatPrice(el['price']))
351
-                    canvas.drawString(left + 13.7 * cm, y - font_height, str(part.vat[el['vat']][1]))
352
-                    if el['tender']:
353
-                        canvas.drawRightString(left + 16.8 * cm, y - font_height, 'eventual')
354
-                    else:
355
-                        canvas.drawRightString(left + 16.8 * cm, y - font_height, _formatPrice(el['total']))
356
-                    subject = subject[1:]
357
-                    x = 1
358
-                    for line in subject:
359
-                        canvas.drawString(left + 2.7 * cm, y - (x * line_height) - font_height, line)
360
-                        x += 1
361
-                    for line in desc:
362
-                        canvas.drawString(left + 2.7 * cm, y - (x * line_height) - font_height, line)
363
-                        x += 1
364
-                odd = not odd
365
-                y -= (need_lines * line_height) + line_padding
366
-            if part.summary:
367
-                y -= (0.3 * cm)
368
-                if part.vatType == 'gross':
369
-                    summaries = []
370
-                    if len(part.vat) == 1:
371
-                        vat = list(part.vat.keys())[0]
372
-                        (integer, decimals) = _niceCount((vat * 100))
373
-                        vatstr = '%s' % integer
374
-                        if decimals:
375
-                            vatstr += ',%s' % decimals
376
-                        canvas.drawRightString(left + 14.5 * cm, y - font_height, 'Nettobetrag:')
377
-                        canvas.drawRightString(left + 16.8 * cm, y - font_height, _formatPrice(part.sum - (part.sum / (vat + 1)) * vat))
378
-                        y -= line_height
379
-                        summaries.append(('%s%% MwSt:' % vatstr, _formatPrice((part.sum / (vat + 1)) * vat)))
380
-                    else:
381
-                        net = 0.0
382
-                        for vat, vatdata in list(part.vat.items()):
383
-                            (integer, decimals) = _niceCount((vat * 100))
384
-                            vatstr = '%s' % integer
385
-                            if decimals:
386
-                                vatstr += ',%s' % decimals
387
-                            _gross = vatdata[0]
388
-                            _net = _gross / (1+vat)
389
-                            _vat = _net * vat
390
-                            summaries.append(('%s: Teilbetrag %s: Nettobetrag %s zzgl. %s%% MwSt:' % (vatdata[1], _formatPrice(_gross), _formatPrice(_net), vatstr), _formatPrice(_vat)))
391
-                            net += _net
392
-                        summaries.append(('Nettobetrag gesamt:', _formatPrice(net)))
393
-                    summaries.sort()
394
-                    for line in summaries:
395
-                        canvas.drawRightString(left + 14.5 * cm, y - font_height, line[0])
396
-                        canvas.drawRightString(left + 16.8 * cm, y - font_height, line[1])
397
-                        y -= line_height
398
-                    canvas.setFont(font + '-Bold', font_size)
399
-                    if iv.tender:
400
-                        canvas.drawRightString(left + 14.5 * cm, y - font_height, 'Gesamtbetrag:')
401
-                    else:
402
-                        canvas.drawRightString(left + 14.5 * cm, y - font_height, 'Rechnungsbetrag:')
403
-                    canvas.drawRightString(left + 16.8 * cm, y - font_height, _formatPrice(part.sum))
404
-                    canvas.setFont(font, font_size)
405
-                    y -= line_height + line_padding
406
-                else:
407
-                    canvas.drawRightString(left + 14.5 * cm, y - font_height, 'Nettobetrag:')
408
-                    canvas.drawRightString(left + 16.8 * cm, y - font_height, _formatPrice(part.sum))
409
-                    y -= line_height
410
-                    summaries = []
411
-                    if len(part.vat) == 1:
412
-                        vat = list(part.vat.keys())[0]
413
-                        (integer, decimals) = _niceCount((vat * 100))
414
-                        vatstr = '%s' % integer
415
-                        if decimals:
416
-                            vatstr += ',%s' % decimals
417
-                        summaries.append(('zzgl. %s%% MwSt:' % vatstr, _formatPrice(vat * part.sum)))
418
-                    elif len(part.vat) > 1:
419
-                        for vat, vatdata in list(part.vat.items()):
420
-                            (integer, decimals) = _niceCount((vat * 100))
421
-                            vatstr = '%s' % integer
422
-                            if decimals:
423
-                                vatstr += ',%s' % decimals
424
-                            summaries.append(('zzgl. %s%% MwSt (%s):' % (vatstr, vatdata[1]), _formatPrice(vat * vatdata[0])))
425
-                    summaries.sort()
426
-                    for line in summaries:
427
-                        canvas.drawRightString(left + 14.5 * cm, y - font_height, line[0])
428
-                        canvas.drawRightString(left + 16.8 * cm, y - font_height, line[1])
429
-                        y -= line_height
430
-                    sum = part.sum
431
-                    for vat, vatdata in list(part.vat.items()):
432
-                        sum += vat * vatdata[0]
433
-                    canvas.setFont(font + '-Bold', font_size)
434
-                    if iv.tender:
435
-                        canvas.drawRightString(left + 14.5 * cm, y - font_height, 'Gesamtbetrag:')
436
-                    else:
437
-                        canvas.drawRightString(left + 14.5 * cm, y - font_height, 'Rechnungsbetrag:')
438
-                    canvas.drawRightString(left + 16.8 * cm, y - font_height, _formatPrice(sum))
439
-                    canvas.setFont(font, font_size)
440
-                    y -= line_height + line_padding
441
-        elif type(part) == Invoice.Text:
442
-            my_font_size = font_size
443
-            canvas.setFont(font, my_font_size)
444
-            left, right = leftcontent, rightcontent
445
-            firsttime = True
446
-            headlines = []
447
-            if part.urgent:
448
-                left += 1.5 * cm
449
-                right -= 1.5 * cm
450
-            if part.headline:
451
-                headlines = _splitToWidth(canvas, part.headline, right - left, font, my_font_size)
452
-            for para in part.paragraphs:
453
-                lines = _splitToWidth(canvas, para, right - left, font, my_font_size)
454
-                if part.urgent:
455
-                    need_height = len(lines) * line_height
456
-                    if len(headlines) > 0:
457
-                        need_height += len(headlines) * (line_height + 1) + line_padding
458
-                    canvas.setFillColorRGB(0.95, 0.95, 0.95)
459
-                    canvas.rect(left - 0.5 * cm, y - (need_height + (6 * line_padding)), height=need_height + (6 * line_padding), width=right - left + 1 * cm, fill=1, stroke=1)
460
-                    canvas.setFillColorRGB(0, 0, 0)
461
-                    y -= line_padding * 3
462
-                if part.headline and firsttime:
463
-                    firsttime = False
464
-                    canvas.setFont(font + '-Bold', my_font_size + 1)
465
-                    for line in headlines:
466
-                        canvas.drawString(left, y - (font_height + 1), line)
467
-                        y -= line_height + 1
468
-                    y -= line_padding
469
-                    canvas.setFont(font, my_font_size)
470
-                for line in lines[:-1]:
471
-                    _drawJustifiedString(left, y - font_height, line, canvas, right - left, font, my_font_size)
472
-                    y -= line_height
473
-                canvas.drawString(left, y - font_height, lines[-1])
474
-                y -= line_height
475
-
476
-                y -= line_padding * 3
477
-            left, right = leftcontent, rightcontent
478
-        elif type(part) == Invoice.Image:
479
-            width = (part.imagedata.width / part.dpi) * inch
480
-            height = width * (part.imagedata.height / part.imagedata.width)
481
-            x = leftcontent
482
-            if part.alignment == "center":
483
-                x = leftcontent + (rightcontent - leftcontent)/2 - width/2
484
-            elif part.alignment == "right":
485
-                x = rightcontent - width
486
-            canvas.drawInlineImage(part.imagedata, x, y-height, width=width, height=height)
487
-            y -= line_padding + height
488
-            if part.caption:
489
-                canvas.drawString(x, y-font_height, part.caption)
490
-                y -= line_height
491
-        else:
492
-            raise NotImplementedError("Cannot handle part of type %s" % type(part))
493
-        y -= (0.5 * cm)
494
-
495
-    canvas.showPage()
496
-    canvas.save()
497
-    pdfdata = fd.getvalue()
498
-    return pdfdata
499 0