Files

46 lines
2.4 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""Prepare a reviewed email draft; never sends mail automatically."""
from email.message import EmailMessage
from email.policy import SMTP
from pathlib import Path
import hashlib
import json
from .io import load_invoice_yaml
def prepare_email(invoice_dir: Path, jar: Path, logger, recipient: str | None = None) -> Path:
# Invalidate any previous draft before rebuilding.
out = invoice_dir / 'out'
(out / 'invoice.eml').unlink(missing_ok=True)
(out / 'manifest.json').unlink(missing_ok=True)
inv = load_invoice_yaml(invoice_dir / 'invoice.yaml')
recipient = recipient or inv.buyer.email
import re
if not recipient or not re.fullmatch(r'[^\s@<>]+@[^\s@<>]+\.[^\s@<>]+', recipient):
raise ValueError('Set buyer.email or pass --to with the agreed invoice address')
out = invoice_dir / 'out'
# Rebuild from current YAML so the draft cannot attach an obsolete invoice.
from .pipeline import build_in_folder
template = Path(__file__).resolve().parent.parent / 'templates/invoice.html.j2'
if not template.is_file():
template = Path(__file__).resolve().parent / 'data/templates/invoice.html.j2'
result = build_in_folder(invoice_dir, 'out', template, logger, jar, True, True)
pdf = result.facturx_pdf
msg = EmailMessage(policy=SMTP)
msg['From'] = inv.seller.email or ''
if not inv.seller.email:
raise ValueError('seller.email is required for an email draft')
msg['To'] = recipient
msg['Subject'] = f'Rechnung {inv.meta.invoice_number} – {inv.seller.name}'
msg['X-Unsent'] = '1'
msg.set_content(f'Sehr geehrte Damen und Herren,\n\nanbei erhalten Sie unsere E-Rechnung {inv.meta.invoice_number} als ZUGFeRD/Factur-X-PDF mit eingebetteten strukturierten Rechnungsdaten.\n\nVielen Dank für Ihren Auftrag.\n\nFreundliche Grüße\n{inv.seller.name}\n')
msg.add_attachment(pdf.read_bytes(), maintype='application', subtype='pdf', filename=f'Rechnung_{_safe_name(inv.meta.invoice_number)}.pdf')
target = out / 'invoice.eml'
target.write_bytes(msg.as_bytes())
manifest = {p.name: hashlib.sha256(p.read_bytes()).hexdigest() for p in
[invoice_dir / 'invoice.yaml', result.facturx_xml, pdf, result.validate_report, target]}
(out / 'manifest.json').write_text(json.dumps(manifest, indent=2) + '\n', encoding='utf-8')
return target
def _safe_name(number: str) -> str:
import re
return re.sub(r'[^A-Za-z0-9_-]', '_', number)