
    iir              	      D   S r SSKJr  SSKrSSKrSSKJrJrJr  SSKJ	r	  SSK
Jr  SSKJrJrJrJrJr  SSKJrJr  SS	KJrJrJrJrJrJrJrJrJrJr  SS
KJ r J!r!J"r"J#r#  SSK$J%r%  SSK&J'r'  SSK(J)r)  SSK*J+r+  SSK,J-r-  \-" 5         \R\                  " SS5      r/\" \/SSS9r0\#" \!" \0SSSS95      r1\ " 5       r2 " S S\25      r3 " S S\25      r4 " S S\25      r5\" \65      r7\R\                  " SS5      \7l8        Sr9SHS jr:\7Rw                  S 5      S! 5       r<\7Rw                  S"5      S# 5       r=\7Rw                  S$5      S% 5       r>\7R                  S"5      S& 5       r@\7Rw                  S'5      SIS( j5       rA\7R                  S'5      SIS) j5       rB\7Rw                  S*5      SIS+ j5       rC\7Rw                  S,5      S- 5       rD\7Rw                  S.5      S/ 5       rE\7R                  S,5      S0 5       rF\7Rw                  S15      SIS2 j5       rG\7R                  S15      SIS3 j5       rH\7Rw                  S45      SIS5 j5       rI\7Rw                  S65      S7 5       rJ\7Rw                  S85      S9 5       rK\7R                  S65      S: 5       rL\7Rw                  S;5      SIS< j5       rM\7R                  S;5      SIS= j5       rN\7Rw                  S>5      SIS? j5       rO\7Rw                  S@5      SA 5       rP\7Rw                  SB5      SC 5       rQ\7Rw                  SD5      SE 5       rR\6SF:X  a  \7R                  SSG9  gg)Juk  
HFS Abrechnung – Minimal Flask-App (Flask + SQLAlchemy + MariaDB)
---------------------------------------------------------------
Funktionen:
- CRUD für grunddaten, kurs, rechnungen
- Simple Verknüpfung: rechnungen.dgid -> grunddaten.elleid
- PDF-Rechnung pro Kunde/Einrichtung (grunddaten) und Datumsbereich
- Einfache HTML-Views via render_template_string (keine externen Templates nötig)

Voraussetzungen:
- Python 3.10+
- pip install flask SQLAlchemy pymysql reportlab python-dotenv
- Laufende MariaDB mit Schema/Tables wie vom Nutzer beschrieben
- .env mit DB_URL (siehe unten)

Start:
    export FLASK_APP=hfs_app.py
    flask run --debug

Beispiel .env:
    DB_URL=mysql+pymysql://www_usr:yOPbAI8Pd@localhost:3306/hfs?charset=utf8mb4

Hinweis Sicherheit: Bitte die echten Zugangsdaten nicht commiten. Für Produktion weitere Härtung (Auth, CSRF, Rollen, etc.).
    )annotationsN)datedatetimetime)Decimal)Optional)Flaskrequestredirecturl_for	send_file)render_template_stringflash)
create_engineColumnIntegerStringDECIMALDateTime
ForeignKeyselectfunc)declarative_basesessionmakerrelationshipscoped_session)A4)canvas)mm)simpleSplit)load_dotenvDB_URLzDmysql+pymysql://www_usr:yOPbAI8Pd@localhost:3306/hfs?charset=utf8mb4T)pool_pre_pingfutureF)bind	autoflush
autocommitr%   c                  "   \ rS rSrSr\" \SSS9r\" \" S5      5      r	\" \" S5      5      r
\" \" S5      5      r\" \" S5      5      r\" \" S5      5      r\" \" S5      5      r\" \" SS	5      5      r\" \" SS	5      5      r\" S
SSS9rS rSrg)
Grunddaten4   
grunddatenTprimary_keyautoincrement   -            Rechnungkundezall, delete-orphan)back_populatescascadec                N    SU R                    SU R                  =(       d    S S3$ )Nz<Grunddaten   >)elleidfirmaselfs    
hfs_app.py__repr__Grunddaten.__repr__B   s%    dkk]!DJJ,<"+=Q??     N)__name__
__module____qualname____firstlineno____tablename__r   r   r=   r   r>   bereich	abteilungstrasseplzortr   verguetung1verguetung2r   
rechnungenrB   __static_attributes__rE   rD   rA   r*   r*   4   s     MGTBF6":EVBZ Gvbz"IVBZ G

C

