فهرست منبع

Kundenvalidierung abgeschlossen

Arne Diekmann 5 سال پیش
والد
کامیت
9e21d31c40

+ 14 - 0
GreenTree.Strohrmann.ERP.Services/Geolocator/GoogleApiOptions.cs

@@ -0,0 +1,14 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace GreenTree.Strohrmann.ERP.Services.Geolocator
+{
+    public class GoogleApiOptions
+    {
+        /// <summary>
+        /// The Google provided API key
+        /// </summary>
+        public string ApiKey { get; set; }
+    }
+}

+ 101 - 0
GreenTree.Strohrmann.ERP.Services/Geolocator/GoogleGeocodingService.cs

@@ -0,0 +1,101 @@
+using GuigleApi;
+using GuigleApi.Models.Extension;
+using GuigleApi.Models.Response;
+using Microsoft.EntityFrameworkCore.Internal;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Net.Http;
+using System.Text;
+
+namespace GreenTree.Strohrmann.ERP.Services.Geolocator
+{
+    public class GoogleGeocodingService : IGeocodingService
+    {
+        #region Contants
+
+        // The default address component types to check for an address validation
+        private readonly string[] _defaultCheckComponents = 
+        {
+            "street_number",
+            "route",
+            "locality",
+            "country",
+            "postal_code"
+        };
+
+        #endregion
+
+        #region DI fields
+
+        // The global Google API settings
+        private readonly GoogleApiOptions _googleApiOptions;
+
+        #endregion
+
+        #region Ctor
+
+        /// <summary>
+        /// Initializes a new instance of the GoogleGeocodingService
+        /// </summary>
+        /// <param name="googleApiOptions">Global Google API options.</param>
+        public GoogleGeocodingService(
+            GoogleApiOptions googleApiOptions)
+        {
+            _googleApiOptions = googleApiOptions;
+        }
+
+        #endregion
+
+        #region Implementation
+
+        /// <summary>
+        /// Checks an address search string for valid street address
+        /// </summary>
+        /// <param name="searchString">The address search string.</param>
+        public bool IsValidAddress(string searchString)
+        {
+            return IsValidAddress(searchString, _defaultCheckComponents);
+        }
+
+        /// <summary>
+        /// Checks an address search string for valid street address
+        /// </summary>
+        /// <param name="searchString">The address search string.</param>
+        /// <param name="addressComponents">
+        /// The address components the API result shall be checked for 
+        /// (NULL if validation check shall succeed).
+        /// </param>
+        public bool IsValidAddress(string searchString, string[] addressComponents)
+        {
+            if (addressComponents == null)
+                return true;
+
+            var client = new HttpClient();
+
+            var googleGeocodingApi = new GoogleGeocodingApi(_googleApiOptions.ApiKey);
+            var addressSearchResult = googleGeocodingApi.SearchAddress(
+                client, searchString);
+
+            var result = addressSearchResult.Result;
+
+            if (result.Status != "OK")
+                return false;
+
+            if (result.Results.Count == 0)
+                return false;
+
+            var addressResult = result.Results[0];
+
+            foreach (var addressComponent in addressComponents)
+            {
+                if (!addressResult.AddressComponents.Exists(a => a.Types.Any(t => t.ToString() == addressComponent)))
+                    return false;
+            }
+
+            return true;
+        }
+
+        #endregion
+    }
+}

+ 22 - 0
GreenTree.Strohrmann.ERP.Services/Geolocator/IGeocodingService.cs

@@ -0,0 +1,22 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace GreenTree.Strohrmann.ERP.Services.Geolocator
+{
+    public interface IGeocodingService
+    {
+        /// <summary>
+        /// Checks an address search string for valid street address
+        /// </summary>
+        /// <param name="searchString">The address search string.</param>
+        public bool IsValidAddress(string searchString);
+
+        /// <summary>
+        /// Checks an address search string for valid street address
+        /// </summary>
+        /// <param name="searchString">The address search string.</param>
+        /// <param name="addressComponents">The address components the API result shall be checked for.</param>
+        public bool IsValidAddress(string searchString, string[] addressComponents);
+    }
+}

+ 1 - 0
GreenTree.Strohrmann.ERP.Services/GreenTree.Strohrmann.ERP.Services.csproj

@@ -5,6 +5,7 @@
   </PropertyGroup>
 
   <ItemGroup>
+    <PackageReference Include="GuigleCore" Version="1.1.7" />
     <PackageReference Include="Microsoft.AspNetCore.Authorization" Version="3.1.5" />
     <PackageReference Include="Microsoft.AspNetCore.Identity" Version="2.2.0" />
     <PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="3.1.5">

+ 9 - 1
GreenTree.Strohrmann.ERP.Web/Controllers/CustomerController.cs

@@ -1,10 +1,12 @@
 using System;
 using System.Collections.Generic;
 using System.Linq;
