@@ -68,39 +68,45 @@ public Page<MbtiAdminResultRowResponse> searchResults(String keyword, Pageable p
6868 @ Transactional (readOnly = true )
6969 public MbtiTeamMatchResponse matchTeams (MbtiTeamMatchRequest request ) {
7070 List <MbtiTeamMatchRequest .Candidate > rawCandidates = request .candidates ();
71- Map <String , MbtiTeamMatchRequest .Candidate > uniqueByStudentId = new LinkedHashMap <>();
71+ Map <String , MbtiTeamMatchRequest .Candidate > uniqueByCandidateKey = new LinkedHashMap <>();
7272
7373 for (MbtiTeamMatchRequest .Candidate candidate : rawCandidates ) {
7474 if (candidate == null ) {
7575 continue ;
7676 }
7777
78- String studentId = normalize (candidate .studentId ());
79- if (studentId .isEmpty ()) {
78+ String name = normalize (candidate .name ());
79+ String studentYear = normalizeAcademicYear (candidate .studentId ());
80+ if (name .isEmpty () || studentYear .isEmpty ()) {
8081 continue ;
8182 }
8283
83- uniqueByStudentId .putIfAbsent (
84- studentId ,
85- new MbtiTeamMatchRequest .Candidate (normalize (candidate .name ()), studentId )
84+ String candidateKey = buildCandidateKey (name , studentYear );
85+ uniqueByCandidateKey .putIfAbsent (
86+ candidateKey ,
87+ new MbtiTeamMatchRequest .Candidate (name , studentYear )
8688 );
8789 }
8890
89- List <MbtiTeamMatchRequest .Candidate > uniqueCandidates = new ArrayList <>(uniqueByStudentId .values ());
90- List <String > studentIds = uniqueCandidates .stream ()
91- .map (MbtiTeamMatchRequest .Candidate ::studentId )
92- .toList ();
93- Map <String , UserRole > roleByStudentId = userRepository .findByStudentIdIn (studentIds ).stream ()
91+ List <MbtiTeamMatchRequest .Candidate > uniqueCandidates = new ArrayList <>(uniqueByCandidateKey .values ());
92+ Map <String , UserRole > privilegedRoleByCandidateKey = userRepository
93+ .findByUserRoleIn (List .of (UserRole .LEAD , UserRole .ORGANIZER ))
94+ .stream ()
9495 .collect (
9596 LinkedHashMap ::new ,
96- (acc , user ) -> acc .putIfAbsent (user .getStudentId (), user .getUserRole ()),
97+ (acc , user ) -> acc .putIfAbsent (
98+ buildCandidateKey (user .getName (), user .getStudentId ()),
99+ user .getUserRole ()
100+ ),
97101 Map ::putAll
98102 );
99-
100- Map <String , MbtiResult > resultMap = mbtiResultRepository .findByStudentIdIn (studentIds ).stream ()
103+ Map <String , MbtiResult > resultMap = mbtiResultRepository .findAll ().stream ()
101104 .collect (
102105 LinkedHashMap ::new ,
103- (acc , row ) -> acc .putIfAbsent (row .getStudentId (), row ),
106+ (acc , row ) -> acc .putIfAbsent (
107+ buildCandidateKey (row .getName (), row .getStudentId ()),
108+ row
109+ ),
104110 Map ::putAll
105111 );
106112
@@ -109,7 +115,8 @@ public MbtiTeamMatchResponse matchTeams(MbtiTeamMatchRequest request) {
109115 List <MbtiTeamMatchResponse .UnmatchedCandidate > unmatched = new ArrayList <>();
110116
111117 for (MbtiTeamMatchRequest .Candidate candidate : uniqueCandidates ) {
112- UserRole userRole = roleByStudentId .get (candidate .studentId ());
118+ String candidateKey = buildCandidateKey (candidate .name (), candidate .studentId ());
119+ UserRole userRole = privilegedRoleByCandidateKey .get (candidateKey );
113120 if (userRole == UserRole .LEAD || userRole == UserRole .ORGANIZER ) {
114121 unmatched .add (new MbtiTeamMatchResponse .UnmatchedCandidate (
115122 candidate .name (),
@@ -119,7 +126,7 @@ public MbtiTeamMatchResponse matchTeams(MbtiTeamMatchRequest request) {
119126 continue ;
120127 }
121128
122- MbtiResult matched = resultMap .get (candidate . studentId () );
129+ MbtiResult matched = resultMap .get (candidateKey );
123130 if (matched == null ) {
124131 unmatchedMembers .add (new MbtiTeamMatchResponse .Member (
125132 candidate .name (),
@@ -262,6 +269,29 @@ private String normalize(String value) {
262269 return value == null ? "" : value .trim ();
263270 }
264271
272+ private String buildCandidateKey (String name , String studentIdOrYear ) {
273+ String normalizedName = normalize (name ).toLowerCase ();
274+ String normalizedYear = normalizeAcademicYear (studentIdOrYear );
275+ if (normalizedName .isEmpty () || normalizedYear .isEmpty ()) {
276+ return "" ;
277+ }
278+ return normalizedName + "|" + normalizedYear ;
279+ }
280+
281+ private String normalizeAcademicYear (String value ) {
282+ String digits = value == null ? "" : value .replaceAll ("\\ D" , "" );
283+ if (digits .length () == 2 ) {
284+ return digits ;
285+ }
286+ if (digits .startsWith ("12" ) && digits .length () >= 4 ) {
287+ return digits .substring (2 , 4 );
288+ }
289+ if (digits .length () >= 2 ) {
290+ return digits .substring (0 , 2 );
291+ }
292+ return "" ;
293+ }
294+
265295 private static final class TeamBucket {
266296 private final int teamNumber ;
267297 private final int unmatchedTarget ;
0 commit comments