CA'KA'KjJ^_J@rD   r*   c                      \ rS rSrSr\" \SSS9r\" \" S5      5      r	\" \" S5      5      r
\" \" S5      5      rS rSrg	)
KursE   kursTr-   r0      c                N    SU R                    SU R                  =(       d    S S3$ )Nz<Kurs r:   r;   r<   )r=   rW   r?   s    rA   rB   Kurs.__repr__L   s$    }Adiio2%6a88rD   rE   N)rF   rG   rH   rI   rJ   r   r   r=   r   rW   status	bemerkungrB   rS   rE   rD   rA   rU   rU   E   sD    MGTBF&*DF2JFvc{#I9rD   rU   c                      \ rS rSrSr\" \SSS9r\" \5      r	\" \
5      r\" \
5      r\" \
5      r\" \" S5      5      r\" \5      r\" \" S5      5      r\" \\" SSS	95      r\" S
SS9rSS jrSrg)r5   O   rR   Tr-   r1   r0   zgrunddaten.elleidCASCADE)ondeleter*   )r7   c                2   U R                   (       d  [        S5      $ U R                   R                  U R                   R                  U R                   R                  p2n[        U5      [        U5      [        S5      -  -   [        U5      [        S5      -  -   $ )zDWandelt stunden (Time) in Dezimalstunden um (z. B. 01:30:00 -> 1.5).0<   i  )stundenr   hourminutesecond)r@   hmss       rA   stunden_decimalRechnung.stunden_decimal]   sj    ||3<,,##T\\%8%8$,,:M:MaqzGAJ44wqzGDM7QQQrD   rE   N)returnr   )rF   rG   rH   rI   rJ   r   r   r=   r   datumr   vonbisrd   r   r\   kmrW   r   dgidr   r6   rk   rS   rE   rD   rA   r5   r5   O   s     MGTBF4LE
,C
,CTlGvbz"I	B&*D':&9INODlCERrD   r5   FLASK_SECRETz
dev-secreta  
<!doctype html>
<html lang="de">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>HFS Abrechnung</title>
  <link rel="preconnect" href="https://fonts.googleapis.com">
  <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600&display=swap" rel="stylesheet">
  <style>
    body { font-family: Inter, system-ui, -apple-system, Segoe UI, Roboto, Arial, sans-serif; margin: 24px; }
    header { display:flex; gap:12px; align-items:center; margin-bottom: 16px; }
    nav a { margin-right: 12px; text-decoration:none; color:#0b57d0; }
    table { border-collapse: collapse; width: 100%; }
    th, td { border: 1px solid #ddd; padding: 8px; }
    th { background: #f7f7f7; text-align: left; }
    input, select { padding:6px; width: 100%; box-sizing: border-box; }
    .btn { display:inline-block; padding:8px 12px; background:#0b57d0; color:#fff; text-decoration:none; border-radius:6px; }
    .btn.secondary { background:#666; }
    .btn.danger { background:#c62828; }
    .grid { display:grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap:12px; }
    .row { display:flex; gap:8px; align-items:center; }
    .flash { background:#fff3cd; border:1px solid #ffecb5; color:#664d03; padding:8px 12px; border-radius:6px; margin-bottom:12px; }
  </style>
</head>
<body>
  <header>
    <h2 style="margin:0">HFS Abrechnung</h2>
    <nav>
      <a href="{{ url_for('index') }}">Dashboard</a>
      <a href="{{ url_for('grunddaten_list') }}">Grunddaten</a>
      <a href="{{ url_for('kurs_list') }}">Kurse</a>
      <a href="{{ url_for('rechnungen_list') }}">Rechnungen</a>
      <a href="{{ url_for('rechnung_tools') }}">Rechnung erstellen</a>
    </nav>
  </header>
  {% with messages = get_flashed_messages() %}
    {% if messages %}
      <div class="flash">{{ messages[0] }}</div>
    {% endif %}
  {% endwith %}
  {{ body|safe }}
</body>
</html>
c                    [        [        U S9$ )Nbody)r   	BASE_HTML)contents    rA   pagery      s    !)'::rD   /c                 .   [        5       n  U R                  [        [        R                  " [
        R                  5      5      5      =(       d    SnU R                  [        [        R                  " [        R                  5      5      5      =(       d    SnU R                  [        [        R                  " [        R                  5      5      5      =(       d    SnU R                  5         SU SU SU S3n[        U5      $ ! U R                  5         f = f)Nr   u_   
    <div class='grid'>
      <div><h3>Überblick</h3>
        <p><b>Kunden/Einrichtungen:</b> z</p>
        <p><b>Kurse:</b> z(</p>
        <p><b>Rechnungszeilen:</b> z!</p>
      </div>
    </div>
    )SessionLocalscalarr   r   countr*   r=   rU   r5   closery   )dbkundenkurserechsrv   s        rA   indexr      s    	B6$**Z->->"?@AFQ		&DKK!89:?a		&HOO!<=>C!

) *0 1 !$$)7 +D : 	
s   CD Dz/grunddatenc                 T   [        5       n  U R                  [        [        5      R	                  [        R
                  R                  5       5      5      R                  5       R                  5       nU R                  5         Sn[        [        X!S95      $ ! U R                  5         f = f)Nu  
    <div class='row'>
      <h3 style='margin-right:auto'>Grunddaten</h3>
      <a class='btn' href='{{ url_for("grunddaten_new") }}'>Neu</a>
    </div>
    <table>
      <tr><th>ID</th><th>Firma</th><th>Bereich</th><th>Abteilung</th><th>Adresse</th><th>Vergütung1</th><th>Vergütung2</th><th>Aktion</th></tr>
      {% for g in rows %}
        <tr>
          <td>{{ g.elleid }}</td>
          <td>{{ g.firma or '' }}</td>
          <td>{{ g.bereich or '' }}</td>
          <td>{{ g.abteilung or '' }}</td>
          <td>{{ (g.strasse or '') + ', ' + (g.plz or '') + ' ' + (g.ort or '') }}</td>
          <td>{{ g.verguetung1 or '' }}</td>
          <td>{{ g.verguetung2 or '' }}</td>
          <td>
            <a class='btn secondary' href='{{ url_for("grunddaten_edit", id=g.elleid) }}'>Bearbeiten</a>
            <a class='btn danger' href='{{ url_for("grunddaten_delete", id=g.elleid) }}' onclick="return confirm('Wirklich löschen?')">Löschen</a>
          </td>
        </tr>
      {% endfor %}
    </table>
    rows)r|   executer   r*   order_byr=   descscalarsallr   ry   r   r   r   rv   s      rA   grunddaten_listr      s}    	Bzz&,55j6G6G6L6L6NOPXXZ^^`

D0 &t7883 	
s   A%B B'z/grunddaten/newc                     Sn [        U 5      $ )Nu  
    <h3>Grunddaten anlegen</h3>
    <form method='post' action='{{ url_for("grunddaten_create") }}'>
      <div class='grid'>
        <div><label>Firma<input name='firma'></label></div>
        <div><label>Bereich<input name='bereich'></label></div>
        <div><label>Abteilung<input name='abteilung'></label></div>
        <div><label>Straße<input name='strasse'></label></div>
        <div><label>PLZ<input name='plz'></label></div>
        <div><label>Ort<input name='ort'></label></div>
        <div><label>Vergütung 1 (€)<input name='verguetung1' type='number' step='0.01'></label></div>
        <div><label>Vergütung 2 (€)<input name='verguetung2' type='number' step='0.01'></label></div>
      </div>
      <p><button class='btn'>Speichern</button></p>
    </form>
    ry   ru   s    rA   grunddaten_newr      s    D  :rD   c                    [        5       n  [        [        R                  R	                  S5      [        R                  R	                  S5      [        R                  R	                  S5      [        R                  R	                  S5      [        R                  R	                  S5      [        R                  R	                  S5      [        R                  R	                  S5      =(       d    S [        R                  R	                  S5      =(       d    S S	9nU R                  U5        U R                  5         [        S
5        U R                  5         [        [        S5      5      $ ! U R                  5         f = f)Nr>   rK   rL   rM   rN   rO   rP   rQ   )r>   rK   rL   rM   rN   rO   rP   rQ   Gespeichert.r   )r|   r*   r
   formgetaddcommitr   r   r   r   )r   gs     rA   grunddaten_creater      s    	B,,""7+LL$$Y/ll&&{3LL$$Y/  '  '((7?4((7?4	
 	q	
		n

G-.// 	
s   D6E& &E8z/grunddaten/<int:id>c                    [        5       n UR                  [        U 5      nUR                  5         U(       d  [	        S5      $ [        SUS9n[	        U5      $ ! UR                  5         f = f)N<p>Nicht gefunden.</p>u&  
    <h3>Grunddaten bearbeiten #{{ g.elleid }}</h3>
    <form method='post' action='{{ url_for("grunddaten_update", id=g.elleid) }}'>
      <div class='grid'>
        <div><label>Firma<input name='firma' value='{{ g.firma or "" }}'></label></div>
        <div><label>Bereich<input name='bereich' value='{{ g.bereich or "" }}'></label></div>
        <div><label>Abteilung<input name='abteilung' value='{{ g.abteilung or "" }}'></label></div>
        <div><label>Straße<input name='strasse' value='{{ g.strasse or "" }}'></label></div>
        <div><label>PLZ<input name='plz' value='{{ g.plz or "" }}'></label></div>
        <div><label>Ort<input name='ort' value='{{ g.ort or "" }}'></label></div>
        <div><label>Vergütung 1 (€)<input name='verguetung1' type='number' step='0.01' value='{{ g.verguetung1 or "" }}'></label></div>
        <div><label>Vergütung 2 (€)<input name='verguetung2' type='number' step='0.01' value='{{ g.verguetung2 or "" }}'></label></div>
      </div>
      <p><button class='btn'>Aktualisieren</button></p>
    </form>
    )r   )r|   r   r*   r   ry   r   )idr   r   rv   s       rA   grunddaten_editr      sc    	BFF:r"

,--! # D  :' 	
   A A+c                H   [        5       n UR                  [        U 5      nU(       d  [        S5      UR	                  5         $ S H,  n[        X#[        R                  R                  U5      5        M.     [        R                  R                  S5      =(       d    S Ul        [        R                  R                  S5      =(       d    S Ul	        UR                  5         [        S5        UR	                  5         [        [        S5      5      $ ! UR	                  5         f = f)Nr   )r>   rK   rL   rM   rN   rO   rP   rQ   Aktualisiert.r   )r|   r   r*   ry   r   setattrr
   r   rP   rQ   r   r   r   r   )r   r   r   fields       rA   grunddaten_updater     s    	BFF:r"01 	
 KEAgll..u56 K((7?4((7?4
		o

G-.// 	
s   'D B'D D!z/grunddaten/<int:id>/deletec                   [        5       n UR                  [        U 5      nU(       a,  UR                  U5        UR	                  5         [        S5        UR                  5         [        [        S5      5      $ ! UR                  5         f = f)N
   Gelöscht.r   )	r|   r   r*   deleter   r   r   r   r   )r   r   r   s      rA   grunddaten_deleter   &  sd    	BFF:r"IIaLIIK,

G-.// 	
   A	A9 9Bz/kursc                 V   [        5       n  U R                  [        [        5      R	                  [        R
                  R                  5       5      5      R                  5       R                  5       nU R                  5         [        SUS9n[        U5      $ ! U R                  5         f = f)Nu  
    <div class='row'>
      <h3 style='margin-right:auto'>Kurse</h3>
      <a class='btn' href='{{ url_for("kurs_new") }}'>Neu</a>
    </div>
    <table>
      <tr><th>ID</th><th>Kurs</th><th>Status</th><th>Bemerkung</th><th>Aktion</th></tr>
      {% for k in rows %}
        <tr>
          <td>{{ k.elleid }}</td>
          <td>{{ k.kurs or '' }}</td>
          <td>{{ k.status or '' }}</td>
          <td>{{ k.bemerkung or '' }}</td>
          <td>
            <a class='btn secondary' href='{{ url_for("kurs_edit", id=k.elleid) }}'>Bearbeiten</a>
            <a class='btn danger' href='{{ url_for("kurs_delete", id=k.elleid) }}' onclick="return confirm('Wirklich löschen?')">Löschen</a>
          </td>
        </tr>
      {% endfor %}
    </table>
    r   )r|   r   r   rU   r   r=   r   r   r   r   r   ry   r   s      rA   	kurs_listr   4  s    	Bzz&,//0@0@0BCDLLNRRT

! #( )D* :- 	
s   A%B B(z	/kurs/newc                     Sn [        U 5      $ )Na  
    <h3>Kurs anlegen</h3>
    <form method='post' action='{{ url_for("kurs_create") }}'>
      <div class='grid'>
        <div><label>Kurs<input name='kurs'></label></div>
        <div><label>Status<input name='status'></label></div>
        <div><label>Bemerkung<input name='bemerkung'></label></div>
      </div>
      <p><button class='btn'>Speichern</button></p>
    </form>
    r   ru   s    rA   kurs_newr   R  s    
D :rD   c                    [        5       n  [        [        R                  R	                  S5      [        R                  R	                  S5      [        R                  R	                  S5      S9nU R                  U5        U R                  5         [        S5        U R                  5         [        [        S5      5      $ ! U R                  5         f = f)NrW   r[   r\   )rW   r[   r\   r   r   )r|   rU   r
   r   r   r   r   r   r   r   r   )r   ks     rA   kurs_creater   a  s    	Bgll&&v.w||7G7G7Q]d]i]i]m]mny]z{
q	
		n

GK()) 	
s   BB> >Cz/kurs/<int:id>c                    [        5       n UR                  [        U 5      nUR                  5         U(       d  [	        S5      $ [        SUS9n[	        U5      $ ! UR                  5         f = f)Nr   a  
    <h3>Kurs bearbeiten #{{ k.elleid }}</h3>
    <form method='post' action='{{ url_for("kurs_update", id=k.elleid) }}'>
      <div class='grid'>
        <div><label>Kurs<input name='kurs' value='{{ k.kurs or "" }}'></label></div>
        <div><label>Status<input name='status' value='{{ k.status or "" }}'></label></div>
        <div><label>Bemerkung<input name='bemerkung' value='{{ k.bemerkung or "" }}'></label></div>
      </div>
      <p><button class='btn'>Aktualisieren</button></p>
    </form>
    )r   )r|   r   rU   r   ry   r   )r   r   r   rv   s       rA   	kurs_editr   m  sc    	BFF4

,--! 
# 
D : 	
r   c                   [        5       n UR                  [        U 5      nU(       d  [        S5      UR	                  5         $ [
        R                  R                  S5      Ul        [
        R                  R                  S5      Ul        [
        R                  R                  S5      Ul	        UR                  5         [        S5        UR	                  5         [        [        S5      5      $ ! UR	                  5         f = f)Nr   rW   r[   r\   r   r   )r|   r   rU   ry   r   r
   r   rW   r[   r\   r   r   r   r   r   r   r   s      rA   kurs_updater     s    	B
FF401 	
 !!&)<<##H-ll&&{3
		o

GK()) 	
s   'C/ BC/ /Dz/kurs/<int:id>/deletec                   [        5       n UR                  [        U 5      nU(       a,  UR                  U5        UR	                  5         [        S5        UR                  5         [        [        S5      5      $ ! UR                  5         f = f)Nr   r   )	r|   r   rU   r   r   r   r   r   r   r   s      rA   kurs_deleter     sc    	BFF4IIaLIIK,

GK()) 	
r   z/rechnungenc                 B   [        5       n  U R                  [        [        5      R	                  [        R
                  R                  5       [        R                  R                  5       5      5      R                  5       R                  5       nU R                  [        [        5      5      R                  5       R                  5        Vs0 s H  o"R                  U_M     nnU R                  5         [        SXS9n[        U5      $ s  snf ! U R                  5         f = f)Nu$  
    <div class='row'>
      <h3 style='margin-right:auto'>Rechnungs-Positionen</h3>
      <a class='btn' href='{{ url_for("rechnung_new") }}'>Neu</a>
    </div>
    <table>
      <tr><th>ID</th><th>Datum</th><th>Von</th><th>Bis</th><th>Stunden</th><th>KM</th><th>Kurs</th><th>Kunde</th><th>Bemerkung</th><th>Aktion</th></tr>
      {% for r in rows %}
        <tr>
          <td>{{ r.elleid }}</td>
          <td>{{ r.datum }}</td>
          <td>{{ r.von }}</td>
          <td>{{ r.bis }}</td>
          <td>{{ r.stunden }}</td>
          <td>{{ r.km or 0 }}</td>
          <td>{{ r.kurs or '' }}</td>
          <td>{{ kunden.get(r.dgid).firma if kunden.get(r.dgid) else r.dgid }}</td>
          <td>{{ r.bemerkung or '' }}</td>
          <td>
            <a class='btn secondary' href='{{ url_for("rechnung_edit", id=r.elleid) }}'>Bearbeiten</a>
            <a class='btn danger' href='{{ url_for("rechnung_delete", id=r.elleid) }}' onclick="return confirm('Wirklich löschen?')">Löschen</a>
          </td>
        </tr>
      {% endfor %}
    </table>
    )r   r   )r|   r   r   r5   r   rn   r   r=   r   r   r*   r   r   ry   )r   r   r   r   rv   s        rA   rechnungen_listr     s    	BJJx ))(..*=*=*?AUAUAWXgi 	
 (*zz&2D'E'M'M'O'S'S'UV'U!((A+'UV

! #2 3#D4 :; W

s   B>D 
D D D Dz/rechnungen/newc                 ,   [        5       n  U R                  [        [        5      R	                  [        R
                  5      5      R                  5       R                  5       nU R                  [        [        5      R	                  [        R                  5      5      R                  5       R                  5       nU R                  5         [        SX[        R                  " 5       R                  5       S9n[        U5      $ ! U R                  5         f = f)NuC  
    <h3>Position anlegen</h3>
    <form method='post' action='{{ url_for("rechnung_create") }}'>
      <div class='grid'>
        <div><label>Datum<input type='date' name='datum' value='{{ nowdate }}'></label></div>
        <div><label>Von<input type='time' name='von'></label></div>
        <div><label>Bis<input type='time' name='bis'></label></div>
        <div><label>Stunden (HH:MM)<input type='time' name='stunden' step='60'></label></div>
        <div><label>KM<input type='number' name='km'></label></div>
        <div><label>Kurs<select name='kurs'>
          <option value=''>—</option>
          {% for k in kurse %}<option value='{{ k.kurs }}'>{{ k.kurs }}</option>{% endfor %}
        </select></label></div>
        <div><label>Kunde<select name='dgid'>
          {% for g in kunden %}<option value='{{ g.elleid }}'>{{ g.firma }} ({{ g.ort }})</option>{% endfor %}
        </select></label></div>
        <div style='grid-column: 1 / -1'><label>Bemerkung<input name='bemerkung'></label></div>
      </div>
      <p><button class='btn'>Speichern</button></p>
    </form>
    )r   r   nowdate)r|   r   r   r*   r   r>   r   r   rU   rW   r   r   r   today	isoformatry   )r   r   r   rv   s       rA   rechnung_newr     s    	BF:.77
8H8HIJRRTXXZ

6$<00;<DDFJJL

! #( TZZ\-C-C-E)GD* :- 	
s   B.D Dc                 N   SS jn [        5       n [        [        R                  R	                  S5      (       aB  [
        R                  " [        R                  R	                  S5      S5      R                  5       OS U " [        R                  R	                  S5      5      U " [        R                  R	                  S5      5      U " [        R                  R	                  S5      5      [        R                  R	                  S5      [        R                  R	                  S5      (       a(  [        [        R                  R	                  S5      5      OS [        R                  R	                  S	5      [        R                  R	                  S
5      (       a(  [        [        R                  R	                  S
5      5      OS S9nUR                  U5        UR                  5         [        S5        UR                  5         [        [        S5      5      $ ! UR                  5         f = f)Nc                    U (       d  g  [        [        U R                  S5      5      u  p[        XS9$ ! [         a     g f = fN:)re   rf   mapintsplitr   	Exceptionvalhhr    s      rA   
parse_time#rechnung_create.<locals>.parse_time  @    	ciin-FBR++ 		   )4 
A Arn   %Y-%m-%dro   rp   rd   r\   rq   rW   rr   )rn   ro   rp   rd   r\   rq   rW   rr   r   r   r   zOptional[str]rm   zOptional[time])r|   r5   r
   r   r   r   strptimer   r   r   r   r   r   r   r   )r   r   rs      rA   rechnung_creater     sj    
BU\UaUaUeUefmUnUn(##GLL$4$4W$=zJOOQtx7<<++E237<<++E23w||//	:;ll&&{3.5ll.>.>t.D.Ds7<<##D)*$!!&)29,,2B2B62J2JW\\%%f-.PT	
 	q	
		n

G-.// 	
s   GH H$z/rechnungen/<int:id>c                :   [        5       n UR                  [        U 5      nUR                  [	        [
        5      R                  [
        R                  5      5      R                  5       R                  5       nUR                  [	        [        5      R                  [        R                  5      5      R                  5       R                  5       nUR                  5         U(       d  [        S5      $ [        SX#US9n[        U5      $ ! UR                  5         f = f)Nr   u/  
    <h3>Position bearbeiten #{{ r.elleid }}</h3>
    <form method='post' action='{{ url_for("rechnung_update", id=r.elleid) }}'>
      <div class='grid'>
        <div><label>Datum<input type='date' name='datum' value='{{ r.datum }}'></label></div>
        <div><label>Von<input type='time' name='von' value='{{ r.von }}'></label></div>
        <div><label>Bis<input type='time' name='bis' value='{{ r.bis }}'></label></div>
        <div><label>Stunden<input type='time' step='60' name='stunden' value='{{ r.stunden }}'></label></div>
        <div><label>KM<input type='number' name='km' value='{{ r.km or 0 }}'></label></div>
        <div><label>Kurs<select name='kurs'>
          <option value=''>—</option>
          {% for k in kurse %}<option value='{{ k.kurs }}' {% if r.kurs==k.kurs %}selected{% endif %}>{{ k.kurs }}</option>{% endfor %}
        </select></label></div>
        <div><label>Kunde<select name='dgid'>
          {% for g in kunden %}<option value='{{ g.elleid }}' {% if r.dgid==g.elleid %}selected{% endif %}>{{ g.firma }} ({{ g.ort }})</option>{% endfor %}
        </select></label></div>
        <div style='grid-column: 1 / -1'><label>Bemerkung<input name='bemerkung' value='{{ r.bemerkung or "" }}'></label></div>
      </div>
      <p><button class='btn'>Aktualisieren</button></p>
    </form>
    )r   r   r   )r|   r   r5   r   r   r*   r   r>   r   r   rU   rW   r   ry   r   )r   r   r   r   r   rv   s         rA   rechnung_editr     s    	BFF8R F:.77
8H8HIJRRTXXZ

6$<00;<DDFJJL

,--! #( 5)*D* :1 	
s   CD Dc                   SS jn[        5       n UR                  [        U 5      nU(       d  [        S5      UR	                  5         $ [
        R                  R                  S5      (       aB  [        R                  " [
        R                  R                  S5      S5      R                  5       OS Ul
        U" [
        R                  R                  S5      5      Ul        U" [
        R                  R                  S5      5      Ul        U" [
        R                  R                  S5      5      Ul        [
        R                  R                  S5      (       a(  [        [
        R                  R                  S5      5      OS Ul        [
        R                  R                  S	5      Ul        [
        R                  R                  S
5      (       a(  [        [
        R                  R                  S
5      5      OS Ul        [
        R                  R                  S5      Ul        UR'                  5         [)        S5        UR	                  5         [+        [-        S5      5      $ ! UR	                  5         f = f)Nc                    U (       d  g  [        [        U R                  S5      5      u  p[        XS9$ ! [         a     g f = fr   r   r   s      rA   r   #rechnung_update.<locals>.parse_time*  r   r   r   rn   r   ro   rp   rd   rq   rW   rr   r\   r   r   r   )r|   r   r5   ry   r   r
   r   r   r   r   rn   ro   rp   rd   r   rq   rW   rr   r\   r   r   r   r   )r   r   r   r   s       rA   rechnung_updater   (  s    
BFF8R 01 	
 V]UaUaUeUefmUnUn(##GLL$4$4W$=zJOOQtx7<<++E237<<++E23w||//	:;	.5ll.>.>t.D.Ds7<<##D)*$!!&)29,,2B2B62J2JW\\%%f-.PTll&&{3
		o

G-.// 	
s   'I! 	G4I! !I3z/rechnungen/<int:id>/deletec                   [        5       n UR                  [        U 5      nU(       a,  UR                  U5        UR	                  5         [        S5        UR                  5         [        [        S5      5      $ ! UR                  5         f = f)Nr   r   )	r|   r   r5   r   r   r   r   r   r   )r   r   r   s      rA   rechnung_deleter   E  sd    	BFF8R IIaLIIK,

G-.// 	
r   z/rechnung-toolsc                    [        5       n  U R                  [        [        5      R	                  [        R
                  5      5      R                  5       R                  5       nU R                  5         [        SU[        R                  " 5       R                  SS9R                  5       [        R                  " 5       R                  5       S9n[        U5      $ ! U R                  5         f = f)NaQ  
    <h3>Rechnung erstellen</h3>
    <form method='get' action='{{ url_for("rechnung_preview") }}'>
      <div class='grid'>
        <div><label>Kunde<select name='dgid'>
          {% for g in kunden %}<option value='{{ g.elleid }}'>{{ g.firma }} ({{ g.ort }})</option>{% endfor %}
        </select></label></div>
        <div><label>Von<input type='date' name='from' value='{{ first_day }}'></label></div>
        <div><label>Bis<input type='date' name='to' value='{{ last_day }}'></label></div>
      </div>
      <p>
        <button class='btn'>Vorschau</button>
      </p>
    </form>
       )day)r   	first_daylast_day)r|   r   r   r*   r   r>   r   r   r   r   r   r   replacer   ry   )r   r   rv   s      rA   rechnung_toolsr   S  s    	BF:.77
8H8HIJRRTXXZ

! # $**,"6"61"6"="G"G"ITXT^T^T`TjTjTlnD :! 	
s   AC C+z/rechnung-previewc                 6   [        [        R                  R                  S5      5      n [        R
                  " [        R                  R                  S5      S5      R                  5       n[        R
                  " [        R                  R                  S5      S5      R                  5       n[        5       n UR                  [        U 5      nUR                  [        [        5      R                  [        R                  U :H  [        R                  U:  [        R                  U:*  5      R                  [        R                  5      5      R!                  5       R#                  5       n[%        U Vs/ s H  ofR'                  5       PM     sn[)        S5      5      n[)        UR*                  =(       d    S5      nXx-  R-                  [)        S5      5      n	[%        U Vs/ s H  ofR.                  =(       d    SPM     sn5      n
[)        S5      n[)        U
5      U-  R-                  [)        S5      5      nX-   R-                  [)        S5      5      n[)        S	5      nX-  R-                  [)        S5      5      nX-   R-                  [)        S5      5      nUR1                  5         [3        S
XAX%U[%        U Vs/ s H  ofR.                  =(       d    SPM     sn5      X[)        S5      UXUU S9n[5        U5      $ s  snf s  snf ! UR1                  5         f = fs  snf )Nrr   fromr   torb   r   0.010.350.19u8  
    <h3>Vorschau Rechnung</h3>
    <p><b>Kunde:</b> {{ kunde.firma }} – {{ kunde.strasse }}, {{ kunde.plz }} {{ kunde.ort }}</p>
    <p><b>Zeitraum:</b> {{ dfrom }} bis {{ dto }}</p>
    <table>
      <tr><th>Datum</th><th>Kurs</th><th>Stunden (dezimal)</th><th>KM</th><th>Bemerkung</th></tr>
      {% for i in items %}
        <tr>
          <td>{{ i.datum }}</td>
          <td>{{ i.kurs or '' }}</td>
          <td>{{ '%.2f' % i.stunden_decimal() }}</td>
          <td>{{ i.km or 0 }}</td>
          <td>{{ i.bemerkung or '' }}</td>
        </tr>
      {% endfor %}
      <tr><th colspan=2 style='text-align:right'>Summe</th><th>{{ '%.2f' % sum_stunden }}</th><th>{{ sum_km }}</th><th></th></tr>
    </table>
    <p>
      Stundensatz: {{ satz }} € | Stundenbetrag: {{ betrag_stunden }} €<br>
      KM-Satz: 0.35 € | KM-Betrag: {{ betrag_km }} €
    </p>
    <h4>Netto: {{ netto }} € | MwSt 19%: {{ mwst }} € | Brutto: {{ brutto }} €</h4>
    <p><a class='btn' href='{{ url_for("rechnung_pdf", dgid=dgid, dfrom=dfrom, dto=dto) }}'>Als PDF erzeugen</a></p>
    )r6   dfromdtoitemssum_stundensum_kmsatzbetrag_stundenkm_satz	betrag_kmnettomwstbruttorr   )r   r
   argsr   r   r   r   r|   r*   r   r   r5   whererr   rn   r   r   r   sumrk   r   rP   quantizerq   r   r   ry   )rr   r   r   r   r6   r   ir   r   r   r   r   r   r   	mwst_satzr   r   rv   s                     rA   rechnung_previewr   k  sa   w||'(Dgll..v6
CHHJE


GLL,,T2J
?
D
D
FC	Bz4(JJx &&x}}'<hnnPU>UW_WeWeilWlmvvw  xF  xF  Ggi 	
 >1,,.>Mu((-A.%,66wvG/Addiai/0&/V_w.88I	+55gfoFFO	!++GFO<,((9

! #. s -GAddiai-G)H76?V_T5;D6 :S ? 0 	
4 .Hs3   8B:L 2K7AL K<=BL 6L7
L Lz/rechnung-pdfc                   ^^^ [        [        R                  R                  S5      5      n [        R
                  " [        R                  R                  S5      S5      R                  5       n[        R
                  " [        R                  R                  S5      S5      R                  5       n[        5       n UR                  [        U 5      nUR                  [        [        5      R                  [        R                  U :H  [        R                  U:  [        R                  U:*  5      R                  [        R                  5      5      R!                  5       R#                  5       n[%        U Vs/ s H  ofR'                  5       PM     sn[)        S5      5      n[)        UR*                  =(       d    S5      nXx-  R-                  [)        S5      5      n	[%        U Vs/ s H  ofR.                  =(       d    SPM     sn5      n
[)        S5      n[)        U
5      U-  R-                  [)        S5      5      nX-   R-                  [)        S5      5      n[)        S	5      nX-  R-                  [)        S5      5      nX-   R-                  [)        S5      5      nUR1                  5         [2        R4                  " 5       n[6        R8                  " U[:        S
9m[:        u  mnS[<        -  mS8UUU4S jjnTR?                  S5        UT-
  nTRA                  SS5        TRC                  TUS5        TRA                  SS5        US-  nU" TUSURD                   SURF                   SURH                   SURJ                   35      nUS-  nTRC                  TUSURM                  5        SURM                  5        35        US-  nTRA                  SS5        TRC                  TUS5        TRC                  TS-   US5        TRC                  TS-   US5        TRC                  TS-   US5        TRC                  TS -   US!5        US-  nTRA                  SS5        U H  nUS":  a  TRO                  5         UT-
  nTRC                  TUUR                  RM                  5       5        TRC                  TS-   UURP                  =(       d    S#S S$ 5        TRS                  TS%-   UUR'                  5       S& 5        TRS                  TS'-   U[U        UR.                  =(       d    S5      5        TRC                  TS -   UURV                  =(       d    S#S S( 5        US-  nGM     US-  nTRA                  SS5        TRS                  TS%-   US)US& 35        TRS                  TS'-   US-
  S*U
 35        US$-  nTRC                  TUS+U S,U	 S-35        US-  nTRC                  TUS.U S-35        US-  nTRC                  TUS/U S0U S1U S-35        TRO                  5         TRY                  5         UR[                  S5        S2U  S3URM                  5        S3URM                  5        S43n[]        US5US6S79$ s  snf s  snf ! UR1                  5         f = f)9Nrr   r   r   r   rb   r   r   r   r   )pagesize   c                   > [        USSU=(       d    T	ST-  -
  5      n[        U5       H  u  pVTR                  XSU-  -
  U5        M     US[        U5      -  -
  $ )N	Helvetica
   r4      )r!   	enumerate
drawStringlen)
xytext	max_widthlinesidxlncmarginws
          rA   	draw_textrechnung_pdf.<locals>.draw_text  sZ    D+r93NQvXO 'GCLL3J+ (2c%j=  rD   r5   zHelvetica-Bold   r   r      zKunde: 
r:   r  z
Zeitraum: z bis DatumP   rU      Stundeni@  KMir  	Bemerkungrc   r;      i6  z.2fi^  (   zSumme Stunden: z
Summe KM: zStundensatz: u    €  -> Betrag: u    €u#   KM-Satz: 0.35 €       -> Betrag: zNetto: u    €  | MwSt 19%: u    €  | Brutto: 	rechnung__z.pdfTzapplication/pdf)as_attachmentdownload_namemimetype)N)/r   r
   r   r   r   r   r   r|   r*   r   r   r5   r   rr   rn   r   r   r   r   rk   r   rP   r   rq   r   ioBytesIOr   Canvasr   r    setTitlesetFontr  r>   rM   rN   rO   r   showPagerW   drawRightStringstrr\   saveseekr   )rr   r   r   r   r6   r   r   r   r   r   r   r   r   r   r   r   r   bufrh   r  r  filenamer  r  r  s                         @@@rA   rechnung_pdfr-    s   w||'(Dgll..w7DIIKE


GLL,,U3Z
@
E
E
GC	Bz4(JJx &&x}}'<hnnPU>UW_WeWeilWlmvvw  xF  xF  Ggi 	
 >1,,.>Mu((-A.%,66wvG/Addiai/0&/V_w.88I	+55gfoFFO	!++GFO<,((9

 **,CcB'ADAq"WF! ! JJz	F
AII#LLJ'IIk2GA&!wu{{m2emm_BuyykQRSXS\S\R]^_AGALLj):(;5@QRSGA II#LLG$LL"a(LL#q),LL#q$'LL#q+.GAIIk2r6JJLF
A	VQ 1 1 34	Vb[!afflCR%89	&3,a.?.?.A#-FH	&3,3qttyq>:	Vc\1q{{'8b#2&>?	R  GAII#fslAS8I'JKfslAFj,ABGALLmD61B>BRRVWXGALLA)DQRGALLgeW,>tfDTU[T\\`abJJLFFHHHQK4&%//"3!4Acmmo5FdKHSHO`aaS ? 0 	
s-   ;B:Y2 5Y(AY2 "Y- BY2 (
Y2 2Z__main__)debug)rx   r(  rm   r(  )r   r   )T__doc__
__future__r   r!  osr   r   r   decimalr   typingr   flaskr	   r
   r   r   r   r   r   
sqlalchemyr   r   r   r   r   r   r   r   r   r   sqlalchemy.ormr   r   r   r   reportlab.lib.pagesizesr   reportlab.pdfgenr   reportlab.lib.unitsr    reportlab.lib.utilsr!   dotenvr"   getenvr#   enginer|   Baser*   rU   r5   rF   app
secret_keyrw   ry   r   r   r   r   postr   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r-  runrE   rD   rA   <module>rD     s  0 # 	 	 ) )   > > / l l l W W & # " +  	8c	d	vT$	?l%TYbfgh@ @"94 9Rt R, Ho><8,	\;  ( 9 9@ 	 & -0 0( 	  !4 
 !0 "0  	&'
0 (
0  :   '	* 	* 	 * 
* * 	 !
* "
* % %N 	 < -0 0: 	  !B 
 !0 "08 	&'
0 (
0 	 . 	5 5n Vb Vbr zGG$G rD   