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",
|
"supplier": "SUPP-00887",
|
||||||
"title_prefix": "Abrechnung Microsoft Abo ",
|
"title_prefix": "Abrechnung Microsoft Abo ",
|
||||||
"title_prefix_credit_note": "Gutschrift Microsoft Abo ",
|
"title_prefix_credit_note": "Gutschrift Microsoft Abo ",
|
||||||
|
"title_template": "{prefix} {period}",
|
||||||
|
"title_template_credit_note": "{prefix} {period}",
|
||||||
"vendor": "Microsoft"
|
"vendor": "Microsoft"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -113,16 +113,15 @@ class DocumentBuilder:
|
|||||||
"""Erzeugt das Grundgerüst (ohne Zeilen) der Sales Invoice / Delivery Note."""
|
"""Erzeugt das Grundgerüst (ohne Zeilen) der Sales Invoice / Delivery Note."""
|
||||||
profile = self.profile
|
profile = self.profile
|
||||||
period = self._format_period_label(first)
|
period = self._format_period_label(first)
|
||||||
title_prefix = profile.title_prefix_credit_note if is_return else profile.title_prefix
|
posting_date = self._coerce_german_date(first.raw.get("DATUM") or frappe.utils.today())
|
||||||
title = f"{(title_prefix or '').strip()} {period}".strip()
|
title = self._render_title(customer, period, posting_date, is_return=is_return)
|
||||||
|
|
||||||
if self.output_mode == "Sales Invoice":
|
if self.output_mode == "Sales Invoice":
|
||||||
doc = frappe.new_doc("Sales Invoice")
|
doc = frappe.new_doc("Sales Invoice")
|
||||||
doc.customer = customer
|
doc.customer = customer
|
||||||
doc.company = profile.default_company
|
doc.company = profile.default_company
|
||||||
doc.currency = frappe.db.get_value("Company", profile.default_company, "default_currency") or "EUR"
|
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 = posting_date
|
||||||
doc.posting_date = self._coerce_german_date(doc.posting_date)
|
|
||||||
doc.set_posting_time = 1
|
doc.set_posting_time = 1
|
||||||
if profile.default_cost_center:
|
if profile.default_cost_center:
|
||||||
doc.cost_center = profile.default_cost_center
|
doc.cost_center = profile.default_cost_center
|
||||||
@@ -147,7 +146,7 @@ class DocumentBuilder:
|
|||||||
doc = frappe.new_doc("Delivery Note")
|
doc = frappe.new_doc("Delivery Note")
|
||||||
doc.customer = customer
|
doc.customer = customer
|
||||||
doc.company = profile.default_company
|
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
|
doc.set_posting_time = 1
|
||||||
if profile.default_cost_center:
|
if profile.default_cost_center:
|
||||||
doc.cost_center = profile.default_cost_center
|
doc.cost_center = profile.default_cost_center
|
||||||
@@ -312,6 +311,42 @@ class DocumentBuilder:
|
|||||||
return invdate.strftime("%m.%Y")
|
return invdate.strftime("%m.%Y")
|
||||||
return _d.today().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
|
@staticmethod
|
||||||
def _copy_tax_template_rows(doc, template_name: str) -> None:
|
def _copy_tax_template_rows(doc, template_name: str) -> None:
|
||||||
"""Kopiert die Zeilen des Sales-Taxes-and-Charges-Templates explizit in doc.taxes.
|
"""Kopiert die Zeilen des Sales-Taxes-and-Charges-Templates explizit in doc.taxes.
|
||||||
|
|||||||
@@ -29,6 +29,8 @@
|
|||||||
"text_section",
|
"text_section",
|
||||||
"title_prefix",
|
"title_prefix",
|
||||||
"title_prefix_credit_note",
|
"title_prefix_credit_note",
|
||||||
|
"title_template",
|
||||||
|
"title_template_credit_note",
|
||||||
"intro_text_invoice",
|
"intro_text_invoice",
|
||||||
"intro_text_credit_note",
|
"intro_text_credit_note",
|
||||||
"fallback_section",
|
"fallback_section",
|
||||||
@@ -170,6 +172,18 @@
|
|||||||
"fieldtype": "Data",
|
"fieldtype": "Data",
|
||||||
"label": "Title Prefix (Credit Note)"
|
"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",
|
"fieldname": "intro_text_invoice",
|
||||||
"fieldtype": "Text Editor",
|
"fieldtype": "Text Editor",
|
||||||
|
|||||||
Reference in New Issue
Block a user