오류 수정, 통계 보강
This commit is contained in:
@@ -5,6 +5,7 @@
|
||||
const { Event, EventParticipant, Member, Club, EventScore, ClubMember, EventTeam, EventTeamMember } = require('../models');
|
||||
const { Op } = require('sequelize');
|
||||
const { sequelize } = require('../models');
|
||||
const averageService = require('../services/averageService');
|
||||
|
||||
// 이벤트 목록 조회
|
||||
exports.getAllEvents = async (req, res) => {
|
||||
@@ -18,7 +19,7 @@ exports.getAllEvents = async (req, res) => {
|
||||
const events = await Event.findAll({
|
||||
where: {
|
||||
clubId,
|
||||
status: { [Op.ne]: '삭제' }
|
||||
status: { [Op.ne]: 'deleted' }
|
||||
},
|
||||
include: [
|
||||
{
|
||||
@@ -29,7 +30,7 @@ exports.getAllEvents = async (req, res) => {
|
||||
model: EventParticipant,
|
||||
attributes: ['id', 'status', 'paymentStatus'],
|
||||
where: {
|
||||
status: { [Op.ne]: '취소' }
|
||||
status: { [Op.ne]: 'canceled' }
|
||||
},
|
||||
required: false,
|
||||
include: [{
|
||||
@@ -69,7 +70,7 @@ exports.getEventById = async (req, res) => {
|
||||
const event = await Event.findOne({
|
||||
where: {
|
||||
id: eventId,
|
||||
status: { [Op.ne]: '삭제' }
|
||||
status: { [Op.ne]: 'deleted' }
|
||||
},
|
||||
include: [
|
||||
{
|
||||
@@ -79,12 +80,12 @@ exports.getEventById = async (req, res) => {
|
||||
{
|
||||
model: EventParticipant,
|
||||
attributes: ['id', 'status', 'paymentStatus'],
|
||||
where: { status: { [Op.ne]: '취소' } },
|
||||
where: { status: { [Op.ne]: 'canceled' } },
|
||||
required: false,
|
||||
include: [
|
||||
{
|
||||
model: Member,
|
||||
attributes: ['id', 'name', 'average']
|
||||
attributes: ['id', 'name']
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -95,10 +96,48 @@ exports.getEventById = async (req, res) => {
|
||||
return res.status(404).json({ message: '이벤트를 찾을 수 없습니다.' });
|
||||
}
|
||||
|
||||
const eventData = event.toJSON();
|
||||
|
||||
// 참가자들의 동적 에버리지 계산
|
||||
if (eventData.participants && eventData.participants.length > 0) {
|
||||
const participantsWithDynamicAverage = await Promise.all(
|
||||
eventData.participants.map(async (participant) => {
|
||||
if (participant.Member && participant.Member.id) {
|
||||
try {
|
||||
const averageData = await averageService.calculateMemberAverageByClubSetting(
|
||||
participant.Member.id,
|
||||
eventData.clubId
|
||||
);
|
||||
|
||||
return {
|
||||
...participant,
|
||||
Member: {
|
||||
...participant.Member,
|
||||
average: averageData.average
|
||||
}
|
||||
};
|
||||
} catch (error) {
|
||||
console.error(`회원 ${participant.Member.id}의 에버리지 계산 오류:`, error);
|
||||
return {
|
||||
...participant,
|
||||
Member: {
|
||||
...participant.Member,
|
||||
average: 0
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
return participant;
|
||||
})
|
||||
);
|
||||
|
||||
eventData.participants = participantsWithDynamicAverage;
|
||||
}
|
||||
|
||||
const formattedEvent = {
|
||||
...event.toJSON(),
|
||||
participantCount: event.participants ? event.participants.length : 0,
|
||||
clubName: event.Club ? event.Club.name : ''
|
||||
...eventData,
|
||||
participantCount: eventData.participants ? eventData.participants.length : 0,
|
||||
clubName: eventData.Club ? eventData.Club.name : ''
|
||||
};
|
||||
|
||||
res.json(formattedEvent);
|
||||
@@ -224,28 +263,80 @@ exports.getEventByPublicHash = async (req, res) => {
|
||||
// 3. 전체 회원 명단 추출 (clubId 사용, clubId는 응답에 포함 X)
|
||||
const allMembers = await Member.findAll({
|
||||
where: { clubId: event.clubId },
|
||||
attributes: [[sequelize.col('id'), 'memberId'], 'name', 'memberType', 'gender', 'average']
|
||||
attributes: [[sequelize.col('id'), 'memberId'], 'name', 'memberType', 'gender']
|
||||
});
|
||||
|
||||
// 전체 회원의 동적 에버리지 계산
|
||||
const allMembersWithAverage = await Promise.all(
|
||||
allMembers.map(async (member) => {
|
||||
try {
|
||||
const averageData = await averageService.calculateMemberAverageByClubSetting(
|
||||
member.dataValues.memberId,
|
||||
event.clubId
|
||||
);
|
||||
return {
|
||||
...member.dataValues,
|
||||
average: averageData.average
|
||||
};
|
||||
} catch (error) {
|
||||
console.error(`회원 ${member.dataValues.memberId}의 에버리지 계산 오류:`, error);
|
||||
return {
|
||||
...member.dataValues,
|
||||
average: 0
|
||||
};
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
// 4. 참가자 명단 추출 (참가자 테이블 + Member 조인)
|
||||
const participants = await EventParticipant.findAll({
|
||||
where: { eventId: event.id, status: { [Op.ne]: '취소' } },
|
||||
where: { eventId: event.id, status: { [Op.ne]: 'canceled' } },
|
||||
include: [
|
||||
{ model: Member, attributes: [[sequelize.col('id'), 'memberId'], 'name', 'memberType', 'gender', 'average'] }
|
||||
{ model: Member, attributes: [[sequelize.col('id'), 'memberId'], 'name', 'memberType', 'gender'] }
|
||||
]
|
||||
});
|
||||
|
||||
// 참가자들의 동적 에버리지 계산
|
||||
const participantsWithAverage = await Promise.all(
|
||||
participants.map(async (participant) => {
|
||||
if (participant.Member && participant.Member.dataValues.memberId) {
|
||||
try {
|
||||
const averageData = await averageService.calculateMemberAverageByClubSetting(
|
||||
participant.Member.dataValues.memberId,
|
||||
event.clubId
|
||||
);
|
||||
|
||||
// 기존 객체 복사
|
||||
const participantObj = {...participant.dataValues};
|
||||
participantObj.Member = {
|
||||
...participant.Member.dataValues,
|
||||
average: averageData.average
|
||||
};
|
||||
|
||||
return participantObj;
|
||||
} catch (error) {
|
||||
console.error(`참가자 회원 ${participant.Member.dataValues.memberId}의 에버리지 계산 오류:`, error);
|
||||
const participantObj = {...participant.dataValues};
|
||||
participantObj.Member = {
|
||||
...participant.Member.dataValues,
|
||||
average: 0
|
||||
};
|
||||
return participantObj;
|
||||
}
|
||||
}
|
||||
return participant.dataValues;
|
||||
})
|
||||
);
|
||||
// 5. 참가 신청 가능 명단(아직 참가하지 않은 회원)
|
||||
// Sequelize 인스턴스에서 dataValues 추출
|
||||
const allMemberObjs = allMembers.map(m => m.dataValues);
|
||||
// '취소'가 아닌 status가 하나라도 있으면 참가자로 간주 (중복 제거)
|
||||
const participantMemberIds = [
|
||||
...new Set(
|
||||
participants
|
||||
.filter(p => p.dataValues.status !== '취소')
|
||||
.map(p => parseInt(p.dataValues.memberId))
|
||||
participantsWithAverage
|
||||
.filter(p => p.status !== '취소')
|
||||
.map(p => parseInt(p.memberId))
|
||||
)
|
||||
];
|
||||
const availableMembers = allMemberObjs.filter(m => !participantMemberIds.includes(parseInt(m.memberId)));
|
||||
const availableMembers = allMembersWithAverage.filter(m => !participantMemberIds.includes(parseInt(m.memberId)));
|
||||
// 6. 팀 정보 등 추가 조회 (기존 코드 유지)
|
||||
const teams = await EventTeam.findAll({
|
||||
where: { eventId: event.id },
|
||||
@@ -256,7 +347,7 @@ exports.getEventByPublicHash = async (req, res) => {
|
||||
include: [
|
||||
{
|
||||
model: EventParticipant,
|
||||
include: [{ model: Member, attributes: [[sequelize.col('id'), 'memberId'], 'name', 'memberType', 'gender', 'handicap', 'average'] }]
|
||||
include: [{ model: Member, attributes: [[sequelize.col('id'), 'memberId'], 'name', 'memberType', 'gender', 'handicap'] }]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -269,35 +360,60 @@ exports.getEventByPublicHash = async (req, res) => {
|
||||
// 팀별 그룹핑
|
||||
let teamList = [];
|
||||
if (teams.length > 0) {
|
||||
teamList = teams.map(team => ({
|
||||
teamId: team.id,
|
||||
teamNumber: team.teamNumber,
|
||||
handicap: team.handicap,
|
||||
members: (team.EventTeamMembers || []).map(tm => {
|
||||
// 팀 리스트 처리
|
||||
const teamsWithMembers = [];
|
||||
for (const team of teams) {
|
||||
const membersWithAverage = [];
|
||||
for (const tm of (team.EventTeamMembers || [])) {
|
||||
const participant = tm.EventParticipant;
|
||||
const member = participant?.Member;
|
||||
const scoreObj = scores.find(s => s.participantId === participant?.id);
|
||||
return {
|
||||
|
||||
// 회원의 동적 에버리지 계산
|
||||
let dynamicAverage = 0;
|
||||
if (member && member.memberId) {
|
||||
try {
|
||||
const averageData = await averageService.calculateMemberAverageByClubSetting(
|
||||
member.memberId,
|
||||
event.clubId
|
||||
);
|
||||
dynamicAverage = averageData.average;
|
||||
} catch (error) {
|
||||
console.error(`팀 멤버 ${member.memberId}의 에버리지 계산 오류:`, error);
|
||||
}
|
||||
}
|
||||
|
||||
membersWithAverage.push({
|
||||
participantId: participant?.id,
|
||||
memberId: member?.memberId,
|
||||
name: member?.name || `참가자 ${participant?.id}`,
|
||||
gender: member?.gender,
|
||||
memberType: member?.memberType,
|
||||
average: member?.average || 0,
|
||||
average: dynamicAverage,
|
||||
handicap: member?.handicap || 0,
|
||||
status: participant?.status,
|
||||
paymentStatus: participant?.paymentStatus,
|
||||
comment: participant?.comment,
|
||||
isGuest: member?.memberType === '게스트',
|
||||
score: scoreObj ? scoreObj.score : null
|
||||
};
|
||||
})
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
teamsWithMembers.push({
|
||||
teamId: team.id,
|
||||
teamNumber: team.teamNumber,
|
||||
handicap: team.handicap,
|
||||
members: membersWithAverage
|
||||
});
|
||||
}
|
||||
|
||||
teamList = teamsWithMembers;
|
||||
}
|
||||
|
||||
// 참가자 리스트(팀 없는 경우)
|
||||
let participantList = [];
|
||||
participantList = participants.map(p => {
|
||||
// 참가자들의 동적 에버리지 계산
|
||||
participantList = participantsWithAverage.map(p => {
|
||||
const member = p.Member;
|
||||
const scoreObj = scores.find(s => s.participantId === p.id);
|
||||
return {
|
||||
@@ -307,7 +423,7 @@ exports.getEventByPublicHash = async (req, res) => {
|
||||
gender: member?.gender,
|
||||
memberType: member?.memberType,
|
||||
handicap: member?.handicap || 0,
|
||||
average: member?.average || 0,
|
||||
average: member?.average || 0, // 이미 participantsWithAverage에서 동적 계산된 값
|
||||
status: p.status,
|
||||
paymentStatus: p.paymentStatus,
|
||||
comment: p.comment,
|
||||
@@ -507,7 +623,7 @@ exports.updateEvent = async (req, res) => {
|
||||
model: EventParticipant,
|
||||
attributes: ['id', 'status'],
|
||||
where: {
|
||||
status: { [Op.ne]: '취소' }
|
||||
status: { [Op.ne]: 'canceled' }
|
||||
},
|
||||
required: false
|
||||
}
|
||||
@@ -567,7 +683,7 @@ exports.deleteEvent = async (req, res) => {
|
||||
{
|
||||
where: {
|
||||
eventId,
|
||||
status: { [Op.ne]: '취소' }
|
||||
status: { [Op.ne]: 'canceled' }
|
||||
}
|
||||
}
|
||||
);
|
||||
@@ -669,7 +785,7 @@ exports.addEventScore = async (req, res) => {
|
||||
where: {
|
||||
id: participantId,
|
||||
eventId,
|
||||
status: { [Op.ne]: '취소' }
|
||||
status: { [Op.ne]: 'canceled' }
|
||||
}
|
||||
});
|
||||
|
||||
@@ -733,6 +849,9 @@ exports.addEventScore = async (req, res) => {
|
||||
average: averageScore
|
||||
});
|
||||
|
||||
// 점수 등록 후 에버리지 캐시 무효화
|
||||
await averageService.invalidateMemberAverageCache(participant.memberId);
|
||||
|
||||
res.status(201).json({
|
||||
message: '점수가 등록되었습니다.',
|
||||
score: {
|
||||
@@ -762,11 +881,7 @@ exports.updateEventScore = async (req, res) => {
|
||||
score,
|
||||
handicap = 0
|
||||
} = req.body;
|
||||
|
||||
console.log('Updating score:', {
|
||||
params: { eventId, scoreId },
|
||||
body: { gameNumber, score, handicap }
|
||||
});
|
||||
|
||||
|
||||
if (!eventId || !scoreId || !gameNumber || score === undefined || score === null) {
|
||||
return res.status(400).json({
|
||||
@@ -821,6 +936,9 @@ exports.updateEventScore = async (req, res) => {
|
||||
totalScore: score + handicap
|
||||
});
|
||||
|
||||
// 캐시 무효화 추가
|
||||
await averageService.invalidateMemberAverageCache(scoreRecord.participantId);
|
||||
|
||||
// 업데이트된 레코드 조회
|
||||
const updatedScore = await EventScore.findOne({
|
||||
where: {
|
||||
@@ -835,10 +953,10 @@ exports.updateEventScore = async (req, res) => {
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.error('점수 수정 오류:', error);
|
||||
console.error('점수 수정 오류:', error, JSON.stringify(error, Object.getOwnPropertyNames(error)));
|
||||
res.status(500).json({
|
||||
message: '점수 수정 중 오류가 발생했습니다.',
|
||||
error: error.message
|
||||
error: error.message || error.toString() || error
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -891,6 +1009,16 @@ exports.deleteEventScore = async (req, res) => {
|
||||
|
||||
await score.destroy();
|
||||
|
||||
// 점수 삭제 시 해당 회원의 에버리지 캡시 무효화
|
||||
if (score.participant && score.participant.Member) {
|
||||
try {
|
||||
await averageService.invalidateMemberAverageCache(score.participant.Member.id);
|
||||
console.log(`회원 ${score.participant.Member.id}의 에버리지 캡시 무효화 완료`);
|
||||
} catch (error) {
|
||||
console.error(`회원 ${score.participant.Member.id}의 에버리지 캡시 무효화 오류:`, error);
|
||||
}
|
||||
}
|
||||
|
||||
res.json({
|
||||
message: '점수가 삭제되었습니다.',
|
||||
score: {
|
||||
@@ -1057,7 +1185,7 @@ exports.registerForEvent = async (req, res) => {
|
||||
where: {
|
||||
eventId,
|
||||
userId,
|
||||
status: { [Op.ne]: '취소' }
|
||||
status: { [Op.ne]: 'canceled' }
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1094,7 +1222,7 @@ exports.removeParticipant = async (req, res) => {
|
||||
where: {
|
||||
eventId,
|
||||
userId,
|
||||
status: { [Op.ne]: '취소' }
|
||||
status: { [Op.ne]: 'canceled' }
|
||||
},
|
||||
include: [{
|
||||
model: Event,
|
||||
@@ -1132,7 +1260,7 @@ exports.updateParticipantStatus = async (req, res) => {
|
||||
where: {
|
||||
eventId,
|
||||
userId,
|
||||
status: { [Op.ne]: '취소' }
|
||||
status: { [Op.ne]: 'canceled' }
|
||||
},
|
||||
include: [{
|
||||
model: Event,
|
||||
@@ -1233,12 +1361,12 @@ exports.getEventParticipants = async (req, res) => {
|
||||
const participants = await EventParticipant.findAll({
|
||||
where: {
|
||||
eventId,
|
||||
status: { [Op.ne]: '취소' }
|
||||
status: { [Op.ne]: 'canceled' }
|
||||
},
|
||||
include: [
|
||||
{
|
||||
model: Member,
|
||||
attributes: ['id', 'name', 'email', 'phone', 'memberType', 'average']
|
||||
attributes: ['id', 'name', 'email', 'phone', 'memberType']
|
||||
}
|
||||
],
|
||||
order: [
|
||||
@@ -1246,13 +1374,42 @@ exports.getEventParticipants = async (req, res) => {
|
||||
]
|
||||
});
|
||||
|
||||
const formattedParticipants = participants.map(participant => ({
|
||||
...participant.toJSON(),
|
||||
}));
|
||||
// 참가자들의 동적 에버리지 계산
|
||||
const participantsWithAverage = await Promise.all(
|
||||
participants.map(async (participant) => {
|
||||
const participantData = participant.toJSON();
|
||||
if (participantData.Member && participantData.Member.id) {
|
||||
try {
|
||||
const averageData = await averageService.calculateMemberAverageByClubSetting(
|
||||
participantData.Member.id,
|
||||
clubId
|
||||
);
|
||||
|
||||
return {
|
||||
...participantData,
|
||||
Member: {
|
||||
...participantData.Member,
|
||||
average: averageData.average
|
||||
}
|
||||
};
|
||||
} catch (error) {
|
||||
console.error(`회원 ${participantData.Member.id}의 에버리지 계산 오류:`, error);
|
||||
return {
|
||||
...participantData,
|
||||
Member: {
|
||||
...participantData.Member,
|
||||
average: 0
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
return participantData;
|
||||
})
|
||||
);
|
||||
|
||||
res.json({
|
||||
message: '참가자 목록 조회가 완료되었습니다.',
|
||||
participants: formattedParticipants
|
||||
participants: participantsWithAverage
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('참가자 목록 조회 오류:', error);
|
||||
@@ -1323,7 +1480,7 @@ exports.addEventParticipant = async (req, res) => {
|
||||
where: {
|
||||
eventId,
|
||||
memberId,
|
||||
status: { [Op.ne]: '취소' }
|
||||
status: { [Op.ne]: 'canceled' }
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1567,7 +1724,7 @@ exports.deleteEventParticipant = async (req, res) => {
|
||||
where: {
|
||||
eventId,
|
||||
id,
|
||||
status: { [Op.ne]: '취소' }
|
||||
status: { [Op.ne]: 'canceled' }
|
||||
},
|
||||
include: [
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user