feat(user): add certificate production tracking and update localization
All checks were successful
Deploy to production / deploy (push) Successful in 2m50s
All checks were successful
Deploy to production / deploy (push) Successful in 2m50s
- Introduced a new field `certificateProductionsCountSince` in the `FalukantUser` model to track the date from which production logs are counted for certificate requirements. - Updated the `FalukantService` to utilize the new field for calculating completed productions since the specified date. - Enhanced the UI to display the count of productions since the last promotion, with corresponding translations added for multiple languages including Cebuano, German, English, Spanish, and French. - Implemented a method to delete old production logs, ensuring efficient data management while maintaining necessary historical records for certificate calculations.
This commit is contained in:
@@ -0,0 +1,22 @@
|
||||
/* eslint-disable */
|
||||
'use strict';
|
||||
|
||||
module.exports = {
|
||||
async up(queryInterface) {
|
||||
await queryInterface.sequelize.query(`
|
||||
ALTER TABLE falukant_data.falukant_user
|
||||
ADD COLUMN IF NOT EXISTS certificate_productions_count_since TIMESTAMPTZ;
|
||||
`);
|
||||
await queryInterface.sequelize.query(`
|
||||
COMMENT ON COLUMN falukant_data.falukant_user.certificate_productions_count_since IS
|
||||
'Daemon/UI: Zählt nur falukant_log.production-Zeilen mit COALESCE(production_timestamp, production_date::timestamp) >= diesem Wert; bei Stufenänderung (Aufstieg/Bankrott/Erbfolge) auf NOW() (YpDaemon QUERY_UPDATE_FALUKANT_USER_CERTIFICATE). NULL = alle passenden Log-Zeilen bis zur ersten Stufenänderung nach Migration. Kein Löschen der Logs zum Reset.';
|
||||
`);
|
||||
},
|
||||
|
||||
async down(queryInterface) {
|
||||
await queryInterface.sequelize.query(`
|
||||
ALTER TABLE falukant_data.falukant_user
|
||||
DROP COLUMN IF EXISTS certificate_productions_count_since;
|
||||
`);
|
||||
}
|
||||
};
|
||||
13
backend/migrations/README.md
Normal file
13
backend/migrations/README.md
Normal file
@@ -0,0 +1,13 @@
|
||||
# Backend-Migrationen (Sequelize)
|
||||
|
||||
Migrationen in diesem Ordner werden mit dem Sequelize-CLI ausgeführt (Konfiguration siehe Projekt-Root / `backend`).
|
||||
|
||||
## Falukant: Zertifikat und Produktionszählung
|
||||
|
||||
| Datei | Inhalt |
|
||||
|--------|--------|
|
||||
| `20260402140000-add-certificate-productions-count-since.cjs` | Spalte `falukant_data.falukant_user.certificate_productions_count_since` (`TIMESTAMPTZ`, nullable) inkl. Kommentar. Setzt die DB-Grundlage dafür, dass Daemon, Backend und UI dieselbe Periode für „abgeschlossene Produktionen“ nutzen (Filter mit `COALESCE(production_timestamp, production_date::timestamp)` ab diesem Zeitpunkt; `NULL` = bisherige Historie). |
|
||||
|
||||
Eine parallele SQL-Migration im Daemon-Repository (z. B. `014_falukant_certificate_productions_count_since.sql`) kann dieselbe Spalte anlegen, wenn das Deployment dort getrennt ist – Schema doppelt anlegen vermeiden.
|
||||
|
||||
Details zur Zähl- und Retention-Logik: `docs/FALUKANT_PRODUCTION_CERTIFICATE.md`.
|
||||
@@ -29,6 +29,10 @@ FalukantUser.init({
|
||||
type: DataTypes.INTEGER,
|
||||
allowNull: false,
|
||||
defaultValue: 1},
|
||||
certificateProductionsCountSince: {
|
||||
type: DataTypes.DATE,
|
||||
allowNull: true
|
||||
},
|
||||
mainBranchRegionId: {
|
||||
type: DataTypes.INTEGER,
|
||||
allowNull: true
|
||||
|
||||
@@ -14,7 +14,6 @@ import TitleBenefit from '../models/falukant/type/title_benefit.js';
|
||||
import Branch from '../models/falukant/data/branch.js';
|
||||
import BranchType from '../models/falukant/type/branch.js';
|
||||
import Production from '../models/falukant/data/production.js';
|
||||
import DayProduction from '../models/falukant/log/dayproduction.js';
|
||||
import ProductType from '../models/falukant/type/product.js';
|
||||
import Knowledge from '../models/falukant/data/product_knowledge.js';
|
||||
import Inventory from '../models/falukant/data/inventory.js';
|
||||
@@ -976,7 +975,7 @@ class FalukantService extends BaseService {
|
||||
]
|
||||
},
|
||||
],
|
||||
attributes: ['id', 'money', 'creditAmount', 'todayCreditTaken', 'certificate']
|
||||
attributes: ['id', 'money', 'creditAmount', 'todayCreditTaken', 'certificate', 'certificateProductionsCountSince']
|
||||
});
|
||||
if (!u) throw new Error('User not found');
|
||||
if (u.certificate == null) {
|
||||
@@ -2952,6 +2951,36 @@ class FalukantService extends BaseService {
|
||||
return candidates[0] || { rank: 0, name: null };
|
||||
}
|
||||
|
||||
/**
|
||||
* Zertifikat: abgeschlossene Produktionen über alle Regionen/Niederlassungen.
|
||||
* Pro (Produkt, Kalendertag) nur ein Zähler – mehrere Niederlassungen in verschiedenen Regionen werden zusammengeführt.
|
||||
* Filter bei gesetztem countSince wie Daemon (GET_PRODUCTION_CERTIFICATE_INPUT_ROWS):
|
||||
* COALESCE(production_timestamp, production_date::timestamp) >= countSince.
|
||||
*
|
||||
* @param {number} producerId falukant_user.id
|
||||
* @param {Date|null|undefined} countSince null/undefined = gesamte Historie (Bestand / vor erster Stufenänderung)
|
||||
*/
|
||||
async getCertificateCompletedProductionCount(producerId, countSince) {
|
||||
const sinceClause = countSince
|
||||
? ' AND COALESCE(production_timestamp, production_date::timestamp) >= :countSince'
|
||||
: '';
|
||||
const replacements = { producerId };
|
||||
if (countSince) replacements.countSince = countSince;
|
||||
const rows = await sequelize.query(
|
||||
`
|
||||
SELECT COUNT(*)::int AS cnt
|
||||
FROM (
|
||||
SELECT 1
|
||||
FROM falukant_log.production
|
||||
WHERE producer_id = :producerId${sinceClause}
|
||||
GROUP BY product_id, production_date
|
||||
) AS sub
|
||||
`,
|
||||
{ replacements, type: sequelize.QueryTypes.SELECT }
|
||||
);
|
||||
return Number(rows[0]?.cnt ?? 0);
|
||||
}
|
||||
|
||||
async buildCertificateProgress(user) {
|
||||
const character = user?.character || await FalukantCharacter.findOne({
|
||||
where: { userId: user.id },
|
||||
@@ -2961,9 +2990,10 @@ class FalukantService extends BaseService {
|
||||
return null;
|
||||
}
|
||||
|
||||
const productionsSince = user.certificateProductionsCountSince ?? null;
|
||||
const [avgKnowledge, completedProductions, highestPoliticalOffice, highestChurchOffice, house, title] = await Promise.all([
|
||||
this.calculateAverageKnowledge(character.id),
|
||||
DayProduction.count({ where: { producerId: user.id } }),
|
||||
this.getCertificateCompletedProductionCount(user.id, productionsSince),
|
||||
this.getHighestPoliticalOfficeInfo(user.id),
|
||||
this.getHighestChurchOfficeInfo(user.id),
|
||||
UserHouse.findOne({
|
||||
@@ -3077,6 +3107,9 @@ class FalukantService extends BaseService {
|
||||
scoreRequirementMet,
|
||||
minimumRequirementsMet,
|
||||
readyForNextCertificate: scoreRequirementMet && minimumRequirementsMet,
|
||||
certificateProductionsCountSince: productionsSince
|
||||
? new Date(productionsSince).toISOString()
|
||||
: null,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -4112,6 +4145,10 @@ class FalukantService extends BaseService {
|
||||
}
|
||||
|
||||
await candidate.update({ userId: user.id });
|
||||
await FalukantUser.update(
|
||||
{ certificateProductionsCountSince: new Date() },
|
||||
{ where: { id: user.id } }
|
||||
);
|
||||
return { success: true, heirId: candidate.id };
|
||||
}
|
||||
|
||||
|
||||
56
docs/FALUKANT_PRODUCTION_CERTIFICATE.md
Normal file
56
docs/FALUKANT_PRODUCTION_CERTIFICATE.md
Normal file
@@ -0,0 +1,56 @@
|
||||
# Falukant: Produktions-Log und Zertifikatszählung (Abgleich Daemon ↔ Backend/UI)
|
||||
|
||||
## Ziel
|
||||
|
||||
Die sichtbare Zertifikatsvorschau (Backend `buildCertificateProgress` / UI) soll dieselbe **abgeschlossene Produktionen**-Logik verwenden wie der Zertifikats-Daemon. Außerdem soll klar sein, wie Log-Zeilen aufbewahrt und bereinigt werden – **ohne** breites Löschen nur zum Zurücksetzen der Zählung.
|
||||
|
||||
## Spalte `certificate_productions_count_since`
|
||||
|
||||
- Tabelle: `falukant_data.falukant_user`
|
||||
- Typ: `TIMESTAMPTZ`, nullable
|
||||
- **Semantik:** Nach einem **Zertifikatsaufstieg**, **Bankrott** oder **Erbfolge** (und gleichartigen Stufenänderungen im Daemon) wird der Zeitpunkt auf `NOW()` gesetzt. Alle Zählungen für Mindestanforderungen / Produktionspunkte berücksichtigen nur noch Log-Zeilen mit effektivem Zeitpunkt **≥** diesem Wert.
|
||||
- **`NULL`:** Wie bisher die gesamte relevante Historie zählen (Bestand bis zur ersten Stufenänderung nach Einführung der Spalte).
|
||||
|
||||
Daemon-seitig typisch: `QUERY_UPDATE_FALUKANT_USER_CERTIFICATE` setzt bei jeder Stufenänderung `certificate_productions_count_since = NOW()`.
|
||||
|
||||
## Effektiver Zeitpunkt einer Log-Zeile
|
||||
|
||||
Überall, wo der Daemon und das Backend dieselbe Bedeutung brauchen:
|
||||
|
||||
```sql
|
||||
COALESCE(pl.production_timestamp, pl.production_date::timestamp)
|
||||
```
|
||||
|
||||
- `production_timestamp` fehlt oder ist unzuverlässig (z. B. ältere Upserts): Fallback auf Kalendertag `production_date`.
|
||||
- So wird **nicht** nur „Produktionen für den laufenden Kalendertag“ gewertet, sondern konsistent der gespeicherte Zeitbezug der Zeile – abgestimmt mit dem Daemon (`QUERY_GET_PRODUCTION_CERTIFICATE_INPUT_ROWS`).
|
||||
|
||||
Backend-Implementierung: `getCertificateCompletedProductionCount` in `backend/services/falukantService.js` filtert bei gesetztem `certificateProductionsCountSince` mit derselben `COALESCE`-Bedingung.
|
||||
|
||||
## Log-Retention (30 Tage)
|
||||
|
||||
`falukant_log.production` wird u. a. für Wissens-Updates, Preis-/Producer-Events und Zertifikatszählung genutzt. **Nicht** sinnvoll: alle Logs nach einem Aufstieg löschen, nur um neu zu zählen.
|
||||
|
||||
Stattdessen:
|
||||
|
||||
- Zähler-Reset über **`certificate_productions_count_since`** (siehe oben).
|
||||
- Alte Zeilen werden mit **Retention 30 Tage** bereinigt, damit die Tabelle nicht unbegrenzt wächst.
|
||||
|
||||
In diesem Repo: **`UserCharacterWorker`** führt stündlich `QUERY_DELETE_OLD_PRODUCTIONS` aus:
|
||||
|
||||
```sql
|
||||
DELETE FROM falukant_log.production
|
||||
WHERE COALESCE(production_timestamp, production_date::timestamp) < NOW() - INTERVAL '30 days';
|
||||
```
|
||||
|
||||
Parallel löscht derselbe Worker weiterhin einzelne Zeilen nach dem Wissens-Update (`QUERY_DELETE_LOG_ENTRY`), sobald die Zeile „vom Vortag“ verarbeitet wurde (`QUERY_UPDATE_GET_ITEMS_TO_UPDATE` mit `COALESCE` für das Datumsfenster).
|
||||
|
||||
## Migrationen
|
||||
|
||||
- **Sequelize (dieses Repo):** `backend/migrations/20260402140000-add-certificate-productions-count-since.cjs` – fügt die Spalte und den DB-Kommentar hinzu.
|
||||
- **Externer Daemon / SQL-Pfad:** falls vorhanden z. B. `migrations/014_falukant_certificate_productions_count_since.sql` – inhaltlich dieselbe Spalte; nur eine Quelle der Wahrheit fürs Schema nötig.
|
||||
|
||||
Weitere Hinweise: `backend/migrations/README.md`.
|
||||
|
||||
## Verwandte Spezifikation
|
||||
|
||||
Ausführlicheres Fachkonzept (Stufen, Score, Events): [`FALUKANT_PRODUCTION_CERTIFICATE_SPEC.md`](./FALUKANT_PRODUCTION_CERTIFICATE_SPEC.md).
|
||||
@@ -16,9 +16,8 @@ Dieses Dokument beschreibt:
|
||||
|
||||
Wichtig:
|
||||
|
||||
- Die nötigen DB-Grundlagen sind bereits vorhanden.
|
||||
- Der Daemon muss keine neuen Schemaänderungen erwarten.
|
||||
- Bestehende Felder wie `falukant_data.falukant_user.certificate` und `falukant_type.product.category` bleiben die führende Basis.
|
||||
- Zusätzlich zu `falukant_user.certificate` gibt es `falukant_user.certificate_productions_count_since` (Zeitpunkt, ab dem Produktions-Log-Zeilen für Zertifikats-Mindestanforderungen zählen; siehe [`FALUKANT_PRODUCTION_CERTIFICATE.md`](./FALUKANT_PRODUCTION_CERTIFICATE.md)).
|
||||
- Bestehende Felder wie `falukant_data.falukant_user.certificate` und `falukant_type.product.category` bleiben die führende Basis für die Produktfreigabe.
|
||||
|
||||
## 2. Bestehende technische Basis
|
||||
|
||||
@@ -26,6 +25,8 @@ Bereits vorhanden:
|
||||
|
||||
- `falukant_data.falukant_user.certificate`
|
||||
- aktuelle Produktionsfreigabe des Spielers
|
||||
- `falukant_data.falukant_user.certificate_productions_count_since` (optional, empfohlen)
|
||||
- ab diesem Zeitpunkt zählen Produktions-Log-Zeilen für Zertifikats-Mindestanforderungen (`NULL` = volle Historie); Details: [`FALUKANT_PRODUCTION_CERTIFICATE.md`](./FALUKANT_PRODUCTION_CERTIFICATE.md)
|
||||
- `falukant_type.product.category`
|
||||
- erforderliche Zertifikatsstufe des Produkts
|
||||
- `falukant_data.knowledge`
|
||||
@@ -109,7 +110,7 @@ Für jeden Spielercharakter mit `falukant_user`:
|
||||
- `avgKnowledge`
|
||||
- Durchschnitt aus `falukant_data.knowledge.knowledge` des Spielercharakters
|
||||
- `completedProductions`
|
||||
- Anzahl abgeschlossener Produktionen des Spielers
|
||||
- Anzahl abgeschlossener Produktionen des Spielers (Daemon und Backend/UI: aus `falukant_log.production`, gruppiert nach Produkt und Kalendertag, gefiltert ab `certificate_productions_count_since` mit `COALESCE(production_timestamp, production_date::timestamp)`; siehe [`FALUKANT_PRODUCTION_CERTIFICATE.md`](./FALUKANT_PRODUCTION_CERTIFICATE.md))
|
||||
- `highestPoliticalOfficeRank`
|
||||
- höchster politischer Amtsrang
|
||||
- `highestChurchOfficeRank`
|
||||
@@ -317,11 +318,10 @@ Diese Aktionen verändern nur die Eingangsgrößen. Die eigentliche Zertifikatsa
|
||||
|
||||
## 5.2 Daemon-Hinweis
|
||||
|
||||
Für den Daemon gilt ausdrücklich:
|
||||
Für den Daemon gilt:
|
||||
|
||||
- die relevanten DB-Felder sind bereits vorhanden
|
||||
- es müssen für diese Funktion keine zusätzlichen Schemaänderungen mehr eingeplant werden
|
||||
- der Daemon soll direkt mit den vorhandenen Tabellen arbeiten
|
||||
- Zertifikatsstufe und Produktkategorien wie oben; für die Produktionszählung nach Stufenwechsel ist `certificate_productions_count_since` vorgesehen (Migration siehe Repo / [`FALUKANT_PRODUCTION_CERTIFICATE.md`](./FALUKANT_PRODUCTION_CERTIFICATE.md)).
|
||||
- Der Daemon soll dieselbe `COALESCE(production_timestamp, production_date::timestamp)`-Logik wie Backend und UI verwenden, damit Daily-Prüfung und Oberfläche übereinstimmen.
|
||||
|
||||
## 5.3 Empfohlener Daily-Ablauf
|
||||
|
||||
@@ -482,6 +482,6 @@ Fertig ist die erste Version, wenn:
|
||||
|
||||
- nur Produkte mit `product.category <= falukant_user.certificate` produzierbar sind
|
||||
- der Daemon die Zertifikatsprüfung genau einmal täglich ausführt
|
||||
- der Daemon bei Aufstieg das Zertifikat fortschreibt
|
||||
- der Daemon bei Aufstieg das Zertifikat fortschreibt und `certificate_productions_count_since` setzt
|
||||
- die UI auf das Zertifikats-Event gezielt reagiert
|
||||
- keine neuen DB-Änderungen für diese Funktion nötig sind
|
||||
- Backend/UI dieselbe Produktionszählung wie der Daemon verwenden (siehe [`FALUKANT_PRODUCTION_CERTIFICATE.md`](./FALUKANT_PRODUCTION_CERTIFICATE.md))
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"falukant": {
|
||||
"overview": {
|
||||
"certificate": {
|
||||
"productionsSince": "Mga produksyon sugod sa {date} ra ang ihap (sukad sa katapusang pag-asenso, bangkaruta, o panununod).",
|
||||
"factor": {
|
||||
"avgKnowledge": "Average kahibalo",
|
||||
"completedProductions": "Nahuman produksyons",
|
||||
|
||||
@@ -158,6 +158,7 @@
|
||||
},
|
||||
"factors": "Karon nga mga bili",
|
||||
"requirements": "Mga kinahanglanon sa sunod nga level",
|
||||
"productionsSince": "Mga produksyon sugod sa {date} ra ang ihap (sukad sa katapusang pag-asenso, bangkaruta, o panununod).",
|
||||
"factor": {
|
||||
"avgKnowledge": "Average kahibalo",
|
||||
"completedProductions": "Nahuman produksyons",
|
||||
|
||||
@@ -178,6 +178,7 @@
|
||||
},
|
||||
"factors": "Aktuelle Werte",
|
||||
"requirements": "Bedingungen für die nächste Stufe",
|
||||
"productionsSince": "Nur Produktionen ab {date} zählen (seit letztem Aufstieg, Bankrott oder Erbfolge).",
|
||||
"factor": {
|
||||
"avgKnowledge": "Durchschnittliches Wissen",
|
||||
"completedProductions": "Abgeschlossene Produktionen",
|
||||
|
||||
@@ -159,6 +159,7 @@
|
||||
},
|
||||
"factors": "Current values",
|
||||
"requirements": "Requirements for the next level",
|
||||
"productionsSince": "Only productions on or after {date} count (since last promotion, bankruptcy, or succession).",
|
||||
"factor": {
|
||||
"avgKnowledge": "Average knowledge",
|
||||
"completedProductions": "Completed productions",
|
||||
|
||||
@@ -177,6 +177,7 @@
|
||||
},
|
||||
"factors": "Valores actuales",
|
||||
"requirements": "Condiciones para el siguiente nivel",
|
||||
"productionsSince": "Solo cuentan producciones desde el {date} (desde el último ascenso, quiebra o sucesión).",
|
||||
"factor": {
|
||||
"avgKnowledge": "Conocimiento medio",
|
||||
"completedProductions": "Producciones completadas",
|
||||
|
||||
@@ -177,6 +177,7 @@
|
||||
},
|
||||
"factors": "Valeurs actuelles",
|
||||
"requirements": "Conditions pour la prochaine étape",
|
||||
"productionsSince": "Seules les productions à partir du {date} comptent (depuis la dernière promotion, faillite ou succession).",
|
||||
"factor": {
|
||||
"avgKnowledge": "Connaissance moyenne",
|
||||
"completedProductions": "Productions terminées",
|
||||
|
||||
@@ -131,6 +131,16 @@
|
||||
<div class="detail-list__item">
|
||||
<span>{{ $t('falukant.overview.certificate.factor.completedProductions') }}</span>
|
||||
<strong>{{ certificateProgress.currentValues.completedProductions }}</strong>
|
||||
<p
|
||||
v-if="certificateProgress.certificateProductionsCountSince"
|
||||
class="certificate-panel__productions-since"
|
||||
>
|
||||
{{
|
||||
$t('falukant.overview.certificate.productionsSince', {
|
||||
date: formatDate(certificateProgress.certificateProductionsCountSince),
|
||||
})
|
||||
}}
|
||||
</p>
|
||||
</div>
|
||||
<div class="detail-list__item">
|
||||
<span>{{ $t('falukant.overview.certificate.factor.reputation') }}</span>
|
||||
@@ -907,6 +917,13 @@ export default {
|
||||
color: var(--color-text-secondary);
|
||||
}
|
||||
|
||||
.certificate-panel__productions-since {
|
||||
margin: 6px 0 0;
|
||||
font-size: 0.85rem;
|
||||
line-height: 1.35;
|
||||
color: var(--color-text-secondary);
|
||||
}
|
||||
|
||||
.certificate-panel__grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
|
||||
@@ -194,8 +194,12 @@ void ProduceWorker::addProductionToLog(int regionId, int userId, int productId,
|
||||
ConnectionGuard connGuard(pool);
|
||||
auto &db = connGuard.get();
|
||||
db.prepare("QUERY_INSERT_UPDATE_PRODUCTION_LOG", QUERY_INSERT_UPDATE_PRODUCTION_LOG);
|
||||
db.execute("QUERY_INSERT_UPDATE_PRODUCTION_LOG", { std::to_string(regionId), std::to_string(productId),
|
||||
std::to_string(productId), std::to_string(userId) });
|
||||
db.execute("QUERY_INSERT_UPDATE_PRODUCTION_LOG", {
|
||||
std::to_string(regionId),
|
||||
std::to_string(productId),
|
||||
std::to_string(quantity),
|
||||
std::to_string(userId),
|
||||
});
|
||||
} catch (const std::exception &e) {
|
||||
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ void UserCharacterWorker::run() {
|
||||
processCharacterEvents();
|
||||
updateCharactersMood();
|
||||
handleCredits();
|
||||
deleteOldProductionLogs();
|
||||
} catch (const std::exception &e) {
|
||||
std::cerr << "[UserCharacterWorker] Fehler in processCharacterEvents: " << e.what() << std::endl;
|
||||
}
|
||||
@@ -233,6 +234,17 @@ void UserCharacterWorker::setNewMoney(int falukantUserId, double newAmount) {
|
||||
});
|
||||
}
|
||||
|
||||
void UserCharacterWorker::deleteOldProductionLogs() {
|
||||
try {
|
||||
ConnectionGuard connGuard(pool);
|
||||
auto &db = connGuard.get();
|
||||
db.prepare("QUERY_DELETE_OLD_PRODUCTIONS", QUERY_DELETE_OLD_PRODUCTIONS);
|
||||
db.execute("QUERY_DELETE_OLD_PRODUCTIONS");
|
||||
} catch (const std::exception &e) {
|
||||
std::cerr << "[UserCharacterWorker] Fehler in deleteOldProductionLogs: " << e.what() << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void UserCharacterWorker::recalculateKnowledge() {
|
||||
setCurrentStep("Get character data");
|
||||
ConnectionGuard connGuard(pool);
|
||||
|
||||
@@ -25,6 +25,7 @@ private:
|
||||
int calculateHealthChange(int age);
|
||||
void handleCharacterDeath(int characterId);
|
||||
void recalculateKnowledge();
|
||||
void deleteOldProductionLogs();
|
||||
void processPregnancies();
|
||||
void handleCredits();
|
||||
void setHeir(int characterId);
|
||||
@@ -61,7 +62,13 @@ private:
|
||||
static constexpr const char *QUERY_UPDATE_GET_ITEMS_TO_UPDATE = R"(
|
||||
SELECT id, product_id, producer_id, quantity
|
||||
FROM falukant_log.production p
|
||||
WHERE p.production_timestamp::date < current_date
|
||||
WHERE (COALESCE(p.production_timestamp, p.production_date::timestamp))::date < CURRENT_DATE
|
||||
)";
|
||||
|
||||
/** Log-Retention: ältere Zeilen entfernen (Daemon/UI-Zertifikatszählung braucht Historie nur begrenzt). */
|
||||
static constexpr const char *QUERY_DELETE_OLD_PRODUCTIONS = R"(
|
||||
DELETE FROM falukant_log.production
|
||||
WHERE COALESCE(production_timestamp, production_date::timestamp) < NOW() - INTERVAL '30 days'
|
||||
)";
|
||||
|
||||
static constexpr const char *QUERY_UPDATE_GET_CHARACTER_IDS = R"(
|
||||
|
||||
@@ -71,8 +71,10 @@ void ValueRecalculationWorker::calculateProductKnowledge() {
|
||||
const auto userId = std::stoi(user.at("producer_id"));
|
||||
sendMessageToFalukantUsers(userId, message);
|
||||
}
|
||||
db.prepare("QUERY_DELETE_OLD_PRODUCTIONS", QUERY_DELETE_OLD_PRODUCTIONS);
|
||||
db.execute("QUERY_DELETE_OLD_PRODUCTIONS");
|
||||
/* Kein DELETE mehr auf falukant_log.production um Mitternacht: Die Einträge werden für
|
||||
* Zertifikatsfortschritt (Backend + Daemon) benötigt.
|
||||
* UserCharacterWorker: nach Wissens-Update pro Zeile löschen; zusätzlich stündlich Retention
|
||||
* QUERY_DELETE_OLD_PRODUCTIONS (30 Tage, COALESCE(timestamp, production_date)). */
|
||||
}
|
||||
|
||||
void ValueRecalculationWorker::calculateRegionalSellPrice() {
|
||||
|
||||
@@ -42,21 +42,16 @@ private:
|
||||
SET knowledge = LEAST(100, k.knowledge + 1)
|
||||
FROM falukant_data."character" c
|
||||
JOIN falukant_log.production p
|
||||
ON DATE(p.production_timestamp) = CURRENT_DATE - INTERVAL '1 day'
|
||||
ON DATE(COALESCE(p.production_timestamp, p.production_date::timestamp)) = CURRENT_DATE - INTERVAL '1 day'
|
||||
WHERE c.id = k.character_id
|
||||
AND c.user_id = 18
|
||||
AND k.product_id = 10
|
||||
)";
|
||||
|
||||
static constexpr const char *QUERY_DELETE_OLD_PRODUCTIONS = R"(
|
||||
delete from falukant_log.production flp
|
||||
where date(flp.production_timestamp) < CURRENT_DATE
|
||||
)";
|
||||
|
||||
static constexpr const char *QUERY_GET_PRODUCERS_LAST_DAY = R"(
|
||||
select p."producer_id"
|
||||
from falukant_log.production p
|
||||
where date(p."production_timestamp") = CURRENT_DATE - interval '1 day'
|
||||
where date(COALESCE(p.production_timestamp, p.production_date::timestamp)) = CURRENT_DATE - interval '1 day'
|
||||
group by producer_id
|
||||
)";
|
||||
|
||||
|
||||
Reference in New Issue
Block a user