mirror of
https://github.com/itsdave-de/msp.git
synced 2026-09-28 04:02:42 -03:00
feat(msp): Beleg-Titel pro Profil per Template einstellbar
Bisher wurde der Titel hart als '{title_prefix} {period}' gebaut.
Jetzt zwei optionale Felder im Supplier Import Profile:
- title_template (für Rechnungen / Lieferscheine)
- title_template_credit_note (für Gutschriften)
Verfügbare Platzhalter:
{prefix} — bisheriges title_prefix / title_prefix_credit_note
{period} — z. B. "09.2025" oder "09.2025 – 03.2026"
{customer} — Customer-Ref (CUST-…)
{customer_name} — Anzeigename des Kunden
{vendor} — Vendor-Feld des Profils (z. B. "Microsoft")
{posting_date} — DD.MM.YYYY
{document_type} — "Sales Invoice" / "Delivery Note"
Backwards-compatible: leeres Template fällt auf das alte Verhalten
zurück. Unbekannte Platzhalter werden geloggt und der Builder fällt
ebenfalls auf {prefix} {period} zurück, statt einen Run zu kippen.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
a1ebe0481c
commit
db6b4e07fa
@@ -22,6 +22,8 @@
|
||||
"supplier": "SUPP-00887",
|
||||
"title_prefix": "Abrechnung Microsoft Abo ",
|
||||
"title_prefix_credit_note": "Gutschrift Microsoft Abo ",
|
||||
"title_template": "{prefix} {period}",
|
||||
"title_template_credit_note": "{prefix} {period}",
|
||||
"vendor": "Microsoft"
|
||||
}
|
||||
]
|
||||
@@ -113,16 +113,15 @@ class DocumentBuilder:
|
||||
"""Erzeugt das Grundgerüst (ohne Zeilen) der Sales Invoice / Delivery Note."""
|
||||
profile = self.profile
|
||||
period = self._format_period_label(first)
|
||||
title_prefix = profile.title_prefix_credit_note if is_return else profile.title_prefix
|
||||
title = f"{(title_prefix or '').strip()} {period}".strip()
|
||||
posting_date = self._coerce_german_date(first.raw.get("DATUM") or frappe.utils.today())
|
||||
title = self._render_title(customer, period, posting_date, is_return=is_return)
|
||||
|
||||
if self.output_mode == "Sales Invoice":
|
||||
doc = frappe.new_doc("Sales Invoice")
|
||||
doc.customer = customer
|
||||
doc.company = profile.default_company
|
||||
doc.currency = frappe.db.get_value("Company", profile.default_company, "default_currency") or "EUR"
|
||||
doc.posting_date = first.raw.get("DATUM") or frappe.utils.today()
|
||||
doc.posting_date = self._coerce_german_date(doc.posting_date)
|
||||
doc.posting_date = posting_date
|
||||
doc.set_posting_time = 1
|
||||
if profile.default_cost_center:
|
||||
doc.cost_center = profile.default_cost_center
|
||||
@@ -147,7 +146,7 @@ class DocumentBuilder:
|
||||
doc = frappe.new_doc("Delivery Note")
|
||||
doc.customer = customer
|
||||
doc.company = profile.default_company
|
||||
doc.posting_date = self._coerce_german_date(first.raw.get("DATUM") or frappe.utils.today())
|
||||
doc.posting_date = posting_date
|
||||
doc.set_posting_time = 1
|
||||
if profile.default_cost_center:
|
||||
doc.cost_center = profile.default_cost_center
|
||||
@@ -312,6 +311,42 @@ class DocumentBuilder:
|
||||
return invdate.strftime("%m.%Y")
|
||||
return _d.today().strftime("%m.%Y")
|
||||
|
||||
def _render_title(self, customer: str, period: str, posting_date, *, is_return: bool) -> str:
|
||||
"""Rendert den Beleg-Titel aus dem konfigurierten Template (mit Fallback).
|
||||
|
||||
Platzhalter: {prefix}, {period}, {customer}, {customer_name},
|
||||
{vendor}, {posting_date}, {document_type}.
|
||||
"""
|
||||
profile = self.profile
|
||||
template = (profile.title_template_credit_note if is_return else profile.title_template) or ""
|
||||
prefix = (profile.title_prefix_credit_note if is_return else profile.title_prefix) or ""
|
||||
template = template.strip()
|
||||
if not template:
|
||||
# Backwards-compat: bisheriges Verhalten "{prefix} {period}".
|
||||
return f"{prefix.strip()} {period}".strip()
|
||||
|
||||
customer_name = frappe.db.get_value("Customer", customer, "customer_name") or customer
|
||||
try:
|
||||
rendered = template.format(
|
||||
prefix=prefix.strip(),
|
||||
period=period,
|
||||
customer=customer,
|
||||
customer_name=customer_name,
|
||||
vendor=profile.vendor or "",
|
||||
posting_date=posting_date.strftime("%d.%m.%Y") if hasattr(posting_date, "strftime") else str(posting_date),
|
||||
document_type=self.output_mode or "",
|
||||
)
|
||||
except (KeyError, IndexError) as e:
|
||||
# Unbekannter Platzhalter — robust auf Fallback zurückfallen, aber dem Run
|
||||
# trotzdem einen Hinweis mitgeben, indem wir den Profilfehler in die Logs schreiben.
|
||||
frappe.log_error(
|
||||
f"Title-Template enthält ungültigen Platzhalter ({e}); fällt auf '{{prefix}} {{period}}' zurück.",
|
||||
"Supplier Import Builder",
|
||||
)
|
||||
rendered = f"{prefix.strip()} {period}".strip()
|
||||
# Mehrfach-Whitespace zusammenfassen
|
||||
return " ".join(rendered.split())
|
||||
|
||||
@staticmethod
|
||||
def _copy_tax_template_rows(doc, template_name: str) -> None:
|
||||
"""Kopiert die Zeilen des Sales-Taxes-and-Charges-Templates explizit in doc.taxes.
|
||||
|
||||
@@ -29,6 +29,8 @@
|
||||
"text_section",
|
||||
"title_prefix",
|
||||
"title_prefix_credit_note",
|
||||
"title_template",
|
||||
"title_template_credit_note",
|
||||
"intro_text_invoice",
|
||||
"intro_text_credit_note",
|
||||
"fallback_section",
|
||||
@@ -170,6 +172,18 @@
|
||||
"fieldtype": "Data",
|
||||
"label": "Title Prefix (Credit Note)"
|
||||
},
|
||||
{
|
||||
"fieldname": "title_template",
|
||||
"fieldtype": "Data",
|
||||
"label": "Title Template (Invoice)",
|
||||
"description": "Optionales Format-String für den Beleg-Titel. Platzhalter: {prefix}, {period}, {customer}, {customer_name}, {vendor}, {posting_date}, {document_type}. Leer = '{prefix} {period}'."
|
||||
},
|
||||
{
|
||||
"fieldname": "title_template_credit_note",
|
||||
"fieldtype": "Data",
|
||||
"label": "Title Template (Credit Note)",
|
||||
"description": "Wie 'Title Template (Invoice)', nur für Gutschriften. Leer = '{prefix} {period}'."
|
||||
},
|
||||
{
|
||||
"fieldname": "intro_text_invoice",
|
||||
"fieldtype": "Text Editor",
|
||||
|
||||
Reference in New Issue
Block a user