Validation & UI fixes.

This commit is contained in:
Alexey Zinchenko 2019-05-16 00:32:30 +03:00
parent af110658b6
commit 1b07e1d3fe
8 changed files with 60 additions and 31 deletions

View File

@ -15,7 +15,7 @@ public class OrderStatusFormatter implements Formatter<OrderStatus> {
private static final Logger logger = LogManager.getLogger(OrderStatusFormatter.class);
@Override
public OrderStatus parse(String text, Locale locale) throws ParseException {
public OrderStatus parse(String text, Locale locale) {
final OrderStatus parsedOrderStatus = OrderStatus.valueOf(text.toUpperCase());
logger.trace("Parsing String[{}] to OrderStatus instance: {}.", () -> text, () -> parsedOrderStatus);
return parsedOrderStatus;

View File

@ -1,17 +1,21 @@
package com.github.prominence.carrepair.model.mapper;
import com.github.prominence.carrepair.enums.OrderStatus;
import com.github.prominence.carrepair.formatter.CustomDateTimeFormatter;
import com.github.prominence.carrepair.formatter.OrderStatusFormatter;
import com.github.prominence.carrepair.model.domain.Order;
import com.github.prominence.carrepair.model.dto.OrderDto;
import org.mapstruct.InheritInverseConfiguration;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.Mappings;
import org.apache.commons.lang3.StringUtils;
import org.mapstruct.*;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.List;
@Mapper(componentModel = "spring")
public interface OrderMapper {
@Mapper(componentModel = "spring", injectionStrategy = InjectionStrategy.CONSTRUCTOR)
public abstract class OrderMapper {
@Autowired
protected OrderStatusFormatter orderStatusFormatter;
@Mappings({
@Mapping(source = "id", target = "id"),
@ -26,10 +30,29 @@ public interface OrderMapper {
@Mapping(source = "createdOn", target = "createdOnDate", dateFormat = CustomDateTimeFormatter.DATETIME_PATTERN),
@Mapping(source = "finishedOn", target = "finishedOnDate", dateFormat = CustomDateTimeFormatter.DATETIME_PATTERN)
})
OrderDto orderToOrderDto(Order order);
abstract public OrderDto orderToOrderDto(Order order);
@InheritInverseConfiguration
Order orderDtoToOrder(OrderDto orderDto);
abstract public Order orderDtoToOrder(OrderDto orderDto);
List<OrderDto> ordersToOrderDtoList(List<Order> orders);
abstract public List<OrderDto> ordersToOrderDtoList(List<Order> orders);
public String orderStatusToString(OrderStatus orderStatus) {
return orderStatusFormatter.print(orderStatus, null);
}
public OrderStatus stringToOrderStatus(String status) {
return orderStatusFormatter.parse(status, null);
}
@BeforeMapping
protected void checkForEmptyStrings(OrderDto orderDto) {
if (StringUtils.isEmpty(orderDto.getCreatedOnDate())) {
orderDto.setCreatedOnDate(null);
}
if (StringUtils.isEmpty(orderDto.getFinishedOnDate())) {
orderDto.setFinishedOnDate(null);
}
}
}

View File

@ -4,6 +4,7 @@ import com.github.prominence.carrepair.enums.OrderStatus;
import com.github.prominence.carrepair.formatter.CustomDateTimeFormatter;
import com.github.prominence.carrepair.formatter.OrderStatusFormatter;
import com.github.prominence.carrepair.model.dto.OrderDto;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.context.i18n.LocaleContextHolder;
@ -11,7 +12,6 @@ import org.springframework.stereotype.Component;
import org.springframework.validation.Errors;
import org.springframework.validation.Validator;
import java.text.ParseException;
import java.time.LocalDateTime;
import java.util.Locale;
@ -37,25 +37,28 @@ public class OrderValidator implements Validator {
OrderDto order = (OrderDto) o;
Locale locale = LocaleContextHolder.getLocale();
OrderStatus orderStatus = orderStatusFormatter.parse(order.getOrderStatus(), locale);
if (order.getFinishedOnDate() != null) {
try {
LocalDateTime finishedOn = customDateTimeFormatter.parse(order.getFinishedOnDate(), locale);
LocalDateTime createdOn = customDateTimeFormatter.parse(order.getCreatedOnDate(), locale);
if (createdOn != null && finishedOn != null && finishedOn.isBefore(createdOn)) {
logger.debug("[{}] validation error: \"finishedOnDate\" value[{}] is before \"createdOn\"[{}].",
() -> order, () -> finishedOn, () -> createdOn);
errors.rejectValue("finishedOnDate", "error.finishedOn.finishedBeforeStarted");
}
if (StringUtils.isNotBlank(order.getFinishedOnDate())) {
LocalDateTime finishedOn = customDateTimeFormatter.parse(order.getFinishedOnDate(), locale);
LocalDateTime createdOn = customDateTimeFormatter.parse(order.getCreatedOnDate(), locale);
if (createdOn != null && finishedOn != null && finishedOn.isBefore(createdOn)) {
logger.debug("[{}] validation error: \"finishedOnDate\" value[{}] is before \"createdOn\"[{}].",
() -> order, () -> finishedOn, () -> createdOn);
errors.rejectValue("finishedOnDate", "error.finishedOn.finishedBeforeStarted");
}
OrderStatus orderStatus = orderStatusFormatter.parse(order.getOrderStatus(), locale);
if (finishedOn != null && orderStatus != OrderStatus.ACCEPTED) {
logger.debug("[{}] validation error: \"finishedOn\" cannot be set for order in status differ from {}.",
() -> order, () -> OrderStatus.ACCEPTED);
errors.rejectValue("finishedOnDate", "error.finishedOn.incompatibleStatus");
}
} catch (ParseException ex) {
logger.debug("Cannot parse: {}", () -> ex);
if (finishedOn != null && orderStatus != OrderStatus.ACCEPTED) {
logger.debug("[{}] validation error: \"finishedOn\" cannot be set for order in status differ from {}.",
() -> order, () -> OrderStatus.ACCEPTED);
errors.rejectValue("finishedOnDate", "error.finishedOn.incompatibleStatus");
}
} else {
if (orderStatus == OrderStatus.ACCEPTED) {
logger.debug("[{}] validation error: \"orderStatus\" cannot be set to {} until \"finishedOn\" isn't set.",
() -> order, () -> OrderStatus.ACCEPTED);
errors.rejectValue("orderStatus", "error.orderStatus.acceptedButNotFinished");
}
}
}

View File

@ -47,3 +47,4 @@ common.deleteConfirmation.label = Are you sure to delete?
# validation
error.finishedOn.finishedBeforeStarted = value must be after starting date
error.finishedOn.incompatibleStatus = order cannot be finished until it isn't accepted by client
error.orderStatus.acceptedButNotFinished = order cannot be accepter until it isn't finished

View File

@ -47,3 +47,4 @@ common.deleteConfirmation.label = Are you sure to delete?
# validation
error.finishedOn.finishedBeforeStarted = value must be after starting date
error.finishedOn.incompatibleStatus = order cannot be finished until it isn't accepted by client
error.orderStatus.acceptedButNotFinished = order cannot be accepter until it isn't finished

View File

@ -47,3 +47,4 @@ common.deleteConfirmation.label = Вы действительно хотите
# validation
error.finishedOn.finishedBeforeStarted = дата окончания должна быть после даты начала
error.finishedOn.incompatibleStatus = заказ не может быть закончен если клиент еще не принял его
error.orderStatus.acceptedButNotFinished = заказ не может быть принят пока он не закончен

View File

@ -36,10 +36,10 @@
</ul>
</div>
<div class="float-right">
<a th:href="@{?lang=en}">
<a th:href="@{/?lang=en}">
<img th:src="@{/images/us.png}" th:alt="#{lang.en}"/>
</a>
<a th:href="@{?lang=ru}">
<a th:href="@{/?lang=ru}">
<img th:src="@{/images/ru.png}" th:alt="#{lang.ru}"/>
</a>
</div>

View File

@ -68,7 +68,7 @@
<label for="orderStatus" class="col-sm-2 col-form-label" th:text="#{status.label}"></label>
<div class="col-sm-10">
<select name="orderStatus" class="form-control custom-select" id="orderStatus" th:field="*{orderStatus}" th:errorclass="is-invalid" th:value="${orderDto.orderStatus}">
<option th:each="orderStatus : ${orderStatuses}" th:value="${orderStatus.toString()}" th:text="${{orderStatus}}"></option>
<option th:each="orderStatus : ${orderStatuses}" th:value="${{orderStatus}}" th:text="${{orderStatus}}"></option>
</select>
<div th:replace="common::errors('orderStatus')"></div>
</div>