public void SetUp() { var idCounter = 0; repoList = new List<DriveReport>(); _emplMock = Substitute.For<IGenericRepository<Employment>>(); _calculatorMock = Substitute.For<IReimbursementCalculator>(); _orgUnitMock = Substitute.For<IGenericRepository<OrgUnit>>(); _routeMock = Substitute.For<IRoute<RouteInformation>>(); _coordinatesMock = Substitute.For<IAddressCoordinates>(); _subMock = Substitute.For<IGenericRepository<Core.DomainModel.Substitute>>(); _mailServiceMock = Substitute.For<IMailService>(); _reportRepoMock = NSubstitute.Substitute.For<IGenericRepository<DriveReport>>(); _personMock = Substitute.For<IGenericRepository<Person>>(); _logger = new Core.ApplicationServices.Logger.Logger(); _customSettings = new CustomSettings(); _reportRepoMock.Insert(new DriveReport()).ReturnsForAnyArgs(x => x.Arg<DriveReport>()).AndDoes(x => repoList.Add(x.Arg<DriveReport>())).AndDoes(x => x.Arg<DriveReport>().Id = idCounter).AndDoes(x => idCounter++); _reportRepoMock.AsQueryable().ReturnsForAnyArgs(repoList.AsQueryable()); _calculatorMock.Calculate(new RouteInformation(), new DriveReport()).ReturnsForAnyArgs(x => x.Arg<DriveReport>()); _coordinatesMock.GetAddressCoordinates(new Address()).ReturnsForAnyArgs(new DriveReportPoint() { Latitude = "1", Longitude = "2", }); _routeMock.GetRoute(DriveReportTransportType.Car, new List<Address>()).ReturnsForAnyArgs(new RouteInformation() { Length = 2000 }); _uut = new DriveReportService(_mailServiceMock, _reportRepoMock, _calculatorMock, _orgUnitMock, _emplMock, _subMock, _coordinatesMock, _routeMock, _rateTypeMock, _personMock, _logger, _customSettings); }
public double GetDistanceFromHome(Person person, int addressId) { var homeAddress = person.PersonalAddresses.AsQueryable().FirstOrDefault(x => x.Type == PersonalAddressType.AlternativeHome); // Get primary home address if alternative doesnt exist. homeAddress = homeAddress ?? person.PersonalAddresses.AsQueryable().FirstOrDefault(x => x.Type == PersonalAddressType.Home); var workAddress = _addressRepo.AsQueryable().FirstOrDefault(a => a.Id == addressId); return(_route.GetRoute(DriveReportTransportType.Car, new List <Address>() { homeAddress, workAddress }).Length); }
public void SetUp() { var idCounter = 0; repoList = new List <DriveReport>(); _emplMock = Substitute.For <IGenericRepository <Employment> >(); _calculatorMock = Substitute.For <IReimbursementCalculator>(); _orgUnitMock = Substitute.For <IGenericRepository <OrgUnit> >(); _rateTypeMock = Substitute.For <IGenericRepository <RateType> >(); _routeMock = Substitute.For <IRoute <RouteInformation> >(); _coordinatesMock = Substitute.For <IAddressCoordinates>(); _subMock = Substitute.For <IGenericRepository <Core.DomainModel.Substitute> >(); _mailServiceMock = Substitute.For <IMailService>(); _subServiceMock = Substitute.For <ISubstituteService>(); _reportRepoMock = NSubstitute.Substitute.For <IGenericRepository <DriveReport> >(); _personMock = Substitute.For <IGenericRepository <Person> >(); _logger = new Core.ApplicationServices.Logger.Logger(); _customSettings = new CustomSettings(); _reportRepoMock.Insert(new DriveReport()).ReturnsForAnyArgs(x => x.Arg <DriveReport>()).AndDoes(x => repoList.Add(x.Arg <DriveReport>())).AndDoes(x => x.Arg <DriveReport>().Id = idCounter).AndDoes(x => idCounter++); _reportRepoMock.AsQueryable().ReturnsForAnyArgs(repoList.AsQueryable()); _calculatorMock.Calculate(new RouteInformation(), new DriveReport()).ReturnsForAnyArgs(x => x.Arg <DriveReport>()); // The mocked reports share the exact same timestamp if they are driven on same day, so for test purposes we simplify the method and check if they are identical, so we are able to mock the method. _calculatorMock.AreReportsDrivenOnSameDay(1, 1).ReturnsForAnyArgs(x => (long)x[0] == (long)x[1]); _rateTypeMock.AsQueryable().ReturnsForAnyArgs(new List <RateType> { new RateType() { TFCode = "1234", IsBike = false, RequiresLicensePlate = true, Id = 1, Description = "TestRate" } }.AsQueryable()); _coordinatesMock.GetAddressCoordinates(new Address()).ReturnsForAnyArgs(new DriveReportPoint() { Latitude = "1", Longitude = "2", }); _routeMock.GetRoute(DriveReportTransportType.Car, new List <Address>()).ReturnsForAnyArgs(new RouteInformation() { Length = 2000 }); _uut = new DriveReportService(_mailServiceMock, _reportRepoMock, _calculatorMock, _orgUnitMock, _emplMock, _subMock, _coordinatesMock, _routeMock, _rateTypeMock, _personMock, _logger, _customSettings); }
public async Task <IActionResult> ViewRoutes(int LineID = 0) { UserDetailModel user = HttpContext.Session.SessionGet <UserDetailModel>("user"); if (user == null) { return(PartialView("_ErrorPartial", new ErrorViewModel { ErrorMessage = "Session expired. Please login to continue.", ErrorCode = 1 })); } return(PartialView("RoutesPartial", await _routeRepository.GetRoute(LineID))); }
public void SetUp() { var idCounter = 0; repoList = new List <DriveReport>(); _emplMock = Substitute.For <IGenericRepository <Employment> >(); _calculatorMock = Substitute.For <IReimbursementCalculator>(); _orgUnitMock = Substitute.For <IGenericRepository <OrgUnit> >(); _rateTypeMock = Substitute.For <IGenericRepository <RateType> >(); _routeMock = Substitute.For <IRoute <RouteInformation> >(); _coordinatesMock = Substitute.For <IAddressCoordinates>(); _subMock = Substitute.For <IGenericRepository <Core.DomainModel.Substitute> >(); _mailMock = Substitute.For <IMailSender>(); _reportRepoMock = NSubstitute.Substitute.For <IGenericRepository <DriveReport> >(); _loggerMock = NSubstitute.Substitute.For <ILogger>(); _reportRepoMock.Insert(new DriveReport()).ReturnsForAnyArgs(x => x.Arg <DriveReport>()).AndDoes(x => repoList.Add(x.Arg <DriveReport>())).AndDoes(x => x.Arg <DriveReport>().Id = idCounter).AndDoes(x => idCounter++); _reportRepoMock.AsQueryable().ReturnsForAnyArgs(repoList.AsQueryable()); _calculatorMock.Calculate(new RouteInformation(), new DriveReport()).ReturnsForAnyArgs(x => x.Arg <DriveReport>()); _rateTypeMock.AsQueryable().ReturnsForAnyArgs(new List <RateType> { new RateType() { TFCode = "1234", IsBike = false, RequiresLicensePlate = true, Id = 1, Description = "TestRate" } }.AsQueryable()); _coordinatesMock.GetAddressCoordinates(new Address()).ReturnsForAnyArgs(new DriveReportPoint() { Latitude = "1", Longitude = "2", }); _routeMock.GetRoute(DriveReportTransportType.Car, new List <Address>()).ReturnsForAnyArgs(new RouteInformation() { Length = 2000 }); _uut = new DriveReportService(_reportRepoMock, _calculatorMock, _coordinatesMock, _routeMock, _rateTypeMock, _mailMock, _orgUnitMock, _emplMock, _subMock, _loggerMock); }
/// <summary> /// Calculates and sets HomeWorkDistance to each employment belonging to person. /// </summary> /// <param name="person"></param> /// <returns></returns> public Person AddHomeWorkDistanceToEmployments(Person person) { // Get employments for person // Get alternative home address. var homeAddress = person.PersonalAddresses.AsQueryable().FirstOrDefault(x => x.Type == PersonalAddressType.AlternativeHome); // Get primary home address if alternative doesnt exist. homeAddress = homeAddress ?? person.PersonalAddresses.AsQueryable().FirstOrDefault(x => x.Type == PersonalAddressType.Home); foreach (var employment in person.Employments) { if (employment.WorkDistanceOverride > 0) { employment.HomeWorkDistance = employment.WorkDistanceOverride; } else { var workAddress = employment.AlternativeWorkAddress ?? new PersonalAddress() { StreetName = employment.OrgUnit.Address.StreetName, StreetNumber = employment.OrgUnit.Address.StreetNumber, ZipCode = employment.OrgUnit.Address.ZipCode, Town = employment.OrgUnit.Address.Town }; if (homeAddress != null && workAddress != null) { try { employment.HomeWorkDistance = _route.GetRoute(DriveReportTransportType.Car, new List <Address>() { homeAddress, workAddress }).Length; } catch (AddressCoordinatesException e) { // Catch the exception to write the error to the log file. _logger.LogForAdmin(person.FullName + " kan ikke logge på, da der er fejl i vedkommendes arbejds- eller hjemmeadresse."); // Rethrow the exception to allow to front end to display the error aswell. throw e; } } } } return(person); }
public void SetUp() { _persons = new List <Person> { new Person { Id = 1, FirstName = "Morten", LastName = "Rasmussen", CprNumber = "1234567890", Initials = "MR" }, new Person { Id = 2, FirstName = "Morten", LastName = "Jørgensen", CprNumber = "0987654321", Initials = "MJ" }, new Person { Id = 3, FirstName = "Jacob", LastName = "Jensen", CprNumber = "456456456", Initials = "JOJ" } }.AsQueryable(); _routeMock = NSubstitute.Substitute.For <IRoute <RouteInformation> >(); _routeMock.GetRoute(DriveReportTransportType.Car, new List <Address>()).ReturnsForAnyArgs(new RouteInformation()); _addressRepoMock = NSubstitute.Substitute.For <IGenericRepository <PersonalAddress> >(); _coordinatesMock = NSubstitute.Substitute.For <IAddressCoordinates>(); _loggerMock = NSubstitute.Substitute.For <ILogger>(); _absenceService = NSubstitute.Substitute.For <IKMDAbsenceService>(); _coordinatesMock.GetAddressCoordinates(new Address()).ReturnsForAnyArgs(new Address { Latitude = "1", Longitude = "1" }); _uut = new Core.ApplicationServices.PersonService(_addressRepoMock, _routeMock, _coordinatesMock, _loggerMock, _absenceService); }
/// <summary> /// Takes a DriveReport as input and returns it with data. /// /// FourKmRule: If a user has set the FourKmRule to be used, the distance between /// the users home and municipality is used in the correction of the driven distance. /// If the rule is not used, the distance between the users home and work address are /// calculated and used, provided that the user has not set a override for this value. /// /// Calculated: The driven route is calculated, and based on whether the user starts /// and/or ends at home, the driven distance is corrected by subtracting the distance /// between the users home address and work address. /// Again, this is dependend on wheter the user has overridden this value. /// /// Calculated without extra distance: If this method is used, the driven distance is /// still calculated, but the distance is not corrected with the distance between the /// users home address and work address. The distance calculated from the service is /// therefore used directly in the calculation of the amount to reimburse /// /// </summary> public DriveReport Calculate(RouteInformation drivenRoute, DriveReport report) { //Check if user has manually provided a distance between home address and work address var homeWorkDistance = 0.0; var person = _personRepo.AsQueryable().First(x => x.Id == report.PersonId); var homeAddress = _personService.GetHomeAddress(person); // Get Work and Homeaddress of employment at time of DriveDateTimestamp for report. var addressHistory = _addressHistoryRepo.AsQueryable().SingleOrDefault(x => x.EmploymentId == report.EmploymentId && x.StartTimestamp <report.DriveDateTimestamp && x.EndTimestamp> report.DriveDateTimestamp); if (homeAddress.Type != PersonalAddressType.AlternativeHome) { if (addressHistory != null && addressHistory.HomeAddress != null) { // If user doesn't have an alternative address set up then use the homeaddress at the time of DriveDateTimestamp // If the user does have an alternative address then always use that. homeAddress = addressHistory.HomeAddress; } } var employment = _emplrepo.AsQueryable().FirstOrDefault(x => x.Id.Equals(report.EmploymentId)); Address workAddress = employment.OrgUnit.Address; if (addressHistory != null && addressHistory.WorkAddress != null) { // If an AddressHistory.WorkAddress exists, then use that. workAddress = addressHistory.WorkAddress; } if (employment.AlternativeWorkAddress != null) { // Overwrite workaddress if an alternative work address exists. workAddress = employment.AlternativeWorkAddress; } if (report.KilometerAllowance != KilometerAllowance.Read && !report.IsFromApp) { //Check if drivereport starts at users home address. report.StartsAtHome = areAddressesCloseToEachOther(homeAddress, report.DriveReportPoints.First()); //Check if drivereport ends at users home address. report.EndsAtHome = areAddressesCloseToEachOther(homeAddress, report.DriveReportPoints.Last()); } homeWorkDistance = employment.WorkDistanceOverride; if (homeWorkDistance <= 0) { homeWorkDistance = _route.GetRoute(DriveReportTransportType.Car, new List <Address>() { homeAddress, workAddress }).Length; } //Calculate distance to subtract double toSubtract = 0; //If user indicated to use the Four Km Rule if (report.FourKmRule) { //Take users provided distance from home to border of municipality var borderDistance = person.DistanceFromHomeToBorder; //Adjust distance based on if user starts or ends at home if (report.StartsAtHome) { toSubtract += borderDistance; } if (report.EndsAtHome) { toSubtract += borderDistance; } } else { //Same logic as above, but uses calculated distance between home and work if (report.StartsAtHome) { toSubtract += homeWorkDistance; } if (report.EndsAtHome) { toSubtract += homeWorkDistance; } } switch (report.KilometerAllowance) { case KilometerAllowance.Calculated: { if ((report.StartsAtHome || report.EndsAtHome) && !report.FourKmRule) { report.IsExtraDistance = true; } double drivenDistance = report.Distance; if (!report.IsFromApp) { // In case the report is not from app then get distance from the supplied route. drivenDistance = drivenRoute.Length; } //Adjust distance based on FourKmRule and if user start and/or ends at home var correctDistance = drivenDistance - toSubtract; //Set distance to corrected report.Distance = correctDistance; if (!report.IsFromApp) { //Get RouteGeometry from driven route if the report is not from app. If it is from App then RouteGeometry is already set. report.RouteGeometry = drivenRoute.GeoPoints; } break; } case KilometerAllowance.CalculatedWithoutExtraDistance: { report.Distance = drivenRoute.Length; //Save RouteGeometry report.RouteGeometry = drivenRoute.GeoPoints; break; } case KilometerAllowance.Read: { if ((report.StartsAtHome || report.EndsAtHome) && !report.FourKmRule) { report.IsExtraDistance = true; } //Take distance from report var manuallyProvidedDrivenDistance = report.Distance; report.Distance = manuallyProvidedDrivenDistance - toSubtract; break; } default: { throw new Exception("No calculation method provided"); } } //Calculate the actual amount to reimburse if (report.Distance < 0) { report.Distance = 0; } // Multiply the distance by two if the report is a return trip if (report.IsRoundTrip == true) { report.Distance *= 2; } if (report.FourKmRule) { report.Distance -= FourKmAdjustment; } SetAmountToReimburse(report); return(report); }
/// <summary> /// Validates report and creates it in the database if it validates. /// </summary> /// <param name="report">Report to be created.</param> /// <returns>Created report.</returns> public DriveReport Create(DriveReport report) { if (report.PersonId == 0) { throw new Exception("No person provided"); } if (!Validate(report)) { throw new Exception("DriveReport has some invalid parameters"); } if (report.IsFromApp) { report = _calculator.Calculate(null, report); } else { if (report.KilometerAllowance != KilometerAllowance.Read) { var pointsWithCoordinates = new List <DriveReportPoint>(); foreach (var driveReportPoint in report.DriveReportPoints) { if (string.IsNullOrEmpty(driveReportPoint.Latitude) || driveReportPoint.Latitude == "0" || string.IsNullOrEmpty(driveReportPoint.Longitude) || driveReportPoint.Longitude == "0") { pointsWithCoordinates.Add( (DriveReportPoint)_coordinates.GetAddressCoordinates(driveReportPoint)); } else { pointsWithCoordinates.Add(driveReportPoint); } } report.DriveReportPoints = pointsWithCoordinates; var isBike = _rateTypeRepo.AsQueryable().First(x => x.TFCode.Equals(report.TFCode)).IsBike; // Set transportType to Bike if isBike is true. Otherwise set it to Car. var drivenRoute = _route.GetRoute( isBike ? DriveReportTransportType.Bike : DriveReportTransportType.Car, report.DriveReportPoints); report.Distance = drivenRoute.Length / 1000; if (report.Distance < 0) { report.Distance = 0; } report = _calculator.Calculate(drivenRoute, report); } else { report = _calculator.Calculate(null, report); } } // Round off Distance and AmountToReimburse to two decimals. report.Distance = Convert.ToDouble(report.Distance.ToString("0.##", CultureInfo.InvariantCulture), CultureInfo.InvariantCulture); report.AmountToReimburse = Convert.ToDouble(report.AmountToReimburse.ToString("0.##", CultureInfo.InvariantCulture), CultureInfo.InvariantCulture); var createdReport = _driveReportRepository.Insert(report); createdReport.UpdateResponsibleLeaders(GetResponsibleLeadersForReport(report)); var actualLeader = GetActualLeaderForReport(report); if (actualLeader != null) { createdReport.ActualLeaderId = actualLeader.Id; } if (report.Status == ReportStatus.Rejected) { // User is editing a rejected report to try and get it approved. report.Status = ReportStatus.Pending; } _driveReportRepository.Save(); // If the report is calculated or from an app, then we would like to store the points. if (report.KilometerAllowance != KilometerAllowance.Read || report.IsFromApp) { // Reports from app with manual distance have no drivereportpoints. if (report.DriveReportPoints.Count > 1) { for (var i = 0; i < createdReport.DriveReportPoints.Count; i++) { var currentPoint = createdReport.DriveReportPoints.ElementAt(i); if (i == report.DriveReportPoints.Count - 1) { // last element currentPoint.PreviousPointId = createdReport.DriveReportPoints.ElementAt(i - 1).Id; } else if (i == 0) { // first element currentPoint.NextPointId = createdReport.DriveReportPoints.ElementAt(i + 1).Id; } else { // between first and last currentPoint.NextPointId = createdReport.DriveReportPoints.ElementAt(i + 1).Id; currentPoint.PreviousPointId = createdReport.DriveReportPoints.ElementAt(i - 1).Id; } } _driveReportRepository.Save(); } } //AddFullName(report); SixtyDayRuleCheck(report); return(report); }
public void SetUp() { _persons = new List <Person> { new Person { Id = 1, FirstName = "Morten", LastName = "Rasmussen", CprNumber = "1234567890", Initials = "MR" }, new Person { Id = 2, FirstName = "Morten", LastName = "Jørgensen", CprNumber = "0987654321", Initials = "MJ" }, new Person { Id = 3, FirstName = "Jacob", LastName = "Jensen", CprNumber = "456456456", Initials = "JOJ" } }.AsQueryable(); _routeMock = NSubstitute.Substitute.For <IRoute <RouteInformation> >(); _routeMock.GetRoute(DriveReportTransportType.Car, new List <Address>()).ReturnsForAnyArgs(new RouteInformation()); _personalAddressRepoMock = NSubstitute.Substitute.For <IGenericRepository <PersonalAddress> >(); _addressRepoMock = NSubstitute.Substitute.For <IGenericRepository <Address> >(); _employmentsRepoMock = NSubstitute.Substitute.For <IGenericRepository <Employment> >(); _orgUnitsRepoMock = NSubstitute.Substitute.For <IGenericRepository <OrgUnit> >(); _orgUnitsRepoMock.AsQueryable().ReturnsForAnyArgs(new List <OrgUnit> { new OrgUnit { Id = 1, OrgId = 1, ShortDescription = "orgUnit1", LongDescription = "OrgUnit 1.0", Level = 1, ParentId = null }, new OrgUnit { Id = 2, OrgId = 2, ShortDescription = "orgUnit2", LongDescription = "OrgUnit 2.1", Level = 2, ParentId = 1 }, new OrgUnit { Id = 3, OrgId = 3, ShortDescription = "orgUnit3", LongDescription = "OrgUnit 2.2", Level = 2, ParentId = 1 } }.AsQueryable()); _loggerMock = NSubstitute.Substitute.For <ILogger>(); _coordinatesMock = NSubstitute.Substitute.For <IAddressCoordinates>(); _coordinatesMock.GetAddressCoordinates(new Address()).ReturnsForAnyArgs(new Address { Latitude = "1", Longitude = "1" }); _uut = new Core.ApplicationServices.PersonService(_personalAddressRepoMock, _addressRepoMock, _employmentsRepoMock, _orgUnitsRepoMock, _routeMock, _coordinatesMock, _loggerMock); }
/// <summary> /// Takes a DriveReport as input and returns it with data. /// /// FourKmRule: If a user has set the FourKmRule to be used, the distance between /// the users home and municipality is used in the correction of the driven distance. /// If the rule is not used, the distance between the users home and work address are /// calculated and used, provided that the user has not set a override for this value. /// /// Calculated: The driven route is calculated, and based on whether the user starts /// and/or ends at home, the driven distance is corrected by subtracting the distance /// between the users home address and work address. /// Again, this is dependend on wheter the user has overridden this value. /// /// Calculated without extra distance: If this method is used, the driven distance is /// still calculated, but the distance is not corrected with the distance between the /// users home address and work address. The distance calculated from the service is /// therefore used directly in the calculation of the amount to reimburse /// /// </summary> public DriveReport Calculate(RouteInformation drivenRoute, DriveReport report) { //Check if user has manually provided a distance between home address and work address var homeWorkDistance = 0.0; var person = _personRepo.AsQueryable().First(x => x.Id == report.PersonId); var homeAddress = _personService.GetHomeAddress(person); // Get Work and Homeaddress of employment at time of DriveDateTimestamp for report. AddressHistory addressHistory = null; try { addressHistory = _addressHistoryRepo.AsQueryable().SingleOrDefault(x => x.EmploymentId == report.EmploymentId && x.StartTimestamp <report.DriveDateTimestamp && x.EndTimestamp> report.DriveDateTimestamp); } catch (InvalidOperationException) { _logger.LogForAdmin(report.FullName + " har et overlap i sin adressehistorik"); throw; } if (homeAddress.Type != PersonalAddressType.AlternativeHome) { if (addressHistory != null && addressHistory.HomeAddress != null) { // If user doesn't have an alternative address set up then use the homeaddress at the time of DriveDateTimestamp // If the user does have an alternative address then always use that. homeAddress = addressHistory.HomeAddress; } } var employment = _emplrepo.AsQueryable().FirstOrDefault(x => x.Id.Equals(report.EmploymentId)); Address workAddress = employment.OrgUnit.Address; if (addressHistory != null && addressHistory.WorkAddress != null) { // If an AddressHistory.WorkAddress exists, then use that. workAddress = addressHistory.WorkAddress; } if (employment.AlternativeWorkAddress != null) { // Overwrite workaddress if an alternative work address exists. workAddress = employment.AlternativeWorkAddress; } if (report.WorkAddressId != 0) { if (report.WorkAddressId != employment.AlternativeWorkAddress?.Id && report.WorkAddressId != employment.OrgUnit.Address.Id) { // only allow work address id that is either the address of the orgunit or is the alternative address throw new Exception("Invalid WorkAddressId for report"); } // Overwrite workaddress if chosen on web report page workAddress = _addressRepo.AsQueryable().First(a => a.Id == report.WorkAddressId); } if (report.KilometerAllowance != KilometerAllowance.Read && !report.IsFromApp) { //Check if drivereport starts at users home address. report.StartsAtHome = areAddressesCloseToEachOther(homeAddress, report.DriveReportPoints.First()); //Check if drivereport ends at users home address. report.EndsAtHome = areAddressesCloseToEachOther(homeAddress, report.DriveReportPoints.Last()); } homeWorkDistance = employment.WorkDistanceOverride; if (homeWorkDistance <= 0) { homeWorkDistance = _route.GetRoute(DriveReportTransportType.Car, new List <Address>() { homeAddress, workAddress }).Length; } //Calculate distance to subtract double toSubtract = 0; //If user indicated to use the Four Km Rule if (report.FourKmRule) { //Take users provided distance from home to border of municipality. If report is from app, use distance provided in report, else use distance saved on person. var borderDistance = report.IsFromApp ? report.HomeToBorderDistance : person.DistanceFromHomeToBorder; //Adjust distance based on if user starts or ends at home if (report.StartsAtHome) { toSubtract += borderDistance; } if (report.EndsAtHome) { toSubtract += borderDistance; } } else { //Same logic as above, but uses calculated distance between home and work if (report.StartsAtHome) { toSubtract += homeWorkDistance; } if (report.EndsAtHome) { toSubtract += homeWorkDistance; } } switch (report.KilometerAllowance) { case KilometerAllowance.Calculated: { // Norddjurs Kommune uses an alternative way of calculating the amount to reimburse. Instead of subtracting the distance from home to work from the driven distance, // either the home-to-destination or work-to-destination distance is used, which ever is shortest. This only applies to routes starting from home, in any other case // the standard calculation method is used. bool useNorddjursAltCalculation; bool parseSucces = bool.TryParse(_customSettings.AlternativeCalculationMethod, out useNorddjursAltCalculation); useNorddjursAltCalculation = parseSucces ? useNorddjursAltCalculation : false; // Use Norddjurs alternative reimbursemnt calculation method if configured so. if (useNorddjursAltCalculation) { // The alternative calculationmethod is only used for reports starting at home. if (report.StartsAtHome) { // Distance from home. var homeDistance = report.Distance; if (!report.IsFromApp) { // In case the report is not from app then get distance from the supplied route. homeDistance = drivenRoute.Length; } // Get distance from work. var addresses = new List <Address>(); addresses.Add(workAddress); foreach (Address address in report.DriveReportPoints) { if (!(address.Latitude == homeAddress.Latitude && address.Longitude == homeAddress.Longitude)) { addresses.Add(address); } } var isBike = _rateTypeRepo.AsQueryable().First(x => x.TFCode.Equals(report.TFCode)).IsBike; var workDistance = _route.GetRoute(isBike ? DriveReportTransportType.Bike : DriveReportTransportType.Car, addresses).Length; // Compare the distance from home to the distance from work and apply the shortest of them. report.Distance = homeDistance < workDistance ? homeDistance : workDistance; if (!report.IsFromApp) { //Get RouteGeometry from driven route if the report is not from app. If it is from App then RouteGeometry is already set. report.RouteGeometry = drivenRoute.GeoPoints; } break; } else { if (!report.IsFromApp) { report.Distance = drivenRoute.Length; //Save RouteGeometry report.RouteGeometry = drivenRoute.GeoPoints; } break; } } if ((report.StartsAtHome || report.EndsAtHome) && !report.FourKmRule) { report.IsExtraDistance = true; } double drivenDistance = report.Distance; if (!report.IsFromApp) { // In case the report is not from app then get distance from the supplied route. drivenDistance = drivenRoute.Length; } //Adjust distance based on FourKmRule and if user start and/or ends at home var correctDistance = drivenDistance - toSubtract; //Set distance to corrected report.Distance = correctDistance; if (!report.IsFromApp) { //Get RouteGeometry from driven route if the report is not from app. If it is from App then RouteGeometry is already set. report.RouteGeometry = drivenRoute.GeoPoints; } break; } case KilometerAllowance.CalculatedWithoutExtraDistance: { report.Distance = drivenRoute.Length; //Save RouteGeometry report.RouteGeometry = drivenRoute.GeoPoints; break; } case KilometerAllowance.Read: { if ((report.StartsAtHome || report.EndsAtHome) && !report.FourKmRule) { report.IsExtraDistance = true; } //Take distance from report var manuallyProvidedDrivenDistance = report.Distance; report.Distance = manuallyProvidedDrivenDistance - toSubtract; break; } default: { throw new Exception("No calculation method provided"); } } //Calculate the actual amount to reimburse if (report.Distance < 0) { report.Distance = 0; } // Multiply the distance by two if the report is a return trip if (report.IsRoundTrip == true) { report.Distance *= 2; } CalculateFourKmRuleForReport(report); SetAmountToReimburse(report); return(report); }
public void Create_ValidCalculatedReport_DistanceLessThanZero_ShouldSetDistanceToZero() { var empl = new Employment { Id = 4, OrgUnitId = 2, OrgUnit = new OrgUnit(), Person = new Person() { Id = 1 }, PersonId = 12, IsLeader = false }; var leaderEmpl = new Employment { Id = 1, OrgUnitId = 2, OrgUnit = new OrgUnit() { Id = 2 }, Person = new Person() { Id = 13 }, PersonId = 13, IsLeader = true }; _orgUnitMock.AsQueryable().ReturnsForAnyArgs(new List <OrgUnit>() { new OrgUnit() { Id = 2 } }.AsQueryable()); _subMock.AsQueryable().ReturnsForAnyArgs(new List <Core.DomainModel.Substitute>().AsQueryable()); _emplMock.AsQueryable().ReturnsForAnyArgs(new List <Employment>() { empl, leaderEmpl }.AsQueryable()); _routeMock.GetRoute(DriveReportTransportType.Car, new List <Address>()).ReturnsForAnyArgs(new RouteInformation() { Length = -10 }); var report = new DriveReport { KilometerAllowance = KilometerAllowance.Calculated, DriveReportPoints = new List <DriveReportPoint> { new DriveReportPoint(), new DriveReportPoint(), new DriveReportPoint() }, PersonId = 12, EmploymentId = 4, Purpose = "Test", TFCode = "1234", }; var res = _uut.Create(report); Assert.AreEqual(0, res.Distance); }
public void SetUp() { _emplRepo = NSubstitute.Substitute.For <IGenericRepository <Employment> >(); _logger = NSubstitute.Substitute.For <ILogger>(); _dmzRepoMock = NSubstitute.Substitute.For <IGenericRepository <Core.DmzModel.DriveReport> >(); _coordinatesMock = NSubstitute.Substitute.For <IAddressCoordinates>(); _masterRepoMock = NSubstitute.Substitute.For <IGenericRepository <Core.DomainModel.DriveReport> >(); _driveReportServiceMock = NSubstitute.Substitute.For <IDriveReportService>(); _rateRepoMock = NSubstitute.Substitute.For <IGenericRepository <Rate> >(); _licensePlateRepoMock = NSubstitute.Substitute.For <IGenericRepository <LicensePlate> >(); _routeMock = NSubstitute.Substitute.For <IRoute <RouteInformation> >(); _routeMock.GetRoute(DriveReportTransportType.Car, new List <Address>()).ReturnsForAnyArgs(new RouteInformation() { GeoPoints = "geogeo" }); _coordinatesMock.GetAddressFromCoordinates(new Address()).ReturnsForAnyArgs(new Address() { Latitude = "1", Longitude = "1", StreetName = "Katrinebjergvej", StreetNumber = "93B", ZipCode = 8200, Town = "Aarhus N" }); _dmzRepoMock.WhenForAnyArgs(x => x.Delete(new Core.DmzModel.DriveReport())).Do(p => _dmzReportList.Remove(p.Arg <Core.DmzModel.DriveReport>())); _driveReportServiceMock.WhenForAnyArgs(x => x.Create(new Core.DomainModel.DriveReport())).Do(rep => _masterReportList.Add(rep.Arg <Core.DomainModel.DriveReport>())); _dmzRepoMock.WhenForAnyArgs(x => x.Insert(new Core.DmzModel.DriveReport())).Do(t => _dmzReportList.Add(t.Arg <Core.DmzModel.DriveReport>())); _rateRepoMock.AsQueryable().ReturnsForAnyArgs(new List <Rate>() { new Rate() { Id = 1, KmRate = 12, Active = true, Year = 2015, Type = new RateType() { Id = 1, RequiresLicensePlate = true, TFCode = "1234", Description = "TestDescription" } } }.AsQueryable()); _licensePlateRepoMock.AsQueryable().ReturnsForAnyArgs(new List <LicensePlate>() { new LicensePlate() { Id = 1, PersonId = 1, Plate = "TestPlate", IsPrimary = true, Description = "TestDesc", } }.AsQueryable()); _dmzReportList = new List <DriveReport>() { new DriveReport() { Id = 1, Purpose = "Test", StartsAtHome = false, EndsAtHome = false, ManualEntryRemark = "ManualEntry", Date = "2015-05-27", EmploymentId = 1, ProfileId = 1, RateId = 1, Profile = new Profile() { FullName = "Test Testesen [TT]" }, Route = new Route() { Id = 1, GPSCoordinates = new List <GPSCoordinate>() { new GPSCoordinate() { Latitude = StringCipher.Encrypt("1", Encryptor.EncryptKey), Longitude = StringCipher.Encrypt("1", Encryptor.EncryptKey), }, new GPSCoordinate() { Latitude = StringCipher.Encrypt("2", Encryptor.EncryptKey), Longitude = StringCipher.Encrypt("2", Encryptor.EncryptKey), } } } }, new DriveReport() { Id = 2, Purpose = "Test2", StartsAtHome = true, EndsAtHome = true, ManualEntryRemark = "ManualEntry", Date = "2015-05-26", EmploymentId = 1, ProfileId = 1, RateId = 1, Profile = new Profile() { FullName = "Test Testesen [TT]" }, Route = new Route() { Id = 2, GPSCoordinates = new List <GPSCoordinate>() { new GPSCoordinate() { Latitude = StringCipher.Encrypt("1", Encryptor.EncryptKey), Longitude = StringCipher.Encrypt("1", Encryptor.EncryptKey), }, new GPSCoordinate() { Latitude = StringCipher.Encrypt("2", Encryptor.EncryptKey), Longitude = StringCipher.Encrypt("2", Encryptor.EncryptKey), } } } } }; _masterRepoMock.AsQueryable().ReturnsForAnyArgs(_masterReportList.AsQueryable()); _dmzRepoMock.AsQueryable().ReturnsForAnyArgs(_dmzReportList.AsQueryable()); _uut = new DriveReportSyncService(_dmzRepoMock, _masterRepoMock, _rateRepoMock, _licensePlateRepoMock, _driveReportServiceMock, _routeMock, _coordinatesMock, _emplRepo, _logger); }
/// <summary> /// Takes a DriveReport as input and returns it with data. /// /// FourKmRule: If a user has set the FourKmRule to be used, the distance between /// the users home and municipality is used in the correction of the driven distance. /// If the rule is not used, the distance between the users home and work address are /// calculated and used, provided that the user has not set a override for this value. /// /// Calculated: The driven route is calculated, and based on whether the user starts /// and/or ends at home, the driven distance is corrected by subtracting the distance /// between the users home address and work address. /// Again, this is dependend on wheter the user has overridden this value. /// /// Calculated without extra distance: If this method is used, the driven distance is /// still calculated, but the distance is not corrected with the distance between the /// users home address and work address. The distance calculated from the service is /// therefore used directly in the calculation of the amount to reimburse /// /// </summary> public DriveReport Calculate(RouteInformation drivenRoute, DriveReport report) { //Check if user has manually provided a distance between home address and work address var homeWorkDistance = 0.0; var person = _personRepo.AsQueryable().First(x => x.Id == report.PersonId); var homeAddress = _personService.GetHomeAddress(person); // Get Work and Homeaddress of employment at time of DriveDateTimestamp for report. AddressHistory addressHistory = null; try { addressHistory = _addressHistoryRepo.AsQueryable().SingleOrDefault(x => x.EmploymentId == report.EmploymentId && x.StartTimestamp <report.DriveDateTimestamp && x.EndTimestamp> report.DriveDateTimestamp); } catch (InvalidOperationException) { _logger.LogForAdmin(report.FullName + " har et overlap i sin adressehistorik"); throw; } if (homeAddress.Type != PersonalAddressType.AlternativeHome) { if (addressHistory != null && addressHistory.HomeAddress != null) { // If user doesn't have an alternative address set up then use the homeaddress at the time of DriveDateTimestamp // If the user does have an alternative address then always use that. homeAddress = addressHistory.HomeAddress; } } var employment = _emplrepo.AsQueryable().FirstOrDefault(x => x.Id.Equals(report.EmploymentId)); Address workAddress = employment.OrgUnit.Address; if (addressHistory != null && addressHistory.WorkAddress != null) { // If an AddressHistory.WorkAddress exists, then use that. workAddress = addressHistory.WorkAddress; } if (employment.AlternativeWorkAddress != null) { // Overwrite workaddress if an alternative work address exists. workAddress = employment.AlternativeWorkAddress; } if (report.KilometerAllowance != KilometerAllowance.Read && !report.IsFromApp) { //Check if drivereport starts at users home address. report.StartsAtHome = areAddressesCloseToEachOther(homeAddress, report.DriveReportPoints.First()); //Check if drivereport ends at users home address. report.EndsAtHome = areAddressesCloseToEachOther(homeAddress, report.DriveReportPoints.Last()); } homeWorkDistance = employment.WorkDistanceOverride; if (homeWorkDistance <= 0) { homeWorkDistance = _route.GetRoute(DriveReportTransportType.Car, new List <Address>() { homeAddress, workAddress }).Length; } //Calculate distance to subtract //double toSubtract = 0; double toSubtractFourKmRule = 0; double toSubtractHomeRule = 0; double toSubtractAltRule = 0; //If user indicated to use the Four Km Rule if (report.FourKmRule) { //Take users provided distance from home to border of municipality. If report is from app, use distance provided in report, else use distance saved on person. var borderDistance = report.IsFromApp ? report.HomeToBorderDistance : person.DistanceFromHomeToBorder; //Adjust distance based on if user starts or ends at home if (report.StartsAtHome) { //toSubtract += borderDistance; toSubtractFourKmRule += borderDistance; } if (report.EndsAtHome) { //toSubtract += borderDistance; toSubtractFourKmRule += borderDistance; } } else { //Same logic as above, but uses calculated distance between home and work if (report.StartsAtHome) { //toSubtract += homeWorkDistance; toSubtractHomeRule += homeWorkDistance; } if (report.EndsAtHome) { //toSubtract += homeWorkDistance; toSubtractHomeRule += homeWorkDistance; } } switch (report.KilometerAllowance) { case KilometerAllowance.Calculated: { string alternativeCalculationMethod = ConfigurationManager.AppSettings["AlternativeCalculationMethod"]; if (alternativeCalculationMethod == null) { alternativeCalculationMethod = string.Empty; } // Use Norddjurs alternative reimbursemnt calculation method if configured so. if (alternativeCalculationMethod.ToLower() == "ndk") { // Newer subtract the "daily" distance between HOME and WORK. toSubtractHomeRule = 0.0; // Get the drive report points. List <DriveReportPoint> altDriveReportPoints = new List <DriveReportPoint>(); foreach (DriveReportPoint altDriveReportPoint in report.DriveReportPoints) { altDriveReportPoints.Add(altDriveReportPoint); } // Get if a bike is used for transportation. Boolean altIsBike = _rateTypeRepo.AsQueryable().First(x => x.TFCode.Equals(report.TFCode)).IsBike; DriveReportTransportType altTransportType = (altIsBike == true) ? DriveReportTransportType.Bike : DriveReportTransportType.Car; Double altToSubtract1 = 0.0; Double altToSubtract2 = 0.0; // 1a. When starting from home if ( //(report.IsFromApp == false) && (report.StartsAtHome == true) && (altDriveReportPoints.Count >= 2) && ((altDriveReportPoints[1].Latitude != workAddress.Latitude) && (altDriveReportPoints[1].Longitude != workAddress.Longitude))) { // A1) Get the distance between HOME and the first LOCATION (the route in the report). // This is used to select the reported route, or the alternative route. List <Address> altAddressesToHome = new List <Address>(); altAddressesToHome.Add(homeAddress); altAddressesToHome.Add(altDriveReportPoints[1]); Double altDistanceToHome = _route.GetRoute(altTransportType, altAddressesToHome).Length; // A2) Get the distance for the entire route (the route in the report). // This is used to calculate the distance to subtract. altAddressesToHome = new List <Address>(altDriveReportPoints); Double altDistanceA = _route.GetRoute(altTransportType, altAddressesToHome).Length; // B1) Get the distance between WORK and the first LOCATION. // This is used to select the reported route, or the alternative route. List <Address> altAddressesToWork = new List <Address>(); altAddressesToWork.Add(workAddress); altAddressesToWork.Add(altDriveReportPoints[1]); Double altDistanceToWork = _route.GetRoute(altTransportType, altAddressesToWork).Length; // B2) Get the distance for the entire alternative route. // This is used to calculate the distance to subtract. altAddressesToWork = new List <Address>(altDriveReportPoints); altAddressesToWork[0] = workAddress; Double altDistanceB = _route.GetRoute(altTransportType, altAddressesToWork).Length; // The current report distance is including the route between HOME and LOCATION. // Substract the difference, if the distance between WORK and LOCATION is smaller. if (altDistanceToWork < altDistanceToHome) { altToSubtract1 = (altDistanceA - altDistanceB); } } // 1b. When starting from home if ( //(report.IsFromApp == false) && (report.StartsAtHome == true) && (altDriveReportPoints.Count == 2) && ((altDriveReportPoints[1].Latitude == workAddress.Latitude) && (altDriveReportPoints[1].Longitude == workAddress.Longitude))) { toSubtractHomeRule += homeWorkDistance; } // 2a. When finishing at home if ( //(report.IsFromApp == false) && (report.EndsAtHome == true) && (altDriveReportPoints.Count >= 2) && ((altDriveReportPoints[altDriveReportPoints.Count - 2].Latitude != workAddress.Latitude) && (altDriveReportPoints[altDriveReportPoints.Count - 2].Longitude != workAddress.Longitude))) { // A1) Get the distance between the second last LOCATION and HOME (the route in the report). // This is used to select the reported route, or the alternative route. List <Address> altAddressesToHome = new List <Address>(); altAddressesToHome.Add(altDriveReportPoints[altDriveReportPoints.Count - 2]); altAddressesToHome.Add(homeAddress); Double altDistanceToHome = _route.GetRoute(altTransportType, altAddressesToHome).Length; // A2) Get the distance for the entire route (the route in the report). // This is used to calculate the distance to subtract. altAddressesToHome = new List <Address>(altDriveReportPoints); Double altDistanceA = _route.GetRoute(altTransportType, altAddressesToHome).Length; // B1) Get the distance between the second last LOCATION and WORK. // This is used to select the reported route, or the alternative route. List <Address> altAddressesToWork = new List <Address>(); altAddressesToWork.Add(altDriveReportPoints[altDriveReportPoints.Count - 2]); altAddressesToWork.Add(workAddress); Double altDistanceToWork = _route.GetRoute(altTransportType, altAddressesToWork).Length; // B2) Get the distance for the entire alternative route. // This is used to calculate the distance to subtract. altAddressesToWork = new List <Address>(altDriveReportPoints); altAddressesToWork[altAddressesToWork.Count - 1] = workAddress; Double altDistanceB = _route.GetRoute(altTransportType, altAddressesToWork).Length; // The current report distance is including the route between HOME and LOCATION. // Substract the difference, if the distance between WORK and LOCATION is smaller. if (altDistanceToWork < altDistanceToHome) { altToSubtract2 = (altDistanceA - altDistanceB); } } // 2b. When finishing at home and 2 points and 1 is work if ( //(report.IsFromApp == false) && (report.EndsAtHome == true) && (altDriveReportPoints.Count == 2) && ((altDriveReportPoints[altDriveReportPoints.Count - 2].Latitude == workAddress.Latitude) && (altDriveReportPoints[altDriveReportPoints.Count - 2].Longitude == workAddress.Longitude))) { toSubtractHomeRule += homeWorkDistance; } // Subtract. toSubtractAltRule = altToSubtract1 + altToSubtract2; } //End NDK if ((report.StartsAtHome || report.EndsAtHome) && !report.FourKmRule) { report.IsExtraDistance = true; } double drivenDistance = report.Distance; if (!report.IsFromApp) { // In case the report is not from app then get distance from the supplied route. drivenDistance = drivenRoute.Length; } //Adjust distance based on FourKmRule and if user start and/or ends at home //var correctDistance = drivenDistance - toSubtract; var correctDistance = drivenDistance - (toSubtractFourKmRule + toSubtractHomeRule + toSubtractAltRule); //Set distance to corrected report.Distance = correctDistance; if (!report.IsFromApp) { //Get RouteGeometry from driven route if the report is not from app. If it is from App then RouteGeometry is already set. report.RouteGeometry = drivenRoute.GeoPoints; } break; } case KilometerAllowance.CalculatedWithoutExtraDistance: { report.Distance = drivenRoute.Length; //Save RouteGeometry report.RouteGeometry = drivenRoute.GeoPoints; break; } case KilometerAllowance.Read: { if ((report.StartsAtHome || report.EndsAtHome) && !report.FourKmRule) { report.IsExtraDistance = true; } //Take distance from report var manuallyProvidedDrivenDistance = report.Distance; //report.Distance = manuallyProvidedDrivenDistance - toSubtract; report.Distance = manuallyProvidedDrivenDistance - toSubtractFourKmRule - toSubtractHomeRule; break; } default: { throw new Exception("No calculation method provided"); } } //Calculate the actual amount to reimburse if (report.Distance < 0) { report.Distance = 0; } // Multiply the distance by two if the report is a return trip if (report.IsRoundTrip == true) { report.Distance *= 2; } CalculateFourKmRuleForReport(report); SetAmountToReimburse(report); return(report); }