Hosting-Produkte: Staffelpreise nach Laufzeit (1/3/6/12/24 Monate)

This commit is contained in:
Kundencenter 2026-09-27 18:35:34 +02:00
parent e0fd57532d
commit 5efe37ecc0
12 changed files with 145 additions and 28 deletions

View file

@ -266,3 +266,37 @@ describe('Familytool-Editionen (Paket), Edition und Laufzeitpflege', () => {
const days = (new Date(tr.validUntil).getTime() - Date.now()) / 86400000; expect(days).toBeGreaterThan(13); expect(days).toBeLessThan(14.1);
});
});
describe('Staffelpreise nach Laufzeit', () => {
it('Produkt mit mehreren Laufzeiten: Bestellung wählt eine Staffel, Preis/Laufzeit werden serverseitig aus der Staffel übernommen', async () => {
const admin = await staff('term-admin@example.com', 'admin');
const A = await customer(admin, 'business', 'Firma Term', 'term-a@example.com');
const t19 = (await call(app, admin, 'GET', '/admin/tax-rates')).json().find((t: any) => t.rateBp === 1900).id;
const prod = await call(app, admin, 'POST', '/admin/products', {
sku: 'HOST-TERM', category: 'hosting', orderableByCustomer: true, requiresApproval: false, customerActions: [], status: 'active',
version: { name: 'Hosting Staffel', taxRateId: t19, setupCents: 500, recurringCents: 999, billingInterval: 'monthly', termMonths: 1, renewal: 'auto', renewalTermMonths: 1, noticeDays: 30, provisioning: {},
termPrices: [{ termMonths: 1, recurringCents: 999 }, { termMonths: 3, recurringCents: 2699 }, { termMonths: 12, recurringCents: 9588 }, { termMonths: 24, recurringCents: 17988 }] },
});
expect(prod.statusCode).toBe(200);
// doppelte Laufzeit wird abgelehnt
expect((await call(app, admin, 'POST', '/admin/products', {
sku: 'HOST-TERM-BAD', category: 'hosting', orderableByCustomer: true, requiresApproval: false, customerActions: [], status: 'draft',
version: { name: 'x', taxRateId: t19, setupCents: 0, recurringCents: 0, billingInterval: 'monthly', termMonths: 1, renewal: 'none', noticeDays: 30, provisioning: {}, termPrices: [{ termMonths: 12, recurringCents: 100 }, { termMonths: 12, recurringCents: 200 }] },
})).statusCode).toBe(400);
const cat = (await call(app, A.client, 'GET', `/catalog?org=${A.org}`)).json();
const item = cat.find((c: any) => c.sku === 'HOST-TERM');
expect(item.termPrices).toEqual([
{ termMonths: 1, price: { net: 999, tax: 190, gross: 1189 } }, { termMonths: 3, price: { net: 2699, tax: 513, gross: 3212 } },
{ termMonths: 12, price: { net: 9588, tax: 1822, gross: 11410 } }, { termMonths: 24, price: { net: 17988, tax: 3418, gross: 21406 } },
]);
// nicht angebotene Laufzeit wird abgelehnt
expect((await call(app, A.client, 'POST', '/orders', { orgId: A.org, items: [{ productId: prod.json().id, termMonths: 6 }] })).statusCode).toBe(400);
const order = (await call(app, A.client, 'POST', '/orders', { orgId: A.org, items: [{ productId: prod.json().id, termMonths: 12 }] })).json();
const items = (await call(app, admin, 'GET', `/orders/${order.id}`)).json().items;
expect(items[0].snapshot.recurring).toEqual({ net: 9588, tax: 1822, gross: 11410 });
expect(items[0].snapshot.terms).toEqual({ termMonths: 12, renewal: 'auto', renewalTermMonths: 12, noticeDays: 30 });
});
});