+using System.Net.Http;
 using System.Threading.Tasks;
 using GreenTree.Strohrmann.ERP.Core.Domain.Business;
 using GreenTree.Strohrmann.ERP.Core.Helper;
 using GreenTree.Strohrmann.ERP.Domain.Model;
+using GreenTree.Strohrmann.ERP.Services.Geolocator;
 using GreenTree.Strohrmann.ERP.Web.Models.Business;
 using GreenTree.Strohrmann.ERP.Web.Models.Rights.User;
 using Microsoft.AspNetCore.Http;
@@ -22,6 +24,9 @@ namespace GreenTree.Strohrmann.ERP.Web.Controllers
         // The global user helper
         private readonly IUserHelper _userHelper;
 
+        // The global geocoding service
+        private readonly IGeocodingService _geocodingService;
+
         #endregion
 
         #region Ctor
@@ -31,12 +36,15 @@ namespace GreenTree.Strohrmann.ERP.Web.Controllers
         /// </summary>
         /// <param name="eRPDbContext">Global DbContext.</param>
         /// <param name="userHelper">Global user helper.</param>
+        /// <param name="geocodingService">Global geocoding service.</param>
         public CustomerController(
             ERPDbContext eRPDbContext,
-            IUserHelper userHelper)
+            IUserHelper userHelper,
+            IGeocodingService geocodingService)
         {
             _eRPDbContext = eRPDbContext;
             _userHelper = userHelper;
+            _geocodingService = geocodingService;
         }
 
         #endregion

+ 12 - 0
GreenTree.Strohrmann.ERP.Web/Startup.cs

@@ -8,6 +8,7 @@ using GreenTree.Strohrmann.ERP.Core.Helper;
 using GreenTree.Strohrmann.ERP.Domain.Model;
 using GreenTree.Strohrmann.ERP.Services.Authentication;
 using GreenTree.Strohrmann.ERP.Services.Authorization;
+using GreenTree.Strohrmann.ERP.Services.Geolocator;
 using GreenTree.Strohrmann.ERP.Services.Notification;
 using Microsoft.AspNetCore.Authentication;
 using Microsoft.AspNetCore.Authentication.Cookies;
@@ -93,6 +94,17 @@ namespace GreenTree.Strohrmann.ERP.Web
             // Add the mail notification service
             services.AddSingleton<INotificationService, MailNotificationService>();
 
