987 lines
27 KiB
C#
987 lines
27 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Data.Entity;
|
|
using System.Data.Entity.SqlServer;
|
|
using System.Linq;
|
|
using System.Text.RegularExpressions;
|
|
using MileageTraker.Web.Context;
|
|
using MileageTraker.Web.Models;
|
|
using MileageTraker.Web.Utility;
|
|
using MileageTraker.Web.ViewModels;
|
|
using MileageTraker.Web.ViewModels.FuelLog;
|
|
using MileageTraker.Web.ViewModels.Log;
|
|
using MileageTraker.Web.ViewModels.Vehicle;
|
|
using MileageTraker.Web.ViewModels.VehicleService;
|
|
|
|
namespace MileageTraker.Web.DAL
|
|
{
|
|
public class DataService : IDisposable
|
|
{
|
|
private readonly MileageTrakerContext _db = new MileageTrakerContext();
|
|
|
|
public void Dispose()
|
|
{
|
|
_db.Dispose();
|
|
}
|
|
|
|
#region Log
|
|
|
|
public void AddLog(Log log)
|
|
{
|
|
if (FindCityByName(log.CityName) == null)
|
|
throw new CityNotFoundException("City Name '" + log.CityName + "' not found");
|
|
|
|
log.Created = DateTime.Now;
|
|
_db.Logs.Add(log);
|
|
|
|
// update previous log links
|
|
var previousLog = SearchPreviousLog(log);
|
|
log.VehiclePreviousLog = previousLog;
|
|
var nextLog = SearchNextLog(log);
|
|
if (nextLog != null)
|
|
{
|
|
nextLog.VehiclePreviousLog = log;
|
|
nextLog.User = _db.Users.Find(nextLog.User.UserId);
|
|
_db.Entry(nextLog).State = EntityState.Modified;
|
|
}
|
|
|
|
_db.SaveChanges();
|
|
|
|
UpdateCurrentOdometer(log.Vehicle);
|
|
}
|
|
|
|
public void UpdateLog(Log log)
|
|
{
|
|
if (FindCityByName(log.CityName) == null)
|
|
throw new CityNotFoundException("City Name '" + log.CityName + "' not found");
|
|
// note: assumes log is already attached to current context
|
|
|
|
// remove from the list
|
|
var nextLog =
|
|
(from l in _db.Logs
|
|
where l.VehiclePreviousLogId == log.LogId
|
|
select l).FirstOrDefault();
|
|
if (nextLog != null)
|
|
{
|
|
nextLog.VehiclePreviousLogId = log.VehiclePreviousLogId;
|
|
nextLog.User = _db.Users.Find(nextLog.User.UserId);
|
|
_db.Entry(nextLog).State = EntityState.Modified;
|
|
}
|
|
|
|
log.VehiclePreviousLog = null;
|
|
log.VehiclePreviousLogId = null;
|
|
|
|
// add it back in new position
|
|
var previousLog = SearchPreviousLog(log);
|
|
if (previousLog != null)
|
|
log.VehiclePreviousLogId = previousLog.LogId;
|
|
var newNextLog = SearchNextLog(log);
|
|
if (newNextLog != null)
|
|
{
|
|
newNextLog.VehiclePreviousLogId = log.LogId;
|
|
newNextLog.User = _db.Users.Find(newNextLog.User.UserId);
|
|
_db.Entry(newNextLog).State = EntityState.Modified;
|
|
}
|
|
|
|
log.User = _db.Users.Find(log.User.UserId);
|
|
_db.Entry(log).State = EntityState.Modified;
|
|
_db.SaveChanges();
|
|
|
|
UpdateCurrentOdometer(log.Vehicle);
|
|
}
|
|
|
|
public void DeleteLog(int id)
|
|
{
|
|
var log = _db.Logs.Find(id);
|
|
|
|
var nextLog = GetNextLog(log.LogId);
|
|
if (nextLog != null)
|
|
{
|
|
nextLog.VehiclePreviousLog = log.VehiclePreviousLog;
|
|
nextLog.User = _db.Users.Find(nextLog.User.UserId);
|
|
_db.Entry(nextLog).State = EntityState.Modified;
|
|
}
|
|
|
|
// remove the reference to the log from any fuellogs
|
|
foreach (var fuelLog in log.FuelLogs)
|
|
{
|
|
fuelLog.Log = null;
|
|
}
|
|
|
|
var vehicle = log.Vehicle; // save reference to vehicle
|
|
_db.Logs.Remove(log);
|
|
_db.SaveChanges();
|
|
|
|
UpdateCurrentOdometer(vehicle);
|
|
}
|
|
|
|
public IQueryable<Log> GetLogs()
|
|
{
|
|
return _db.Logs;
|
|
}
|
|
|
|
public Log GetLog(int id)
|
|
{
|
|
return _db.Logs.Find(id);
|
|
}
|
|
|
|
public Log GetNextLog(int id)
|
|
{
|
|
return
|
|
(from l in _db.Logs
|
|
where l.VehiclePreviousLogId == id
|
|
select l).FirstOrDefault();
|
|
}
|
|
|
|
public IList<DateTime> GetValidLogMonths()
|
|
{
|
|
var months =
|
|
from l in GetLogs()
|
|
group l by new {l.Date.Year, l.Date.Month}
|
|
into g
|
|
//let dt = new DateTime(g.Key.Year, g.Key.Month, 1)
|
|
select g.Key;
|
|
|
|
var ym =
|
|
from m in months.ToList()
|
|
select new DateTime(m.Year, m.Month, 1);
|
|
|
|
return ym.OrderByDescending(dt => dt).ToList();
|
|
}
|
|
|
|
public IEnumerable<LogIndexViewModel> GetLogIndexViewModels(IQueryable<Log> logs)
|
|
{
|
|
var t =
|
|
from log in logs
|
|
select new { log, log.VehiclePreviousLog };
|
|
return from l in t.ToList()
|
|
select new LogIndexViewModel(l.log, l.VehiclePreviousLog);
|
|
}
|
|
|
|
public IEnumerable<VehicleMileageItem> GetMonthlyVehicleMileageItems(LogQueryViewModel query)
|
|
{
|
|
var items =
|
|
from l in
|
|
from log in FilterLogs(_db.Logs, query)
|
|
let previousLog = log.VehiclePreviousLog
|
|
select new {log, previousLog, miles = (previousLog != null ? log.EndOdometer - previousLog.EndOdometer : 0)}
|
|
group l by l.log.Vehicle
|
|
into g
|
|
let miles = g.Sum(l => l.miles)
|
|
let gasPurchased = g.Sum(l => l.log.GasPurchased)
|
|
where miles > 0 || gasPurchased > 0
|
|
select
|
|
new
|
|
{
|
|
g.Key.VehicleId,
|
|
GasPurchased = gasPurchased,
|
|
Miles = miles,
|
|
g.Key.Prog,
|
|
TripCount = g.Count()
|
|
};
|
|
|
|
return items.ToList().Select(i => new VehicleMileageItem
|
|
{
|
|
VehicleId = i.VehicleId,
|
|
GasPurchased = i.GasPurchased,
|
|
Miles = i.Miles,
|
|
Prog = i.Prog,
|
|
TripCount = i.TripCount
|
|
});
|
|
}
|
|
|
|
public IEnumerable<DriverMileageItem> GetMonthlyDriverMileageItems(LogQueryViewModel query)
|
|
{
|
|
var items =
|
|
from l in
|
|
from log in FilterLogs(_db.Logs, query)
|
|
let previousLog = log.VehiclePreviousLog
|
|
select new { log, previousLog, miles = (previousLog != null ? log.EndOdometer - previousLog.EndOdometer : 0) }
|
|
group l by l.log.User into g
|
|
let vehicleLogs =
|
|
from i in g
|
|
group i by i.log.Vehicle into v
|
|
let vehicle = v.Key
|
|
let vehicleProg = vehicle.Prog
|
|
let vehicleMiles = v.Sum(l => l.miles)
|
|
let vehicleGasPurchased = v.Sum(l => l.log.GasPurchased)
|
|
where vehicleMiles > 0 || vehicleGasPurchased > 0
|
|
select new
|
|
{
|
|
v.Key.VehicleId,
|
|
Prog = vehicleProg,
|
|
Miles = vehicleMiles,
|
|
GasPurchased = vehicleGasPurchased,
|
|
TripCount = v.Count()
|
|
}
|
|
select
|
|
new
|
|
{
|
|
User = g.Key,
|
|
VehicleLogs = vehicleLogs
|
|
};
|
|
|
|
return items.ToList().Select(i => new DriverMileageItem
|
|
{
|
|
DriverName = i.User.FullName,
|
|
VehicleMileageItems = i.VehicleLogs.ToList().Select(v => new VehicleMileageItem
|
|
{
|
|
VehicleId = v.VehicleId,
|
|
Prog = v.Prog,
|
|
Miles = v.Miles,
|
|
GasPurchased = v.GasPurchased,
|
|
TripCount = v.TripCount
|
|
}).ToList()
|
|
});
|
|
}
|
|
|
|
public static IQueryable<Log> FilterLogs(IQueryable<Log> logs, LogQueryViewModel query)
|
|
{
|
|
// date filtering
|
|
if (query.Year.HasValue & query.Month.HasValue)
|
|
{
|
|
var start = new DateTime(query.Year.Value, query.Month.Value, 1);
|
|
var monthRange = query.MonthRange.HasValue ? query.MonthRange.Value : 1;
|
|
var end = start.AddMonths(monthRange);
|
|
logs = logs.Where(l => l.Date >= start && l.Date < end);
|
|
}
|
|
|
|
// log type
|
|
if (query.LogType.HasValue)
|
|
{
|
|
// WTF The specified value is not an instance of type 'Edm.Int32'
|
|
logs = logs.Where(query.LogType.Value.GetEqualsPredicate());
|
|
}
|
|
|
|
// employee name
|
|
if (!String.IsNullOrEmpty(query.EmployeeName))
|
|
{
|
|
logs = logs.Where(l =>
|
|
l.User.FullName == query.EmployeeName
|
|
|| l.User.Username == query.EmployeeName);
|
|
}
|
|
|
|
// vehicle id
|
|
if (!String.IsNullOrEmpty(query.VehicleId))
|
|
{
|
|
logs = logs.Where(l => l.Vehicle.VehicleId == query.VehicleId);
|
|
}
|
|
|
|
return logs;
|
|
}
|
|
|
|
public IEnumerable<Log> GetDuplicateLogs(Log log)
|
|
{
|
|
return
|
|
from dbLog in GetLogs().Where(log.LogType.Enum.GetEqualsPredicate())
|
|
where
|
|
dbLog.Date == log.Date &&
|
|
dbLog.EndOdometer == log.EndOdometer &&
|
|
dbLog.Vehicle.VehicleId == log.Vehicle.VehicleId
|
|
select dbLog;
|
|
}
|
|
|
|
public IEnumerable<Log> GetRecentLogsByUsername(string username)
|
|
{
|
|
return
|
|
(from l in _db.Logs
|
|
where l.User.Username == username
|
|
orderby l.Created descending
|
|
select l)
|
|
.Take(3)
|
|
.ToList();
|
|
}
|
|
|
|
public Log SearchPreviousLog(Log current)
|
|
{
|
|
var vehicleId = current.Vehicle.VehicleId;
|
|
var date = current.Date;
|
|
var endOdometer = current.EndOdometer;
|
|
return SearchPreviousLog(endOdometer, vehicleId, date, current.Created, current.LogId);
|
|
}
|
|
|
|
public Log SearchPreviousLog(int endOdometer, string vehicleId, DateTime date, DateTime created, int? excludeLogId = null)
|
|
{
|
|
return (from pl in _db.Logs
|
|
where pl.Vehicle.VehicleId == vehicleId &&
|
|
((pl.EndOdometer < endOdometer && pl.Date <= date)
|
|
|| (pl.EndOdometer == endOdometer && pl.Date < date)
|
|
|| (pl.EndOdometer == endOdometer && pl.Date == date && pl.Created < created))
|
|
orderby pl.EndOdometer descending, pl.Date descending, pl.Created descending
|
|
select pl)
|
|
.FirstOrDefault(l => !excludeLogId.HasValue || l.LogId != excludeLogId.Value);
|
|
}
|
|
|
|
public Log SearchNextLog(Log current)
|
|
{
|
|
var vehicleId = current.Vehicle.VehicleId;
|
|
var date = current.Date;
|
|
var endOdometer = current.EndOdometer;
|
|
return SearchNextLog(endOdometer, vehicleId, date, current.Created, current.LogId);
|
|
}
|
|
|
|
public Log SearchNextLog(int endOdometer, string vehicleId, DateTime date, DateTime created, int? excludeLogId = null)
|
|
{
|
|
return (from nl in GetLogs()
|
|
where nl.Vehicle.VehicleId == vehicleId &&
|
|
((nl.EndOdometer > endOdometer && nl.Date >= date)
|
|
|| (nl.EndOdometer == endOdometer && nl.Date > date)
|
|
|| (nl.EndOdometer == endOdometer && nl.Date >= date && nl.Created > created))
|
|
orderby nl.EndOdometer ascending, nl.Date ascending, nl.Created ascending
|
|
select nl)
|
|
.FirstOrDefault(l => !excludeLogId.HasValue || l.LogId != excludeLogId.Value);
|
|
}
|
|
|
|
public IEnumerable<PurposeType> GetPurposeTypes()
|
|
{
|
|
return
|
|
(from pt in _db.PurposeTypes
|
|
select pt).OrderBy(pt => pt.SortOrder).ToList();
|
|
}
|
|
|
|
public void AddPurposeType(PurposeType purposeType)
|
|
{
|
|
_db.PurposeTypes.Add(purposeType);
|
|
_db.SaveChanges();
|
|
}
|
|
|
|
public void UpdatePurposeType(PurposeType purposeType)
|
|
{
|
|
_db.Entry(purposeType).State = EntityState.Modified;
|
|
_db.SaveChanges();
|
|
}
|
|
|
|
public PurposeType FindPurposeType(int id)
|
|
{
|
|
return GetPurposeTypes().FirstOrDefault(pt => pt.PurposeTypeId == id);
|
|
}
|
|
|
|
public PurposeType FindPurposeType(string name)
|
|
{
|
|
if (string.IsNullOrEmpty(name))
|
|
return null;
|
|
|
|
var mpt =
|
|
GetPurposeTypes()
|
|
.Select(pt =>
|
|
Tuple.Create(pt.PurposeTypeId,
|
|
Algorithms.Similarity(
|
|
pt.Purpose.ToLowerInvariant(),
|
|
name.ToLowerInvariant())))
|
|
.OrderByDescending(tp => tp.Item2)
|
|
.FirstOrDefault(tp => tp.Item2 > .8);
|
|
|
|
if (mpt != null)
|
|
return FindPurposeType(mpt.Item1);
|
|
return null;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Vehicle
|
|
|
|
public void AddVehicle(Vehicle vehicle)
|
|
{
|
|
if (vehicle.Assigned == "Unassigned")
|
|
vehicle.Assigned = null;
|
|
_db.Vehicles.Add(vehicle);
|
|
_db.SaveChanges();
|
|
}
|
|
|
|
public void UpdateVehicle(Vehicle vehicle)
|
|
{
|
|
if (vehicle.Assigned == "Unassigned")
|
|
vehicle.Assigned = null;
|
|
_db.Entry(vehicle).State = EntityState.Modified;
|
|
_db.SaveChanges();
|
|
}
|
|
|
|
public IQueryable<Vehicle> GetVehicles()
|
|
{
|
|
var vehicles = _db.Vehicles;
|
|
return vehicles;
|
|
}
|
|
|
|
public Vehicle GetVehicle(string id)
|
|
{
|
|
return _db.Vehicles.Find(id);
|
|
}
|
|
|
|
public string GetVehicleIdByTag(string tagNumber)
|
|
{
|
|
var vehicle = GetVehicleByTag(tagNumber);
|
|
if (vehicle != null)
|
|
return vehicle.VehicleId;
|
|
return null;
|
|
}
|
|
|
|
public Vehicle GetVehicleByTag(string tagNumber)
|
|
{
|
|
var vehicle = GetVehicles().FirstOrDefault(v => v.TagNumber == tagNumber);
|
|
if (vehicle != null)
|
|
return vehicle; // exact match, this is optimal for the DB query
|
|
|
|
// no match, normalize the tags, have to get all the vehicles for regex
|
|
var vehicles = GetVehicles().ToList();
|
|
Func<string, string> b = s => Regex.Replace(s.ToLower(), @"-|\s", "");
|
|
vehicle = vehicles.FirstOrDefault(v => b(v.TagNumber) == b(tagNumber));
|
|
|
|
return vehicle;
|
|
}
|
|
|
|
public void UpdateCurrentOdometer(Vehicle vehicle)
|
|
{
|
|
var mostRecentOdometerQuery =
|
|
from log in _db.Logs
|
|
where
|
|
log.Vehicle.VehicleId == vehicle.VehicleId
|
|
orderby log.Date descending, log.EndOdometer descending
|
|
select log;
|
|
var mostRecentOdometer = mostRecentOdometerQuery.FirstOrDefault();
|
|
if (mostRecentOdometer != null && mostRecentOdometer.EndOdometer != vehicle.CurrentOdometer)
|
|
{
|
|
vehicle.CurrentOdometer = mostRecentOdometer.EndOdometer;
|
|
UpdateVehicle(vehicle);
|
|
}
|
|
}
|
|
|
|
public void ValidateOdometerChronology(string vehicleId, int odometer, DateTime date)
|
|
{
|
|
var conflictingLog = GetFirstConflictingOdometerChronologyLog(vehicleId, date, odometer);
|
|
if (conflictingLog != null)
|
|
{
|
|
throw new ChronologicalOrderException(
|
|
String.Format(
|
|
"Odometer of {0} miles on {1:d} conflicts with other logs for vehicle {2}" +
|
|
", including an odometer log of {3} miles on {4:d} reported by {5}.",
|
|
odometer, date, vehicleId, conflictingLog.EndOdometer, conflictingLog.Date, conflictingLog.User.FullName));
|
|
}
|
|
}
|
|
|
|
public Log GetFirstConflictingOdometerChronologyLog(string vehicleId, DateTime date, int odometer)
|
|
{
|
|
var conflictingLogsQuery =
|
|
from log in _db.Logs
|
|
let existingDate = log.Date
|
|
let existingOdometer = log.EndOdometer
|
|
where
|
|
log.Vehicle.VehicleId == vehicleId &&
|
|
// this is also in Utility.Algorithms, but doesn't get emitted to DB as SQL if used in method call
|
|
!(existingDate == date
|
|
|| existingOdometer == odometer
|
|
|| existingDate < date && existingOdometer < odometer
|
|
|| existingDate > date && existingOdometer > odometer)
|
|
orderby existingOdometer descending
|
|
select log;
|
|
|
|
return conflictingLogsQuery.FirstOrDefault();
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region City
|
|
|
|
public string GetCitiesCorrected(string term)
|
|
{
|
|
var termLower = term.ToLower();
|
|
return (from city in GetCities().ToList()
|
|
let cityToLower = city.Name.ToLower()
|
|
let similarity = Algorithms.Similarity(cityToLower, termLower)
|
|
where city.Name.StartsWith(term) || Algorithms.Similarity(cityToLower, termLower) > .8
|
|
select city.Name).FirstOrDefault();
|
|
}
|
|
|
|
public IEnumerable<string> GetCitiesAutocomplete(string term)
|
|
{
|
|
return
|
|
from city in GetCities()
|
|
where city.Name.StartsWith(term)
|
|
select city.Name;
|
|
}
|
|
|
|
public IQueryable<City> GetCities()
|
|
{
|
|
return _db.Cities;
|
|
}
|
|
|
|
public City FindCityByName(string name)
|
|
{
|
|
return _db.Cities.FirstOrDefault(u => name.Equals(u.Name, StringComparison.InvariantCultureIgnoreCase));
|
|
}
|
|
|
|
public void AddCity(City city)
|
|
{
|
|
_db.Cities.Add(city);
|
|
_db.SaveChanges();
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Membership
|
|
|
|
public void AddUser(User user)
|
|
{
|
|
user.Created = DateTime.Now;
|
|
|
|
_db.Users.Add(user);
|
|
|
|
_db.SaveChanges();
|
|
}
|
|
|
|
public void UpdateUser(User user)
|
|
{
|
|
_db.Entry(user).State = EntityState.Modified;
|
|
_db.SaveChanges();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Update only fields not needing extra membership provider support
|
|
/// </summary>
|
|
public void UpdateUserPersonalInfo(User user)
|
|
{
|
|
var original = GetUser(user.UserId);
|
|
|
|
original.Comment = user.Comment;
|
|
original.Email = user.Email;
|
|
original.FullName = user.FullName;
|
|
original.Username = user.Username;
|
|
|
|
UpdateUser(original);
|
|
}
|
|
|
|
public void UpdateUserPassword(Guid userId, string password)
|
|
{
|
|
var user = GetUser(userId);
|
|
user.Password = Crypto.HashPassword(password);
|
|
user.LastPasswordChangedDate = DateTime.Now;
|
|
user.IsLockedOut = false;
|
|
user.PasswordFailuresSinceLastSuccess = 0;
|
|
user.PasswordResetToken = null;
|
|
UpdateUser(user);
|
|
}
|
|
|
|
public void UpdateUserLastActivity(string username)
|
|
{
|
|
var user = FindUserByUsername(username);
|
|
if (user != null)
|
|
{
|
|
user.LastActivityDate = DateTime.Now;
|
|
UpdateUser(user);
|
|
}
|
|
}
|
|
|
|
public IQueryable<User> GetUsers()
|
|
{
|
|
return _db.Users;
|
|
}
|
|
|
|
public User GetUser(Guid guid)
|
|
{
|
|
return _db.Users.Find(guid);
|
|
}
|
|
|
|
public User FindUserByUsername(string username)
|
|
{
|
|
return _db.Users.FirstOrDefault(u => username.Equals(u.Username, StringComparison.InvariantCultureIgnoreCase));
|
|
}
|
|
|
|
public User FindUserByFullName(string fullName)
|
|
{
|
|
return _db.Users.FirstOrDefault(u => fullName.Equals(u.FullName, StringComparison.InvariantCultureIgnoreCase));
|
|
}
|
|
|
|
public User FindUserByEmail(string email)
|
|
{
|
|
return _db.Users.FirstOrDefault(u => email.Equals(u.Email, StringComparison.InvariantCultureIgnoreCase));
|
|
}
|
|
|
|
public IQueryable<Role> GetRoles()
|
|
{
|
|
return _db.Roles;
|
|
}
|
|
|
|
public IEnumerable<string> GetUserFullNamesAutocomplete(string term)
|
|
{
|
|
var termLower = term.ToLower();
|
|
return from name in GetUserFullNames()
|
|
let nameLower = name.ToLower()
|
|
where nameLower.StartsWith(termLower) || Algorithms.Similarity(nameLower, termLower) > .8
|
|
select name;
|
|
}
|
|
|
|
public IEnumerable<string> GetUserFullNames()
|
|
{
|
|
var logNames =
|
|
(from l in _db.Users
|
|
select l.FullName);
|
|
return logNames;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region FuelLog
|
|
|
|
public void AddFuelLog(FuelLog fuelLog)
|
|
{
|
|
_db.FuelLogs.Add(fuelLog);
|
|
_db.SaveChanges();
|
|
}
|
|
|
|
public void AddFuelLogs(IEnumerable<FuelLog> fuelLogs)
|
|
{
|
|
_db.FuelLogs.AddRange(fuelLogs);
|
|
_db.SaveChanges();
|
|
}
|
|
|
|
public void UpdateFuelLog(FuelLog fuelLog)
|
|
{
|
|
_db.Entry(fuelLog).State = EntityState.Modified;
|
|
_db.SaveChanges();
|
|
}
|
|
|
|
public IQueryable<FuelLog> GetFuelLogs()
|
|
{
|
|
return _db.FuelLogs;
|
|
}
|
|
|
|
public FuelLog GetFuelLog(int id)
|
|
{
|
|
return _db.FuelLogs.Find(id);
|
|
}
|
|
|
|
public static IQueryable<FuelLog> FilterFuelLogs(IQueryable<FuelLog> fuelLogs, FuelLogQueryViewModel query)
|
|
{
|
|
// date filtering
|
|
if (query.Year.HasValue & query.Month.HasValue)
|
|
{
|
|
var start = new DateTime(query.Year.Value, query.Month.Value, 1);
|
|
var monthRange = query.MonthRange.HasValue ? query.MonthRange.Value : 1;
|
|
var end = start.AddMonths(monthRange);
|
|
fuelLogs = fuelLogs.Where(l => l.Date >= start && l.Date < end);
|
|
}
|
|
if (query.Unmatched)
|
|
{
|
|
fuelLogs = fuelLogs.Where(l => l.Log == null);
|
|
}
|
|
return fuelLogs;
|
|
}
|
|
|
|
public IEnumerable<FuelLog> GetDuplicateFuelLogs(FuelLog log)
|
|
{
|
|
return
|
|
from dbLog in GetFuelLogs()
|
|
where
|
|
dbLog.Date == log.Date &&
|
|
dbLog.GasPurchased == log.GasPurchased &&
|
|
dbLog.TagNumber == log.TagNumber
|
|
select dbLog;
|
|
}
|
|
|
|
public Log GetMatchingLog(FuelLog fuelLog)
|
|
{
|
|
// add a little wiggle room for the gas - it is common to be off by a couple hundreths
|
|
const double gasRange = .01;
|
|
var gasMax = fuelLog.GasPurchased + gasRange;
|
|
var gasMin = fuelLog.GasPurchased - gasRange;
|
|
|
|
var dateGasVehicleQuery = GetLogs();
|
|
|
|
// matching by Date, Gas Purchased (gallons), and Vehicle
|
|
var vehicle = GetVehicleByTag(fuelLog.TagNumber);
|
|
if (vehicle != null)
|
|
dateGasVehicleQuery = dateGasVehicleQuery.Where(log => log.Vehicle.VehicleId == vehicle.VehicleId);
|
|
|
|
dateGasVehicleQuery = dateGasVehicleQuery
|
|
.Where(log =>
|
|
log.Date.Year == fuelLog.Date.Year &&
|
|
log.Date.Month == fuelLog.Date.Month &&
|
|
log.Date.Day == fuelLog.Date.Day)
|
|
.Where(log => log.GasPurchased <= gasMax && log.GasPurchased >= gasMin);
|
|
|
|
var dateDriverGasQuery
|
|
= GetLogs()
|
|
.Where(log =>
|
|
log.Date.Year == fuelLog.Date.Year &&
|
|
log.Date.Month == fuelLog.Date.Month &&
|
|
log.Date.Day == fuelLog.Date.Day)
|
|
.Where(log => log.User.FullName.Contains(fuelLog.DriverFullName))
|
|
.Where(log => log.GasPurchased <= gasMax && log.GasPurchased >= gasMin);
|
|
|
|
return dateGasVehicleQuery.Union(dateDriverGasQuery).FirstOrDefault();
|
|
}
|
|
|
|
public IEnumerable<Log> GetPossibleMatchingLogs(FuelLog fuelLog)
|
|
{
|
|
const int dateRange = 3;
|
|
const double gasRange = 1;
|
|
const double odometerRange = 100;
|
|
var gasVehicleQuery = GetLogs();
|
|
|
|
// matching by Date, Gas Purchased (gallons), and Vehicle
|
|
|
|
var vehicle = GetVehicleByTag(fuelLog.TagNumber);
|
|
if (vehicle != null)
|
|
gasVehicleQuery = gasVehicleQuery.Where(log => log.Vehicle.VehicleId == vehicle.VehicleId);
|
|
|
|
var futureDate = fuelLog.Date.AddDays(dateRange);
|
|
var pastDate = fuelLog.Date.AddDays(-dateRange);
|
|
|
|
gasVehicleQuery = gasVehicleQuery.Where(log =>
|
|
log.Date.Year <= futureDate.Year &&
|
|
log.Date.Month <= futureDate.Month &&
|
|
log.Date.Day <= futureDate.Day &&
|
|
log.Date.Year >= pastDate.Year &&
|
|
log.Date.Month >= pastDate.Month &&
|
|
log.Date.Day >= pastDate.Day
|
|
);
|
|
|
|
var gasMax = fuelLog.GasPurchased + gasRange;
|
|
var gasMin = fuelLog.GasPurchased - gasRange;
|
|
gasVehicleQuery = gasVehicleQuery.Where(log => log.GasPurchased <= gasMax && log.GasPurchased >= gasMin);
|
|
|
|
var driverQuery =
|
|
GetLogs()
|
|
.Where(log => log.User.FullName.Contains(fuelLog.DriverFullName))
|
|
.Where(log => log.GasPurchased > 0)
|
|
.Where(log =>
|
|
log.Date.Year <= futureDate.Year &&
|
|
log.Date.Month <= futureDate.Month &&
|
|
log.Date.Day <= futureDate.Day &&
|
|
log.Date.Year >= pastDate.Year &&
|
|
log.Date.Month >= pastDate.Month &&
|
|
log.Date.Day >= pastDate.Day
|
|
);
|
|
|
|
var odoMax = fuelLog.Odometer + odometerRange;
|
|
var odoMin = fuelLog.Odometer - odometerRange;
|
|
var odometerQuery =
|
|
GetLogs()
|
|
.Where(log => log.EndOdometer > odoMin && log.EndOdometer < odoMax)
|
|
.Where(log => log.GasPurchased > 0)
|
|
.Where(log =>
|
|
log.Date.Year <= futureDate.Year &&
|
|
log.Date.Month <= futureDate.Month &&
|
|
log.Date.Day <= futureDate.Day &&
|
|
log.Date.Year >= pastDate.Year &&
|
|
log.Date.Month >= pastDate.Month &&
|
|
log.Date.Day >= pastDate.Day
|
|
);
|
|
|
|
return gasVehicleQuery.Union(driverQuery).Union(odometerQuery);
|
|
}
|
|
|
|
public IList<DateTime> GetValidFuelLogMonths()
|
|
{
|
|
var months =
|
|
from l in GetFuelLogs()
|
|
group l by new { l.Date.Year, l.Date.Month }
|
|
into g
|
|
//let dt = new DateTime(g.Key.Year, g.Key.Month, 1)
|
|
select g.Key;
|
|
|
|
var ym =
|
|
from m in months.ToList()
|
|
select new DateTime(m.Year, m.Month, 1);
|
|
|
|
return ym.OrderByDescending(dt => dt).ToList();
|
|
}
|
|
#endregion
|
|
|
|
#region Vehicle Service
|
|
public void AddVehicleService(VehicleService vehicleService)
|
|
{
|
|
_db.VehicleServices.Add(vehicleService);
|
|
_db.SaveChanges();
|
|
}
|
|
|
|
public void UpdateVehicleService(VehicleService vehicleService)
|
|
{
|
|
_db.Entry(vehicleService).State = EntityState.Modified;
|
|
_db.SaveChanges();
|
|
}
|
|
|
|
public IQueryable<VehicleService> GetVehicleServices()
|
|
{
|
|
var vehicleServices = _db.VehicleServices;
|
|
return vehicleServices;
|
|
}
|
|
|
|
public VehicleService GetVehicleService(int id)
|
|
{
|
|
return _db.VehicleServices.Find(id);
|
|
}
|
|
|
|
public void DeleteVehicleService(int id)
|
|
{
|
|
var vehicleService = _db.VehicleServices.Find(id);
|
|
|
|
_db.VehicleServices.Remove(vehicleService);
|
|
_db.SaveChanges();
|
|
}
|
|
|
|
public IList<DateTime> GetValidVehicleServiceMonths()
|
|
{
|
|
var months =
|
|
from l in GetVehicleServices()
|
|
group l by new {l.InvoiceDate.Year, l.InvoiceDate.Month}
|
|
into g
|
|
select g.Key;
|
|
|
|
var ym =
|
|
from m in months.ToList()
|
|
select new DateTime(m.Year, m.Month, 1);
|
|
|
|
return ym.OrderByDescending(dt => dt).ToList();
|
|
}
|
|
|
|
public static IQueryable<VehicleService> FilterVehicleServices(IQueryable<VehicleService> vehicleServices, VehicleServiceQueryViewModel query)
|
|
{
|
|
// date filtering
|
|
if (query.Year.HasValue & query.Month.HasValue)
|
|
{
|
|
var start = new DateTime(query.Year.Value, query.Month.Value, 1);
|
|
var monthRange = query.MonthRange.HasValue ? query.MonthRange.Value : 1;
|
|
var end = start.AddMonths(monthRange);
|
|
vehicleServices = vehicleServices.Where(l => l.InvoiceDate >= start && l.InvoiceDate < end);
|
|
}
|
|
return vehicleServices;
|
|
}
|
|
|
|
public IQueryable<string> GetServiceCenterNames()
|
|
{
|
|
return
|
|
from l in GetVehicleServices()
|
|
group l by new {l.ServiceCenterName}
|
|
into g
|
|
select g.Key.ServiceCenterName;
|
|
}
|
|
|
|
public IEnumerable<string> GetServiceCenterNamesAutocomplete(string term)
|
|
{
|
|
return
|
|
from name in GetServiceCenterNames()
|
|
where name.StartsWith(term)
|
|
select name;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Vehicle Cost Report
|
|
|
|
private const int FiscalYearStartMonth = 7;
|
|
|
|
public IQueryable<VehicleCostItem> GetFuelLogCost(int fiscalYear)
|
|
{
|
|
var fiscalYearStart = new DateTime(fiscalYear - 1, FiscalYearStartMonth, 1);
|
|
var fiscalYearEnd = new DateTime(fiscalYear, FiscalYearStartMonth, 1);
|
|
|
|
return
|
|
from fuelLog in _db.FuelLogs
|
|
where fuelLog.Date >= fiscalYearStart && fuelLog.Date < fiscalYearEnd
|
|
group fuelLog by fuelLog.TagNumber
|
|
into tagGroup
|
|
let totalFuelPrice = tagGroup.Sum(i => i.TotalPrice)
|
|
select new VehicleCostItem { CostType = "Fuel", TotalPrice = totalFuelPrice, TagNumber = tagGroup.Key};
|
|
}
|
|
|
|
public IQueryable<VehicleCostItem> GetVehicleServiceCost(int fiscalYear)
|
|
{
|
|
var fiscalYearStart = new DateTime(fiscalYear - 1, FiscalYearStartMonth, 1);
|
|
var fiscalYearEnd = new DateTime(fiscalYear, FiscalYearStartMonth, 1);
|
|
|
|
return
|
|
from vehicleService in _db.VehicleServices
|
|
where vehicleService.InvoiceDate >= fiscalYearStart && vehicleService.InvoiceDate < fiscalYearEnd
|
|
group vehicleService by vehicleService.Vehicle.TagNumber
|
|
into tagGroup
|
|
let totalServicePrice = tagGroup.Sum(i => i.Price)
|
|
select new VehicleCostItem { CostType = "Service", TotalPrice = totalServicePrice, TagNumber = tagGroup.Key };
|
|
}
|
|
|
|
public IList<VehicleCostItem> GetVehicleCostItems(int fiscalYear)
|
|
{
|
|
var costItems = GetFuelLogCost(fiscalYear).Union(GetVehicleServiceCost(fiscalYear)).ToList();
|
|
foreach (var costItem in costItems)
|
|
{
|
|
costItem.VehicleId = GetVehicleIdByTag(costItem.TagNumber);
|
|
}
|
|
return costItems;
|
|
}
|
|
|
|
public IList<int> GetValidVehicleCostItemsYears()
|
|
{
|
|
var fuelYears =
|
|
(from fuelLog in _db.FuelLogs
|
|
let fiscalYear = SqlFunctions.DateAdd("month", FiscalYearStartMonth - 1, fuelLog.Date).Value.Year
|
|
select fiscalYear).Distinct();
|
|
|
|
var serviceYears =
|
|
(from vehicleService in _db.VehicleServices
|
|
let fiscalYear = SqlFunctions.DateAdd("month", FiscalYearStartMonth - 1, vehicleService.InvoiceDate).Value.Year
|
|
select fiscalYear).Distinct();
|
|
|
|
var years = fuelYears.Union(serviceYears).Distinct().OrderByDescending(y => y);
|
|
|
|
return years.ToList();
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Service Reminder
|
|
public void AddServiceReminder(ServiceReminder serviceReminder)
|
|
{
|
|
_db.ServiceReminders.Add(serviceReminder);
|
|
_db.SaveChanges();
|
|
}
|
|
|
|
public void UpdateServiceReminder(ServiceReminder serviceReminder)
|
|
{
|
|
_db.Entry(serviceReminder).State = EntityState.Modified;
|
|
_db.SaveChanges();
|
|
}
|
|
|
|
public IQueryable<ServiceReminder> GetServiceReminders(string vehicleId)
|
|
{
|
|
var serviceReminders = _db.ServiceReminders.Where(sr => sr.Vehicle.VehicleId == vehicleId);
|
|
return serviceReminders;
|
|
}
|
|
|
|
public ServiceReminder GetServiceReminder(int 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)
|
|
{
|
|
var serviceReminder = _db.ServiceReminders.Find(id);
|
|
|
|
_db.ServiceReminders.Remove(serviceReminder);
|
|
_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
|
|
|
|
}
|
|
} |