482 lines
13 KiB
C#
482 lines
13 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Data.Entity.Validation;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Web.Mvc;
|
|
using System.Web.Routing;
|
|
using MileageTraker.Web.Attributes;
|
|
using MileageTraker.Web.DAL;
|
|
using MileageTraker.Web.Utility;
|
|
using MileageTraker.Web.ViewModels;
|
|
using MileageTraker.Web.ViewModels.Log;
|
|
using MileageTraker.Web.ViewModels.Vehicle;
|
|
|
|
namespace MileageTraker.Web.Controllers
|
|
{
|
|
[Authorize(Roles = "Administrator, Developer")]
|
|
public class LogController : ControllerBase
|
|
{
|
|
public ViewResult Index(LogQueryViewModel query)
|
|
{
|
|
var validLogYearMonths = DataService.GetValidLogMonths();
|
|
|
|
if (!validLogYearMonths.Any()) // this means no logs in DB
|
|
return View("Empty");
|
|
|
|
// default parameter processing
|
|
if (!query.HasParameters())
|
|
{
|
|
query.Year = validLogYearMonths.First().Year;
|
|
query.Month = validLogYearMonths.First().Month;
|
|
query.MonthRange = 1;
|
|
}
|
|
if (query.Year.HasValue && !query.Month.HasValue)
|
|
{
|
|
var validLogMonths = validLogYearMonths.Where(dt => dt.Year == query.Year).ToList();
|
|
query.Month = validLogMonths.Min(dt => dt.Month);
|
|
query.MonthRange = validLogMonths.Max(dt => dt.Month) - query.Month + 1;
|
|
}
|
|
|
|
var logs = DataService.GetLogs();
|
|
|
|
var filteredLogs =
|
|
(from log in DataService.GetLogIndexViewModels(DataService.FilterLogs(logs, query))
|
|
orderby log.Created descending
|
|
select log).ToList();
|
|
|
|
var viewModel = new LogResultsViewModel(filteredLogs, query, CustomExtensions.YearMonthList(validLogYearMonths));
|
|
|
|
Session.Add("LogPage", Request.Url.PathAndQuery);
|
|
|
|
return View(viewModel);
|
|
}
|
|
|
|
[ActionLog]
|
|
public ActionResult Export(LogQueryViewModel query)
|
|
{
|
|
var logs = DataService.GetLogs();
|
|
var filteredLogs =
|
|
DataService.GetLogIndexViewModels(
|
|
DataService.FilterLogs(logs, query)
|
|
).ToList();
|
|
|
|
var name = string.Format("MileageLogs_{0}", query);
|
|
|
|
var export = ExcelWriter<LogIndexViewModel>.WriteXls(filteredLogs, name, name);
|
|
return File(export, "application/ms-excel", name + ".xls");
|
|
}
|
|
|
|
public ViewResult VehicleMileageReport(LogQueryViewModel query)
|
|
{
|
|
var items = DataService.GetMonthlyVehicleMileageItems(query);
|
|
|
|
var report = new VehicleMileageViewModel (items, query);
|
|
|
|
return View(report);
|
|
}
|
|
|
|
public ActionResult ExportVehicleMileageReport(LogQueryViewModel query)
|
|
{
|
|
var items = DataService.GetMonthlyVehicleMileageItems(query);
|
|
|
|
var name = string.Format("VehicleMileageReport_{0}", query);
|
|
|
|
var export = ExcelWriter<VehicleMileageItem>.WriteXls(items, name, name);
|
|
|
|
return File(export, "application/ms-excel", name + ".xls");
|
|
}
|
|
|
|
public ActionResult DriverMileageReport(LogQueryViewModel query)
|
|
{
|
|
var items = DataService.GetMonthlyDriverMileageItems(query);
|
|
items = items.OrderBy(i => i.DriverName);
|
|
|
|
var report = new DriverMileageViewModel(items, query);
|
|
|
|
return View(report);
|
|
}
|
|
|
|
public ActionResult ExportDriverMileageReport(LogQueryViewModel query)
|
|
{
|
|
var items = DataService.GetMonthlyDriverMileageItems(query);
|
|
items = items.OrderBy(i => i.DriverName);
|
|
var report = new DriverMileageViewModel(items, query);
|
|
var flattenedReport = report.Flatten();
|
|
|
|
var name = string.Format("DriverMileageReport_{0}", query);
|
|
|
|
var export = ExcelWriter<DriverMileageFlattenedViewModel>.WriteXls(flattenedReport, name, name);
|
|
|
|
return File(export, "application/ms-excel", name + ".xls");
|
|
}
|
|
|
|
public ViewResult Details(int id)
|
|
{
|
|
var log = DataService.GetLog(id);
|
|
var viewModel = new LogViewModel(log)
|
|
{
|
|
Purpose = {Available = GetPurposeTypesSelectList()}
|
|
};
|
|
return View(viewModel);
|
|
}
|
|
|
|
public ActionResult PreviousDetails(int id)
|
|
{
|
|
var log = DataService.GetLog(id);
|
|
int logId;
|
|
if (log.VehiclePreviousLog != null)
|
|
{
|
|
logId = log.VehiclePreviousLog.LogId;
|
|
}
|
|
else
|
|
{
|
|
logId = id;
|
|
SetStatusMessage("This is the first log for this vehicle");
|
|
}
|
|
return RedirectToAction("Details", new {id = logId});
|
|
}
|
|
|
|
public ActionResult NextDetails(int id)
|
|
{
|
|
var nextLog = DataService.GetNextLog(id);
|
|
int logId;
|
|
if (nextLog != null)
|
|
{
|
|
logId = nextLog.LogId;
|
|
}
|
|
else
|
|
{
|
|
logId = id;
|
|
SetStatusMessage("This is the most recent log for this vehicle");
|
|
}
|
|
return RedirectToAction("Details", new { id = logId });
|
|
}
|
|
|
|
[HttpGet]
|
|
public ActionResult Create(string vehicleId)
|
|
{
|
|
var viewModel = new LogViewModel
|
|
{
|
|
Date = DateTime.Today,
|
|
VehicleId = vehicleId,
|
|
Purpose = {Available = GetPurposeTypesSelectList()},
|
|
};
|
|
|
|
return View(viewModel);
|
|
}
|
|
|
|
[HttpPost]
|
|
[ActionLog]
|
|
public ActionResult Create(LogViewModel viewModel)
|
|
{
|
|
if (ModelState.IsValid)
|
|
{
|
|
var log = viewModel.GetLog();
|
|
log.Vehicle = DataService.GetVehicle(viewModel.VehicleId);
|
|
log.User = DataService.FindUserByFullName(viewModel.UserFullName);
|
|
log.Source = HttpContext.Request.Url.AbsolutePath;
|
|
log.UserHostAddress = HttpContext.Request.UserHostAddress;
|
|
log.UserAgent = HttpContext.Request.UserAgent;
|
|
|
|
if (viewModel.Purpose != null)
|
|
log.Purpose =
|
|
DataService.GetPurposeTypes()
|
|
.First(pt => pt.PurposeTypeId == viewModel.Purpose.Selected);
|
|
|
|
DataService.AddLog(log);
|
|
|
|
SetStatusMessage("Log created", StatusType.Success);
|
|
|
|
if (TempData.ContainsKey("FuelLogId"))
|
|
{
|
|
// update fuel log
|
|
var fuelLogId = (int)TempData["FuelLogId"];
|
|
var fuelLog = DataService.GetFuelLog(fuelLogId);
|
|
fuelLog.Log = log;
|
|
DataService.UpdateFuelLog(fuelLog);
|
|
|
|
// return to the fuel log match page
|
|
SetStatusMessage("Log created and matched to the fuel log", StatusType.Success);
|
|
return RedirectToAction("Match", "FuelLog", new {id = fuelLogId});
|
|
}
|
|
|
|
return RedirectToAction("Index");
|
|
}
|
|
|
|
viewModel.Purpose.Available = GetPurposeTypesSelectList();
|
|
return View(viewModel);
|
|
}
|
|
|
|
public ActionResult Edit(int id)
|
|
{
|
|
var log = DataService.GetLog(id);
|
|
var viewModel = new LogViewModel(log)
|
|
{
|
|
Purpose = {Available = GetPurposeTypesSelectList()}
|
|
};
|
|
return View(viewModel);
|
|
}
|
|
|
|
[HttpPost]
|
|
[ActionLog]
|
|
public ActionResult Edit(LogViewModel viewModel)
|
|
{
|
|
if (ModelState.IsValid)
|
|
{
|
|
var log = DataService.GetLog(viewModel.LogId);
|
|
viewModel.SetProperties(log);
|
|
log.User = DataService.FindUserByFullName(viewModel.UserFullName);
|
|
log.Vehicle = DataService.GetVehicle(viewModel.VehicleId);
|
|
|
|
if (viewModel.Purpose != null)
|
|
log.Purpose =
|
|
DataService.GetPurposeTypes()
|
|
.First(pt => pt.PurposeTypeId == viewModel.Purpose.Selected);
|
|
|
|
DataService.UpdateLog(log);
|
|
|
|
SetStatusMessage("Log updated");
|
|
return RedirectToAction("Details", new{id = log.LogId});
|
|
}
|
|
|
|
viewModel.Purpose.Available = GetPurposeTypesSelectList();
|
|
return View(viewModel);
|
|
}
|
|
|
|
public ActionResult Delete(int id)
|
|
{
|
|
var log = DataService.GetLog(id);
|
|
var viewModel = new LogViewModel(log)
|
|
{
|
|
Purpose = {Available = GetPurposeTypesSelectList()}
|
|
};
|
|
return View(viewModel);
|
|
}
|
|
|
|
[HttpPost, ActionName("Delete")]
|
|
[ActionLog]
|
|
public ActionResult DeleteConfirmed(int id)
|
|
{
|
|
DataService.DeleteLog(id);
|
|
|
|
SetStatusMessage("Log deleted");
|
|
if (Session["LogPage"] != null)
|
|
return Redirect((string) Session["LogPage"]);
|
|
return RedirectToAction("Index");
|
|
}
|
|
|
|
public PartialViewResult DetailsPrevious(int id)
|
|
{
|
|
var log = DataService.GetLog(id);
|
|
return PartialView(new LogPartialDetails(log));
|
|
}
|
|
|
|
#region Import
|
|
|
|
public ActionResult ImportUpload()
|
|
{
|
|
return View();
|
|
}
|
|
|
|
[HttpPost]
|
|
public ActionResult Import(ImportUploadViewModel viewModel)
|
|
{
|
|
if (ModelState.IsValid && viewModel.File != null && viewModel.File.ContentLength > 0)
|
|
{
|
|
var user = DataService.FindUserByFullName(viewModel.UserName) ??
|
|
DataService.FindUserByUsername(viewModel.UserName);
|
|
if (user == null)
|
|
{
|
|
SetStatusMessage("User " + viewModel.UserName + " not found", StatusType.Error);
|
|
}
|
|
else
|
|
{
|
|
ViewData["UserFullName"] = user.FullName;
|
|
|
|
var fileName = Path.GetFileName(viewModel.File.FileName);
|
|
var path = Path.Combine(Server.MapPath("~/App_Data/uploads"), fileName);
|
|
viewModel.File.SaveAs(path);
|
|
|
|
try
|
|
{
|
|
var logImports = LogImporter.Import(path);
|
|
// todo: delete file?
|
|
return View(logImports.ToList());
|
|
}
|
|
catch (OutOfMemoryException)
|
|
{
|
|
SetStatusMessage(
|
|
"Problem reading excel document - please verify that the document is in Excel 97-2003 Workbook (.xls) format", StatusType.Error);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
SetStatusMessage("Problem reading excel document: " + ex.Message, StatusType.Error);
|
|
}
|
|
}
|
|
}
|
|
return RedirectToAction("ImportUpload");
|
|
}
|
|
|
|
enum ImportStatus
|
|
{
|
|
Success,
|
|
Failure,
|
|
Duplicate
|
|
}
|
|
|
|
[HttpPost]
|
|
[ActionLog]
|
|
public ActionResult ImportCreate(ImportLogViewModel viewModel, string userFullName)
|
|
{
|
|
var buttonAttributes = new Dictionary<string, object> { { "class", "btn btn-mini" }, { "target", "_blank" } };
|
|
|
|
try
|
|
{
|
|
// verify purpose
|
|
var purposeType = DataService.FindPurposeType(viewModel.Purpose);
|
|
if (purposeType == null)
|
|
{
|
|
return Json(new
|
|
{
|
|
Status = ImportStatus.Failure.ToString(),
|
|
Message = "Invalid Purpose: " + viewModel.Purpose,
|
|
Action = GetFixLink(viewModel)
|
|
}, JsonRequestBehavior.AllowGet);
|
|
}
|
|
|
|
if (!ModelState.IsValid)
|
|
{
|
|
var errorList = GetModelStateErrorList(ModelState);
|
|
// remove the object name from the errors
|
|
errorList = errorList.Select(s => s.Replace("viewModel.", ""));
|
|
|
|
return Json(new
|
|
{
|
|
Status = ImportStatus.Failure.ToString(),
|
|
Message = string.Join(", ", errorList),
|
|
Action = GetFixLink(viewModel)
|
|
}, JsonRequestBehavior.AllowGet);
|
|
}
|
|
|
|
var log = viewModel.GetLog();
|
|
log.Vehicle = DataService.GetVehicle(viewModel.VehicleId);
|
|
log.User = DataService.FindUserByFullName(userFullName);
|
|
log.Source = HttpContext.Request.Url.AbsolutePath;
|
|
log.UserHostAddress = HttpContext.Request.UserHostAddress;
|
|
log.UserAgent = HttpContext.Request.UserAgent;
|
|
log.Purpose = purposeType;
|
|
|
|
// check duplicate
|
|
var duplicateLogs = DataService.GetDuplicateLogs(log).ToList();
|
|
if (duplicateLogs.Any())
|
|
{
|
|
var link = HtmlHelper.GenerateLink(
|
|
ControllerContext.RequestContext, RouteTable.Routes,
|
|
"Details", "Default", "Details", "Log",
|
|
new RouteValueDictionary(new{ id = duplicateLogs.First().LogId }),
|
|
buttonAttributes);
|
|
return Json(new
|
|
{
|
|
Status = ImportStatus.Duplicate.ToString(),
|
|
Message = "This log has been previously entered",
|
|
Action = link
|
|
}, JsonRequestBehavior.AllowGet);
|
|
}
|
|
// verify vehicle exists
|
|
if (log.Vehicle == null)
|
|
{
|
|
return Json(new
|
|
{
|
|
Status = ImportStatus.Failure.ToString(),
|
|
Message = "Vehile with supplied ID does not exist",
|
|
Action = GetFixLink(viewModel)
|
|
}, JsonRequestBehavior.AllowGet);
|
|
}
|
|
// verify city exists
|
|
if (DataService.FindCityByName(log.CityName) == null)
|
|
{
|
|
return Json(new
|
|
{
|
|
Status = ImportStatus.Failure.ToString(),
|
|
Message = "City must exist in system",
|
|
Action = GetFixLink(viewModel)
|
|
}, JsonRequestBehavior.AllowGet);
|
|
}
|
|
|
|
// SAVE IT!
|
|
DataService.AddLog(log);
|
|
|
|
var successLink = HtmlHelper.GenerateLink(
|
|
ControllerContext.RequestContext, RouteTable.Routes,
|
|
"Details", "Default", "Details", "Log",
|
|
new RouteValueDictionary(new { id = log.LogId }),
|
|
buttonAttributes);
|
|
|
|
return Json(new
|
|
{
|
|
Status = ImportStatus.Success.ToString(),
|
|
Action = successLink
|
|
}, JsonRequestBehavior.AllowGet);
|
|
}
|
|
catch (DbEntityValidationException ex)
|
|
{
|
|
// Retrieve the error messages as a list of strings.
|
|
var errorMessages = ex.EntityValidationErrors
|
|
.SelectMany(x => x.ValidationErrors)
|
|
.Select(x => x.ErrorMessage);
|
|
|
|
// Join the list to a single string.
|
|
var fullErrorMessage = string.Join(", ", errorMessages);
|
|
|
|
return Json(new
|
|
{
|
|
Status = ImportStatus.Failure.ToString(),
|
|
Message = fullErrorMessage,
|
|
Action = GetFixLink(viewModel)
|
|
},
|
|
JsonRequestBehavior.AllowGet);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
var message = ex.Message;
|
|
return Json(new
|
|
{
|
|
Status = ImportStatus.Failure.ToString(),
|
|
Message = message,
|
|
Action = GetFixLink(viewModel)
|
|
}, JsonRequestBehavior.AllowGet);
|
|
}
|
|
}
|
|
|
|
private string GetFixLink(ImportLogViewModel viewModel)
|
|
{
|
|
try
|
|
{
|
|
viewModel.GetLogViewModel();
|
|
}
|
|
catch
|
|
{
|
|
return string.Empty;
|
|
}
|
|
|
|
return RenderRazorViewToString("ImportFix", viewModel);
|
|
}
|
|
|
|
[HttpPost]
|
|
public ActionResult ImportFix(ImportLogViewModel viewModel)
|
|
{
|
|
var logViewModel = viewModel.GetLogViewModel();
|
|
logViewModel.Purpose.Available = GetPurposeTypesSelectList();
|
|
return View("Create", logViewModel);
|
|
}
|
|
|
|
public ActionResult ImportTemplate()
|
|
{
|
|
var template = LogImportTemplateWriter.Write();
|
|
return File(template, "application/ms-excel", "MileageTraker_ImportTemplate.xls");
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
} |