Die Rechnung auf eine Regel bringen, plus Knopf zum Nachrechnen
Die Regel lautet: so viele CC-Pakete wie Ketten, so viele Redesigns wie Eintraege minus Ketten. Anders gesagt - wer keinen Vorgaenger hat, ist der Anfang einer Kette und damit ein gekaufter CC; wer einen hat, ist dessen Redesign. In welcher Linie ein Eintrag gefuehrt wird, spielt keine Rolle. Ich hatte das mit einer Sonderbehandlung fuer "Herkunft ausserhalb der Linie" gebaut. Die faellt weg: Sie war ein Umweg um dieselbe Regel und hat sie an einer Stelle verfehlt. Jetzt steht sie direkt im Code, und der Fall mit dem fremden Gruppen-CC folgt von selbst daraus - dessen eigener Strang hat einen Vorgaenger, ist also kein Kauf. Fuer Bestaende, die aus einer Zeit stammen, in der eine Buchung blieb, wo sie beim Anlegen entstand, gibt es "Buchungen nachrechnen" auf der Spielerseite. Es richtet alle Buchungen eines Spielers nach dieser Regel aus, fasst nur an, was nicht passt, bucht ueber Gegenbuchungen um und laesst Kulanz- Entscheidungen stehen. Vier Tests halten die Rechnung fest, einer davon genau in der Form, in der sie formuliert wurde: Ketten zaehlen, Eintraege zaehlen, Buchungen zaehlen, vergleichen.
This commit is contained in:
@@ -837,3 +837,133 @@ describe('Eine Kette mit Vorgeschichte ausserhalb', () => {
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Die Rechnung geht auf', () => {
|
||||
/**
|
||||
* Die Regel in einem Satz: **So viele CC-Pakete wie Ketten, so viele
|
||||
* Redesigns wie Einträge minus Ketten.** Bei drei Ketten mit zusammen
|
||||
* sechzehn Einträgen sind das drei Pakete und dreizehn Redesigns.
|
||||
*/
|
||||
async function zaehle(playerId: number) {
|
||||
const eintraege = await db.prisma.characterMember.findMany({
|
||||
where: { playerId },
|
||||
select: { character: { select: { predecessorId: true } } },
|
||||
});
|
||||
|
||||
const ketten = eintraege.filter((e) => e.character.predecessorId === null).length;
|
||||
return { eintraege: eintraege.length, ketten };
|
||||
}
|
||||
|
||||
async function verbraeuche(playerId: number) {
|
||||
const zeilen = await db.prisma.creditLedger.findMany({
|
||||
where: { playerId, source: 'CONSUME', reversedBy: null },
|
||||
select: { kind: true },
|
||||
});
|
||||
return {
|
||||
cc: zeilen.filter((z) => z.kind === 'CC').length,
|
||||
redesign: zeilen.filter((z) => z.kind !== 'CC').length,
|
||||
};
|
||||
}
|
||||
|
||||
it('bucht so viele Pakete wie Ketten und den Rest als Redesign', async () => {
|
||||
const spieler = await spielerMitPaketen('Rechenbeispiel', 3);
|
||||
|
||||
// Drei Ketten mit 3, 2 und 1 Eintrag: zusammen sechs.
|
||||
const ketten: number[] = [];
|
||||
for (const [name, laenge] of [
|
||||
['Kette A', 3],
|
||||
['Kette B', 2],
|
||||
['Kette C', 1],
|
||||
] as const) {
|
||||
const erster = await characters.createCharacter(spieler, { name: `${name} 1` }, ctx);
|
||||
let letzter = erster.character.id;
|
||||
for (let i = 2; i <= laenge; i += 1) {
|
||||
await credits.bookRedesignPackage(spieler, ctx);
|
||||
const naechster = await characters.redesignCharacter(
|
||||
letzter,
|
||||
{ name: `${name} ${i}`, useKind: 'REDESIGN_PAID' },
|
||||
ctx,
|
||||
);
|
||||
letzter = naechster.character.id;
|
||||
}
|
||||
ketten.push(erster.character.id);
|
||||
}
|
||||
|
||||
const struktur = await zaehle(spieler);
|
||||
assert.equal(struktur.ketten, 3);
|
||||
assert.equal(struktur.eintraege, 6);
|
||||
|
||||
const gebucht = await verbraeuche(spieler);
|
||||
assert.equal(gebucht.cc, struktur.ketten, 'so viele Pakete wie Ketten');
|
||||
assert.equal(
|
||||
gebucht.redesign,
|
||||
struktur.eintraege - struktur.ketten,
|
||||
'und der Rest sind Redesigns',
|
||||
);
|
||||
});
|
||||
|
||||
it('rechnet einen verbogenen Bestand wieder gerade', async () => {
|
||||
const spieler = await spielerMitPaketen('Verbogen', 2);
|
||||
const eins = await characters.createCharacter(spieler, { name: 'Anfang' }, ctx);
|
||||
await credits.bookRedesignPackage(spieler, ctx);
|
||||
const zwei = await characters.redesignCharacter(
|
||||
eins.character.id,
|
||||
{ name: 'Fortsetzung', useKind: 'REDESIGN_PAID' },
|
||||
ctx,
|
||||
);
|
||||
|
||||
// So sah es aus, bevor die Buchung der Kette folgte: das zweite Glied
|
||||
// stand als eigener Kauf im Konto.
|
||||
const falsch = await db.prisma.creditLedger.findFirstOrThrow({
|
||||
where: { characterId: zwei.character.id, source: 'CONSUME', reversedBy: null },
|
||||
});
|
||||
await db.prisma.creditLedger.update({ where: { id: falsch.id }, data: { kind: 'CC' } });
|
||||
|
||||
const vorher = await verbraeuche(spieler);
|
||||
assert.equal(vorher.cc, 2, 'zwei Käufe bei nur einer Kette - das kann nicht stimmen');
|
||||
|
||||
const ergebnis = await characters.rebuildFunding(spieler, ctx);
|
||||
assert.equal(ergebnis.umgebucht, 1);
|
||||
|
||||
const struktur = await zaehle(spieler);
|
||||
const gebucht = await verbraeuche(spieler);
|
||||
assert.equal(gebucht.cc, struktur.ketten, 'jetzt passt es wieder');
|
||||
assert.equal(gebucht.redesign, struktur.eintraege - struktur.ketten);
|
||||
});
|
||||
|
||||
it('fasst nichts an, wenn schon alles stimmt', async () => {
|
||||
const spieler = await spielerMitPaketen('Sauber', 1);
|
||||
const eins = await characters.createCharacter(spieler, { name: 'Passt' }, ctx);
|
||||
await credits.bookRedesignPackage(spieler, ctx);
|
||||
await characters.redesignCharacter(
|
||||
eins.character.id,
|
||||
{ name: 'Passt auch', useKind: 'REDESIGN_PAID' },
|
||||
ctx,
|
||||
);
|
||||
|
||||
const vorher = await credits.getBalances(spieler);
|
||||
const ergebnis = await characters.rebuildFunding(spieler, ctx);
|
||||
|
||||
assert.equal(ergebnis.umgebucht, 0);
|
||||
assert.deepEqual(ergebnis.balances, vorher);
|
||||
});
|
||||
|
||||
it('lässt eine Kulanz-Entscheidung auch beim Nachrechnen stehen', async () => {
|
||||
const spieler = await spielerMitPaketen('Kulanz bleibt', 1);
|
||||
const eins = await characters.createCharacter(spieler, { name: 'Start' }, ctx);
|
||||
await credits.bookKulanz(spieler, 1, 'Absprache', ctx);
|
||||
const zwei = await characters.redesignCharacter(
|
||||
eins.character.id,
|
||||
{ name: 'Aus Kulanz', useKind: 'REDESIGN_KULANZ' },
|
||||
ctx,
|
||||
);
|
||||
|
||||
await characters.rebuildFunding(spieler, ctx);
|
||||
|
||||
const buchung = await db.prisma.creditLedger.findFirst({
|
||||
where: { characterId: zwei.character.id, source: 'CONSUME', reversedBy: null },
|
||||
orderBy: { id: 'desc' },
|
||||
});
|
||||
assert.equal(buchung?.kind, 'REDESIGN_KULANZ');
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user