package io.oasp.gastronomy.restaurant.salesmanagement.logic.impl.usecase;
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.logic.api.UseCase;
import io.oasp.gastronomy.restaurant.salesmanagement.common.api.Order;
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.dataaccess.api.OrderEntity;
import io.oasp.gastronomy.restaurant.salesmanagement.logic.api.Salesmanagement;
import io.oasp.gastronomy.restaurant.salesmanagement.logic.api.to.OrderCto;
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.UcManageOrder;
import io.oasp.gastronomy.restaurant.salesmanagement.logic.base.usecase.AbstractOrderUc;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import javax.annotation.security.RolesAllowed;
import javax.inject.Inject;
import javax.inject.Named;
import net.sf.mmm.util.exception.api.ObjectMismatchException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.validation.annotation.Validated;
/**
* Implementation of {@link UcManageOrder}.
*
*/
@Named
@UseCase
@Validated
public class UcManageOrderImpl extends AbstractOrderUc implements UcManageOrder {
/** Logger instance. */
private static final Logger LOG = LoggerFactory.getLogger(UcManageOrderImpl.class);
private Salesmanagement salesmanagement;
/**
* The constructor.
*/
public UcManageOrderImpl() {
super();
}
/**
* @param salesmanagement the {@link Salesmanagement} to {@link Inject}.
*/
@Inject
public void setSalesmanagement(Salesmanagement salesmanagement) {
this.salesmanagement = salesmanagement;
}
@Override
@RolesAllowed(PermissionConstants.SAVE_ORDER)
public OrderEto saveOrder(OrderEto order) {
return saveOrder(order, null);
}
private OrderEto saveOrder(OrderEto order, List<OrderPositionEto> positions) {
Objects.requireNonNull(order, "order");
Long orderId = order.getId();
if (orderId == null) {
OrderState state = order.getState();
if (state != OrderState.OPEN) {
throw new IllegalEntityStateException(order, state);
}
} else {
OrderEntity currentOrder = getOrderDao().find(orderId);
verifyUpdate(currentOrder, order, positions);
}
OrderEntity orderEntity = getBeanMapper().map(order, OrderEntity.class);
orderEntity = getOrderDao().save(orderEntity);
LOG.debug("Saved order with id {}.", orderEntity.getId());
return getBeanMapper().map(orderEntity, OrderEto.class);
}
/**
* @param currentOrder is the current {@link Order} from the persistence.
* @param updateOrder is the new {@link Order} to update to.
* @param positions the {@link List} of {@link OrderPositionEto positions} or {@code null} if undefined.
*/
private void verifyUpdate(Order currentOrder, Order updateOrder, List<OrderPositionEto> positions) {
if (currentOrder.getTableId() != updateOrder.getTableId()) {
LOG.info("Changing order from table-id {} to table-id {}", currentOrder.getTableId(), updateOrder.getTableId());
}
verifyOrderStateChange(updateOrder, currentOrder.getState(), updateOrder.getState(), positions);
}
/**
* Verifies if an update of the {@link OrderPositionState} is legal.
*
* @param updateOrder the new {@link Order} to update to.
* @param currentState the old/current {@link OrderState} of the {@link Order}.
* @param newState new {@link OrderState} of the {@link Order} to be updated to.
* @param positions the {@link List} of {@link OrderPositionEto positions} or {@code null} if undefined.
*/
private void verifyOrderStateChange(Order updateOrder, OrderState currentState, OrderState newState,
List<OrderPositionEto> positions) {
if (currentState == newState) {
return;
}
if (newState == OrderState.CLOSED) {
if (positions == null) {
throw new IllegalEntityStateException(updateOrder, currentState, newState);
}
// we can only close an order if all its positions are closed...
for (OrderPositionEto position : positions) {
OrderPositionState positionState = position.getState();
if ((positionState == null) || !positionState.isClosed()) {
IllegalEntityStateException cause = new IllegalEntityStateException(position, positionState);
throw new IllegalEntityStateException(cause, updateOrder, currentState, newState);
}
}
}
}
@Override
@RolesAllowed(PermissionConstants.SAVE_ORDER)
public OrderCto saveOrder(OrderCto order) {
Objects.requireNonNull(order, "order");
OrderEto orderEto = order.getOrder();
Long orderId = orderEto.getId();
List<OrderPositionEto> currentOrderPositionList;
if (orderId == null) {
currentOrderPositionList = Collections.emptyList();
} else {
// we could add a relation OrderEntity.positions of type List<OrderPositionEntity>...
currentOrderPositionList = this.salesmanagement.findOrderPositionsByOrderId(orderId);
}
List<OrderPositionEto> positions = order.getPositions();
orderEto = saveOrder(orderEto, positions);
if (orderId == null) {
orderId = orderEto.getId();
}
OrderCto result = new OrderCto();
result.setOrder(orderEto);
// we can not use hibernate (Cascade and Delete orphaned) as we need to validate and react on them...
List<OrderPositionEto> positions2DeleteList = getEntities2Delete(currentOrderPositionList, positions);
List<OrderPositionEto> savedPositionList = result.getPositions();
if (positions2DeleteList.size() > 0) {
LOG.warn("Marking {} number of order position(s) as cancelled that are missing in update of order with id {}",
positions2DeleteList.size(), orderId);
for (OrderPositionEto position : positions2DeleteList) {
// only logically delete, actually the client should still send the cancelled positions...
position.setState(OrderPositionState.CANCELLED);
OrderPositionEto updatedOrderPosition = this.salesmanagement.saveOrderPosition(position);
savedPositionList.add(updatedOrderPosition);
}
}
for (OrderPositionEto position : positions) {
Long positionOrderId = position.getOrderId();
if (positionOrderId == null) {
position.setOrderId(orderId);
} else if (!positionOrderId.equals(orderId)) {
throw new ObjectMismatchException(positionOrderId, orderId, "position.orderId");
}
OrderPositionEto updatedOrderPosition = this.salesmanagement.saveOrderPosition(position);
savedPositionList.add(updatedOrderPosition);
}
return result;
}
@Override
@RolesAllowed(PermissionConstants.DELETE_ORDER)
public void deleteOrder(long id) {
getOrderDao().delete(id);
}
}