Import FuelLog

This commit is contained in:
2015-09-09 22:45:27 -04:00
parent f3a7249793
commit 56dd091178
21 changed files with 500 additions and 15 deletions
+1
View File
@@ -447,6 +447,7 @@ namespace MileageTraker.Web.DAL
let existingOdometer = log.EndOdometer
where
log.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
+76
View File
@@ -0,0 +1,76 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using CsvHelper;
using CsvHelper.Configuration;
using MileageTraker.Web.Models;
using MileageTraker.Web.Utility;
namespace MileageTraker.Web.DAL
{
public class FuelmanCsvImporter
{
private sealed class FuelmanCsvClassMap : CsvClassMap<FuelLog>
{
public FuelmanCsvClassMap()
{
Map(m => m.Date).ConvertUsing(row =>
{
var date = row.GetField("CEDATE");
var time = row.GetField<int>("CETIME");
var dttm = string.Format(@"{0} {1:00:00}", date, time);
return DateTime.ParseExact(dttm, @"M/d/yyyy HH:mm", CultureInfo.InvariantCulture);
});
Map(m => m.DriverFullName).ConvertUsing(row =>
{
var name = row.GetField("CEEMNAME");
return NameNormalizer.Normalize(name);
});
Map(m => m.TagNumber).Name("CEVEHNO");
Map(m => m.Odometer).Name("CEODOMETER");
Map(m => m.CityName).ConvertUsing(row =>
{
var city = row.GetField("CESITCTY");
return city.ToLower().ToTitleCase();
});
Map(m => m.MPG).Name("CEMPG");
Map(m => m.GasPurchased).Name("CEQTY");
Map(m => m.TotalPrice).Name("CECUSAMT");
}
}
public static IEnumerable<FuelLog> Import(string filename)
{
var fileInfo = new FileInfo(filename);
if (!fileInfo.Exists)
throw new ImportException("Cannot find file '" + filename + "'");
using (var tr = File.OpenText(fileInfo.FullName))
{
var csv = new CsvReader(tr);
csv.Configuration.RegisterClassMap<FuelmanCsvClassMap>();
var fuelLogs = new List<FuelLog>();
while (csv.Read())
{
try
{
// Skip non-FUEL entries
if (csv.GetField<string>("CEPRDTYPE") != "FUEL")
continue;
fuelLogs.Add(csv.GetRecord<FuelLog>());
}
catch (Exception ex)
{
throw new ImportException("Problem with document encountered on row " + csv.Row + ". " + ex.Message);
}
}
return fuelLogs;
}
}
}
}
+11
View File
@@ -0,0 +1,11 @@
using System;
namespace MileageTraker.Web.DAL
{
public class ImportException : Exception
{
public ImportException(string message) : base(message)
{
}
}
}
-11
View File
@@ -1,11 +0,0 @@
using System;
namespace MileageTraker.Web.DAL
{
public class LogImportException : Exception
{
public LogImportException(string message) : base(message)
{
}
}
}
+1 -1
View File
@@ -35,7 +35,7 @@ namespace MileageTraker.Web.DAL
var missingHeaderColumns = GetMissingHeaderColumns(columnIndex.Keys);
if (missingHeaderColumns.Any())
{
throw new LogImportException(string.Format("Excel document missing columns: {0}", string.Join(", ", missingHeaderColumns)));
throw new ImportException(string.Format("Excel document missing columns: {0}", string.Join(", ", missingHeaderColumns)));
}
for (var r = 1; r <= sheet.Cells.LastRowIndex; r++)
+38
View File
@@ -0,0 +1,38 @@
using System;
using System.ComponentModel.DataAnnotations;
namespace MileageTraker.Web.Models
{
public class FuelLog
{
[Required]
[DataType(DataType.Date)]
public DateTime Date { get; set; }
[Required]
[StringLength(128)]
public string DriverFullName { get; set; }
[Required]
[Display(Name = "Tag#")]
public string TagNumber { get; set; }
[Required]
[Range(1, 500000, ErrorMessage = "Between 1 and 500k")]
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; }
// Matched log
public virtual Log Log { get; set; }
}
}
+7
View File
@@ -2,6 +2,7 @@ using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Data.SqlTypes;
using System.Globalization;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
@@ -21,6 +22,12 @@ namespace MileageTraker.Web.Utility
current + (Char.IsUpper(c) ? " " + c : c.ToString()));
}
public static string ToTitleCase(this string str)
{
// http://stackoverflow.com/q/1943273/99492
return CultureInfo.CurrentCulture.TextInfo.ToTitleCase(str);
}
private static T GetAttribute<T>(this Enum enumeration) where T : Attribute
{
var type = enumeration.GetType();
+19
View File
@@ -0,0 +1,19 @@
using System.Text.RegularExpressions;
namespace MileageTraker.Web.Utility
{
public static class NameNormalizer
{
private const string NamePattern = @"(?<Last>\w+),\s*(?<First>\w+)(?:\s*)?(?<Suffix>(jr|sr|iii))?";
private static readonly Regex NameRegex = new Regex(NamePattern, RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace | RegexOptions.Compiled);
public static string Normalize(string name)
{
var match = NameRegex.Match(name);
if (!match.Success)
return name;
return string.Format("{0} {1} {2}",
match.Groups["First"], match.Groups["Last"], match.Groups["Suffix"]).TrimEnd();
}
}
}
+1 -1
View File
@@ -7,7 +7,7 @@ namespace MileageTraker.Web.Utility
{
protected override string FormatValueCore(string value)
{
return CultureInfo.CurrentCulture.TextInfo.ToTitleCase(value);
return value.ToTitleCase();
}
}
}
+2 -1
View File
@@ -151,7 +151,7 @@
<Compile Include="DAL\CodeFirstRoleProvider.cs" />
<Compile Include="DAL\FuelmanCsvImporter.cs" />
<Compile Include="DAL\LogImporter.cs" />
<Compile Include="DAL\LogImportException.cs" />
<Compile Include="DAL\ImportException.cs" />
<Compile Include="DAL\LogImportTemplateWriter.cs" />
<Compile Include="DAL\UninitializedAccountException.cs" />
<Compile Include="DAL\UserAccountDisabledException.cs" />
@@ -210,6 +210,7 @@
<Compile Include="Models\DomainRules.cs" />
<Compile Include="Models\FuelLog.cs" />
<Compile Include="Models\PurposeType.cs" />
<Compile Include="Utility\NameNormalizer.cs" />
<Compile Include="ViewModels\Account\ResetPasswordViewModel.cs" />
<Compile Include="Models\Role.cs" />
<Compile Include="Models\User.cs" />
+1
View File
@@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="AutoMapper" version="3.3.1" targetFramework="net45" />
<package id="CsvHelper" version="2.13.2.0" targetFramework="net45" />
<package id="EntityFramework" version="6.1.3" targetFramework="net45" />
<package id="ExcelLibrary" version="1.2011.7.30" />
<package id="FontAwesome" version="4.0.3.1" targetFramework="net40" />