瀏覽代碼

Generelles Datenmanagement beinahe fertiggestellt!

Arne Diekmann 8 年之前
父節點
當前提交
589dc04f72
共有 61 個文件被更改,包括 1402 次插入533 次删除
  1. 11 2
      GreenTree.Nachtragsmanagement.Core/Domain/Appendix/Appendix.cs
  2. 10 0
      GreenTree.Nachtragsmanagement.Core/Domain/Appendix/State.cs
  3. 1 1
      GreenTree.Nachtragsmanagement.Core/Domain/Deviation/Deviation.cs
  4. 5 0
      GreenTree.Nachtragsmanagement.Core/Domain/Deviation/Kind.cs
  5. 5 0
      GreenTree.Nachtragsmanagement.Core/Domain/Deviation/Status.cs
  6. 5 0
      GreenTree.Nachtragsmanagement.Core/Domain/User/Function.cs
  7. 5 0
      GreenTree.Nachtragsmanagement.Core/Domain/User/Role.cs
  8. 2 2
      GreenTree.Nachtragsmanagement.Data/AppendixObjectContext.cs
  9. 1 1
      GreenTree.Nachtragsmanagement.Data/Mapping/Appendix/AppendixMap.cs
  10. 2 0
      GreenTree.Nachtragsmanagement.Data/Mapping/Appendix/StateMap.cs
  11. 1 0
      GreenTree.Nachtragsmanagement.Data/Mapping/Deviation/KindMap.cs
  12. 1 0
      GreenTree.Nachtragsmanagement.Data/Mapping/Deviation/StatusMap.cs
  13. 1 0
      GreenTree.Nachtragsmanagement.Data/Mapping/User/FunctionMap.cs
  14. 1 0
      GreenTree.Nachtragsmanagement.Data/Mapping/User/RoleMap.cs
  15. 9 0
      GreenTree.Nachtragsmanagement.Services/Appendix/AppendixService.cs
  16. 5 0
      GreenTree.Nachtragsmanagement.Services/Appendix/IAppendixService.cs
  17. 18 0
      GreenTree.Nachtragsmanagement.Services/Deviation/DeviationService.cs
  18. 10 0
      GreenTree.Nachtragsmanagement.Services/Deviation/IDeviationService.cs
  19. 10 7
      GreenTree.Nachtragsmanagement.Web/App_Start/FunctionConfig.cs
  20. 48 4
      GreenTree.Nachtragsmanagement.Web/Controllers/AppendixController.cs
  21. 72 14
      GreenTree.Nachtragsmanagement.Web/Controllers/DataCallbackController.cs
  22. 61 7
      GreenTree.Nachtragsmanagement.Web/Controllers/DeviationController.cs
  23. 95 20
      GreenTree.Nachtragsmanagement.Web/Controllers/SiteController.cs
  24. 144 136
      GreenTree.Nachtragsmanagement.Web/Global.asax.cs
  25. 1 1
      GreenTree.Nachtragsmanagement.Web/GreenTree.Nachtragsmanagement.Web.csproj
  26. 2 0
      GreenTree.Nachtragsmanagement.Web/Models/Admin/User/RoleDataModel.cs
  27. 29 7
      GreenTree.Nachtragsmanagement.Web/Models/Appendix/AppendixDataModel.cs
  28. 8 2
      GreenTree.Nachtragsmanagement.Web/Models/Appendix/StateDataModel.cs
  29. 10 4
      GreenTree.Nachtragsmanagement.Web/Models/Deviation/DeviationDataModel.cs
  30. 5 2
      GreenTree.Nachtragsmanagement.Web/Models/Deviation/KindDataModel.cs
  31. 5 2
      GreenTree.Nachtragsmanagement.Web/Models/Deviation/StatusDataModel.cs
  32. 2 0
      GreenTree.Nachtragsmanagement.Web/Models/Global/YesNoDialogModel.cs
  33. 11 2
      GreenTree.Nachtragsmanagement.Web/Models/Site/SiteDataModel.cs
  34. 6 2
      GreenTree.Nachtragsmanagement.Web/Models/Site/SiteTreeDataModel.cs
  35. 0 4
      GreenTree.Nachtragsmanagement.Web/Validation/Appendix/AppendixDataModelValidator.cs
  36. 4 0
      GreenTree.Nachtragsmanagement.Web/Validation/Appendix/StateDataModelValidator.cs
  37. 0 16
      GreenTree.Nachtragsmanagement.Web/Validation/Deviation/DeviationDataModelValidator.cs
  38. 5 7
      GreenTree.Nachtragsmanagement.Web/Validation/Site/SiteDataModelValidator.cs
  39. 107 72
      GreenTree.Nachtragsmanagement.Web/Views/Admin/Roles/_RoleEditPartial.cshtml
  40. 38 3
      GreenTree.Nachtragsmanagement.Web/Views/Appendices/Claims.cshtml
  41. 53 8
      GreenTree.Nachtragsmanagement.Web/Views/Appendices/_AppendixEditPartial.cshtml
  42. 1 1
      GreenTree.Nachtragsmanagement.Web/Views/Appendices/_AppendixGridPartial.cshtml
  43. 2 2
      GreenTree.Nachtragsmanagement.Web/Views/Appendices/_CategoryEditPartial.cshtml
  44. 1 1
      GreenTree.Nachtragsmanagement.Web/Views/Appendices/_CategoryListPartial.cshtml
  45. 42 0
      GreenTree.Nachtragsmanagement.Web/Views/Appendices/_StateEditPartial.cshtml
  46. 7 1
      GreenTree.Nachtragsmanagement.Web/Views/Appendices/_StateListPartial.cshtml
  47. 25 7
      GreenTree.Nachtragsmanagement.Web/Views/Deviations/Claims.cshtml
  48. 21 22
      GreenTree.Nachtragsmanagement.Web/Views/Deviations/_DeviationEditPartial.cshtml
  49. 35 0
      GreenTree.Nachtragsmanagement.Web/Views/Deviations/_KindEditPartial.cshtml
  50. 7 1
      GreenTree.Nachtragsmanagement.Web/Views/Deviations/_KindListPartial.cshtml
  51. 35 0
      GreenTree.Nachtragsmanagement.Web/Views/Deviations/_StatusEditPartial.cshtml
  52. 7 1
      GreenTree.Nachtragsmanagement.Web/Views/Deviations/_StatusListPartial.cshtml
  53. 22 1
      GreenTree.Nachtragsmanagement.Web/Views/Home/Index.cshtml
  54. 16 0
      GreenTree.Nachtragsmanagement.Web/Views/Shared/DataEditorTemplates/_CategoriesComboBox.cshtml
  55. 5 2
      GreenTree.Nachtragsmanagement.Web/Views/Shared/DataEditorTemplates/_KindsComboBox.cshtml
  56. 5 2
      GreenTree.Nachtragsmanagement.Web/Views/Shared/DataEditorTemplates/_StatesComboBox.cshtml
  57. 5 2
      GreenTree.Nachtragsmanagement.Web/Views/Shared/DataEditorTemplates/_StatusesComboBox.cshtml
  58. 2 2
      GreenTree.Nachtragsmanagement.Web/Views/Shared/_PopupButtonPanelYesNo.cshtml
  59. 7 26
      GreenTree.Nachtragsmanagement.Web/Views/Sites/View.cshtml
  60. 333 133
      GreenTree.Nachtragsmanagement.Web/Views/Sites/_SiteEditPartial.cshtml
  61. 15 3
      GreenTree.Nachtragsmanagement.Web/Views/Sites/_SiteEditTreePartial.cshtml

+ 11 - 2
GreenTree.Nachtragsmanagement.Core/Domain/Appendix/Appendix.cs

@@ -43,9 +43,9 @@ namespace GreenTree.Nachtragsmanagement.Core.Domain.Appendix
         public decimal? Value { get; set; }
 
         /// <summary>
-        /// Percentage probalitity
+        /// Montary percentage value
         /// </summary>
-        public decimal? Probability { get; set; }
+        public decimal? Percentage { get; set; }
 
         /// <summary>
         /// Number of corresponding offer
@@ -138,5 +138,14 @@ namespace GreenTree.Nachtragsmanagement.Core.Domain.Appendix
             get { return _invoices ?? (_invoices = new List<Invoice.Invoice>()); }
             protected set { _invoices = value; }
         }
+
+        #region Helper
+
+        public void SetCategoryValues(ICollection<CategoryValue> categoryValues)
+        {
+            CategoryValues = categoryValues;
+        }
+
+        #endregion
     }
 }

+ 10 - 0
GreenTree.Nachtragsmanagement.Core/Domain/Appendix/State.cs

@@ -12,5 +12,15 @@ namespace GreenTree.Nachtragsmanagement.Core.Domain.Appendix
         /// Description
         /// </summary>
         public string Description { get; set; }
+
+        /// <summary>
+        /// Color Hex-Code
+        /// </summary>
+        public string HexColor { get; set; }
+
+        /// <summary>
+        /// Determines if this state is defaultly selected
+        /// </summary>
+        public bool IsDefault { get; set; }
     }
 }

+ 1 - 1
GreenTree.Nachtragsmanagement.Core/Domain/Deviation/Deviation.cs

@@ -45,7 +45,7 @@ namespace GreenTree.Nachtragsmanagement.Core.Domain.Deviation
         /// <summary>
         /// Montary percentage value
         /// </summary>
-        public int? Percentage { get; set; }
+        public decimal? Percentage { get; set; }
 
         /// <summary>
         /// Id of corresponding appendix

+ 5 - 0
GreenTree.Nachtragsmanagement.Core/Domain/Deviation/Kind.cs

@@ -17,5 +17,10 @@ namespace GreenTree.Nachtragsmanagement.Core.Domain.Deviation
         /// Shortance
         /// </summary>
         public string Shortance { get; set; }
+
+        /// <summary>
+        /// Determines if this state is defaultly selected
+        /// </summary>
+        public bool IsDefault { get; set; }
     }
 }

+ 5 - 0
GreenTree.Nachtragsmanagement.Core/Domain/Deviation/Status.cs

@@ -12,5 +12,10 @@ namespace GreenTree.Nachtragsmanagement.Core.Domain.Deviation
         /// Description
         /// </summary>
         public string Description { get; set; }
+
+        /// <summary>
+        /// Determines if this state is defaultly selected
+        /// </summary>
+        public bool IsDefault { get; set; }
     }
 }

+ 5 - 0
GreenTree.Nachtragsmanagement.Core/Domain/User/Function.cs

@@ -67,5 +67,10 @@ namespace GreenTree.Nachtragsmanagement.Core.Domain.User
         /// Allow window maximization
         /// </summary>
         public bool? AllowMaximize { get; set; }
+
+        /// <summary>
+        /// Maximized when used
+        /// </summary>
+        public bool? MaximizedOnStart { get; set; }
     }
 }

+ 5 - 0
GreenTree.Nachtragsmanagement.Core/Domain/User/Role.cs

@@ -27,6 +27,11 @@ namespace GreenTree.Nachtragsmanagement.Core.Domain.User
         /// </summary>
         public int Level { get; set; }
 
+        /// <summary>
+        /// Determines if the role can only see sites which it is assigned to
+        /// </summary>
+        public bool SeeOnlyAssigned { get; set; }
+
         /// <summary>
         /// Functions the role have
         /// </summary>

+ 2 - 2
GreenTree.Nachtragsmanagement.Data/AppendixObjectContext.cs

@@ -40,8 +40,6 @@ namespace GreenTree.Nachtragsmanagement.Data
         public AppendixObjectContext(string nameOrConnectionString)
             : base(nameOrConnectionString)
         {
-            ((IObjectContextAdapter)this).ObjectContext.ContextOptions.LazyLoadingEnabled = true;
-
             var userSet = Set<User>();
             var roleSet = Set<Role>();
             var functionSet = Set<Function>();
@@ -86,6 +84,8 @@ namespace GreenTree.Nachtragsmanagement.Data
 
             Database.CreateIfNotExists();
 
+            ((IObjectContextAdapter)this).ObjectContext.ContextOptions.LazyLoadingEnabled = true;
+
             SaveChanges();
         }
 

+ 1 - 1
GreenTree.Nachtragsmanagement.Data/Mapping/Appendix/AppendixMap.cs

@@ -27,7 +27,7 @@ namespace GreenTree.Nachtragsmanagement.Data.Mapping.Appendix
             Property(a => a.Description);
             Property(a => a.Comment);
             Property(a => a.Value);
-            Property(a => a.Probability);
+            Property(a => a.Percentage);
             Property(a => a.OfferingNumber);
             Property(a => a.OfferingDate);
             Property(a => a.NegotiationDate);

+ 2 - 0
GreenTree.Nachtragsmanagement.Data/Mapping/Appendix/StateMap.cs

@@ -16,6 +16,8 @@ namespace GreenTree.Nachtragsmanagement.Data.Mapping.Deviation
             HasKey(f => f.Id);
 
             Property(f => f.Description);
+            Property(f => f.HexColor);
+            Property(f => f.IsDefault);
         }
     }
 }

+ 1 - 0
GreenTree.Nachtragsmanagement.Data/Mapping/Deviation/KindMap.cs

@@ -17,6 +17,7 @@ namespace GreenTree.Nachtragsmanagement.Data.Mapping.Deviation
 
             Property(f => f.Description);
             Property(f => f.Shortance);
+            Property(f => f.IsDefault);
         }
     }
 }

+ 1 - 0
GreenTree.Nachtragsmanagement.Data/Mapping/Deviation/StatusMap.cs

@@ -16,6 +16,7 @@ namespace GreenTree.Nachtragsmanagement.Data.Mapping.Deviation
             HasKey(f => f.Id);
 
             Property(f => f.Description);
+            Property(f => f.IsDefault);
         }
     }
 }

+ 1 - 0
GreenTree.Nachtragsmanagement.Data/Mapping/User/FunctionMap.cs

@@ -27,6 +27,7 @@ namespace GreenTree.Nachtragsmanagement.Data.Mapping.User
             Property(f => f.BaseHeight);
             Property(f => f.MinHeight);
             Property(f => f.AllowMaximize);
+            Property(f => f.MaximizedOnStart);
         }
     }
 }

+ 1 - 0
GreenTree.Nachtragsmanagement.Data/Mapping/User/RoleMap.cs

@@ -17,6 +17,7 @@ namespace GreenTree.Nachtragsmanagement.Data.Mapping.User
 
             Property(r => r.Description);
             Property(r => r.Level);
+            Property(r => r.SeeOnlyAssigned);
 
             HasMany(r => r.Functions)
                 .WithMany()

+ 9 - 0
GreenTree.Nachtragsmanagement.Services/Appendix/AppendixService.cs

@@ -263,6 +263,15 @@ namespace GreenTree.Nachtragsmanagement.Services.Appendix
                 .ToList();
         }
 
+        /// <summary>
+        /// Gets the state which is defaultly selected
+        /// </summary>
+        public State GetDefaultState()
+        {
+            return _stateRepository.Table
+                .FirstOrDefault(s => s.IsDefault);
+        }
+
         /// <summary>
         /// Insert a appendix
         /// </summary>

+ 5 - 0
GreenTree.Nachtragsmanagement.Services/Appendix/IAppendixService.cs

@@ -154,6 +154,11 @@ namespace GreenTree.Nachtragsmanagement.Services.Appendix
         /// <param name="id">State identifier.</param>
         IList<Core.Domain.Appendix.Appendix> GetAppendicesByState(int id);
 
+        /// <summary>
+        /// Gets the state which is defaultly selected
+        /// </summary>
+        State GetDefaultState();
+
         /// <summary>
         /// Insert a state
         /// </summary>

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

@@ -204,6 +204,15 @@ namespace GreenTree.Nachtragsmanagement.Services.Deviation
                 .ToList();
         }
 
+        /// <summary>
+        /// Gets the kind which is defaultly selected
+        /// </summary>
+        public Kind GetDefaultKind()
+        {
+            return _kindRepository.Table
+                .FirstOrDefault(k => k.IsDefault);
+        }
+
         /// <summary>
         /// Insert a kind
         /// </summary>
@@ -273,6 +282,15 @@ namespace GreenTree.Nachtragsmanagement.Services.Deviation
                 .ToList();
         }
 
+        /// <summary>
+        /// Gets the status which is defaultly selected
+        /// </summary>
+        public Status GetDefaultStatus()
+        {
+            return _statusRepository.Table
+                .FirstOrDefault(s => s.IsDefault);
+        }
+
         /// <summary>
         /// Insert a status
         /// </summary>

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

@@ -115,6 +115,11 @@ namespace GreenTree.Nachtragsmanagement.Services.Deviation
         /// <param name="id">Kind identifier.</param>
         IList<Core.Domain.Deviation.Deviation> GetDeviationsByKind(int id);
 
+        /// <summary>
+        /// Gets the kind which is defaultly selected
+        /// </summary>
+        Kind GetDefaultKind();
+
         /// <summary>
         /// Insert a kind
         /// </summary>
@@ -159,6 +164,11 @@ namespace GreenTree.Nachtragsmanagement.Services.Deviation
         /// <param name="id">Status identifier.</param>
         IList<Core.Domain.Deviation.Deviation> GetDeviationsByStatus(int id);
 
+        /// <summary>
+        /// Gets the status which is defaultly selected
+        /// </summary>
+        Status GetDefaultStatus();
+
         /// <summary>
         /// Insert a status
         /// </summary>

+ 10 - 7
GreenTree.Nachtragsmanagement.Web/App_Start/FunctionConfig.cs

@@ -155,7 +155,8 @@ namespace GreenTree.Nachtragsmanagement.Web.App_Start
                     MinWidth = 800,
                     BaseHeight = 650,
                     MinHeight = 500,
