/** * *************************************************************************** * Copyright (c) 2010 Qcadoo Limited * Project: Qcadoo MES * Version: 1.4 * * This file is part of Qcadoo. * * Qcadoo is free software; you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published * by the Free Software Foundation; either version 3 of the License, * or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * *************************************************************************** */ package com.qcadoo.mes.assignmentToShift.hooks; import com.google.common.base.Function; import com.google.common.base.Optional; import com.google.common.collect.ContiguousSet; import com.google.common.collect.DiscreteDomain; import com.google.common.collect.FluentIterable; import com.google.common.collect.Range; import com.qcadoo.mes.assignmentToShift.constants.AssignmentToShiftFields; import com.qcadoo.mes.assignmentToShift.dataProviders.AssignmentToShiftCriteria; import com.qcadoo.mes.assignmentToShift.dataProviders.AssignmentToShiftDataProvider; import com.qcadoo.mes.assignmentToShift.states.constants.AssignmentToShiftState; import com.qcadoo.mes.assignmentToShift.states.constants.AssignmentToShiftStateChangeDescriber; import com.qcadoo.mes.basic.shift.Shift; import com.qcadoo.mes.basic.shift.ShiftsFactory; import com.qcadoo.mes.states.service.StateChangeEntityBuilder; import com.qcadoo.model.api.DataDefinition; import com.qcadoo.model.api.Entity; import com.qcadoo.model.api.search.SearchCriterion; import com.qcadoo.model.api.utils.EntityUtils; import org.joda.time.LocalDate; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.*; import static com.qcadoo.model.api.search.SearchOrders.asc; import static com.qcadoo.model.api.search.SearchProjections.*; import static com.qcadoo.model.api.search.SearchRestrictions.*; @Service public class AssignmentToShiftHooks { private static final String L_ALREADY_EXISTS = "assignmentToShift.assignmentToShift.entityAlreadyExists"; @Autowired private StateChangeEntityBuilder stateChangeEntityBuilder; @Autowired private AssignmentToShiftStateChangeDescriber describer; @Autowired private AssignmentToShiftDataProvider assignmentToShiftDataProvider; @Autowired private ShiftsFactory shiftsFactory; public void onCreate(final DataDefinition assignmentToShiftDD, final Entity assignmentToShift) { setExternalSynchronized(assignmentToShift); setInitialState(assignmentToShift); } public void onCopy(final DataDefinition assignmentToShiftDD, final Entity assignmentToShift) { setExternalSynchronized(assignmentToShift); setNextDay(assignmentToShift); setInitialState(assignmentToShift); } public boolean onValidate(final DataDefinition assignmentToShiftDD, final Entity assignmentToShift) { return checkUniqueEntity(assignmentToShift); } private void setExternalSynchronized(final Entity assignmentToShift) { assignmentToShift.setField(AssignmentToShiftFields.EXTERNAL_SYNCHRONIZED, true); } void setInitialState(final Entity assignmentToShift) { stateChangeEntityBuilder.buildInitial(describer, assignmentToShift, AssignmentToShiftState.DRAFT); } void setNextDay(final Entity assignmentToShift) { Optional<LocalDate> maybeNewDate = resolveNextStartDate(assignmentToShift); assignmentToShift.setField(AssignmentToShiftFields.START_DATE, maybeNewDate.transform(TO_DATE).orNull()); } private Optional<LocalDate> resolveNextStartDate(final Entity assignmentToShift) { LocalDate startDate = LocalDate.fromDateFields(assignmentToShift.getDateField(AssignmentToShiftFields.START_DATE)); Shift shift = shiftsFactory.buildFrom(assignmentToShift.getBelongsToField(AssignmentToShiftFields.SHIFT)); Entity factory = assignmentToShift.getBelongsToField(AssignmentToShiftFields.FACTORY); Entity crew = assignmentToShift.getBelongsToField(AssignmentToShiftFields.CREW); Set<LocalDate> occupiedDates = findNextStartDatesMatching(assignmentToShift.getDataDefinition(), startDate, shift, factory, crew); Calendar cal = Calendar.getInstance(); cal.setTime(new Date()); int daysInYear = cal.getActualMaximum(Calendar.DAY_OF_YEAR); Iterable<Integer> daysRange = ContiguousSet.create(Range.closed(1, daysInYear), DiscreteDomain.integers()); return FluentIterable.from(daysRange).transform(startDate::plusDays).firstMatch((final LocalDate localDate) -> !occupiedDates.contains(localDate) && shift.worksAt(localDate)); } private static final Function<Date, LocalDate> TO_LOCAL_DATE = LocalDate::fromDateFields; private static final Function<LocalDate, Date> TO_DATE = LocalDate::toDate; private Set<LocalDate> findNextStartDatesMatching(final DataDefinition assignmentToShiftDD, final LocalDate laterThan, final Shift shift, final Entity factory, Entity crew) { AssignmentToShiftCriteria criteria = AssignmentToShiftCriteria.empty(); criteria.withCriteria(gt(AssignmentToShiftFields.START_DATE, laterThan.toDate())); criteria.withShiftCriteria(idEq(shift.getId())); criteria.withFactoryCriteria(idEq(factory.getId())); if(Objects.nonNull(crew)){ criteria.withCrewCriteria(idEq(crew.getId())); } List<Entity> matchingStartDatesProjection = assignmentToShiftDataProvider.findAll(criteria, Optional.of(alias(field(AssignmentToShiftFields.START_DATE), AssignmentToShiftFields.START_DATE)), Optional.of(asc(AssignmentToShiftFields.START_DATE))); return FluentIterable.from(matchingStartDatesProjection) .transform(EntityUtils.<Date> getFieldExtractor(AssignmentToShiftFields.START_DATE)).transform(TO_LOCAL_DATE) .toSet(); } boolean checkUniqueEntity(final Entity assignmentToShift) { Date startDate = assignmentToShift.getDateField(AssignmentToShiftFields.START_DATE); Entity shift = assignmentToShift.getBelongsToField(AssignmentToShiftFields.SHIFT); Entity factory = assignmentToShift.getBelongsToField(AssignmentToShiftFields.FACTORY); Entity crew = assignmentToShift.getBelongsToField(AssignmentToShiftFields.CREW); AssignmentToShiftCriteria criteria = AssignmentToShiftCriteria.empty(); SearchCriterion additionalCriteria = eq(AssignmentToShiftFields.START_DATE, startDate); criteria.withShiftCriteria(idEq(shift.getId())); criteria.withFactoryCriteria(idEq(factory.getId())); if (crew != null) { criteria.withCrewCriteria(idEq(crew.getId())); } else { additionalCriteria = and(additionalCriteria, isNull(AssignmentToShiftFields.CREW)); } if (assignmentToShift.getId() != null) { additionalCriteria = and(additionalCriteria, idNe(assignmentToShift.getId())); } criteria.withCriteria(additionalCriteria); for (Entity matchingAssignment : assignmentToShiftDataProvider.find(criteria, Optional.of(alias(id(), "id"))).asSet()) { addErrorMessages(assignmentToShift.getDataDefinition(), assignmentToShift); return false; } return true; } private void addErrorMessages(final DataDefinition assignmentToShiftDD, final Entity assignmentToShift) { assignmentToShift.addError(assignmentToShiftDD.getField(AssignmentToShiftFields.START_DATE), L_ALREADY_EXISTS); assignmentToShift.addError(assignmentToShiftDD.getField(AssignmentToShiftFields.SHIFT), L_ALREADY_EXISTS); assignmentToShift.addError(assignmentToShiftDD.getField(AssignmentToShiftFields.FACTORY), L_ALREADY_EXISTS); assignmentToShift.addError(assignmentToShiftDD.getField(AssignmentToShiftFields.CREW), L_ALREADY_EXISTS); } }