MonthlyInventory report
This commit is contained in:
@@ -79,6 +79,7 @@ namespace InventoryTraker.Web
|
|||||||
|
|
||||||
for (var dd = DateTime.Today.AddYears(-4); dd < DateTime.Today.AddMonths(-2); dd = dd.AddMonths(3))
|
for (var dd = DateTime.Today.AddYears(-4); dd < DateTime.Today.AddMonths(-2); dd = dd.AddMonths(3))
|
||||||
{
|
{
|
||||||
|
ExprireLossInventory(context, dd, r);
|
||||||
// add some inventory
|
// add some inventory
|
||||||
for (int i = 0; i < r.Next(5,10); i++)
|
for (int i = 0; i < r.Next(5,10); i++)
|
||||||
{
|
{
|
||||||
@@ -113,50 +114,13 @@ namespace InventoryTraker.Web
|
|||||||
}
|
}
|
||||||
dd = dd.AddDays(14);
|
dd = dd.AddDays(14);
|
||||||
// expire/loss some inventory
|
// expire/loss some inventory
|
||||||
var availableInventories =
|
ExprireLossInventory(context, dd, r);
|
||||||
context.Inventories.Local.Where(i => i.Quantity > 0).ToList();
|
|
||||||
|
|
||||||
foreach (var inventory in availableInventories)
|
|
||||||
{
|
|
||||||
if (inventory.ExpirationDate <= dd && r.Next(0, 3) > 0)
|
|
||||||
{
|
|
||||||
var expiredTransaction = new Transaction
|
|
||||||
{
|
|
||||||
TransactionType = TransactionType.Expired,
|
|
||||||
RemovedQuantity = inventory.Quantity,
|
|
||||||
CurrentQuantity = 0,
|
|
||||||
Inventory = inventory,
|
|
||||||
Memo = $"Expired on {inventory.ExpirationDate.ToShortDateString()}",
|
|
||||||
TransactionDate = dd,
|
|
||||||
Timestamp = dd
|
|
||||||
};
|
|
||||||
inventory.Quantity = expiredTransaction.CurrentQuantity;
|
|
||||||
inventory.Transactions.Add(expiredTransaction);
|
|
||||||
}
|
|
||||||
else if (r.Next(0, 20) == 0)
|
|
||||||
{
|
|
||||||
var lossQty = r.Next(1, inventory.Quantity + 1);
|
|
||||||
var lossTransaction = new Transaction
|
|
||||||
{
|
|
||||||
TransactionType = TransactionType.Loss,
|
|
||||||
RemovedQuantity = lossQty,
|
|
||||||
CurrentQuantity = inventory.Quantity - lossQty,
|
|
||||||
Inventory = inventory,
|
|
||||||
Memo = $"Missing",
|
|
||||||
TransactionDate = dd,
|
|
||||||
Timestamp = dd
|
|
||||||
};
|
|
||||||
inventory.Quantity = lossTransaction.CurrentQuantity;
|
|
||||||
inventory.Transactions.Add(lossTransaction);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
dd = dd.AddDays(14);
|
dd = dd.AddDays(14);
|
||||||
// distribute some inventory
|
// distribute some inventory
|
||||||
foreach (var destination in counties)
|
foreach (var destination in counties)
|
||||||
{
|
{
|
||||||
availableInventories =
|
var availableInventories =
|
||||||
context.Inventories.Local.Where(i => i.Quantity > 0).ToList();
|
context.Inventories.Local.Where(i => i.Quantity > 0).ToList();
|
||||||
|
|
||||||
for (
|
for (
|
||||||
@@ -189,6 +153,7 @@ namespace InventoryTraker.Web
|
|||||||
inventory.Transactions.Add(distributeTransaction);
|
inventory.Transactions.Add(distributeTransaction);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ExprireLossInventory(context, dd, r);
|
||||||
}
|
}
|
||||||
|
|
||||||
//for (int i = 0; i < 200; i++)
|
//for (int i = 0; i < 200; i++)
|
||||||
@@ -282,5 +247,46 @@ namespace InventoryTraker.Web
|
|||||||
// }
|
// }
|
||||||
//}
|
//}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void ExprireLossInventory(AppDbContext context, DateTime dd, Random r)
|
||||||
|
{
|
||||||
|
var availableInventories =
|
||||||
|
context.Inventories.Local.Where(i => i.Quantity > 0).ToList();
|
||||||
|
|
||||||
|
foreach (var inventory in availableInventories)
|
||||||
|
{
|
||||||
|
if (inventory.ExpirationDate <= dd && r.Next(0, 4) > 0)
|
||||||
|
{
|
||||||
|
var expiredTransaction = new Transaction
|
||||||
|
{
|
||||||
|
TransactionType = TransactionType.Expired,
|
||||||
|
RemovedQuantity = inventory.Quantity,
|
||||||
|
CurrentQuantity = 0,
|
||||||
|
Inventory = inventory,
|
||||||
|
Memo = $"Expired on {inventory.ExpirationDate.ToShortDateString()}",
|
||||||
|
TransactionDate = dd,
|
||||||
|
Timestamp = dd
|
||||||
|
};
|
||||||
|
inventory.Quantity = expiredTransaction.CurrentQuantity;
|
||||||
|
inventory.Transactions.Add(expiredTransaction);
|
||||||
|
}
|
||||||
|
else if (r.Next(0, 40) == 0)
|
||||||
|
{
|
||||||
|
var lossQty = r.Next(1, inventory.Quantity + 1);
|
||||||
|
var lossTransaction = new Transaction
|
||||||
|
{
|
||||||
|
TransactionType = TransactionType.Loss,
|
||||||
|
RemovedQuantity = lossQty,
|
||||||
|
CurrentQuantity = inventory.Quantity - lossQty,
|
||||||
|
Inventory = inventory,
|
||||||
|
Memo = $"Missing",
|
||||||
|
TransactionDate = dd,
|
||||||
|
Timestamp = dd
|
||||||
|
};
|
||||||
|
inventory.Quantity = lossTransaction.CurrentQuantity;
|
||||||
|
inventory.Transactions.Add(lossTransaction);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -7,6 +7,7 @@ using AutoMapper.QueryableExtensions;
|
|||||||
using InventoryTraker.Web.Core;
|
using InventoryTraker.Web.Core;
|
||||||
using InventoryTraker.Web.Data;
|
using InventoryTraker.Web.Data;
|
||||||
using InventoryTraker.Web.Models;
|
using InventoryTraker.Web.Models;
|
||||||
|
using InventoryTraker.Web.Utilities;
|
||||||
|
|
||||||
namespace InventoryTraker.Web.Controllers
|
namespace InventoryTraker.Web.Controllers
|
||||||
{
|
{
|
||||||
@@ -40,8 +41,6 @@ namespace InventoryTraker.Web.Controllers
|
|||||||
Date = g.Key.TransactionDate,
|
Date = g.Key.TransactionDate,
|
||||||
Destination = g.Key.Destination,
|
Destination = g.Key.Destination,
|
||||||
Transactions = g.ToList()
|
Transactions = g.ToList()
|
||||||
//(from transaction in g
|
|
||||||
//select Mapper.Map<TransactionViewModel>(transaction)).ToArray()
|
|
||||||
};
|
};
|
||||||
|
|
||||||
var report =
|
var report =
|
||||||
@@ -66,7 +65,143 @@ namespace InventoryTraker.Web.Controllers
|
|||||||
|
|
||||||
public ActionResult MonthlyInventory(DateTime month)
|
public ActionResult MonthlyInventory(DateTime month)
|
||||||
{
|
{
|
||||||
return BetterJson(true);
|
var startDate = month;
|
||||||
|
var endDate = startDate.AddMonths(1);
|
||||||
|
|
||||||
|
var inventoryTypeReport
|
||||||
|
= new InventoryTypeReport
|
||||||
|
{
|
||||||
|
Items = GetInventoryTypeReportItems(startDate, endDate),
|
||||||
|
Month = month
|
||||||
|
};
|
||||||
|
|
||||||
|
return BetterJson(inventoryTypeReport);
|
||||||
|
}
|
||||||
|
|
||||||
|
private IEnumerable<InventoryTypeReportItem> GetInventoryTypeReportItems(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 InventoryReportItem();
|
||||||
|
|
||||||
|
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 InventoryTypeReportItem
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class InventoryReportItem
|
||||||
|
{
|
||||||
|
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; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class InventoryTypeReport
|
||||||
|
{
|
||||||
|
public DateTime Month { get; set; }
|
||||||
|
public IEnumerable<InventoryTypeReportItem> Items { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class InventoryTypeReportItem
|
||||||
|
{
|
||||||
|
public InventoryTypeViewModel InventoryType { 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; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -246,14 +246,18 @@
|
|||||||
<Content Include="js\inventory\InventoryEditDirective.js" />
|
<Content Include="js\inventory\InventoryEditDirective.js" />
|
||||||
<Content Include="js\inventory\InventoryDistributeDirective.js" />
|
<Content Include="js\inventory\InventoryDistributeDirective.js" />
|
||||||
<Content Include="js\profile\EditProfileController.js" />
|
<Content Include="js\profile\EditProfileController.js" />
|
||||||
|
<Content Include="js\report\MonthlyInventoryReportDirective.js" />
|
||||||
<Content Include="js\report\MonthlyInventoryReportController.js" />
|
<Content Include="js\report\MonthlyInventoryReportController.js" />
|
||||||
<Content Include="js\report\DistributionReportDirective.js" />
|
<Content Include="js\report\DistributionReportDirective.js" />
|
||||||
<Content Include="js\report\DistributionReportQueryDirective.js" />
|
<Content Include="js\utility\MonthQueryDirective.js" />
|
||||||
|
<Content Include="js\utility\DateRangeQueryDirective.js" />
|
||||||
<Content Include="js\report\DistributionReportController.js" />
|
<Content Include="js\report\DistributionReportController.js" />
|
||||||
<Content Include="js\report\reportSvc.js" />
|
<Content Include="js\report\reportSvc.js" />
|
||||||
<Content Include="js\transaction\TransactionController.js" />
|
<Content Include="js\transaction\TransactionController.js" />
|
||||||
<Content Include="js\transaction\transactionSvc.js" />
|
<Content Include="js\transaction\transactionSvc.js" />
|
||||||
<Content Include="js\utility\ArrayExtensions.js" />
|
<Content Include="js\utility\ArrayExtensions.js" />
|
||||||
|
<Content Include="js\utility\FormatCases.js" />
|
||||||
|
<Content Include="js\utility\ToUnits.js" />
|
||||||
<Content Include="js\utility\StatusMessage.js" />
|
<Content Include="js\utility\StatusMessage.js" />
|
||||||
<Content Include="js\utility\ErrorList.js" />
|
<Content Include="js\utility\ErrorList.js" />
|
||||||
<Content Include="js\utility\FormGroupValidationDirective.js" />
|
<Content Include="js\utility\FormGroupValidationDirective.js" />
|
||||||
@@ -300,10 +304,12 @@
|
|||||||
<Content Include="NLog.config">
|
<Content Include="NLog.config">
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
</Content>
|
</Content>
|
||||||
<Content Include="js\report\templates\distributionReportQuery.tmpl.cshtml" />
|
<Content Include="js\utility\templates\dateRangeQuery.tmpl.cshtml" />
|
||||||
<Content Include="js\utility\templates\errorList.tmpl.cshtml" />
|
<Content Include="js\utility\templates\errorList.tmpl.cshtml" />
|
||||||
<Content Include="js\report\templates\distributionReport.tmpl.cshtml" />
|
<Content Include="js\report\templates\distributionReport.tmpl.cshtml" />
|
||||||
<Content Include="js\utility\templates\statusMessage.tmpl.cshtml" />
|
<Content Include="js\utility\templates\statusMessage.tmpl.cshtml" />
|
||||||
|
<Content Include="js\utility\templates\monthQuery.tmpl.cshtml" />
|
||||||
|
<Content Include="js\report\templates\monthlyInventoryReport.tmpl.cshtml" />
|
||||||
<None Include="NLog.xsd">
|
<None Include="NLog.xsd">
|
||||||
<SubType>Designer</SubType>
|
<SubType>Designer</SubType>
|
||||||
</None>
|
</None>
|
||||||
@@ -371,6 +377,7 @@
|
|||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
<Compile Include="Utilities\ControllerContextExtensions.cs" />
|
<Compile Include="Utilities\ControllerContextExtensions.cs" />
|
||||||
<Compile Include="Utilities\ExcelParserBase.cs" />
|
<Compile Include="Utilities\ExcelParserBase.cs" />
|
||||||
|
<Compile Include="Utilities\IEnumerableExtensions.cs" />
|
||||||
<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" />
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ namespace InventoryTraker.Web.Models
|
|||||||
{
|
{
|
||||||
public int Id { get; set; }
|
public int Id { get; set; }
|
||||||
|
|
||||||
|
public int InventoryTypeId { get; set; }
|
||||||
|
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
|
|
||||||
public int UnitsPerCase { get; set; }
|
public int UnitsPerCase { get; set; }
|
||||||
@@ -32,6 +34,7 @@ namespace InventoryTraker.Web.Models
|
|||||||
public void CreateMappings(IMapperConfiguration configuration)
|
public void CreateMappings(IMapperConfiguration configuration)
|
||||||
{
|
{
|
||||||
configuration.CreateMap<Inventory, InventoryViewModel>()
|
configuration.CreateMap<Inventory, InventoryViewModel>()
|
||||||
|
.ForMember(d => d.InventoryTypeId, opt => opt.MapFrom(s => s.InventoryType.Id))
|
||||||
.ForMember(d => d.Name, opt => opt.MapFrom(s => s.InventoryType.Name))
|
.ForMember(d => d.Name, opt => opt.MapFrom(s => s.InventoryType.Name))
|
||||||
.ForMember(d => d.UnitsPerCase, opt => opt.MapFrom(s => s.InventoryType.UnitsPerCase))
|
.ForMember(d => d.UnitsPerCase, opt => opt.MapFrom(s => s.InventoryType.UnitsPerCase))
|
||||||
.ForMember(d => d.ContainerType, opt => opt.MapFrom(s => s.InventoryType.ContainerType))
|
.ForMember(d => d.ContainerType, opt => opt.MapFrom(s => s.InventoryType.ContainerType))
|
||||||
|
|||||||
@@ -0,0 +1,57 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace InventoryTraker.Web.Utilities
|
||||||
|
{
|
||||||
|
public static class IEnumerableExtensions
|
||||||
|
{
|
||||||
|
public static IEnumerable<TResult> FullOuterGroupJoin<TA, TB, TKey, TResult>(
|
||||||
|
this IEnumerable<TA> a,
|
||||||
|
IEnumerable<TB> b,
|
||||||
|
Func<TA, TKey> selectKeyA,
|
||||||
|
Func<TB, TKey> selectKeyB,
|
||||||
|
Func<IEnumerable<TA>, IEnumerable<TB>, TKey, TResult> projection,
|
||||||
|
IEqualityComparer<TKey> cmp = null)
|
||||||
|
{
|
||||||
|
cmp = cmp ?? EqualityComparer<TKey>.Default;
|
||||||
|
var alookup = a.ToLookup(selectKeyA, cmp);
|
||||||
|
var blookup = b.ToLookup(selectKeyB, cmp);
|
||||||
|
|
||||||
|
var keys = new HashSet<TKey>(alookup.Select(p => p.Key), cmp);
|
||||||
|
keys.UnionWith(blookup.Select(p => p.Key));
|
||||||
|
|
||||||
|
var join = from key in keys
|
||||||
|
let xa = alookup[key]
|
||||||
|
let xb = blookup[key]
|
||||||
|
select projection(xa, xb, key);
|
||||||
|
|
||||||
|
return join;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IEnumerable<TResult> FullOuterJoin<TA, TB, TKey, TResult>(
|
||||||
|
this IEnumerable<TA> a,
|
||||||
|
IEnumerable<TB> b,
|
||||||
|
Func<TA, TKey> selectKeyA,
|
||||||
|
Func<TB, TKey> selectKeyB,
|
||||||
|
Func<TA, TB, TKey, TResult> projection,
|
||||||
|
TA defaultA = default(TA),
|
||||||
|
TB defaultB = default(TB),
|
||||||
|
IEqualityComparer<TKey> cmp = null)
|
||||||
|
{
|
||||||
|
cmp = cmp ?? EqualityComparer<TKey>.Default;
|
||||||
|
var alookup = a.ToLookup(selectKeyA, cmp);
|
||||||
|
var blookup = b.ToLookup(selectKeyB, cmp);
|
||||||
|
|
||||||
|
var keys = new HashSet<TKey>(alookup.Select(p => p.Key), cmp);
|
||||||
|
keys.UnionWith(blookup.Select(p => p.Key));
|
||||||
|
|
||||||
|
var join = from key in keys
|
||||||
|
from xa in alookup[key].DefaultIfEmpty(defaultA)
|
||||||
|
from xb in blookup[key].DefaultIfEmpty(defaultB)
|
||||||
|
select projection(xa, xb, key);
|
||||||
|
|
||||||
|
return join;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -11,7 +11,7 @@
|
|||||||
<div class="col-md-9">
|
<div class="col-md-9">
|
||||||
<div class="panel panel-default">
|
<div class="panel panel-default">
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
<distribution-report-query></distribution-report-query>
|
<date-range-query query-fn="vm.loadData"></date-range-query>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -11,14 +11,15 @@
|
|||||||
<div class="col-md-9">
|
<div class="col-md-9">
|
||||||
<div class="panel panel-default">
|
<div class="panel panel-default">
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
<monthly-inventory-report-query></monthly-inventory-report-query>
|
<month-query query-fn="vm.loadData"></month-query>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row" ng-show="vm.monthlyInventoryData.length">
|
<div class="row" ng-show="vm.monthlyInventoryData.items.length">
|
||||||
<div class="col-md-12">
|
<div class="col-md-12">
|
||||||
<monthly-inventory-report distribution-data="vm.monthlyInventoryData"></monthly-inventory-report>
|
<h3>{{vm.monthlyInventoryData.month | date:'MMMM yyyy'}}</h3>
|
||||||
|
<monthly-inventory-report monthly-inventory-data="vm.monthlyInventoryData"></monthly-inventory-report>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,5 +1,14 @@
|
|||||||
(function() {
|
(function() {
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
window.app = angular.module('InventoryTraker', ['ngAnimate', 'ui.bootstrap', 'ui.grid', 'ui.grid.pagination', 'mgcrea.ngStrap']);
|
window.app =
|
||||||
|
angular
|
||||||
|
.module('InventoryTraker', ['ngAnimate', 'ui.bootstrap', 'ui.grid', 'ui.grid.pagination', 'mgcrea.ngStrap'])
|
||||||
|
.config(function($datepickerProvider) {
|
||||||
|
angular.extend($datepickerProvider.defaults,
|
||||||
|
{
|
||||||
|
iconLeft: 'fa fa-chevron-left',
|
||||||
|
iconRight: 'fa fa-chevron-right'
|
||||||
|
});
|
||||||
|
});
|
||||||
})();
|
})();
|
||||||
@@ -36,7 +36,7 @@
|
|||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody ng-hide="vm.loadingTransactions">
|
<tbody ng-hide="vm.loadingTransactions">
|
||||||
<tr ng-repeat-start="transaction in vm.transactions | orderBy:'-transactionDate'">
|
<tr ng-repeat-start="transaction in vm.transactions | orderBy:['-transactionDate', 'currentQuantity']">
|
||||||
<td>{{transaction.transactionType}}</td>
|
<td>{{transaction.transactionType}}</td>
|
||||||
<td>{{transaction.memo}}</td>
|
<td>{{transaction.memo}}</td>
|
||||||
<td>{{transaction.transactionDate | date:'shortDate'}}</td>
|
<td>{{transaction.transactionDate | date:'shortDate'}}</td>
|
||||||
@@ -53,8 +53,8 @@
|
|||||||
<tr ng-repeat-end ng-show="$first && vm.confirmDeleteTransaction">
|
<tr ng-repeat-end ng-show="$first && vm.confirmDeleteTransaction">
|
||||||
<td colspan="7">
|
<td colspan="7">
|
||||||
<span ng-show="vm.transactions.length == 1" class="text-danger">
|
<span ng-show="vm.transactions.length == 1" class="text-danger">
|
||||||
Warning: Deleting the only transaction will delete the entire inventory
|
Warning: Deleting the only transaction will delete the entire inventory
|
||||||
</span>
|
</span>
|
||||||
<button
|
<button
|
||||||
ng-click="vm.deleteTransaction(transaction.id)"
|
ng-click="vm.deleteTransaction(transaction.id)"
|
||||||
class="btn btn-danger btn-sm pull-right">
|
class="btn btn-danger btn-sm pull-right">
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
<dd>{{inventory.addedDate | date:'shortDate'}}</dd>
|
<dd>{{inventory.addedDate | date:'shortDate'}}</dd>
|
||||||
<dt>Expiration Date</dt>
|
<dt>Expiration Date</dt>
|
||||||
<dd>
|
<dd>
|
||||||
<span ng-class="{ 'bg-danger': inventory.isExpired }">
|
<span ng-class="{ 'bg-danger': inventory.quantity && inventory.isExpired }">
|
||||||
{{inventory.expirationDate | date:'shortDate'}}
|
{{inventory.expirationDate | date:'shortDate'}}
|
||||||
<span ng-show="inventory.isExpired" class="label label-danger">Expired</span>
|
<span ng-show="inventory.isExpired" class="label label-danger">Expired</span>
|
||||||
</span>
|
</span>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<table class="table">
|
<table class="table table-striped">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th class="control-column"></th>
|
<th class="control-column"></th>
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
DistributionReportController.$inject = ['$scope', 'reportSvc'];
|
DistributionReportController.$inject = ['$scope', 'reportSvc'];
|
||||||
function DistributionReportController($scope, reportSvc) {
|
function DistributionReportController($scope, reportSvc) {
|
||||||
var vm = this;
|
var vm = this;
|
||||||
|
vm.loadData = reportSvc.loadDistributionReport;
|
||||||
vm.distributionData = reportSvc.distributionData;
|
vm.distributionData = reportSvc.distributionData;
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
@@ -6,6 +6,7 @@
|
|||||||
MonthlyInventoryReportController.$inject = ['$scope', 'reportSvc'];
|
MonthlyInventoryReportController.$inject = ['$scope', 'reportSvc'];
|
||||||
function MonthlyInventoryReportController($scope, reportSvc) {
|
function MonthlyInventoryReportController($scope, reportSvc) {
|
||||||
var vm = this;
|
var vm = this;
|
||||||
|
vm.loadData = reportSvc.loadMonthlyInventoryData;
|
||||||
vm.monthlyInventoryData = reportSvc.monthlyInventoryData;
|
vm.monthlyInventoryData = reportSvc.monthlyInventoryData;
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
(function() {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
window.app.directive('monthlyInventoryReport', monthlyInventoryReport);
|
||||||
|
function monthlyInventoryReport() {
|
||||||
|
return {
|
||||||
|
scope: { monthlyInventoryData: "=" },
|
||||||
|
templateUrl: '/report/template/monthlyInventoryReport.tmpl.cshtml',
|
||||||
|
controller: controller,
|
||||||
|
controllerAs: 'vm'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
controller.$inject = ['$scope', '$uibModal', 'inventorySvc'];
|
||||||
|
function controller($scope, $uibModal, inventorySvc) {
|
||||||
|
var vm = this;
|
||||||
|
vm.monthlyInventoryData = $scope.monthlyInventoryData;
|
||||||
|
|
||||||
|
vm.editInventory = function (inventoryId) {
|
||||||
|
inventorySvc.find(inventoryId)
|
||||||
|
.success(function (inventory) {
|
||||||
|
$uibModal.open({
|
||||||
|
template: '<edit-inventory inventory="inventory" />',
|
||||||
|
scope: angular.extend($scope.$new(true), { inventory: inventory })
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})();
|
||||||
@@ -4,15 +4,15 @@
|
|||||||
reportSvc.$inject = ['$http'];
|
reportSvc.$inject = ['$http'];
|
||||||
function reportSvc($http) {
|
function reportSvc($http) {
|
||||||
var distributionData = [];
|
var distributionData = [];
|
||||||
var monthlyInventoryData = [];
|
var monthlyInventoryData = {};
|
||||||
|
|
||||||
var svc = {
|
var svc = {
|
||||||
distributionData: distributionData,
|
distributionData: distributionData,
|
||||||
|
loadDistributionReport: loadDistributionReport,
|
||||||
monthlyInventoryData: monthlyInventoryData,
|
monthlyInventoryData: monthlyInventoryData,
|
||||||
loadDistributionReport: loadDistributionReport
|
loadMonthlyInventoryData: loadMonthlyInventoryData
|
||||||
};
|
};
|
||||||
|
|
||||||
loadDistributionReport({ startDate: '2015-05-01', endDate: '2016-01-01' });
|
|
||||||
return svc;
|
return svc;
|
||||||
|
|
||||||
function loadDistributionReport(query) {
|
function loadDistributionReport(query) {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<div ng-repeat="distribution in vm.distributionData">
|
<div ng-repeat="distribution in vm.distributionData">
|
||||||
<h3>{{distribution.destination}}</h3>
|
<h3>{{distribution.destination}}</h3>
|
||||||
<h4>{{distribution.date | date:'shortDate'}}</h4>
|
<h4>{{distribution.date | date:'shortDate'}}</h4>
|
||||||
<table class="table">
|
<table class="table table-striped">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th class="col-md-3">Name</th>
|
<th class="col-md-3">Name</th>
|
||||||
|
|||||||
@@ -0,0 +1,47 @@
|
|||||||
|
<table class="table table-striped">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
@*<th></th>*@
|
||||||
|
<th class="col-md-2">Name of Commodity</th>
|
||||||
|
<th class="col-md-1">Pack Size / Units per Case</th>
|
||||||
|
<th class="col-md-1">Beginning Inventory</th>
|
||||||
|
<th class="col-md-1">Units Rec'd</th>
|
||||||
|
<th class="col-md-1">Total Units Available</th>
|
||||||
|
<th class="col-md-1">Adjustments (show + or -)</th>
|
||||||
|
<th class="col-md-1">Units Distributed</th>
|
||||||
|
<th class="col-md-1">Ending Inventory</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr ng-repeat="item in vm.monthlyInventoryData.items | orderBy:'inventoryType.name'">
|
||||||
|
@*<td><a href="" ng-click="vm.editInventory(item.inventory.id)"><i class="fa fa-edit"></i></a> </td>*@
|
||||||
|
<td>{{item.inventoryType.name}}</td>
|
||||||
|
<td>{{item.inventoryType.unitsPerCase}} / {{item.inventoryType.containerType}}</td>
|
||||||
|
<td>
|
||||||
|
{{item.beginningQuantity | toUnits:item.inventoryType.unitsPerCase}}
|
||||||
|
{{item.beginningQuantity | formatCases}}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{{item.addedQuantity | hideZero | toUnits:item.inventoryType.unitsPerCase}}
|
||||||
|
{{item.addedQuantity | hideZero | formatCases}}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{{item.totalAvailableQuantity | hideZero | toUnits:item.inventoryType.unitsPerCase}}
|
||||||
|
{{item.totalAvailableQuantity | hideZero | formatCases}}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{{item.adjustmentQuantity ? '-' : ''}}
|
||||||
|
{{item.adjustmentQuantity | hideZero | toUnits:item.inventoryType.unitsPerCase}}
|
||||||
|
{{item.adjustmentQuantity | hideZero | formatCases}}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{{item.distributedQuantity | hideZero | toUnits:item.inventoryType.unitsPerCase}}
|
||||||
|
{{item.distributedQuantity | hideZero | formatCases}}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{{item.endingQuantity | toUnits:item.inventoryType.unitsPerCase}}
|
||||||
|
{{item.endingQuantity | formatCases}}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
+9
-7
@@ -1,18 +1,20 @@
|
|||||||
(function() {
|
(function() {
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
window.app.directive('distributionReportQuery', distributionReportQuery);
|
window.app.directive('dateRangeQuery', dateRangeQuery);
|
||||||
function distributionReportQuery() {
|
function dateRangeQuery() {
|
||||||
return {
|
return {
|
||||||
scope: true,
|
scope: {
|
||||||
templateUrl: '/report/template/distributionReportQuery.tmpl.cshtml',
|
queryFn: '='
|
||||||
|
},
|
||||||
|
templateUrl: '/utility/template/dateRangeQuery.tmpl.cshtml',
|
||||||
controller: controller,
|
controller: controller,
|
||||||
controllerAs: 'vm'
|
controllerAs: 'vm'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
controller.$inject = ['$scope', 'reportSvc'];
|
controller.$inject = ['$scope'];
|
||||||
function controller($scope, reportSvc) {
|
function controller($scope) {
|
||||||
var vm = this;
|
var vm = this;
|
||||||
vm.query = {};
|
vm.query = {};
|
||||||
vm.submitting = false;
|
vm.submitting = false;
|
||||||
@@ -21,7 +23,7 @@
|
|||||||
|
|
||||||
function submit() {
|
function submit() {
|
||||||
vm.submitting = true;
|
vm.submitting = true;
|
||||||
reportSvc.loadDistributionReport(vm.query)
|
$scope.queryFn(vm.query)
|
||||||
.error(function (data) {
|
.error(function (data) {
|
||||||
vm.errorMessages = angular.copy(data.errorMessages, vm.errorMessages);
|
vm.errorMessages = angular.copy(data.errorMessages, vm.errorMessages);
|
||||||
})
|
})
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
(function() {
|
||||||
|
window.app.filter('formatCases', formatCases);
|
||||||
|
|
||||||
|
function formatCases() {
|
||||||
|
return function (qty) {
|
||||||
|
if (qty === '' || !isFinite(qty))
|
||||||
|
return '';
|
||||||
|
|
||||||
|
return '(' + qty + ' cs)';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})();
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
(function() {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
window.app.directive('monthQuery', monthQuery);
|
||||||
|
function monthQuery() {
|
||||||
|
return {
|
||||||
|
scope: {
|
||||||
|
queryFn: '='
|
||||||
|
},
|
||||||
|
templateUrl: '/utility/template/monthQuery.tmpl.cshtml',
|
||||||
|
controller: controller,
|
||||||
|
controllerAs: 'vm'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
controller.$inject = ['$scope'];
|
||||||
|
function controller($scope) {
|
||||||
|
var vm = this;
|
||||||
|
vm.query = {};
|
||||||
|
vm.submitting = false;
|
||||||
|
vm.errorMessages = [];
|
||||||
|
vm.submit = submit;
|
||||||
|
|
||||||
|
function submit() {
|
||||||
|
vm.submitting = true;
|
||||||
|
$scope.queryFn({ month: vm.query })
|
||||||
|
.error(function (data) {
|
||||||
|
vm.errorMessages = angular.copy(data.errorMessages, vm.errorMessages);
|
||||||
|
})
|
||||||
|
.finally(function () {
|
||||||
|
vm.submitting = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})();
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
(function() {
|
||||||
|
window.app.filter('toUnits', toUnits);
|
||||||
|
|
||||||
|
function toUnits() {
|
||||||
|
return function (caseQty, unitsPerCase) {
|
||||||
|
if (caseQty === '' || !isFinite(caseQty) || !isFinite(unitsPerCase))
|
||||||
|
return '';
|
||||||
|
|
||||||
|
return caseQty * unitsPerCase;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
})();
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
<form novalidate
|
||||||
|
name="vm.form"
|
||||||
|
ng-submit="vm.form.$valid && vm.submit()">
|
||||||
|
<fieldset ng-disabled="vm.submitting">
|
||||||
|
<error-list errors="vm.errorMessages"></error-list>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-12">
|
||||||
|
<div class="form-group" form-group-validation="Month">
|
||||||
|
<label for="Month" class="control-label">Month</label>
|
||||||
|
<input name="Month" type="text"
|
||||||
|
ng-model="vm.query"
|
||||||
|
required
|
||||||
|
data-min-view="1"
|
||||||
|
data-date-format="M/yy"
|
||||||
|
class="form-control"
|
||||||
|
bs-datepicker="" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button class="btn btn-success pull-right">Submit</button>
|
||||||
|
</fieldset>
|
||||||
|
</form>
|
||||||
Reference in New Issue
Block a user