-                    AllowMaximize = true
+                    AllowMaximize = true,
+                    MaximizedOnStart = true
                 },
                 new Function
                 {
@@ -168,7 +169,7 @@ namespace GreenTree.Nachtragsmanagement.Web.App_Start
                 new Function
                 {
                     Name = "Deviation-Claims",
-                    Description = "Stammdaten",
+                    Description = "VA-Stammdaten",
                     ImageUrl = "~/Content/Images/function-Deviation-Claims-32.png",
                     GroupName = "Deviation",
                     RouteName = "GreenTree.Nachtragsmanagement.Web.Deviation.Claims",
@@ -183,7 +184,7 @@ namespace GreenTree.Nachtragsmanagement.Web.App_Start
                 new Function
                 {
                     Name = "Deviation-Claims-Edit",
-                    Description = "Stammdaten editieren",
+                    Description = "VA-Stammdaten editieren",
                     GroupName = "Deviation-Claims",
                     IsMenuMember = false,
                     Plugin = "System"
@@ -209,7 +210,8 @@ namespace GreenTree.Nachtragsmanagement.Web.App_Start
                     MinWidth = 800,
                     BaseHeight = 650,
                     MinHeight = 500,
-                    AllowMaximize = true
+                    AllowMaximize = true,
+                    MaximizedOnStart = true
                 },
                 new Function
                 {
@@ -222,7 +224,7 @@ namespace GreenTree.Nachtragsmanagement.Web.App_Start
                 new Function
                 {
                     Name = "Appendix-Claims",
-                    Description = "Stammdaten",
+                    Description = "NT-Stammdaten",
                     ImageUrl = "~/Content/Images/function-Appendix-Claims-32.png",
                     GroupName = "Appendix",
                     RouteName = "GreenTree.Nachtragsmanagement.Web.Appendix.Claims",
@@ -237,7 +239,7 @@ namespace GreenTree.Nachtragsmanagement.Web.App_Start
                 new Function
                 {
                     Name = "Appendix-Claims-Edit",
-                    Description = "Stammdaten editieren",
+                    Description = "NT-Stammdaten editieren",
                     GroupName = "Appendix-Claims",
                     IsMenuMember = false,
                     Plugin = "System"
@@ -263,7 +265,8 @@ namespace GreenTree.Nachtragsmanagement.Web.App_Start
                     MinWidth = 800,
                     BaseHeight = 650,
                     MinHeight = 500,
-                    AllowMaximize = true
+                    AllowMaximize = true,
+                    MaximizedOnStart = true
                 },
                 new Function
                 {

+ 48 - 4
GreenTree.Nachtragsmanagement.Web/Controllers/AppendixController.cs

@@ -94,6 +94,11 @@ namespace GreenTree.Nachtragsmanagement.Web.Controllers
             var appendix = _appendixService.GetAppendixById(id);
             var appendixModel = AppendixDataModel.FromAppendix(appendix, true);
 
+            var defaultState = _appendixService.GetDefaultState();
+
+            if (defaultState != null)
+                ViewData["DefaultState"] = defaultState.Id;
+
             return PartialView("~/Views/Appendices/_AppendixEditPartial.cshtml", appendixModel);
         }
 
@@ -111,11 +116,18 @@ namespace GreenTree.Nachtragsmanagement.Web.Controllers
             var appendixModel = new AppendixDataModel
             {
                 Id = -1,
-                CustomNumber = (lastCustomNumber + 1).ToString()
+                SiteId = siteId,
+                CustomNumber = (lastCustomNumber + 1).ToString(),
+                Percentage = (decimal)0.5
             };
 
-            ViewData["relationType"] = "site";
-            ViewData["relationId"] = siteId;
+            var defaultState = _appendixService.GetDefaultState();
+
+            if (defaultState != null)
+                ViewData["DefaultState"] = defaultState.Id;
+
+            //ViewData["relationType"] = "site";
+            //ViewData["relationId"] = siteId;
 
             return PartialView("~/Views/Appendices/_AppendixEditPartial.cshtml", appendixModel);
         }
@@ -135,6 +147,8 @@ namespace GreenTree.Nachtragsmanagement.Web.Controllers
             for (int i = 0; i < appendixModel.CategoryValueEntities.Count; i++)
                 appendixModel.CategoryValueEntities.ElementAt(i).Json = appendixModel.CategoryEntities.ElementAt(i);
 
+            appendixModel.PercentageValue = appendixModel.OfferingValue * appendixModel.Percentage;
+
             if (!ModelState.IsValid)
                 return PartialView("~/Views/Appendices/_AppendixEditPartial.cshtml", appendixModel);
 
@@ -146,6 +160,8 @@ namespace GreenTree.Nachtragsmanagement.Web.Controllers
             {
                 var appendix = appendixModel.ToAppendix();
 
+                appendix.SetCategoryValues(categoryValues);
+
                 _appendixService.InsertAppendix(appendix);
             }
             else
@@ -154,18 +170,21 @@ namespace GreenTree.Nachtragsmanagement.Web.Controllers
 
                 appendix.CustomNumber = appendixModel.CustomNumber;
                 appendix.Description = appendixModel.Description;
-                appendix.Probability = appendixModel.Probability;
+                appendix.Percentage = appendixModel.Percentage;
                 appendix.OfferingNumber = appendixModel.OfferingNumber;
                 appendix.OfferingDate = appendixModel.OfferingDate;
                 appendix.NegotiationDate = appendixModel.NegotiationDate;
                 appendix.NegotiationValue = appendixModel.NegotiationValue;
                 appendix.ProtocolExists = appendixModel.ProtocolExists;
+                appendix.StateId = appendixModel.StateId;
                 appendix.OrderNumber = appendixModel.OrderNumber;
                 appendix.OrderDate = appendixModel.OrderDate;
                 appendix.OrderInvoiceCreated = appendixModel.OrderInvoiceCreated;
                 appendix.Comment = appendixModel.Comment;
                 appendix.SiteId = appendixModel.SiteId;
 
+                appendix.SetCategoryValues(categoryValues);
+
                 _appendixService.UpdateAppendix(appendix);
             }
 
@@ -302,6 +321,8 @@ namespace GreenTree.Nachtragsmanagement.Web.Controllers
                 var state = _appendixService.GetStateById(stateModel.Id);
 
                 state.Description = stateModel.Description;
+                state.HexColor = stateModel.HexColor;
+                state.IsDefault = stateModel.IsDefault;
 
                 _appendixService.UpdateState(state);
             }
@@ -371,6 +392,29 @@ namespace GreenTree.Nachtragsmanagement.Web.Controllers
                     if (state != null)
                         _appendixService.DeleteState(state);
                     break;
+                case "category":
+                    var category = _appendixService.GetCategoryById(id);
+                    var replaceCategory = _appendixService.GetCategoryById(replaceId);
+
+                    var allAppendices = _appendixService.GetAllAppendices();
+
+                    foreach (var appendix in allAppendices)
+                    {
+                        foreach (var categoryValue in appendix.CategoryValues)
+                        {
+                            if (categoryValue.CategoryId == id)
+                            {
+                                categoryValue.Category = replaceCategory;
+                                categoryValue.CategoryId = replaceCategory.Id;
+                            }
+                        }
+
+                        _appendixService.UpdateAppendix(appendix);
+                    }
+
+                    if (category != null)
+                        _appendixService.DeleteCategory(category);
+                    break;
                 default:
                     return new EmptyResult();
             }

+ 72 - 14
GreenTree.Nachtragsmanagement.Web/Controllers/DataCallbackController.cs

@@ -123,6 +123,14 @@ namespace GreenTree.Nachtragsmanagement.Web.Controllers
                 }
             }
 
+            var defaultStatusId =
+                allStatuses
+                    .Any(s => s.IsDefault)
+                        ? allStatuses
+                            .First(s => s.IsDefault).Id
+                        : -1;
+
+            ViewData["DefaultStatus"] = defaultStatusId;
             ViewData["AllStatuses"] = allStatuses;
             ViewData["StatusesComboBoxSettings"] = settingsKey;
 
@@ -192,20 +200,7 @@ namespace GreenTree.Nachtragsmanagement.Web.Controllers
         /// <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);
+            return KindsComboBoxExcluded(settingsKey, model, type, null);
         }
 
         /// <summary>
@@ -230,6 +225,14 @@ namespace GreenTree.Nachtragsmanagement.Web.Controllers
                 }
             }
 
+            var defaultKindId =
+                allKinds
+                    .Any(s => s.IsDefault)
+                        ? allKinds
+                            .First(s => s.IsDefault).Id
+                        : -1;
+
+            ViewData["DefaultKind"] = defaultKindId;
             ViewData["AllKinds"] = allKinds;
             ViewData["KindsComboBoxSettings"] = settingsKey;
 
@@ -281,6 +284,14 @@ namespace GreenTree.Nachtragsmanagement.Web.Controllers
                 }
             }
 
+            var defaultStateId =
+                allStates
+                    .Any(s => s.IsDefault)
+                        ? allStates
+                            .First(s => s.IsDefault).Id
+                        : -1;
+
+            ViewData["DefaultState"] = defaultStateId;
             ViewData["AllStates"] = allStates;
             ViewData["StatesComboBoxSettings"] = settingsKey;
 
@@ -295,6 +306,53 @@ namespace GreenTree.Nachtragsmanagement.Web.Controllers
             return PartialView("~/Views/Shared/DataEditorTemplates/_StatesComboBox.cshtml", null);
         }
 
+        /// <summary>
+        /// Returns a DevExpress ComboBox for all categories 
+        /// </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 CategoriesComboBox(string settingsKey, string model, string type)
+        {
+            return CategoriesComboBoxExcluded(settingsKey, model, type, null);
+        }
+
+        /// <summary>
+        /// Returns a DevExpress ComboBox for all categories 
+        /// </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 categories.</param>
+        public ActionResult CategoriesComboBoxExcluded(string settingsKey, string model, string type, int[] excludedIds)
+        {
+            var allCategories = _appendixService.GetAllCategories();
+
+            if (excludedIds != null)
+            {
+                foreach (var excludedId in excludedIds)
+                {
+                    var item = allCategories
+                        .FirstOrDefault(s => s.Id == excludedId);
+
+                    allCategories.Remove(item);
+                }
+            }
+
+            ViewData["AllCategories"] = allCategories;
+            ViewData["CategoriesComboBoxSettings"] = settingsKey;
+
+            if (model != null && type != null)
+            {
+                var modelType = Type.GetType(type);
+                var modelObject = JsonConvert.DeserializeObject(model, modelType, _serializerSettings);
+
+                return PartialView("~/Views/Shared/DataEditorTemplates/_CategoriesComboBox.cshtml", modelObject);
+            }
+
+            return PartialView("~/Views/Shared/DataEditorTemplates/_CategoriesComboBox.cshtml", null);
+        }
+
         #endregion
     }
 }

+ 61 - 7
GreenTree.Nachtragsmanagement.Web/Controllers/DeviationController.cs

@@ -96,6 +96,15 @@ namespace GreenTree.Nachtragsmanagement.Web.Controllers
             var deviation = _deviationService.GetDeviationById(id);
             var deviationModel = DeviationDataModel.FromDeviation(deviation, true);
 
+            var defaultKind = _deviationService.GetDefaultKind();
+            var defaultStatus = _deviationService.GetDefaultStatus();
+
+            if (defaultKind != null)
+                ViewData["DefaultKind"] = defaultKind.Id;
+
+            if (defaultStatus != null)
+                ViewData["DefaultStatus"] = defaultStatus.Id;
+
             return PartialView("~/Views/Deviations/_DeviationEditPartial.cshtml", deviationModel);
         }
 
@@ -121,12 +130,22 @@ namespace GreenTree.Nachtragsmanagement.Web.Controllers
             var deviationModel = new DeviationDataModel
             {
                 Id = -1,
+                SiteId = siteId,
                 CustomNumber = (lastCustomNumber + 1).ToString(),
-                Percentage = 100,
+                Percentage = 1,
             };
 
-            ViewData["relationType"] = "site";
-            ViewData["relationId"] = siteId;
+            var defaultKind = _deviationService.GetDefaultKind();
+            var defaultStatus = _deviationService.GetDefaultStatus();
+
+            if (defaultKind != null)
+                ViewData["DefaultKind"] = defaultKind.Id;
+
+            if (defaultStatus != null)
+                ViewData["DefaultStatus"] = defaultStatus.Id;
+
+            //ViewData["relationType"] = "site";
+            //ViewData["relationId"] = siteId;
 
             return PartialView("~/Views/Deviations/_DeviationEditPartial.cshtml", deviationModel);
         }
@@ -155,12 +174,22 @@ namespace GreenTree.Nachtragsmanagement.Web.Controllers
             var deviationModel = new DeviationDataModel
             {
                 Id = -1,
+                AppendixId = appendixId,
                 CustomNumber = (lastCustomNumber + 1).ToString(),
-                Percentage = 100,
+                Percentage = 1,
             };
 
-            ViewData["relationType"] = "appendix";
-            ViewData["relationId"] = appendixId;
+            var defaultKind = _deviationService.GetDefaultKind();
+            var defaultStatus = _deviationService.GetDefaultStatus();
+
+            if (defaultKind != null)
+                ViewData["DefaultKind"] = defaultKind.Id;
+
+            if (defaultStatus != null)
+                ViewData["DefaultStatus"] = defaultStatus.Id;
+
+            //ViewData["relationType"] = "appendix";
+            //ViewData["relationId"] = appendixId;
 
             return PartialView("~/Views/Deviations/_DeviationEditPartial.cshtml", deviationModel);
         }
@@ -180,7 +209,7 @@ namespace GreenTree.Nachtragsmanagement.Web.Controllers
             for (int i = 0; i < deviationModel.DisturbanceValueEntities.Count; i++)
                 deviationModel.DisturbanceValueEntities.ElementAt(i).Json = deviationModel.DisturbanceEntities.ElementAt(i);
 
-            deviationModel.PercentageValue = deviationModel.Value * ((decimal)deviationModel.Percentage / (decimal)100);
+            deviationModel.PercentageValue = deviationModel.Value * deviationModel.Percentage;
 
             if (!ModelState.IsValid)
                 return PartialView("~/Views/Deviations/_DeviationEditPartial.cshtml", deviationModel);
@@ -364,6 +393,7 @@ namespace GreenTree.Nachtragsmanagement.Web.Controllers
                 var status = _deviationService.GetStatusById(statusModel.Id);
 
                 status.Description = statusModel.Description;
+                status.IsDefault = statusModel.IsDefault;
 
                 _deviationService.UpdateStatus(status);
             }
@@ -426,6 +456,7 @@ namespace GreenTree.Nachtragsmanagement.Web.Controllers
                 var kind = _deviationService.GetKindById(kindModel.Id);
 
                 kind.Description = kindModel.Description;
+                kind.IsDefault = kindModel.IsDefault;
 
                 _deviationService.UpdateKind(kind);
             }
@@ -481,6 +512,29 @@ namespace GreenTree.Nachtragsmanagement.Web.Controllers
                     if (kind != null)
                         _deviationService.DeleteKind(kind);
                     break;
+                case "disturbance":
+                    var disturbance = _deviationService.GetDisturbanceById(id);
+                    var replaceDisturbance = _deviationService.GetDisturbanceById(replaceId);
+
+                    var allDeviations = _deviationService.GetAllDeviations();
+
+                    foreach (var deviation in allDeviations)
+                    {
+                        foreach (var disturbanceValue in deviation.DisturbanceValues)
+                        {
+                            if (disturbanceValue.DisturbanceId == id)
+                            {
+                                disturbanceValue.Disturbance = replaceDisturbance;
+                                disturbanceValue.DisturbanceId = replaceDisturbance.Id;
+                            }
+                        }
+
+                        _deviationService.UpdateDeviation(deviation);
+                    }
+
+                    if (disturbance != null)
+                        _deviationService.DeleteDisturbance(disturbance);
+                    break;
                 default:
                     return new EmptyResult();
             }

+ 95 - 20
GreenTree.Nachtragsmanagement.Web/Controllers/SiteController.cs

@@ -1,4 +1,5 @@
 using GreenTree.Nachtragsmanagement.Core.Domain.Deviation;
+using GreenTree.Nachtragsmanagement.Core.Domain.User;
 using GreenTree.Nachtragsmanagement.Services.Appendix;
 using GreenTree.Nachtragsmanagement.Services.Deviation;
 using GreenTree.Nachtragsmanagement.Services.Site;
@@ -140,34 +141,20 @@ namespace GreenTree.Nachtragsmanagement.Web.Controllers
         {
             if (!ModelState.IsValid)
             {
-                //foreach (var deviation in siteModel.DeviationValues)
-                //    siteModel.DeviationDescriptions.Add(
-                //        ((IList<Deviation>)ViewData["AllDeviations"])
-                //            .First(r => r.Id == deviation).Description);
-
-                //foreach (var deviation in siteModel.DeviationValues)
-                //    siteModel.DeviationDescriptions.Add(
-                //        ((IList<Deviation>)ViewData["AllDeviations"])
-                //            .First(r => r.Id == deviation).Description);
-
-                //foreach (var deviation in siteModel.DeviationValues)
-                //    siteModel.DeviationDescriptions.Add(
-                //        ((IList<Deviation>)ViewData["AllDeviations"])
-                //            .First(r => r.Id == deviation).Description);
+                foreach (var role in siteModel.UserValues)
+                    siteModel.UserDescriptions.Add(
+                        ((IList<User>)ViewData["AllUsers"])
+                            .First(r => r.Id == role).Lastname);
 
                 return PartialView("~/Views/Sites/_SiteEditPartial.cshtml", siteModel);
             }
 
-            var selectedDeviations = _deviationService.GetDeviationsByIds(siteModel.DeviationValues.ToArray());
-            var selectedAppendices = _appendixService.GetAppendicesByIds(siteModel.AppendixValues.ToArray());
             var selectedUsers = _userService.GetUsersByIds(siteModel.UserValues.ToArray());
 
             if (siteModel.Id == -1)
             {
                 var site = siteModel.ToSite();
 
-                site.SetDeviations(selectedDeviations);
-                site.SetAppendices(selectedAppendices);
                 site.SetUsers(selectedUsers);
 
                 _siteService.InsertSite(site);
@@ -182,8 +169,6 @@ namespace GreenTree.Nachtragsmanagement.Web.Controllers
                 site.End = siteModel.End;
                 site.Comment = siteModel.Comment;
 
-                site.SetDeviations(selectedDeviations);
-                site.SetAppendices(selectedAppendices);
                 site.SetUsers(selectedUsers);
 
                 _siteService.UpdateSite(site);
@@ -195,6 +180,41 @@ namespace GreenTree.Nachtragsmanagement.Web.Controllers
             };
         }
 
