diff --git a/src/main/java/no/nibio/vips/logic/controller/session/UserBean.java b/src/main/java/no/nibio/vips/logic/controller/session/UserBean.java
index 80a92d6d45dc0ff7deb90e6e9610993389a01969..72bc3a5a26a5da099e5e258c439d7a1866fe0b6c 100755
--- a/src/main/java/no/nibio/vips/logic/controller/session/UserBean.java
+++ b/src/main/java/no/nibio/vips/logic/controller/session/UserBean.java
@@ -925,4 +925,14 @@ public class UserBean {
     public Organization storeOrganization(Organization organization) {
         return em.merge(organization);
     }
+
+    public List<VipsLogicUser> getUsersByVipsLogicRoles(Integer[] vipsLogicRoleIds) {
+        return em.createNativeQuery(
+                "SELECT * FROM vips_logic_user "
+                        + "WHERE user_id IN ("
+                        + "SELECT user_id FROM user_vips_logic_role WHERE vips_logic_role_id IN (:vipsLogicRoleIds)"
+                        + ")", VipsLogicUser.class)
+                .setParameter("vipsLogicRoleIds", Arrays.asList(vipsLogicRoleIds))
+                .getResultList();
+    }
 }
diff --git a/src/main/java/no/nibio/vips/logic/entity/VipsLogicRole.java b/src/main/java/no/nibio/vips/logic/entity/VipsLogicRole.java
index f1e082c2172e29c262cf714932275d7a99612728..e4d22468c1cbc00e28a1b8e4cbf06afb2197f65c 100755
--- a/src/main/java/no/nibio/vips/logic/entity/VipsLogicRole.java
+++ b/src/main/java/no/nibio/vips/logic/entity/VipsLogicRole.java
@@ -54,6 +54,9 @@ public class VipsLogicRole implements Serializable {
     public static Integer APPLE_FRUIT_MOTH_ADMINISTRATOR = 6; // Norway only
     public static Integer ORGANISM_EDITOR = 7;
     public static Integer APPLE_FRUIT_MOTH_BERRY_CLUSTER_COUNTER = 8; // Norway only
+    public static Integer BARKBEETLE_REGISTRATOR = 9;
+    public static Integer BARKBEETLE_ADMIN = 10;
+
 
     private static final long serialVersionUID = 1L;
     @Id
diff --git a/src/main/java/no/nibio/vips/logic/modules/barkbeetle/BarkbeetleBean.java b/src/main/java/no/nibio/vips/logic/modules/barkbeetle/BarkbeetleBean.java
new file mode 100644
index 0000000000000000000000000000000000000000..04da9831fd6768250f5a62f271522a25434be3c0
--- /dev/null
+++ b/src/main/java/no/nibio/vips/logic/modules/barkbeetle/BarkbeetleBean.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2020 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.modules.barkbeetle;
+
+import java.util.List;
+import javax.ejb.LocalBean;
+import javax.ejb.Stateless;
+import javax.naming.InitialContext;
+import javax.naming.NamingException;
+import javax.persistence.EntityManager;
+import javax.persistence.PersistenceContext;
+import no.nibio.vips.logic.util.SessionControllerGetter;
+
+/**
+ * @copyright 2020 <a href="http://www.nibio.no/">NIBIO</a>
+ * @author Tor-Einar Skog <tor-einar.skog@nibio.no>
+ */
+@LocalBean
+@Stateless
+public class BarkbeetleBean {
+    @PersistenceContext(unitName="VIPSLogic-PU")
+    EntityManager em;
+    
+    /**
+     * Get the list of trapsites for the given season
+     * @param season
+     * @return 
+     */
+    public List<SeasonTrapsite> getSeasonTrapsites(Integer season){
+        return em.createNamedQuery("SeasonTrapsite.findBySeason")
+                .setParameter("season", season)
+                .getResultList();
+    }
+    
+    /**
+     * Get a specific trapsite
+     * @param seasonTrapsiteId
+     * @return 
+     */
+    public SeasonTrapsite getSeasonTrapsite(Integer seasonTrapsiteId)
+    {
+        return em.find(SeasonTrapsite.class, seasonTrapsiteId);
+    }
+    
+    public SeasonTrapsite storeSeasonTrapsite(SeasonTrapsite seasonTrapsite)
+    {
+        if(seasonTrapsite.getSeasonTrapsiteId() == null)
+        {
+            em.persist(seasonTrapsite);
+            return seasonTrapsite;
+        }
+        else
+        {
+            return em.merge(seasonTrapsite);
+        }
+    }
+    
+    public List<TrapsiteType> getTrapsiteTypes()
+    {
+        return em.createNamedQuery("TrapsiteType.findAll").getResultList();
+    }
+    
+    public TrapsiteType getTrapsiteType(Integer trapsiteTypeId)
+    {
+        return em.find(TrapsiteType.class, trapsiteTypeId);
+    }
+    
+    /**
+     * Util method for getting this bean through JNDI
+     * @return 
+     */
+    public static BarkbeetleBean getInstance()
+    {
+        try
+        {
+            InitialContext ic = new InitialContext();
+            BarkbeetleBean retVal = (BarkbeetleBean) ic.lookup(SessionControllerGetter.getJndiPath(BarkbeetleBean.class));
+
+            return retVal;
+        }catch(NamingException ne)
+        {
+            System.out.println("Could not find " + BarkbeetleBean.class.getSimpleName());
+            return null;
+        }
+    }
+
+    public List<TrapsiteRegistration> getRegistrationsForSite(SeasonTrapsite trapsite) {
+        return em.createNamedQuery("TrapsiteRegistration.findBySeasonTrapsiteId")
+                .setParameter("seasonTrapsiteId", trapsite.getSeasonTrapsiteId())
+                .getResultList();
+    }
+
+    public List<RegistrationStatusType> getRegistrationStatusTypes() {
+        return em.createNamedQuery("RegistrationStatusType.findAll").getResultList();
+    }
+
+    public SeasonTrapsite storeTrapsiteRegistrations(Integer seasonTrapsiteId, List<TrapsiteRegistration> registrations) {
+        SeasonTrapsite trapsite = em.find(SeasonTrapsite.class, seasonTrapsiteId);
+        trapsite.setTrapsiteRegistrationCollection(registrations);
+        return em.merge(trapsite);
+    }
+}
diff --git a/src/main/java/no/nibio/vips/logic/modules/barkbeetle/BarkbeetleController.java b/src/main/java/no/nibio/vips/logic/modules/barkbeetle/BarkbeetleController.java
new file mode 100644
index 0000000000000000000000000000000000000000..4d02cd9dc4e82e5d3840f6d33c9fd1b3c912e8d9
--- /dev/null
+++ b/src/main/java/no/nibio/vips/logic/modules/barkbeetle/BarkbeetleController.java
@@ -0,0 +1,306 @@
+/*
+ * Copyright (c) 2020 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.modules.barkbeetle;
+
+import java.io.IOException;
+import java.time.LocalDate;
+import java.time.ZoneId;
+import java.time.temporal.WeekFields;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Locale;
+import java.util.Set;
+import java.util.stream.Collectors;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.ws.rs.core.Response;
+import no.nibio.vips.gis.GISUtil;
+import no.nibio.vips.logic.entity.VipsLogicRole;
+import no.nibio.vips.logic.entity.VipsLogicUser;
+import no.nibio.vips.logic.util.Globals;
+import no.nibio.vips.logic.util.SessionControllerGetter;
+import no.nibio.vips.util.ExceptionUtil;
+import no.nibio.vips.util.ServletUtil;
+import no.nibio.web.forms.FormValidation;
+import no.nibio.web.forms.FormValidationException;
+import no.nibio.web.forms.FormValidator;
+import org.locationtech.jts.geom.Coordinate;
+import org.locationtech.jts.geom.Point;
+
+/**
+ * @copyright 2020 <a href="http://www.bioforsk.no/">Bioforsk</a>
+ * @author Tor-Einar Skog <tor-einar.skog@bioforsk.no>
+ */
+public class BarkbeetleController extends HttpServlet {
+   
+    /** 
+     * Processes requests for both HTTP <code>GET</code> and <code>POST</code> methods.
+     * @param request servlet request
+     * @param response servlet response
+     * @throws ServletException if a servlet-specific error occurs
+     * @throws IOException if an I/O error occurs
+     */
+    protected void processRequest(HttpServletRequest request, HttpServletResponse response)
+    throws ServletException, IOException {
+        response.setContentType("text/html;charset=UTF-8");
+        VipsLogicUser user = (VipsLogicUser) request.getSession().getAttribute("user");
+        if(SessionControllerGetter.getUserBean().authorizeUser(user, VipsLogicRole.BARKBEETLE_ADMIN, VipsLogicRole.BARKBEETLE_REGISTRATOR, VipsLogicRole.ORGANIZATION_ADMINISTRATOR, VipsLogicRole.SUPERUSER))
+        {
+            request.setAttribute("user",user);
+            request.setAttribute("userIsAdmin",SessionControllerGetter.getUserBean().authorizeUser(user, VipsLogicRole.BARKBEETLE_ADMIN, VipsLogicRole.SUPERUSER));
+            Integer season = request.getParameter("season") != null?  Integer.valueOf(request.getParameter("season"))
+                        : LocalDate.now().getYear();
+            String action = request.getParameter("action");
+            if(action == null)
+            {
+                List<SeasonTrapsite> seasonTrapSites = BarkbeetleBean.getInstance().getSeasonTrapsites(season);
+                request.setAttribute("season", season);
+                request.setAttribute("seasonTrapsites", seasonTrapSites);
+                request.getRequestDispatcher("/modules/barkbeetle/barkbeetleSeasonTrapsiteList.ftl").forward(request, response);
+            }
+            else if(action.equals("editSeasonTrapsite"))
+            {
+                if(!SessionControllerGetter.getUserBean().authorizeUser(user, VipsLogicRole.BARKBEETLE_ADMIN, VipsLogicRole.ORGANIZATION_ADMINISTRATOR, VipsLogicRole.SUPERUSER))
+                {
+                    response.sendError(403,"Access not authorized"); // HTTP Forbidden
+                }
+                request.setAttribute("trapsiteRegistrators", SessionControllerGetter.getUserBean().getUsersByVipsLogicRoles(new Integer[]{VipsLogicRole.BARKBEETLE_ADMIN, VipsLogicRole.BARKBEETLE_REGISTRATOR}));
+                SeasonTrapsite trapsite = request.getParameter("seasonTrapsiteId") != null ? 
+                        BarkbeetleBean.getInstance().getSeasonTrapsite(Integer.valueOf(request.getParameter("seasonTrapsiteId")))
+                        : new SeasonTrapsite();
+                
+                List<TrapsiteType> trapsiteTypes = BarkbeetleBean.getInstance().getTrapsiteTypes();
+                request.setAttribute("season", season);
+                request.setAttribute("seasonTrapsite", trapsite);
+                request.setAttribute("seasonTrapsiteTypes", trapsiteTypes);
+                request.setAttribute("messageKey", request.getParameter("messageKey"));
+                request.getRequestDispatcher("/modules/barkbeetle/barkbeetleSeasonTrapsiteForm.ftl").forward(request, response);
+            }
+            else if(action.equals("seasonTrapsiteFormSubmit"))
+            {
+                if(!SessionControllerGetter.getUserBean().authorizeUser(user, VipsLogicRole.BARKBEETLE_ADMIN, VipsLogicRole.ORGANIZATION_ADMINISTRATOR, VipsLogicRole.SUPERUSER))
+                {
+                    response.sendError(403,"Access not authorized"); // HTTP Forbidden
+                }
+                try
+                {
+                    FormValidation formValidation = FormValidator.validateForm("modules/barkbeetle/seasonTrapsiteForm", request, getServletContext());
+                    if(formValidation.isValid())
+                    {
+                        SeasonTrapsite trapsite = (request.getParameter("seasonTrapsiteId") != null && Integer.valueOf(request.getParameter("seasonTrapsiteId")) > 0) ? 
+                                BarkbeetleBean.getInstance().getSeasonTrapsite(Integer.valueOf(request.getParameter("seasonTrapsiteId")))
+                                : new SeasonTrapsite();
+                        trapsite.setSeason(formValidation.getFormField("season").getValueAsInteger());
+                        trapsite.setTrapsiteType(BarkbeetleBean.getInstance().getTrapsiteType(formValidation.getFormField("trapsiteTypeId").getValueAsInteger()));
+                        
+                        trapsite.setCountyNo(formValidation.getFormField("countyNo").getValueAsInteger());
+                        trapsite.setCountyName(formValidation.getFormField("countyName").getWebValue());
+                        trapsite.setMunicipalityNo(formValidation.getFormField("municipalityNo").getValueAsInteger());
+                        trapsite.setMunicipalityName(formValidation.getFormField("municipalityName").getWebValue());
+                        trapsite.setPropertyNo(formValidation.getFormField("propertyNo").getValueAsInteger());
+                        trapsite.setPropertySectionNo(formValidation.getFormField("propertySectionNo").getValueAsInteger());
+                        trapsite.setOwnerName(formValidation.getFormField("ownerName").getWebValue());
+                        trapsite.setOwnerPhone(formValidation.getFormField("ownerPhone").getWebValue());
+                        trapsite.setDateInstalled(formValidation.getFormField("dateInstalled").getValueAsDate());
+                        trapsite.setInstallationRemarks(formValidation.getFormField("installationRemarks").getWebValue());
+                        trapsite.setUserId(SessionControllerGetter.getUserBean().getVipsLogicUser(formValidation.getFormField("userId").getValueAsInteger()));
+                        
+                        // Handling the GIS
+                        Point p2d = formValidation.getFormField("gisGeom").getValueAsPointWGS84();
+                        Coordinate coordinate = new Coordinate(p2d.getX(), p2d.getY(),0);
+                        try
+                        {
+                            Double altitude = formValidation.getFormField("altitude").getValueAsDouble();
+                            coordinate = new Coordinate(p2d.getX(), p2d.getY(),altitude);
+                        }
+                        catch(NullPointerException | NumberFormatException ex) {}
+                        GISUtil gisUtil = new GISUtil();
+                        Point p3d = gisUtil.createPointWGS84(coordinate);
+                        trapsite.setGisGeom(p3d);
+                        
+                        trapsite = BarkbeetleBean.getInstance().storeSeasonTrapsite(trapsite);
+                        
+                        // Redirect to form
+                        response.sendRedirect(Globals.PROTOCOL + "://"
+                                + ServletUtil.getServerName(request)
+                                + "/barkbeetle?messageKey=storeOK&action=editSeasonTrapsite&seasonTrapsiteId=" + trapsite.getSeasonTrapsiteId()
+                        );
+                    }
+                    else
+                    {
+                        response.sendError(500, formValidation.getValidationMessages());
+                    }
+                }
+                catch(FormValidationException ex)
+                {
+                    response.sendError(500, ExceptionUtil.getStackTrace(ex));
+                }
+            }
+            else if(action.equals("registerData"))
+            {
+                SeasonTrapsite trapsite = request.getParameter("seasonTrapsiteId") != null ? 
+                        BarkbeetleBean.getInstance().getSeasonTrapsite(Integer.valueOf(request.getParameter("seasonTrapsiteId")))
+                        : null;
+                if(trapsite != null)
+                {
+                    request.setAttribute("seasonTrapsite", trapsite);
+                    Set<Integer> missingWeeks = new HashSet(trapsite.getTrapsiteType().getTrapsiteTypeId().equals(TrapsiteType.TRAPSITE_TYPE_STANDARD)?
+                            Arrays.asList(new Integer[]{21,24,28,33})
+                            : Arrays.asList(new Integer[]{21,24,28,33,37}));
+                    //request.setAttribute("weeks", weeks);
+                    request.setAttribute("traps", trapsite.getTrapsiteType().getTrapsiteTypeId().equals(TrapsiteType.TRAPSITE_TYPE_STANDARD)? 4 : 2 );
+                    List<TrapsiteRegistration> trapsiteReg = new ArrayList(trapsite.getTrapsiteRegistrationCollection());
+                    
+                    // Finding which registrations are present, removing them from "missing" collection
+                    trapsiteReg.forEach(r -> {
+                        missingWeeks.remove(r.getTrapsiteRegistrationPK().getWeek());
+                    });
+                    // Adding the missing
+                    trapsiteReg.addAll(missingWeeks.stream().map(w->{
+                        TrapsiteRegistration tr = new TrapsiteRegistration();
+                        tr.setTrapsiteRegistrationPK(new TrapsiteRegistrationPK(trapsite.getSeasonTrapsiteId(), w));
+                        return tr;
+                    }).collect(Collectors.toList()));
+                    Collections.sort(trapsiteReg);
+                    request.setAttribute("trapsiteRegistrations", trapsiteReg);
+                    // Setting the current week - last week for enabled registrations (future reg. not allowed)
+                    WeekFields weekFields = WeekFields.of(Locale.getDefault());
+                    //request.setAttribute("currentWeek", LocalDate.now().get(weekFields.weekOfWeekBasedYear()));
+                    request.setAttribute("currentWeek", 32); // TEST!
+                    request.setAttribute("registrationStatusTypes", BarkbeetleBean.getInstance().getRegistrationStatusTypes());
+                    request.setAttribute("messageKey", request.getParameter("messageKey"));
+                    request.getRequestDispatcher("/modules/barkbeetle/barkbeetleTrapsiteRegistrationForm.ftl").forward(request, response);
+                }
+                else
+                {
+                    response.sendError(Response.Status.BAD_REQUEST.getStatusCode(),"Kan ikke registrere data, fordi fellelokalitet med id=" + request.getParameter("seasonTrapsiteId") + " ikke ble funnet.");
+                }
+            }
+            else if(action.equals("trapsiteRegistrationFormSubmit"))
+            {
+                SeasonTrapsite trapsite = request.getParameter("seasonTrapsiteId") != null ? 
+                        BarkbeetleBean.getInstance().getSeasonTrapsite(Integer.valueOf(request.getParameter("seasonTrapsiteId")))
+                        : null;
+                
+                if(trapsite != null)
+                {
+                    try
+                    {
+                        // Build all objects, send to bean for storage
+                        // If date is set, the row is valid for storage
+                        List<TrapsiteRegistration> registrations = new ArrayList();
+                        request.getParameterNames().asIterator().forEachRemaining(parameterName->{
+                            if(parameterName.contains("dateRegistration") && !request.getParameter(parameterName).isBlank())
+                            {
+                                Integer week = Integer.valueOf(parameterName.split("_")[0]);
+                                TrapsiteRegistration tr = new TrapsiteRegistration();
+                                tr.setTrapsiteRegistrationPK(new TrapsiteRegistrationPK(trapsite.getSeasonTrapsiteId(), week));
+                                tr.setDateRegistration(Date.from(LocalDate.parse(request.getParameter(parameterName)).atStartOfDay(ZoneId.systemDefault()).toInstant()));
+                                String trap1 = request.getParameter(week + "_trap1");
+                                tr.setTrap1(!trap1.equals("M") && ! trap1.isBlank() ? Integer.valueOf(trap1) : null);
+                                String trap2 = request.getParameter(week + "_trap2");
+                                tr.setTrap2(!trap2.equals("M") && ! trap2.isBlank() ? Integer.valueOf(trap2) : null);
+                                String trap3 = request.getParameter(week + "_trap3");
+                                tr.setTrap3(!trap3.equals("M") && ! trap3.isBlank() ? Integer.valueOf(trap3) : null);
+                                String trap4 = request.getParameter(week + "_trap4");
+                                tr.setTrap4(!trap4.equals("M") && ! trap4.isBlank() ? Integer.valueOf(trap4) : null);
+
+                                tr.setTrap1Remarks(request.getParameter(week + "_trap1Remarks"));
+                                tr.setTrap2Remarks(request.getParameter(week + "_trap2Remarks"));
+                                tr.setTrap3Remarks(request.getParameter(week + "_trap3Remarks"));
+                                tr.setTrap4Remarks(request.getParameter("_trap4Remarks"));
+                                
+                                String registrationStatusTypeIdFieldValue = request.getParameter(week + "_registrationStatusTypeId");
+                                if(registrationStatusTypeIdFieldValue != null && ! registrationStatusTypeIdFieldValue.isBlank())
+                                {
+                                    tr.setRegistrationStatusTypeId(Integer.valueOf(registrationStatusTypeIdFieldValue));
+                                }
+                                
+                                registrations.add(tr);
+                            }
+                        });
+                        BarkbeetleBean.getInstance().storeTrapsiteRegistrations(trapsite.getSeasonTrapsiteId(), registrations);
+                        // Redirect to form
+                        response.sendRedirect(Globals.PROTOCOL + "://"
+                                + ServletUtil.getServerName(request)
+                                + "/barkbeetle?messageKey=storeOK&action=registerData&seasonTrapsiteId=" + trapsite.getSeasonTrapsiteId()
+                        );
+                    }
+                    catch(NumberFormatException ex)
+                    {
+                        response.sendError(500, ex.getMessage());
+                    }
+                    
+                }
+                else
+                {
+                    response.sendError(Response.Status.BAD_REQUEST.getStatusCode(),"Kan ikke registrere data, fordi fellelokalitet med id=" + request.getParameter("seasonTrapsiteId") + " ikke ble funnet.");
+                }
+            }
+        }
+        else
+        {
+            response.sendError(403,"Access not authorized"); // HTTP Forbidden
+        }
+    } 
+
+    // <editor-fold defaultstate="collapsed" desc="HttpServlet methods. Click on the + sign on the left to edit the code.">
+    /** 
+     * Handles the HTTP <code>GET</code> method.
+     * @param request servlet request
+     * @param response servlet response
+     * @throws ServletException if a servlet-specific error occurs
+     * @throws IOException if an I/O error occurs
+     */
+    @Override
+    protected void doGet(HttpServletRequest request, HttpServletResponse response)
+    throws ServletException, IOException {
+        processRequest(request, response);
+    } 
+
+    /** 
+     * Handles the HTTP <code>POST</code> method.
+     * @param request servlet request
+     * @param response servlet response
+     * @throws ServletException if a servlet-specific error occurs
+     * @throws IOException if an I/O error occurs
+     */
+    @Override
+    protected void doPost(HttpServletRequest request, HttpServletResponse response)
+    throws ServletException, IOException {
+        processRequest(request, response);
+    }
+
+    /** 
+     * Returns a short description of the servlet.
+     * @return a String containing servlet description
+     */
+    @Override
+    public String getServletInfo() {
+        return "Short description";
+    }// </editor-fold>
+
+}
diff --git a/src/main/java/no/nibio/vips/logic/modules/barkbeetle/RegistrationStatusType.java b/src/main/java/no/nibio/vips/logic/modules/barkbeetle/RegistrationStatusType.java
new file mode 100644
index 0000000000000000000000000000000000000000..932a7a3de43bdbf0353ef91b2d56d7e08768ed50
--- /dev/null
+++ b/src/main/java/no/nibio/vips/logic/modules/barkbeetle/RegistrationStatusType.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2020 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.modules.barkbeetle;
+
+import java.io.Serializable;
+import javax.persistence.Basic;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.NamedQueries;
+import javax.persistence.NamedQuery;
+import javax.persistence.Table;
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Size;
+import javax.xml.bind.annotation.XmlRootElement;
+
+/**
+ * @copyright 2020 <a href="http://www.nibio.no/">NIBIO</a>
+ * @author Tor-Einar Skog <tor-einar.skog@nibio.no>
+ */
+@Entity
+@Table(name = "registration_status_type", schema="barkbeetle")
+@XmlRootElement
+@NamedQueries({
+    @NamedQuery(name = "RegistrationStatusType.findAll", query = "SELECT r FROM RegistrationStatusType r"),
+    @NamedQuery(name = "RegistrationStatusType.findByRegistrationStatusTypeId", query = "SELECT r FROM RegistrationStatusType r WHERE r.registrationStatusTypeId = :registrationStatusTypeId"),
+    @NamedQuery(name = "RegistrationStatusType.findByTitle", query = "SELECT r FROM RegistrationStatusType r WHERE r.title = :title")})
+public class RegistrationStatusType implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+    @Id
+    @Basic(optional = false)
+    @NotNull
+    @Column(name = "registration_status_type_id")
+    private Integer registrationStatusTypeId;
+    @Size(max = 255)
+    @Column(name = "title")
+    private String title;
+
+    public RegistrationStatusType() {
+    }
+
+    public RegistrationStatusType(Integer registrationStatusId) {
+        this.registrationStatusTypeId = registrationStatusId;
+    }
+
+    public Integer getRegistrationStatusTypeId() {
+        return registrationStatusTypeId;
+    }
+
+    public void setRegistrationStatusTypeId(Integer registrationStatusTypeId) {
+        this.registrationStatusTypeId = registrationStatusTypeId;
+    }
+
+    public String getTitle() {
+        return title;
+    }
+
+    public void setTitle(String title) {
+        this.title = title;
+    }
+
+    @Override
+    public int hashCode() {
+        int hash = 0;
+        hash += (registrationStatusTypeId != null ? registrationStatusTypeId.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 RegistrationStatusType)) {
+            return false;
+        }
+        RegistrationStatusType other = (RegistrationStatusType) object;
+        if ((this.registrationStatusTypeId == null && other.registrationStatusTypeId != null) || (this.registrationStatusTypeId != null && !this.registrationStatusTypeId.equals(other.registrationStatusTypeId))) {
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    public String toString() {
+        return "no.nibio.vips.logic.modules.barkbeetle.RegistrationStatusType[ registrationStatusId=" + registrationStatusTypeId + " ]";
+    }
+
+}
diff --git a/src/main/java/no/nibio/vips/logic/modules/barkbeetle/SeasonTrapsite.java b/src/main/java/no/nibio/vips/logic/modules/barkbeetle/SeasonTrapsite.java
new file mode 100644
index 0000000000000000000000000000000000000000..8c2ab104050a4e24d0621a5a92171758b884a821
--- /dev/null
+++ b/src/main/java/no/nibio/vips/logic/modules/barkbeetle/SeasonTrapsite.java
@@ -0,0 +1,343 @@
+/*
+ * Copyright (c) 2020 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.modules.barkbeetle;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import java.io.Serializable;
+import java.util.Collection;
+import java.util.Date;
+import javax.persistence.Basic;
+import javax.persistence.CascadeType;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.Lob;
+import javax.persistence.ManyToOne;
+import javax.persistence.NamedQueries;
+import javax.persistence.NamedQuery;
+import javax.persistence.OneToMany;
+import javax.persistence.Table;
+import javax.persistence.Temporal;
+import javax.persistence.TemporalType;
+import javax.persistence.Transient;
+import javax.validation.constraints.Size;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlTransient;
+import no.nibio.vips.logic.entity.VipsLogicUser;
+import org.locationtech.jts.geom.Geometry;
+import org.locationtech.jts.geom.Point;
+
+/**
+ * @copyright 2020 <a href="http://www.nibio.no/">NIBIO</a>
+ * @author Tor-Einar Skog <tor-einar.skog@nibio.no>
+ */
+@Entity
+@Table(name = "season_trapsite", schema="barkbeetle")
+@XmlRootElement
+@NamedQueries({
+    @NamedQuery(name = "SeasonTrapsite.findAll", query = "SELECT s FROM SeasonTrapsite s"),
+    @NamedQuery(name = "SeasonTrapsite.findBySeasonTrapsiteId", query = "SELECT s FROM SeasonTrapsite s WHERE s.seasonTrapsiteId = :seasonTrapsiteId"),
+    @NamedQuery(name = "SeasonTrapsite.findBySeason", query = "SELECT s FROM SeasonTrapsite s WHERE s.season = :season"),
+    @NamedQuery(name = "SeasonTrapsite.findByUserId", query = "SELECT s FROM SeasonTrapsite s WHERE s.userId = :userId"),
+    @NamedQuery(name = "SeasonTrapsite.findByOwnerName", query = "SELECT s FROM SeasonTrapsite s WHERE s.ownerName = :ownerName"),
+    @NamedQuery(name = "SeasonTrapsite.findByOwnerPhone", query = "SELECT s FROM SeasonTrapsite s WHERE s.ownerPhone = :ownerPhone"),
+    @NamedQuery(name = "SeasonTrapsite.findByDateInstalled", query = "SELECT s FROM SeasonTrapsite s WHERE s.dateInstalled = :dateInstalled"),
+    @NamedQuery(name = "SeasonTrapsite.findByInstallationRemarks", query = "SELECT s FROM SeasonTrapsite s WHERE s.installationRemarks = :installationRemarks")})
+public class SeasonTrapsite implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+    @Id
+    @GeneratedValue(strategy = GenerationType.IDENTITY)
+    @Basic(optional = false)
+    @Column(name = "season_trapsite_id")
+    private Integer seasonTrapsiteId;
+    @Column(name = "season")
+    private Integer season;
+    @Column(name = "gis_geom", columnDefinition = "Geometry")
+    @JsonIgnore
+    private Geometry gisGeom;
+    @JoinColumn(name = "user_id", referencedColumnName = "user_id")
+    @ManyToOne(optional = false)
+    private VipsLogicUser userId;
+    @Size(max = 255)
+    @Column(name = "owner_name")
+    private String ownerName;
+    @Size(max = 31)
+    @Column(name = "owner_phone")
+    private String ownerPhone;
+    @Column(name = "date_installed")
+    @Temporal(TemporalType.DATE)
+    private Date dateInstalled;
+    @Size(max = 2147483647)
+    @Column(name = "installation_remarks")
+    private String installationRemarks;
+    @Column(name = "county_no")
+    private Integer countyNo;
+    @Column(name = "county_name")
+    private String countyName;
+    @Column(name = "municipality_no")
+    private Integer municipalityNo;
+    @Column(name = "municipality_name")
+    private String municipalityName;
+    @Column(name = "property_no")
+    private Integer propertyNo;
+    @Column(name = "property_section_no")
+    private Integer propertySectionNo;
+    @OneToMany(cascade = CascadeType.MERGE, mappedBy = "seasonTrapsite", fetch = FetchType.EAGER)
+    private Collection<TrapsiteRegistration> trapsiteRegistrationCollection;
+    @JoinColumn(name = "trapsite_type", referencedColumnName = "trapsite_type_id")
+    @ManyToOne
+    private TrapsiteType trapsiteType;
+
+    public SeasonTrapsite() {
+    }
+
+    public SeasonTrapsite(Integer seasonTrapsiteId) {
+        this.seasonTrapsiteId = seasonTrapsiteId;
+    }
+
+    public Integer getSeasonTrapsiteId() {
+        return seasonTrapsiteId;
+    }
+
+    public void setSeasonTrapsiteId(Integer seasonTrapsiteId) {
+        this.seasonTrapsiteId = seasonTrapsiteId;
+    }
+
+    public Integer getSeason() {
+        return season;
+    }
+
+    public void setSeason(Integer season) {
+        this.season = season;
+    }
+
+    public Geometry getGisGeom() {
+        return gisGeom;
+    }
+
+    public void setGisGeom(Geometry gisGeom) {
+        this.gisGeom = gisGeom;
+    }
+
+    public VipsLogicUser getUserId() {
+        return userId;
+    }
+
+    public void setUserId(VipsLogicUser userId) {
+        this.userId = userId;
+    }
+
+    public String getOwnerName() {
+        return ownerName;
+    }
+
+    public void setOwnerName(String ownerName) {
+        this.ownerName = ownerName;
+    }
+
+    public String getOwnerPhone() {
+        return ownerPhone;
+    }
+
+    public void setOwnerPhone(String ownerPhone) {
+        this.ownerPhone = ownerPhone;
+    }
+
+    public Date getDateInstalled() {
+        return dateInstalled;
+    }
+
+    public void setDateInstalled(Date dateInstalled) {
+        this.dateInstalled = dateInstalled;
+    }
+
+    public String getInstallationRemarks() {
+        return installationRemarks;
+    }
+
+    public void setInstallationRemarks(String installationRemarks) {
+        this.installationRemarks = installationRemarks;
+    }
+
+    @XmlTransient
+    public Collection<TrapsiteRegistration> getTrapsiteRegistrationCollection() {
+        return trapsiteRegistrationCollection;
+    }
+
+    public void setTrapsiteRegistrationCollection(Collection<TrapsiteRegistration> trapsiteRegistrationCollection) {
+        this.trapsiteRegistrationCollection = trapsiteRegistrationCollection;
+    }
+
+    public TrapsiteType getTrapsiteType() {
+        return trapsiteType;
+    }
+
+    public void setTrapsiteType(TrapsiteType trapsiteType) {
+        this.trapsiteType = trapsiteType;
+    }
+    
+    // Helper methods
+    
+    /** Returns a WGS84 projected longitude for the site
+     * 
+     */
+    @Transient
+    public Double getLongitude()
+    {
+        return this.getGisGeom() != null ? ((Point) this.getGisGeom()).getCoordinate().getX()
+                : 0.0;
+    }
+    
+    /** Returns a WGS84 projected latitude for the site
+     * 
+     */
+    @Transient
+    public Double getLatitude()
+    {
+        return this.getGisGeom() != null ? ((Point) this.getGisGeom()).getCoordinate().getY()
+                : 0.0;
+    }
+    
+    
+    /**
+     * @return the altitude for the site 
+     */
+    @Transient
+    public Double getAltitude()
+    {
+        return this.getGisGeom() != null ? ((Point) this.getGisGeom()).getCoordinate().getZ()
+                : 0.0;
+    }
+
+    @Override
+    public int hashCode() {
+        int hash = 0;
+        hash += (seasonTrapsiteId != null ? seasonTrapsiteId.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 SeasonTrapsite)) {
+            return false;
+        }
+        SeasonTrapsite other = (SeasonTrapsite) object;
+        if ((this.seasonTrapsiteId == null && other.seasonTrapsiteId != null) || (this.seasonTrapsiteId != null && !this.seasonTrapsiteId.equals(other.seasonTrapsiteId))) {
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    public String toString() {
+        return "no.nibio.vips.logic.modules.barkbeetle.SeasonTrapsite[ seasonTrapsiteId=" + seasonTrapsiteId + " ]";
+    }
+
+    /**
+     * @return the countyNo
+     */
+    public Integer getCountyNo() {
+        return countyNo;
+    }
+
+    /**
+     * @param countyNo the countyNo to set
+     */
+    public void setCountyNo(Integer countyNo) {
+        this.countyNo = countyNo;
+    }
+
+    /**
+     * @return the countyName
+     */
+    public String getCountyName() {
+        return countyName;
+    }
+
+    /**
+     * @param countyName the countyName to set
+     */
+    public void setCountyName(String countyName) {
+        this.countyName = countyName;
+    }
+
+    /**
+     * @return the municipalityNo
+     */
+    public Integer getMunicipalityNo() {
+        return municipalityNo;
+    }
+
+    /**
+     * @param municipalityNo the municipalityNo to set
+     */
+    public void setMunicipalityNo(Integer municipalityNo) {
+        this.municipalityNo = municipalityNo;
+    }
+
+    /**
+     * @return the propertyNo
+     */
+    public Integer getPropertyNo() {
+        return propertyNo;
+    }
+
+    /**
+     * @param propertyNo the propertyNo to set
+     */
+    public void setPropertyNo(Integer propertyNo) {
+        this.propertyNo = propertyNo;
+    }
+
+    /**
+     * @return the propertySectionNo
+     */
+    public Integer getPropertySectionNo() {
+        return propertySectionNo;
+    }
+
+    /**
+     * @param propertySectionNo the propertySectionNo to set
+     */
+    public void setPropertySectionNo(Integer propertySectionNo) {
+        this.propertySectionNo = propertySectionNo;
+    }
+
+    /**
+     * @return the municipalityName
+     */
+    public String getMunicipalityName() {
+        return municipalityName;
+    }
+
+    /**
+     * @param municipalityName the municipalityName to set
+     */
+    public void setMunicipalityName(String municipalityName) {
+        this.municipalityName = municipalityName;
+    }
+
+}
diff --git a/src/main/java/no/nibio/vips/logic/modules/barkbeetle/TrapsiteRegistration.java b/src/main/java/no/nibio/vips/logic/modules/barkbeetle/TrapsiteRegistration.java
new file mode 100644
index 0000000000000000000000000000000000000000..79f577f9dc78388bb6c9a4bd034003fd3d12a738
--- /dev/null
+++ b/src/main/java/no/nibio/vips/logic/modules/barkbeetle/TrapsiteRegistration.java
@@ -0,0 +1,235 @@
+/*
+ * Copyright (c) 2020 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.modules.barkbeetle;
+
+import java.io.Serializable;
+import java.util.Date;
+import javax.persistence.Column;
+import javax.persistence.EmbeddedId;
+import javax.persistence.Entity;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.NamedQueries;
+import javax.persistence.NamedQuery;
+import javax.persistence.Table;
+import javax.persistence.Temporal;
+import javax.persistence.TemporalType;
+import javax.validation.constraints.Size;
+import javax.xml.bind.annotation.XmlRootElement;
+
+/**
+ * @copyright 2020 <a href="http://www.nibio.no/">NIBIO</a>
+ * @author Tor-Einar Skog <tor-einar.skog@nibio.no>
+ */
+@Entity
+@Table(name = "trapsite_registration", schema="barkbeetle")
+@XmlRootElement
+@NamedQueries({
+    @NamedQuery(name = "TrapsiteRegistration.findAll", query = "SELECT t FROM TrapsiteRegistration t"),
+    @NamedQuery(name = "TrapsiteRegistration.findBySeasonTrapsiteId", query = "SELECT t FROM TrapsiteRegistration t WHERE t.trapsiteRegistrationPK.seasonTrapsiteId = :seasonTrapsiteId"),
+    @NamedQuery(name = "TrapsiteRegistration.findByWeek", query = "SELECT t FROM TrapsiteRegistration t WHERE t.trapsiteRegistrationPK.week = :week"),
+    @NamedQuery(name = "TrapsiteRegistration.findByTrap1", query = "SELECT t FROM TrapsiteRegistration t WHERE t.trap1 = :trap1"),
+    @NamedQuery(name = "TrapsiteRegistration.findByTrap2", query = "SELECT t FROM TrapsiteRegistration t WHERE t.trap2 = :trap2"),
+    @NamedQuery(name = "TrapsiteRegistration.findByTrap3", query = "SELECT t FROM TrapsiteRegistration t WHERE t.trap3 = :trap3"),
+    @NamedQuery(name = "TrapsiteRegistration.findByTrap4", query = "SELECT t FROM TrapsiteRegistration t WHERE t.trap4 = :trap4"),
+    @NamedQuery(name = "TrapsiteRegistration.findByTrap1Remarks", query = "SELECT t FROM TrapsiteRegistration t WHERE t.trap1Remarks = :trap1Remarks"),
+    @NamedQuery(name = "TrapsiteRegistration.findByTrap2Remarks", query = "SELECT t FROM TrapsiteRegistration t WHERE t.trap2Remarks = :trap2Remarks"),
+    @NamedQuery(name = "TrapsiteRegistration.findByTrap3Remarks", query = "SELECT t FROM TrapsiteRegistration t WHERE t.trap3Remarks = :trap3Remarks"),
+    @NamedQuery(name = "TrapsiteRegistration.findByTrap4Remarks", query = "SELECT t FROM TrapsiteRegistration t WHERE t.trap4Remarks = :trap4Remarks"),
+    @NamedQuery(name = "TrapsiteRegistration.findByRegistrationStatusTypeId", query = "SELECT t FROM TrapsiteRegistration t WHERE t.registrationStatusTypeId = :registrationStatusTypeId")})
+public class TrapsiteRegistration implements Serializable, Comparable {
+
+    private static final long serialVersionUID = 1L;
+    @EmbeddedId
+    protected TrapsiteRegistrationPK trapsiteRegistrationPK;
+    @Column(name = "date_registration")
+    @Temporal(TemporalType.DATE)
+    private Date dateRegistration;
+    @Column(name = "trap_1")
+    private Integer trap1;
+    @Column(name = "trap_2")
+    private Integer trap2;
+    @Column(name = "trap_3")
+    private Integer trap3;
+    @Column(name = "trap_4")
+    private Integer trap4;
+    @Size(max = 2147483647)
+    @Column(name = "trap_1_remarks")
+    private String trap1Remarks;
+    @Size(max = 2147483647)
+    @Column(name = "trap_2_remarks")
+    private String trap2Remarks;
+    @Size(max = 2147483647)
+    @Column(name = "trap_3_remarks")
+    private String trap3Remarks;
+    @Size(max = 2147483647)
+    @Column(name = "trap_4_remarks")
+    private String trap4Remarks;
+    @Column(name = "registration_status_type_id")
+    private Integer registrationStatusTypeId;
+    @JoinColumn(name = "season_trapsite_id", referencedColumnName = "season_trapsite_id", insertable = false, updatable = false)
+    @ManyToOne(optional = false)
+    private SeasonTrapsite seasonTrapsite;
+    
+    public TrapsiteRegistration() {
+    }
+
+    public TrapsiteRegistration(TrapsiteRegistrationPK trapsiteRegistrationPK) {
+        this.trapsiteRegistrationPK = trapsiteRegistrationPK;
+    }
+
+    public TrapsiteRegistration(int seasonTrapsiteId, int week) {
+        this.trapsiteRegistrationPK = new TrapsiteRegistrationPK(seasonTrapsiteId, week);
+    }
+
+    public TrapsiteRegistrationPK getTrapsiteRegistrationPK() {
+        return trapsiteRegistrationPK;
+    }
+
+    public void setTrapsiteRegistrationPK(TrapsiteRegistrationPK trapsiteRegistrationPK) {
+        this.trapsiteRegistrationPK = trapsiteRegistrationPK;
+    }
+
+    public Integer getTrap1() {
+        return trap1;
+    }
+
+    public void setTrap1(Integer trap1) {
+        this.trap1 = trap1;
+    }
+
+    public Integer getTrap2() {
+        return trap2;
+    }
+
+    public void setTrap2(Integer trap2) {
+        this.trap2 = trap2;
+    }
+
+    public Integer getTrap3() {
+        return trap3;
+    }
+
+    public void setTrap3(Integer trap3) {
+        this.trap3 = trap3;
+    }
+
+    public Integer getTrap4() {
+        return trap4;
+    }
+
+    public void setTrap4(Integer trap4) {
+        this.trap4 = trap4;
+    }
+
+    public String getTrap1Remarks() {
+        return trap1Remarks;
+    }
+
+    public void setTrap1Remarks(String trap1Remarks) {
+        this.trap1Remarks = trap1Remarks;
+    }
+
+    public String getTrap2Remarks() {
+        return trap2Remarks;
+    }
+
+    public void setTrap2Remarks(String trap2Remarks) {
+        this.trap2Remarks = trap2Remarks;
+    }
+
+    public String getTrap3Remarks() {
+        return trap3Remarks;
+    }
+
+    public void setTrap3Remarks(String trap3Remarks) {
+        this.trap3Remarks = trap3Remarks;
+    }
+
+    public String getTrap4Remarks() {
+        return trap4Remarks;
+    }
+
+    public void setTrap4Remarks(String trap4Remarks) {
+        this.trap4Remarks = trap4Remarks;
+    }
+
+    public Integer getRegistrationStatusTypeId() {
+        return registrationStatusTypeId;
+    }
+
+    public void setRegistrationStatusTypeId(Integer registrationStatusTypeId) {
+        this.registrationStatusTypeId = registrationStatusTypeId;
+    }
+
+    public SeasonTrapsite getSeasonTrapsite() {
+        return seasonTrapsite;
+    }
+
+    public void setSeasonTrapsite(SeasonTrapsite seasonTrapsite) {
+        this.seasonTrapsite = seasonTrapsite;
+    }
+
+    @Override
+    public int hashCode() {
+        int hash = 0;
+        hash += (trapsiteRegistrationPK != null ? trapsiteRegistrationPK.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 TrapsiteRegistration)) {
+            return false;
+        }
+        TrapsiteRegistration other = (TrapsiteRegistration) object;
+        if ((this.trapsiteRegistrationPK == null && other.trapsiteRegistrationPK != null) || (this.trapsiteRegistrationPK != null && !this.trapsiteRegistrationPK.equals(other.trapsiteRegistrationPK))) {
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    public String toString() {
+        return "no.nibio.vips.logic.modules.barkbeetle.TrapsiteRegistration[ trapsiteRegistrationPK=" + trapsiteRegistrationPK + " ]";
+    }
+
+    @Override
+    public int compareTo(Object t) {
+        TrapsiteRegistration other = (TrapsiteRegistration) t;
+        return this.getTrapsiteRegistrationPK().getWeek().compareTo(other.getTrapsiteRegistrationPK().getWeek());
+    }
+
+    /**
+     * @return the dateRegistration
+     */
+    public Date getDateRegistration() {
+        return dateRegistration;
+    }
+
+    /**
+     * @param dateRegistration the dateRegistration to set
+     */
+    public void setDateRegistration(Date dateRegistration) {
+        this.dateRegistration = dateRegistration;
+    }
+
+}
diff --git a/src/main/java/no/nibio/vips/logic/modules/barkbeetle/TrapsiteRegistrationPK.java b/src/main/java/no/nibio/vips/logic/modules/barkbeetle/TrapsiteRegistrationPK.java
new file mode 100644
index 0000000000000000000000000000000000000000..1466e4e101655a1ccf585f09fb20a07fcfad1e28
--- /dev/null
+++ b/src/main/java/no/nibio/vips/logic/modules/barkbeetle/TrapsiteRegistrationPK.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2020 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.modules.barkbeetle;
+
+import java.io.Serializable;
+import javax.persistence.Basic;
+import javax.persistence.Column;
+import javax.persistence.Embeddable;
+import javax.validation.constraints.NotNull;
+
+/**
+ * @copyright 2020 <a href="http://www.nibio.no/">NIBIO</a>
+ * @author Tor-Einar Skog <tor-einar.skog@nibio.no>
+ */
+@Embeddable
+public class TrapsiteRegistrationPK implements Serializable {
+
+    @Basic(optional = false)
+    @NotNull
+    @Column(name = "season_trapsite_id")
+    private int seasonTrapsiteId;
+    @Basic(optional = false)
+    @NotNull
+    @Column(name = "week")
+    private Integer week;
+
+    public TrapsiteRegistrationPK() {
+    }
+
+    public TrapsiteRegistrationPK(int seasonTrapsiteId, int week) {
+        this.seasonTrapsiteId = seasonTrapsiteId;
+        this.week = week;
+    }
+
+    public int getSeasonTrapsiteId() {
+        return seasonTrapsiteId;
+    }
+
+    public void setSeasonTrapsiteId(int seasonTrapsiteId) {
+        this.seasonTrapsiteId = seasonTrapsiteId;
+    }
+
+    public Integer getWeek() {
+        return week;
+    }
+
+    public void setWeek(Integer week) {
+        this.week = week;
+    }
+
+    @Override
+    public int hashCode() {
+        int hash = 0;
+        hash += (int) seasonTrapsiteId;
+        hash += (int) week;
+        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 TrapsiteRegistrationPK)) {
+            return false;
+        }
+        TrapsiteRegistrationPK other = (TrapsiteRegistrationPK) object;
+        if (this.seasonTrapsiteId != other.seasonTrapsiteId) {
+            return false;
+        }
+        if (this.week != other.week) {
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    public String toString() {
+        return "no.nibio.vips.logic.modules.barkbeetle.TrapsiteRegistrationPK[ seasonTrapsiteId=" + seasonTrapsiteId + ", week=" + week + " ]";
+    }
+
+}
diff --git a/src/main/java/no/nibio/vips/logic/modules/barkbeetle/TrapsiteType.java b/src/main/java/no/nibio/vips/logic/modules/barkbeetle/TrapsiteType.java
new file mode 100644
index 0000000000000000000000000000000000000000..8f918e1aa8e51e77c12c6ae67f9c4e8d27323cab
--- /dev/null
+++ b/src/main/java/no/nibio/vips/logic/modules/barkbeetle/TrapsiteType.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2020 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.modules.barkbeetle;
+
+import java.io.Serializable;
+import javax.persistence.Basic;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.NamedQueries;
+import javax.persistence.NamedQuery;
+import javax.persistence.Table;
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Size;
+import javax.xml.bind.annotation.XmlRootElement;
+
+/**
+ * @copyright 2020 <a href="http://www.nibio.no/">NIBIO</a>
+ * @author Tor-Einar Skog <tor-einar.skog@nibio.no>
+ */
+@Entity
+@Table(name = "trapsite_type", schema="barkbeetle")
+@XmlRootElement
+@NamedQueries({
+    @NamedQuery(name = "TrapsiteType.findAll", query = "SELECT l FROM TrapsiteType l"),
+    @NamedQuery(name = "TrapsiteType.findByLocationTypeId", query = "SELECT l FROM TrapsiteType l WHERE l.trapsiteTypeId = :trapsiteTypeId"),
+    @NamedQuery(name = "TrapsiteType.findByTitle", query = "SELECT l FROM TrapsiteType l WHERE l.title = :title"),
+    @NamedQuery(name = "TrapsiteType.findByDescription", query = "SELECT l FROM TrapsiteType l WHERE l.description = :description")})
+public class TrapsiteType implements Serializable {
+    
+    public static Integer TRAPSITE_TYPE_STANDARD = 1;
+    public static Integer TRAPSITE_TYPE_EXTENDED = 2;
+
+
+    private static final long serialVersionUID = 1L;
+    @Id
+    @Basic(optional = false)
+    @NotNull
+    @Column(name = "trapsite_type_id")
+    private Integer trapsiteTypeId;
+    @Size(max = 255)
+    @Column(name = "title")
+    private String title;
+    @Size(max = 2147483647)
+    @Column(name = "description")
+    private String description;
+    
+
+    public TrapsiteType() {
+    }
+
+    public TrapsiteType(Integer trapsiteTypeId) {
+        this.trapsiteTypeId = trapsiteTypeId;
+    }
+
+    public Integer getTrapsiteTypeId() {
+        return trapsiteTypeId;
+    }
+
+    public void setTrapsiteTypeId(Integer trapsiteTypeId) {
+        this.trapsiteTypeId = trapsiteTypeId;
+    }
+
+    public String getTitle() {
+        return title;
+    }
+
+    public void setTitle(String title) {
+        this.title = title;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+    @Override
+    public int hashCode() {
+        int hash = 0;
+        hash += (trapsiteTypeId != null ? trapsiteTypeId.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 TrapsiteType)) {
+            return false;
+        }
+        TrapsiteType other = (TrapsiteType) object;
+        if ((this.trapsiteTypeId == null && other.trapsiteTypeId != null) || (this.trapsiteTypeId != null && !this.trapsiteTypeId.equals(other.trapsiteTypeId))) {
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    public String toString() {
+        return "no.nibio.vips.logic.modules.barkbeetle.TrapsiteType[ trapsiteTypeId=" + trapsiteTypeId + " ]";
+    }
+
+}
diff --git a/src/main/java/no/nibio/vips/logic/util/SessionControllerGetter.java b/src/main/java/no/nibio/vips/logic/util/SessionControllerGetter.java
index 24e1dbae7d66b25d304290a0fb5a3c6b90817135..b214f0cbff880db06ca5c8111b1179fea24d66ba 100755
--- a/src/main/java/no/nibio/vips/logic/util/SessionControllerGetter.java
+++ b/src/main/java/no/nibio/vips/logic/util/SessionControllerGetter.java
@@ -170,7 +170,7 @@ public class SessionControllerGetter {
         }
     }
     
-    private static String getJndiPath(Class obj)
+    public static String getJndiPath(Class obj)
     {
         String retVal = SessionControllerGetter.JNDI_PATH + obj.getSimpleName();
         //System.out.println("JNDI-path=" + retVal);
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 8b63096e97cb3168c8d55e7907eef47c67932a9d..a608e4036b48ef84105742e76b124967debb4d66 100755
--- a/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts.properties
+++ b/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts.properties
@@ -497,3 +497,5 @@ sprayingDate04=Spraying Date 04
 fieldIsRequired=The field is required
 fields=Fields
 farms=Farms
+vipsLogicRole_9=Bark beetle registrator
+vipsLogicRole_10=Bark beetle administrator
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 09e80271881045b91bbdc3692cd1520a75cb8170..a4683f50a3673daae52419396f0804ffd85c0cfc 100755
--- a/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_bs.properties
+++ b/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_bs.properties
@@ -497,3 +497,5 @@ sprayingDate03=Spraying Date 03
 sprayingDate04=Spraying Date 04
 fields=Fields
 farms=Farms
+vipsLogicRole_9=Bark beetle registrator
+vipsLogicRole_10=Bark beetle administrator
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 1c160f31ef5052cfe47352603c76aa0db99a9573..3b6ba0b6b92b13789dd3f0fed896f624738f73f4 100755
--- a/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_hr.properties
+++ b/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_hr.properties
@@ -496,3 +496,5 @@ sprayingDate03=Spraying Date 03
 sprayingDate04=Spraying Date 04
 fields=Fields
 farms=Farms
+vipsLogicRole_9=Bark beetle registrator
+vipsLogicRole_10=Bark beetle administrator
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 9744b7f391d76485bc5a1fe06f95c45c036ba6ae..2e5adcaf11beeb6d1fb93cba3f563f35330b1237 100755
--- a/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_nb.properties
+++ b/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_nb.properties
@@ -497,3 +497,5 @@ sprayingDate03=Dato for spr\u00f8yting #3
 sprayingDate04=Dato for spr\u00f8yting #4
 fields=Felt
 farms=G\u00e5rder
+vipsLogicRole_9=Barkbilleregistrator
+vipsLogicRole_10=Barkbilleadministrator
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 a411235554614487d51b4d670225ac1fae83219f..e92c357ab4a0ec5ad5b8aded9dba67fb22cb41c9 100755
--- a/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_sr.properties
+++ b/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_sr.properties
@@ -497,3 +497,5 @@ sprayingDate03=Spraying Date 03
 sprayingDate04=Spraying Date 04
 fields=Fields
 farms=Farms
+vipsLogicRole_9=Bark beetle registrator
+vipsLogicRole_10=Bark beetle administrator
diff --git a/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_zh_CN.properties b/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_zh_CN.properties
index 3e21faf58a800dd6e9c1768e4636fe3b0fc49ba6..77f36e196ac554e06292c8bb18648ff670fc5bd2 100755
--- a/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_zh_CN.properties
+++ b/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_zh_CN.properties
@@ -494,3 +494,5 @@ sprayingDate03=Spraying Date 03
 sprayingDate04=Spraying Date 04
 fields=Fields
 farms=Farms
+vipsLogicRole_9=Bark beetle registrator
+vipsLogicRole_10=Bark beetle administrator
diff --git a/src/main/setup/jboss-ds.xml b/src/main/setup/jboss-ds.xml
index 67a462f0d033a6d4c6b3dc511adb594f3c41eca1..a9dbfeb095668b8e061a93908db614859b2a9d45 100755
--- a/src/main/setup/jboss-ds.xml
+++ b/src/main/setup/jboss-ds.xml
@@ -1,5 +1,15 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <datasources>
+      <local-tx-datasource>
+    <jndi-name>barkbeetle</jndi-name>
+    <connection-url>jdbc:postgresql://localhost:5432/vipslogic?searchpath=barkbeetle</connection-url>
+    <driver-class>org.postgresql.Driver</driver-class>
+    <user-name>vipslogic</user-name>
+    <password>VIPS123</password>
+    <min-pool-size>5</min-pool-size>
+    <max-pool-size>20</max-pool-size>
+    <idle-timeout-minutes>5</idle-timeout-minutes>
+  </local-tx-datasource>
   <local-tx-datasource>
     <jndi-name>VIPSLogic</jndi-name>
     <connection-url>jdbc:postgresql://localhost:5432/vipslogic</connection-url>
@@ -20,6 +30,7 @@
     <max-pool-size>20</max-pool-size>
     <idle-timeout-minutes>5</idle-timeout-minutes>
   </local-tx-datasource>
+
   <local-tx-datasource>
     <jndi-name>wheatleafb</jndi-name>
     <connection-url>jdbc:postgresql://localhost:5432/vipslogic?searchpath=wheatleafb</connection-url>
diff --git a/src/main/webapp/WEB-INF/web.xml b/src/main/webapp/WEB-INF/web.xml
index 9bd85db2c3822cdeb262ba5a2ff5828c2ecbe903..e3e75ee8aa921d35060651278dea16c16ba78711 100755
--- a/src/main/webapp/WEB-INF/web.xml
+++ b/src/main/webapp/WEB-INF/web.xml
@@ -87,6 +87,10 @@
         <servlet-name>OrganizationController</servlet-name>
         <servlet-class>no.nibio.vips.logic.controller.servlet.OrganizationController</servlet-class>
     </servlet>
+    <servlet>
+        <servlet-name>BarkbeetleController</servlet-name>
+        <servlet-class>no.nibio.vips.logic.modules.barkbeetle.BarkbeetleController</servlet-class>
+    </servlet>
     <servlet-mapping>
         <servlet-name>PointOfInterestController</servlet-name>
         <url-pattern>/poi/*</url-pattern>
@@ -161,6 +165,10 @@
         <servlet-name>OrganizationController</servlet-name>
         <url-pattern>/organization</url-pattern>
     </servlet-mapping>
+    <servlet-mapping>
+        <servlet-name>BarkbeetleController</servlet-name>
+        <url-pattern>/barkbeetle</url-pattern>
+    </servlet-mapping>
     <welcome-file-list>
         <welcome-file>index.html</welcome-file>
     </welcome-file-list>
diff --git a/src/main/webapp/formdefinitions/modules/barkbeetle/seasonTrapsiteForm.json b/src/main/webapp/formdefinitions/modules/barkbeetle/seasonTrapsiteForm.json
new file mode 100644
index 0000000000000000000000000000000000000000..8b2db7bbc53ea5e0ab963d60858fb9900a19747b
--- /dev/null
+++ b/src/main/webapp/formdefinitions/modules/barkbeetle/seasonTrapsiteForm.json
@@ -0,0 +1,108 @@
+{
+    "_licenseNote": [
+        "Copyright (c) 2020 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/>. "
+    ],
+    "_comment" : "Structure of the seasonTrapsiteForm and how to validate it",
+    "fields": [
+        {
+            "name" : "seasonTrapsiteId",
+            "dataType" : "INTEGER",
+            "required" : true
+        },
+        {
+            "name" : "season",
+            "dataType" : "INTEGER",
+            "required" : true
+        },
+        {
+            "name" : "trapsiteTypeId",
+            "dataType" : "INTEGER",
+            "fieldType" : "SELECT_SINGLE",
+            "required" : true,
+            "nullValue" : "-1"
+        },
+        {
+            "name" : "userId",
+            "dataType" : "INTEGER",
+            "fieldType" : "SELECT_SINGLE",
+            "required" : true,
+            "nullValue" : "-1"
+        },
+        {
+            "name" : "gisGeom",
+            "dataType" : "POINT_WGS84",
+            "required" : true
+        },
+        {
+            "name" : "altitude",
+            "dataType" : "DOUBLE",
+            "required" : false
+        },
+        {
+            "name" : "ownerName",
+            "dataType" : "STRING",
+            "required" : true
+        },
+        {
+            "name" : "ownerPhone",
+            "dataType" : "STRING",
+            "required" : false
+        },
+        {
+            "name" : "dateInstalled",
+            "dataType" : "DATE",
+            "required" : true
+        },
+        {
+            "name" : "installationRemarks",
+            "dataType" : "STRING",
+            "required" : false
+        },
+        {
+            "name" : "countyNo",
+            "dataType" : "INTEGER",
+            "required" : false
+        },
+        {
+            "name" : "countyName",
+            "dataType" : "STRING",
+            "required" : false
+        },
+        {
+            "name" : "municipalityNo",
+            "dataType" : "INTEGER",
+            "required" : false
+        },
+        {
+            "name" : "municipalityName",
+            "dataType" : "STRING",
+            "required" : false
+        },
+        {
+            "name" : "propertyNo",
+            "dataType" : "INTEGER",
+            "required" : false
+        },
+        {
+            "name" : "propertySectionNo",
+            "dataType" : "INTEGER",
+            "required" : false
+        }
+        
+        
+    ]
+}
diff --git a/src/main/webapp/templates/modules/barkbeetle/barkbeetleSeasonTrapsiteForm.ftl b/src/main/webapp/templates/modules/barkbeetle/barkbeetleSeasonTrapsiteForm.ftl
new file mode 100644
index 0000000000000000000000000000000000000000..42b489ce921bcef610cb716454f606fdafb836c6
--- /dev/null
+++ b/src/main/webapp/templates/modules/barkbeetle/barkbeetleSeasonTrapsiteForm.ftl
@@ -0,0 +1,161 @@
+<#--
+    Copyright (c) 2020 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/>.
+	
+--><#include "../../master.ftl">
+<#macro page_head>
+	<title>Barkbilleregistrering: Rediger fellelokalitet for ${season}</title>
+</#macro>
+<#macro custom_js>
+	<script type="text/javascript" src="/js/resourcebundle.js"></script>
+	<script src="/js/validateForm.js"></script>
+	<script src="//code.jquery.com/ui/1.10.3/jquery-ui.min.js"></script>
+	<script type="text/javascript" src="/js/3rdparty/modernizr_custom.js"></script>
+	<script type="text/javascript">
+		// Make sure that there is a date picker present for HTML5 
+		// date input fields
+		if (!Modernizr.inputtypes.date) {
+		    $('input[type=date]').datepicker({ dateFormat: 'yy-mm-dd' });
+		}
+		// Load main form definition (for validation)
+		loadFormDefinition("seasonTrapsiteForm","/formdefinitions/modules/barkbeetle/");
+		function updateMarkerPosition(){
+			console.info("TODO: updateMarkerPosition");
+		}
+	</script>
+</#macro>
+<#macro custom_css>
+	<link href="//code.jquery.com/ui/1.10.3/themes/redmond/jquery-ui.css" rel="stylesheet" />
+</#macro>
+<#macro page_contents>
+	<#if messageKey?has_content>
+		<div class="alert alert-success">Data ble lagret ${.now}</div>
+	</#if>
+	<h1><#if seasonTrapsite.seasonTrapsiteId?has_content>Rediger<#else>Ny</#if> fellelokalitet</h1>
+	<p>
+		<a href="/barkbeetle?season=${season}" class="btn btn-default back" role="button">${i18nBundle.back}</a>
+	</p>
+<div class="singleBlockContainer">
+	<div class="row">
+	<div class="col-md-8">
+<#assign formId = "seasonTrapsiteForm">
+	<form id="${formId}" role="form" action="/barkbeetle?action=seasonTrapsiteFormSubmit" method="POST" onsubmit="return validateForm(this);"">
+		<input type="hidden" name="seasonTrapsiteId" value="${seasonTrapsite.seasonTrapsiteId!"-1"}"/>
+		<div class="form-group">
+	    <label for="trapsiteType">Type fellelokalitet</label>
+	    <select class="form-control" name="trapsiteTypeId" onblur="validateField(this);">
+			<#list seasonTrapsiteTypes as trapsite>
+				<option value="${trapsite.trapsiteTypeId}"
+				<#if (seasonTrapsite.trapsiteType?has_content && seasonTrapsite.trapsiteType.trapsiteTypeId == trapsite.trapsiteTypeId) 
+				||  (!(seasonTrapsite.trapsiteType?has_content) && trapsite.trapsiteTypeId == 1)>
+				selected="selected"</#if>
+				>${trapsite.title}</option>
+			</#list>
+		
+	     </select>
+	</div>
+	<div class="form-group">
+			<label for="season">Sesong</label>
+			<input type="text" class="form-control" name="season" placeholder="Sesong" value="${season}" onblur="validateField(this);"/>
+			<span class="help-block" id="${formId}_season_validation"></span>
+		  </div>
+		<div class="form-group">
+			<label for="gisGeom">Lokalitet (<a href="http://en.wikipedia.org/wiki/World_Geodetic_System#A_new_World_Geodetic_System:_WGS_84" target="new">WGS84</a>: lengdegrad, breddegrad. <a href="https://coordinates-converter.com/" target="new">Her kan du konvertere automatisk.</a>)</label>
+			<input type="text" class="form-control" id="gisGeom" name="gisGeom" placeholder="Lokalitet" value="${(seasonTrapsite.longitude?c)!""},${(seasonTrapsite.latitude?c)!""}" onblur="validateField(this);" onchange="if(validateField(this)){updateMarkerPosition();}" />
+			<span class="help-block" id="${formId}_location_validation"></span>
+		  </div>
+		  <div class="form-group">
+			<label for="altitude">Høyde over havet (m)</label>
+			<input type="number" class="form-control" name="altitude" placeholder="Høyde over havet" value="${(seasonTrapsite.altitude?c)!""}" onblur="validateField(this);"/>
+			<span class="help-block" id="${formId}_altitude_validation"></span>
+		  </div>
+		  <div class="form-group">
+			<label for="countyNo">Fylkesnr</label>
+			<input type="number" class="form-control" name="countyNo" placeholder="Fylkesnr" value="${(seasonTrapsite.countyNo)!""}" onblur="validateField(this);"/>
+			<span class="help-block" id="${formId}_countyNo_validation"></span>
+		  </div>
+		  <div class="form-group">
+			<label for="countyName">Fylkesnavn</label>
+			<input type="text" class="form-control" name="countyName" placeholder="Fylkesnavn" value="${(seasonTrapsite.countyName)!""}" onblur="validateField(this);"/>
+			<span class="help-block" id="${formId}_countyName_validation"></span>
+		  </div>
+		  <div class="form-group">
+			<label for="municipalityNo">Kommunenr</label>
+			<input type="number" class="form-control" name="municipalityNo" placeholder="Kommunenr" value="${(seasonTrapsite.municipalityNo)!""}" onblur="validateField(this);"/>
+			<span class="help-block" id="${formId}_municipalityNo_validation"></span>
+		  </div>
+		  <div class="form-group">
+			<label for="municipalityName">Kommunenavn</label>
+			<input type="text" class="form-control" name="municipalityName" placeholder="Kommunenavn" value="${(seasonTrapsite.municipalityName)!""}" onblur="validateField(this);"/>
+			<span class="help-block" id="${formId}_municipalityName_validation"></span>
+		  </div>
+		  <div class="form-group">
+			<label for="propertyNo">Gårdsnr</label>
+			<input type="number" class="form-control" name="propertyNo" placeholder="Gårdsnr" value="${(seasonTrapsite.propertyNo)!""}" onblur="validateField(this);"/>
+			<span class="help-block" id="${formId}_propertyNo_validation"></span>
+		  </div>
+		  <div class="form-group">
+			<label for="propertySectionNo">Bruksnr</label>
+			<input type="number" class="form-control" name="propertySectionNo" placeholder="Bruksnr" value="${(seasonTrapsite.propertySectionNo)!""}" onblur="validateField(this);"/>
+			<span class="help-block" id="${formId}_propertySectionNo_validation"></span>
+		  </div>
+		  <div class="form-group">
+			<label for="ownerName">Eier av lokalitet</label>
+			<input type="text" class="form-control" name="ownerName" placeholder="Eier av lokalitet" value="${(seasonTrapsite.ownerName)!""}" onblur="validateField(this);"/>
+			<span class="help-block" id="${formId}_ownerName_validation"></span>
+		  </div>
+		  <div class="form-group">
+			<label for="ownerName">Tlf til eier av lokalitet</label>
+			<input type="text" class="form-control" name="ownerPhone" placeholder="Tlf til eier av lokalitet" value="${(seasonTrapsite.ownerPhone)!""}" onblur="validateField(this);"/>
+			<span class="help-block" id="${formId}_ownerPhone_validation"></span>
+		  </div>
+		  <div class="form-group">
+			<label for="userId">Registrant</label>
+			<select class="form-control" name="userId">
+			<option value="-1">-- Velg registrant --</option>
+			<#list trapsiteRegistrators as registrator>
+				<option value="${registrator.userId}"
+				<#if seasonTrapsite.userId?has_content>
+					<#if seasonTrapsite.userId.userId == registrator.userId>
+					selected="selected"
+					</#if>
+				<#elseif user.userId == registrator.userId>
+					selected="selected"
+				</#if>
+				>${registrator.lastName}, ${registrator.firstName}</option>
+			</#list>
+			</select>
+		  </div>
+		  <div class="form-group">
+				<label for="dateInstalled">Dato oppmontering</label>
+				<input type="date" class="form-control" name="dateInstalled" placeholder="Dato oppmontering" value="${(seasonTrapsite.dateInstalled?date)!""}" onblur="validateField(this);" />
+				<span class="help-block" id="${formId}_dateInstalled_validation"></span>
+		  </div>
+		  <div class="form-group">
+				<label for="installationRemarks">Kommentar fellemontering</label>
+				<textarea class="form-control" name="installationRemarks" placeholder="Kommentar fellemontering" onblur="validateField(this);" >${(seasonTrapsite.installationRemarks)!""}</textarea>
+				<span class="help-block" id="${formId}_installationRemarks_validation"></span>
+		  </div>
+		  <button type="submit" class="btn btn-default">Lagre</button>
+	</form>
+	</div>
+	<div class="col-md-4">
+	Kartet kommer her!
+	</div>
+	</div>
+</div>
+</#macro>
+<@page_html/>
\ No newline at end of file
diff --git a/src/main/webapp/templates/modules/barkbeetle/barkbeetleSeasonTrapsiteList.ftl b/src/main/webapp/templates/modules/barkbeetle/barkbeetleSeasonTrapsiteList.ftl
new file mode 100644
index 0000000000000000000000000000000000000000..4d8951094ef0d98245311ab3c7b8c5b4738fb7ac
--- /dev/null
+++ b/src/main/webapp/templates/modules/barkbeetle/barkbeetleSeasonTrapsiteList.ftl
@@ -0,0 +1,69 @@
+<#--
+    Copyright (c) 2020 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/>.
+	
+--><#include "../../master.ftl">
+<#macro page_head>
+	<title>Barkbilleregistrering: Fellelokaliteter for sesongen ${season}</title>
+</#macro>
+<#macro page_contents>
+<h1>Fellelokaliteter for sesongen ${season}</h1>
+<#if userIsAdmin || user.userId == site.userId.userId>
+<p>
+	<a href="/barkbeetle?action=editSeasonTrapsite&season=${season}" class="btn btn-default" role="button">${i18nBundle.addNew}</a>
+</p>
+</#if>
+<div class="singleBlockContainer">
+	<div class="row">
+	<div class="col-md-12">
+	<h1>Kartet kommer her!</h1>
+	</div>
+	</div>
+	<div class="row">
+	<table class="table table-striped">
+		<thead>
+			<th>Fylke</th>
+			<th>Kommune</th>
+			<th>Gårdsnr/bruksnr</th>
+			<th>Høyde o.h.</th>
+			<th>Eier</th>
+			<th>Registrant</th>
+			<th></th>
+			<th></th>
+		</thead>
+		<tbody>
+		<#list seasonTrapsites as site>
+			<tr>
+				<td>${site.countyName!""}</td>
+				<td>${site.municipalityName!""}</td>
+				<td>${site.propertyNo!""}/${site.propertySectionNo!""}</td>
+				<td>${site.altitude!""}</td>
+				<td>${site.ownerName!""}</td>
+				<td>${site.userId.firstName} ${site.userId.lastName}</td>
+				<#if userIsAdmin || user.userId == site.userId.userId>
+				<td><a href="/barkbeetle?action=editSeasonTrapsite&season=${season}&seasonTrapsiteId=${site.seasonTrapsiteId}" class="btn btn-default" role="button">Endre lokalitetsinfo</a></td>
+				<td><a href="/barkbeetle?action=registerData&seasonTrapsiteId=${site.seasonTrapsiteId}" class="btn btn-default" role="button">Registrer data</a></td>
+				<#else>
+				<td colspan="2"></td>
+				</#if>
+			</tr>
+		</#list>
+		</tbody>
+	</table>
+	</div>
+</div>
+</#macro>
+<@page_html/>
\ No newline at end of file
diff --git a/src/main/webapp/templates/modules/barkbeetle/barkbeetleTrapsiteRegistrationForm.ftl b/src/main/webapp/templates/modules/barkbeetle/barkbeetleTrapsiteRegistrationForm.ftl
new file mode 100644
index 0000000000000000000000000000000000000000..b74d81823633f9d59d8438102c1147666c3f10ca
--- /dev/null
+++ b/src/main/webapp/templates/modules/barkbeetle/barkbeetleTrapsiteRegistrationForm.ftl
@@ -0,0 +1,142 @@
+<#--
+    Copyright (c) 2020 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/>.
+	
+--><#include "../../master.ftl">
+<#macro page_head>
+	<title>Barkbilleregistrering: Registrer data for lokalitet X, sesong ${seasonTrapsite.season}</title>
+</#macro>
+<#macro page_contents>
+	<#if messageKey?has_content>
+		<div class="alert alert-success">Data ble lagret ${.now}</div>
+	</#if>
+	<h1>Registrer data for lokalitet X, sesong ${seasonTrapsite.season}</h1>
+	<p>
+		<a href="/barkbeetle?action=editSeasonTrapsite&season=${seasonTrapsite.season}&seasonTrapsiteId=${seasonTrapsite.seasonTrapsiteId}" class="btn btn-default back" role="button">${i18nBundle.back}</a>
+	</p>
+	<div class="singleBlockContainer">
+		<div class="row">
+		<form id="trapsiteRegistrationForm" action="/barkbeetle?action=trapsiteRegistrationFormSubmit" method="post">
+		<input type="hidden" name="seasonTrapsiteId" value="${seasonTrapsite.seasonTrapsiteId}"/>
+		<table class="table table-striped">
+			<thead>
+				<th></th>
+				<th></th>
+				<th colspan="2">BEKAFelle 1</th>
+				<th colspan="2">BEKAFelle 2</th>
+				<th colspan="2">BEKAFelle 3</th>
+				<th colspan="2">BEKAFelle 4</th>
+				<th></th>
+				<th></th>
+				<th></th>
+				<th></th>
+			</thead>
+			<thead>
+				<th>Uke</th>
+				<th>Dato</th>
+				<th>ml</th>
+				<th>antall</th>
+				<th>ml</th>
+				<th>antall</th>
+				<th>ml</th>
+				<th>antall</th>
+				<th>ml</th>
+				<th>antall</th>
+				<th>Status</th>
+			</thead>
+			
+			<tbody>
+			<#list trapsiteRegistrations as reg>
+				<tr>
+					<td rowspan="2">${reg.trapsiteRegistrationPK.week}</td>
+					<td rowspan="2"><input class="form-control" type="date" name="${reg.trapsiteRegistrationPK.week}_dateRegistration" value="${reg.dateRegistration!""}"<#if reg.trapsiteRegistrationPK.week gt currentWeek> disabled="disabled"<#else> required="required"</#if>/></td>
+					<td><input class="form-control" type="number" name="${reg.trapsiteRegistrationPK.week}_trap1_ml" onblur="setCalculatedAmount(this);" value=""<#if reg.trapsiteRegistrationPK.week gt currentWeek> disabled="disabled"</#if>/></td>
+					<td><input class="form-control" type="text" name="${reg.trapsiteRegistrationPK.week}_trap1" value="${reg.trap1!"M"}"<#if reg.trapsiteRegistrationPK.week gt currentWeek> disabled="disabled"</#if>/></td>
+					<td><input class="form-control" type="number" name="${reg.trapsiteRegistrationPK.week}_trap2_ml" onblur="setCalculatedAmount(this);" value=""<#if reg.trapsiteRegistrationPK.week gt currentWeek> disabled="disabled"</#if>/></td>
+					<td><input class="form-control" type="text" name="${reg.trapsiteRegistrationPK.week}_trap2" value="${reg.trap2!"M"}"<#if reg.trapsiteRegistrationPK.week gt currentWeek> disabled="disabled"</#if>/></td>
+					<td><input class="form-control" type="number" name="${reg.trapsiteRegistrationPK.week}_trap3_ml" onblur="setCalculatedAmount(this);" value=""<#if reg.trapsiteRegistrationPK.week gt currentWeek> disabled="disabled"</#if>/></td>
+					<td><input class="form-control" type="text" name="${reg.trapsiteRegistrationPK.week}_trap3" value="${reg.trap3!"M"}"<#if reg.trapsiteRegistrationPK.week gt currentWeek> disabled="disabled"</#if>/></td>
+					<td><input class="form-control" type="number" name="${reg.trapsiteRegistrationPK.week}_trap4_ml" onblur="setCalculatedAmount(this);" value=""<#if reg.trapsiteRegistrationPK.week gt currentWeek> disabled="disabled"</#if>/></td>
+					<td><input class="form-control" type="text" name="${reg.trapsiteRegistrationPK.week}_trap4" value="${reg.trap4!"M"}"<#if reg.trapsiteRegistrationPK.week gt currentWeek> disabled="disabled"</#if>/></td>
+					
+					<td rowspan="2"><#if reg.dateRegistration?has_content>
+						<select class="form-control status_${reg.registrationStatusTypeId}" name="${reg.trapsiteRegistrationPK.week}_registrationStatusTypeId" onchange="this.className='form-control status_' + this.options[this.selectedIndex].value;">
+						<#list registrationStatusTypes as registrationStatusType>
+							<option class="status_${registrationStatusType.registrationStatusTypeId}" value="${registrationStatusType.registrationStatusTypeId}"
+							<#if reg.registrationStatusTypeId?has_content && reg.registrationStatusTypeId==registrationStatusType.registrationStatusTypeId>selected="selected"</#if>
+							>${registrationStatusType.title}</option>
+						</#list>
+						</select>
+					</#if></td>
+				</tr>
+				<tr>
+					<td colspan="2"><input class="form-control" type="text" name="${reg.trapsiteRegistrationPK.week}_trap1Remarks" placeholder="Kommentar felle 1" value="${reg.trap1Remarks!""}"<#if reg.trapsiteRegistrationPK.week gt currentWeek> disabled="disabled"</#if>/></td>
+					<td colspan="2"><input class="form-control" type="text" name="${reg.trapsiteRegistrationPK.week}_trap2Remarks" placeholder="Kommentar felle 2" value="${reg.trap2Remarks!""}"<#if reg.trapsiteRegistrationPK.week gt currentWeek> disabled="disabled"</#if>/></td>
+					<td colspan="2"><input class="form-control" type="text" name="${reg.trapsiteRegistrationPK.week}_trap3Remarks" placeholder="Kommentar felle 3" value="${reg.trap3Remarks!""}"<#if reg.trapsiteRegistrationPK.week gt currentWeek> disabled="disabled"</#if>/></td>
+					<td colspan="2"><input class="form-control" type="text" name="${reg.trapsiteRegistrationPK.week}_trap4Remarks" placeholder="Kommentar felle 4" value="${reg.trap4Remarks!""}"<#if reg.trapsiteRegistrationPK.week gt currentWeek> disabled="disabled"</#if>/></td>
+
+				</tr>
+			</#list>
+			</tbody>
+		</table>
+		<p>
+			<button type="submit" class="btn btn-default">Lagre</button>
+		</p>
+		</form>
+		</div>
+	</div>
+</#macro>
+<#macro custom_js>
+<script type="text/javascript" src="/js/resourcebundle.js"></script>
+<script src="//code.jquery.com/ui/1.10.3/jquery-ui.min.js"></script>
+<script type="text/javascript" src="/js/3rdparty/modernizr_custom.js"></script>
+<script type="text/javascript">
+		var theForm = document.getElementById("trapsiteRegistrationForm");
+		// Make sure that there is a date picker present for HTML5 
+		// date input fields
+		if (!Modernizr.inputtypes.date) {
+		    $('input[type=date]').datepicker({ dateFormat: 'yy-mm-dd' });
+		}
+		
+		function setCalculatedAmount(sourceField)
+		{
+
+			var volumeValue = parseFloat(sourceField.value);
+			if(!isNaN(volumeValue))
+			{
+				theForm[sourceField.name.substring(0,sourceField.name.indexOf("_ml"))].value = volumeValue * 50;
+			}
+		}
+		
+</script>
+</#macro>
+<#macro custom_css>
+	<link href="//code.jquery.com/ui/1.10.3/themes/redmond/jquery-ui.css" rel="stylesheet" />
+	<style type="text/css">
+		select option[value="1"], select.status_1 {
+			background-color: #ffe066 !important;
+		}
+		select option[value="2"], select.status_2 {
+			background-color: #1aff88 !important;
+		}
+		select option[value="3"], select.status_3 {
+			background-color: #ff6e66 !important;
+		}
+
+			
+	</style>
+</#macro>
+<@page_html/>
\ No newline at end of file