GExtension-Abgleich mit Handpruefung fuer unklare Pakete
Die Profilseiten sind ohne Login abrufbar und betten die Kaeufe als JSON ins HTML ein. Gelesen wird dieses JSON statt der gerenderten Tabelle: das ist unempfindlich gegen Layout-Aenderungen und liefert zusaetzlich Kaufdatum, Betrag und den Storno-Status. Ein Headless-Browser ist nicht noetig. Der Abgleich bucht nichts von sich aus. Eindeutige Treffer landen als regulaerer Import in der bestehenden Vorschau, die per package_bought_id dedupliziert. Titel, die nach CC klingen, sich aber keiner Guthaben-Art sicher zuordnen lassen, gehen in eine Handpruefung statt geraten zu werden - sichtbar als Hinweis auf der Uebersicht und als Box beim Spieler. Beachtet werden dabei: stornierte Kaeufe werden uebersprungen, der Web- Bereich enthaelt nie CC-Pakete, und ein Redesign-Titel zaehlt als Redesign, auch wenn Custom Character darin vorkommt. Letzteres war auch in den Standard-Mappings des Datei-Imports falsch herum einsortiert. Der Lauf geht bewusst nur ueber bereits erfasste Spieler und haelt eine Sekunde Abstand zwischen den Anfragen, da die Seite fremde Infrastruktur ist. Voraussetzung dafuer ist, dass SteamIDs auf eine Schreibweise gebracht werden: die Legacy-Form, die Steam3-Form und die 64-Bit-Zahl bezeichnen dieselbe Person, wurden bisher aber als verschiedene Spieler gefuehrt. Gespeichert wird jetzt immer die 64-Bit-Form, Eingabe und Suche akzeptieren alle drei.
This commit is contained in:
@@ -62,10 +62,31 @@ CREATE TABLE "Player" (
|
||||
"notes" TEXT,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
"gextensionUsage" INTEGER,
|
||||
"gextensionSyncedAt" TIMESTAMP(3),
|
||||
|
||||
CONSTRAINT "Player_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "UnmatchedPackage" (
|
||||
"id" SERIAL NOT NULL,
|
||||
"externalId" TEXT NOT NULL,
|
||||
"playerId" INTEGER,
|
||||
"steamId" TEXT NOT NULL,
|
||||
"rawTitle" TEXT NOT NULL,
|
||||
"rawTag" TEXT NOT NULL,
|
||||
"amount" TEXT,
|
||||
"purchasedAt" TIMESTAMP(3),
|
||||
"scrapedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"resolved" BOOLEAN NOT NULL DEFAULT false,
|
||||
"resolvedAs" TEXT,
|
||||
"resolvedById" INTEGER,
|
||||
"resolvedAt" TIMESTAMP(3),
|
||||
|
||||
CONSTRAINT "UnmatchedPackage_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "CreditLedger" (
|
||||
"id" SERIAL NOT NULL,
|
||||
@@ -195,6 +216,15 @@ CREATE UNIQUE INDEX "Player_steamId_key" ON "Player"("steamId");
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Player_displayName_idx" ON "Player"("displayName");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "UnmatchedPackage_externalId_key" ON "UnmatchedPackage"("externalId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "UnmatchedPackage_resolved_idx" ON "UnmatchedPackage"("resolved");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "UnmatchedPackage_playerId_idx" ON "UnmatchedPackage"("playerId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "CreditLedger_reversalOfId_key" ON "CreditLedger"("reversalOfId");
|
||||
|
||||
@@ -246,6 +276,9 @@ CREATE INDEX "AuditLog_actorUserId_idx" ON "AuditLog"("actorUserId");
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Session" ADD CONSTRAINT "Session_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "UnmatchedPackage" ADD CONSTRAINT "UnmatchedPackage_playerId_fkey" FOREIGN KEY ("playerId") REFERENCES "Player"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "CreditLedger" ADD CONSTRAINT "CreditLedger_playerId_fkey" FOREIGN KEY ("playerId") REFERENCES "Player"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
|
||||
@@ -96,13 +96,44 @@ model Player {
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
/// Von GExtension gemeldeter Verbrauchszaehler. Reine Anzeige zum Abgleich,
|
||||
/// wird nie automatisch mit dem Ledger verrechnet.
|
||||
gextensionUsage Int?
|
||||
gextensionSyncedAt DateTime?
|
||||
|
||||
ledger CreditLedger[]
|
||||
characters Character[]
|
||||
orders ImportedOrder[]
|
||||
unmatched UnmatchedPackage[]
|
||||
|
||||
@@index([displayName])
|
||||
}
|
||||
|
||||
/// Pakete, deren Titel nach CC oder Redesign klingt, sich aber keiner
|
||||
/// Guthaben-Art sicher zuordnen laesst. Wird nie automatisch gebucht,
|
||||
/// sondern im CC-Manager von Hand entschieden.
|
||||
model UnmatchedPackage {
|
||||
id Int @id @default(autoincrement())
|
||||
externalId String @unique
|
||||
playerId Int?
|
||||
player Player? @relation(fields: [playerId], references: [id], onDelete: Cascade)
|
||||
steamId String
|
||||
rawTitle String
|
||||
rawTag String
|
||||
amount String?
|
||||
purchasedAt DateTime?
|
||||
scrapedAt DateTime @default(now())
|
||||
|
||||
resolved Boolean @default(false)
|
||||
/// CC_PACKAGE | REDESIGN_PACKAGE | REDESIGN_KULANZ | IGNORE
|
||||
resolvedAs String?
|
||||
resolvedById Int?
|
||||
resolvedAt DateTime?
|
||||
|
||||
@@index([resolved])
|
||||
@@index([playerId])
|
||||
}
|
||||
|
||||
/// Kontobuch: jede Guthaben-Bewegung ist eine Zeile (+1 Zugang, -1 Verbrauch).
|
||||
/// Der offene Stand eines Topfes ist die Summe der amounts je kind.
|
||||
model CreditLedger {
|
||||
|
||||
Reference in New Issue
Block a user