Fuel Log Import basic functionality
This commit is contained in:
@@ -0,0 +1,46 @@
|
|||||||
|
using System;
|
||||||
|
using MileageTraker.Web.ViewModels.FuelLog;
|
||||||
|
using NUnit.Framework;
|
||||||
|
|
||||||
|
namespace Web.Tests.ViewModels.FuelLog
|
||||||
|
{
|
||||||
|
[TestFixture]
|
||||||
|
public class ImportFuelLogViewModelTests
|
||||||
|
{
|
||||||
|
private static readonly ImportFuelLogViewModel Iflvm = new ImportFuelLogViewModel
|
||||||
|
{
|
||||||
|
Date = new DateTime(2015, 10, 1, 3, 2, 1),
|
||||||
|
DriverFullName = "Bob Dobalina",
|
||||||
|
TagNumber = "TG2832",
|
||||||
|
Odometer = 98323,
|
||||||
|
CityName = "Knoxville",
|
||||||
|
MPG = 23.1,
|
||||||
|
GasPurchased = 2.123,
|
||||||
|
TotalPrice = 4.32M
|
||||||
|
};
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void Converts_To_FuelLog()
|
||||||
|
{
|
||||||
|
var fuelLog = Iflvm.GetFuelLog();
|
||||||
|
Assert.That(fuelLog.Date, Is.EqualTo(Iflvm.Date));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void Converts_To_FuelLog_And_Back()
|
||||||
|
{
|
||||||
|
var fuelLog = Iflvm.GetFuelLog();
|
||||||
|
var importFuelLogViewModel = new ImportFuelLogViewModel(fuelLog);
|
||||||
|
Assert.That(importFuelLogViewModel.TotalPrice, Is.EqualTo(Iflvm.TotalPrice));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void Converts_FuelLogLogId()
|
||||||
|
{
|
||||||
|
var fuelLog = Iflvm.GetFuelLog();
|
||||||
|
fuelLog.Log = new MileageTraker.Web.Models.Log {LogId = 123};
|
||||||
|
var importFuelLogViewModel = new ImportFuelLogViewModel(fuelLog);
|
||||||
|
Assert.That(importFuelLogViewModel.TotalPrice, Is.EqualTo(Iflvm.TotalPrice));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -108,6 +108,7 @@
|
|||||||
<Compile Include="Utility\NameNormalizerTests.cs" />
|
<Compile Include="Utility\NameNormalizerTests.cs" />
|
||||||
<Compile Include="ViewModels\CreateLog\CreateLogViewModelTests.cs" />
|
<Compile Include="ViewModels\CreateLog\CreateLogViewModelTests.cs" />
|
||||||
<Compile Include="ViewModels\CreateLog\LogImportViewModelTests.cs" />
|
<Compile Include="ViewModels\CreateLog\LogImportViewModelTests.cs" />
|
||||||
|
<Compile Include="ViewModels\FuelLog\ImportFuelLogViewModelTests.cs" />
|
||||||
<Compile Include="ViewModels\Log\LogQueryViewModelTests.cs" />
|
<Compile Include="ViewModels\Log\LogQueryViewModelTests.cs" />
|
||||||
<Compile Include="ViewModels\Log\LogViewModelTests.cs" />
|
<Compile Include="ViewModels\Log\LogViewModelTests.cs" />
|
||||||
<Compile Include="ViewModels\User\CreateUserViewModelTests.cs" />
|
<Compile Include="ViewModels\User\CreateUserViewModelTests.cs" />
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Web.Mvc;
|
using System.Web.Mvc;
|
||||||
|
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.FuelLog;
|
using MileageTraker.Web.ViewModels.FuelLog;
|
||||||
|
|
||||||
@@ -40,7 +39,7 @@ namespace MileageTraker.Web.Controllers
|
|||||||
// orderby log. descending
|
// orderby log. descending
|
||||||
// select log).ToList();
|
// select log).ToList();
|
||||||
|
|
||||||
var viewModel = new FuelLogResultsViewModel(fuelLogs, query, CustomExtensions.YearMonthList(validLogYearMonths));
|
var viewModel = new ResultsViewModel(fuelLogs, query, CustomExtensions.YearMonthList(validLogYearMonths));
|
||||||
|
|
||||||
//Session.Add("FuelLogPage", Request.Url.PathAndQuery);
|
//Session.Add("FuelLogPage", Request.Url.PathAndQuery);
|
||||||
|
|
||||||
@@ -55,7 +54,8 @@ namespace MileageTraker.Web.Controllers
|
|||||||
}
|
}
|
||||||
|
|
||||||
[HttpPost]
|
[HttpPost]
|
||||||
public ActionResult Import(FuelLogImportUploadViewModel viewModel)
|
[ActionLog]
|
||||||
|
public ActionResult Import(ImportUploadViewModel viewModel)
|
||||||
{
|
{
|
||||||
if (ModelState.IsValid && viewModel.File != null && viewModel.File.ContentLength > 0)
|
if (ModelState.IsValid && viewModel.File != null && viewModel.File.ContentLength > 0)
|
||||||
{
|
{
|
||||||
@@ -66,17 +66,23 @@ namespace MileageTraker.Web.Controllers
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var logImports = FuelmanCsvImporter.Import(fileInfo);
|
var fuelLogs = FuelmanCsvImporter.Import(fileInfo);
|
||||||
// todo: add to the database
|
|
||||||
DataService.AddFuelLogs(logImports);
|
|
||||||
// todo: delete file?
|
// todo: delete file?
|
||||||
return View(logImports.ToList());
|
|
||||||
|
var fls = (from fuelLog in fuelLogs
|
||||||
|
let prevAdds = DataService.GetDuplicateFuelLogs(fuelLog)
|
||||||
|
select new {ImportedFuelLog = fuelLog, PrevAdded = prevAdds.FirstOrDefault()}).ToList();
|
||||||
|
|
||||||
|
// add new logs to the database
|
||||||
|
DataService.AddFuelLogs(fls.Where(fl => fl.PrevAdded == null).Select(fl => fl.ImportedFuelLog));
|
||||||
|
|
||||||
|
var vms = from fl in fls
|
||||||
|
let vm = fl.PrevAdded == null
|
||||||
|
? new ImportFuelLogViewModel(fl.ImportedFuelLog)
|
||||||
|
: new ImportFuelLogViewModel(fl.PrevAdded) {PreviouslyAdded = true}
|
||||||
|
select vm;
|
||||||
|
return View(vms.ToList());
|
||||||
}
|
}
|
||||||
//catch (OutOfMemoryException)
|
|
||||||
//{
|
|
||||||
// TempData["StatusMessage"] = "Problem reading excel document - please verify that the document is in Excel 97-2003 Workbook (.xls) format";
|
|
||||||
// TempData["StatusMessage-Type"] = "alert-error";
|
|
||||||
//}
|
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
TempData["StatusMessage"] = "Problem reading document: " + ex.Message;
|
TempData["StatusMessage"] = "Problem reading document: " + ex.Message;
|
||||||
@@ -90,6 +96,56 @@ namespace MileageTraker.Web.Controllers
|
|||||||
}
|
}
|
||||||
return RedirectToAction("ImportUpload");
|
return RedirectToAction("ImportUpload");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum MatchStatus
|
||||||
|
{
|
||||||
|
Match,
|
||||||
|
NoMatch,
|
||||||
|
Error
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost]
|
||||||
|
public ActionResult Match(int fuelLogId)
|
||||||
|
{
|
||||||
|
var fuelLog = DataService.GetFuelLog(fuelLogId);
|
||||||
|
if (fuelLog == null)
|
||||||
|
{
|
||||||
|
return Json(new
|
||||||
|
{
|
||||||
|
Status = MatchStatus.Error.ToString(),
|
||||||
|
Message = "Fuel Log not found with given ID: " + fuelLogId
|
||||||
|
}, JsonRequestBehavior.AllowGet);
|
||||||
|
}
|
||||||
|
if (fuelLog.Log != null)
|
||||||
|
{
|
||||||
|
return Json(new
|
||||||
|
{
|
||||||
|
Status = MatchStatus.NoMatch.ToString(),
|
||||||
|
Message = "Already matched to log",
|
||||||
|
Action = RenderRazorViewToString("ImportMatchLogView", fuelLog.Log.LogId)
|
||||||
|
|
||||||
|
}, JsonRequestBehavior.AllowGet);
|
||||||
|
}
|
||||||
|
|
||||||
|
// run the match
|
||||||
|
var matchingLog = DataService.GetMatchingLog(fuelLog);
|
||||||
|
if (matchingLog == null)
|
||||||
|
{
|
||||||
|
return Json(new
|
||||||
|
{
|
||||||
|
Status = MatchStatus.NoMatch.ToString(),
|
||||||
|
Message = "Unable to find match"
|
||||||
|
}, JsonRequestBehavior.AllowGet);
|
||||||
|
}
|
||||||
|
fuelLog.Log = matchingLog;
|
||||||
|
DataService.UpdateFuelLog(fuelLog);
|
||||||
|
return Json(new
|
||||||
|
{
|
||||||
|
Status = MatchStatus.Match.ToString(),
|
||||||
|
Action = RenderRazorViewToString("ImportMatchedLog", new ImportMatchedLogViewModel { LogId = fuelLog.Log.LogId })
|
||||||
|
}, JsonRequestBehavior.AllowGet);
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -259,10 +259,9 @@ namespace MileageTraker.Web.Controllers
|
|||||||
var path = Path.Combine(Server.MapPath("~/App_Data/uploads"), fileName);
|
var path = Path.Combine(Server.MapPath("~/App_Data/uploads"), fileName);
|
||||||
viewModel.File.SaveAs(path);
|
viewModel.File.SaveAs(path);
|
||||||
|
|
||||||
IEnumerable<ImportLogViewModel> logImports;
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
logImports = LogImporter.Import(path);
|
var logImports = LogImporter.Import(path);
|
||||||
// todo: delete file?
|
// todo: delete file?
|
||||||
return View(logImports.ToList());
|
return View(logImports.ToList());
|
||||||
}
|
}
|
||||||
|
|||||||
+49
-1
@@ -1,8 +1,8 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Data;
|
|
||||||
using System.Data.Entity;
|
using System.Data.Entity;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
using MileageTraker.Web.Context;
|
using MileageTraker.Web.Context;
|
||||||
using MileageTraker.Web.Models;
|
using MileageTraker.Web.Models;
|
||||||
using MileageTraker.Web.Utility;
|
using MileageTraker.Web.Utility;
|
||||||
@@ -409,6 +409,20 @@ namespace MileageTraker.Web.DAL
|
|||||||
return _db.Vehicles.Find(id);
|
return _db.Vehicles.Find(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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(string vehicleId)
|
public void UpdateCurrentOdometer(string vehicleId)
|
||||||
{
|
{
|
||||||
var mostRecentOdometerQuery =
|
var mostRecentOdometerQuery =
|
||||||
@@ -630,6 +644,40 @@ namespace MileageTraker.Web.DAL
|
|||||||
return _db.FuelLogs.Find(id);
|
return _db.FuelLogs.Find(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
var logs = GetLogs();
|
||||||
|
|
||||||
|
// matching by Date, Gas Purchased (gallons), and Vehicle
|
||||||
|
|
||||||
|
var vehicle = GetVehicleByTag(fuelLog.TagNumber);
|
||||||
|
if (vehicle != null)
|
||||||
|
logs = logs.Where(log => log.VehicleId == vehicle.VehicleId);
|
||||||
|
else return null;
|
||||||
|
|
||||||
|
logs = logs.Where(log =>
|
||||||
|
log.Date.Year == fuelLog.Date.Year &&
|
||||||
|
log.Date.Month == fuelLog.Date.Month &&
|
||||||
|
log.Date.Day == fuelLog.Date.Day
|
||||||
|
);
|
||||||
|
logs = logs.Where(log => log.GasPurchased == fuelLog.GasPurchased);
|
||||||
|
|
||||||
|
//logs = logs.Where(log => log.User.FullName == fuelLog.DriverFullName);
|
||||||
|
//logs = logs.Where(log => log.EndOdometer == fuelLog.Odometer);
|
||||||
|
|
||||||
|
return logs.FirstOrDefault();
|
||||||
|
}
|
||||||
|
|
||||||
public IList<DateTime> GetValidFuelLogMonths()
|
public IList<DateTime> GetValidFuelLogMonths()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ namespace MileageTraker.Web.Models
|
|||||||
|
|
||||||
[Required]
|
[Required]
|
||||||
[DataType(DataType.Date)]
|
[DataType(DataType.Date)]
|
||||||
|
[DisplayFormatAttribute(ApplyFormatInEditMode = true, DataFormatString = "{0:d}")]
|
||||||
public DateTime Date { get; set; }
|
public DateTime Date { get; set; }
|
||||||
|
|
||||||
[Required]
|
[Required]
|
||||||
|
|||||||
@@ -0,0 +1,61 @@
|
|||||||
|
function importFuelLogs() {
|
||||||
|
$('.breadcrumb').hide();
|
||||||
|
$('tr:not(.complete) .match-status').append('<span class="label">Pending</span');
|
||||||
|
var total = $("#fuellogs > tbody > tr:not(.complete)").length;
|
||||||
|
$('#page-match-status').html('<span class="label label-warning"><i class="fa fa-spinner fa-spin"></i> Matching In Progress</span> <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>');
|
||||||
|
|
||||||
|
submitNext();
|
||||||
|
var failureCount = 0;
|
||||||
|
|
||||||
|
function submitNext() {
|
||||||
|
var $fuelLogs = $("#fuellogs > tbody > tr:not(.complete)");
|
||||||
|
var percentComplete = Math.round( (1 - ($fuelLogs.length / total)) * 100 );
|
||||||
|
$('.progress .bar').attr('style', 'width:' + percentComplete + '%');
|
||||||
|
|
||||||
|
if ($fuelLogs.length > 0) {
|
||||||
|
var $row = $($fuelLogs[0]);
|
||||||
|
var data = $('form', $row).serialize();
|
||||||
|
var url = $('form', $row).attr('action');
|
||||||
|
|
||||||
|
$('.match-status', $row).html('<span class="label label-info"><i class="fa fa-spinner fa-spin"></i> Submitting</span>');
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
url: url,
|
||||||
|
type: 'post',
|
||||||
|
data: data,
|
||||||
|
success: function (result) {
|
||||||
|
$row.addClass("complete");
|
||||||
|
if (result.Status == "Match") {
|
||||||
|
$('.match-status', $row).html('<span class="label label-success">Match found</span>');
|
||||||
|
}
|
||||||
|
else if (result.Status == "NoMatch" || result.Status == "Error") {
|
||||||
|
if (result.Status == "NoMatch") {
|
||||||
|
$('.match-status', $row).html('<span class="label label-warning">No Match</span>');
|
||||||
|
} else {
|
||||||
|
$('.match-status', $row).html('<span class="label label-important">Error</span>');
|
||||||
|
}
|
||||||
|
$('.match-message', $row).text(result.Message);
|
||||||
|
failureCount++;
|
||||||
|
$('.progress .bar').addClass('bar-warning');
|
||||||
|
}
|
||||||
|
if (result.Action != undefined && result.Action != null) {
|
||||||
|
$('.match-status', $row).append(" " + result.Action);
|
||||||
|
}
|
||||||
|
|
||||||
|
submitNext();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
$('.breadcrumb').show();
|
||||||
|
$('.progress').removeClass('progress-striped');
|
||||||
|
$('.progress').removeClass('active');
|
||||||
|
if (failureCount == 0) {
|
||||||
|
$('#page-match-status').html('<span class="label">Complete</span> with all matches.');
|
||||||
|
$('.progress .bar').addClass('bar-success');
|
||||||
|
} else {
|
||||||
|
$('#page-match-status').html('<span class="label label-warning">Complete</span> but with errors. See details below.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
using System;
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using AutoMapper;
|
||||||
|
|
||||||
|
namespace MileageTraker.Web.ViewModels.FuelLog
|
||||||
|
{
|
||||||
|
public class ImportFuelLogViewModel
|
||||||
|
{
|
||||||
|
public int FuelLogId { get; set; }
|
||||||
|
|
||||||
|
[Required]
|
||||||
|
[DataType(DataType.Date)]
|
||||||
|
[DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:d}")]
|
||||||
|
public DateTime Date { get; set; }
|
||||||
|
|
||||||
|
[Required]
|
||||||
|
[StringLength(128)]
|
||||||
|
public string DriverFullName { get; set; }
|
||||||
|
|
||||||
|
[Required]
|
||||||
|
[Display(Name = "Tag#")]
|
||||||
|
public string TagNumber { get; set; }
|
||||||
|
|
||||||
|
[Required]
|
||||||
|
public int Odometer { get; set; }
|
||||||
|
|
||||||
|
[StringLength(64)]
|
||||||
|
public string CityName { get; set; }
|
||||||
|
|
||||||
|
public double MPG { get; set; }
|
||||||
|
|
||||||
|
[Required]
|
||||||
|
public double GasPurchased { get; set; }
|
||||||
|
|
||||||
|
[Required]
|
||||||
|
public decimal TotalPrice { get; set; }
|
||||||
|
|
||||||
|
public bool PreviouslyAdded { get; set; }
|
||||||
|
|
||||||
|
public int? LogId { get; set; }
|
||||||
|
|
||||||
|
static ImportFuelLogViewModel()
|
||||||
|
{
|
||||||
|
Mapper.CreateMap<ImportFuelLogViewModel, Models.FuelLog>();
|
||||||
|
Mapper.CreateMap<Models.FuelLog, ImportFuelLogViewModel>()
|
||||||
|
.ForMember(dest => dest.LogId,
|
||||||
|
opt => opt.ResolveUsing(
|
||||||
|
fl => fl.Log != null ? (int?)fl.Log.LogId : null
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
public ImportFuelLogViewModel(Models.FuelLog fuelLog)
|
||||||
|
{
|
||||||
|
Mapper.Map(fuelLog, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ImportFuelLogViewModel()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public Models.FuelLog GetFuelLog()
|
||||||
|
{
|
||||||
|
var log = new Models.FuelLog();
|
||||||
|
Mapper.Map(this, log);
|
||||||
|
return log;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
namespace MileageTraker.Web.ViewModels.FuelLog
|
||||||
|
{
|
||||||
|
public class ImportMatchedLogViewModel
|
||||||
|
{
|
||||||
|
public int LogId { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
+2
-2
@@ -3,10 +3,10 @@ using System.Web;
|
|||||||
|
|
||||||
namespace MileageTraker.Web.ViewModels.FuelLog
|
namespace MileageTraker.Web.ViewModels.FuelLog
|
||||||
{
|
{
|
||||||
public class FuelLogImportUploadViewModel
|
public class ImportUploadViewModel
|
||||||
{
|
{
|
||||||
[Required]
|
[Required]
|
||||||
[Display(Name = "FuelMan CSV File")]
|
[Display(Name = @"FuelMan CSV/Text Data File")]
|
||||||
public HttpPostedFileBase File { get; set; }
|
public HttpPostedFileBase File { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+5
-6
@@ -1,10 +1,9 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using MileageTraker.Web.Models;
|
using System.Globalization;
|
||||||
using MileageTraker.Web.ViewModels.Log;
|
|
||||||
|
|
||||||
namespace MileageTraker.Web.ViewModels.FuelLog
|
namespace MileageTraker.Web.ViewModels.FuelLog
|
||||||
{
|
{
|
||||||
public class FuelLogResultsViewModel
|
public class ResultsViewModel
|
||||||
{
|
{
|
||||||
public IEnumerable<Models.FuelLog> Logs { get; set; }
|
public IEnumerable<Models.FuelLog> Logs { get; set; }
|
||||||
public Dictionary<string, List<string>> AvailableYearMonths { get; set; }
|
public Dictionary<string, List<string>> AvailableYearMonths { get; set; }
|
||||||
@@ -19,12 +18,12 @@ namespace MileageTraker.Web.ViewModels.FuelLog
|
|||||||
public string Year { get; set; }
|
public string Year { get; set; }
|
||||||
public string Month { get; set; }
|
public string Month { get; set; }
|
||||||
|
|
||||||
public FuelLogResultsViewModel(IEnumerable<Models.FuelLog> logs, FuelLogQueryViewModel query, Dictionary<string, List<string>> availableYearMonths)
|
public ResultsViewModel(IEnumerable<Models.FuelLog> logs, FuelLogQueryViewModel query, Dictionary<string, List<string>> availableYearMonths)
|
||||||
{
|
{
|
||||||
Logs = logs;
|
Logs = logs;
|
||||||
AvailableYearMonths = availableYearMonths;
|
AvailableYearMonths = availableYearMonths;
|
||||||
Year = query.Year.HasValue ? query.Year.Value.ToString() : string.Empty;
|
Year = query.Year.HasValue ? query.Year.Value.ToString(CultureInfo.InvariantCulture) : string.Empty;
|
||||||
Month = query.Month.HasValue ? query.Month.Value.ToString() : string.Empty;
|
Month = query.Month.HasValue ? query.Month.Value.ToString(CultureInfo.InvariantCulture) : string.Empty;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
@{
|
||||||
|
ViewBag.Title = "No Fuel Logs";
|
||||||
|
}
|
||||||
|
|
||||||
|
<h2 class="center-content">@ViewBag.Title</h2>
|
||||||
|
|
||||||
|
<div class="center-content well">
|
||||||
|
No Fuel logs have been added yet. @Html.ActionLink("Import", "ImportUpload", null, new { @class = "btn" })
|
||||||
|
</div>
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
@model IList<MileageTraker.Web.Models.FuelLog>
|
@using MileageTraker.Web.ViewModels.FuelLog
|
||||||
|
@model IList<ImportFuelLogViewModel>
|
||||||
|
|
||||||
@{
|
@{
|
||||||
ViewBag.Title = "Import Fuel Logs";
|
ViewBag.Title = "Import Fuel Logs";
|
||||||
@@ -8,58 +9,63 @@
|
|||||||
<link href="@Url.Content("~/Content/font-awesome.min.css")" rel="stylesheet" type="text/css" />
|
<link href="@Url.Content("~/Content/font-awesome.min.css")" rel="stylesheet" type="text/css" />
|
||||||
}
|
}
|
||||||
|
|
||||||
@{ Html.RenderPartial("BackToLogs"); }
|
|
||||||
|
|
||||||
@Html.Partial("_StatusMessage")
|
@Html.Partial("_StatusMessage")
|
||||||
|
|
||||||
<h2>@ViewBag.Title</h2>
|
<h2>@ViewBag.Title</h2>
|
||||||
<p>Driver: <strong>@ViewData["UserFullName"]</strong></p>
|
<h5>Matching Mileage Logs based on Date, Vehicle, and Gas Purchased</h5>
|
||||||
|
|
||||||
<p id="page-import-status"></p>
|
<p id="page-match-status"></p>
|
||||||
|
|
||||||
<table id="logs" class="table table-striped table-bordered table-hover table-condensed">
|
<table id="fuellogs" class="table table-striped table-bordered table-hover table-condensed">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Import Status</th>
|
<th>Match Status</th>
|
||||||
<th style="width:20%"></th>
|
<th style="width:15%"></th>
|
||||||
<th>Vehicle ID</th>
|
|
||||||
<th>End Odometer</th>
|
|
||||||
<th>Type</th>
|
|
||||||
<th>Destination City</th>
|
|
||||||
<th>Purpose</th>
|
|
||||||
<th>Notes</th>
|
|
||||||
<th>Gas Purchased</th>
|
|
||||||
<th>Date</th>
|
<th>Date</th>
|
||||||
|
<th>Driver</th>
|
||||||
|
<th>Tag Number</th>
|
||||||
|
<th>Odometer</th>
|
||||||
|
<th>MPG</th>
|
||||||
|
<th>Gas Purchased</th>
|
||||||
|
<th>Total Price</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
@for (var i = 0; i < Model.Count; i++)
|
@for (var i = 0; i < Model.Count; i++)
|
||||||
{
|
{
|
||||||
var viewModel = Model[i];
|
var viewModel = Model[i];
|
||||||
<tr id="log-@i">
|
<tr id="fuellog-@i" @if (viewModel.PreviouslyAdded && viewModel.LogId != null) { <text>class="complete"</text>}>
|
||||||
@using (Html.BeginForm("ImportCreate", "Log", FormMethod.Post))
|
@using (Html.BeginForm("Match", "FuelLog", FormMethod.Post))
|
||||||
{
|
{
|
||||||
@Html.EditorFor(x => viewModel)
|
<input type="hidden" name="fuelLogId" value="@viewModel.FuelLogId"/>
|
||||||
}
|
}
|
||||||
<td class="import-status"></td>
|
<td class="match-status">
|
||||||
<td class="import-message"></td>
|
@if (viewModel.PreviouslyAdded)
|
||||||
<td>@Html.ValueFor(x => viewModel.VehicleId)</td>
|
{
|
||||||
<td>@Html.ValueFor(x => viewModel.EndOdometer)</td>
|
<span class="label label-info">Previously Imported</span>
|
||||||
<td>@Html.ValueFor(x => viewModel.LogType)</td>
|
}
|
||||||
<td>@Html.ValueFor(x => viewModel.CityName)</td>
|
@if (viewModel.LogId != null)
|
||||||
<td>@Html.ValueFor(x => viewModel.Purpose)</td>
|
{
|
||||||
<td>@Html.ValueFor(x => viewModel.Notes)</td>
|
@Html.Partial("ImportMatchedLog", new ImportMatchedLogViewModel { LogId = viewModel.LogId.Value })
|
||||||
<td>@Html.ValueFor(x => viewModel.GasPurchased)</td>
|
}
|
||||||
<td>@Html.ValueFor(x => viewModel.Date)</td>
|
</td>
|
||||||
|
<td class="match-message"></td>
|
||||||
|
<td>@Html.ValueFor(x => viewModel.Date, "{0:d}")</td>
|
||||||
|
<td>@Html.ValueFor(x => viewModel.DriverFullName)</td>
|
||||||
|
<td>@Html.ValueFor(x => viewModel.TagNumber)</td>
|
||||||
|
<td>@Html.ValueFor(x => viewModel.Odometer)</td>
|
||||||
|
<td>@Html.ValueFor(x => viewModel.MPG)</td>
|
||||||
|
<td>@Html.ValueFor(x => viewModel.GasPurchased, "{0:0.000}")</td>
|
||||||
|
<td>@Html.ValueFor(x => viewModel.TotalPrice, "{0:C}")</td>
|
||||||
</tr>
|
</tr>
|
||||||
}
|
}
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
@section Scripts
|
@section Scripts
|
||||||
{
|
{
|
||||||
<script src="@Url.Content("~/Scripts/Shared/ImportCreate.js")" type="text/javascript"></script>
|
<script src="@Url.Content("~/Scripts/Shared/FuelLogImport.js")" type="text/javascript"></script>
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
$(function () {
|
$(function () {
|
||||||
importLogs("@ViewData["UserFullName"]");
|
importFuelLogs();
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
@model MileageTraker.Web.ViewModels.FuelLog.ImportMatchedLogViewModel
|
||||||
|
@{
|
||||||
|
Layout = null;
|
||||||
|
}
|
||||||
|
@Html.ActionLink("View Log", "Details", "Log", new{id=Model.LogId}, new{@class="btn btn-mini", target="_blank"})
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
@model MileageTraker.Web.ViewModels.FuelLog.FuelLogImportUploadViewModel
|
@model MileageTraker.Web.ViewModels.FuelLog.ImportUploadViewModel
|
||||||
@{
|
@{
|
||||||
ViewBag.Title = "Import Fuel Logs";
|
ViewBag.Title = "Import Fuel Logs";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,67 @@
|
|||||||
|
@using MileageTraker.Web.Utility
|
||||||
|
@model MileageTraker.Web.ViewModels.FuelLog.ResultsViewModel
|
||||||
|
|
||||||
|
@{
|
||||||
|
ViewBag.Title = "Fuel Logs";
|
||||||
|
var grid = new WebGrid(Model.Logs, rowsPerPage: 45);
|
||||||
|
var parameters = new {Model.Year, Model.Month};
|
||||||
|
}
|
||||||
|
@section Styles {
|
||||||
|
<link href="@Url.Content("~/Content/VehicleColors.css")" rel="stylesheet" type="text/css" />
|
||||||
|
}
|
||||||
|
@section Scripts {
|
||||||
|
<script type="text/javascript">
|
||||||
|
var availableLogYearMonths = @Html.Raw(Json.Encode(Model.AvailableYearMonths));
|
||||||
|
@if (Model.Year != null)
|
||||||
|
{
|
||||||
|
<text>var selectedYear = "@Model.Year";</text>
|
||||||
|
<text>var selectedMonth = "@Model.Month";</text>
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
}
|
||||||
|
|
||||||
|
@Html.Partial("_StatusMessage")
|
||||||
|
|
||||||
|
<div class="btn-toolbar pull-right">
|
||||||
|
@using (Html.BeginForm("Index", "Log", FormMethod.Get, new { id = "filter", @class = "form" }))
|
||||||
|
{
|
||||||
|
<div class="">
|
||||||
|
@*@Html.EditorForModel()*@
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h2 id="log-title">@ViewBag.Title</h2>
|
||||||
|
|
||||||
|
<div class="btn-toolbar clearfix">
|
||||||
|
@Html.ActionLink("Import", "ImportUpload", null, new { @class = "btn" })
|
||||||
|
@Html.ActionLink("Export", "Export", parameters, new { @class = "btn" })
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
@grid.GetHtml(columns:
|
||||||
|
grid.Columns(
|
||||||
|
grid.Column("Date", format: item => item.Date.ToString("d")),
|
||||||
|
grid.Column("DriverFullName", "Driver Name"),
|
||||||
|
grid.Column("TagNumber"),
|
||||||
|
grid.Column("Odometer"),
|
||||||
|
grid.Column("MPG"),
|
||||||
|
grid.Column("GasPurchased", "Gas Purchased", @<text>@String.Format("{0:0.000}", item.GasPurchased)</text>),
|
||||||
|
grid.Column("TotalPrice", "Total Price", @<text>@String.Format("{0:C}", item.TotalPrice)</text>),
|
||||||
|
grid.Column("Log", "Matched Log", @<text>
|
||||||
|
@(item.Log != null
|
||||||
|
? Html.ActionLink("View Log", "Details", "Log", new {id = item.Log.LogId}, new {@class = "btn btn-mini", target="_blank"})
|
||||||
|
: Html.ActionLink("Match", "Match", new {id = item.FuelLogId}, new {@class = "btn btn-warning btn-mini", target="_blank"}))
|
||||||
|
</text>),
|
||||||
|
grid.Column("Total Results: " + Model.Logs.Count(), canSort:false, format:
|
||||||
|
@<div class='btn-group'> @Html.ActionLink("Details", "Details", new { id = item.FuelLogId }, new { @class = "btn btn-mini" }) </div>)),
|
||||||
|
htmlAttributes: new { @class = "table table-striped table-bordered table-hover table-condensed"},
|
||||||
|
numericLinksCount: 20
|
||||||
|
)
|
||||||
|
</div>
|
||||||
|
@if (!Model.Logs.Any())
|
||||||
|
{
|
||||||
|
<div>
|
||||||
|
No results.
|
||||||
|
</div>
|
||||||
|
}
|
||||||
+10
-4
@@ -8,7 +8,7 @@
|
|||||||
</ProductVersion>
|
</ProductVersion>
|
||||||
<SchemaVersion>2.0</SchemaVersion>
|
<SchemaVersion>2.0</SchemaVersion>
|
||||||
<ProjectGuid>{36D4C321-E918-460F-B348-16A805F88884}</ProjectGuid>
|
<ProjectGuid>{36D4C321-E918-460F-B348-16A805F88884}</ProjectGuid>
|
||||||
<ProjectTypeGuids>{E3E379DF-F4C6-4180-9B81-6769533ABE47};{349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc}</ProjectTypeGuids>
|
<ProjectTypeGuids>{349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc}</ProjectTypeGuids>
|
||||||
<OutputType>Library</OutputType>
|
<OutputType>Library</OutputType>
|
||||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||||
<RootNamespace>MileageTraker.Web</RootNamespace>
|
<RootNamespace>MileageTraker.Web</RootNamespace>
|
||||||
@@ -230,9 +230,11 @@
|
|||||||
<Compile Include="ViewModels\CreateLog\ImportUploadViewModel.cs" />
|
<Compile Include="ViewModels\CreateLog\ImportUploadViewModel.cs" />
|
||||||
<Compile Include="ViewModels\DriverMileageItem.cs" />
|
<Compile Include="ViewModels\DriverMileageItem.cs" />
|
||||||
<Compile Include="ViewModels\DriverMileageViewModel.cs" />
|
<Compile Include="ViewModels\DriverMileageViewModel.cs" />
|
||||||
<Compile Include="ViewModels\FuelLog\FuelLogImportUploadViewModel.cs" />
|
<Compile Include="ViewModels\FuelLog\ImportFuelLogViewModel.cs" />
|
||||||
<Compile Include="ViewModels\FuelLog\LogQueryViewModel.cs" />
|
<Compile Include="ViewModels\FuelLog\ImportMatchedLogViewModel.cs" />
|
||||||
<Compile Include="ViewModels\FuelLog\FuelLogResultsViewModel.cs" />
|
<Compile Include="ViewModels\FuelLog\ImportUploadViewModel.cs" />
|
||||||
|
<Compile Include="ViewModels\FuelLog\FuelLogQueryViewModel.cs" />
|
||||||
|
<Compile Include="ViewModels\FuelLog\ResultsViewModel.cs" />
|
||||||
<Compile Include="ViewModels\Log\ImportLogViewModel.cs" />
|
<Compile Include="ViewModels\Log\ImportLogViewModel.cs" />
|
||||||
<Compile Include="ViewModels\Log\ImportUploadViewModel.cs" />
|
<Compile Include="ViewModels\Log\ImportUploadViewModel.cs" />
|
||||||
<Compile Include="ViewModels\Log\LogViewModel.cs" />
|
<Compile Include="ViewModels\Log\LogViewModel.cs" />
|
||||||
@@ -292,6 +294,7 @@
|
|||||||
<Content Include="Scripts\jquery.validate.min.js" />
|
<Content Include="Scripts\jquery.validate.min.js" />
|
||||||
<Content Include="Scripts\jquery.validate.unobtrusive.js" />
|
<Content Include="Scripts\jquery.validate.unobtrusive.js" />
|
||||||
<Content Include="Scripts\jquery.validate.unobtrusive.min.js" />
|
<Content Include="Scripts\jquery.validate.unobtrusive.min.js" />
|
||||||
|
<Content Include="Scripts\Shared\FuelLogImport.js" />
|
||||||
<Content Include="Views\Log\ImportFix.cshtml" />
|
<Content Include="Views\Log\ImportFix.cshtml" />
|
||||||
<Content Include="Views\Shared\EditorTemplates\HttpPostedFileBase.cshtml" />
|
<Content Include="Views\Shared\EditorTemplates\HttpPostedFileBase.cshtml" />
|
||||||
<Content Include="Views\City\Index.cshtml" />
|
<Content Include="Views\City\Index.cshtml" />
|
||||||
@@ -299,6 +302,9 @@
|
|||||||
<Content Include="Views\Shared\DisplayTemplates\LogQueryViewModel.cshtml" />
|
<Content Include="Views\Shared\DisplayTemplates\LogQueryViewModel.cshtml" />
|
||||||
<Content Include="Views\FuelLog\ImportUpload.cshtml" />
|
<Content Include="Views\FuelLog\ImportUpload.cshtml" />
|
||||||
<Content Include="Views\FuelLog\Import.cshtml" />
|
<Content Include="Views\FuelLog\Import.cshtml" />
|
||||||
|
<Content Include="Views\FuelLog\Index.cshtml" />
|
||||||
|
<Content Include="Views\FuelLog\ImportMatchedLog.cshtml" />
|
||||||
|
<Content Include="Views\FuelLog\Empty.cshtml" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Content Include="Content\Account.Login.css" />
|
<Content Include="Content\Account.Login.css" />
|
||||||
|
|||||||
Reference in New Issue
Block a user