+
+        /// <summary>
+        /// Partial edit result if ModelState is valid, otherwise simple JSON result for success
+        /// </summary>
+        /// <param name="siteModel">Site model to be saved.</param>
+        [HttpPost, ValidateInput(false)]
+        public ActionResult EditSiteForAppend(SiteDataModel siteModel)
+        {
+            if (!ModelState.IsValid)
+            {
+                foreach (var role in siteModel.UserValues)
+                    siteModel.UserDescriptions.Add(
+                        ((IList<User>)ViewData["AllUsers"])
+                            .First(r => r.Id == role).Lastname);
+
+                return PartialView("~/Views/Sites/_SiteEditPartial.cshtml", siteModel);
+            }
+
+            var selectedUsers = _userService.GetUsersByIds(siteModel.UserValues.ToArray());
+            var siteId = siteModel.Id;
+
+            if (siteModel.Id == -1)
+            {
+                var site = siteModel.ToSite();
+
+                site.SetUsers(selectedUsers);
+
+                _siteService.InsertSite(site);
+
+                siteId = site.Id;
+            }
+
+            return EditSite(siteId);
+        }
+
         /// <summary>
         /// Simple JSON result for deleting a specific site
         /// </summary>
@@ -214,5 +234,60 @@ namespace GreenTree.Nachtragsmanagement.Web.Controllers
         }
 
         #endregion
+
+        #region Assigning
+
+        /// <summary>
+        /// Assigns a deviation to an existing entity of type site or appendix
+        /// </summary>
+        /// <param name="siteId">The siteId in which the context works.</param>
+        /// <param name="sourceKey">The sourceKey of the deviation.</param>
+        /// <param name="targetKey">The targetKey of the site or appendix.</param>
+        public ActionResult AssignDeviationToEntity(int siteId, string sourceKey, string targetKey)
+        {
+            if (!sourceKey.StartsWith("d"))
+            {
+                return new JsonResult
+                {
+                    Data = "invalidSourceKey"
+                };
+            }
+
+            var deviationId = Convert.ToInt32(sourceKey.Replace("d_", String.Empty));
+            var deviation = _deviationService.GetDeviationById(deviationId);
+
+            if (targetKey == "a_0")
+            {
+                var site = _siteService.GetSiteById(siteId);
+
+                deviation.Appendix = null;
+                deviation.AppendixId = null;
+
+                site.Deviations.Add(deviation);
+
+                _siteService.UpdateSite(site);
+                _deviationService.UpdateDeviation(deviation);
+            }
+            else
+            {
+                var appendixId = Convert.ToInt32(targetKey.Replace("a_", String.Empty));
+                var appendix = _appendixService.GetAppendixById(appendixId);
+
+                deviation.Site = null;
+                deviation.SiteId = null;
+
+                appendix.Deviations.Add(deviation);
+
+                _appendixService.UpdateAppendix(appendix);
+                _deviationService.UpdateDeviation(deviation);
+            }
+
+            return new JsonResult
+            {
+                Data = "success"
+            };
+        }
+
+        #endregion
     }
 }

+ 144 - 136
GreenTree.Nachtragsmanagement.Web/Global.asax.cs

@@ -92,28 +92,32 @@ namespace GreenTree.Nachtragsmanagement.Web
                 var r1 = new Role
                 {
                     Description = "Administrator",
-                    Level = 100
+                    Level = 100,
+                    SeeOnlyAssigned = false
                 };
                 userService.InsertRole(r1);
 
                 var r2 = new Role
                 {
                     Description = "Kaufmann",
-                    Level = 10
+                    Level = 10,
+                    SeeOnlyAssigned = true
                 };
                 userService.InsertRole(r2);
 
                 var r3 = new Role
                 {
                     Description = "Nachtragsmanager",
-                    Level = 10
+                    Level = 10,
+                    SeeOnlyAssigned = false
                 };
                 userService.InsertRole(r3);
 
                 var r4 = new Role
                 {
                     Description = "Bauleiter",
-                    Level = 10
+                    Level = 10,
+                    SeeOnlyAssigned = true
                 };
                 userService.InsertRole(r4);
 
@@ -215,7 +219,7 @@ namespace GreenTree.Nachtragsmanagement.Web
                 u2.Roles.Add(r1);
                 u3.Roles.Add(r1);
                 u4.Roles.Add(r3);
-                u4.Roles.Add(r3);
+                u8.Roles.Add(r3);
                 u5.Roles.Add(r4);
                 u7.Roles.Add(r4);
                 u6.Roles.Add(r2);
@@ -258,96 +262,100 @@ namespace GreenTree.Nachtragsmanagement.Web
 
                 var categories = new[]
                 {
-                new Category { Description = "RPM" },
-                new Category { Description = "RM" },
-                new Category { Description = "Stopftechnik" },
-                new Category { Description = "Umbauzug" },
-                new Category { Description = "Logistik" },
-                new Category { Description = "Oberbau" },
-                new Category { Description = "Erdbau" },
-                new Category { Description = "Kabeltiefbau" },
-                new Category { Description = "Entwässerung" },
-                new Category { Description = "Sonstiges" }
-            };
+                    new Category { Description = "RPM" },
+                    new Category { Description = "RM" },
+                    new Category { Description = "Stopftechnik" },
+                    new Category { Description = "Umbauzug" },
+                    new Category { Description = "Logistik" },
+                    new Category { Description = "Oberbau" },
+                    new Category { Description = "Erdbau" },
+                    new Category { Description = "Kabeltiefbau" },
+                    new Category { Description = "Entwässerung" },
+                    new Category { Description = "Sonstiges" }
+                };
 
                 foreach (var category in categories)
                     appendixService.InsertCategory(category);
 
                 var states = new[]
                 {
-                new State { Description = "Offen" },
-                new State { Description = "Erinnerung Verhandlung" },
-                new State { Description = "Verhandelt" },
-                new State { Description = "Erledigt / Entfällt" }
-            };
+                    new State { Description = "Offen", IsDefault = true, HexColor = "#FFFFFF" },
+                    new State { Description = "Erinnerung Verhandlung", IsDefault = false, HexColor = "#D90800" },
+                    new State { Description = "Verhandelt", IsDefault = false, HexColor = "#CECECE" },
+                    new State { Description = "Erledigt / Entfällt", IsDefault = false, HexColor = "#00A800" }
+                };
 
                 foreach (var state in states)
                     appendixService.InsertState(state);
 
                 var appendices = new[]
                 {
-                new Appendix
-                {
-                    CustomNumber = "3",
-                    Description = "Lückenschluss Weiche 523",
-                    State = states[0],
-                    StateId = states[0].Id,
-                    CategoryValues =
+                    new Appendix
                     {
-                        new CategoryValue { Category = categories[2], CategoryId = categories[2].Id, Value = 44000 },
-                        new CategoryValue { Category = categories[3], CategoryId = categories[3].Id, Value = 30000 },
+                        CustomNumber = "3",
+                        Description = "Lückenschluss Weiche 523",
+                        State = states[0],
+                        StateId = states[0].Id,
+                        CategoryValues =
+                        {
+                            new CategoryValue { Category = categories[2], CategoryId = categories[2].Id, Value = 44000 },
+                            new CategoryValue { Category = categories[3], CategoryId = categories[3].Id, Value = 30000 },
+                        },
+                        Value = Convert.ToDecimal(74833.6),
+                        Percentage = (decimal)0.5,
+                        NegotiationValue = 70000,
+                        OfferingDate = new DateTime(2016, 12, 20),
+                        Comment = "hier 3 % NA enthalten = Delta zu iTWO  = 77148,04€, Abgabeddatum per Mail, Post später"
                     },
-                    Value = Convert.ToDecimal(74833.6),
-                    NegotiationValue = 70000,
-                    OfferingDate = new DateTime(2016, 12, 20),
-                    Comment = "hier 3 % NA enthalten = Delta zu iTWO  = 77148,04€, Abgabeddatum per Mail, Post später"
-                },
-                new Appendix
-                {
-                    CustomNumber = "6",
-                    Description = "Erschwerniss masch. Gleisbau ZEB 22",
-                    State = states[0],
-                    StateId = states[0].Id,
-                    CategoryValues =
+                    new Appendix
                     {
-                        new CategoryValue { Category = categories[0], CategoryId = categories[0].Id, Value = 43000 }
+                        CustomNumber = "6",
+                        Description = "Erschwerniss masch. Gleisbau ZEB 22",
+                        State = states[0],
+                        StateId = states[0].Id,
+                        CategoryValues =
+                        {
+                            new CategoryValue { Category = categories[0], CategoryId = categories[0].Id, Value = 43000 }
+                        },
+                        Value = Convert.ToDecimal(43514.35),
+                        Percentage = (decimal)0.5,
+                        NegotiationValue = 40000,
+                        OfferingDate = new DateTime(2016, 12, 20),
+                        Comment = "Teilweise Abrechnung über HLV in Höhe von 5322,12€ (nicht in Summe oben enthalten) hier 3 % NA enthalten = Delta zu iTWO  = 44860,15€ Abgabeddatum per Mail, Post später"
                     },
-                    Value = Convert.ToDecimal(43514.35),
-                    NegotiationValue = 40000,
-                    OfferingDate = new DateTime(2016, 12, 20),
-                    Comment = "Teilweise Abrechnung über HLV in Höhe von 5322,12€ (nicht in Summe oben enthalten) hier 3 % NA enthalten = Delta zu iTWO  = 44860,15€ Abgabeddatum per Mail, Post später"
-                },
-                new Appendix
-                {
-                    CustomNumber = "1",
-                    Description = "Umsetzen von Haufwerken",
-                    State = states[0],
-                    StateId = states[0].Id,
-                    CategoryValues =
+                    new Appendix
                     {
-                        new CategoryValue { Category = categories[9], CategoryId = categories[9].Id, Value = 2500 }
+                        CustomNumber = "1",
+                        Description = "Umsetzen von Haufwerken",
+                        State = states[0],
+                        StateId = states[0].Id,
+                        CategoryValues =
+                        {
+                            new CategoryValue { Category = categories[9], CategoryId = categories[9].Id, Value = 2500 }
+                        },
+                        Value = Convert.ToDecimal(2549.18),
+                        Percentage = (decimal)0.5,
+                        NegotiationValue = 2000,
+                        OfferingDate = new DateTime(2017, 2, 2),
+                        Comment = "Beginn der Frist der Nachtragsprüfung 16.02.17"
                     },
-                    Value = Convert.ToDecimal(2549.18),
-                    NegotiationValue = 2000,
-                    OfferingDate = new DateTime(2017, 2, 2),
-                    Comment = "Beginn der Frist der Nachtragsprüfung 16.02.17"
-                },
-                new Appendix
-                {
-                    CustomNumber = "2",
-                    Description = "Nichtbereitstellung der Ladevorrichtung",
-                    State = states[0],
-                    StateId = states[0].Id,
-                    CategoryValues =
+                    new Appendix
                     {
-                        new CategoryValue { Category = categories[4], CategoryId = categories[4].Id }
-                    },
-                    Value = Convert.ToDecimal(23738.06),
-                    NegotiationValue = 20000,
-                    OfferingDate = new DateTime(2017, 2, 3),
-                    Comment = "Aufmaße noch nicht erstellt"
-                }
-            };
+                        CustomNumber = "2",
+                        Description = "Nichtbereitstellung der Ladevorrichtung",
+                        State = states[0],
+                        StateId = states[0].Id,
+                        CategoryValues =
+                        {
+                            new CategoryValue { Category = categories[4], CategoryId = categories[4].Id }
+                        },
+                        Value = Convert.ToDecimal(23738.06),
+                        Percentage = (decimal)0.5,
+                        NegotiationValue = 20000,
+                        OfferingDate = new DateTime(2017, 2, 3),
+                        Comment = "Aufmaße noch nicht erstellt"
+                    }
+                };
 
                 foreach (var appendix in appendices)
                     appendixService.InsertAppendix(appendix);
@@ -356,43 +364,43 @@ namespace GreenTree.Nachtragsmanagement.Web
 
                 var sites = new[]
                 {
-                new Site
-                {
-                    CustomNumber = "2101000",
-                    Description = "POS Nord Kaiserslautern Los 19-21",
-                    Appendices =
-                    {
-                        appendices[0],
-                        appendices[1]
-                    },
-                    Finished = false,
-                    Start = new DateTime(2016, 1, 1),
-                    Users =
-                    {
-                        u4,
-                        u5,
-                        u6
-                    }
-                },
-                new Site
-                {
-                    CustomNumber = "211200",
-                    Description = "GE Geisenheim-Rüdesheim",
-                    Appendices =
+                    new Site
                     {
-                        appendices[2],
-                        appendices[3]
+                        CustomNumber = "2101000",
+                        Description = "POS Nord Kaiserslautern Los 19-21",
+                        Appendices =
+                        {
+                            appendices[0],
+                            appendices[1]
+                        },
+                        Finished = false,
+                        Start = new DateTime(2016, 1, 1),
+                        Users =
+                        {
+                            u4,
+                            u5,
+                            u6
+                        }
                     },
-                    Finished = false,
-                    Start = new DateTime(2016, 1, 1),
-                    Users =
+                    new Site
                     {
-                        u7,
-                        u8,
-                        u9
+                        CustomNumber = "211200",
+                        Description = "GE Geisenheim-Rüdesheim",
+                        Appendices =
+                        {
+                            appendices[2],
+                            appendices[3]
+                        },
+                        Finished = false,
+                        Start = new DateTime(2016, 1, 1),
+                        Users =
+                        {
+                            u7,
+                            u8,
+                            u9
+                        }
                     }
-                }
-            };
+                };
 
                 foreach (var site in sites)
                     siteService.InsertSite(site);
@@ -401,38 +409,38 @@ namespace GreenTree.Nachtragsmanagement.Web
 
                 var kinds = new[]
                 {
-                new Kind { Shortance = "MK", Description = "Mehrkosten" },
-                new Kind { Shortance = "BH", Description = "Behinderung" },
-                new Kind { Shortance = "BD", Description = "Bedenken" }
-            };
+                    new Kind { Shortance = "MK", Description = "Mehrkosten", IsDefault = true },
+                    new Kind { Shortance = "BH", Description = "Behinderung", IsDefault = false },
+                    new Kind { Shortance = "BD", Description = "Bedenken", IsDefault = false }
+                };
 
                 foreach (var kind in kinds)
                     deviationService.InsertKind(kind);
 
                 var disturbances = new[]
                 {
-                new Disturbance { Description = "RPM" },
-                new Disturbance { Description = "RM" },
-                new Disturbance { Description = "Stopftechnik" },
-                new Disturbance { Description = "Umbauzug" },
-                new Disturbance { Description = "Logistik" },
-                new Disturbance { Description = "Oberbau" },
-                new Disturbance { Description = "Erdbau" },
-                new Disturbance { Description = "Kabeltiefbau" },
-                new Disturbance { Description = "Entwässerung" },
-                new Disturbance { Description = "Sonstiges" }
-            };
+                    new Disturbance { Description = "RPM" },
+                    new Disturbance { Description = "RM" },
+                    new Disturbance { Description = "Stopftechnik" },
+                    new Disturbance { Description = "Umbauzug" },
+                    new Disturbance { Description = "Logistik" },
+                    new Disturbance { Description = "Oberbau" },
+                    new Disturbance { Description = "Erdbau" },
+                    new Disturbance { Description = "Kabeltiefbau" },
+                    new Disturbance { Description = "Entwässerung" },
+                    new Disturbance { Description = "Sonstiges" }
+                };
 
                 foreach (var disturbance in disturbances)
                     deviationService.InsertDisturbance(disturbance);
 
                 var statuses = new[]
                 {
-                new Status { Description = "Standard" },
-                new Status { Description = "Entfällt" },
-                new Status { Description = "Strittig" },
-                new Status { Description = "Abr. über HLV" }
-            };
+                    new Status { Description = "Standard", IsDefault = true },
+                    new Status { Description = "Entfällt", IsDefault = false },
+                    new Status { Description = "Strittig", IsDefault = false },
+                    new Status { Description = "Abr. über HLV", IsDefault = false }
+                };
 
                 foreach (var status in statuses)
                     deviationService.InsertStatus(status);
@@ -452,7 +460,7 @@ namespace GreenTree.Nachtragsmanagement.Web
                         Status = statuses[0],
                         StatusId = statuses[0].Id,
                         Value = 40000,
-                        Percentage = 100,
+                        Percentage = 1,
                         Appendix = appendices[0],
                         AppendixId = appendices[0].Id,
                         AppendixDate = appendices[0].OfferingDate
@@ -488,7 +496,7 @@ namespace GreenTree.Nachtragsmanagement.Web
                         Status = statuses[0],
                         StatusId = statuses[0].Id,
                         Value = 2000,
-                        Percentage = 100,
+                        Percentage = 1,
                         Appendix = appendices[1],
                         AppendixId = appendices[1].Id,
                         AppendixDate = appendices[1].OfferingDate
@@ -506,7 +514,7 @@ namespace GreenTree.Nachtragsmanagement.Web
                         Status = statuses[2],
                         StatusId = statuses[2].Id,
                         Value = 40000,
-                        Percentage = 30,
+                        Percentage = (decimal)0.3,
                         Site = sites[0],
                         SiteId = sites[0].Id
                     },
@@ -523,7 +531,7 @@ namespace GreenTree.Nachtragsmanagement.Web
                         Status = statuses[0],
                         StatusId = statuses[0].Id,
                         Value = 2500,
-                        Percentage = 100,
+                        Percentage = 1,
                         Appendix = appendices[2],
                         AppendixId = appendices[2].Id,
                         AppendixDate = appendices[2].OfferingDate
@@ -541,7 +549,7 @@ namespace GreenTree.Nachtragsmanagement.Web
                         Status = statuses[0],
                         StatusId = statuses[0].Id,
                         Value = 10000,
-                        Percentage = 100,
+                        Percentage = 1,
                         Appendix = appendices[3],
                         AppendixId = appendices[3].Id,
                         AppendixDate = appendices[3].OfferingDate
@@ -559,7 +567,7 @@ namespace GreenTree.Nachtragsmanagement.Web
                         Status = statuses[3],
                         StatusId = statuses[3].Id,
                         Value = 10000,
