Arne Diekmann 8 rokov pred
rodič
commit
ebf38e7c4f
56 zmenil súbory, kde vykonal 2050 pridanie a 144 odobranie
  1. 0 10
      GreenTree.Nachtragsmanagement.Data/AppendixObjectContext.cs
  2. 33 0
      GreenTree.Nachtragsmanagement.Services/Deviation/DeviationService.cs
  3. 18 0
      GreenTree.Nachtragsmanagement.Services/Deviation/IDeviationService.cs
  4. 2 0
      GreenTree.Nachtragsmanagement.Web.Framework/ApplicationContext.cs
  5. 23 0
      GreenTree.Nachtragsmanagement.Web/App_Start/FunctionConfig.cs
  6. 15 1
      GreenTree.Nachtragsmanagement.Web/App_Start/RouteConfig.cs
  7. BIN
      GreenTree.Nachtragsmanagement.Web/Content/Images/add-16-contrast.png
  8. BIN
      GreenTree.Nachtragsmanagement.Web/Content/Images/add-16.png
  9. BIN
      GreenTree.Nachtragsmanagement.Web/Content/Images/add-24-contrast.png
  10. BIN
      GreenTree.Nachtragsmanagement.Web/Content/Images/add-24.png
  11. BIN
      GreenTree.Nachtragsmanagement.Web/Content/Images/add-32-contrast.png
  12. BIN
      GreenTree.Nachtragsmanagement.Web/Content/Images/add-32.png
  13. BIN
      GreenTree.Nachtragsmanagement.Web/Content/Images/function-Deviation-Claims-32-contrast.png
  14. BIN
      GreenTree.Nachtragsmanagement.Web/Content/Images/function-Deviation-Claims-32.png
  15. 7 1
      GreenTree.Nachtragsmanagement.Web/Content/devex.css
  16. 24 0
      GreenTree.Nachtragsmanagement.Web/Content/function.css
  17. 277 0
      GreenTree.Nachtragsmanagement.Web/Controllers/DataCallbackController.cs
  18. 278 15
      GreenTree.Nachtragsmanagement.Web/Controllers/DeviationController.cs
  19. 7 0
      GreenTree.Nachtragsmanagement.Web/Global.asax.cs
  20. 35 1
      GreenTree.Nachtragsmanagement.Web/GreenTree.Nachtragsmanagement.Web.csproj
  21. 13 0
      GreenTree.Nachtragsmanagement.Web/Models/Admin/User/IRequireRoleDataModel.cs
  22. 13 0
      GreenTree.Nachtragsmanagement.Web/Models/Appendix/IRequireAppendixDataModel.cs
  23. 7 5
      GreenTree.Nachtragsmanagement.Web/Models/Deviation/DeviationDataModel.cs
  24. 40 0
      GreenTree.Nachtragsmanagement.Web/Models/Deviation/DisturbanceDataModel.cs
  25. 13 0
      GreenTree.Nachtragsmanagement.Web/Models/Deviation/IRequireDisturbanceDataModel.cs
  26. 13 0
      GreenTree.Nachtragsmanagement.Web/Models/Deviation/IRequireKindDataModel.cs
  27. 13 0
      GreenTree.Nachtragsmanagement.Web/Models/Deviation/IRequireStatusDataModel.cs
  28. 40 0
      GreenTree.Nachtragsmanagement.Web/Models/Deviation/KindDataModel.cs
  29. 40 0
      GreenTree.Nachtragsmanagement.Web/Models/Deviation/StatusDataModel.cs
  30. 28 0
      GreenTree.Nachtragsmanagement.Web/Models/Global/EmptyIRequireDataModel.cs
  31. 22 0
      GreenTree.Nachtragsmanagement.Web/Properties/PublishProfiles/greentreestudios.pubxml
  32. 3 0
      GreenTree.Nachtragsmanagement.Web/Validation/AppendixValidatorFactory.cs
  33. 21 0
      GreenTree.Nachtragsmanagement.Web/Validation/Deviation/DisturbanceDataModelValidator.cs
  34. 21 0
      GreenTree.Nachtragsmanagement.Web/Validation/Deviation/KindDataModelValidator.cs
  35. 21 0
      GreenTree.Nachtragsmanagement.Web/Validation/Deviation/StatusDataModelValidator.cs
  36. 40 44
      GreenTree.Nachtragsmanagement.Web/Views/Admin/Roles/View.cshtml
  37. 23 0
      GreenTree.Nachtragsmanagement.Web/Views/Admin/Roles/_RoleEditPartial.cshtml
  38. 0 23
      GreenTree.Nachtragsmanagement.Web/Views/Admin/Users/View.cshtml
  39. 23 0
      GreenTree.Nachtragsmanagement.Web/Views/Admin/Users/_UserEditPartial.cshtml
  40. 268 0
      GreenTree.Nachtragsmanagement.Web/Views/Deviations/Claims.cshtml
  41. 3 3
      GreenTree.Nachtragsmanagement.Web/Views/Deviations/View.cshtml
  42. 227 35
      GreenTree.Nachtragsmanagement.Web/Views/Deviations/_DeviationEditPartial.cshtml
  43. 13 3
      GreenTree.Nachtragsmanagement.Web/Views/Deviations/_DeviationGridPartial.cshtml
  44. 80 0
      GreenTree.Nachtragsmanagement.Web/Views/Deviations/_DisturbanceEditPartial.cshtml
  45. 29 0
      GreenTree.Nachtragsmanagement.Web/Views/Deviations/_DisturbanceListPartial.cshtml
  46. 80 0
      GreenTree.Nachtragsmanagement.Web/Views/Deviations/_KindEditPartial.cshtml
  47. 29 0
      GreenTree.Nachtragsmanagement.Web/Views/Deviations/_KindListPartial.cshtml
  48. 80 0
      GreenTree.Nachtragsmanagement.Web/Views/Deviations/_StatusEditPartial.cshtml
  49. 30 0
      GreenTree.Nachtragsmanagement.Web/Views/Deviations/_StatusListPartial.cshtml
  50. 16 1
      GreenTree.Nachtragsmanagement.Web/Views/Home/Index.cshtml
  51. 16 0
      GreenTree.Nachtragsmanagement.Web/Views/Shared/DataEditorTemplates/_AppendicesComboBox.cshtml
  52. 16 0
      GreenTree.Nachtragsmanagement.Web/Views/Shared/DataEditorTemplates/_DisturbancesComboBox.cshtml
  53. 16 0
      GreenTree.Nachtragsmanagement.Web/Views/Shared/DataEditorTemplates/_KindsComboBox.cshtml
  54. 16 0
      GreenTree.Nachtragsmanagement.Web/Views/Shared/DataEditorTemplates/_RolesComboBox.cshtml
  55. 16 0
      GreenTree.Nachtragsmanagement.Web/Views/Shared/DataEditorTemplates/_StatusesComboBox.cshtml
  56. 2 2
      GreenTree.Nachtragsmanagement.Web/Views/Shared/_PopupButtonPanel.cshtml

+ 0 - 10
GreenTree.Nachtragsmanagement.Data/AppendixObjectContext.cs

@@ -252,16 +252,6 @@ namespace GreenTree.Nachtragsmanagement.Data
 
             SaveChanges();
 
-            r1.Functions.Add(Get<Function>().FirstOrDefault(f => f.Name == "Administration"));
-            r1.Functions.Add(Get<Function>().FirstOrDefault(f => f.Name == "Administration-Users"));
-            r1.Functions.Add(Get<Function>().FirstOrDefault(f => f.Name == "Administration-Users-Edit"));
-            r1.Functions.Add(Get<Function>().FirstOrDefault(f => f.Name == "Administration-Roles"));
-            r1.Functions.Add(Get<Function>().FirstOrDefault(f => f.Name == "Administration-Roles-Edit"));
-            r1.Functions.Add(Get<Function>().FirstOrDefault(f => f.Name == "Administration-Plugins"));
-            r1.Functions.Add(Get<Function>().FirstOrDefault(f => f.Name == "Deviation"));
-            r1.Functions.Add(Get<Function>().FirstOrDefault(f => f.Name == "Deviation-Deviaitons"));
-            r1.Functions.Add(Get<Function>().FirstOrDefault(f => f.Name == "Deviation-Deviaitons-Edit"));
-
             var u1 = Get<User>().Add(new User
             {
                 Forename = "Arne",

+ 33 - 0
GreenTree.Nachtragsmanagement.Services/Deviation/DeviationService.cs

@@ -135,6 +135,17 @@ namespace GreenTree.Nachtragsmanagement.Services.Deviation
                 .ToList();
         }
 
+        /// <summary>
+        /// Gets all deviations to the specified with the specified disturbance id
+        /// </summary>
+        /// <param name="id">Disturbance identifier.</param>
+        public IList<Core.Domain.Deviation.Deviation> GetDeviationsByDisturbance(int id)
+        {
+            return _deviationRepository.Table
+                .Where(d => d.DisturbanceId == id)
+                .ToList();
+        }
+
         /// <summary>
         /// Insert a deviation
         /// </summary>
@@ -193,6 +204,17 @@ namespace GreenTree.Nachtragsmanagement.Services.Deviation
                 .ToList();
         }
 
+        /// <summary>
+        /// Gets all deviations to the specified with the specified kind id
+        /// </summary>
+        /// <param name="id">Kind identifier.</param>
+        public IList<Core.Domain.Deviation.Deviation> GetDeviationsByKind(int id)
+        {
+            return _deviationRepository.Table
+                .Where(d => d.KindId == id)
+                .ToList();
+        }
+
         /// <summary>
         /// Insert a kind
         /// </summary>
@@ -251,6 +273,17 @@ namespace GreenTree.Nachtragsmanagement.Services.Deviation
                 .ToList();
         }
 
+        /// <summary>
+        /// Gets all deviations to the specified with the specified status id
+        /// </summary>
+        /// <param name="id">Status identifier.</param>
+        public IList<Core.Domain.Deviation.Deviation> GetDeviationsByStatus(int id)
+        {
+            return _deviationRepository.Table
+                .Where(d => d.StatusId == id)
+                .ToList();
+        }
+
         /// <summary>
         /// Insert a status
         /// </summary>

+ 18 - 0
GreenTree.Nachtragsmanagement.Services/Deviation/IDeviationService.cs

@@ -71,6 +71,12 @@ namespace GreenTree.Nachtragsmanagement.Services.Deviation
         /// </summary>
         IList<Disturbance> GetDisturbancesByIds(int[] ids);
 
+        /// <summary>
+        /// Gets all deviations to the specified with the specified disturbance id
+        /// </summary>
+        /// <param name="id">Disturbance identifier.</param>
+        IList<Core.Domain.Deviation.Deviation> GetDeviationsByDisturbance(int id);
+
         /// <summary>
         /// Insert a disturbance
         /// </summary>
@@ -109,6 +115,12 @@ namespace GreenTree.Nachtragsmanagement.Services.Deviation
         /// </summary>
         IList<Kind> GetKindsByIds(int[] ids);
 
+        /// <summary>
+        /// Gets all deviations to the specified with the specified kind id
+        /// </summary>
+        /// <param name="id">Kind identifier.</param>
+        IList<Core.Domain.Deviation.Deviation> GetDeviationsByKind(int id);
+
         /// <summary>
         /// Insert a kind
         /// </summary>
@@ -147,6 +159,12 @@ namespace GreenTree.Nachtragsmanagement.Services.Deviation
         /// </summary>
         IList<Status> GetStatusesByIds(int[] ids);
 
+        /// <summary>
+        /// Gets all deviations to the specified with the specified status id
+        /// </summary>
+        /// <param name="id">Status identifier.</param>
+        IList<Core.Domain.Deviation.Deviation> GetDeviationsByStatus(int id);
+
         /// <summary>
         /// Insert a status
         /// </summary>

+ 2 - 0
GreenTree.Nachtragsmanagement.Web.Framework/ApplicationContext.cs

@@ -25,6 +25,7 @@ using GreenTree.Nachtragsmanagement.Core.Plugins;
 using GreenTree.Nachtragsmanagement.Web.Framework.Mvc.Routes;
 using System.Web.Routing;
 using GreenTree.Nachtragsmanagement.Core.Authentication;
+using GreenTree.Nachtragsmanagement.Services.Appendix;
 
 namespace GreenTree.Nachtragsmanagement.Web.Framework
 {
@@ -108,6 +109,7 @@ namespace GreenTree.Nachtragsmanagement.Web.Framework
             builder.RegisterType<AuthenticationService>().As<IAuthenticationService>();
             builder.RegisterType<SiteService>().As<ISiteService>();
             builder.RegisterType<DeviationService>().As<IDeviationService>();
+            builder.RegisterType<AppendixService>().As<IAppendixService>();
             builder.RegisterType<MiscService>().As<IMiscService>();
             builder.RegisterType<PluginFinder>().As<IPluginFinder>();
             builder.RegisterType<WebHelper>().As<IWebHelper>();

+ 23 - 0
GreenTree.Nachtragsmanagement.Web/App_Start/FunctionConfig.cs

@@ -165,6 +165,29 @@ namespace GreenTree.Nachtragsmanagement.Web.App_Start
                     IsMenuMember = false,
                     Plugin = "System"
                 },
+                new Function
+                {
+                    Name = "Deviation-Claims",
+                    Description = "Stammdaten",
+                    ImageUrl = "~/Content/Images/function-Deviation-Claims-32.png",
+                    GroupName = "Deviation",
+                    RouteName = "GreenTree.Nachtragsmanagement.Web.Deviation.Claims",
+                    IsMenuMember = true,
+                    Plugin = "System",
+                    BaseWidth = 1000,
+                    MinWidth = 600,
+                    BaseHeight = 500,
+                    MinHeight = 350,
+                    AllowMaximize = true
+                },
+                new Function
+                {
+                    Name = "Deviation-Claims-Edit",
+                    Description = "Stammdaten editieren",
+                    GroupName = "Deviation-Claims",
+                    IsMenuMember = false,
+                    Plugin = "System"
+                },
             };
         }
     }

+ 15 - 1
GreenTree.Nachtragsmanagement.Web/App_Start/RouteConfig.cs

@@ -64,7 +64,7 @@ namespace GreenTree.Nachtragsmanagement.Web
 
             routes.MapRoute(
                 "GreenTree.Nachtragsmanagement.Web.Deviation.Deviations",
-                "admin/viewdeviations",
+                "deviation/viewdeviations",
                new
                {
                    controller = "Deviation",
@@ -75,6 +75,20 @@ namespace GreenTree.Nachtragsmanagement.Web
                    "GreenTree.Nachtragsmanagement.Web.Controllers"
                }
             );
