├── src ├── main │ └── java │ │ └── com │ │ └── mayank │ │ └── fooddelivery │ │ ├── model │ │ ├── OrderCommandType.java │ │ ├── CouponCode.java │ │ ├── CartCommandType.java │ │ ├── PaymentStatus.java │ │ ├── OrderStatus.java │ │ ├── MealType.java │ │ ├── PaymentType.java │ │ ├── CuisineType.java │ │ ├── Location.java │ │ ├── Restaurant.java │ │ ├── User.java │ │ ├── FoodMenu.java │ │ ├── Bill.java │ │ ├── Address.java │ │ ├── MenuItem.java │ │ ├── Delivery.java │ │ ├── Payment.java │ │ └── Order.java │ │ ├── exceptions │ │ ├── FoodDeliveryException.java │ │ └── ExceptionType.java │ │ ├── datastore │ │ ├── UserData.java │ │ ├── PaymentData.java │ │ ├── OrderData.java │ │ ├── DeliveryData.java │ │ ├── FoodMenuData.java │ │ ├── RestaurantData.java │ │ └── CartData.java │ │ ├── FoodDeliveryStartApplication.java │ │ ├── strategy │ │ ├── PricingStrategy.java │ │ ├── FiveHundredOffPricingStrategy.java │ │ └── TwentyPercentOffPricingStrategy.java │ │ ├── commands │ │ ├── OrderCommandExecutor.java │ │ ├── CartCommandExecutor.java │ │ ├── CancelOrderCommandExecutor.java │ │ ├── RemoveCartCommandExecutor.java │ │ ├── PlaceOrderCommandExecutor.java │ │ └── AddCartCommandExecutor.java │ │ ├── controllers │ │ ├── PricingController.java │ │ ├── PaymentController.java │ │ ├── UserController.java │ │ ├── CartController.java │ │ ├── OrderController.java │ │ ├── DeliveryController.java │ │ ├── RestaurantController.java │ │ └── FoodMenuController.java │ │ └── services │ │ ├── PricingService.java │ │ ├── UserService.java │ │ ├── CartService.java │ │ ├── OrderService.java │ │ ├── PaymentService.java │ │ ├── RestaurantService.java │ │ ├── DeliveryService.java │ │ └── FoodMenuService.java └── test │ └── java │ └── com │ └── mayank │ └── fooddelivery │ ├── UserTest.java │ ├── TestHelper.java │ ├── RestaurantProcessTest.java │ ├── OrderProcessTest.java │ ├── FoodMenuTest.java │ ├── CartTest.java │ ├── PricingTest.java │ ├── PaymentTest.java │ └── DeliveryTest.java ├── README.md └── pom.xml /src/main/java/com/mayank/fooddelivery/model/OrderCommandType.java: -------------------------------------------------------------------------------- 1 | package com.mayank.fooddelivery.model; 2 | 3 | public enum OrderCommandType { 4 | PLACE, 5 | CANCEL 6 | } 7 | -------------------------------------------------------------------------------- /src/main/java/com/mayank/fooddelivery/model/CouponCode.java: -------------------------------------------------------------------------------- 1 | package com.mayank.fooddelivery.model; 2 | 3 | public enum CouponCode { 4 | TWENTY_PERCENT_OFF, 5 | FIVE_HUNDRED_OFF 6 | } 7 | -------------------------------------------------------------------------------- /src/main/java/com/mayank/fooddelivery/model/CartCommandType.java: -------------------------------------------------------------------------------- 1 | package com.mayank.fooddelivery.model; 2 | 3 | public enum CartCommandType { 4 | ADD_ITEM, 5 | REMOVE_ITEM, 6 | CLEAR_CART 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/com/mayank/fooddelivery/model/PaymentStatus.java: -------------------------------------------------------------------------------- 1 | package com.mayank.fooddelivery.model; 2 | 3 | public enum PaymentStatus { 4 | PENDING, 5 | APPROVED, 6 | DECLINED, 7 | TIMEOUT 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/com/mayank/fooddelivery/model/OrderStatus.java: -------------------------------------------------------------------------------- 1 | package com.mayank.fooddelivery.model; 2 | 3 | public enum OrderStatus { 4 | PENDING, 5 | WAITING_FOR_PAYMENT, 6 | PLACED, 7 | CANCELLED, 8 | OUT_FOR_DELIVERY, 9 | DELIVERED 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/com/mayank/fooddelivery/model/MealType.java: -------------------------------------------------------------------------------- 1 | package com.mayank.fooddelivery.model; 2 | 3 | public enum MealType { 4 | BREAKFAST, 5 | BRUNCH, 6 | ELEVENSES, 7 | LUNCH, 8 | DINNER, 9 | SUPPER, 10 | AFTERNOON_TEA, 11 | HIGH_TEA 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/com/mayank/fooddelivery/model/PaymentType.java: -------------------------------------------------------------------------------- 1 | package com.mayank.fooddelivery.model; 2 | 3 | public enum PaymentType { 4 | CREDIT_CARD, 5 | DEBIT_CARD, 6 | CASH_ON_DELIVERY, 7 | AMAZON_PAY, 8 | PAYTM, 9 | WALLET, 10 | PAYPAL 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/com/mayank/fooddelivery/exceptions/FoodDeliveryException.java: -------------------------------------------------------------------------------- 1 | package com.mayank.fooddelivery.exceptions; 2 | 3 | import lombok.AllArgsConstructor; 4 | 5 | @AllArgsConstructor 6 | public class FoodDeliveryException extends RuntimeException { 7 | private ExceptionType exceptionType; 8 | private String message; 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/com/mayank/fooddelivery/model/CuisineType.java: -------------------------------------------------------------------------------- 1 | package com.mayank.fooddelivery.model; 2 | 3 | public enum CuisineType { 4 | INDIAN_CUISINE, 5 | INDIAN_CHINESE, 6 | ITALIAN_CUISINE, 7 | ITALIAN_AMERICAN, 8 | CHINESE_CUISINE, 9 | GUJARATI, 10 | HYDERABAD, 11 | JAPANESE, 12 | SOUTH_INDIAN, 13 | KOREAN 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/com/mayank/fooddelivery/model/Location.java: -------------------------------------------------------------------------------- 1 | package com.mayank.fooddelivery.model; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Builder; 5 | import lombok.Getter; 6 | import lombok.ToString; 7 | 8 | @AllArgsConstructor 9 | @Builder 10 | @Getter 11 | @ToString 12 | public class Location { 13 | private double longitude; 14 | private double latitude; 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/mayank/fooddelivery/model/Restaurant.java: -------------------------------------------------------------------------------- 1 | package com.mayank.fooddelivery.model; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Builder; 5 | import lombok.Getter; 6 | import lombok.ToString; 7 | 8 | @AllArgsConstructor 9 | @Getter 10 | @Builder 11 | @ToString 12 | public class Restaurant { 13 | private String id; 14 | private String name; 15 | private Address address; 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/mayank/fooddelivery/datastore/UserData.java: -------------------------------------------------------------------------------- 1 | package com.mayank.fooddelivery.datastore; 2 | 3 | import com.mayank.fooddelivery.model.User; 4 | import lombok.Getter; 5 | import org.springframework.stereotype.Component; 6 | 7 | import java.util.HashMap; 8 | import java.util.Map; 9 | 10 | @Component 11 | @Getter 12 | public class UserData { 13 | private Map userById = new HashMap<>(); 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/com/mayank/fooddelivery/model/User.java: -------------------------------------------------------------------------------- 1 | package com.mayank.fooddelivery.model; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Builder; 5 | import lombok.Getter; 6 | import lombok.ToString; 7 | 8 | @AllArgsConstructor 9 | @Getter 10 | @Builder 11 | @ToString 12 | public class User { 13 | private String id; 14 | private String name; 15 | private long phoneNo; 16 | private Address address; 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/mayank/fooddelivery/FoodDeliveryStartApplication.java: -------------------------------------------------------------------------------- 1 | package com.mayank.fooddelivery; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class FoodDeliveryStartApplication { 8 | public static void main(String[] args) { 9 | SpringApplication.run(FoodDeliveryStartApplication.class, args); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/com/mayank/fooddelivery/strategy/PricingStrategy.java: -------------------------------------------------------------------------------- 1 | package com.mayank.fooddelivery.strategy; 2 | 3 | import com.mayank.fooddelivery.model.Bill; 4 | import com.mayank.fooddelivery.model.CouponCode; 5 | import com.mayank.fooddelivery.model.MenuItem; 6 | 7 | import java.util.List; 8 | 9 | 10 | public interface PricingStrategy { 11 | Bill generateBill(List menuItemList); 12 | 13 | boolean isApplicable(CouponCode couponCode); 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/com/mayank/fooddelivery/model/FoodMenu.java: -------------------------------------------------------------------------------- 1 | package com.mayank.fooddelivery.model; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Builder; 5 | import lombok.Getter; 6 | import lombok.ToString; 7 | 8 | import java.util.List; 9 | 10 | @AllArgsConstructor 11 | @Builder 12 | @Getter 13 | @ToString 14 | public class FoodMenu { 15 | private String id; 16 | private List restaurantIds; 17 | private List menuItemList; 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/mayank/fooddelivery/model/Bill.java: -------------------------------------------------------------------------------- 1 | package com.mayank.fooddelivery.model; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Builder; 5 | import lombok.Getter; 6 | import lombok.ToString; 7 | 8 | @AllArgsConstructor 9 | @Builder 10 | @Getter 11 | @ToString 12 | public class Bill { 13 | private String id; 14 | private double totalCost; 15 | private double discount; 16 | private double tax; 17 | private double amountToBePaid; 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/mayank/fooddelivery/model/Address.java: -------------------------------------------------------------------------------- 1 | package com.mayank.fooddelivery.model; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Builder; 5 | import lombok.Getter; 6 | import lombok.ToString; 7 | 8 | @AllArgsConstructor 9 | @Builder 10 | @Getter 11 | @ToString 12 | public class Address { 13 | private String id; 14 | private String streetAddress; 15 | private String city; 16 | private String zipCode; 17 | private Location location; 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/mayank/fooddelivery/model/MenuItem.java: -------------------------------------------------------------------------------- 1 | package com.mayank.fooddelivery.model; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Builder; 5 | import lombok.Getter; 6 | import lombok.ToString; 7 | 8 | @AllArgsConstructor 9 | @Builder 10 | @Getter 11 | @ToString 12 | public class MenuItem { 13 | private String id; 14 | private String itemName; 15 | private CuisineType cuisineType; 16 | private MealType mealType; 17 | private double price; 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/mayank/fooddelivery/datastore/PaymentData.java: -------------------------------------------------------------------------------- 1 | package com.mayank.fooddelivery.datastore; 2 | 3 | import com.mayank.fooddelivery.model.Payment; 4 | import lombok.Getter; 5 | import org.springframework.stereotype.Component; 6 | 7 | import java.util.HashMap; 8 | import java.util.Map; 9 | 10 | @Component 11 | @Getter 12 | public class PaymentData { 13 | private Map paymentById = new HashMap<>(); 14 | private Map paymentIdByOrderId = new HashMap<>(); 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/mayank/fooddelivery/model/Delivery.java: -------------------------------------------------------------------------------- 1 | package com.mayank.fooddelivery.model; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Builder; 5 | import lombok.Getter; 6 | import lombok.ToString; 7 | 8 | import java.util.Date; 9 | 10 | @AllArgsConstructor 11 | @Builder 12 | @Getter 13 | @ToString 14 | public class Delivery { 15 | private String id; 16 | private String deliveryBoyId; 17 | private String userId; 18 | private String orderId; 19 | private Date deliveryTime; 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/com/mayank/fooddelivery/datastore/OrderData.java: -------------------------------------------------------------------------------- 1 | package com.mayank.fooddelivery.datastore; 2 | 3 | import com.mayank.fooddelivery.model.Order; 4 | import lombok.Getter; 5 | import org.springframework.stereotype.Component; 6 | 7 | import java.util.HashMap; 8 | import java.util.List; 9 | import java.util.Map; 10 | 11 | @Component 12 | @Getter 13 | public class OrderData { 14 | private Map orderById = new HashMap<>(); 15 | private Map> orderIdsByUserId = new HashMap<>(); 16 | 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/mayank/fooddelivery/exceptions/ExceptionType.java: -------------------------------------------------------------------------------- 1 | package com.mayank.fooddelivery.exceptions; 2 | 3 | public enum ExceptionType { 4 | RESTAURANT_ALREADY_EXISTS, 5 | RESTAURANT_NOT_FOUND, 6 | MENU_NOT_FOUND, 7 | MENU_ALREADY_EXISTS, 8 | CART_IS_EMPTY, 9 | MENU_ITEM_NOT_FOUND, 10 | ORDER_NOT_VALID, 11 | ORDER_NOT_FOUND, 12 | USER_ALREADY_EXISTS, 13 | USER_NOT_FOUND, 14 | PAYMENT_NOT_EXISTS, 15 | DELIVERY_ALREADY_EXISTS, 16 | DELIVERY_NOT_FOUND, 17 | ORDER_NOT_CONFIRMED 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/mayank/fooddelivery/datastore/DeliveryData.java: -------------------------------------------------------------------------------- 1 | package com.mayank.fooddelivery.datastore; 2 | 3 | import com.mayank.fooddelivery.model.Delivery; 4 | import lombok.Getter; 5 | import org.springframework.stereotype.Component; 6 | 7 | import java.util.HashMap; 8 | import java.util.List; 9 | import java.util.Map; 10 | 11 | @Component 12 | @Getter 13 | public class DeliveryData { 14 | private Map deliveryById = new HashMap<>(); 15 | private Map> deliveryIdsByDeliveryBoyId = new HashMap<>(); 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/mayank/fooddelivery/datastore/FoodMenuData.java: -------------------------------------------------------------------------------- 1 | package com.mayank.fooddelivery.datastore; 2 | 3 | import com.mayank.fooddelivery.model.FoodMenu; 4 | import com.mayank.fooddelivery.model.MenuItem; 5 | import lombok.Getter; 6 | import org.springframework.stereotype.Component; 7 | 8 | import java.util.HashMap; 9 | import java.util.Map; 10 | 11 | @Component 12 | @Getter 13 | public class FoodMenuData { 14 | private Map foodMenuById = new HashMap<>(); 15 | private Map foodMenuIdByRestaurantId = new HashMap<>(); 16 | private Map menuItemById = new HashMap<>(); 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/mayank/fooddelivery/datastore/RestaurantData.java: -------------------------------------------------------------------------------- 1 | package com.mayank.fooddelivery.datastore; 2 | 3 | import com.mayank.fooddelivery.model.Restaurant; 4 | import lombok.Getter; 5 | import org.springframework.stereotype.Component; 6 | 7 | import java.util.HashMap; 8 | import java.util.List; 9 | import java.util.Map; 10 | 11 | @Component 12 | @Getter 13 | public class RestaurantData { 14 | private Map restaurantById = new HashMap<>(); 15 | private Map> restaurantIdsByName = new HashMap<>(); 16 | private Map> restaurantIdsByCity = new HashMap<>(); 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/mayank/fooddelivery/commands/OrderCommandExecutor.java: -------------------------------------------------------------------------------- 1 | package com.mayank.fooddelivery.commands; 2 | 3 | import com.mayank.fooddelivery.exceptions.ExceptionType; 4 | import com.mayank.fooddelivery.exceptions.FoodDeliveryException; 5 | import com.mayank.fooddelivery.model.Order; 6 | import com.mayank.fooddelivery.model.OrderCommandType; 7 | import lombok.NonNull; 8 | 9 | public abstract class OrderCommandExecutor { 10 | public void execute(@NonNull final Order order) { 11 | if (!isValid(order)) { 12 | throw new FoodDeliveryException(ExceptionType.ORDER_NOT_VALID, "order not valid"); 13 | } 14 | executeCommand(order); 15 | } 16 | 17 | public abstract boolean isValid(final Order order); 18 | 19 | public abstract void executeCommand(final Order order); 20 | 21 | public abstract boolean isApplicable(final OrderCommandType orderCommandType); 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/com/mayank/fooddelivery/controllers/PricingController.java: -------------------------------------------------------------------------------- 1 | package com.mayank.fooddelivery.controllers; 2 | 3 | import com.mayank.fooddelivery.model.Bill; 4 | import com.mayank.fooddelivery.model.CouponCode; 5 | import com.mayank.fooddelivery.services.PricingService; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.web.bind.annotation.GetMapping; 8 | import org.springframework.web.bind.annotation.RestController; 9 | 10 | @RestController 11 | public class PricingController { 12 | private PricingService pricingService; 13 | 14 | @Autowired 15 | public PricingController(PricingService pricingService) { 16 | this.pricingService = pricingService; 17 | } 18 | 19 | @GetMapping(value = "/user/{userId}/cart/{couponCode}") 20 | public Bill getBill(final String userId, final String restaurantId, final CouponCode couponCode) { 21 | return pricingService.getBill(userId, restaurantId, couponCode); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/com/mayank/fooddelivery/model/Payment.java: -------------------------------------------------------------------------------- 1 | package com.mayank.fooddelivery.model; 2 | 3 | import lombok.Getter; 4 | import lombok.ToString; 5 | 6 | import java.util.Map; 7 | 8 | @Getter 9 | @ToString 10 | public class Payment { 11 | private String id; 12 | private String orderId; 13 | private Map amountPaid; 14 | private CouponCode couponCode; 15 | private PaymentStatus paymentStatus; 16 | 17 | public Payment(String id, String orderId, Map amountPaid, CouponCode couponCode) { 18 | this.id = id; 19 | this.orderId = orderId; 20 | this.amountPaid = amountPaid; 21 | this.couponCode = couponCode; 22 | paymentStatus = PaymentStatus.PENDING; 23 | } 24 | 25 | public void markPaymentDeclined() { 26 | paymentStatus = PaymentStatus.DECLINED; 27 | } 28 | 29 | public void markPaymentApproved() { 30 | paymentStatus = PaymentStatus.APPROVED; 31 | } 32 | 33 | public void markPaymentTimeout() { 34 | paymentStatus = PaymentStatus.TIMEOUT; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/com/mayank/fooddelivery/commands/CartCommandExecutor.java: -------------------------------------------------------------------------------- 1 | package com.mayank.fooddelivery.commands; 2 | 3 | import com.mayank.fooddelivery.exceptions.ExceptionType; 4 | import com.mayank.fooddelivery.exceptions.FoodDeliveryException; 5 | import com.mayank.fooddelivery.model.CartCommandType; 6 | import lombok.NonNull; 7 | 8 | public abstract class CartCommandExecutor { 9 | public void execute(@NonNull final String userId, @NonNull final String restaurantId, 10 | @NonNull final String itemId) { 11 | if (!isValid(userId, restaurantId, itemId)) { 12 | throw new FoodDeliveryException(ExceptionType.MENU_ITEM_NOT_FOUND, "menu item not found"); 13 | } 14 | executeCommand(userId, restaurantId, itemId); 15 | } 16 | 17 | public abstract boolean isValid(final String userId, final String restaurantId, final String itemId); 18 | 19 | public abstract void executeCommand(final String userId, final String restaurantId, final String itemId); 20 | 21 | public abstract boolean isApplicable(final CartCommandType cartCommandType); 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/com/mayank/fooddelivery/strategy/FiveHundredOffPricingStrategy.java: -------------------------------------------------------------------------------- 1 | package com.mayank.fooddelivery.strategy; 2 | 3 | import com.mayank.fooddelivery.model.Bill; 4 | import com.mayank.fooddelivery.model.CouponCode; 5 | import com.mayank.fooddelivery.model.MenuItem; 6 | 7 | import java.util.List; 8 | import java.util.UUID; 9 | 10 | public class FiveHundredOffPricingStrategy implements PricingStrategy { 11 | private final double discount = 500; 12 | 13 | @Override 14 | public Bill generateBill(List menuItemList) { 15 | double totalCost = menuItemList.stream().mapToDouble(menuItem -> menuItem.getPrice()).sum(); 16 | return Bill.builder() 17 | .id(UUID.randomUUID().toString()) 18 | .totalCost(totalCost) 19 | .discount(discount) 20 | .amountToBePaid(totalCost - discount) 21 | .tax((totalCost - discount) * 0.05) 22 | .build(); 23 | } 24 | 25 | @Override 26 | public boolean isApplicable(CouponCode couponCode) { 27 | return couponCode == CouponCode.FIVE_HUNDRED_OFF; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/test/java/com/mayank/fooddelivery/UserTest.java: -------------------------------------------------------------------------------- 1 | package com.mayank.fooddelivery; 2 | 3 | import com.mayank.fooddelivery.controllers.UserController; 4 | import com.mayank.fooddelivery.datastore.UserData; 5 | import com.mayank.fooddelivery.services.UserService; 6 | import org.junit.jupiter.api.BeforeEach; 7 | import org.junit.jupiter.api.Test; 8 | 9 | public class UserTest { 10 | UserController userController; 11 | 12 | @BeforeEach 13 | void setup() { 14 | UserService userService = new UserService(new UserData()); 15 | userController = new UserController(userService); 16 | } 17 | 18 | @Test 19 | void UserFlowTest() { 20 | userController.addUser(TestHelper.buildUser("USER1","User Name1")); 21 | userController.addUser(TestHelper.buildUser("USER2","User Name2")); 22 | userController.addUser(TestHelper.buildUser("USER3","User Name3")); 23 | 24 | System.out.println(userController.getUser("USER2")); 25 | 26 | userController.deleteUser("USER1"); 27 | 28 | userController.updateUser(TestHelper.buildUser("USER2", "User Name4")); 29 | System.out.println(userController.getUser("USER2")); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/com/mayank/fooddelivery/commands/CancelOrderCommandExecutor.java: -------------------------------------------------------------------------------- 1 | package com.mayank.fooddelivery.commands; 2 | 3 | import com.mayank.fooddelivery.datastore.OrderData; 4 | import com.mayank.fooddelivery.model.Order; 5 | import com.mayank.fooddelivery.model.OrderCommandType; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.stereotype.Component; 8 | 9 | @Component 10 | public class CancelOrderCommandExecutor extends OrderCommandExecutor { 11 | private OrderData orderData; 12 | 13 | @Autowired 14 | public CancelOrderCommandExecutor(OrderData orderData) { 15 | this.orderData = orderData; 16 | } 17 | 18 | @Override 19 | public boolean isValid(Order order) { 20 | if (!orderData.getOrderById().containsKey(order.getId())) { 21 | return false; 22 | } 23 | return true; 24 | } 25 | 26 | @Override 27 | public void executeCommand(Order order) { 28 | order.markOrderCancelled(); 29 | } 30 | 31 | @Override 32 | public boolean isApplicable(OrderCommandType orderCommandType) { 33 | return orderCommandType == OrderCommandType.CANCEL; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/com/mayank/fooddelivery/strategy/TwentyPercentOffPricingStrategy.java: -------------------------------------------------------------------------------- 1 | package com.mayank.fooddelivery.strategy; 2 | 3 | import com.mayank.fooddelivery.model.Bill; 4 | import com.mayank.fooddelivery.model.CouponCode; 5 | import com.mayank.fooddelivery.model.MenuItem; 6 | 7 | import java.util.List; 8 | import java.util.UUID; 9 | 10 | public class TwentyPercentOffPricingStrategy implements PricingStrategy { 11 | private final double discountPercent = 20; 12 | 13 | @Override 14 | public Bill generateBill(List menuItemList) { 15 | double totalCost = menuItemList.stream().mapToDouble(menuItem -> menuItem.getPrice()).sum(); 16 | return Bill.builder() 17 | .id(UUID.randomUUID().toString()) 18 | .totalCost(totalCost) 19 | .discount(totalCost * discountPercent / 100) 20 | .amountToBePaid(totalCost - totalCost * discountPercent / 100) 21 | .tax((totalCost - totalCost * discountPercent / 100) * 0.05) 22 | .build(); 23 | } 24 | 25 | @Override 26 | public boolean isApplicable(CouponCode couponCode) { 27 | return couponCode == CouponCode.TWENTY_PERCENT_OFF; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/com/mayank/fooddelivery/datastore/CartData.java: -------------------------------------------------------------------------------- 1 | package com.mayank.fooddelivery.datastore; 2 | 3 | import com.mayank.fooddelivery.exceptions.ExceptionType; 4 | import com.mayank.fooddelivery.exceptions.FoodDeliveryException; 5 | import lombok.Getter; 6 | import lombok.NonNull; 7 | import org.springframework.stereotype.Component; 8 | 9 | import java.util.HashMap; 10 | import java.util.List; 11 | import java.util.Map; 12 | 13 | @Component 14 | @Getter 15 | public class CartData { 16 | private Map>> userToRestaurantIdToMenuItemIds = new HashMap<>(); 17 | 18 | public List getMenuItemIds(@NonNull final String userId, @NonNull final String restaurantId) { 19 | Map> restaurantIdToMenuItemIds = getRestaurantIdToMenuItemIds(userId); 20 | if (!restaurantIdToMenuItemIds.containsKey(restaurantId)) { 21 | throw new FoodDeliveryException(ExceptionType.CART_IS_EMPTY, "Cart is empty for this restaurant"); 22 | } 23 | return restaurantIdToMenuItemIds.get(restaurantId); 24 | } 25 | 26 | public Map> getRestaurantIdToMenuItemIds(@NonNull final String userId) { 27 | return userToRestaurantIdToMenuItemIds.getOrDefault(userId, new HashMap<>()); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/com/mayank/fooddelivery/controllers/PaymentController.java: -------------------------------------------------------------------------------- 1 | package com.mayank.fooddelivery.controllers; 2 | 3 | import com.mayank.fooddelivery.model.Payment; 4 | import com.mayank.fooddelivery.services.PaymentService; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.web.bind.annotation.GetMapping; 7 | import org.springframework.web.bind.annotation.PostMapping; 8 | import org.springframework.web.bind.annotation.RestController; 9 | 10 | @RestController 11 | public class PaymentController { 12 | private PaymentService paymentService; 13 | 14 | @Autowired 15 | public PaymentController(PaymentService paymentService) { 16 | this.paymentService = paymentService; 17 | } 18 | 19 | @PostMapping(value = "/payment") 20 | public void addPayment(final Payment payment) { 21 | paymentService.addPayment(payment); 22 | } 23 | 24 | @GetMapping(value = "/payment/{paymentId}") 25 | public Payment getPaymentById(final String paymentId) { 26 | return paymentService.getPaymentById(paymentId); 27 | } 28 | 29 | @GetMapping(value = "/payment/order/{orderId}") 30 | public Payment getPaymentByOrderId(final String orderId) { 31 | return paymentService.getPaymentByOrderId(orderId); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/com/mayank/fooddelivery/model/Order.java: -------------------------------------------------------------------------------- 1 | package com.mayank.fooddelivery.model; 2 | 3 | import lombok.Getter; 4 | import lombok.ToString; 5 | 6 | import java.util.List; 7 | 8 | @Getter 9 | @ToString 10 | public class Order { 11 | private String id; 12 | private String userId; 13 | private String restaurantId; 14 | private List menuItemList; 15 | private OrderStatus orderStatus; 16 | 17 | public Order(String id, String userId, String restaurantId, List menuItemList) { 18 | this.id = id; 19 | this.userId = userId; 20 | this.restaurantId = restaurantId; 21 | this.menuItemList = menuItemList; 22 | this.orderStatus = OrderStatus.PENDING; 23 | } 24 | 25 | public void markOrderCancelled() { 26 | orderStatus = OrderStatus.CANCELLED; 27 | } 28 | 29 | public void markOrderDelivered() { 30 | orderStatus = OrderStatus.DELIVERED; 31 | } 32 | 33 | public void markOrderOutForDelivery() { 34 | orderStatus = OrderStatus.OUT_FOR_DELIVERY; 35 | } 36 | 37 | public void markOrderPlaced() { 38 | orderStatus = OrderStatus.PLACED; 39 | } 40 | 41 | public void markOrderWaitingForPayment() { 42 | orderStatus = OrderStatus.WAITING_FOR_PAYMENT; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/com/mayank/fooddelivery/services/PricingService.java: -------------------------------------------------------------------------------- 1 | package com.mayank.fooddelivery.services; 2 | 3 | import com.mayank.fooddelivery.model.Bill; 4 | import com.mayank.fooddelivery.model.CouponCode; 5 | import com.mayank.fooddelivery.model.MenuItem; 6 | import com.mayank.fooddelivery.strategy.PricingStrategy; 7 | import lombok.NonNull; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.stereotype.Service; 10 | 11 | import java.util.List; 12 | 13 | @Service 14 | public class PricingService { 15 | private List pricingStrategyList; 16 | private CartService cartService; 17 | 18 | @Autowired 19 | public PricingService(List pricingStrategyList, CartService cartService) { 20 | this.pricingStrategyList = pricingStrategyList; 21 | this.cartService = cartService; 22 | } 23 | 24 | public Bill getBill(@NonNull final String userId, @NonNull final String restaurantId, 25 | @NonNull final CouponCode couponCode) { 26 | List menuItemList = cartService.getAllItemsOfCart(userId, restaurantId); 27 | return pricingStrategyList.stream().filter(pricingStrategy -> pricingStrategy.isApplicable(couponCode)) 28 | .findAny().get().generateBill(menuItemList); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/com/mayank/fooddelivery/commands/RemoveCartCommandExecutor.java: -------------------------------------------------------------------------------- 1 | package com.mayank.fooddelivery.commands; 2 | 3 | import com.mayank.fooddelivery.datastore.CartData; 4 | import com.mayank.fooddelivery.model.CartCommandType; 5 | import lombok.NonNull; 6 | import org.springframework.stereotype.Component; 7 | 8 | import java.util.List; 9 | 10 | @Component 11 | public class RemoveCartCommandExecutor extends CartCommandExecutor { 12 | private CartData cartData; 13 | 14 | public RemoveCartCommandExecutor(CartData cartData) { 15 | this.cartData = cartData; 16 | } 17 | 18 | @Override 19 | public boolean isValid(@NonNull final String userId, @NonNull final String restaurantId, 20 | @NonNull final String itemId) { 21 | return cartData.getMenuItemIds(userId, restaurantId).contains(itemId); 22 | } 23 | 24 | @Override 25 | public void executeCommand(@NonNull final String userId, @NonNull final String restaurantId, 26 | @NonNull final String itemId) { 27 | List menuItemIds = cartData.getMenuItemIds(userId, restaurantId); 28 | menuItemIds.remove(itemId); 29 | } 30 | 31 | @Override 32 | public boolean isApplicable(CartCommandType cartCommandType) { 33 | return cartCommandType == CartCommandType.REMOVE_ITEM; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/test/java/com/mayank/fooddelivery/TestHelper.java: -------------------------------------------------------------------------------- 1 | package com.mayank.fooddelivery; 2 | 3 | import com.mayank.fooddelivery.model.*; 4 | import org.mockito.internal.matchers.Or; 5 | 6 | public class TestHelper { 7 | public static Restaurant buildRestaurant(String id, String name) { 8 | return Restaurant.builder() 9 | .id(id) 10 | .name(name) 11 | .address(buildAddress("ADD1", "CITY")) 12 | .build(); 13 | } 14 | 15 | public static Address buildAddress(String id, String city) { 16 | return Address.builder() 17 | .id(id) 18 | .city(city) 19 | .build(); 20 | } 21 | 22 | public static MenuItem buildMenuItem(String id, String name, double price) { 23 | return MenuItem.builder() 24 | .id(id) 25 | .itemName(name) 26 | .cuisineType(CuisineType.ITALIAN_CUISINE) 27 | .mealType(MealType.DINNER) 28 | .price(price) 29 | .build(); 30 | } 31 | 32 | public static User buildUser(String id, String name) { 33 | return User.builder() 34 | .id(id) 35 | .name(name) 36 | .phoneNo(9988998899L) 37 | .address(buildAddress("ADD1", "CITY1")) 38 | .build(); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/com/mayank/fooddelivery/controllers/UserController.java: -------------------------------------------------------------------------------- 1 | package com.mayank.fooddelivery.controllers; 2 | 3 | import com.mayank.fooddelivery.model.User; 4 | import com.mayank.fooddelivery.services.UserService; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.web.bind.annotation.GetMapping; 7 | import org.springframework.web.bind.annotation.PostMapping; 8 | import org.springframework.web.bind.annotation.PutMapping; 9 | import org.springframework.web.bind.annotation.RestController; 10 | 11 | @RestController 12 | public class UserController { 13 | private UserService userService; 14 | 15 | @Autowired 16 | public UserController(UserService userService) { 17 | this.userService = userService; 18 | } 19 | 20 | @PostMapping(value = "/user") 21 | public void addUser(final User user) { 22 | userService.addUser(user); 23 | } 24 | 25 | @PostMapping(value = "/user/delete") 26 | public void deleteUser(final String userId) { 27 | userService.deleteUser(userId); 28 | } 29 | 30 | @PutMapping(value = "/user/update") 31 | public void updateUser(final User user) { 32 | userService.updateUser(user); 33 | } 34 | 35 | @GetMapping(value = "/user/{userId}") 36 | public User getUser(final String userId) { 37 | return userService.getUser(userId); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/test/java/com/mayank/fooddelivery/RestaurantProcessTest.java: -------------------------------------------------------------------------------- 1 | package com.mayank.fooddelivery; 2 | 3 | import com.mayank.fooddelivery.controllers.RestaurantController; 4 | import com.mayank.fooddelivery.datastore.RestaurantData; 5 | import com.mayank.fooddelivery.services.RestaurantService; 6 | import org.junit.jupiter.api.BeforeEach; 7 | import org.junit.jupiter.api.Test; 8 | 9 | public class RestaurantProcessTest { 10 | RestaurantController restaurantController; 11 | 12 | @BeforeEach 13 | void setup() { 14 | RestaurantService restaurantService = new RestaurantService(new RestaurantData()); 15 | restaurantController = new RestaurantController(restaurantService); 16 | } 17 | 18 | @Test 19 | void RestaurantFlowTest() { 20 | restaurantController.addRestaurant(TestHelper.buildRestaurant("REST1", "Restaurant")); 21 | restaurantController.addRestaurant(TestHelper.buildRestaurant("REST2", "Restaurant")); 22 | restaurantController.addRestaurant(TestHelper.buildRestaurant("REST3", "Restaurant 2")); 23 | 24 | System.out.println(restaurantController.getAllRestaurant()); 25 | 26 | System.out.println(restaurantController.getRestaurantById("REST2")); 27 | 28 | System.out.println(restaurantController.getRestaurantsByName("Restaurant")); 29 | 30 | System.out.println(restaurantController.getRestaurantsByCity("CITY")); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/com/mayank/fooddelivery/commands/PlaceOrderCommandExecutor.java: -------------------------------------------------------------------------------- 1 | package com.mayank.fooddelivery.commands; 2 | 3 | import com.mayank.fooddelivery.datastore.OrderData; 4 | import com.mayank.fooddelivery.model.Order; 5 | import com.mayank.fooddelivery.model.OrderCommandType; 6 | import com.mayank.fooddelivery.model.OrderStatus; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.stereotype.Component; 9 | 10 | import java.util.ArrayList; 11 | import java.util.List; 12 | 13 | @Component 14 | public class PlaceOrderCommandExecutor extends OrderCommandExecutor { 15 | private OrderData orderData; 16 | 17 | @Autowired 18 | public PlaceOrderCommandExecutor(OrderData orderData) { 19 | this.orderData = orderData; 20 | } 21 | 22 | @Override 23 | public boolean isValid(Order order) { 24 | if (!(order.getOrderStatus() == OrderStatus.PENDING)) { 25 | return false; 26 | } 27 | return true; 28 | } 29 | 30 | @Override 31 | public void executeCommand(Order order) { 32 | orderData.getOrderById().put(order.getId(), order); 33 | List orderIds = orderData.getOrderIdsByUserId().getOrDefault(order.getUserId(), new ArrayList<>()); 34 | orderIds.add(order.getId()); 35 | orderData.getOrderIdsByUserId().put(order.getUserId(), orderIds); 36 | order.markOrderWaitingForPayment(); 37 | } 38 | 39 | @Override 40 | public boolean isApplicable(OrderCommandType orderCommandType) { 41 | return orderCommandType == OrderCommandType.PLACE; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/com/mayank/fooddelivery/controllers/CartController.java: -------------------------------------------------------------------------------- 1 | package com.mayank.fooddelivery.controllers; 2 | 3 | import com.mayank.fooddelivery.model.CartCommandType; 4 | import com.mayank.fooddelivery.model.MenuItem; 5 | import com.mayank.fooddelivery.services.CartService; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.web.bind.annotation.GetMapping; 8 | import org.springframework.web.bind.annotation.PostMapping; 9 | import org.springframework.web.bind.annotation.PutMapping; 10 | import org.springframework.web.bind.annotation.RestController; 11 | 12 | import java.util.List; 13 | 14 | @RestController 15 | public class CartController { 16 | private CartService cartService; 17 | 18 | @Autowired 19 | public CartController(CartService cartService) { 20 | this.cartService = cartService; 21 | } 22 | 23 | @PostMapping(value = "/user/{userId}/cart/update") 24 | public void updateCart(final String userId, final String restaurantId, final String itemId, 25 | final CartCommandType cartCommandType) { 26 | cartService.updateCart(userId, restaurantId, itemId, cartCommandType); 27 | } 28 | 29 | @PutMapping(value = "/user/{userId}/cart/clear") 30 | public void clearCart(final String userId, final String restaurantId) { 31 | cartService.clearCart(userId, restaurantId); 32 | } 33 | 34 | @GetMapping(value = "/user/{userId}/cart") 35 | public List getAllItemsOfCart(final String userId, final String restaurantId) { 36 | return cartService.getAllItemsOfCart(userId, restaurantId); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/com/mayank/fooddelivery/controllers/OrderController.java: -------------------------------------------------------------------------------- 1 | package com.mayank.fooddelivery.controllers; 2 | 3 | import com.mayank.fooddelivery.model.Order; 4 | import com.mayank.fooddelivery.model.OrderCommandType; 5 | import com.mayank.fooddelivery.services.OrderService; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.web.bind.annotation.GetMapping; 8 | import org.springframework.web.bind.annotation.PostMapping; 9 | import org.springframework.web.bind.annotation.RestController; 10 | 11 | import java.util.List; 12 | 13 | @RestController 14 | public class OrderController { 15 | private OrderService orderService; 16 | 17 | @Autowired 18 | public OrderController(OrderService orderService) { 19 | this.orderService = orderService; 20 | } 21 | 22 | @PostMapping(value = "/user/{userId}/order/update") 23 | public void updateOrder(final Order order, final OrderCommandType orderCommandType) { 24 | orderService.updateOrder(order, orderCommandType); 25 | } 26 | 27 | @GetMapping(value = "/order/{orderId}") 28 | public Order getOrderById(final String orderId) { 29 | return orderService.getOrderById(orderId); 30 | } 31 | 32 | @GetMapping(value = "/user/{userId}/order") 33 | public List getAllOrders(final String userId) { 34 | return orderService.getAllOrders(userId); 35 | } 36 | 37 | @GetMapping(value = "/user/{userId}/order/{restaurantId}") 38 | public List getAllOrdersByRestaurantId(final String userId, final String restaurantId) { 39 | return orderService.getAllOrdersByRestaurantId(userId, restaurantId); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/com/mayank/fooddelivery/controllers/DeliveryController.java: -------------------------------------------------------------------------------- 1 | package com.mayank.fooddelivery.controllers; 2 | 3 | import com.mayank.fooddelivery.model.Delivery; 4 | import com.mayank.fooddelivery.model.OrderStatus; 5 | import com.mayank.fooddelivery.services.DeliveryService; 6 | import lombok.NonNull; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.web.bind.annotation.GetMapping; 9 | import org.springframework.web.bind.annotation.PostMapping; 10 | import org.springframework.web.bind.annotation.RestController; 11 | 12 | import java.util.List; 13 | 14 | @RestController 15 | public class DeliveryController { 16 | private DeliveryService deliveryService; 17 | 18 | @Autowired 19 | public DeliveryController(DeliveryService deliveryService) { 20 | this.deliveryService = deliveryService; 21 | } 22 | 23 | @PostMapping(value = "/delivery") 24 | public void addDelivery(@NonNull final Delivery delivery) { 25 | deliveryService.addDelivery(delivery); 26 | } 27 | 28 | @GetMapping(value = "/delivery/{deliveryId}") 29 | public Delivery getDeliveryById(@NonNull final String deliveryId) { 30 | return deliveryService.getDeliveryById(deliveryId); 31 | } 32 | 33 | @GetMapping(value = "/delivery/list/{deliveryBoyId}") 34 | public List getDeliveriesByDeliveryBoyId(@NonNull final String deliveryBoyId) { 35 | return deliveryService.getDeliveriesByDeliveryBoyId(deliveryBoyId); 36 | } 37 | 38 | @GetMapping(value = "/delivery/orderStatus/{deliveryId}") 39 | public OrderStatus getOrderStatus(@NonNull final String deliveryId) { 40 | return deliveryService.getOrderStatus(deliveryId); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/com/mayank/fooddelivery/controllers/RestaurantController.java: -------------------------------------------------------------------------------- 1 | package com.mayank.fooddelivery.controllers; 2 | 3 | import com.mayank.fooddelivery.model.Restaurant; 4 | import com.mayank.fooddelivery.services.RestaurantService; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.http.HttpStatus; 7 | import org.springframework.web.bind.annotation.*; 8 | 9 | import java.util.List; 10 | 11 | @RestController 12 | public class RestaurantController { 13 | private RestaurantService restaurantService; 14 | 15 | @Autowired 16 | public RestaurantController(RestaurantService restaurantService) { 17 | this.restaurantService = restaurantService; 18 | } 19 | 20 | @PostMapping(value = "/restaurant") 21 | @ResponseStatus(HttpStatus.CREATED) 22 | public void addRestaurant(@RequestBody final Restaurant restaurant) { 23 | restaurantService.addRestaurant(restaurant); 24 | } 25 | 26 | @GetMapping(value = "/restaurants") 27 | public List getAllRestaurant() { 28 | return restaurantService.getAllRestaurants(); 29 | } 30 | 31 | @GetMapping(value = "/restaurant/{restaurantId}") 32 | public Restaurant getRestaurantById(final String restaurantId) { 33 | return restaurantService.getRestaurantById(restaurantId); 34 | } 35 | 36 | @GetMapping(value = "/restaurants/name/{restaurantName}") 37 | public List getRestaurantsByName(final String restaurantName) { 38 | return restaurantService.getRestaurantsByName(restaurantName); 39 | } 40 | 41 | @GetMapping(value = "/restaurants/city/{city}") 42 | public List getRestaurantsByCity(final String city) { 43 | return restaurantService.getRestaurantsByCity(city); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # lld-food-delivery-zomato-swiggy 2 | Low Level Design of Food delivery app - Zomato, Swiggy, UberEats 3 | 4 | # Requirements 5 | 1. Restaurant can register themselves. 6 | 2. User can create, update, delete, get their profiles. 7 | 3. User can search for the restaurant using restaurant name, city name. 8 | 4. Restaurant can add, update foodmenu. 9 | 5. User can see the foodmenu. User can get the food items based on Meal type or Cuisine type. 10 | 6. User can add/remove items to/from the cart. User can get all the items of the cart. 11 | 7. User can place or cancel the order. User can get all the orders ordered by him/her. 12 | 8. User can apply the coupons. User can get the detailed bill containing tax details. 13 | 9. User can made a payment using different modes of payment - credit card, wallet, etc. 14 | 10. Delivery boy can get all the deliveries made by him using his Id. 15 | 11. User can get the order status anytime. Success, Out for Delivery, Delivered, etc. 16 | 17 | # Services 18 | * [RestaurantService](src/main/java/com/mayank/fooddelivery/services/RestaurantService.java) 19 | * [UserService](src/main/java/com/mayank/fooddelivery/services/UserService.java) 20 | * [FoodMenuService](src/main/java/com/mayank/fooddelivery/services/FoodMenuService.java) 21 | * [CartService](src/main/java/com/mayank/fooddelivery/services/CartService.java) 22 | * [OrderService](src/main/java/com/mayank/fooddelivery/services/OrderService.java) 23 | * [PricingService](src/main/java/com/mayank/fooddelivery/services/PricingService.java) 24 | * [PaymentService](src/main/java/com/mayank/fooddelivery/services/PaymentService.java) 25 | * [DeliveryService](src/main/java/com/mayank/fooddelivery/services/DeliveryService.java) 26 | 27 | # Explanation 28 | [Medium Story](https://medium.com/@mayankbansal933/food-delivery-app-lld-c1409ef49266?source=friends_link&sk=6c753c471dae09bf1fcbe79bee2d8be1) 29 | -------------------------------------------------------------------------------- /src/main/java/com/mayank/fooddelivery/services/UserService.java: -------------------------------------------------------------------------------- 1 | package com.mayank.fooddelivery.services; 2 | 3 | import com.mayank.fooddelivery.datastore.UserData; 4 | import com.mayank.fooddelivery.exceptions.ExceptionType; 5 | import com.mayank.fooddelivery.exceptions.FoodDeliveryException; 6 | import com.mayank.fooddelivery.model.User; 7 | import lombok.NonNull; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.stereotype.Service; 10 | 11 | @Service 12 | public class UserService { 13 | private UserData userData; 14 | 15 | @Autowired 16 | public UserService(UserData userData) { 17 | this.userData = userData; 18 | } 19 | 20 | public void addUser(@NonNull final User user) { 21 | if (userData.getUserById().containsKey(user.getId())) { 22 | throw new FoodDeliveryException(ExceptionType.USER_ALREADY_EXISTS, "userId already exists"); 23 | } 24 | userData.getUserById().put(user.getId(), user); 25 | } 26 | 27 | public void deleteUser(@NonNull final String userId) { 28 | if (!userData.getUserById().containsKey(userId)) { 29 | throw new FoodDeliveryException(ExceptionType.USER_NOT_FOUND, "user not found"); 30 | } 31 | userData.getUserById().remove(userId); 32 | } 33 | 34 | public void updateUser(@NonNull final User user) { 35 | if (!userData.getUserById().containsKey(user.getId())) { 36 | throw new FoodDeliveryException(ExceptionType.USER_NOT_FOUND, "user not found"); 37 | } 38 | userData.getUserById().put(user.getId(), user); 39 | } 40 | 41 | public User getUser(@NonNull final String userId) { 42 | if (!userData.getUserById().containsKey(userId)) { 43 | throw new FoodDeliveryException(ExceptionType.USER_NOT_FOUND, "user not found"); 44 | } 45 | return userData.getUserById().get(userId); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/test/java/com/mayank/fooddelivery/OrderProcessTest.java: -------------------------------------------------------------------------------- 1 | package com.mayank.fooddelivery; 2 | 3 | import com.mayank.fooddelivery.commands.CancelOrderCommandExecutor; 4 | import com.mayank.fooddelivery.commands.OrderCommandExecutor; 5 | import com.mayank.fooddelivery.commands.PlaceOrderCommandExecutor; 6 | import com.mayank.fooddelivery.controllers.OrderController; 7 | import com.mayank.fooddelivery.datastore.OrderData; 8 | import com.mayank.fooddelivery.model.MenuItem; 9 | import com.mayank.fooddelivery.model.Order; 10 | import com.mayank.fooddelivery.model.OrderCommandType; 11 | import com.mayank.fooddelivery.services.OrderService; 12 | import org.junit.jupiter.api.BeforeEach; 13 | import org.junit.jupiter.api.Test; 14 | 15 | import java.util.ArrayList; 16 | import java.util.List; 17 | 18 | public class OrderProcessTest { 19 | OrderController orderController; 20 | 21 | @BeforeEach 22 | void setup() { 23 | OrderData orderData = new OrderData(); 24 | List orderCommandExecutorList = List.of(new PlaceOrderCommandExecutor(orderData), 25 | new CancelOrderCommandExecutor(orderData)); 26 | OrderService orderService = new OrderService(orderData, orderCommandExecutorList); 27 | orderController = new OrderController(orderService); 28 | } 29 | 30 | @Test 31 | void OrderFlowTest() { 32 | List menuItemList = new ArrayList<>(); 33 | for (int i = 1; i <= 2; i++) { 34 | menuItemList.add(TestHelper.buildMenuItem("ITEM" + i, "Item Name " + i, i * 1000)); 35 | } 36 | Order order = new Order("ORDER1", "USER1", "REST1", menuItemList); 37 | orderController.updateOrder(order, OrderCommandType.PLACE); 38 | 39 | System.out.println(orderController.getAllOrders("USER1")); 40 | 41 | System.out.println(orderController.getOrderById("ORDER1")); 42 | 43 | System.out.println(orderController.getAllOrdersByRestaurantId("USER1","REST1")); 44 | 45 | orderController.updateOrder(order, OrderCommandType.CANCEL); 46 | 47 | System.out.println(orderController.getOrderById("ORDER1")); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/com/mayank/fooddelivery/commands/AddCartCommandExecutor.java: -------------------------------------------------------------------------------- 1 | package com.mayank.fooddelivery.commands; 2 | 3 | import com.mayank.fooddelivery.datastore.CartData; 4 | import com.mayank.fooddelivery.model.CartCommandType; 5 | import com.mayank.fooddelivery.model.FoodMenu; 6 | import com.mayank.fooddelivery.services.FoodMenuService; 7 | import lombok.NonNull; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.stereotype.Component; 10 | 11 | import java.util.ArrayList; 12 | import java.util.HashMap; 13 | import java.util.List; 14 | import java.util.Map; 15 | 16 | @Component 17 | public class AddCartCommandExecutor extends CartCommandExecutor { 18 | private FoodMenuService foodMenuService; 19 | private CartData cartData; 20 | 21 | @Autowired 22 | public AddCartCommandExecutor(FoodMenuService foodMenuService, CartData cartData) { 23 | this.foodMenuService = foodMenuService; 24 | this.cartData = cartData; 25 | } 26 | 27 | @Override 28 | public boolean isValid(@NonNull final String userId, @NonNull final String restaurantId, 29 | @NonNull final String itemId) { 30 | FoodMenu foodMenu = foodMenuService.getMenuByRestaurantId(restaurantId); 31 | return foodMenu.getMenuItemList().stream() 32 | .filter(menuItem -> menuItem.getId().equals(itemId)).findAny().isPresent(); 33 | } 34 | 35 | @Override 36 | public void executeCommand(@NonNull final String userId, @NonNull final String restaurantId, 37 | @NonNull final String itemId) { 38 | Map> restaurantIdToMenuItemIds = 39 | cartData.getUserToRestaurantIdToMenuItemIds().getOrDefault(userId, new HashMap<>()); 40 | List menuItemIds = restaurantIdToMenuItemIds.getOrDefault(restaurantId, new ArrayList<>()); 41 | menuItemIds.add(itemId); 42 | restaurantIdToMenuItemIds.put(restaurantId, menuItemIds); 43 | cartData.getUserToRestaurantIdToMenuItemIds().put(userId, restaurantIdToMenuItemIds); 44 | } 45 | 46 | @Override 47 | public boolean isApplicable(CartCommandType cartCommandType) { 48 | return cartCommandType == CartCommandType.ADD_ITEM; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/test/java/com/mayank/fooddelivery/FoodMenuTest.java: -------------------------------------------------------------------------------- 1 | package com.mayank.fooddelivery; 2 | 3 | import com.mayank.fooddelivery.controllers.FoodMenuController; 4 | import com.mayank.fooddelivery.datastore.FoodMenuData; 5 | import com.mayank.fooddelivery.model.CuisineType; 6 | import com.mayank.fooddelivery.model.MealType; 7 | import com.mayank.fooddelivery.model.MenuItem; 8 | import com.mayank.fooddelivery.services.FoodMenuService; 9 | import org.junit.jupiter.api.BeforeEach; 10 | import org.junit.jupiter.api.Test; 11 | 12 | import java.util.ArrayList; 13 | import java.util.List; 14 | 15 | public class FoodMenuTest { 16 | FoodMenuController foodMenuController; 17 | 18 | @BeforeEach 19 | void setup() { 20 | FoodMenuService foodMenuService = new FoodMenuService(new FoodMenuData()); 21 | foodMenuController = new FoodMenuController(foodMenuService); 22 | } 23 | 24 | @Test 25 | void FoodMenuFlowTest() { 26 | List menuItemList = new ArrayList<>(); 27 | for (int i = 1; i <= 2; i++) { 28 | menuItemList.add(TestHelper.buildMenuItem("ITEM" + i, "Item Name " + i, i * 1000)); 29 | } 30 | foodMenuController.addMenuByRestaurantId("MENU1", "REST1", menuItemList); 31 | foodMenuController.addMenuByRestaurantId("MENU2", "REST2", menuItemList); 32 | foodMenuController.addMenuByRestaurantId("MENU1", "REST3", menuItemList); 33 | 34 | System.out.println(foodMenuController.getMenuById("MENU1")); 35 | 36 | System.out.println(foodMenuController.getMenuByRestaurantId("REST2")); 37 | 38 | List menuItemList1 = new ArrayList<>(); 39 | for (int i = 3; i <= 4; i++) { 40 | menuItemList1.add(TestHelper.buildMenuItem("ITEM" + i, "Item Name" + i, i * 1000)); 41 | } 42 | foodMenuController.addMenuItemsByMenuId("MENU1", menuItemList1); 43 | 44 | foodMenuController.addMenuItemsByRestaurantId("REST2", menuItemList1); 45 | 46 | System.out.println(foodMenuController.getMenuItemsByRestaurantIdAndCuisine( 47 | "REST1", CuisineType.ITALIAN_CUISINE)); 48 | 49 | System.out.println(foodMenuController.getMenuItemsByRestaurantIdAndMealType( 50 | "REST1", MealType.DINNER)); 51 | 52 | 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/com/mayank/fooddelivery/services/CartService.java: -------------------------------------------------------------------------------- 1 | package com.mayank.fooddelivery.services; 2 | 3 | import com.mayank.fooddelivery.commands.CartCommandExecutor; 4 | import com.mayank.fooddelivery.datastore.CartData; 5 | import com.mayank.fooddelivery.model.CartCommandType; 6 | import com.mayank.fooddelivery.model.MenuItem; 7 | import lombok.NonNull; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.stereotype.Service; 10 | 11 | import java.util.ArrayList; 12 | import java.util.HashMap; 13 | import java.util.List; 14 | import java.util.Map; 15 | 16 | @Service 17 | public class CartService { 18 | private CartData cartData; 19 | private List cartCommandExecutorList; 20 | private FoodMenuService foodMenuService; 21 | 22 | @Autowired 23 | public CartService(CartData cartData, List cartCommandExecutorList, 24 | FoodMenuService foodMenuService) { 25 | this.cartData = cartData; 26 | this.cartCommandExecutorList = cartCommandExecutorList; 27 | this.foodMenuService = foodMenuService; 28 | } 29 | 30 | public void clearCart(@NonNull final String userId, @NonNull final String restaurantId) { 31 | Map> restaurantIdToMenuItemIds = cartData.getUserToRestaurantIdToMenuItemIds() 32 | .getOrDefault(userId, new HashMap<>()); 33 | restaurantIdToMenuItemIds.put(restaurantId, new ArrayList<>()); 34 | } 35 | 36 | public void updateCart(@NonNull final String userId, @NonNull final String restaurantId, 37 | @NonNull final String itemId, @NonNull final CartCommandType cartCommandType) { 38 | for (CartCommandExecutor cartCommandExecutor : cartCommandExecutorList) { 39 | if (cartCommandExecutor.isApplicable(cartCommandType)) { 40 | cartCommandExecutor.execute(userId, restaurantId, itemId); 41 | } 42 | } 43 | } 44 | 45 | public List getAllItemsOfCart(@NonNull final String userId, @NonNull final String restaurantId) { 46 | List menuItems = new ArrayList<>(); 47 | List menuItemIds = cartData.getMenuItemIds(userId, restaurantId); 48 | menuItemIds.forEach(menuItem -> menuItems.add(foodMenuService.getMenuItemById(menuItem))); 49 | return menuItems; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/com/mayank/fooddelivery/services/OrderService.java: -------------------------------------------------------------------------------- 1 | package com.mayank.fooddelivery.services; 2 | 3 | import com.mayank.fooddelivery.commands.OrderCommandExecutor; 4 | import com.mayank.fooddelivery.datastore.OrderData; 5 | import com.mayank.fooddelivery.exceptions.ExceptionType; 6 | import com.mayank.fooddelivery.exceptions.FoodDeliveryException; 7 | import com.mayank.fooddelivery.model.Order; 8 | import com.mayank.fooddelivery.model.OrderCommandType; 9 | import lombok.NonNull; 10 | import org.springframework.beans.factory.annotation.Autowired; 11 | import org.springframework.stereotype.Service; 12 | 13 | import java.util.ArrayList; 14 | import java.util.List; 15 | import java.util.Optional; 16 | import java.util.stream.Collectors; 17 | 18 | @Service 19 | public class OrderService { 20 | private OrderData orderData; 21 | private List orderCommandExecutorList; 22 | 23 | @Autowired 24 | public OrderService(OrderData orderData, List orderCommandExecutorList) { 25 | this.orderData = orderData; 26 | this.orderCommandExecutorList = orderCommandExecutorList; 27 | } 28 | 29 | public void updateOrder(@NonNull final Order order, @NonNull final OrderCommandType orderCommandType) { 30 | for (OrderCommandExecutor orderCommandExecutor : orderCommandExecutorList) { 31 | if (orderCommandExecutor.isApplicable(orderCommandType)) { 32 | orderCommandExecutor.execute(order); 33 | } 34 | } 35 | } 36 | 37 | public Order getOrderById(@NonNull final String orderId) { 38 | if (!orderData.getOrderById().containsKey(orderId)) { 39 | throw new FoodDeliveryException(ExceptionType.ORDER_NOT_FOUND, "order not found"); 40 | } 41 | return orderData.getOrderById().get(orderId); 42 | } 43 | 44 | public List getAllOrdersByRestaurantId(@NonNull final String userId, @NonNull final String restaurantId) { 45 | List orderList = getAllOrders(userId); 46 | return orderList.stream().filter(order -> order.getRestaurantId() 47 | .equals(restaurantId)).collect(Collectors.toList()); 48 | } 49 | 50 | public List getAllOrders(@NonNull final String userId) { 51 | List orderList = new ArrayList<>(); 52 | List orderIds = orderData.getOrderIdsByUserId().get(userId); 53 | if (Optional.of(orderIds).isPresent()) { 54 | orderIds.forEach(orderId -> orderList.add(getOrderById(orderId))); 55 | } 56 | return orderList; 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /src/main/java/com/mayank/fooddelivery/services/PaymentService.java: -------------------------------------------------------------------------------- 1 | package com.mayank.fooddelivery.services; 2 | 3 | import com.mayank.fooddelivery.datastore.PaymentData; 4 | import com.mayank.fooddelivery.exceptions.ExceptionType; 5 | import com.mayank.fooddelivery.exceptions.FoodDeliveryException; 6 | import com.mayank.fooddelivery.model.Bill; 7 | import com.mayank.fooddelivery.model.Order; 8 | import com.mayank.fooddelivery.model.Payment; 9 | import lombok.NonNull; 10 | import org.springframework.beans.factory.annotation.Autowired; 11 | import org.springframework.stereotype.Service; 12 | 13 | import java.math.BigDecimal; 14 | 15 | @Service 16 | public class PaymentService { 17 | private PaymentData paymentData; 18 | private PricingService pricingService; 19 | private OrderService orderService; 20 | 21 | @Autowired 22 | public PaymentService(PaymentData paymentData, PricingService pricingService, OrderService orderService) { 23 | this.paymentData = paymentData; 24 | this.pricingService = pricingService; 25 | this.orderService = orderService; 26 | } 27 | 28 | public void addPayment(@NonNull final Payment payment) { 29 | Order order = orderService.getOrderById(payment.getOrderId()); 30 | if (!validatePayment(payment, order)) { 31 | order.markOrderCancelled(); 32 | payment.markPaymentDeclined(); 33 | return; 34 | } 35 | paymentData.getPaymentById().put(payment.getId(), payment); 36 | paymentData.getPaymentIdByOrderId().put(payment.getOrderId(), payment.getId()); 37 | order.markOrderPlaced(); 38 | payment.markPaymentApproved(); 39 | } 40 | 41 | public Payment getPaymentById(@NonNull final String paymentId) { 42 | if (!paymentData.getPaymentById().containsKey(paymentId)) { 43 | throw new FoodDeliveryException(ExceptionType.PAYMENT_NOT_EXISTS, "payment not exists"); 44 | } 45 | return paymentData.getPaymentById().get(paymentId); 46 | } 47 | 48 | public Payment getPaymentByOrderId(@NonNull final String orderId) { 49 | String paymentId = paymentData.getPaymentIdByOrderId().get(orderId); 50 | return getPaymentById(paymentId); 51 | } 52 | 53 | private boolean validatePayment(Payment payment, Order order) { 54 | Bill bill = pricingService.getBill(order.getUserId(), order.getRestaurantId(), payment.getCouponCode()); 55 | double amountPaid = payment.getAmountPaid().values().stream().mapToDouble(amount -> amount).sum(); 56 | return BigDecimal.valueOf(amountPaid).compareTo(BigDecimal.valueOf(bill.getAmountToBePaid())) == 0; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/test/java/com/mayank/fooddelivery/CartTest.java: -------------------------------------------------------------------------------- 1 | package com.mayank.fooddelivery; 2 | 3 | import com.mayank.fooddelivery.commands.AddCartCommandExecutor; 4 | import com.mayank.fooddelivery.commands.CartCommandExecutor; 5 | import com.mayank.fooddelivery.commands.RemoveCartCommandExecutor; 6 | import com.mayank.fooddelivery.controllers.CartController; 7 | import com.mayank.fooddelivery.controllers.FoodMenuController; 8 | import com.mayank.fooddelivery.datastore.CartData; 9 | import com.mayank.fooddelivery.datastore.FoodMenuData; 10 | import com.mayank.fooddelivery.model.CartCommandType; 11 | import com.mayank.fooddelivery.model.MenuItem; 12 | import com.mayank.fooddelivery.services.CartService; 13 | import com.mayank.fooddelivery.services.FoodMenuService; 14 | import org.junit.jupiter.api.BeforeEach; 15 | import org.junit.jupiter.api.Test; 16 | 17 | import java.util.ArrayList; 18 | import java.util.List; 19 | 20 | public class CartTest { 21 | CartController cartController; 22 | FoodMenuController foodMenuController; 23 | 24 | @BeforeEach 25 | void setup() { 26 | CartData cartData = new CartData(); 27 | FoodMenuService foodMenuService = new FoodMenuService(new FoodMenuData()); 28 | List commandExecutors = List.of(new AddCartCommandExecutor(foodMenuService, cartData), 29 | new RemoveCartCommandExecutor(cartData)); 30 | CartService cartService = new CartService(cartData, commandExecutors, foodMenuService); 31 | cartController = new CartController(cartService); 32 | foodMenuController = new FoodMenuController(foodMenuService); 33 | } 34 | 35 | @Test 36 | void CartTest() { 37 | List menuItemList = new ArrayList<>(); 38 | for (int i = 1; i <= 2; i++) { 39 | menuItemList.add(TestHelper.buildMenuItem("ITEM" + i, "Item Name " + i, i * 1000)); 40 | } 41 | foodMenuController.addMenuByRestaurantId("MENU1", "REST1", menuItemList); 42 | foodMenuController.addMenuByRestaurantId("MENU2", "REST2", menuItemList); 43 | foodMenuController.addMenuByRestaurantId("MENU1", "REST3", menuItemList); 44 | 45 | cartController.updateCart("USER1","REST1","ITEM2", CartCommandType.ADD_ITEM); 46 | 47 | System.out.println(cartController.getAllItemsOfCart("USER1", "REST1")); 48 | 49 | cartController.updateCart("USER1","REST1","ITEM2", CartCommandType.REMOVE_ITEM); 50 | 51 | System.out.println(cartController.getAllItemsOfCart("USER1", "REST1")); 52 | 53 | cartController.updateCart("USER1","REST1","ITEM2", CartCommandType.ADD_ITEM); 54 | 55 | System.out.println(cartController.getAllItemsOfCart("USER1", "REST1")); 56 | 57 | cartController.clearCart("USER1", "REST1"); 58 | 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/main/java/com/mayank/fooddelivery/controllers/FoodMenuController.java: -------------------------------------------------------------------------------- 1 | package com.mayank.fooddelivery.controllers; 2 | 3 | import com.mayank.fooddelivery.model.CuisineType; 4 | import com.mayank.fooddelivery.model.FoodMenu; 5 | import com.mayank.fooddelivery.model.MealType; 6 | import com.mayank.fooddelivery.model.MenuItem; 7 | import com.mayank.fooddelivery.services.FoodMenuService; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.http.HttpStatus; 10 | import org.springframework.web.bind.annotation.*; 11 | 12 | import java.util.List; 13 | 14 | @RestController 15 | public class FoodMenuController { 16 | private FoodMenuService foodMenuService; 17 | 18 | @Autowired 19 | public FoodMenuController(FoodMenuService foodMenuService) { 20 | this.foodMenuService = foodMenuService; 21 | } 22 | 23 | @PostMapping(value = "/restaurant/menu") 24 | @ResponseStatus(HttpStatus.CREATED) 25 | public void addMenuByRestaurantId(final String menuId, final String restaurantId, 26 | final List menuItemList) { 27 | foodMenuService.addMenuByRestaurantId(menuId, restaurantId, menuItemList); 28 | } 29 | 30 | @GetMapping(value = "/menu/{menuId}") 31 | public FoodMenu getMenuById(final String menuId) { 32 | return foodMenuService.getMenuById(menuId); 33 | } 34 | 35 | @GetMapping(value = "/restaurant/{restaurantId}/menu") 36 | public FoodMenu getMenuByRestaurantId(final String restaurantId) { 37 | return foodMenuService.getMenuByRestaurantId(restaurantId); 38 | } 39 | 40 | @PutMapping(value = "/menu/items") 41 | public void addMenuItemsByMenuId(final String menuId, final List menuItemList) { 42 | foodMenuService.addMenuItemsByMenuId(menuId, menuItemList); 43 | } 44 | 45 | @PutMapping(value = "/restaurant/{restaurantId}/menu/items") 46 | public void addMenuItemsByRestaurantId(final String restaurantId, final List menuItemList) { 47 | foodMenuService.addMenuItemsByRestaurantId(restaurantId, menuItemList); 48 | } 49 | 50 | @GetMapping(value = "/restaurant/{restaurantId}/menu/cuisine/{cuisineType}") 51 | public List getMenuItemsByRestaurantIdAndCuisine(final String restaurantId, 52 | final CuisineType cuisineType) { 53 | return foodMenuService.getMenuItemsByRestaurantIdAndCuisine(restaurantId, cuisineType); 54 | } 55 | 56 | @GetMapping(value = "/restaurant/{restaurantId}/menu/meal/{mealType}") 57 | public List getMenuItemsByRestaurantIdAndMealType(final String restaurantId, 58 | final MealType mealType) { 59 | return foodMenuService.getMenuItemsByRestaurantIdAndMealType(restaurantId, mealType); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | org.springframework.boot 8 | spring-boot-starter-parent 9 | 2.2.2.RELEASE 10 | 11 | 12 | com.mayank 13 | lld-food-delivery-zomato-swiggy-ubereats 14 | 1.0-SNAPSHOT 15 | lld-food-delivery 16 | LLD for Food Delivery App 17 | 18 | 19 | 20 | org.springframework.boot 21 | spring-boot-starter 22 | 23 | 24 | 25 | org.springframework.boot 26 | spring-boot-starter-test 27 | test 28 | 29 | 30 | org.junit.vintage 31 | junit-vintage-engine 32 | 33 | 34 | 35 | 36 | org.springframework.boot 37 | spring-boot-starter-web 38 | 39 | 40 | 41 | 42 | org.springframework 43 | spring-web 44 | 5.2.2.RELEASE 45 | 46 | 47 | 48 | 49 | org.projectlombok 50 | lombok 51 | 1.18.10 52 | provided 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | org.springframework.boot 61 | spring-boot-maven-plugin 62 | 63 | 64 | org.apache.maven.plugins 65 | maven-compiler-plugin 66 | 67 | 9 68 | 9 69 | 70 | 71 | 72 | 73 | 74 | 75 | -------------------------------------------------------------------------------- /src/main/java/com/mayank/fooddelivery/services/RestaurantService.java: -------------------------------------------------------------------------------- 1 | package com.mayank.fooddelivery.services; 2 | 3 | import com.mayank.fooddelivery.datastore.RestaurantData; 4 | import com.mayank.fooddelivery.exceptions.ExceptionType; 5 | import com.mayank.fooddelivery.exceptions.FoodDeliveryException; 6 | import com.mayank.fooddelivery.model.Restaurant; 7 | import lombok.NonNull; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.stereotype.Service; 10 | 11 | import java.util.ArrayList; 12 | import java.util.List; 13 | 14 | @Service 15 | public class RestaurantService { 16 | private RestaurantData restaurantData; 17 | 18 | @Autowired 19 | public RestaurantService(RestaurantData restaurantData) { 20 | this.restaurantData = restaurantData; 21 | } 22 | 23 | public void addRestaurant(@NonNull final Restaurant restaurant) { 24 | if (restaurantData.getRestaurantById().containsKey(restaurant.getId())) { 25 | throw new FoodDeliveryException(ExceptionType.RESTAURANT_ALREADY_EXISTS, "Duplicate Restaurant"); 26 | } 27 | restaurantData.getRestaurantById().put(restaurant.getId(), restaurant); 28 | 29 | List restaurantIds = restaurantData.getRestaurantIdsByName() 30 | .getOrDefault(restaurant.getName(), new ArrayList<>()); 31 | restaurantIds.add(restaurant.getId()); 32 | restaurantData.getRestaurantIdsByName().put(restaurant.getName(), restaurantIds); 33 | 34 | List restaurantsByCity = restaurantData.getRestaurantIdsByCity() 35 | .getOrDefault(restaurant.getAddress().getCity(), new ArrayList<>()); 36 | restaurantsByCity.add(restaurant.getId()); 37 | restaurantData.getRestaurantIdsByCity().put(restaurant.getAddress().getCity(), restaurantsByCity); 38 | } 39 | 40 | public List getAllRestaurants() { 41 | return new ArrayList<>(restaurantData.getRestaurantById().values()); 42 | } 43 | 44 | public Restaurant getRestaurantById(@NonNull final String restaurantId) { 45 | if (!restaurantData.getRestaurantById().containsKey(restaurantId)) { 46 | throw new FoodDeliveryException(ExceptionType.RESTAURANT_NOT_FOUND, "Restaurant not exists"); 47 | } 48 | return restaurantData.getRestaurantById().get(restaurantId); 49 | } 50 | 51 | public List getRestaurantsByName(@NonNull final String restaurantName) { 52 | List restaurants = new ArrayList<>(); 53 | for (String restaurantId : restaurantData.getRestaurantIdsByName().get(restaurantName)) { 54 | restaurants.add(getRestaurantById(restaurantId)); 55 | } 56 | return restaurants; 57 | } 58 | 59 | public List getRestaurantsByCity(@NonNull final String city) { 60 | List restaurants = new ArrayList<>(); 61 | for (String restaurantId : restaurantData.getRestaurantIdsByCity().get(city)) { 62 | restaurants.add(getRestaurantById(restaurantId)); 63 | } 64 | return restaurants; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/test/java/com/mayank/fooddelivery/PricingTest.java: -------------------------------------------------------------------------------- 1 | package com.mayank.fooddelivery; 2 | 3 | import com.mayank.fooddelivery.commands.AddCartCommandExecutor; 4 | import com.mayank.fooddelivery.commands.CartCommandExecutor; 5 | import com.mayank.fooddelivery.commands.RemoveCartCommandExecutor; 6 | import com.mayank.fooddelivery.controllers.CartController; 7 | import com.mayank.fooddelivery.controllers.FoodMenuController; 8 | import com.mayank.fooddelivery.controllers.PricingController; 9 | import com.mayank.fooddelivery.datastore.CartData; 10 | import com.mayank.fooddelivery.datastore.FoodMenuData; 11 | import com.mayank.fooddelivery.model.CartCommandType; 12 | import com.mayank.fooddelivery.model.CouponCode; 13 | import com.mayank.fooddelivery.model.MenuItem; 14 | import com.mayank.fooddelivery.services.CartService; 15 | import com.mayank.fooddelivery.services.FoodMenuService; 16 | import com.mayank.fooddelivery.services.PricingService; 17 | import com.mayank.fooddelivery.strategy.FiveHundredOffPricingStrategy; 18 | import com.mayank.fooddelivery.strategy.PricingStrategy; 19 | import com.mayank.fooddelivery.strategy.TwentyPercentOffPricingStrategy; 20 | import org.junit.jupiter.api.BeforeEach; 21 | import org.junit.jupiter.api.Test; 22 | 23 | import java.util.ArrayList; 24 | import java.util.List; 25 | 26 | public class PricingTest { 27 | PricingController pricingController; 28 | FoodMenuController foodMenuController; 29 | CartController cartController; 30 | 31 | @BeforeEach 32 | void setup() { 33 | List pricingStrategyList = List.of(new TwentyPercentOffPricingStrategy(), 34 | new FiveHundredOffPricingStrategy()); 35 | CartData cartData = new CartData(); 36 | FoodMenuService foodMenuService = new FoodMenuService(new FoodMenuData()); 37 | List commandExecutors = List.of(new AddCartCommandExecutor(foodMenuService, cartData), 38 | new RemoveCartCommandExecutor(cartData)); 39 | CartService cartService = new CartService(cartData, commandExecutors, foodMenuService); 40 | PricingService pricingService = new PricingService(pricingStrategyList, cartService); 41 | pricingController = new PricingController(pricingService); 42 | cartController = new CartController(cartService); 43 | foodMenuController = new FoodMenuController(foodMenuService); 44 | } 45 | 46 | @Test 47 | void PricingTest(){ 48 | List menuItemList = new ArrayList<>(); 49 | for (int i = 1; i <= 2; i++) { 50 | menuItemList.add(TestHelper.buildMenuItem("ITEM" + i, "Item Name " + i, i * 1000)); 51 | } 52 | foodMenuController.addMenuByRestaurantId("MENU1", "REST1", menuItemList); 53 | foodMenuController.addMenuByRestaurantId("MENU2", "REST2", menuItemList); 54 | foodMenuController.addMenuByRestaurantId("MENU1", "REST3", menuItemList); 55 | 56 | cartController.updateCart("USER1","REST1","ITEM2", CartCommandType.ADD_ITEM); 57 | 58 | System.out.println(pricingController 59 | .getBill("USER1", "REST1", CouponCode.TWENTY_PERCENT_OFF)); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/com/mayank/fooddelivery/services/DeliveryService.java: -------------------------------------------------------------------------------- 1 | package com.mayank.fooddelivery.services; 2 | 3 | import com.mayank.fooddelivery.datastore.DeliveryData; 4 | import com.mayank.fooddelivery.exceptions.ExceptionType; 5 | import com.mayank.fooddelivery.exceptions.FoodDeliveryException; 6 | import com.mayank.fooddelivery.model.Delivery; 7 | import com.mayank.fooddelivery.model.Order; 8 | import com.mayank.fooddelivery.model.OrderStatus; 9 | import lombok.NonNull; 10 | import org.springframework.beans.factory.annotation.Autowired; 11 | import org.springframework.stereotype.Service; 12 | 13 | import java.util.ArrayList; 14 | import java.util.Date; 15 | import java.util.List; 16 | 17 | @Service 18 | public class DeliveryService { 19 | private DeliveryData deliveryData; 20 | private OrderService orderService; 21 | 22 | @Autowired 23 | public DeliveryService(DeliveryData deliveryData, OrderService orderService) { 24 | this.deliveryData = deliveryData; 25 | this.orderService = orderService; 26 | } 27 | 28 | public void addDelivery(@NonNull final Delivery delivery) { 29 | if (deliveryData.getDeliveryById().containsKey(delivery)) { 30 | throw new FoodDeliveryException(ExceptionType.DELIVERY_ALREADY_EXISTS, "delivery already exists"); 31 | } 32 | Order order = orderService.getOrderById(delivery.getOrderId()); 33 | if (order.getOrderStatus() != OrderStatus.PLACED) { 34 | throw new FoodDeliveryException(ExceptionType.ORDER_NOT_CONFIRMED, "Order not confirmed"); 35 | } 36 | deliveryData.getDeliveryById().put(delivery.getId(), delivery); 37 | List deliveryIds = deliveryData.getDeliveryIdsByDeliveryBoyId() 38 | .getOrDefault(delivery.getId(), new ArrayList<>()); 39 | deliveryIds.add(delivery.getId()); 40 | deliveryData.getDeliveryIdsByDeliveryBoyId().put(delivery.getDeliveryBoyId(), deliveryIds); 41 | } 42 | 43 | public Delivery getDeliveryById(@NonNull final String deliveryId) { 44 | if (!deliveryData.getDeliveryById().containsKey(deliveryId)) { 45 | throw new FoodDeliveryException(ExceptionType.DELIVERY_NOT_FOUND, "delivery not found"); 46 | } 47 | return deliveryData.getDeliveryById().get(deliveryId); 48 | } 49 | 50 | public List getDeliveriesByDeliveryBoyId(@NonNull final String deliveryBoyId) { 51 | List deliveryList = new ArrayList<>(); 52 | List deliveryIds = deliveryData.getDeliveryIdsByDeliveryBoyId().get(deliveryBoyId); 53 | deliveryIds.forEach(id -> deliveryList.add(getDeliveryById(id))); 54 | return deliveryList; 55 | } 56 | 57 | public OrderStatus getOrderStatus(@NonNull final String deliveryId) { 58 | Delivery delivery = getDeliveryById(deliveryId); 59 | Order order = orderService.getOrderById(delivery.getOrderId()); 60 | updateOrderStatus(delivery, order); 61 | return order.getOrderStatus(); 62 | } 63 | 64 | private void updateOrderStatus(@NonNull final Delivery delivery, @NonNull final Order order) { 65 | long diffInTime = new Date().getTime() - delivery.getDeliveryTime().getTime(); 66 | long diffInMinutes = diffInTime / (60 * 1000) % 60; 67 | if (diffInMinutes > 30) { 68 | order.markOrderDelivered(); 69 | } else if (diffInMinutes > 20) { 70 | order.markOrderOutForDelivery(); 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/test/java/com/mayank/fooddelivery/PaymentTest.java: -------------------------------------------------------------------------------- 1 | package com.mayank.fooddelivery; 2 | 3 | import com.mayank.fooddelivery.commands.*; 4 | import com.mayank.fooddelivery.controllers.CartController; 5 | import com.mayank.fooddelivery.controllers.FoodMenuController; 6 | import com.mayank.fooddelivery.controllers.OrderController; 7 | import com.mayank.fooddelivery.controllers.PaymentController; 8 | import com.mayank.fooddelivery.datastore.CartData; 9 | import com.mayank.fooddelivery.datastore.FoodMenuData; 10 | import com.mayank.fooddelivery.datastore.OrderData; 11 | import com.mayank.fooddelivery.datastore.PaymentData; 12 | import com.mayank.fooddelivery.model.*; 13 | import com.mayank.fooddelivery.services.*; 14 | import com.mayank.fooddelivery.strategy.FiveHundredOffPricingStrategy; 15 | import com.mayank.fooddelivery.strategy.PricingStrategy; 16 | import com.mayank.fooddelivery.strategy.TwentyPercentOffPricingStrategy; 17 | import org.junit.jupiter.api.BeforeEach; 18 | import org.junit.jupiter.api.Test; 19 | 20 | import java.util.ArrayList; 21 | import java.util.HashMap; 22 | import java.util.List; 23 | import java.util.Map; 24 | 25 | public class PaymentTest { 26 | PaymentController paymentController; 27 | OrderController orderController; 28 | FoodMenuController foodMenuController; 29 | CartController cartController; 30 | 31 | @BeforeEach 32 | void setup() { 33 | OrderData orderData = new OrderData(); 34 | List orderCommandExecutorList = List.of(new PlaceOrderCommandExecutor(orderData), 35 | new CancelOrderCommandExecutor(orderData)); 36 | OrderService orderService = new OrderService(orderData, orderCommandExecutorList); 37 | 38 | List pricingStrategyList = List.of(new TwentyPercentOffPricingStrategy(), 39 | new FiveHundredOffPricingStrategy()); 40 | CartData cartData = new CartData(); 41 | FoodMenuService foodMenuService = new FoodMenuService(new FoodMenuData()); 42 | List commandExecutors = List.of(new AddCartCommandExecutor(foodMenuService, cartData), 43 | new RemoveCartCommandExecutor(cartData)); 44 | CartService cartService = new CartService(cartData, commandExecutors, foodMenuService); 45 | PricingService pricingService = new PricingService(pricingStrategyList, cartService); 46 | 47 | PaymentService paymentService = new PaymentService(new PaymentData(), pricingService, orderService); 48 | paymentController = new PaymentController(paymentService); 49 | orderController = new OrderController(orderService); 50 | foodMenuController = new FoodMenuController(foodMenuService); 51 | cartController = new CartController(cartService); 52 | } 53 | 54 | @Test 55 | void PaymentFlowTest() { 56 | List menuItemList = new ArrayList<>(); 57 | for (int i = 1; i <= 2; i++) { 58 | menuItemList.add(TestHelper.buildMenuItem("ITEM" + i, "Item Name " + i, i * 1000)); 59 | } 60 | 61 | foodMenuController.addMenuByRestaurantId("MENU1", "REST1", menuItemList); 62 | foodMenuController.addMenuByRestaurantId("MENU2", "REST2", menuItemList); 63 | foodMenuController.addMenuByRestaurantId("MENU1", "REST3", menuItemList); 64 | 65 | cartController.updateCart("USER1", "REST1", "ITEM2", CartCommandType.ADD_ITEM); 66 | 67 | Order order = new Order("ORDER1", "USER1", "REST1", menuItemList); 68 | orderController.updateOrder(order, OrderCommandType.PLACE); 69 | 70 | Map amountPaidMap = new HashMap<>(); 71 | amountPaidMap.put(PaymentType.DEBIT_CARD, 1200.0); 72 | amountPaidMap.put(PaymentType.WALLET, 400.0); 73 | paymentController.addPayment( 74 | new Payment("PAYMENT1", "ORDER1", amountPaidMap, CouponCode.TWENTY_PERCENT_OFF)); 75 | 76 | System.out.println(orderController.getOrderById("ORDER1")); 77 | 78 | System.out.println(paymentController.getPaymentById("PAYMENT1")); 79 | 80 | System.out.println(paymentController.getPaymentByOrderId("ORDER1")); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/main/java/com/mayank/fooddelivery/services/FoodMenuService.java: -------------------------------------------------------------------------------- 1 | package com.mayank.fooddelivery.services; 2 | 3 | import com.mayank.fooddelivery.datastore.FoodMenuData; 4 | import com.mayank.fooddelivery.exceptions.ExceptionType; 5 | import com.mayank.fooddelivery.exceptions.FoodDeliveryException; 6 | import com.mayank.fooddelivery.model.CuisineType; 7 | import com.mayank.fooddelivery.model.FoodMenu; 8 | import com.mayank.fooddelivery.model.MealType; 9 | import com.mayank.fooddelivery.model.MenuItem; 10 | import lombok.NonNull; 11 | import org.springframework.beans.factory.annotation.Autowired; 12 | import org.springframework.stereotype.Service; 13 | 14 | import java.util.ArrayList; 15 | import java.util.List; 16 | import java.util.stream.Collectors; 17 | 18 | @Service 19 | public class FoodMenuService { 20 | private FoodMenuData foodMenuData; 21 | 22 | @Autowired 23 | public FoodMenuService(FoodMenuData foodMenuData) { 24 | this.foodMenuData = foodMenuData; 25 | } 26 | 27 | public void addMenuByRestaurantId(@NonNull final String menuId, @NonNull final String restaurantId, 28 | @NonNull final List menuItemList) { 29 | if (foodMenuData.getFoodMenuIdByRestaurantId().containsKey(restaurantId)) { 30 | throw new FoodDeliveryException(ExceptionType.MENU_ALREADY_EXISTS, "Menu Already exists for this " + 31 | "restaurant"); 32 | } 33 | FoodMenu foodMenu = foodMenuData.getFoodMenuById().getOrDefault(menuId, 34 | new FoodMenu(menuId, new ArrayList<>(), menuItemList)); 35 | foodMenu.getRestaurantIds().add(restaurantId); 36 | foodMenuData.getFoodMenuById().put(menuId, foodMenu); 37 | foodMenuData.getFoodMenuIdByRestaurantId().put(restaurantId, menuId); 38 | for (MenuItem menuItem : menuItemList) { 39 | foodMenuData.getMenuItemById().put(menuItem.getId(), menuItem); 40 | } 41 | } 42 | 43 | public FoodMenu getMenuById(@NonNull final String menuId) { 44 | if (!foodMenuData.getFoodMenuById().containsKey(menuId)) { 45 | throw new FoodDeliveryException(ExceptionType.MENU_NOT_FOUND, "Food Menu not exists"); 46 | } 47 | return foodMenuData.getFoodMenuById().get(menuId); 48 | } 49 | 50 | public FoodMenu getMenuByRestaurantId(@NonNull final String restaurantId) { 51 | if (!foodMenuData.getFoodMenuIdByRestaurantId().containsKey(restaurantId)) { 52 | throw new FoodDeliveryException(ExceptionType.MENU_NOT_FOUND, "Food Menu not exists"); 53 | } 54 | return getMenuById(foodMenuData.getFoodMenuIdByRestaurantId().get(restaurantId)); 55 | } 56 | 57 | public void addMenuItemsByMenuId(@NonNull final String menuId, @NonNull final List menuItemList) { 58 | for (MenuItem menuItem : menuItemList) { 59 | foodMenuData.getMenuItemById().put(menuItem.getId(), menuItem); 60 | } 61 | getMenuById(menuId).getMenuItemList().addAll(menuItemList); 62 | } 63 | 64 | public void addMenuItemsByRestaurantId(@NonNull final String restaurantId, 65 | @NonNull final List menuItemList) { 66 | for (MenuItem menuItem : menuItemList) { 67 | foodMenuData.getMenuItemById().put(menuItem.getId(), menuItem); 68 | } 69 | getMenuByRestaurantId(restaurantId).getMenuItemList().addAll(menuItemList); 70 | } 71 | 72 | public List getMenuItemsByRestaurantIdAndCuisine(@NonNull final String restaurantId, 73 | @NonNull final CuisineType cuisineType) { 74 | FoodMenu foodMenu = getMenuByRestaurantId(restaurantId); 75 | return foodMenu.getMenuItemList().stream().filter(menuItem -> menuItem.getCuisineType() == cuisineType) 76 | .collect(Collectors.toList()); 77 | } 78 | 79 | public List getMenuItemsByRestaurantIdAndMealType(@NonNull final String restaurantId, 80 | @NonNull final MealType mealType) { 81 | FoodMenu foodMenu = getMenuByRestaurantId(restaurantId); 82 | return foodMenu.getMenuItemList().stream().filter(menuItem -> menuItem.getMealType() == mealType) 83 | .collect(Collectors.toList()); 84 | } 85 | 86 | public MenuItem getMenuItemById(@NonNull final String itemId) { 87 | if (!foodMenuData.getMenuItemById().containsKey(itemId)) { 88 | throw new FoodDeliveryException(ExceptionType.MENU_ITEM_NOT_FOUND, "Menu Item not found"); 89 | } 90 | return foodMenuData.getMenuItemById().get(itemId); 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /src/test/java/com/mayank/fooddelivery/DeliveryTest.java: -------------------------------------------------------------------------------- 1 | package com.mayank.fooddelivery; 2 | 3 | import com.mayank.fooddelivery.commands.*; 4 | import com.mayank.fooddelivery.controllers.*; 5 | import com.mayank.fooddelivery.datastore.*; 6 | import com.mayank.fooddelivery.model.*; 7 | import com.mayank.fooddelivery.services.*; 8 | import com.mayank.fooddelivery.strategy.FiveHundredOffPricingStrategy; 9 | import com.mayank.fooddelivery.strategy.PricingStrategy; 10 | import com.mayank.fooddelivery.strategy.TwentyPercentOffPricingStrategy; 11 | import org.junit.jupiter.api.BeforeEach; 12 | import org.junit.jupiter.api.Test; 13 | 14 | import java.util.*; 15 | 16 | public class DeliveryTest { 17 | DeliveryController deliveryController; 18 | OrderController orderController; 19 | FoodMenuController foodMenuController; 20 | PaymentController paymentController; 21 | CartController cartController; 22 | 23 | @BeforeEach 24 | void setup() { 25 | OrderData orderData = new OrderData(); 26 | List orderCommandExecutorList = List.of(new PlaceOrderCommandExecutor(orderData), 27 | new CancelOrderCommandExecutor(orderData)); 28 | OrderService orderService = new OrderService(orderData, orderCommandExecutorList); 29 | 30 | List pricingStrategyList = List.of(new TwentyPercentOffPricingStrategy(), 31 | new FiveHundredOffPricingStrategy()); 32 | CartData cartData = new CartData(); 33 | FoodMenuService foodMenuService = new FoodMenuService(new FoodMenuData()); 34 | List commandExecutors = List.of(new AddCartCommandExecutor(foodMenuService, cartData), 35 | new RemoveCartCommandExecutor(cartData)); 36 | CartService cartService = new CartService(cartData, commandExecutors, foodMenuService); 37 | PricingService pricingService = new PricingService(pricingStrategyList, cartService); 38 | PaymentService paymentService = new PaymentService(new PaymentData(), pricingService, orderService); 39 | 40 | DeliveryService deliveryService = new DeliveryService(new DeliveryData(), orderService); 41 | deliveryController = new DeliveryController(deliveryService); 42 | paymentController = new PaymentController(paymentService); 43 | orderController = new OrderController(orderService); 44 | foodMenuController = new FoodMenuController(foodMenuService); 45 | cartController = new CartController(cartService); 46 | } 47 | 48 | @Test 49 | void DeliveryFlowTest() { 50 | List menuItemList = new ArrayList<>(); 51 | for (int i = 1; i <= 2; i++) { 52 | menuItemList.add(TestHelper.buildMenuItem("ITEM" + i, "Item Name " + i, i * 1000)); 53 | } 54 | 55 | foodMenuController.addMenuByRestaurantId("MENU1", "REST1", menuItemList); 56 | foodMenuController.addMenuByRestaurantId("MENU2", "REST2", menuItemList); 57 | foodMenuController.addMenuByRestaurantId("MENU1", "REST3", menuItemList); 58 | 59 | cartController.updateCart("USER1", "REST1", "ITEM2", CartCommandType.ADD_ITEM); 60 | 61 | Order order = new Order("ORDER1", "USER1", "REST1", menuItemList); 62 | orderController.updateOrder(order, OrderCommandType.PLACE); 63 | 64 | Map amountPaidMap = new HashMap<>(); 65 | amountPaidMap.put(PaymentType.DEBIT_CARD, 1200.0); 66 | amountPaidMap.put(PaymentType.WALLET, 400.0); 67 | paymentController.addPayment( 68 | new Payment("PAYMENT1", "ORDER1", amountPaidMap, CouponCode.TWENTY_PERCENT_OFF)); 69 | 70 | Delivery delivery = Delivery.builder().id("ID1") 71 | .deliveryBoyId("DBID1") 72 | .orderId("ORDER1") 73 | .userId("USER1") 74 | .deliveryTime(new Date()) 75 | .build(); 76 | deliveryController.addDelivery(delivery); 77 | 78 | System.out.println(orderController.getOrderById("ORDER1")); 79 | 80 | System.out.println(paymentController.getPaymentById("PAYMENT1")); 81 | 82 | System.out.println(deliveryController.getDeliveryById("ID1")); 83 | 84 | System.out.println(deliveryController.getDeliveriesByDeliveryBoyId("DBID1")); 85 | 86 | System.out.println(deliveryController.getOrderStatus("ID1")); 87 | 88 | Delivery delivery2 = Delivery.builder().id("ID2") 89 | .deliveryBoyId("DBID2") 90 | .orderId("ORDER1") 91 | .userId("USER1") 92 | .deliveryTime(new Date(new Date().getTime() - 60000 * 24)) 93 | .build(); 94 | deliveryController.addDelivery(delivery2); 95 | System.out.println(deliveryController.getOrderStatus("ID2")); 96 | 97 | } 98 | } 99 | --------------------------------------------------------------------------------