Skip to content

Commit 0a3f8c2

Browse files
authored
🐛 fix: 데이트 코스 리턴 (#102)
2 parents 9831b0e + 305f355 commit 0a3f8c2

File tree

12 files changed

+334
-191
lines changed

12 files changed

+334
-191
lines changed

src/main/java/org/withtime/be/withtimebe/domain/date/controller/command/DateCommandController.java

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,24 +3,24 @@
33
import io.swagger.v3.oas.annotations.Operation;
44
import io.swagger.v3.oas.annotations.responses.ApiResponse;
55
import io.swagger.v3.oas.annotations.responses.ApiResponses;
6+
import io.swagger.v3.oas.annotations.tags.Tag;
67
import lombok.RequiredArgsConstructor;
78
import org.namul.api.payload.response.DefaultResponse;
89
import org.springframework.web.bind.annotation.*;
910
import org.withtime.be.withtimebe.domain.date.converter.DateConverter;
1011
import org.withtime.be.withtimebe.domain.date.dto.request.DateRequestDTO;
1112
import org.withtime.be.withtimebe.domain.date.dto.response.DateResponseDTO;
1213
import org.withtime.be.withtimebe.domain.date.entity.DateCourseBookmark;
13-
import org.withtime.be.withtimebe.domain.date.entity.DatePlace;
1414
import org.withtime.be.withtimebe.domain.date.service.command.DateCommandService;
15+
import org.withtime.be.withtimebe.domain.date.service.command.dto.RecommendedCourseResult;
1516
import org.withtime.be.withtimebe.domain.member.entity.Member;
1617
import org.withtime.be.withtimebe.global.security.annotation.AuthenticatedMember;
1718

18-
import java.util.List;
19-
2019

2120
@RestController
2221
@RequiredArgsConstructor
2322
@RequestMapping("/api/v1/date-courses")
23+
@Tag(name = "데이트 생성 API")
2424
public class DateCommandController {
2525

2626
private final DateCommandService dateCommandService;
@@ -32,10 +32,9 @@ public class DateCommandController {
3232
@PostMapping("/")
3333
public DefaultResponse<DateResponseDTO.DateCourse> createDateCourse(
3434
@RequestBody DateRequestDTO.CreateDateCourse request
35-
// @AuthenticatedMember Member member
3635
){
37-
List<DatePlace> datePlaces = dateCommandService.createDateCourse(request);
38-
DateResponseDTO.DateCourse dateCourse = DateConverter.createDateCourseInfo(datePlaces);
36+
RecommendedCourseResult datePlaces = dateCommandService.createDateCourse(request);
37+
DateResponseDTO.DateCourse dateCourse = DateConverter.createDateCourseInfo(datePlaces.places(), datePlaces.signature());
3938
return DefaultResponse.created(dateCourse);
4039
}
4140

src/main/java/org/withtime/be/withtimebe/domain/date/controller/query/DateQueryController.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import io.swagger.v3.oas.annotations.Operation;
44
import io.swagger.v3.oas.annotations.responses.ApiResponse;
55
import io.swagger.v3.oas.annotations.responses.ApiResponses;
6+
import io.swagger.v3.oas.annotations.tags.Tag;
67
import lombok.RequiredArgsConstructor;
78
import org.namul.api.payload.response.DefaultResponse;
89
import org.springframework.data.domain.Page;
@@ -21,6 +22,7 @@
2122
@RestController
2223
@RequiredArgsConstructor
2324
@RequestMapping("/api/v1/date-courses")
25+
@Tag(name = "데이트 조회 API")
2426
public class DateQueryController {
2527

2628
private final DateQueryService dateQueryService;

src/main/java/org/withtime/be/withtimebe/domain/date/converter/DateConverter.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,19 +40,23 @@ public static DateCourse createDateCourse(DateRequestDTO.SaveDateCourse dateCour
4040
// 나중에 생성한 정보를 리턴하는 데 사용,,? 근데 애초에 그 뭐야
4141
// builder()로 만들 때 잘 만들어주면 안되냐
4242
// List<DatePlace> -> DateResponseDTO.DateCourseInfo
43-
public static DateResponseDTO.DateCourse createDateCourseInfo(List<DatePlace> datePlaces){
43+
// 단일 추천 코스를 응답으로 구성(시그니처 포함)
44+
public static DateResponseDTO.DateCourse createDateCourseInfo(List<DatePlace> datePlaces, String signature){
4445
List<DateResponseDTO.DatePlace> datePlaceDtos = datePlaces.stream()
4546
.map(DateConverter::createDatePlace)
4647
.toList();
4748

4849
return DateResponseDTO.DateCourse.builder()
4950
.name(LocalDateTime.now().toLocalDate().toString())
51+
.datePlaces(datePlaceDtos)
52+
.signature(signature) // ← 추가
5053
.build();
5154
}
5255

5356
// DatePlace -> DateResponseDTO.DatePlace
5457
public static DateResponseDTO.DatePlace createDatePlace(DatePlace datePlace) {
5558
return DateResponseDTO.DatePlace.builder()
59+
.datePlaceId(datePlace.getId())
5660
.name(datePlace.getName())
5761
.image(datePlace.getImage())
5862
.tel(datePlace.getTel())
@@ -75,7 +79,6 @@ public static DateResponseDTO.DateCourse createDateCourse(DateCourse dateCourse)
7579
.toList();
7680

7781
return DateResponseDTO.DateCourse.builder()
78-
.dateCourseId(dateCourse.getId())
7982
.name(dateCourse.getName())
8083
.datePlaces(datePlaces)
8184
.build();

src/main/java/org/withtime/be/withtimebe/domain/date/dto/request/DateRequestDTO.java

Lines changed: 35 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
package org.withtime.be.withtimebe.domain.date.dto.request;
22

33
import com.fasterxml.jackson.annotation.JsonFormat;
4+
import com.fasterxml.jackson.annotation.JsonProperty;
5+
import io.swagger.v3.oas.annotations.media.Schema;
46
import jakarta.validation.constraints.NotBlank;
57
import jakarta.validation.constraints.NotNull;
8+
import jakarta.validation.constraints.Pattern;
69
import jakarta.validation.constraints.Size;
710
import org.withtime.be.withtimebe.domain.date.entity.enums.DatePriceRange;
811
import org.withtime.be.withtimebe.domain.date.entity.enums.DateTime;
@@ -11,37 +14,50 @@
1114

1215
import java.time.LocalDateTime;
1316
import java.util.List;
17+
import java.util.Set;
1418

1519
public record DateRequestDTO() {
1620

1721

1822
public record CreateDateCourse(
19-
@NotNull(message = "예산을 선택해주세요")
20-
DatePriceRange budget,
23+
@NotNull(message = "예산을 선택해주세요")
24+
@Schema(example = "UNDER_10K")
25+
DatePriceRange budget,
2126

22-
@Size(min = 1, message = "최소 하나 이상의 값을 선택해주세요")
23-
@NotNull(message = "값이 비어있을 수 없습니다")
24-
List<String> datePlaces,
27+
@Size(min = 1, message = "최소 하나 이상의 값을 선택해주세요")
28+
@NotNull(message = "값이 비어있을 수 없습니다")
29+
@Schema(example = "[\"서울 종로구\"]")
30+
List<String> datePlaces,
2531

26-
@NotNull(message = "데이트 시간을 선택해주세요")
27-
DateTime dateDurationTime,
32+
@NotNull(message = "데이트 시간을 선택해주세요")
33+
@Schema(example = "ONETOTWO")
34+
DateTime dateDurationTime,
2835

29-
List<MealType> mealPlan,
36+
@Schema(example = "[\"BREAKFAST\"]")
37+
List<MealType> mealPlan,
3038

31-
@NotBlank(message = "이동 수단을 선택해주세요")
32-
Transportation transportation,
39+
@NotNull(message = "이동 수단을 선택해주세요")
40+
@Schema(example = "WALK")
41+
Transportation transportation,
3342

34-
@Size(min = 1, max = 3)
35-
@NotNull(message = "사용자 취향을 선택해주세요")
36-
List<String> userPreferredKeywords,
43+
@Size(min = 1, max = 3)
44+
@NotNull(message = "사용자 취향을 선택해주세요")
45+
@Schema(example = "[\"레트로 골목\", \"카페\"]")
46+
List<String> userPreferredKeywords,
3747

38-
@JsonFormat(shape = JsonFormat.Shape.STRING,
39-
pattern = "yyyy-MM-dd'T'HH:mm:ss"
40-
)
41-
LocalDateTime startTime,
48+
@NotBlank(message = "startTime은 필수입니다")
49+
@Pattern(
50+
regexp = "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}$",
51+
message = "startTime 형식은 yyyy-MM-dd'T'HH:mm 이어야 합니다"
52+
)
53+
@JsonProperty("startTime")
54+
@Schema(example = "2025-08-14T07:45")
55+
LocalDateTime startTime,
4256

43-
int attemptCount
44-
){}
57+
// 이미 보여줬던 코스의 시그니처(예: "12-45-33")
58+
@Schema(example = "[]")
59+
Set<String> excludedCourseSignatures
60+
) {}
4561

4662
public record SaveDateCourse(
4763
List<Long> datePlaceIds,

src/main/java/org/withtime/be/withtimebe/domain/date/dto/response/DateResponseDTO.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ public record DateCourseBookmark(
1414

1515
@Builder
1616
public record DatePlace(
17+
Long datePlaceId,
1718
String name,
1819
String image,
1920
String tel,
@@ -28,9 +29,9 @@ public record DatePlace(
2829

2930
@Builder
3031
public record DateCourse(
31-
Long dateCourseId,
3232
String name,
33-
List<DateResponseDTO.DatePlace> datePlaces
33+
List<DateResponseDTO.DatePlace> datePlaces,
34+
String signature
3435
){}
3536

3637
@Builder
Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,32 @@
1+
// ScheduledDateCourse
12
package org.withtime.be.withtimebe.domain.date.entity.model;
23

34
import lombok.Builder;
45
import lombok.Getter;
56

7+
import java.util.Comparator;
68
import java.util.List;
9+
import java.util.Objects;
710

811
@Builder
912
@Getter
1013
public class ScheduledDateCourse implements Comparable<ScheduledDateCourse> {
11-
private List<ScheduledDatePlace> scheduledDatePlaces;
12-
private double weight;
14+
15+
private final List<ScheduledDatePlace> scheduledDatePlaces;
16+
private final double weight; // 코스 총점
1317

1418
@Override
1519
public int compareTo(ScheduledDateCourse o) {
16-
return (int)(this.weight - o.weight);
20+
return Double.compare(this.weight, o.weight);
21+
}
22+
23+
public static final Comparator<ScheduledDateCourse> BY_WEIGHT_ASC =
24+
Comparator.comparingDouble(ScheduledDateCourse::getWeight);
25+
public static final Comparator<ScheduledDateCourse> BY_WEIGHT_DESC =
26+
BY_WEIGHT_ASC.reversed();
27+
28+
public ScheduledDateCourse(List<ScheduledDatePlace> scheduledDatePlaces, double weight) {
29+
this.scheduledDatePlaces = Objects.requireNonNull(scheduledDatePlaces, "scheduledDatePlaces must not be null");
30+
this.weight = weight;
1731
}
1832
}
Lines changed: 44 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,63 @@
1+
// ScheduledDatePlace
12
package org.withtime.be.withtimebe.domain.date.entity.model;
23

34
import lombok.Builder;
45
import lombok.Getter;
6+
import lombok.ToString;
57
import org.withtime.be.withtimebe.domain.date.entity.DatePlace;
8+
import org.withtime.be.withtimebe.domain.date.entity.enums.PlaceType;
69

710
import java.time.Duration;
8-
import java.time.LocalTime;
11+
import java.time.LocalDateTime;
12+
import java.util.Objects;
913

1014
@Getter
15+
@ToString
1116
public class ScheduledDatePlace {
12-
private DatePlace datePlace;
13-
private LocalTime startTime;
14-
private LocalTime endTime;
15-
private double score;
1617

17-
// 그리고 여기서 그냥 comparator 쓰면 되지 않나?
18+
private final DatePlace datePlace;
1819

19-
@Builder
20-
public ScheduledDatePlace(DatePlace datePlace, LocalTime startTime, Duration duration, double score) {
21-
this.datePlace = datePlace;
20+
// 시간은 점수 산정 단계에선 없어도 됨(선택)
21+
private final LocalDateTime startTime; // nullable
22+
private final LocalDateTime endTime; // nullable
23+
24+
private final double score;
25+
26+
@Builder(toBuilder = true)
27+
private ScheduledDatePlace(DatePlace datePlace,
28+
LocalDateTime startTime,
29+
LocalDateTime endTime,
30+
double score) {
31+
this.datePlace = Objects.requireNonNull(datePlace, "datePlace must not be null");
2232
this.startTime = startTime;
23-
this.endTime = startTime.plus(duration);
33+
this.endTime = endTime;
2434
this.score = score;
2535
}
2636

37+
// 시간 없이 점수만 설정
38+
public static ScheduledDatePlace ofScoreOnly(DatePlace place, double score) {
39+
return ScheduledDatePlace.builder()
40+
.datePlace(place)
41+
.score(score)
42+
.build();
43+
}
44+
45+
// 시작시각 주면 placeType duration으로 종료시각 계산
46+
public ScheduledDatePlace withScheduleFrom(LocalDateTime start) {
47+
PlaceType type = datePlace.getPlaceType();
48+
Duration dur = (type != null) ? type.getDuration() : Duration.ZERO;
49+
LocalDateTime end = (start != null) ? start.plus(dur) : null;
50+
return this.toBuilder()
51+
.startTime(start)
52+
.endTime(end)
53+
.build();
54+
}
55+
2756
public Duration getDuration() {
28-
return Duration.between(startTime, endTime);
57+
if (startTime != null && endTime != null) {
58+
return Duration.between(startTime, endTime);
59+
}
60+
PlaceType type = datePlace.getPlaceType();
61+
return (type != null) ? type.getDuration() : Duration.ZERO;
2962
}
3063
}

src/main/java/org/withtime/be/withtimebe/domain/date/service/command/DateCommandService.java

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,13 @@
33
import org.withtime.be.withtimebe.domain.date.dto.request.DateRequestDTO;
44
import org.withtime.be.withtimebe.domain.date.entity.DateCourse;
55
import org.withtime.be.withtimebe.domain.date.entity.DateCourseBookmark;
6-
import org.withtime.be.withtimebe.domain.date.entity.DatePlace;
6+
import org.withtime.be.withtimebe.domain.date.service.command.dto.RecommendedCourseResult;
77
import org.withtime.be.withtimebe.domain.member.entity.Member;
88

9-
import java.util.List;
10-
119

1210
public interface DateCommandService {
13-
public DateCourseBookmark createDateCourseBookmark(Long dateCourseId, Member member);
14-
public DateCourse deleteDateCourseBookmark(Long dateCourseId, Member member);
15-
public DateCourseBookmark createDateCourseBookmarkWithGeneratedCourse(DateRequestDTO.SaveDateCourse request, Member members);
16-
public List<DatePlace> createDateCourse(DateRequestDTO.CreateDateCourse request);
11+
DateCourseBookmark createDateCourseBookmark(Long dateCourseId, Member member);
12+
DateCourse deleteDateCourseBookmark(Long dateCourseId, Member member);
13+
DateCourseBookmark createDateCourseBookmarkWithGeneratedCourse(DateRequestDTO.SaveDateCourse request, Member members);
14+
RecommendedCourseResult createDateCourse(DateRequestDTO.CreateDateCourse request);
1715
}

0 commit comments

Comments
 (0)