+
+            routes.MapRoute(
+                "GreenTree.Nachtragsmanagement.Web.Deviation.Claims",
+                "deviation/viewclaims",
+               new
+               {
+                   controller = "Deviation",
+                   action = "ViewClaims"
+               },
+               new[]
+               {
+                   "GreenTree.Nachtragsmanagement.Web.Controllers"
+               }
+            );
         }
     }
 }

BIN
GreenTree.Nachtragsmanagement.Web/Content/Images/add-16-contrast.png


BIN
GreenTree.Nachtragsmanagement.Web/Content/Images/add-16.png


BIN
GreenTree.Nachtragsmanagement.Web/Content/Images/add-24-contrast.png


BIN
GreenTree.Nachtragsmanagement.Web/Content/Images/add-24.png


BIN
GreenTree.Nachtragsmanagement.Web/Content/Images/add-32-contrast.png


BIN
GreenTree.Nachtragsmanagement.Web/Content/Images/add-32.png


BIN
GreenTree.Nachtragsmanagement.Web/Content/Images/function-Deviation-Claims-32-contrast.png


BIN
GreenTree.Nachtragsmanagement.Web/Content/Images/function-Deviation-Claims-32.png


+ 7 - 1
GreenTree.Nachtragsmanagement.Web/Content/devex.css

@@ -25,4 +25,10 @@
 .devExAllowDrag { cursor: move; }
 
 .devExDisplayHidden { display: none; }
-.devExDisplayTableRow { display: table-row; }
+.devExDisplayTableRow { display: table-row; }
+
+.devExListItemControlContainer { float: right; }
+.devExListItemControlContainer > a { color: #009688; text-decoration: none; }
+.devExListItemControlContainer > a:hover { text-decoration: underline; }
+.dxeListBoxItemSelected_Material .devExListItemControlContainer > a { color: white; text-decoration: none; }
+.dxeListBoxItemSelected_Material .devExListItemControlContainer > a:hover { text-decoration: underline; }

+ 24 - 0
GreenTree.Nachtragsmanagement.Web/Content/function.css

@@ -6,6 +6,30 @@
     padding: 0 12px 18px;
 }
 
+.listHeader {
+    width: auto;
+    font-size: 14px;
+    color: white;
+    background-color: #009688;
+    padding: 4px 6px;
+    overflow: auto;
+}
+
+.listHeader > span {
+    float: left;
+    line-height: 24px;
+}
+
+.listHeader > img {
+    float: right;
+    cursor: pointer;
+}
+
+.deleteValidation {
+    margin-top: 8px;
+    color: red;
+}
+
 /* Label and validation customization */
 
 

+ 277 - 0
GreenTree.Nachtragsmanagement.Web/Controllers/DataCallbackController.cs

@@ -0,0 +1,277 @@
+using DevExpress.Web.Mvc;
+using GreenTree.Nachtragsmanagement.Services.Appendix;
+using GreenTree.Nachtragsmanagement.Services.Deviation;
+using GreenTree.Nachtragsmanagement.Services.User;
+using GreenTree.Nachtragsmanagement.Web.Models.Appendix;
+using GreenTree.Nachtragsmanagement.Web.Models.Deviation;
+using Newtonsoft.Json;
+using Newtonsoft.Json.Linq;
+using Newtonsoft.Json.Serialization;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using System.Web;
+using System.Web.Mvc;
+
+namespace GreenTree.Nachtragsmanagement.Web.Controllers
+{
+    public class DataCallbackController : Controller
+    {
+        private readonly IUserService _userService;
+        private readonly IDeviationService _deviationService;
+        private readonly IAppendixService _appendixService;
+
+        private readonly JsonSerializerSettings _serializerSettings = new JsonSerializerSettings
+        {
+            Error = (serializer, ex) => { ex.ErrorContext.Handled = true; }
+        };
+
+        public DataCallbackController(
+            IUserService userService,
+            IDeviationService deviationService,
+            IAppendixService appendixService)
+        {
+            _userService = userService;
+            _deviationService = deviationService;
+            _appendixService = appendixService;
+        }
+
+        #region User
+
+        /// <summary>
+        /// Returns a DevExpress ComboBox for all roles 
+        /// </summary>
+        /// <param name="settingsKey">Current comboBox settings key.</param>
+        /// <param name="model">JSON-serialized model.</param>
+        /// <param name="type">Type of model.</param>
+        public ActionResult RolesComboBox(string settingsKey, string model = null, string type = null)
+        {
+            return RolesComboBoxExcluded(settingsKey, model, type, null);
+        }
+
+        /// <summary>
+        /// Returns a DevExpress ComboBox for all roles 
+        /// </summary>
+        /// <param name="settingsKey">Current comboBox settings key.</param>
+        /// <param name="model">JSON-serialized model.</param>
+        /// <param name="type">Type of model.</param>
+        /// <param name="excludedIdsJson">Ids of the excluded roles.</param>
+        public ActionResult RolesComboBoxExcluded(string settingsKey, string model, string type, int[] excludedIds)
+        {
+            var allRoles = _userService.GetAllRoles();
+
+            if (excludedIds != null)
+            {
+                foreach (var excludedId in excludedIds)
+                {
+                    var item = allRoles
+                        .FirstOrDefault(s => s.Id == excludedId);
+
+                    allRoles.Remove(item);
+                }
+            }
+
+            ViewData["AllRoles"] = allRoles;
+            ViewData["RolesComboBoxSettings"] = settingsKey;
+
+            if (model != null && type != null)
+            {
+                var modelType = Type.GetType(type);
+                var modelObject = JsonConvert.DeserializeObject(model, modelType, _serializerSettings);
+
+                return PartialView("~/Views/Shared/DataEditorTemplates/_RolesComboBox.cshtml", modelObject);
+            }
+
+            return PartialView("~/Views/Shared/DataEditorTemplates/_RolesComboBox.cshtml", null);
+        }
+
+        #endregion
+
+        #region Appendix
+
+        /// <summary>
+        /// Returns a DevExpress ComboBox for all appendices 
+        /// </summary>
+        /// <param name="settingsKey">Current comboBox settings key.</param>
+        /// <param name="model">JSON-serialized model.</param>
+        /// <param name="type">Type of model.</param>
+        public ActionResult AppendicesComboBox(string settingsKey, string model = null, string type = null)
+        {
+            var allAppendices = _appendixService.GetAllAppendices();
+
+            ViewData["AllAppendices"] = allAppendices;
+            ViewData["AppendicesComboBoxSettings"] = settingsKey;
+
+            if (model != null && type != null)
+            {
+                var modelType = Type.GetType(type);
+                var modelObject = JsonConvert.DeserializeObject(model, modelType, _serializerSettings);
+
+                return PartialView("~/Views/Shared/DataEditorTemplates/_AppendicesComboBox.cshtml", modelObject);
+            }
+
+            return PartialView("~/Views/Shared/DataEditorTemplates/_AppendicesComboBox.cshtml", null);
+        }
+
+        #endregion
+
+        #region Deviations
+
+        /// <summary>
+        /// Returns a DevExpress ComboBox for all statuses 
+        /// </summary>
+        /// <param name="settingsKey">Current comboBox settings key.</param>
+        /// <param name="model">JSON-serialized model.</param>
+        /// <param name="type">Type of model.</param>
+        public ActionResult StatusesComboBox(string settingsKey, string model, string type)
+        {
+            return StatusesComboBoxExcluded(settingsKey, model, type, null);
+        }
+
+        /// <summary>
+        /// Returns a DevExpress ComboBox for all statuses 
+        /// </summary>
+        /// <param name="settingsKey">Current comboBox settings key.</param>
+        /// <param name="model">JSON-serialized model.</param>
+        /// <param name="type">Type of model.</param>
+        /// <param name="excludedIdsJson">Ids of the excluded statuses.</param>
+        public ActionResult StatusesComboBoxExcluded(string settingsKey, string model, string type, int[] excludedIds)
+        {
+            var allStatuses = _deviationService.GetAllStatuses();
+
+            if (excludedIds != null)
+            {
+                foreach (var excludedId in excludedIds)
+                {
+                    var item = allStatuses
+                        .FirstOrDefault(s => s.Id == excludedId);
+
+                    allStatuses.Remove(item);
+                }
+            }
+
+            ViewData["AllStatuses"] = allStatuses;
+            ViewData["StatusesComboBoxSettings"] = settingsKey;
+
+            if (model != null && type != null)
+            {
+                var modelType = Type.GetType(type);
+                var modelObject = JsonConvert.DeserializeObject(model, modelType, _serializerSettings);
+
+                return PartialView("~/Views/Shared/DataEditorTemplates/_StatusesComboBox.cshtml", modelObject);
+            }
+
+            return PartialView("~/Views/Shared/DataEditorTemplates/_StatusesComboBox.cshtml", null);
+        }
+
+        /// <summary>
+        /// Returns a DevExpress ComboBox for all disturbances 
+        /// </summary>
+        /// <param name="settingsKey">Current comboBox settings key.</param>
+        /// <param name="model">JSON-serialized model.</param>
+        /// <param name="type">Type of model.</param>
+        public ActionResult DisturbancesComboBox(string settingsKey, string model, string type)
+        {
+            return DisturbancesComboBoxExcluded(settingsKey, model, type, null);
+        }
+
+        /// <summary>
+        /// Returns a DevExpress ComboBox for all disturbances 
+        /// </summary>
+        /// <param name="settingsKey">Current comboBox settings key.</param>
+        /// <param name="model">JSON-serialized model.</param>
+        /// <param name="type">Type of model.</param>
+        /// <param name="excludedIdsJson">Ids of the excluded disturbances.</param>
+        public ActionResult DisturbancesComboBoxExcluded(string settingsKey, string model, string type, int[] excludedIds)
+        {
+            var allDisturbances = _deviationService.GetAllDisturbances();
+
+            if (excludedIds != null)
+            {
+                foreach (var excludedId in excludedIds)
+                {
+                    var item = allDisturbances
+                        .FirstOrDefault(s => s.Id == excludedId);
+
+                    allDisturbances.Remove(item);
+                }
+            }
+
+            ViewData["AllDisturbances"] = allDisturbances;
+            ViewData["DisturbancesComboBoxSettings"] = settingsKey;
+
+            if (model != null && type != null)
+            {
+                var modelType = Type.GetType(type);
+                var modelObject = JsonConvert.DeserializeObject(model, modelType, _serializerSettings);
+
+                return PartialView("~/Views/Shared/DataEditorTemplates/_DisturbancesComboBox.cshtml", modelObject);
+            }
+
+            return PartialView("~/Views/Shared/DataEditorTemplates/_DisturbancesComboBox.cshtml", null);
+        }
+
+        /// <summary>
+        /// Returns a DevExpress ComboBox for all kinds 
+        /// </summary>
+        /// <param name="settingsKey">Current comboBox settings key.</param>
+        /// <param name="model">JSON-serialized model.</param>
+        /// <param name="type">Type of model.</param>
+        public ActionResult KindsComboBox(string settingsKey, string model, string type)
+        {
+            var allKinds = _deviationService.GetAllKinds();
+
+            ViewData["AllKinds"] = allKinds;
+            ViewData["KindsComboBoxSettings"] = settingsKey;
+
+            if (model != null && type != null)
+            {
+                var modelType = Type.GetType(type);
+                var modelObject = JsonConvert.DeserializeObject(model, modelType, _serializerSettings);
+
+                return PartialView("~/Views/Shared/DataEditorTemplates/_KindsComboBox.cshtml", modelObject);
+            }
+
+            return PartialView("~/Views/Shared/DataEditorTemplates/_KindsComboBox.cshtml", null);
+        }
+
+        /// <summary>
+        /// Returns a DevExpress ComboBox for all kinds 
+        /// </summary>
+        /// <param name="settingsKey">Current comboBox settings key.</param>
+        /// <param name="model">JSON-serialized model.</param>
+        /// <param name="type">Type of model.</param>
+        /// <param name="excludedIdsJson">Ids of the excluded kinds.</param>
+        public ActionResult KindsComboBoxExcluded(string settingsKey, string model, string type, int[] excludedIds)
+        {
+            var allKinds = _deviationService.GetAllKinds();
+
+            if (excludedIds != null)
+            {
+                foreach (var excludedId in excludedIds)
+                {
+                    var item = allKinds
+                        .FirstOrDefault(s => s.Id == excludedId);
+
+                    allKinds.Remove(item);
+                }
+            }
+
+            ViewData["AllKinds"] = allKinds;
+            ViewData["KindsComboBoxSettings"] = settingsKey;
+
+            if (model != null && type != null)
+            {
+                var modelType = Type.GetType(type);
+                var modelObject = JsonConvert.DeserializeObject(model, modelType, _serializerSettings);
+
+                return PartialView("~/Views/Shared/DataEditorTemplates/_KindsComboBox.cshtml", modelObject);
+            }
+
+            return PartialView("~/Views/Shared/DataEditorTemplates/_KindsComboBox.cshtml", null);
+        }
+
+        #endregion
+    }
+}

+ 278 - 15
GreenTree.Nachtragsmanagement.Web/Controllers/DeviationController.cs

@@ -23,6 +23,7 @@ namespace GreenTree.Nachtragsmanagement.Web.Controllers
             IAppendixService appendixService)
         {
             _deviationService = deviationService;
+            _appendixService = appendixService;
 
             ViewData["AllAppendices"] = _appendixService.GetAllAppendices();
             ViewData["AllStatuses"] = _deviationService.GetAllStatuses();
@@ -30,6 +31,8 @@ namespace GreenTree.Nachtragsmanagement.Web.Controllers
             ViewData["AllKinds"] = _deviationService.GetAllKinds();
         }
 
+        #region Deviations
+
         /// <summary>
         /// Basic deviation view function
         /// </summary>
@@ -41,7 +44,7 @@ namespace GreenTree.Nachtragsmanagement.Web.Controllers
                 .Select(u => DeviationDataModel.FromDeviation(u, false))
                 .ToList();
 
-            return View("~/Views/Admin/Deviations/View.cshtml", deviationModels);
+            return View("~/Views/Deviations/View.cshtml", deviationModels);
         }
 
         /// <summary>
@@ -77,7 +80,7 @@ namespace GreenTree.Nachtragsmanagement.Web.Controllers
                 .Select(u => DeviationDataModel.FromDeviation(u, false))
                 .ToList();
 
-            return PartialView("~/Views/Admin/Deviations/_DeviationGridPartial.cshtml", deviationModels);
+            return PartialView("~/Views/Deviations/_DeviationGridPartial.cshtml", deviationModels);
         }
 
         /// <summary>
@@ -89,7 +92,7 @@ namespace GreenTree.Nachtragsmanagement.Web.Controllers
             var deviation = _deviationService.GetDeviationById(id);
             var deviationModel = DeviationDataModel.FromDeviation(deviation, true);
 
