Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;
import young.blaybus.api_response.ApiResponse;
Expand Down Expand Up @@ -53,7 +54,7 @@ public ApiResponse<?> get() {
content = @Content(schema = @Schema(implementation = GetMatchingSeniorListResponse.class))
)
})
public ApiResponse<?> getMatchingSeniorList() {
public ApiResponse<List<GetMatchingSeniorListResponse>> getMatchingSeniorList() {
return ApiResponse.onSuccess(matchingService.getMatchingSeniorList());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@

import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
import young.blaybus.domain.address.Address;
import young.blaybus.util.enums.CareStyle;
import young.blaybus.util.enums.DayOfWeek;

import java.util.List;
Expand All @@ -17,7 +15,7 @@
public class GetMatchingSeniorListResponse {

@Schema(description = "어르신 ID")
private String seniorId;
private long seniorId;

@Schema(description = "프로필 사진")
private String profileUrl;
Expand All @@ -39,4 +37,7 @@ public class GetMatchingSeniorListResponse {

@Schema(description = "케어 스타일")
private String careStyle;

@Schema(description = "적합도")
private int fitness;
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@
import young.blaybus.domain.matching.Matching;

import java.util.List;
import young.blaybus.domain.matching.enums.MatchingStatus;

public interface MatchingRepository extends JpaRepository<Matching, Long> {
Matching findBySenior_IdAndMember_Id(Long senior_id, String member_id);
List<Matching> findByMember_IdAndStatus(String memberId, MatchingStatus status);
List<Matching> findByMember_Id(String memberId);
List<Matching> findBySenior_Id(Long seniorId);
}
253 changes: 130 additions & 123 deletions src/main/java/young/blaybus/domain/matching/service/MatchingService.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import jakarta.transaction.Transactional;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import young.blaybus.api_response.exception.GeneralException;
import young.blaybus.api_response.status.ErrorStatus;
import young.blaybus.domain.matching.Matching;
import young.blaybus.domain.matching.controller.request.PatchStatusRequest;
import young.blaybus.domain.matching.controller.response.*;
Expand All @@ -12,7 +14,9 @@
import young.blaybus.domain.member.repository.MemberRepository;
import young.blaybus.domain.member.security.SecurityUtils;
import young.blaybus.domain.senior.Senior;
import young.blaybus.domain.senior.SeniorDay;
import young.blaybus.domain.senior.repository.SeniorRepository;
import young.blaybus.domain.senior.service.RecommendService;
import young.blaybus.util.enums.DayOfWeek;

import java.time.LocalDateTime;
Expand All @@ -26,137 +30,140 @@
@RequiredArgsConstructor
public class MatchingService {

private final MemberRepository memberRepository;
private final SeniorRepository seniorRepository;
private final MatchingRepository matchingRepository;

// 매칭 요청
@Transactional
public void matchingRequest(String workerId, long seniorId) {
Member member = memberRepository.findById(workerId).orElse(null);
Senior senior = seniorRepository.findById(seniorId).orElse(null);

Matching matching = Matching.builder()
.senior(senior)
.member(member)
.status(MatchingStatus.PENDING)
.createdTime(LocalDateTime.now())
.build();

matchingRepository.save(matching);
}

// 매칭 현황 조회 (특정)
@Transactional
public GetMatchingStatistics getMatching() {
String workerId = SecurityUtils.getCurrentMemberName();
Member member = memberRepository.findById(workerId).orElse(null);
if (member != null) {
List<Matching> matching = matchingRepository.findByMember_Id(member.getId());

AtomicInteger fullMatchingCount = new AtomicInteger();
AtomicInteger acceptance = new AtomicInteger();
AtomicInteger refusal = new AtomicInteger();
AtomicInteger tuning = new AtomicInteger();

matching.forEach(m -> {
switch (m.getStatus()) {
case ACCEPTED -> acceptance.getAndIncrement();
case REJECTED -> refusal.getAndIncrement();
case TUNE_REQUESTED -> tuning.getAndIncrement();
}
fullMatchingCount.getAndIncrement();
});

return GetMatchingStatistics.builder()
.fullMatching(fullMatchingCount.get())
.acceptance(acceptance.get())
.refusal(refusal.get())
.tuning(tuning.get())
.build();
private final MemberRepository memberRepository;
private final SeniorRepository seniorRepository;
private final MatchingRepository matchingRepository;

private static final String emojiRegex = "[\uD83C-\uDBFF\uDC00-\uDFFF\u2600-\u26FF]+";
private final RecommendService recommendService;

// 매칭 요청
@Transactional
public void matchingRequest(String workerId, long seniorId) {
Member member = memberRepository.findById(workerId).orElse(null);
Senior senior = seniorRepository.findById(seniorId).orElse(null);

Matching matching = Matching.builder()
.senior(senior)
.member(member)
.status(MatchingStatus.PENDING)
.createdTime(LocalDateTime.now())
.build();

matchingRepository.save(matching);
}

// 매칭 현황 조회 (특정)
@Transactional
public GetMatchingStatistics getMatching() {
String workerId = SecurityUtils.getCurrentMemberName();
Member member = memberRepository.findById(workerId).orElse(null);
if (member != null) {
List<Matching> matching = matchingRepository.findByMember_Id(member.getId());

AtomicInteger fullMatchingCount = new AtomicInteger();
AtomicInteger acceptance = new AtomicInteger();
AtomicInteger refusal = new AtomicInteger();
AtomicInteger tuning = new AtomicInteger();

matching.forEach(m -> {
switch (m.getStatus()) {
case ACCEPTED -> acceptance.getAndIncrement();
case REJECTED -> refusal.getAndIncrement();
case TUNE_REQUESTED -> tuning.getAndIncrement();
}

return null;
fullMatchingCount.getAndIncrement();
});

return GetMatchingStatistics.builder()
.fullMatching(fullMatchingCount.get())
.acceptance(acceptance.get())
.refusal(refusal.get())
.tuning(tuning.get())
.build();
}

// 매칭 현황 어르신 리스트 조회 -> 요양보호사 쪽에서 어르신 매칭 요청 조회
@Transactional
public List<GetMatchingSeniorListResponse> getMatchingSeniorList() {
String workerId = SecurityUtils.getCurrentMemberName();
List<Matching> matching = matchingRepository.findByMember_Id(workerId);

List<GetMatchingSeniorListResponse> responseList = new ArrayList<>();
return null;
}

// 매칭 현황 어르신 리스트 조회 -> 요양보호사 쪽에서 어르신 매칭 요청 조회
@Transactional
public List<GetMatchingSeniorListResponse> getMatchingSeniorList() {
Member worker = memberRepository.findById(SecurityUtils.getCurrentMemberName())
.orElseThrow(() -> new GeneralException(ErrorStatus.KEY_NOT_EXIST));
List<Matching> matching = matchingRepository.findByMember_IdAndStatus(worker.getId(), MatchingStatus.PENDING);

List<GetMatchingSeniorListResponse> responseList = new ArrayList<>();
matching.forEach(m -> {
Senior senior = m.getSenior();
List<DayOfWeek> days = senior.getDayList().stream().map(SeniorDay::getDay).toList();

responseList.add(
GetMatchingSeniorListResponse.builder()
.seniorId(senior.getId())
.profileUrl(senior.getProfileUrl())
.seniorName(senior.getName())
.address(senior.getAddress())
.seniorDay(days)
.startTime(senior.getStartTime().format(DateTimeFormatter.ofPattern("a HH:mm").withLocale(Locale.forLanguageTag("ko"))))
.endTime(senior.getEndTime().format(DateTimeFormatter.ofPattern("HH:mm").withLocale(Locale.forLanguageTag("ko"))))
.careStyle(senior.getCareStyle().getValue().replaceAll(emojiRegex, "").strip())
.fitness(recommendService.calculateFitness(worker, senior))
.build()
);
});

return responseList;
}

// 매칭 상태 수정
@Transactional
public void matchingStatusPatch(PatchStatusRequest statusRequest) {
String workerId = SecurityUtils.getCurrentMemberName();
Matching matching = matchingRepository.findBySenior_IdAndMember_Id(Long.parseLong(statusRequest.seniorId()), workerId);

Matching matchingUpdateObject = Matching.builder()
.id(matching.getId())
.senior(matching.getSenior())
.member(matching.getMember())
.status(statusRequest.status())
.build();

matchingRepository.save(matchingUpdateObject);
}

// 매칭중인 어르신 목록 조회
@Transactional
public GetProgressMatchingSeniorList getMatchingSeniors() {
String adminId = SecurityUtils.getCurrentMemberName();
Member member = memberRepository.findById(adminId).orElse(null);

List<GetProgressMatchingSeniors> seniorsList = new ArrayList<>();
if (member != null) {
List<Senior> center = seniorRepository.findByCenterId(member.getCenter().getId());
center.forEach(s -> {
List<Matching> matching = matchingRepository.findBySenior_Id(s.getId());
matching.forEach(m -> {
List<DayOfWeek> days = new ArrayList<>();
m.getSenior().getDayList().forEach(day -> {
days.add(day.getDay());
});

responseList.add(
GetMatchingSeniorListResponse.builder()
.seniorId(String.valueOf(m.getSenior().getId()))
.profileUrl(m.getSenior().getProfileUrl())
.seniorName(m.getSenior().getName())
.address(m.getSenior().getAddress())
.seniorDay(days)
.startTime(m.getSenior().getStartTime().format(DateTimeFormatter.ofPattern("a HH:mm").withLocale(Locale.forLanguageTag("ko"))))
.endTime(m.getSenior().getEndTime().format(DateTimeFormatter.ofPattern("HH:mm").withLocale(Locale.forLanguageTag("ko"))))
.careStyle(m.getSenior().getCareStyle().getValue())
.build()
if (m.getStatus().equals(MatchingStatus.PENDING)) {
seniorsList.add(
GetProgressMatchingSeniors.builder()
.seniorId(String.valueOf(s.getId()))
.profileUrl(s.getProfileUrl())
.name(s.getName())
.sex(s.getSex().name())
.birthday(s.getBirthday().format(DateTimeFormatter.ofPattern("yyyy/MM/dd")))
.address(s.getAddress())
.build()
);
}
});
});

return responseList;
}

// 매칭 상태 수정
@Transactional
public void matchingStatusPatch(PatchStatusRequest statusRequest) {
String workerId = SecurityUtils.getCurrentMemberName();
Matching matching = matchingRepository.findBySenior_IdAndMember_Id(Long.parseLong(statusRequest.seniorId()), workerId);

Matching matchingUpdateObject = Matching.builder()
.id(matching.getId())
.senior(matching.getSenior())
.member(matching.getMember())
.status(statusRequest.status())
.build();

matchingRepository.save(matchingUpdateObject);
}

// 매칭중인 어르신 목록 조회
@Transactional
public GetProgressMatchingSeniorList getMatchingSeniors() {
String adminId = SecurityUtils.getCurrentMemberName();
Member member = memberRepository.findById(adminId).orElse(null);

List<GetProgressMatchingSeniors> seniorsList = new ArrayList<>();
if (member != null) {
List<Senior> center = seniorRepository.findByCenterId(member.getCenter().getId());
center.forEach(s -> {
List<Matching> matching = matchingRepository.findBySenior_Id(s.getId());
matching.forEach(m -> {
if (m.getStatus().equals(MatchingStatus.PENDING)) {
seniorsList.add(
GetProgressMatchingSeniors.builder()
.seniorId(String.valueOf(s.getId()))
.profileUrl(s.getProfileUrl())
.name(s.getName())
.sex(s.getSex().name())
.birthday(s.getBirthday().format(DateTimeFormatter.ofPattern("yyyy/MM/dd")))
.address(s.getAddress())
.build()
);
}
});
});

}

return GetProgressMatchingSeniorList.builder()
.seniorList(seniorsList)
.build();
}
return GetProgressMatchingSeniorList.builder()
.seniorList(seniorsList)
.build();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ public ListRecommendResponse getRecommendList(Long seniorId) {
.startTime(jobSearch.getStartTime())
.endTime(jobSearch.getEndTime())
.careStyle(member.getCareStyle().getValue())
.fitness(calculateFitness(member, jobSearch, senior))
.fitness(calculateFitness(member, senior))
.build()
);
}
Expand All @@ -76,21 +76,24 @@ public ListRecommendResponse getRecommendList(Long seniorId) {
.build();
}

private int calculateFitness(Member member, JobSearch jobSearch, Senior senior) {
public int calculateFitness(Member member, Senior senior) {
double fitness = 0.0;

JobSearch jobSearch = jobSearchRepository.findByMemberId(member.getId()).orElse(null);
JobSeek jobSeek = jobSeekRepository.findBySenior(senior);

// 거리 : 0km 최고점, 350km 최하점 → 30점 만점
fitness += 30;
Coordinate memberGeocoding = mapService.geocoding(member.getAddress().toString());
Coordinate seniorGeocoding = mapService.geocoding(senior.getAddress());
Double distance = mapService.getDistance(memberGeocoding, seniorGeocoding);
// todo 429 시 로직 추가
// Coordinate memberGeocoding = mapService.geocoding(member.getAddress().toString());
// Coordinate seniorGeocoding = mapService.geocoding(senior.getAddress());
// Double distance = mapService.getDistance(memberGeocoding, seniorGeocoding);
double maxDistance = 350_000;

fitness -= Math.min(30, distance * 30 / maxDistance);
// fitness -= Math.min(30, distance * 30 / maxDistance);

// 요일 → (노인의 희망 요일이 보호사의 요일과 겹치는 개수) * 15 / (노인의 희망 요일 개수) 점 → 15점 만점
assert jobSearch != null;
List<DayOfWeek> memberDayList = jobSearch.getDayList().stream().map(JobSearchDay::getDay).toList();
List<DayOfWeek> seniorDayList = senior.getDayList().stream().map(SeniorDay::getDay).toList();
int intersectCount = memberDayList.stream()
Expand Down
10 changes: 5 additions & 5 deletions src/main/java/young/blaybus/util/enums/CareStyle.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@
@RequiredArgsConstructor
public enum CareStyle {

STYLE1("📖 메뉴얼과 규칙을 중요시하는 꼼꼼형"),
STYLE2("😌 조용하고 신뢰있게 돕는 차분형"),
STYLE3("⚖️ 필요에 따라 유연하게 조정하는 균형형"),
STYLE4("🤝 감정에 공감하는 정서 교감형"),
STYLE5("🧒 친근한 가족같이 적극적인 돌봄");
STYLE1("📖 메뉴얼과 규칙을 중요시하는 꼼꼼형"),
STYLE2("😌 조용하고 신뢰있게 돕는 차분형"),
STYLE3("⚖️ 필요에 따라 유연하게 조정하는 균형형"),
STYLE4("🤝 감정에 공감하는 정서 교감형"),
STYLE5("🧒 친근한 가족같이 적극적인 돌봄");

private final String value;
}