Service reminder implemented.

This commit is contained in:
2015-10-21 20:32:37 -04:00
parent e42fcd16fa
commit 93065de77f
26 changed files with 652 additions and 89 deletions
+47 -16
View File
@@ -21,22 +21,6 @@ namespace MileageTraker.Web.Controllers
return View(viewModel); return View(viewModel);
} }
[HttpGet]
[RequireRequestValue("vehicleId")]
public ActionResult Create(string vehicleId)
{
var viewModel = new ServiceReminderViewModel
{
VehicleId = vehicleId,
};
var vehicle = DataService.GetVehicle(vehicleId);
if (vehicle.CurrentOdometer.HasValue)
viewModel.TargetOdometer = (int) (Math.Ceiling((decimal) ((vehicle.CurrentOdometer.Value + 3000)/1000))*1000);
return View(viewModel);
}
public ActionResult Delete(int id) public ActionResult Delete(int id)
{ {
var serviceReminder = DataService.GetServiceReminder(id); var serviceReminder = DataService.GetServiceReminder(id);
@@ -45,6 +29,24 @@ namespace MileageTraker.Web.Controllers
return RedirectToAction("Index", new { vehicleId }); return RedirectToAction("Index", new { vehicleId });
} }
[HttpGet]
[RequireRequestValue("vehicleId")]
public ActionResult Create(string vehicleId)
{
var vehicle = DataService.GetVehicle(vehicleId);
var viewModel = new ServiceReminderViewModel
{
VehicleId = vehicleId,
CurrentOdometer = vehicle.CurrentOdometer
};
if (vehicle.CurrentOdometer.HasValue)
viewModel.TargetOdometer = vehicle.CurrentOdometer.Value + 4000;
return View(viewModel);
}
[HttpPost] [HttpPost]
[ActionLog] [ActionLog]
public ActionResult Create(ServiceReminderViewModel viewModel) public ActionResult Create(ServiceReminderViewModel viewModel)
@@ -54,6 +56,7 @@ namespace MileageTraker.Web.Controllers
var serviceReminder = viewModel.GetServiceReminder(); var serviceReminder = viewModel.GetServiceReminder();
serviceReminder.Vehicle = DataService.GetVehicle(viewModel.VehicleId); serviceReminder.Vehicle = DataService.GetVehicle(viewModel.VehicleId);
DataService.AddServiceReminder(serviceReminder); DataService.AddServiceReminder(serviceReminder);
SetStatusMessage( SetStatusMessage(
@@ -63,5 +66,33 @@ namespace MileageTraker.Web.Controllers
return View(viewModel); return View(viewModel);
} }
[HttpGet]
public ActionResult Edit(int id)
{
var serviceReminder = DataService.GetServiceReminder(id);
var viewModel = new ServiceReminderViewModel(serviceReminder);
return View(viewModel);
}
[HttpPost]
[ActionLog]
public ActionResult Edit(ServiceReminderViewModel viewModel)
{
if (ModelState.IsValid)
{
var serviceReminder = viewModel.GetServiceReminder();
serviceReminder.Vehicle = DataService.GetVehicle(viewModel.VehicleId);
DataService.UpdateServiceReminder(serviceReminder);
SetStatusMessage(
string.Format("Service Reminder at {0} miles updated", viewModel.TargetOdometer), StatusType.Success);
return RedirectToAction("Index", new {vehicleId = viewModel.VehicleId});
}
return View(viewModel);
}
} }
} }
+5 -1
View File
@@ -13,7 +13,11 @@ namespace MileageTraker.Web.Controllers
{ {
public ViewResult Index(bool inactive = false) public ViewResult Index(bool inactive = false)
{ {
var vehicles = DataService.GetVehicles().Where(v => inactive == (v.InactiveDate.HasValue && v.InactiveDate.Value < DateTime.Today.AddDays(1))); var vehicles =
(from v in DataService.GetVehicles().ToList()
where inactive == (v.InactiveDate.HasValue && v.InactiveDate.Value < DateTime.Today.AddDays(1))
select new VehicleViewModel(v)).ToList();
var viewModel = new VehicleResultsViewModel(vehicles, inactive); var viewModel = new VehicleResultsViewModel(vehicles, inactive);
return View(viewModel); return View(viewModel);
} }
+100 -5
View File
@@ -1,9 +1,12 @@
using System; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Web.Mvc; using System.Web.Mvc;
using MileageTraker.Web.Attributes; using MileageTraker.Web.Attributes;
using MileageTraker.Web.DAL; using MileageTraker.Web.DAL;
using MileageTraker.Web.Models;
using MileageTraker.Web.Utility; using MileageTraker.Web.Utility;
using MileageTraker.Web.ViewModels;
using MileageTraker.Web.ViewModels.ServiceReminder;
using MileageTraker.Web.ViewModels.VehicleService; using MileageTraker.Web.ViewModels.VehicleService;
namespace MileageTraker.Web.Controllers namespace MileageTraker.Web.Controllers
@@ -23,10 +26,16 @@ namespace MileageTraker.Web.Controllers
var vehicleServices = DataService.FilterVehicleServices(DataService.GetVehicleServices(), query).ToList(); var vehicleServices = DataService.FilterVehicleServices(DataService.GetVehicleServices(), query).ToList();
var upcomingServiceReminders =
DataService.GetUpcomingServiceReminders().ToList()
.Select(sr => new ServiceReminderViewModel(sr)).ToList();
upcomingServiceReminders.Sort();
var viewModel = new VehicleServiceResultsViewModel( var viewModel = new VehicleServiceResultsViewModel(
vehicleServices.Select(s => new VehicleServiceViewModel(s)), vehicleServices.Select(s => new VehicleServiceViewModel(s)),
query, upcomingServiceReminders,
CustomExtensions.YearMonthList(validVehicleServiceYearMonths)); query,
CustomExtensions.YearMonthList(validVehicleServiceYearMonths));
return View(viewModel); return View(viewModel);
} }
@@ -78,18 +87,104 @@ namespace MileageTraker.Web.Controllers
{ {
var vehicleService = viewModel.GetVehicleService(); var vehicleService = viewModel.GetVehicleService();
vehicleService.Vehicle = DataService.GetVehicle(viewModel.VehicleId); vehicleService.Vehicle = DataService.GetVehicle(viewModel.VehicleId);
DataService.AddVehicleService(vehicleService); DataService.AddVehicleService(vehicleService);
SetStatusMessage( SetStatusMessage(
string.Format("Vehicle Service for vehicle {0} created", viewModel.VehicleId), StatusType.Success); string.Format("Vehicle Service for vehicle {0} created", viewModel.VehicleId), StatusType.Success);
return RedirectToAction("UpdateServiceReminders", new {vehicleId = viewModel.VehicleId});
}
return View(viewModel);
}
[HttpGet]
public ActionResult UpdateServiceReminders(string vehicleId)
{
var vehicle = DataService.GetVehicle(vehicleId);
var viewModel = new UpdateServiceRemindersViewModel { VehicleId = vehicleId };
RefreshServiceReminderViewModel(viewModel, vehicle, true);
if (vehicle.CurrentOdometer.HasValue)
viewModel.TargetOdometer = vehicle.CurrentOdometer.Value + 4000;
return View(viewModel);
}
[HttpPost]
[ActionLog]
public ActionResult UpdateServiceReminders(UpdateServiceRemindersViewModel viewModel)
{
var vehicle = DataService.GetVehicle(viewModel.VehicleId);
RefreshServiceReminderViewModel(viewModel, vehicle); // this data doesn't get posted back
if (ModelState.IsValid)
{
var serviceReminder = viewModel.GetServiceReminder();
var status = new List<string>();
// handle the new service reminder
if (serviceReminder != null)
{
serviceReminder.Vehicle = vehicle;
DataService.AddServiceReminder(serviceReminder);
status.Add(string.Format("Service Reminder at {0} miles created", viewModel.TargetOdometer));
}
// handle any deletion
if (viewModel.DeleteServiceReminders != null
&& viewModel.DeleteServiceReminders.Selected != null
&& viewModel.DeleteServiceReminders.Selected.Length > 0)
{
var serviceReminders =
(from sr in vehicle.ServiceReminders
select new { format = UpdateServiceRemindersViewModel.FormatServiceReminder(sr), id = sr.ServiceReminderId })
.ToDictionary(o => o.format);
foreach (var selected in viewModel.DeleteServiceReminders.Selected)
{
DataService.DeleteServiceReminder(serviceReminders[selected].id);
}
status.Add(string.Format("Selected {0} service reminders deleted", viewModel.DeleteServiceReminders.Selected.Count()));
}
if (status.Count > 0)
{
SetStatusMessage(string.Join(", ", status), StatusType.Success);
}
return RedirectToAction("Index"); return RedirectToAction("Index");
} }
return View(viewModel); return View(viewModel);
} }
private void RefreshServiceReminderViewModel(
UpdateServiceRemindersViewModel viewModel, Vehicle vehicle, bool setDefaultSelectedServiceReminders = false)
{
if (viewModel.DeleteServiceReminders == null)
viewModel.DeleteServiceReminders = new CheckBoxViewModel();
var existingServiceReminders =
(from sr in vehicle.ServiceReminders
select UpdateServiceRemindersViewModel.FormatServiceReminder(sr)).ToArray();
viewModel.DeleteServiceReminders.Available = existingServiceReminders;
viewModel.CurrentOdometer = vehicle.CurrentOdometer;
if (vehicle.CurrentOdometer.HasValue && setDefaultSelectedServiceReminders)
{
viewModel.DeleteServiceReminders.Selected =
(from sr in vehicle.ServiceReminders
where sr.TargetOdometer <= vehicle.CurrentOdometer.Value
select UpdateServiceRemindersViewModel.FormatServiceReminder(sr)).ToArray();
}
}
public ActionResult Edit(int id) public ActionResult Edit(int id)
{ {
var vehicleService = DataService.GetVehicleService(id); var vehicleService = DataService.GetVehicleService(id);
+23 -1
View File
@@ -407,7 +407,7 @@ namespace MileageTraker.Web.DAL
_db.SaveChanges(); _db.SaveChanges();
} }
public IEnumerable<Vehicle> GetVehicles() public IQueryable<Vehicle> GetVehicles()
{ {
var vehicles = _db.Vehicles; var vehicles = _db.Vehicles;
return vehicles; return vehicles;
@@ -901,6 +901,17 @@ namespace MileageTraker.Web.DAL
return _db.ServiceReminders.Find(id); return _db.ServiceReminders.Find(id);
} }
public ServiceReminder FindDuplicateServiceReminder(string vehicleId, int targetOdometer, string description)
{
return
(from sr in _db.ServiceReminders
where
sr.Vehicle.VehicleId == vehicleId &&
sr.TargetOdometer == targetOdometer &&
sr.Description == description
select sr).FirstOrDefault();
}
public void DeleteServiceReminder(int id) public void DeleteServiceReminder(int id)
{ {
var serviceReminder = _db.ServiceReminders.Find(id); var serviceReminder = _db.ServiceReminders.Find(id);
@@ -909,6 +920,17 @@ namespace MileageTraker.Web.DAL
_db.SaveChanges(); _db.SaveChanges();
} }
public IQueryable<ServiceReminder> GetUpcomingServiceReminders()
{
const int mileageThreshold = 500;
return
from sr in _db.ServiceReminders
where
sr.Vehicle.CurrentOdometer.HasValue
&& sr.Vehicle.CurrentOdometer.Value > (sr.TargetOdometer - mileageThreshold)
select sr;
}
#endregion #endregion
} }
} }
+2 -1
View File
@@ -12,7 +12,8 @@ namespace MileageTraker.Web.Models
public virtual Vehicle Vehicle { get; set; } public virtual Vehicle Vehicle { get; set; }
[InputSize("small")] [InputSize("small")]
public int TargetOdometer { get; set; } [Range(1, 500000, ErrorMessage = "Between 1 and 500k")]
public int TargetOdometer { get; set; }
[StringLength(64)] [StringLength(64)]
public string Description { get; set; } public string Description { get; set; }
+5 -2
View File
@@ -5,6 +5,8 @@
$('#page-match-status').html('<span class="label label-warning"><i class="fa fa-spinner fa-spin"></i> Matching In Progress</span> for ' + total + ' fuel logs. <strong>Keep page open until complete.</strong>'); $('#page-match-status').html('<span class="label label-warning"><i class="fa fa-spinner fa-spin"></i> Matching In Progress</span> for ' + total + ' fuel logs. <strong>Keep page open until complete.</strong>');
$('#page-match-status').after('<div class="progress progress-striped active"><div class="bar" style="width:0%"></div><div>'); $('#page-match-status').after('<div class="progress progress-striped active"><div class="bar" style="width:0%"></div><div>');
$(".match-status a").addClass('pull-right');
submitNext(); submitNext();
var unmatchedCount = 0; var unmatchedCount = 0;
var errorCount = 0; var errorCount = 0;
@@ -41,10 +43,11 @@
} }
$('.match-message', $row).text(result.Message); $('.match-message', $row).text(result.Message);
} }
if (result.Action != undefined && result.Action != null) { if (result.Action != undefined && result.Action != null) {
$('.match-status', $row).append(" " + result.Action); $('.match-status', $row).append(" " + result.Action);
var $action = $("a[matchcount]", $row); $("a", $row).addClass('pull-right');
matchCountFunc.apply($action); matchCountFunc.apply($("a[matchcount]", $row));
} }
submitNext(); submitNext();
+78 -11
View File
@@ -75,7 +75,7 @@ $(function () {
var $recentLogs = $("#RecentLogs"); var $recentLogs = $("#RecentLogs");
if ($recentLogs.length > 0) { if ($recentLogs.length > 0) {
$.ajax({ $.ajax({
url: "/FuelLog/RecentLogs", url: "/CreateLog/RecentLogs",
success: function (data) { success: function (data) {
$recentLogs.append(data); $recentLogs.append(data);
} }
@@ -83,12 +83,69 @@ $(function () {
} }
}); });
/**
Ability to run the defered promises in sequence
*/
(function ($) {
"use strict";
var copy = function (a) {
return Array.prototype.slice.call(a);
};
/**
Handle a sequence of methods, stopping on failure by default
@param Array<Function> chain List of methods to execute. Non-deferred return values will be treated as successful deferreds.
@param Boolean continueOnFailure Continue executing even if one of the returned deferreds fails.
@returns Deferred
*/
$.sequence = function (chain, continueOnFailure) {
var handleStep, handleResult,
steps = copy(chain),
def = new $.Deferred(),
defs = [],
results = [];
handleStep = function () {
if (!steps.length) {
def.resolveWith(defs, [results]);
return;
}
var step = steps.shift(),
result = step; // used to be step();, but we're already dealing with promises
handleResult(
$.when(result).always(function () {
defs.push(this);
}).done(function () {
results.push({ resolved: copy(arguments) });
}).fail(function () {
results.push({ rejected: copy(arguments) });
})
);
};
handleResult = continueOnFailure ?
function (result) {
result.always(function () {
handleStep();
});
} :
function (result) {
result.done(handleStep)
.fail(function () {
def.rejectWith(defs, [results]);
});
};
handleStep();
return def.promise();
};
}(this.jQuery));
var matchCountFunc = function() { var matchCountFunc = function() {
var $link = $(this); var $link = $(this);
var url = $link.attr("matchcount"); var url = $link.attr("matchcount");
$link.append(' <span class="badge"><i class="fa fa-spinner fa-spin"></i></span>');
return $.ajax({ return $.ajax({
url: url, url: url,
success: function(matchcount) { success: function (matchcount) {
$('span', $link).remove();
if (matchcount > 0) { if (matchcount > 0) {
$link.append(" <span class='badge badge-info'>" + matchcount + "</span>"); $link.append(" <span class='badge badge-info'>" + matchcount + "</span>");
} else { } else {
@@ -101,7 +158,7 @@ var matchCountFunc = function() {
// add get match count for all the current items // add get match count for all the current items
$(function () { $(function () {
var $requests = $("a[matchcount]").map(matchCountFunc); var $requests = $("a[matchcount]").map(matchCountFunc);
$.when.apply($, $requests); $.sequence($requests);
}); });
$(function() { $(function() {
@@ -124,7 +181,7 @@ $(function() {
var idNavActiveRegex = { var idNavActiveRegex = {
'fuellog-nav': /\/fuellog/i, 'fuellog-nav': /\/fuellog/i,
'log-nav': /\/log/i, 'log-nav': /\/log/i,
'vehicle-nav': /\/vehicle/i, 'vehicle-nav': /\/vehicle|\/servicereminder/i,
'user-nav': /\/user/i, 'user-nav': /\/user/i,
'config-nav': /\/City|\/Purpose/i 'config-nav': /\/City|\/Purpose/i
}; };
@@ -142,23 +199,33 @@ $(function() {
function addButtonIcons () { function addButtonIcons () {
var textToIcon = { var textToIcon = {
'Edit': 'edit', 'Enter Log': 'plus',
'Edit': 'edit',
'Filter': 'filter', 'Filter': 'filter',
'Details' : 'zoom-in', 'Details': 'info-circle',
'Delete': 'trash', 'Delete': 'trash',
'Add': 'plus', 'Add': 'plus',
'Export': 'download', 'Export': 'download',
'Import': 'upload', 'Import': 'upload',
'Driver Mileage': 'user', 'Driver Mileage': 'user',
'Vehicle Mileage': 'car', 'Vehicle Mileage': 'car',
'Show Active': 'ok-circle', 'Show Active': 'check-circle',
'Show Inactive': 'ban-circle', 'Show Inactive': 'ban',
'Set Inactive' : 'ban-circle', 'Set Inactive' : 'ban',
'Reactivate' : 'ok-circle' 'Reactivate': 'check-circle',
'Config': 'cog',
'Cities': 'map',
'Purposes': 'arrow-right',
'Vehicle Service': 'wrench',
'Vehicle': 'car',
'Reminder': 'clock-o',
'Fuel Logs': 'tachometer',
'Users': 'user',
'Logs': 'road'
}; };
$.each(textToIcon, function(text, icon) { $.each(textToIcon, function(text, icon) {
$("a:contains('" + text + "'):not(:has(i))") $("a:contains('" + text + "'):not(:has(i))")
.prepend('<i class="icon-' + icon + '" /> '); .prepend('<i class="fa fa-'+ icon +'"></i> ');
}); });
$(".navbar-inverse a[title='Manage']:not(:has(i))") $(".navbar-inverse a[title='Manage']:not(:has(i))")
@@ -1,11 +1,14 @@
using System.ComponentModel.DataAnnotations; using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Web.Mvc; using System.Web.Mvc;
using AutoMapper; using AutoMapper;
using MileageTraker.Web.Attributes; using MileageTraker.Web.Attributes;
using MileageTraker.Web.DAL;
namespace MileageTraker.Web.ViewModels.ServiceReminder namespace MileageTraker.Web.ViewModels.ServiceReminder
{ {
public class ServiceReminderViewModel public class ServiceReminderViewModel : IComparable<ServiceReminderViewModel>, IValidatableObject
{ {
[HiddenInput(DisplayValue = false)] [HiddenInput(DisplayValue = false)]
public int? ServiceReminderId { get; set; } public int? ServiceReminderId { get; set; }
@@ -19,17 +22,28 @@ namespace MileageTraker.Web.ViewModels.ServiceReminder
[InputSize("mini")] [InputSize("mini")]
public string VehicleId { get; set; } public string VehicleId { get; set; }
[HiddenInput(DisplayValue = false)]
public int? CurrentOdometer { get; set; }
[InputSize("small")] [InputSize("small")]
public int TargetOdometer { get; set; } [Range(1, 500000, ErrorMessage = "Between 1 and 500k")]
public int TargetOdometer { get; set; }
[StringLength(64)] [StringLength(64)]
public string Description { get; set; } public string Description { get; set; }
[HiddenInput(DisplayValue = false)]
public bool IsServiceOverdue { get { return ServiceDueInMiles <= 0; } }
[HiddenInput(DisplayValue = false)]
public int ServiceDueInMiles { get { return CurrentOdometer.HasValue ? TargetOdometer - CurrentOdometer.Value : int.MaxValue; } }
static ServiceReminderViewModel() static ServiceReminderViewModel()
{ {
Mapper.CreateMap<ServiceReminderViewModel, Models.ServiceReminder>(); Mapper.CreateMap<ServiceReminderViewModel, Models.ServiceReminder>();
Mapper.CreateMap<Models.ServiceReminder, ServiceReminderViewModel>() Mapper.CreateMap<Models.ServiceReminder, ServiceReminderViewModel>()
.ForMember(dest => dest.VehicleId, opt => opt.MapFrom(src => src.Vehicle.VehicleId)); .ForMember(dest => dest.VehicleId, opt => opt.MapFrom(src => src.Vehicle.VehicleId))
.ForMember(dest => dest.CurrentOdometer, opt => opt.MapFrom(src => src.Vehicle.CurrentOdometer));
} }
public ServiceReminderViewModel(Models.ServiceReminder serviceReminder) public ServiceReminderViewModel(Models.ServiceReminder serviceReminder)
@@ -47,5 +61,32 @@ namespace MileageTraker.Web.ViewModels.ServiceReminder
Mapper.Map(this, serviceReminder); Mapper.Map(this, serviceReminder);
return serviceReminder; return serviceReminder;
} }
public int CompareTo(ServiceReminderViewModel other)
{
return ServiceDueInMiles - other.ServiceDueInMiles;
}
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
using (var dataService = new DataService())
{
var duplicateServiceReminder = dataService.FindDuplicateServiceReminder(VehicleId, TargetOdometer, Description);
if (duplicateServiceReminder != null)
yield return new ValidationResult("Exact duplicate of this reminder already exists");
var vehicle = dataService.GetVehicle(VehicleId);
if (vehicle.InactiveDate.HasValue)
yield return new ValidationResult("Vehicle is inactive, no service reminder permitted");
// no reminders for mileage less than the current odometer
if (vehicle.CurrentOdometer.HasValue && TargetOdometer <= vehicle.CurrentOdometer)
yield return new ValidationResult(
string.Format("Target odometer {0} must be greater than current odometer {1}",
TargetOdometer, vehicle.CurrentOdometer.Value), new[]{"TargetOdometer"});
}
}
} }
} }
@@ -4,10 +4,10 @@ namespace MileageTraker.Web.ViewModels.Vehicle
{ {
public class VehicleResultsViewModel public class VehicleResultsViewModel
{ {
public IEnumerable<Models.Vehicle> Vehicles { get; set; } public IEnumerable<VehicleViewModel> Vehicles { get; set; }
public bool Inactive { get; set; } public bool Inactive { get; set; }
public VehicleResultsViewModel(IEnumerable<Models.Vehicle> vehicles, bool activeInactive) public VehicleResultsViewModel(IEnumerable<VehicleViewModel> vehicles, bool activeInactive)
{ {
Vehicles = vehicles; Vehicles = vehicles;
Inactive = activeInactive; Inactive = activeInactive;
+142
View File
@@ -0,0 +1,142 @@
using System;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Web.Mvc;
using AutoMapper;
using MileageTraker.Web.Attributes;
namespace MileageTraker.Web.ViewModels.Vehicle
{
public class VehicleViewModel
{
[Required]
[InputSize("mini")]
public int Key { get; set; }
[Key]
[Required]
[StringLength(6, MinimumLength = 4, ErrorMessage = "Must be at least a 4 digit number")]
[Display(Name = "EHTRA ID")]
[RegularExpression(@"\d+", ErrorMessage = "Vehicle ID must be all numbers")]
[InputSize("mini")]
public string VehicleId { get; set; }
[Required]
[RegularExpression(@"\d{4}", ErrorMessage = "Must be 4 numbers")]
[InputSize("mini")]
public string ModelYear { get; set; }
[Required]
[InputSize("medium")]
public string Make { get; set; }
[Display(Name = "Model")]
[Required]
[InputSize("medium")]
public string CarModel { get; set; }
[InputSize("small")]
public string Color { get; set; }
[Required]
[RegularExpression(@"Car|Truck|SUV|Van", ErrorMessage = "Must be Car, Truck, SUV, or Van")]
[FormatHint("Car, Truck, SUV or Van")]
[InputSize("mini")]
public string Type { get; set; }
[Required]
[Display(Name = "VIN")]
[RegularExpression(@"[0-9A-HJ-NPR-Z]{17}", ErrorMessage = "VIN must be 17-characters, not including letters I, O or Q")]
[InputSize("large")]
public string Vin { get; set; }
[Required]
[InputSize("small")]
[Currency]
public decimal Price { get; set; }
[Required]
[RegularExpression(@"\d{1,2}/\d{2}", ErrorMessage = "PurDate must be in mm/yy format")]
[InputSize("small")]
[FormatHint("mm/yy")]
public string PurDate { get; set; }
[DataType(DataType.DateTime)]
[DisplayFormat(NullDisplayText = "Currently Active", DataFormatString = @"{0:MM/dd/yyyy}", ApplyFormatInEditMode = true)]
[InputSize("small")]
[FormatHint("mm/dd/yyyy")]
public DateTime? InactiveDate { get; set; }
[Required]
[Display(Name = "Tag#")]
[InputSize("small")]
public string TagNumber { get; set; }
[Required]
[InputSize("medium")]
public string Prog { get; set; }
[RegularExpression(@"Unassigned|[A-Za-z().]+(\s+[A-Za-z().]+)+", ErrorMessage = "Please enter the full name")]
[DisplayFormat(NullDisplayText = "Unassigned")]
[FormatHint("Blank for Unassigned")]
public string Assigned { get; set; }
[InputSize("medium")]
public string Notes { get; set; }
[Display(Name = "Current Odometer", ShortName= "ODO")]
[DisplayFormat(NullDisplayText = "?")]
[InputSize("small")]
public int? CurrentOdometer { get; set; }
[HiddenInput(DisplayValue = true)]
public int? NextServiceOdometer { get; set; }
[HiddenInput(DisplayValue = false)]
public bool IsNextServiceOverdue
{
get { return NextServiceDueInMiles <= 0; }
}
[HiddenInput(DisplayValue = false)]
public int NextServiceDueInMiles
{
get
{
return CurrentOdometer.HasValue && NextServiceOdometer.HasValue
? NextServiceOdometer.Value - CurrentOdometer.Value
: int.MaxValue;
}
}
static VehicleViewModel()
{
Mapper.CreateMap<VehicleViewModel, Models.Vehicle>();
Mapper.CreateMap<Models.Vehicle, VehicleViewModel>()
.ForMember(dest => dest.NextServiceOdometer,
opt => opt.ResolveUsing(v =>
v.ServiceReminders
.OrderBy(s => s.TargetOdometer)
.Select(s => (int?) s.TargetOdometer)
.FirstOrDefault()
));
}
public VehicleViewModel(Models.Vehicle vehicle)
{
Mapper.Map(vehicle, this);
}
public VehicleViewModel()
{
}
public Models.Vehicle GetVehicle()
{
var vehicle = new Models.Vehicle();
Mapper.Map(this, vehicle);
return vehicle;
}
}
}
@@ -0,0 +1,84 @@
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Web.Mvc;
using AutoMapper;
using MileageTraker.Web.Attributes;
using MileageTraker.Web.DAL;
using MileageTraker.Web.ViewModels.ServiceReminder;
namespace MileageTraker.Web.ViewModels.VehicleService
{
public class UpdateServiceRemindersViewModel : IValidatableObject
{
[Display(Name = "Existing Reminders")]
public CheckBoxViewModel DeleteServiceReminders { get; set; }
[HiddenInput(DisplayValue = false)]
public int? ServiceReminderId { get; set; }
[HiddenInput(DisplayValue = false)]
[Required]
[Remote("Exists", "Vehicle", ErrorMessage = "ID not found")]
[StringLength(6, MinimumLength = 4, ErrorMessage = "Must be at least a 4 digit number")]
[Display(Name = "Vehicle ID")]
[RegularExpression(@"\d+", ErrorMessage = "Vehicle ID must be all numbers")]
[InputSize("mini")]
public string VehicleId { get; set; }
[HiddenInput(DisplayValue = false)]
public int? CurrentOdometer { get; set; }
[InputSize("small")]
[Range(1, 500000, ErrorMessage = "Between 1 and 500k")]
public int? TargetOdometer { get; set; }
[StringLength(64)]
public string Description { get; set; }
static UpdateServiceRemindersViewModel()
{
Mapper.CreateMap<UpdateServiceRemindersViewModel, Models.ServiceReminder>();
}
public Models.ServiceReminder GetServiceReminder()
{
if (!TargetOdometer.HasValue || TargetOdometer.Value == 0)
return null;
var serviceReminder = new Models.ServiceReminder();
Mapper.Map(this, serviceReminder);
return serviceReminder;
}
public static string FormatServiceReminder(Models.ServiceReminder serviceReminder)
{
var s = "Target ODO: " + serviceReminder.TargetOdometer;
if (!string.IsNullOrEmpty(serviceReminder.Description))
s += " Description: " + serviceReminder.Description;
return s;
}
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if (!TargetOdometer.HasValue) yield break;
using (var dataService = new DataService())
{
var duplicateServiceReminder = dataService.FindDuplicateServiceReminder(VehicleId, TargetOdometer.Value, Description);
if (duplicateServiceReminder != null)
yield return new ValidationResult("Exact duplicate of this reminder already exists");
var vehicle = dataService.GetVehicle(VehicleId);
if (vehicle.InactiveDate.HasValue)
yield return new ValidationResult("Vehicle is inactive, no service reminder permitted");
// no reminders for mileage less than the current odometer
if (vehicle.CurrentOdometer.HasValue && TargetOdometer <= vehicle.CurrentOdometer)
yield return new ValidationResult(
string.Format("Target odometer {0} must be greater than current odometer {1}",
TargetOdometer, vehicle.CurrentOdometer.Value), new[] {"TargetOdometer"});
}
}
}
}
@@ -1,11 +1,13 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization; using System.Globalization;
using MileageTraker.Web.ViewModels.ServiceReminder;
namespace MileageTraker.Web.ViewModels.VehicleService namespace MileageTraker.Web.ViewModels.VehicleService
{ {
public class VehicleServiceResultsViewModel public class VehicleServiceResultsViewModel
{ {
public IEnumerable<VehicleServiceViewModel> ServiceItems { get; set; } public IEnumerable<VehicleServiceViewModel> ServiceItems { get; set; }
public IList<ServiceReminderViewModel> UpcomingServiceReminders { get; set; }
public Dictionary<string, List<string>> AvailableYearMonths { get; set; } public Dictionary<string, List<string>> AvailableYearMonths { get; set; }
public IEnumerable<string> SelectedYearMonths public IEnumerable<string> SelectedYearMonths
{ {
@@ -24,10 +26,12 @@ namespace MileageTraker.Web.ViewModels.VehicleService
public VehicleServiceResultsViewModel( public VehicleServiceResultsViewModel(
IEnumerable<VehicleServiceViewModel> serviceItems, IEnumerable<VehicleServiceViewModel> serviceItems,
IList<ServiceReminderViewModel> upcomingServiceReminders,
VehicleServiceQueryViewModel query, VehicleServiceQueryViewModel query,
Dictionary<string, List<string>> availableYearMonths) Dictionary<string, List<string>> availableYearMonths)
{ {
ServiceItems = serviceItems; ServiceItems = serviceItems;
UpcomingServiceReminders = upcomingServiceReminders;
AvailableYearMonths = availableYearMonths; AvailableYearMonths = availableYearMonths;
Year = query.Year.HasValue ? query.Year.Value.ToString(CultureInfo.InvariantCulture) : string.Empty; Year = query.Year.HasValue ? query.Year.Value.ToString(CultureInfo.InvariantCulture) : string.Empty;
Month = query.Month.HasValue ? query.Month.Value.ToString(CultureInfo.InvariantCulture) : string.Empty; Month = query.Month.HasValue ? query.Month.Value.ToString(CultureInfo.InvariantCulture) : string.Empty;
@@ -21,8 +21,10 @@ namespace MileageTraker.Web.ViewModels.VehicleService
[DataType(DataType.DateTime)] [DataType(DataType.DateTime)]
[DisplayFormatAttribute(ApplyFormatInEditMode = true, DataFormatString = "{0:d}")] [DisplayFormatAttribute(ApplyFormatInEditMode = true, DataFormatString = "{0:d}")]
[DenyFutureDate(ErrorMessage = "Future date")]
[FormatHint("mm/dd/yyyy")] [FormatHint("mm/dd/yyyy")]
[InputSize("small")] [InputSize("small")]
[Required]
public DateTime? InvoiceDate { get; set; } public DateTime? InvoiceDate { get; set; }
[Required] [Required]
+4 -1
View File
@@ -1,9 +1,11 @@
@model MileageTraker.Web.ViewModels.ServiceReminder.ServiceReminderViewModel @model MileageTraker.Web.ViewModels.ServiceReminder.ServiceReminderViewModel
@{ @{
ViewBag.Title = "Create Vehicle Service Reminder"; ViewBag.Title = "Create Service Reminder";
} }
@Html.Partial("_StatusMessage")
<h2 class="center-content"><i class="fa fa-clock-o"></i> @ViewBag.Title</h2> <h2 class="center-content"><i class="fa fa-clock-o"></i> @ViewBag.Title</h2>
@using (Html.BeginForm("Create", "ServiceReminder", FormMethod.Post, new { @class = "form-horizontal well center-content" })) @using (Html.BeginForm("Create", "ServiceReminder", FormMethod.Post, new { @class = "form-horizontal well center-content" }))
@@ -11,6 +13,7 @@
@Html.Partial("_ValidationSummary") @Html.Partial("_ValidationSummary")
<fieldset> <fieldset>
<legend></legend> <legend></legend>
@Html.DisplayFor(m => m.CurrentOdometer)
@Html.EditorForModel() @Html.EditorForModel()
<div class="form-actions"> <div class="form-actions">
<input type="submit" value="Create" class="btn btn-primary" /> <input type="submit" value="Create" class="btn btn-primary" />
+1 -1
View File
@@ -1,7 +1,7 @@
@model MileageTraker.Web.ViewModels.ServiceReminder.ServiceReminderViewModel @model MileageTraker.Web.ViewModels.ServiceReminder.ServiceReminderViewModel
@{ @{
ViewBag.Title = "Vehicle Service Reminder Details" ; ViewBag.Title = "Service Reminder Details" ;
} }
@Html.Partial("_StatusMessage") @Html.Partial("_StatusMessage")
+4 -3
View File
@@ -1,19 +1,20 @@
@model MileageTraker.Web.ViewModels.ServiceReminder.ServiceReminderViewModel @model MileageTraker.Web.ViewModels.ServiceReminder.ServiceReminderViewModel
@{ @{
ViewBag.Title = "Edit Vehicle Service Reminder"; ViewBag.Title = "Edit Service Reminder";
} }
@Html.Partial("_StatusMessage") @Html.Partial("_StatusMessage")
<h2 class="center-content"><i class="fa fa-clock-o"></i> @ViewBag.Title</h2> <h2 class="center-content"><i class="fa fa-clock-o"></i> @ViewBag.Title</h2>
@using (Html.BeginForm("Edit", "ServiceREminder", FormMethod.Post, new { @class = "form-horizontal well center-content" })) @using (Html.BeginForm("Edit", "ServiceReminder", FormMethod.Post, new { @class = "form-horizontal well center-content" }))
{ {
@Html.Partial("_ValidationSummary") @Html.Partial("_ValidationSummary")
<fieldset> <fieldset>
<legend></legend> <legend></legend>
@Html.EditorForModel() @Html.DisplayFor(m => m.CurrentOdometer)
@Html.EditorForModel()
<div class="form-actions"> <div class="form-actions">
<input type="submit" value="Save" class="btn btn-primary" /> <input type="submit" value="Save" class="btn btn-primary" />
</div> </div>
+5 -3
View File
@@ -1,12 +1,13 @@
@model MileageTraker.Web.ViewModels.ServiceReminder.ServiceReminderResultsViewModel @model MileageTraker.Web.ViewModels.ServiceReminder.ServiceReminderResultsViewModel
@{ @{
ViewBag.Title = "Vehicle Service Reminders for Vehicle Id " + Model.VehicleId; ViewBag.Title = "Service Reminders";
} }
@Html.Partial("_StatusMessage") @Html.Partial("_StatusMessage")
<h2 id="vehicle-title"><i class="fa fa-clock-o"></i> @ViewBag.Title</h2> <h2 class="center-content"><i class="fa fa-clock-o"></i> @ViewBag.Title</h2>
<h4 class="center-content">for Vehicle @Model.VehicleId</h4>
<div class="center-content"> <div class="center-content">
@foreach (var item in Model.ServiceReminderItems) @foreach (var item in Model.ServiceReminderItems)
@@ -16,6 +17,7 @@
</div> </div>
<div class="btn-toolbar center-content well"> <div class="btn-toolbar center-content well">
@Html.ActionLink("Add Service Reminder", "Create", new { vehicleId = Model.VehicleId }, new{@class="btn"}) @Html.ActionLink("Add Reminder", "Create", new { vehicleId = Model.VehicleId }, new{@class="btn"})
@Html.ActionLink("Add Service", "Create", "VehicleService", new { vehicleId = Model.VehicleId }, new { @class = "btn" })
@Html.ActionLink("Vehicle Details", "Details", "Vehicle", new { id = Model.VehicleId }, new{@class="btn"}) @Html.ActionLink("Vehicle Details", "Details", "Vehicle", new { id = Model.VehicleId }, new{@class="btn"})
</div> </div>
@@ -1,7 +1,7 @@
@model MileageTraker.Web.ViewModels.ServiceReminder.ServiceReminderViewModel @model MileageTraker.Web.ViewModels.ServiceReminder.ServiceReminderViewModel
<div class="well"> <div class="well">
<h3>Service Reminder</h3> <h4 class="center-content"><i class="fa fa-clock-o"></i> Service Reminder</h4>
@Html.DisplayForModel() @Html.DisplayForModel()
<div class='btn-toolbar'> <div class='btn-toolbar'>
@Html.ActionLink("Edit", "Edit", new { id = Model.ServiceReminderId }, new { @class = "btn" }) @Html.ActionLink("Edit", "Edit", new { id = Model.ServiceReminderId }, new { @class = "btn" })
+1 -1
View File
@@ -1,5 +1,5 @@
@if (Session["LogPage"] != null) { @if (Session["LogPage"] != null) {
<ul class="no-print breadcrumb"> <ul class="no-print breadcrumb">
<li><a href="@Session["LogPage"]">&larr; Back To Logs</a></li> <li><a href="@Session["LogPage"]"><i class="fa fa-arrow-circle-left"></i> Back To Logs</a></li>
</ul> </ul>
} }
+1 -1
View File
@@ -1,5 +1,5 @@
<ul class="no-print breadcrumb"> <ul class="no-print breadcrumb">
<li> <li>
<a href="@Url.Action("Index", "User")">&larr; Back to Users</a> <a href="@Url.Action("Index", "User")"><i class="fa fa-arrow-circle-left"></i> Back to Users</a>
</li> </li>
</ul> </ul>
+1 -1
View File
@@ -1,5 +1,5 @@
<ul class="no-print breadcrumb"> <ul class="no-print breadcrumb">
<li> <li>
<a href="@Url.Action("Index", "Vehicle")">&larr; Back to Vehicles</a> <a href="@Url.Action("Index", "Vehicle")"><i class="fa fa-arrow-circle-left"></i> Back to Vehicles</a>
</li> </li>
</ul> </ul>
+2 -2
View File
@@ -34,10 +34,10 @@
</a> </a>
<ul class="dropdown-menu"> <ul class="dropdown-menu">
<li> <li>
@Html.ActionLink("View Service Reminders", "Index", "ServiceReminder", new { VehicleId = Model.VehicleId }, null) @Html.ActionLink("View Reminders", "Index", "ServiceReminder", new { VehicleId = Model.VehicleId }, null)
</li> </li>
<li> <li>
@Html.ActionLink("Add Completed Service", "Create", "VehicleService", new { VehicleId = Model.VehicleId }, null) @Html.ActionLink("Add Service", "Create", "VehicleService", new { VehicleId = Model.VehicleId }, null)
</li> </li>
</ul> </ul>
</div> </div>
+20 -22
View File
@@ -13,7 +13,7 @@
<h2 id="vehicle-title"><i class="fa fa-car"></i> @ViewBag.Title</h2> <h2 id="vehicle-title"><i class="fa fa-car"></i> @ViewBag.Title</h2>
<div class="btn-toolbar"> <div class="btn-toolbar">
@Html.ActionLink("Add Another Vehicle", "Create", null, new{@class="btn"}) @Html.ActionLink("Add Vehicle", "Create", null, new{@class="btn"})
@Html.ActionLink("Export All", "Export", null, new { @class = "btn" }) @Html.ActionLink("Export All", "Export", null, new { @class = "btn" })
@Html.ActionLink(Model.Inactive ? "Show Active" : "Show Inactive", "Index", new {inactive = !Model.Inactive}, new { @class = "btn" }) @Html.ActionLink(Model.Inactive ? "Show Active" : "Show Inactive", "Index", new {inactive = !Model.Inactive}, new { @class = "btn" })
</div> </div>
@@ -26,13 +26,7 @@
Ethra Id Ethra Id
</th> </th>
<th> <th>
Model Yr Year, Make, Model
</th>
<th>
Make
</th>
<th>
Model
</th> </th>
<th> <th>
Type Type
@@ -46,9 +40,12 @@
<th> <th>
Assigned Assigned
</th> </th>
<th> <th>
ODO ODO
</th> </th>
<th>
Next Service
</th>
<th></th> <th></th>
</tr> </tr>
@@ -61,13 +58,7 @@
@Html.DisplayTextFor(m => item.VehicleId) @Html.DisplayTextFor(m => item.VehicleId)
</td> </td>
<td> <td>
@Html.DisplayTextFor(m => item.ModelYear) @Html.DisplayTextFor(m => item.ModelYear) @Html.DisplayTextFor(m => item.Make) @Html.DisplayTextFor(m => item.CarModel)
</td>
<td>
@Html.DisplayTextFor(m => item.Make)
</td>
<td>
@Html.DisplayTextFor(m => item.CarModel)
</td> </td>
<td> <td>
<span class="label @item.Color"> <span class="label @item.Color">
@@ -85,13 +76,20 @@
<small class="muted"><em>@Html.DisplayTextFor(m => item.Notes)</em></small> <small class="muted"><em>@Html.DisplayTextFor(m => item.Notes)</em></small>
} }
</td> </td>
<td> <td>
@Html.DisplayTextFor(m => item.CurrentOdometer) @Html.DisplayTextFor(m => item.CurrentOdometer)
</td> </td>
<td>
@Html.DisplayTextFor(m => item.NextServiceOdometer)
@if (item.IsNextServiceOverdue)
{
<span class="badge badge-warning" title="overdue @(-item.NextServiceDueInMiles) miles">!</span>
}
@Html.ActionLink("Reminder", "Index", "ServiceReminder", new { vehicleId = item.VehicleId }, new { @class = "btn btn-mini pull-right" })
</td>
<td> <td>
<div class='btn-group'> <div class='btn-group'>
@Html.ActionLink("Details", "Details", new { id = item.VehicleId }, new { @class = "btn btn-mini" }) @Html.ActionLink("Details", "Details", new { id = item.VehicleId }, new { @class = "btn btn-mini" })
@Html.ActionLink("Svc Reminder", "Index", "ServiceReminder", new { vehicleId = item.VehicleId }, new { @class = "btn btn-mini" })
</div> </div>
</td> </td>
</tr> </tr>
+38 -10
View File
@@ -26,22 +26,50 @@
} }
</div> </div>
<div class="pull-right" style="width:400px">
<h4>Upcoming Services</h4>
<table class="table table-striped table-bordered table-hover table-condensed">
<tr>
<th>Vehicle ID</th>
<th>ODO</th>
<th>Next Service</th>
<th>Description</th>
<th></th>
</tr>
@foreach (var sr in Model.UpcomingServiceReminders)
{
<tr>
<td>@Html.DisplayTextFor(m => sr.VehicleId)</td>
<td>@Html.DisplayTextFor(m => sr.CurrentOdometer)</td>
<td>@Html.DisplayTextFor(m => sr.TargetOdometer)
@if (sr.IsServiceOverdue)
{
<span class="badge badge-warning" title="overdue @(-sr.ServiceDueInMiles) miles">!</span>
}
</td>
<td>@Html.DisplayTextFor(m => sr.Description)</td>
<td>@Html.ActionLink("Add Service", "Create", "VehicleService", new { vehicleId = sr.VehicleId }, new { @class = "btn btn-mini" })</td>
</tr>
}
</table>
</div>
<h2 id="vehicle-title"><i class="fa fa-wrench"></i> @ViewBag.Title</h2> <h2 id="vehicle-title"><i class="fa fa-wrench"></i> @ViewBag.Title</h2>
<div class="btn-toolbar pull-left"> <div class="btn-toolbar pull-left">
@Html.ActionLink("Add Service", "Create", null, new{@class="btn"}) @Html.ActionLink("Add Service", "Create", null, new { @class = "btn" })
@Html.ActionLink("Export", "Export", queryParams, new{@class="btn"}) @Html.ActionLink("Export", "Export", queryParams, new { @class = "btn" })
</div> </div>
@grid.GetHtml(columns: @grid.GetHtml(columns:
grid.Columns( grid.Columns(
grid.Column("InvoiceDate", "Invoice Date", item => item.InvoiceDate.ToString("d")), grid.Column("InvoiceDate", "Invoice Date", item => item.InvoiceDate.ToString("d")),
grid.Column("VehicleID", "Vehicle Id"), grid.Column("VehicleID", "Vehicle Id"),
grid.Column("ServiceCenterName", "Service Center Name"), grid.Column("ServiceCenterName", "Service Center Name"),
grid.Column("Price", "Price"), grid.Column("Price", "Price"),
grid.Column("Description", "Description"), grid.Column("Description", "Description"),
grid.Column(format: grid.Column(format:
@<div class='btn-group'> @<div class='btn-group'>
@Html.ActionLink("Details", "Details", new { id = item.VehicleServiceId }, new { @class = "btn btn-mini" }) @Html.ActionLink("Details", "Details", new { id = item.VehicleServiceId }, new { @class = "btn btn-mini" })
</div>) </div>)
), ),
@@ -0,0 +1,32 @@
@model MileageTraker.Web.ViewModels.VehicleService.UpdateServiceRemindersViewModel
@{
ViewBag.Title = "Update Service Reminders";
}
@Html.Partial("_StatusMessage")
<h2 class="center-content"><i class="fa fa-clock-o"></i> @ViewBag.Title</h2>
<h5 class="center-content">Add the next service for this vehicle and remove existing reminders.</h5>
@using (Html.BeginForm("UpdateServiceReminders", "VehicleService", FormMethod.Post, new { @class = "form-horizontal well center-content" }))
{
@Html.Partial("_ValidationSummary")
@Html.HiddenFor(m => m.VehicleId)
if (Model.DeleteServiceReminders.Available.Count > 0)
{
<fieldset>
<legend>Delete Reminders for this Vehicle?</legend>
@Html.EditorFor(m => m.DeleteServiceReminders)
</fieldset>
}
<fieldset>
<legend>Add a new Reminder?</legend>
@Html.DisplayFor(m => m.CurrentOdometer)
@Html.EditorFor(m => m.TargetOdometer)
@Html.EditorFor(m => m.Description)
</fieldset>
<div class="form-actions">
<input type="submit" value="Update" class="btn btn-primary" />
</div>
}
+3
View File
@@ -146,6 +146,7 @@
<Compile Include="Controllers\AccountController.cs" /> <Compile Include="Controllers\AccountController.cs" />
<Compile Include="Controllers\CityController.cs" /> <Compile Include="Controllers\CityController.cs" />
<Compile Include="Controllers\ControllerBase.cs" /> <Compile Include="Controllers\ControllerBase.cs" />
<Compile Include="ViewModels\VehicleService\UpdateServiceRemindersViewModel.cs" />
<Compile Include="Controllers\FuelLogController.cs" /> <Compile Include="Controllers\FuelLogController.cs" />
<Compile Include="Controllers\ServiceReminderController.cs" /> <Compile Include="Controllers\ServiceReminderController.cs" />
<Compile Include="Controllers\VehicleServiceController.cs" /> <Compile Include="Controllers\VehicleServiceController.cs" />
@@ -268,6 +269,7 @@
<Compile Include="ViewModels\VehicleService\VehicleServiceQueryViewModel.cs" /> <Compile Include="ViewModels\VehicleService\VehicleServiceQueryViewModel.cs" />
<Compile Include="ViewModels\VehicleService\VehicleServiceResultsViewModel.cs" /> <Compile Include="ViewModels\VehicleService\VehicleServiceResultsViewModel.cs" />
<Compile Include="ViewModels\VehicleService\VehicleServiceViewModel.cs" /> <Compile Include="ViewModels\VehicleService\VehicleServiceViewModel.cs" />
<Compile Include="ViewModels\Vehicle\VehicleViewModel.cs" />
<Compile Include="ViewModels\Vehicle\VehicleResultsViewModel.cs" /> <Compile Include="ViewModels\Vehicle\VehicleResultsViewModel.cs" />
<Compile Include="ViewModels\SelectListViewModel.cs" /> <Compile Include="ViewModels\SelectListViewModel.cs" />
<Compile Include="ViewModels\User\ExportUserViewModel.cs" /> <Compile Include="ViewModels\User\ExportUserViewModel.cs" />
@@ -350,6 +352,7 @@
<Content Include="Views\ServiceReminder\Edit.cshtml" /> <Content Include="Views\ServiceReminder\Edit.cshtml" />
<Content Include="Views\ServiceReminder\Index.cshtml" /> <Content Include="Views\ServiceReminder\Index.cshtml" />
<Content Include="Views\ServiceReminder\ServiceReminderViewModel.cshtml" /> <Content Include="Views\ServiceReminder\ServiceReminderViewModel.cshtml" />
<Content Include="Views\VehicleService\UpdateServiceReminders.cshtml" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Content Include="Content\Account.Login.css" /> <Content Include="Content\Account.Login.css" />