From be7db6ad96cd3abf30e4d00321ab1f85c0f4c1c9 Mon Sep 17 00:00:00 2001 From: "Torsten Schulz (local)" Date: Sat, 14 Feb 2026 16:12:07 +0100 Subject: [PATCH] =?UTF-8?q?Verbessere=20die=20Berechnung=20der=20Geschenke?= =?UTF-8?q?kosten=20in=20FalukantService=20und=20f=C3=BCge=20Tests=20f?= =?UTF-8?q?=C3=BCr=20die=20Funktion=20hinzu?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/services/falukantService.js | 37 +++++++++++++++++--------- backend/tools/simulate_getGiftCost.js | 20 ++++++++++++++ backend/tools/testGiftCost.js | 38 +++++++++++++++++++++++++++ 3 files changed, 82 insertions(+), 13 deletions(-) create mode 100644 backend/tools/simulate_getGiftCost.js create mode 100644 backend/tools/testGiftCost.js diff --git a/backend/services/falukantService.js b/backend/services/falukantService.js index d2c4d9e..4fdc7a6 100644 --- a/backend/services/falukantService.js +++ b/backend/services/falukantService.js @@ -3112,17 +3112,24 @@ class FalukantService extends BaseService { // 5) Rest wie gehabt: Kosten berechnen und zurückgeben const lowestTitleOfNobility = await TitleOfNobility.findOne({ order: [['id', 'ASC']] }); - return Promise.all(gifts.map(async gift => ({ - id: gift.id, - name: gift.name, - cost: await this.getGiftCost( - gift.value, - myChar.titleOfNobility, - lowestTitleOfNobility.id - ), - moodsAffects: gift.promotionalgiftmoods, // nur Einträge mit relatedMoodId - charactersAffects: gift.characterTraits // nur Einträge mit relatedTraitIds - }))); + // Sicherstellen, dass wir eine gültige titleOfNobility haben (getFalukantUserByHashedId liefert nicht immer das Feld) + let characterTitleOfNobility = myChar.titleOfNobility; + if (characterTitleOfNobility == null && myChar.id) { + const reloadChar = await FalukantCharacter.findOne({ where: { id: myChar.id }, attributes: ['titleOfNobility'] }); + characterTitleOfNobility = reloadChar?.titleOfNobility ?? lowestTitleOfNobility?.id ?? 1; + } + + return Promise.all(gifts.map(async gift => { + const value = typeof gift.value === 'number' ? gift.value : (gift.value ? Number(gift.value) : 0); + const cost = await this.getGiftCost(value, characterTitleOfNobility, lowestTitleOfNobility?.id ?? 1); + return { + id: gift.id, + name: gift.name, + cost, + moodsAffects: gift.promotionalgiftmoods, // nur Einträge mit relatedMoodId + charactersAffects: gift.characterTraits // nur Einträge mit relatedTraitIds + }; + })); } async getChildren(hashedUserId) { @@ -3279,8 +3286,12 @@ class FalukantService extends BaseService { } async getGiftCost(value, titleOfNobility, lowestTitleOfNobility) { - const titleLevel = titleOfNobility - lowestTitleOfNobility + 1; - return Math.round(value * Math.pow(1 + titleLevel * 0.3, 1.3) * 100) / 100; + const val = Number(value) || 0; + const title = Number(titleOfNobility) || 1; + const lowest = Number(lowestTitleOfNobility) || 1; + const titleLevel = title - lowest + 1; + const cost = Math.round(val * Math.pow(1 + titleLevel * 0.3, 1.3) * 100) / 100; + return Number.isFinite(cost) ? cost : 0; } async getTitlesOfNobility() { diff --git a/backend/tools/simulate_getGiftCost.js b/backend/tools/simulate_getGiftCost.js new file mode 100644 index 0000000..2f149e6 --- /dev/null +++ b/backend/tools/simulate_getGiftCost.js @@ -0,0 +1,20 @@ +function getGiftCostLocal(value, titleOfNobility, lowestTitleOfNobility) { + const val = Number(value) || 0; + const title = Number(titleOfNobility) || 1; + const lowest = Number(lowestTitleOfNobility) || 1; + const titleLevel = title - lowest + 1; + const cost = Math.round(val * Math.pow(1 + titleLevel * 0.3, 1.3) * 100) / 100; + return Number.isFinite(cost) ? cost : 0; +} + +const cases = [ + { giftValue: 100, title: 3, lowest: 1 }, + { giftValue: '200', title: '2', lowest: '1' }, + { giftValue: null, title: null, lowest: null }, + { giftValue: undefined, title: undefined, lowest: undefined }, + { giftValue: 'abc', title: 5, lowest: 1 } +]; + +for (const c of cases) { + console.log(`in=${JSON.stringify(c)} -> cost=${getGiftCostLocal(c.giftValue, c.title, c.lowest)}`); +} diff --git a/backend/tools/testGiftCost.js b/backend/tools/testGiftCost.js new file mode 100644 index 0000000..389f838 --- /dev/null +++ b/backend/tools/testGiftCost.js @@ -0,0 +1,38 @@ +import { fileURLToPath } from 'url'; +import path from 'path'; +import { readFileSync } from 'fs'; + +// Kleine Testhilfe: extrahiere getGiftCost aus service-file via eval (schneller Smoke-test ohne DB) +const svcPath = path.resolve(process.cwd(), 'services', 'falukantService.js'); +const src = readFileSync(svcPath, 'utf8'); + +// Extrahiere die getGiftCost-Funktion via Regex (vereinfachte Annahme) +const re = /async getGiftCost\([\s\S]*?\n\s*}\n/; +const match = src.match(re); +if (!match) { + console.error('getGiftCost function not found'); + process.exit(2); +} +const funcSrc = match[0]; +// Wrappe in Async-Function und erzeuge getGiftCost im lokalen Scope +const wrapper = `(async () => { ${funcSrc}; return getGiftCost; })()`; +// eslint-disable-next-line no-eval +const getGiftCostPromise = eval(wrapper); +let getGiftCost; +getGiftCostPromise.then(f => { getGiftCost = f; runTests(); }).catch(e => { console.error('eval failed', e); process.exit(2); }); + +function runTests() { + const cases = [ + { value: 100, title: 3, lowest: 1 }, + { value: '200', title: '2', lowest: '1' }, + { value: null, title: null, lowest: null }, + { value: 'abc', title: 5, lowest: 1 } + ]; + + for (const c of cases) { + getGiftCost(c.value, c.title, c.lowest).then(out => { + console.log(`in=${JSON.stringify(c)} -> cost=${out}`); + }).catch(err => console.error('error calling getGiftCost', err)); + } +} +// Ende Patch