diff --git a/ArdalisRating.Tests/ArdalisRating.Tests.csproj b/ArdalisRating.Tests/ArdalisRating.Tests.csproj index 0ecc9e7..ce2c983 100644 --- a/ArdalisRating.Tests/ArdalisRating.Tests.csproj +++ b/ArdalisRating.Tests/ArdalisRating.Tests.csproj @@ -1,15 +1,18 @@ - + - netcoreapp2.2 + netcoreapp3.1 false - - - + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + diff --git a/ArdalisRating.Tests/JsonPolicySerializerGetPolicyFromJsonString.cs b/ArdalisRating.Tests/JsonPolicySerializerGetPolicyFromJsonString.cs new file mode 100644 index 0000000..c1afd29 --- /dev/null +++ b/ArdalisRating.Tests/JsonPolicySerializerGetPolicyFromJsonString.cs @@ -0,0 +1,57 @@ +using Xunit; + + +namespace ArdalisRating.Tests +{ + public class JsonPolicySerializerGetPolicyFromJsonString + { + [Fact] + public void ReturnsDefaultPolicyFromEmptyJsonString() + { + var inputJson = "{}"; + var serializer = new JsonPolicySerializer(); + + var result = serializer.GetPolicyFromJsonString(inputJson); + + var policy = new Policy(); + AssertPoliciesEqual(result, policy); + } + + [Fact] + public void ReturnsSimpleAutoPolicyFromValidJsonString() + { + var inputJson = @"{ + ""type"": ""Auto"", + ""make"": ""BMW"" + } + "; + var serializer = new JsonPolicySerializer(); + + var result = serializer.GetPolicyFromJsonString(inputJson); + + var policy = new Policy + { + Type = "Auto", + Make = "BMW" + }; + AssertPoliciesEqual(result, policy); + } + + private static void AssertPoliciesEqual(Policy result, Policy policy) + { + Assert.Equal(policy.Address, result.Address); + Assert.Equal(policy.Amount, result.Amount); + Assert.Equal(policy.BondAmount, result.BondAmount); + Assert.Equal(policy.DateOfBirth, result.DateOfBirth); + Assert.Equal(policy.Deductible, result.Deductible); + Assert.Equal(policy.FullName, result.FullName); + Assert.Equal(policy.IsSmoker, result.IsSmoker); + Assert.Equal(policy.Make, result.Make); + Assert.Equal(policy.Miles, result.Miles); + Assert.Equal(policy.Model, result.Model); + Assert.Equal(policy.Type, result.Type); + Assert.Equal(policy.Valuation, result.Valuation); + Assert.Equal(policy.Year, result.Year); + } + } +} diff --git a/ArdalisRating.Tests/RatingEngineRate.cs b/ArdalisRating.Tests/RatingEngineRate.cs index b470f06..6d08f27 100644 --- a/ArdalisRating.Tests/RatingEngineRate.cs +++ b/ArdalisRating.Tests/RatingEngineRate.cs @@ -1,48 +1,108 @@ -using Newtonsoft.Json; -using System; +using Newtonsoft.Json; +using System.Collections.Generic; using System.IO; using Xunit; + namespace ArdalisRating.Tests { - public class RatingEngineRate + // only for testing purpose + public class FakeLogger : ILogger { -[Fact] -public void ReturnsRatingOf10000For200000LandPolicy() -{ - var policy = new Policy + public List LoggedMessages { get; } = new List(); + + public void Log(string message) + { + LoggedMessages.Add(message); + } + } + + // Only for testing purpose + public class FakePolicySource : IPolicySource { - Type = PolicyType.Land, - BondAmount = 200000, - Valuation = 200000 - }; - string json = JsonConvert.SerializeObject(policy); - File.WriteAllText("policy.json", json); - - var engine = new RatingEngine(); - engine.Rate(); - var result = engine.Rating; - - Assert.Equal(10000, result); -} + public string PolicyString { get; set; } = ""; + + public string GetPolicyFromSource() + { + return PolicyString; + } + } + + public class RatingEngineRate + { + private readonly RatingEngine _engine; + private readonly ILogger _logger; + private readonly IPolicySource _policySource; + private IRatingContext Context { get; set; } + + public RatingEngineRate() + { + _logger = new FakeLogger(); + _policySource = new FakePolicySource(); + _engine = new RatingEngine(_logger, _policySource); + this.Context = new DefaultRatingContext(_policySource); + } + + [Fact] + public void ReturnsRatingOf10000For200000LandPolicy() + { + var policy = new Policy + { + Type = "Land", + BondAmount = 200000, + Valuation = 200000 + }; + string json = JsonConvert.SerializeObject(policy); + //File.WriteAllText("policy.json", json); + _policySource.PolicyString = json; + + //var engine = new RatingEngine(); + _engine.Rate(); + var result = _engine.Rating; + + Assert.Equal(10000, result); + } [Fact] public void ReturnsRatingOf0For200000BondOn260000LandPolicy() { var policy = new Policy { - Type = PolicyType.Land, + Type = "Land", BondAmount = 200000, Valuation = 260000 }; string json = JsonConvert.SerializeObject(policy); File.WriteAllText("policy.json", json); - var engine = new RatingEngine(); - engine.Rate(); - var result = engine.Rating; + // var _engine = new RatingEngine(); + _engine.Rate(); + var result = _engine.Rating; Assert.Equal(0, result); } + + [Fact] + public void LogsStartingLoadingAndCompleting() + { + var policy = new Policy() + { + Type = "Land", + BondAmount = 2000000, + Valuation = 260000 + }; + + string json = JsonConvert.SerializeObject(policy); + File.WriteAllText("policy.json", json); + + _engine.Rate(); + var result = _engine.Rating; + + + Assert.Contains(_logger.LoggedMessages, m => m == "Starting rate."); + Assert.Contains(_logger.LoggedMessages, m => m == "Loading policy."); + Assert.Contains(_logger.LoggedMessages, m => m == "Rating completed."); + + } } } diff --git a/ArdalisRating/ArdalisRating.csproj b/ArdalisRating/ArdalisRating.csproj index a16eac7..d20b3ab 100644 --- a/ArdalisRating/ArdalisRating.csproj +++ b/ArdalisRating/ArdalisRating.csproj @@ -2,7 +2,7 @@ Exe - netcoreapp2.2 + netcoreapp3.1 diff --git a/ArdalisRating/Core/Interfaces/ILogger.cs b/ArdalisRating/Core/Interfaces/ILogger.cs new file mode 100644 index 0000000..aa60943 --- /dev/null +++ b/ArdalisRating/Core/Interfaces/ILogger.cs @@ -0,0 +1,8 @@ +namespace ArdalisRating +{ + public interface ILogger + { + //public List LoggedMessages { get; } + void Log(string message); + } +} diff --git a/ArdalisRating/Core/Interfaces/IPolicySerializer.cs b/ArdalisRating/Core/Interfaces/IPolicySerializer.cs new file mode 100644 index 0000000..b99c051 --- /dev/null +++ b/ArdalisRating/Core/Interfaces/IPolicySerializer.cs @@ -0,0 +1,7 @@ +namespace ArdalisRating +{ + public interface IPolicySerializer + { + public Policy GetPolicyFromJsonString(string jsonString); + } +} diff --git a/ArdalisRating/Core/Interfaces/IPolicySource.cs b/ArdalisRating/Core/Interfaces/IPolicySource.cs new file mode 100644 index 0000000..74003a3 --- /dev/null +++ b/ArdalisRating/Core/Interfaces/IPolicySource.cs @@ -0,0 +1,7 @@ +namespace ArdalisRating +{ + public interface IPolicySource + { + string GetPolicyFromSource(); + } +} diff --git a/ArdalisRating/Policy.cs b/ArdalisRating/Core/Model/Policy.cs similarity index 82% rename from ArdalisRating/Policy.cs rename to ArdalisRating/Core/Model/Policy.cs index 791432d..522fc48 100644 --- a/ArdalisRating/Policy.cs +++ b/ArdalisRating/Core/Model/Policy.cs @@ -5,7 +5,8 @@ namespace ArdalisRating public class Policy { - public PolicyType Type { get; set; } + public string Type { get; set; } + #region Life Insurance public string FullName { get; set; } public DateTime DateOfBirth { get; set; } @@ -20,6 +21,10 @@ public class Policy public decimal BondAmount { get; set; } #endregion + #region Flood In Addition To Land + public int ElevationAboveSeaLevelFeet { get; set; } + #endregion + #region Auto public string Make { get; set; } public string Model { get; set; } @@ -27,6 +32,5 @@ public class Policy public int Miles { get; set; } public decimal Deductible { get; set; } #endregion - } } diff --git a/ArdalisRating/PolicyType.cs b/ArdalisRating/Core/Model/PolicyType.cs similarity index 77% rename from ArdalisRating/PolicyType.cs rename to ArdalisRating/Core/Model/PolicyType.cs index 741c630..d391e03 100644 --- a/ArdalisRating/PolicyType.cs +++ b/ArdalisRating/Core/Model/PolicyType.cs @@ -7,6 +7,7 @@ public enum PolicyType { Life = 0, Land = 1, - Auto = 2 + Auto = 2, + Flood = 3 } } diff --git a/ArdalisRating/Core/Rater/AutoPolicyRater.cs b/ArdalisRating/Core/Rater/AutoPolicyRater.cs new file mode 100644 index 0000000..58aa5e6 --- /dev/null +++ b/ArdalisRating/Core/Rater/AutoPolicyRater.cs @@ -0,0 +1,43 @@ +using System; + +namespace ArdalisRating +{ + public class AutoPolicyRater : Rater + { + //public AutoPolicyRater(IRatingContext context) + /* + public AutoPolicyRater(IRatingUpdater ratingUpdater, ILogger logger) + : base(ratingUpdater, logger) + { + + } + */ + public AutoPolicyRater(ILogger logger) + : base(logger) { } + + + //public override void Rate(Policy policy) + public override decimal Rate(Policy policy) + { + Logger.Log("Rating AUTO policy..."); + Logger.Log("Validating policy."); + if (String.IsNullOrEmpty(policy.Make)) + { + Logger.Log("Auto policy must specify Make"); + return 0m; + } + if (policy.Make == "BMW") + { + if (policy.Deductible < 500) + { + //_ratingUpdater.UpdateRating(1000m); + return 1000m; + } + //_ratingUpdater.UpdateRating(900m); + return 900m; + } + + return 0m; + } + } +} diff --git a/ArdalisRating/Core/Rater/FloodPolicyRater.cs b/ArdalisRating/Core/Rater/FloodPolicyRater.cs new file mode 100644 index 0000000..94e2db0 --- /dev/null +++ b/ArdalisRating/Core/Rater/FloodPolicyRater.cs @@ -0,0 +1,54 @@ +namespace ArdalisRating +{ + public class FloodPolicyRater : Rater + { + /* + public FloodPolicyRater(IRatingUpdater ratingUpdater) + : base(ratingUpdater) + { + } + */ + public FloodPolicyRater(ILogger logger) + : base(logger) + { + } + + public override decimal Rate(Policy policy) + { + // The _logger is removed and the Logger used across + //_logger.Log("Rating FLOOD policy..."); + Logger.Log("Rating FLOOD policy..."); + Logger.Log("Validating policy."); + if (policy.BondAmount == 0 || policy.Valuation == 0) + { + Logger.Log("Flood policy must specify Bond Amount and Valuation."); + return 0m; + } + if (policy.ElevationAboveSeaLevelFeet <= 0) + { + Logger.Log("Flood policy is not available for elevations at or below sea level."); + return 0m; + } + if (policy.BondAmount < 0.8m * policy.Valuation) + { + Logger.Log("Insufficient bond amount."); + return 0m; + } + decimal multiple = 1.0m; + if (policy.ElevationAboveSeaLevelFeet < 100) + { + multiple = 2.0m; + } + else if (policy.ElevationAboveSeaLevelFeet < 500) + { + multiple = 1.5m; + } + else if (policy.ElevationAboveSeaLevelFeet < 1000) + { + multiple = 1.1m; + } + //_ratingUpdater.UpdateRating(policy.BondAmount * 0.05m * multiple); + return (policy.BondAmount * 0.05m * multiple); + } + } +} diff --git a/ArdalisRating/Core/Rater/LandPolicyRater.cs b/ArdalisRating/Core/Rater/LandPolicyRater.cs new file mode 100644 index 0000000..d386464 --- /dev/null +++ b/ArdalisRating/Core/Rater/LandPolicyRater.cs @@ -0,0 +1,36 @@ +namespace ArdalisRating +{ + public class LandPolicyRater : Rater + { + + /* + public LandPolicyRater(IRatingUpdater ratingUpdater) + : base(ratingUpdater) + { + } + */ + + public LandPolicyRater(ILogger logger) + : base(logger) + { + } + + public override decimal Rate(Policy policy) + { + Logger.Log("Rating LAND policy..."); + Logger.Log("Validating policy."); + if (policy.BondAmount == 0 || policy.Valuation == 0) + { + Logger.Log("Land policy must specify Bond Amount and Valuation."); + return 0m; + } + if (policy.BondAmount < 0.8m * policy.Valuation) + { + Logger.Log("Insufficient bond amount."); + return 0m; + } + //_ratingUpdater.UpdateRating(policy.BondAmount * 0.05m); + return (policy.BondAmount * 0.05m); + } + } +} diff --git a/ArdalisRating/Core/Rater/LifePolicyRater.cs b/ArdalisRating/Core/Rater/LifePolicyRater.cs new file mode 100644 index 0000000..68782fb --- /dev/null +++ b/ArdalisRating/Core/Rater/LifePolicyRater.cs @@ -0,0 +1,48 @@ +using System; + +namespace ArdalisRating +{ + public class LifePolicyRater : Rater + { + public LifePolicyRater(ILogger logger) + : base(logger) + { + } + + public override decimal Rate(Policy policy) + { + Logger.Log("Rating LIFE policy..."); + Logger.Log("Validating policy."); + if (policy.DateOfBirth == DateTime.MinValue) + { + Logger.Log("Life policy must include Date of Birth."); + return 0m; + } + if (policy.DateOfBirth < DateTime.Today.AddYears(-100)) + { + Logger.Log("Centenarians are not eligible for coverage."); + return 0m; + } + if (policy.Amount == 0) + { + Logger.Log("Life policy must include an Amount."); + return 0m; + } + int age = DateTime.Today.Year - policy.DateOfBirth.Year; + if (policy.DateOfBirth.Month == DateTime.Today.Month && + DateTime.Today.Day < policy.DateOfBirth.Day || + DateTime.Today.Month < policy.DateOfBirth.Month) + { + age--; + } + decimal baseRate = policy.Amount * age / 200; + if (policy.IsSmoker) + { + //_ratingUpdater.UpdateRating(baseRate * 2); + return (baseRate * 2); + } + //_ratingUpdater.UpdateRating(baseRate); + return (baseRate); + } + } +} diff --git a/ArdalisRating/Core/Rater/Rater.cs b/ArdalisRating/Core/Rater/Rater.cs new file mode 100644 index 0000000..65730d3 --- /dev/null +++ b/ArdalisRating/Core/Rater/Rater.cs @@ -0,0 +1,37 @@ +namespace ArdalisRating +{ + public abstract class Rater + { + //protected readonly IRatingContext _context; + //protected readonly IRatingUpdater _ratingUpdater; + + //protected readonly ConsoleLogger _logger; + + + + // protected ILogger Logger { get; set; } = new ConsoleLogger(); + public ILogger Logger { get; set; } + + /* + public Rater(ILogger logger) + { + Logger = logger; + } + */ + + //public Rater(IRatingContext context) + //public Rater(IRatingUpdater ratingUpdater, ILogger logger) + //public Rater(IRatingUpdater ratingUpdater) + public Rater(ILogger logger) + { + //_context = context; + //_ratingUpdater = ratingUpdater; + + //_logger = _context.Logger; + Logger = logger; + } + + //public abstract void Rate(Policy policy); + public abstract decimal Rate(Policy policy); + } +} diff --git a/ArdalisRating/Core/Rater/RaterFactory.cs b/ArdalisRating/Core/Rater/RaterFactory.cs new file mode 100644 index 0000000..6f6b105 --- /dev/null +++ b/ArdalisRating/Core/Rater/RaterFactory.cs @@ -0,0 +1,39 @@ +using System; + +namespace ArdalisRating +{ + public class RaterFactory + { + private readonly IRatingUpdater _ratingUpdater; + private readonly ILogger _logger; + + //public Rater Create(Policy policy, IRatingContext context) + + //public RaterFactory(IRatingUpdater ratingUpdater) + public RaterFactory(ILogger logger) + { + //_ratingUpdater = ratingUpdater; + _logger = logger; + } + public Rater Create(Policy policy) + { + try + { + /* + return (Rater)Activator.CreateInstance( + Type.GetType($"ArdalisRating.{policy.Type}PolicyRater"), + new object[] { context }); + */ + return (Rater)Activator.CreateInstance( + Type.GetType($"ArdalisRating.{policy.Type}PolicyRater"), + new object[] { _logger }); + + } + catch + { + //return new UnknownPolicyRater(context); + return new UnknownPolicyRater(_logger); + } + } + } +} diff --git a/ArdalisRating/Core/Rater/UnknownPolicyRater.cs b/ArdalisRating/Core/Rater/UnknownPolicyRater.cs new file mode 100644 index 0000000..6fe923b --- /dev/null +++ b/ArdalisRating/Core/Rater/UnknownPolicyRater.cs @@ -0,0 +1,32 @@ +namespace ArdalisRating +{ + public class UnknownPolicyRater : Rater + { + /* + public UnknownPolicyRater(IRatingContext context) + : base(context) + { + } + */ + + /* + public UnknownPolicyRater(IRatingUpdater ratingUpdater) + : base(ratingUpdater) + { + + } + */ + public UnknownPolicyRater(ILogger logger) + : base(logger) + { + + } + + + public override decimal Rate(Policy policy) + { + Logger.Log("Unknown policy type"); + return 0m; + } + } +} diff --git a/ArdalisRating/Core/RatingEngine.cs b/ArdalisRating/Core/RatingEngine.cs new file mode 100644 index 0000000..70d5412 --- /dev/null +++ b/ArdalisRating/Core/RatingEngine.cs @@ -0,0 +1,60 @@ +namespace ArdalisRating +{ + /// + /// The RatingEngine reads the policy application details from a file and produces a numeric + /// rating value based on the details. + /// + public class RatingEngine + { + private readonly ILogger _logger; + private readonly IPolicySource _policySource; + private readonly IPolicySerializer _policySerializer; + private readonly RaterFactory _factory; + + + //public IRatingContext Context { get; set; } = new DefaultRatingContext(); + public IRatingContext Context { get; set; } + public decimal Rating { get; set; } + + /* + public RatingEngine() : this(new ConsoleLogger()) + { + // default Ctor; + // chaining ctor to include the one parameter constructor + } + */ + + public RatingEngine(ILogger logger, IPolicySource policySource, IPolicySerializer policySerializer, RaterFactory factory) + { + _policySource = policySource; + _policySerializer = policySerializer; + //Context = new DefaultRatingContext(_policySource, _policySerializer, logger); + //Context.Engine = this; + _logger = logger; + _factory = factory; + } + + public void Rate() + { + _logger.Log("Starting rate."); + + // Rather than using the Context instance, explicitly adding dependecies as constructor + // Context.Log("Loading policy."); + _logger.Log("Loading policy."); + + //string policyJson = Context.LoadPolicyFromFile(); + string policyJson = _policySource.GetPolicyFromSource(); + + //var policy = Context.GetPolicyFromJsonString(policyJson); + var policy = _policySerializer.GetPolicyFromJsonString(policyJson); + + + //var rater = Context.CreateRaterForPolicy(policy, Context); + var rater = _factory.Create(policy); + + rater.Rate(policy); + + _logger.Log("Rating completed."); + } + } +} diff --git a/ArdalisRating/DefaultRatingContext.cs b/ArdalisRating/DefaultRatingContext.cs new file mode 100644 index 0000000..d894f5c --- /dev/null +++ b/ArdalisRating/DefaultRatingContext.cs @@ -0,0 +1,61 @@ +using System; + +namespace ArdalisRating +{ + public class DefaultRatingContext : IRatingContext + { + public RatingEngine Engine { get; set; } + + //public ConsoleLogger Logger => new ConsoleLogger(); + + // DIP made change + private readonly IPolicySource _policySource; + private readonly IPolicySerializer _policySerializer; + private readonly ILogger _logger; + + public DefaultRatingContext(IPolicySource policySource, IPolicySerializer policySerializer, ILogger logger) + { + _policySource = policySource; + _policySerializer = policySerializer; + _logger = logger; + } + + public Rater CreateRaterForPolicy(Policy policy, IRatingContext context) + { + //return new RaterFactory().Create(policy, context); + return new RaterFactory(_logger).Create(policy); + } + + public Policy GetPolicyFromJsonString(string policyJson) + { + //return new JsonPolicySerializer().GetPolicyFromJsonString(policyJson); + return _policySerializer.GetPolicyFromJsonString(policyJson); + } + + public Policy GetPolicyFromXmlString(string policyXml) + { + throw new NotImplementedException(); + } + + public string LoadPolicyFromFile() + { + // return new FilePolicySource().GetPolicyFromSource(); + return _policySource.GetPolicyFromSource(); + } + + public string LoadPolicyFromURI(string uri) + { + throw new NotImplementedException(); + } + + + public void Log(string message) + { + new ConsoleLogger().Log(message); + } + public void UpdateRating(decimal rating) + { + Engine.Rating = rating; + } + } +} diff --git a/ArdalisRating/IRatingContext.cs b/ArdalisRating/IRatingContext.cs new file mode 100644 index 0000000..ea0f11f --- /dev/null +++ b/ArdalisRating/IRatingContext.cs @@ -0,0 +1,16 @@ +namespace ArdalisRating +{ + public interface IRatingContext : ILogger, IRatingUpdater + { + // Removing both the logging options since it is available in ILogger + //void Log(string message); + string LoadPolicyFromFile(); + string LoadPolicyFromURI(string uri); + Policy GetPolicyFromJsonString(string policyJson); + Policy GetPolicyFromXmlString(string policyXml); + Rater CreateRaterForPolicy(Policy policy, IRatingContext context); + //void UpdateRating(decimal rating); + RatingEngine Engine { get; set; } + //ConsoleLogger Logger { get; } + } +} diff --git a/ArdalisRating/IRatingUpdater.cs b/ArdalisRating/IRatingUpdater.cs new file mode 100644 index 0000000..85035e0 --- /dev/null +++ b/ArdalisRating/IRatingUpdater.cs @@ -0,0 +1,7 @@ +namespace ArdalisRating +{ + public interface IRatingUpdater + { + void UpdateRating(decimal rating); + } +} diff --git a/ArdalisRating/Infrastructure/Loggers/ConsoleLogger.cs b/ArdalisRating/Infrastructure/Loggers/ConsoleLogger.cs new file mode 100644 index 0000000..795652c --- /dev/null +++ b/ArdalisRating/Infrastructure/Loggers/ConsoleLogger.cs @@ -0,0 +1,12 @@ +using System; + +namespace ArdalisRating +{ + public class ConsoleLogger : ILogger + { + public void Log(string message) + { + Console.WriteLine(message); + } + } +} diff --git a/ArdalisRating/Infrastructure/Loggers/FileLogger.cs b/ArdalisRating/Infrastructure/Loggers/FileLogger.cs new file mode 100644 index 0000000..ee30955 --- /dev/null +++ b/ArdalisRating/Infrastructure/Loggers/FileLogger.cs @@ -0,0 +1,16 @@ +using System.IO; + +namespace ArdalisRating +{ + public class FileLogger : ILogger + { + public void Log(string message) + { + using (var stream = File.AppendText("log.txt")) + { + stream.WriteLine(message); + stream.Flush(); + } + } + } +} diff --git a/ArdalisRating/Infrastructure/PolicySources/FilePolicySource.cs b/ArdalisRating/Infrastructure/PolicySources/FilePolicySource.cs new file mode 100644 index 0000000..cbfb698 --- /dev/null +++ b/ArdalisRating/Infrastructure/PolicySources/FilePolicySource.cs @@ -0,0 +1,12 @@ +using System.IO; + +namespace ArdalisRating +{ + public class FilePolicySource : IPolicySource + { + public string GetPolicyFromSource() + { + return File.ReadAllText("policy.json"); + } + } +} diff --git a/ArdalisRating/Infrastructure/Serializers/JsonPolicySerializer.cs b/ArdalisRating/Infrastructure/Serializers/JsonPolicySerializer.cs new file mode 100644 index 0000000..9258f2f --- /dev/null +++ b/ArdalisRating/Infrastructure/Serializers/JsonPolicySerializer.cs @@ -0,0 +1,14 @@ +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; + +namespace ArdalisRating +{ + public class JsonPolicySerializer : IPolicySerializer + { + public Policy GetPolicyFromJsonString(string jsonString) + { + return JsonConvert.DeserializeObject(jsonString, + new StringEnumConverter()); + } + } +} diff --git a/ArdalisRating/RatingEngine.cs b/ArdalisRating/RatingEngine.cs deleted file mode 100644 index 0e373d3..0000000 --- a/ArdalisRating/RatingEngine.cs +++ /dev/null @@ -1,105 +0,0 @@ -using Newtonsoft.Json; -using Newtonsoft.Json.Converters; -using System; -using System.IO; - -namespace ArdalisRating -{ - /// - /// The RatingEngine reads the policy application details from a file and produces a numeric - /// rating value based on the details. - /// - public class RatingEngine - { - public decimal Rating { get; set; } - public void Rate() - { - Console.WriteLine("Starting rate."); - - Console.WriteLine("Loading policy."); - - // load policy - open file policy.json - string policyJson = File.ReadAllText("policy.json"); - - var policy = JsonConvert.DeserializeObject(policyJson, - new StringEnumConverter()); - - switch (policy.Type) - { - case PolicyType.Auto: - Console.WriteLine("Rating AUTO policy..."); - Console.WriteLine("Validating policy."); - if (String.IsNullOrEmpty(policy.Make)) - { - Console.WriteLine("Auto policy must specify Make"); - return; - } - if (policy.Make == "BMW") - { - if (policy.Deductible < 500) - { - Rating = 1000m; - } - Rating = 900m; - } - break; - - case PolicyType.Land: - Console.WriteLine("Rating LAND policy..."); - Console.WriteLine("Validating policy."); - if (policy.BondAmount == 0 || policy.Valuation == 0) - { - Console.WriteLine("Land policy must specify Bond Amount and Valuation."); - return; - } - if (policy.BondAmount < 0.8m * policy.Valuation) - { - Console.WriteLine("Insufficient bond amount."); - return; - } - Rating = policy.BondAmount * 0.05m; - break; - - case PolicyType.Life: - Console.WriteLine("Rating LIFE policy..."); - Console.WriteLine("Validating policy."); - if (policy.DateOfBirth == DateTime.MinValue) - { - Console.WriteLine("Life policy must include Date of Birth."); - return; - } - if (policy.DateOfBirth < DateTime.Today.AddYears(-100)) - { - Console.WriteLine("Centenarians are not eligible for coverage."); - return; - } - if (policy.Amount == 0) - { - Console.WriteLine("Life policy must include an Amount."); - return; - } - int age = DateTime.Today.Year - policy.DateOfBirth.Year; - if (policy.DateOfBirth.Month == DateTime.Today.Month && - DateTime.Today.Day < policy.DateOfBirth.Day || - DateTime.Today.Month < policy.DateOfBirth.Month) - { - age--; - } - decimal baseRate = policy.Amount * age / 200; - if (policy.IsSmoker) - { - Rating = baseRate * 2; - break; - } - Rating = baseRate; - break; - - default: - Console.WriteLine("Unknown policy type"); - break; - } - - Console.WriteLine("Rating completed."); - } - } -} diff --git a/ArdalisRating/RatingUpdater.cs b/ArdalisRating/RatingUpdater.cs new file mode 100644 index 0000000..d21cd92 --- /dev/null +++ b/ArdalisRating/RatingUpdater.cs @@ -0,0 +1,17 @@ +namespace ArdalisRating +{ + public class RatingUpdater : IRatingUpdater + { + private readonly RatingEngine _engine; + + public RatingUpdater(RatingEngine engine) + { + _engine = engine; + } + + public void UpdateRating(decimal rating) + { + _engine.Rating = rating; + } + } +} diff --git a/ArdalisRating/Program.cs b/ArdalisRating/UI/Program.cs similarity index 65% rename from ArdalisRating/Program.cs rename to ArdalisRating/UI/Program.cs index af231a9..3db971e 100644 --- a/ArdalisRating/Program.cs +++ b/ArdalisRating/UI/Program.cs @@ -7,8 +7,10 @@ class Program static void Main(string[] args) { Console.WriteLine("Ardalis Insurance Rating System Starting..."); + //var logger = new ConsoleLogger(); + var logger = new FileLogger(); - var engine = new RatingEngine(); + var engine = new RatingEngine(logger, new FilePolicySource(), new JsonPolicySerializer(), new RaterFactory(logger)); engine.Rate(); if (engine.Rating > 0) @@ -20,6 +22,7 @@ static void Main(string[] args) Console.WriteLine("No rating produced."); } + Console.ReadLine(); } } }