@RequestMapping(value = "/buildOrder.html", method = RequestMethod.GET) public ModelAndView get(HttpServletRequest request) { if (LOGGER.isDebugEnabled()) { LOGGER.debug("Redirecting to current order details page"); } HttpSession session = request.getSession(true); String orderrestaurantid = (String) session.getAttribute("orderrestaurantid"); String restaurantid = (String) session.getAttribute("restaurantid"); Search search = (Search) session.getAttribute("search"); if (orderrestaurantid != null) { restaurantid = orderrestaurantid; } if (restaurantid == null) { if (search == null) { return new ModelAndView("redirect:/home.html", null); } else { return new ModelAndView("redirect:/search.html" + search.getQueryString()); } } else { Restaurant restaurant = restaurantRepository.findByRestaurantId(restaurantid); return new ModelAndView("redirect:/" + restaurant.getUrl()); } }
@ResponseBody @RequestMapping(value = "/admin/upload.ajax", method = RequestMethod.POST) public ResponseEntity<byte[]> upload( @RequestParam("restaurantId") String restaurantId, @RequestParam("file") CommonsMultipartFile file) throws Exception { Map<String, Object> model = new HashMap<String, Object>(); try { S3Object object = new S3Object(basePath + "/" + restaurantId); object.setDataInputStream(file.getInputStream()); object.setContentLength(file.getSize()); object.setContentType(file.getContentType()); S3Bucket bucket = s3Service.getBucket(bucketName); s3Service.putObject(bucket, object); Restaurant restaurant = restaurantRepository.findByRestaurantId(restaurantId); restaurant.setHasUploadedImage(true); restaurantRepository.saveRestaurant(restaurant); model.put("success", true); } catch (Exception ex) { LOGGER.error("", ex); model.put("success", false); model.put("message", ex.getMessage()); } String json = jsonUtils.serializeAndEscape(model); final HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.TEXT_HTML); headers.setCacheControl("no-cache"); return new ResponseEntity<byte[]>(json.getBytes("utf-8"), headers, HttpStatus.OK); }
@SuppressWarnings("unchecked") @ResponseBody @RequestMapping(value = "/order/checkSpecialOffer.ajax", method = RequestMethod.POST) public ResponseEntity<byte[]> checkSpecialOfferAvailability( HttpServletRequest request, @RequestParam(value = "body") String body) throws Exception { if (LOGGER.isDebugEnabled()) { LOGGER.debug("Checking if special offer is applicable for order"); } Map<String, Object> model = new HashMap<String, Object>(); try { // Extract request parameters Map<String, Object> params = (Map<String, Object>) jsonUtils.deserialize(body); String restaurantId = (String) params.get("restaurantId"); String orderId = (String) params.get("orderId"); String specialOfferId = (String) params.get("specialOfferId"); // Get the restaurant object Restaurant restaurant = restaurantRepository.findByRestaurantId(restaurantId); SpecialOffer specialOffer = restaurant.getSpecialOffer(specialOfferId); // Get the order object if (orderId != null) { Order order = orderRepository.findByOrderId(orderId); model.put("success", true); model.put("applicable", specialOffer.isApplicableTo(order)); } else { model.put("success", true); model.put("applicable", specialOffer.isAvailableAt(new DateTime())); } } catch (Exception ex) { LOGGER.error("", ex); model.put("success", false); model.put("message", ex.getMessage()); } return buildOrderResponse(model); }
@SuppressWarnings("unchecked") @ResponseBody @RequestMapping(value = "/order/deliveryEdit.ajax", method = RequestMethod.POST) public ResponseEntity<byte[]> buildDeliveryEdit(@RequestParam(value = "orderId") String orderId) throws Exception { if (LOGGER.isDebugEnabled()) { LOGGER.debug("Building delivery options for orderId: " + orderId); } Map<String, Object> model = new HashMap<String, Object>(); try { Order order = orderRepository.findByOrderId(orderId); Restaurant restaurant = order.getRestaurant(); // Get opening times for today and the next three days DateTime currentTime = new DateTime(); DateTime now = new DateTime( currentTime.getYear(), currentTime.getMonthOfYear(), currentTime.getDayOfMonth(), currentTime.getHourOfDay(), currentTime.getMinuteOfHour(), 0, 0); // Store if the restaurant is currently open boolean isOpen = restaurant.isOpen(currentTime); List<Integer> days = new ArrayList<Integer>(); List<Set<LocalTime>> deliveryTimes = new ArrayList<Set<LocalTime>>(); List<Set<LocalTime>> collectionTimes = new ArrayList<Set<LocalTime>>(); // Get the remaining options for today first days.add(now.getDayOfWeek()); DateTime[] openingAndClosingTimes = restaurant.getOpeningAndClosingTimes(now); DateTime earlyOpeningTime = openingAndClosingTimes[0] == null ? now : openingAndClosingTimes[0]; DateTime lateOpeningTime = openingAndClosingTimes[2] == null ? now : openingAndClosingTimes[2]; // For delivery times push the current time past the delivery time in minutes int deliveryTimeMinutes = restaurant.getDeliveryTimeMinutes(); Pair<Set<LocalTime>, Set<LocalTime>> earlyDeliveryTimesPair = getTimeOptions( now.isBefore(earlyOpeningTime) ? earlyOpeningTime : now, openingAndClosingTimes[1], deliveryTimeMinutes); Pair<Set<LocalTime>, Set<LocalTime>> lateDeliveryTimesPair = getTimeOptions( now.isBefore(lateOpeningTime) ? lateOpeningTime : now, openingAndClosingTimes[3], deliveryTimeMinutes); earlyDeliveryTimesPair.first.addAll(lateDeliveryTimesPair.first); earlyDeliveryTimesPair.second.addAll(lateDeliveryTimesPair.second); // For delivery times push the current time past the collection time in minutes int collectionTimeMinutes = restaurant.getCollectionTimeMinutes(); Pair<Set<LocalTime>, Set<LocalTime>> earlyCollectionTimesPair = getTimeOptions( now.isBefore(earlyOpeningTime) ? earlyOpeningTime : now, openingAndClosingTimes[1], collectionTimeMinutes); Pair<Set<LocalTime>, Set<LocalTime>> lateCollectionTimesPair = getTimeOptions( now.isBefore(lateOpeningTime) ? lateOpeningTime : now, openingAndClosingTimes[3], collectionTimeMinutes); earlyCollectionTimesPair.first.addAll(lateCollectionTimesPair.first); earlyCollectionTimesPair.second.addAll(lateCollectionTimesPair.second); // Add today's opening times deliveryTimes.add(earlyDeliveryTimesPair.first); collectionTimes.add(earlyCollectionTimesPair.first); // Now get the rest of the options for the remaining times for (int i = 0; i < 3; i++) { // Add any times after midnight from the previous list Set<LocalTime> deliveryTimesSet = new TreeSet<LocalTime>(); Set<LocalTime> collectionTimesSet = new TreeSet<LocalTime>(); deliveryTimesSet.addAll(earlyDeliveryTimesPair.second); collectionTimesSet.addAll(earlyCollectionTimesPair.second); // Now get the next set of opening and closing times now = now.plusDays(1); days.add(now.getDayOfWeek()); openingAndClosingTimes = restaurant.getOpeningAndClosingTimes(now); earlyDeliveryTimesPair = getTimeOptions( openingAndClosingTimes[0], openingAndClosingTimes[1], deliveryTimeMinutes); lateDeliveryTimesPair = getTimeOptions( openingAndClosingTimes[2], openingAndClosingTimes[3], deliveryTimeMinutes); earlyDeliveryTimesPair.first.addAll(lateDeliveryTimesPair.first); earlyDeliveryTimesPair.second.addAll(lateDeliveryTimesPair.second); earlyCollectionTimesPair = getTimeOptions( openingAndClosingTimes[0], openingAndClosingTimes[1], collectionTimeMinutes); lateCollectionTimesPair = getTimeOptions( openingAndClosingTimes[2], openingAndClosingTimes[3], collectionTimeMinutes); earlyCollectionTimesPair.first.addAll(lateCollectionTimesPair.first); earlyCollectionTimesPair.second.addAll(lateCollectionTimesPair.second); // Add this day's time options to the list deliveryTimesSet.addAll(earlyDeliveryTimesPair.first); collectionTimesSet.addAll(earlyCollectionTimesPair.first); // Add these lists to the return deliveryTimes.add(deliveryTimesSet); collectionTimes.add(collectionTimesSet); } // Add the time options to the model model.put("days", days); model.put("deliveryTimes", deliveryTimes); model.put("collectionTimes", collectionTimes); model.put("collectionOnly", restaurant.getCollectionOnly()); model.put("open", isOpen); model.put("success", true); } catch (Exception ex) { LOGGER.error("", ex); model.put("success", false); model.put("message", ex.getMessage()); } return buildOrderResponse(model); }
@SuppressWarnings("unchecked") @ResponseBody @RequestMapping(value = "/order/addSpecialOffer.ajax", method = RequestMethod.POST) public ResponseEntity<byte[]> addSpecialOfferToOrder( HttpServletRequest request, @RequestParam(value = "body") String body) throws Exception { if (LOGGER.isDebugEnabled()) { LOGGER.debug("Adding special offer to order: " + body); } Map<String, Object> model = new HashMap<String, Object>(); try { // Extract request parameters Map<String, Object> params = (Map<String, Object>) jsonUtils.deserialize(body); String restaurantId = (String) params.get("restaurantId"); String specialOfferId = (String) params.get("specialOfferId"); List<String> itemChoices = (List<String>) params.get("itemChoices"); List<String> itemChoiceCosts = (List<String>) params.get("itemChoiceCosts"); Integer quantity = Integer.valueOf(params.get("quantity").toString()); // Get the restaurant object Restaurant restaurant = restaurantRepository.findByRestaurantId(restaurantId); SpecialOffer specialOffer = restaurant.getSpecialOffer(specialOfferId); // Get the order out of the session HttpSession session = request.getSession(true); String orderId = (String) session.getAttribute("orderid"); Order order; if (orderId == null) { order = buildAndRegister(session, restaurantId); } else { order = orderRepository.findByOrderId(orderId); if (order == null) { order = buildAndRegister(session, restaurantId); } } // Check if the special offer is applicable to this order if (!specialOffer.isApplicableTo(order)) { model.put("success", true); model.put("applicable", false); } else { // Wipe existing order if a new restaurant is selected if (!restaurantId.equals(order.getRestaurantId())) { order.setRestaurantId(restaurantId); order.setRestaurant(restaurant); order.getOrderItems().clear(); order.getOrderDiscounts().clear(); } // Build new order item OrderItem orderItem = new OrderItem(); orderItem.setMenuItemNumber(specialOffer.getNumber()); orderItem.setMenuItemId(specialOfferId); orderItem.setMenuItemTitle(specialOffer.getTitle()); orderItem.setAdditionalItems(itemChoices); orderItem.setQuantity(quantity); double additionalCost = 0d; for (String itemChoiceCost : itemChoiceCosts) { additionalCost += Double.valueOf(itemChoiceCost); } orderItem.setCost(specialOffer.getCost() + additionalCost); // Add new order item to order and update order.addOrderItem(orderItem); order = orderRepository.saveOrder(order); // Update can checkout status of order session.setAttribute("cancheckout", order.getCanCheckout()); // Update order restaurant id session attribute if any items present if (order.getOrderItems().size() > 0) { session.setAttribute("orderrestaurantid", order.getRestaurantId()); session.setAttribute("orderrestauranturl", order.getRestaurant().getUrl()); } else { session.removeAttribute("orderrestaurantId"); session.removeAttribute("orderrestauranturl"); } // Return success model.put("success", true); model.put("applicable", true); model.put("order", order); } } catch (Exception ex) { LOGGER.error("", ex); model.put("success", false); model.put("message", ex.getMessage()); } return buildOrderResponse(model); }
@SuppressWarnings("unchecked") @ResponseBody @RequestMapping(value = "/order/addItem.ajax", method = RequestMethod.POST) public ResponseEntity<byte[]> addToOrder( HttpServletRequest request, @RequestParam(value = "body") String body) throws Exception { if (LOGGER.isDebugEnabled()) { LOGGER.debug("Adding to order: " + body); } Map<String, Object> model = new HashMap<String, Object>(); try { // Extract request parameters Map<String, Object> params = (Map<String, Object>) jsonUtils.deserialize(body); String restaurantId = (String) params.get("restaurantId"); String itemId = (String) params.get("itemId"); String itemType = (String) params.get("itemType"); String itemSubType = (String) params.get("itemSubType"); List<String> additionalItems = (List<String>) params.get("additionalItems"); Integer quantity = Integer.valueOf(params.get("quantity").toString()); // Get the restaurant object Restaurant restaurant = restaurantRepository.findByRestaurantId(restaurantId); MenuItem menuItem = restaurant.getMenuItem(itemId); // Build new order item OrderItem orderItem = new OrderItem(); orderItem.setMenuItemNumber(menuItem.getNumber()); orderItem.setMenuItemId(itemId); orderItem.setMenuItemTitle(menuItem.getTitle()); orderItem.setMenuItemTypeName(itemType); orderItem.setMenuItemSubTypeName(itemSubType); orderItem.setAdditionalItems(additionalItems); orderItem.setQuantity(quantity); // Work out the cost of any additional Items double additionalItemCost = 0d; for (String additionalItemName : additionalItems) { if (StringUtils.hasText(itemType)) { MenuItemTypeCost menuItemTypeCost = menuItem.getMenuItemTypeCost(itemType); additionalItemCost += menuItemTypeCost.getAdditionalItemCost() == null ? 0d : menuItemTypeCost.getAdditionalItemCost(); } else if (menuItem.getAdditionalItemCost() != null) { additionalItemCost += menuItem.getAdditionalItemCost(); } else { MenuItemAdditionalItemChoice additionalItemChoice = menuItem.getMenuItemAdditionalItemChoice(additionalItemName); additionalItemCost += additionalItemChoice.getCost() == null ? 0d : additionalItemChoice.getCost(); } } // Build the cost of the item if (StringUtils.hasText(itemType)) { MenuItemTypeCost menuItemTypeCost = menuItem.getMenuItemTypeCost(itemType); orderItem.setCost(menuItemTypeCost.getCost() + additionalItemCost); } else if (StringUtils.hasText(itemSubType)) { MenuItemSubType menuItemSubType = menuItem.getMenuItemSubType(itemSubType); orderItem.setCost(menuItemSubType.getCost() + additionalItemCost); } else { orderItem.setCost(menuItem.getCost() + additionalItemCost); } // Get the order out of the session HttpSession session = request.getSession(true); String orderId = (String) session.getAttribute("orderid"); Order order; if (orderId == null) { order = buildAndRegister(session, restaurantId); } else { order = orderRepository.findByOrderId(orderId); if (order == null) { order = buildAndRegister(session, restaurantId); } else if (!restaurantId.equals(order.getRestaurantId())) { order.setRestaurant(restaurant); order.getOrderItems().clear(); order.getOrderDiscounts().clear(); } } // Add new order item to order and update order.addOrderItem(orderItem); order = orderRepository.saveOrder(order); // Update can checkout status of order session.setAttribute("cancheckout", order.getCanCheckout()); // Update order restaurant id session attribute if any items present if (order.getOrderItems().size() > 0) { session.setAttribute("orderrestaurantid", order.getRestaurantId()); session.setAttribute("orderrestauranturl", order.getRestaurant().getUrl()); } else { session.removeAttribute("orderrestaurantid"); session.removeAttribute("orderrestauranturl"); } // Return success model.put("success", true); model.put("order", order); } catch (Exception ex) { LOGGER.error("", ex); model.put("success", false); model.put("message", ex.getMessage()); } return buildOrderResponse(model); }
@Scheduled(cron = "0 0/1 * * * ?") public void execute() { try { if (lock.acquire()) { List<Order> orders = orderRepository.findByOrderStatus(ORDER_STATUS_AWAITING_RESTAURANT); if (orders.size() > 0) { LOGGER.info("Found " + orders.size() + " orders with status 'AWAITING_RESTAURANT'"); } for (Order order : orders) { DateTime orderPlacedTime = order.getOrderPlacedTime(); String orderId = order.getOrderId(); LOGGER.info("Order id: " + orderId + " was placed at: " + orderPlacedTime); Restaurant restaurant = order.getRestaurant(); DateTime now = new DateTime(); LOGGER.info("Current time is: " + now); String notificationStatus = order.getOrderNotificationStatus(); LOGGER.info("Order id: " + orderId + " notification status is: " + notificationStatus); // Get the time the restaurant opened DateTime restaurantOpenedTime = restaurant.getEarlyOpeningTime(now); // Don't do anything if the restaurant is not currently open LOGGER.info( "Restaurant " + restaurant.getName() + " opened time today is: " + restaurantOpenedTime); if (restaurantOpenedTime == null || restaurantOpenedTime.isAfter(now)) { LOGGER.info( "Restaurant " + restaurant.getName() + " has not opened yet, not doing any processing"); continue; } // Auto cancel orders which have been awaiting confirmation for too long and the // restaurant has been open long enough to respond DateTime autoCancelCutoff = new DateTime().minusMinutes(minutesBeforeAutoCancelOrder); LOGGER.info("Auo cancel cutoff time is: " + autoCancelCutoff); if (orderPlacedTime.isBefore(autoCancelCutoff) && restaurantOpenedTime.isBefore(autoCancelCutoff)) { try { LOGGER.info( "Order id: " + orderId + " has been awaiting confirmation for more than " + minutesBeforeAutoCancelOrder + " minutes, auto-cancelling"); orderWorkflowEngine.processAction(order, ACTION_AUTO_CANCEL); } catch (WorkflowException e) { LOGGER.error( "Exception sending auto cancel email for orderId: " + order.getOrderId(), e); order.setOrderStatus(ORDER_STATUS_AUTO_CANCELLED); orderRepository.saveOrder(order); } catch (Exception ex) { exceptionHandler.handleException(ex); } continue; } // Send email to customer giving them the option to cancel the order if it has been // awaiting confirmation for too long DateTime cancellationOfferCutoff = new DateTime().minusMinutes(minutesBeforeSendCancellationEmail); LOGGER.info("Cancellation offer cutoff time is: " + cancellationOfferCutoff); if (!order.getCancellationOfferEmailSent() && orderPlacedTime.isBefore(cancellationOfferCutoff) && restaurantOpenedTime.isBefore(cancellationOfferCutoff)) { try { LOGGER.info( "Order id: " + order.getOrderId() + " has been awaiting confirmation for more than " + minutesBeforeSendCancellationEmail + " minutes, sending email"); orderWorkflowEngine.processAction(order, ACTION_SEND_CANCEL_OFFER_TO_CUSTOMER); } catch (Exception ex) { exceptionHandler.handleException(ex); } } // If there is a call in progress then do not call again if (order.isCallInProgress()) { LOGGER.info( "There is already a call in progress for order id: " + orderId + ", not placing another call"); continue; } // If restaurant did not respond at all, do not call again if (NOTIFICATION_STATUS_RESTAURANT_FAILED_TO_RESPOND.equals(notificationStatus)) { LOGGER.info( "Not attempting another call for order id:" + orderId + " as notification status is; " + notificationStatus); continue; } // If call was answered but order not accepted/rejected, retry after 5 minutes otherwise // after 1 minute DateTime lastCallCutoff = new DateTime() .minusSeconds( NOTIFICATION_STATUS_RESTAURANT_ANSWERED.equals(notificationStatus) ? secondsBeforeRetryAnsweredCall : secondsBeforeRetryCall); DateTime lastCallTime = order.getLastCallPlacedTime(); if (lastCallTime == null || lastCallTime.isBefore(lastCallCutoff)) { try { orderWorkflowEngine.processAction(order, ACTION_CALL_RESTAURANT); } catch (Exception ex) { LOGGER.error( "Error occurred placing order call to restaurant for order id: " + order.getOrderId()); } } } } } catch (Exception ex) { LOGGER.error("Error occurred processing open orders: " + ex.getMessage(), ex); } finally { lock.release(); } }