-            return PartialView("~/Views/Admin/Deviations/_DeviationEditPartial.cshtml", deviationModel);
+            return PartialView("~/Views/Deviations/_DeviationEditPartial.cshtml", deviationModel);
         }
 
         /// <summary>
@@ -100,18 +103,7 @@ namespace GreenTree.Nachtragsmanagement.Web.Controllers
         public ActionResult EditDeviation(DeviationDataModel deviationModel)
         {
             if (!ModelState.IsValid)
-            {
-                //deviationModel.AppendixDescription = ((IList<Appendix>)ViewData["AllAppendices"])
-                //    .First(d => d.Id == deviationModel.AppendixId).CustomNumber;
-                //deviationModel.StatusDescription = ((IList<Status>)ViewData["AllStatuses"])
-                //    .First(d => d.Id == deviationModel.StatusId).Description;
-                //deviationModel.DisturbanceDescription = ((IList<Disturbance>)ViewData["AllDisturbances"])
-                //    .First(d => d.Id == deviationModel.DisturbanceId).Description;
-                //deviationModel.KindDescription = ((IList<Kind>)ViewData["AllKinds"])
-                //    .First(d => d.Id == deviationModel.KindId).Description;
-
-                return PartialView("~/Views/Admin/Deviations/_DeviationEditPartial.cshtml", deviationModel);
-            }
+                return PartialView("~/Views/Deviations/_DeviationEditPartial.cshtml", deviationModel);
 
             if (deviationModel.Id == -1)
             {
@@ -158,5 +150,276 @@ namespace GreenTree.Nachtragsmanagement.Web.Controllers
                 Data = "success"
             };
         }
+
+        #endregion
+
+        #region Claims
+
+        /// <summary>
+        /// Basic claim view function
+        /// </summary>
+        [FunctionAuthorize(true, "Deviation-Claims")]
+        public ActionResult ViewClaims()
+        {
+            return View("~/Views/Deviations/Claims.cshtml");
+        }
+
+        /// <summary>
+        /// Get JSON data of specific claim
+        /// </summary>
+        /// <param name="claimType">Claim type.</param>
+        /// <param name="id">Claim id.</param>
+        public ActionResult GetClaim(string claimType, int id = -1)
+        {
+            switch (claimType.ToLower())
+            {
+                case "status":
+                    var status = _deviationService.GetStatusById(id);
+                    if (status == null)
+                        return new JsonResult { Data = "notFound", JsonRequestBehavior = JsonRequestBehavior.AllowGet };
+                    else
+                        return new JsonResult {
+                            Data = JsonConvert.SerializeObject(status),
+                            JsonRequestBehavior = JsonRequestBehavior.AllowGet
+                        };
+                case "disturbance":
+                    var disturbance = _deviationService.GetDisturbanceById(id);
+                    if (disturbance == null)
+                        return new JsonResult { Data = "notFound", JsonRequestBehavior = JsonRequestBehavior.AllowGet };
+                    else
+                        return new JsonResult
+                        {
+                            Data = JsonConvert.SerializeObject(disturbance),
+                            JsonRequestBehavior = JsonRequestBehavior.AllowGet
+                        };
+                case "kind":
+                    var kind = _deviationService.GetKindById(id);
+                    if (kind == null)
+                        return new JsonResult { Data = "notFound", JsonRequestBehavior = JsonRequestBehavior.AllowGet };
+                    else
+                        return new JsonResult
+                        {
+                            Data = JsonConvert.SerializeObject(kind),
+                            JsonRequestBehavior = JsonRequestBehavior.AllowGet
+                        };
+                default:
+                    return new JsonResult { Data = "unknownClaimType", JsonRequestBehavior = JsonRequestBehavior.AllowGet };
+            }
+        }
+
+        /// <summary>
+        /// Callback result for claim grid
+        /// </summary>
+        /// <param name="claimType">Claim type.</param>
+        public ActionResult PartialClaims(string claimType)
+        {
+            switch (claimType.ToLower())
+            {
+                case "status":
+                    return PartialView("~/Views/Deviations/_StatusListPartial.cshtml", ViewData["AllStatuses"]);
+                case "disturbance":
+                    return PartialView("~/Views/Deviations/_DisturbanceListPartial.cshtml", ViewData["AllDisturbances"]);
+                case "kind":
+                    return PartialView("~/Views/Deviations/_KindListPartial.cshtml", ViewData["AllKinds"]);
+                default:
+                    return new EmptyResult();
+            }
+        }
+
+        /// <summary>
+        /// Partial edit for editing of existing or for new claim
+        /// </summary>
+        /// <param name="claimType">Claim type.</param>
+        /// <param name="id">Id for existing claim, otherweise -1.</param>
+        public ActionResult EditClaim(string claimType = "", int id = -1)
+        {
+            switch (claimType.ToLower())
+            {
+                case "status":
+                    var status = _deviationService.GetStatusById(id);
+                    var statusModel = StatusDataModel.FromStatus(status, true);
+
+                    return PartialView("~/Views/Deviations/_StatusEditPartial.cshtml", statusModel);
+                case "disturbance":
+                    var disturbance = _deviationService.GetDisturbanceById(id);
+                    var disturbanceModel = DisturbanceDataModel.FromDisturbance(disturbance, true);
+
+                    return PartialView("~/Views/Deviations/_DisturbanceEditPartial.cshtml", disturbanceModel);
+                case "kind":
+                    var kind = _deviationService.GetKindById(id);
+                    var kindModel = KindDataModel.FromKind(kind, true);
+
+                    return PartialView("~/Views/Deviations/_KindEditPartial.cshtml", kindModel);
+                default:
+                    return new EmptyResult();
+            }
+        }
+
+        /// <summary>
+        /// Partial edit result if ModelState is valid, otherwise simple JSON result for success
+        /// </summary>
+        /// <param name="statusModel">Status model to be saved.</param>
+        [HttpPost, ValidateInput(false)]
+        public ActionResult EditStatus(StatusDataModel statusModel)
+        {
+            if (!ModelState.IsValid)
+                return PartialView("~/Views/Deviations/_StatusEditPartial.cshtml", statusModel);
+
+            if (statusModel.Id == -1)
+            {
+                var claim = statusModel.ToStatus();
+
+                _deviationService.InsertStatus(claim);
+            }
+            else
+            {
+                var status = _deviationService.GetStatusById(statusModel.Id);
+
+                status.Description = statusModel.Description;
+
+                _deviationService.UpdateStatus(status);
+            }
+
+            return new JsonResult
+            {
+                Data = "success"
+            };
+        }
+
+        /// <summary>
+        /// Partial edit result if ModelState is valid, otherwise simple JSON result for success
+        /// </summary>
+        /// <param name="disturbanceModel">Disturbance model to be saved.</param>
+        [HttpPost, ValidateInput(false)]
+        public ActionResult EditDisturbance(DisturbanceDataModel disturbanceModel)
+        {
+            if (!ModelState.IsValid)
+                return PartialView("~/Views/Deviations/_DisturbanceEditPartial.cshtml", disturbanceModel);
+
+            if (disturbanceModel.Id == -1)
+            {
+                var claim = disturbanceModel.ToDisturbance();
+
+                _deviationService.InsertDisturbance(claim);
+            }
+            else
+            {
+                var disturbance = _deviationService.GetDisturbanceById(disturbanceModel.Id);
+
+                disturbance.Description = disturbanceModel.Description;
+
+                _deviationService.UpdateDisturbance(disturbance);
+            }
+
+            return new JsonResult
+            {
+                Data = "success"
+            };
+        }
+
+        /// <summary>
+        /// Partial edit result if ModelState is valid, otherwise simple JSON result for success
+        /// </summary>
+        /// <param name="kindModel">Kind model to be saved.</param>
+        [HttpPost, ValidateInput(false)]
+        public ActionResult EditKind(KindDataModel kindModel)
+        {
+            if (!ModelState.IsValid)
+                return PartialView("~/Views/Deviations/_KindEditPartial.cshtml", kindModel);
+
+            if (kindModel.Id == -1)
+            {
+                var claim = kindModel.ToKind();
+
+                _deviationService.InsertKind(claim);
+            }
+            else
+            {
+                var kind = _deviationService.GetKindById(kindModel.Id);
+
+                kind.Description = kindModel.Description;
+
+                _deviationService.UpdateKind(kind);
+            }
+
+            return new JsonResult
+            {
+                Data = "success"
+            };
+        }
+
+        /// <summary>
+        /// Simple JSON result for deleting a specific claim
+        /// </summary>
+        /// <param name="claimType">Claim type.</param>
+        /// <param name="id">Claim id.</param>
+        /// <param name="replaceId">Id of claim which deviations get in place of deleting claim.</param>
+        [HttpPost]
+        public ActionResult DeleteClaim(string claimType, int id, int replaceId)
+        {
+            switch (claimType.ToLower())
+            {
+                case "status":
+                    var status = _deviationService.GetStatusById(id);
+                    var replaceStatus = _deviationService.GetStatusById(replaceId);
+
+                    var statusDeviations = _deviationService.GetDeviationsByStatus(id);
+
+                    foreach (var deviation in statusDeviations)
+                    {
+                        deviation.StatusId = replaceId;
+                        deviation.Status = replaceStatus;
+
+                        _deviationService.UpdateDeviation(deviation);
+                    }
+
+                    if (status != null)
+                        _deviationService.DeleteStatus(status);
+                    break;
+                case "disturbance":
+                    var disturbance = _deviationService.GetDisturbanceById(id);
+                    var replaceDisturbance = _deviationService.GetDisturbanceById(replaceId);
+
+                    var disturbanceDeviations = _deviationService.GetDeviationsByDisturbance(id);
+
+                    foreach (var deviation in disturbanceDeviations)
+                    {
+                        deviation.DisturbanceId = replaceId;
+                        deviation.Disturbance = replaceDisturbance;
+
+                        _deviationService.UpdateDeviation(deviation);
+                    }
+
+                    if (disturbance != null)
+                        _deviationService.DeleteDisturbance(disturbance);
+                    break;
+                case "kind":
+                    var kind = _deviationService.GetKindById(id);
+                    var replaceKind = _deviationService.GetKindById(replaceId);
+
+                    var kindDeviations = _deviationService.GetDeviationsByKind(id);
+
+                    foreach (var deviation in kindDeviations)
+                    {
+                        deviation.KindId = replaceId;
+                        deviation.Kind = replaceKind;
+
+                        _deviationService.UpdateDeviation(deviation);
+                    }
+
+                    if (kind != null)
+                        _deviationService.DeleteKind(kind);
+                    break;
+                default:
+                    return new EmptyResult();
+            }
+
+            return new JsonResult
+            {
+                Data = "success"
+            };
+        }
+
+        #endregion
     }
 }

+ 7 - 0
GreenTree.Nachtragsmanagement.Web/Global.asax.cs

@@ -15,6 +15,7 @@ using GreenTree.Nachtragsmanagement.Web.App_Start;
 using System.Web.Optimization;
 using FluentValidation.Mvc;
 using GreenTree.Nachtragsmanagement.Web.Validation;
+using GreenTree.Nachtragsmanagement.Services.User;
 
 namespace GreenTree.Nachtragsmanagement.Web
 {
@@ -45,6 +46,12 @@ namespace GreenTree.Nachtragsmanagement.Web
                 provider.ValidatorFactory = new AppendixValidatorFactory();
             });
 
+            var userService = Singleton<IContainer>.Instance.Resolve<IUserService>();
+            var allFunctions = userService.GetAllFunctions();
+            var adminRole = userService.GetRoleById(1);
+            adminRole.SetFunctions(allFunctions);
+            userService.UpdateRole(adminRole);
+
             DevExpress.Web.ASPxWebControl.CallbackError += Application_Error;   
         }
 

+ 35 - 1
GreenTree.Nachtragsmanagement.Web/GreenTree.Nachtragsmanagement.Web.csproj

@@ -151,7 +151,15 @@
     <Content Include="Content\devex.css" />
     <Content Include="Content\function.css" />
     <Content Include="Content\global.css" />
+    <Content Include="Content\Images\add-16-contrast.png" />
+    <Content Include="Content\Images\add-16.png" />
+    <Content Include="Content\Images\add-24-contrast.png" />
+    <Content Include="Content\Images\add-24.png" />
+    <Content Include="Content\Images\add-32-contrast.png" />
+    <Content Include="Content\Images\add-32.png" />
     <Content Include="Content\Images\close-16.png" />
+    <Content Include="Content\Images\function-Deviation-Claims-32-contrast.png" />
+    <Content Include="Content\Images\function-Deviation-Claims-32.png" />
     <Content Include="Content\Images\function-Deviation-Deviations-32-contrast.png" />
     <Content Include="Content\Images\function-Deviation-Deviations-32.png" />
     <Content Include="Content\Images\function-Administration-Plugins-32-contrast.png" />
@@ -200,6 +208,7 @@
     <Content Include="Scripts\knockout-3.3.0.debug.js" />
     <Content Include="Scripts\knockout-3.3.0.js" />
     <Content Include="packages.config" />
+    <None Include="Properties\PublishProfiles\greentreestudios.pubxml" />
     <None Include="Scripts\jquery.validate-vsdoc.js" />
     <Content Include="Scripts\modernizr-2.6.2.js" />
     <Content Include="Views\Web.config" />
@@ -239,6 +248,18 @@
     <Content Include="Views\Deviations\View.cshtml" />
     <Content Include="Views\Deviations\_DeviationGridPartial.cshtml" />
     <Content Include="Views\Deviations\_DeviationEditPartial.cshtml" />
+    <Content Include="Views\Deviations\_StatusListPartial.cshtml" />
+    <Content Include="Views\Deviations\_DisturbanceListPartial.cshtml" />
+    <Content Include="Views\Deviations\_KindListPartial.cshtml" />
+    <Content Include="Views\Deviations\Claims.cshtml" />
+    <Content Include="Views\Deviations\_StatusEditPartial.cshtml" />
+    <Content Include="Views\Deviations\_DisturbanceEditPartial.cshtml" />
+    <Content Include="Views\Deviations\_KindEditPartial.cshtml" />
+    <Content Include="Views\Shared\DataEditorTemplates\_AppendicesComboBox.cshtml" />
+    <Content Include="Views\Shared\DataEditorTemplates\_StatusesComboBox.cshtml" />
+    <Content Include="Views\Shared\DataEditorTemplates\_KindsComboBox.cshtml" />
+    <Content Include="Views\Shared\DataEditorTemplates\_DisturbancesComboBox.cshtml" />
+    <Content Include="Views\Shared\DataEditorTemplates\_RolesComboBox.cshtml" />
     <None Include="Web.Debug.config">
       <DependentUpon>Web.config</DependentUpon>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
