Von Hand vergebenes CC-Guthaben ohne Redesign

Der Knopf trug bisher die Regel des Shops: ein CC-Paket ist ein Platz plus
ein Redesign. Fuer Einzelfaelle - jemand bekommt einen Platz als Ausgleich,
aus einer Absprache, weil etwas schiefging - war das zu viel.

"+ CC-Guthaben" schreibt jetzt nur den Platz gut. Wer ein volles Paket
nachtragen will, klickt zusaetzlich auf "+ Redesign-Paket". Der Abgleich mit
dem Shop bleibt unberuehrt: dort ist ein Paket weiterhin beides, und die
Regel dafuer steht unveraendert an einer Stelle.

In der Historie steht "CC-Guthaben (von Hand)" statt "CC-Paket" - eine eigene
Quelle, damit zu sehen ist, dass kein Kauf dahintersteht. Das Minus daneben
nimmt entsprechend diese Zugabe zurueck.
This commit is contained in:
2026-09-21 23:43:26 +02:00
parent e57bfbabc7
commit ae5c67eea6
10 changed files with 145 additions and 23 deletions
+6 -5
View File
@@ -361,7 +361,7 @@ describe('Erstpasswort', () => {
});
describe('Guthaben über die API', () => {
it('ein CC-Paket schlägt in beiden Töpfen auf', async () => {
it('von Hand vergeben schreibt nur das CC-Guthaben gut', async () => {
const credentials = await login('team');
const created = await app.inject({
@@ -380,13 +380,14 @@ describe('Guthaben über die API', () => {
});
assert.equal(booked.statusCode, 200);
// Ein im Shop gekauftes Paket bringt ein Redesign mit; hier geht es um
// den Einzelfall, in dem jemand nur einen Platz bekommt.
assert.deepEqual(booked.json().balances, {
CC: 1,
REDESIGN_PAID: 1,
REDESIGN_PAID: 0,
REDESIGN_KULANZ: 0,
redesignTotal: 1,
// Was offen ist, und wovon: "1 von 1".
granted: { CC: 1, REDESIGN_PAID: 1, REDESIGN_KULANZ: 0 },
redesignTotal: 0,
granted: { CC: 1, REDESIGN_PAID: 0, REDESIGN_KULANZ: 0 },
});
});
+48
View File
@@ -404,3 +404,51 @@ describe('Von Hand eingetragene Guthaben zurücknehmen', () => {
);
});
});
describe('CC-Guthaben von Hand vergeben', () => {
it('schreibt nur das CC-Guthaben gut, kein Redesign', async () => {
// Ein gekauftes Paket bringt beides mit. Von Hand gibt es Einzelfälle,
// in denen jemand nur einen Platz bekommen soll.
const playerId = await freshPlayer('Einzelfall');
const { balances } = await credits.grantCcSlot(playerId, ctx, { note: 'Ausgleich' });
assert.equal(balances.CC, 1);
assert.equal(balances.REDESIGN_PAID, 0, 'kein Redesign obendrauf');
assert.equal(balances.granted.CC, 1);
});
it('macht in der Historie sichtbar, dass kein Kauf dahintersteht', async () => {
const playerId = await freshPlayer('Nachvollziehbar');
await credits.grantCcSlot(playerId, ctx);
const zeile = await db.prisma.creditLedger.findFirstOrThrow({ where: { playerId } });
assert.equal(zeile.source, 'CC_GRANT');
});
it('lässt den Abgleich mit dem Shop unberührt', async () => {
// Ein Paket aus dem Shop bleibt, was es ist: Platz plus Redesign.
const playerId = await freshPlayer('Aus dem Shop');
const { balances } = await credits.bookCcPackage(playerId, ctx);
assert.equal(balances.CC, 1);
assert.equal(balances.REDESIGN_PAID, 1, 'das Redesign gehört zum Paket');
});
it('nimmt einen von Hand vergebenen Platz wieder zurück', async () => {
const playerId = await freshPlayer('Doch nicht');
await credits.grantCcSlot(playerId, ctx);
const { balances } = await credits.removeLastGrant(playerId, 'CC_GRANT', ctx);
assert.equal(balances.CC, 0);
assert.equal(balances.granted.CC, 0);
});
it('reicht für einen neuen CC', async () => {
const playerId = await freshPlayer('Baut damit');
await credits.grantCcSlot(playerId, ctx);
const ergebnis = await characters.createCharacter(playerId, { name: 'Daraus gebaut' }, ctx);
assert.equal(ergebnis.balances.CC, 0);
assert.equal(ergebnis.overdrawn, false, 'der Platz war gedeckt');
});
});