Skip to content

Commit

Permalink
농장 예약 가능 시간대 등록 및 조회 (#30)
Browse files Browse the repository at this point in the history
* feat: FarmSchedule 추가
#13

* refacto: userId로 네이밍 수정
#13

* feat: secret 내리자...

* feat:FarmSchedule 도메인 추가
- 스케쥴 추가
- 스케쥴 조회
#13

* refactor: AllArgsConstructor -> RequiredArgsConstructor
#13

* refactor: Enumerated추가

* refactor: where/sqlselect 제거

* feat: 이미 농장이 있는 경우 새로운 농장 등록을 막는다

* bug: 농장 조회 기능 에러 수정
- 쿼리로 삭제된 농장 조회 필터링
-  JPA 메소드 수정
#13

* bug: 농장 조회 기능 에러 수정
- 쿼리로 삭제된 농장 조회 필터링
-  JPA 메소드 수정
#13

* feat: 농장 스케쥴 등록
- 시작 날짜, 종료 날짜, 요일 선택시 추가 가능
#13

* feat: 농장 예약 가능날짜 조회
#13

* chore: 필요없는 코드 정리
#13

* chore: 필요없는 코드 정리
#13

* refactor: schedule 도메인 분리
- 생각보다 너무 커져서 Farm 안에 집어 넣어버렸습니다
#13

* refactor: schedule controller 분리
#13

* refactor: schedule controller 분리
#13

* refactor: now() -> current_timestamp
#13

* refactor: userId -> memberId
#13

* refactor: 기간 범위의 스케쥴 한번에 가져와서 비교하도록 수정
#13

* feature: 체험 비용 추가
#13

* feat: 농장 스케쥴 등록 validation 추가
#36

* feat: 농장 스케쥴 등록 validation 추가
#36

* 충돌 해결
  • Loading branch information
stopmin authored Oct 2, 2024
1 parent a78d73d commit a526089
Show file tree
Hide file tree
Showing 18 changed files with 324 additions and 36 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package poomasi.domain.farm._schedule.controller;

import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import poomasi.domain.farm._schedule.dto.FarmScheduleRequest;
import poomasi.domain.farm._schedule.service.FarmScheduleService;

@RestController
@RequiredArgsConstructor
@RequestMapping("/api/farm")
public class FarmScheduleController {
private final FarmScheduleService farmScheduleService;

@GetMapping("/schedule")
public ResponseEntity<?> getFarmSchedule(@RequestParam Long farmId, @RequestParam Integer year, @RequestParam Integer month) {
return ResponseEntity.ok(farmScheduleService.getFarmSchedulesByYearAndMonth(new FarmScheduleRequest(farmId, year, month)));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package poomasi.domain.farm._schedule.controller;

import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import poomasi.domain.farm._schedule.dto.FarmScheduleUpdateRequest;
import poomasi.domain.farm._schedule.service.FarmScheduleService;

@RestController
@RequiredArgsConstructor
@RequestMapping("/api/farm")
public class FarmScheduleFarmerController {
private final FarmScheduleService farmScheduleService;

@PostMapping("/schedule")
public ResponseEntity<?> addFarmSchedule(@Valid @RequestBody FarmScheduleUpdateRequest request) {
farmScheduleService.addFarmSchedule(request);
return ResponseEntity.ok().build();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package poomasi.domain.farm._schedule.dto;

public record FarmScheduleRequest(
Long farmId,
Integer year,
Integer month
) {
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package poomasi.domain.farm._schedule.dto;

import lombok.Builder;
import poomasi.domain.farm._schedule.entity.FarmSchedule;
import poomasi.domain.farm._schedule.entity.ScheduleStatus;

import java.time.LocalDate;

@Builder
public record FarmScheduleResponse(
LocalDate date,
ScheduleStatus status
) {
public static FarmScheduleResponse fromEntity(FarmSchedule farmSchedule) {
return FarmScheduleResponse.builder()
.date(farmSchedule.getDate())
.status(farmSchedule.getStatus())
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package poomasi.domain.farm._schedule.dto;

import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import poomasi.domain.farm._schedule.entity.FarmSchedule;
import poomasi.domain.farm._schedule.entity.ScheduleStatus;

import java.time.DayOfWeek;
import java.time.LocalDate;
import java.util.List;

public record FarmScheduleUpdateRequest(
Long farmId,
@NotNull(message = "시작 날짜는 필수 값입니다.")
LocalDate startDate,
@NotNull(message = "종료 날짜는 필수 값입니다.")
LocalDate endDate,
ScheduleStatus status,
@NotEmpty(message = "예약 가능한 요일은 필수 값입니다.")
List<DayOfWeek> availableDays // 예약 가능한 요일 리스트
) {
public FarmSchedule toEntity(LocalDate date) {
return FarmSchedule.builder()
.farmId(farmId)
.date(date)
.status(status)
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package poomasi.domain.farm._schedule.entity;

import jakarta.persistence.*;
import lombok.AccessLevel;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.hibernate.annotations.Comment;

import java.time.LocalDate;

@Entity
@Getter
@Table(name = "farm_schedule")
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class FarmSchedule {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@Comment("농장")
private Long farmId;

@Comment("예약 가능 날짜")
private LocalDate date;

@Comment("예약 가능 여부")
@Enumerated(EnumType.STRING)
private ScheduleStatus status;

@Builder
public FarmSchedule(Long farmId, LocalDate date, ScheduleStatus status) {
this.farmId = farmId;
this.date = date;
this.status = status;
}

public void updateStatus(ScheduleStatus status) {
this.status = status;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package poomasi.domain.farm._schedule.entity;

public enum ScheduleStatus {
PENDING,
RESERVED,
;

public boolean isAvailable() {
return this == PENDING;
}

public boolean isReserved() {
return this == RESERVED;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package poomasi.domain.farm._schedule.repository;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;
import poomasi.domain.farm._schedule.entity.FarmSchedule;

import java.time.LocalDate;
import java.util.List;
import java.util.Optional;

@Repository
public interface FarmScheduleRepository extends JpaRepository<FarmSchedule, Long> {
@Query("SELECT f FROM FarmSchedule f WHERE f.farmId = :farmId AND f.date BETWEEN :startDate AND :endDate")
List<FarmSchedule> findByFarmIdAndDateRange(Long farmId, LocalDate startDate, LocalDate endDate);

Optional<FarmSchedule> findByFarmIdAndDate(Long aLong, LocalDate date);

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package poomasi.domain.farm._schedule.service;

import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import poomasi.domain.farm._schedule.dto.FarmScheduleRequest;
import poomasi.domain.farm._schedule.dto.FarmScheduleResponse;
import poomasi.domain.farm._schedule.dto.FarmScheduleUpdateRequest;
import poomasi.domain.farm._schedule.entity.FarmSchedule;
import poomasi.domain.farm._schedule.repository.FarmScheduleRepository;
import poomasi.global.error.BusinessException;

import java.time.LocalDate;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

import static poomasi.global.error.BusinessError.FARM_SCHEDULE_ALREADY_EXISTS;
import static poomasi.global.error.BusinessError.START_DATE_SHOULD_BE_BEFORE_END_DATE;

@Service
@RequiredArgsConstructor
public class FarmScheduleService {
private final FarmScheduleRepository farmScheduleRepository;

public void addFarmSchedule(FarmScheduleUpdateRequest request) {
List<FarmSchedule> existingSchedules = farmScheduleRepository.findByFarmIdAndDateRange(request.farmId(), request.startDate(), request.endDate());

if (request.startDate().isAfter(request.endDate())) {
throw new BusinessException(START_DATE_SHOULD_BE_BEFORE_END_DATE);
}

Set<LocalDate> existingDates = existingSchedules.stream()
.map(FarmSchedule::getDate)
.collect(Collectors.toSet());

for (LocalDate date = request.startDate(); !date.isAfter(request.endDate()); date = date.plusDays(1)) {
if (request.availableDays().contains(date.getDayOfWeek())) {
if (existingDates.contains(date)) {
throw new BusinessException(FARM_SCHEDULE_ALREADY_EXISTS);
}

FarmSchedule newSchedule = request.toEntity(date);
farmScheduleRepository.save(newSchedule);
}
}
}

public List<FarmScheduleResponse> getFarmSchedulesByYearAndMonth(FarmScheduleRequest request) {
LocalDate startDate = LocalDate.of(request.year(), request.month(), 1);
LocalDate endDate = startDate.withDayOfMonth(startDate.lengthOfMonth());

return farmScheduleRepository.findByFarmIdAndDateRange(request.farmId(), startDate, endDate).stream()
.map(FarmScheduleResponse::fromEntity)
.toList();
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
import org.springframework.data.domain.Pageable;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import poomasi.domain.farm.service.FarmService;

Expand All @@ -17,7 +17,7 @@ public class FarmController {
private final FarmService farmService;

@GetMapping("/{farmId}")
public ResponseEntity<?> getFarm(@RequestParam Long farmId) {
public ResponseEntity<?> getFarm(@PathVariable Long farmId) {
return ResponseEntity.ok(farmService.getFarmByFarmId(farmId));
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,21 +1,20 @@
package poomasi.domain.farm.controller;

import jakarta.validation.Valid;
import lombok.AllArgsConstructor;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.*;
import poomasi.domain.farm.dto.FarmRegisterRequest;
import poomasi.domain.farm.dto.FarmUpdateRequest;
import poomasi.domain.farm.service.FarmFarmerService;
import poomasi.domain.farm._schedule.service.FarmScheduleService;

@RestController
@AllArgsConstructor
@RequiredArgsConstructor
@RequestMapping("/api/farm")
public class FarmFarmerController {
private final FarmFarmerService farmFarmerService;
private final FarmScheduleService farmScheduleService;

// TODO: 판매자만 접근가능하도록 인증/인가 annotation 추가
@PostMapping("")
Expand All @@ -29,4 +28,14 @@ public ResponseEntity<?> updateFarm(@Valid @RequestBody FarmUpdateRequest reques
Long farmerId = 1L;
return ResponseEntity.ok(farmFarmerService.updateFarm(farmerId, request));
}

@DeleteMapping("/{farmId}")
public ResponseEntity<?> deleteFarm(@PathVariable Long farmId) {
// TODO: 판매자 ID
Long farmerId = 1L;

farmFarmerService.deleteFarm(farmerId, farmId);
return ResponseEntity.ok().build();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,25 @@

public record FarmRegisterRequest(
String name,
Long ownerId,
Long memberId,
String address,
String addressDetail,
Double latitude,
Double longitude,
String phoneNumber,
String description
String description,
Long experiencePrice
) {
public Farm toEntity() {
return Farm.builder()
.name(name)
.ownerId(ownerId)
.ownerId(memberId)
.address(address)
.addressDetail(addressDetail)
.latitude(latitude)
.longitude(longitude)
.description(description)
.experiencePrice(experiencePrice)
.build();
}
}
8 changes: 5 additions & 3 deletions src/main/java/poomasi/domain/farm/dto/FarmResponse.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,9 @@ public record FarmResponse( // FIXME: 사용자 정보 추가 및 설명/전화
String addressDetail,
Double latitude,
Double longitude,
String description
) {
String description,
Long experiencePrice
) {
public static FarmResponse fromEntity(Farm farm) {
return new FarmResponse(
farm.getId(),
Expand All @@ -20,7 +21,8 @@ public static FarmResponse fromEntity(Farm farm) {
farm.getAddressDetail(),
farm.getLatitude(),
farm.getLongitude(),
farm.getDescription()
farm.getDescription(),
farm.getExperiencePrice()
);
}
}
Loading

0 comments on commit a526089

Please sign in to comment.