Quellcode durchsuchen

Nachtragsmanagement ist jetzt möglich!

Arne Diekmann vor 8 Jahren
Ursprung
Commit
4b6443a39a
44 geänderte Dateien mit 1571 neuen und 274 gelöschten Zeilen
  1. 11 0
      GreenTree.Nachtragsmanagement.Services/Appendix/AppendixService.cs
  2. 6 0
      GreenTree.Nachtragsmanagement.Services/Appendix/IAppendixService.cs
  3. 11 11
      GreenTree.Nachtragsmanagement.Web/App_Start/FunctionConfig.cs
  4. 3 3
      GreenTree.Nachtragsmanagement.Web/App_Start/RouteConfig.cs
  5. 0 0
      GreenTree.Nachtragsmanagement.Web/Content/Images/function-Appendix-Claims-32-contrast.png
  6. 0 0
      GreenTree.Nachtragsmanagement.Web/Content/Images/function-Appendix-Claims-32.png
  7. 168 52
      GreenTree.Nachtragsmanagement.Web/Controllers/AppendixController.cs
  8. 51 28
      GreenTree.Nachtragsmanagement.Web/Controllers/DataCallbackController.cs
  9. 6 1
      GreenTree.Nachtragsmanagement.Web/Controllers/DeviationController.cs
  10. 10 1
      GreenTree.Nachtragsmanagement.Web/Controllers/SiteController.cs
  11. 17 7
      GreenTree.Nachtragsmanagement.Web/GreenTree.Nachtragsmanagement.Web.csproj
  12. 45 12
      GreenTree.Nachtragsmanagement.Web/Models/Appendix/AppendixDataModel.cs
  13. 23 0
      GreenTree.Nachtragsmanagement.Web/Models/Appendix/CategoryValueDataModel.cs
  14. 2 2
      GreenTree.Nachtragsmanagement.Web/Models/Appendix/IRequireStateDataModel.cs
  15. 40 0
      GreenTree.Nachtragsmanagement.Web/Models/Appendix/StateDataModel.cs
  16. 11 1
      GreenTree.Nachtragsmanagement.Web/Models/Deviation/DeviationDataModel.cs
  17. 13 0
      GreenTree.Nachtragsmanagement.Web/Models/Deviation/IRequireDisturbanceDataModel.cs
  18. 3 3
      GreenTree.Nachtragsmanagement.Web/Models/Global/EmptyIRequireDataModel.cs
  19. 3 2
      GreenTree.Nachtragsmanagement.Web/Models/Site/SiteDataModel.cs
  20. 38 0
      GreenTree.Nachtragsmanagement.Web/Validation/Appendix/AppendixDataModelValidator.cs
  21. 22 0
      GreenTree.Nachtragsmanagement.Web/Validation/Appendix/CategoryDataModelValidator.cs
  22. 22 0
      GreenTree.Nachtragsmanagement.Web/Validation/Appendix/StateDataModelValidator.cs
  23. 7 0
      GreenTree.Nachtragsmanagement.Web/Validation/AppendixValidatorFactory.cs
  24. 1 1
      GreenTree.Nachtragsmanagement.Web/Validation/Deviation/DeviationDataModelValidator.cs
  25. 1 1
      GreenTree.Nachtragsmanagement.Web/Validation/Deviation/DisturbanceDataModelValidator.cs
  26. 1 1
      GreenTree.Nachtragsmanagement.Web/Validation/Deviation/KindDataModelValidator.cs
  27. 1 1
      GreenTree.Nachtragsmanagement.Web/Validation/Deviation/StatusDataModelValidator.cs
  28. 1 1
      GreenTree.Nachtragsmanagement.Web/Validation/Site/SiteDataModelValidator.cs
  29. 0 71
      GreenTree.Nachtragsmanagement.Web/Views/Appendices/Categories.cshtml
  30. 205 0
      GreenTree.Nachtragsmanagement.Web/Views/Appendices/Claims.cshtml
  31. 399 0
      GreenTree.Nachtragsmanagement.Web/Views/Appendices/_AppendixEditPartial.cshtml
  32. 44 11
      GreenTree.Nachtragsmanagement.Web/Views/Appendices/_AppendixGridPartial.cshtml
  33. 3 3
      GreenTree.Nachtragsmanagement.Web/Views/Appendices/_CategoryListPartial.cshtml
  34. 70 0
      GreenTree.Nachtragsmanagement.Web/Views/Appendices/_CategoryValueEditPartial.cshtml
  35. 80 0
      GreenTree.Nachtragsmanagement.Web/Views/Appendices/_StateEditPartial.cshtml
  36. 30 0
      GreenTree.Nachtragsmanagement.Web/Views/Appendices/_StateListPartial.cshtml
  37. 2 2
      GreenTree.Nachtragsmanagement.Web/Views/Deviations/Claims.cshtml
  38. 2 4
      GreenTree.Nachtragsmanagement.Web/Views/Deviations/_DeviationEditPartial.cshtml
  39. 24 3
      GreenTree.Nachtragsmanagement.Web/Views/Deviations/_DeviationGridPartial.cshtml
  40. 6 0
      GreenTree.Nachtragsmanagement.Web/Views/Deviations/_DisturbanceValueEditPartial.cshtml
  41. 0 16
      GreenTree.Nachtragsmanagement.Web/Views/Shared/DataEditorTemplates/_AppendicesComboBox.cshtml
  42. 16 0
      GreenTree.Nachtragsmanagement.Web/Views/Shared/DataEditorTemplates/_StatesComboBox.cshtml
  43. 167 35
      GreenTree.Nachtragsmanagement.Web/Views/Sites/_SiteEditPartial.cshtml
  44. 6 1
      GreenTree.Nachtragsmanagement.Web/Views/Sites/_SiteEditTreePartial.cshtml

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

@@ -252,6 +252,17 @@ namespace GreenTree.Nachtragsmanagement.Services.Appendix
                 .ToList();
         }
 
+        /// <summary>
+        /// Gets all appendices to the specified with the specified status id
+        /// </summary>
+        /// <param name="id">State identifier.</param>
+        public IList<Core.Domain.Appendix.Appendix> GetAppendicesByState(int id)
+        {
+            return _appendixRepository.Table
+                .Where(d => d.StateId == id)
+                .ToList();
+        }
+
         /// <summary>
         /// Insert a appendix
         /// </summary>

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

@@ -148,6 +148,12 @@ namespace GreenTree.Nachtragsmanagement.Services.Appendix
         /// </summary>
         IList<State> GetStatesByIds(int[] ids);
 
+        /// <summary>
+        /// Gets all appendices to the specified with the specified status id
+        /// </summary>
+        /// <param name="id">State identifier.</param>
+        IList<Core.Domain.Appendix.Appendix> GetAppendicesByState(int id);
+
         /// <summary>
         /// Insert a state
         /// </summary>

+ 11 - 11
GreenTree.Nachtragsmanagement.Web/App_Start/FunctionConfig.cs

@@ -221,24 +221,24 @@ namespace GreenTree.Nachtragsmanagement.Web.App_Start
                 },
                 new Function
                 {
-                    Name = "Appendix-Categories",
-                    Description = "Kategorien",
-                    ImageUrl = "~/Content/Images/function-Appendix-Categories-32.png",
+                    Name = "Appendix-Claims",
+                    Description = "Stammdaten",
+                    ImageUrl = "~/Content/Images/function-Appendix-Claims-32.png",
                     GroupName = "Appendix",
-                    RouteName = "GreenTree.Nachtragsmanagement.Web.Appendix.Categories",
+                    RouteName = "GreenTree.Nachtragsmanagement.Web.Appendix.Claims",
                     IsMenuMember = true,
                     Plugin = "System",
-                    BaseWidth = 500,
-                    MinWidth = 400,
-                    BaseHeight = 350,
-                    MinHeight = 300,
+                    BaseWidth = 800,
+                    MinWidth = 600,
+                    BaseHeight = 500,
+                    MinHeight = 350,
                     AllowMaximize = true
                 },
                 new Function
                 {
-                    Name = "Appendix-Categories-Edit",
-                    Description = "Kategorien editieren",
-                    GroupName = "Appendix-Categories",
+                    Name = "Appendix-Claims-Edit",
+                    Description = "Stammdaten editieren",
+                    GroupName = "Appendix-Claims",
                     IsMenuMember = false,
                     Plugin = "System"
                 },

+ 3 - 3
GreenTree.Nachtragsmanagement.Web/App_Start/RouteConfig.cs

