Feat: Kündigung blockt Erneuerungsentwurf; Upgrade storniert alte Rechnungen + legt neuen Entwurf an
This commit is contained in:
parent
b1dbde332f
commit
a9f7923716
2 changed files with 69 additions and 2 deletions
|
|
@ -1150,7 +1150,7 @@ async def list_upgrade_requests(user=Depends(require_admin)):
|
|||
async def fulfill_upgrade_request(req_id: int, user=Depends(require_admin)):
|
||||
with db() as conn:
|
||||
req = conn.execute(
|
||||
"SELECT r.*, u.name, u.email FROM upgrade_requests r JOIN users u ON u.id=r.user_id WHERE r.id=?",
|
||||
"SELECT r.*, u.name, u.email, u.subscription_tier AS old_tier FROM upgrade_requests r JOIN users u ON u.id=r.user_id WHERE r.id=?",
|
||||
(req_id,)
|
||||
).fetchone()
|
||||
if not req:
|
||||
|
|
@ -1259,9 +1259,70 @@ async def fulfill_upgrade_request(req_id: int, user=Depends(require_admin)):
|
|||
import logging
|
||||
logging.getLogger(__name__).warning(f"Bestätigungsmail fehlgeschlagen: {e}")
|
||||
|
||||
# Offene Rechnungen (sent/draft) des alten Tiers stornieren + neuen Entwurf anlegen
|
||||
try:
|
||||
await _handle_upgrade_invoices(req, tier_label)
|
||||
except Exception as e:
|
||||
logger.warning(f"Upgrade-Rechnungslogik fehlgeschlagen für {req['name']}: {e}")
|
||||
|
||||
return {"ok": True, "tier": req["tier"], "user": req["name"]}
|
||||
|
||||
|
||||
async def _handle_upgrade_invoices(req: dict, new_tier_label: str):
|
||||
"""Storniert offene Rechnungen des alten Tiers und legt neuen Entwurf an."""
|
||||
from routes.invoices import _next_invoice_number
|
||||
from datetime import timedelta
|
||||
|
||||
with db() as conn:
|
||||
# Offene Rechnungen (draft + sent) dieses Users finden
|
||||
open_invoices = conn.execute(
|
||||
"SELECT * FROM invoices WHERE user_id=? AND status IN ('draft','sent')",
|
||||
(req["user_id"],)
|
||||
).fetchall()
|
||||
|
||||
for inv in open_invoices:
|
||||
cancel_num = _next_invoice_number(conn, "ST")
|
||||
conn.execute(
|
||||
"""UPDATE invoices SET status='cancelled', cancelled_at=strftime('%Y-%m-%dT%H:%M:%SZ','now'),
|
||||
cancellation_reason=?, cancellation_number=? WHERE id=?""",
|
||||
(f"Tarif-Upgrade auf {new_tier_label}", cancel_num, inv["id"])
|
||||
)
|
||||
logger.info(f"Rechnung {inv['invoice_number']} storniert ({cancel_num}) — Upgrade auf {new_tier_label}")
|
||||
|
||||
# Neuen Entwurf für den neuen Tier anlegen
|
||||
tier = req["tier"]
|
||||
price = {"pro": 29.00, "breeder": 49.00}.get(tier, 29.00)
|
||||
today = datetime.now(_TZ).date()
|
||||
end_date = today.replace(year=today.year + 1) - timedelta(days=1)
|
||||
period = f"{today.strftime('%d.%m.%Y')} – {end_date.strftime('%d.%m.%Y')}"
|
||||
description = f"{new_tier_label} Jahresabo"
|
||||
|
||||
billing = conn.execute(
|
||||
"SELECT billing_address FROM users WHERE id=?", (req["user_id"],)
|
||||
).fetchone()
|
||||
billing_address = billing["billing_address"] if billing else None
|
||||
|
||||
inv_number = _next_invoice_number(conn)
|
||||
conn.execute("""
|
||||
INSERT INTO invoices
|
||||
(invoice_number, user_id, recipient_name, recipient_email, recipient_address,
|
||||
description, service_period, amount_net, discount_pct, discount_amount,
|
||||
amount_after_discount, tax_rate, tax_amount, amount_gross, notes)
|
||||
VALUES (?,?,?,?,?,?,?,?,0,0,?,0,0,?,?)
|
||||
""", (
|
||||
inv_number, req["user_id"], req["name"], req["email"], billing_address,
|
||||
description, period, price, price, price,
|
||||
f"Automatisch bei Upgrade von {req.get('old_tier','Standard')} auf {new_tier_label}.",
|
||||
))
|
||||
invoice_id = conn.execute("SELECT last_insert_rowid()").fetchone()[0]
|
||||
conn.execute(
|
||||
"INSERT INTO invoice_items (invoice_id, description, quantity, unit_price, total) VALUES (?,?,1,?,?)",
|
||||
(invoice_id, description, price, price)
|
||||
)
|
||||
|
||||
logger.info(f"Neuer Rechnungsentwurf {inv_number} für {req['email']} nach Upgrade auf {new_tier_label}")
|
||||
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Helpers: Quartalsdaten
|
||||
# ------------------------------------------------------------------
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue