Jede Liste gehoert einem Spieler, CC-Guthaben wird umgewandelt
Ein Gruppen-CC wird fuer jeden Nutzer einzeln gerechnet: fuer den einen kann er der gekaufte Platz sein, fuer den anderen ein Redesign seines vorherigen CCs. Dafuer haengt die Liste jetzt an der Mitgliedschaft statt am CC, und verschieben ordnet nur die eigene Liste. Ein Redesign wird nie aus dem CC-Topf bezahlt. Wer sein CC-Guthaben dafuer einsetzt, wandelt es um: ein Platz weniger, ein bezahltes Redesign mehr. Damit entfaellt die Ausnahme, die sich bisher durch Slot-Pruefung und Kettenrechnung zog. Beim Start werden Buchungen einmalig an die Listen angeglichen.
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
-- Ein CC-Guthaben, das fuer ein Redesign eingesetzt wird, wird umgewandelt
|
||||
-- statt als Ausnahme gebucht. Der neue Wert steht allein in dieser Migration:
|
||||
-- Postgres laesst einen frisch angelegten Enum-Wert in derselben Transaktion
|
||||
-- noch nicht verwenden.
|
||||
ALTER TYPE "CreditSource" ADD VALUE IF NOT EXISTS 'CONVERSION' BEFORE 'CONSUME';
|
||||
@@ -0,0 +1,4 @@
|
||||
-- Ob ein Eintrag ein Platz oder ein Redesign ist, entscheidet seine Stelle in
|
||||
-- der Kette - nicht eine Markierung an der Buchung. Wer sein CC-Guthaben fuer
|
||||
-- ein Redesign einsetzt, wandelt es um, statt eine Ausnahme zu buchen.
|
||||
ALTER TABLE "CreditLedger" DROP COLUMN IF EXISTS "fundingPinned";
|
||||
@@ -0,0 +1,65 @@
|
||||
-- Ein Gruppen-CC wird fuer jeden Nutzer einzeln gerechnet: fuer den einen ist
|
||||
-- er der gekaufte Platz, fuer den anderen ein Redesign seines vorherigen CCs.
|
||||
-- Deshalb wandert die Liste vom CC an die Mitgliedschaft.
|
||||
ALTER TABLE "CharacterMember" ADD COLUMN IF NOT EXISTS "lineageId" TEXT;
|
||||
ALTER TABLE "CharacterMember" ADD COLUMN IF NOT EXISTS "chainPosition" INTEGER NOT NULL DEFAULT 0;
|
||||
|
||||
-- Wer den CC angelegt hat, bringt seine bisherige Kette mit.
|
||||
UPDATE "CharacterMember" m
|
||||
SET "lineageId" = c."lineageId", "chainPosition" = c."chainPosition"
|
||||
FROM "Character" c
|
||||
WHERE c.id = m."characterId" AND c."playerId" = m."playerId" AND m."lineageId" IS NULL;
|
||||
|
||||
-- Die uebrigen haengen an einem Eintrag, der schon zugeordnet ist: entweder am
|
||||
-- CC, den sie dafuer aufgegeben haben, oder an einem frueheren Glied derselben
|
||||
-- Kette, in der sie mitgezogen wurden. Beides kann mehrere Stufen tief gehen,
|
||||
-- deshalb die Schleife.
|
||||
DO $$
|
||||
DECLARE
|
||||
ueber_vorgaenger INTEGER;
|
||||
ueber_kette INTEGER;
|
||||
geaendert INTEGER := 1;
|
||||
BEGIN
|
||||
WHILE geaendert > 0 LOOP
|
||||
UPDATE "CharacterMember" m
|
||||
SET "lineageId" = v."lineageId", "chainPosition" = v."chainPosition" + 10
|
||||
FROM "CharacterMember" v
|
||||
WHERE v."characterId" = m."predecessorId"
|
||||
AND v."playerId" = m."playerId"
|
||||
AND v."lineageId" IS NOT NULL
|
||||
AND m."lineageId" IS NULL;
|
||||
GET DIAGNOSTICS ueber_vorgaenger = ROW_COUNT;
|
||||
|
||||
UPDATE "CharacterMember" m
|
||||
SET "lineageId" = q."lineageId",
|
||||
"chainPosition" = q."chainPosition" + (q."cc_pos" - q."von_pos")
|
||||
FROM (
|
||||
SELECT DISTINCT ON (offen.id)
|
||||
offen.id AS mitglied_id,
|
||||
v."lineageId",
|
||||
v."chainPosition",
|
||||
cm."chainPosition" AS cc_pos,
|
||||
cv."chainPosition" AS von_pos
|
||||
FROM "CharacterMember" offen
|
||||
JOIN "Character" cm ON cm.id = offen."characterId"
|
||||
JOIN "Character" cv
|
||||
ON cv."lineageId" = cm."lineageId" AND cv."chainPosition" < cm."chainPosition"
|
||||
JOIN "CharacterMember" v ON v."characterId" = cv.id AND v."playerId" = offen."playerId"
|
||||
WHERE offen."lineageId" IS NULL AND v."lineageId" IS NOT NULL
|
||||
ORDER BY offen.id, cv."chainPosition" DESC
|
||||
) q
|
||||
WHERE m.id = q.mitglied_id;
|
||||
GET DIAGNOSTICS ueber_kette = ROW_COUNT;
|
||||
|
||||
geaendert := ueber_vorgaenger + ueber_kette;
|
||||
END LOOP;
|
||||
END $$;
|
||||
|
||||
-- Alles Uebrige beginnt eine eigene Liste: ein Platz, der fuer sich steht.
|
||||
UPDATE "CharacterMember"
|
||||
SET "lineageId" = gen_random_uuid()::text, "chainPosition" = 0
|
||||
WHERE "lineageId" IS NULL;
|
||||
|
||||
ALTER TABLE "CharacterMember" ALTER COLUMN "lineageId" SET NOT NULL;
|
||||
|
||||
CREATE INDEX IF NOT EXISTS "CharacterMember_lineageId_idx" ON "CharacterMember"("lineageId");
|
||||
@@ -30,6 +30,9 @@ enum CreditSource {
|
||||
CC_GRANT
|
||||
KULANZ
|
||||
ADJUSTMENT
|
||||
/// Ein CC-Guthaben, das in ein Redesign-Guthaben umgewandelt wurde.
|
||||
/// Immer ein Paar: eine Zeile ab im CC-Topf, eine Zeile zu im Redesign-Topf.
|
||||
CONVERSION
|
||||
CONSUME
|
||||
REVERSAL
|
||||
}
|
||||
@@ -227,11 +230,6 @@ model CreditLedger {
|
||||
/// hier eingetippt hat.
|
||||
occurredAt DateTime @default(now())
|
||||
|
||||
/// Von Hand so entschieden. Das Ausrichten der Buchungen an den Ketten
|
||||
/// lässt solche Zeilen in Ruhe - sonst würde jede Ausnahme beim nächsten
|
||||
/// Umsortieren wieder eingeebnet.
|
||||
fundingPinned Boolean @default(false)
|
||||
|
||||
@@index([playerId])
|
||||
@@index([playerId, kind])
|
||||
@@index([groupId])
|
||||
@@ -473,6 +471,15 @@ model CharacterMember {
|
||||
paidWith CreditKind?
|
||||
note String?
|
||||
|
||||
/// Die Liste dieses Spielers, in der der CC für ihn steht, und seine
|
||||
/// Stelle darin.
|
||||
///
|
||||
/// Ein Gruppen-CC wird für jeden Nutzer einzeln gerechnet: Für den einen
|
||||
/// kann er der gekaufte Platz sein, für den anderen ein Redesign seines
|
||||
/// vorherigen CCs. Deshalb hängt die Kette am Nutzer, nicht am CC.
|
||||
lineageId String @default(uuid())
|
||||
chainPosition Int @default(0)
|
||||
|
||||
/// Der eigene CC, den der Spieler für diesen Platz aufgegeben hat. Nur
|
||||
/// gesetzt, wenn der Beitritt über ein Redesign lief - dann gilt dieselbe
|
||||
/// Regel wie sonst: ein Redesign ersetzt einen CC, es kommt keiner dazu.
|
||||
@@ -491,6 +498,7 @@ model CharacterMember {
|
||||
@@unique([characterId, playerId])
|
||||
@@index([playerId])
|
||||
@@index([characterId])
|
||||
@@index([lineageId])
|
||||
}
|
||||
|
||||
/// Wann ein wiederkehrender Lauf zuletzt lief. Der Zeitplan steht im Code,
|
||||
|
||||
Reference in New Issue
Block a user