Guthaben: "von wie vielen" anzeigen und Zugaben zuruecknehmen
In den Kaesten steht jetzt neben dem offenen Stand, wie viel jemals in den Topf kam: "0 von 3" liest sich anders als "0 von 0" - das eine heisst aufgebraucht, das andere nie etwas gehabt. Gezaehlt werden dabei nur echte Zugaenge: Die Ruecknahme eines Verbrauchs zaehlt dorthin, wo die stornierte Zeile zaehlte, sonst saehe ein zurueckgenommenes Redesign wie ein zusaetzliches Paket aus. Neben jedem Plus steht ein Minus, das die zuletzt von Hand eingetragene Zugabe dieser Art zurueckholt - fuer den vertippten oder doppelten Klick, ohne in der Historie nach der richtigen Zeile zu suchen. Zurueckgenommen wird ueber eine Gegenbuchung; bei einem CC-Paket gehen beide Zeilen mit. Aus einem Import gebuchte Pakete bleiben aussen vor: die gehoeren zu einer Bestellung und werden dort storniert, wo der Zusammenhang sichtbar ist. Die Rechte folgen dem Eintragen - Kulanz bleibt bei den Admins. Nebenbei zwei wacklige Tests festgezurrt: Die Testdatenbanken weichen auf den naechsten Port aus, wenn einer aus einem frueheren Lauf noch haengt, und der Sperr-Test des Abgleichs klopft nicht mehr bei GExtension an, sondern laeuft gegen eine tote Adresse.
This commit is contained in:
@@ -314,3 +314,93 @@ describe('Korrekturen', () => {
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Von Hand eingetragene Guthaben zurücknehmen', () => {
|
||||
it('zählt, wie viel jemals in den Topf kam', async () => {
|
||||
const playerId = await freshPlayer('Zaehler');
|
||||
await credits.bookCcPackage(playerId, ctx);
|
||||
await credits.bookCcPackage(playerId, ctx);
|
||||
await characters.createCharacter(playerId, { name: 'Verbraucht eines' }, ctx);
|
||||
|
||||
const stand = await credits.getBalances(playerId);
|
||||
assert.equal(stand.CC, 1, 'eines ist noch offen');
|
||||
assert.equal(stand.granted.CC, 2, 'zwei kamen jemals herein');
|
||||
assert.equal(stand.granted.REDESIGN_PAID, 2, 'jedes Paket bringt eines mit');
|
||||
});
|
||||
|
||||
it('zählt die Rücknahme eines Verbrauchs nicht als Zugang', async () => {
|
||||
// Sonst sähe ein storniertes Redesign wie ein zusätzliches Paket aus.
|
||||
const playerId = await freshPlayer('Stornierer');
|
||||
await credits.bookCcPackage(playerId, ctx);
|
||||
const cc = await characters.createCharacter(playerId, { name: 'Wird zurückgenommen' }, ctx);
|
||||
await characters.revertCharacter(cc.character.id, 'Fehleintrag', ctx);
|
||||
|
||||
const stand = await credits.getBalances(playerId);
|
||||
assert.equal(stand.CC, 1, 'das Guthaben ist zurück');
|
||||
assert.equal(stand.granted.CC, 1, 'hereingekommen ist trotzdem nur eines');
|
||||
});
|
||||
|
||||
it('nimmt das zuletzt eingetragene CC-Paket zurück, beide Zeilen', async () => {
|
||||
const playerId = await freshPlayer('Vertipper');
|
||||
await credits.bookCcPackage(playerId, ctx);
|
||||
await credits.bookCcPackage(playerId, ctx);
|
||||
|
||||
const { balances } = await credits.removeLastGrant(playerId, 'CC_PACKAGE', ctx);
|
||||
|
||||
assert.equal(balances.CC, 1);
|
||||
assert.equal(balances.REDESIGN_PAID, 1, 'das mitgelieferte Redesign geht mit zurück');
|
||||
assert.equal(balances.granted.CC, 1, 'und zählt auch nicht mehr als erhalten');
|
||||
});
|
||||
|
||||
it('nimmt eine Kulanz zurück', async () => {
|
||||
const playerId = await freshPlayer('Kulanzfall');
|
||||
await credits.bookKulanz(playerId, ctx, { note: 'War zu grosszügig' });
|
||||
|
||||
const { balances } = await credits.removeLastGrant(playerId, 'KULANZ', ctx);
|
||||
assert.equal(balances.REDESIGN_KULANZ, 0);
|
||||
assert.equal(balances.granted.REDESIGN_KULANZ, 0);
|
||||
});
|
||||
|
||||
it('meldet sich, wenn es nichts zurückzunehmen gibt', async () => {
|
||||
const playerId = await freshPlayer('Leerer Topf');
|
||||
|
||||
await assert.rejects(
|
||||
() => credits.removeLastGrant(playerId, 'CC_PACKAGE', ctx),
|
||||
(error: Error & { code?: string }) => error.code === 'NOTHING_TO_REMOVE',
|
||||
);
|
||||
});
|
||||
|
||||
it('lässt gebuchte Import-Pakete in Ruhe', async () => {
|
||||
// Ein Paket aus einer Bestellung gehört in die Historie, nicht unter
|
||||
// einen Knopf, der "das letzte weg" bedeutet.
|
||||
const playerId = await freshPlayer('Importiert');
|
||||
const importRecord = await db.prisma.import.create({
|
||||
data: { filename: 'shop.csv', status: 'COMMITTED', rowCount: 1 },
|
||||
});
|
||||
await db.prisma.creditLedger.create({
|
||||
data: {
|
||||
playerId,
|
||||
kind: 'CC',
|
||||
amount: 1,
|
||||
source: 'CC_PACKAGE',
|
||||
importId: importRecord.id,
|
||||
},
|
||||
});
|
||||
|
||||
await assert.rejects(
|
||||
() => credits.removeLastGrant(playerId, 'CC_PACKAGE', ctx),
|
||||
(error: Error & { code?: string }) => error.code === 'NOTHING_TO_REMOVE',
|
||||
);
|
||||
});
|
||||
|
||||
it('nimmt dieselbe Zugabe nicht zweimal zurück', async () => {
|
||||
const playerId = await freshPlayer('Doppelklicker');
|
||||
await credits.bookKulanz(playerId, ctx);
|
||||
|
||||
await credits.removeLastGrant(playerId, 'KULANZ', ctx);
|
||||
await assert.rejects(
|
||||
() => credits.removeLastGrant(playerId, 'KULANZ', ctx),
|
||||
(error: Error & { code?: string }) => error.code === 'NOTHING_TO_REMOVE',
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user