@@ -105,12 +105,12 @@ namespace GreenTree.Nachtragsmanagement.Web
             );
 
             routes.MapRoute(
-                "GreenTree.Nachtragsmanagement.Web.Appendix.Categories",
-                "appendix/viewcategories",
+                "GreenTree.Nachtragsmanagement.Web.Appendix.Claims",
+                "appendix/viewclaims",
                new
                {
                    controller = "Appendix",
-                   action = "ViewCategories"
+                   action = "ViewClaims"
                },
                new[]
                {

+ 0 - 0
GreenTree.Nachtragsmanagement.Web/Content/Images/function-Appendix-Categories-32-contrast.png → GreenTree.Nachtragsmanagement.Web/Content/Images/function-Appendix-Claims-32-contrast.png


+ 0 - 0
GreenTree.Nachtragsmanagement.Web/Content/Images/function-Appendix-Categories-32.png → GreenTree.Nachtragsmanagement.Web/Content/Images/function-Appendix-Claims-32.png


+ 168 - 52
GreenTree.Nachtragsmanagement.Web/Controllers/AppendixController.cs

@@ -1,7 +1,10 @@
-using GreenTree.Nachtragsmanagement.Services.Appendix;
+using GreenTree.Nachtragsmanagement.Core;
+using GreenTree.Nachtragsmanagement.Services.Appendix;
 using GreenTree.Nachtragsmanagement.Services.Deviation;
+using GreenTree.Nachtragsmanagement.Services.Site;
 using GreenTree.Nachtragsmanagement.Web.Framework.Authorization;
 using GreenTree.Nachtragsmanagement.Web.Models.Appendix;
+using GreenTree.Nachtragsmanagement.Web.Models.Deviation;
 using Newtonsoft.Json;
 using System;
 using System.Collections.Generic;
@@ -15,15 +18,19 @@ namespace GreenTree.Nachtragsmanagement.Web.Controllers
     {
         private readonly IDeviationService _deviationSerivce;
         private readonly IAppendixService _appendixService;
+        private readonly ISiteService _siteService;
 
         public AppendixController(
             IDeviationService deviationService,
-            IAppendixService appendixService)
+            IAppendixService appendixService,
+            ISiteService siteService)
         {
             _deviationSerivce = deviationService;
             _appendixService = appendixService;
+            _siteService = siteService;
 
             ViewData["AllCategories"] = _appendixService.GetAllCategories();
+            ViewData["AllStates"] = _appendixService.GetAllStates();
         }
 
         #region Appendices
@@ -90,6 +97,29 @@ namespace GreenTree.Nachtragsmanagement.Web.Controllers
             return PartialView("~/Views/Appendices/_AppendixEditPartial.cshtml", appendixModel);
         }
 
+        /// <summary>
+        /// Partial edit for creating a new deviation for a site
+        /// </summary>
+        /// <param name="siteId">Id of the site which the deviation should be appended to.</param>
+        public ActionResult AppendAppendixToSite(int siteId)
+        {
+            var site = _siteService.GetSiteById(siteId);
+
+            var lastCustomNumber = site.Appendices
+                .Max(d => StaticHelper.TryParseInt(d.CustomNumber));
+
+            var appendixModel = new AppendixDataModel
+            {
+                Id = -1,
+                CustomNumber = (lastCustomNumber + 1).ToString()
+            };
+
+            ViewData["relationType"] = "site";
+            ViewData["relationId"] = siteId;
+
+            return PartialView("~/Views/Appendices/_AppendixEditPartial.cshtml", appendixModel);
+        }
+
         /// <summary>
         /// Partial edit result if ModelState is valid, otherwise simple JSON result for success
         /// </summary>
@@ -97,9 +127,21 @@ namespace GreenTree.Nachtragsmanagement.Web.Controllers
         [HttpPost, ValidateInput(false)]
         public ActionResult EditAppendix(AppendixDataModel appendixModel)
         {
+            appendixModel.CategoryValueEntities =
+                appendixModel.CategoryEntities
+                    .Select(r => JsonConvert.DeserializeObject<CategoryValueDataModel>(r))
+                    .ToList();
+
+            for (int i = 0; i < appendixModel.CategoryValueEntities.Count; i++)
+                appendixModel.CategoryValueEntities.ElementAt(i).Json = appendixModel.CategoryEntities.ElementAt(i);
+
             if (!ModelState.IsValid)
                 return PartialView("~/Views/Appendices/_AppendixEditPartial.cshtml", appendixModel);
 
+            var categoryValues = appendixModel.CategoryValueEntities
+                .Select(r => r.ToCategoryValue())
+                .ToList();
+
             if (appendixModel.Id == -1)
             {
                 var appendix = appendixModel.ToAppendix();
@@ -120,6 +162,7 @@ namespace GreenTree.Nachtragsmanagement.Web.Controllers
                 appendix.ProtocolExists = appendixModel.ProtocolExists;
                 appendix.OrderNumber = appendixModel.OrderNumber;
                 appendix.OrderDate = appendixModel.OrderDate;
+                appendix.OrderInvoiceCreated = appendixModel.OrderInvoiceCreated;
                 appendix.Comment = appendixModel.Comment;
                 appendix.SiteId = appendixModel.SiteId;
 
@@ -152,68 +195,121 @@ namespace GreenTree.Nachtragsmanagement.Web.Controllers
 
         #endregion
 
-        #region Categories
+        #region Claims
 
         /// <summary>
-        /// Basic category view function
+        /// Basic claim view function
         /// </summary>
-        [FunctionAuthorize(true, "Appendix-Categories")]
-        public ActionResult ViewCategories()
+        [FunctionAuthorize(true, "Appendix-Claims")]
+        public ActionResult ViewClaims()
         {
-            var categories = _appendixService.GetAllCategories();
-            var categoryModels = categories
-                .Select(u => CategoryDataModel.FromCategory(u, false))
-                .ToList();
-
-            return View("~/Views/Appendix/Categories.cshtml", categoryModels);
+            return View("~/Views/Appendices/Claims.cshtml");
         }
 
         /// <summary>
-        /// Get JSON data of specific category
+        /// Get JSON data of specific claim
         /// </summary>
-        /// <param name="id">Category id.</param>
-        public ActionResult GetCategory(int id = -1)
+        /// <param name="claimType">Claim type.</param>
+        /// <param name="id">Claim id.</param>
+        public ActionResult GetClaim(string claimType, int id = -1)
         {
-            var category = _appendixService.GetCategoryById(id);
-            if (category == null)
-                return new JsonResult
-                {
-                    Data = "notFound",
-                    JsonRequestBehavior = JsonRequestBehavior.AllowGet
-                };
-
-            var categoryModel = CategoryDataModel.FromCategory(category, false);
-
-            return new JsonResult
+            switch (claimType.ToLower())
             {
-                Data = JsonConvert.SerializeObject(categoryModel),
-                JsonRequestBehavior = JsonRequestBehavior.AllowGet
-            };
+                case "state":
+                    var state = _appendixService.GetStateById(id);
+                    if (state == null)
+                        return new JsonResult { Data = "notFound", JsonRequestBehavior = JsonRequestBehavior.AllowGet };
+                    else
+                        return new JsonResult
+                        {
+                            Data = JsonConvert.SerializeObject(state),
+                            JsonRequestBehavior = JsonRequestBehavior.AllowGet
+                        };
+                case "category":
+                    var category = _appendixService.GetCategoryById(id);
+                    if (category == null)
+                        return new JsonResult { Data = "notFound", JsonRequestBehavior = JsonRequestBehavior.AllowGet };
+                    else
+                        return new JsonResult
+                        {
+                            Data = JsonConvert.SerializeObject(category),
+                            JsonRequestBehavior = JsonRequestBehavior.AllowGet
+                        };
+                default:
+                    return new JsonResult { Data = "unknownClaimType", JsonRequestBehavior = JsonRequestBehavior.AllowGet };
+            }
         }
 
         /// <summary>
-        /// Callback result for category grid
+        /// Callback result for claim grid
         /// </summary>
-        public ActionResult PartialCategories()
+        /// <param name="claimType">Claim type.</param>
+        public ActionResult PartialClaims(string claimType)
         {
-            var categories = _appendixService.GetAllCategories();
-            var categoryModels = categories
-                .Select(u => CategoryDataModel.FromCategory(u, false))
-                .ToList();
+            switch (claimType.ToLower())
+            {
+                case "state":
+                    return PartialView("~/Views/Appendices/_StateListPartial.cshtml", ViewData["AllStates"]);
+                case "category":
+                    return PartialView("~/Views/Appendices/_CategoryListPartial.cshtml", ViewData["AllCategories"]);
+                default:
+                    return new EmptyResult();
+            }
+        }
 
-            return PartialView("~/Views/Admin/Categories/_CategoryListPartial.cshtml", categoryModels);
+        /// <summary>
+        /// Partial edit for editing of existing or for new claim
+        /// </summary>
+        /// <param name="claimType">Claim type.</param>
+        /// <param name="id">Id for existing claim, otherweise -1.</param>
+        public ActionResult EditClaim(string claimType = "", int id = -1)
+        {
+            switch (claimType.ToLower())
+            {
+                case "state":
+                    var state = _appendixService.GetStateById(id);
+                    var stateModel = StateDataModel.FromState(state, true);
+
+                    return PartialView("~/Views/Appendices/_StateEditPartial.cshtml", stateModel);
+                case "category":
+                    var category = _appendixService.GetCategoryById(id);
+                    var categoryModel = CategoryDataModel.FromCategory(category, true);
+
+                    return PartialView("~/Views/Appendices/_CategoryEditPartial.cshtml", categoryModel);
+                default:
+                    return new EmptyResult();
+            }
         }
 
         /// <summary>
-        /// Partial edit for editing of existing or for new category
+        /// Partial edit result if ModelState is valid, otherwise simple JSON result for success
         /// </summary>
-        /// <param name="id">Id for existing category, otherweise -1.</param>
-        public ActionResult EditCategory(int id = -1)
+        /// <param name="stateModel">State model to be saved.</param>
+        [HttpPost, ValidateInput(false)]
+        public ActionResult EditState(StateDataModel stateModel)
         {
-            var category = _appendixService.GetCategoryById(id);
-            var categoryModel = CategoryDataModel.FromCategory(category, true);
+            if (!ModelState.IsValid)
+                return PartialView("~/Views/Appendices/_StateEditPartial.cshtml", stateModel);
 
-            return PartialView("~/Views/Admin/Categories/_CategoryEditPartial.cshtml", categoryModel);
+            if (stateModel.Id == -1)
+            {
+                var claim = stateModel.ToState();
+
+                _appendixService.InsertState(claim);
+            }
+            else
+            {
+                var state = _appendixService.GetStateById(stateModel.Id);
+
+                state.Description = stateModel.Description;
+
+                _appendixService.UpdateState(state);
+            }
+
+            return new JsonResult
+            {
+                Data = "success"
+            };
         }
 
         /// <summary>
@@ -224,7 +320,7 @@ namespace GreenTree.Nachtragsmanagement.Web.Controllers
         public ActionResult EditCategory(CategoryDataModel categoryModel)
         {
             if (!ModelState.IsValid)
-                return PartialView("~/Views/Deviations/_CategoryEditPartial.cshtml", categoryModel);
+                return PartialView("~/Views/Appendices/_CategoryEditPartial.cshtml", categoryModel);
 
             if (categoryModel.Id == -1)
             {
@@ -234,11 +330,11 @@ namespace GreenTree.Nachtragsmanagement.Web.Controllers
             }
             else
             {
-                var disturbance = _appendixService.GetCategoryById(categoryModel.Id);
+                var category = _appendixService.GetCategoryById(categoryModel.Id);
 
-                disturbance.Description = categoryModel.Description;
+                category.Description = categoryModel.Description;
 
-                _appendixService.UpdateCategory(disturbance);
+                _appendixService.UpdateCategory(category);
             }
 
             return new JsonResult
@@ -248,16 +344,36 @@ namespace GreenTree.Nachtragsmanagement.Web.Controllers
         }
 
         /// <summary>
-        /// Simple JSON result for deleting a specific category
+        /// Simple JSON result for deleting a specific claim
         /// </summary>
-        /// <param name="id">Category id.</param>
+        /// <param name="claimType">Claim type.</param>
+        /// <param name="id">Claim id.</param>
+        /// <param name="replaceId">Id of claim which deviations get in place of deleting claim.</param>
         [HttpPost]
-        public ActionResult DeleteCategory(int id)
+        public ActionResult DeleteClaim(string claimType, int id, int replaceId)
         {
-            var category = _appendixService.GetCategoryById(id);
+            switch (claimType.ToLower())
+            {
+                case "state":
+                    var state = _appendixService.GetStateById(id);
+                    var replaceState = _appendixService.GetStateById(replaceId);
+
+                    var stateAppendices = _appendixService.GetAppendicesByState(id);
 
-            if (category != null)
-                _appendixService.DeleteCategory(category);
+                    foreach (var appendix in stateAppendices)
+                    {
+                        appendix.StateId = replaceId;
+                        appendix.State = replaceState;
+
+                        _appendixService.UpdateAppendix(appendix);
+                    }
+
+                    if (state != null)
+                        _appendixService.DeleteState(state);
+                    break;
+                default:
+                    return new EmptyResult();
+            }
 
             return new JsonResult
             {

+ 51 - 28
GreenTree.Nachtragsmanagement.Web/Controllers/DataCallbackController.cs

@@ -88,34 +88,6 @@ namespace GreenTree.Nachtragsmanagement.Web.Controllers
 
         #endregion
 
-        #region Appendix
-
-        /// <summary>
-        /// Returns a DevExpress ComboBox for all appendices 
-        /// </summary>
-        /// <param name="settingsKey">Current comboBox settings key.</param>
-        /// <param name="model">JSON-serialized model.</param>
-        /// <param name="type">Type of model.</param>
-        public ActionResult AppendicesComboBox(string settingsKey, string model = null, string type = null)
-        {
-            var allAppendices = _appendixService.GetAllAppendices();
-
-            ViewData["AllAppendices"] = allAppendices;
-            ViewData["AppendicesComboBoxSettings"] = settingsKey;
-
-            if (model != null && type != null)
-            {
-                var modelType = Type.GetType(type);
-                var modelObject = JsonConvert.DeserializeObject(model, modelType, _serializerSettings);
-
-                return PartialView("~/Views/Shared/DataEditorTemplates/_AppendicesComboBox.cshtml", modelObject);
-            }
-
-            return PartialView("~/Views/Shared/DataEditorTemplates/_AppendicesComboBox.cshtml", null);
-        }
-
-        #endregion
-
         #region Deviations
 
         /// <summary>
@@ -273,5 +245,56 @@ namespace GreenTree.Nachtragsmanagement.Web.Controllers
         }
 
         #endregion
+
+        #region Appendices
+
+        /// <summary>
+        /// Returns a DevExpress ComboBox for all states 
+        /// </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 StatesComboBox(string settingsKey, string model, string type)
+        {
+            return StatesComboBoxExcluded(settingsKey, model, type, null);
+        }
+
+        /// <summary>
+        /// Returns a DevExpress ComboBox for all states 
+        /// </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 states.</param>
+        public ActionResult StatesComboBoxExcluded(string settingsKey, string model, string type, int[] excludedIds)
+        {
+            var allStates = _appendixService.GetAllStates();
+
+            if (excludedIds != null)
+            {
+                foreach (var excludedId in excludedIds)
+                {
+                    var item = allStates
+                        .FirstOrDefault(s => s.Id == excludedId);
+
+                    allStates.Remove(item);
+                }
+            }
+
+            ViewData["AllStates"] = allStates;
+            ViewData["StatesComboBoxSettings"] = settingsKey;
+
+            if (model != null && type != null)
+            {
+                var modelType = Type.GetType(type);
+                var modelObject = JsonConvert.DeserializeObject(model, modelType, _serializerSettings);
+
+                return PartialView("~/Views/Shared/DataEditorTemplates/_StatesComboBox.cshtml", modelObject);
+            }
+
+            return PartialView("~/Views/Shared/DataEditorTemplates/_StatesComboBox.cshtml", null);
+        }
+
+        #endregion
     }
 }

+ 6 - 1
GreenTree.Nachtragsmanagement.Web/Controllers/DeviationController.cs

@@ -30,8 +30,8 @@ namespace GreenTree.Nachtragsmanagement.Web.Controllers
             _appendixService = appendixService;
             _siteService = siteService;
 
-            ViewData["AllStatuses"] = _deviationService.GetAllStatuses();
             ViewData["AllDisturbances"] = _deviationService.GetAllDisturbances();
+            ViewData["AllStatuses"] = _deviationService.GetAllStatuses();
             ViewData["AllKinds"] = _deviationService.GetAllKinds();
         }
 
