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
@@ -11,7 +11,7 @@ const aw = await startAppwriteMock({
|
||||
const st = await startFakeStripe()
|
||||
after(() => Promise.all([aw.close(), st.close()]))
|
||||
useTestEnv({ appwriteUrl: aw.url, stripeUrl: st.url })
|
||||
const { grantCreditForInvoice } = await import('../server/services/stripeBilling.js')
|
||||
const { grantCreditForInvoice, loadInvoice, invoiceLines } = await import('../server/services/stripeBilling.js')
|
||||
|
||||
const price = (id, lookup_key, unit_amount) => ({ id, object: 'price', lookup_key, unit_amount, active: true })
|
||||
st.prices.set('price_w', price('price_w', 'webklar_wartung_monatlich_5000', 5000))
|
||||
@@ -116,3 +116,49 @@ test('Altbestand: Abo ohne bekannten Preis bekommt weiter seine Stunde, auch bei
|
||||
assert.equal(aw.docs('hourCredits').get('in_6').minutes, 60)
|
||||
assert.equal(aw.docs('subscriptions').get('sub_alt').productKey, 'wartung')
|
||||
})
|
||||
|
||||
// F18 / Hinweis aus dem Review von Plan 1: invoices.retrieve bettet hoechstens 10 Zeilen ein. Anteilige
|
||||
// Zeilen stehen vor den Abo-Zeilen; mehrere Speicheraenderungen in einem Monat schieben die Wartungs-Zeile
|
||||
// hinaus. Der Nachbau bettet wie Stripe 10 Zeilen ein (has_more), der Rest kommt ueber /lines.
|
||||
test('Rechnung mit 11 Zeilen: die Wartungs-Zeile als elfte wird nachgeladen → 60 Minuten', async () => {
|
||||
st.prices.set('price_s', price('price_s', 'webklar_mailspeicher_5gb_monatlich_100', 100))
|
||||
const proration = (amount) => ({
|
||||
amount,
|
||||
pricing: { type: 'price_details', price_details: { price: 'price_s' } },
|
||||
parent: { type: 'subscription_item_details', subscription_item_details: { proration: true } },
|
||||
})
|
||||
const prorations = Array.from({ length: 10 }, (_, i) => proration(10 + i))
|
||||
st.invoices.set('in_11', inv('in_11', 'sub_w', [...prorations, regular('price_w', 5000)]))
|
||||
const before = st.calls.length
|
||||
const r = await grantCreditForInvoice(payload('in_11', 'sub_w', 5000))
|
||||
assert.equal(r.granted, true)
|
||||
assert.equal(aw.docs('hourCredits').get('in_11').minutes, 60)
|
||||
const calls = st.calls.slice(before)
|
||||
assert.equal(calls.filter((c) => c.method === 'GET' && c.path === '/v1/invoices/in_11').length, 1)
|
||||
assert.ok(calls.some((c) => c.method === 'GET' && c.path === '/v1/invoices/in_11/lines'), 'weitere Zeilen ueber /lines geladen')
|
||||
})
|
||||
|
||||
test('invoiceLines: eingebettete Zeilen ohne has_more, sonst alle Seiten; loadInvoice liefert alle Zeilen', async () => {
|
||||
const embedded = { id: 'in_egal', lines: { data: [{ amount: 1 }, { amount: 2 }], has_more: false } }
|
||||
const before = st.calls.length
|
||||
assert.deepEqual(await invoiceLines(embedded), [{ amount: 1 }, { amount: 2 }])
|
||||
assert.equal(st.calls.length, before, 'kein Stripe-Aufruf ohne has_more')
|
||||
const loaded = await loadInvoice('in_11')
|
||||
assert.equal(loaded.lines.data.length, 11)
|
||||
assert.equal(loaded.lines.has_more, false)
|
||||
assert.equal(loaded.lines.data[10].amount, 5000)
|
||||
// Vorschau-Rechnungen haben keine ID: has_more laesst sich dann nicht nachladen, die eingebetteten zaehlen
|
||||
assert.deepEqual(await invoiceLines({ lines: { data: [{ amount: 3 }], has_more: true } }), [{ amount: 3 }])
|
||||
})
|
||||
|
||||
// F18: der Webhook laedt die Rechnung einmal (loadInvoice) und reicht sie als fresh weiter - kein zweiter Abruf
|
||||
test('Schon frisch geladene Rechnung (fresh: true) wird nicht noch einmal geladen', async () => {
|
||||
st.invoices.set('in_7', inv('in_7', 'sub_w', [regular('price_w', 5000)]))
|
||||
const fresh = await loadInvoice('in_7')
|
||||
const before = st.calls.length
|
||||
const r = await grantCreditForInvoice(fresh, { fresh: true })
|
||||
assert.equal(r.granted, true)
|
||||
assert.equal(aw.docs('hourCredits').get('in_7').minutes, 60)
|
||||
assert.equal(aw.docs('hourCredits').get('in_7').note, 'Rechnung WK-in_7')
|
||||
assert.deepEqual(st.calls.slice(before).filter((c) => c.path.startsWith('/v1/invoices')), [])
|
||||
})
|
||||
Reference in new issue
Block a user