-                        Percentage = 110,
+                        Percentage = 1,
                         Appendix = appendices[3],
                         AppendixId = appendices[3].Id,
                         AppendixDate = appendices[3].OfferingDate
@@ -577,7 +585,7 @@ namespace GreenTree.Nachtragsmanagement.Web
                         Status = statuses[2],
                         StatusId = statuses[2].Id,
                         Value = 6000,
-                        Percentage = 50,
+                        Percentage = (decimal)0.5,
                         Site = sites[1],
                         SiteId = sites[1].Id
                     }

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

@@ -281,6 +281,7 @@
     <Content Include="Views\Appendices\Claims.cshtml" />
     <Content Include="Views\Appendices\_StateEditPartial.cshtml" />
     <Content Include="Views\Appendices\_StateListPartial.cshtml" />
+    <Content Include="Views\Shared\DataEditorTemplates\_CategoriesComboBox.cshtml" />
     <None Include="Web.Debug.config">
       <DependentUpon>Web.config</DependentUpon>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
@@ -352,7 +353,6 @@
   <ItemGroup>
     <Folder Include="App_Data\" />
     <Folder Include="Fonts\" />
-    <Folder Include="Views\DataCallback\" />
   </ItemGroup>
   <ItemGroup>
     <ProjectReference Include="..\GreenTree.Nachtragsmanagement.Core\GreenTree.Nachtragsmanagement.Core.csproj">

+ 2 - 0
GreenTree.Nachtragsmanagement.Web/Models/Admin/User/RoleDataModel.cs

@@ -10,6 +10,7 @@ namespace GreenTree.Nachtragsmanagement.Web.Models.Admin.User
         public int Id { get; set; }
         public string Description { get; set; }
         public int Level { get; set; }
+        public bool SeeOnlyAssigned { get; set; }
         public ICollection<int> FunctionValues { get; set; }
         public ICollection<string> FunctionDescriptions { get; set; }
         public string FunctionDescription
@@ -45,6 +46,7 @@ namespace GreenTree.Nachtragsmanagement.Web.Models.Admin.User
                 Id = roleEntity.Id,
                 Description = roleEntity.Description,
                 Level = roleEntity.Level,
+                SeeOnlyAssigned = roleEntity.SeeOnlyAssigned,
                 FunctionValues =
                     roleEntity.Functions
                         .Select(r => r.Id)

+ 29 - 7
GreenTree.Nachtragsmanagement.Web/Models/Appendix/AppendixDataModel.cs

@@ -1,4 +1,5 @@
-using System;
+using Newtonsoft.Json;
+using System;
 using System.Collections.Generic;
 using System.Linq;
 using System.Web;
@@ -13,7 +14,9 @@ namespace GreenTree.Nachtragsmanagement.Web.Models.Appendix
         public decimal? Probability { get; set; }
         public int? OfferingNumber { get; set; }
         public DateTime? OfferingDate { get; set; }
-        public decimal? OfferingValue { get; set; }
+        public decimal OfferingValue { get; set; }
+        public decimal Percentage { get; set; }
+        public decimal PercentageValue { get; set; }
         public DateTime? NegotiationDate { get; set; }
         public decimal? NegotiationValue { get; set; }
         public bool ProtocolExists { get; set; }
@@ -54,21 +57,27 @@ namespace GreenTree.Nachtragsmanagement.Web.Models.Appendix
             if (appendixEntity == null && newWhenIsNull)
                 return new AppendixDataModel
                 {
-                    Id = -1
+                    Id = -1,
+                    Percentage = 50
                 };
 
             if (appendixEntity == null && !newWhenIsNull)
                 throw new ArgumentNullException("appendixEntity", "Cannot create AppendixDataModel from NULL appendix entity.");
 
-            return new AppendixDataModel
+            var model = new AppendixDataModel
             {
                 Id = appendixEntity.Id,
                 CustomNumber = appendixEntity.CustomNumber,
                 Description = appendixEntity.Description,
-                Probability = appendixEntity.Probability,
+                Percentage = appendixEntity.Percentage.HasValue 
+                    ? appendixEntity.Percentage.Value 
+                    : (decimal)0.5,
+                PercentageValue = appendixEntity.Value.HasValue && appendixEntity.Percentage.HasValue
+                    ? appendixEntity.Value.Value * appendixEntity.Percentage.Value
+                    : 0,
                 OfferingNumber = appendixEntity.OfferingNumber,
                 OfferingDate = appendixEntity.OfferingDate,
-                OfferingValue = appendixEntity.Value,
+                OfferingValue = appendixEntity.Value.Value,
                 NegotiationDate = appendixEntity.NegotiationDate,
                 NegotiationValue = appendixEntity.NegotiationValue,
                 ProtocolExists = appendixEntity.ProtocolExists,
@@ -107,6 +116,17 @@ namespace GreenTree.Nachtragsmanagement.Web.Models.Appendix
                         appendixEntity.Deviations
                             .Select(d => d.CustomNumber))
             };
+
+            foreach (var disturbance in model.CategoryValueEntities)
+            {
+                var json = JsonConvert.SerializeObject(disturbance);
+
+                disturbance.Json = json;
+
+                model.CategoryEntities.Add(json);
+            }
+
+            return model;
         }
 
         public Core.Domain.Appendix.Appendix ToAppendix()
@@ -116,7 +136,9 @@ namespace GreenTree.Nachtragsmanagement.Web.Models.Appendix
                 Id = this.Id,
                 CustomNumber = this.CustomNumber,
                 Description = this.Description,
-                Probability = this.Probability,
+                Percentage = this.Percentage,
+                StateId = this.StateId,
+                Value = this.OfferingValue,
                 OfferingNumber = this.OfferingNumber,
                 OfferingDate = this.OfferingDate,
                 NegotiationDate = this.NegotiationDate,

+ 8 - 2
GreenTree.Nachtragsmanagement.Web/Models/Appendix/StateDataModel.cs

@@ -9,6 +9,8 @@ namespace GreenTree.Nachtragsmanagement.Web.Models.Appendix
     {
         public int Id { get; set; }
         public string Description { get; set; }
+        public string HexColor { get; set; }
+        public bool IsDefault { get; set; }
 
         public static StateDataModel FromState(Core.Domain.Appendix.State stateEntity, bool newWhenIsNull)
         {
@@ -24,7 +26,9 @@ namespace GreenTree.Nachtragsmanagement.Web.Models.Appendix
             return new StateDataModel
             {
                 Id = stateEntity.Id,
-                Description = stateEntity.Description
+                Description = stateEntity.Description,
+                HexColor = stateEntity.HexColor,
+                IsDefault = stateEntity.IsDefault
             };
         }
 
@@ -33,7 +37,9 @@ namespace GreenTree.Nachtragsmanagement.Web.Models.Appendix
             return new Core.Domain.Appendix.State
             {
                 Id = this.Id,
-                Description = this.Description
+                Description = this.Description,
+                HexColor = this.HexColor,
+                IsDefault = this.IsDefault
             };
         }
     }

+ 10 - 4
GreenTree.Nachtragsmanagement.Web/Models/Deviation/DeviationDataModel.cs

@@ -17,7 +17,7 @@ namespace GreenTree.Nachtragsmanagement.Web.Models.Deviation
         public DateTime? ReceiptDate { get; set; }
         public DateTime? AppendixDate { get; set; }
         public decimal Value { get; set; }
-        public int Percentage { get; set; }
+        public decimal Percentage { get; set; }
         public decimal PercentageValue { get; set; }
         public int? StatusId { get; set; }
         public string StatusDescription { get; set; }
@@ -67,13 +67,19 @@ namespace GreenTree.Nachtragsmanagement.Web.Models.Deviation
                 ReceiptDate = deviationEntity.ReceiptDate,
                 AppendixDate = deviationEntity.AppendixDate,
                 Value = deviationEntity.Value.Value,
-                Percentage = deviationEntity.Percentage.Value,
-                PercentageValue = deviationEntity.Value.Value * ((decimal)deviationEntity.Percentage.Value / (decimal)100),
+                Percentage = deviationEntity.Percentage.HasValue
+                    ? deviationEntity.Percentage.Value
+                    : (decimal)1.0,
+                PercentageValue = deviationEntity.Value.HasValue && deviationEntity.Percentage.HasValue
+                    ? deviationEntity.Value.Value * deviationEntity.Percentage.Value
+                    : 0,
                 SiteId = deviationEntity.SiteId,
                 SiteDescription = deviationEntity.Site == null
                     ? deviationEntity.Appendix == null
                         ? String.Empty
-                        : deviationEntity.Appendix.Site.CustomNumber
+                        : deviationEntity.Appendix.Site == null
+                            ? String.Empty
+                            : deviationEntity.Appendix.Site.CustomNumber
                     : deviationEntity.Site.CustomNumber,
                 AppendixId = deviationEntity.AppendixId,
                 AppendixDescription = deviationEntity.Appendix == null

+ 5 - 2
GreenTree.Nachtragsmanagement.Web/Models/Deviation/KindDataModel.cs

@@ -10,6 +10,7 @@ namespace GreenTree.Nachtragsmanagement.Web.Models.Deviation
         public int Id { get; set; }
         public string Description { get; set; }
         public string Shortance { get; set; }
+        public bool IsDefault { get; set; }
 
         public static KindDataModel FromKind(Core.Domain.Deviation.Kind kindEntity, bool newWhenIsNull)
         {
@@ -26,7 +27,8 @@ namespace GreenTree.Nachtragsmanagement.Web.Models.Deviation
             {
                 Id = kindEntity.Id,
                 Description = kindEntity.Description,
-                Shortance = kindEntity.Shortance
+                Shortance = kindEntity.Shortance,
+                IsDefault = kindEntity.IsDefault
             };
         }
 
@@ -36,7 +38,8 @@ namespace GreenTree.Nachtragsmanagement.Web.Models.Deviation
             {
                 Id = this.Id,
                 Description = this.Description,
-                Shortance = this.Shortance
+                Shortance = this.Shortance,
+                IsDefault = this.IsDefault
             };
         }
     }

+ 5 - 2
GreenTree.Nachtragsmanagement.Web/Models/Deviation/StatusDataModel.cs

@@ -9,6 +9,7 @@ namespace GreenTree.Nachtragsmanagement.Web.Models.Deviation
     {
         public int Id { get; set; }
         public string Description { get; set; }
+        public bool IsDefault { get; set; }
 
         public static StatusDataModel FromStatus(Core.Domain.Deviation.Status statusEntity, bool newWhenIsNull)
         {
@@ -24,7 +25,8 @@ namespace GreenTree.Nachtragsmanagement.Web.Models.Deviation
             return new StatusDataModel
             {
                 Id = statusEntity.Id,
-                Description = statusEntity.Description
+                Description = statusEntity.Description,
+                IsDefault = statusEntity.IsDefault
             };
         }
 
@@ -33,7 +35,8 @@ namespace GreenTree.Nachtragsmanagement.Web.Models.Deviation
             return new Core.Domain.Deviation.Status
             {
                 Id = this.Id,
-                Description = this.Description
+                Description = this.Description,
+                IsDefault = this.IsDefault
             };
         }
     }

+ 2 - 0
GreenTree.Nachtragsmanagement.Web/Models/Global/YesNoDialogModel.cs

@@ -9,7 +9,9 @@ namespace GreenTree.Nachtragsmanagement.Web.Models.Global
     {
         public string PopupName { get; set; }
         public string YesFunction { get; set; }
+        public string YesButtonName { get; set; }
         public string NoFunction { get; set; }
+        public string NoButtonName { get; set; }
         public string HeaderText { get; set; }
         public string Content { get; set; }
     }

+ 11 - 2
GreenTree.Nachtragsmanagement.Web/Models/Site/SiteDataModel.cs

@@ -103,7 +103,14 @@ namespace GreenTree.Nachtragsmanagement.Web.Models.Site
                         .ToList(),
                 DeviationValue = 
                     siteEntity.Deviations
-                        .Sum(r => r.Value * ((decimal)r.Percentage.Value / (decimal)100)),
+                        .Sum(r => r.Value.HasValue && r.Percentage.HasValue
+                            ? r.Value * r.Percentage.Value
+                            : 0) +
+                    siteEntity.Appendices
+                        .SelectMany(r => r.Deviations)
+                            .Sum(r => r.Value.HasValue && r.Percentage.HasValue
+                                ? r.Value * r.Percentage.Value
+                                : 0),
                 AppendixValues =
                     siteEntity.Appendices
                         .Select(r => r.Id)
@@ -139,7 +146,9 @@ namespace GreenTree.Nachtragsmanagement.Web.Models.Site
                 Id = this.Id,
                 CustomNumber = this.CustomNumber,
                 Description = Description,
-                Comment = this.Comment
+                Comment = this.Comment,
+                Start = this.Start,
+                End = this.End
             };
         }
     }

+ 6 - 2
GreenTree.Nachtragsmanagement.Web/Models/Site/SiteTreeDataModel.cs

@@ -16,6 +16,7 @@ namespace GreenTree.Nachtragsmanagement.Web.Models.Site
         public decimal? Value { get; set; }
         public int? StatusId { get; set; }
         public string StatusDescription { get; set; }
+        public string StatusColor { get; set; }
         public ICollection<int> DistCatValues { get; set; }
         public ICollection<string> DistCatDescriptions { get; set; }
         public string DistCatDescription
@@ -80,7 +81,7 @@ namespace GreenTree.Nachtragsmanagement.Web.Models.Site
                     StatusDescription = openDeviation.Status == null
                         ? String.Empty
                         : openDeviation.Status.Description,
-                    Value = openDeviation.Value.Value * ((decimal)openDeviation.Percentage.Value / (decimal)100),
+                    Value = openDeviation.Value.Value * openDeviation.Percentage.Value,
                     Comment = openDeviation.Comment
                 });
             }
@@ -109,6 +110,9 @@ namespace GreenTree.Nachtragsmanagement.Web.Models.Site
                     StatusDescription = appendix.State == null
                         ? String.Empty
                         : appendix.State.Description,
+                    StatusColor = appendix.State == null
+                        ? "#FFFFFF"
+                        : appendix.State.HexColor,
                     Value = appendix.NegotiationValue,
                     Comment = appendix.Comment
                 };
@@ -139,7 +143,7 @@ namespace GreenTree.Nachtragsmanagement.Web.Models.Site
                         StatusDescription = deviation.Status == null
                         ? String.Empty
                         : deviation.Status.Description,
-                        Value = deviation.Value.Value * (deviation.Percentage.Value / 100),
+                        Value = deviation.Value.Value * deviation.Percentage.Value,
                         Comment = deviation.Comment
                     };
 

+ 0 - 4
GreenTree.Nachtragsmanagement.Web/Validation/Appendix/AppendixDataModelValidator.cs

@@ -29,10 +29,6 @@ namespace GreenTree.Nachtragsmanagement.Web.Validation.Appendix
             RuleFor(m => m.OfferingValue)
                 .NotEmpty()
                     .WithMessage("Eine Angebotssumme wird benötigt");
-
-            RuleFor(m => m.Comment)
-                .NotEmpty()
-                    .WithMessage("Ein Kommentar wird benötigt");
         }
     }
 }

+ 4 - 0
GreenTree.Nachtragsmanagement.Web/Validation/Appendix/StateDataModelValidator.cs

@@ -17,6 +17,10 @@ namespace GreenTree.Nachtragsmanagement.Web.Validation.Appendix
                     .WithMessage("Beschreibung wird benötigt")
                 .MaximumLength(50)
                     .WithMessage("Muss unter 50 Zeichen sein");
+
+            RuleFor(m => m.HexColor)
+                .NotEmpty()
+                    .WithMessage("Eine Farbe muss ausgewählt werden");
         }
     }
 }

+ 0 - 16
GreenTree.Nachtragsmanagement.Web/Validation/Deviation/DeviationDataModelValidator.cs

@@ -25,29 +25,13 @@ namespace GreenTree.Nachtragsmanagement.Web.Validation.Deviation
                 .NotEmpty()
                     .WithMessage("Einreichdatum wird benötigt");
 
-            RuleFor(m => m.Value)
-                .NotEmpty()
-                    .WithMessage("Eine Schätzung wird benötigt");
-
-            RuleFor(m => m.Percentage)
-                .NotEmpty()
-                    .WithMessage("Eine Bewertung wird benötigt");
-
             RuleFor(m => m.StatusId)
                 .NotEmpty()
                     .WithMessage("Ein Status muss gewählt werden");
 
-            RuleFor(m => m.DisturbanceEntities)
-                .Must(r => r.Count > 0)
-                    .WithMessage("Eine Kategorie muss ausgewählt werden");
-
             RuleFor(m => m.KindId)
                 .NotEmpty()
                     .WithMessage("Eine Art muss gewählt werden");
-
-            RuleFor(m => m.Comment)
-                .NotEmpty()
-                    .WithMessage("Ein Kommentar wird benötigt");
         }
     }
 }

+ 5 - 7
GreenTree.Nachtragsmanagement.Web/Validation/Site/SiteDataModelValidator.cs

@@ -14,21 +14,19 @@ namespace GreenTree.Nachtragsmanagement.Web.Validation.Site
         {
             RuleFor(m => m.CustomNumber)
                 .NotEmpty()
-                    .WithMessage("Kostenstelle wird benötigt")
-                .Length(7)
-                    .WithMessage("Muss 7 Zeichen lang sein");
+                    .WithMessage("Kostenstelle wird benötigt");
 
             RuleFor(m => m.Description)
                 .NotEmpty()
                     .WithMessage("Beschreibung wird benötigt");
 
+            RuleFor(m => m.Start)
+                .NotEmpty()
+                    .WithMessage("Ein Startdatum wird benötigt");
+
             RuleFor(m => m.UserValues)
                 .Must(r => r.Count > 0)
                     .WithMessage("Mind. ein Bearbeiter muss ausgewählt werden");
-
-            RuleFor(m => m.Comment)
-                .NotEmpty()
-                    .WithMessage("Ein Kommentar wird benötigt");
         }
     }
 }

+ 107 - 72
GreenTree.Nachtragsmanagement.Web/Views/Admin/Roles/_RoleEditPartial.cshtml

