Skip to content

Commit

Permalink
feat : 배송 API 구현 #26
Browse files Browse the repository at this point in the history
  • Loading branch information
JiwonKKang committed Aug 12, 2024
1 parent 3f31f13 commit b1b740d
Show file tree
Hide file tree
Showing 27 changed files with 963 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package core.startup.mealtoktok.api.mealdelivery;

import java.util.List;

import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import lombok.RequiredArgsConstructor;

import core.startup.mealtoktok.api.mealdelivery.dto.FullDiningResponse;
import core.startup.mealtoktok.api.mealdelivery.dto.MealDeliveryResponse;
import core.startup.mealtoktok.common.dto.Response;
import core.startup.mealtoktok.domain.mealdelivery.CollectingState;
import core.startup.mealtoktok.domain.mealdelivery.DeliveryState;
import core.startup.mealtoktok.domain.mealdelivery.FullDining;
import core.startup.mealtoktok.domain.mealdelivery.MealDeliveryService;
import core.startup.mealtoktok.domain.mealdelivery.TargetFullDining;
import core.startup.mealtoktok.domain.mealdelivery.TargetMealDelivery;
import core.startup.mealtoktok.domain.order.Orderer;
import core.startup.mealtoktok.domain.user.User;

@RequestMapping("/api/v1/meal-deliveries")
@RestController
@RequiredArgsConstructor
public class MealDeliveryApi implements MealDeliveryApiDocs {

private final MealDeliveryService mealDeliveryService;

@GetMapping("/delivering")
public Response<MealDeliveryResponse> deliveringMeal(
@AuthenticationPrincipal User currentUser) {
return Response.success(
MealDeliveryResponse.from(
mealDeliveryService.getDeliveringMeal(Orderer.from(currentUser))));
}

@GetMapping("/{mealDeliveryId}")
public Response<MealDeliveryResponse> mealDelivery(@PathVariable Long mealDeliveryId) {
return Response.success(
MealDeliveryResponse.from(
mealDeliveryService.getMealDelivery(
TargetMealDelivery.from(mealDeliveryId))));
}

@GetMapping("/delivered")
public Response<MealDeliveryResponse> recentDeliveredMeal(
@AuthenticationPrincipal User currentUser) {
return Response.success(
MealDeliveryResponse.from(
mealDeliveryService.getRecentDeliveredMeal(Orderer.from(currentUser))));
}

@PatchMapping("/{mealDeliveryId}/{deliveryState}")
public Response<Void> changeDeliveryState(
@PathVariable Long mealDeliveryId, @PathVariable DeliveryState deliveryState) {
mealDeliveryService.changeDeliveryState(
TargetMealDelivery.from(mealDeliveryId), deliveryState);
return Response.success("배송 상태 변경 성공");
}

@PatchMapping("/full-dinings/{fullDiningId}/{collectingState}")
public Response<Void> changeCollectingState(
@PathVariable Long fullDiningId, @PathVariable CollectingState collectingState) {
mealDeliveryService.changeCollectingState(
TargetFullDining.from(fullDiningId), collectingState);
return Response.success("수거 상태 변경 성공");
}

@GetMapping("/full-dinings/collect-requested/count")
public Response<Integer> countCollectRequestContainers(
@AuthenticationPrincipal User currentUser) {
return Response.success(
mealDeliveryService.countCollectRequestContainers(Orderer.from(currentUser)));
}

@GetMapping("/full-dinings")
public Response<List<FullDiningResponse>> fullDinings(
@AuthenticationPrincipal User currentUser) {
List<FullDining> fullDinings =
mealDeliveryService.getFullDinings(Orderer.from(currentUser));
return Response.success(
fullDinings.parallelStream().map(FullDiningResponse::from).toList());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package core.startup.mealtoktok.api.mealdelivery;

import java.util.List;

import core.startup.mealtoktok.api.mealdelivery.dto.FullDiningResponse;
import core.startup.mealtoktok.api.mealdelivery.dto.MealDeliveryResponse;
import core.startup.mealtoktok.common.dto.Response;
import core.startup.mealtoktok.domain.mealdelivery.CollectingState;
import core.startup.mealtoktok.domain.mealdelivery.DeliveryState;
import core.startup.mealtoktok.domain.user.User;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;

@Tag(name = "도시락 배달 API")
public interface MealDeliveryApiDocs {

@Operation(summary = "배송 중인 도시락 조회")
Response<MealDeliveryResponse> deliveringMeal(User currentUser);

@Operation(summary = "도시락 배송 단건 조회")
Response<MealDeliveryResponse> mealDelivery(Long mealDeliveryId);

@Operation(summary = "최근 배송 완료된 도시락 조회")
Response<MealDeliveryResponse> recentDeliveredMeal(User currentUser);

@Operation(summary = "도시락 배송 상태 변경")
Response<Void> changeDeliveryState(Long mealDeliveryId, DeliveryState deliveryState);

@Operation(summary = "풀대접 서비스 수거 상태 변경")
Response<Void> changeCollectingState(Long fullDiningId, CollectingState collectingState);

@Operation(summary = "풀대접 서비스 수거 요청된 다회용기 갯수 조회")
Response<Integer> countCollectRequestContainers(User currentUser);

@Operation(summary = "풀대접 서비스 다회용기 납부 목록 조회")
Response<List<FullDiningResponse>> fullDinings(User currentUser);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package core.startup.mealtoktok.api.mealdelivery.dto;

import java.time.LocalDateTime;

import core.startup.mealtoktok.domain.mealdelivery.CollectingState;
import core.startup.mealtoktok.domain.mealdelivery.FullDining;

public record FullDiningResponse(
Long fullDiningId,
Long mealDeliveryId,
CollectingState collectState,
LocalDateTime collectedDateTime) {

public static FullDiningResponse from(FullDining fullDining) {
return new FullDiningResponse(
fullDining.getFullDiningId(),
fullDining.getMealDeliveryId(),
fullDining.getCollectState(),
fullDining.getCollectedDateTime());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package core.startup.mealtoktok.api.mealdelivery.dto;

import static com.fasterxml.jackson.annotation.JsonInclude.Include.*;

import core.startup.mealtoktok.domain.mealdelivery.DeliveryDateTime;
import core.startup.mealtoktok.domain.mealdelivery.DeliveryState;
import core.startup.mealtoktok.domain.mealdelivery.MealDelivery;
import core.startup.mealtoktok.domain.order.OrderedMeal;

import com.fasterxml.jackson.annotation.JsonInclude;

@JsonInclude(NON_NULL)
public record MealDeliveryResponse(
Long mealDeliveryId,
Long orderId,
OrderedMeal orderedMeal,
DeliveryState deliveryState,
DeliveryDateTime deliveryDateTime) {

public static MealDeliveryResponse from(MealDelivery mealDelivery) {
return new MealDeliveryResponse(
mealDelivery.getMealDeliveryId(),
mealDelivery.getTargetOrder().orderId(),
mealDelivery.getOrderedMeal(),
mealDelivery.getDeliveryState(),
mealDelivery.getDeliveryDateTime());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package core.startup.mealtoktok.domain.mealdelivery;

public enum CollectingState {
NOT_COLLECTED,
COLLECT_REQUESTED,
COLLECTED
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package core.startup.mealtoktok.domain.mealdelivery;

import java.time.LocalDateTime;

public record DeliveryDateTime(
LocalDateTime deliveryStartTime, LocalDateTime deliveryCompleteTime) {

public static DeliveryDateTime of(
LocalDateTime deliveryStartTime, LocalDateTime deliveryCompleteTime) {
return new DeliveryDateTime(deliveryStartTime, deliveryCompleteTime);
}

public static DeliveryDateTime start(LocalDateTime deliveryStartTime) {
return new DeliveryDateTime(deliveryStartTime, null);
}

public static DeliveryDateTime complete(
LocalDateTime deliveryStartTime, LocalDateTime deliveryCompleteTime) {
return new DeliveryDateTime(deliveryStartTime, deliveryCompleteTime);
}

public static DeliveryDateTime init() {
return new DeliveryDateTime(null, null);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package core.startup.mealtoktok.domain.mealdelivery;

public enum DeliveryState {
PENDING,
DELIVERING,
DELIVERED
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package core.startup.mealtoktok.domain.mealdelivery;

import java.time.LocalDateTime;

import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@Builder
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor(access = AccessLevel.PRIVATE)
public class FullDining {

private Long fullDiningId;
private Long mealDeliveryId;
private CollectingState collectState;
private LocalDateTime collectedDateTime;

public static FullDining create(MealDelivery mealDelivery) {
return new FullDining(
null, mealDelivery.getMealDeliveryId(), CollectingState.NOT_COLLECTED, null);
}

public void collectRequest() {
this.collectState = CollectingState.COLLECT_REQUESTED;
}

public void collect() {
this.collectState = CollectingState.COLLECTED;
this.collectedDateTime = LocalDateTime.now();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package core.startup.mealtoktok.domain.mealdelivery;

import java.time.LocalDateTime;
import java.util.List;

import org.springframework.stereotype.Component;

import lombok.RequiredArgsConstructor;

import core.startup.mealtoktok.domain.order.Orderer;

@Component
@RequiredArgsConstructor
public class FullDiningManager {

private final FullDiningRepository fullDiningRepository;

public void reserve(List<MealDelivery> mealDeliveries) {
List<FullDining> fullDinings =
mealDeliveries.parallelStream()
.filter(MealDelivery::hasFullDiningOption)
.map(FullDining::create)
.toList();
fullDiningRepository.saveAll(fullDinings);
}

public void collectRequest(TargetFullDining targetFullDining, CollectingState collectingState) {
FullDining fullDining = fullDiningRepository.find(targetFullDining);
switch (collectingState) {
case COLLECT_REQUESTED -> fullDining.collectRequest();
case COLLECTED -> fullDining.collect();
}
fullDiningRepository.update(fullDining);
}

public int countReturnableContainers(Orderer orderer, CollectingState collectingState) {
return fullDiningRepository.countByCollectingState(orderer, collectingState);
}

public List<FullDining> getFullDinings(
Orderer orderer, DeliveryState deliveryState, LocalDateTime validDateTime) {
return fullDiningRepository.findAll(orderer, deliveryState, validDateTime);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package core.startup.mealtoktok.domain.mealdelivery;

import java.time.LocalDateTime;
import java.util.List;

import core.startup.mealtoktok.domain.order.Orderer;

public interface FullDiningRepository {

void saveAll(List<FullDining> fullDinings);

void update(FullDining fullDining);

FullDining find(TargetFullDining targetFullDining);

List<FullDining> findAll(
Orderer orderer, DeliveryState deliveryState, LocalDateTime validDateTime);

int countByCollectingState(Orderer orderer, CollectingState collectingState);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package core.startup.mealtoktok.domain.mealdelivery;

import java.time.LocalDateTime;

import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;

import core.startup.mealtoktok.domain.order.OrderedMeal;
import core.startup.mealtoktok.domain.order.TargetOrder;

@Getter
@AllArgsConstructor(access = AccessLevel.PRIVATE)
@Builder
public class MealDelivery {

private Long mealDeliveryId;
private TargetOrder targetOrder;
private OrderedMeal orderedMeal;
private DeliveryState deliveryState;
private DeliveryDateTime deliveryDateTime;

public void startDelivery(LocalDateTime startDateTime) {
this.deliveryDateTime = DeliveryDateTime.start(startDateTime);
this.deliveryState = DeliveryState.DELIVERING;
}

public void completeDelivery(LocalDateTime completeDateTime) {
this.deliveryDateTime =
DeliveryDateTime.complete(deliveryDateTime.deliveryStartTime(), completeDateTime);
this.deliveryState = DeliveryState.DELIVERED;
}

public static MealDelivery create(TargetOrder targetOrder, OrderedMeal orderedMeal) {
return new MealDelivery(
null, targetOrder, orderedMeal, DeliveryState.PENDING, DeliveryDateTime.init());
}

public boolean hasFullDiningOption() {
return orderedMeal.hasFullDiningOption();
}
}
Loading

0 comments on commit b1b740d

Please sign in to comment.