@@ -256,6 +277,7 @@
     <Compile Include="App_Start\WebApiConfig.cs" />
     <Compile Include="Controllers\AdminController.cs" />
     <Compile Include="Controllers\AuthController.cs" />
+    <Compile Include="Controllers\DataCallbackController.cs" />
     <Compile Include="Controllers\DeviationController.cs" />
     <Compile Include="Controllers\GlobalController.cs" />
     <Compile Include="Controllers\HomeController.cs" />
@@ -264,9 +286,18 @@
     <Compile Include="Global.asax.cs">
       <DependentUpon>Global.asax</DependentUpon>
     </Compile>
+    <Compile Include="Models\Admin\User\IRequireRoleDataModel.cs" />
     <Compile Include="Models\Admin\User\RoleDataModel.cs" />
     <Compile Include="Models\Admin\User\UserDataModel.cs" />
+    <Compile Include="Models\Appendix\IRequireAppendixDataModel.cs" />
     <Compile Include="Models\Deviation\DeviationDataModel.cs" />
+    <Compile Include="Models\Deviation\DisturbanceDataModel.cs" />
+    <Compile Include="Models\Deviation\IRequireKindDataModel.cs" />
+    <Compile Include="Models\Deviation\IRequireDisturbanceDataModel.cs" />
+    <Compile Include="Models\Deviation\IRequireStatusDataModel.cs" />
+    <Compile Include="Models\Deviation\KindDataModel.cs" />
+    <Compile Include="Models\Deviation\StatusDataModel.cs" />
+    <Compile Include="Models\Global\EmptyIRequireDataModel.cs" />
     <Compile Include="Models\Global\OptionDialogItemModel.cs" />
     <Compile Include="Models\Global\YesNoDialogModel.cs" />
     <Compile Include="Models\Global\OptionDialogModel.cs" />
@@ -278,12 +309,15 @@
     <Compile Include="Models\Login\LoginModel.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="Validation\AppendixValidatorFactory.cs" />
+    <Compile Include="Validation\Deviation\KindDataModelValidator.cs" />
+    <Compile Include="Validation\Deviation\DisturbanceDataModelValidator.cs" />
+    <Compile Include="Validation\Deviation\StatusDataModelValidator.cs" />
     <Compile Include="Validation\Deviation\DeviationDataModelValidator.cs" />
   </ItemGroup>
   <ItemGroup>
     <Folder Include="App_Data\" />
     <Folder Include="Fonts\" />
-    <Folder Include="Views\Deviation\" />
+    <Folder Include="Views\DataCallback\" />
   </ItemGroup>
   <ItemGroup>
     <ProjectReference Include="..\GreenTree.Nachtragsmanagement.Core\GreenTree.Nachtragsmanagement.Core.csproj">

+ 13 - 0
GreenTree.Nachtragsmanagement.Web/Models/Admin/User/IRequireRoleDataModel.cs

@@ -0,0 +1,13 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace GreenTree.Nachtragsmanagement.Web.Models.Admin.User
+{
+    public interface IRequireRoleDataModel
+    {
+        int? RoleId { get; set; }
+    }
+}

+ 13 - 0
GreenTree.Nachtragsmanagement.Web/Models/Appendix/IRequireAppendixDataModel.cs

@@ -0,0 +1,13 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace GreenTree.Nachtragsmanagement.Web.Models.Appendix
+{
+    public interface IRequireAppendixDataModel
+    {
+        int? AppendixId { get; set; }
+    }
+}

+ 7 - 5
GreenTree.Nachtragsmanagement.Web/Models/Deviation/DeviationDataModel.cs

