Author: tchemit Date: 2014-04-04 17:37:35 +0200 (Fri, 04 Apr 2014) New Revision: 1837 Url: http://forge.codelutin.com/projects/wao/repository/revisions/1837 Log: refs #4487 import + save contacts Added: trunk/wao-persistence/src/main/java/fr/ifremer/wao/entity/ElligibleBoatTopiaDao.java trunk/wao-persistence/src/main/java/fr/ifremer/wao/entity/SampleMonthTopiaDao.java trunk/wao-persistence/src/main/java/fr/ifremer/wao/entity/SampleMonths.java trunk/wao-services/src/main/java/fr/ifremer/wao/services/service/ContactNotValidException.java trunk/wao-services/src/main/java/fr/ifremer/wao/services/service/ContactStatus.java trunk/wao-services/src/main/java/fr/ifremer/wao/services/service/EmailService.java trunk/wao-services/src/main/java/fr/ifremer/wao/services/service/NullSampleMonthException.java trunk/wao-services/src/main/java/fr/ifremer/wao/services/service/csv/ObsMerContactImportExportModel.java trunk/wao-web/src/main/webapp/WEB-INF/content/obsmer/import-contacts-input.jsp Removed: trunk/wao-web/src/main/webapp/WEB-INF/content/obsmer/import-contacts.jsp Modified: trunk/wao-persistence/src/main/java/fr/ifremer/wao/entity/SampleRowImpl.java trunk/wao-services/src/main/java/fr/ifremer/wao/services/service/ImportErrorException.java trunk/wao-services/src/main/java/fr/ifremer/wao/services/service/ObsMerContactsService.java trunk/wao-services/src/main/resources/i18n/wao-services_en_GB.properties trunk/wao-services/src/main/resources/i18n/wao-services_fr_FR.properties trunk/wao-services/src/test/java/fr/ifremer/wao/services/service/ObsMerContactsServiceTest.java trunk/wao-web/src/main/webapp/WEB-INF/content/obsmer/contacts.jsp Added: trunk/wao-persistence/src/main/java/fr/ifremer/wao/entity/ElligibleBoatTopiaDao.java =================================================================== --- trunk/wao-persistence/src/main/java/fr/ifremer/wao/entity/ElligibleBoatTopiaDao.java (rev 0) +++ trunk/wao-persistence/src/main/java/fr/ifremer/wao/entity/ElligibleBoatTopiaDao.java 2014-04-04 15:37:35 UTC (rev 1837) @@ -0,0 +1,19 @@ +package fr.ifremer.wao.entity; + +public class ElligibleBoatTopiaDao extends AbstractElligibleBoatTopiaDao<ElligibleBoat> { + + public ElligibleBoat findUniqueOrNull(Contact contact) { + ElligibleBoat elligible = + forProperties( + ElligibleBoat.PROPERTY_BOAT, contact.getBoat(), + ElligibleBoat.PROPERTY_SAMPLE_ROW, contact.getSampleRow()).findUniqueOrNull(); + return elligible; + } + + public ElligibleBoat create(Contact contact) { + ElligibleBoat elligibleBoat = create( + ElligibleBoat.PROPERTY_BOAT, contact.getBoat(), + ElligibleBoat.PROPERTY_SAMPLE_ROW, contact.getSampleRow()); + return elligibleBoat; + } +} Property changes on: trunk/wao-persistence/src/main/java/fr/ifremer/wao/entity/ElligibleBoatTopiaDao.java ___________________________________________________________________ Added: svn:keywords + Author Date Id Revision Added: svn:eol-style + native Added: trunk/wao-persistence/src/main/java/fr/ifremer/wao/entity/SampleMonthTopiaDao.java =================================================================== --- trunk/wao-persistence/src/main/java/fr/ifremer/wao/entity/SampleMonthTopiaDao.java (rev 0) +++ trunk/wao-persistence/src/main/java/fr/ifremer/wao/entity/SampleMonthTopiaDao.java 2014-04-04 15:37:35 UTC (rev 1837) @@ -0,0 +1,27 @@ +package fr.ifremer.wao.entity; + +import com.google.common.collect.ImmutableMap; +import org.nuiton.topia.persistence.HqlAndParametersBuilder; +import org.nuiton.topia.persistence.TopiaNoResultException; +import org.nuiton.util.PeriodDates; + +import java.util.Date; + +public class SampleMonthTopiaDao extends AbstractSampleMonthTopiaDao<SampleMonth> { + + public SampleMonth getExistingSampleMonth(SampleRow sampleRow, Date tideBeginDate) throws TopiaNoResultException { + + PeriodDates period = new PeriodDates(tideBeginDate, tideBeginDate); + period.initDayOfMonthExtremities(); + + HqlAndParametersBuilder<SampleMonth> query = newHqlAndParametersBuilder(); + query.addEquals(SampleMonth.PROPERTY_SAMPLE_ROW, sampleRow); + query.addWhereClause(SampleMonth.PROPERTY_PERIOD_DATE + " >= :beforeDate", ImmutableMap.of("beforeDate", (Object) period.getFromDate())); + query.addWhereClause(SampleMonth.PROPERTY_PERIOD_DATE + " <= :endDate", ImmutableMap.of("endDate", (Object) period.getThruDate())); + + + SampleMonth result = findUnique(query.getHql(), query.getHqlParameters()); + return result; + } + +} Property changes on: trunk/wao-persistence/src/main/java/fr/ifremer/wao/entity/SampleMonthTopiaDao.java ___________________________________________________________________ Added: svn:keywords + Author Date Id Revision Added: svn:eol-style + native Added: trunk/wao-persistence/src/main/java/fr/ifremer/wao/entity/SampleMonths.java =================================================================== --- trunk/wao-persistence/src/main/java/fr/ifremer/wao/entity/SampleMonths.java (rev 0) +++ trunk/wao-persistence/src/main/java/fr/ifremer/wao/entity/SampleMonths.java 2014-04-04 15:37:35 UTC (rev 1837) @@ -0,0 +1,49 @@ +package fr.ifremer.wao.entity; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * Created on 4/4/14. + * + * @author Tony Chemit <chemit@codelutin.com> + * @since 4.0 + */ +public class SampleMonths { + + + /** Logger. */ + private static final Log log = LogFactory.getLog(SampleMonths.class); + + /** + * Method could be use to add some time for realTidesValue or + * remove time with a negative nbDays. + * If nbDays is negative and superior to the current value, + * the real tides value will be set to 0. + * + * @param nbDays to add or remove (if negative) + */ + public static void addRealTideTime(SampleMonth sampleMonth, int nbDays) { + int result = sampleMonth.getRealTidesValue() + nbDays; + if (result < 0) { + result = 0; + } + if (log.isDebugEnabled()) { + log.debug("Change realTides : " + sampleMonth.getRealTidesValue() + + " -> " + result + " _ date = " + sampleMonth.getPeriodDate()); + } + sampleMonth.setRealTidesValue(result); + } + + public static void addEstimatedTideTime(SampleMonth sampleMonth, int nbDays) { + int result = sampleMonth.getEstimatedTidesValue() + nbDays; + if (result < 0) { + result = 0; + } + if (log.isDebugEnabled()) { + log.debug("Change estimatedTides : " + sampleMonth.getEstimatedTidesValue() + + " -> " + result + " _ date = " + sampleMonth.getPeriodDate()); + } + sampleMonth.setEstimatedTidesValue(result); + } +} Property changes on: trunk/wao-persistence/src/main/java/fr/ifremer/wao/entity/SampleMonths.java ___________________________________________________________________ Added: svn:keywords + Author Date Id Revision Added: svn:eol-style + native Modified: trunk/wao-persistence/src/main/java/fr/ifremer/wao/entity/SampleRowImpl.java =================================================================== --- trunk/wao-persistence/src/main/java/fr/ifremer/wao/entity/SampleRowImpl.java 2014-04-04 14:52:44 UTC (rev 1836) +++ trunk/wao-persistence/src/main/java/fr/ifremer/wao/entity/SampleRowImpl.java 2014-04-04 15:37:35 UTC (rev 1837) @@ -25,6 +25,7 @@ package fr.ifremer.wao.entity; import com.google.common.base.Preconditions; +import com.google.common.collect.Iterables; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; @@ -36,7 +37,7 @@ /** * SampleRowImpl - * + * <p/> * Created: 30 nov. 2009 * * @author fdesbois <fdesbois@codelutin.com> @@ -109,7 +110,7 @@ /** * Used to get a list of boat's immatriculations linked with the sampleRow. - * + * * @return a simple String which contains immatriculations separate by * a space */ @@ -126,10 +127,10 @@ } /** - * Check if SampleMonth of the SampleRow has already realTidesValue set + * Check if SampleMonth of the SampleRow has already realTidesValue set * (different from 0). It means the SampleRow could'nt be deleted and * have some modification constraints. - * + * * @return true if a SampleMonth have realTidesValue, false otherwise */ @Override @@ -144,7 +145,8 @@ @Override public String getProfessionDescription() { - String code = StringUtils.join(getdCF5Code(), ", "); + String code = isdCF5CodeEmpty() ? "" : + StringUtils.join(Iterables.transform(getdCF5Code(), DCF5Codes.getCode()), ", "); code += getProfessionDescriptionWithoutDCF5(); return code; } @@ -245,9 +247,8 @@ @Override public TerrestrialLocation getTerrestrialLocation() { TerrestrialLocation terrestrialLocation = null; - if ( ! isTerrestrialLocationsEmpty()) { - terrestrialLocation = (TerrestrialLocation) - CollectionUtils.get(getTerrestrialLocations(), 0); + if (!isTerrestrialLocationsEmpty()) { + terrestrialLocation = CollectionUtils.get(getTerrestrialLocations(), 0); } return terrestrialLocation; } @@ -255,7 +256,7 @@ @Override public SampleMonth getSampleMonth(Date date) { Preconditions.checkState( - ! getObsProgram().equals(ObsProgram.OBSDEB), + !getObsProgram().equals(ObsProgram.OBSDEB), "opération non prévue pour ObsDeb"); if (CollectionUtils.isNotEmpty(getSampleMonth())) { for (SampleMonth sampleMonth : getSampleMonth()) { Added: trunk/wao-services/src/main/java/fr/ifremer/wao/services/service/ContactNotValidException.java =================================================================== --- trunk/wao-services/src/main/java/fr/ifremer/wao/services/service/ContactNotValidException.java (rev 0) +++ trunk/wao-services/src/main/java/fr/ifremer/wao/services/service/ContactNotValidException.java 2014-04-04 15:37:35 UTC (rev 1837) @@ -0,0 +1,20 @@ +package fr.ifremer.wao.services.service; + +import fr.ifremer.wao.WaoException; + +/** + * Quand un contact n'est pas valide (lors d'une création ou d'un import). + * <p/> + * Created on 4/4/14. + * + * @author Tony Chemit <chemit@codelutin.com> + * @since 4.0 + */ +public class ContactNotValidException extends WaoException { + + private static final long serialVersionUID = 1L; + + public ContactNotValidException(String message) { + super(message); + } +} Property changes on: trunk/wao-services/src/main/java/fr/ifremer/wao/services/service/ContactNotValidException.java ___________________________________________________________________ Added: svn:keywords + Author Date Id Revision Added: svn:eol-style + native Added: trunk/wao-services/src/main/java/fr/ifremer/wao/services/service/ContactStatus.java =================================================================== --- trunk/wao-services/src/main/java/fr/ifremer/wao/services/service/ContactStatus.java (rev 0) +++ trunk/wao-services/src/main/java/fr/ifremer/wao/services/service/ContactStatus.java 2014-04-04 15:37:35 UTC (rev 1837) @@ -0,0 +1,350 @@ +/* + * #%L + * Wao :: Business + * * + * $Id$ + * $HeadURL: https://svn.codelutin.com/wao/tags/wao-3.4.1/wao-business/src/main/java/fr/i... $ + * %% + * Copyright (C) 2009 - 2010 Ifremer + * %% + * This program 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 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, see <http://www.gnu.org/licenses/>. + * #L% + */ + +package fr.ifremer.wao.services.service; + +import fr.ifremer.wao.entity.Contact; +import fr.ifremer.wao.entity.ContactState; +import fr.ifremer.wao.entity.SampleMonth; +import fr.ifremer.wao.entity.SampleMonthTopiaDao; +import fr.ifremer.wao.entity.SampleRow; +import org.apache.commons.lang3.BooleanUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.nuiton.topia.persistence.TopiaNoResultException; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Date; + +/** + * //FIXME a revoir... + * This class is used to know status changed between an old contact and a new + * one (new change to apply). There is three different cases for constructor + * parameters : + * <ul> + * <li>CREATE : olContact is null and newContact is defined</li> + * <li>UPDATE : both oldContact and newContact are defined</li> + * <li>DELETE : oldContact is defined and newContact is null</li> + * </ul> + * Three fields of contact are considered to be changed for sampleMonth calcul + * on tides value : + * <ul> + * <li> + * STATE : check the change on {@link ContactState#OBSERVATION_DONE} state. + * Use {@link #isContactDoneChanged() } method to check the change. + * This change is important to manage estimated tides value on sampleMonth + * referenced by the contact retrieve with {@link #getSampleMonth()} + * </li> + * <li> + * VALIDATION : check the change on validationCompany and validationProgram. + * Use {@link #isContactValidateChanged() } method to check the change. + * This change is important to manage real tides value on sampleMonth + * referenced by the contact retrieve with {@link #getSampleMonth()} + * </li> + * <li> + * TIDE BEGIN DATE : check the change on tideBeginDate month. + * Use {@link #isTideBeginDateMonthChanged() } method to check the change. + * This change is important to manage both estimated and real tides value on + * the old sampleMonth referenced by the old contact retrieve with + * {@link #getOldSampleMonth()} + * </ul> + * <p/> + * <p/> + * Created: 19 avr. 2010 + * + * @author fdesbois + */ +public class ContactStatus { + + /** Logger. */ + private static final Log logger = LogFactory.getLog(ContactStatus.class); + + protected Contact oldContact; + + protected Contact newContact; + + protected SampleRow sampleRow; + + protected SampleMonth oldSampleMonth; + + protected SampleMonth sampleMonth; + + protected final SampleMonthTopiaDao dao; + + public ContactStatus(SampleMonthTopiaDao dao, + Contact old, + Contact contact) { + this.dao = dao; + this.oldContact = old; + this.newContact = contact; + this.sampleRow = contact != null ? + newContact.getSampleRow() : oldContact.getSampleRow(); + } + + public boolean isOldContactValidate() { + return isContactValidate(Context.OLD); + } + + public boolean isNewContactValidate() { + return isContactValidate(Context.NEW); + } + + /** + * Return true if oldContact validate is not the same as newContact + * validate. + * + * @return true if contact validate has changed. + * @see #isContactValidate(Context) + */ + public boolean isContactValidateChanged() { + return isOldContactValidate() != isNewContactValidate(); + } + + public boolean isOldContactDone() { + return isContactDone(Context.OLD); + } + + public boolean isNewContactDone() { + return isContactDone(Context.NEW); + } + + /** + * Return true if oldContact state is not the same as newContact state. + * Check only for {@link ContactState#OBSERVATION_DONE} changed. + * + * @return true if contact state has changed. + * @see #isContactDone(Context) + */ + public boolean isContactDoneChanged() { + return isOldContactDone() != isNewContactDone(); + } + + /** + * Return true if tideBeginDate has changed its month between oldContact + * and newContact. The both oldContact and newContact dates must be not + * null. + * + * @return true if tideBeginDate status changed + */ + public boolean isTideBeginDateMonthChanged() { + + if (oldContact == null || newContact == null) { + return false; + } + DateFormat dateFormat = new SimpleDateFormat("MM/yyyy"); + Date oldTideBeginDate = oldContact.getObservationBeginDate(); + Date newTideBeginDate = newContact.getObservationBeginDate(); + + logger.debug("old : " + oldTideBeginDate + ", new : " + newTideBeginDate); + + // Only if old not null and new not null + if (oldTideBeginDate != null && newTideBeginDate != null) { + String oldTideBeginStr = dateFormat.format(oldTideBeginDate); + String newTideBeginStr = dateFormat.format(newTideBeginDate); + return !oldTideBeginStr.equals(newTideBeginStr); + } + return false; + } + + public SampleRow getSampleRow() { + return sampleRow; + } + + /** + * Retrive the old SampleMonth referenced by the tideBeginDate of the + * old contact. + * + * @return the sampleMonth found or throw NullSampleMonthException + * @throws NullSampleMonthException + */ + public SampleMonth getOldSampleMonth() + throws NullSampleMonthException { + if (oldSampleMonth == null) { + oldSampleMonth = getExistingSampleMonth(Context.OLD); + } + return oldSampleMonth; + } + + /** + * Retrive the SampleMonth referenced by the tideBeginDate of the + * new contact. + * + * @return the sampleMonth found or throw NullSampleMonthException + * @throws NullSampleMonthException + */ + public SampleMonth getSampleMonth() + throws NullSampleMonthException { + if (sampleMonth == null) { + sampleMonth = getExistingSampleMonth(Context.NEW); + } + return sampleMonth; + } + + protected enum Context { + OLD, NEW + } + + /** + * Retrieve existing sampleMonth corresponding to the contact. The + * sampleMonth must match with contact sampleRow, also the tideBeginDate + * (day) of the contact must match the sampleMonth periodDate (month). + * + * @param context OLD or NEW + * @return the sampleMonth found if exists, or NullSampleMonthException + * will be thrown + * @throws NullSampleMonthException if month was not found + */ + protected SampleMonth getExistingSampleMonth(Context context) throws NullSampleMonthException { + + // Reference date for query + Date tideBeginDate = null; + + switch (context) { + case OLD: + tideBeginDate = oldContact.getObservationBeginDate(); + break; + // newContact may be null in CREATE case, so we use the previous + // one + case NEW: + if (newContact != null && + newContact.getObservationBeginDate() != null) { + tideBeginDate = newContact.getObservationBeginDate(); + } else { + tideBeginDate = oldContact.getObservationBeginDate(); + } + } + + SampleMonth result; + try { + result = dao.getExistingSampleMonth(sampleRow, tideBeginDate); + } catch (TopiaNoResultException e) { + throw new NullSampleMonthException( + "Aucun mois correspondant pour" + + " la ligne du plan d'échantillonnage " + + sampleRow.getCode() + + " et la date de début de marée du contact " + + tideBeginDate + ); + } + return result; + } + + /** + * Return true if contact is validate depends on {@code context}. The + * oldContact validation will be tested for an {@link Context#OLD} context + * and the newContact will be tested for a {@link Context#NEW} context. + * The validation is tested as validationCompany must be TRUE and + * validationProgram must be not FALSE (otherwise TRUE or NULL). + * + * @param context to check the good contact + * @return true depends on validationCompany and validationProgram of + * the contact (oldContact or newContact depends on context in argument). + */ + protected boolean isContactValidate(Context context) { + Contact contact = context == Context.OLD ? oldContact : newContact; + + Boolean validationCompany = contact != null ? + contact.getValidationCompany() : null; + Boolean validationProgram = contact != null ? + contact.getValidationProgram() : null; + + if (logger.isTraceEnabled()) { + logger.trace(context + " validation company = " + validationCompany + + " _ validation program = " + validationProgram); + } + + boolean contactValidate = + BooleanUtils.isTrue(validationCompany) && + BooleanUtils.isNotFalse(validationProgram); + return contactValidate; + } + + public boolean isRefused() { + Boolean oldValidationProgram = oldContact != null ? + oldContact.getValidationProgram() : null; + Boolean newValidationProgram = newContact != null ? + newContact.getValidationProgram() : null; + + return BooleanUtils.isNotFalse(oldValidationProgram) && + BooleanUtils.isFalse(newValidationProgram); + } + + public boolean isNoMoreRefused() { + Boolean oldValidationProgram = oldContact != null ? + oldContact.getValidationProgram() : null; + Boolean newValidationProgram = newContact != null ? + newContact.getValidationProgram() : null; + + return BooleanUtils.isFalse(oldValidationProgram) && + BooleanUtils.isNotFalse(newValidationProgram); + } + + /** + * Return true if contact state is {@link ContactState#OBSERVATION_DONE} + * depends on {@code context}. To check oldContact state, use + * {@link Context#OLD} and to check newContact state, use + * {@link Context#NEW}. A null contact will return false. + * + * @param context to check the good contact + * @return true if the contact state is {@link ContactState#OBSERVATION_DONE} + */ + protected boolean isContactDone(Context context) { + Contact contact = context == Context.OLD ? oldContact : newContact; + ContactState contactState = contact != null ? + contact.getContactState() : null; + + if (logger.isTraceEnabled()) { + logger.trace(context + " contact state = " + contactState); + } + boolean contactDone = ContactState.OBSERVATION_DONE.equals(contactState); + return contactDone; + } + + @Override + public String toString() { + DateFormat dateFormat = new SimpleDateFormat("MM/yyyy"); + String oldMonth = oldContact != null && + oldContact.getObservationBeginDate() != null ? + dateFormat.format(oldContact.getObservationBeginDate()) : ""; + + String newMonth = newContact != null && + newContact.getObservationBeginDate() != null ? + dateFormat.format(newContact.getObservationBeginDate()) : ""; + + StringBuilder builder = + new StringBuilder("\nContactStatus : VALIDATE :: "). + append("oldValidate = ").append(isOldContactValidate()). + append(" _ newValidate = ").append(isNewContactValidate()). + append("\nContactStatus : CONTACT_STATE :: "). + append("oldDone = ").append(isOldContactDone()). + append(" _ newDone = ").append(isNewContactDone()). + append("\nContactStatus : TIDE_BEGIN_DATE :: "). + append("oldMonth = ").append(oldMonth). + append(" _ newMonth = ").append(newMonth). + append(" _ changed = ").append(isTideBeginDateMonthChanged()); + + return builder.toString(); + } +} Property changes on: trunk/wao-services/src/main/java/fr/ifremer/wao/services/service/ContactStatus.java ___________________________________________________________________ Added: svn:keywords + Author Date Id Revision Added: svn:eol-style + native Added: trunk/wao-services/src/main/java/fr/ifremer/wao/services/service/EmailService.java =================================================================== --- trunk/wao-services/src/main/java/fr/ifremer/wao/services/service/EmailService.java (rev 0) +++ trunk/wao-services/src/main/java/fr/ifremer/wao/services/service/EmailService.java 2014-04-04 15:37:35 UTC (rev 1837) @@ -0,0 +1,50 @@ +package fr.ifremer.wao.services.service; + +import com.google.common.base.Charsets; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.commons.mail.EmailException; +import org.apache.commons.mail.SimpleEmail; + +/** + * Created on 4/4/14. + * + * @author Tony Chemit <chemit@codelutin.com> + * @since 4.0 + */ +public class EmailService extends WaoServiceSupport { + + /** Logger. */ + private static final Log log = LogFactory.getLog(EmailService.class); + + public void sendEmail(String to, String subject, String msg) + throws EmailException { + if (log.isInfoEnabled()) { + log.info("Send an email to " + to + " : " + subject); + } + SimpleEmail email = prepareEmail(to, subject, msg); + if (getApplicationConfig().isDevMode()) { + log.debug("send email to " + to + " subject " + subject + " msg " + msg); + } else { + email.send(); + } + } + + public SimpleEmail prepareEmail(String to, String subject, String msg) + throws EmailException { + + String smtpFrom = getApplicationConfig().getSmtpFrom(); + int smtpPort = getApplicationConfig().getSmtpPort(); + String smtpHost = getApplicationConfig().getSmtpHost(); + + SimpleEmail email = new SimpleEmail(); + email.setHostName(smtpHost); + email.setSmtpPort(smtpPort); + email.setFrom(smtpFrom); + email.addTo(to); + email.setSubject(subject); + email.setMsg(msg); + email.setCharset(Charsets.UTF_8.toString()); + return email; + } +} Property changes on: trunk/wao-services/src/main/java/fr/ifremer/wao/services/service/EmailService.java ___________________________________________________________________ Added: svn:keywords + Author Date Id Revision Added: svn:eol-style + native Modified: trunk/wao-services/src/main/java/fr/ifremer/wao/services/service/ImportErrorException.java =================================================================== --- trunk/wao-services/src/main/java/fr/ifremer/wao/services/service/ImportErrorException.java 2014-04-04 14:52:44 UTC (rev 1836) +++ trunk/wao-services/src/main/java/fr/ifremer/wao/services/service/ImportErrorException.java 2014-04-04 15:37:35 UTC (rev 1837) @@ -30,12 +30,23 @@ */ public class ImportErrorException extends WaoException { + private static final long serialVersionUID = 1L; + + //FIXME ? Why? protected static final String MESSAGE = I18n.t("wao.import.failure"); public ImportErrorException(ImportRuntimeException e) { super(e); } + public ImportErrorException(ContactNotValidException e) { + super(e); + } + + public ImportErrorException(NullSampleMonthException e) { + super(e); + } + @Override public String getMessage() { return MESSAGE + " " + getCause().getMessage(); Added: trunk/wao-services/src/main/java/fr/ifremer/wao/services/service/NullSampleMonthException.java =================================================================== --- trunk/wao-services/src/main/java/fr/ifremer/wao/services/service/NullSampleMonthException.java (rev 0) +++ trunk/wao-services/src/main/java/fr/ifremer/wao/services/service/NullSampleMonthException.java 2014-04-04 15:37:35 UTC (rev 1837) @@ -0,0 +1,16 @@ +package fr.ifremer.wao.services.service; + +import fr.ifremer.wao.WaoException; + +/** + * This exception is used to indicate that a problem is occured during + * retrieving sampleMonth corresponding to a contact. + */ +public final class NullSampleMonthException extends WaoException { + + private static final long serialVersionUID = 1L; + + public NullSampleMonthException(String message) { + super(message); + } +} Property changes on: trunk/wao-services/src/main/java/fr/ifremer/wao/services/service/NullSampleMonthException.java ___________________________________________________________________ Added: svn:keywords + Author Date Id Revision Added: svn:eol-style + native Modified: trunk/wao-services/src/main/java/fr/ifremer/wao/services/service/ObsMerContactsService.java =================================================================== --- trunk/wao-services/src/main/java/fr/ifremer/wao/services/service/ObsMerContactsService.java 2014-04-04 14:52:44 UTC (rev 1836) +++ trunk/wao-services/src/main/java/fr/ifremer/wao/services/service/ObsMerContactsService.java 2014-04-04 15:37:35 UTC (rev 1837) @@ -4,29 +4,56 @@ import com.google.common.collect.ImmutableSet; import fr.ifremer.wao.ContactsFilter; import fr.ifremer.wao.WaoTechnicalException; +import fr.ifremer.wao.WaoUtils; +import fr.ifremer.wao.entity.Boat; import fr.ifremer.wao.entity.Contact; +import fr.ifremer.wao.entity.ContactState; +import fr.ifremer.wao.entity.ContactStateMotif; import fr.ifremer.wao.entity.ContactTopiaDao; +import fr.ifremer.wao.entity.DataReliability; +import fr.ifremer.wao.entity.ElligibleBoat; +import fr.ifremer.wao.entity.ElligibleBoatTopiaDao; +import fr.ifremer.wao.entity.FishingZone; +import fr.ifremer.wao.entity.ObsProgram; +import fr.ifremer.wao.entity.ObservedDataControl; +import fr.ifremer.wao.entity.SampleMonth; +import fr.ifremer.wao.entity.SampleMonths; +import fr.ifremer.wao.entity.SampleRow; +import fr.ifremer.wao.entity.WaoUser; +import fr.ifremer.wao.entity.WaoUserTopiaDao; import fr.ifremer.wao.services.AuthenticatedWaoUser; -import fr.ifremer.wao.services.service.csv.ContactImportExportModel; +import fr.ifremer.wao.services.service.csv.ObsMerContactImportExportModel; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.BooleanUtils; +import org.apache.commons.lang3.ObjectUtils; +import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.time.DateUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.apache.commons.mail.EmailException; import org.nuiton.csv.Export; import org.nuiton.csv.ExportModel; import org.nuiton.csv.Import; import org.nuiton.csv.ImportModel; import org.nuiton.csv.ImportRuntimeException; import org.nuiton.topia.persistence.pager.TopiaPagerBean; +import org.nuiton.util.DateUtil; +import org.nuiton.util.StringUtil; +import org.nuiton.util.beans.Binder; +import org.nuiton.util.beans.BinderFactory; import java.io.InputStream; +import java.util.ArrayList; import java.util.Calendar; import java.util.Collection; import java.util.Date; import java.util.HashSet; import java.util.List; +import java.util.Locale; +import static org.nuiton.i18n.I18n.l; + public class ObsMerContactsService extends WaoServiceSupport { private static final Log log = LogFactory.getLog(ObsMerContactsService.class); @@ -124,12 +151,11 @@ public InputStream exportContacts(ContactsFilter filter) { ContactTopiaDao dao = getContactDao(); - List<Contact> sampleRows = dao.findAll(filter); + List<Contact> contacts = dao.findAll(filter); - ExportModel<Contact> exportModel = - new ContactImportExportModel(filter.getSampleRowFilter().getObsProgram()); + ExportModel<Contact> exportModel = ObsMerContactImportExportModel.forExport(filter.getSampleRowFilter().getObsProgram()); - Export<Contact> export = Export.newExport(exportModel, sampleRows); + Export<Contact> export = Export.newExport(exportModel, contacts); try { @@ -144,56 +170,558 @@ } } - public void importContacts(AuthenticatedWaoUser authenticatedWaoUser, InputStream csv) throws ImportErrorException { - ImportModel<Contact> contactImportModel = newContactsImportModel(authenticatedWaoUser); + public void importContacts(AuthenticatedWaoUser authenticatedWaoUser, + InputStream csv) throws ImportErrorException { + ObsProgram obsProgram = authenticatedWaoUser.getObsProgram(); + + List<SampleRow> sampleRows = + getSampleRowDao().forObsProgramOrdinalEquals(obsProgram.ordinal()).findAll(); + List<WaoUser> waoUsers = getWaoUserDao().findAll(); + List<Boat> boats = getBoatDao().findAll(); + List<ContactStateMotif> motives = getContactStateMotifDao().findAll(); + + ImportModel<Contact> contactImportModel = + ObsMerContactImportExportModel.forImport(obsProgram, + waoUsers, + sampleRows, + boats, + motives); + Import<Contact> contactImport = Import.newImport(contactImportModel, csv); - ContactTopiaDao dao = getContactDao(); - try { for (Contact contact : contactImport) { - //FIXME - dao.create(contact); - + createOrUpdateContact(authenticatedWaoUser, contact); } } catch (ImportRuntimeException e) { throw new ImportErrorException(e); + } catch (ContactNotValidException e) { + throw new ImportErrorException(e); + } catch (NullSampleMonthException e) { + throw new ImportErrorException(e); } commit(); } - //FIXME - protected ImportModel<Contact> newContactsImportModel(AuthenticatedWaoUser authenticatedWaoUser) { + public void save(AuthenticatedWaoUser authenticatedWaoUser, Contact contact) + throws EmailException, ContactNotValidException, NullSampleMonthException { -// ObsProgram obsProgram = authenticatedWaoUser.getObsProgram(); -// -// CompanyTopiaDao companyDao = getCompanyDao(); -// List<Company> activeCompanies = companyDao.forActiveEquals(true).findAll(); -// -// TerrestrialLocationTopiaDao terrestrialLocationDao = getTerrestrialLocationDao(); -// List<TerrestrialLocation> terrestrialDistricts = -// terrestrialLocationDao.forLocationTypeEquals(LocationType.DISTRICT).findAll(); -// -// FishingZoneTopiaDao fishingZoneDao = getFishingZoneDao(); -// List<FishingZone> fishingZones = fishingZoneDao.findAll(); -// -// ReferentialService referentialService = getReferentialService(); + ContactTopiaDao dao = getContactDao(); + Contact contactFound = dao.findByTopiaId(contact.getTopiaId()); -// ImportModel<Contact> samplingPlanImportModel = -// new ContactImportExportModel(obsProgram, -// null, -// activeCompanies, -// fishingZones, -// terrestrialDistricts, -// referentialService); -// -// return samplingPlanImportModel; - return null; + notifyUsersForMammalsObservation(contactFound, contact); + // createOrUpdateContact(transaction, contactFound, contact, true); + createOrUpdateContact(authenticatedWaoUser, contact); + + commit(); } + + public void delete(Contact contact) throws NullSampleMonthException { + + ContactTopiaDao dao = getContactDao(); + Contact contactFound = dao.findByTopiaId(contact.getTopiaId()); + + // Need to decrement estimated value if contactFound has + // OBSERVATION_DONE state and may be real value (normally not allowed) + updateSampleMonthTidesValue(contactFound, null, true); + + // Execute delete + dao.delete(contactFound); + + commit(); + } + + /** + * The goal of this method is to put in common code that will be executed + * while updating a single contact (from UI) and while updating multiple + * contacts (from import). + * + * @param connectedUser user who is modifying the contact + * @param contact the contact to save or create + * @return true if the contact was successfully updated, false if contact + * was not updated due to insufficient right (modifying data as + * observer after a validation by administrator) + */ + protected boolean createOrUpdateContact(AuthenticatedWaoUser connectedUser, + Contact contact) throws ContactNotValidException, NullSampleMonthException { + + validateContact(contact); + + ContactTopiaDao dao = getContactDao(); + Contact contactFound = null; + if (contact.getTopiaId() != null) { + contactFound = dao.findByTopiaId(contact.getTopiaId()); + } + + // Prevent that someone who is not admin change data that only admin + // must be able to modify + if (!connectedUser.isAdmin()) { + if (contactFound == null) { + contact.setCommentAdmin(null); + contact.setValidationProgram(null); + contact.setDataReliability(DataReliability.UNKNOWN); + } else { + contact.setCommentAdmin(contactFound.getCommentAdmin()); + contact.setValidationProgram(contactFound.getValidationProgram()); + contact.setDataReliability(contactFound.getDataReliability()); + } + } + + boolean contactCanBeUpdated = true; + if (contactFound != null && connectedUser.isCoordinatorOrObserver()) { + contactCanBeUpdated = contactFound.getValidationProgram() == null; + } + + if (contactCanBeUpdated) { + + updateElligibleBoatForContact(contact); + updateSampleMonthTidesValue(contactFound, contact, true); + + if (contactFound == null) { + if (contact.getCreationDate() == null) { + contact.setCreationDate(serviceContext.getNow()); + } + dao.create(contact); + } else { + Binder<Contact, Contact> contactBinder = BinderFactory.newBinder(Contact.class); + contactBinder.copyExcluding(contact, contactFound, + Contact.PROPERTY_TOPIA_ID, + Contact.PROPERTY_TOPIA_VERSION, + Contact.PROPERTY_TOPIA_CREATE_DATE, + Contact.PROPERTY_SAMPLE_ROW); +// contactFound.clearSecondaryObservers(); +// if (contact.getSecondaryObservers() != null) { +// contactFound.addAllSecondaryObservers(contact.getSecondaryObservers()); +// } + dao.update(contactFound); + } + } + return contactCanBeUpdated; + } + + + protected void notifyUsersForMammalsObservation(Contact contactFound, Contact contact) { + + boolean sendNotification = false; + + // we send notifications if there is mammals Capture and + // we prevent re-send of multiple identical messages + if (contact.isMammalsCapture()) { + String oldMessage = null; + if (contactFound != null) { + oldMessage = contactFound.getMammalsInfo(); + } + boolean messageChanged = ObjectUtils.notEqual(contact.getMammalsInfo(), oldMessage); + if (messageChanged) { + sendNotification = true; + } + } + + if (sendNotification) { + + // we will send a mail with a body like + //Bonjour, + // + //Un observateur du programme Obsmer a renseigné dans WAO l'information suivante : + // + //Marée : 25/10/2010 00:00 - 26/10/2010 00:00 + //Métier : 2010_0037 Manche Ouest (Manche, Mer du Nord) Secteur Brest Granville centré autour de St malo OTB_DEF 80-90 Chalutage de fond côtier sole, seiche + // + //Capture accidentelle : + //deux tritons et une sirène + // + //Cordialement, + // + //Le programme Obsmer + //http://www.ifremer.fr/wao + + Locale locale = serviceContext.getLocale(); + + String object = l(locale, "wao.business.mammalsCapture.mail.subject"); + + // building 2 string, components of the body + + // the time of the capture (it's between tide begin and end) + String time = ""; + if (contact.getObservationBeginDate() != null) { + time = WaoUtils.formatDateTime(locale, contact.getObservationBeginDate()) + " "; + } + if (contact.getObservationEndDate() != null) { + time += WaoUtils.formatDateTime(locale, contact.getObservationEndDate()); + } + + // some details from the sample row, facade, etc. + SampleRow sampleRow = contact.getSampleRow(); + List<String> facadesNames = new ArrayList<String>(); + for (FishingZone fishingZone : sampleRow.getFishingZone()) { + facadesNames.add(fishingZone.getSectorName() + " (" + fishingZone.getFacadeName() + ")"); + } + String profession = sampleRow.getCode() + " " + + " " + StringUtil.join(facadesNames, ", ", true) + + " " + sampleRow.getFishingZonesInfos() + + " " + sampleRow.getProfessionDescription() + + " " + sampleRow.getProfession().getLibelle() + + " " + sampleRow.getProfession().getSpecies(); + + // constructing the whole mail + String body = l(locale, "wao.business.mammalsCapture.mail.message", + time, profession, contact.getMammalsInfo()); + + if (log.isInfoEnabled()) { + log.info("will send email with object '" + object + "' and body \n" + body); + } + + // now trying to find to what user we need to send the mail + WaoUserTopiaDao userDao = getWaoUserDao(); + // users contains all the user we need to notify for the capture + List<WaoUser> waoUsers = userDao.forMammalsNotificationsEquals(true).findAll(); + + if (log.isDebugEnabled()) { + log.debug("notification will be sent to " + waoUsers.size() + " users"); + } + + // sending the same e-mail to all of them + for (WaoUser waoUser : waoUsers) { + String userLogin = waoUser.getLogin(); + if (StringUtil.isEmail(userLogin)) { + try { + EmailService emailService = newService(EmailService.class); + emailService.sendEmail(userLogin, object, body); + if (log.isInfoEnabled()) { + log.info("email sent to " + userLogin); + } + } catch (EmailException e) { + if (log.isErrorEnabled()) { + log.error("unable to send email to " + userLogin, e); + } + } + } + } + } + } + + /** + * Update the SampleMonth data for tidesValue (estimated and real) from + * {@code contact} compared to its old state {@code oldContact}. The + * estimated is update when contact state {@link ContactState#OBSERVATION_DONE} + * is changed. The real is update when contact validationCompany is changed. + * The {@code calculateReal} flag determines if the real tides has to be + * calculated or not. Three cases : + * <ul> + * <li>CREATE : {@code oldContact} = null and {@code contact} is defined</li> + * <li>UPDATE : both {@code oldContact} and {@code contact} are defined</li> + * <li>DELETE : {@code oldContact} is defined and {@code contact} = null</li> + * </ul> + * <p> + * <strong>Estimated Tides value</strong> = nbContacts with OBSERVATION_DONE + * state and not refused by program (validationProgram != FALSE) + * </p> + * <p> + * <strong>Real Tides value</strong> = nbContacts accepted by company + * (validationCompany = TRUE) and not refused by program + * (validationProgram != FALSE) + * </p> + * + * @param oldContact old state of the contact + * @param contact changed can be null for delete case + * @param calculateReal to calculate real tides value + * @throws NullSampleMonthException if SampleMonth can't be found + */ + protected void updateSampleMonthTidesValue(Contact oldContact, + Contact contact, + boolean calculateReal) throws NullSampleMonthException { + + if (oldContact == null && contact == null) { + throw new IllegalArgumentException("Both contact and oldContact" + + " can't be null to update sampleMonth tides value"); + } + + // Instantiate contact status which provide status on oldContact and + // contact changes + ContactStatus status = new ContactStatus(getSampleMonthDao(), oldContact, contact); + + if (log.isDebugEnabled()) { + log.debug(status.toString()); + } + + // Month of TideBeginDate has changed, must decrement values on + // old sampleMonth + boolean tideBeginDateChanged = false; + if (oldContact != null && contact != null && + status.isTideBeginDateMonthChanged()) { + + tideBeginDateChanged = status.isTideBeginDateMonthChanged(); + + // Retrieve oldMonth from status + try { + SampleMonth oldMonth = status.getOldSampleMonth(); + + // Apply changes on oldMonth + if (status.isOldContactValidate()) { + // decrement real tides + SampleMonths.addRealTideTime(oldMonth, -1); + } + // Decrement estimated only if old state is OBSERVATION_DONE + // and old validationProgram is NOT FALSE + // the estimated value has already been decremented during + // refused + if (status.isOldContactDone() && BooleanUtils.isNotFalse( + oldContact.getValidationProgram())) { + // decrement estimated tides + SampleMonths.addEstimatedTideTime(oldMonth, -1); + } + + // Catch the null exception, only a warning if the oldSampleMonth is + // not found + } catch (NullSampleMonthException eee) { + if (log.isWarnEnabled()) { + log.warn("Error on retrieve old sampleMonth", eee); + } + } + } + + ContactState currentState = contact != null ? + contact.getContactState() : oldContact.getContactState(); + + // Validation of contact has changed in status, modify realTides + // Only calculate real for a currentState equals to OBSERVATION_DONE + if (calculateReal && ContactState.OBSERVATION_DONE.equals(currentState) && + (status.isContactValidateChanged() || tideBeginDateChanged)) { + + SampleMonth sampleMonth = status.getSampleMonth(); + + if (status.isNewContactValidate()) { + // increment real tides + SampleMonths.addRealTideTime(sampleMonth, 1); + // validationProgram becomes not FALSE, estimatedTides must be + // incremented + if (status.isNoMoreRefused()) { + SampleMonths.addEstimatedTideTime(sampleMonth, 1); + } + // never decrement if tideBeginDate has changed + } else if (status.isOldContactValidate() && !tideBeginDateChanged) { + // decrement real tides + SampleMonths.addRealTideTime(sampleMonth, -1); + // validationProgram becomes FALSE, estimatedTides must be + // decremented + if (status.isRefused()) { + SampleMonths.addEstimatedTideTime(sampleMonth, -1); + } + } + } + + // ContactState of contact has changed in status, modify estimatedTides + if (status.isContactDoneChanged() || tideBeginDateChanged) { + + SampleMonth sampleMonth = status.getSampleMonth(); + + if (status.isNewContactDone()) { + // increment estimated tides + SampleMonths.addEstimatedTideTime(sampleMonth, 1); + // never decrement if tideBeginDate has changed + } else if (status.isOldContactDone() && !tideBeginDateChanged) { + // decrement estimated tides + SampleMonths.addEstimatedTideTime(sampleMonth, -1); + } + } + } + + protected void validateContact(Contact contact) throws ContactNotValidException { + + Locale l = serviceContext.getLocale(); + + Contact oldContact = null; + if (contact.getTopiaId() != null) { + oldContact = getContactDao().findByTopiaId(contact.getTopiaId()); + } + + // S'il s'agit de dé-valider pour le coordinateur ou l'administrateur + // on ne fait aucun contrôle + boolean skip = oldContact != null + && oldContact.getValidationProgram() != null && + contact.getValidationProgram() == null; + + if (skip) { + return; + } + + if (contact.getMainObserver() == null) { + throw new ContactNotValidException(l(l, "wao.import.contact.failure.missing.main.observer")); + } + + if (contact.getSecondaryObservers() != null && + contact.getSecondaryObservers().contains(contact.getMainObserver())) { + throw new ContactNotValidException(l(l, "wao.import.contact.failure.mainObserver.cant.be.secondaryObserver")); + } + + for (WaoUser observer : contact.getAllObservers()) { + boolean observerWorksForCompanyInSampleRow = observer.getCompany().equals(contact.getSampleRow().getCompany()); + if (!observerWorksForCompanyInSampleRow) { + throw new ContactNotValidException(l(l, "wao.import.contact.failure.invalid.company.for.observer", + observer.getLogin(), contact.getSampleRow().getCompany().getName())); + } + } + + // Validation for saving contact depends on contactState + ContactState contactState = contact.getContactState(); + Date observationBeginDate = contact.getObservationBeginDate(); + if (log.isDebugEnabled()) { + log.debug("For state : " + contactState + " and observation begin date " + observationBeginDate); + } + + // need the sample months to be loaded, it's never the case :-( + // boolean operationBeginDateIsValid = contact.getSampleRow().isValid(observationBeginDate); + + String sampleRowCode = contact.getSampleRow().getCode(); + SampleRow sampleRow = getSampleRowDao().forCodeEquals(sampleRowCode).findAny(); + + SampleMonth month = sampleRow.getSampleMonth(observationBeginDate); + boolean operationBeginDateIsValid = month != null; + + if (log.isDebugEnabled()) { + log.debug("operation begin data is valid : " + operationBeginDateIsValid); + } + + if (observationBeginDate != null && !operationBeginDateIsValid) { + throw new ContactNotValidException(l(l, "wao.import.contact.failure.invalid.trip.beginDate", + contact.getSampleRow().getCode())); + } + + Date observationEndDate = contact.getObservationEndDate(); + if (observationBeginDate != null && observationEndDate != null + && observationEndDate.before(observationBeginDate)) { + throw new ContactNotValidException(l(l, "wao.import.contact.failure.invalid.observation.endDate")); + } + + Date dataInputDate = contact.getDataInputDate(); + // Here, we check that the date input date is after the end of the + // observation. Since the first is a day (at 00:00) and the second + // is date-time, there may be a bug if the data input day is the same + // as the end of observation + boolean observationEndDateIsBeforeDataInputDate = + observationEndDate == null + || dataInputDate == null + || observationEndDate.before(DateUtil.setMaxTimeOfDay(dataInputDate)); + + if (log.isDebugEnabled()) { + log.debug("observationEndDate = " + observationEndDate + + ", dateInputDate = " + dataInputDate + ", observationEndDateIsBeforeDataInputDate = " + + observationEndDateIsBeforeDataInputDate); + } + if (!observationEndDateIsBeforeDataInputDate) { + throw new ContactNotValidException(l(l, "wao.import.contact.failure.invalid.observation.end")); + } + + Date currentDate = serviceContext.getNow(); + if (observationEndDate != null && observationEndDate.after(currentDate)) { + throw new ContactNotValidException(l(l, "wao.import.contact.failure.invalid.trip.endDate")); + } + + if (dataInputDate != null && dataInputDate.after(currentDate)) { + throw new ContactNotValidException(l(l, "wao.import.contact.failure.invalid.observation.end2")); + } + + // Non abouti + if (contactState == ContactState.OBSERVATION_CANCELLED && StringUtils.isBlank(contact.getComment())) { + throw new ContactNotValidException(l(l, "wao.business.contact.validation.commentMissingForState", + contact.getContactState().toString())); + // Observation réalisée + } else if (contactState.equals(ContactState.OBSERVATION_DONE)) { + + if (observationBeginDate == null) { + throw new ContactNotValidException(l(l, "wao.import.contact.failure.missing.trip.beginDate", contactState)); + } + if (observationEndDate == null) { + throw new ContactNotValidException(l(l, "wao.import.contact.failure.missing.observation.endDate", contactState)); + } + if (contact.getNbObservants() == 0) { + throw new ContactNotValidException(l(l, "wao.import.contact.failure.invalid.observer.state", contactState)); + } + if (contact.getObsProgram() == ObsProgram.OBSVENTE) { + if (contact.getTerrestrialLocation() == null) { + throw new ContactNotValidException(l(l, "wao.import.contact.failure.missing.observationArea")); + } + } + } + + // Ici, les contrôle spécifique à ObsMer + if (contact.getObsProgram() == ObsProgram.OBSMER) { + + boolean contactMustHaveAMotif = contact.getObsProgram() == ObsProgram.OBSMER + && (contactState == ContactState.CONTACT_REFUSED + || contactState == ContactState.CONTACT_DEFINITELY_REFUSED); + if (contactMustHaveAMotif && contact.getContactStateMotif() == null) { + throw new ContactNotValidException(l(l, "wao.business.contact.validation.contactStateMotifMissing")); + } + + if (!contactMustHaveAMotif && contact.getContactStateMotif() != null) { + throw new ContactNotValidException(l(l, "wao.business.contact.validation.contactStateMotifUnwanted")); + } + + if (log.isDebugEnabled()) { + log.debug("validationProgram = " + contact.getValidationProgram()); + } + + if (BooleanUtils.isTrue(contact.getValidationCompany())) { + // Pour valider un contact société, il faut que le contact aie une date de transmission + if (contact.getContactState() == ContactState.OBSERVATION_DONE && contact.getObservedDataControl() == null) { + throw new ContactNotValidException(l(l, "wao.business.contact.validation.observedDataControlMissingForValidation")); + } + if (contact.getObservedDataControl() == ObservedDataControl.ACCEPTED && contact.getRestitution() == null) { + throw new ContactNotValidException(l(l, "wao.business.contact.validation.restitutionMissingForValidation")); + } + if (contact.getDataInputDate() == null && contact.getRestitution() != null) { + throw new ContactNotValidException(l(l, "wao.import.contact.failure.missing.observationDate")); + } + if (contact.getDataInputDate() != null && contact.getRestitution() != null && contact.getRestitution().before(contact.getDataInputDate())) { + throw new ContactNotValidException(l(l, "wao.import.contact.failure.invalid.transmissionDate")); + } + } + + if (BooleanUtils.isTrue(contact.getValidationProgram())) { + // it's an admin validation, data-reliability field must be filled + if (log.isDebugEnabled()) { + log.debug("field data reliability is " + contact.getDataReliability()); + } + + if (contact.getDataReliability() == null || + contact.getDataReliability() == DataReliability.UNKNOWN) { + throw new ContactNotValidException(l(l, "wao.business.contact.validation.dataReliabilityMissingForValidation")); + } else if (contact.getDataReliability() != DataReliability.RELIABLE + && StringUtils.isEmpty(contact.getCommentAdmin())) { + throw new ContactNotValidException(l(l, "wao.business.contact.validation.commentAdminNecessaryForDataReliability", + contact.getDataReliability().toString())); + } + } + } + } + + /** + * Update the elligible boat depends on contact creation. The + * {@code contact} reference can only be created for a sampleRow and a + * boat if both are linked with an elligibleBoat. So this method is + * used to create the link if needed during contacts import. This + * elligibleBoat is needed for the contact owned by a company, so + * the companyActive property of ElligibleBoat will be set to TRUE. No + * admin has decided to explicitly create this link. + * + * @param contact which contains sampleRow and boat to link + */ + protected void updateElligibleBoatForContact(Contact contact) { + + ElligibleBoatTopiaDao elligibleDAO = getElligibleBoatDao(); + ElligibleBoat elligible = elligibleDAO.findUniqueOrNull(contact); + + if (elligible == null) { + // Create new elligible boat not active in a global way + elligible = elligibleDAO.create(contact); + } + elligible.setCompanyActive(Boolean.TRUE); + } } Copied: trunk/wao-services/src/main/java/fr/ifremer/wao/services/service/csv/ObsMerContactImportExportModel.java (from rev 1830, trunk/wao-services/src/main/java/fr/ifremer/wao/services/service/csv/ContactImportExportModel.java) =================================================================== --- trunk/wao-services/src/main/java/fr/ifremer/wao/services/service/csv/ObsMerContactImportExportModel.java (rev 0) +++ trunk/wao-services/src/main/java/fr/ifremer/wao/services/service/csv/ObsMerContactImportExportModel.java 2014-04-04 15:37:35 UTC (rev 1837) @@ -0,0 +1,222 @@ +/* + * #%L + * Wao :: Business + * + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2009 - 2011 Ifremer + * %% + * This program 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 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, see <http://www.gnu.org/licenses/>. + * #L% + */ +package fr.ifremer.wao.services.service.csv; + +import com.google.common.base.Preconditions; +import fr.ifremer.wao.entity.Boat; +import fr.ifremer.wao.entity.Company; +import fr.ifremer.wao.entity.Contact; +import fr.ifremer.wao.entity.ContactImpl; +import fr.ifremer.wao.entity.ContactState; +import fr.ifremer.wao.entity.ContactStateMotif; +import fr.ifremer.wao.entity.DataReliability; +import fr.ifremer.wao.entity.ObsProgram; +import fr.ifremer.wao.entity.SampleRow; +import fr.ifremer.wao.entity.WaoUser; +import fr.ifremer.wao.services.service.csv.operations.BoatParserFormatter; +import fr.ifremer.wao.services.service.csv.operations.CompanyParserFormatter; +import fr.ifremer.wao.services.service.csv.operations.ContactStateMotivesParserFormatter; +import fr.ifremer.wao.services.service.csv.operations.ObservedDataControlParserFormatter; +import fr.ifremer.wao.services.service.csv.operations.SampleRowParserFormatter; +import fr.ifremer.wao.services.service.csv.operations.UserParserFormatter; +import fr.ifremer.wao.services.service.csv.operations.UsersParserFormatter; +import org.apache.commons.lang3.StringUtils; +import org.nuiton.csv.Common; +import org.nuiton.csv.ExportableColumn; +import org.nuiton.csv.ImportExportModel; +import org.nuiton.csv.ImportableColumn; +import org.nuiton.csv.ModelBuilder; +import org.nuiton.csv.ValueFormatter; +import org.nuiton.csv.ValueGetter; + +import java.util.LinkedList; +import java.util.List; + +public class ObsMerContactImportExportModel implements ImportExportModel<Contact> { + + protected ObsProgram obsProgram; + + protected List<WaoUser> waoUsers; + + protected List<SampleRow> sampleRows; + + protected List<Boat> boats; + + protected List<ContactStateMotif> motives; + + public static ObsMerContactImportExportModel forExport(ObsProgram obsProgram) { + return new ObsMerContactImportExportModel(obsProgram, null, null, null, null); + } + + public static ObsMerContactImportExportModel forImport(ObsProgram obsProgram, + List<WaoUser> waoUsers, + List<SampleRow> sampleRows, + List<Boat> boats, + List<ContactStateMotif> motives) { + + Preconditions.checkState(waoUsers != null, "To import must have waoUsers"); + Preconditions.checkState(boats != null, "To import must have boats"); + Preconditions.checkState(sampleRows != null, "To import must have sampleRows"); + Preconditions.checkState(motives != null, "To import must have motives"); + return new ObsMerContactImportExportModel(obsProgram, waoUsers, sampleRows, boats, motives); + } + + protected ObsMerContactImportExportModel(ObsProgram obsProgram, + List<WaoUser> waoUsers, + List<SampleRow> sampleRows, + List<Boat> boats, + List<ContactStateMotif> motives) { + this.obsProgram = obsProgram; + this.waoUsers = waoUsers; + this.sampleRows = sampleRows; + this.boats = boats; + this.motives = motives; + } + + @Override + public char getSeparator() { + return ';'; + } + + @Override + public void pushCsvHeaderNames(List<String> headerNames) { + // nothing to do + } + + @Override + public Contact newEmptyInstance() { + Contact newContact = new ContactImpl(); + newContact.setObsProgram(obsProgram); + return newContact; + } + + public ModelBuilder<Contact> getExportModel() { + return getModel(); + } + + public ModelBuilder<Contact> getImportModel() { + Preconditions.checkState(sampleRows != null, "To import must have sampleRows"); + Preconditions.checkState(waoUsers != null, "To import must have waoUsers"); + Preconditions.checkState(boats != null, "To import must have boats"); + Preconditions.checkState(motives != null, "To import must have motives"); + return getModel(); + } + + protected ModelBuilder<Contact> getModel() { + ModelBuilder<Contact> modelBuilder = new ModelBuilder<>(); + modelBuilder.newColumnForImportExport("CONTACT_ID", Contact.PROPERTY_TOPIA_ID); + modelBuilder.newColumnForImportExport("CONTACT_DATE_CREATION", Contact.PROPERTY_CREATION_DATE, Common.DAY_TIME); + if (waoUsers != null) { + modelBuilder.newColumnForImportExport("CONTACT_OBSERVATEUR_PRINCIPAL", Contact.PROPERTY_MAIN_OBSERVER, new UserParserFormatter(waoUsers)); + modelBuilder.newColumnForImportExport("CONTACT_OBSERVATEURS_SECONDAIRES", Contact.PROPERTY_SECONDARY_OBSERVERS, new UsersParserFormatter(waoUsers)); + } + + modelBuilder.newIgnoredColumn("CONTACT_OBSERVATEURS_NOMS"); + modelBuilder.newColumnForExport( + "CONTACT_OBSERVATEURS_NOMS", + "allObservers", + new ValueFormatter<List<WaoUser>>() { + @Override + public String format(List<WaoUser> value) { + List<String> fullNames = new LinkedList<>(); + for (WaoUser waoUser : value) { + fullNames.add(waoUser.getFullName()); + } + return StringUtils.join(fullNames, ", "); + } + } + ); + modelBuilder.newIgnoredColumn("CONTACT_OBSERVATEURS_SOCIETE"); + modelBuilder.newColumnForExport( + "CONTACT_OBSERVATEURS_SOCIETE", + new ValueGetter<Contact, Company>() { + @Override + public Company get(Contact contact) { + return contact.getMainObserver().getCompany(); + } + }, + new CompanyParserFormatter(null) + ); + modelBuilder.newColumnForImportExport("CONTACT_ETAT", "contactState", new Common.ToStringParserFormatter(ContactState.getAllowedStates(obsProgram))); + modelBuilder.newColumnForImportExport("CONTACT_DEBUT_OBSERVATION", Contact.PROPERTY_OBSERVATION_BEGIN_DATE, Common.DAY_TIME); + modelBuilder.newColumnForImportExport("CONTACT_FIN_OBSERVATION", Contact.PROPERTY_OBSERVATION_END_DATE, Common.DAY_TIME); + modelBuilder.newColumnForImportExport("CONTACT_SAISIE_DONNEES", Contact.PROPERTY_DATA_INPUT_DATE, Common.DAY); + modelBuilder.newColumnForImportExport("CONTACT_COMMENTAIRE_OBSERVATEUR", Contact.PROPERTY_COMMENT); + modelBuilder.newColumnForImportExport("CONTACT_COMMENTAIRE_COORDINATEUR", Contact.PROPERTY_COMMENT_COORDINATOR); + modelBuilder.newColumnForImportExport("CONTACT_COMMENTAIRE_PROGRAMME", Contact.PROPERTY_COMMENT_ADMIN); + + if (boats != null) { + modelBuilder.newColumnForImportExport("NAVIRE_IMMATRICULATION", Contact.PROPERTY_BOAT, new BoatParserFormatter(boats)); + } + modelBuilder.newIgnoredColumn("NAVIRE_NOM"); + modelBuilder.newColumnForExport("NAVIRE_NOM", new ValueGetter<Contact, String>() { + @Override + public String get(Contact contact) throws Exception { + return contact.getBoat().getName(); + } + }); + modelBuilder.newColumnForImportExport("CONTACT_VALIDATION_SOCIETE", Contact.PROPERTY_VALIDATION_COMPANY, Common.BOOLEAN); + modelBuilder.newColumnForImportExport("CONTACT_VALIDATION_PROGRAMME", Contact.PROPERTY_VALIDATION_PROGRAM, Common.BOOLEAN); + + if (sampleRows != null) { + modelBuilder.newColumnForImportExport("PLAN_CODE", Contact.PROPERTY_SAMPLE_ROW, new SampleRowParserFormatter(sampleRows)); + } + + modelBuilder.newColumnForImportExport("CONTACT_QUALITE_DONNEE", "dataReliability", + new Common.ToStringParserFormatter<>(DataReliability.values())); + modelBuilder.newColumnForImportExport("CONTACT_OBSERVATION_MAMMIFERE", Contact.PROPERTY_MAMMALS_OBSERVATION, Common.BOOLEAN); + modelBuilder.newColumnForImportExport("CONTACT_CAPTURE_ACCIDENTELLE", Contact.PROPERTY_MAMMALS_CAPTURE, Common.BOOLEAN); + modelBuilder.newIgnoredColumn("CONTACT_CAPTURE_ACCIDENTELLE_DETAILS"); + modelBuilder.newColumnForExport("CONTACT_CAPTURE_ACCIDENTELLE_DETAILS", Contact.PROPERTY_MAMMALS_INFO); + if (motives != null) { + modelBuilder.newColumnForImportExport("CONTACT_ETAT_MOTIF_CODE", Contact.PROPERTY_CONTACT_STATE_MOTIF, new ContactStateMotivesParserFormatter(motives)); + } + modelBuilder.newIgnoredColumn("CONTACT_ETAT_MOTIF_NOM"); + modelBuilder.newColumnForExport("CONTACT_ETAT_MOTIF_NOM", new ValueGetter<Contact, String>() { + @Override + public String get(Contact contact) throws Exception { + String name = ""; + if (contact.getContactStateMotif() != null) { + name = contact.getContactStateMotif().getName(); + } + return name; + } + }); + modelBuilder.newColumnForImportExport("CONTACT_TRANSMISSION_RESTITUTION", Contact.PROPERTY_RESTITUTION, Common.DAY); + modelBuilder.newColumnForImportExport("CONTACT_DONNEES_ALLEGRO_VALIDEES", Contact.PROPERTY_OBSERVED_DATA_CONTROL, new ObservedDataControlParserFormatter()); + + return modelBuilder; + } + + @Override + public Iterable<ExportableColumn<Contact, Object>> getColumnsForExport() { + return (Iterable) getModel().getColumnsForExport(); + } + + @Override + public Iterable<ImportableColumn<Contact, Object>> getColumnsForImport() { + return (Iterable) getModel().getColumnsForImport(); + } + +} Modified: trunk/wao-services/src/main/resources/i18n/wao-services_en_GB.properties =================================================================== --- trunk/wao-services/src/main/resources/i18n/wao-services_en_GB.properties 2014-04-04 14:52:44 UTC (rev 1836) +++ trunk/wao-services/src/main/resources/i18n/wao-services_en_GB.properties 2014-04-04 15:37:35 UTC (rev 1837) @@ -34,7 +34,22 @@ wao.export.ical.title=ObsDeb Observation wao.import.contact.failure.boatMissing=You need to precise the plate number of the boat associated to the contact wao.import.contact.failure.districtMissing=You need to precise the boat district +wao.import.contact.failure.invalid.company.for.observer=L'observateur %s n'est pas membre de la société %s +wao.import.contact.failure.invalid.observation.end=La date de saisie des données ne peut pas être antérieure à la date de fin d'observation +wao.import.contact.failure.invalid.observation.end2=La date de saisie des données ne peut pas être postérieure à la date du jour +wao.import.contact.failure.invalid.observation.endDate=La date de fin d'observation ne peut pas être antérieure à celle du début +wao.import.contact.failure.invalid.observer.state=Il ne peut y avoir aucun observateur pour l'état '%s' +wao.import.contact.failure.invalid.transmissionDate=Il faut que la date de transmission de la restitution soit après la date de saisie des données +wao.import.contact.failure.invalid.trip.beginDate=La date de début de la marée doit correspondre à un mois valide (non vide) de la ligne +wao.import.contact.failure.invalid.trip.endDate=La date de fin de la marée ne peut pas être postérieure à la date du jour wao.import.contact.failure.locationTypeMissing=The type of the location must be filled +wao.import.contact.failure.mainObserver.cant.be.secondaryObserver= +wao.import.contact.failure.mainObserver.cant.be.secondaryObserver.=L'utilisateur référant ne doit pas se trouver aussi parmi les observateurs secondaires +wao.import.contact.failure.missing.main.observer=Il faut au moins un observateur référant +wao.import.contact.failure.missing.observation.endDate=La date de fin d'observation est obligatoire pour l'état '%s' +wao.import.contact.failure.missing.observationArea=Il faut préciser un lieu d'observation +wao.import.contact.failure.missing.observationDate=Il faut préciser une date de saisie des données en plus de la date de transmission de la restitution +wao.import.contact.failure.missing.trip.beginDate=La date de début de marée est obligatoire pour l'état '%s' wao.import.contact.failure.sampleRowCodeMissing=The code of the sample row line is missing wao.import.contact.failure.terrestrialLocationMissing=The code of the terrestrial location is missing wao.import.contact.failure.wrongBoat=There is no boat with plate number '%s' Modified: trunk/wao-services/src/main/resources/i18n/wao-services_fr_FR.properties =================================================================== --- trunk/wao-services/src/main/resources/i18n/wao-services_fr_FR.properties 2014-04-04 14:52:44 UTC (rev 1836) +++ trunk/wao-services/src/main/resources/i18n/wao-services_fr_FR.properties 2014-04-04 15:37:35 UTC (rev 1837) @@ -33,7 +33,22 @@ wao.export.ical.title=Observation ObsDeb wao.import.contact.failure.boatMissing=Il faut préciser l'immatriculation du navire associé au contact wao.import.contact.failure.districtMissing=Il faut préciser le code d'un quartier maritime +wao.import.contact.failure.invalid.company.for.observer=L'observateur %s n'est pas membre de la société %s +wao.import.contact.failure.invalid.observation.end=La date de saisie des données ne peut pas être antérieure à la date de fin d'observation +wao.import.contact.failure.invalid.observation.end2=La date de saisie des données ne peut pas être postérieure à la date du jour +wao.import.contact.failure.invalid.observation.endDate=La date de fin d'observation ne peut pas être antérieure à celle du début +wao.import.contact.failure.invalid.observer.state=Il ne peut y avoir aucun observateur pour l'état '%s' +wao.import.contact.failure.invalid.transmissionDate=Il faut que la date de transmission de la restitution soit après la date de saisie des données +wao.import.contact.failure.invalid.trip.beginDate=La date de début de la marée doit correspondre à un mois valide (non vide) de la ligne +wao.import.contact.failure.invalid.trip.endDate=La date de fin de la marée ne peut pas être postérieure à la date du jour wao.import.contact.failure.locationTypeMissing=Le type du lieu doit être renseigné +wao.import.contact.failure.mainObserver.cant.be.secondaryObserver= +wao.import.contact.failure.mainObserver.cant.be.secondaryObserver.=L'utilisateur référant ne doit pas se trouver aussi parmi les observateurs secondaires +wao.import.contact.failure.missing.main.observer=Il faut au moins un observateur référant +wao.import.contact.failure.missing.observation.endDate=La date de fin d'observation est obligatoire pour l'état '%s' +wao.import.contact.failure.missing.observationArea=Il faut préciser un lieu d'observation +wao.import.contact.failure.missing.observationDate=Il faut préciser une date de saisie des données en plus de la date de transmission de la restitution +wao.import.contact.failure.missing.trip.beginDate=La date de début de marée est obligatoire pour l'état '%s' wao.import.contact.failure.sampleRowCodeMissing=Il manque le code de la ligne de plan associée wao.import.contact.failure.terrestrialLocationMissing=Il manque le code du lieu wao.import.contact.failure.wrongBoat=Il n'y a pas de navire avec l'immatriculation '%s' Modified: trunk/wao-services/src/test/java/fr/ifremer/wao/services/service/ObsMerContactsServiceTest.java =================================================================== --- trunk/wao-services/src/test/java/fr/ifremer/wao/services/service/ObsMerContactsServiceTest.java 2014-04-04 14:52:44 UTC (rev 1836) +++ trunk/wao-services/src/test/java/fr/ifremer/wao/services/service/ObsMerContactsServiceTest.java 2014-04-04 15:37:35 UTC (rev 1837) @@ -24,7 +24,7 @@ } @Test - public void testGetBoatsFilterValues() { + public void testGetContactsFilterValues() { ContactsFilter filter = service.newContactFilter(fixtures.admin()); @@ -32,7 +32,7 @@ } @Test - public void testGetBoatsList() { + public void testGetContactsList() { ContactsFilter filter = service.newContactFilter(fixtures.admin()); Modified: trunk/wao-web/src/main/webapp/WEB-INF/content/obsmer/contacts.jsp =================================================================== --- trunk/wao-web/src/main/webapp/WEB-INF/content/obsmer/contacts.jsp 2014-04-04 14:52:44 UTC (rev 1836) +++ trunk/wao-web/src/main/webapp/WEB-INF/content/obsmer/contacts.jsp 2014-04-04 15:37:35 UTC (rev 1837) @@ -246,7 +246,7 @@ <i class="icon-download"></i> <s:text name="wao.ui.action.csvExport"/> </s:submit> - <s:submit action="import-contacts" type="button" cssClass="btn"> + <s:submit action="import-contacts" method="input" type="button" cssClass="btn"> <i class="icon-upload"></i> <s:text name="wao.ui.action.csvImport"/> </s:submit> @@ -304,7 +304,8 @@ </div> <s:set var="fullView" value="%{fullView}"/> <s:if test="authenticatedWaoUser.admin"> - <button type="button" id="switch-compact-full-view" class="btn <s:if test="fullView">full-view</s:if><s:else>compact-view</s:else>"> + <button type="button" id="switch-compact-full-view" + class="btn <s:if test="fullView">full-view</s:if><s:else>compact-view</s:else>"> <span class="only-in-compact-view"> <i class="icon-resize-full"></i> <s:text name="wao.ui.action.switchToFullView"/> </span> @@ -317,19 +318,19 @@ <thead> <tr> <th><s:text name="wao.ui.field.Contact.creationDate"/></th> - <th><s:text name="wao.ui.contacts.observers"/></th> - <th><s:text name="wao.ui.field.SampleRow.company"/></th> + <th class="only-in-full-view"><s:text name="wao.ui.contacts.observers"/></th> + <th class="only-in-full-view"><s:text name="wao.ui.field.SampleRow.company"/></th> <th><s:text name="wao.ui.field.Contact.sampleRow"/></th> - <th><s:text name="wao.ui.field.SampleRow.programName"/></th> - <th><s:text name="wao.ui.field.SampleRow.professionCode"/></th> - <th><s:text name="wao.ui.field.Profression.libelle"/></th> - <th><s:text name="wao.ui.field.SampleRow.species"/></th> - <th><s:text name="wao.ui.field.FishingZone.facadeName"/></th> - <th><s:text name="wao.ui.field.FishingZone.sectorName"/></th> - <th><s:text name="wao.ui.contacts.division"/></th> - <th><s:text name="wao.ui.field.Boat.name"/></th> - <th><s:text name="wao.ui.field.Boat.immatriculation"/></th> - <th><s:text name="wao.ui.field.Boat.district"/></th> + <th class="only-in-full-view"><s:text name="wao.ui.field.SampleRow.programName"/></th> + <th class="only-in-full-view"><s:text name="wao.ui.field.SampleRow.professionCode"/></th> + <th class="only-in-full-view"><s:text name="wao.ui.field.Profression.libelle"/></th> + <th class="only-in-full-view"><s:text name="wao.ui.field.SampleRow.species"/></th> + <th class="only-in-full-view"><s:text name="wao.ui.field.FishingZone.facadeName"/></th> + <th class="only-in-full-view"><s:text name="wao.ui.field.FishingZone.sectorName"/></th> + <th class="only-in-full-view"><s:text name="wao.ui.contacts.division"/></th> + <th class="only-in-full-view"><s:text name="wao.ui.field.Boat.name"/></th> + <th class="only-in-full-view"><s:text name="wao.ui.field.Boat.immatriculation"/></th> + <th class="only-in-full-view"><s:text name="wao.ui.field.Boat.district"/></th> <th><s:text name="wao.ui.field.Contact.contactState"/></th> <th><s:text name="wao.ui.field.Contact.contactStateMotif"/></th> <th><s:text name="wao.ui.field.Contact.beginDate"/></th> @@ -351,213 +352,213 @@ <s:iterator value="contacts" var="contact"> <tr class="contact-row"> - <td> - <s:property value="%{formatDate(creationDate)}"/> - </td> - <td> - <s:if test="secondaryObserversEmpty"> - <s:property value="mainObserver.fullName"/> - </s:if> - <s:else> - <s:property value="mainObserver.fullName"/>... - <%--TODO<s:text name="wao.ui.field.Contact.secondaryObservers"><s:param value="secondaryObservers"/></s:text>--%> - </s:else> +<td> + <s:property value="%{formatDate(creationDate)}"/> +</td> +<td class="only-in-full-view"> + <s:if test="secondaryObserversEmpty"> + <s:property value="mainObserver.fullName"/> + </s:if> + <s:else> + <s:property value="mainObserver.fullName"/>... + <%--TODO<s:text name="wao.ui.field.Contact.secondaryObservers"><s:param value="secondaryObservers"/></s:text>--%> + </s:else> - </td> - <td> - <s:property value="sampleRow.company.name"/> - </td> - <td> - <s:property value="sampleRow.code"/> +</td> +<td class="only-in-full-view"> + <s:property value="sampleRow.company.name"/> +</td> +<td> + <s:property value="sampleRow.code"/> <%--TODO<s:property value="%{getTooltipSampleRow(sampleRow)}"/>--%> - </td> - <td> - <s:property value="sampleRow.programName"/> - </td> - <td> - <s:property value="sampleRow.professionDescription"/> - </td> - <td> - <s:property value="sampleRow.profession.libelle"/> - </td> - <td> - <s:property value="sampleRow.profession.species"/> - </td> - <td> - <s:property value="sampleRow.facade"/> - </td> - <td> - <s:property value="sampleRow.sectors"/> - </td> - <td> - <s:property value="%{getDivision(sampleRow)}"/> - </td> - <td> - <s:property value="boat.name"/> +</td> +<td class="only-in-full-view"> + <s:property value="sampleRow.programName"/> +</td> +<td class="only-in-full-view"> + <s:property value="sampleRow.professionDescription"/> +</td> +<td class="only-in-full-view"> + <s:property value="sampleRow.profession.libelle"/> +</td> +<td class="only-in-full-view"> + <s:property value="sampleRow.profession.species"/> +</td> +<td class="only-in-full-view"> + <s:property value="sampleRow.facade"/> +</td> +<td class="only-in-full-view"> + <s:property value="sampleRow.sectors"/> +</td> +<td class="only-in-full-view"> + <s:property value="%{getDivision(sampleRow)}"/> +</td> +<td> + <s:property value="boat.name"/> <%--TODO <s:property value="%{getTooltipBoat(boat)}"/>--%> - </td> - <td> - <s:property value="%{'' + boat.immatriculation}"/> - </td> - <td> - <s:property value="boat.districtCode"/> - </td> - <td> - <s:if test="contactStateMotif != null"> - <s:text name="%{contactState.i18nKey}"/> - <%--TODO <s:text name="wao.ui.field.Contact.contactStateMotif"><s:param value="%{contactStateMotif.name}"/></s:text>--%> +</td> +<td class="only-in-full-view"> + <s:property value="%{'' + boat.immatriculation}"/> +</td> +<td class="only-in-full-view"> + <s:property value="boat.districtCode"/> +</td> +<td> + <s:if test="contactStateMotif"> + <s:text name="%{contactState.i18nKey}"/> + <%--TODO <s:text name="wao.ui.field.Contact.contactStateMotif"><s:param value="%{contactStateMotif.name}"/></s:text>--%> + </s:if> + <s:else> + <s:text name="%{contactState.i18nKey}"/> + </s:else> +</td> +<td> + <s:if test="contactStateMotif"> + <s:property value="contactStateMotif.name"/> + </s:if> +</td> +<td> + <s:if test="observationBeginDate"> + <s:property value="%{formatDateTime(observationBeginDate)}"/> + </s:if> +</td> +<td> + <s:if test="observationEndDate"> + <s:property value="%{formatDateTime(observationEndDate)}"/> + </s:if> +</td> +<td> + <s:property value="nbObservants"/> +</td> +<td> + <s:if test="mammalsObservation"> + <img src="<s:url value="/img/eye-22px.png"/>" + alt="<s:text name="wao.ui.field.Contact.mammalsObservation"/>"/> + </s:if> + <s:if test="mammalsCapture"> + <s:if test="mammalsInfo"> + <img src="<s:url value="fishing-net-22px.png"/>" + alt="<s:text name="wao.ui.field.Contact.mammalsCapture"/>"/> + <%--TODO<s:text name="wao.ui.field.Contact.mammalsInfo"><s:param value="%{getMammalsInfo(#contact)}"/></s:text>--%> </s:if> <s:else> - <s:text name="%{contactState.i18nKey}"/> + <img src="<s:url value="fishing-net-22px.png"/>" + alt="<s:text name="wao.ui.field.Contact.mammalsCapture"/>"/> </s:else> - </td> - <td> - <s:if test="contactStateMotif"> - <s:property value="contactStateMotif.name"/> + </s:if> +</td> +<td> + <s:if test="comment"> + <s:property value="%{getCommentDisplayText(comment)}"/> + <%--TODO<s:text name="wao.ui.misc.comment"><s:param value="%{getTooltipText(comment)}"/></s:text>--%> + </s:if> +</td> +<td> + <s:if test="dataInputDate"> + <s:property value="%{formatDate(dataInputDate)}"/> + </s:if> +</td> +<td> + <s:if test="observedDataControl"> + <s:text name="%{observedDataControl.i18nKey}"/> + </s:if> +</td> +<td> + <s:if test="restitution"> + <s:property value="%{formatDate(restitution)}"/> + </s:if> +</td> +<td> + Validation + <s:property value=""/> + <%--<t:booleanImage t:value="contact.validationCompany" t:empty="isEmpty(contact.validationCompany)"--%> + <%--t:emptyTitle="${message:wao.ui.misc.notValidated}"--%> + <%--t:trueTitle="${message:wao.ui.misc.validated}" t:falseTitle="${message:wao.ui.misc.refused}"/> --%> + <%--<t:booleanImage t:value="contact.validationProgram" t:empty="isEmpty(contact.validationProgram)"--%> + <%--t:emptyTitle="${message:wao.ui.misc.notValidated}"--%> + <%--t:trueTitle="${message:wao.ui.misc.validated}" t:falseTitle="${message:wao.ui.misc.refused}"/>--%> +</td> +<td> + <s:if test="commentCoordinator"> + <s:property value="%{getCommentDisplayText(commentCoordinator)}"/> + <%--TODO<s:text name="wao.ui.field.Contact.commentCoordinator"><s:param value="%{getTooltipText(commentCoordinator)}"/></s:text>--%> + </s:if> +</td> +<td> + <s:if test="commentAdmin"> + <s:property value="%{getCommentDisplayText(commentAdmin)}"/> + <%--TODO<s:text name="wao.ui.field.Contact.commentAdmin"><s:param value="%{getTooltipText(commentAdmin)}"/></s:text>--%> + </s:if> +</td> +<td> + <s:if test="boardingDone"> + <s:if test="validationCompany"> + <s:text name="%{dataReliability.i18nKey}"/> </s:if> - </td> - <td> - <s:if test="observationBeginDate"> - <s:property value="%{formatDateTime(observationBeginDate)}"/> - </s:if> - </td> - <td> - <s:if test="observationEndDate"> - <s:property value="%{formatDateTime(observationEndDate)}"/> - </s:if> - </td> - <td> - <s:property value="nbObservants"/> - </td> - <td> - <s:if test="mammalsObservation"> - <img src="<s:url value="/img/eye-22px.png"/>" - alt="<s:text name="wao.ui.field.Contact.mammalsObservation"/>"/> - </s:if> - <s:if test="mammalsCapture"> - <s:if test="mammalsInfo"> - <img src="<s:url value="fishing-net-22px.png"/>" - alt="<s:text name="wao.ui.field.Contact.mammalsCapture"/>"/> - <%--TODO<s:text name="wao.ui.field.Contact.mammalsInfo"><s:param value="%{getMammalsInfo(#contact)}"/></s:text>--%> + </s:if> +</td> +<td class="actions"> + <div class="dropdown"> + <a class="btn dropdown-toggle" data-toggle="dropdown" href="#"> + <s:text name="wao.ui.actions"/> + <b class="caret"></b> + </a> + <ul class="dropdown-menu"> + <s:if test="authenticatedWaoUser.isAuthorizedToEditContact(#contact)"> + <li> + <s:url action="edit-contact!input" id="editContactUrl"> + <s:param name="contactId" value="topiaId"/> + </s:url> + <s:a href="%{editContactUrl}"> + <i class="icon-edit"></i> <s:text name="wao.ui.action.edit"/> + </s:a> + </li> </s:if> - <s:else> - <img src="<s:url value="fishing-net-22px.png"/>" - alt="<s:text name="wao.ui.field.Contact.mammalsCapture"/>"/> - </s:else> - </s:if> - </td> - <td> - <s:if test="comment"> - <s:property value="%{getCommentDisplayText(comment)}"/> - <%--TODO<s:text name="wao.ui.misc.comment"><s:param value="%{getTooltipText(comment)}"/></s:text>--%> - </s:if> - </td> - <td> - <s:if test="dataInputDate"> - <s:property value="%{formatDate(dataInputDate)}"/> - </s:if> - </td> - <td> - <s:if test="observedDataControl"> - <s:text name="%{observedDataControl.i18nKey}"/> - </s:if> - </td> - <td> - <s:if test="restitution"> - <s:property value="%{formatDate(restitution)}"/> - </s:if> - </td> - <td> - Validation - <s:property value=""/> - <%--<t:booleanImage t:value="contact.validationCompany" t:empty="isEmpty(contact.validationCompany)"--%> - <%--t:emptyTitle="${message:wao.ui.misc.notValidated}"--%> - <%--t:trueTitle="${message:wao.ui.misc.validated}" t:falseTitle="${message:wao.ui.misc.refused}"/> --%> - <%--<t:booleanImage t:value="contact.validationProgram" t:empty="isEmpty(contact.validationProgram)"--%> - <%--t:emptyTitle="${message:wao.ui.misc.notValidated}"--%> - <%--t:trueTitle="${message:wao.ui.misc.validated}" t:falseTitle="${message:wao.ui.misc.refused}"/>--%> - </td> - <td> - <s:if test="commentCoordinator"> - <s:property value="%{getCommentDisplayText(commentCoordinator)}"/> - <%--TODO<s:text name="wao.ui.field.Contact.commentCoordinator"><s:param value="%{getTooltipText(commentCoordinator)}"/></s:text>--%> - </s:if> - </td> - <td> - <s:if test="commentAdmin"> - <s:property value="%{getCommentDisplayText(commentAdmin)}"/> - <%--TODO<s:text name="wao.ui.field.Contact.commentAdmin"><s:param value="%{getTooltipText(commentAdmin)}"/></s:text>--%> - </s:if> - </td> - <td> - <s:if test="boardingDone"> - <s:if test="validationCompany"> - <s:text name="%{dataReliability.i18nKey}"/> + <s:if test="authenticatedWaoUser.isAuthorizedToDeleteContact(#contact)"> + <li> + <s:url action="delete-contact!input" id="deleteContactUrl"> + <s:param name="contactId" value="topiaId"/> + </s:url> + <s:a href="%{deleteContactUrl}"> + <i class="icon-delete"></i> <s:text name="wao.ui.action.delete"/> + </s:a> + </li> </s:if> - </s:if> - </td> - <td class="actions"> - <div class="dropdown"> - <a class="btn dropdown-toggle" data-toggle="dropdown" href="#"> - <s:text name="wao.ui.actions" /> - <b class="caret"></b> - </a> - <ul class="dropdown-menu"> - <s:if test="authenticatedWaoUser.isAuthorizedToEditContact(#contact)"> + <s:if test="authenticatedWaoUser.authorizedToValidateContacts"> + <s:if test="authenticatedWaoUser.isAuthorizedToValidateContact(#contact)"> <li> - <s:url action="edit-contact!input" id="editContactUrl"> - <s:param name="contactId" value="topiaId" /> + <s:url action="validate-contact!input" id="acceptContactUrl"> + <s:param name="contactId" value="topiaId"/> + <s:param name="validateState" value="true"/> </s:url> - <s:a href="%{editContactUrl}"> - <i class="icon-edit"></i> <s:text name="wao.ui.action.edit" /> + <s:a href="%{acceptContactUrl}"> + <s:text name="wao.ui.action.acceptContact"/> </s:a> </li> + <li> + <s:url action="validate-contact!input" id="refuseContactUrl"> + <s:param name="contactId" value="topiaId"/> + <s:param name="validateState" value="false"/> + </s:url> + <s:a href="%{refuseContactUrl}"> + <s:text name="wao.ui.action.refuseContact"/> + </s:a> + </li> </s:if> - <s:if test="authenticatedWaoUser.isAuthorizedToDeleteContact(#contact)"> + <s:if test="authenticatedWaoUser.isAuthorizedToUnvalidateContact(#contact)"> <li> - <s:url action="delete-contact!input" id="deleteContactUrl"> - <s:param name="contactId" value="topiaId" /> + <s:url action="validate-contact!input" id="unvalidateContactUrl"> + <s:param name="contactId" value="topiaId"/> </s:url> - <s:a href="%{deleteContactUrl}"> - <i class="icon-delete"></i> <s:text name="wao.ui.action.delete" /> + <s:a href="%{unvalidateContactUrl}"> + <s:text name="wao.ui.action.unvalidateContact"/> </s:a> </li> </s:if> - <s:if test="authenticatedWaoUser.authorizedToValidateContacts"> - <s:if test="authenticatedWaoUser.isAuthorizedToValidateContact(#contact)"> - <li> - <s:url action="validate-contact!input" id="acceptContactUrl"> - <s:param name="contactId" value="topiaId"/> - <s:param name="validateState" value="true"/> - </s:url> - <s:a href="%{acceptContactUrl}"> - <s:text name="wao.ui.action.acceptContact"/> - </s:a> - </li> - <li> - <s:url action="validate-contact!input" id="refuseContactUrl"> - <s:param name="contactId" value="topiaId"/> - <s:param name="validateState" value="false"/> - </s:url> - <s:a href="%{refuseContactUrl}"> - <s:text name="wao.ui.action.refuseContact"/> - </s:a> - </li> - </s:if> - <s:if test="authenticatedWaoUser.isAuthorizedToUnvalidateContact(#contact)"> - <li> - <s:url action="validate-contact!input" id="unvalidateContactUrl"> - <s:param name="contactId" value="topiaId" /> - </s:url> - <s:a href="%{unvalidateContactUrl}"> - <s:text name="wao.ui.action.unvalidateContact" /> - </s:a> - </li> - </s:if> - </s:if> - </ul> - </div> - </td> + </s:if> + </ul> + </div> +</td> </tr> </s:iterator> </todby> Copied: trunk/wao-web/src/main/webapp/WEB-INF/content/obsmer/import-contacts-input.jsp (from rev 1830, trunk/wao-web/src/main/webapp/WEB-INF/content/obsmer/import-contacts.jsp) =================================================================== --- trunk/wao-web/src/main/webapp/WEB-INF/content/obsmer/import-contacts-input.jsp (rev 0) +++ trunk/wao-web/src/main/webapp/WEB-INF/content/obsmer/import-contacts-input.jsp 2014-04-04 15:37:35 UTC (rev 1837) @@ -0,0 +1,32 @@ +<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%> +<%@taglib uri="/struts-tags" prefix="s" %> + +<html> + +<head> + <title><s:text name="wao.ui.import.contacts" /></title> +</head> + +<h1><s:text name="wao.ui.import.contacts" /></h1> + +<div class="alert alert-info"> + <s:text name="wao.ui.import.disclaimer" /> +</div> + +<s:form action="import-contacts" method="POST" enctype="multipart/form-data"> + + <fieldset> + <legend> + <s:text name="wao.ui.import.contacts" /> + </legend> + + <s:file name="csvFile" /> + + <s:submit type="button"> + <i class="icon-upload"></i> <s:text name="wao.ui.action.csvImport"/> + </s:submit> + </fieldset> + +</s:form> + +</html> \ No newline at end of file Deleted: trunk/wao-web/src/main/webapp/WEB-INF/content/obsmer/import-contacts.jsp =================================================================== --- trunk/wao-web/src/main/webapp/WEB-INF/content/obsmer/import-contacts.jsp 2014-04-04 14:52:44 UTC (rev 1836) +++ trunk/wao-web/src/main/webapp/WEB-INF/content/obsmer/import-contacts.jsp 2014-04-04 15:37:35 UTC (rev 1837) @@ -1,32 +0,0 @@ -<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%> -<%@taglib uri="/struts-tags" prefix="s" %> - -<html> - -<head> - <title><s:text name="wao.ui.import.contacts" /></title> -</head> - -<h1><s:text name="wao.ui.import.contacts" /></h1> - -<div class="alert alert-info"> - <s:text name="wao.ui.import.disclaimer" /> -</div> - -<s:form action="import-contacts" method="POST" enctype="multipart/form-data"> - - <fieldset> - <legend> - <s:text name="wao.ui.import.contacts" /> - </legend> - - <s:file name="csvFile" /> - - <s:submit type="button"> - <i class="icon-upload"></i> <s:text name="wao.ui.action.csvImport"/> - </s:submit> - </fieldset> - -</s:form> - -</html> \ No newline at end of file