@@ -69,94 +69,129 @@
 	</script>
 
 	@Html.DevExpress().PopupControl(s =>
+{
+	s.Name = "devPopupControlEditRole";
+
+	if (Model.Id == -1)
+		s.HeaderText = "Neue Rolle erstellen";
+	else
+		s.HeaderText = "\"" + Model.Description + "\" bearbeiten";
+
+	s.Modal = true;
+	s.Width = new Unit(400, UnitType.Pixel);
+	s.CloseAction = CloseAction.CloseButton;
+	s.PopupHorizontalAlign = PopupHorizontalAlign.WindowCenter;
+	s.PopupVerticalAlign = PopupVerticalAlign.TopSides;
+	s.PopupVerticalOffset = 10;
+	s.AllowDragging = false;
+	s.AllowResize = false;
+	s.ShowFooter = false;
+	s.ShowOnPageLoad = true;
+	s.SetContent(() =>
 	{
-		s.Name = "devPopupControlEditRole";
-
-		if (Model.Id == -1)
-			s.HeaderText = "Neue Rolle erstellen";
-		else
-			s.HeaderText = "\"" + Model.Description + "\" bearbeiten";
-
-		s.Modal = true;
-		s.Width = new Unit(400, UnitType.Pixel);
-		s.CloseAction = CloseAction.CloseButton;
-		s.PopupHorizontalAlign = PopupHorizontalAlign.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("EditRole", "Admin", FormMethod.Post, new { id = "roleEditForm" }))
 		{
-			using (Html.BeginForm("EditRole", "Admin", FormMethod.Post, new { id = "roleEditForm" }))
+			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.FunctionValues, "Funktionen:"));
+			ViewContext.Writer.Write(Html.ValidationMessageFor(m => m.FunctionValues).ToHtmlString());
+			Html.DevExpress().DropDownEdit(t =>
 			{
-				ViewContext.Writer.Write("<div class='editFormWrapper'>");
+				t.Name = "devDropDownListFunctionValues";
+				t.Width = new Unit(100, UnitType.Percentage);
 
-				ViewContext.Writer.Write("<input type=\"hidden\" value=\"" + Model.Id + "\" id=\"Id\" name=\"Id\" />");
+				if (Model.FunctionDescriptions != null && Model.FunctionDescriptions.Any())
+					t.Text = String.Join(", ", Model.FunctionDescriptions);
 
-				ViewContext.Writer.Write(Html.CustomLabelFor(m => m.FunctionValues, "Funktionen:"));
-				ViewContext.Writer.Write(Html.ValidationMessageFor(m => m.FunctionValues).ToHtmlString());
-				Html.DevExpress().DropDownEdit(t =>
+				t.SetDropDownWindowTemplateContent(l =>
 				{
-					t.Name = "devDropDownListFunctionValues";
-					t.Width = new Unit(100, UnitType.Percentage);
+					ViewContext.Writer.Write("<div style='width: auto; overflow: auto; max-height: 200px'>");
+					Html.DevExpress().TreeView(tv =>
+					{
+						var allFunctions = ViewData["AllFunctions"] as IList<Function>;
 
-					if (Model.FunctionDescriptions != null && Model.FunctionDescriptions.Any())
-						t.Text = String.Join(", ", Model.FunctionDescriptions);
+						tv.Name = "devTreeViewFunctionValues";
+						tv.AllowCheckNodes = true;
 
-					t.SetDropDownWindowTemplateContent(l =>
-					{
-						ViewContext.Writer.Write("<div style='width: auto; overflow: auto; max-height: 200px'>");
-						Html.DevExpress().TreeView(tv =>
+						tv.CreateGroupedFunctionList(allFunctions);
+
+						foreach (var checkedFunction in Model.FunctionValues)
 						{
-							var allFunctions = ViewData["AllFunctions"] as IList<Function>;
+							tv.Nodes.FindRecursive(n => n.Name == checkedFunction.ToString()).Checked = true;
+						}
 
-							tv.Name = "devTreeViewFunctionValues";
-							tv.AllowCheckNodes = true;
+						tv.ClientSideEvents.CheckedChanged = "function (s, e) { synchronizeTreeViewValues(s, e); }";
+					}).Render();
+					ViewContext.Writer.Write("</div>");
+				});
+			}).Render();
 
-							tv.CreateGroupedFunctionList(allFunctions);
+			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();
 
-							foreach (var checkedFunction in Model.FunctionValues)
+			ViewContext.Writer.Write(Html.CustomLabelFor(m => m.Level, "Stufe:"));
+			ViewContext.Writer.Write(Html.ValidationMessageFor(m => m.Level).ToHtmlString());
+			Html.DevExpress().SpinEditFor(m => m.Level, t =>
+			{
+				t.Width = new Unit(60, UnitType.Percentage);
+				t.Properties.NumberType = SpinEditNumberType.Integer;
+				t.Properties.MinValue = 0;
+			}).Render();
+
+			ViewContext.Writer.Write("<div class='inlineModelPropertyContainer'>");
+			{
+				ViewContext.Writer.Write("<div class='inlineModelProperty' style='width: 100%'>");
+				{
+					ViewContext.Writer.Write(Html.CustomLabelFor(m => m.SeeOnlyAssigned, "Kann nur zugewiesene Baustellen einsehen:"));
+					ViewContext.Writer.Write("<div style=\"overflow: hidden\">");
+					{
+						ViewContext.Writer.Write("<div style=\"float: left\">");
+						{
+							Html.DevExpress().RadioButtonFor(m => m.SeeOnlyAssigned, t =>
 							{
-								tv.Nodes.FindRecursive(n => n.Name == checkedFunction.ToString()).Checked = true;
-							}
+								t.Text = "Ja";
+								t.GroupName = "seeOnlyAssigned";
+							}).Render();
+						}
+						ViewContext.Writer.Write("</div>");
 
-							tv.ClientSideEvents.CheckedChanged = "function (s, e) { synchronizeTreeViewValues(s, e); }";
-						}).Render();
+						ViewContext.Writer.Write("<div style=\"float: left; margin-left: 8px\">");
+						{
+							Html.DevExpress().RadioButton(t =>
+							{
+								t.Name = "seeOnlyAssignedFalse";
+								t.Text = "Nein";
+								t.GroupName = "seeOnlyAssigned";
+								t.Checked = !Model.SeeOnlyAssigned;
+							}).Render();
+						}
 						ViewContext.Writer.Write("</div>");
-					});
-				}).Render();
+					}
+					ViewContext.Writer.Write("</div>");
+				}
+				ViewContext.Writer.Write("</div>");
+			}
+			ViewContext.Writer.Write("</div>");
 
-				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>");
 
-				ViewContext.Writer.Write(Html.CustomLabelFor(m => m.Level, "Stufe:"));
-				ViewContext.Writer.Write(Html.ValidationMessageFor(m => m.Level).ToHtmlString());
-				Html.DevExpress().SpinEditFor(m => m.Level, t =>
+			Html.RenderPartial(
+				"~/Views/Shared/_PopupButtonPanel.cshtml",
+				new GreenTree.Nachtragsmanagement.Web.Models.Global.PopupModel
 				{
-					t.Width = new Unit(60, UnitType.Percentage);
-					t.Properties.NumberType = SpinEditNumberType.Integer;
-					t.Properties.MinValue = 0;
-				}).Render();
-
-				ViewContext.Writer.Write("</div>");
-
-				Html.RenderPartial(
-					"~/Views/Shared/_PopupButtonPanel.cshtml",
-					new GreenTree.Nachtragsmanagement.Web.Models.Global.PopupModel
-					{
-						PopupName = "devPopupControlEditRole",
-						AcceptFunction = "function (s, e) { saveRole(); }"
-					}
-				);
-			}
-		});
-		s.Styles.Content.Paddings.Padding = new Unit(0);
-		s.Styles.ModalBackground.Opacity = 0;
-	}).GetHtml()
+					PopupName = "devPopupControlEditRole",
+					AcceptFunction = "function (s, e) { saveRole(); }"
+				}
+			);
+		}
+	});
+	s.Styles.Content.Paddings.Padding = new Unit(0);
+	s.Styles.ModalBackground.Opacity = 0;
+}).GetHtml()
 </div>

+ 38 - 3
GreenTree.Nachtragsmanagement.Web/Views/Appendices/Claims.cshtml

@@ -10,7 +10,7 @@
 	var deleteClaimType;
 
 	var claimTypeTranslation = {
-		state: "NT-State",
+		state: "NT-Status",
 		category: "Kategorie"
 	};
 
@@ -21,7 +21,6 @@
 		var windowHeight = $(window).height();
 		devListBoxStates.SetHeight(windowHeight - 40);
 		devListBoxCategories.SetHeight(windowHeight - 40);
-		devListBoxKinds.SetHeight(windowHeight - 40);
 	}
 
 	function editClaim(claimType, id) {
@@ -33,6 +32,15 @@
 				setTimeout(function () {
 					$(".claimEditContainer").remove();
 					$("body").append(response);
+					if (claimType == "state") {
+						parent.addCustomEventListener('StateDataCallbackEventReceiver', function () {
+							devListBoxStates.PerformCallback();
+						});
+					} else if (claimType == "category") {
+						parent.addCustomEventListener('CategoryDataCallbackEventReceiver', function () {
+							devListBoxCategories.PerformCallback();
+						});
+					}
 				}, 200);
 			},
 			error: function () {
@@ -65,13 +73,17 @@
 				devRadioButtonDeleteReplaceClaim
 					.SetText(devRadioButtonDeleteReplaceClaim.GetText().replace("{claimType}", claimTypeTranslation[claimType]));
 
-				var comboBox = null;
 				devComboBoxClaimDeleteReplaceState.SetVisible(false);
 				devComboBoxClaimDeleteReplaceCategory.SetVisible(false);
 
+				var comboBox = null;
+
 				if (deleteClaimType == "state") {
 					devComboBoxClaimDeleteReplaceState.SetVisible(true);
 					comboBox = MVCxClientComboBox.Cast(devComboBoxClaimDeleteReplaceState);
+				} else if (deleteClaimType == "category") {
+					devComboBoxClaimDeleteReplaceCategory.SetVisible(true);
+					comboBox = MVCxClientComboBox.Cast(devComboBoxClaimDeleteReplaceCategory);
 				}
 
 				comboBox.PerformCallback();
@@ -84,6 +96,8 @@
 	function deleteClaim() {
 		if (deleteClaimType == "state") {
 			deleteReplaceId = devComboBoxClaimDeleteReplaceState.GetValue();
+		} else if (deleteClaimType == "category") {
+			deleteReplaceId = devComboBoxClaimDeleteReplaceCategory.GetValue();
 		}
 
 		if (deleteReplaceId == 0) {
@@ -188,6 +202,27 @@
 		ViewData.Add("StatesComboBoxSettings", "StatesDeleteComboBoxSettings");
 		Html.RenderPartial("~/Views/Shared/DataEditorTemplates/_StatesComboBox.cshtml", null, ViewData);
 
+		Session.Add("CategoriesDeleteComboBoxSettings", new Action<ComboBoxSettings>(a =>
+		{
+			a.Name = "devComboBoxClaimDeleteReplaceCategory";
+			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 = "CategoriesComboBoxExcluded",
+				SettingsKey = "CategoriesDeleteComboBoxSettings"
+			};
+		}));
+		ViewData.Add("CategoriesComboBoxSettings", "CategoriesDeleteComboBoxSettings");
+		Html.RenderPartial("~/Views/Shared/DataEditorTemplates/_CategoriesComboBox.cshtml", null, ViewData);
+
 		ViewContext.Writer.Write("<div class=\"deleteValidation\" style=\"display: none\"></div>");
 
 		ViewContext.Writer.Write("</div>");

+ 53 - 8
GreenTree.Nachtragsmanagement.Web/Views/Appendices/_AppendixEditPartial.cshtml

@@ -112,9 +112,13 @@
 			}
 			setDropDownText();
 		}
+
+		function calculateValueAppendix() {
+			PercentageValueAppendix.SetValue(OfferingValueAppendix.GetValue() * PercentageAppendix.GetValue());
+		}
 	</script>
 
-	@Html.Partial("~/Views/Appendices/_CategoryValueEditPartial.cshtml");
+	@Html.Partial("~/Views/Appendices/_CategoryValueEditPartial.cshtml")
 
 	@Html.DevExpress().PopupControl(s =>
 {
@@ -142,6 +146,7 @@
 			ViewContext.Writer.Write("<div class='editFormWrapper'>");
 
 			ViewContext.Writer.Write("<input type=\"hidden\" value=\"" + Model.Id + "\" id=\"Id\" name=\"Id\" />");
+			ViewContext.Writer.Write("<input type=\"hidden\" value=\"" + Model.SiteId + "\" id=\"SiteId\" name=\"SiteId\" />");
 
 			ViewContext.Writer.Write("<div class='inlineModelPropertyContainer'>");
 			{
@@ -229,21 +234,59 @@
 				}
 				ViewContext.Writer.Write("</div>");
 
-				ViewContext.Writer.Write("<div class='inlineModelProperty' style='width: 30%'>");
+				ViewContext.Writer.Write("<div class='inlineModelProperty' style='width: 22%'>");
 				{
 					ViewContext.Writer.Write(Html.CustomLabelFor(m => m.OfferingValue, "Angebotssumme:"));
 					ViewContext.Writer.Write(Html.ValidationMessageFor(m => m.OfferingValue).ToHtmlString());
 					Html.DevExpress().SpinEditFor(m => m.OfferingValue, t =>
 					{
 						t.Width = new Unit(94, UnitType.Percentage);
+						t.Properties.ClientInstanceName = "OfferingValueAppendix";
 						t.Properties.DecimalPlaces = 2;
 						t.Properties.NumberType = SpinEditNumberType.Float;
 						t.Properties.DisplayFormatString = "c2";
-						t.Properties.ClientSideEvents.ValueChanged = "function (s, e) { calculateValue(); }";
+						t.Properties.ClientSideEvents.ValueChanged = "function (s, e) { calculateValueAppendix(); }";
 					}).Render();
 				}
 				ViewContext.Writer.Write("</div>");
 
+				ViewContext.Writer.Write("<div class='inlineModelProperty' style='width: 16%'>");
+				{
+					ViewContext.Writer.Write(Html.CustomLabelFor(m => m.Percentage, "Bewertung (%):"));
+					ViewContext.Writer.Write(Html.ValidationMessageFor(m => m.Percentage).ToHtmlString());
+					Html.DevExpress().SpinEditFor(m => m.Percentage, t =>
+					{
+						t.Width = new Unit(88, UnitType.Percentage);
+						t.Properties.ClientInstanceName = "PercentageAppendix";
+						t.Properties.MaxValue = 1;
+						t.Properties.MinValue = 0;
+						t.Properties.Increment = (decimal)0.1;
+						t.Properties.NumberType = SpinEditNumberType.Float;
+						t.Properties.NumberFormat = SpinEditNumberFormat.Percent;
+						t.Properties.DisplayFormatString = "p0";
+						t.Properties.DisplayFormatInEditMode = true;
+						t.Properties.ClientSideEvents.ValueChanged = "function (s, e) { calculateValueAppendix(); }";
+					}).Render();
+				}
+				ViewContext.Writer.Write("</div>");
+				ViewContext.Writer.Write("<div class='inlineModelProperty' style='width: 22%'>");
+				{
+					ViewContext.Writer.Write(Html.CustomLabelFor(m => m.PercentageValue, "Wert:"));
+					Html.DevExpress().SpinEditFor(m => m.PercentageValue, t =>
+					{
+						t.Width = new Unit(100, UnitType.Percentage);
+						t.Properties.ClientInstanceName = "PercentageValueAppendix";
+						t.Properties.DecimalPlaces = 2;
+						t.Properties.NumberType = SpinEditNumberType.Float;
+						t.Properties.DisplayFormatString = "c2";
+					}).Render();
+				}
+				ViewContext.Writer.Write("</div>");
+			}
+			ViewContext.Writer.Write("</div>");
+
+			ViewContext.Writer.Write("<div class='inlineModelPropertyContainer'>");
+			{
 				ViewContext.Writer.Write("<div class='inlineModelProperty' style='width: 30%'>");
 				{
 					ViewContext.Writer.Write(Html.CustomLabelFor(m => m.NegotiationValue, "Verhandlungssumme:"));
@@ -259,11 +302,11 @@
 			}
 			ViewContext.Writer.Write("</div>");
 
-			if (ViewData["relationType"] != null && ViewData["relationType"].ToString() == "site")
-			{
-				ViewContext.Writer.Write(
-					"<input type=\"hidden\" value=\"" + ViewData["relationId"].ToString() + "\" id=\"SiteId\" name=\"SiteId\" />");
-			}
+			//if (ViewData["relationType"] != null && ViewData["relationType"].ToString() == "site")
+			//{
+			//	ViewContext.Writer.Write(
+			//		"<input type=\"hidden\" value=\"" + ViewData["relationId"].ToString() + "\" id=\"SiteId\" name=\"SiteId\" />");
+			//}
 
 			ViewContext.Writer.Write("<div class='inlineModelPropertyContainer'>");
 			{
@@ -333,6 +376,7 @@
 								t.Name = "protocolExistsFalse";
 								t.Text = "Nein";
 								t.GroupName = "protocolExists";
+								t.Checked = !Model.ProtocolExists;
 							}).Render();
 						}
 						ViewContext.Writer.Write("</div>");
@@ -363,6 +407,7 @@
 								t.Name = "orderInvoiceCreatedFalse";
 								t.Text = "Nein";
 								t.GroupName = "orderInvoiceCreated";
+								t.Checked = !Model.OrderInvoiceCreated;
 							}).Render();
 						}
 						ViewContext.Writer.Write("</div>");

+ 1 - 1
GreenTree.Nachtragsmanagement.Web/Views/Appendices/_AppendixGridPartial.cshtml

@@ -36,7 +36,7 @@
 		column.FieldName = "NegotiationValue";
 		column.PropertiesEdit.DisplayFormatString = "c2";
 	});
