Struktur verändern (broken!)
Bernd Wurst

Bernd Wurst commited on 2008-01-23 17:59:01
Zeige 3 geänderte Dateien mit 669 Einfügungen und 0 Löschungen.

... ...
@@ -0,0 +1,74 @@
1
+# -* coding: utf8 *-
2
+
3
+import datetime
4
+
5
+class InvoiceText(object):
6
+  def __init__(self, content, urgent=False, headline=None):
7
+    self.paragraphs = [content]
8
+    self.urgent = urgent
9
+    self.headline = headline
10
+
11
+  def addParagraph(self, content):
12
+    self.paragraphs.append(content)
13
+
14
+
15
+class InvoiceTable(object):
16
+  def __init__(self, vatType = 'gross', tender = False, summary = True):
17
+    self.entries = []
18
+    self.vat = {}
19
+    self.sum = 0.0
20
+    self.tender = tender
21
+    self.summary = summary
22
+    if vatType not in ['gross', 'net']:
23
+      raise ValueError('vatType must be »gross« or »net«')
24
+    self.vatType = vatType
25
+
26
+  def validEntry(self, entry):
27
+    '''bekommt einen Eintrag und liefert einen Eintrag wenn ok, wirft ansonsten ValueError.
28
+    wird benutzt um z.B. die Summe auszurechnen oder ähnliches
29
+    '''
30
+    k = entry.keys()
31
+    e = entry
32
+    if not ('count' in k and 'subject' in k and 'price' in k and 'vat' in k):
33
+      raise ValueError('Some data is missing!')
34
+    ret = {'count': e['count'],
35
+          'subject': e['subject'],
36
+          'price': e['price'],
37
+          'total': (e['price'] * e['count']),
38
+          'vat': e['vat'],
39
+          'tender': False,
40
+          }
41
+    if 'tender' in e.keys():
42
+      ret['tender'] = e['tender']
43
+    if 'desc' in k:
44
+      ret['desc'] = e['desc']
45
+    return ret
46
+
47
+  def addItem(self, data):
48
+    '''Fügt eine Zeile ein. data muss ein Dict mit passenden Keys und passenden
49
+    Typen sein'''
50
+    d = self.validEntry(data)
51
+    if not d['vat'] in self.vat.keys():
52
+      self.vat[d['vat']] = [0, chr(65+len(self.vat))]
53
+    if 'tender' not in data or not data['tender']:
54
+      self.vat[d['vat']][0] += d['total']
55
+      self.sum += d['total']
56
+    self.entries.append(d)
57
+
58
+
59
+
60
+class Invoice(object):
61
+  def __init__(self, tender = False):
62
+    self.customerno = None
63
+    self.addresslines = ['', ]
64
+    self.salutation = 'Sehr geehte Damen und Herren,'
65
+    self.id = None
66
+    self.tender = tender
67
+    self.parts = []
68
+    self.pagecount = 0
69
+    self.date = datetime.date.today()
70
+
71
+  def setDate(self, date):
72
+    if type(date) != datetime.date:
73
+      raise ValueError('date must be of type »datetime.date«')
74
+    self.date = date
... ...
@@ -0,0 +1,480 @@
1
+# -* coding: utf8 *-
2
+
3
+from InvoiceObjects import *
4
+import re
5
+
6
+# reportlab imports
7
+from reportlab.lib.units import cm
8
+from reportlab.lib.pagesizes import A4
9
+from reportlab.pdfbase.ttfonts import TTFont, TTFontFace, TTFontFile, TTFOpenFile, \
10
+                                  TTFontParser, TTFontMaker, TTFError, \
11
+                                  parse_utf8, makeToUnicodeCMap, \
12
+                                  FF_SYMBOLIC, FF_NONSYMBOLIC, \
13
+                                  calcChecksum
14
+from reportlab.pdfbase import pdfmetrics
15
+from reportlab.pdfgen import canvas as Canvas
16
+
17
+fontpath_vera = '/usr/share/fonts/ttf-bitstream-vera/'
18
+
19
+
20
+def _formatPrice(price, symbol='€'):
21
+  '''_formatPrice(price, symbol='€'):
22
+  Gets a floating point value and returns a formatted price, suffixed by 'symbol'. '''
23
+  s = ("%.2f" % price).replace('.', ',')
24
+  pat = re.compile(r'([0-9])([0-9]{3}[.,])')
25
+  while pat.search(s):
26
+    s = pat.sub(r'\1.\2', s)
27
+  return s+' '+symbol
28
+
29
+def _niceCount(value):
30
+  '''_niceCount(value):
31
+  Returns a tuple (integer , decimals) where decimals can be None'''
32
+  if type(value) == int:
33
+    return ('%i' % value, None)
34
+  if round(value, 2) == int(value):
35
+    return ('%i' % int(value), None)
36
+  s = '%.2f' % value
37
+  (integer, decimals) = s.split('.', 1)
38
+  if decimals[-1] == '0':
39
+    decimals = decimals[:-1]
40
+  return (integer, decimals)
41
+
42
+
43
+def _registerFonts():
44
+  pdfmetrics.registerFont(TTFont("Vera", fontpath_vera + "Vera.ttf"))
45
+  pdfmetrics.registerFont(TTFont("Vera-Bold", fontpath_vera + "VeraBd.ttf"))
46
+  pdfmetrics.registerFont(TTFont("Vera-Oblique", fontpath_vera + "VeraIt.ttf"))
47
+  pdfmetrics.registerFont(TTFont("Vera-BoldOblique", fontpath_vera + "VeraBI.ttf"))
48
+
49
+
50
+
51
+def _splitToWidth(canvas, text, width, font, size):
52
+  '''_splitToWidth(canvas, text, width, font, size)
53
+  Split a string to several lines of a given width.'''
54
+  lines = []
55
+  paras = text.split('\n')
56
+  for para in paras:
57
+    words = para.split(' ')
58
+    while len(words) > 0:
59
+      mywords = [words[0], ]
60
+      del words[0]
61
+      while len(words) > 0 and canvas.stringWidth(' '.join(mywords) + ' ' + words[0], font, size) <= width:
62
+        mywords.append(words[0])
63
+        del words[0]
64
+      lines.append(' '.join(mywords))
65
+  return lines
66
+
67
+
68
+def _PageMarkers(canvas):
69
+  """Setzt Falzmarken"""
70
+  from reportlab.lib.units import cm
71
+  canvas.setStrokeColorRGB(0,0,0)
72
+  canvas.setLineWidth(0.01*cm)
73
+  canvas.lines(
74
+   [(0.3*cm,-10.5*cm,0.65*cm,-10.5*cm),
75
+    (0.3*cm,-21.0*cm,0.65*cm,-21.0*cm),
76
+    (0.3*cm,-14.85*cm,0.7*cm,-14.85*cm)]);
77
+
78
+
79
+
80
+def _PageWrap(canvas):
81
+  '''Seitenumbruch'''
82
+  canvas.showPage()
83
+  canvas.translate(0, A4[1])
84
+  _PageMarkers(canvas)
85
+
86
+
87
+
88
+def InvoiceToPDF(iv):
89
+  _registerFonts()
90
+  from StringIO import StringIO
91
+  fd = StringIO()
92
+  canvas = Canvas.Canvas(fd, pagesize=A4)
93
+  (width, height) = A4
94
+  font = 'Vera'
95
+  canvas.setFont(font, 12)
96
+  # Set marker to top.
97
+  canvas.translate(0, A4[1])
98
+  # Set default font size
99
+  default_font_size = 9
100
+  # set margins
101
+  topmargin = 2*cm
102
+  bottommargin = 2.5*cm
103
+  leftmargin = 2*cm
104
+  rightmargin = 2*cm
105
+
106
+  num_pages = 1
107
+
108
+  topcontent = -topmargin
109
+  leftcontent = leftmargin
110
+  rightcontent = A4[0] - rightmargin
111
+  bottomcontent =  -(A4[1] - bottommargin)
112
+
113
+  rightcolumn = 13*cm
114
+
115
+  # Waehrungssysmbol
116
+  symbol = '€'
117
+  y = topcontent
118
+  font_size = default_font_size
119
+  font_height = 0.35*cm
120
+  line_padding = 0.1*cm
121
+  line_height = font_height+0.1*cm
122
+  _PageMarkers(canvas)
123
+
124
+  def _partHeight(part):
125
+    height = 0
126
+    if type(part) == InvoiceText:
127
+      left, right = leftcontent, rightcontent
128
+      if part.urgent:
129
+        left += 1.5*cm
130
+        right -= 1.5*cm
131
+        height += len(part.paragraphs) * 3 * line_padding
132
+      if part.headline:
133
+        height += (len(_splitToWidth(canvas, part.headline, right-left, font+'-Bold', default_font_size+1)) * line_height) + line_padding
134
+      for para in part.paragraphs:  
135
+        height += (len(_splitToWidth(canvas, para, right-left, font, default_font_size)) * line_height) + line_padding
136
+    elif type(part) == InvoiceTable:
137
+      ## FIXME: Das ist dreckig
138
+      height = len(part.entries) * 1.1*cm
139
+      height += 3*cm
140
+    return height
141
+
142
+  def _Footer():
143
+    canvas.line(leftcontent, bottomcontent, rightcontent, bottomcontent)
144
+    canvas.setFont(font, 8)
145
+    canvas.drawCentredString(leftcontent+((rightcontent-leftcontent)/2), bottomcontent-10, 'schokokeks.org GbR · Bernd Wurst / Johannes Böck · http://www.schokokeks.org/')
146
+    canvas.drawCentredString(leftcontent+((rightcontent-leftcontent)/2), bottomcontent-20, 'Steuernummer: 51072/01109 (FA Backnang) · USt-ID: DE255720588')
147
+    canvas.drawCentredString(leftcontent+((rightcontent-leftcontent)/2), bottomcontent-30, 'Bankverbindung: Volksbank Backnang, BLZ 602 911 20, Konto Nr. 671279 017')
148
+    canvas.drawCentredString(leftcontent+((rightcontent-leftcontent)/2), bottomcontent-40, 'IBAN: DE78602911200671279017, BIC: GENODES1VBK')
149
+  
150
+  
151
+  addy_width = 8.5*cm
152
+  addy_height = 5.0*cm
153
+
154
+  font_size = 8
155
+  x = 2.0 * cm
156
+  y = -4.8 * cm - font_size - 1
157
+
158
+  canvas.setFont(font, font_size)
159
+
160
+
161
+  canvas.drawString(x, y+0.1*cm, ' schokokeks.org - Köchersberg 25 - 71540 Murrhardt')
162
+  canvas.line(x, y, x + (8.5 * cm), y)
163
+  y = y - font_size - 3
164
+
165
+  font_size = 11
166
+  x += 0.5*cm
167
+  y -= 0.5*cm
168
+  canvas.setFont(font, font_size)
169
+  for line in iv.addresslines:
170
+    canvas.drawString(x, y, line)
171
+    y -= line_height
172
+
173
+
174
+  font_size = default_font_size
175
+
176
+  y = topcontent
177
+  canvas.drawInlineImage("logo.png", rightcolumn, topcontent-(3*cm), width=4.08*cm, height=3*cm)
178
+  y -= (3.5*cm)
179
+  canvas.setFont(font+"-Bold", font_size)
180
+  #canvas.drawString(rightcolumn, y, "schokokeks.org Webhosting")
181
+  #y -= (font_size + 5 + 0.2*cm)
182
+  canvas.drawString(rightcolumn, y, "schokokeks.org GbR")
183
+  y -= (font_size + 5)
184
+  canvas.setFont(font, font_size)
185
+  canvas.drawString(rightcolumn, y, "Bernd Wurst / Johannes Böck")
186
+  y -= (font_size + 5)
187
+  canvas.drawString(rightcolumn, y, "Köchersberg 25")
188
+  y -= (font_size + 5)
189
+  canvas.drawString(rightcolumn, y, "71540 Murrhardt")
190
+  y -= (font_size + 10)
191
+  canvas.drawString(rightcolumn, y, "Tel: 07192-936432")
192
+  y -= (font_size + 5)
193
+  canvas.drawString(rightcolumn, y, "Fax: 07192-936431")
194
+  y -= (font_size + 5)
195
+  canvas.drawString(rightcolumn, y, "E-Mail: root@schokokeks.org")
196
+  y -= (font_size + 10)
197
+  y = -9.5*cm
198
+  canvas.setFont(font+'-Bold', font_size+3)
199
+  if iv.tender:
200
+    canvas.drawString(leftcontent, y, 'Angebot')
201
+  else:
202
+    canvas.drawString(leftcontent, y, 'Rechnung')
203
+
204
+  if iv.tender:
205
+    canvas.setFont(font, font_size)
206
+    canvas.drawString(rightcolumn, y, "Erstellungsdatum:")
207
+    canvas.drawRightString(rightcontent, y, "%s" % iv.date.strftime('%d. %m. %Y'))
208
+    y -= (font_size + 0.1*cm)
209
+    
210
+  else:
211
+    canvas.setFont(font+'-Bold', font_size)
212
+    canvas.drawString(rightcolumn, y, "Bei Fragen bitte immer angeben:")
213
+    y -= (font_size + 0.2*cm)
214
+    canvas.setFont(font, font_size)
215
+    canvas.drawString(rightcolumn, y, "Rechnungsdatum:")
216
+    canvas.drawRightString(rightcontent, y, "%s" % iv.date.strftime('%d. %m. %Y'))
217
+    y -= (font_size + 0.1*cm)
218
+    canvas.drawString(rightcolumn, y, "Rechnungsnummer:")
219
+    canvas.drawRightString(rightcontent, y, "%i" % iv.id)
220
+    y -= (font_size + 0.1*cm)
221
+  if iv.customerno:
222
+    canvas.drawString(rightcolumn, y, "Kundennummer:")
223
+    canvas.drawRightString(rightcontent, y, "%s" % iv.customerno)
224
+    y -= (font_size + 0.5*cm)
225
+  canvas.setFont(font, font_size)
226
+
227
+  canvas.drawString(leftcontent, y, iv.salutation)
228
+  y -= font_size + 0.2*cm
229
+  introText = 'hiermit stellen wir Ihnen die nachfolgend genannten Leistungen in Rechnung.'
230
+  if iv.tender:
231
+    introText = 'hiermit unterbreiten wir Ihnen folgendes Angebot.'
232
+  intro = _splitToWidth(canvas, introText, rightcontent - leftcontent, font, font_size)
233
+  for line in intro:
234
+    canvas.drawString(leftcontent, y, line)
235
+    y -= font_size + 0.1*cm
236
+  y -= font_size + 0.1*cm
237
+
238
+  
239
+  font_size = default_font_size
240
+  for part in iv.parts:
241
+    if y - _partHeight(part) < (bottomcontent + (0.5*cm)):
242
+      num_pages += 1
243
+      y = bottomcontent + (0.5*cm)
244
+      canvas.setFont(font, default_font_size-2)
245
+      canvas.drawRightString(rightcontent, bottomcontent + line_padding, 'Fortsetzung auf Seite %i' % num_pages)
246
+      _Footer()
247
+      _PageWrap(canvas)
248
+      y = topcontent - font_size
249
+      canvas.setFillColor((0,0,0))
250
+      canvas.setFont(font, font_size-2)
251
+      canvas.drawCentredString(leftcontent + (rightcontent - leftcontent) / 2, y, '- Seite %i -' % num_pages)
252
+      y -= line_padding*3
253
+    if type(part) == InvoiceTable:
254
+        
255
+      left = leftcontent
256
+      right = rightcontent
257
+      top = topcontent
258
+      bottom = bottomcontent
259
+      canvas.setFont(font, font_size)
260
+      canvas.drawString(left+(0.1*cm), y-line_height+line_padding, 'Anz.')
261
+      canvas.drawString(left+(1.6*cm), y-line_height+line_padding, 'Beschreibung')
262
+      if len(part.vat) == 1:
263
+        canvas.drawRightString(left+(14.3*cm), y-line_height+line_padding, 'Einzelpreis')
264
+      else:
265
+        canvas.drawRightString(left+(13.7*cm), y-line_height+line_padding, 'Einzelpreis')
266
+      canvas.drawRightString(left+(16.8*cm), y-line_height+line_padding, 'Gesamtpreis')
267
+      canvas.setLineWidth(0.01*cm)
268
+      canvas.line(left, y - line_height, right, y - line_height)
269
+      y -= line_height + 0.02*cm
270
+      odd=True
271
+      for el in part.entries:
272
+        subject = []
273
+        if len(part.vat) == 1:
274
+          subject = _splitToWidth(canvas, el['subject'], 10.3*cm, font, font_size)
275
+        else:
276
+          subject = _splitToWidth(canvas, el['subject'], 9.3*cm, font, font_size)
277
+        desc = []
278
+        if 'desc' in el and el['desc'] != '':
279
+          desc = _splitToWidth(canvas, el['desc'], 14.5*cm, font, font_size)
280
+
281
+        # draw the background
282
+        if not odd:
283
+          canvas.setFillColorRGB(0.9, 0.9, 0.9)
284
+        else:
285
+          canvas.setFillColorRGB(1, 1, 1)
286
+        need_lines = len(subject) + len(desc)
287
+        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)
288
+        canvas.setFillColorRGB(0, 0, 0)
289
+        y -= line_padding
290
+        (integer, decimals) = _niceCount(el['count'])
291
+        canvas.drawRightString(left+0.8*cm, y-font_height, integer)
292
+        if decimals:
293
+          canvas.drawString(left+0.8*cm, y-font_height, ',%s' % decimals)
294
+        if len(part.vat) == 1:
295
+          canvas.drawString(left+1.7*cm, y-font_height, subject[0])
296
+          canvas.drawRightString(left+14.3*cm, y-font_height, _formatPrice(el['price']))
297
+          if el['tender']:  
298
+            canvas.drawRightString(left+16.8*cm, y-font_height, 'eventual')
299
+          else:
300
+            canvas.drawRightString(left+16.8*cm, y-font_height, _formatPrice(el['total']))
301
+          subject = subject[1:]
302
+          x = 1
303
+          for line in subject:
304
+            canvas.drawString(left+1.7*cm, y-(x * line_height)-font_height, line)
305
+            x += 1
306
+          for line in desc:
307
+            canvas.drawString(left+1.7*cm, y-(x * line_height)-font_height, line)
308
+            x += 1
309
+        else:
310
+          canvas.drawString(left+1.7*cm, y-font_height, subject[0])
311
+          canvas.drawRightString(left+13.3*cm, y-font_height, _formatPrice(el['price']))
312
+          canvas.drawString(left+13.7*cm, y-font_height, str(part.vat[el['vat']][1]))
313
+          if el['tender']:  
314
+            canvas.drawRightString(left+16.8*cm, y-font_height, 'eventual')
315
+          else:
316
+            canvas.drawRightString(left+16.8*cm, y-font_height, _formatPrice(el['total']))
317
+          subject = subject[1:]
318
+          x = 1
319
+          for line in subject:
320
+            canvas.drawString(left+1.7*cm, y-(x * line_height)-font_height, line)
321
+            x += 1
322
+          for line in desc:
323
+            canvas.drawString(left+1.7*cm, y-(x * line_height)-font_height, line)
324
+            x += 1
325
+        odd = not odd
326
+        y -= (need_lines * line_height) + line_padding
327
+      if part.summary:
328
+        y -= (0.3*cm)
329
+        if part.vatType == 'gross':
330
+          canvas.setFont(font+'-Bold', font_size)
331
+          if iv.tender:
332
+            canvas.drawRightString(left + 14.5*cm, y-font_height, 'Gesamtbetrag:')
333
+          else:
334
+            canvas.drawRightString(left + 14.5*cm, y-font_height, 'Rechnungsbetrag:')
335
+          canvas.drawRightString(left + 16.8*cm, y-font_height, _formatPrice(part.sum))
336
+          canvas.setFont(font, font_size)
337
+          y -= line_height + line_padding
338
+          summaries = []
339
+          if len(part.vat) == 1:
340
+            vat = part.vat.keys()[0]
341
+            if iv.tender:
342
+              summaries.append(('Im Gesamtbetrag sind %.1f%% MwSt enthalten:' % (vat*100), _formatPrice((part.sum/(vat+1))*vat)))
343
+            else:
344
+              summaries.append(('Im Rechnungsbetrag sind %.1f%% MwSt enthalten:' % (vat*100), _formatPrice((part.sum/(vat+1))*vat)))
345
+          else:
346
+            for vat, vatdata in part.vat.iteritems():
347
+              summaries.append('%s: Im Teilbetrag von %s sind %.1f%% MwSt enthalten:' % (vatdata[1], _formatPrice(vatdata[0]), vat*100), _formatPrice((vatdata[0]/(vat+1))*vat))
348
+          summaries.sort()
349
+          for line in summaries:
350
+            canvas.drawRightString(left + 14.5*cm, y-font_height, line[0])
351
+            canvas.drawRightString(left + 16.8*cm, y-font_height, line[1])
352
+            y -= line_height
353
+        else:
354
+          canvas.drawRightString(left + 14.5*cm, y-font_height, 'Nettobetrag:')
355
+          canvas.drawRightString(left + 16.8*cm, y-font_height, _formatPrice(part.sum))
356
+          y -= line_height
357
+          summaries = []
358
+          if len(part.vat) == 1:
359
+            vat = part.vat.keys()[0]
360
+            summaries.append(('zzgl. %.1f%% MwSt:' % (vat*100), _formatPrice(vat*part.sum)))
361
+          else:
362
+            for vat, vatdata in part.vat.iteritems():
363
+              summaries.append(('zzgl. %.1f%% MwSt (%s):' % (vat*100, vatdata[1]), _formatPrice(vat*vatdata[0])))
364
+          summaries.sort()
365
+          for line in summaries:
366
+            canvas.drawRightString(left + 14.5*cm, y-font_height, line[0])
367
+            canvas.drawRightString(left + 16.8*cm, y-font_height, line[1])
368
+            y -= line_height
369
+          sum = 0
370
+          for vat, vatdata in part.vat.iteritems():
371
+            sum += (vat+1)*vatdata[0]
372
+          canvas.setFont(font+'-Bold', font_size)
373
+          if iv.tender:
374
+            canvas.drawRightString(left + 14.5*cm, y-font_height, 'Gesamtbetrag:')
375
+          else:
376
+            canvas.drawRightString(left + 14.5*cm, y-font_height, 'Rechnungsbetrag:')
377
+          canvas.drawRightString(left + 16.8*cm, y-font_height, _formatPrice(sum))
378
+          canvas.setFont(font, font_size)
379
+          y -= line_height + line_padding
380
+    elif type(part) == InvoiceText:
381
+      my_font_size = font_size
382
+      canvas.setFont(font, my_font_size)
383
+      left, right = leftcontent, rightcontent
384
+      firsttime = True
385
+      headlines = []
386
+      if part.urgent:
387
+        left += 1.5*cm
388
+        right -= 1.5*cm
389
+      if part.headline:
390
+        headlines = _splitToWidth(canvas, part.headline, right-left, font, my_font_size)
391
+      for para in part.paragraphs:
392
+        lines = _splitToWidth(canvas, para, right-left, font, my_font_size)
393
+        if part.urgent:
394
+          need_height = len(lines) * line_height
395
+          if len(headlines) > 0:
396
+            need_height += len(headlines) * (line_height + 1) + line_padding
397
+          canvas.setFillColorRGB(0.95, 0.95, 0.95)
398
+          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)
399
+          canvas.setFillColorRGB(0, 0, 0)
400
+          y -= line_padding*3
401
+        if part.headline and firsttime:
402
+          firsttime = False
403
+          canvas.setFont(font+'-Bold', my_font_size+1)
404
+          for line in headlines:
405
+            canvas.drawString(left, y-(font_height+1), line)
406
+            y -= line_height + 1
407
+          y -= line_padding
408
+          canvas.setFont(font, my_font_size)
409
+        for line in lines:
410
+          canvas.drawString(left, y-font_height, line)
411
+          y -= line_height
412
+        y -= line_padding*3
413
+      left, right = leftcontent, rightcontent
414
+    else:
415
+      raise NotImplementedError("Cannot handle part of type %s" % type(part))
416
+    y -= (0.5*cm)
417
+    
418
+  _Footer()
419
+  
420
+  canvas.showPage()
421
+  canvas.save()
422
+  pdfdata = fd.getvalue()
423
+  return pdfdata
424
+
425
+
426
+
427
+
428
+
429
+
430
+
431
+#######################################
432
+'''
433
+  for el in invoiceTable.entries:
434
+    if len(invoiceTable.vat) == 1:
435
+      subject = _breakLine(el['subject'], width=43)
436
+      ret.append(u'%5.2f %-43s  %10s %10s' % (el['count'], subject[0], format_price(el['price']), format_price(el['total'])))
437
+      for i in range(1,len(subject)):
438
+        ret.append(u'      %s' % subject[i])
439
+    else:
440
+      subject = _breakLine(el['subject'], width=41)
441
+      ret.append(u'%5.2f %-41s  %10s %s %10s' % (el['count'], subject[0], format_price(el['price']), invoiceTable.vat[el['vat']][1], format_price(el['total'])))
442
+      for i in range(1,len(subject)):
443
+        ret.append(u'      %s' % subject[i])
444
+    if 'desc' in el and el['desc']:
445
+      desc = _breakLine(el['desc'], 43)
446
+      for  line in desc:
447
+        ret.append(u'      %s' % line)
448
+  ret.append('-'*72)
449
+  if invoiceTable.vatType == 'gross':
450
+    ret.append((u'Rechnungsbetrag:  %11s' % format_price(invoiceTable.sum)).rjust(72))
451
+    ret.append('')
452
+    summaries = []
453
+    if len(invoiceTable.vat) == 1:
454
+      vat = invoiceTable.vat.keys()[0]
455
+      summaries.append(u'      Im Rechnungsbetrag sind %.1f%% MwSt enthalten (%s)' % (vat*100, format_price((invoiceTable.sum/(vat+1))*vat)))
456
+    else:
457
+      for vat, vatdata in invoiceTable.vat.iteritems():
458
+        summaries.append(u'    %s: Im Teilbetrag von %s sind %.1f%% MwSt enthalten (%s)' % (vatdata[1], format_price(vatdata[0]), vat*100, format_price((vatdata[0]/(vat+1))*vat)))
459
+    summaries.sort()
460
+    for line in summaries:
461
+      ret.append(line)
462
+  else:
463
+    ret.append((u'Nettobetrag: %11s' % format_price(invoiceTable.sum)).rjust(72))
464
+    summaries = []
465
+    if len(invoiceTable.vat) == 1:
466
+      vat = invoiceTable.vat.keys()[0]
467
+      summaries.append((u'zzgl. %.1f%% MwSt: %11s' % (vat*100, format_price(vat*invoiceTable.sum))).rjust(72))
468
+    else:
469
+      for vat, vatdata in invoiceTable.vat.iteritems():
470
+        summaries.append((u'zzgl. %4.1f%% MwSt (%s): %11s' % (vat*100, vatdata[1], format_price(vat*vatdata[0]))).rjust(72))
471
+    summaries.sort()
472
+    for line in summaries:
473
+      ret.append(line)
474
+    sum = 0
475
+    for vat, vatdata in invoiceTable.vat.iteritems():
476
+      sum += (vat+1)*vatdata[0]
477
+    ret.append((u'Rechnungsbetrag: %11s' % format_price(sum)).rjust(72))
478
+  return ('\n'.join(ret)).encode('utf-8')
479
+
480
+'''
... ...
@@ -0,0 +1,115 @@
1
+# -* coding: utf8 *-
2
+
3
+from InvoiceObjects import *
4
+from utils import format_price, split_to_width
5
+
6
+
7
+
8
+def _breakLine(text, width=72):
9
+  lines = []
10
+  paras = text.split('\n')
11
+  for para in paras:
12
+    words = para.split(' ')
13
+    while len(words) > 0:
14
+      mywords = [words[0], ]
15
+      del words[0]
16
+      while len(words) > 0 and len(u' '.join(mywords) + ' ' + words[0]) <= width:
17
+        mywords.append(words[0])
18
+        del words[0]
19
+      lines.append(' '.join(mywords))
20
+  return lines
21
+  
22
+
23
+def InvoiceToText(iv):
24
+  ret = []
25
+  ret.append(u'Rechnungsempfänger:')
26
+  for line in iv.addresslines:
27
+    ret.append('  %s' % line)
28
+  ret.append('')
29
+  ret.append('Kundennummer:    %4i' % iv.customerno)
30
+  ret.append('Rechnungsnummer: %4i    Rechnungsdatum:  %s' % (iv.id, iv.date.strftime('%d.%m.%Y')))
31
+
32
+  ret.append('')
33
+  for part in iv.parts:
34
+    if type(part) == InvoiceTable:
35
+      ret.append(InvoiceTableToText(part))
36
+    elif type(part) == InvoiceText:
37
+      ret.append(InvoiceTextToText(part))
38
+    else:
39
+      raise NotImplementedError("Cannot handle part of type %s" % type(part))
40
+
41
+
42
+  ret.append('-'*72)
43
+  ret.append('Unsere Bankverbindung:')
44
+  ret.append('Volksbank Backnang, BLZ 602 911 20, Konto-Nr. 671279 017')
45
+  ret.append('IBAN: DE78602911200671279017, BIC: GENODES1VBK')
46
+  return ('\n'.join(ret)).encode('utf-8')
47
+
48
+
49
+
50
+def InvoiceTableToText(invoiceTable):
51
+  ret = []
52
+  if len(invoiceTable.vat) == 1:
53
+    ret.append(u'Anz   Beschreibung                                      Preis     Gesamt')
54
+    ret.append(u'-'*72)
55
+  else:
56
+    ret.append(u'Anz   Beschreibung                                    Preis       Gesamt')
57
+    ret.append(u'-'*72)
58
+
59
+  for el in invoiceTable.entries:
60
+    if len(invoiceTable.vat) == 1:
61
+      subject = _breakLine(el['subject'], width=43)
62
+      ret.append(u'%5.2f %-43s  %10s %10s' % (el['count'], subject[0], format_price(el['price']), format_price(el['total'])))
63
+      for i in range(1,len(subject)):
64
+        ret.append(u'      %s' % subject[i])
65
+    else:
66
+      subject = _breakLine(el['subject'], width=41)
67
+      ret.append(u'%5.2f %-41s  %10s %s %10s' % (el['count'], subject[0], format_price(el['price']), invoiceTable.vat[el['vat']][1], format_price(el['total'])))
68
+      for i in range(1,len(subject)):
69
+        ret.append(u'      %s' % subject[i])
70
+    if 'desc' in el and el['desc']:
71
+      desc = _breakLine(el['desc'], 43)
72
+      for line in desc:
73
+        ret.append(u'      %s' % line)
74
+  ret.append('-'*72)
75
+  if invoiceTable.vatType == 'gross':
76
+    ret.append((u'Rechnungsbetrag:  %11s' % format_price(invoiceTable.sum)).rjust(72))
77
+    ret.append('')
78
+    summaries = []
79
+    if len(invoiceTable.vat) == 1:
80
+      vat = invoiceTable.vat.keys()[0]
81
+      summaries.append(u'      Im Rechnungsbetrag sind %.1f%% MwSt enthalten (%s)' % (vat*100, format_price((invoiceTable.sum/(vat+1))*vat)))
82
+    else:
83
+      for vat, vatdata in invoiceTable.vat.iteritems():
84
+        summaries.append(u'    %s: Im Teilbetrag von %s sind %.1f%% MwSt enthalten (%s)' % (vatdata[1], format_price(vatdata[0]), vat*100, format_price((vatdata[0]/(vat+1))*vat)))
85
+    summaries.sort()
86
+    for line in summaries:
87
+      ret.append(line)
88
+  else:
89
+    ret.append((u'Nettobetrag: %11s' % format_price(invoiceTable.sum)).rjust(72))
90
+    summaries = []
91
+    if len(invoiceTable.vat) == 1:
92
+      vat = invoiceTable.vat.keys()[0]
93
+      summaries.append((u'zzgl. %.1f%% MwSt: %11s' % (vat*100, format_price(vat*invoiceTable.sum))).rjust(72))
94
+    else:
95
+      for vat, vatdata in invoiceTable.vat.iteritems():
96
+        summaries.append((u'zzgl. %4.1f%% MwSt (%s): %11s' % (vat*100, vatdata[1], format_price(vat*vatdata[0]))).rjust(72))
97
+    summaries.sort()
98
+    for line in summaries:
99
+      ret.append(line)
100
+    sum = 0
101
+    for vat, vatdata in invoiceTable.vat.iteritems():
102
+      sum += (vat+1)*vatdata[0]
103
+    ret.append((u'Rechnungsbetrag: %11s' % format_price(sum)).rjust(72))
104
+  ret.append('')
105
+  return ('\n'.join(ret)).encode('utf-8')
106
+
107
+
108
+def InvoiceTextToText(invoiceText):
109
+  ret = []
110
+  for par in invoiceText.paragraphs:
111
+    for str in split_to_width(par, 72):
112
+      ret.append(str)
113
+    ret.append('')
114
+  return ('\n'.join(ret)).encode('utf-8')
115
+  
0 116