diff --git a/src/main/java/no/nibio/vips/logic/controller/servlet/MessageController.java b/src/main/java/no/nibio/vips/logic/controller/servlet/MessageController.java
index afb15eee363f69bac4fc9da51d7034de3742c31d..dd5592e4c44b18b1ccbbd2358fd313ec9ce9fac6 100644
--- a/src/main/java/no/nibio/vips/logic/controller/servlet/MessageController.java
+++ b/src/main/java/no/nibio/vips/logic/controller/servlet/MessageController.java
@@ -158,7 +158,6 @@ public class MessageController extends HttpServlet {
{
Integer messageId = Integer.valueOf(request.getParameter("messageId"));
Message message = em.find(Message.class, messageId);
- message.setMessageCropOrganismIds(SessionControllerGetter.getMessageBean().getMessageCropOrganismIds(message));
request.setAttribute("message", message);
String messageLocale = request.getParameter("messageLocale") != null ?
request.getParameter("messageLocale")
@@ -213,7 +212,7 @@ public class MessageController extends HttpServlet {
request.setAttribute("unusedTags", tags);
request.setAttribute("messageKey", request.getParameter("messageKey"));
request.setAttribute("organizations", SessionControllerGetter.getUserBean().getOrganizations());
- request.setAttribute("allCrops", em.createNamedQuery("Organism.findAllCrops").getResultList());
+ request.setAttribute("allCropCategoryIds", em.createNamedQuery("CropCategory.findByOrganizationId").setParameter("organizationId",user.getOrganizationId().getOrganizationId()).getResultList());
request.getRequestDispatcher("/messageForm.ftl").forward(request, response);
}
catch(NullPointerException | NumberFormatException ex)
@@ -241,13 +240,18 @@ public class MessageController extends HttpServlet {
request.setAttribute("availableLocales", LanguageUtil.getAvailableLocalesWithDistinctLanguage());
request.setAttribute("unusedTags", em.createNamedQuery("MessageTag.findAll").getResultList());
request.setAttribute("organizations", SessionControllerGetter.getUserBean().getOrganizations());
- request.setAttribute("allCrops", em.createNamedQuery("Organism.findAllCrops").getResultList());
+ request.setAttribute("allCropCategoryIds", em.createNamedQuery("CropCategory.findByOrganizationId").setParameter("organizationId",user.getOrganizationId().getOrganizationId()).getResultList());
request.getRequestDispatcher("/messageForm.ftl").forward(request, response);
}
catch(NullPointerException | NumberFormatException ex)
{
+ ex.printStackTrace();
response.sendError(500, ExceptionUtil.getStackTrace(ex));
}
+ catch(Exception ex)
+ {
+ ex.printStackTrace();
+ }
}
else if(action.equals("messageFormSubmit"))
{
diff --git a/src/main/java/no/nibio/vips/logic/controller/session/ForecastBean.java b/src/main/java/no/nibio/vips/logic/controller/session/ForecastBean.java
index da528cf17523bb4742763de5aca782246603c8b3..e9705b23f1e37c47968e23aaa00323354c8347f7 100644
--- a/src/main/java/no/nibio/vips/logic/controller/session/ForecastBean.java
+++ b/src/main/java/no/nibio/vips/logic/controller/session/ForecastBean.java
@@ -744,12 +744,18 @@ public class ForecastBean {
.append(" TRUNCATE forecast_result_cache;")
.append(" INSERT INTO forecast_result_cache ")
.append(" SELECT * FROM forecast_result ")
- .append(" WHERE to_char(result_valid_time, '").append(dateFormat).append("') = :dateStr ;")
+ .append(" WHERE to_char(result_valid_time, '").append(dateFormat).append("') = :dateStr ")
+ .append(" AND forecast_configuration_id IN (")
+ .append(" SELECT forecast_configuration_id ")
+ .append(" FROM public.forecast_configuration ")
+ .append(" WHERE date_start <= :currentDate AND date_end >= :currentDate")
+ .append(" );")
.append("END;")
.toString();
Query query = em.createNativeQuery(transactionSQL);
query.setParameter("dateStr", format.format(SystemTime.getSystemTime()));
+ query.setParameter("currentDate", SystemTime.getSystemTime());
query.executeUpdate();
}
@@ -761,8 +767,10 @@ public class ForecastBean {
{
//
// Collect all forecasts that are active TODAY
- List<ForecastConfiguration> activeForecasts = em.createNamedQuery("ForecastConfiguration.findActiveAtDate")
+ // This
+ List<ForecastConfiguration> activeForecasts = em.createNamedQuery("ForecastConfiguration.findAllActiveAtDate")
.setParameter("currentDate", currentDate).getResultList();
+
// Loop through them
List<Long> activeForecastIds = new ArrayList<>();
Query deleteQ = em.createNativeQuery(
@@ -921,7 +929,7 @@ public class ForecastBean {
(cropOrganismIds != null && ! cropOrganismIds.isEmpty() ? " AND crop_organism_id IN (" + StringUtils.join(cropOrganismIds, ",") + ") " : "") +
")\n" +
"AND to_char(result_valid_time, '" + dateFormat + "') = :dateStr";
-
+ //System.out.println(poi.getName() + " SQL=" + sql);
Query q = em.createNativeQuery(sql);
q.setParameter("locationPointOfInterestId", poi.getPointOfInterestId());
q.setParameter("dateStr", format.format(theDate));
diff --git a/src/main/java/no/nibio/vips/logic/controller/session/MessageBean.java b/src/main/java/no/nibio/vips/logic/controller/session/MessageBean.java
index 15a486d1788870f077cec468150a404330c7f2be..8e3a1f694b68cac13c51012bec76ee20d0743b75 100644
--- a/src/main/java/no/nibio/vips/logic/controller/session/MessageBean.java
+++ b/src/main/java/no/nibio/vips/logic/controller/session/MessageBean.java
@@ -95,21 +95,7 @@ public class MessageBean {
}
- /**
- * Crops are not part of persistence scheme for performance reasons.
- * Must be added manually
- * @param messages
- * @return
- */
- public List<Message> addMessageOrganismIds(List<Message> messages)
- {
- // Need to add all crops
- for(Message message:messages)
- {
- message.setMessageCropOrganismIds(this.getMessageCropOrganismIds(message));
- }
- return messages;
- }
+
public List<Message> getMessageList(Integer organizationId) {
Organization mainOrg = em.find(Organization.class, organizationId);
@@ -193,18 +179,16 @@ public class MessageBean {
message.setMessageTagSet(tags);
// Store message organisms
- List<Integer> cropOrganismIds = new ArrayList<>();
- if(formFields.get("cropOrganismIds").getWebValues() != null)
+ List<Integer> cropCategoryIds = new ArrayList<>();
+ if(formFields.get("cropCategoryIds").getWebValues() != null)
{
- for(String cropOrganismId:formFields.get("cropOrganismIds").getWebValues())
+ for(String cropCategoryId:formFields.get("cropCategoryIds").getWebValues())
{
- cropOrganismIds.add(Integer.valueOf(cropOrganismId));
+ cropCategoryIds.add(Integer.valueOf(cropCategoryId));
}
}
- message.setMessageCropOrganismIds(cropOrganismIds);
- // This property is not part of the automatic persistence scheme, need
- // to store manually
- this.storeMessageOrganismIds(message);
+ message.setCropCategoryIds(cropCategoryIds.toArray(new Integer[cropCategoryIds.size()]));
+
return message;
}
@@ -455,24 +439,5 @@ public class MessageBean {
}
}
- /**
- *
- * @param message
- */
- public void storeMessageOrganismIds(Message message)
- {
- if(message.getMessageCropOrganismIds() != null)
- {
- Query q = em.createNativeQuery("DELETE FROM public.organism_message WHERE message_id = :messageId");
- q.setParameter("messageId", message.getMessageId());
- q.executeUpdate();
- q = em.createNativeQuery("INSERT INTO public.organism_message(organism_id, message_id) VALUES(:organismId,:messageId);");
- q.setParameter("messageId", message.getMessageId());
- for(Integer organismId : message.getMessageCropOrganismIds())
- {
- q.setParameter("organismId", organismId);
- q.executeUpdate();
- }
- }
- }
+
}
diff --git a/src/main/java/no/nibio/vips/logic/controller/session/OrganismBean.java b/src/main/java/no/nibio/vips/logic/controller/session/OrganismBean.java
index 5adfe7915673526377a87ba50b4c6cc62696d16c..b29fac85526c4475857ec8132c3ff9e5b4a9e120 100644
--- a/src/main/java/no/nibio/vips/logic/controller/session/OrganismBean.java
+++ b/src/main/java/no/nibio/vips/logic/controller/session/OrganismBean.java
@@ -21,6 +21,7 @@ package no.nibio.vips.logic.controller.session;
import com.ibm.icu.util.ULocale;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -29,6 +30,7 @@ import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
+import no.nibio.vips.logic.entity.CropCategory;
import no.nibio.vips.logic.entity.CropPest;
import no.nibio.vips.logic.entity.ExternalResource;
import no.nibio.vips.logic.entity.ExternalResourceType;
@@ -37,6 +39,7 @@ import no.nibio.vips.logic.entity.Organism;
import no.nibio.vips.logic.entity.OrganismExternalResource;
import no.nibio.vips.logic.entity.OrganismLocale;
import no.nibio.vips.logic.entity.OrganismLocalePK;
+import no.nibio.vips.logic.entity.Organization;
import no.nibio.vips.logic.util.HierarchyCategoryLocaleNames;
/**
@@ -303,4 +306,34 @@ public class OrganismBean {
{
return em.merge(cropPest);
}
+
+ public List<Integer> getCropCategoryOrganismIds(List<Integer> cropCategoryIds) {
+ List<CropCategory> cropCategories = em.createNamedQuery("CropCategory.findByCropCategoryIds")
+ .setParameter("cropCategoryIds", cropCategoryIds)
+ .getResultList();
+ List<Integer> retVal = new ArrayList<>();
+ for(CropCategory cc:cropCategories)
+ {
+ if(cc.getCropOrganismIds() != null)
+ {
+ retVal.addAll(Arrays.asList(cc.getCropOrganismIds()));
+ }
+ }
+
+ return retVal;
+ }
+
+ public List<CropCategory> getCropCategories(Integer organizationId)
+ {
+ try
+ {
+ return em.createNamedQuery("CropCategory.findByOrganizationId")
+ .setParameter("organizationId", organizationId)
+ .getResultList();
+ }
+ catch(NoResultException ex)
+ {
+ return new ArrayList<>();
+ }
+ }
}
diff --git a/src/main/java/no/nibio/vips/logic/entity/CropCategory.java b/src/main/java/no/nibio/vips/logic/entity/CropCategory.java
new file mode 100644
index 0000000000000000000000000000000000000000..29300e7815df9b50279aec95b33a50150c9668ba
--- /dev/null
+++ b/src/main/java/no/nibio/vips/logic/entity/CropCategory.java
@@ -0,0 +1,177 @@
+/*
+ * Copyright (c) 2016 NIBIO <http://www.nibio.no/>.
+ *
+ * This file is part of VIPSLogic.
+ * VIPSLogic is free software: you can redistribute it and/or modify
+ * it under the terms of the NIBIO Open Source License as published by
+ * NIBIO, either version 1 of the License, or (at your option) any
+ * later version.
+ *
+ * VIPSLogic 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
+ * NIBIO Open Source License for more details.
+ *
+ * You should have received a copy of the NIBIO Open Source License
+ * along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>.
+ *
+ */
+
+package no.nibio.vips.logic.entity;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import java.io.Serializable;
+import java.util.Set;
+import javax.persistence.Basic;
+import javax.persistence.CascadeType;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.Id;
+import javax.persistence.NamedQueries;
+import javax.persistence.NamedQuery;
+import javax.persistence.OneToMany;
+import javax.persistence.Table;
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Size;
+import javax.xml.bind.annotation.XmlRootElement;
+import no.nibio.vips.logic.util.IntegerArrayUserType;
+import org.hibernate.annotations.Type;
+import org.hibernate.annotations.TypeDef;
+import org.hibernate.annotations.TypeDefs;
+
+/**
+ * @copyright 2016 <a href="http://www.nibio.no/">NIBIO</a>
+ * @author Tor-Einar Skog <tor-einar.skog@nibio.no>
+ */
+@Entity
+@Table(name = "crop_category")
+@XmlRootElement
+@TypeDefs( {@TypeDef( name= "IntegerArray", typeClass = IntegerArrayUserType.class)})
+@NamedQueries({
+ @NamedQuery(name = "CropCategory.findAll", query = "SELECT c FROM CropCategory c"),
+ @NamedQuery(name = "CropCategory.findByCropCategoryId", query = "SELECT c FROM CropCategory c WHERE c.cropCategoryId = :cropCategoryId"),
+ @NamedQuery(name = "CropCategory.findByCropCategoryIds", query = "SELECT c FROM CropCategory c WHERE c.cropCategoryId IN :cropCategoryIds"),
+ @NamedQuery(name = "CropCategory.findByDefaultName", query = "SELECT c FROM CropCategory c WHERE c.defaultName = :defaultName"),
+ @NamedQuery(name = "CropCategory.findByCropOrganismIds", query = "SELECT c FROM CropCategory c WHERE c.cropOrganismIds = :cropOrganismIds"),
+ @NamedQuery(name = "CropCategory.findByOrganizationId", query = "SELECT c FROM CropCategory c WHERE c.organizationId = :organizationId")
+})
+public class CropCategory implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+ @Id
+ @Basic(optional = false)
+ @NotNull
+ @Column(name = "crop_category_id")
+ private Integer cropCategoryId;
+ @Size(max = 255)
+ @Column(name = "default_name")
+ private String defaultName;
+ @OneToMany(cascade = CascadeType.ALL, mappedBy = "cropCategoryId", fetch = FetchType.EAGER)
+ private Set<CropCategoryLocal> cropCategoryLocalSet;
+ @Type(type = "IntegerArray")
+ @Column(name = "crop_organism_ids")
+ private Integer[] cropOrganismIds;
+ @Column(name = "organization_id")
+ private Integer organizationId;
+
+ public CropCategory() {
+ }
+
+ public CropCategory(Integer cropCategoryId) {
+ this.cropCategoryId = cropCategoryId;
+ }
+
+ public Integer getCropCategoryId() {
+ return cropCategoryId;
+ }
+
+ public void setCropCategoryId(Integer cropCategoryId) {
+ this.cropCategoryId = cropCategoryId;
+ }
+
+ public String getDefaultName() {
+ return defaultName;
+ }
+
+ public void setDefaultName(String defaultName) {
+ this.defaultName = defaultName;
+ }
+
+ public Integer[] getCropOrganismIds() {
+ return cropOrganismIds;
+ }
+
+ public void setCropOrganismIds(Integer[] cropOrganismIds) {
+ this.cropOrganismIds = cropOrganismIds;
+ }
+
+ @Override
+ public int hashCode() {
+ int hash = 0;
+ hash += (cropCategoryId != null ? cropCategoryId.hashCode() : 0);
+ return hash;
+ }
+
+ @Override
+ public boolean equals(Object object) {
+ // TODO: Warning - this method won't work in the case the id fields are not set
+ if (!(object instanceof CropCategory)) {
+ return false;
+ }
+ CropCategory other = (CropCategory) object;
+ if ((this.cropCategoryId == null && other.cropCategoryId != null) || (this.cropCategoryId != null && !this.cropCategoryId.equals(other.cropCategoryId))) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ return "no.nibio.vips.logic.entity.CropCategory[ cropCategoryId=" + cropCategoryId + " ]";
+ }
+
+ /**
+ * @return the organizationId
+ */
+ public Integer getOrganizationId() {
+ return organizationId;
+ }
+
+ /**
+ * @param organizationId the organizationId to set
+ */
+ public void setOrganizationId(Integer organizationId) {
+ this.organizationId = organizationId;
+ }
+
+ /**
+ * @return the cropCategoryLocalSet
+ */
+ public Set<CropCategoryLocal> getCropCategoryLocalSet() {
+ return cropCategoryLocalSet;
+ }
+
+ /**
+ * @param cropCategoryLocalSet the cropCategoryLocalSet to set
+ */
+ public void setCropCategoryLocalSet(Set<CropCategoryLocal> cropCategoryLocalSet) {
+ this.cropCategoryLocalSet = cropCategoryLocalSet;
+ }
+
+ @JsonIgnore
+ public String getLocalName(String language)
+ {
+ if(this.cropCategoryLocalSet != null && ! this.getCropCategoryLocalSet().isEmpty())
+ {
+ for(CropCategoryLocal ccl:this.getCropCategoryLocalSet())
+ {
+ if(ccl.getCropCategoryLocalPK().getLocale().equals(language))
+ {
+ return ccl.getLocalName();
+ }
+ }
+ }
+ return null;
+ }
+}
diff --git a/src/main/java/no/nibio/vips/logic/entity/CropCategoryLocal.java b/src/main/java/no/nibio/vips/logic/entity/CropCategoryLocal.java
new file mode 100644
index 0000000000000000000000000000000000000000..32fe771bfdd21aaae601684f14820e219585cb66
--- /dev/null
+++ b/src/main/java/no/nibio/vips/logic/entity/CropCategoryLocal.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 2016 NIBIO <http://www.nibio.no/>.
+ *
+ * This file is part of VIPSLogic.
+ * VIPSLogic is free software: you can redistribute it and/or modify
+ * it under the terms of the NIBIO Open Source License as published by
+ * NIBIO, either version 1 of the License, or (at your option) any
+ * later version.
+ *
+ * VIPSLogic 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
+ * NIBIO Open Source License for more details.
+ *
+ * You should have received a copy of the NIBIO Open Source License
+ * along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>.
+ *
+ */
+
+package no.nibio.vips.logic.entity;
+
+import java.io.Serializable;
+import javax.persistence.Column;
+import javax.persistence.EmbeddedId;
+import javax.persistence.Entity;
+import javax.persistence.NamedQueries;
+import javax.persistence.NamedQuery;
+import javax.persistence.Table;
+import javax.validation.constraints.Size;
+import javax.xml.bind.annotation.XmlRootElement;
+
+/**
+ * @copyright 2016 <a href="http://www.nibio.no/">NIBIO</a>
+ * @author Tor-Einar Skog <tor-einar.skog@nibio.no>
+ */
+@Entity
+@Table(name = "crop_category_local")
+@XmlRootElement
+@NamedQueries({
+ @NamedQuery(name = "CropCategoryLocal.findAll", query = "SELECT c FROM CropCategoryLocal c"),
+ @NamedQuery(name = "CropCategoryLocal.findByCropCategoryId", query = "SELECT c FROM CropCategoryLocal c WHERE c.cropCategoryLocalPK.cropCategoryId = :cropCategoryId"),
+ @NamedQuery(name = "CropCategoryLocal.findByLocale", query = "SELECT c FROM CropCategoryLocal c WHERE c.cropCategoryLocalPK.locale = :locale"),
+ @NamedQuery(name = "CropCategoryLocal.findByLocalName", query = "SELECT c FROM CropCategoryLocal c WHERE c.localName = :localName")})
+public class CropCategoryLocal implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+ @EmbeddedId
+ protected CropCategoryLocalPK cropCategoryLocalPK;
+ @Size(max = 255)
+ @Column(name = "local_name")
+ private String localName;
+
+ // Easy fix for mapping from CropCategory
+ @Column(name="crop_category_id", insertable = false, updatable = false)
+ private Integer cropCategoryId;
+
+ public CropCategoryLocal() {
+ }
+
+ public CropCategoryLocal(CropCategoryLocalPK cropCategoryLocalPK) {
+ this.cropCategoryLocalPK = cropCategoryLocalPK;
+ }
+
+ public CropCategoryLocal(int cropCategoryId, String locale) {
+ this.cropCategoryLocalPK = new CropCategoryLocalPK(cropCategoryId, locale);
+ }
+
+ public CropCategoryLocalPK getCropCategoryLocalPK() {
+ return cropCategoryLocalPK;
+ }
+
+ public void setCropCategoryLocalPK(CropCategoryLocalPK cropCategoryLocalPK) {
+ this.cropCategoryLocalPK = cropCategoryLocalPK;
+ }
+
+ public String getLocalName() {
+ return localName;
+ }
+
+ public void setLocalName(String localName) {
+ this.localName = localName;
+ }
+
+ @Override
+ public int hashCode() {
+ int hash = 0;
+ hash += (cropCategoryLocalPK != null ? cropCategoryLocalPK.hashCode() : 0);
+ return hash;
+ }
+
+ @Override
+ public boolean equals(Object object) {
+ // TODO: Warning - this method won't work in the case the id fields are not set
+ if (!(object instanceof CropCategoryLocal)) {
+ return false;
+ }
+ CropCategoryLocal other = (CropCategoryLocal) object;
+ if ((this.cropCategoryLocalPK == null && other.cropCategoryLocalPK != null) || (this.cropCategoryLocalPK != null && !this.cropCategoryLocalPK.equals(other.cropCategoryLocalPK))) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ return "no.nibio.vips.logic.entity.CropCategoryLocal[ cropCategoryLocalPK=" + cropCategoryLocalPK + " ]";
+ }
+
+ /**
+ * @return the cropCategoryId
+ */
+ public Integer getCropCategoryId() {
+ return cropCategoryId;
+ }
+
+ /**
+ * @param cropCategoryId the cropCategoryId to set
+ */
+ public void setCropCategoryId(Integer cropCategoryId) {
+ this.cropCategoryId = cropCategoryId;
+ }
+
+}
diff --git a/src/main/java/no/nibio/vips/logic/entity/CropCategoryLocalPK.java b/src/main/java/no/nibio/vips/logic/entity/CropCategoryLocalPK.java
new file mode 100644
index 0000000000000000000000000000000000000000..e4c8aa4fb0fdd7d6937f711ea09684b2f03fbbf0
--- /dev/null
+++ b/src/main/java/no/nibio/vips/logic/entity/CropCategoryLocalPK.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2016 NIBIO <http://www.nibio.no/>.
+ *
+ * This file is part of VIPSLogic.
+ * VIPSLogic is free software: you can redistribute it and/or modify
+ * it under the terms of the NIBIO Open Source License as published by
+ * NIBIO, either version 1 of the License, or (at your option) any
+ * later version.
+ *
+ * VIPSLogic 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
+ * NIBIO Open Source License for more details.
+ *
+ * You should have received a copy of the NIBIO Open Source License
+ * along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>.
+ *
+ */
+
+package no.nibio.vips.logic.entity;
+
+import java.io.Serializable;
+import javax.persistence.Basic;
+import javax.persistence.Column;
+import javax.persistence.Embeddable;
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Size;
+
+/**
+ * @copyright 2016 <a href="http://www.nibio.no/">NIBIO</a>
+ * @author Tor-Einar Skog <tor-einar.skog@nibio.no>
+ */
+@Embeddable
+public class CropCategoryLocalPK implements Serializable {
+
+ @Basic(optional = false)
+ @NotNull
+ @Column(name = "crop_category_id")
+ private int cropCategoryId;
+ @Basic(optional = false)
+ @NotNull
+ @Size(min = 1, max = 10)
+ @Column(name = "locale")
+ private String locale;
+
+ public CropCategoryLocalPK() {
+ }
+
+ public CropCategoryLocalPK(int cropCategoryId, String locale) {
+ this.cropCategoryId = cropCategoryId;
+ this.locale = locale;
+ }
+
+ public int getCropCategoryId() {
+ return cropCategoryId;
+ }
+
+ public void setCropCategoryId(int cropCategoryId) {
+ this.cropCategoryId = cropCategoryId;
+ }
+
+ public String getLocale() {
+ return locale;
+ }
+
+ public void setLocale(String locale) {
+ this.locale = locale;
+ }
+
+ @Override
+ public int hashCode() {
+ int hash = 0;
+ hash += (int) cropCategoryId;
+ hash += (locale != null ? locale.hashCode() : 0);
+ return hash;
+ }
+
+ @Override
+ public boolean equals(Object object) {
+ // TODO: Warning - this method won't work in the case the id fields are not set
+ if (!(object instanceof CropCategoryLocalPK)) {
+ return false;
+ }
+ CropCategoryLocalPK other = (CropCategoryLocalPK) object;
+ if (this.cropCategoryId != other.cropCategoryId) {
+ return false;
+ }
+ if ((this.locale == null && other.locale != null) || (this.locale != null && !this.locale.equals(other.locale))) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ return "no.nibio.vips.logic.entity.CropCategoryLocalPK[ cropCategoryId=" + cropCategoryId + ", locale=" + locale + " ]";
+ }
+
+}
diff --git a/src/main/java/no/nibio/vips/logic/entity/ForecastConfiguration.java b/src/main/java/no/nibio/vips/logic/entity/ForecastConfiguration.java
index 6fa0860969cfa571174869654cc4121f393dcd5e..99c8aae8748be308378afa746eac8b7bf2e1998f 100644
--- a/src/main/java/no/nibio/vips/logic/entity/ForecastConfiguration.java
+++ b/src/main/java/no/nibio/vips/logic/entity/ForecastConfiguration.java
@@ -62,6 +62,7 @@ import no.nibio.vips.util.WeatherUtil;
@NamedQuery(name = "ForecastConfiguration.findByDateStart", query = "SELECT f FROM ForecastConfiguration f WHERE f.dateStart = :dateStart AND f.isPrivate = FALSE"),
@NamedQuery(name = "ForecastConfiguration.findByDateEnd", query = "SELECT f FROM ForecastConfiguration f WHERE f.dateEnd = :dateEnd AND f.isPrivate = FALSE"),
@NamedQuery(name = "ForecastConfiguration.findActiveAtDate", query = "SELECT f FROM ForecastConfiguration f WHERE f.dateStart <= :currentDate AND f.dateEnd >= :currentDate AND f.isPrivate = FALSE"),
+ @NamedQuery(name = "ForecastConfiguration.findAllActiveAtDate", query = "SELECT f FROM ForecastConfiguration f WHERE f.dateStart <= :currentDate AND f.dateEnd >= :currentDate"),
@NamedQuery(name = "ForecastConfiguration.findByLocationPointOfInterestId", query = "SELECT f FROM ForecastConfiguration f WHERE f.locationPointOfInterestId = :locationPointOfInterestId AND f.isPrivate = FALSE"),
@NamedQuery(name = "ForecastConfiguration.findByWeatherStationPointOfInterestId", query = "SELECT f FROM ForecastConfiguration f WHERE f.weatherStationPointOfInterestId = :weatherStationPointOfInterestId AND f.isPrivate = FALSE"),
@NamedQuery(name = "ForecastConfiguration.findByWeatherStationPointOfInterestIdAndDate", query = "SELECT f FROM ForecastConfiguration f WHERE f.weatherStationPointOfInterestId = :weatherStationPointOfInterestId AND f.dateStart <= :to AND f.dateEnd >= :from AND f.isPrivate = FALSE"),
diff --git a/src/main/java/no/nibio/vips/logic/entity/Message.java b/src/main/java/no/nibio/vips/logic/entity/Message.java
index 1e2a36f0387a26a451cfa82013d206b4344e57c0..4003789ab76c60fb7a18fd50ee0cc91cf5409147 100644
--- a/src/main/java/no/nibio/vips/logic/entity/Message.java
+++ b/src/main/java/no/nibio/vips/logic/entity/Message.java
@@ -44,6 +44,10 @@ import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.persistence.Transient;
import javax.xml.bind.annotation.XmlRootElement;
+import no.nibio.vips.logic.util.IntegerArrayUserType;
+import org.hibernate.annotations.Type;
+import org.hibernate.annotations.TypeDef;
+import org.hibernate.annotations.TypeDefs;
/**
* @copyright 2014 <a href="http://www.nibio.no/">NIBIO</a>
@@ -52,6 +56,7 @@ import javax.xml.bind.annotation.XmlRootElement;
@Entity
@Table(name = "message")
@XmlRootElement
+@TypeDefs( {@TypeDef( name= "IntegerArray", typeClass = IntegerArrayUserType.class)})
@NamedQueries({
@NamedQuery(name = "Message.findAll", query = "SELECT m FROM Message m"),
@NamedQuery(name = "Message.findByMessageId", query = "SELECT m FROM Message m WHERE m.messageId = :messageId"),
@@ -71,7 +76,7 @@ public class Message implements Serializable {
private Set<MessageIllustration> messageIllustrationSet;
private Set<MessageLocale> messageLocaleSet;
private Integer organizationId;
- private List<Integer> messageCropOrganismIds;
+ private Integer[] cropCategoryIds;
public Message() {
}
@@ -270,18 +275,20 @@ public class Message implements Serializable {
}
/**
- * @return the messageCropOrganismIds
+ * @return the cropCategoryIds
*/
- @Transient
- public List<Integer> getMessageCropOrganismIds() {
- return this.messageCropOrganismIds != null ? this.messageCropOrganismIds : new ArrayList<Integer>();
+ @Type(type = "IntegerArray")
+ @Column(name="crop_category_ids")
+ public Integer[] getCropCategoryIds() {
+ return cropCategoryIds;
}
/**
- * @param messageCropOrganismIds the messageCropOrganismIds to set
+ * @param cropCategoryIds the cropCategoryIds to set
*/
- public void setMessageCropOrganismIds(List<Integer> messageCropOrganismIds) {
- this.messageCropOrganismIds = messageCropOrganismIds;
+ public void setCropCategoryIds(Integer[] cropCategoryIds) {
+ this.cropCategoryIds = cropCategoryIds;
}
+
}
diff --git a/src/main/java/no/nibio/vips/logic/messaging/ForecastEventNotificationSubscription.java b/src/main/java/no/nibio/vips/logic/messaging/ForecastEventNotificationSubscription.java
index 0a128b6351f357c796df57b129ac41fc89db8ded..f8291514c654520f9d46663de3245836b2fe58a2 100644
--- a/src/main/java/no/nibio/vips/logic/messaging/ForecastEventNotificationSubscription.java
+++ b/src/main/java/no/nibio/vips/logic/messaging/ForecastEventNotificationSubscription.java
@@ -54,8 +54,8 @@ public class ForecastEventNotificationSubscription {
private Integer[] weatherStationIds;
@Type(type = "IntegerArray")
- @Column(name = "crop_ids")
- private Integer[] cropIds;
+ @Column(name = "crop_category_ids")
+ private Integer[] cropCategoryIds;
/**
* @return the userId
@@ -109,21 +109,21 @@ public class ForecastEventNotificationSubscription {
}
/**
- * @return the cropIds
+ * @return the cropCategoryIds
*/
- public Integer[] getCropIds() {
- return cropIds;
+ public Integer[] getCropCategoryIds() {
+ return cropCategoryIds;
}
/**
- * @param cropIds the cropIds to set
+ * @param cropCategoryIds the cropCategoryIds to set
*/
- public void setCropIds(Integer[] cropIds) {
- this.cropIds = cropIds;
+ public void setCropCategoryIds(Integer[] cropCategoryIds) {
+ this.cropCategoryIds = cropCategoryIds;
}
public void setCropIds(List<Integer> cropIds)
{
- this.cropIds = cropIds.toArray(new Integer[cropIds.size()]);
+ this.cropCategoryIds = cropIds.toArray(new Integer[cropIds.size()]);
}
}
diff --git a/src/main/java/no/nibio/vips/logic/messaging/MessageNotificationSubscription.java b/src/main/java/no/nibio/vips/logic/messaging/MessageNotificationSubscription.java
index 2e70064f2e4ead1c3bf2ca58e45d20db5ce15cfc..8ee570be8121f53187b4f8bb489f986b5b3f28c4 100644
--- a/src/main/java/no/nibio/vips/logic/messaging/MessageNotificationSubscription.java
+++ b/src/main/java/no/nibio/vips/logic/messaging/MessageNotificationSubscription.java
@@ -53,8 +53,8 @@ public class MessageNotificationSubscription implements Serializable {
private Integer[] messageTagIds;
@Type(type = "IntegerArray")
- @Column(name = "crop_ids")
- private Integer[] cropIds;
+ @Column(name = "crop_category_ids")
+ private Integer[] cropCategoryIds;
public Integer getUserId() {
return this.userId;
@@ -127,22 +127,22 @@ public class MessageNotificationSubscription implements Serializable {
}
/**
- * @return the cropIds
+ * @return the cropCategoryIds
*/
- public Integer[] getCropIds() {
- return cropIds;
+ public Integer[] getCropCategoryIds() {
+ return cropCategoryIds;
}
/**
- * @param cropIds the cropIds to set
+ * @param cropCategoryIds the cropCategoryIds to set
*/
- public void setCropIds(Integer[] cropIds) {
- this.cropIds = cropIds;
+ public void setCropCategoryIds(Integer[] cropCategoryIds) {
+ this.cropCategoryIds = cropCategoryIds;
}
public void setCropIds(List<Integer> cropIds)
{
- this.cropIds = cropIds.toArray(new Integer[cropIds.size()]);
+ this.cropCategoryIds = cropIds.toArray(new Integer[cropIds.size()]);
}
}
diff --git a/src/main/java/no/nibio/vips/logic/messaging/MessagingBean.java b/src/main/java/no/nibio/vips/logic/messaging/MessagingBean.java
index 5ad2cfdeab402c0a9498d149f3dc34f390ab1def..fb3197edb144b1d4191a7e7d8ace11d8a64b9cca 100644
--- a/src/main/java/no/nibio/vips/logic/messaging/MessagingBean.java
+++ b/src/main/java/no/nibio/vips/logic/messaging/MessagingBean.java
@@ -321,8 +321,7 @@ public class MessagingBean {
public List<MessageRecipient> getForecastEventNotificationSubscribers(ForecastConfiguration config)
{
- Query q = em.createNativeQuery(
- "SELECT \n" +
+ String sql = "SELECT \n" +
" u.preferred_locale,\n" +
" umf.format_name AS type,\n" +
" CASE fns.universal_message_format_id " +
@@ -336,13 +335,13 @@ public class MessagingBean {
"WHERE fns.user_id=u.user_id\n" +
"AND fns.universal_message_format_id = umf.universal_message_format_id\n" +
"AND u.user_id IN (\n" +
- " SELECT user_id FROM messaging.forecast_event_notification_subscription fens, public.vips_logic_user u \n" +
+ " SELECT u.user_id FROM messaging.forecast_event_notification_subscription fens, public.vips_logic_user u \n" +
" WHERE :weatherStationId = ANY(fens.weather_station_ids) \n" +
- " AND :cropOrganismId = ANY(fens.crop_ids)" +
+ " AND fens.crop_category_ids && ARRAY(SELECT crop_category_id FROM public.crop_category WHERE :cropOrganismId = ANY(crop_organism_ids))" +
" AND fens.user_id = u.user_id \n" +
" AND (fens.universal_message_format_id <> " + UniversalMessageFormat.FORMAT_SMS + " OR (fens.universal_message_format_id = " + UniversalMessageFormat.FORMAT_SMS + " AND u.approves_sms_billing IS TRUE))" +
- ");\n",
- MessageRecipient.class);
+ ");\n";
+ Query q = em.createNativeQuery(sql, MessageRecipient.class);
q.setParameter("weatherStationId", config.getWeatherStationPointOfInterestId().getPointOfInterestId());
q.setParameter("cropOrganismId", config.getCropOrganismId().getOrganismId());
@@ -420,7 +419,7 @@ public class MessagingBean {
"AND ons.universal_message_format_id = umf.universal_message_format_id\n" +
"AND u.user_id IN (\n" +
" SELECT ons.user_id FROM messaging.observation_notification_subscription ons, public.vips_logic_user u \n" +
- " WHERE :cropOrganismId = ANY(ons.crop_ids) \n" +
+ " WHERE ons.crop_category_ids && ARRAY(SELECT crop_category_id FROM public.crop_category WHERE :cropOrganismId = ANY(crop_organism_ids)) \n" +
" AND ons.user_id = u.user_id \n" +
" AND (ons.universal_message_format_id <> " + UniversalMessageFormat.FORMAT_SMS + " OR (ons.universal_message_format_id = " + UniversalMessageFormat.FORMAT_SMS + " AND u.approves_sms_billing IS TRUE))" +
");\n",
diff --git a/src/main/java/no/nibio/vips/logic/messaging/ObservationNotificationSubscription.java b/src/main/java/no/nibio/vips/logic/messaging/ObservationNotificationSubscription.java
index a477030cfde46bfc053f9064f5e21aab5a6dfdcd..b178320b22e4f3c400205c1f96aefe32d53530ee 100644
--- a/src/main/java/no/nibio/vips/logic/messaging/ObservationNotificationSubscription.java
+++ b/src/main/java/no/nibio/vips/logic/messaging/ObservationNotificationSubscription.java
@@ -49,8 +49,8 @@ public class ObservationNotificationSubscription implements Serializable {
private Integer universalMessageFormatId;
@Type(type = "IntegerArray")
- @Column(name = "crop_ids")
- private Integer[] cropIds;
+ @Column(name = "crop_category_ids")
+ private Integer[] cropCategoryIds;
public Integer getUserId() {
return this.userId;
@@ -100,22 +100,22 @@ public class ObservationNotificationSubscription implements Serializable {
}
/**
- * @return the cropIds
+ * @return the cropCategoryIds
*/
- public Integer[] getCropIds() {
- return cropIds;
+ public Integer[] getCropCategoryIds() {
+ return cropCategoryIds;
}
/**
- * @param cropIds the cropIds to set
+ * @param cropCategoryIds the cropCategoryIds to set
*/
- public void setCropIds(Integer[] cropIds) {
- this.cropIds = cropIds;
+ public void setCropCategoryIds(Integer[] cropCategoryIds) {
+ this.cropCategoryIds = cropCategoryIds;
}
public void setCropIds(List<Integer> cropIds)
{
- this.cropIds = cropIds.toArray(new Integer[cropIds.size()]);
+ this.cropCategoryIds = cropIds.toArray(new Integer[cropIds.size()]);
}
}
diff --git a/src/main/java/no/nibio/vips/logic/service/LogicService.java b/src/main/java/no/nibio/vips/logic/service/LogicService.java
index 53a70b1a48adad398bbab9e92b78709f5fba877c..2bf2f79d53e29d7d3d1660ac4d2dc2f89a61b856 100644
--- a/src/main/java/no/nibio/vips/logic/service/LogicService.java
+++ b/src/main/java/no/nibio/vips/logic/service/LogicService.java
@@ -293,10 +293,18 @@ public class LogicService {
@Produces("application/vnd.google-earth.kml+xml;charset=utf-8")
public Response getForecastResultsAggregate(
@PathParam("organizationId") Integer organizationId,
- @QueryParam("cropOrganismId") List<Integer> cropOrganismIds)
+ @QueryParam("cropCategoryId") List<Integer> cropCategoryIds)
{
+ if(cropCategoryIds == null || cropCategoryIds.isEmpty())
+ {
+ return Response.noContent().build();
+ }
+ else
+ {
+ List<Integer> cropOrganismIds = SessionControllerGetter.getOrganismBean().getCropCategoryOrganismIds(cropCategoryIds);
Kml retVal = SessionControllerGetter.getForecastBean().getForecastsAggregateKml(organizationId, cropOrganismIds, SystemTime.getSystemTime(), ServletUtil.getServerName(httpServletRequest));
return Response.ok().entity(retVal).build();
+ }
}
@GET
@@ -352,7 +360,7 @@ public class LogicService {
public Response getMessage(@PathParam("messageId") Integer messageId)
{
Message message = SessionControllerGetter.getMessageBean().getMessage(messageId);
- message.setMessageCropOrganismIds(SessionControllerGetter.getMessageBean().getMessageCropOrganismIds(message));
+
return Response.ok().entity(message).build();
}
@@ -382,9 +390,6 @@ public class LogicService {
}
List<Message> messageList = SessionControllerGetter.getMessageBean().getMessageList(organizationId, datePublishedFrom, datePublishedTo);
- // Adding the crop connections manually
- messageList = SessionControllerGetter.getMessageBean().addMessageOrganismIds(messageList);
-
return Response.ok().entity(messageList).build();
}
catch(ParseException ex){
@@ -398,7 +403,6 @@ public class LogicService {
public Response getMessageListWithTags(@QueryParam("tagId") List<Integer> tagIds, @PathParam("organizationId") Integer organizationId)
{
List<Message> messageListWithTags = SessionControllerGetter.getMessageBean().getCurrentFilteredMessagesForOrganization(tagIds, organizationId);
- messageListWithTags = SessionControllerGetter.getMessageBean().addMessageOrganismIds(messageListWithTags);
return Response.ok().entity(messageListWithTags).build();
}
@@ -684,6 +688,21 @@ public class LogicService {
}
}
+ @GET
+ @Path("organism/cropcategory/{organizationId}")
+ @Produces("application/json;charset=UTF-8")
+ public Response getCropCategories(@PathParam("organizationId") Integer organizationId)
+ {
+ if(organizationId != null)
+ {
+ return Response.ok().entity(SessionControllerGetter.getOrganismBean().getCropCategories(organizationId)).build();
+ }
+ else
+ {
+ return Response.noContent().build();
+ }
+ }
+
private ManagerResource getManagerResource()
{
Client client = ClientBuilder.newClient();
diff --git a/src/main/java/no/nibio/vips/logic/util/IntegerArrayUserType.java b/src/main/java/no/nibio/vips/logic/util/IntegerArrayUserType.java
index 1a765f7047c1592eb7f4507533d8ea223db1c03f..7bdb5d98873374201825f3519277de07972efd8e 100644
--- a/src/main/java/no/nibio/vips/logic/util/IntegerArrayUserType.java
+++ b/src/main/java/no/nibio/vips/logic/util/IntegerArrayUserType.java
@@ -109,8 +109,15 @@ public class IntegerArrayUserType implements UserType {
return null;
}
- Integer[] array = (Integer[]) rs.getArray(names[0]).getArray();
- return array;
+ try
+ {
+ Integer[] array = (Integer[]) rs.getArray(names[0]).getArray();
+ return array;
+ }
+ catch(NullPointerException ex)
+ {
+ return new Integer[0];
+ }
}
/**
diff --git a/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts.properties b/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts.properties
index d7a88344f520e7fa966b6eca75ddbf8d1f2b7237..3c50ddd93acf527793814beb939ab75b5347029b 100644
--- a/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts.properties
+++ b/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts.properties
@@ -345,3 +345,4 @@ noPrivateForecastsFoundForUser=No private forecasts found for user
listCrops=List all crops
listPests=List all pests
allPests=All pests
+cropCategoryIds=Crop categories
diff --git a/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_bs.properties b/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_bs.properties
index 28f283f92ec8fe045d61ad1d297c3b4d83c0b60d..74f4537fe0791a2d3d17f5197ba5b0a0fc70d633 100644
--- a/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_bs.properties
+++ b/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_bs.properties
@@ -345,3 +345,4 @@ noPrivateForecastsFoundForUser=No private forecasts found for user
listCrops=List all crops
listPests=List all pests
allPests=All pests
+cropCategoryIds=Crop categories
diff --git a/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_hr.properties b/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_hr.properties
index 3c24137038ad283cddfff91a96f6b3a16a77acc3..185b130d5491418bba9f97a3ba7b056f87526435 100644
--- a/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_hr.properties
+++ b/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_hr.properties
@@ -344,3 +344,4 @@ noPrivateForecastsFoundForUser=No private forecasts found for user
listCrops=List all crops
listPests=List all pests
allPests=All pests
+cropCategoryIds=Crop categories
diff --git a/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_nb.properties b/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_nb.properties
index a17b91864b96e5e27a88d76e901cdf188d7d6042..0a9e2fd4b5e43723a4791eb02c476a49be1fcdc8 100644
--- a/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_nb.properties
+++ b/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_nb.properties
@@ -345,3 +345,4 @@ noPrivateForecastsFoundForUser=Fant ingen private varsler for brukeren
listCrops=Kulturliste
listPests=Skadegj\u00f8rerliste
allPests=Alle skadegj\u00f8rere
+cropCategoryIds=Kulturgrupper
diff --git a/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_sr.properties b/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_sr.properties
index dd6e64359cd5603aaae188a2d31e9e070fbe7e72..8fb755a2e8b923be9426edea8cd9e04672ba639c 100644
--- a/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_sr.properties
+++ b/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_sr.properties
@@ -345,3 +345,4 @@ noPrivateForecastsFoundForUser=No private forecasts found for user
listCrops=List all crops
listPests=List all pests
allPests=All pests
+cropCategoryIds=Crop categories
diff --git a/src/main/webapp/formdefinitions/messageForm.json b/src/main/webapp/formdefinitions/messageForm.json
index 9e09b1d21326a55e688860ad3e2bce32c2916367..5e7b86b9c16319c421fc6c160cfe44f5a391e133 100644
--- a/src/main/webapp/formdefinitions/messageForm.json
+++ b/src/main/webapp/formdefinitions/messageForm.json
@@ -37,7 +37,7 @@
"required" : false
},
{
- "name" : "cropOrganismIds",
+ "name" : "cropCategoryIds",
"dataType" : "INTEGER",
"fieldType" : "SELECT_MULTIPLE",
"required" : false
diff --git a/src/main/webapp/templates/messageForm.ftl b/src/main/webapp/templates/messageForm.ftl
index 8b15cd257812fb8356fe0a1cfa9c516b996d5be8..04a08a9fc20f410871244502f1091007270976ca 100644
--- a/src/main/webapp/templates/messageForm.ftl
+++ b/src/main/webapp/templates/messageForm.ftl
@@ -140,17 +140,15 @@
</select>
</div>
<div class="form-group">
- <label for="cropOrganismIds">${i18nBundle.cropOrganismIds}</label>
- <select class="form-control chosen-select" name="cropOrganismIds" onblur="validateField(this);" multiple="multiple">
- <#list allCrops?sort_by("latinName") as organism>
- <option value="${organism.organismId}"
- <#list message.messageCropOrganismIds as organismId>
- <#if organismId == organism.organismId>
- selected="selected"
+ <label for="cropCategoryIds">${i18nBundle.cropCategoryIds}</label>
+ <select class="form-control chosen-select" name="cropCategoryIds" onblur="validateField(this);" multiple="multiple">
+ <#list allCropCategoryIds as cropCategory>
+ <option value="${cropCategory.cropCategoryId}"
+ <#if message.cropCategoryIds?has_content && message.cropCategoryIds?seq_index_of(cropCategory.cropCategoryId) gte 0>
+ selected="selected"
</#if>
+ >${cropCategory.getLocalName(currentLocale.language)!cropCategory.defaultName}</option>
</#list>
- >${organism.latinName!""} / ${organism.tradeName!""} / ${organism.getLocalName(currentLocale.language)!""}</option>
- </#list>
</select>
</div>