@@ -177,6 +177,11 @@ namespace GreenTree.Nachtragsmanagement.Web.Controllers
                     .Select(r => JsonConvert.DeserializeObject<DisturbanceValueDataModel>(r))
                     .ToList();
 
+            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);
+
             if (!ModelState.IsValid)
                 return PartialView("~/Views/Deviations/_DeviationEditPartial.cshtml", deviationModel);
 

+ 10 - 1
GreenTree.Nachtragsmanagement.Web/Controllers/SiteController.cs

@@ -32,7 +32,16 @@ namespace GreenTree.Nachtragsmanagement.Web.Controllers
             _appendixService = appendixService;
             _userService = userService;
 
-            ViewData["AllSite"] = _siteService.GetAllSites();
+            ViewData["AllUsers"] =
+                _userService.GetAllUsers()
+                    .Select(u => new
+                    {
+                        Id = u.Id,
+                        Description = String.Format("{0} - {1}", u.Lastname,
+                            String.Join(", ", u.Roles
+                                .Select(r => r.Description)))
+                    })
+                    .ToList();
         }
 
         #region Sites

+ 17 - 7
GreenTree.Nachtragsmanagement.Web/GreenTree.Nachtragsmanagement.Web.csproj

@@ -161,7 +161,7 @@
     <Content Include="Content\Images\close-16.png" />
     <Content Include="Content\Images\function-Appendix-Appendices-32-contrast.png" />
     <Content Include="Content\Images\function-Appendix-Appendices-32.png" />
-    <Content Include="Content\Images\function-Appendix-Categories-32-contrast.png" />
+    <Content Include="Content\Images\function-Appendix-Claims-32-contrast.png" />
     <Content Include="Content\Images\function-Deviation-Claims-32-contrast.png" />
     <Content Include="Content\Images\function-Deviation-Claims-32.png" />
     <Content Include="Content\Images\function-Deviation-Deviations-32-contrast.png" />
@@ -182,7 +182,7 @@
     <Content Include="Content\Images\function-Site-Sites-32.png" />
     <Content Include="Content\Images\maximize-16.png" />
     <Content Include="Content\Images\minimize-16.png" />
-    <Content Include="Content\Images\function-Appendix-Categories-32.png" />
+    <Content Include="Content\Images\function-Appendix-Claims-32.png" />
     <Content Include="Content\Images\user-32.png" />
     <Content Include="Content\Images\password-32.png" />
     <Content Include="Content\Images\password-24.png" />
@@ -262,12 +262,9 @@
     <Content Include="Views\Deviations\_StatusEditPartial.cshtml" />
     <Content Include="Views\Deviations\_DisturbanceEditPartial.cshtml" />
     <Content Include="Views\Deviations\_KindEditPartial.cshtml" />
-    <Content Include="Views\Shared\DataEditorTemplates\_AppendicesComboBox.cshtml" />
     <Content Include="Views\Shared\DataEditorTemplates\_StatusesComboBox.cshtml" />
     <Content Include="Views\Shared\DataEditorTemplates\_KindsComboBox.cshtml" />
-    <Content Include="Views\Shared\DataEditorTemplates\_DisturbancesComboBox.cshtml" />
     <Content Include="Views\Shared\DataEditorTemplates\_RolesComboBox.cshtml" />
-    <Content Include="Views\Appendices\Categories.cshtml" />
     <Content Include="Views\Appendices\_CategoryListPartial.cshtml" />
     <Content Include="Views\Appendices\_CategoryEditPartial.cshtml" />
     <Content Include="Views\Sites\_SiteEditPartial.cshtml" />
@@ -276,7 +273,14 @@
     <Content Include="Views\Sites\_SiteEditTreePartial.cshtml" />
     <Content Include="Views\Appendices\View.cshtml" />
     <Content Include="Views\Appendices\_AppendixGridPartial.cshtml" />
-    <Content Include="Views\Deviations\_DisturbanceValueEdit.cshtml" />
+    <Content Include="Views\Deviations\_DisturbanceValueEditPartial.cshtml" />
+    <Content Include="Views\Shared\DataEditorTemplates\_DisturbancesComboBox.cshtml" />
+    <Content Include="Views\Appendices\_AppendixEditPartial.cshtml" />
+    <Content Include="Views\Appendices\_CategoryValueEditPartial.cshtml" />
+    <Content Include="Views\Shared\DataEditorTemplates\_StatesComboBox.cshtml" />
+    <Content Include="Views\Appendices\Claims.cshtml" />
+    <Content Include="Views\Appendices\_StateEditPartial.cshtml" />
+    <Content Include="Views\Appendices\_StateListPartial.cshtml" />
     <None Include="Web.Debug.config">
       <DependentUpon>Web.config</DependentUpon>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
@@ -309,12 +313,15 @@
     <Compile Include="Models\Admin\User\RoleDataModel.cs" />
     <Compile Include="Models\Admin\User\UserDataModel.cs" />
     <Compile Include="Models\Appendix\AppendixDataModel.cs" />
-    <Compile Include="Models\Appendix\IRequireAppendixDataModel.cs" />
     <Compile Include="Models\Appendix\CategoryDataModel.cs" />
+    <Compile Include="Models\Appendix\CategoryValueDataModel.cs" />
     <Compile Include="Models\Appendix\IRequireCategoryDataModel.cs" />
+    <Compile Include="Models\Appendix\IRequireStateDataModel.cs" />
+    <Compile Include="Models\Appendix\StateDataModel.cs" />
     <Compile Include="Models\Deviation\DeviationDataModel.cs" />
     <Compile Include="Models\Deviation\DisturbanceDataModel.cs" />
     <Compile Include="Models\Deviation\IRequireKindDataModel.cs" />
+    <Compile Include="Models\Deviation\IRequireDisturbanceDataModel.cs" />
     <Compile Include="Models\Deviation\IRequireStatusDataModel.cs" />
     <Compile Include="Models\Deviation\KindDataModel.cs" />
     <Compile Include="Models\Deviation\StatusDataModel.cs" />
@@ -333,6 +340,9 @@
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="Validation\AppendixValidatorFactory.cs" />
     <Compile Include="Models\Deviation\DisturbanceValueDataModel.cs" />
+    <Compile Include="Validation\Appendix\AppendixDataModelValidator.cs" />
+    <Compile Include="Validation\Appendix\CategoryDataModelValidator.cs" />
+    <Compile Include="Validation\Appendix\StateDataModelValidator.cs" />
     <Compile Include="Validation\Deviation\KindDataModelValidator.cs" />
     <Compile Include="Validation\Deviation\DisturbanceDataModelValidator.cs" />
     <Compile Include="Validation\Deviation\StatusDataModelValidator.cs" />

+ 45 - 12
GreenTree.Nachtragsmanagement.Web/Models/Appendix/AppendixDataModel.cs

