77 lines
3.8 KiB
Python
77 lines
3.8 KiB
Python
"""PDF-Erzeugung in einem eigenen Prozess ohne Qt-Laufzeit ausführen."""
|
||
from __future__ import annotations
|
||
|
||
import json
|
||
import logging
|
||
from pathlib import Path
|
||
import shutil
|
||
import sys
|
||
|
||
from .create import create_invoice, find_customer, save_customer
|
||
from .gui_data import InvoiceForm
|
||
from .models import Party
|
||
from .render import render_html, render_pdf
|
||
|
||
|
||
def execute(request: dict, progress) -> dict:
|
||
"""Nur geprüfte Formulardaten an die gemeinsame Rechnungserstellung übergeben."""
|
||
form = InvoiceForm.model_validate(request['form'])
|
||
presets, resources = Path(request['presets']), Path(request['resources'])
|
||
invoice = form.invoice(presets)
|
||
if request['mode'] == 'preview':
|
||
progress('Entwurf wird ohne Nummernreservierung erstellt …')
|
||
invoice.meta.invoice_number = 'ENTWURF'
|
||
invoice.payment.reference = 'Entwurf – noch keine Rechnungsnummer vergeben'
|
||
invoice.meta.notes = 'ENTWURF – nicht zum Versand.\n' + (invoice.meta.notes or '')
|
||
folder = Path(request['scratch'])
|
||
(folder / 'assets').mkdir(exist_ok=True)
|
||
logo = presets / 'logo.svg'
|
||
if not logo.is_file():
|
||
logo = resources / 'assets/logo.svg'
|
||
shutil.copy2(logo, folder / 'assets/logo.svg')
|
||
result = render_pdf(render_html(invoice, resources / 'templates/invoice.html.j2'),
|
||
folder / 'entwurf.pdf', logging.getLogger('gui-preview'), base_url=str(folder))
|
||
if not result.ok:
|
||
raise RuntimeError(result.error)
|
||
return {'pdf': str(result.path)}
|
||
if request['mode'] != 'generate':
|
||
raise ValueError('Unbekannter Auftrag')
|
||
jar = Path(request['jar'])
|
||
if not jar.is_file():
|
||
raise ValueError('Mustang fehlt. Einmalig jr-einvoice setup-mustang ausführen.')
|
||
existing = find_customer(presets, form.buyer.name)
|
||
if existing and Party.model_validate(existing[1]['buyer']) != form.buyer:
|
||
raise ValueError('Dieser Kundenname ist mit anderen Stammdaten gespeichert. '
|
||
'Bitte den gespeicherten Kunden auswählen oder die Kundendatei prüfen.')
|
||
# Vorlagen dürfen vorhandene Kundenadressen nicht stillschweigend ersetzen.
|
||
match = existing or save_customer(presets, form.buyer.name, form.buyer.model_dump(mode='json'))
|
||
first = form.items[0]
|
||
result = create_invoice(root=Path(request['root']), resources=resources, presets=presets,
|
||
customer=match[0], entry=first.name, volume=first.quantity,
|
||
price=first.unit_price_net, items=form.items, notes=form.notes,
|
||
jar=jar, logger=logging.getLogger('gui'), number=form.number,
|
||
issued=form.issued, due_days=form.due_days,
|
||
service_period_start=form.start, service_period_end=form.end,
|
||
buyer_reference=form.buyer_reference, order_reference=form.order_reference,
|
||
progress=progress)
|
||
return {'invoice': result.invoice.model_dump(mode='json'), 'attachment': str(result.attachment),
|
||
'build': {key: str(value) if value is not None else None
|
||
for key, value in vars(result.build).items()}}
|
||
|
||
|
||
def main(argv=None):
|
||
request_path = Path((argv or sys.argv[1:])[0])
|
||
result_path = request_path.with_name('result.json')
|
||
try:
|
||
request = json.loads(request_path.read_text(encoding='utf-8'))
|
||
result = execute(request, lambda message: print(json.dumps({'progress': message}), flush=True))
|
||
result_path.write_text(json.dumps({'result': result}), encoding='utf-8')
|
||
return 0
|
||
except Exception as exc:
|
||
result_path.write_text(json.dumps({'error': str(exc)}), encoding='utf-8')
|
||
return 1
|
||
|
||
|
||
if __name__ == '__main__':
|
||
raise SystemExit(main())
|