From c80cc8ec86af65f17b72e66147951f69486a8312 Mon Sep 17 00:00:00 2001 From: "Torsten Schulz (local)" Date: Fri, 9 Jan 2026 14:32:27 +0100 Subject: [PATCH] Enhance logging and error handling in FalukantService and FamilyView - Added detailed logging for partner search and creation processes in FalukantService to improve traceability and debugging. - Refactored the partner search logic to use a dynamic where clause for better readability and maintainability. - Implemented error handling in FamilyView's loadGifts method to ensure an empty array is returned on API errors, enhancing user experience. --- backend/services/falukantService.js | 105 +++++++++++++++------ frontend/src/views/falukant/FamilyView.vue | 9 +- 2 files changed, 81 insertions(+), 33 deletions(-) diff --git a/backend/services/falukantService.js b/backend/services/falukantService.js index 8673f24..5ee319b 100644 --- a/backend/services/falukantService.js +++ b/backend/services/falukantService.js @@ -2902,9 +2902,12 @@ class FalukantService extends BaseService { possiblePartners: [] }; const ownAge = calcAge(character.birthdate); + console.log(`[getFamily] Character age: ${ownAge}, relationships: ${family.relationships.length}`); if (ownAge >= 12 && family.relationships.length === 0) { family.possiblePartners = await this.getPossiblePartners(character.id); + console.log(`[getFamily] Found ${family.possiblePartners.length} existing proposals`); if (family.possiblePartners.length === 0) { + console.log(`[getFamily] Creating new possible partners...`); await this.createPossiblePartners( character.id, character.gender, @@ -2913,7 +2916,10 @@ class FalukantService extends BaseService { ownAge ); family.possiblePartners = await this.getPossiblePartners(character.id); + console.log(`[getFamily] After creation: ${family.possiblePartners.length} proposals`); } + } else { + console.log(`[getFamily] Skipping partner search: age=${ownAge}, relationships=${family.relationships.length}`); } return family; } @@ -3175,29 +3181,54 @@ class FalukantService extends BaseService { } const minTitle = minTitleResult.id; + // Logging für Debugging + console.log(`[createPossiblePartners] Searching for partners:`, { + requestingCharacterId, + requestingCharacterGender, + requestingRegionId, + requestingCharacterTitleOfNobility, + ownAge + }); + + const whereClause = { + id: { [Op.ne]: requestingCharacterId }, + gender: { [Op.ne]: requestingCharacterGender }, + regionId: requestingRegionId, + createdAt: { [Op.lt]: new Date(new Date() - 12 * 24 * 60 * 60 * 1000) }, + titleOfNobility: { [Op.between]: [Math.max(1, requestingCharacterTitleOfNobility - 1), requestingCharacterTitleOfNobility + 1] } + }; + + // Nur NPCs suchen (userId ist null) + whereClause.userId = null; + + console.log(`[createPossiblePartners] Where clause:`, JSON.stringify(whereClause, null, 2)); + const potentialPartners = await FalukantCharacter.findAll({ - where: { - id: { [Op.ne]: requestingCharacterId }, - gender: { [Op.ne]: requestingCharacterGender }, - regionId: requestingRegionId, - createdAt: { [Op.lt]: new Date(new Date() - 12 * 24 * 60 * 60 * 1000) }, - titleOfNobility: { [Op.between]: [requestingCharacterTitleOfNobility - 1, requestingCharacterTitleOfNobility + 1] } - }, + where: whereClause, order: [ [Sequelize.literal(`ABS((EXTRACT(EPOCH FROM (NOW() - "birthdate")) / 86400) - ${ownAge})`), 'ASC'] ], limit: 5, }); + console.log(`[createPossiblePartners] Found ${potentialPartners.length} potential partners`); + + if (potentialPartners.length === 0) { + console.warn(`[createPossiblePartners] No partners found with criteria. Consider creating NPCs.`); + return; // Keine Partner gefunden, aber kein Fehler + } + const proposals = potentialPartners.map(partner => { const age = calcAge(partner.birthdate); return { requesterCharacterId: requestingCharacterId, proposedCharacterId: partner.id, - cost: calculateMarriageCost(partner.titleOfNobility, age, minTitle), + cost: calculateMarriageCost(partner.titleOfNobility, age), }; }); + await MarriageProposal.bulkCreate(proposals); + console.log(`[createPossiblePartners] Created ${proposals.length} marriage proposals`); } catch (error) { console.error('Error creating possible partners:', error); throw error; @@ -3250,7 +3281,7 @@ class FalukantService extends BaseService { const myChar = await FalukantCharacter.findOne({ where: { userId: user.id } }); if (!myChar) throw new Error('Character not found'); - // 2) Beziehung finden und „anderen“ Character bestimmen + // 2) Beziehung finden und „anderen" Character bestimmen const rel = await Relationship.findOne({ where: { [Op.or]: [ @@ -3263,32 +3294,44 @@ class FalukantService extends BaseService { { model: FalukantCharacter, as: 'character2', include: [{ model: CharacterTrait, as: 'traits' }] } ] }); - if (!rel) throw new Error('Beziehung nicht gefunden'); - const relatedChar = rel.character1.id === myChar.id ? rel.character2 : rel.character1; + // 3) Wenn keine Beziehung gefunden, alle Gifts ohne Filter zurückgeben + let relatedTraitIds = []; + let relatedMoodId = null; - // 3) Trait-IDs und Mood des relatedChar - const relatedTraitIds = relatedChar.traits.map(t => t.id); - const relatedMoodId = relatedChar.moodId; + if (rel) { + const relatedChar = rel.character1.id === myChar.id ? rel.character2 : rel.character1; + // Trait-IDs und Mood des relatedChar + relatedTraitIds = relatedChar.traits ? relatedChar.traits.map(t => t.id) : []; + relatedMoodId = relatedChar.moodId; + } + + // 4) Gifts laden – mit Mood/Trait-Filter nur wenn Beziehung existiert + const giftIncludes = [ + { + model: PromotionalGiftMood, + as: 'promotionalgiftmoods', + attributes: ['mood_id', 'suitability'], + required: false + }, + { + model: PromotionalGiftCharacterTrait, + as: 'characterTraits', + attributes: ['trait_id', 'suitability'], + required: false + } + ]; + + // Wenn Beziehung existiert, Filter anwenden + if (rel && relatedMoodId) { + giftIncludes[0].where = { mood_id: relatedMoodId }; + } + if (rel && relatedTraitIds.length > 0) { + giftIncludes[1].where = { trait_id: relatedTraitIds }; + } - // 4) Gifts laden – aber nur die passenden Moods und Traits als Unter-Arrays const gifts = await PromotionalGift.findAll({ - include: [ - { - model: PromotionalGiftMood, - as: 'promotionalgiftmoods', - attributes: ['mood_id', 'suitability'], - where: { mood_id: relatedMoodId }, - required: false // Gifts ohne Mood-Match bleiben erhalten, haben dann leeres Array - }, - { - model: PromotionalGiftCharacterTrait, - as: 'characterTraits', - attributes: ['trait_id', 'suitability'], - where: { trait_id: relatedTraitIds }, - required: false // Gifts ohne Trait-Match bleiben erhalten - } - ] + include: giftIncludes }); // 5) Rest wie gehabt: Kosten berechnen und zurückgeben diff --git a/frontend/src/views/falukant/FamilyView.vue b/frontend/src/views/falukant/FamilyView.vue index 62842c1..8692286 100644 --- a/frontend/src/views/falukant/FamilyView.vue +++ b/frontend/src/views/falukant/FamilyView.vue @@ -295,8 +295,13 @@ export default { }, async loadGifts() { - const response = await apiClient.get('/api/falukant/family/gifts'); - this.gifts = response.data; + try { + const response = await apiClient.get('/api/falukant/family/gifts'); + this.gifts = response.data || []; + } catch (error) { + console.error('Error loading gifts:', error); + this.gifts = []; // Leeres Array bei Fehler + } }, async sendGift() {