package io.oasp.gastronomy.restaurant.salesmanagement.logic.impl.usecase;
import java.util.Objects;
import javax.annotation.security.RolesAllowed;
import javax.inject.Inject;
import javax.inject.Named;
import net.sf.mmm.util.exception.api.ObjectNotFoundUserException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.validation.annotation.Validated;
import io.oasp.gastronomy.restaurant.general.common.api.constants.PermissionConstants;
import io.oasp.gastronomy.restaurant.general.common.api.exception.IllegalEntityStateException;
import io.oasp.gastronomy.restaurant.general.common.api.exception.IllegalPropertyChangeException;
import io.oasp.gastronomy.restaurant.general.logic.api.UseCase;
import io.oasp.gastronomy.restaurant.offermanagement.common.api.Offer;
import io.oasp.gastronomy.restaurant.offermanagement.logic.api.Offermanagement;
import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.OfferEto;
import io.oasp.gastronomy.restaurant.salesmanagement.common.api.OrderPosition;
import io.oasp.gastronomy.restaurant.salesmanagement.common.api.datatype.OrderPositionState;
import io.oasp.gastronomy.restaurant.salesmanagement.common.api.datatype.OrderState;
import io.oasp.gastronomy.restaurant.salesmanagement.common.api.datatype.ProductOrderState;
import io.oasp.gastronomy.restaurant.salesmanagement.dataaccess.api.OrderEntity;
import io.oasp.gastronomy.restaurant.salesmanagement.dataaccess.api.OrderPositionEntity;
import io.oasp.gastronomy.restaurant.salesmanagement.logic.api.Salesmanagement;
import io.oasp.gastronomy.restaurant.salesmanagement.logic.api.to.OrderEto;
import io.oasp.gastronomy.restaurant.salesmanagement.logic.api.to.OrderPositionEto;
import io.oasp.gastronomy.restaurant.salesmanagement.logic.api.usecase.UcManageOrderPosition;
import io.oasp.gastronomy.restaurant.salesmanagement.logic.base.usecase.AbstractOrderPositionUc;
/**
* Implementation of {@link UcManageOrderPosition}.
*
*/
@Named
@UseCase
@Validated
public class UcManageOrderPositionImpl extends AbstractOrderPositionUc implements UcManageOrderPosition {
/** Logger instance. */
private static final Logger LOG = LoggerFactory.getLogger(UcManageOrderPositionImpl.class);
private Salesmanagement salesManagement;
private Offermanagement offerManagement;
/**
* The constructor.
*/
public UcManageOrderPositionImpl() {
super();
}
@Override
@RolesAllowed(PermissionConstants.SAVE_ORDER_POSITION)
public OrderPositionEto createOrderPosition(OfferEto offer, OrderEto order, String comment) {
Objects.requireNonNull(offer, "offer");
Long offerId = offer.getId();
OfferEto offerFromDb = this.offerManagement.findOffer(offerId);
if (offerFromDb == null) {
throw new ObjectNotFoundUserException(Offer.class, offerId);
}
OrderPositionEntity orderPosition = new OrderPositionEntity();
order.setState(OrderState.OPEN);
// Declare the order position.
orderPosition.setOfferId(offerId);
orderPosition.setOfferName(offerFromDb.getDescription());
orderPosition.setPrice(offerFromDb.getPrice());
orderPosition.setOrder(getBeanMapper().map(this.salesManagement.saveOrder(order), OrderEntity.class));
orderPosition.setComment(comment);
// Save the order position and return it.
getOrderPositionDao().save(orderPosition);
LOG.debug("The order position with id '" + orderPosition.getId() + "' has been created. It's linked with order id '"
+ order.getId() + "' and offer id '" + offerId + "'.");
return getBeanMapper().map(orderPosition, OrderPositionEto.class);
}
@Override
@RolesAllowed(PermissionConstants.SAVE_ORDER_POSITION)
public OrderPositionEto saveOrderPosition(OrderPositionEto orderPosition) {
Objects.requireNonNull(orderPosition, "orderPosition");
Long orderPositionId = orderPosition.getId();
String action;
if (orderPositionId == null) {
action = "saved";
Long offerId = orderPosition.getOfferId();
OfferEto offer = this.offerManagement.findOffer(offerId);
Objects.requireNonNull(offer, "Offer@" + offerId);
orderPosition.setPrice(offer.getPrice());
orderPosition.setOfferName(offer.getName());
} else {
OrderPositionEntity currentOrderPosition = getOrderPositionDao().find(orderPositionId);
verifyUpdate(currentOrderPosition, orderPosition);
action = "updated";
}
OrderPositionEntity orderPositionEntity = getBeanMapper().map(orderPosition, OrderPositionEntity.class);
orderPositionEntity = getOrderPositionDao().save(orderPositionEntity);
LOG.debug("The order position with id {} has been {}.", orderPositionEntity.getId(), action);
return getBeanMapper().map(orderPositionEntity, OrderPositionEto.class);
}
/**
* @param currentOrderPosition is the current {@link OrderPosition} from the persistence.
* @param updateOrderPosition is the new {@link OrderPosition} to update to.
*/
private void verifyUpdate(OrderPosition currentOrderPosition, OrderPosition updateOrderPosition) {
if (!Objects.equals(currentOrderPosition.getOrderId(), currentOrderPosition.getOrderId())) {
throw new IllegalPropertyChangeException(updateOrderPosition, "orderId");
}
if (!Objects.equals(currentOrderPosition.getOfferId(), currentOrderPosition.getOfferId())) {
throw new IllegalPropertyChangeException(updateOrderPosition, "offerId");
}
if (!Objects.equals(currentOrderPosition.getPrice(), currentOrderPosition.getPrice())) {
throw new IllegalPropertyChangeException(updateOrderPosition, "price");
}
if (!Objects.equals(currentOrderPosition.getOfferName(), currentOrderPosition.getOfferName())) {
throw new IllegalPropertyChangeException(updateOrderPosition, "offerName");
}
OrderPositionState currentState = currentOrderPosition.getState();
OrderPositionState newState = updateOrderPosition.getState();
ProductOrderState newDrinkState = updateOrderPosition.getDrinkState();
verifyOrderPositionStateChange(updateOrderPosition, currentState, newState);
// TODO add verification methods of other sub-states of OrderPosition (i.e. Meal and SideDish)
verifyDrinkStateChange(updateOrderPosition, currentState, newState, newDrinkState);
}
/**
* Verifies if an update of the {@link OrderPositionState} is legal.
*
* @param updateOrderPosition the new {@link OrderPosition} to update to.
* @param currentState the old/current {@link OrderPositionState} of the {@link OrderPosition}.
* @param newState new {@link OrderPositionState} of the {@link OrderPosition} to be updated to.
*/
private void verifyOrderPositionStateChange(OrderPosition updateOrderPosition, OrderPositionState currentState,
OrderPositionState newState) {
switch (currentState) {
case CANCELLED:
if ((newState != OrderPositionState.CANCELLED) && (newState != OrderPositionState.ORDERED)) {
throw new IllegalEntityStateException(updateOrderPosition, currentState, newState);
}
break;
case ORDERED:
if ((newState != OrderPositionState.ORDERED) && (newState != OrderPositionState.CANCELLED)
&& (newState != OrderPositionState.PREPARED)) {
throw new IllegalEntityStateException(updateOrderPosition, currentState, newState);
}
break;
case PREPARED:
// from here we can go to any other state (back to ORDERED in case that the kitchen has to rework)
break;
case DELIVERED:
if ((newState == OrderPositionState.PREPARED) || (newState == OrderPositionState.ORDERED)) {
throw new IllegalEntityStateException(updateOrderPosition, currentState, newState);
}
break;
case PAYED:
if (newState != OrderPositionState.PAYED) {
throw new IllegalEntityStateException(updateOrderPosition, currentState, newState);
}
break;
default:
LOG.error("Illegal state {}", currentState);
break;
}
}
/**
* Verifies if an update of the {@link ProductOrderState} is legal. This verification is based on both the states of
* {@link ProductOrderState} and {@link OrderPositionState}.
*
* @param updateOrderPosition the new {@link OrderPosition} to update to.
* @param currentState the old/current {@link OrderPositionState} of the {@link OrderPosition}.
* @param newState new {@link OrderPositionState} of the {@link OrderPosition} to be updated to.
* @param newDrinkState new {@link ProductOrderState} of the drink of the {@link OrderPosition} to be updated to.
*/
private void verifyDrinkStateChange(OrderPosition updateOrderPosition, OrderPositionState currentState,
OrderPositionState newState, ProductOrderState newDrinkState) {
switch (currentState) {
case CANCELLED:
if ((newState != OrderPositionState.CANCELLED) && (newState != OrderPositionState.ORDERED)) {
throw new IllegalEntityStateException(updateOrderPosition, currentState, newDrinkState);
}
break;
case ORDERED:
if ((newState != OrderPositionState.ORDERED) && (newState != OrderPositionState.CANCELLED)
&& (newState != OrderPositionState.PREPARED) && (newDrinkState != ProductOrderState.ORDERED)
&& (newDrinkState != ProductOrderState.PREPARED)) {
throw new IllegalEntityStateException(updateOrderPosition, currentState, newDrinkState);
}
break;
case PREPARED:
// from here we can go to any other state (back to ORDERED in case that the kitchen has to rework)
break;
case DELIVERED:
if ((newState == OrderPositionState.PREPARED) || (newState == OrderPositionState.ORDERED)
|| (newDrinkState == ProductOrderState.PREPARED) || (newDrinkState == ProductOrderState.ORDERED)) {
throw new IllegalEntityStateException(updateOrderPosition, currentState, newDrinkState);
}
break;
case PAYED:
if (newState != OrderPositionState.PAYED) {
throw new IllegalEntityStateException(updateOrderPosition, currentState, newDrinkState);
}
break;
default:
LOG.error("Illegal state {}", currentState);
break;
}
}
/**
* @param salesManagement the {@link Salesmanagement} to {@link Inject}.
*/
@Inject
public void setSalesManagement(Salesmanagement salesManagement) {
this.salesManagement = salesManagement;
}
/**
* @param offerManagement the {@link Offermanagement} to {@link Inject}.
*/
@Inject
public void setOfferManagement(Offermanagement offerManagement) {
this.offerManagement = offerManagement;
}
}