@@ -5,7 +5,7 @@ using System.Web;
 
 namespace GreenTree.Nachtragsmanagement.Web.Models.Appendix
 {
-    public class AppendixDataModel
+    public class AppendixDataModel : IRequireStateDataModel
     {
         public int Id { get; set; }
         public string CustomNumber { get; set; }
@@ -13,18 +13,41 @@ 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 DateTime? NegotiationDate { get; set; }
         public decimal? NegotiationValue { get; set; }
         public bool ProtocolExists { get; set; }
         public int? OrderNumber { get; set; }
         public DateTime? OrderDate { get; set; }
+        public bool OrderInvoiceCreated { get; set; }
         public string Comment { get; set; }
+        public int? StateId { get; set; }
+        public string StateDescription { get; set; }
         public int? SiteId { get; set; }
         public string SiteDescription { get; set; }
-        public ICollection<int> CategoryValues { get; set; }
-        public ICollection<string> CategoryDescriptions { get; set; }
         public ICollection<int> DeviationValues { get; set; }
         public ICollection<string> DeviationDescriptions { get; set; }
+        public string DeviationDescription { get; set; }
+        public ICollection<string> CategoryEntities { get; set; }
+        public ICollection<CategoryValueDataModel> CategoryValueEntities { get; set; }
+        public string CategoryValuesDescription
+        {
+            get
+            {
+                if (CategoryValueEntities == null)
+                    return String.Empty;
+                else
+                    return String.Join(", ", CategoryValueEntities.Select(d => d.Description));
+            }
+        }
+
+        public AppendixDataModel()
+        {
+            DeviationValues = new List<int>();
+            DeviationDescriptions = new List<string>();
+            CategoryEntities = new List<string>();
+            CategoryValueEntities = new List<CategoryValueDataModel>();
+        }
 
         public static AppendixDataModel FromAppendix(Core.Domain.Appendix.Appendix appendixEntity, bool newWhenIsNull)
         {
@@ -45,25 +68,31 @@ namespace GreenTree.Nachtragsmanagement.Web.Models.Appendix
                 Probability = appendixEntity.Probability,
                 OfferingNumber = appendixEntity.OfferingNumber,
                 OfferingDate = appendixEntity.OfferingDate,
+                OfferingValue = appendixEntity.Value,
                 NegotiationDate = appendixEntity.NegotiationDate,
                 NegotiationValue = appendixEntity.NegotiationValue,
                 ProtocolExists = appendixEntity.ProtocolExists,
                 OrderNumber = appendixEntity.OrderNumber,
                 OrderDate = appendixEntity.OrderDate,
                 Comment = appendixEntity.Comment,
+                OrderInvoiceCreated = appendixEntity.OrderInvoiceCreated,
+                StateId = appendixEntity.StateId,
+                StateDescription = appendixEntity.State == null
+                    ? null
+                    : appendixEntity.State.Description,
                 SiteId = appendixEntity.SiteId,
                 SiteDescription = appendixEntity.Site == null
                     ? null
                     : appendixEntity.Site.Description,
-                CategoryValues =
+                CategoryValueEntities =
                     appendixEntity.CategoryValues
-                        .Select(r => r.Id)
-                        .ToList(),
-                CategoryDescriptions =
-                    appendixEntity.CategoryValues
-                        .Select(r => r.Category == null
-                            ? String.Empty
-                            : r.Category.Description)
+                        .Select(r =>
+                            new CategoryValueDataModel
+                            {
+                                CategoryId = r.CategoryId,
+                                Description = String.Format("{0} - {1:c2}", r.Category.Description, r.Value),
+                                Value = r.Value
+                            })
                         .ToList(),
                 DeviationValues =
                     appendixEntity.Deviations
@@ -72,7 +101,11 @@ namespace GreenTree.Nachtragsmanagement.Web.Models.Appendix
                 DeviationDescriptions =
                     appendixEntity.Deviations
                         .Select(r => r.CustomNumber)
-                        .ToList()
+                        .ToList(),
+                DeviationDescription = 
+                    String.Join(", ",
+                        appendixEntity.Deviations
+                            .Select(d => d.CustomNumber))
             };
         }
 

+ 23 - 0
GreenTree.Nachtragsmanagement.Web/Models/Appendix/CategoryValueDataModel.cs

@@ -0,0 +1,23 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Web;
+
+namespace GreenTree.Nachtragsmanagement.Web.Models.Appendix
+{
+    public class CategoryValueDataModel
+    {
+        public int? CategoryId { get; set; }
+        public decimal? Value { get; set; }
+        public string Description { get; set; }
+        public string Json { get; set; }
+        public Core.Domain.Appendix.CategoryValue ToCategoryValue()
+        {
+            return new Core.Domain.Appendix.CategoryValue
+            {
+                CategoryId = CategoryId.Value,
+                Value = Value.Value
+            };
+        }
+    }
+}

+ 2 - 2
GreenTree.Nachtragsmanagement.Web/Models/Appendix/IRequireAppendixDataModel.cs → GreenTree.Nachtragsmanagement.Web/Models/Appendix/IRequireStateDataModel.cs

@@ -6,8 +6,8 @@ using System.Threading.Tasks;
 
 namespace GreenTree.Nachtragsmanagement.Web.Models.Appendix
 {
-    public interface IRequireAppendixDataModel
+    public interface IRequireStateDataModel
     {
-        int? AppendixId { get; set; }
+        int? StateId { get; set; }
     }
 }

+ 40 - 0
GreenTree.Nachtragsmanagement.Web/Models/Appendix/StateDataModel.cs

@@ -0,0 +1,40 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Web;
+
+namespace GreenTree.Nachtragsmanagement.Web.Models.Appendix
+{
+    public class StateDataModel
+    {
+        public int Id { get; set; }
+        public string Description { get; set; }
+
+        public static StateDataModel FromState(Core.Domain.Appendix.State stateEntity, bool newWhenIsNull)
+        {
+            if (stateEntity == null && newWhenIsNull)
+                return new StateDataModel
+                {
+                    Id = -1
+                };
+
+            if (stateEntity == null && !newWhenIsNull)
+                throw new ArgumentNullException("stateEntity", "Cannot create StateDataModel from NULL state entity.");
+
+            return new StateDataModel
+            {
+                Id = stateEntity.Id,
+                Description = stateEntity.Description
+            };
+        }
+
+        public Core.Domain.Appendix.State ToState()
+        {
+            return new Core.Domain.Appendix.State
+            {
+                Id = this.Id,
+                Description = this.Description
+            };
+        }
+    }
+}

+ 11 - 1
GreenTree.Nachtragsmanagement.Web/Models/Deviation/DeviationDataModel.cs

@@ -9,7 +9,7 @@ using System.Web;
 namespace GreenTree.Nachtragsmanagement.Web.Models.Deviation
 {
     public class DeviationDataModel 
-        : IRequireAppendixDataModel, IRequireStatusDataModel, IRequireKindDataModel
+        : IRequireStatusDataModel, IRequireKindDataModel
     {
         public int Id { get; set; }
         public string CustomNumber { get; set; }
@@ -30,6 +30,16 @@ namespace GreenTree.Nachtragsmanagement.Web.Models.Deviation
         public int? AppendixId { get; set; }
         public ICollection<string> DisturbanceEntities { get; set; }
         public ICollection<DisturbanceValueDataModel> DisturbanceValueEntities { get; set; }
+        public string DisturbanceValuesDescription
+        {
+            get
+            {
+                if (DisturbanceValueEntities == null)
+                    return String.Empty;
+                else
+                    return String.Join(", ", DisturbanceValueEntities.Select(d => d.Description));
+            }
+        }
 
         public DeviationDataModel()
         {

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

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

+ 3 - 3
GreenTree.Nachtragsmanagement.Web/Models/Global/EmptyIRequireDataModel.cs

@@ -9,13 +9,13 @@ using System.Web;
 namespace GreenTree.Nachtragsmanagement.Web.Models.Global
 {
     public class EmptyIRequireDataModel
-        : IRequireRoleDataModel, IRequireStatusDataModel, IRequireKindDataModel, IRequireAppendixDataModel
+        : IRequireRoleDataModel, IRequireStatusDataModel, IRequireDisturbanceDataModel, IRequireKindDataModel, IRequireStateDataModel
     {
         public int? RoleId { get; set; }
         public int? StatusId { get; set; }
-        public ICollection<int> DisturbanceValues { get; set; }
+        public int? DisturbanceId { get; set; }
         public int? KindId { get; set; }
-        public int? AppendixId { get; set; }
+        public int? StateId { get; set; }
 
         public static EmptyIRequireDataModel Instance
         {

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

@@ -117,12 +117,13 @@ namespace GreenTree.Nachtragsmanagement.Web.Models.Site
                         .Select(r => AppendixDataModel.FromAppendix(r, false))
                         .ToList(),
                 UserValues =
-                    siteEntity.Appendices
+                    siteEntity.Users
                         .Select(r => r.Id)
                         .ToList(),
                 UserDescriptions =
                     siteEntity.Users
-                        .Select(r => r.Lastname)
+                        .Select(r => String.Format("{0} - ({1})", r.Lastname, 
+                            String.Join(", ", r.Roles.Select(u => u.Description))))
                         .ToList(),
                 Users = 
                     siteEntity.Users

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

@@ -0,0 +1,38 @@
+using FluentValidation;
+using GreenTree.Nachtragsmanagement.Web.Models.Appendix;
+using GreenTree.Nachtragsmanagement.Web.Models.Deviation;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Web;
+
+namespace GreenTree.Nachtragsmanagement.Web.Validation.Appendix
+{
+    public class AppendixDataModelValidator : AbstractValidator<AppendixDataModel>
+    {
+        public AppendixDataModelValidator()
+        {
+            RuleFor(m => m.CustomNumber)
+                .NotEmpty()
+                    .WithMessage("Nummer wird benötigt")
+                .MaximumLength(10)
+                    .WithMessage("Muss unter 10 Zeichen sein");
+
+            RuleFor(m => m.Description)
+                .NotEmpty()
+                    .WithMessage("Beschreibung wird benötigt");
+
+            RuleFor(m => m.OfferingDate)
+                .NotEmpty()
+                    .WithMessage("Einreichdatum wird benötigt");
+
+            RuleFor(m => m.OfferingValue)
+                .NotEmpty()
+                    .WithMessage("Eine Angebotssumme wird benötigt");
+
+            RuleFor(m => m.Comment)
+                .NotEmpty()
+                    .WithMessage("Ein Kommentar wird benötigt");
+        }
+    }
+}

+ 22 - 0
GreenTree.Nachtragsmanagement.Web/Validation/Appendix/CategoryDataModelValidator.cs

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

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

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

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

@@ -1,8 +1,12 @@
 using FluentValidation;
 using GreenTree.Nachtragsmanagement.Web.Models.Admin.User;
+using GreenTree.Nachtragsmanagement.Web.Models.Appendix;
 using GreenTree.Nachtragsmanagement.Web.Models.Deviation;
 using GreenTree.Nachtragsmanagement.Web.Models.Site;
 using GreenTree.Nachtragsmanagement.Web.Validation.Admin.User;
+using GreenTree.Nachtragsmanagement.Web.Validation.Appendix;
+using GreenTree.Nachtragsmanagement.Web.Validation.Deviation;
+using GreenTree.Nachtragsmanagement.Web.Validation.Site;
 using System;
 using System.Collections.Generic;
 using System.Linq;
@@ -22,6 +26,9 @@ namespace GreenTree.Nachtragsmanagement.Web.Validation
             validators.Add(typeof(IValidator<StatusDataModel>), new StatusDataModelValidator());
             validators.Add(typeof(IValidator<DisturbanceDataModel>), new DisturbanceDataModelValidator());
             validators.Add(typeof(IValidator<KindDataModel>), new KindDataModelValidator());
+            validators.Add(typeof(IValidator<AppendixDataModel>), new AppendixDataModelValidator());
+            validators.Add(typeof(IValidator<StateDataModel>), new StateDataModelValidator());
+            validators.Add(typeof(IValidator<CategoryDataModel>), new CategoryDataModelValidator());
             validators.Add(typeof(IValidator<SiteDataModel>), new SiteDataModelValidator());
         }
 

+ 1 - 1
GreenTree.Nachtragsmanagement.Web/Validation/Deviation/DeviationDataModelValidator.cs

@@ -5,7 +5,7 @@ using System.Collections.Generic;
 using System.Linq;
 using System.Web;
 
-namespace GreenTree.Nachtragsmanagement.Web.Validation.Admin.User
+namespace GreenTree.Nachtragsmanagement.Web.Validation.Deviation
 {
     public class DeviationDataModelValidator : AbstractValidator<DeviationDataModel>
     {

+ 1 - 1
GreenTree.Nachtragsmanagement.Web/Validation/Deviation/DisturbanceDataModelValidator.cs

@@ -5,7 +5,7 @@ using System.Collections.Generic;
 using System.Linq;
 using System.Web;
 
-namespace GreenTree.Nachtragsmanagement.Web.Validation.Admin.User
+namespace GreenTree.Nachtragsmanagement.Web.Validation.Deviation
 {
     public class DisturbanceDataModelValidator : AbstractValidator<DisturbanceDataModel>
     {

+ 1 - 1
GreenTree.Nachtragsmanagement.Web/Validation/Deviation/KindDataModelValidator.cs

@@ -5,7 +5,7 @@ using System.Collections.Generic;
 using System.Linq;
 using System.Web;
 
-namespace GreenTree.Nachtragsmanagement.Web.Validation.Admin.User
+namespace GreenTree.Nachtragsmanagement.Web.Validation.Deviation
 {
     public class KindDataModelValidator : AbstractValidator<KindDataModel>
     {

+ 1 - 1
GreenTree.Nachtragsmanagement.Web/Validation/Deviation/StatusDataModelValidator.cs

@@ -5,7 +5,7 @@ using System.Collections.Generic;
 using System.Linq;
 using System.Web;
 
-namespace GreenTree.Nachtragsmanagement.Web.Validation.Admin.User
+namespace GreenTree.Nachtragsmanagement.Web.Validation.Deviation
 {
     public class StatusDataModelValidator : AbstractValidator<StatusDataModel>
     {

+ 1 - 1
GreenTree.Nachtragsmanagement.Web/Validation/Site/SiteDataModelValidator.cs

@@ -6,7 +6,7 @@ using System.Collections.Generic;
 using System.Linq;
 using System.Web;
 
-namespace GreenTree.Nachtragsmanagement.Web.Validation.Admin.User
+namespace GreenTree.Nachtragsmanagement.Web.Validation.Site
 {
     public class SiteDataModelValidator : AbstractValidator<SiteDataModel>
     {

+ 0 - 71
GreenTree.Nachtragsmanagement.Web/Views/Appendices/Categories.cshtml

@@ -1,71 +0,0 @@
-@{
-	Layout = "~/Views/Shared/_FunctionLayout.cshtml";
-}
-
-@model IEnumerable<GreenTree.Nachtragsmanagement.Web.Models.Appendix.CategoryDataModel>
-
-<script>
-	var deleteId;
-
-	function editCategory(id) {
-		if (!id) return;
-		$.ajax({
-			url: '@Url.Action("EditCategory", "Appendix")',
-			data: { Id: id },
-			success: function (response) {
-				setTimeout(function () {
-					$(".categoryEditContainer").remove();
-					$("body").append(response);
-				}, 200);
-			},
-			error: function () {
-				 alert("error occured");
-			}
-		});
-	}
-
-	function confirmDelete(id) {
-		if (!id) return;
-		deleteId = id;
-		$.ajax({
-			type: "GET",
-			url: '@Url.Action("GetCategory", "Appendix")',
-			data: { Id: id },
-			success: function (response) {
-				if (response == "notFound") return;
-				var category = JSON.parse(response);
-				var popupControl = MVCxClientPopupControl.Cast(devPopupControlDeleteCategory);
-				popupControl.SetHeaderText(popupControl.GetHeaderText().replace("{category}", category.Description));
-				$(".dialogText").text($(".dialogText").text().replace("{category}", category.Description));
-				popupControl.Show();
-			}
-		});
-	}
-
-	function deleteCategory() {
-		$.ajax({
-			type: "POST",
-			url: '@Url.Action("DeleteCategory", "Appendix")',
-			data: { Id: deleteId },
-			success: function (response) {
-				var popupControl = MVCxClientPopupControl.Cast(devPopupControlDeleteCategory);
-				popupControl.Hide();
-				setTimeout(function () {
-					devGridViewCategory.PerformCallback();
-				}, 200);
-			},
-			error: function () {
-				 alert("error occured");
-			}
-		});
-	}
-</script>
-
-@Html.Partial("~/Views/Appendix/_CategoryListPartial.cshtml", Model)
-@Html.Partial("~/Views/Shared/_PopupDialogYesNo.cshtml", new GreenTree.Nachtragsmanagement.Web.Models.Global.YesNoDialogModel
-{
-	PopupName = "devPopupControlDeleteCategory",
-	Content = "<div class='dialogText' style='padding: 12px'>Sind Sie sicher, dass Sie die Kategorie \"{category}\" löschen möchten?</div>",
-	HeaderText = "\"{category}\" löschen",
-	YesFunction = "function (s, e) { deleteCategory(); }"
-})

+ 205 - 0
GreenTree.Nachtragsmanagement.Web/Views/Appendices/Claims.cshtml

@@ -0,0 +1,205 @@
+@using GreenTree.Nachtragsmanagement.Web.Models.Global
+
+@{
+	Layout = "~/Views/Shared/_FunctionLayout.cshtml";
+}
+
+<script>
+	var deleteId;
+	var deleteReplaceId;
+	var deleteClaimType;
+
+	var claimTypeTranslation = {
+		state: "NT-State",
+		category: "Kategorie"
+	};
+
+	$(document).ready(setListBoxHeights);
+	$(window).resize(setListBoxHeights);
+
+	function setListBoxHeights() {
+		var windowHeight = $(window).height();
+		devListBoxStates.SetHeight(windowHeight - 40);
+		devListBoxCategories.SetHeight(windowHeight - 40);
+		devListBoxKinds.SetHeight(windowHeight - 40);
+	}
+
+	function editClaim(claimType, id) {
+		if (!id) return;
+		$.ajax({
+			url: '@Url.Action("EditClaim", "Appendix")',
+			data: { claimType: claimType, Id: id },
+			success: function (response) {
+				setTimeout(function () {
+					$(".claimEditContainer").remove();
+					$("body").append(response);
+				}, 200);
+			},
+			error: function () {
+				 alert("error occured");
+			}
+		});
+	}
+
+	function confirmDelete(claimType, id) {
+		if (!id) return;
+		deleteId = id;
+		deleteClaimType = claimType;
+		$.ajax({
+			type: "GET",
+			url: '@Url.Action("GetClaim", "Appendix")',
+			data: { claimType: deleteClaimType, Id: id },
+			success: function (response) {
+				if (response == "notFound") return;
+
+				var claim = JSON.parse(response);
+
+				$(".deleteValidation").hide();
+
+				var popupControl = MVCxClientPopupControl.Cast(devPopupControlDeleteClaim);
+				popupControl.SetHeaderText(popupControl.GetHeaderText().replace("{claim}", claim.Description));
+				$(".dialogText").text($(".dialogText").text().replace("{claim}", claim.Description));
+				$(".dialogText").text($(".dialogText").text().replace("{claim}", claim.Description));
+				$(".dialogText").text($(".dialogText").text().replace("{claimType}", claimTypeTranslation[claimType]));
+
+				devRadioButtonDeleteReplaceClaim
+					.SetText(devRadioButtonDeleteReplaceClaim.GetText().replace("{claimType}", claimTypeTranslation[claimType]));
+
+				var comboBox = null;
+				devComboBoxClaimDeleteReplaceState.SetVisible(false);
+				devComboBoxClaimDeleteReplaceCategory.SetVisible(false);
+
+				if (deleteClaimType == "state") {
+					devComboBoxClaimDeleteReplaceState.SetVisible(true);
+					comboBox = MVCxClientComboBox.Cast(devComboBoxClaimDeleteReplaceState);
+				}
+
+				comboBox.PerformCallback();
+
+				popupControl.Show();
+			}
+		});
+	}
+
+	function deleteClaim() {
+		if (deleteClaimType == "state") {
+			deleteReplaceId = devComboBoxClaimDeleteReplaceState.GetValue();
+		}
+
+		if (deleteReplaceId == 0) {
+			$(".deleteValidation").text("Es muss ein Ersatz ausgewählt werden.");
+			$(".deleteValidation").show();
+			return;
+		}
+		if (deleteId == deleteReplaceId) {
+			$(".deleteValidation").text("Der Ersatz darf nicht gleich dem zu löschenden Element sein.");
+			$(".deleteValidation").show();
+			return;
+		}
+
+		$.ajax({
+			type: "POST",
+			url: '@Url.Action("DeleteClaim", "Appendix")',
+			data: { claimType: deleteClaimType, Id: deleteId, replaceId: deleteReplaceId },
+			success: function (response) {
+				var popupControl = MVCxClientPopupControl.Cast(devPopupControlDeleteClaim);
+				popupControl.Hide();
+				setTimeout(function () {
+					if (deleteClaimType == "state") {
+						devListBoxStates.PerformCallback();
+					} else if (deleteClaimType == "category") {
+						devListBoxCategories.PerformCallback();
+					}
+				}, 200);
+			},
+			error: function () {
+				 alert("error occured");
+			}
+		});
+	}
+</script>
+
+<table style="width: 100%">
+	<tbody>
+		<tr>
+			<td style="width: 50%; padding-right: 8px">
+				<div class="listHeader">
+					<span>NT-Stati</span>
+					<img src='@Url.Content("~/Content/Images/add-24-contrast.png")' onclick='editClaim("state", -1)' title="Neuer NT-Status" />
+				</div>
+				@Html.Partial("~/Views/Appendices/_StateListPartial.cshtml", ViewData["AllStates"])
+			</td>
+			<td style="width: 50%; padding-left: 8px">
+				<div class="listHeader">
+					<span>Kategorien</span>
+					<img src='@Url.Content("~/Content/Images/add-24-contrast.png")' onclick='editClaim("category", -1)' title="Neue NT-Kategorie" />
+				</div>
+				@Html.Partial("~/Views/Appendices/_CategoryListPartial.cshtml", ViewData["AllCategories"])
+			</td>
+		</tr>
+	</tbody>
+</table>
+
+@Html.DevExpress().PopupControl(s =>
+{
+	s.Name = "devPopupControlDeleteClaim";
+	s.HeaderText = "\"{claim}\" löschen";
+	s.Modal = false;
+	s.Width = new Unit(350, UnitType.Pixel);
+	s.CloseAction = CloseAction.CloseButton;
+	s.PopupHorizontalAlign = PopupHorizontalAlign.WindowCenter;
+	s.PopupVerticalAlign = PopupVerticalAlign.WindowCenter;
+	s.AllowDragging = false;
+	s.AllowResize = false;
+	s.ShowFooter = false;
+	s.SetContent(() =>
+	{
+		ViewContext.Writer.Write("<div class='dialogText' style='padding: 12px'>");
+		ViewContext.Writer.Write("Falls Sie \"{claim}\" löschen möchten, was soll mit den Nachträgen geschehen, die bereits \"{claim}\" zugeordnet sind?");
+		ViewContext.Writer.Write("</div>");
+
+		ViewContext.Writer.Write("<div style='padding: 0 12px 12px 12px'>");
+		Html.DevExpress().RadioButton(rb =>
+		{
+			rb.Name = "devRadioButtonDeleteReplaceClaim";
+			rb.Text = "Eine neue(n) {claimType} zuweisen";
+			rb.GroupName = "claimDelete";
+			rb.Checked = true;
+		}).Render();
+
+		Session.Add("StatesDeleteComboBoxSettings", new Action<ComboBoxSettings>(a =>
+		{
+			a.Name = "devComboBoxClaimDeleteReplaceState";
+			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 = "StatesComboBoxExcluded",
+				SettingsKey = "StatesDeleteComboBoxSettings"
+			};
+		}));
+		ViewData.Add("StatesComboBoxSettings", "StatesDeleteComboBoxSettings");
+		Html.RenderPartial("~/Views/Shared/DataEditorTemplates/_StatesComboBox.cshtml", null, ViewData);
+
+		ViewContext.Writer.Write("<div class=\"deleteValidation\" style=\"display: none\"></div>");
+
+		ViewContext.Writer.Write("</div>");
+
+		Html.RenderPartial(
+			"~/Views/Shared/_PopupButtonPanelYesNo.cshtml",
+			new YesNoDialogModel
+			{
+				PopupName = "devPopupControlDeleteClaim",
+				YesFunction = "function (s, e) { deleteClaim(); }"
+			}
+		);
+	});
+	s.Styles.Content.Paddings.Padding = new Unit(0, UnitType.Pixel);
+}).GetHtml()

+ 399 - 0
GreenTree.Nachtragsmanagement.Web/Views/Appendices/_AppendixEditPartial.cshtml

@@ -0,0 +1,399 @@
+@using GreenTree.Nachtragsmanagement.Web.Extensions
+
+@{ 
+	var userContext = GreenTree.Nachtragsmanagement.Core.CommonHelper.UserContext();
+	var categoryValues = Model.CategoryValueEntities.ToArray();
+}
+
+@model GreenTree.Nachtragsmanagement.Web.Models.Appendix.AppendixDataModel
+
+<div class="appendixEditContainer">
+
+	<script>
+		var textSeparator = ", ";
+
+		function saveAppendix() {
+			CategoryEntities.SelectAll();
+			var form = $("#appendixEditForm");
+			$(form).submit(function (e) {
+				$.ajax({
+					type: "POST",
+					url: '@Url.Action("EditAppendix", "Appendix")',
+					data: form.serialize(),
+					success: function (response) {
+						setTimeout(function () {
+							$(".appendixEditContainer").remove();
+							if (response == "success") {
+								if (typeof onAppendixSaveSuccess === 'function') {
+									onAppendixSaveSuccess();
+								}
+							} else {
+								$("body").append(response);
+							}
+						}, 200);
+					}
+				});
+				e.preventDefault();
+			});
+			form.submit();
+		}
+
+		function addState() {
+			$.ajax({
+				url: '@Url.Action("EditState", "Appendix")',
+				data: { claimType: "status", Id: -1 },
+				success: function (response) {
+					setTimeout(function () {
+						$(".stateEditContainer").remove();
+						$("body").append(response);
+						parent.addCustomEventListener('StateDataCallbackEventReceiver', function () {
+							StateId.PerformCallback();
+						});
+					}, 200);
+				},
+				error: function () {
+					 alert("error occured");
+				}
+			});
+		}
+
+		function addCategory() {
+			$.ajax({
+				url: '@Url.Action("EditClaim", "Appendix")',
+				data: { claimType: "disturbance", Id: -1 },
+				success: function (response) {
+					setTimeout(function () {
+						$(".claimEditContainer").remove();
+						$("body").append(response);
+						parent.addCustomEventListener('CategoryDataCallbackEventReceiver', function () {
+							CategoryId.PerformCallback();
+						});
+					}, 200);
+				},
+				error: function () {
+					 alert("error occured");
+				}
+			});
+		}
+
+		function setDropDownText() {
+			var allItems = CategoryEntities.GetItemCount();
+			var text = "";
+			for (var i = 0; i < allItems; i++) {
+				if (i == allItems - 1) {
+					text += JSON.parse(CategoryEntities.GetItem(i).value).Description;
+				} else {
+					text += JSON.parse(CategoryEntities.GetItem(i).value).Description + ", ";
+				}
+			}
+			devDropDownListCategoryValues.SetText(text);
+		}
+
+		function addCategoryValue() {
+			var distVal = {
+				CategoryId: devListBoxAllCategories.GetValue(),
+				Description: devListBoxAllCategories.GetSelectedItem().text + " - " + devSpinEditCategoryValue.GetText(),
+				Value: devSpinEditCategoryValue.GetValue()
+			};
+			var distValJson = JSON.stringify(distVal);
+			var listBox = MVCxClientListBox.Cast(CategoryEntities);
+			listBox.AddItem(distVal.Description + "<a style=\"float: right\" href=\"#\" onclick='removeCategoryValue(\"" + distVal.Description + "\")'>Entfernen</a>", distValJson);
+			devCategoryValuePopup.Hide();
+			setDropDownText();
+		}
+
+		function removeCategoryValue(description) {
+			var allItems = CategoryEntities.GetItemCount();
+			for (var i = 0; i < allItems; i++) {
+				var item = CategoryEntities.GetItem(i);
+				if (item.text.startsWith(description)) {
+					CategoryEntities.RemoveItem(i);
+				}
+			}
+			setDropDownText();
+		}
+	</script>
+
+	@Html.Partial("~/Views/Appendices/_CategoryValueEditPartial.cshtml");
+
+	@Html.DevExpress().PopupControl(s =>
+{
+	s.Name = "devPopupControlEditAppendix";
+
+	if (Model.Id == -1)
+		s.HeaderText = "Neuen Nachtrag erstellen";
+	else
+		s.HeaderText = "\"" + Model.CustomNumber + "\" bearbeiten";
+
+	s.Modal = true;
+	s.Width = new Unit(700, UnitType.Pixel);
+	s.CloseAction = CloseAction.CloseButton;
+	s.PopupHorizontalAlign = PopupHorizontalAlign.WindowCenter;
+	s.PopupVerticalAlign = PopupVerticalAlign.TopSides;
+	s.PopupVerticalOffset = 15;
+	s.AllowDragging = true;
+	s.AllowResize = false;
+	s.ShowFooter = false;
+	s.ShowOnPageLoad = true;
+	s.SetContent(() =>
+	{
+		using (Html.BeginForm("EditAppendix", "Appendix", FormMethod.Post, new { id = "appendixEditForm" }))
+		{
+			ViewContext.Writer.Write("<div class='editFormWrapper'>");
+
+			ViewContext.Writer.Write("<input type=\"hidden\" value=\"" + Model.Id + "\" id=\"Id\" name=\"Id\" />");
+
+			ViewContext.Writer.Write("<div class='inlineModelPropertyContainer'>");
+			{
+				ViewContext.Writer.Write("<div class='inlineModelProperty' style='width: 15%'>");
+				{
+					ViewContext.Writer.Write(Html.CustomLabelFor(m => m.CustomNumber, "Nummer:"));
+					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: 55%'>");
+				{
+					ViewContext.Writer.Write(Html.CustomLabelFor(m => m.Description, "Bezeichnung:"));
+					ViewContext.Writer.Write(Html.ValidationMessageFor(m => m.Description).ToHtmlString());
+					Html.DevExpress().TextBoxFor(m => m.Description, t =>
+					{
+						t.Width = new Unit(97, UnitType.Percentage);
+					}).Render();
+				}
+				ViewContext.Writer.Write("</div>");
+				ViewContext.Writer.Write("<div class='inlineModelProperty' style='width: 30%'>");
+				{
+					ViewContext.Writer.Write(Html.CustomLabelFor(m => m.OfferingDate, "Einreichdatum NT:"));
+					ViewContext.Writer.Write(Html.ValidationMessageFor(m => m.OfferingDate).ToHtmlString());
+					Html.DevExpress().DateEditFor(m => m.OfferingDate, t =>
+					{
+						t.Width = new Unit(100, UnitType.Percentage);
+					}).Render();
+				}
+				ViewContext.Writer.Write("</div>");
+			}
+			ViewContext.Writer.Write("</div>");
+
+			ViewContext.Writer.Write("<div class='inlineModelPropertyContainer'>");
+			{
+				ViewContext.Writer.Write("<div class='inlineModelProperty' style='width: 40%'>");
+				{
+					ViewContext.Writer.Write(Html.CustomLabelFor(m => m.CategoryEntities, "Kategorien:"));
+					ViewContext.Writer.Write(Html.ValidationMessageFor(m => m.CategoryEntities).ToHtmlString());
+					Html.DevExpress().DropDownEdit(t =>
+					{
+						t.Name = "devDropDownListCategoryValues";
+						t.Width = new Unit(96, UnitType.Percentage);
+
+						if (Model.CategoryValueEntities != null && Model.CategoryValueEntities.Any())
+							t.Text = String.Join(", ",
+								Model.CategoryValueEntities
+									.Select(d => d.Description));
+
+						t.SetDropDownWindowTemplateContent(l =>
+						{
+							Html.DevExpress().ListBoxFor(m => m.CategoryEntities, lb =>
+							{
+								lb.Width = new Unit(100, UnitType.Percentage);
+								lb.Properties.TextField = "Description";
+								lb.Properties.ValueField = "Json";
+								lb.Properties.ValueType = typeof(string);
+								lb.Properties.EnableClientSideAPI = true;
+								lb.Properties.SelectionMode = ListEditSelectionMode.Multiple;
+								lb.EncodeHtml = false;
+								lb.SetItemTemplateContent(i =>
+								{
+									var description = DataBinder.Eval(i.DataItem, "Description").ToString();
+
+									ViewContext.Writer.Write(description);
+									ViewContext.Writer.Write(
+										"<a class=\"disturbanceRemoveLink\" style=\"float: right\" href=\"#\" onclick='removeCategoryValue(\"" + description + "\")'>Entfernen</a>");
+								});
+								lb.ControlStyle.Border.BorderStyle = BorderStyle.None;
+							}).BindList(Model.CategoryValueEntities).Render();
+						});
+					}).Render();
+
+					Html.DevExpress().HyperLink(t =>
+					{
+						t.Name = "devHyperLinkCategoryValueAdd";
+						t.Properties.Text = "Hinzufügen";
+						t.NavigateUrl = "#";
+						t.Properties.ClientSideEvents.Click = "function (s, e) { devCategoryValuePopup.Show(); }";
+						t.Style.Add("line-height", "24px");
+					}).Render();
+				}
+				ViewContext.Writer.Write("</div>");
+
+				ViewContext.Writer.Write("<div class='inlineModelProperty' style='width: 30%'>");
+				{
+					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.DecimalPlaces = 2;
+						t.Properties.NumberType = SpinEditNumberType.Float;
+						t.Properties.DisplayFormatString = "c2";
+						t.Properties.ClientSideEvents.ValueChanged = "function (s, e) { calculateValue(); }";
+					}).Render();
+				}
+				ViewContext.Writer.Write("</div>");
+
+				ViewContext.Writer.Write("<div class='inlineModelProperty' style='width: 30%'>");
+				{
+					ViewContext.Writer.Write(Html.CustomLabelFor(m => m.NegotiationValue, "Verhandlungssumme:"));
+					Html.DevExpress().SpinEditFor(m => m.NegotiationValue, t =>
+					{
+						t.Width = new Unit(100, UnitType.Percentage);
+						t.Properties.DecimalPlaces = 2;
+						t.Properties.NumberType = SpinEditNumberType.Float;
+						t.Properties.DisplayFormatString = "c2";
+					}).Render();
+				}
+				ViewContext.Writer.Write("</div>");
+			}
+			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\" />");
+			}
+
+			ViewContext.Writer.Write("<div class='inlineModelPropertyContainer'>");
+			{
+				ViewContext.Writer.Write("<div class='inlineModelProperty' style='width: 35%'>");
+				{
+					ViewContext.Writer.Write(Html.CustomLabelFor(m => m.StateId, "NT-Status:"));
+					ViewContext.Writer.Write(Html.ValidationMessageFor(m => m.StateId).ToHtmlString());
+
+					Session.Add("AppendixStatesComboBoxSettings", new Action<ComboBoxSettings>(a =>
+					{
+						a.Width = new Unit(95, UnitType.Percentage);
+						a.Properties.ValueType = typeof(int);
+						a.Properties.ValueField = "Id";
+						a.Properties.TextField = "Description";
+
+						var serializedModel = Newtonsoft.Json.JsonConvert.SerializeObject(Model);
+
+						a.CallbackRouteValues = new
+						{
+							Controller = "DataCallback",
+							Action = "StatesComboBox",
+							SettingsKey = "AppendixStatesComboBoxSettings",
+							Model = serializedModel,
+							Type = Model.GetType().FullName
+						};
+					}));
+					ViewData.Add("StatesComboBoxSettings", "AppendixStatesComboBoxSettings");
+					Html.RenderPartial("~/Views/Shared/DataEditorTemplates/_StatesComboBox.cshtml", Model, ViewData);
+
+					if (userContext.CurrentUser.HasFunction("Appendix-Claims-Edit"))
+					{
+						Html.DevExpress().HyperLink(t =>
+						{
+							t.Name = "devHyperLinkStateEventReceiver";
+							t.Properties.Text = "Hinzufügen";
+							t.NavigateUrl = "#";
+							t.Properties.ClientSideEvents.Click = "function (s, e) { addState(); }";
+							t.Style.Add("line-height", "24px");
+						}).Render();
+					}
+				}
+				ViewContext.Writer.Write("</div>");
+			}
+			ViewContext.Writer.Write("</div>");
+
+			ViewContext.Writer.Write("<div class='inlineModelPropertyContainer'>");
+			{
+				ViewContext.Writer.Write("<div class='inlineModelProperty' style='width: 25%'>");
+				{
+					ViewContext.Writer.Write(Html.CustomLabelFor(m => m.ProtocolExists, "Protokoll liegt vor:"));
+					ViewContext.Writer.Write("<div style=\"overflow: hidden\">");
+					{
+						ViewContext.Writer.Write("<div style=\"float: left\">");
+						{
+							Html.DevExpress().RadioButtonFor(m => m.ProtocolExists, t =>
+							{
+								t.Text = "Ja";
+								t.GroupName = "protocolExists";
+							}).Render();
+						}
+						ViewContext.Writer.Write("</div>");
+
+						ViewContext.Writer.Write("<div style=\"float: left; margin-left: 8px\">");
+						{
+							Html.DevExpress().RadioButton(t =>
+							{
+								t.Name = "protocolExistsFalse";
+								t.Text = "Nein";
+								t.GroupName = "protocolExists";
+							}).Render();
+						}
+						ViewContext.Writer.Write("</div>");
+					}
+					ViewContext.Writer.Write("</div>");
+				}
+				ViewContext.Writer.Write("</div>");
+
+				ViewContext.Writer.Write("<div class='inlineModelProperty' style='width: 25%'>");
+				{
+					ViewContext.Writer.Write(Html.CustomLabelFor(m => m.OrderInvoiceCreated, "AR gestellt:"));
+					ViewContext.Writer.Write("<div style=\"overflow: hidden\">");
+					{
+						ViewContext.Writer.Write("<div style=\"float: left\">");
+						{
+							Html.DevExpress().RadioButtonFor(m => m.OrderInvoiceCreated, t =>
+							{
+								t.Text = "Ja";
+								t.GroupName = "orderInvoiceCreated";
+							}).Render();
+						}
+						ViewContext.Writer.Write("</div>");
+
+						ViewContext.Writer.Write("<div style=\"float: left; margin-left: 8px\">");
+						{
+							Html.DevExpress().RadioButton(t =>
+							{
+								t.Name = "orderInvoiceCreatedFalse";
+								t.Text = "Nein";
+								t.GroupName = "orderInvoiceCreated";
+							}).Render();
+						}
+						ViewContext.Writer.Write("</div>");
+					}
+					ViewContext.Writer.Write("</div>");
+				}
+				ViewContext.Writer.Write("</div>");
+			}
+			ViewContext.Writer.Write("</div>");
+
+			ViewContext.Writer.Write(Html.CustomLabelFor(m => m.Comment, "Kommentar:"));
+			ViewContext.Writer.Write(Html.ValidationMessageFor(m => m.Comment).ToHtmlString());
+			Html.DevExpress().MemoFor(m => m.Comment, t =>
+			{
+				t.Width = new Unit(100, UnitType.Percentage);
+				t.Height = new Unit(90, UnitType.Pixel);
+			}).Render();
+
+			ViewContext.Writer.Write("</div>");
+
+			Html.RenderPartial(
+				"~/Views/Shared/_PopupButtonPanel.cshtml",
+				new GreenTree.Nachtragsmanagement.Web.Models.Global.PopupModel
+				{
+					PopupName = "devPopupControlEditAppendix",
+					AcceptFunction = "function (s, e) { saveAppendix(); }"
+				}
+			);
+		}
+	});
+	s.Styles.Content.Paddings.Padding = new Unit(0);
+	s.Styles.ModalBackground.Opacity = 0;
+}).GetHtml()
+</div>

+ 44 - 11
GreenTree.Nachtragsmanagement.Web/Views/Appendices/_AppendixGridPartial.cshtml

@@ -18,26 +18,59 @@
 	s.Columns.Add("CustomNumber", "Nummer");
 	s.Columns.Add("Description", "Bezeichnung");
 	s.Columns.Add("SiteDescription", "Baustelle");
-	s.Columns.Add("AppendixDescription", "Nachtrag");
 	s.Columns.Add(column =>
 	{
-		column.Caption = "Eingang";
-		column.FieldName = "ReceiptDate";
+		column.Caption = "Einreichung";
+		column.FieldName = "OfferingDate";
 		column.PropertiesEdit.DisplayFormatString = "dd.MM.yyyy";
 	});
 	s.Columns.Add(column =>
 	{
-		column.Caption = "Schätzung bew.";
-		column.FieldName = "PercentageValue";
+		column.Caption = "Angebotssumme";
+		column.FieldName = "OfferingValue";
 		column.PropertiesEdit.DisplayFormatString = "c2";
 	});
-	s.Columns.Add("StatusDescription", "Status");
-	s.Columns.Add("DisturbanceDescription", "Kategorien");
-	s.Columns.Add("KindDescription", "Art");
-	s.Columns.Add("Comment", "Kommentar");
+	s.Columns.Add(column =>
+	{
+		column.Caption = "Verhandlungssumme";
+		column.FieldName = "NegotiationValue";
+		column.PropertiesEdit.DisplayFormatString = "c2";
+	});
+	s.Columns.Add("DeviationDescriptions", "Vertragsabweichungen");
+	s.Columns.Add("StateDescription", "Status");
+	s.Columns.Add("CategoryValuesDescription", "Kategorien");
+	s.Columns.Add(column =>
+	{
+		column.Caption = "Kommentar";
+		column.CellStyle.Wrap = DefaultBoolean.True;
+		column.SetDataItemTemplateContent(c =>
+		{
+			var id = Convert.ToInt32(DataBinder.Eval(c.DataItem, "Id"));
+
+			var comment = DataBinder.Eval(c.DataItem, "Comment");
+			var text = comment == null
+				? String.Empty
+				: comment.ToString();
+
+			if (text.ToString().Length > 40)
+			{
+				ViewContext.Writer.Write(text.Substring(0, 40) + " ...");
+				ViewContext.Writer.Write("<a href=\"#\" onclick='showComment(\"appendix\"," + id + ",this)'><br />Anzeigen</a>");
+			}
+			else
+				ViewContext.Writer.Write(text);
+		});
+	});
+
+	s.TotalSummary.Add(new ASPxSummaryItem
+	{
+		SummaryType = DevExpress.Data.SummaryItemType.Sum,
+		FieldName = "OfferingValue"
+	});
+	s.GroupSummary.Add(DevExpress.Data.SummaryItemType.Sum, "OfferingValue");
 
-	s.TotalSummary.Add(DevExpress.Data.SummaryItemType.Sum, "PercentageValue");
-	s.GroupSummary.Add(DevExpress.Data.SummaryItemType.Sum, "PercentageValue");
+	s.TotalSummary.Add(DevExpress.Data.SummaryItemType.Sum, "NegotiationValue");
+	s.GroupSummary.Add(DevExpress.Data.SummaryItemType.Sum, "NegotiationValue");
 
 	s.ClientLayout = (sender, e) =>
 	{

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

@@ -10,15 +10,15 @@
 	s.Properties.ValueType = typeof(int);
 	s.Properties.ValueField = "Id";
 	s.Properties.TextField = "Description";
-	if (userContext.CurrentUser.HasFunction("Appendix-Category-Edit"))
+	if (userContext.CurrentUser.HasFunction("Appendix-Claims-Edit"))
 	{
 		s.SetItemTemplateContent(c =>
 		{
 			ViewContext.Writer.Write(DataBinder.Eval(c.DataItem, "Description"));
 			ViewContext.Writer.Write(
 				"<div class=\"devExListItemControlContainer\">" +
-					"<a href=\"#\" onclick='editCategory(\"disturbance\", " + DataBinder.Eval(c.DataItem, "Id") + ")'>Bearbeiten</a>&nbsp;" +
-					"<a href=\"#\" onclick='confirmDelete(\"disturbance\", " + DataBinder.Eval(c.DataItem, "Id") + ")'>Löschen</a>" +
+					"<a href=\"#\" onclick='editCategory(\"category\", " + DataBinder.Eval(c.DataItem, "Id") + ")'>Bearbeiten</a>&nbsp;" +
+					"<a href=\"#\" onclick='confirmDelete(\"category\", " + DataBinder.Eval(c.DataItem, "Id") + ")'>Löschen</a>" +
 				"</div>"
 			);
 		});

+ 70 - 0
GreenTree.Nachtragsmanagement.Web/Views/Appendices/_CategoryValueEditPartial.cshtml

@@ -0,0 +1,70 @@
+@using GreenTree.Nachtragsmanagement.Web.Extensions
+@using GreenTree.Nachtragsmanagement.Core.Domain.Appendix
+
+@model GreenTree.Nachtragsmanagement.Web.Models.Appendix.AppendixDataModel
+
+@Html.DevExpress().PopupControl(s =>
+{
+	s.Name = "devCategoryValuePopup";
+	s.HeaderText = "Kategorie zuweisen";
+	s.Modal = true;
+	s.Width = new Unit(350, UnitType.Pixel);
+	s.CloseAction = CloseAction.CloseButton;
+	s.PopupHorizontalAlign = PopupHorizontalAlign.WindowCenter;
+	s.PopupVerticalAlign = PopupVerticalAlign.TopSides;
+	s.PopupVerticalOffset = 40;
+	s.AllowDragging = true;
+	s.AllowResize = false;
+	s.ShowFooter = false;
+	s.SetContent(() =>
+	{
+		ViewContext.Writer.Write("<div class='editFormWrapper'>");
+		{
+			ViewContext.Writer.Write(Html.CustomLabelFor(m => m.CategoryEntities, "Kategorie:"));
+			Html.DevExpress().DropDownEdit(t =>
+			{
+				t.Name = "devDropDownListAllCategories";
+				t.Width = new Unit(100, UnitType.Percentage);
+				t.Text = ((ICollection<Category>)ViewData["AllCategories"]).ToArray()[0].Description;
+				t.SetDropDownWindowTemplateContent(l =>
+				{
+					Html.DevExpress().ListBox(lb =>
+					{
+						lb.Name = "devListBoxAllCategories";
+						lb.Width = new Unit(100, UnitType.Percentage);
+						lb.Properties.TextField = "Description";
+						lb.Properties.ValueField = "Id";
+						lb.Properties.ValueType = typeof(int);
+						lb.Properties.SelectionMode = ListEditSelectionMode.Single;
+						lb.SelectedIndex = 0;
+						lb.Properties.ClientSideEvents.SelectedIndexChanged = "function (s, e) { devDropDownListAllCategories.SetText(s.GetSelectedItem().text); devDropDownListAllCategories.HideDropDown(); }";
+						lb.ControlStyle.Border.BorderStyle = BorderStyle.None;
+					}).BindList(ViewData["AllCategories"]).Render();
+				});
+			}).Render();
+
+			ViewContext.Writer.Write(Html.CustomLabelFor(m => m.CategoryEntities, "Wert:"));
+			Html.DevExpress().SpinEdit(t =>
+			{
+				t.Name = "devSpinEditCategoryValue";
+				t.Number = 0;
+				t.Properties.MinValue = 0;
+				t.Properties.MaxValue = decimal.MaxValue;
+				t.Properties.NumberType = SpinEditNumberType.Float;
+				t.Properties.DisplayFormatString = "c2";
+			}).Render();
+		}
+		ViewContext.Writer.Write("</div>");
+
+		Html.RenderPartial(
+			"~/Views/Shared/_PopupButtonPanel.cshtml",
+			new GreenTree.Nachtragsmanagement.Web.Models.Global.PopupModel
+			{
+				PopupName = "devCategoryValuePopup",
+				AcceptFunction = "function (s, e) { addCategoryValue(); }"
+			}
+		);
+	});
+	s.Styles.Content.Paddings.Padding = new Unit(0);
+	s.Styles.ModalBackground.Opacity = 0;
+}).GetHtml()

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

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

+ 30 - 0
GreenTree.Nachtragsmanagement.Web/Views/Appendices/_StateListPartial.cshtml

@@ -0,0 +1,30 @@
+@model IEnumerable<GreenTree.Nachtragsmanagement.Core.Domain.Appendix.State>
+
+@{ 
+	var userContext = GreenTree.Nachtragsmanagement.Core.CommonHelper.UserContext();
+}
+
+@Html.DevExpress().ListBox(s =>
+{
+	s.Name = "devListBoxStates";
+	s.Properties.ValueType = typeof(int);
+	s.Properties.ValueField = "Id";
+	s.Properties.TextField = "Description";
+	if (userContext.CurrentUser.HasFunction("Appendix-Claims-Edit"))
+	{
+		s.SetItemTemplateContent(c =>
+		{
+			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;" +
+					"<a href=\"#\" onclick='confirmDelete(\"state\", " + DataBinder.Eval(c.DataItem, "Id") + ")'>Löschen</a>" +
+				"</div>"
+			);
+		});
+	}
+	s.CallbackRouteValues = new { Controller = "Appendix", Action = "PartialClaims", claimType = "state" };
+	s.Properties.ItemStyle.CssClass += "devExListDataItem";
+	s.Width = Unit.Percentage(100);
+	s.Height = Unit.Pixel(370);
+}).BindList(Model).GetHtml()

+ 2 - 2
GreenTree.Nachtragsmanagement.Web/Views/Deviations/Claims.cshtml

@@ -133,8 +133,8 @@
 		<tr>
 			<td style="width: 33%; padding-right: 6px">
 				<div class="listHeader">
-					<span>Statusse</span>
-					<img src='@Url.Content("~/Content/Images/add-24-contrast.png")' onclick='editClaim("status", -1)' title="Neuer Status" />
+					<span>VA-Stati</span>
+					<img src='@Url.Content("~/Content/Images/add-24-contrast.png")' onclick='editClaim("status", -1)' title="Neuer VA-Status" />
 				</div>
 				@Html.Partial("~/Views/Deviations/_StatusListPartial.cshtml", ViewData["AllStatuses"])
 			</td>

+ 2 - 4
GreenTree.Nachtragsmanagement.Web/Views/Deviations/_DeviationEditPartial.cshtml

@@ -133,7 +133,7 @@
 		}
 	</script>
 
-	@Html.Partial("~/Views/Deviations/_DisturbanceValueEdit.cshtml");
+	@Html.Partial("~/Views/Deviations/_DisturbanceValueEditPartial.cshtml");
 
 	@Html.DevExpress().PopupControl(s =>
 {
@@ -258,7 +258,6 @@
 						t.Properties.DecimalPlaces = 2;
 						t.Properties.NumberType = SpinEditNumberType.Float;
 						t.Properties.DisplayFormatString = "c2";
-						t.Properties.ClientSideEvents.Init = "function (s, e) { calculateValue(); }";
 						t.Properties.ClientSideEvents.ValueChanged = "function (s, e) { calculateValue(); }";
 					}).Render();
 				}
@@ -276,7 +275,6 @@
 						t.Properties.MinValue = 0;
 						t.Properties.NumberType = SpinEditNumberType.Integer;
 						t.Properties.DisplayFormatString = "{0:n0} %";
-						t.Properties.ClientSideEvents.Init = "function (s, e) { calculateValue(); }";
 						t.Properties.ClientSideEvents.ValueChanged = "function (s, e) { calculateValue(); }";
 					}).Render();
 				}
@@ -284,7 +282,7 @@
 				ViewContext.Writer.Write("<div class='inlineModelProperty' style='width: 22%'>");
 				{
 					ViewContext.Writer.Write(Html.CustomLabelFor(m => m.Value, "Wert:"));
-					Html.DevExpress().SpinEdit(t =>
+					Html.DevExpress().SpinEditFor(m => m.PercentageValue, t =>
 					{
 						t.Name = "Sum";
 						t.Width = new Unit(100, UnitType.Percentage);

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

@@ -21,7 +21,7 @@
 	s.Columns.Add("AppendixDescription", "Nachtrag");
 	s.Columns.Add(column =>
 	{
-		column.Caption = "Eingang";
+		column.Caption = "Einreichung";
 		column.FieldName = "ReceiptDate";
 		column.PropertiesEdit.DisplayFormatString = "dd.MM.yyyy";
 	});
@@ -32,9 +32,30 @@
 		column.PropertiesEdit.DisplayFormatString = "c2";
 	});
 	s.Columns.Add("StatusDescription", "Status");
-	s.Columns.Add("DisturbanceDescription", "Kategorien");
+	s.Columns.Add("DisturbanceValuesDescription", "Kategorien");
 	s.Columns.Add("KindDescription", "Art");
-	s.Columns.Add("Comment", "Kommentar");
+	s.Columns.Add(column =>
+	{
+		column.Caption = "Kommentar";
+		column.CellStyle.Wrap = DefaultBoolean.True;
+		column.SetDataItemTemplateContent(c =>
+		{
+			var id = Convert.ToInt32(DataBinder.Eval(c.DataItem, "Id"));
+
+			var comment = DataBinder.Eval(c.DataItem, "Comment");
+			var text = comment == null
+				? String.Empty
+				: comment.ToString();
+
+			if (text.ToString().Length > 40)
+			{
+				ViewContext.Writer.Write(text.Substring(0, 40) + " ...");
+				ViewContext.Writer.Write("<a href=\"#\" onclick='showComment(\"deviation\"," + id + ",this)'><br />Anzeigen</a>");
+			}
+			else
+				ViewContext.Writer.Write(text);
+		});
+	});
 
 	s.TotalSummary.Add(DevExpress.Data.SummaryItemType.Sum, "PercentageValue");
 	s.GroupSummary.Add(DevExpress.Data.SummaryItemType.Sum, "PercentageValue");

+ 6 - 0
GreenTree.Nachtragsmanagement.Web/Views/Deviations/_DisturbanceValueEdit.cshtml → GreenTree.Nachtragsmanagement.Web/Views/Deviations/_DisturbanceValueEditPartial.cshtml

@@ -1,4 +1,5 @@
 @using GreenTree.Nachtragsmanagement.Web.Extensions
+@using GreenTree.Nachtragsmanagement.Core.Domain.Deviation
 
 @model GreenTree.Nachtragsmanagement.Web.Models.Deviation.DeviationDataModel
 
@@ -24,6 +25,7 @@
 			{
 				t.Name = "devDropDownListAllDisturbances";
 				t.Width = new Unit(100, UnitType.Percentage);
+				t.Text = ((ICollection<Disturbance>)ViewData["AllDisturbances"]).ToArray()[0].Description;
 				t.SetDropDownWindowTemplateContent(l =>
 				{
 					Html.DevExpress().ListBox(lb =>
@@ -34,6 +36,7 @@
 						lb.Properties.ValueField = "Id";
 						lb.Properties.ValueType = typeof(int);
 						lb.Properties.SelectionMode = ListEditSelectionMode.Single;
+						lb.SelectedIndex = 0;
 						lb.Properties.ClientSideEvents.SelectedIndexChanged = "function (s, e) { devDropDownListAllDisturbances.SetText(s.GetSelectedItem().text); devDropDownListAllDisturbances.HideDropDown(); }";
 						lb.ControlStyle.Border.BorderStyle = BorderStyle.None;
 					}).BindList(ViewData["AllDisturbances"]).Render();
@@ -44,7 +47,10 @@
 			Html.DevExpress().SpinEdit(t =>
 			{
 				t.Name = "devSpinEditDisturbanceValue";
+				t.Number = 0;
 				t.Properties.MinValue = 0;
+				t.Properties.MaxValue = decimal.MaxValue;
+				t.Properties.NumberType = SpinEditNumberType.Float;
 				t.Properties.DisplayFormatString = "c2";
 			}).Render();
 		}

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

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

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

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

+ 167 - 35
GreenTree.Nachtragsmanagement.Web/Views/Sites/_SiteEditPartial.cshtml

@@ -9,6 +9,25 @@
 <div class="siteEditContainer">
 
 	<script>
+		var textSeparator = ", ";
+
+		function addAppendixToSite(siteId) {
+			if (!siteId) return;
+			$.ajax({
+				url: '@Url.Action("AppendAppendixToSite", "Appendix")',
+				data: { SiteId: siteId },
+				success: function (response) {
+					setTimeout(function () {
+						$(".appendixEditContainer").remove();
+						$("body").append(response);
+					}, 200);
+				},
+				error: function () {
+					 alert("error occured");
+				}
+			});
+		}
+
 		function addDeviationToSite(siteId) {
 			if (!siteId) return;
 			$.ajax({
@@ -60,15 +79,83 @@
 			});
 		}
 
+		function editAppendix(id) {
+			if (!id) return;
+			$.ajax({
+				url: '@Url.Action("EditAppendix", "Appendix")',
+				data: { Id: id },
+				success: function (response) {
+					setTimeout(function () {
+						$(".appendixEditContainer").remove();
+						$("body").append(response);
+					}, 200);
+				},
+				error: function () {
+					 alert("error occured");
+				}
+			});
+		}
+
 		function onDeviationSaveSuccess() {
 			devTreeListSiteDeviationAppendices.PerformCallback();
 		}
+
+		function onAppendixSaveSuccess() {
+			devTreeListSiteDeviationAppendices.PerformCallback();
+		}
+
+		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);
+			return texts.join(textSeparator);
+		}
+		function getValuesByTexts(texts) {
+			var actualValues = [];
+			var item;
+			for (var i = 0; i < texts.length; i++) {
+				item = UserValues.FindItemByText(texts[i]);
+				if (item != null)
+					actualValues.push(item.value);
+			}
+			return actualValues;
+		}
 	</script>
 
 	<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; }
+		.siteEditLayoutTable { width: 100%; }
+		.siteEditLayoutTable > tbody > tr > td { width: 50%; padding-right: 8px; vertical-align: top }
 	</style>
 
 	@Html.DevExpress().PopupControl(s =>
@@ -100,56 +187,101 @@
 
 			ViewContext.Writer.Write("<input type=\"hidden\" value=\"" + Model.Id + "\" id=\"Id\" name=\"Id\" />");
 
-			ViewContext.Writer.Write("<div class='inlineModelPropertyContainer'>");
+			ViewContext.Writer.Write("<table class=\"siteEditLayoutTable\"><tbody><tr><td>");
 			{
-				ViewContext.Writer.Write("<div class='inlineModelProperty' style='width: 15%'>");
+				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(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%'>");
+					{
+						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 class='inlineModelProperty' style='width: 35%'>");
+
+				ViewContext.Writer.Write("<div class='inlineModelPropertyContainer'>");
 				{
-					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("<div class='inlineModelProperty' style='width: 52%'>");
 					{
-						t.Width = new Unit(100, UnitType.Percentage);
-					}).Render();
+						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 =>
+						{
+							t.Width = new Unit(98, UnitType.Percentage);
+						}).Render();
+					}
+					ViewContext.Writer.Write("</div>");
 				}
 				ViewContext.Writer.Write("</div>");
 			}
-			ViewContext.Writer.Write("</div>");
-
-			ViewContext.Writer.Write("<div class='inlineModelPropertyContainer'>");
+			ViewContext.Writer.Write("</td><td>");
 			{
-				ViewContext.Writer.Write("<div class='inlineModelProperty' style='width: 26%'>");
+				ViewContext.Writer.Write(Html.CustomLabelFor(m => m.Start, "Benutzer:"));
+				Html.DevExpress().DropDownEdit(t =>
 				{
-					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>");
+					t.Name = "devDropDownListUserValues";
+					t.Width = new Unit(100, UnitType.Percentage);
+					t.Text = Model.UserDescription;
 
-				ViewContext.Writer.Write("<div class='inlineModelProperty' style='width: 24%'>");
-				{
-					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 =>
+					t.SetDropDownWindowTemplateContent(l =>
 					{
-						t.Width = new Unit(100, UnitType.Percentage);
-					}).Render();
-				}
-				ViewContext.Writer.Write("</div>");
+						Html.DevExpress().ListBox(lb =>
+						{
+							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) =>
+							{
+								var listBox = sender as MVCxListBox;
+
+								foreach (ListEditItem listItem in listBox.Items)
+								{
+									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("</div>");
+			ViewContext.Writer.Write("</td></tr></tbody></table>");
+
 
 			ViewContext.Writer.Write(Html.CustomLabelFor(m => m.Deviations, "Vertragsabweichungen / Nachträge:"));
 

+ 6 - 1
GreenTree.Nachtragsmanagement.Web/Views/Sites/_SiteEditTreePartial.cshtml

@@ -15,7 +15,12 @@
 
 	t.Columns.Add(column =>
 	{
-		column.Caption = "#";
+		column.AllowSort = DefaultBoolean.False;
+		column.SetHeaderCaptionTemplateContent(c =>
+		{
+			ViewContext.Writer.Write(
+				"<a href=\"#\" onclick=\"addAppendixToSite(" + Model.Id + ")\">Neuer Nachtrag</a><br />");
+		});
 		column.SetDataCellTemplateContent(c =>
 		{
 			var treeKey = DataBinder.Eval(c.DataItem, "TreeKey").ToString();