changes to the pricing
This commit is contained in:
+47
-7
@@ -204,6 +204,14 @@ def _utc_now_iso() -> str:
|
||||
return datetime.utcnow().isoformat(timespec="seconds") + "Z"
|
||||
|
||||
|
||||
def _booking_amounts(net_amount: float, is_trial: bool = False) -> tuple[float, float, float]:
|
||||
net = round(float(net_amount or 0.0), 2)
|
||||
if is_trial:
|
||||
return 0.0, 0.0, 0.0
|
||||
vat = round(net * 0.19, 2)
|
||||
return net, vat, round(net + vat, 2)
|
||||
|
||||
|
||||
def _is_allowed_invoice_filename(filename: str) -> bool:
|
||||
return bool(filename) and filename.lower().endswith(".pdf")
|
||||
|
||||
@@ -2433,6 +2441,7 @@ def background_booking_provisioning(
|
||||
"billing_reference": booking_data.get("billing_reference"),
|
||||
"package": booking_request.get("package_label") or booking_request.get("package"),
|
||||
"amount_eur": booking_request.get("amount_eur"),
|
||||
"amount_gross_eur": booking_request.get("amount_eur"),
|
||||
"amount_net_eur": booking_request.get("amount_net_eur") or booking_request.get("amount_eur"),
|
||||
"booking_flow": booking_request.get("booking_flow"),
|
||||
"invoice_id": booking_request.get("invoice_id"),
|
||||
@@ -2892,6 +2901,7 @@ def booking_payment():
|
||||
|
||||
selected_package = ", ".join(selected_package_names)
|
||||
package_raw = packages_str
|
||||
net_price, vat_amount, gross_price = _booking_amounts(total_price, is_trial)
|
||||
|
||||
flow_config = BOOKING_FLOW_MAP.get(booking_flow, BOOKING_FLOW_MAP.get("payment"))
|
||||
|
||||
@@ -2950,6 +2960,8 @@ def booking_payment():
|
||||
"package_price": total_price if not is_trial else 0.0,
|
||||
"price": total_price if not is_trial else 0.0,
|
||||
"price_net": total_price if not is_trial else 0.0,
|
||||
"price_vat": vat_amount,
|
||||
"price_gross": gross_price,
|
||||
"flow": booking_flow,
|
||||
"is_trial": is_trial,
|
||||
"title": flow_config["title"],
|
||||
@@ -3104,8 +3116,9 @@ def booking_payment():
|
||||
"booking_number": booking_number,
|
||||
"package": package_raw,
|
||||
"package_label": selected_package,
|
||||
"amount_eur": total_price if not is_trial else 0.0,
|
||||
"amount_net_eur": total_price if not is_trial else 0.0,
|
||||
"amount_eur": gross_price,
|
||||
"amount_net_eur": net_price,
|
||||
"vat_eur": vat_amount,
|
||||
"booking_flow": booking_flow,
|
||||
"booking_data": form_data,
|
||||
"is_trial": is_trial,
|
||||
@@ -3134,8 +3147,9 @@ def booking_payment():
|
||||
"username": session.get("username"),
|
||||
"invoice_number": booking_number,
|
||||
"period": date.today().strftime("%m/%Y"),
|
||||
"amount_eur": total_price,
|
||||
"amount_net_eur": total_price,
|
||||
"amount_eur": gross_price,
|
||||
"amount_net_eur": net_price,
|
||||
"vat_eur": vat_amount,
|
||||
"status": "Offen",
|
||||
"due_date": due_date,
|
||||
"created_at": _utc_now_iso(),
|
||||
@@ -3158,7 +3172,7 @@ def booking_payment():
|
||||
module_config = build_module_config_string(package_list)
|
||||
user_email = session.get("email") or form_data.get("contact_email")
|
||||
address_process = f"{form_data['billing_street']}, {form_data['billing_zip']} {form_data['billing_city']}"
|
||||
price_str = f"{total_price:.2f}".replace('.', ',')
|
||||
price_str = f"{gross_price:.2f}".replace('.', ',')
|
||||
billing_update = {
|
||||
"package": package_raw,
|
||||
"invoice_id": invoice_id,
|
||||
@@ -3207,7 +3221,9 @@ def booking_payment():
|
||||
"billing_city": form_data.get("billing_city"),
|
||||
"billing_reference": form_data.get("billing_reference"),
|
||||
"package": selected_package,
|
||||
"amount_eur": total_price,
|
||||
"amount_eur": gross_price,
|
||||
"amount_gross_eur": gross_price,
|
||||
"amount_net_eur": net_price,
|
||||
"booking_flow": booking_flow,
|
||||
"invoice_id": invoice_id,
|
||||
"subdomain": subdomain,
|
||||
@@ -3262,7 +3278,7 @@ def booking_payment():
|
||||
username = session.get("username")
|
||||
user_email = session.get("email") or form_data.get("contact_email")
|
||||
address_process = f"{form_data['billing_street']}, {form_data['billing_zip']} {form_data['billing_city']}"
|
||||
price_str = f"{total_price:.2f}".replace('.', ',') if not is_trial else "Kostenlose Testversion"
|
||||
price_str = f"{gross_price:.2f}".replace('.', ',') if not is_trial else "Kostenlose Testversion"
|
||||
|
||||
thread = threading.Thread(
|
||||
target=background_booking_provisioning,
|
||||
@@ -3584,6 +3600,14 @@ def my_invoices():
|
||||
except ValueError:
|
||||
amt = 0.0
|
||||
inv["amount_eur"] = amt
|
||||
if "amount_net_eur" in inv:
|
||||
net_amt = inv.get("amount_net_eur")
|
||||
if isinstance(net_amt, str):
|
||||
try:
|
||||
net_amt = float(net_amt.replace('.', '').replace(',', '.'))
|
||||
except ValueError:
|
||||
net_amt = 0.0
|
||||
inv["amount_net_eur"] = net_amt
|
||||
|
||||
# Flags setzen, ob Verträge/Rechnungen in MongoDB existieren (anhand des Dateinamens)
|
||||
inv["has_hauptvertrag"] = bool(inv.get("hauptvertrag_filename"))
|
||||
@@ -3609,6 +3633,14 @@ def my_invoices():
|
||||
except ValueError:
|
||||
amt = 0.0
|
||||
item["amount_eur"] = amt
|
||||
if "amount_net_eur" in item:
|
||||
net_amt = item.get("amount_net_eur")
|
||||
if isinstance(net_amt, str):
|
||||
try:
|
||||
net_amt = float(net_amt.replace('.', '').replace(',', '.'))
|
||||
except ValueError:
|
||||
net_amt = 0.0
|
||||
item["amount_net_eur"] = net_amt
|
||||
except Exception:
|
||||
flash("Instanz-Anfragen konnten nicht geladen werden.", "error")
|
||||
finally:
|
||||
@@ -4038,6 +4070,14 @@ def admin_invoices():
|
||||
except ValueError:
|
||||
amt = 0.0
|
||||
item["amount_eur"] = amt
|
||||
if "amount_net_eur" in item:
|
||||
net_amt = item.get("amount_net_eur")
|
||||
if isinstance(net_amt, str):
|
||||
try:
|
||||
net_amt = float(net_amt.replace('.', '').replace(',', '.'))
|
||||
except ValueError:
|
||||
net_amt = 0.0
|
||||
item["amount_net_eur"] = net_amt
|
||||
|
||||
if not isinstance(item.get("booking_data"), dict):
|
||||
item["booking_data"] = {}
|
||||
|
||||
@@ -255,7 +255,8 @@ def send_booking_admin_notification(booking: dict, recipient: str = "info@invari
|
||||
"billing_city": "Rechnungsort",
|
||||
"billing_reference": "Kassenzeichen / Aktenzeichen",
|
||||
"package": "Gebuchte Produkte",
|
||||
"amount_eur": "Betrag netto",
|
||||
"amount_gross_eur": "Betrag brutto",
|
||||
"amount_net_eur": "Betrag netto",
|
||||
"booking_flow": "Buchungsfluss",
|
||||
"invoice_id": "Rechnungs-ID",
|
||||
"subdomain": "Subdomain",
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
</select>
|
||||
<input type="text" name="invoice_number" placeholder="Rechnungsnummer (optional, eigener Wert möglich)">
|
||||
<input type="text" name="period" placeholder="Zeitraum (MM/YYYY)" required>
|
||||
<input type="text" name="amount_eur" placeholder="Betrag netto in EUR" required>
|
||||
<input type="text" name="amount_eur" placeholder="Betrag brutto in EUR" required>
|
||||
<input type="text" name="due_date" placeholder="Fälligkeit (YYYY-MM-DD)">
|
||||
|
||||
<!-- NEU: Dropdown für Status beim Erstellen -->
|
||||
@@ -46,7 +46,7 @@
|
||||
<article class="entry">
|
||||
<h3>{{ item.invoice_number }}</h3>
|
||||
<p><strong>Nutzer:</strong> {{ item.username }} | <strong>Zeitraum:</strong> {{ item.period }}</p>
|
||||
<p><strong>Betrag netto:</strong> {{ '%.2f'|format(item.amount_eur) }} EUR | <strong>Status:</strong> {{ item.status }} | <strong>Fälligkeit:</strong> {{ item.due_date }}</p>
|
||||
<p><strong>Betrag brutto:</strong> {{ '%.2f'|format(item.amount_eur) }} EUR{% if item.amount_net_eur is defined %} | Netto: {{ '%.2f'|format(item.amount_net_eur) }} EUR{% endif %} | <strong>Status:</strong> {{ item.status }} | <strong>Fälligkeit:</strong> {{ item.due_date }}</p>
|
||||
|
||||
{% if item.source == 'booking_payment' %}
|
||||
<p><strong>Buchung:</strong> {{ item.booking_package_label or item.booking_package }} | <strong>Flow:</strong> {{ item.booking_flow }}</p>
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
<tr>
|
||||
<td class="font-semibold">{{ invoice.invoice_number }}</td>
|
||||
<td>{{ invoice.period }}</td>
|
||||
<td class="amount-cell">{{ '%.2f'|format(invoice.amount_eur) }} € netto</td>
|
||||
<td class="amount-cell"><strong>{{ '%.2f'|format(invoice.amount_eur) }} € brutto</strong>{% if invoice.amount_net_eur is defined %}<br><small>{{ '%.2f'|format(invoice.amount_net_eur) }} € netto</small>{% endif %}</td>
|
||||
<td class="text-muted">{{ invoice.due_date }}</td>
|
||||
<td>
|
||||
{% set status_lower = (invoice.status or '')|lower %}
|
||||
|
||||
@@ -319,16 +319,16 @@
|
||||
{% if price_net %}
|
||||
<div class="price-breakdown">
|
||||
<div class="price-row">
|
||||
<span>Verbindlicher Buchungsbetrag (Netto):</span>
|
||||
<span>{{ ("%.2f"|format(price_net)) | replace('.', ',') }} €</span>
|
||||
<span>Verbindlicher Buchungsbetrag (Brutto):</span>
|
||||
<span>{{ ("%.2f"|format(price_gross)) | replace('.', ',') }} €</span>
|
||||
</div>
|
||||
<div class="price-row">
|
||||
<span>zzgl. 19% USt:</span>
|
||||
<span>{{ ("%.2f"|format(price_net * 0.19)) | replace('.', ',') }} €</span>
|
||||
<span>{{ ("%.2f"|format(price_vat)) | replace('.', ',') }} €</span>
|
||||
</div>
|
||||
<div class="price-row total">
|
||||
<span>Brutto (nur Information):</span>
|
||||
<span>{{ ("%.2f"|format(price_net * 1.19)) | replace('.', ',') }} €</span>
|
||||
<span>Brutto:</span>
|
||||
<span>{{ ("%.2f"|format(price_gross)) | replace('.', ',') }} €</span>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
Reference in New Issue
Block a user