-	s.Columns.Add("DeviationDescriptions", "Vertragsabweichungen");
+	s.Columns.Add("DeviationDescription", "Vertragsabweichungen");
 	s.Columns.Add("StateDescription", "Status");
 	s.Columns.Add("CategoryValuesDescription", "Kategorien");
 	s.Columns.Add(column =>

+ 2 - 2
GreenTree.Nachtragsmanagement.Web/Views/Appendices/_CategoryEditPartial.cshtml

@@ -2,7 +2,7 @@
 
 @model GreenTree.Nachtragsmanagement.Web.Models.Appendix.CategoryDataModel
 
-<div class="categoryEditContainer">
+<div class="claimEditContainer">
 
 	<script>
 		function saveCategory() {
@@ -10,7 +10,7 @@
 			$(form).submit(function (e) {
 				$.ajax({
 					type: "POST",
-					url: '@Url.Action("EditCategory", "Deviation")',
+					url: '@Url.Action("EditCategory", "Appendix")',
 					data: form.serialize(),
 					success: function (response) {
 						setTimeout(function () {

+ 1 - 1
GreenTree.Nachtragsmanagement.Web/Views/Appendices/_CategoryListPartial.cshtml

@@ -23,7 +23,7 @@
 			);
 		});
 	}
-	s.CallbackRouteValues = new { Controller = "Appendix", Action = "PartialCategories" };
+	s.CallbackRouteValues = new { Controller = "Appendix", Action = "PartialClaims", claimType = "category" };
 	s.Width = Unit.Percentage(100);
 	s.Height = Unit.Pixel(370);
 }).BindList(Model).GetHtml()

+ 42 - 0
GreenTree.Nachtragsmanagement.Web/Views/Appendices/_StateEditPartial.cshtml

@@ -62,6 +62,48 @@
 				t.Width = new Unit(100, UnitType.Percentage);
 			}).Render();
 
+			ViewContext.Writer.Write(Html.CustomLabelFor(m => m.HexColor, "Darstellung:"));
+			ViewContext.Writer.Write(Html.ValidationMessageFor(m => m.HexColor).ToHtmlString());
+			Html.DevExpress().ColorEditFor(m => m.HexColor, t =>
+			{
+				t.Width = new Unit(100, UnitType.Percentage);
+			}).Render();
+
+			ViewContext.Writer.Write("<div class='inlineModelPropertyContainer'>");
+			{
+				ViewContext.Writer.Write("<div class='inlineModelProperty' style='width: 100%'>");
+				{
+					ViewContext.Writer.Write(Html.CustomLabelFor(m => m.IsDefault, "Ist Standard:"));
+					ViewContext.Writer.Write("<div style=\"overflow: hidden\">");
+					{
+						ViewContext.Writer.Write("<div style=\"float: left\">");
+						{
+							Html.DevExpress().RadioButtonFor(m => m.IsDefault, t =>
+							{
+								t.Text = "Ja";
+								t.GroupName = "isDefault";
+							}).Render();
+						}
+						ViewContext.Writer.Write("</div>");
+
+						ViewContext.Writer.Write("<div style=\"float: left; margin-left: 8px\">");
+						{
+							Html.DevExpress().RadioButton(t =>
+							{
+								t.Name = "isDefaultFalse";
+								t.Text = "Nein";
+								t.GroupName = "isDefault";
+								t.Checked = !Model.IsDefault;
+							}).Render();
+						}
+						ViewContext.Writer.Write("</div>");
+					}
+					ViewContext.Writer.Write("</div>");
+				}
+				ViewContext.Writer.Write("</div>");
+			}
+			ViewContext.Writer.Write("</div>");
+
 			ViewContext.Writer.Write("</div>");
 
 			Html.RenderPartial(

+ 7 - 1
GreenTree.Nachtragsmanagement.Web/Views/Appendices/_StateListPartial.cshtml

@@ -14,7 +14,13 @@
 	{
 		s.SetItemTemplateContent(c =>
 		{
-			ViewContext.Writer.Write(DataBinder.Eval(c.DataItem, "Description"));
+			var isDefault = (bool)DataBinder.Eval(c.DataItem, "IsDefault");
+
+			if (isDefault)
+				ViewContext.Writer.Write("<b><i>" + DataBinder.Eval(c.DataItem, "Description") + "</i></b>");
+			else
+				ViewContext.Writer.Write(DataBinder.Eval(c.DataItem, "Description"));
+
 			ViewContext.Writer.Write(
 				"<div class=\"devExListItemControlContainer\">" +
 					"<a href=\"#\" onclick='editClaim(\"state\", " + DataBinder.Eval(c.DataItem, "Id") + ")'>Bearbeiten</a>&nbsp;" +

+ 25 - 7
GreenTree.Nachtragsmanagement.Web/Views/Deviations/Claims.cshtml

@@ -34,6 +34,19 @@
 				setTimeout(function () {
 					$(".claimEditContainer").remove();
 					$("body").append(response);
+					if (claimType == "status") {
+						parent.addCustomEventListener('StatusDataCallbackEventReceiver', function () {
+							devListBoxStatuses.PerformCallback();
+						});
+					} else if (claimType == "kind") {
+						parent.addCustomEventListener('KindDataCallbackEventReceiver', function () {
+							devListBoxKinds.PerformCallback();
+						});
+					} else if (claimType == "disturbance") {
+						parent.addCustomEventListener('DisturbanceDataCallbackEventReceiver', function () {
+							devListBoxDisturbances.PerformCallback();
+						});
+					}
 				}, 200);
 			},
 			error: function () {
@@ -76,7 +89,10 @@
 					comboBox = MVCxClientComboBox.Cast(devComboBoxClaimDeleteReplaceStatus);
 				} else if (deleteClaimType == "kind") {
 					devComboBoxClaimDeleteReplaceKind.SetVisible(true);
-					comboBox = MVCxClientComboBox.Cast(devComboBoxClaimDeleteReplaceStatus);
+					comboBox = MVCxClientComboBox.Cast(devComboBoxClaimDeleteReplaceKind);
+				} else if (deleteClaimType == "disturbance") {
+					devComboBoxClaimDeleteReplaceDisturbance.SetVisible(true);
+					comboBox = MVCxClientComboBox.Cast(devComboBoxClaimDeleteReplaceDisturbance);
 				}
 
 				comboBox.PerformCallback();
@@ -91,6 +107,8 @@
 			deleteReplaceId = devComboBoxClaimDeleteReplaceStatus.GetValue();
 		} else if (deleteClaimType == "kind") {
 			deleteReplaceId = devComboBoxClaimDeleteReplaceKind.GetValue();
+		} else if (deleteClaimType == "disturbance") {
+			deleteReplaceId = devComboBoxClaimDeleteReplaceDisturbance.GetValue();
 		}
 
 		if (deleteReplaceId == 0) {
@@ -140,17 +158,17 @@
 			</td>
 			<td style="width: 33%; padding: 0 6px">
 				<div class="listHeader">
-					<span>Kategorien</span>
-					<img src='@Url.Content("~/Content/Images/add-24-contrast.png")' onclick='editClaim("disturbance", -1)' title="Neue VA-Kategorie" />
+					<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/_DisturbanceListPartial.cshtml", ViewData["AllDisturbances"])
+				@Html.Partial("~/Views/Deviations/_KindListPartial.cshtml", ViewData["AllKinds"])
 			</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" />
+					<span>VA-Kategorien</span>
+					<img src='@Url.Content("~/Content/Images/add-24-contrast.png")' onclick='editClaim("disturbance", -1)' title="Neue VA-Kategorie" />
 				</div>
-				@Html.Partial("~/Views/Deviations/_KindListPartial.cshtml", ViewData["AllKinds"])
+				@Html.Partial("~/Views/Deviations/_DisturbanceListPartial.cshtml", ViewData["AllDisturbances"])
 			</td>
 		</tr>
 	</tbody>

+ 21 - 22
GreenTree.Nachtragsmanagement.Web/Views/Deviations/_DeviationEditPartial.cshtml

@@ -131,9 +131,13 @@
 			}
 			setDropDownText();
 		}
+
+		function calculateValueDeviation() {
+			PercentageValueDeviation.SetValue(ValueDeviation.GetValue() * PercentageDeviation.GetValue());
+		}
 	</script>
 
-	@Html.Partial("~/Views/Deviations/_DisturbanceValueEditPartial.cshtml");
+	@Html.Partial("~/Views/Deviations/_DisturbanceValueEditPartial.cshtml")
 
 	@Html.DevExpress().PopupControl(s =>
 {
@@ -161,6 +165,8 @@
 			ViewContext.Writer.Write("<div class='editFormWrapper'>");
 
 			ViewContext.Writer.Write("<input type=\"hidden\" value=\"" + Model.Id + "\" id=\"Id\" name=\"Id\" />");
+			ViewContext.Writer.Write("<input type=\"hidden\" value=\"" + Model.AppendixId + "\" id=\"AppendixId\" name=\"AppendixId\" />");
+			ViewContext.Writer.Write("<input type=\"hidden\" value=\"" + Model.SiteId + "\" id=\"SiteId\" name=\"SiteId\" />");
 
 			ViewContext.Writer.Write("<div class='inlineModelPropertyContainer'>");
 			{
@@ -255,37 +261,41 @@
 					Html.DevExpress().SpinEditFor(m => m.Value, t =>
 					{
 						t.Width = new Unit(90, UnitType.Percentage);
+						t.Properties.ClientInstanceName = "ValueDeviation";
 						t.Properties.DecimalPlaces = 2;
 						t.Properties.NumberType = SpinEditNumberType.Float;
 						t.Properties.DisplayFormatString = "c2";
-						t.Properties.ClientSideEvents.ValueChanged = "function (s, e) { calculateValue(); }";
+						t.Properties.ClientSideEvents.ValueChanged = "function (s, e) { calculateValueDeviation(); }";
 					}).Render();
 				}
 				ViewContext.Writer.Write("</div>");
 
 				ViewContext.Writer.Write("<div class='inlineModelProperty' style='width: 16%'>");
 				{
-					ViewContext.Writer.Write(Html.CustomLabelFor(m => m.Value, "Bewertung (%):"));
-					ViewContext.Writer.Write(Html.ValidationMessageFor(m => m.Value).ToHtmlString());
+					ViewContext.Writer.Write(Html.CustomLabelFor(m => m.Percentage, "Bewertung (%):"));
+					ViewContext.Writer.Write(Html.ValidationMessageFor(m => m.Percentage).ToHtmlString());
 					Html.DevExpress().SpinEditFor(m => m.Percentage, t =>
 					{
 						t.Width = new Unit(88, UnitType.Percentage);
-						t.Properties.DecimalPlaces = 0;
-						t.Properties.MaxValue = 1000;
+						t.Properties.ClientInstanceName = "PercentageDeviation";
+						t.Properties.MaxValue = 1;
 						t.Properties.MinValue = 0;
-						t.Properties.NumberType = SpinEditNumberType.Integer;
-						t.Properties.DisplayFormatString = "{0:n0} %";
-						t.Properties.ClientSideEvents.ValueChanged = "function (s, e) { calculateValue(); }";
+						t.Properties.Increment = (decimal)0.1;
+						t.Properties.NumberType = SpinEditNumberType.Float;
+						t.Properties.NumberFormat = SpinEditNumberFormat.Percent;
+						t.Properties.DisplayFormatString = "p0";
+						t.Properties.DisplayFormatInEditMode = true;
+						t.Properties.ClientSideEvents.ValueChanged = "function (s, e) { calculateValueDeviation(); }";
 					}).Render();
 				}
 				ViewContext.Writer.Write("</div>");
 				ViewContext.Writer.Write("<div class='inlineModelProperty' style='width: 22%'>");
 				{
-					ViewContext.Writer.Write(Html.CustomLabelFor(m => m.Value, "Wert:"));
+					ViewContext.Writer.Write(Html.CustomLabelFor(m => m.PercentageValue, "Wert:"));
 					Html.DevExpress().SpinEditFor(m => m.PercentageValue, t =>
 					{
-						t.Name = "Sum";
 						t.Width = new Unit(100, UnitType.Percentage);
+						t.Properties.ClientInstanceName = "PercentageValueDeviation";
 						t.Properties.DecimalPlaces = 2;
 						t.Properties.NumberType = SpinEditNumberType.Float;
 						t.Properties.DisplayFormatString = "c2";
@@ -295,17 +305,6 @@
 			}
 			ViewContext.Writer.Write("</div>");
 
-			if (ViewData["relationType"] != null && ViewData["relationType"].ToString() == "site")
-			{
-				ViewContext.Writer.Write(
-					"<input type=\"hidden\" value=\"" + ViewData["relationId"].ToString() + "\" id=\"SiteId\" name=\"SiteId\" />");
-			}
-			else if (ViewData["relationType"] != null && ViewData["relationType"].ToString() == "appendix")
-			{
-				ViewContext.Writer.Write(
-					"<input type=\"hidden\" value=\"" + ViewData["relationId"].ToString() + "\" id=\"AppendixId\" name=\"AppendixId\" />");
-			}
-
 			ViewContext.Writer.Write("<div class='inlineModelPropertyContainer'>");
 			{
 				ViewContext.Writer.Write("<div class='inlineModelProperty' style='width: 50%'>");

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

@@ -69,6 +69,41 @@
 				t.Width = new Unit(100, UnitType.Percentage);
 			}).Render();
 
+			ViewContext.Writer.Write("<div class='inlineModelPropertyContainer'>");
+			{
+				ViewContext.Writer.Write("<div class='inlineModelProperty' style='width: 100%'>");
+				{
+					ViewContext.Writer.Write(Html.CustomLabelFor(m => m.IsDefault, "Ist Standard:"));
+					ViewContext.Writer.Write("<div style=\"overflow: hidden\">");
+					{
+						ViewContext.Writer.Write("<div style=\"float: left\">");
+						{
+							Html.DevExpress().RadioButtonFor(m => m.IsDefault, t =>
+							{
+								t.Text = "Ja";
+								t.GroupName = "isDefault";
+							}).Render();
+						}
+						ViewContext.Writer.Write("</div>");
+
+						ViewContext.Writer.Write("<div style=\"float: left; margin-left: 8px\">");
+						{
+							Html.DevExpress().RadioButton(t =>
+							{
+								t.Name = "isDefaultFalse";
+								t.Text = "Nein";
+								t.GroupName = "isDefault";
+								t.Checked = !Model.IsDefault;
+							}).Render();
+						}
+						ViewContext.Writer.Write("</div>");
+					}
+					ViewContext.Writer.Write("</div>");
+				}
+				ViewContext.Writer.Write("</div>");
+			}
+			ViewContext.Writer.Write("</div>");
+
 			ViewContext.Writer.Write("</div>");
 
 			Html.RenderPartial(

+ 7 - 1
GreenTree.Nachtragsmanagement.Web/Views/Deviations/_KindListPartial.cshtml

@@ -14,7 +14,13 @@
 	{
 		s.SetItemTemplateContent(c =>
 		{
-			ViewContext.Writer.Write(DataBinder.Eval(c.DataItem, "Description"));
+			var isDefault = (bool)DataBinder.Eval(c.DataItem, "IsDefault");
+
+			if (isDefault)
+				ViewContext.Writer.Write("<b><i>" + DataBinder.Eval(c.DataItem, "Description") + "</i></b>");
+			else
+				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;" +

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

@@ -62,6 +62,41 @@
 				t.Width = new Unit(100, UnitType.Percentage);
 			}).Render();
 
+			ViewContext.Writer.Write("<div class='inlineModelPropertyContainer'>");
+			{
+				ViewContext.Writer.Write("<div class='inlineModelProperty' style='width: 100%'>");
+				{
+					ViewContext.Writer.Write(Html.CustomLabelFor(m => m.IsDefault, "Ist Standard:"));
+					ViewContext.Writer.Write("<div style=\"overflow: hidden\">");
+					{
+						ViewContext.Writer.Write("<div style=\"float: left\">");
+						{
+							Html.DevExpress().RadioButtonFor(m => m.IsDefault, t =>
+							{
+								t.Text = "Ja";
+								t.GroupName = "isDefault";
+							}).Render();
+						}
+						ViewContext.Writer.Write("</div>");
+
+						ViewContext.Writer.Write("<div style=\"float: left; margin-left: 8px\">");
+						{
+							Html.DevExpress().RadioButton(t =>
+							{
+								t.Name = "isDefaultFalse";
+								t.Text = "Nein";
+								t.GroupName = "isDefault";
+								t.Checked = !Model.IsDefault;
+							}).Render();
+						}
+						ViewContext.Writer.Write("</div>");
+					}
+					ViewContext.Writer.Write("</div>");
+				}
+				ViewContext.Writer.Write("</div>");
+			}
+			ViewContext.Writer.Write("</div>");
+
 			ViewContext.Writer.Write("</div>");
 
 			Html.RenderPartial(

+ 7 - 1
GreenTree.Nachtragsmanagement.Web/Views/Deviations/_StatusListPartial.cshtml

@@ -14,7 +14,13 @@
 	{
 		s.SetItemTemplateContent(c =>
 		{
-			ViewContext.Writer.Write(DataBinder.Eval(c.DataItem, "Description"));
+			var isDefault = (bool)DataBinder.Eval(c.DataItem, "IsDefault");
+
+			if (isDefault)
+				ViewContext.Writer.Write("<b><i>" + DataBinder.Eval(c.DataItem, "Description") + "</i></b>");
+			else
+				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;" +

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

@@ -21,6 +21,7 @@
 	var popupLocationsY = {};
 	var popupMinimized = {};
 	var popupUrls = {};
+	var popupMaxOnStartup = {};
 
 	var contentX = 0;
 	var contentY = 0;
@@ -39,6 +40,7 @@
 			ViewContext.Writer.WriteLine("popupImages[\"" + i.Name + "\"] = \"" + Url.Content(i.ImageUrl) + "\";");
 			ViewContext.Writer.WriteLine("popupDescriptions[\"" + i.Name + "\"] = \"" + i.Description + "\";");
 			ViewContext.Writer.WriteLine("popupUrls[\"" + i.Name + "\"] = \"" + Url.RouteUrl(i.RouteName) + "\";");
+			ViewContext.Writer.WriteLine("popupMaxOnStartup[\"" + i.Name + "\"] = " + (i.MaximizedOnStart.HasValue ? i.MaximizedOnStart.Value.ToString().ToLower() : "false") + ";");
 		}
 	}
 
@@ -114,6 +116,20 @@
 			if (popupWidths[e.item.name] && popupHeights[e.item.name]) {
 				popupControl.SetWidth(popupWidths[e.item.name]);
 				popupControl.SetHeight(popupHeights[e.item.name]);
+			} else if (popupMaxOnStartup[e.item.name] && popupMaxOnStartup[e.item.name] == true) {
+				var popupElem = $("#" + popupName + "_PW-1");
+				var popupContentElem = $("#" + popupName + "_PW-1 > .dxpc-mainDiv");
+				var popupHeaderElem = $("#" + popupName + "_PW-1 > .dxpc-mainDiv > .dxpc-header");
+				openOffsetX = 0;
+				openOffsetY = 0;
+				popupControl.SetWidth($(".functionContentContainer").width());
+				popupControl.SetHeight($(".functionContentContainer").height() - 1);
+				popupContentElem.removeClass("dxpc-shadow");
+				popupHeaderElem.removeClass("devExAllowDrag");
+				popupElem.draggable("disable");
+				popupElem.resizable("disable");
+				popupWidths[e.item.name] = ($(".functionContentContainer").width() * 0.8);
+				popupHeights[e.item.name] = ($(".functionContentContainer").height() * 0.8);
 			}
 			if (!parameters) {
 				popupControl.SetContentUrl(popupUrls[e.item.name]);
@@ -135,7 +151,12 @@
 				.appendTo(".popupPanel")
 				.fadeIn(500);
 		}
-		popupStatus[e.item.name] = "normalized";
+
+		if (popupMaxOnStartup[e.item.name] && popupMaxOnStartup[e.item.name] == true) {
+			popupStatus[e.item.name] = "maximized";
+		} else {
+			popupStatus[e.item.name] = "normalized";
+		}
 	}
 
 	function normalizeFunction(popupName) {

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

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

+ 5 - 2
GreenTree.Nachtragsmanagement.Web/Views/Shared/DataEditorTemplates/_KindsComboBox.cshtml

@@ -2,15 +2,18 @@
 
 @{ 
 	var comboBoxSettingsAction = (Action<ComboBoxSettings>)Session[ViewData["KindsComboBoxSettings"].ToString()];
+	var kindValue = (Model == null || (Model != null && Model.KindId == -1) || (Model != null && !Model.KindId.HasValue))
+		? Convert.ToInt32(ViewData["DefaultKind"])
+		: Model.KindId;
 }
 
 @if (Model == null)
 {
 	Html.DevExpress().ComboBox(comboBoxSettingsAction)
-		.BindList(ViewData["AllKinds"]).GetHtml();
+		.BindList(ViewData["AllKinds"]).Bind(kindValue).GetHtml();
 }
 else
 {
 	Html.DevExpress().ComboBoxFor(m => m.KindId, comboBoxSettingsAction)
-		.BindList(ViewData["AllKinds"]).Bind(Model.KindId).GetHtml();
+		.BindList(ViewData["AllKinds"]).Bind(kindValue).GetHtml();
 }

+ 5 - 2
GreenTree.Nachtragsmanagement.Web/Views/Shared/DataEditorTemplates/_StatesComboBox.cshtml

@@ -2,15 +2,18 @@
 
 @{ 
 	var comboBoxSettingsAction = (Action<ComboBoxSettings>)Session[ViewData["StatesComboBoxSettings"].ToString()];
+	var stateValue = (Model == null || (Model != null && Model.StateId == -1) || (Model != null && !Model.StateId.HasValue))
+		? Convert.ToInt32(ViewData["DefaultState"])
+		: Model.StateId;
 }
 
 @if (Model == null)
 {
 	Html.DevExpress().ComboBox(comboBoxSettingsAction)
-		.BindList(ViewData["AllStates"]).GetHtml();
+		.BindList(ViewData["AllStates"]).Bind(stateValue).GetHtml();
 }
 else
 {
 	Html.DevExpress().ComboBoxFor(m => m.StateId, comboBoxSettingsAction)
-		.BindList(ViewData["AllStates"]).Bind(Model.StateId).GetHtml();
+		.BindList(ViewData["AllStates"]).Bind(stateValue).GetHtml();
 }

+ 5 - 2
GreenTree.Nachtragsmanagement.Web/Views/Shared/DataEditorTemplates/_StatusesComboBox.cshtml

@@ -2,15 +2,18 @@
 
 @{ 
 	var comboBoxSettingsAction = (Action<ComboBoxSettings>)Session[ViewData["StatusesComboBoxSettings"].ToString()];
+	var statusValue = (Model == null || (Model != null && Model.StatusId == -1) || (Model != null && !Model.StatusId.HasValue))
+		? Convert.ToInt32(ViewData["DefaultStatus"])
+		: Model.StatusId;
 }
 
 @if (Model == null)
 {
 	Html.DevExpress().ComboBox(comboBoxSettingsAction)
-		.BindList(ViewData["AllStatuses"]).GetHtml();
+		.BindList(ViewData["AllStatuses"]).Bind(statusValue).GetHtml();
 }
 else
 {
 	Html.DevExpress().ComboBoxFor(m => m.StatusId, comboBoxSettingsAction)
-		.BindList(ViewData["AllStatuses"]).Bind(Model.StatusId).GetHtml();
+		.BindList(ViewData["AllStatuses"]).Bind(statusValue).GetHtml();
 }

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

@@ -3,7 +3,7 @@
 <div class="popupButtonPanel">
 	@Html.DevExpress().Button(b =>
 	{
-		b.Name = "devButtonDialogNo";
+		b.Name = String.IsNullOrEmpty(Model.NoButtonName) ? Guid.NewGuid().ToString() : Model.NoButtonName;
 		b.Text = "Nein";
 		b.Width = new Unit(100, UnitType.Pixel);
 		b.ControlStyle.CssClass += "devExFloatRight devExPopupPanelButton";
@@ -19,7 +19,7 @@
 	}).GetHtml()
 	@Html.DevExpress().Button(b =>
 	{
-		b.Name = "devButtonDialogYes";
+		b.Name = String.IsNullOrEmpty(Model.YesButtonName) ? Guid.NewGuid().ToString() : Model.YesButtonName;
 		b.Text = "Ja";
 		b.Width = new Unit(100, UnitType.Pixel);
 		b.ControlStyle.CssClass += "devExFloatRight devExPopupPanelButton";

+ 7 - 26
GreenTree.Nachtragsmanagement.Web/Views/Sites/View.cshtml

@@ -7,29 +7,6 @@
 <script>
 	var deleteId;
 
-	function saveSite() {
-		var form = $("#siteEditForm");
-		$(form).submit(function (e) {
-			$.ajax({
-				type: "POST",
-				url: '@Url.Action("EditSite", "Site")',
-				data: form.serialize(),
-				success: function (response) {
-					setTimeout(function () {
-						$(".siteEditContainer").remove();
-						if (response == "success") {
-							devGridViewSite.PerformCallback();
-						} else {
-							$("body").append(response);
-						}
-					}, 200);
-				}
-			});
-			e.preventDefault();
-		});
-		form.submit();
-	}
-
 	function editSite(id) {
 		if (!id) return;
 		$.ajax({
@@ -59,7 +36,7 @@
 				var site = JSON.parse(response);
 				var popupControl = MVCxClientPopupControl.Cast(devPopupControlDeleteSite);
 				popupControl.SetHeaderText(popupControl.GetHeaderText().replace("{site}", site.CustomNumber));
-				$(".dialogText").text($(".dialogText").text().replace("{site}", site.CustomNumber));
+				$(".dialogTextSite").text($(".dialogTextSite").text().replace("{site}", site.CustomNumber));
 				popupControl.Show();
 			}
 		});
@@ -88,7 +65,11 @@
 @Html.Partial("~/Views/Shared/_PopupDialogYesNo.cshtml", new GreenTree.Nachtragsmanagement.Web.Models.Global.YesNoDialogModel
 {
 	PopupName = "devPopupControlDeleteSite",
-	Content = "<div class='dialogText' style='padding: 12px'>Sind Sie sicher, dass Sie die Baustelle \"{site}\" löschen möchten?</div>",
+	Content = "<div class='dialogTextSite' style='padding: 12px'>Sind Sie sicher, dass Sie die Baustelle \"{site}\" " +
+			  "und alle zugehörigen Nachträge / Vertragsabweichungen löschen möchten? " +
+			  "Der Vorgang kann nicht rückgängig gemacht werden. </div>",
 	HeaderText = "\"{site}\" löschen",
-	YesFunction = "function (s, e) { deleteSite(); }"
+	YesFunction = "function (s, e) { deleteSite(); }",
+	YesButtonName = "devButtonDeleteSiteYes",
+	NoButtonName = "devButtonDeleteSiteNo"
 })

+ 333 - 133
GreenTree.Nachtragsmanagement.Web/Views/Sites/_SiteEditPartial.cshtml

@@ -10,9 +10,77 @@
 
 	<script>
 		var textSeparator = ", ";
+		var isDragging = false;
+		var dragStartY = 0;
+		var isScrolling = false;
+		var scrollInterval = null;
+		var deleteId = null;
+
+		$(document).ready(function () {
+			$(window).mouseup(function () {
+				isDragging = false;
+			});
+			$(window).mousemove(function (e) {
+				if (isDragging) {
+					var offset = e.clientY - dragStartY;
+					var scrollOffset = $("#siteTreeContainer").scrollTop();
+					if (isDragging) {
+						var result = scrollOffset + (offset / 10);
+						$("#siteTreeContainer").scrollTop(result);
+					}
+				}
+			});
+		});
+
+		function saveSite() {
+			var form = $("#siteEditForm");
+			$(form).submit(function (e) {
+				$.ajax({
+					type: "POST",
+					url: '@Url.Action("EditSite", "Site")',
+					data: form.serialize(),
+					success: function (response) {
+						setTimeout(function () {
+							$(".siteEditContainer").remove();
+							if (response == "success") {
+								devGridViewSite.PerformCallback();
+							} else {
+								$("body").append(response);
+							}
+						}, 200);
+					}
+				});
+				e.preventDefault();
+			});
+			form.submit();
+		}
+
+		function saveSiteForAppend() {
+			devPopupControlSaveForAppend.Hide();
+			var form = $("#siteEditForm");
+			$(form).submit(function (e) {
+				$.ajax({
+					type: "POST",
+					url: '@Url.Action("EditSiteForAppend", "Site")',
+					data: form.serialize(),
+					success: function (response) {
+						setTimeout(function () {
+							$(".siteEditContainer").remove();
+							$("body").append(response);
+						}, 200);
+					}
+				});
+				e.preventDefault();
+			});
+			form.submit();
+		}
 
 		function addAppendixToSite(siteId) {
 			if (!siteId) return;
+			if (siteId == -1) {
+				devPopupControlSaveForAppend.Show();
+				return;
+			}
 			$.ajax({
 				url: '@Url.Action("AppendAppendixToSite", "Appendix")',
 				data: { SiteId: siteId },
@@ -79,6 +147,42 @@
 			});
 		}
 
+		function confirmDeleteDeviation(id) {
+			if (!id) return;
+			deleteId = id;
+			$.ajax({
+				type: "GET",
+				url: '@Url.Action("GetDeviation", "Deviation")',
+				data: { Id: id },
+				success: function (response) {
+					if (response == "notFound") return;
+					var deviation = JSON.parse(response);
+					var popupControl = MVCxClientPopupControl.Cast(devPopupControlDeleteDeviation);
+					popupControl.SetHeaderText(popupControl.GetHeaderText().replace("{deviation}", deviation.CustomNumber));
+					$(".dialogTextDeviation").text($(".dialogTextDeviation").text().replace("{deviation}", deviation.CustomNumber));
+					popupControl.Show();
+				}
+			});
+		}
+
+		function deleteDeviation() {
+			$.ajax({
+				type: "POST",
+				url: '@Url.Action("DeleteDeviation", "Deviation")',
+				data: { Id: deleteId },
+				success: function (response) {
+					var popupControl = MVCxClientPopupControl.Cast(devPopupControlDeleteDeviation);
+					popupControl.Hide();
+					setTimeout(function () {
+						devTreeListSiteDeviationAppendices.PerformCallback();
+					}, 200);
+				},
+				error: function () {
+					 alert("error occured");
+				}
+			});
+		}
+
 		function editAppendix(id) {
 			if (!id) return;
 			$.ajax({
@@ -96,6 +200,76 @@
 			});
 		}
 
+		function confirmDeleteAppendix(id) {
+			if (!id) return;
+			deleteId = id;
+			$.ajax({
+				type: "GET",
+				url: '@Url.Action("GetAppendix", "Appendix")',
+				data: { Id: id },
+				success: function (response) {
+					if (response == "notFound") return;
+					var appendix = JSON.parse(response);
+					var popupControl = MVCxClientPopupControl.Cast(devPopupControlDeleteAppendix);
+					popupControl.SetHeaderText(popupControl.GetHeaderText().replace("{appendix}", appendix.CustomNumber));
+					$(".dialogTextAppendix").text($(".dialogTextAppendix").text().replace("{appendix}", appendix.CustomNumber));
+					popupControl.Show();
+				}
+			});
+		}
+
+		function deleteAppendix() {
+			$.ajax({
+				type: "POST",
+				url: '@Url.Action("DeleteAppendix", "Appendix")',
+				data: { Id: deleteId },
+				success: function (response) {
+					var popupControl = MVCxClientPopupControl.Cast(devPopupControlDeleteAppendix);
+					popupControl.Hide();
+					setTimeout(function () {
+						devTreeListSiteDeviationAppendices.PerformCallback();
+					}, 200);
+				},
+				error: function () {
+					 alert("error occured");
+				}
+			});
+		}
+
+		function startSiteTreeNodeDrag(s, e) {
+			if (!s || !e) return;
+			if (e.nodeKey.startsWith("a")) {
+				e.cancel = true;
+				return;
+			}
+			dragStartY = e.htmlEvent.clientY;
+			isDragging = true;
+			var source = e.nodeKey;
+		}
+
+		function endSiteTreeNodeDrag(s, e) {
+			if (!s || !e) return;
+			isDragging = false;
+			var sourceKey = e.nodeKey;
+			var targetKey = devTreeListSiteDeviationAppendices.GetNodeKeyByRow(e.targetElement);
+			if (!sourceKey || !targetKey) return;
+			$.ajax({
+				type: "POST",
+				url: '@Url.Action("AssignDeviationToEntity", "Site")',
+				data: { SiteId: @Model.Id, SourceKey: sourceKey, TargetKey: targetKey },
+				success: function (response) {
+					if (response == "success") {
+						setTimeout(function () {
+							devTreeListSiteDeviationAppendices.PerformCallback();
+						}, 200);
+					}
+				},
+				error: function () {
+					 alert("error occured");
+				}
+			});
+		}
+
 		function onDeviationSaveSuccess() {
 			devTreeListSiteDeviationAppendices.PerformCallback();
 		}
@@ -105,39 +279,30 @@
 		}
 
 		function onListBoxSelectionChanged(s, e) {
-			if (e.index == 0)
-				e.isSelected ? s.SelectAll() : s.UnselectAll();
 			updateSelectAllItemState();
 			updateText();
 		}
-		function updateSelectAllItemState() {
-			isAllSelected() ? UserValues.SelectIndices([0]) : UserValues.UnselectIndices([0]);
-		}
-		function isAllSelected() {
-			for (var i = 1; i < UserValues.GetItemCount(); i++)
-				if (!UserValues.GetItem(i).selected)
-					return false;
-			return true;
-		}
+
 		function updateText() {
 			var selectedItems = UserValues.GetSelectedItems();
 			devDropDownListUserValues.SetText(getSelectedItemsText(selectedItems));
 		}
+
 		function synchronizeListBoxValues(s, e) {
 			UserValues.UnselectAll();
 			var texts = s.GetText().split(textSeparator);
 			var values = getValuesByTexts(texts);
 			UserValues.SelectValues(values);
-			updateSelectAllItemState();
 			updateText();
 		}
+
 		function getSelectedItemsText(items) {
 			var texts = [];
 			for (var i = 0; i < items.length; i++)
-				if (items[i].index != 0)
-					texts.push(items[i].text);
+				texts.push(items[i].text);
 			return texts.join(textSeparator);
 		}
+
 		function getValuesByTexts(texts) {
 			var actualValues = [];
 			var item;
@@ -152,158 +317,193 @@
 
 	<style>
 		.siteTreeList { }
-		.siteTreeList > tbody > tr > td > table > tbody > tr:nth-child(2n) { background-color: #F7F7F7; }
-		.siteTreeList > tbody > tr > td > table > tbody > tr:nth-child(2n) > td:first-child { background-color: #F7F7F7; }
+		/*.siteTreeList > tbody > tr > td > table > tbody > tr:nth-child(2n) { background-color: #F7F7F7; }
+		.siteTreeList > tbody > tr > td > table > tbody > tr:nth-child(2n) > td:first-child { background-color: #F7F7F7; }*/
+		.siteTreeList a { text-decoration: none; }
+		.siteTreeList a:hover { text-decoration: underline; }
 		.siteEditLayoutTable { width: 100%; }
 		.siteEditLayoutTable > tbody > tr > td { width: 50%; padding-right: 8px; vertical-align: top }
 	</style>
 
 	@Html.DevExpress().PopupControl(s =>
-{
-	s.Name = "devPopupControlEditSite";
-
-	if (Model.Id == -1)
-		s.HeaderText = "Neue Baustelle erstellen";
-	else
-		s.HeaderText = "\"" + Model.CustomNumber + "\" bearbeiten";
-
-	s.Modal = true;
-	s.Width = new Unit(1000, UnitType.Pixel);
-	//s.Height = new Unit(700, UnitType.Pixel);
-	s.CloseAction = CloseAction.CloseButton;
-	s.PopupHorizontalAlign = PopupHorizontalAlign.WindowCenter;
-	s.PopupVerticalAlign = PopupVerticalAlign.TopSides;
-	s.PopupVerticalOffset = 10;
-	s.AllowDragging = true;
-	s.AllowResize = false;
-	s.ShowMaximizeButton = true;
-	s.ShowFooter = false;
-	s.ShowOnPageLoad = true;
-	s.SetContent(() =>
 	{
-		using (Html.BeginForm("EditSite", "Site", FormMethod.Post, new { id = "siteEditForm" }))
-		{
-			ViewContext.Writer.Write("<div class='editFormWrapper'>");
+		s.Name = "devPopupControlEditSite";
 
-			ViewContext.Writer.Write("<input type=\"hidden\" value=\"" + Model.Id + "\" id=\"Id\" name=\"Id\" />");
+		if (Model.Id == -1)
+			s.HeaderText = "Neue Baustelle erstellen";
+		else
+			s.HeaderText = "\"" + Model.CustomNumber + "\" bearbeiten";
 
-			ViewContext.Writer.Write("<table class=\"siteEditLayoutTable\"><tbody><tr><td>");
+		s.Modal = true;
+		s.Width = new Unit(1000, UnitType.Pixel);
+		s.CloseAction = CloseAction.CloseButton;
+		s.PopupHorizontalAlign = PopupHorizontalAlign.WindowCenter;
+		s.PopupVerticalAlign = PopupVerticalAlign.TopSides;
+		s.PopupVerticalOffset = 10;
+		s.AllowDragging = true;
+		s.AllowResize = false;
+		s.ShowMaximizeButton = true;
+		s.ShowFooter = false;
+		s.ShowOnPageLoad = true;
+		s.SetContent(() =>
+		{
+			using (Html.BeginForm("EditSite", "Site", FormMethod.Post, new { id = "siteEditForm" }))
 			{
-				ViewContext.Writer.Write("<div class='inlineModelPropertyContainer'>");
+				ViewContext.Writer.Write("<div class='editFormWrapper'>");
+
+				ViewContext.Writer.Write("<input type=\"hidden\" value=\"" + Model.Id + "\" id=\"Id\" name=\"Id\" />");
+
+				ViewContext.Writer.Write("<table class=\"siteEditLayoutTable\"><tbody><tr><td>");
 				{
-					ViewContext.Writer.Write("<div class='inlineModelProperty' style='width: 30%'>");
+					ViewContext.Writer.Write("<div class='inlineModelPropertyContainer'>");
 					{
-						ViewContext.Writer.Write(Html.CustomLabelFor(m => m.CustomNumber, "Kostenstelle:"));
-						ViewContext.Writer.Write(Html.ValidationMessageFor(m => m.CustomNumber).ToHtmlString());
-						Html.DevExpress().TextBoxFor(m => m.CustomNumber, t =>
+						ViewContext.Writer.Write("<div class='inlineModelProperty' style='width: 30%'>");
 						{
-							t.Width = new Unit(90, UnitType.Percentage);
-						}).Render();
-					}
-					ViewContext.Writer.Write("</div>");
-					ViewContext.Writer.Write("<div class='inlineModelProperty' style='width: 70%'>");
-					{
-						ViewContext.Writer.Write(Html.CustomLabelFor(m => m.Description, "Bauvorhaben:"));
-						ViewContext.Writer.Write(Html.ValidationMessageFor(m => m.Description).ToHtmlString());
-						Html.DevExpress().TextBoxFor(m => m.Description, t =>
+							ViewContext.Writer.Write(Html.CustomLabelFor(m => m.CustomNumber, "Kostenstelle:"));
+							ViewContext.Writer.Write(Html.ValidationMessageFor(m => m.CustomNumber).ToHtmlString());
+							Html.DevExpress().TextBoxFor(m => m.CustomNumber, t =>
+							{
+								t.Width = new Unit(90, UnitType.Percentage);
+							}).Render();
+						}
+						ViewContext.Writer.Write("</div>");
+						ViewContext.Writer.Write("<div class='inlineModelProperty' style='width: 70%'>");
 						{
-							t.Width = new Unit(99, UnitType.Percentage);
-						}).Render();
+							ViewContext.Writer.Write(Html.CustomLabelFor(m => m.Description, "Bauvorhaben:"));
+							ViewContext.Writer.Write(Html.ValidationMessageFor(m => m.Description).ToHtmlString());
+							Html.DevExpress().TextBoxFor(m => m.Description, t =>
+							{
+								t.Width = new Unit(99, UnitType.Percentage);
+							}).Render();
+						}
+						ViewContext.Writer.Write("</div>");
 					}
 					ViewContext.Writer.Write("</div>");
-				}
-				ViewContext.Writer.Write("</div>");
 
-				ViewContext.Writer.Write("<div class='inlineModelPropertyContainer'>");
-				{
-					ViewContext.Writer.Write("<div class='inlineModelProperty' style='width: 52%'>");
+					ViewContext.Writer.Write("<div class='inlineModelPropertyContainer'>");
 					{
-						ViewContext.Writer.Write(Html.CustomLabelFor(m => m.Start, "Start:"));
-						ViewContext.Writer.Write(Html.ValidationMessageFor(m => m.Start).ToHtmlString());
-						Html.DevExpress().DateEditFor(m => m.Start, t =>
+						ViewContext.Writer.Write("<div class='inlineModelProperty' style='width: 52%'>");
 						{
-							t.Width = new Unit(95, UnitType.Percentage);
-						}).Render();
-					}
-					ViewContext.Writer.Write("</div>");
+							ViewContext.Writer.Write(Html.CustomLabelFor(m => m.Start, "Start:"));
+							ViewContext.Writer.Write(Html.ValidationMessageFor(m => m.Start).ToHtmlString());
+							Html.DevExpress().DateEditFor(m => m.Start, t =>
+							{
+								t.Width = new Unit(95, UnitType.Percentage);
+							}).Render();
+						}
+						ViewContext.Writer.Write("</div>");
 
-					ViewContext.Writer.Write("<div class='inlineModelProperty' style='width: 48%'>");
-					{
-						ViewContext.Writer.Write(Html.CustomLabelFor(m => m.End, "Ende:"));
-						ViewContext.Writer.Write(Html.ValidationMessageFor(m => m.End).ToHtmlString());
-						Html.DevExpress().DateEditFor(m => m.End, t =>
+						ViewContext.Writer.Write("<div class='inlineModelProperty' style='width: 48%'>");
 						{
-							t.Width = new Unit(98, UnitType.Percentage);
-						}).Render();
+							ViewContext.Writer.Write(Html.CustomLabelFor(m => m.End, "Ende:"));
+							Html.DevExpress().DateEditFor(m => m.End, t =>
+							{
+								t.Width = new Unit(98, UnitType.Percentage);
+							}).Render();
+						}
+						ViewContext.Writer.Write("</div>");
 					}
 					ViewContext.Writer.Write("</div>");
 				}
-				ViewContext.Writer.Write("</div>");
-			}
-			ViewContext.Writer.Write("</td><td>");
-			{
-				ViewContext.Writer.Write(Html.CustomLabelFor(m => m.Start, "Benutzer:"));
-				Html.DevExpress().DropDownEdit(t =>
+				ViewContext.Writer.Write("</td><td>");
 				{
-					t.Name = "devDropDownListUserValues";
-					t.Width = new Unit(100, UnitType.Percentage);
-					t.Text = Model.UserDescription;
-
-					t.SetDropDownWindowTemplateContent(l =>
+					ViewContext.Writer.Write(Html.CustomLabelFor(m => m.UserValues, "Benutzer:"));
+					ViewContext.Writer.Write(Html.ValidationMessageFor(m => m.UserValues).ToHtmlString());
+					Html.DevExpress().DropDownEdit(t =>
 					{
-						Html.DevExpress().ListBox(lb =>
+						t.Name = "devDropDownListUserValues";
+						t.Width = new Unit(100, UnitType.Percentage);
+						t.Text = Model.UserDescription;
+
+						t.SetDropDownWindowTemplateContent(l =>
 						{
-							lb.Name = "UserValues";
-							lb.Width = new Unit(100, UnitType.Percentage);
-							lb.Height = new Unit(250, UnitType.Pixel);
-							lb.Properties.TextField = "Description";
-							lb.Properties.ValueField = "Id";
-							lb.Properties.ValueType = typeof(int);
-							lb.Properties.SelectionMode = ListEditSelectionMode.CheckColumn;
-							lb.ControlStyle.Border.BorderStyle = BorderStyle.None;
-							lb.PreRender = (sender, e) =>
+							Html.DevExpress().ListBox(lb =>
 							{
-								var listBox = sender as MVCxListBox;
-
-								foreach (ListEditItem listItem in listBox.Items)
+								lb.Name = "UserValues";
+								lb.Width = new Unit(100, UnitType.Percentage);
+								lb.Height = new Unit(250, UnitType.Pixel);
+								lb.Properties.TextField = "Description";
+								lb.Properties.ValueField = "Id";
+								lb.Properties.ValueType = typeof(int);
+								lb.Properties.SelectionMode = ListEditSelectionMode.CheckColumn;
+								lb.ControlStyle.Border.BorderStyle = BorderStyle.None;
+								lb.PreRender = (sender, e) =>
 								{
-									if (Model.UserValues == null || !Model.UserValues.Any(m => m == (int)listItem.Value)) continue;
-
-									listItem.Selected = true;
-								}
-							};
-							lb.Properties.ClientSideEvents.SelectedIndexChanged = "function (s, e) { onListBoxSelectionChanged(s, e); }";
-						}).BindList(ViewData["AllUsers"]).Render();
-
-						t.Properties.ClientSideEvents.TextChanged = "function (s, e) { synchronizeListBoxValues(s, e); }";
-						t.Properties.ClientSideEvents.DropDown = "function (s, e) { synchronizeListBoxValues(s, e); }";
-					});
-				}).Render();
-			}
-			ViewContext.Writer.Write("</td></tr></tbody></table>");
+									var listBox = sender as MVCxListBox;
 
+									foreach (ListEditItem listItem in listBox.Items)
+									{
+										if (Model.UserValues == null || !Model.UserValues.Any(m => m == (int)listItem.Value)) continue;
 
-			ViewContext.Writer.Write(Html.CustomLabelFor(m => m.Deviations, "Vertragsabweichungen / Nachträge:"));
+										listItem.Selected = true;
+									}
+								};
+								lb.Properties.ClientSideEvents.SelectedIndexChanged = "function (s, e) { onListBoxSelectionChanged(s, e); }";
+							}).BindList(ViewData["AllUsers"]).Render();
+
+							t.Properties.ClientSideEvents.TextChanged = "function (s, e) { synchronizeListBoxValues(s, e); }";
+							t.Properties.ClientSideEvents.DropDown = "function (s, e) { synchronizeListBoxValues(s, e); }";
+						});
+					}).Render();
+				}
+				ViewContext.Writer.Write("</td></tr></tbody></table>");
 
-			ViewContext.Writer.Write("<div style='width: 100%; overflow: auto; max-height: 450px; border: 1px solid #d0d0d0'>");
-			{
-				ViewContext.Writer.Write(Html.Partial("~/Views/Sites/_SiteEditTreePartial.cshtml", Model).ToHtmlString());
-			}
-			ViewContext.Writer.Write("</div>");
 
-			ViewContext.Writer.Write("</div>");
+				ViewContext.Writer.Write(Html.CustomLabelFor(m => m.Deviations, "Vertragsabweichungen / Nachträge:"));
 
-			Html.RenderPartial(
-				"~/Views/Shared/_PopupButtonPanel.cshtml",
-				new GreenTree.Nachtragsmanagement.Web.Models.Global.PopupModel
+				ViewContext.Writer.Write("<div id=\"siteTreeContainer\" style='width: 100%; overflow: auto; max-height: 450px; border: 1px solid #d0d0d0'>");
 				{
-					PopupName = "devPopupControlEditSite",
-					AcceptFunction = "function (s, e) { saveSite(); }"
+					ViewContext.Writer.Write(Html.Partial("~/Views/Sites/_SiteEditTreePartial.cshtml", Model).ToHtmlString());
 				}
-			);
-		}
-	});
-	s.Styles.Content.Paddings.Padding = new Unit(0);
-	s.Styles.ModalBackground.Opacity = 0;
-}).GetHtml()
+				ViewContext.Writer.Write("</div>");
+
+				ViewContext.Writer.Write("</div>");
+
+				Html.RenderPartial(
+					"~/Views/Shared/_PopupButtonPanel.cshtml",
+					new GreenTree.Nachtragsmanagement.Web.Models.Global.PopupModel
+					{
+						PopupName = "devPopupControlEditSite",
+						AcceptFunction = "function (s, e) { saveSite(); }"
+					}
+				);
+			}
+		});
+		s.Styles.Content.Paddings.Padding = new Unit(0);
+		s.Styles.ModalBackground.Opacity = 0;
+	}).GetHtml()
+
+	@Html.Partial("~/Views/Shared/_PopupDialogYesNo.cshtml", new GreenTree.Nachtragsmanagement.Web.Models.Global.YesNoDialogModel
+{
+	PopupName = "devPopupControlSaveForAppend",
+	Content = "<div class='dialogTextSaveForAppend' style='padding: 12px'>Damit ein Nachtrag für die Baustelle erfasst werden kann, " +
+			  "muss Sie zunächst gespeichert werden. Soll die Baustelle jetzt gespeichert werden?</div>",
+	HeaderText = "Baustelle speichern",
+	YesFunction = "function (s, e) { saveSiteForAppend(); }",
+	YesButtonName = "devButtonSaveForAppendYes",
+	NoButtonName = "devButtonSaveForAppendNo"
+})
+
+	@Html.Partial("~/Views/Shared/_PopupDialogYesNo.cshtml", new GreenTree.Nachtragsmanagement.Web.Models.Global.YesNoDialogModel
+	{
+		PopupName = "devPopupControlDeleteAppendix",
+		Content = "<div class='dialogTextAppendix' style='padding: 12px'>Sind Sie sicher, dass Sie den Nachtrag \"{appendix}\" und " +
+				  "alle zugehörigen Vertragsabweichungen löschen möchten? Der Vorgang kann nicht rückgängig gemacht werden.</div>",
+		HeaderText = "\"{appendix}\" löschen",
+		YesFunction = "function (s, e) { deleteAppendix(); }",
+		YesButtonName = "devButtonDeleteAppendixYes",
+		NoButtonName = "devButtonDeleteAppendixNo"
+	})
+
+	@Html.Partial("~/Views/Shared/_PopupDialogYesNo.cshtml", new GreenTree.Nachtragsmanagement.Web.Models.Global.YesNoDialogModel
+	{
+		PopupName = "devPopupControlDeleteDeviation",
+		Content = "<div class='dialogTextDeviation' style='padding: 12px'>Sind Sie sicher, dass Sie die Vertragsabweichung \"{deviation}\" " +
+				  "löschen möchten? Der Vorgang kann nicht rückgängig gemacht werden.</div>",
+		HeaderText = "\"{deviation}\" löschen",
+		YesFunction = "function (s, e) { deleteDeviation(); }",
+		YesButtonName = "devButtonDeleteDeviationYes",
+		NoButtonName = "devButtonDeleteDeviationNo"
+	})
+
 </div>

+ 15 - 3
GreenTree.Nachtragsmanagement.Web/Views/Sites/_SiteEditTreePartial.cshtml

@@ -12,6 +12,10 @@
 	t.CallbackRouteValues = new { Controller = "Site", Action = "PartialDeviationAppendices", siteId = Model.Id };
 	t.Width = Unit.Percentage(100);
 	t.Settings.GridLines = GridLines.Vertical;
+	t.SettingsBehavior.AllowDragDrop = true;
+	t.SettingsEditing.NodeDragDropRouteValues = new { Controller = "Site", Action = "PartialDeviationAppendices", siteId = Model.Id };
+	t.ClientSideEvents.StartDragNode = "function (s, e) { startSiteTreeNodeDrag(s, e); }";
+	t.ClientSideEvents.EndDragNode = "function (s, e) { endSiteTreeNodeDrag(s, e); }";
 
 	t.Columns.Add(column =>
 	{
@@ -33,7 +37,7 @@
 			else if (treeKey.StartsWith("d"))
 			{
 				ViewContext.Writer.Write(
-					"<a href=\"#\" onclick=\"editDeviation(" + DataBinder.Eval(c.DataItem, "Id") + ")\">Bearbeiten</a>&nbsp;");
+					"<a href=\"#\" onclick=\"editDeviation(" + DataBinder.Eval(c.DataItem, "Id") + ")\">Bearbeiten</a><br />");
 				ViewContext.Writer.Write(
 					"<a href=\"#\" onclick=\"confirmDeleteDeviation(" + DataBinder.Eval(c.DataItem, "Id") + ")\">Löschen</a>");
 			}
@@ -42,7 +46,7 @@
 				ViewContext.Writer.Write(
 					"<a href=\"#\" onclick=\"addDeviationToAppendix(" + DataBinder.Eval(c.DataItem, "Id") + ")\">Neue VA</a><br />");
 				ViewContext.Writer.Write(
-					"<a href=\"#\" onclick=\"editAppendix(" + DataBinder.Eval(c.DataItem, "Id") + ")\">Bearbeiten</a>&nbsp;");
+					"<a href=\"#\" onclick=\"editAppendix(" + DataBinder.Eval(c.DataItem, "Id") + ")\">Bearbeiten</a><br />");
 				ViewContext.Writer.Write(
 					"<a href=\"#\" onclick=\"confirmDeleteAppendix(" + DataBinder.Eval(c.DataItem, "Id") + ")\">Löschen</a>");
 			}
@@ -119,10 +123,18 @@
 		});
 	});
 
+	t.HtmlRowPrepared = (sender, e) =>
+	{
+		var hexColor = e.GetValue("StatusColor");
+
+		if (hexColor == null) return;
+
+		e.Row.BackColor = System.Drawing.ColorTranslator.FromHtml(hexColor.ToString());
+	};
+
 	t.ControlStyle.CssClass += "siteTreeList";
 	t.Styles.IndentWithButton.Paddings.PaddingTop = new Unit(18, UnitType.Pixel);
 	t.Styles.Cell.VerticalAlign = VerticalAlign.Top;
 	t.Styles.Cell.Paddings.PaddingTop = new Unit(14, UnitType.Pixel);
 	t.Styles.Cell.Paddings.PaddingBottom = new Unit(14, UnitType.Pixel);
-	t.Styles.AlternatingNode.BackColor = System.Drawing.Color.FromArgb(247, 247, 247);
 }).Bind(Model.SiteTreeData).GetHtml()