feat(pricing): Sätze kommen aus der Preistabelle, Rechner kann sie speichern
Die Credits-Sätze sind im Portal nicht mehr hart codiert. Neuer Endpoint GET /api/pricing/tariff liest die geteilte Tabelle billing_tariff (mit den beschlossenen Werten als Rückfallebene, falls die Tabelle fehlt), PUT /api/pricing/tariff schreibt sie mit Validierung und Audit-Eintrag. - Die Infozeile im Verbrauch-Bereich rendert ihre Zahlen aus der Tabelle, der statische Text bleibt nur als Rückfallebene stehen. - Die Rechner-Regler starten auf den aktiven Preisen, der Hinweis nennt die tatsächlich abgerechneten Sätze, und der neue Knopf "Diese Sätze als aktive Preise speichern" schreibt sie nach Rückfrage in die Tabelle. Der Monitor bucht ab der nächsten Aktion mit den neuen Werten. - Migration migrations/2026-07-25_billing_tariff.py für die eigene Staging-DB (auf Live legt die Tabelle der Monitor an und befüllt sie mit seinen wirksamen Konfigurationswerten). Gegenstück im Monitor: Commit 027244a (billing_tariff als Quelle der Buchung). Promote-Reihenfolge bleibt, erst Monitor, dann Verwaltung. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Dieser Commit ist enthalten in:
@@ -69,6 +69,23 @@ const ThemeManager = {
|
||||
},
|
||||
};
|
||||
|
||||
// Wirksame Credits-Sätze aus der Preistabelle, für alle Anzeigetexte
|
||||
let PORTAL_TARIFF = null;
|
||||
async function loadTariffInfo() {
|
||||
try {
|
||||
const data = await API.get("/api/pricing/tariff");
|
||||
PORTAL_TARIFF = data.tariff || null;
|
||||
const el = document.getElementById("tariffInfoText");
|
||||
if (el && PORTAL_TARIFF) {
|
||||
const t = PORTAL_TARIFF;
|
||||
const n = (v) => Number(v).toLocaleString("de-DE");
|
||||
el.textContent = `Zur Einordnung. Ein Live-Lauf kostet ${n(t.monitor_adhoc)} Credits, ` +
|
||||
`das Anlegen einer Recherche ${n(t.monitor_research * 3)} (drei Durchläufe), ` +
|
||||
`jede Vertiefung ${n(t.monitor_research)}, Chat und Beschreibungs-Assistent je ${n(t.chat)}.`;
|
||||
}
|
||||
} catch (e) { /* statischer Text bleibt als Rückfallebene stehen */ }
|
||||
}
|
||||
|
||||
// Sprung zum (nachgeladenen) Verbrauchsrechner-Tab
|
||||
function openRechnerTab() {
|
||||
const tab = document.querySelector('.nav-tab[data-section="rechner"]');
|
||||
@@ -115,6 +132,7 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||
setupForms();
|
||||
setupTranslation();
|
||||
loadDashboard();
|
||||
loadTariffInfo();
|
||||
loadDashboardTokenStats();
|
||||
loadTranslationStatus();
|
||||
loadOrgs();
|
||||
@@ -1289,6 +1307,6 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||
// --- Verbrauchsrechner nachladen (eigenstaendiges Modul, siehe rechner.js) ---
|
||||
(function () {
|
||||
var s = document.createElement("script");
|
||||
s.src = "/static/js/rechner.js?v=20260725a";
|
||||
s.src = "/static/js/rechner.js?v=20260725b";
|
||||
document.head.appendChild(s);
|
||||
})();
|
||||
|
||||
In neuem Issue referenzieren
Einen Benutzer sperren