diff --git a/navalplanner-business/src/main/java/org/navalplanner/business/workreports/entities/WorkReport.java b/navalplanner-business/src/main/java/org/navalplanner/business/workreports/entities/WorkReport.java index 94e807ee2..23f9c2a01 100644 --- a/navalplanner-business/src/main/java/org/navalplanner/business/workreports/entities/WorkReport.java +++ b/navalplanner-business/src/main/java/org/navalplanner/business/workreports/entities/WorkReport.java @@ -275,7 +275,7 @@ public class WorkReport extends IntegrationEntity { return true; } - if (this.workReportType.getHeadingFields().size() != this.descriptionValues + if (this.workReportType.getHeadingFields().size() > this.descriptionValues .size()) { return false; } @@ -291,6 +291,27 @@ public class WorkReport extends IntegrationEntity { return true; } + @SuppressWarnings("unused") + @AssertTrue(message = "There are repeated description values in the work report ") + public boolean checkConstraintAssignedRepeatedDescriptionValues() { + + Set textFields = new HashSet(); + + for (DescriptionValue v : this.descriptionValues) { + + String name = v.getFieldName(); + + if (!StringUtils.isBlank(name)) { + if (textFields.contains(name.toLowerCase())) { + return false; + } else { + textFields.add(name.toLowerCase()); + } + } + } + return true; + } + public DescriptionValue getDescriptionValueByFieldName(String fieldName) throws InstanceNotFoundException { @@ -402,4 +423,8 @@ public class WorkReport extends IntegrationEntity { } + @AssertTrue(message = "The work report line codes must be unique.") + public boolean checkConstraintNonRepeatedWorkReportLinesCodes() { + return getFirstRepeatedCode(this.workReportLines) == null; + } } diff --git a/navalplanner-business/src/main/java/org/navalplanner/business/workreports/entities/WorkReportLine.java b/navalplanner-business/src/main/java/org/navalplanner/business/workreports/entities/WorkReportLine.java index 949d92eb9..bbea6eb96 100644 --- a/navalplanner-business/src/main/java/org/navalplanner/business/workreports/entities/WorkReportLine.java +++ b/navalplanner-business/src/main/java/org/navalplanner/business/workreports/entities/WorkReportLine.java @@ -272,6 +272,25 @@ public class WorkReportLine extends IntegrationEntity implements Comparable { return true; } + @SuppressWarnings("unused") + @AssertTrue(message = "The start hour cannot be higher than finish hour") + public boolean checkCannotBeHigher() { + if (!firstLevelValidationsPassed()) { + return true; + } + + if (workReport.getWorkReportType().getHoursManagement().equals( + HoursManagementEnum.HOURS_CALCULATED_BY_CLOCK)) { + return checkCannotBeHigher(this.clockStart, this.clockFinish); + } + return true; + } + + public boolean checkCannotBeHigher(LocalTime starting, LocalTime ending) { + return !((ending != null) && (starting != null) && (starting + .compareTo(ending) > 0)); + } + void updateItsFieldsAndLabels() { if (workReport != null) { assignItsLabels(workReport.getWorkReportType()); @@ -455,7 +474,7 @@ public class WorkReportLine extends IntegrationEntity implements Comparable { return true; } - if (this.workReport.getWorkReportType().getLineFields().size() != this.descriptionValues + if (this.workReport.getWorkReportType().getLineFields().size() > this.descriptionValues .size()) { return false; } @@ -471,6 +490,27 @@ public class WorkReportLine extends IntegrationEntity implements Comparable { return true; } + @SuppressWarnings("unused") + @AssertTrue(message = "There are repeated description values in the work report line") + public boolean checkConstraintAssignedRepeatedDescriptionValues() { + + Set textFields = new HashSet(); + + for (DescriptionValue v : this.descriptionValues) { + + String name = v.getFieldName(); + + if (!StringUtils.isBlank(name)) { + if (textFields.contains(name.toLowerCase())) { + return false; + } else { + textFields.add(name.toLowerCase()); + } + } + } + return true; + } + public DescriptionValue getDescriptionValueByFieldName(String fieldName) throws InstanceNotFoundException { @@ -505,4 +545,5 @@ public class WorkReportLine extends IntegrationEntity implements Comparable { throw new InstanceNotFoundException(type, LabelType.class.getName()); } + } diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/ws/common/impl/DateConverter.java b/navalplanner-webapp/src/main/java/org/navalplanner/ws/common/impl/DateConverter.java index 468c2f4d5..db9cbc4c1 100644 --- a/navalplanner-webapp/src/main/java/org/navalplanner/ws/common/impl/DateConverter.java +++ b/navalplanner-webapp/src/main/java/org/navalplanner/ws/common/impl/DateConverter.java @@ -28,6 +28,7 @@ import javax.xml.datatype.DatatypeFactory; import javax.xml.datatype.XMLGregorianCalendar; import org.joda.time.LocalDate; +import org.joda.time.LocalTime; /** * A converter from java.util.Date to/from @@ -58,9 +59,34 @@ public class DateConverter { /** * It converts a XMLGregorianCalendar representing a - * xsd:date XML type to a Joda's LocalDate. - *

- * + * xsd:localTime XML type to a LocalTime.
+ *
+ * If the localTime passed as a parameter is null, it also + * returns null. + */ + public final static LocalTime toLocalTime(XMLGregorianCalendar date) { + + if (date == null) { + return null; + } else { + if (isDefined(date.getHour()) && isDefined(date.getMinute()) + && isDefined(date.getSecond())){ + return new LocalTime(date.getHour(), date.getMinute(), date + .getSecond()); + } + return null; + } + + } + + private static boolean isDefined(int hour){ + return hour != DatatypeConstants.FIELD_UNDEFINED; + } + + /** + * It converts a XMLGregorianCalendar representing a + * xsd:date XML type to a Joda's LocalDate.
+ *
* If the date passed as a parameter is null, it also returns * null. */ @@ -106,4 +132,23 @@ public class DateConverter { return toXMLGregorianCalendar(LocalDate.fromDateFields(date)); } + public static XMLGregorianCalendar toXMLGregorianCalendar(LocalTime dateTime) { + if (dateTime == null) { + return null; + } else { + DatatypeFactory factory; + try { + factory = DatatypeFactory.newInstance(); + } catch (DatatypeConfigurationException e) { + throw new RuntimeException(e); + } + + LocalDate date = dateTime.toDateTimeToday().toLocalDate(); + return factory.newXMLGregorianCalendarTime(dateTime + .getHourOfDay(), dateTime.getMinuteOfHour(), dateTime + .getSecondOfMinute(), dateTime.getMillisOfSecond(), + DatatypeConstants.FIELD_UNDEFINED + ); + } + } } diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/ws/workreports/api/WorkReportDTO.java b/navalplanner-webapp/src/main/java/org/navalplanner/ws/workreports/api/WorkReportDTO.java index 3d207c7ef..bc81f5f3c 100644 --- a/navalplanner-webapp/src/main/java/org/navalplanner/ws/workreports/api/WorkReportDTO.java +++ b/navalplanner-webapp/src/main/java/org/navalplanner/ws/workreports/api/WorkReportDTO.java @@ -20,7 +20,6 @@ package org.navalplanner.ws.workreports.api; -import java.util.Date; import java.util.HashSet; import java.util.Set; @@ -28,6 +27,7 @@ import javax.xml.bind.annotation.XmlAttribute; import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlElementWrapper; import javax.xml.bind.annotation.XmlRootElement; +import javax.xml.datatype.XMLGregorianCalendar; import org.navalplanner.business.workreports.entities.WorkReport; import org.navalplanner.ws.common.api.IntegrationEntityDTO; @@ -47,7 +47,7 @@ public class WorkReportDTO extends IntegrationEntityDTO { public String workReportType; @XmlAttribute - public Date date; + public XMLGregorianCalendar date; @XmlAttribute public String resource; @@ -70,7 +70,8 @@ public class WorkReportDTO extends IntegrationEntityDTO { public WorkReportDTO() { } - public WorkReportDTO(String code, String workReportType, Date date, + public WorkReportDTO(String code, String workReportType, + XMLGregorianCalendar date, String resource, String orderElement, Set labels, Set descriptionValues, Set workReportLines) { diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/ws/workreports/api/WorkReportLineDTO.java b/navalplanner-webapp/src/main/java/org/navalplanner/ws/workreports/api/WorkReportLineDTO.java index 3464c433a..8ac04bf51 100644 --- a/navalplanner-webapp/src/main/java/org/navalplanner/ws/workreports/api/WorkReportLineDTO.java +++ b/navalplanner-webapp/src/main/java/org/navalplanner/ws/workreports/api/WorkReportLineDTO.java @@ -20,7 +20,6 @@ package org.navalplanner.ws.workreports.api; -import java.util.Date; import java.util.HashSet; import java.util.Set; @@ -28,6 +27,7 @@ import javax.xml.bind.annotation.XmlAttribute; import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlElementWrapper; import javax.xml.bind.annotation.XmlRootElement; +import javax.xml.datatype.XMLGregorianCalendar; import org.navalplanner.business.workreports.entities.WorkReportLine; import org.navalplanner.ws.common.api.IntegrationEntityDTO; @@ -44,7 +44,7 @@ public class WorkReportLineDTO extends IntegrationEntityDTO { public final static String ENTITY_TYPE = "work-report-line"; @XmlAttribute - public Date date; + public XMLGregorianCalendar date; @XmlAttribute public String resource; @@ -56,10 +56,10 @@ public class WorkReportLineDTO extends IntegrationEntityDTO { public String typeOfWorkHours; @XmlAttribute(name = "start-hour") - public Date clockStart; + public XMLGregorianCalendar clockStart; @XmlAttribute(name = "finish-hour") - public Date clockFinish; + public XMLGregorianCalendar clockFinish; @XmlAttribute(name = "hours") public Integer numHours; @@ -75,9 +75,11 @@ public class WorkReportLineDTO extends IntegrationEntityDTO { public WorkReportLineDTO() { } - public WorkReportLineDTO(String code, Date date, String resource, - String orderElement, String typeOfWorkHours, Date clockStart, - Date clockFinish, Integer numHours, Set labels, + public WorkReportLineDTO(String code, XMLGregorianCalendar date, + String resource, + String orderElement, String typeOfWorkHours, + XMLGregorianCalendar clockStart, XMLGregorianCalendar clockFinish, + Integer numHours, Set labels, Set descriptionValues) { super(code); this.date = date; diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/ws/workreports/impl/WorkReportConverter.java b/navalplanner-webapp/src/main/java/org/navalplanner/ws/workreports/impl/WorkReportConverter.java index e4a77bec4..1f87957ed 100644 --- a/navalplanner-webapp/src/main/java/org/navalplanner/ws/workreports/impl/WorkReportConverter.java +++ b/navalplanner-webapp/src/main/java/org/navalplanner/ws/workreports/impl/WorkReportConverter.java @@ -26,6 +26,8 @@ import java.util.Date; import java.util.HashSet; import java.util.Set; +import javax.xml.datatype.XMLGregorianCalendar; + import org.apache.commons.lang.StringUtils; import org.navalplanner.business.common.Registry; import org.navalplanner.business.common.exceptions.InstanceNotFoundException; @@ -41,6 +43,7 @@ import org.navalplanner.business.workreports.entities.WorkReportLine; import org.navalplanner.business.workreports.entities.WorkReportType; import org.navalplanner.business.workreports.valueobjects.DescriptionValue; import org.navalplanner.ws.common.api.LabelReferenceDTO; +import org.navalplanner.ws.common.impl.DateConverter; import org.navalplanner.ws.common.impl.LabelReferenceConverter; import org.navalplanner.ws.workreports.api.DescriptionValueDTO; import org.navalplanner.ws.workreports.api.WorkReportDTO; @@ -78,7 +81,7 @@ public final class WorkReportConverter { // Optional fields if (workReportDTO.date != null) { - workReport.setDate(workReportDTO.date); + workReport.setDate(DateConverter.toDate(workReportDTO.date)); } if (workReportDTO.orderElement != null) { @@ -88,6 +91,8 @@ public final class WorkReportConverter { workReport.setOrderElement(orderElement); } catch (InstanceNotFoundException e) { workReport.setOrderElement(null); + throw new ValidationException( + _("There is no order element with this code")); } } @@ -98,15 +103,24 @@ public final class WorkReportConverter { workReport.setResource(worker); } catch (InstanceNotFoundException e) { workReport.setResource(null); + throw new ValidationException( + _("There is no resource with this nif")); } } - if (workReportDTO.labels != null) { + if (workReportDTO.labels != null && !workReportDTO.labels.isEmpty()) { + try { workReport.setLabels(LabelReferenceConverter .toEntity(workReportDTO.labels)); + } catch (InstanceNotFoundException e) { + throw new ValidationException( + _("There is no label with this code " + + (String) e.getKey())); + } } - if (workReportDTO.descriptionValues != null) { + if (workReportDTO.descriptionValues != null + && !workReportDTO.descriptionValues.isEmpty()) { workReport .setDescriptionValues(toEntity(workReportDTO.descriptionValues)); } @@ -138,7 +152,8 @@ public final class WorkReportConverter { // Optional fields if (workReportLineDTO.date != null) { - workReportLine.setDate(workReportLineDTO.date); + workReportLine + .setDate(DateConverter.toDate(workReportLineDTO.date)); } if (workReportLineDTO.orderElement != null) { @@ -148,6 +163,8 @@ public final class WorkReportConverter { workReportLine.setOrderElement(orderElement); } catch (InstanceNotFoundException e) { workReportLine.setOrderElement(null); + throw new ValidationException( + _("There is no order element with this code")); } } @@ -158,17 +175,22 @@ public final class WorkReportConverter { workReportLine.setResource(worker); } catch (InstanceNotFoundException e) { workReportLine.setResource(null); + throw new ValidationException( + _("There is no resource with this nif")); } } if (workReportLineDTO.clockStart != null) { - workReportLine.setClockStart(workReportLineDTO.clockStart); + workReportLine.setClockStart(DateConverter + .toLocalTime(workReportLineDTO.clockStart)); } if (workReportLineDTO.clockFinish != null) { - workReportLine.setClockFinish(workReportLineDTO.clockFinish); + workReportLine.setClockFinish(DateConverter + .toLocalTime(workReportLineDTO.clockFinish)); } - if (workReportLineDTO.labels != null) { + if (workReportLineDTO.labels != null + && !workReportLineDTO.labels.isEmpty()) { workReportLine.setLabels(LabelReferenceConverter .toEntity(workReportLineDTO.labels)); } @@ -211,9 +233,9 @@ public final class WorkReportConverter { } // Optional fields - Date date = null; + XMLGregorianCalendar date = null; if (workReport.getDate() != null) { - date = workReport.getDate(); + date = DateConverter.toXMLGregorianCalendar(workReport.getDate()); } String orderElementCode = null; @@ -262,7 +284,8 @@ public final class WorkReportConverter { public final static WorkReportLineDTO toDTO(WorkReportLine line){ String code = line.getCode(); - Date date = line.getDate(); + XMLGregorianCalendar date = DateConverter.toXMLGregorianCalendar(line + .getDate()); String resource = null; if((line.getResource() != null) && (line.getResource() instanceof Worker)){ @@ -279,14 +302,15 @@ public final class WorkReportConverter { typeOfWorkHours = line.getTypeOfWorkHours().getCode(); } - Date clockStart = null; + XMLGregorianCalendar clockStart = null; if(line.getClockStart() != null){ - clockStart = line.getClockStart().toDateTimeToday().toDate(); + clockStart = DateConverter.toXMLGregorianCalendar(line.getClockStart()); } - Date clockFinish = null; + XMLGregorianCalendar clockFinish = null; if(line.getClockFinish() != null){ - clockFinish = line.getClockFinish().toDateTimeToday().toDate(); + clockFinish = DateConverter.toXMLGregorianCalendar(line + .getClockFinish()); } Integer numHours = null; @@ -331,6 +355,10 @@ public final class WorkReportConverter { public final static void updateWorkReport(WorkReport workReport, WorkReportDTO workReportDTO) throws ValidationException { + if (StringUtils.isBlank(workReportDTO.code)) { + throw new ValidationException(_("missing code in a work report.")); + } + WorkReportType type = workReport.getWorkReportType(); /* * 1: Update the existing work report line or add new @@ -361,41 +389,44 @@ public final class WorkReportConverter { /* * 2: Update the existing labels */ - for (LabelReferenceDTO labelDTO : workReportDTO.labels) { + if (workReportDTO.labels != null) { + for (LabelReferenceDTO labelDTO : workReportDTO.labels) { - /* Step 2.1: requires each label reference DTO to have a code. */ - if (StringUtils.isBlank(labelDTO.code)) { - throw new ValidationException( - _("missing code in a label")); - } + /* Step 2.1: requires each label reference DTO to have a code. */ + if (StringUtils.isBlank(labelDTO.code)) { + throw new ValidationException(_("missing code in a label")); + } - try { - Set