Merge pull request #24 from hargata/fuelly.import

Fuelly.import
This commit is contained in:
Hargata Softworks
2024-01-07 23:14:06 -07:00
committed by GitHub
10 changed files with 125 additions and 102 deletions

View File

@@ -7,6 +7,7 @@ using CsvHelper;
using System.Globalization;
using Microsoft.AspNetCore.Authorization;
using CarCareTracker.External.Implementations;
using CarCareTracker.MapProfile;
namespace CarCareTracker.Controllers
{
@@ -122,12 +123,12 @@ namespace CarCareTracker.Controllers
}
#region "Bulk Imports"
[HttpGet]
public IActionResult GetBulkImportModalPartialView(string mode)
public IActionResult GetBulkImportModalPartialView(ImportMode mode)
{
return PartialView("_BulkDataImporter", mode);
}
[HttpPost]
public IActionResult ImportToVehicleIdFromCsv(int vehicleId, string mode, string fileName)
public IActionResult ImportToVehicleIdFromCsv(int vehicleId, ImportMode mode, string fileName)
{
if (vehicleId == default || string.IsNullOrWhiteSpace(fileName))
{
@@ -145,81 +146,85 @@ namespace CarCareTracker.Controllers
var config = new CsvHelper.Configuration.CsvConfiguration(System.Globalization.CultureInfo.InvariantCulture);
config.MissingFieldFound = null;
config.HeaderValidated = null;
config.PrepareHeaderForMatch = args => { return args.Header.Trim().ToLower(); };
using (var csv = new CsvReader(reader, config))
{
if (mode == "gasrecord")
csv.Context.RegisterClassMap<FuellyMapper>();
var records = csv.GetRecords<ImportModel>().ToList();
if (records.Any())
{
var records = csv.GetRecords<GasRecordImport>().ToList();
if (records.Any())
foreach (ImportModel importModel in records)
{
foreach (GasRecordImport recordToInsert in records)
if (mode == ImportMode.GasRecord)
{
//convert to gas model.
var convertedRecord = new GasRecord()
{
VehicleId = vehicleId,
Date = recordToInsert.Date,
Mileage = recordToInsert.Odometer,
Gallons = recordToInsert.FuelConsumed,
Cost = recordToInsert.Cost
Date = DateTime.Parse(importModel.Date),
Mileage = int.Parse(importModel.Odometer, NumberStyles.Any),
Gallons = decimal.Parse(importModel.FuelConsumed, NumberStyles.Any)
};
_gasRecordDataAccess.SaveGasRecordToVehicle(convertedRecord);
if (string.IsNullOrWhiteSpace(importModel.Cost) && !string.IsNullOrWhiteSpace(importModel.Price))
{
//cost was not given but price is.
//fuelly sometimes exports CSVs without total cost.
var parsedPrice = decimal.Parse(importModel.Price, NumberStyles.Any);
convertedRecord.Cost = convertedRecord.Gallons * parsedPrice;
} else
{
convertedRecord.Cost = decimal.Parse(importModel.Cost, NumberStyles.Any);
}
if (string.IsNullOrWhiteSpace(importModel.IsFillToFull) && !string.IsNullOrWhiteSpace(importModel.PartialFuelUp))
{
var parsedBool = importModel.PartialFuelUp.Trim() == "1";
convertedRecord.IsFillToFull = !parsedBool;
} else if (!string.IsNullOrWhiteSpace(importModel.IsFillToFull))
{
var parsedBool = importModel.IsFillToFull.Trim() == "1" || importModel.IsFillToFull.Trim() == "Full";
convertedRecord.IsFillToFull = parsedBool;
}
//insert record into db, check to make sure fuelconsumed is not zero so we don't get a divide by zero error.
if (convertedRecord.Gallons > 0)
{
_gasRecordDataAccess.SaveGasRecordToVehicle(convertedRecord);
}
}
}
}
else if (mode == "servicerecord")
{
var records = csv.GetRecords<ServiceRecordImport>().ToList();
if (records.Any())
{
foreach (ServiceRecordImport recordToInsert in records)
else if (mode == ImportMode.ServiceRecord)
{
var convertedRecord = new ServiceRecord()
{
VehicleId = vehicleId,
Date = recordToInsert.Date,
Mileage = recordToInsert.Odometer,
Description = recordToInsert.Description,
Notes = recordToInsert.Notes,
Cost = recordToInsert.Cost
Date = DateTime.Parse(importModel.Date),
Mileage = int.Parse(importModel.Odometer, NumberStyles.Any),
Description = string.IsNullOrWhiteSpace(importModel.Description) ? $"Service Record on {importModel.Date}" : importModel.Description,
Notes = string.IsNullOrWhiteSpace(importModel.Notes) ? "" : importModel.Notes,
Cost = decimal.Parse(importModel.Cost, NumberStyles.Any)
};
_serviceRecordDataAccess.SaveServiceRecordToVehicle(convertedRecord);
}
}
}
else if (mode == "repairrecord")
{
var records = csv.GetRecords<ServiceRecordImport>().ToList();
if (records.Any())
{
foreach (ServiceRecordImport recordToInsert in records)
else if (mode == ImportMode.RepairRecord)
{
var convertedRecord = new CollisionRecord()
{
VehicleId = vehicleId,
Date = recordToInsert.Date,
Mileage = recordToInsert.Odometer,
Description = recordToInsert.Description,
Notes = recordToInsert.Notes,
Cost = recordToInsert.Cost
Date = DateTime.Parse(importModel.Date),
Mileage = int.Parse(importModel.Odometer, NumberStyles.Any),
Description = string.IsNullOrWhiteSpace(importModel.Description) ? $"Repair Record on {importModel.Date}" : importModel.Description,
Notes = string.IsNullOrWhiteSpace(importModel.Notes) ? "" : importModel.Notes,
Cost = decimal.Parse(importModel.Cost, NumberStyles.Any)
};
_collisionRecordDataAccess.SaveCollisionRecordToVehicle(convertedRecord);
}
}
}
else if (mode == "taxrecord")
{
var records = csv.GetRecords<TaxRecordImport>().ToList();
if (records.Any())
{
foreach (TaxRecordImport recordToInsert in records)
else if (mode == ImportMode.TaxRecord)
{
var convertedRecord = new TaxRecord()
{
VehicleId = vehicleId,
Date = recordToInsert.Date,
Description = recordToInsert.Description,
Notes = recordToInsert.Notes,
Cost = recordToInsert.Cost
Date = DateTime.Parse(importModel.Date),
Description = string.IsNullOrWhiteSpace(importModel.Description) ? $"Tax Record on {importModel.Date}" : importModel.Description,
Notes = string.IsNullOrWhiteSpace(importModel.Notes) ? "" : importModel.Notes,
Cost = decimal.Parse(importModel.Cost, NumberStyles.Any)
};
_taxRecordDataAccess.SaveTaxRecordToVehicle(convertedRecord);
}
@@ -274,7 +279,8 @@ namespace CarCareTracker.Controllers
//reset unFactored vars
unFactoredConsumption = 0;
unFactoredMileage = 0;
} else
}
else
{
unFactoredConsumption += currentObject.Gallons;
unFactoredMileage += deltaMileage;
@@ -581,7 +587,7 @@ namespace CarCareTracker.Controllers
var currentMileage = GetMaxMileage(vehicleId);
var reminders = _reminderRecordDataAccess.GetReminderRecordsByVehicleId(vehicleId);
List<ReminderRecordViewModel> reminderViewModels = new List<ReminderRecordViewModel>();
foreach(var reminder in reminders)
foreach (var reminder in reminders)
{
var reminderViewModel = new ReminderRecordViewModel()
{
@@ -622,12 +628,13 @@ namespace CarCareTracker.Controllers
reminderViewModel.Urgency = ReminderUrgency.Urgent;
reminderViewModel.Metric = ReminderMetric.Date;
}
else if (reminder.Mileage < currentMileage + 100)
else if (reminder.Mileage < currentMileage + 100)
{
reminderViewModel.Urgency = ReminderUrgency.Urgent;
reminderViewModel.Metric = ReminderMetric.Odometer;
}
} else if (reminder.Metric == ReminderMetric.Date)
}
else if (reminder.Metric == ReminderMetric.Date)
{
if (reminder.Date < DateTime.Now)
{
@@ -641,7 +648,8 @@ namespace CarCareTracker.Controllers
{
reminderViewModel.Urgency = ReminderUrgency.Urgent;
}
} else if (reminder.Metric == ReminderMetric.Odometer)
}
else if (reminder.Metric == ReminderMetric.Odometer)
{
if (reminder.Mileage < currentMileage)
{
@@ -665,7 +673,7 @@ namespace CarCareTracker.Controllers
public IActionResult GetVehicleHaveUrgentOrPastDueReminders(int vehicleId)
{
var result = GetRemindersAndUrgency(vehicleId);
if (result.Where(x=>x.Urgency == ReminderUrgency.VeryUrgent || x.Urgency == ReminderUrgency.PastDue).Any())
if (result.Where(x => x.Urgency == ReminderUrgency.VeryUrgent || x.Urgency == ReminderUrgency.PastDue).Any())
{
return Json(true);
}
@@ -675,7 +683,7 @@ namespace CarCareTracker.Controllers
public IActionResult GetReminderRecordsByVehicleId(int vehicleId)
{
var result = GetRemindersAndUrgency(vehicleId);
result = result.OrderByDescending(x=>x.Urgency).ToList();
result = result.OrderByDescending(x => x.Urgency).ToList();
return PartialView("_ReminderRecords", result);
}
[HttpPost]

10
Enum/ImportMode.cs Normal file
View File

@@ -0,0 +1,10 @@
namespace CarCareTracker.Models
{
public enum ImportMode
{
ServiceRecord = 0,
RepairRecord = 1,
GasRecord = 2,
TaxRecord = 3
}
}

View File

@@ -0,0 +1,21 @@
using CarCareTracker.Models;
using CsvHelper.Configuration;
namespace CarCareTracker.MapProfile
{
public class FuellyMapper: ClassMap<ImportModel>
{
public FuellyMapper()
{
Map(m => m.Date).Name(["date", "fuelup_date"]);
Map(m => m.Odometer).Name(["odometer"]);
Map(m => m.FuelConsumed).Name(["gallons", "liters", "litres"]);
Map(m => m.Cost).Name(["cost", "total cost", "totalcost"]);
Map(m => m.Notes).Name("notes", "note");
Map(m => m.Price).Name(["price"]);
Map(m => m.PartialFuelUp).Name(["partial_fuelup"]);
Map(m => m.IsFillToFull).Name(["isfilltofull", "filled up"]);
Map(m => m.Description).Name(["description"]);
}
}
}

18
Models/ImportModel.cs Normal file
View File

@@ -0,0 +1,18 @@
namespace CarCareTracker.Models
{
/// <summary>
/// Import model used for importing Gas records.
/// </summary>
public class ImportModel
{
public string Date { get; set; }
public string Odometer { get; set; }
public string Description { get; set; }
public string Notes { get; set; }
public string FuelConsumed { get; set; }
public string Cost { get; set; }
public string Price { get; set; }
public string PartialFuelUp { get; set; }
public string IsFillToFull { get; set; }
}
}

View File

@@ -1,34 +0,0 @@
namespace CarCareTracker.Models
{
/// <summary>
/// Import model used for importing Gas records.
/// </summary>
public class GasRecordImport
{
public DateTime Date { get; set; }
public int Odometer { get; set; }
public decimal FuelConsumed { get; set; }
public decimal Cost { get; set; }
}
/// <summary>
/// Import model used for importing Service and Repair records.
/// </summary>
public class ServiceRecordImport
{
public DateTime Date { get; set; }
public int Odometer { get; set; }
public string Description { get; set; }
public string Notes { get; set; }
public decimal Cost { get; set; }
}
/// <summary>
/// Import model used for importing tax records.
/// </summary>
public class TaxRecordImport
{
public DateTime Date { get; set; }
public string Description { get; set; }
public string Notes { get; set; }
public decimal Cost { get; set; }
}
}

View File

@@ -1,4 +1,4 @@
@model string
@model ImportMode
<div class="modal-header">
<h5 class="modal-title">Import Data from CSV</h5>
<button type="button" class="btn-close" onclick="hideBulkImportModal()" aria-label="Close"></button>
@@ -16,13 +16,13 @@
<div class="alert alert-danger" role="alert">
Failure to format the data correctly can cause data corruption. Please make sure you make a copy of the local database before proceeding.
</div>
@if (Model == "gasrecord")
@if (Model == ImportMode.GasRecord)
{
<a class="btn btn-link" href="/defaults/gassample.csv" target="_blank">Download Sample</a>
} else if (Model == "servicerecord" || Model == "repairrecord")
} else if (Model == ImportMode.ServiceRecord || Model == ImportMode.RepairRecord)
{
<a class="btn btn-link" href="/defaults/servicerecordsample.csv" target="_blank">Download Sample</a>
} else if (Model == "taxrecord")
} else if (Model == ImportMode.TaxRecord)
{
<a class="btn btn-link" href="/defaults/taxrecordsample.csv" target="_blank">Download Sample</a>
}
@@ -52,13 +52,13 @@
if (data) {
successToast("Data Imported Successfully");
hideBulkImportModal();
if (mode == "gasrecord") {
if (mode == "GasRecord") {
getVehicleGasRecords(vehicleId);
} else if (mode == "servicerecord") {
} else if (mode == "ServiceRecord") {
getVehicleServiceRecords(vehicleId);
} else if (mode == "repairrecord") {
} else if (mode == "RepairRecord") {
getVehicleCollisionRecords(vehicleId);
} else if (mode == "taxrecord") {
} else if (mode == "TaxRecord") {
getVehicleTaxRecords(vehicleId);
}
} else {

View File

@@ -18,7 +18,7 @@
<span class="visually-hidden">Toggle Dropdown</span>
</button>
<ul class="dropdown-menu">
<li><a class="dropdown-item" href="#" onclick="showBulkImportModal('repairrecord')">Import via CSV</a></li>
<li><a class="dropdown-item" href="#" onclick="showBulkImportModal('RepairRecord')">Import via CSV</a></li>
</ul>
</div>
}

View File

@@ -37,7 +37,7 @@
<span class="visually-hidden">Toggle Dropdown</span>
</button>
<ul class="dropdown-menu">
<li><a class="dropdown-item" href="#" onclick="showBulkImportModal('gasrecord')">Import via CSV</a></li>
<li><a class="dropdown-item" href="#" onclick="showBulkImportModal('GasRecord')">Import via CSV</a></li>
</ul>
</div>
} else {

View File

@@ -18,7 +18,7 @@
<span class="visually-hidden">Toggle Dropdown</span>
</button>
<ul class="dropdown-menu">
<li><a class="dropdown-item" href="#" onclick="showBulkImportModal('servicerecord')">Import via CSV</a></li>
<li><a class="dropdown-item" href="#" onclick="showBulkImportModal('ServiceRecord')">Import via CSV</a></li>
</ul>
</div>
}

View File

@@ -1 +1 @@
{"UseDarkMode":true,"UsekWh":false,"EnableCsvImports":false,"UseMPG":true,"UseDescending":false,"EnableAuth":false,"UserNameHash":"","UserPasswordHash":""}
{"UseDarkMode":true,"EnableCsvImports":false,"UseMPG":true,"UseDescending":false,"EnableAuth":false,"UserNameHash":"","UserPasswordHash":""}