Jedes Glied einer Liste kostet, auch in einem Gruppen-CC
Bisher zahlte nur, wer neu einstieg: wer in einer Kette mitgezogen wurde oder einen Gruppen-CC mitbenutzte, stand darin ohne eigene Buchung. Damit ging die Rechnung nicht auf - verbrauchte Redesigns sind alle Glieder aller Listen minus die Anzahl der Listen, und das gilt fuer jeden Nutzer einzeln. Jetzt bucht jedes Glied: das unterste einen Platz, jedes weitere ein Redesign. Wo eine Buchung fehlt, traegt der Abgleich sie nach, und das Redesign eines Gruppen-CCs kostet jeden Nutzer sein eigenes. Am Pfeil stehen alle offenen Buchungen eines Eintrags, nicht nur die juengste - sonst bleibt eine zweite unsichtbar.
This commit is contained in:
+568
-287
File diff suppressed because it is too large
Load Diff
@@ -716,8 +716,9 @@ describe('Die Stelle in der Kette bestimmt, was ein Eintrag kostet', () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('lässt einen Eintrag ohne Buchung in Ruhe', async () => {
|
it('trägt eine fehlende Buchung nach', async () => {
|
||||||
// Nacherfassung ohne Guthaben-Angabe - da gibt es nichts umzustellen.
|
// Jedes Glied einer Liste kostet: das unterste ein Paket, jedes weitere
|
||||||
|
// ein Redesign. Wo nichts gebucht ist, fehlt es in der Rechnung.
|
||||||
const spieler = await spielerMitPaketen('Ohne Buchung', 1);
|
const spieler = await spielerMitPaketen('Ohne Buchung', 1);
|
||||||
const eins = await characters.createCharacter(spieler, { name: 'Mit Buchung' }, ctx);
|
const eins = await characters.createCharacter(spieler, { name: 'Mit Buchung' }, ctx);
|
||||||
|
|
||||||
@@ -735,7 +736,19 @@ describe('Die Stelle in der Kette bestimmt, was ein Eintrag kostet', () => {
|
|||||||
ctx,
|
ctx,
|
||||||
);
|
);
|
||||||
|
|
||||||
assert.deepEqual(await credits.getBalances(spieler), vorher, 'nichts gebucht, nichts geändert');
|
const danach = await credits.getBalances(spieler);
|
||||||
|
assert.equal(danach.CC, vorher.CC, 'der Platz bleibt, wie er war');
|
||||||
|
assert.equal(
|
||||||
|
danach.REDESIGN_PAID,
|
||||||
|
vorher.REDESIGN_PAID - 1,
|
||||||
|
'das zweite Glied kostet ein Redesign',
|
||||||
|
);
|
||||||
|
|
||||||
|
// Und allein gestellt kostet er wieder einen eigenen Platz.
|
||||||
|
await characters.detachFromChain(ohne.id, ctx);
|
||||||
|
const allein = await credits.getBalances(spieler);
|
||||||
|
assert.equal(allein.CC, vorher.CC - 1, 'eine eigene Liste, ein eigenes Paket');
|
||||||
|
assert.equal(allein.REDESIGN_PAID, vorher.REDESIGN_PAID, 'das Redesign ist wieder frei');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -1345,11 +1358,13 @@ describe('Die Umstellung auf Listen je Nutzer', () => {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
assert.equal(
|
for (const wer of [wirt, gast]) {
|
||||||
await characters.richteBuchungenAus(),
|
assert.equal(
|
||||||
0,
|
(await characters.rebuildFunding(wer, ctx)).umgebucht,
|
||||||
'und die Buchungen passen danach zu den Listen',
|
0,
|
||||||
);
|
'und die Buchungen passen danach zu den Listen',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// Der Gast zahlt für seinen Einstieg ein Redesign, nicht einen Platz.
|
// Der Gast zahlt für seinen Einstieg ein Redesign, nicht einen Platz.
|
||||||
assert.equal(
|
assert.equal(
|
||||||
|
|||||||
@@ -107,16 +107,20 @@ describe('Nachträglich aufräumen, was längst passiert ist', () => {
|
|||||||
assert.deepEqual(await mitglieder(alpha), ['Spieler A', 'Spieler B']);
|
assert.deepEqual(await mitglieder(alpha), ['Spieler A', 'Spieler B']);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('zieht ihn durch die Kette, ohne ein zweites Mal zu buchen', async () => {
|
it('zieht ihn durch die Kette und bucht jedes Glied einzeln', async () => {
|
||||||
|
// Für ihn ist jedes Glied ein eigener Eintrag in seiner Liste: der
|
||||||
|
// unterste kostet den Platz, jedes weitere ein Redesign.
|
||||||
const vorher = await credits.getBalances(a);
|
const vorher = await credits.getBalances(a);
|
||||||
|
|
||||||
const ergebnis = await characters.addMemberToChain(beta, a, {}, ctx);
|
const ergebnis = await characters.addMemberToChain(beta, a, {}, ctx);
|
||||||
assert.equal(ergebnis.added, 2, 'Beta und Gamma kommen dazu');
|
assert.equal(ergebnis.added, 2, 'Beta und Gamma kommen dazu');
|
||||||
|
|
||||||
assert.deepEqual(
|
const danach = await credits.getBalances(a);
|
||||||
await credits.getBalances(a),
|
assert.equal(danach.CC, vorher.CC, 'sein Platz wurde einmal bezahlt');
|
||||||
vorher,
|
assert.equal(
|
||||||
'sein Platz wurde einmal bezahlt und ist derselbe geblieben',
|
danach.REDESIGN_PAID,
|
||||||
|
vorher.REDESIGN_PAID - 2,
|
||||||
|
'für Beta und Gamma je ein Redesign',
|
||||||
);
|
);
|
||||||
assert.deepEqual(await mitglieder(gamma), ['Spieler A', 'Spieler B']);
|
assert.deepEqual(await mitglieder(gamma), ['Spieler A', 'Spieler B']);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -409,16 +409,23 @@ const UEBERGANG: Record<string, { zeichen: string; titel: string; klasse: string
|
|||||||
* Eintrag.
|
* Eintrag.
|
||||||
*/
|
*/
|
||||||
function Uebergang({ character }: { character: Character | undefined }) {
|
function Uebergang({ character }: { character: Character | undefined }) {
|
||||||
const art = character?.fundedWith ? UEBERGANG[character.fundedWith] : undefined;
|
const arten = (character?.fundedWith ?? [])
|
||||||
|
.map((art) => UEBERGANG[art])
|
||||||
|
.filter((art): art is (typeof UEBERGANG)[string] => art !== undefined);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="chain-arrow">
|
<div className="chain-arrow">
|
||||||
<span aria-hidden="true">⬆</span>
|
<span aria-hidden="true">⬆</span>
|
||||||
{art && (
|
{arten.map((art, i) => (
|
||||||
<span className={`chain-step ${art.klasse}`} title={art.titel}>
|
<span
|
||||||
|
key={`${art.zeichen}-${i}`}
|
||||||
|
className={`chain-step ${art.klasse}`}
|
||||||
|
style={i > 0 ? { transform: `translate(${0.75 + i * 1.6}rem, -50%)` } : undefined}
|
||||||
|
title={art.titel}
|
||||||
|
>
|
||||||
{art.zeichen}
|
{art.zeichen}
|
||||||
</span>
|
</span>
|
||||||
)}
|
))}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -151,7 +151,8 @@ export interface Character {
|
|||||||
forumThreads?: ThreadRef[];
|
forumThreads?: ThreadRef[];
|
||||||
links?: CharacterLink[];
|
links?: CharacterLink[];
|
||||||
/// Womit dieser Eintrag bezahlt wurde, aus Sicht des betrachteten Spielers.
|
/// Womit dieser Eintrag bezahlt wurde, aus Sicht des betrachteten Spielers.
|
||||||
fundedWith?: CreditKind | null;
|
/// Mehrere, wenn zusätzlich gebucht wurde - etwa bei einer Rückkehr.
|
||||||
|
fundedWith?: CreditKind[];
|
||||||
members?: CharacterMember[];
|
members?: CharacterMember[];
|
||||||
createdAt: string;
|
createdAt: string;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user