diff --git a/Controllers/APIController.cs b/Controllers/APIController.cs index 4c008cd..289bcbf 100644 --- a/Controllers/APIController.cs +++ b/Controllers/APIController.cs @@ -22,10 +22,13 @@ namespace CarCareTracker.Controllers private readonly IReminderRecordDataAccess _reminderRecordDataAccess; private readonly IUpgradeRecordDataAccess _upgradeRecordDataAccess; private readonly IOdometerRecordDataAccess _odometerRecordDataAccess; + private readonly IUserAccessDataAccess _userAccessDataAccess; + private readonly IUserRecordDataAccess _userRecordDataAccess; private readonly IReminderHelper _reminderHelper; private readonly IGasHelper _gasHelper; private readonly IUserLogic _userLogic; private readonly IFileHelper _fileHelper; + private readonly IMailHelper _mailHelper; public APIController(IVehicleDataAccess dataAccess, IGasHelper gasHelper, IReminderHelper reminderHelper, @@ -37,6 +40,9 @@ namespace CarCareTracker.Controllers IReminderRecordDataAccess reminderRecordDataAccess, IUpgradeRecordDataAccess upgradeRecordDataAccess, IOdometerRecordDataAccess odometerRecordDataAccess, + IUserAccessDataAccess userAccessDataAccess, + IUserRecordDataAccess userRecordDataAccess, + IMailHelper mailHelper, IFileHelper fileHelper, IUserLogic userLogic) { @@ -49,6 +55,9 @@ namespace CarCareTracker.Controllers _reminderRecordDataAccess = reminderRecordDataAccess; _upgradeRecordDataAccess = upgradeRecordDataAccess; _odometerRecordDataAccess = odometerRecordDataAccess; + _userAccessDataAccess = userAccessDataAccess; + _userRecordDataAccess = userRecordDataAccess; + _mailHelper = mailHelper; _gasHelper = gasHelper; _reminderHelper = reminderHelper; _userLogic = userLogic; @@ -428,12 +437,65 @@ namespace CarCareTracker.Controllers } [Authorize(Roles = nameof(UserData.IsRootUser))] [HttpGet] + [Route("/api/vehicle/reminders/send")] + public IActionResult SendReminders(List urgencies) + { + var vehicles = _dataAccess.GetVehicles(); + List operationResponses = new List(); + foreach(Vehicle vehicle in vehicles) + { + var vehicleId = vehicle.Id; + //get reminders + var currentMileage = GetMaxMileage(vehicleId); + var reminders = _reminderRecordDataAccess.GetReminderRecordsByVehicleId(vehicleId); + var results = _reminderHelper.GetReminderRecordViewModels(reminders, currentMileage, DateTime.Now).OrderByDescending(x => x.Urgency).ToList(); + results.RemoveAll(x => !urgencies.Contains(x.Urgency)); + if (!results.Any()) + { + continue; + } + //get list of recipients. + var userIds = _userAccessDataAccess.GetUserAccessByVehicleId(vehicleId).Select(x => x.Id.UserId); + List emailRecipients = new List(); + foreach (int userId in userIds) + { + var userData = _userRecordDataAccess.GetUserRecordById(userId); + emailRecipients.Add(userData.EmailAddress); + }; + if (!emailRecipients.Any()) + { + continue; + } + var result = _mailHelper.NotifyUserForReminders(vehicle, emailRecipients, results); + operationResponses.Add(result); + } + if (operationResponses.All(x => x.Success)) + { + return Json(new OperationResponse { Success = true, Message = "Emails sent" }); + } else if (operationResponses.All(x => !x.Success)) + { + return Json(new OperationResponse { Success = false, Message = "All emails failed, check SMTP settings" }); + } else + { + return Json(new OperationResponse { Success = true, Message = "Some emails sent, some failed, check recipient settings" }); + } + } + [Authorize(Roles = nameof(UserData.IsRootUser))] + [HttpGet] [Route("/api/makebackup")] public IActionResult MakeBackup() { var result = _fileHelper.MakeBackup(); return Json(result); } + [Authorize(Roles = nameof(UserData.IsRootUser))] + [HttpGet] + [Route("/api/demo/restore")] + public IActionResult RestoreDemo() + { + var result = _fileHelper.RestoreBackup("/defaults/demo_default.zip"); + return Json(result); + } private int GetMaxMileage(int vehicleId) { var numbersArray = new List(); diff --git a/Controllers/VehicleController.cs b/Controllers/VehicleController.cs index 83ac9b4..862577d 100644 --- a/Controllers/VehicleController.cs +++ b/Controllers/VehicleController.cs @@ -85,6 +85,7 @@ namespace CarCareTracker.Controllers public IActionResult Index(int vehicleId) { var data = _dataAccess.GetVehicleById(vehicleId); + UpdateRecurringTaxes(vehicleId); return View(data); } [HttpGet] @@ -316,7 +317,6 @@ namespace CarCareTracker.Controllers var vehicleRecords = _gasRecordDataAccess.GetGasRecordsByVehicleId(vehicleId); bool useMPG = _config.GetUserConfig(User).UseMPG; bool useUKMPG = _config.GetUserConfig(User).UseUKMPG; - vehicleRecords = vehicleRecords.OrderBy(x => x.Date).ThenBy(x => x.Mileage).ToList(); var convertedRecords = _gasHelper.GetGasRecordViewModels(vehicleRecords, useMPG, useUKMPG); var exportData = convertedRecords.Select(x => new GasRecordExportModel { @@ -376,7 +376,7 @@ namespace CarCareTracker.Controllers { VehicleId = vehicleId, Date = DateTime.Parse(importModel.Date), - Mileage = int.Parse(importModel.Odometer, NumberStyles.Any), + Mileage = decimal.ToInt32(decimal.Parse(importModel.Odometer, NumberStyles.Any)), Gallons = decimal.Parse(importModel.FuelConsumed, NumberStyles.Any), Notes = string.IsNullOrWhiteSpace(importModel.Notes) ? "" : importModel.Notes }; @@ -420,7 +420,7 @@ namespace CarCareTracker.Controllers { VehicleId = vehicleId, Date = DateTime.Parse(importModel.Date), - Mileage = int.Parse(importModel.Odometer, NumberStyles.Any), + Mileage = decimal.ToInt32(decimal.Parse(importModel.Odometer, NumberStyles.Any)), Description = string.IsNullOrWhiteSpace(importModel.Description) ? $"Service Record on {importModel.Date}" : importModel.Description, Notes = string.IsNullOrWhiteSpace(importModel.Notes) ? "" : importModel.Notes, Cost = decimal.Parse(importModel.Cost, NumberStyles.Any) @@ -433,7 +433,7 @@ namespace CarCareTracker.Controllers { VehicleId = vehicleId, Date = DateTime.Parse(importModel.Date), - Mileage = int.Parse(importModel.Odometer, NumberStyles.Any), + Mileage = decimal.ToInt32(decimal.Parse(importModel.Odometer, NumberStyles.Any)), Notes = string.IsNullOrWhiteSpace(importModel.Notes) ? "" : importModel.Notes }; _odometerRecordDataAccess.SaveOdometerRecordToVehicle(convertedRecord); @@ -463,7 +463,7 @@ namespace CarCareTracker.Controllers { VehicleId = vehicleId, Date = DateTime.Parse(importModel.Date), - Mileage = int.Parse(importModel.Odometer, NumberStyles.Any), + Mileage = decimal.ToInt32(decimal.Parse(importModel.Odometer, NumberStyles.Any)), Description = string.IsNullOrWhiteSpace(importModel.Description) ? $"Repair Record on {importModel.Date}" : importModel.Description, Notes = string.IsNullOrWhiteSpace(importModel.Notes) ? "" : importModel.Notes, Cost = decimal.Parse(importModel.Cost, NumberStyles.Any) @@ -476,7 +476,7 @@ namespace CarCareTracker.Controllers { VehicleId = vehicleId, Date = DateTime.Parse(importModel.Date), - Mileage = int.Parse(importModel.Odometer, NumberStyles.Any), + Mileage = decimal.ToInt32(decimal.Parse(importModel.Odometer, NumberStyles.Any)), Description = string.IsNullOrWhiteSpace(importModel.Description) ? $"Upgrade Record on {importModel.Date}" : importModel.Description, Notes = string.IsNullOrWhiteSpace(importModel.Notes) ? "" : importModel.Notes, Cost = decimal.Parse(importModel.Cost, NumberStyles.Any) @@ -529,8 +529,6 @@ namespace CarCareTracker.Controllers public IActionResult GetGasRecordsByVehicleId(int vehicleId) { var result = _gasRecordDataAccess.GetGasRecordsByVehicleId(vehicleId); - //need it in ascending order to perform computation. - result = result.OrderBy(x => x.Date).ThenBy(x => x.Mileage).ToList(); //check if the user uses MPG or Liters per 100km. var userConfig = _config.GetUserConfig(User); bool useMPG = userConfig.UseMPG; @@ -757,6 +755,34 @@ namespace CarCareTracker.Controllers } return PartialView("_TaxRecords", result); } + private void UpdateRecurringTaxes(int vehicleId) + { + var result = _taxRecordDataAccess.GetTaxRecordsByVehicleId(vehicleId); + var recurringFees = result.Where(x => x.IsRecurring); + if (recurringFees.Any()) + { + foreach(TaxRecord recurringFee in recurringFees) + { + var newDate = recurringFee.Date.AddMonths((int)recurringFee.RecurringInterval); + if (DateTime.Now > newDate){ + recurringFee.IsRecurring = false; + var newRecurringFee = new TaxRecord() + { + VehicleId = recurringFee.VehicleId, + Date = newDate, + Description = recurringFee.Description, + Cost = recurringFee.Cost, + IsRecurring = true, + Notes = recurringFee.Notes, + RecurringInterval = recurringFee.RecurringInterval, + Files = recurringFee.Files + }; + _taxRecordDataAccess.SaveTaxRecordToVehicle(recurringFee); + _taxRecordDataAccess.SaveTaxRecordToVehicle(newRecurringFee); + } + } + } + } [HttpPost] public IActionResult SaveTaxRecordToVehicleId(TaxRecordInput taxRecord) { @@ -783,6 +809,8 @@ namespace CarCareTracker.Controllers Description = result.Description, Notes = result.Notes, VehicleId = result.VehicleId, + IsRecurring = result.IsRecurring, + RecurringInterval = result.RecurringInterval, Files = result.Files }; return PartialView("_TaxRecordModal", convertedResult); @@ -816,7 +844,7 @@ namespace CarCareTracker.Controllers UpgradeRecordSum = upgradeRecords.Sum(x => x.Cost) }; //get costbymonth - List allCosts = new List(); + List allCosts = StaticHelper.GetBaseLineCosts(); allCosts.AddRange(_reportHelper.GetServiceRecordSum(serviceRecords, 0)); allCosts.AddRange(_reportHelper.GetRepairRecordSum(collisionRecords, 0)); allCosts.AddRange(_reportHelper.GetUpgradeRecordSum(upgradeRecords, 0)); @@ -867,10 +895,17 @@ namespace CarCareTracker.Controllers var userConfig = _config.GetUserConfig(User); var mileageData = _gasHelper.GetGasRecordViewModels(gasRecords, userConfig.UseMPG, userConfig.UseUKMPG); mileageData.RemoveAll(x => x.MilesPerGallon == default); - var monthlyMileageData = mileageData.GroupBy(x => x.MonthId).OrderBy(x => x.Key).Select(x => new CostForVehicleByMonth + var monthlyMileageData = StaticHelper.GetBaseLineCostsNoMonthName(); + monthlyMileageData.AddRange(mileageData.GroupBy(x => x.MonthId).Select(x => new CostForVehicleByMonth { - MonthName = CultureInfo.CurrentCulture.DateTimeFormat.GetMonthName(x.Key), + MonthId = x.Key, Cost = x.Average(y => y.MilesPerGallon) + })); + monthlyMileageData = monthlyMileageData.GroupBy(x => x.MonthId).OrderBy(x => x.Key).Select(x => new CostForVehicleByMonth + { + MonthId = x.Key, + MonthName = CultureInfo.CurrentCulture.DateTimeFormat.GetMonthName(x.Key), + Cost = x.Sum(y=>y.Cost) }).ToList(); viewModel.FuelMileageForVehicleByMonth = monthlyMileageData; return PartialView("_Report", viewModel); @@ -956,7 +991,7 @@ namespace CarCareTracker.Controllers var gasViewModels = _gasHelper.GetGasRecordViewModels(gasRecords, useMPG, useUKMPG); if (gasViewModels.Any()) { - averageMPG = _gasHelper.GetAverageGasMileage(gasViewModels); + averageMPG = _gasHelper.GetAverageGasMileage(gasViewModels, useMPG); } vehicleHistory.MPG = averageMPG; //insert servicerecords @@ -1012,10 +1047,17 @@ namespace CarCareTracker.Controllers mileageData.RemoveAll(x => DateTime.Parse(x.Date).Year != year); } mileageData.RemoveAll(x => x.MilesPerGallon == default); - var monthlyMileageData = mileageData.GroupBy(x => x.MonthId).OrderBy(x => x.Key).Select(x => new CostForVehicleByMonth + var monthlyMileageData = StaticHelper.GetBaseLineCostsNoMonthName(); + monthlyMileageData.AddRange(mileageData.GroupBy(x => x.MonthId).Select(x => new CostForVehicleByMonth { - MonthName = CultureInfo.CurrentCulture.DateTimeFormat.GetMonthName(x.Key), + MonthId = x.Key, Cost = x.Average(y => y.MilesPerGallon) + })); + monthlyMileageData = monthlyMileageData.GroupBy(x => x.MonthId).OrderBy(x => x.Key).Select(x => new CostForVehicleByMonth + { + MonthId = x.Key, + MonthName = CultureInfo.CurrentCulture.DateTimeFormat.GetMonthName(x.Key), + Cost = x.Sum(y => y.Cost) }).ToList(); return PartialView("_MPGByMonthReport", monthlyMileageData); } @@ -1023,7 +1065,7 @@ namespace CarCareTracker.Controllers [HttpPost] public IActionResult GetCostByMonthByVehicle(int vehicleId, List selectedMetrics, int year = 0) { - List allCosts = new List(); + List allCosts = StaticHelper.GetBaseLineCosts(); if (selectedMetrics.Contains(ImportMode.ServiceRecord)) { var serviceRecords = _serviceRecordDataAccess.GetServiceRecordsByVehicleId(vehicleId); @@ -1266,6 +1308,7 @@ namespace CarCareTracker.Controllers public IActionResult GetNotesByVehicleId(int vehicleId) { var result = _noteDataAccess.GetNotesByVehicleId(vehicleId); + result = result.OrderByDescending(x => x.Pinned).ToList(); return PartialView("_Notes", result); } [HttpPost] diff --git a/Enum/ReminderMileageInterval.cs b/Enum/ReminderMileageInterval.cs index 50ba696..824664c 100644 --- a/Enum/ReminderMileageInterval.cs +++ b/Enum/ReminderMileageInterval.cs @@ -14,7 +14,9 @@ FifteenThousandMiles = 15000, TwentyThousandMiles = 20000, ThirtyThousandMiles = 30000, + FortyThousandMiles = 40000, FiftyThousandMiles = 50000, + SixtyThousandMiles = 60000, OneHundredThousandMiles = 100000, OneHundredFiftyThousandMiles = 150000 } diff --git a/Enum/ReminderMonthInterval.cs b/Enum/ReminderMonthInterval.cs index 675949f..dd1d472 100644 --- a/Enum/ReminderMonthInterval.cs +++ b/Enum/ReminderMonthInterval.cs @@ -2,6 +2,7 @@ { public enum ReminderMonthInterval { + OneMonth = 1, ThreeMonths = 3, SixMonths = 6, OneYear = 12, diff --git a/Helper/GasHelper.cs b/Helper/GasHelper.cs index cacad93..2d12758 100644 --- a/Helper/GasHelper.cs +++ b/Helper/GasHelper.cs @@ -5,11 +5,11 @@ namespace CarCareTracker.Helper public interface IGasHelper { List GetGasRecordViewModels(List result, bool useMPG, bool useUKMPG); - string GetAverageGasMileage(List results); + string GetAverageGasMileage(List results, bool useMPG); } public class GasHelper : IGasHelper { - public string GetAverageGasMileage(List results) + public string GetAverageGasMileage(List results, bool useMPG) { var recordWithCalculatedMPG = results.Where(x => x.MilesPerGallon > 0); var minMileage = results.Min(x => x.Mileage); @@ -19,12 +19,18 @@ namespace CarCareTracker.Helper var totalGallonsConsumed = recordWithCalculatedMPG.Sum(x => x.Gallons); var deltaMileage = maxMileage - minMileage; var averageGasMileage = (maxMileage - minMileage) / totalGallonsConsumed; + if (!useMPG) + { + averageGasMileage = 100 / averageGasMileage; + } return averageGasMileage.ToString("F"); } return "0"; } public List GetGasRecordViewModels(List result, bool useMPG, bool useUKMPG) { + //need to order by to get correct results + result = result.OrderBy(x => x.Date).ThenBy(x => x.Mileage).ToList(); var computedResults = new List(); int previousMileage = 0; decimal unFactoredConsumption = 0.00M; diff --git a/Helper/MailHelper.cs b/Helper/MailHelper.cs index 6915f1d..55871d4 100644 --- a/Helper/MailHelper.cs +++ b/Helper/MailHelper.cs @@ -8,6 +8,7 @@ namespace CarCareTracker.Helper { OperationResponse NotifyUserForRegistration(string emailAddress, string token); OperationResponse NotifyUserForPasswordReset(string emailAddress, string token); + OperationResponse NotifyUserForReminders(Vehicle vehicle, List emailAddresses, List reminders); } public class MailHelper : IMailHelper { @@ -60,20 +61,62 @@ namespace CarCareTracker.Helper return new OperationResponse { Success = false, Message = StaticHelper.GenericErrorMessage }; } } - private bool SendEmail(string emailTo, string emailSubject, string emailBody) { + public OperationResponse NotifyUserForReminders(Vehicle vehicle, List emailAddresses, List reminders) + { + if (string.IsNullOrWhiteSpace(mailConfig.EmailServer)) + { + return new OperationResponse { Success = false, Message = "SMTP Server Not Setup" }; + } + if (!emailAddresses.Any()) + { + return new OperationResponse { Success = false, Message = "No recipients could be found" }; + } + if (!reminders.Any()) + { + return new OperationResponse { Success = false, Message = "No reminders could be found" }; + } + string emailSubject = $"Vehicle Reminders From LubeLogger - {DateTime.Now.ToShortDateString()}"; + //construct html table. + string emailBody = $"

{vehicle.Year} {vehicle.Make} {vehicle.Model} #{vehicle.LicensePlate}


"; + foreach(ReminderRecordViewModel reminder in reminders) + { + emailBody += $""; + } + emailBody += "
UrgencyDescription
{reminder.Urgency}{reminder.Description}
"; + try + { + foreach (string emailAddress in emailAddresses) + { + SendEmail(emailAddress, emailSubject, emailBody, true, true); + } + return new OperationResponse { Success = true, Message = "Email Sent!" }; + } catch (Exception ex) + { + return new OperationResponse { Success = false, Message = ex.Message }; + } + } + private bool SendEmail(string emailTo, string emailSubject, string emailBody, bool isBodyHtml = false, bool useAsync = false) { string to = emailTo; string from = mailConfig.EmailFrom; var server = mailConfig.EmailServer; MailMessage message = new MailMessage(from, to); message.Subject = emailSubject; message.Body = emailBody; + message.IsBodyHtml = isBodyHtml; SmtpClient client = new SmtpClient(server); client.EnableSsl = mailConfig.UseSSL; client.Port = mailConfig.Port; client.Credentials = new NetworkCredential(mailConfig.Username, mailConfig.Password); try { - client.Send(message); + if (useAsync) + { + client.SendMailAsync(message, new CancellationToken()); + } + else + { + client.Send(message); + } return true; } catch (Exception ex) diff --git a/Helper/StaticHelper.cs b/Helper/StaticHelper.cs index 96036d2..7d45f6c 100644 --- a/Helper/StaticHelper.cs +++ b/Helper/StaticHelper.cs @@ -1,4 +1,5 @@ using CarCareTracker.Models; +using System.Globalization; namespace CarCareTracker.Helper { @@ -63,5 +64,41 @@ namespace CarCareTracker.Helper } return ""; } + public static List GetBaseLineCosts() + { + return new List() + { + new CostForVehicleByMonth {MonthName = CultureInfo.CurrentCulture.DateTimeFormat.GetMonthName(1), MonthId = 1, Cost = 0M}, + new CostForVehicleByMonth {MonthName = CultureInfo.CurrentCulture.DateTimeFormat.GetMonthName(2), MonthId = 2, Cost = 0M}, + new CostForVehicleByMonth {MonthName = CultureInfo.CurrentCulture.DateTimeFormat.GetMonthName(3), MonthId = 3, Cost = 0M}, + new CostForVehicleByMonth {MonthName = CultureInfo.CurrentCulture.DateTimeFormat.GetMonthName(4), MonthId = 4, Cost = 0M}, + new CostForVehicleByMonth {MonthName = CultureInfo.CurrentCulture.DateTimeFormat.GetMonthName(5), MonthId = 5, Cost = 0M}, + new CostForVehicleByMonth {MonthName = CultureInfo.CurrentCulture.DateTimeFormat.GetMonthName(6), MonthId = 6, Cost = 0M}, + new CostForVehicleByMonth {MonthName = CultureInfo.CurrentCulture.DateTimeFormat.GetMonthName(7), MonthId = 7, Cost = 0M}, + new CostForVehicleByMonth {MonthName = CultureInfo.CurrentCulture.DateTimeFormat.GetMonthName(8), MonthId = 8, Cost = 0M}, + new CostForVehicleByMonth {MonthName = CultureInfo.CurrentCulture.DateTimeFormat.GetMonthName(9), MonthId = 9, Cost = 0M}, + new CostForVehicleByMonth {MonthName = CultureInfo.CurrentCulture.DateTimeFormat.GetMonthName(10), MonthId = 10, Cost = 0M}, + new CostForVehicleByMonth {MonthName = CultureInfo.CurrentCulture.DateTimeFormat.GetMonthName(11), MonthId = 11, Cost = 0M}, + new CostForVehicleByMonth {MonthName = CultureInfo.CurrentCulture.DateTimeFormat.GetMonthName(12), MonthId = 12, Cost = 0M} + }; + } + public static List GetBaseLineCostsNoMonthName() + { + return new List() + { + new CostForVehicleByMonth { MonthId = 1, Cost = 0M}, + new CostForVehicleByMonth {MonthId = 2, Cost = 0M}, + new CostForVehicleByMonth {MonthId = 3, Cost = 0M}, + new CostForVehicleByMonth {MonthId = 4, Cost = 0M}, + new CostForVehicleByMonth {MonthId = 5, Cost = 0M}, + new CostForVehicleByMonth {MonthId = 6, Cost = 0M}, + new CostForVehicleByMonth {MonthId = 7, Cost = 0M}, + new CostForVehicleByMonth {MonthId = 8, Cost = 0M}, + new CostForVehicleByMonth {MonthId = 9, Cost = 0M}, + new CostForVehicleByMonth { MonthId = 10, Cost = 0M}, + new CostForVehicleByMonth { MonthId = 11, Cost = 0M}, + new CostForVehicleByMonth { MonthId = 12, Cost = 0M} + }; + } } } diff --git a/Models/Note.cs b/Models/Note.cs index eb8e59e..f344c25 100644 --- a/Models/Note.cs +++ b/Models/Note.cs @@ -6,5 +6,6 @@ public int VehicleId { get; set; } public string Description { get; set; } public string NoteText { get; set; } + public bool Pinned { get; set; } } } diff --git a/Models/TaxRecord/TaxRecord.cs b/Models/TaxRecord/TaxRecord.cs index 073695f..5a2f1c7 100644 --- a/Models/TaxRecord/TaxRecord.cs +++ b/Models/TaxRecord/TaxRecord.cs @@ -8,6 +8,8 @@ public string Description { get; set; } public decimal Cost { get; set; } public string Notes { get; set; } + public bool IsRecurring { get; set; } = false; + public ReminderMonthInterval RecurringInterval { get; set; } = ReminderMonthInterval.OneYear; public List Files { get; set; } = new List(); } } diff --git a/Models/TaxRecord/TaxRecordInput.cs b/Models/TaxRecord/TaxRecordInput.cs index cbe33c5..764007d 100644 --- a/Models/TaxRecord/TaxRecordInput.cs +++ b/Models/TaxRecord/TaxRecordInput.cs @@ -8,7 +8,18 @@ public string Description { get; set; } public decimal Cost { get; set; } public string Notes { get; set; } + public bool IsRecurring { get; set; } = false; + public ReminderMonthInterval RecurringInterval { get; set; } = ReminderMonthInterval.ThreeMonths; public List Files { get; set; } = new List(); - public TaxRecord ToTaxRecord() { return new TaxRecord { Id = Id, VehicleId = VehicleId, Date = DateTime.Parse(Date), Cost = Cost, Description = Description, Notes = Notes, Files = Files }; } + public TaxRecord ToTaxRecord() { return new TaxRecord { + Id = Id, + VehicleId = VehicleId, + Date = DateTime.Parse(Date), + Cost = Cost, + Description = Description, + Notes = Notes, + IsRecurring = IsRecurring, + RecurringInterval = RecurringInterval, + Files = Files }; } } } diff --git a/Views/API/Index.cshtml b/Views/API/Index.cshtml index b16e47b..317b0e0 100644 --- a/Views/API/Index.cshtml +++ b/Views/API/Index.cshtml @@ -241,6 +241,21 @@ @if (User.IsInRole(nameof(UserData.IsRootUser))) { +
+
+ GET +
+
+ /api/vehicle/reminders/send +
+
+ Send reminder emails out to collaborators based on specified urgency. +
+
+ (must be root user)
+ urgencies[]=[NotUrgent,Urgent,VeryUrgent,PastDue] +
+
GET diff --git a/Views/Home/_Settings.cshtml b/Views/Home/_Settings.cshtml index f899ca1..149570b 100644 --- a/Views/Home/_Settings.cshtml +++ b/Views/Home/_Settings.cshtml @@ -154,7 +154,7 @@
- Version 1.0.7 + Version 1.0.8

Proudly developed in the rural town of Price, Utah by Hargata Softworks. diff --git a/Views/Vehicle/_CostMakeUpReport.cshtml b/Views/Vehicle/_CostMakeUpReport.cshtml index 4f89530..63ed97f 100644 --- a/Views/Vehicle/_CostMakeUpReport.cshtml +++ b/Views/Vehicle/_CostMakeUpReport.cshtml @@ -12,14 +12,14 @@ labels: ["Service Records", "Repairs", "Upgrades", "Tax", "Fuel"], datasets: [ { - label: "Expenses by Category", + label: "Expenses by Type", backgroundColor: ["#003f5c", "#58508d", "#bc5090", "#ff6361", "#ffa600"], data: [ - @Model.ServiceRecordSum, - @Model.CollisionRecordSum, - @Model.UpgradeRecordSum, - @Model.TaxRecordSum, - @Model.GasRecordSum + globalParseFloat('@Model.ServiceRecordSum'), + globalParseFloat('@Model.CollisionRecordSum'), + globalParseFloat('@Model.UpgradeRecordSum'), + globalParseFloat('@Model.TaxRecordSum'), + globalParseFloat('@Model.GasRecordSum') ] } ] diff --git a/Views/Vehicle/_Gas.cshtml b/Views/Vehicle/_Gas.cshtml index f254bc0..25b7dee 100644 --- a/Views/Vehicle/_Gas.cshtml +++ b/Views/Vehicle/_Gas.cshtml @@ -41,7 +41,7 @@ @($"# of Gas Records: {Model.GasRecords.Count()}") @if (Model.GasRecords.Where(x => x.MilesPerGallon > 0).Any()) { - @($"Average Fuel Economy: {gasHelper.GetAverageGasMileage(Model.GasRecords)}") + @($"Average Fuel Economy: {gasHelper.GetAverageGasMileage(Model.GasRecords, useMPG)}") @($"Min Fuel Economy: {Model.GasRecords.Where(y => y.MilesPerGallon > 0)?.Min(x => x.MilesPerGallon).ToString("F") ?? "0"}") @($"Max Fuel Economy: {Model.GasRecords.Max(x => x.MilesPerGallon).ToString("F") ?? "0"}") } diff --git a/Views/Vehicle/_GasCostByMonthReport.cshtml b/Views/Vehicle/_GasCostByMonthReport.cshtml index d08bfd3..7bbe2ee 100644 --- a/Views/Vehicle/_GasCostByMonthReport.cshtml +++ b/Views/Vehicle/_GasCostByMonthReport.cshtml @@ -3,7 +3,7 @@ var barGraphColors = new string[] { "#00876c", "#43956e", "#67a371", "#89b177", "#a9be80", "#c8cb8b", "#e6d79b", "#e4c281", "#e3ab6b", "#e2925b", "#e07952", "#db5d4f" }; var sortedByMPG = Model.OrderBy(x => x.Cost).ToList(); } -@if (Model.Any()) +@if (Model.Where(x=>x.Cost > 0).Any()) {