Box modifications
This commit is contained in:
@@ -0,0 +1,24 @@
|
||||
using System;
|
||||
|
||||
namespace InventoryTraker.Web.Services
|
||||
{
|
||||
public class ImportException : Exception
|
||||
{
|
||||
public readonly string[] Messages;
|
||||
|
||||
public ImportException(string message, Exception innerException) : base(message, innerException)
|
||||
{
|
||||
Messages = new[] { message };
|
||||
}
|
||||
|
||||
public ImportException(string message) : base(message)
|
||||
{
|
||||
Messages = new [] {message};
|
||||
}
|
||||
|
||||
public ImportException(string[] messages) : base(string.Join(Environment.NewLine, messages))
|
||||
{
|
||||
Messages = messages;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using AutoMapper;
|
||||
using CsvHelper;
|
||||
using InventoryTraker.Web.Core;
|
||||
using InventoryTraker.Web.Models;
|
||||
using InventoryTraker.Web.Utilities;
|
||||
|
||||
namespace InventoryTraker.Web.Services
|
||||
{
|
||||
public class InventoryImporter
|
||||
{
|
||||
private readonly IMapper _mapper;
|
||||
|
||||
public InventoryImporter(IMapper mapper)
|
||||
{
|
||||
_mapper = mapper;
|
||||
}
|
||||
|
||||
public IEnumerable<Inventory> Import(FileSystemInfo excelFile)
|
||||
{
|
||||
var inventoryParser = new InventoryParser(excelFile);
|
||||
|
||||
IList<InventoryAddForm> forms;
|
||||
try
|
||||
{
|
||||
forms = inventoryParser.Parse();
|
||||
}
|
||||
catch (CsvMissingFieldException e)
|
||||
{
|
||||
var fieldname = Regex.Replace(e.Message, ".*'(.*)'.*", "$1");
|
||||
|
||||
throw new ImportException($"Cannot find required field titled '{fieldname}'", e);
|
||||
}
|
||||
//catch (CsvBadDataException e)
|
||||
//{
|
||||
// throw new ImportException(e.Message, e);
|
||||
//}
|
||||
//catch (CsvParserException e)
|
||||
//{
|
||||
// throw new ImportException(e.Message, e);
|
||||
//}
|
||||
//catch (CsvReaderException e)
|
||||
//{
|
||||
// throw new ImportException(e.Message, e);
|
||||
//}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new ImportException(e.Message, e);
|
||||
}
|
||||
|
||||
IList<Inventory> inventories = new List<Inventory>();
|
||||
var validationErrors = new List<string>();
|
||||
foreach (var addForm in forms)
|
||||
{
|
||||
var results = new List<ValidationResult>();
|
||||
var context = new ValidationContext(addForm, null, null);
|
||||
if (!Validator.TryValidateObject(addForm, context, results))
|
||||
{
|
||||
// results will contain all the failed validation errors.
|
||||
validationErrors.AddRange(
|
||||
results.Select(result => $"{addForm.Id} - ${result.ErrorMessage}")
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
inventories.Add(_mapper.Map<Inventory>(addForm));
|
||||
}
|
||||
}
|
||||
|
||||
if (validationErrors.Any())
|
||||
{
|
||||
throw new ImportException(string.Join(Environment.NewLine, validationErrors));
|
||||
}
|
||||
|
||||
return inventories;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,176 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using AutoMapper;
|
||||
using InventoryTraker.Web.Core;
|
||||
using InventoryTraker.Web.Data;
|
||||
using InventoryTraker.Web.Models;
|
||||
using InventoryTraker.Web.Utilities;
|
||||
|
||||
namespace InventoryTraker.Web.Services
|
||||
{
|
||||
public class ReportService
|
||||
{
|
||||
private readonly AppDbContext _context;
|
||||
private readonly IMapper _mapper;
|
||||
|
||||
public ReportService(AppDbContext context, IMapper mapper)
|
||||
{
|
||||
_context = context;
|
||||
_mapper = mapper;
|
||||
}
|
||||
|
||||
public DistributionReport[] GetDistributionReport(DateTime startDate, DateTime endDate)
|
||||
{
|
||||
var query =
|
||||
from t in _context.Transactions
|
||||
where
|
||||
t.TransactionType == TransactionType.Distributed
|
||||
&& t.TransactionDate >= startDate
|
||||
&& t.TransactionDate < endDate
|
||||
group t by new { t.TransactionDate, t.Destination }
|
||||
into g
|
||||
select new
|
||||
{
|
||||
Date = g.Key.TransactionDate,
|
||||
Destination = g.Key.Destination,
|
||||
Transactions = g.ToList()
|
||||
};
|
||||
|
||||
var report =
|
||||
from item in query.ToArray()
|
||||
select new DistributionReport
|
||||
{
|
||||
Date = item.Date,
|
||||
Destination = item.Destination,
|
||||
Transactions =
|
||||
_mapper.Map<IList<Transaction>, IList<TransactionViewModel>>
|
||||
(item.Transactions).ToArray()
|
||||
};
|
||||
|
||||
return report.ToArray();
|
||||
}
|
||||
|
||||
public MovementReport GetMovementReport(DateTime month)
|
||||
{
|
||||
var startDate = month;
|
||||
var endDate = startDate.AddMonths(1);
|
||||
|
||||
return
|
||||
new MovementReport
|
||||
{
|
||||
Items = GetMovementReportItems(startDate, endDate),
|
||||
Month = month
|
||||
};
|
||||
}
|
||||
|
||||
private IEnumerable<MovementReportItem> GetMovementReportItems(DateTime startDate, DateTime endDate)
|
||||
{
|
||||
var transactionsMostRecentBefore =
|
||||
(from transaction in _context.Transactions
|
||||
where
|
||||
transaction.TransactionDate < startDate
|
||||
group transaction by transaction.Inventory
|
||||
into g
|
||||
let mostRecent =
|
||||
g.OrderByDescending(t => t.TransactionDate)
|
||||
.ThenBy(t => t.CurrentQuantity) // for days with multiple, assume it's the smallest
|
||||
.FirstOrDefault()
|
||||
where mostRecent.CurrentQuantity > 0
|
||||
select mostRecent).ToList();
|
||||
|
||||
var transactionSums =
|
||||
(from transaction in _context.Transactions
|
||||
where
|
||||
transaction.TransactionDate >= startDate
|
||||
&& transaction.TransactionDate < endDate
|
||||
group transaction by transaction.Inventory
|
||||
into g
|
||||
let addedQty = g.Sum(t => t.AddedQuantity)
|
||||
let distributed = g.Where(t => t.TransactionType == TransactionType.Distributed)
|
||||
let distributedQty = distributed.Any() ? distributed.Sum(t => t.RemovedQuantity) : 0
|
||||
let adjustment = g.Where(t =>
|
||||
t.TransactionType == TransactionType.Expired
|
||||
|| t.TransactionType == TransactionType.Loss)
|
||||
let adjustmentQty = adjustment.Any() ? adjustment.Sum(t => t.RemovedQuantity) : 0
|
||||
let endingQty =
|
||||
g
|
||||
.OrderByDescending(t => t.TransactionDate)
|
||||
.ThenBy(t => t.CurrentQuantity)
|
||||
.FirstOrDefault().CurrentQuantity
|
||||
select new
|
||||
{
|
||||
Inventory = g.Key,
|
||||
addedQty,
|
||||
adjustmentQty,
|
||||
distributedQty,
|
||||
endingQty
|
||||
}).ToList();
|
||||
|
||||
var inventoryReportItems =
|
||||
transactionsMostRecentBefore.FullOuterJoin( // source
|
||||
transactionSums, // inner
|
||||
before => before.Inventory.Id, // fk
|
||||
sums => sums.Inventory.Id, // pk
|
||||
(before, sums, r) =>
|
||||
{
|
||||
var item = new MovementReportInventoryItem();
|
||||
|
||||
if (before != null)
|
||||
{
|
||||
item.Inventory = before.Inventory;
|
||||
item.BeginningQuantity = before.CurrentQuantity;
|
||||
if (sums != null)
|
||||
{
|
||||
item.AddedQuantity = sums.addedQty;
|
||||
item.DistributedQuantity = sums.distributedQty;
|
||||
item.AdjustmentQuantity = sums.adjustmentQty;
|
||||
item.EndingQuantity = sums.endingQty;
|
||||
}
|
||||
else // no change
|
||||
{
|
||||
item.EndingQuantity = item.BeginningQuantity;
|
||||
}
|
||||
}
|
||||
else if (sums != null) // item was added in this time period
|
||||
{
|
||||
item.Inventory = sums.Inventory;
|
||||
item.AddedQuantity = sums.addedQty;
|
||||
item.DistributedQuantity = sums.distributedQty;
|
||||
item.AdjustmentQuantity = sums.adjustmentQty;
|
||||
item.EndingQuantity = sums.endingQty;
|
||||
}
|
||||
item.TotalAvailableQuantity = item.BeginningQuantity + item.AddedQuantity;
|
||||
return item;
|
||||
}).ToArray();
|
||||
|
||||
// group by inventory type
|
||||
var inventoryTypeReportItems =
|
||||
from item in inventoryReportItems
|
||||
group item by item.Inventory.InventoryType
|
||||
into grp
|
||||
select new MovementReportItem
|
||||
{
|
||||
InventoryType = _mapper.Map<InventoryTypeViewModel>(grp.Key),
|
||||
BeginningQuantity = grp.Sum(g => g.BeginningQuantity),
|
||||
AddedQuantity = grp.Sum(g => g.AddedQuantity),
|
||||
TotalAvailableQuantity = grp.Sum(g => g.TotalAvailableQuantity),
|
||||
DistributedQuantity = grp.Sum(g => g.DistributedQuantity),
|
||||
AdjustmentQuantity = grp.Sum(g => g.AdjustmentQuantity),
|
||||
EndingQuantity = grp.Sum(g => g.EndingQuantity)
|
||||
};
|
||||
return inventoryTypeReportItems;
|
||||
}
|
||||
|
||||
private class MovementReportInventoryItem
|
||||
{
|
||||
public Inventory Inventory { get; set; }
|
||||
public int BeginningQuantity { get; set; }
|
||||
public int AddedQuantity { get; set; }
|
||||
public int TotalAvailableQuantity { get; set; }
|
||||
public int DistributedQuantity { get; set; }
|
||||
public int AdjustmentQuantity { get; set; }
|
||||
public int EndingQuantity { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user