Export Distribution report
This commit is contained in:
@@ -63,6 +63,7 @@
|
|||||||
<Compile Include="App_Start\AutoMapperConfig.cs" />
|
<Compile Include="App_Start\AutoMapperConfig.cs" />
|
||||||
<Compile Include="Models\InventoryAddForm.cs" />
|
<Compile Include="Models\InventoryAddForm.cs" />
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
|
<Compile Include="Utilities\DistributionReportWriterTests.cs" />
|
||||||
<Compile Include="Utilities\MovementReportWriterTests.cs" />
|
<Compile Include="Utilities\MovementReportWriterTests.cs" />
|
||||||
<Compile Include="Utilities\InventoryTypeParserTests.cs" />
|
<Compile Include="Utilities\InventoryTypeParserTests.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|||||||
@@ -0,0 +1,68 @@
|
|||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using Heroic.AutoMapper;
|
||||||
|
using InventoryTraker.Web.Core;
|
||||||
|
using InventoryTraker.Web.Models;
|
||||||
|
using InventoryTraker.Web.Utilities;
|
||||||
|
using NUnit.Framework;
|
||||||
|
|
||||||
|
namespace InventoryTraker.Web.Tests.Utilities
|
||||||
|
{
|
||||||
|
[TestFixture]
|
||||||
|
public class DistributionReportWriterTests
|
||||||
|
{
|
||||||
|
[OneTimeSetUp]
|
||||||
|
public void StartUp()
|
||||||
|
{
|
||||||
|
HeroicAutoMapperConfigurator.LoadMapsFromAssemblyContainingTypeAndReferencedAssemblies<Inventory>();
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly DistributionReport[] _distributionReports =
|
||||||
|
{
|
||||||
|
new DistributionReport
|
||||||
|
{
|
||||||
|
Destination = "First City",
|
||||||
|
Date = new DateTime(2016, 1, 1),
|
||||||
|
Transactions = new[]
|
||||||
|
{
|
||||||
|
new TransactionViewModel
|
||||||
|
{
|
||||||
|
Name = "Beans",
|
||||||
|
ContainerType = "#300 cans",
|
||||||
|
UnitsPerCase = 24,
|
||||||
|
Destination = "First City",
|
||||||
|
RemovedQuantity = 3
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
new DistributionReport
|
||||||
|
{
|
||||||
|
Destination = "Second City",
|
||||||
|
Date = new DateTime(2016, 2, 1),
|
||||||
|
Transactions = new[]
|
||||||
|
{
|
||||||
|
new TransactionViewModel
|
||||||
|
{
|
||||||
|
Name = "Peanut Butter",
|
||||||
|
ContainerType = "Jars",
|
||||||
|
UnitsPerCase = 24,
|
||||||
|
Destination = "Second City",
|
||||||
|
RemovedQuantity = 4
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
[Test, Explicit]
|
||||||
|
public void Write()
|
||||||
|
{
|
||||||
|
using
|
||||||
|
(var outputFile
|
||||||
|
= new StreamWriter(Path.Combine(@"c:\temp", "DistributionReport.xlsx")))
|
||||||
|
{
|
||||||
|
var writer = new DistributionReportWriter();
|
||||||
|
writer.WriteStream(_distributionReports, outputFile.BaseStream);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using Heroic.AutoMapper;
|
using Heroic.AutoMapper;
|
||||||
using InventoryTraker.Web.Core;
|
using InventoryTraker.Web.Core;
|
||||||
@@ -18,7 +17,8 @@ namespace InventoryTraker.Web.Tests.Utilities
|
|||||||
HeroicAutoMapperConfigurator.LoadMapsFromAssemblyContainingTypeAndReferencedAssemblies<Inventory>();
|
HeroicAutoMapperConfigurator.LoadMapsFromAssemblyContainingTypeAndReferencedAssemblies<Inventory>();
|
||||||
}
|
}
|
||||||
|
|
||||||
readonly MovementReport _movementReport = new MovementReport
|
private readonly MovementReport _movementReport
|
||||||
|
= new MovementReport
|
||||||
{
|
{
|
||||||
Month = new DateTime(2016, 04, 1),
|
Month = new DateTime(2016, 04, 1),
|
||||||
Items = new[]
|
Items = new[]
|
||||||
|
|||||||
@@ -27,6 +27,29 @@ namespace InventoryTraker.Web.Controllers
|
|||||||
}
|
}
|
||||||
|
|
||||||
public ActionResult Distribution(DateTime startDate, DateTime endDate)
|
public ActionResult Distribution(DateTime startDate, DateTime endDate)
|
||||||
|
{
|
||||||
|
var report = GetDistributionReport(startDate, endDate);
|
||||||
|
|
||||||
|
return BetterJson(report.ToArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
public ActionResult DistributionExcel(DateTime startDate, DateTime endDate)
|
||||||
|
{
|
||||||
|
var report = GetDistributionReport(startDate, endDate);
|
||||||
|
|
||||||
|
var writer = new DistributionReportWriter();
|
||||||
|
var excel = writer.Write(report);
|
||||||
|
|
||||||
|
var filename = $"InventoryDistributionReport{startDate:yyyyMMdd}-{endDate:yyyyMMdd}.xlsx";
|
||||||
|
|
||||||
|
return
|
||||||
|
new FileContentResult(excel, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
|
||||||
|
{
|
||||||
|
FileDownloadName = filename
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private DistributionReport[] GetDistributionReport(DateTime startDate, DateTime endDate)
|
||||||
{
|
{
|
||||||
var query =
|
var query =
|
||||||
from t in _context.Transactions
|
from t in _context.Transactions
|
||||||
@@ -54,7 +77,7 @@ namespace InventoryTraker.Web.Controllers
|
|||||||
(item.Transactions).ToArray()
|
(item.Transactions).ToArray()
|
||||||
};
|
};
|
||||||
|
|
||||||
return BetterJson(report.ToArray());
|
return report.ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
@@ -196,9 +219,8 @@ namespace InventoryTraker.Web.Controllers
|
|||||||
};
|
};
|
||||||
return inventoryTypeReportItems;
|
return inventoryTypeReportItems;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
internal class MovementReportInventoryItem
|
private class MovementReportInventoryItem
|
||||||
{
|
{
|
||||||
public Inventory Inventory { get; set; }
|
public Inventory Inventory { get; set; }
|
||||||
public int BeginningQuantity { get; set; }
|
public int BeginningQuantity { get; set; }
|
||||||
@@ -208,4 +230,5 @@ namespace InventoryTraker.Web.Controllers
|
|||||||
public int AdjustmentQuantity { get; set; }
|
public int AdjustmentQuantity { get; set; }
|
||||||
public int EndingQuantity { get; set; }
|
public int EndingQuantity { get; set; }
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -390,6 +390,7 @@
|
|||||||
<Compile Include="Utilities\InventoryTypeParser.cs" />
|
<Compile Include="Utilities\InventoryTypeParser.cs" />
|
||||||
<Compile Include="Utilities\DateExtensions.cs" />
|
<Compile Include="Utilities\DateExtensions.cs" />
|
||||||
<Compile Include="Utilities\JsonExtensions.cs" />
|
<Compile Include="Utilities\JsonExtensions.cs" />
|
||||||
|
<Compile Include="Utilities\DistributionReportWriter.cs" />
|
||||||
<Compile Include="Utilities\MovementReportWriter.cs" />
|
<Compile Include="Utilities\MovementReportWriter.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -0,0 +1,89 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using AutoMapper;
|
||||||
|
using ClosedXML.Excel;
|
||||||
|
using CsvHelper;
|
||||||
|
using CsvHelper.Configuration;
|
||||||
|
using CsvHelper.Excel;
|
||||||
|
using Heroic.AutoMapper;
|
||||||
|
using InventoryTraker.Web.Models;
|
||||||
|
|
||||||
|
namespace InventoryTraker.Web.Utilities
|
||||||
|
{
|
||||||
|
public class DistributionReportWriter
|
||||||
|
{
|
||||||
|
public class DistributionReportExportItem : IMapFrom<TransactionViewModel>, IHaveCustomMappings
|
||||||
|
{
|
||||||
|
public string Name { get; set; }
|
||||||
|
public string UnitsPerCaseContainerType { get; set; }
|
||||||
|
public string ExpirationDate { get; set; }
|
||||||
|
public string RemovedQuantity { get; set; }
|
||||||
|
public string UnitQuantity { get; set; }
|
||||||
|
public string Weight { get; set; }
|
||||||
|
|
||||||
|
public void CreateMappings(IMapperConfiguration configuration)
|
||||||
|
{
|
||||||
|
configuration.CreateMap<TransactionViewModel, DistributionReportExportItem>()
|
||||||
|
.ForMember(d => d.Name, opt => opt.MapFrom(i => i.Name))
|
||||||
|
.ForMember(d => d.UnitsPerCaseContainerType,
|
||||||
|
opt => opt.MapFrom(i => $"{i.UnitsPerCase} / {i.ContainerType}"))
|
||||||
|
.ForMember(d => d.ExpirationDate,
|
||||||
|
opt => opt.MapFrom(i => i.ExpirationDate.ToShortDateString()))
|
||||||
|
.ForMember(d => d.UnitQuantity,
|
||||||
|
opt => opt.MapFrom(i => i.RemovedQuantity*i.UnitsPerCase))
|
||||||
|
.ForMember(d => d.Weight,
|
||||||
|
opt => opt.MapFrom(i => $"{i.WeightPerCase*i.RemovedQuantity:0} lbs"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private sealed class DistributionReportMap : CsvClassMap<DistributionReportExportItem>
|
||||||
|
{
|
||||||
|
public DistributionReportMap()
|
||||||
|
{
|
||||||
|
Map(m => m.Name).Name("Name of Commodity");
|
||||||
|
Map(m => m.UnitsPerCaseContainerType).Name("Pack Size / Units per Case");
|
||||||
|
Map(m => m.ExpirationDate).Name("Expiration Date");
|
||||||
|
Map(m => m.RemovedQuantity).Name("Case Quantity");
|
||||||
|
Map(m => m.UnitQuantity).Name("Unit Quantity");
|
||||||
|
Map(m => m.Weight).Name("Weight");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] Write(IEnumerable<DistributionReport> reports)
|
||||||
|
{
|
||||||
|
using (var stream = new MemoryStream())
|
||||||
|
{
|
||||||
|
WriteStream(reports, stream);
|
||||||
|
return stream.ToArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void WriteStream(IEnumerable<DistributionReport> reports, Stream stream)
|
||||||
|
{
|
||||||
|
using (var workbook = new XLWorkbook(XLEventTracking.Disabled))
|
||||||
|
{
|
||||||
|
var worksheet = workbook.AddWorksheet("Distribution Report");
|
||||||
|
using (var writer = new CsvWriter(new ExcelSerializer(worksheet)))
|
||||||
|
{
|
||||||
|
writer.Configuration.RegisterClassMap(new DistributionReportMap());
|
||||||
|
|
||||||
|
foreach (var report in reports)
|
||||||
|
{
|
||||||
|
writer.WriteField(report.Destination);
|
||||||
|
writer.NextRecord();
|
||||||
|
writer.WriteField(report.Date.ToShortDateString());
|
||||||
|
writer.NextRecord();
|
||||||
|
var items =
|
||||||
|
Mapper.Map<IEnumerable<TransactionViewModel>, IEnumerable<DistributionReportExportItem>>
|
||||||
|
(report.Transactions)
|
||||||
|
.OrderBy(i => i.Name);
|
||||||
|
writer.WriteRecords(items);
|
||||||
|
}
|
||||||
|
workbook.SaveAs(stream);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -93,9 +93,6 @@ namespace InventoryTraker.Web.Utilities
|
|||||||
|
|
||||||
public void WriteStream(MovementReport report, Stream stream)
|
public void WriteStream(MovementReport report, Stream stream)
|
||||||
{
|
{
|
||||||
var csvConfiguration = new CsvConfiguration();
|
|
||||||
csvConfiguration.RegisterClassMap<MovementReportMap>();
|
|
||||||
|
|
||||||
using (var workbook = new XLWorkbook(XLEventTracking.Disabled))
|
using (var workbook = new XLWorkbook(XLEventTracking.Disabled))
|
||||||
{
|
{
|
||||||
var worksheet = workbook.AddWorksheet("Monthly Inventory Report");
|
var worksheet = workbook.AddWorksheet("Monthly Inventory Report");
|
||||||
|
|||||||
@@ -13,6 +13,9 @@
|
|||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
<date-range-query query-fn="vm.loadData"></date-range-query>
|
<date-range-query query-fn="vm.loadData"></date-range-query>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="panel-footer" ng-show="vm.distributionData.length">
|
||||||
|
<button ng-click="vm.export(vm.query)"><i class="fa fa-file-excel-o" aria-hidden="true"></i> Export</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -3,10 +3,15 @@
|
|||||||
|
|
||||||
window.app.controller('DistributionReportController', DistributionReportController);
|
window.app.controller('DistributionReportController', DistributionReportController);
|
||||||
|
|
||||||
DistributionReportController.$inject = ['$scope', 'reportSvc'];
|
DistributionReportController.$inject = ['$scope', 'reportSvc', 'downloadSvc'];
|
||||||
function DistributionReportController($scope, reportSvc) {
|
function DistributionReportController($scope, reportSvc, downloadSvc) {
|
||||||
var vm = this;
|
var vm = this;
|
||||||
vm.loadData = reportSvc.loadDistributionReport;
|
vm.loadData = reportSvc.loadDistributionReport;
|
||||||
|
vm.query = reportSvc.distributionQuery;
|
||||||
vm.distributionData = reportSvc.distributionData;
|
vm.distributionData = reportSvc.distributionData;
|
||||||
|
vm.export = function (params) {
|
||||||
|
reportSvc.exportDistributionReport(params)
|
||||||
|
.success(downloadSvc.success);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
@@ -4,11 +4,14 @@
|
|||||||
reportSvc.$inject = ['$http'];
|
reportSvc.$inject = ['$http'];
|
||||||
function reportSvc($http) {
|
function reportSvc($http) {
|
||||||
var distributionData = [];
|
var distributionData = [];
|
||||||
|
var distributionQuery = {};
|
||||||
var movementData = {};
|
var movementData = {};
|
||||||
|
|
||||||
var svc = {
|
var svc = {
|
||||||
distributionData: distributionData,
|
distributionData: distributionData,
|
||||||
|
distributionQuery: distributionQuery,
|
||||||
loadDistributionReport: loadDistributionReport,
|
loadDistributionReport: loadDistributionReport,
|
||||||
|
exportDistributionReport: exportDistributionReport,
|
||||||
movementData: movementData,
|
movementData: movementData,
|
||||||
loadMovementData: loadMovementData,
|
loadMovementData: loadMovementData,
|
||||||
exportMovementData: exportMovementData
|
exportMovementData: exportMovementData
|
||||||
@@ -19,10 +22,15 @@
|
|||||||
function loadDistributionReport(query) {
|
function loadDistributionReport(query) {
|
||||||
return $http.post('/Report/Distribution', query)
|
return $http.post('/Report/Distribution', query)
|
||||||
.success(function (data) {
|
.success(function (data) {
|
||||||
|
distributionQuery = angular.copy(query, distributionQuery);
|
||||||
angular.copy(data, distributionData);
|
angular.copy(data, distributionData);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function exportDistributionReport(query) {
|
||||||
|
return $http.post('/Report/DistributionExcel', query, { responseType: 'arraybuffer' });
|
||||||
|
}
|
||||||
|
|
||||||
function loadMovementData(query) {
|
function loadMovementData(query) {
|
||||||
return $http.post('/Report/Movement', query)
|
return $http.post('/Report/Movement', query)
|
||||||
.success(function (data) {
|
.success(function (data) {
|
||||||
|
|||||||
@@ -4,8 +4,8 @@
|
|||||||
<table class="table table-striped">
|
<table class="table table-striped">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th class="col-md-3">Name</th>
|
<th class="col-md-3">Name of Commodity</th>
|
||||||
<th class="col-md-3">Units per Case</th>
|
<th class="col-md-3">Units per Case / Container Type</th>
|
||||||
<th class="col-md-2">Exp. Date</th>
|
<th class="col-md-2">Exp. Date</th>
|
||||||
<th class="col-md-1">Case Qty</th>
|
<th class="col-md-1">Case Qty</th>
|
||||||
<th class="col-md-1">Unit Qty</th>
|
<th class="col-md-1">Unit Qty</th>
|
||||||
@@ -19,7 +19,7 @@
|
|||||||
<td>{{transaction.expirationDate | date:'shortDate'}}</td>
|
<td>{{transaction.expirationDate | date:'shortDate'}}</td>
|
||||||
<td>{{transaction.removedQuantity}}</td>
|
<td>{{transaction.removedQuantity}}</td>
|
||||||
<td>{{transaction.removedQuantity * transaction.unitsPerCase}}</td>
|
<td>{{transaction.removedQuantity * transaction.unitsPerCase}}</td>
|
||||||
<td>{{transaction.weightPerCase * transaction.unitsPerCase | number:0 }} lbs</td>
|
<td>{{transaction.weightPerCase * transaction.removedQuantity | number:0 }} lbs</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|||||||
Reference in New Issue
Block a user