Abo-API: Nachweis-ID nach Appwrite-Regeln, Webhook bei dauerhaften Fehlern, Tests
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
1 parent
7df0b72019
commit
887e1e54a0
10 files changed
+409
-107
No files matched your search
+41
-20
@@ -1,11 +1,12 @@
|
||||
// testApp.js zuerst: es prueft beim Laden, dass useTestEnv() gelaufen ist, bevor config.js die Umgebung liest
|
||||
// testApp.js zuerst: es prueft beim Laden, dass useTestEnv() vor config.js gelaufen ist
|
||||
import { sessionCookie } from './testApp.js'
|
||||
import { config } from '../../server/config.js'
|
||||
|
||||
/**
|
||||
* Feste Testdaten für die Routen-Tests (Aufgaben 7–13): Kunden c1–c3, Abo-Dokumente, Zustimmung,
|
||||
* Feste Testdaten für die Routen-Tests (Aufgaben 7–13): Kunden c1–c4, Abo-Dokumente, Zustimmung,
|
||||
* Session-Cookies. seedFixtures(aw) legt Kunden und Abos in den Appwrite-Nachbau; c3 hat kein Abo
|
||||
* (Neuabschluss-Tests). Erst nach useTestEnv() dynamisch importieren (siehe testApp.js).
|
||||
* (Neuabschluss-Tests), c4 ist ein Testkonto (ABO_TEST_EMAILS=test@example.invalid im Test setzen).
|
||||
* Erst nach useTestEnv() dynamisch importieren (siehe testApp.js).
|
||||
*/
|
||||
|
||||
const DAY_MS = 86400000
|
||||
@@ -15,18 +16,20 @@ export const customers = {
|
||||
c1: { $id: 'c1', appwriteUserId: 'u1', email: 'k@example.invalid', name: 'Kunde Eins', status: 'active', portalAccessEnabled: true },
|
||||
c2: { $id: 'c2', appwriteUserId: 'u2', email: 'k2@example.invalid', name: 'Kunde Zwei', status: 'active', portalAccessEnabled: true },
|
||||
c3: { $id: 'c3', appwriteUserId: 'u3', email: 'k3@example.invalid', name: 'Kunde Drei', status: 'active', portalAccessEnabled: true },
|
||||
c4: { $id: 'c4', appwriteUserId: 'u4', email: 'test@example.invalid', name: 'Testkonto', status: 'active', portalAccessEnabled: true },
|
||||
}
|
||||
|
||||
/** Abo-Dokument mit id als Dokument-ID und Stripe-Abo-ID (in Produktion immer gleich). */
|
||||
export const subscriptionDoc = (id, overrides = {}) => ({ ...overrides, $id: id, stripeSubscriptionId: id })
|
||||
|
||||
// Abo seit 40 Tagen (Widerrufsfrist des Abschlusses vorbei), naechste Abbuchung in 20 Tagen
|
||||
const startedAt = daysFromNow(-40)
|
||||
|
||||
/** Hosting-Abo sub_h von c1: aktiv, Fassung 4, ohne Zusatzspeicher. */
|
||||
export const hostingDoc = {
|
||||
$id: 'sub_h',
|
||||
export const hostingDoc = subscriptionDoc('sub_h', {
|
||||
customerId: 'c1',
|
||||
email: 'k@example.invalid',
|
||||
stripeCustomerId: 'cus_c1',
|
||||
stripeSubscriptionId: 'sub_h',
|
||||
status: 'active',
|
||||
productKey: 'hosting',
|
||||
planKey: config.products.hosting.lookupKey,
|
||||
@@ -49,27 +52,23 @@ export const hostingDoc = {
|
||||
storageUnits: 0,
|
||||
storagePaidUnits: 0,
|
||||
storagePaidPeriodEnd: null,
|
||||
}
|
||||
})
|
||||
|
||||
/** Wartungs-Abo sub_w von c1 (im Test meist als sub_h eingespielt, damit c1 nur ein Abo hat). */
|
||||
export const wartungDoc = {
|
||||
/** Wartungs-Abo sub_w von c1 (im Test meist per subscriptionDoc('sub_h', { ...wartungDoc }) eingespielt). */
|
||||
export const wartungDoc = subscriptionDoc('sub_w', {
|
||||
...hostingDoc,
|
||||
$id: 'sub_w',
|
||||
stripeSubscriptionId: 'sub_w',
|
||||
productKey: 'wartung',
|
||||
planKey: config.products.wartung.lookupKey,
|
||||
priceAmount: config.products.wartung.amountCents,
|
||||
}
|
||||
})
|
||||
|
||||
/** Zweites Hosting-Abo sub_h2 von c2. */
|
||||
export const hosting2Doc = {
|
||||
export const hosting2Doc = subscriptionDoc('sub_h2', {
|
||||
...hostingDoc,
|
||||
$id: 'sub_h2',
|
||||
customerId: 'c2',
|
||||
email: 'k2@example.invalid',
|
||||
stripeCustomerId: 'cus_c2',
|
||||
stripeSubscriptionId: 'sub_h2',
|
||||
}
|
||||
})
|
||||
|
||||
const consentAt = new Date().toISOString()
|
||||
|
||||
@@ -90,7 +89,21 @@ export const customerCookie = (customerId = 'c1') =>
|
||||
export const adminCookie = () =>
|
||||
sessionCookie({ role: 'admin', appwriteUserId: 'u_admin', name: 'Kenso', email: 'kenso@webklar.com' })
|
||||
|
||||
/** Kunden c1–c3 und die Abos sub_h (c1) und sub_h2 (c2) in den Appwrite-Nachbau legen. */
|
||||
/** Admin im Modus "Als Kunde ansehen" (portalAdmin.js /view-as): Bestellen und Aendern sind gesperrt. */
|
||||
export const viewAsCookie = (customerId = 'c1') =>
|
||||
sessionCookie({
|
||||
role: 'admin',
|
||||
viewAs: true,
|
||||
isAdmin: true,
|
||||
appwriteUserId: 'u_admin',
|
||||
adminName: 'Kenso',
|
||||
adminEmail: 'kenso@webklar.com',
|
||||
customerId,
|
||||
name: customers[customerId]?.name || '',
|
||||
email: customers[customerId]?.email || '',
|
||||
})
|
||||
|
||||
/** Kunden c1–c4 und die Abos sub_h (c1) und sub_h2 (c2) in den Appwrite-Nachbau legen. */
|
||||
export function seedFixtures(aw) {
|
||||
for (const customer of Object.values(customers)) aw.seed('customers', customer)
|
||||
aw.seed('subscriptions', hostingDoc)
|
||||
@@ -101,10 +114,18 @@ const unix = (iso) => Math.floor(new Date(iso).getTime() / 1000)
|
||||
|
||||
/**
|
||||
* Stripe-Abo in der Form der SDK-API-Version für den Stripe-Nachbau: Abo-Posten je Produkt,
|
||||
* dazu ein Zusatzspeicher-Posten, wenn storageUnits > 0. metadata ergaenzt/ueberschreibt die
|
||||
* Zustimmungsdaten, rest alles Weitere (status, cancel_at, ...).
|
||||
* dazu ein Zusatzspeicher-Posten, wenn storageUnits > 0. Die Standard-ID ist 28 Zeichen lang wie
|
||||
* bei Stripe (sub_ + 24); fuer den Spiegel von sub_h explizit id: 'sub_h' uebergeben. metadata
|
||||
* ergaenzt/ueberschreibt die Zustimmungsdaten, rest alles Weitere (status, cancel_at, ...).
|
||||
*/
|
||||
export function stripeSubscription({ id = 'sub_h', customerId = 'c1', productKey = 'hosting', storageUnits = 0, metadata = {}, ...rest } = {}) {
|
||||
export function stripeSubscription({
|
||||
id = 'sub_1SD6vPRxAbCdEfGhIjKlMnOp',
|
||||
customerId = 'c1',
|
||||
productKey = 'hosting',
|
||||
storageUnits = 0,
|
||||
metadata = {},
|
||||
...rest
|
||||
} = {}) {
|
||||
const product = config.products[productKey]
|
||||
const items = [
|
||||
{
|
||||
|
||||
Reference in new issue
Block a user