+            // Add global Google API options
+            var geocodingOptions = Configuration.GetSection("GoogleApiOptions").Get<GoogleApiOptions>();
+
+            if (geocodingOptions == null)
+                throw new Exception("The appsettings.json does not contain Google API options.");
+
+            services.AddSingleton(geocodingOptions);
+
+            // Add the Google Geocoding service
+            services.AddSingleton<IGeocodingService, GoogleGeocodingService>();
+
             // Add sessioning
             services.AddSession(options =>
             {

+ 80 - 0
GreenTree.Strohrmann.ERP.Web/Validators/CustomerValidator.cs

@@ -0,0 +1,80 @@
+using FluentValidation;
+using GreenTree.Strohrmann.ERP.Domain.Model;
+using GreenTree.Strohrmann.ERP.Services.Geolocator;
+using GreenTree.Strohrmann.ERP.Web.Models.Business;
+using System;
+using System.Collections.Generic;
+using System.Data;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace GreenTree.Strohrmann.ERP.Web.Validators
+{
+	public class CustomerValidator : AbstractValidator<CustomerModel>
+	{
+		#region DI fields
+
+		// The global DbContext
+		private readonly ERPDbContext _eRPDbContext;
+
+		// The global geocoding service
+		private readonly IGeocodingService _geocodingService;
+
+		#endregion
+
+		#region Ctor
+
+		/// <summary>
+		/// Initializes a new instance of the CustomerValidator class
+		/// </summary>
+		/// <param name="eRPDbContext">Global DbContext.</param>
+		public CustomerValidator(
+			ERPDbContext eRPDbContext,
+			IGeocodingService geocodingService)
+		{
+			_eRPDbContext = eRPDbContext;
+			_geocodingService = geocodingService;
+
+			RuleFor(m => m.Firstname)
+				.NotEmpty();
+
+			RuleFor(m => m.Lastname)
+				.NotEmpty();
+
+			RuleFor(m => m.Address)
+				.NotEmpty();
+
+			RuleFor(m => m.ZipCode)
+				.NotEmpty();
+
+			RuleFor(m => m.Town)
+				.NotEmpty();
+
+			RuleFor(m => m.Country)
+				.NotEmpty();
+
+			RuleFor(m => m.Address)
+				.Custom((a, context) =>
+				{
+					var model = context.InstanceToValidate as CustomerModel;
+
+					if (model == null)
+					{
+						context.AddFailure("Unbekannter Fehler.");
+						return;
+					}
+
+					var addressValid = _geocodingService.IsValidAddress(
+						String.Format("{0} {1} {2}", model.Address, model.ZipCode, model.Town));
+
+					if (!addressValid)
+					{
+						context.AddFailure("Adresse kann nicht gefunden werden. Bitte überprüfen Sie die Adresseingaben.");
+						return;
+					}
+				});
+		}
+
+        #endregion
+    }
+}

+ 5 - 5
GreenTree.Strohrmann.ERP.Web/Views/Customer/Create.cshtml

@@ -44,16 +44,16 @@
                     <input asp-for="Address" class="form-control" />
                     <span asp-validation-for="Address" class="text-danger"></span>
                 </div>
-                <div class="form-group">
-                    <label asp-for="Town" class="control-label"></label>
-                    <input asp-for="Town" class="form-control" />
-                    <span asp-validation-for="Town" class="text-danger"></span>
-                </div>
                 <div class="form-group">
                     <label asp-for="ZipCode" class="control-label"></label>
                     <input asp-for="ZipCode" class="form-control" />
                     <span asp-validation-for="ZipCode" class="text-danger"></span>
                 </div>
+                <div class="form-group">
+                    <label asp-for="Town" class="control-label"></label>
+                    <input asp-for="Town" class="form-control" />
+                    <span asp-validation-for="Town" class="text-danger"></span>
+                </div>
                 <div class="form-group">
                     <label asp-for="Country" class="control-label"></label>
                     @Html.CountrySelectionFor(m => m.Country, new { @class = "form-control" })

+ 6 - 6
GreenTree.Strohrmann.ERP.Web/Views/Customer/Details.cshtml

@@ -57,16 +57,16 @@
                     @Html.DisplayFor(model => model.Address)
                 </dd>
                 <dt class = "col-sm-6">
-                    @Html.DisplayNameFor(model => model.Town)
+                    @Html.DisplayNameFor(model => model.ZipCode)
                 </dt>
                 <dd class = "col-sm-6">
-                    @Html.DisplayFor(model => model.Town)
+                    @Html.DisplayFor(model => model.ZipCode)
                 </dd>
                 <dt class = "col-sm-6">
-                    @Html.DisplayNameFor(model => model.ZipCode)
+                    @Html.DisplayNameFor(model => model.Town)
                 </dt>
                 <dd class = "col-sm-6">
-                    @Html.DisplayFor(model => model.ZipCode)
+                    @Html.DisplayFor(model => model.Town)
                 </dd>
                 <dt class = "col-sm-6">
                     @Html.DisplayNameFor(model => model.Country)
@@ -108,8 +108,8 @@
 
 <div id="trackingModal" class="modal fade" tabindex="-1" role="dialog">
     <div class="modal-dialog" role="document">
-        <div class="modal-content">
-            <div class="modal-header bg-info text-white">
+        <div class="modal-content modal-content-header-custom">
+            <div class="modal-header modal-header-info text-white">
                 <h5 class="modal-title">Änderungsinfo - @Model.Lastname, @Model.Firstname</h5>
                 <button type="button" class="close" data-dismiss="modal" aria-label="Close">
                     <span aria-hidden="true">&times;</span>

+ 5 - 5
GreenTree.Strohrmann.ERP.Web/Views/Customer/Edit.cshtml

@@ -46,16 +46,16 @@
                     <input asp-for="Address" class="form-control" />
                     <span asp-validation-for="Address" class="text-danger"></span>
                 </div>
-                <div class="form-group">
-                    <label asp-for="Town" class="control-label"></label>
-                    <input asp-for="Town" class="form-control" />
-                    <span asp-validation-for="Town" class="text-danger"></span>
-                </div>
                 <div class="form-group">
                     <label asp-for="ZipCode" class="control-label"></label>
                     <input asp-for="ZipCode" class="form-control" />
                     <span asp-validation-for="ZipCode" class="text-danger"></span>
                 </div>
+                <div class="form-group">
+                    <label asp-for="Town" class="control-label"></label>
+                    <input asp-for="Town" class="form-control" />
+                    <span asp-validation-for="Town" class="text-danger"></span>
+                </div>
                 <div class="form-group">
                     <label asp-for="Country" class="control-label"></label>
                     @Html.CountrySelectionFor(m => m.Country, new { @class = "form-control" })

+ 3 - 0
GreenTree.Strohrmann.ERP.Web/appsettings.json

@@ -26,5 +26,8 @@
         "SmtpServerUsername": "service",
         "SmtpServerPassword": "14595809ad.",
         "SmtpServerDomain": ""
+    },
+    "GoogleApiOptions": {
+        "ApiKey": "AIzaSyDJI7VrvPaCxG1u4rdEWoAjTfai2_6PWU4"
     }
 }

+ 11 - 0
GreenTree.Strohrmann.ERP.Web/wwwroot/css/site.css

@@ -139,4 +139,15 @@ body {
 .user-logo-container img {
     width: 32px;
     height: 32px;
+}
+
+/* Bootstrap extension and editing */
+
+.modal-header-info {
+    background-color: #17a2b8 !important;
+}
+
+.modal-content-header-custom {
+    border-top-left-radius: .4rem;
+    border-top-right-radius: .4rem;
 }