Zusatzspeicher: Plus sofort anteilig, Minus zum Monatsende, Aufgaben für konsoleH
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
1 parent
887e1e54a0
commit
379cc26dcd
11 files changed
+1531
-27
No files matched your search
+62
-1
@@ -9,6 +9,7 @@ import { eventIdFor, listContractEvents, openWithdrawals, recordContractEvent }
|
||||
import { lateStartAt, withdrawalDeadline } from '../services/deadlines.js'
|
||||
import { getLedger } from '../services/hourLedger.js'
|
||||
import { sendAdminNotice, sendCustomerMail } from '../services/mailer.js'
|
||||
import { changeStorage, previewStorageChange, recordPaidStorage } from '../services/mailStorage.js'
|
||||
import { activateOfferFromCheckout, getOpenOffer, offerText, offerView } from '../services/offers.js'
|
||||
import { PRODUCT_KEYS, productView, termsDocFor } from '../services/products.js'
|
||||
import {
|
||||
@@ -20,6 +21,7 @@ import {
|
||||
createBillingPortalUrl,
|
||||
getCurrentSubscription,
|
||||
grantCreditForInvoice,
|
||||
loadInvoice,
|
||||
minTermMonthsFor,
|
||||
isStripeConfigured,
|
||||
syncSubscription,
|
||||
@@ -256,6 +258,59 @@ router.post('/portal', requireSession, async (req, res) => {
|
||||
}
|
||||
})
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// E-Mail-Zusatzspeicher (Spec 3.4, 4.3): Vorschau und Aenderung (mailStorage.js)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/** Vorschau fuer { units }: Richtung, Gesamtgroesse, Mehrpreis, anteiliger Betrag, naechste Abbuchung, Wirksamkeit. */
|
||||
router.post('/storage/preview', requireSession, async (req, res) => {
|
||||
try {
|
||||
if (req.session.viewAs) {
|
||||
return res.status(403).json({ error: 'Im "Als Kunde ansehen"-Modus nicht möglich.' })
|
||||
}
|
||||
return res.json(await previewStorageChange(getSessionCustomerId(req), req.body?.units))
|
||||
} catch (err) {
|
||||
return res.status(err.status || 500).json({ error: err.message || 'Vorschau fehlgeschlagen' })
|
||||
}
|
||||
})
|
||||
|
||||
/**
|
||||
* Aenderung { units, acceptTerms, termsVersion }: ein Plus ist eine Bestellung ("Zahlungspflichtig bestellen")
|
||||
* und braucht acceptTerms zur aktuellen Fassung - der Nachweis (Fassung, Zeitpunkt, IP, Browser) landet im
|
||||
* Ereignis `speicher`; ein Minus ("Speichern") braucht kein Haekchen und speichert keine Zustimmungsdaten.
|
||||
* Antwort: die Abo-Ansicht wie in GET /api/abo (mit Speicherstand) und die Aenderung selbst.
|
||||
*/
|
||||
router.post('/storage', requireSession, async (req, res) => {
|
||||
try {
|
||||
if (req.session.viewAs) {
|
||||
return res.status(403).json({ error: 'Im "Als Kunde ansehen"-Modus kann der Zusatzspeicher nicht geändert werden.' })
|
||||
}
|
||||
const customerId = getSessionCustomerId(req)
|
||||
const { units, acceptTerms, termsVersion } = req.body || {}
|
||||
let consent = null
|
||||
if (acceptTerms === true) {
|
||||
if (termsVersion !== config.abo.termsVersion) {
|
||||
return res.status(409).json({ error: 'Die Bedingungen wurden aktualisiert. Bitte Seite neu laden.' })
|
||||
}
|
||||
consent = {
|
||||
termsVersion,
|
||||
consentAt: new Date().toISOString(),
|
||||
consentIp: req.ip,
|
||||
consentUserAgent: req.get('user-agent') || '',
|
||||
}
|
||||
}
|
||||
const { subscription, change } = await changeStorage(customerId, units, consent)
|
||||
const events = await listContractEvents(customerId).catch((e) => {
|
||||
console.error('[abo] Vertragsereignisse nicht lesbar:', e.message)
|
||||
return []
|
||||
})
|
||||
return res.json({ subscription: publicSubscription(subscription, events), change })
|
||||
} catch (err) {
|
||||
console.error('[abo] Zusatzspeicher-Änderung fehlgeschlagen:', err.message)
|
||||
return res.status(err.status || 500).json({ error: err.message || 'Änderung fehlgeschlagen' })
|
||||
}
|
||||
})
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Stripe-Webhook
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -396,10 +451,16 @@ async function handleStripeEvent(event) {
|
||||
return
|
||||
}
|
||||
case 'invoice.paid': {
|
||||
const result = await grantCreditForInvoice(obj)
|
||||
// Einmal frisch laden, mit allen Zeilen (F18): Stundengutschrift (Wartung) und bezahlte Speichermenge
|
||||
const fresh = await loadInvoice(obj.id)
|
||||
const result = await grantCreditForInvoice(fresh, { fresh: true })
|
||||
if (result.granted) {
|
||||
console.log(`[abo] 60 min gutgeschrieben: Kunde ${result.customerId}, Rechnung ${obj.id}`)
|
||||
}
|
||||
const storage = await recordPaidStorage(fresh)
|
||||
if (storage.recorded) {
|
||||
console.log(`[abo] Zusatzspeicher bezahlt: Abo ${storage.subscriptionId}, ${storage.units} Pakete bis ${storage.periodEnd}`)
|
||||
}
|
||||
return
|
||||
}
|
||||
case 'invoice.payment_failed': {
|
||||
|
||||
Reference in new issue
Block a user