@@ -1,21 +1,23 @@
-using System;
+using GreenTree.Nachtragsmanagement.Web.Models.Appendix;
+using System;
 using System.Collections.Generic;
 using System.Linq;
 using System.Web;
 
 namespace GreenTree.Nachtragsmanagement.Web.Models.Deviation
 {
-    public class DeviationDataModel
+    public class DeviationDataModel 
+        : IRequireAppendixDataModel, IRequireStatusDataModel, IRequireDisturbanceDataModel, IRequireKindDataModel
     {
         public int Id { get; set; }
         public string CustomNumber { get; set; }
         public DateTime ReceiptDate { get; set; }
         public decimal Value { get; set; }
-        public int StatusId { get; set; }
+        public int? StatusId { get; set; }
         public string StatusDescription { get; set; }
-        public int DisturbanceId { get; set; }
+        public int? DisturbanceId { get; set; }
         public string DisturbanceDescription { get; set; }
-        public int KindId { get; set; }
+        public int? KindId { get; set; }
         public string KindDescription { get; set; }
         public string Comment { get; set; }
         public string AppendixDescription { get; set; }

+ 40 - 0
GreenTree.Nachtragsmanagement.Web/Models/Deviation/DisturbanceDataModel.cs

@@ -0,0 +1,40 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Web;
+
+namespace GreenTree.Nachtragsmanagement.Web.Models.Deviation
+{
+    public class DisturbanceDataModel
+    {
+        public int Id { get; set; }
+        public string Description { get; set; }
+
+        public static DisturbanceDataModel FromDisturbance(Core.Domain.Deviation.Disturbance disturbanceEntity, bool newWhenIsNull)
+        {
+            if (disturbanceEntity == null && newWhenIsNull)
+                return new DisturbanceDataModel
+                {
+                    Id = -1
+                };
+
+            if (disturbanceEntity == null && !newWhenIsNull)
+                throw new ArgumentNullException("disturbanceEntity", "Cannot create DisturbanceDataModel from NULL disturbance entity.");
+
+            return new DisturbanceDataModel
+            {
+                Id = disturbanceEntity.Id,
+                Description = disturbanceEntity.Description
+            };
+        }
+
+        public Core.Domain.Deviation.Disturbance ToDisturbance()
+        {
+            return new Core.Domain.Deviation.Disturbance
+            {
+                Id = this.Id,
+                Description = this.Description
+            };
+        }
+    }
+}

+ 13 - 0
GreenTree.Nachtragsmanagement.Web/Models/Deviation/IRequireDisturbanceDataModel.cs

@@ -0,0 +1,13 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace GreenTree.Nachtragsmanagement.Web.Models.Deviation
+{
+    public interface IRequireDisturbanceDataModel
+    {
+        int? DisturbanceId { get; set; }
+    }
+}

+ 13 - 0
GreenTree.Nachtragsmanagement.Web/Models/Deviation/IRequireKindDataModel.cs

@@ -0,0 +1,13 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace GreenTree.Nachtragsmanagement.Web.Models.Deviation
+{
+    public interface IRequireKindDataModel
+    {
+        int? KindId { get; set; }
+    }
+}

+ 13 - 0
GreenTree.Nachtragsmanagement.Web/Models/Deviation/IRequireStatusDataModel.cs

@@ -0,0 +1,13 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace GreenTree.Nachtragsmanagement.Web.Models.Deviation
+{
+    public interface IRequireStatusDataModel
+    {
+        int? StatusId { get; set; }
+    }
+}

+ 40 - 0
GreenTree.Nachtragsmanagement.Web/Models/Deviation/KindDataModel.cs

@@ -0,0 +1,40 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Web;
+
+namespace GreenTree.Nachtragsmanagement.Web.Models.Deviation
+{
+    public class KindDataModel
+    {
+        public int Id { get; set; }
+        public string Description { get; set; }
+
+        public static KindDataModel FromKind(Core.Domain.Deviation.Kind kindEntity, bool newWhenIsNull)
+        {
+            if (kindEntity == null && newWhenIsNull)
+                return new KindDataModel
+                {
+                    Id = -1
+                };
+
+            if (kindEntity == null && !newWhenIsNull)
+                throw new ArgumentNullException("kindEntity", "Cannot create KindDataModel from NULL kind entity.");
+
+            return new KindDataModel
+            {
+                Id = kindEntity.Id,
+                Description = kindEntity.Description
+            };
+        }
+
+        public Core.Domain.Deviation.Kind ToKind()
+        {
+            return new Core.Domain.Deviation.Kind
+            {
+                Id = this.Id,
+                Description = this.Description
+            };
+        }
+    }
+}

+ 40 - 0
GreenTree.Nachtragsmanagement.Web/Models/Deviation/StatusDataModel.cs

@@ -0,0 +1,40 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Web;
+
+namespace GreenTree.Nachtragsmanagement.Web.Models.Deviation
+{
+    public class StatusDataModel
+    {
+        public int Id { get; set; }
+        public string Description { get; set; }
+
+        public static StatusDataModel FromStatus(Core.Domain.Deviation.Status statusEntity, bool newWhenIsNull)
+        {
+            if (statusEntity == null && newWhenIsNull)
+                return new StatusDataModel
+                {
+                    Id = -1
+                };
+
+            if (statusEntity == null && !newWhenIsNull)
+                throw new ArgumentNullException("statusEntity", "Cannot create StatusDataModel from NULL status entity.");
+
+            return new StatusDataModel
+            {
+                Id = statusEntity.Id,
+                Description = statusEntity.Description
+            };
+        }
+
+        public Core.Domain.Deviation.Status ToStatus()
+        {
+            return new Core.Domain.Deviation.Status
+            {
+                Id = this.Id,
+                Description = this.Description
+            };
+        }
+    }
+}

+ 28 - 0
GreenTree.Nachtragsmanagement.Web/Models/Global/EmptyIRequireDataModel.cs

@@ -0,0 +1,28 @@
+using GreenTree.Nachtragsmanagement.Web.Models.Admin.User;
+using GreenTree.Nachtragsmanagement.Web.Models.Appendix;
+using GreenTree.Nachtragsmanagement.Web.Models.Deviation;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Web;
+
+namespace GreenTree.Nachtragsmanagement.Web.Models.Global
+{
+    public class EmptyIRequireDataModel
+        : IRequireRoleDataModel, IRequireStatusDataModel, IRequireDisturbanceDataModel, IRequireKindDataModel, IRequireAppendixDataModel
+    {
+        public int? RoleId { get; set; }
+        public int? StatusId { get; set; }
+        public int? DisturbanceId { get; set; }
+        public int? KindId { get; set; }
+        public int? AppendixId { get; set; }
+
+        public static EmptyIRequireDataModel Instance
+        {
+            get
+            {
+                return new EmptyIRequireDataModel();
+            }
+        }
+    }
+}

+ 22 - 0
GreenTree.Nachtragsmanagement.Web/Properties/PublishProfiles/greentreestudios.pubxml

@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Diese Datei wird vom Veröffentlichungs-/Paketierungsprozess Ihres Webprojekts verwendet. Sie können das Verhalten dieses Prozesses anpassen,
+indem Sie diese MSBuild-Datei bearbeiten. Weitere Informationen hierzu finden Sie unter https://go.microsoft.com/fwlink/?LinkID=208121. 
+-->
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <WebPublishMethod>FTP</WebPublishMethod>
+    <LastUsedBuildConfiguration>Release</LastUsedBuildConfiguration>
+    <LastUsedPlatform>Any CPU</LastUsedPlatform>
+    <SiteUrlToLaunchAfterPublish>
+    </SiteUrlToLaunchAfterPublish>
+    <LaunchSiteAfterPublish>True</LaunchSiteAfterPublish>
+    <ExcludeApp_Data>False</ExcludeApp_Data>
+    <publishUrl>greentreestudios.de</publishUrl>
+    <DeleteExistingFiles>False</DeleteExistingFiles>
+    <FtpPassiveMode>True</FtpPassiveMode>
+    <FtpSitePath>/Webseiten/Nachtragsmanagement</FtpSitePath>
+    <UserName>a.diekmann</UserName>
+    <_SavePWD>True</_SavePWD>
+  </PropertyGroup>
+</Project>

+ 3 - 0
GreenTree.Nachtragsmanagement.Web/Validation/AppendixValidatorFactory.cs

@@ -18,6 +18,9 @@ namespace GreenTree.Nachtragsmanagement.Web.Validation
             validators.Add(typeof(IValidator<UserDataModel>), new UserDataModelValidator());
             validators.Add(typeof(IValidator<RoleDataModel>), new RoleDataModelValidator());
             validators.Add(typeof(IValidator<DeviationDataModel>), new DeviationDataModelValidator());
+            validators.Add(typeof(IValidator<StatusDataModel>), new StatusDataModelValidator());
+            validators.Add(typeof(IValidator<DisturbanceDataModel>), new DisturbanceDataModelValidator());
+            validators.Add(typeof(IValidator<KindDataModel>), new KindDataModelValidator());
         }
 
         public override IValidator CreateInstance(Type validatorType)

+ 21 - 0
GreenTree.Nachtragsmanagement.Web/Validation/Deviation/DisturbanceDataModelValidator.cs

@@ -0,0 +1,21 @@
+using FluentValidation;
+using GreenTree.Nachtragsmanagement.Web.Models.Deviation;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Web;
+
+namespace GreenTree.Nachtragsmanagement.Web.Validation.Admin.User
+{
+    public class DisturbanceDataModelValidator : AbstractValidator<DisturbanceDataModel>
+    {
+        public DisturbanceDataModelValidator()
+        {
+            RuleFor(m => m.Description)
+                .NotEmpty()
+                    .WithMessage("Beschreibung wird benötigt")
+                .MaximumLength(50)
+                    .WithMessage("Muss unter 50 Zeichen sein");
+        }
+    }
+}

+ 21 - 0
GreenTree.Nachtragsmanagement.Web/Validation/Deviation/KindDataModelValidator.cs

@@ -0,0 +1,21 @@
+using FluentValidation;
+using GreenTree.Nachtragsmanagement.Web.Models.Deviation;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Web;
+
+namespace GreenTree.Nachtragsmanagement.Web.Validation.Admin.User
+{
+    public class KindDataModelValidator : AbstractValidator<KindDataModel>
+    {
+        public KindDataModelValidator()
+        {
+            RuleFor(m => m.Description)
+                .NotEmpty()
+                    .WithMessage("Beschreibung wird benötigt")
+                .MaximumLength(50)
+                    .WithMessage("Muss unter 50 Zeichen sein");
+        }
+    }
+}

+ 21 - 0
GreenTree.Nachtragsmanagement.Web/Validation/Deviation/StatusDataModelValidator.cs

@@ -0,0 +1,21 @@
+using FluentValidation;
+using GreenTree.Nachtragsmanagement.Web.Models.Deviation;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Web;
+
+namespace GreenTree.Nachtragsmanagement.Web.Validation.Admin.User
+{
+    public class StatusDataModelValidator : AbstractValidator<StatusDataModel>
+    {
+        public StatusDataModelValidator()
+        {
+            RuleFor(m => m.Description)
+                .NotEmpty()
+                    .WithMessage("Beschreibung wird benötigt")
+                .MaximumLength(50)
+                    .WithMessage("Muss unter 50 Zeichen sein");
+        }
+    }
+}

+ 40 - 44
GreenTree.Nachtragsmanagement.Web/Views/Admin/Roles/View.cshtml

@@ -10,29 +10,6 @@
 	var deleteId;
 	var deleteReplaceId = -1;
 
-	function saveRole() {
-		var form = $("#roleEditForm");
-		$(form).submit(function (e) {
-			$.ajax({
-				type: "POST",
-				url: '@Url.Action("EditRole", "Admin")',
-				data: form.serialize(),
-				success: function (response) {
-					setTimeout(function () {
-						$(".roleEditContainer").remove();
-						if (response == "success") {
-							devGridViewRole.PerformCallback();
-						} else {
-							$("body").append(response);
-						}
-					}, 200);
-				}
-			});
-			e.preventDefault();
-		});
-		form.submit();
-	}
-
 	function editRole(id) {
 		if (!id) return;
 		$.ajax({
@@ -59,20 +36,14 @@
 			data: { id: deleteId },
 			success: function (response) {
 				if (response == "notFound") return;
+
 				var role = JSON.parse(response);
+
+				$(".deleteValidation").hide();
+
 				var comboBox = MVCxClientComboBox.Cast(devComboBoxRoleDeleteReplaceRole);
-				var lastDisplayIndex = -1;
-				for (var i = 0; i < comboBox.GetItemCount(); i++) {
-					comboBox.RemoveItemCssClass(i, "devExDisplayHidden");
-					comboBox.RemoveItemCssClass(i, "devExDisplayTableRow");
-					if (comboBox.GetItem(i).value == deleteId) {
-						comboBox.AddItemCssClass(i, "devExDisplayHidden");
-					} else {
-						lastDisplayIndex = i;
-						comboBox.AddItemCssClass(i, "devExDisplayTableRow");
-					}
-				}
-				comboBox.SetSelectedIndex(lastDisplayIndex);
+				comboBox.PerformCallback();
+
 				var popupControl = MVCxClientPopupControl.Cast(devPopupControlDeleteRole);
 				popupControl.SetHeaderText(popupControl.GetHeaderText().replace("{role}", role.Description));
 				$(".dialogText").text($(".dialogText").text().replace("{role}", role.Description));
@@ -87,6 +58,18 @@
 		} else {
 			deleteReplaceId = -1;
 		}
+
+		if (deleteReplaceId == 0) {
+			$(".deleteValidation").text("Es muss ein Ersatz ausgewählt werden.");
+			$(".deleteValidation").show();
+			return;
+		}
+		if (deleteId == deleteReplaceId) {
+			$(".deleteValidation").text("Der Ersatz darf nicht gleich dem zu löschenden Element sein.");
+			$(".deleteValidation").show();
+			return;
+		}
+
 		$.ajax({
 			type: "POST",
 			url: '@Url.Action("DeleteRole", "Admin")',
@@ -135,16 +118,26 @@
 				"}";
 		}).Render();
 
-		Html.DevExpress().ComboBox(cb =>
+		Session.Add("RolesDeleteComboBoxSettings", new Action<ComboBoxSettings>(a =>
 		{
-			cb.Name = "devComboBoxRoleDeleteReplaceRole";
-			cb.Width = new Unit(100, UnitType.Percentage);
-			cb.Properties.ValueType = typeof(int);
-			cb.Properties.ValueField = "Id";
-			cb.Properties.TextField = "Description";
-			cb.SelectedIndex = 0;
-			cb.ClientEnabled = false;
-		}).BindList(ViewData["AllRoles"]).Render();
+			a.Name = "devComboBoxRoleDeleteReplaceRole";
+			a.Width = new Unit(100, UnitType.Percentage);
+			a.Properties.ValueType = typeof(int);
+			a.Properties.ValueField = "Id";
+			a.Properties.TextField = "Description";
+			a.Properties.ClientSideEvents.BeginCallback = "function (s, e) { e.customArgs['excludedIds'] = [ deleteId ]; }";
+			a.Properties.ClientSideEvents.EndCallback = "function (s, e) { s.SetSelectedIndex(0); }";
+			a.SelectedIndex = 0;
+			a.ClientEnabled = false;
+			a.CallbackRouteValues = new
+			{
+				Controller = "DataCallback",
+				Action = "RolesComboBoxExcluded",
+				SettingsKey = "RolesDeleteComboBoxSettings"
+			};
+		}));
+		ViewData.Add("RolesComboBoxSettings", "RolesDeleteComboBoxSettings");
+		Html.RenderPartial("~/Views/Shared/DataEditorTemplates/_RolesComboBox.cshtml", EmptyIRequireDataModel.Instance, ViewData);
 
 		Html.DevExpress().RadioButton(rb =>
 		{
@@ -157,6 +150,9 @@
 					"devComboBoxRoleDeleteReplaceRole.SetEnabled(!s.GetChecked()); " +
 				"}";
 		}).Render();
+
+		ViewContext.Writer.Write("<div class=\"deleteValidation\" style=\"display: none\"></div>");
+
 		ViewContext.Writer.Write("</div>");
 
 		Html.RenderPartial(

+ 23 - 0
GreenTree.Nachtragsmanagement.Web/Views/Admin/Roles/_RoleEditPartial.cshtml

@@ -10,6 +10,29 @@
 		var checkedNodesText = "";
 		var checkedNodesCounter = 0;
 
+		function saveRole() {
+			var form = $("#roleEditForm");
+			$(form).submit(function (e) {
+				$.ajax({
+					type: "POST",
+					url: '@Url.Action("EditRole", "Admin")',
+					data: form.serialize(),
+					success: function (response) {
+						setTimeout(function () {
+							$(".roleEditContainer").remove();
+							if (response == "success") {
+								devGridViewRole.PerformCallback();
+							} else {
+								$("body").append(response);
+							}
+						}, 200);
+					}
+				});
+				e.preventDefault();
+			});
+			form.submit();
+		}
+
 		function synchronizeTreeViewValues(s, e) {
 			var treeView = MVCxClientTreeView.Cast(s);
 			var node = treeView.GetNodeByName(e.node.name);

+ 0 - 23
GreenTree.Nachtragsmanagement.Web/Views/Admin/Users/View.cshtml

@@ -7,29 +7,6 @@
 <script>
 	var deleteId;
 
-	function saveUser() {
-		var form = $("#userEditForm");
-		$(form).submit(function (e) {
-			$.ajax({
-				type: "POST",
-				url: '@Url.Action("EditUser", "Admin")',
-				data: form.serialize(),
-				success: function (response) {
-					setTimeout(function () {
-						$(".userEditContainer").remove();
-						if (response == "success") {
-							devGridViewUser.PerformCallback();
-						} else {
-							$("body").append(response);
-						}
-					}, 200);
-				}
-			});
-			e.preventDefault();
-		});
-		form.submit();
-	}
-
 	function editUser(id) {
 		if (!id) return;
 		$.ajax({

+ 23 - 0
GreenTree.Nachtragsmanagement.Web/Views/Admin/Users/_UserEditPartial.cshtml

@@ -6,6 +6,29 @@
 	<script>
 		var textSeparator = ", ";
 
+		function saveUser() {
+			var form = $("#userEditForm");
+			$(form).submit(function (e) {
+				$.ajax({
+					type: "POST",
+					url: '@Url.Action("EditUser", "Admin")',
+					data: form.serialize(),
+					success: function (response) {
+						setTimeout(function () {
+							$(".userEditContainer").remove();
+							if (response == "success") {
+								devGridViewUser.PerformCallback();
+							} else {
+								$("body").append(response);
+							}
+						}, 200);
+					}
+				});
+				e.preventDefault();
+			});
+			form.submit();
+		}
+
 		function onListBoxSelectionChanged(s, e) {
 			if (e.index == 0)
 				e.isSelected ? s.SelectAll() : s.UnselectAll();

+ 268 - 0
GreenTree.Nachtragsmanagement.Web/Views/Deviations/Claims.cshtml

@@ -0,0 +1,268 @@
+@using GreenTree.Nachtragsmanagement.Web.Models.Global
+
+@{
+	Layout = "~/Views/Shared/_FunctionLayout.cshtml";
+}
+
+<script>
+	var deleteId;
+	var deleteReplaceId;
+	var deleteClaimType;
+
+	var claimTypeTranslation = {
+		status: "Status",
+		disturbance: "Verzögerung",
+		kind: "Art"
+	};
+
+	$(document).ready(setListBoxHeights);
+	$(window).resize(setListBoxHeights);
+
+	function setListBoxHeights() {
+		var windowHeight = $(window).height();
+		devListBoxStatuses.SetHeight(windowHeight - 40);
+		devListBoxDisturbances.SetHeight(windowHeight - 40);
+		devListBoxKinds.SetHeight(windowHeight - 40);
+	}
+
+	function editClaim(claimType, id) {
+		if (!id) return;
+		$.ajax({
+			url: '@Url.Action("EditClaim", "Deviation")',
+			data: { claimType: claimType, Id: id },
+			success: function (response) {
+				setTimeout(function () {
+					$(".claimEditContainer").remove();
+					$("body").append(response);
+				}, 200);
+			},
+			error: function () {
+				 alert("error occured");
+			}
+		});
+	}
+
+	function confirmDelete(claimType, id) {
+		if (!id) return;
+		deleteId = id;
+		deleteClaimType = claimType;
+		$.ajax({
+			type: "GET",
+			url: '@Url.Action("GetClaim", "Deviation")',
+			data: { claimType: deleteClaimType, Id: id },
+			success: function (response) {
+				if (response == "notFound") return;
+
+				var claim = JSON.parse(response);
+
+				$(".deleteValidation").hide();
+
+				var popupControl = MVCxClientPopupControl.Cast(devPopupControlDeleteClaim);
+				popupControl.SetHeaderText(popupControl.GetHeaderText().replace("{claim}", claim.Description));
+				$(".dialogText").text($(".dialogText").text().replace("{claim}", claim.Description));
+				$(".dialogText").text($(".dialogText").text().replace("{claim}", claim.Description));
+				$(".dialogText").text($(".dialogText").text().replace("{claimType}", claimTypeTranslation[claimType]));
+
+				devRadioButtonDeleteReplaceClaim
+					.SetText(devRadioButtonDeleteReplaceClaim.GetText().replace("{claimType}", claimTypeTranslation[claimType]));
+
+				var comboBox = null;
+				devComboBoxClaimDeleteReplaceStatus.SetVisible(false);
+				devComboBoxClaimDeleteReplaceDisturbance.SetVisible(false);
+				devComboBoxClaimDeleteReplaceKind.SetVisible(false);
+
+				if (deleteClaimType == "status") {
+					devComboBoxClaimDeleteReplaceStatus.SetVisible(true);
+					comboBox = MVCxClientComboBox.Cast(devComboBoxClaimDeleteReplaceStatus);
+				} else if (deleteClaimType == "disturbance") {
+					devComboBoxClaimDeleteReplaceDisturbance.SetVisible(true);
+					comboBox = MVCxClientComboBox.Cast(devComboBoxClaimDeleteReplaceStatus);
+				} else if (deleteClaimType == "kind") {
+					devComboBoxClaimDeleteReplaceKind.SetVisible(true);
+					comboBox = MVCxClientComboBox.Cast(devComboBoxClaimDeleteReplaceStatus);
+				}
+
+				comboBox.PerformCallback();
+
+				popupControl.Show();
+			}
+		});
+	}
+
+	function deleteClaim() {
+		if (deleteClaimType == "status") {
+			deleteReplaceId = devComboBoxClaimDeleteReplaceStatus.GetValue();
+		} else if (deleteClaimType == "disturbance") {
+			deleteReplaceId = devComboBoxClaimDeleteReplaceDisturbance.GetValue();
+		} else if (deleteClaimType == "kind") {
+			deleteReplaceId = devComboBoxClaimDeleteReplaceKind.GetValue();
+		}
+
+		if (deleteReplaceId == 0) {
+			$(".deleteValidation").text("Es muss ein Ersatz ausgewählt werden.");
+			$(".deleteValidation").show();
+			return;
+		}
+		if (deleteId == deleteReplaceId) {
+			$(".deleteValidation").text("Der Ersatz darf nicht gleich dem zu löschenden Element sein.");
+			$(".deleteValidation").show();
+			return;
+		}
+
+		$.ajax({
+			type: "POST",
+			url: '@Url.Action("DeleteClaim", "Deviation")',
+			data: { claimType: deleteClaimType, Id: deleteId, replaceId: deleteReplaceId },
+			success: function (response) {
+				var popupControl = MVCxClientPopupControl.Cast(devPopupControlDeleteClaim);
+				popupControl.Hide();
+				setTimeout(function () {
+					if (deleteClaimType == "status") {
+						devListBoxStatuses.PerformCallback();
+					} else if (deleteClaimType == "disturbance") {
+						devListBoxDisturbances.PerformCallback();
+					} else if (deleteClaimType == "kind") {
+						devListBoxKinds.PerformCallback();
+					}
+				}, 200);
+			},
+			error: function () {
+				 alert("error occured");
+			}
+		});
+	}
+</script>
+
+<table style="width: 100%">
+	<tbody>
+		<tr>
+			<td style="width: 33%; padding-right: 6px">
+				<div class="listHeader">
+					<span>Statusse</span>
+					<img src='@Url.Content("~/Content/Images/add-24-contrast.png")' onclick='editClaim("status", -1)' title="Neuer Status" />
+				</div>
+				@Html.Partial("~/Views/Deviations/_StatusListPartial.cshtml", ViewData["AllStatuses"])
+			</td>
+			<td style="width: 33%; padding: 0 6px">
+				<div class="listHeader">
+					<span>Verzögerungen</span>
+					<img src='@Url.Content("~/Content/Images/add-24-contrast.png")' onclick='editClaim("disturbance", -1)' title="Neue Verzögerung" />
+				</div>
+				@Html.Partial("~/Views/Deviations/_DisturbanceListPartial.cshtml", ViewData["AllDisturbances"])
+			</td>
+			<td style="width: 33%; padding-left: 6px">
+				<div class="listHeader">
+					<span>Arten</span>
+					<img src='@Url.Content("~/Content/Images/add-24-contrast.png")' onclick='editClaim("kind", -1)' title="Neue Art" />
+				</div>
+				@Html.Partial("~/Views/Deviations/_KindListPartial.cshtml", ViewData["AllKinds"])
+			</td>
+		</tr>
+	</tbody>
+</table>
+
+@Html.DevExpress().PopupControl(s =>
+{
+	s.Name = "devPopupControlDeleteClaim";
+	s.HeaderText = "\"{claim}\" löschen";
+	s.Modal = false;
+	s.Width = new Unit(350, UnitType.Pixel);
+	s.CloseAction = CloseAction.CloseButton;
+	s.PopupHorizontalAlign = PopupHorizontalAlign.WindowCenter;
+	s.PopupVerticalAlign = PopupVerticalAlign.WindowCenter;
+	s.AllowDragging = false;
+	s.AllowResize = false;
+	s.ShowFooter = false;
+	s.SetContent(() =>
+	{
+		ViewContext.Writer.Write("<div class='dialogText' style='padding: 12px'>");
+		ViewContext.Writer.Write("Falls Sie \"{claim}\" löschen möchten, was soll mit den Vertragsabweichungen geschehen, die bereits \"{claim}\" zugeordnet sind?");
+		ViewContext.Writer.Write("</div>");
+
+		ViewContext.Writer.Write("<div style='padding: 0 12px 12px 12px'>");
+		Html.DevExpress().RadioButton(rb =>
+		{
+			rb.Name = "devRadioButtonDeleteReplaceClaim";
+			rb.Text = "Eine neue(n) {claimType} zuweisen";
+			rb.GroupName = "claimDelete";
+			rb.Checked = true;
+		}).Render();
+
+		Session.Add("StatusesDeleteComboBoxSettings", new Action<ComboBoxSettings>(a =>
+		{
+			a.Name = "devComboBoxClaimDeleteReplaceStatus";
+			a.Width = new Unit(100, UnitType.Percentage);
+			a.Properties.ValueType = typeof(int);
+			a.Properties.ValueField = "Id";
+			a.Properties.TextField = "Description";
+			a.Properties.ClientSideEvents.BeginCallback = "function (s, e) { e.customArgs['excludedIds'] = [ deleteId ]; }";
+			a.Properties.ClientSideEvents.EndCallback = "function (s, e) { s.SetSelectedIndex(0); }";
+			a.SelectedIndex = 0;
+			a.ClientVisible = false;
+			a.CallbackRouteValues = new
+			{
+				Controller = "DataCallback",
+				Action = "StatusesComboBoxExcluded",
+				SettingsKey = "StatusesDeleteComboBoxSettings"
+			};
+		}));
+		ViewData.Add("StatusesComboBoxSettings", "StatusesDeleteComboBoxSettings");
+		Html.RenderPartial("~/Views/Shared/DataEditorTemplates/_StatusesComboBox.cshtml", null, ViewData);
+
+		Session.Add("DisturbancesDeleteComboBoxSettings", new Action<ComboBoxSettings>(a =>
+		{
+			a.Name = "devComboBoxClaimDeleteReplaceDisturbance";
+			a.Width = new Unit(100, UnitType.Percentage);
+			a.Properties.ValueType = typeof(int);
+			a.Properties.ValueField = "Id";
+			a.Properties.TextField = "Description";
+			a.Properties.ClientSideEvents.BeginCallback = "function (s, e) { e.customArgs['excludedIds'] = [ deleteId ]; }";
+			a.Properties.ClientSideEvents.EndCallback = "function (s, e) { s.SetSelectedIndex(0); }";
+			a.SelectedIndex = 0;
+			a.ClientVisible = false;
+			a.CallbackRouteValues = new
+			{
+				Controller = "DataCallback",
+				Action = "DisturbancesComboBoxExcluded",
+				SettingsKey = "DisturbancesDeleteComboBoxSettings"
+			};
+		}));
+		ViewData.Add("DisturbancesComboBoxSettings", "DisturbancesDeleteComboBoxSettings");
+		Html.RenderPartial("~/Views/Shared/DataEditorTemplates/_DisturbancesComboBox.cshtml", null, ViewData);
+
+		Session.Add("KindsDeleteComboBoxSettings", new Action<ComboBoxSettings>(a =>
+		{
+			a.Name = "devComboBoxClaimDeleteReplaceKind";
+			a.Width = new Unit(100, UnitType.Percentage);
+			a.Properties.ValueType = typeof(int);
+			a.Properties.ValueField = "Id";
+			a.Properties.TextField = "Description";
+			a.Properties.ClientSideEvents.BeginCallback = "function (s, e) { e.customArgs['excludedIds'] = [ deleteId ]; }";
+			a.Properties.ClientSideEvents.EndCallback = "function (s, e) { s.SetSelectedIndex(0); }";
+			a.SelectedIndex = 0;
+			a.ClientVisible = false;
+			a.CallbackRouteValues = new
+			{
+				Controller = "DataCallback",
+				Action = "KindsComboBoxExcluded",
+				SettingsKey = "KindsDeleteComboBoxSettings"
+			};
+		}));
+		ViewData.Add("KindsComboBoxSettings", "KindsDeleteComboBoxSettings");
+		Html.RenderPartial("~/Views/Shared/DataEditorTemplates/_KindsComboBox.cshtml", null, ViewData);
+
+		ViewContext.Writer.Write("<div class=\"deleteValidation\" style=\"display: none\"></div>");
+
+		ViewContext.Writer.Write("</div>");
+
+		Html.RenderPartial(
+			"~/Views/Shared/_PopupButtonPanelYesNo.cshtml",
+			new YesNoDialogModel
+			{
+				PopupName = "devPopupControlDeleteClaim",
+				YesFunction = "function (s, e) { deleteClaim(); }"
+			}
+		);
+	});
+	s.Styles.Content.Paddings.Padding = new Unit(0, UnitType.Pixel);
+}).GetHtml()

+ 3 - 3
GreenTree.Nachtragsmanagement.Web/Views/Deviations/View.cshtml

@@ -12,7 +12,7 @@
 		$(form).submit(function (e) {
 			$.ajax({
 				type: "POST",
-				url: '@Url.Action("EditDeviation", "Admin")',
+				url: '@Url.Action("EditDeviation", "Deviation")',
 				data: form.serialize(),
 				success: function (response) {
 					setTimeout(function () {
@@ -33,7 +33,7 @@
 	function editDeviation(id) {
 		if (!id) return;
 		$.ajax({
-			url: '@Url.Action("EditDeviation", "Admin")',
+			url: '@Url.Action("EditDeviation", "Deviation")',
 			data: { Id: id },
 			success: function (response) {
 				setTimeout(function () {
@@ -59,7 +59,7 @@
 				var deviation = JSON.parse(response);
 				var popupControl = MVCxClientPopupControl.Cast(devPopupControlDeleteDeviation);
 				popupControl.SetHeaderText(popupControl.GetHeaderText().replace("{deviation}", deviation.CustomNumber));
-				$(".dialogText").text($(".dialogText").text().replace("{deviation}", deviation.CustomNumber);
+				$(".dialogText").text($(".dialogText").text().replace("{deviation}", deviation.CustomNumber));
 				popupControl.Show();
 			}
 		});

+ 227 - 35
GreenTree.Nachtragsmanagement.Web/Views/Deviations/_DeviationEditPartial.cshtml

@@ -1,9 +1,71 @@
 @using GreenTree.Nachtragsmanagement.Web.Extensions
 
+@{ 
+	var userContext = GreenTree.Nachtragsmanagement.Core.CommonHelper.UserContext();
+}
+
 @model GreenTree.Nachtragsmanagement.Web.Models.Deviation.DeviationDataModel
 
 <div class="deviationEditContainer">
 
+	<script>
+		function addStatus() {
+			$.ajax({
+				url: '@Url.Action("EditClaim", "Deviation")',
+				data: { claimType: "status", Id: -1 },
+				success: function (response) {
+					setTimeout(function () {
+						$(".claimEditContainer").remove();
+						$("body").append(response);
+						parent.addCustomEventListener('StatusDataCallbackEventReceiver', function () {
+							StatusId.PerformCallback();
+						});
+					}, 200);
+				},
+				error: function () {
+					 alert("error occured");
+				}
+			});
+		}
+
+		function addDisturbance() {
+			$.ajax({
+				url: '@Url.Action("EditClaim", "Deviation")',
+				data: { claimType: "disturbance", Id: -1 },
+				success: function (response) {
+					setTimeout(function () {
+						$(".claimEditContainer").remove();
+						$("body").append(response);
+						parent.addCustomEventListener('DisturbanceDataCallbackEventReceiver', function () {
+							DisturbanceId.PerformCallback();
+						});
+					}, 200);
+				},
+				error: function () {
+					 alert("error occured");
+				}
+			});
+		}
+
+		function addKind() {
+			$.ajax({
+				url: '@Url.Action("EditClaim", "Deviation")',
+				data: { claimType: "kind", Id: -1 },
+				success: function (response) {
+					setTimeout(function () {
+						$(".claimEditContainer").remove();
+						$("body").append(response);
+						parent.addCustomEventListener('KindDataCallbackEventReceiver', function () {
+							KindId.PerformCallback();
+						});
+					}, 200);
+				},
+				error: function () {
+					 alert("error occured");
+				}
+			});
+		}
+	</script>
 	@Html.DevExpress().PopupControl(s =>
 {
 	s.Name = "devPopupControlEditDeviation";
@@ -17,14 +79,15 @@
 	s.Width = new Unit(500, UnitType.Pixel);
 	s.CloseAction = CloseAction.CloseButton;
 	s.PopupHorizontalAlign = PopupHorizontalAlign.WindowCenter;
-	s.PopupVerticalAlign = PopupVerticalAlign.WindowCenter;
+	s.PopupVerticalAlign = PopupVerticalAlign.TopSides;
+	s.PopupVerticalOffset = 10;
 	s.AllowDragging = false;
 	s.AllowResize = false;
 	s.ShowFooter = false;
 	s.ShowOnPageLoad = true;
 	s.SetContent(() =>
 	{
-		using (Html.BeginForm("EditDeviation", "Admin", FormMethod.Post, new { id = "deviationEditForm" }))
+		using (Html.BeginForm("EditDeviation", "Deviation", FormMethod.Post, new { id = "deviationEditForm" }))
 		{
 			ViewContext.Writer.Write("<div class='editFormWrapper'>");
 
@@ -34,62 +97,191 @@
 			ViewContext.Writer.Write(Html.ValidationMessageFor(m => m.CustomNumber).ToHtmlString());
 			Html.DevExpress().TextBoxFor(m => m.CustomNumber, t =>
 			{
-				t.Width = new Unit(60, UnitType.Percentage);
+				t.Width = new Unit(47.5, UnitType.Percentage);
 			}).Render();
 
-			ViewContext.Writer.Write(Html.CustomLabelFor(m => m.Value, "Wert:"));
-			ViewContext.Writer.Write(Html.ValidationMessageFor(m => m.Value).ToHtmlString());
-			Html.DevExpress().SpinEditFor(m => m.Value, t =>
+			ViewContext.Writer.Write("<div class='inlineModelPropertyContainer'>");
 			{
-				t.Width = new Unit(50, UnitType.Percentage);
-			}).Render();
+				ViewContext.Writer.Write("<div class='inlineModelProperty' style='width: 50%'>");
+				{
+					ViewContext.Writer.Write(Html.CustomLabelFor(m => m.Value, "Wert:"));
+					ViewContext.Writer.Write(Html.ValidationMessageFor(m => m.Value).ToHtmlString());
+					Html.DevExpress().SpinEditFor(m => m.Value, t =>
+					{
+						t.Width = new Unit(95, UnitType.Percentage);
+						t.Properties.DecimalPlaces = 2;
+						t.Properties.NumberType = SpinEditNumberType.Float;
+						t.Properties.DisplayFormatString = "c2";
+					}).Render();
+				}
+				ViewContext.Writer.Write("</div>");
+				ViewContext.Writer.Write("<div class='inlineModelProperty' style='width: 50%'>");
+				{
+					ViewContext.Writer.Write(Html.CustomLabelFor(m => m.ReceiptDate, "Eingangsdatum:"));
+					ViewContext.Writer.Write(Html.ValidationMessageFor(m => m.ReceiptDate).ToHtmlString());
+					Html.DevExpress().DateEditFor(m => m.ReceiptDate, t =>
+					{
+						t.Width = new Unit(100, UnitType.Percentage);
+					}).Render();
+				}
+				ViewContext.Writer.Write("</div>");
+			}
+			ViewContext.Writer.Write("</div>");
+
+			ViewContext.Writer.Write(Html.CustomLabelFor(m => m.AppendixId, "Nachtrag:"));
+
+			Session.Add("DeviationAppendicesComboBoxSettings", new Action<ComboBoxSettings>(a =>
+			{
+				a.Width = new Unit(47.5, UnitType.Percentage);
+				a.Properties.ValueType = typeof(int);
+				a.Properties.ValueField = "Id";
+				a.Properties.TextField = "Description";
+
+				var serializedModel = Newtonsoft.Json.JsonConvert.SerializeObject(Model);
+
+				a.CallbackRouteValues = new
+				{
+					Controller = "DataCallback",
+					Action = "AppendicesComboBox",
+					SettingsKey = "DeviationAppendicesComboBoxSettings",
+					Model = serializedModel,
+					Type = Model.GetType().FullName
+				};
+			}));
+			ViewData.Add("AppendicesComboBoxSettings", "DeviationAppendicesComboBoxSettings");
+			Html.RenderPartial("~/Views/Shared/DataEditorTemplates/_AppendicesComboBox.cshtml", Model, ViewData);
 
 			ViewContext.Writer.Write("<div class='inlineModelPropertyContainer'>");
-				ViewContext.Writer.Write("<div class='inlineModelProperty' style='width: 30%'>");
+			{
+				ViewContext.Writer.Write("<div class='inlineModelProperty' style='width: 33%'>");
+				{
 					ViewContext.Writer.Write(Html.CustomLabelFor(m => m.StatusId, "Status:"));
 					ViewContext.Writer.Write(Html.ValidationMessageFor(m => m.StatusId).ToHtmlString());
-					Html.DevExpress().ComboBoxFor(m => m.StatusId, t =>
+
+					Session.Add("DeviationStatusesComboBoxSettings", new Action<ComboBoxSettings>(a =>
 					{
-						t.Width = new Unit(100, UnitType.Percentage);
-						t.Properties.ValueType = typeof(int);
-						t.Properties.ValueField = "Id";
-						t.Properties.TextField = "Description";
-					}).BindList(ViewData["AllStatuses"]).Render();
+						a.Width = new Unit(95, UnitType.Percentage);
+						a.Properties.ValueType = typeof(int);
+						a.Properties.ValueField = "Id";
+						a.Properties.TextField = "Description";
+
+						var serializedModel = Newtonsoft.Json.JsonConvert.SerializeObject(Model);
+
+						a.CallbackRouteValues = new
+						{
+							Controller = "DataCallback",
+							Action = "StatusesComboBox",
+							SettingsKey = "DeviationStatusesComboBoxSettings",
+							Model = serializedModel,
+							Type = Model.GetType().FullName
+						};
+					}));
+					ViewData.Add("StatusesComboBoxSettings", "DeviationStatusesComboBoxSettings");
+					Html.RenderPartial("~/Views/Shared/DataEditorTemplates/_StatusesComboBox.cshtml", Model, ViewData);
+
+					if (userContext.CurrentUser.HasFunction("Deviation-Claims-Edit"))
+					{
+						Html.DevExpress().HyperLink(t =>
+						{
+							t.Name = "devHyperLinkStatusEventReceiver";
+							t.Properties.Text = "Hinzufügen";
+							t.NavigateUrl = "#";
+							t.Properties.ClientSideEvents.Click = "function (s, e) { addStatus(); }";
+							t.Style.Add("line-height", "24px");
+						}).Render();
+					}
+				}
 				ViewContext.Writer.Write("</div>");
 
-				ViewContext.Writer.Write("<div class='inlineModelProperty' style='width: 30%'>");
+				ViewContext.Writer.Write("<div class='inlineModelProperty' style='width: 33%'>");
+				{
 					ViewContext.Writer.Write(Html.CustomLabelFor(m => m.DisturbanceId, "Verzögerung:"));
 					ViewContext.Writer.Write(Html.ValidationMessageFor(m => m.DisturbanceId).ToHtmlString());
-					Html.DevExpress().ComboBoxFor(m => m.DisturbanceId, t =>
+
+					Session.Add("DeviationDisturbancesComboBoxSettings", new Action<ComboBoxSettings>(a =>
 					{
-						t.Width = new Unit(100, UnitType.Percentage);
-						t.Properties.ValueType = typeof(int);
-						t.Properties.ValueField = "Id";
-						t.Properties.TextField = "Description";
-					}).BindList(ViewData["AllDisturbances"]).Render();
+						a.Width = new Unit(95, UnitType.Percentage);
+						a.Properties.ValueType = typeof(int);
+						a.Properties.ValueField = "Id";
+						a.Properties.TextField = "Description";
+
+						var serializedModel = Newtonsoft.Json.JsonConvert.SerializeObject(Model);
+
+						a.CallbackRouteValues = new
+						{
+							Controller = "DataCallback",
+							Action = "DisturbancesComboBox",
+							SettingsKey = "DeviationDisturbancesComboBoxSettings",
+							Model = serializedModel,
+							Type = Model.GetType().FullName
+						};
+					}));
+					ViewData.Add("DisturbancesComboBoxSettings", "DeviationDisturbancesComboBoxSettings");
+					Html.RenderPartial("~/Views/Shared/DataEditorTemplates/_DisturbancesComboBox.cshtml", Model, ViewData);
+
+					if (userContext.CurrentUser.HasFunction("Deviation-Claims-Edit"))
+					{
+						Html.DevExpress().HyperLink(t =>
+						{
+							t.Name = "devHyperLinkDisturbanceEventReceiver";
+							t.Properties.Text = "Hinzufügen";
+							t.NavigateUrl = "#";
+							t.Properties.ClientSideEvents.Click = "function (s, e) { addDisturbance(); }";
+							t.Style.Add("line-height", "24px");
+						}).Render();
+					}
+				}
 				ViewContext.Writer.Write("</div>");
 
-				ViewContext.Writer.Write("<div class='inlineModelProperty' style='width: 40%'>");
+				ViewContext.Writer.Write("<div class='inlineModelProperty' style='width: 34%'>");
+				{
 					ViewContext.Writer.Write(Html.CustomLabelFor(m => m.KindId, "Art:"));
 					ViewContext.Writer.Write(Html.ValidationMessageFor(m => m.KindId).ToHtmlString());
-					Html.DevExpress().ComboBoxFor(m => m.KindId, t =>
+
+					Session.Add("DeviationKindsComboBoxSettings", new Action<ComboBoxSettings>(a =>
 					{
-						t.Width = new Unit(100, UnitType.Percentage);
-						t.Properties.ValueType = typeof(int);
-						t.Properties.ValueField = "Id";
-						t.Properties.TextField = "Description";
-					}).BindList(ViewData["AllKinds"]).Render();
+						a.Width = new Unit(95, UnitType.Percentage);
+						a.Properties.ValueType = typeof(int);
+						a.Properties.ValueField = "Id";
+						a.Properties.TextField = "Description";
+
+						var serializedModel = Newtonsoft.Json.JsonConvert.SerializeObject(Model);
+
+						a.CallbackRouteValues = new
+						{
+							Controller = "DataCallback",
+							Action = "KindsComboBox",
+							SettingsKey = "DeviationKindsComboBoxSettings",
+							Model = serializedModel,
+							Type = Model.GetType().FullName
+						};
+					}));
+					ViewData.Add("KindsComboBoxSettings", "DeviationKindsComboBoxSettings");
+					Html.RenderPartial("~/Views/Shared/DataEditorTemplates/_KindsComboBox.cshtml", Model, ViewData);
+
+					if (userContext.CurrentUser.HasFunction("Deviation-Claims-Edit"))
+					{
+						Html.DevExpress().HyperLink(t =>
+						{
+							t.Name = "devHyperLinkKindEventReceiver";
+							t.Properties.Text = "Hinzufügen";
+							t.NavigateUrl = "#";
+							t.Properties.ClientSideEvents.Click = "function (s, e) { addKind(); }";
+							t.Style.Add("line-height", "24px");
+						}).Render();
+					}
+				}
 				ViewContext.Writer.Write("</div>");
+			}
 			ViewContext.Writer.Write("</div>");
 
-			ViewContext.Writer.Write(Html.CustomLabelFor(m => m.AppendixId, "Nachtrag:"));
-			Html.DevExpress().ComboBoxFor(m => m.AppendixId, t =>
+			ViewContext.Writer.Write(Html.CustomLabelFor(m => m.Comment, "Kommentar:"));
+			ViewContext.Writer.Write(Html.ValidationMessageFor(m => m.Comment).ToHtmlString());
+			Html.DevExpress().MemoFor(m => m.Comment, t =>
 			{
 				t.Width = new Unit(100, UnitType.Percentage);
-				t.Properties.ValueType = typeof(int);
-				t.Properties.ValueField = "Id";
-				t.Properties.TextField = "Description";
-			}).BindList(ViewData["AllAppendices"]).Render();
+				t.Height = new Unit(90, UnitType.Pixel);
+			}).Render();
 
 			ViewContext.Writer.Write("</div>");
 

+ 13 - 3
GreenTree.Nachtragsmanagement.Web/Views/Deviations/_DeviationGridPartial.cshtml

@@ -8,7 +8,7 @@
 {
 	s.Name = "devGridViewDeviation";
 	s.KeyFieldName = "Id";
-	s.CallbackRouteValues = new { Controller = "Admin", Action = "PartialDeviations" };
+	s.CallbackRouteValues = new { Controller = "Deviation", Action = "PartialDeviations" };
 	s.Width = Unit.Percentage(100);
 
 	if (userContext.CurrentUser.HasFunction("Deviation-Deviations-Edit"))
@@ -34,8 +34,18 @@
 		});
 	}
 	s.Columns.Add("CustomNumber", "Eigene ID");
-	s.Columns.Add("ReceiptDate", "Eingang");
-	s.Columns.Add("Value", "Wert");
+	s.Columns.Add(column =>
+	{
+		column.Caption = "Eingang";
+		column.FieldName = "ReceiptDate";
+		column.PropertiesEdit.DisplayFormatString = "dd.MM.yyyy";
+	});
+	s.Columns.Add(column =>
+	{
+		column.Caption = "Wert";
+		column.FieldName = "Value";
+		column.PropertiesEdit.DisplayFormatString = "c2";
+	});
 	s.Columns.Add("StatusDescription", "Status");
 	s.Columns.Add("DisturbanceDescription", "Verzögerung");
 	s.Columns.Add("KindDescription", "Art");

+ 80 - 0
GreenTree.Nachtragsmanagement.Web/Views/Deviations/_DisturbanceEditPartial.cshtml

@@ -0,0 +1,80 @@
+@using GreenTree.Nachtragsmanagement.Web.Extensions
+
+@model GreenTree.Nachtragsmanagement.Web.Models.Deviation.DisturbanceDataModel
+
+<div class="claimEditContainer">
+
+	<script>
+		function saveDisturbance() {
+			var form = $("#disturbanceEditForm");
+			$(form).submit(function (e) {
+				$.ajax({
+					type: "POST",
+					url: '@Url.Action("EditDisturbance", "Deviation")',
+					data: form.serialize(),
+					success: function (response) {
+						setTimeout(function () {
+							$(".claimEditContainer").remove();
+							if (response == "success") {
+								parent.callCustomEventListener('DisturbanceDataCallbackEventReceiver');
+							} else {
+								$("body").append(response);
+							}
+						}, 200);
+					}
+				});
+				e.preventDefault();
+			});
+			form.submit();
+		}
+	</script>
+
+	@Html.DevExpress().PopupControl(s =>
+{
+	s.Name = "devPopupControlEditDisturbance";
+
+	if (Model.Id == -1)
+		s.HeaderText = "Neue Verzögerung erstellen";
+	else
+		s.HeaderText = "\"" + Model.Description + "\" bearbeiten";
+
+	s.Modal = true;
+	s.Width = new Unit(250, UnitType.Pixel);
+	s.CloseAction = CloseAction.CloseButton;
+	s.PopupHorizontalAlign = PopupHorizontalAlign.WindowCenter;
+	s.PopupVerticalAlign = PopupVerticalAlign.WindowCenter;
+	s.AllowDragging = false;
+	s.AllowResize = false;
+	s.ShowFooter = false;
+	s.ShowOnPageLoad = true;
+	s.SetContent(() =>
+	{
+		using (Html.BeginForm("EditDisturbance", "Deviation", FormMethod.Post, new { id = "disturbanceEditForm" }))
+		{
+			ViewContext.Writer.Write("<div class='editFormWrapper'>");
+
+			ViewContext.Writer.Write("<input type=\"hidden\" value=\"" + Model.Id + "\" id=\"Id\" name=\"Id\" />");
+
+			ViewContext.Writer.Write(Html.CustomLabelFor(m => m.Description, "Beschreibung:"));
+			ViewContext.Writer.Write(Html.ValidationMessageFor(m => m.Description).ToHtmlString());
+			Html.DevExpress().TextBoxFor(m => m.Description, t =>
+			{
+				t.Width = new Unit(100, UnitType.Percentage);
+			}).Render();
+
+			ViewContext.Writer.Write("</div>");
+
+			Html.RenderPartial(
+				"~/Views/Shared/_PopupButtonPanel.cshtml",
+				new GreenTree.Nachtragsmanagement.Web.Models.Global.PopupModel
+				{
+					PopupName = "devPopupControlEditDisturbance",
+					AcceptFunction = "function (s, e) { saveDisturbance(); }"
+				}
+			);
+		}
+	});
+	s.Styles.Content.Paddings.Padding = new Unit(0);
+	s.Styles.ModalBackground.Opacity = 0;
+}).GetHtml()
+</div>

+ 29 - 0
GreenTree.Nachtragsmanagement.Web/Views/Deviations/_DisturbanceListPartial.cshtml

@@ -0,0 +1,29 @@
+@model IEnumerable<GreenTree.Nachtragsmanagement.Core.Domain.Deviation.Disturbance>
+
+@{ 
+	var userContext = GreenTree.Nachtragsmanagement.Core.CommonHelper.UserContext();
+}
+
+@Html.DevExpress().ListBox(s =>
+{
+	s.Name = "devListBoxDisturbances";
+	s.Properties.ValueType = typeof(int);
+	s.Properties.ValueField = "Id";
+	s.Properties.TextField = "Description";
+	if (userContext.CurrentUser.HasFunction("Deviation-Claims-Edit"))
+	{
+		s.SetItemTemplateContent(c =>
+		{
+			ViewContext.Writer.Write(DataBinder.Eval(c.DataItem, "Description"));
+			ViewContext.Writer.Write(
+				"<div class=\"devExListItemControlContainer\">" +
+					"<a href=\"#\" onclick='editClaim(\"disturbance\", " + DataBinder.Eval(c.DataItem, "Id") + ")'>Bearbeiten</a>&nbsp;" +
+					"<a href=\"#\" onclick='confirmDelete(\"disturbance\", " + DataBinder.Eval(c.DataItem, "Id") + ")'>Löschen</a>" +
+				"</div>"
+			);
+		});
+	}
+	s.CallbackRouteValues = new { Controller = "Deviation", Action = "PartialClaims", claimType = "disturbance" };
+	s.Width = Unit.Percentage(100);
+	s.Height = Unit.Pixel(370);
+}).BindList(Model).GetHtml()

+ 80 - 0
GreenTree.Nachtragsmanagement.Web/Views/Deviations/_KindEditPartial.cshtml

@@ -0,0 +1,80 @@
+@using GreenTree.Nachtragsmanagement.Web.Extensions
+
+@model GreenTree.Nachtragsmanagement.Web.Models.Deviation.KindDataModel
+
+<div class="claimEditContainer">
+
+	<script>
+		function saveKind() {
+			var form = $("#kindEditForm");
+			$(form).submit(function (e) {
+				$.ajax({
+					type: "POST",
+					url: '@Url.Action("EditKind", "Deviation")',
+					data: form.serialize(),
+					success: function (response) {
+						setTimeout(function () {
+							$(".claimEditContainer").remove();
+							if (response == "success") {
+								parent.callCustomEventListener('KindDataCallbackEventReceiver');
+							} else {
+								$("body").append(response);
+							}
+						}, 200);
+					}
+				});
+				e.preventDefault();
+			});
+			form.submit();
+		}
+	</script>
+
+	@Html.DevExpress().PopupControl(s =>
+{
+	s.Name = "devPopupControlEditKind";
+
+	if (Model.Id == -1)
+		s.HeaderText = "Neue Art erstellen";
+	else
+		s.HeaderText = "\"" + Model.Description + "\" bearbeiten";
+
+	s.Modal = true;
+	s.Width = new Unit(250, UnitType.Pixel);
+	s.CloseAction = CloseAction.CloseButton;
+	s.PopupHorizontalAlign = PopupHorizontalAlign.WindowCenter;
+	s.PopupVerticalAlign = PopupVerticalAlign.WindowCenter;
+	s.AllowDragging = false;
+	s.AllowResize = false;
+	s.ShowFooter = false;
+	s.ShowOnPageLoad = true;
+	s.SetContent(() =>
+	{
+		using (Html.BeginForm("EditKind", "Deviation", FormMethod.Post, new { id = "kindEditForm" }))
+		{
+			ViewContext.Writer.Write("<div class='editFormWrapper'>");
+
+			ViewContext.Writer.Write("<input type=\"hidden\" value=\"" + Model.Id + "\" id=\"Id\" name=\"Id\" />");
+
+			ViewContext.Writer.Write(Html.CustomLabelFor(m => m.Description, "Beschreibung:"));
+			ViewContext.Writer.Write(Html.ValidationMessageFor(m => m.Description).ToHtmlString());
+			Html.DevExpress().TextBoxFor(m => m.Description, t =>
+			{
+				t.Width = new Unit(100, UnitType.Percentage);
+			}).Render();
+
+			ViewContext.Writer.Write("</div>");
+
+			Html.RenderPartial(
+				"~/Views/Shared/_PopupButtonPanel.cshtml",
+				new GreenTree.Nachtragsmanagement.Web.Models.Global.PopupModel
+				{
+					PopupName = "devPopupControlEditKind",
+					AcceptFunction = "function (s, e) { saveKind(); }"
+				}
+			);
+		}
+	});
+	s.Styles.Content.Paddings.Padding = new Unit(0);
+	s.Styles.ModalBackground.Opacity = 0;
+}).GetHtml()
+</div>

+ 29 - 0
GreenTree.Nachtragsmanagement.Web/Views/Deviations/_KindListPartial.cshtml

@@ -0,0 +1,29 @@
+@model IEnumerable<GreenTree.Nachtragsmanagement.Core.Domain.Deviation.Kind>
+
+@{ 
+	var userContext = GreenTree.Nachtragsmanagement.Core.CommonHelper.UserContext();
+}
+
+@Html.DevExpress().ListBox(s =>
+{
+	s.Name = "devListBoxKinds";
+	s.Properties.ValueType = typeof(int);
+	s.Properties.ValueField = "Id";
+	s.Properties.TextField = "Description";
+	if (userContext.CurrentUser.HasFunction("Deviation-Claims-Edit"))
+	{
+		s.SetItemTemplateContent(c =>
+		{
+			ViewContext.Writer.Write(DataBinder.Eval(c.DataItem, "Description"));
+			ViewContext.Writer.Write(
+				"<div class=\"devExListItemControlContainer\">" +
+					"<a href=\"#\" onclick='editClaim(\"kind\", " + DataBinder.Eval(c.DataItem, "Id") + ")'>Bearbeiten</a>&nbsp;" +
+					"<a href=\"#\" onclick='confirmDelete(\"kind\", " + DataBinder.Eval(c.DataItem, "Id") + ")'>Löschen</a>" +
+				"</div>"
+			);
+		});
+	}
+	s.CallbackRouteValues = new { Controller = "Deviation", Action = "PartialClaims", claimType = "kind" };
+	s.Width = Unit.Percentage(100);
+	s.Height = Unit.Pixel(370);
+}).BindList(Model).GetHtml()

+ 80 - 0
GreenTree.Nachtragsmanagement.Web/Views/Deviations/_StatusEditPartial.cshtml

@@ -0,0 +1,80 @@
+@using GreenTree.Nachtragsmanagement.Web.Extensions
+
+@model GreenTree.Nachtragsmanagement.Web.Models.Deviation.StatusDataModel
+
+<div class="claimEditContainer">
+	
+	<script>
+		function saveStatus() {
+			var form = $("#statusEditForm");
+			$(form).submit(function (e) {
+				$.ajax({
+					type: "POST",
+					url: '@Url.Action("EditStatus", "Deviation")',
+					data: form.serialize(),
+					success: function (response) {
+						setTimeout(function () {
+							$(".claimEditContainer").remove();
+							if (response == "success") {
+								parent.callCustomEventListener('StatusDataCallbackEventReceiver');
+							} else {
+								$("body").append(response);
+							}
+						}, 200);
+					}
+				});
+				e.preventDefault();
+			});
+			form.submit();
+		}
+	</script>
+
+	@Html.DevExpress().PopupControl(s =>
+{
+	s.Name = "devPopupControlEditStatus";
+
+	if (Model.Id == -1)
+		s.HeaderText = "Neuen Status erstellen";
+	else
+		s.HeaderText = "\"" + Model.Description + "\" bearbeiten";
+
+	s.Modal = true;
+	s.Width = new Unit(250, UnitType.Pixel);
+	s.CloseAction = CloseAction.CloseButton;
+	s.PopupHorizontalAlign = PopupHorizontalAlign.WindowCenter;
+	s.PopupVerticalAlign = PopupVerticalAlign.WindowCenter;
+	s.AllowDragging = false;
+	s.AllowResize = false;
+	s.ShowFooter = false;
+	s.ShowOnPageLoad = true;
+	s.SetContent(() =>
+	{
+		using (Html.BeginForm("EditStatus", "Deviation", FormMethod.Post, new { id = "statusEditForm" }))
+		{
+			ViewContext.Writer.Write("<div class='editFormWrapper'>");
+
+			ViewContext.Writer.Write("<input type=\"hidden\" value=\"" + Model.Id + "\" id=\"Id\" name=\"Id\" />");
+
+			ViewContext.Writer.Write(Html.CustomLabelFor(m => m.Description, "Beschreibung:"));
+			ViewContext.Writer.Write(Html.ValidationMessageFor(m => m.Description).ToHtmlString());
+			Html.DevExpress().TextBoxFor(m => m.Description, t =>
+			{
+				t.Width = new Unit(100, UnitType.Percentage);
+			}).Render();
+
+			ViewContext.Writer.Write("</div>");
+
+			Html.RenderPartial(
+				"~/Views/Shared/_PopupButtonPanel.cshtml",
+				new GreenTree.Nachtragsmanagement.Web.Models.Global.PopupModel
+				{
+					PopupName = "devPopupControlEditStatus",
+					AcceptFunction = "function (s, e) { saveStatus(); }"
+				}
+			);
+		}
+	});
+	s.Styles.Content.Paddings.Padding = new Unit(0);
+	s.Styles.ModalBackground.Opacity = 0;
+}).GetHtml()
+</div>

+ 30 - 0
GreenTree.Nachtragsmanagement.Web/Views/Deviations/_StatusListPartial.cshtml

@@ -0,0 +1,30 @@
+@model IEnumerable<GreenTree.Nachtragsmanagement.Core.Domain.Deviation.Status>
+
+@{ 
+	var userContext = GreenTree.Nachtragsmanagement.Core.CommonHelper.UserContext();
+}
+
+@Html.DevExpress().ListBox(s =>
+{
+	s.Name = "devListBoxStatuses";
+	s.Properties.ValueType = typeof(int);
+	s.Properties.ValueField = "Id";
+	s.Properties.TextField = "Description";
+	if (userContext.CurrentUser.HasFunction("Deviation-Claims-Edit"))
+	{
+		s.SetItemTemplateContent(c =>
+		{
+			ViewContext.Writer.Write(DataBinder.Eval(c.DataItem, "Description"));
+			ViewContext.Writer.Write(
+				"<div class=\"devExListItemControlContainer\">" +
+					"<a href=\"#\" onclick='editClaim(\"status\", " + DataBinder.Eval(c.DataItem, "Id") + ")'>Bearbeiten</a>&nbsp;" +
+					"<a href=\"#\" onclick='confirmDelete(\"status\", " + DataBinder.Eval(c.DataItem, "Id") + ")'>Löschen</a>" +
+				"</div>"
+			);
+		});
+	}
+	s.CallbackRouteValues = new { Controller = "Deviation", Action = "PartialClaims", claimType = "status" };
+	s.Properties.ItemStyle.CssClass += "devExListDataItem";
+	s.Width = Unit.Percentage(100);
+	s.Height = Unit.Pixel(370);
+}).BindList(Model).GetHtml()

+ 16 - 1
GreenTree.Nachtragsmanagement.Web/Views/Home/Index.cshtml

@@ -28,6 +28,8 @@
 	var dragElement = null;
 	var dragStart = {};
 
+	var eventListeners = [];
+
 	@foreach (var g in Model.AvailableFunctions)
 	{
 		foreach (var i in g.Value)
@@ -40,6 +42,18 @@
 		}
 	}
 
+	function addCustomEventListener(name, func) {
+		if (!name || !func) return;
+		eventListeners.push({ name: name, func: func });
+	}
+
+	function callCustomEventListener(name) {
+		for (var i = 0; i < eventListeners.length; i++) {
+			eventListeners[i].func();
+			eventListeners.splice(i, 1);
+		}
+	}
+
 	$(document).ready(function () {
 		$(".functionNavigationContainer").height($(window).height() - $(".globalFooter").height() - 3);
 		$(".functionContentContainer").height($(window).height() - $(".globalFooter").height() - 3);
@@ -252,7 +266,8 @@
 					s.Styles.GroupHeader.Border.BorderStyle = BorderStyle.None;
 					s.Styles.GroupHeader.CssClass += "devExBorderBottom devExBorderBottomGray devExBorderBottomSmall";
 					s.Styles.GroupContent.Border.BorderStyle = BorderStyle.None;
-					s.Styles.GroupContent.CssClass += "devExBorderBottom";
+					s.Styles.GroupContent.CssClass += "devExBorderBottom devExBorderBottomGray devExBorderBottomSmall";
+					s.Styles.GroupContent.ForeColor = System.Drawing.Color.FromArgb(250, 250, 250);
 					s.Styles.Item.Border.BorderStyle = BorderStyle.None;
 					s.Styles.Item.CssClass += "devExBorderBottom";
 

+ 16 - 0
GreenTree.Nachtragsmanagement.Web/Views/Shared/DataEditorTemplates/_AppendicesComboBox.cshtml

@@ -0,0 +1,16 @@
+@model GreenTree.Nachtragsmanagement.Web.Models.Appendix.IRequireAppendixDataModel
+
+@{ 
+	var comboBoxSettingsAction = (Action<ComboBoxSettings>)Session[ViewData["AppendicesComboBoxSettings"].ToString()];
+}
+
+@if (Model == null)
+{
+	Html.DevExpress().ComboBox(comboBoxSettingsAction)
+		.BindList(ViewData["AllAppendices"]).GetHtml();
+}
+else
+{
+	Html.DevExpress().ComboBoxFor(m => m.AppendixId, comboBoxSettingsAction)
+		.BindList(ViewData["AllAppendices"]).Bind(Model.AppendixId).GetHtml();
+}

+ 16 - 0
GreenTree.Nachtragsmanagement.Web/Views/Shared/DataEditorTemplates/_DisturbancesComboBox.cshtml

@@ -0,0 +1,16 @@
+@model GreenTree.Nachtragsmanagement.Web.Models.Deviation.IRequireDisturbanceDataModel
+
+@{ 
+	var comboBoxSettingsAction = (Action<ComboBoxSettings>)Session[ViewData["DisturbancesComboBoxSettings"].ToString()];
+}
+
+@if (Model == null)
+{
+	Html.DevExpress().ComboBox(comboBoxSettingsAction)
+		.BindList(ViewData["AllDisturbances"]).GetHtml();
+}
+else
+{
+	Html.DevExpress().ComboBoxFor(m => m.DisturbanceId, comboBoxSettingsAction)
+		.BindList(ViewData["AllDisturbances"]).Bind(Model.DisturbanceId).GetHtml();
+}

+ 16 - 0
GreenTree.Nachtragsmanagement.Web/Views/Shared/DataEditorTemplates/_KindsComboBox.cshtml

@@ -0,0 +1,16 @@
+@model GreenTree.Nachtragsmanagement.Web.Models.Deviation.IRequireKindDataModel
+
+@{ 
+	var comboBoxSettingsAction = (Action<ComboBoxSettings>)Session[ViewData["KindsComboBoxSettings"].ToString()];
+}
+
+@if (Model == null)
+{
+	Html.DevExpress().ComboBox(comboBoxSettingsAction)
+		.BindList(ViewData["AllKinds"]).GetHtml();
+}
+else
+{
+	Html.DevExpress().ComboBoxFor(m => m.KindId, comboBoxSettingsAction)
+		.BindList(ViewData["AllKinds"]).Bind(Model.KindId).GetHtml();
+}

+ 16 - 0
GreenTree.Nachtragsmanagement.Web/Views/Shared/DataEditorTemplates/_RolesComboBox.cshtml

@@ -0,0 +1,16 @@
+@model GreenTree.Nachtragsmanagement.Web.Models.Admin.User.IRequireRoleDataModel
+
+@{ 
+	var comboBoxSettingsAction = (Action<ComboBoxSettings>)Session[ViewData["RolesComboBoxSettings"].ToString()];
+}
+
+@if (Model == null)
+{
+	Html.DevExpress().ComboBox(comboBoxSettingsAction)
+		.BindList(ViewData["AllRoles"]).GetHtml();
+}
+else
+{
+	Html.DevExpress().ComboBoxFor(m => m.RoleId, comboBoxSettingsAction)
+		.BindList(ViewData["AllRoles"]).Bind(Model.RoleId).GetHtml();
+}

+ 16 - 0
GreenTree.Nachtragsmanagement.Web/Views/Shared/DataEditorTemplates/_StatusesComboBox.cshtml

@@ -0,0 +1,16 @@
+@model GreenTree.Nachtragsmanagement.Web.Models.Deviation.IRequireStatusDataModel
+
+@{ 
+	var comboBoxSettingsAction = (Action<ComboBoxSettings>)Session[ViewData["StatusesComboBoxSettings"].ToString()];
+}
+
+@if (Model == null)
+{
+	Html.DevExpress().ComboBox(comboBoxSettingsAction)
+		.BindList(ViewData["AllStatuses"]).GetHtml();
+}
+else
+{
+	Html.DevExpress().ComboBoxFor(m => m.StatusId, comboBoxSettingsAction)
+		.BindList(ViewData["AllStatuses"]).Bind(Model.StatusId).GetHtml();
+}

+ 2 - 2
GreenTree.Nachtragsmanagement.Web/Views/Shared/_PopupButtonPanel.cshtml

@@ -3,7 +3,7 @@
 <div class="popupButtonPanel">
 	@Html.DevExpress().Button(b =>
 	{
-		b.Name = "devButtonClose";
+		b.Name = Guid.NewGuid().ToString();
 		b.Text = "Abbrechen";
 		b.Width = new Unit(100, UnitType.Pixel);
 		b.ControlStyle.CssClass += "devExFloatRight devExPopupPanelButton";
@@ -12,7 +12,7 @@
 	}).GetHtml()
 	@Html.DevExpress().Button(b =>
 	{
-		b.Name = "devButtonAccept";
+		b.Name = Guid.NewGuid().ToString();
 		b.Text = "Ok";
 		b.Width = new Unit(100, UnitType.Pixel);
 		b.ControlStyle.CssClass += "devExFloatRight devExPopupPanelButton";