Box modifications
This commit is contained in:
@@ -163,12 +163,20 @@
|
||||
</site>
|
||||
<site name="InventoryTraker.Web" id="2">
|
||||
<application path="/" applicationPool="Clr4IntegratedAppPool">
|
||||
<virtualDirectory path="/" physicalPath="C:\Users\poprhythm\Documents\code\InventoryTraker\InventoryTraker.Web" />
|
||||
<virtualDirectory path="/" physicalPath="C:\Users\poprhythm\Documents\code\InventoryTraker-Box\InventoryTraker.Web" />
|
||||
</application>
|
||||
<bindings>
|
||||
<binding protocol="http" bindingInformation="*:58446:localhost" />
|
||||
</bindings>
|
||||
</site>
|
||||
<site name="InventoryTraker.Web(1)" id="3">
|
||||
<application path="/" applicationPool="Clr4IntegratedAppPool">
|
||||
<virtualDirectory path="/" physicalPath="C:\Users\poprhythm\Documents\code\InventoryTraker-Box\InventoryTraker.Web" />
|
||||
</application>
|
||||
<bindings>
|
||||
<binding protocol="http" bindingInformation="*:58448:localhost" />
|
||||
</bindings>
|
||||
</site>
|
||||
<siteDefaults>
|
||||
<logFile logFormat="W3C" directory="%IIS_USER_HOME%\Logs" />
|
||||
<traceFailedRequestsLogging directory="%IIS_USER_HOME%\TraceLogFiles" enabled="true" maxLogFileSizeKB="1024" />
|
||||
|
||||
@@ -59,10 +59,9 @@
|
||||
<Compile Include="Models\InventoryAddForm.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="App_Start\Setup.cs" />
|
||||
<Compile Include="Services\InventoryImporterTests.cs" />
|
||||
<Compile Include="Utilities\InventoryParserTests.cs" />
|
||||
<Compile Include="Utilities\InventoryReportWriterTests.cs" />
|
||||
<Compile Include="Utilities\DistributionReportWriterTests.cs" />
|
||||
<Compile Include="Utilities\MovementReportWriterTests.cs" />
|
||||
<Compile Include="Utilities\InventoryTypeParserTests.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\InventoryTraker.Web\InventoryTraker.Web.csproj">
|
||||
@@ -73,10 +72,20 @@
|
||||
<ItemGroup>
|
||||
<None Include="app.config" />
|
||||
<None Include="packages.config" />
|
||||
<Content Include="Utilities\Documents\InventoryTypeData.xlsx">
|
||||
<Content Include="Utilities\Documents\InventoryData.xlsx">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="Utilities\Documents\InventoryData-BadHeader.xlsx">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="Utilities\Documents\InventoryData-BadDate.xlsx">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<None Include="Utilities\Documents\InventoryData-NoExtension">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<ItemGroup />
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
|
||||
@@ -23,18 +23,15 @@ namespace InventoryTraker.Web.Tests.Models
|
||||
var form = new InventoryAddForm
|
||||
{
|
||||
AddedDate = DateTime.Today,
|
||||
ExpirationDate = DateTime.Today.AddDays(3),
|
||||
InventoryTypeId = 1,
|
||||
Memo = "My Memo",
|
||||
Quantity = 32
|
||||
ShredReadyDate = DateTime.Today.AddDays(3),
|
||||
Memo = "My Memo"
|
||||
};
|
||||
|
||||
var inventory = _mapper.Map<Inventory>(form);
|
||||
|
||||
Assert.That(inventory.AddedDate, Is.EqualTo(form.AddedDate));
|
||||
Assert.That(inventory.ExpirationDate, Is.EqualTo(form.ExpirationDate));
|
||||
Assert.That(inventory.ShredReadyDate, Is.EqualTo(form.ShredReadyDate));
|
||||
Assert.That(inventory.Memo, Is.EqualTo(form.Memo));
|
||||
Assert.That(inventory.Quantity, Is.EqualTo(form.Quantity));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using AutoMapper;
|
||||
using InventoryTraker.Web.Services;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace InventoryTraker.Web.Tests.Services
|
||||
{
|
||||
[TestFixture]
|
||||
public class InventoryImporterTests
|
||||
{
|
||||
private readonly string _documentFolder =
|
||||
AppDomain.CurrentDomain.BaseDirectory + @"\Utilities\Documents\";
|
||||
|
||||
private IMapper _mapper;
|
||||
|
||||
[OneTimeSetUp]
|
||||
public void StartUp()
|
||||
{
|
||||
_mapper = AutoMapperConfig.Config.CreateMapper();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Import()
|
||||
{
|
||||
var fileInfo = new FileInfo(Path.Combine(_documentFolder, "InventoryData.xlsx"));
|
||||
|
||||
var importer = new InventoryImporter(_mapper);
|
||||
|
||||
var inventories = importer.Import(fileInfo);
|
||||
|
||||
foreach (var inventory in inventories)
|
||||
{
|
||||
Console.WriteLine($"{inventory.Id} {inventory.ProgramName} {inventory.ShredReadyDate}");
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Import_BadDate()
|
||||
{
|
||||
var fileInfo = new FileInfo(Path.Combine(_documentFolder, "InventoryData-BadDate.xlsx"));
|
||||
|
||||
var importer = new InventoryImporter(_mapper);
|
||||
|
||||
var importException = Assert.Throws<ImportException>(() => importer.Import(fileInfo));
|
||||
|
||||
Assert.That(importException.Message, Does.Contain("Date"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Import_BadHeader()
|
||||
{
|
||||
var fileInfo = new FileInfo(Path.Combine(_documentFolder, "InventoryData-BadHeader.xlsx"));
|
||||
|
||||
var importer = new InventoryImporter(_mapper);
|
||||
|
||||
var importException = Assert.Throws<ImportException>(() => importer.Import(fileInfo));
|
||||
|
||||
Assert.That(importException.Message, Does.Contain("Program Name"));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using AutoMapper;
|
||||
using InventoryTraker.Web.Models;
|
||||
using InventoryTraker.Web.Utilities;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace InventoryTraker.Web.Tests.Utilities
|
||||
{
|
||||
[TestFixture]
|
||||
public class DistributionReportWriterTests
|
||||
{
|
||||
private IMapper _mapper;
|
||||
|
||||
[OneTimeSetUp]
|
||||
public void StartUp()
|
||||
{
|
||||
_mapper = AutoMapperConfig.Config.CreateMapper();
|
||||
}
|
||||
|
||||
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(_mapper);
|
||||
writer.WriteStream(_distributionReports, outputFile.BaseStream);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,44 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using InventoryTraker.Web.Utilities;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace InventoryTraker.Web.Tests.Utilities
|
||||
{
|
||||
[TestFixture]
|
||||
public class InventoryParserTests
|
||||
{
|
||||
private readonly string _documentFolder =
|
||||
AppDomain.CurrentDomain.BaseDirectory + @"\Utilities\Documents\";
|
||||
|
||||
[Test]
|
||||
public void Parse()
|
||||
{
|
||||
var fileInfo = new FileInfo(Path.Combine(_documentFolder, "InventoryData.xlsx"));
|
||||
|
||||
var parser = new InventoryParser(fileInfo);
|
||||
|
||||
var forms = parser.Parse();
|
||||
|
||||
foreach (var form in forms)
|
||||
{
|
||||
Console.WriteLine($"{form.Id} {form.ProgramName} {form.ShredReadyDate}");
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Parse_NoExtension()
|
||||
{
|
||||
var fileInfo = new FileInfo(Path.Combine(_documentFolder, "InventoryData-NoExtension"));
|
||||
|
||||
var parser = new InventoryParser(fileInfo);
|
||||
|
||||
var forms = parser.Parse();
|
||||
|
||||
foreach (var form in forms)
|
||||
{
|
||||
Console.WriteLine($"{form.Id} {form.ProgramName} {form.ShredReadyDate}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -13,16 +13,11 @@ namespace InventoryTraker.Web.Tests.Utilities
|
||||
{
|
||||
new InventoryViewModel
|
||||
{
|
||||
|
||||
Name = "Beans",
|
||||
ContainerType = "#300 cans",
|
||||
UnitsPerCase = 24,
|
||||
Id = "34634584",
|
||||
AddedDate = new DateTime(2015,3,1),
|
||||
ExpirationDate = new DateTime(2017,4,1),
|
||||
Quantity = 20,
|
||||
ShredReadyDate = new DateTime(2017,4,1),
|
||||
Quantity = 0,
|
||||
Memo = "my memo",
|
||||
PricePerCase = 12.12M,
|
||||
WeightPerCase = 20.1,
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using InventoryTraker.Web.Utilities;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace InventoryTraker.Web.Tests.Utilities
|
||||
{
|
||||
[TestFixture]
|
||||
public class InventoryTypeParserTests
|
||||
{
|
||||
private readonly string _documentFolder =
|
||||
AppDomain.CurrentDomain.BaseDirectory + @"\Utilities\Documents\";
|
||||
|
||||
[Test]
|
||||
public void Parse()
|
||||
{
|
||||
var fileInfo = new FileInfo(Path.Combine(_documentFolder, "InventoryTypeData.xlsx"));
|
||||
|
||||
var parser = new InventoryTypeParser(fileInfo);
|
||||
|
||||
var inventoryTypes = parser.Parse();
|
||||
|
||||
foreach (var inventoryType in inventoryTypes)
|
||||
{
|
||||
Console.WriteLine($"{inventoryType.Identifier} {inventoryType.Name} {inventoryType.PricePerCase}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,76 +0,0 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using AutoMapper;
|
||||
using InventoryTraker.Web.Models;
|
||||
using InventoryTraker.Web.Utilities;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace InventoryTraker.Web.Tests.Utilities
|
||||
{
|
||||
[TestFixture]
|
||||
public class MovementReportWriterTests
|
||||
{
|
||||
private IMapper _mapper;
|
||||
|
||||
[OneTimeSetUp]
|
||||
public void StartUp()
|
||||
{
|
||||
_mapper = AutoMapperConfig.Config.CreateMapper();
|
||||
}
|
||||
|
||||
private readonly MovementReport _movementReport
|
||||
= new MovementReport
|
||||
{
|
||||
Month = new DateTime(2016, 04, 1),
|
||||
Items = new[]
|
||||
{
|
||||
new MovementReportItem
|
||||
{
|
||||
InventoryType = new InventoryTypeViewModel
|
||||
{
|
||||
Name = "Beans",
|
||||
ContainerType = "#300 cans",
|
||||
Id = 1,
|
||||
Identifier = "10001",
|
||||
UnitsPerCase = 24
|
||||
},
|
||||
BeginningQuantity = 7,
|
||||
AddedQuantity = 5,
|
||||
TotalAvailableQuantity = 12,
|
||||
AdjustmentQuantity = 3,
|
||||
DistributedQuantity = 1,
|
||||
EndingQuantity = 8
|
||||
},
|
||||
new MovementReportItem
|
||||
{
|
||||
InventoryType = new InventoryTypeViewModel
|
||||
{
|
||||
Name = "Peanut Butter",
|
||||
ContainerType = "16oz jars",
|
||||
Id = 2,
|
||||
Identifier = "20001",
|
||||
UnitsPerCase = 12
|
||||
},
|
||||
BeginningQuantity = 5,
|
||||
AddedQuantity = 11,
|
||||
TotalAvailableQuantity = 16,
|
||||
AdjustmentQuantity = 0,
|
||||
DistributedQuantity = 2,
|
||||
EndingQuantity = 14
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
[Test, Explicit]
|
||||
public void Write()
|
||||
{
|
||||
using
|
||||
(var outputFile
|
||||
= new StreamWriter(Path.Combine(@"c:\temp", "MovementReport.xlsx")))
|
||||
{
|
||||
var writer = new MovementReportWriter(_mapper);
|
||||
writer.WriteStream(_movementReport, outputFile.BaseStream);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -23,7 +23,10 @@ namespace InventoryTraker.Web
|
||||
.Include("~/Scripts/angular-strap.js")
|
||||
.Include("~/Scripts/angular-strap.tpl.js")
|
||||
.Include("~/Scripts/ui-grid.js")
|
||||
.Include("~/Scripts/ui-grid.js")
|
||||
.Include("~/Scripts/FileSaver.js")
|
||||
.Include("~/Scripts/ng-file-upload-shim.js")
|
||||
.Include("~/Scripts/ng-file-upload.js")
|
||||
.Include("~/js/app.js")
|
||||
.IncludeDirectory("~/js/", "*.js", true)
|
||||
);
|
||||
|
||||
@@ -7,7 +7,8 @@ namespace InventoryTraker.Web
|
||||
{
|
||||
public static void Initialize()
|
||||
{
|
||||
Database.SetInitializer(new CreateDatabaseIfNotExists<AppDbContext>());
|
||||
//Database.SetInitializer(new CreateDatabaseIfNotExists<AppDbContext>());
|
||||
Database.SetInitializer(new DropCreateDatabaseAlways<AppDbContext>());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
using System.Web.Http;
|
||||
using InventoryTraker.Web.Attributes;
|
||||
|
||||
namespace InventoryTraker.Web
|
||||
{
|
||||
public class WebApiConfig
|
||||
{
|
||||
public static void Register(HttpConfiguration configuration)
|
||||
{
|
||||
configuration.Routes.MapHttpRoute(
|
||||
"API Default",
|
||||
"api/{controller}/{id}",
|
||||
new { id = RouteParameter.Optional });
|
||||
configuration.Filters.Add(new ExceptionHandlingAttribute());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Web;
|
||||
using System.Web.Http;
|
||||
using System.Web.Http.Filters;
|
||||
using InventoryTraker.Web.Utilities;
|
||||
using NLog;
|
||||
|
||||
namespace InventoryTraker.Web.Attributes
|
||||
{
|
||||
// http://stackoverflow.com/questions/15167927/how-do-i-log-all-exceptions-globally-for-a-c-sharp-mvc4-webapi-app
|
||||
public class ExceptionHandlingAttribute : ExceptionFilterAttribute
|
||||
{
|
||||
public override void OnException(HttpActionExecutedContext ctx)
|
||||
{
|
||||
if (ctx != null)
|
||||
{
|
||||
var loggerName = ctx.GetLoggerName();
|
||||
var username = HttpContext.Current.User.Identity.Name;
|
||||
var @params = string.Join(", ", ctx.ActionContext.ActionArguments.Select(i => $"{i.Key}: {{{i.Value}}}"));
|
||||
|
||||
LogManager.GetLogger(loggerName)
|
||||
.Info("username: {0}, params: {{{1}}}", username, @params);
|
||||
}
|
||||
|
||||
throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.InternalServerError)
|
||||
{
|
||||
Content = new StringContent("An error occurred, please try again or contact the administrator."),
|
||||
ReasonPhrase = "Critical Exception"
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -50,7 +50,7 @@ namespace InventoryTraker.Web.Controllers
|
||||
{
|
||||
_authManager.SignOut();
|
||||
|
||||
return this.RedirectToAction<HomeController>(c => c.Index());
|
||||
return this.RedirectToAction(c => c.Login());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
using System.Web.Mvc;
|
||||
|
||||
namespace InventoryTraker.Web.Controllers
|
||||
{
|
||||
public class HomeController : ControllerBase
|
||||
{
|
||||
public ActionResult Index()
|
||||
{
|
||||
return View();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.Entity.Infrastructure;
|
||||
using System.Data.SqlClient;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using System.Web;
|
||||
using System.Web.Http;
|
||||
using InventoryTraker.Web.Core;
|
||||
using InventoryTraker.Web.Data;
|
||||
using InventoryTraker.Web.Services;
|
||||
using InventoryTraker.Web.Utilities;
|
||||
using NLog;
|
||||
|
||||
namespace InventoryTraker.Web.Controllers
|
||||
{
|
||||
public class ImportController : ApiController
|
||||
{
|
||||
private readonly AppDbContext _context;
|
||||
private readonly InventoryImporter _inventoryImporter;
|
||||
|
||||
public ImportController(AppDbContext context, InventoryImporter inventoryImporter)
|
||||
{
|
||||
_context = context;
|
||||
_inventoryImporter = inventoryImporter;
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public async Task<HttpResponseMessage> Upload()
|
||||
{
|
||||
if (!Request.Content.IsMimeMultipartContent())
|
||||
return Request.CreateResponse(HttpStatusCode.UnsupportedMediaType);
|
||||
|
||||
var provider = GetMultipartProvider();
|
||||
var result = await Request.Content.ReadAsMultipartAsync(provider);
|
||||
|
||||
// uploadedFileInfo object will give you some additional stuff like file length,
|
||||
// creation time, directory name, a few filesystem methods etc..
|
||||
var uploadedFileInfo = new FileInfo(result.FileData.First().LocalFileName);
|
||||
|
||||
IEnumerable<Inventory> inventories;
|
||||
try
|
||||
{
|
||||
inventories = _inventoryImporter.Import(uploadedFileInfo);
|
||||
}
|
||||
catch (ImportException e)
|
||||
{
|
||||
LogManager.GetCurrentClassLogger().Info("Import Exception : {0}", e.Message);
|
||||
return Request.CreateResponse(HttpStatusCode.BadRequest, e.Messages);
|
||||
}
|
||||
|
||||
foreach (var inventory in inventories)
|
||||
{
|
||||
_context.Inventories.Add(inventory);
|
||||
inventory.Transactions = ModelHelper.GetAddedTransaction(inventory.AddedDate);
|
||||
}
|
||||
try
|
||||
{
|
||||
_context.SaveChanges();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
var message = ModelHelper.GetUpdateExceptionMessage(e);
|
||||
|
||||
LogManager.GetCurrentClassLogger().Info("Import Exception : {0}", message);
|
||||
return Request.CreateResponse(HttpStatusCode.BadRequest, message);
|
||||
}
|
||||
|
||||
return Request.CreateResponse(HttpStatusCode.OK, new {});
|
||||
}
|
||||
|
||||
private MultipartFormDataStreamProvider GetMultipartProvider()
|
||||
{
|
||||
var uploadFolder = "~/App_Data/Tmp/FileUploads";
|
||||
var root = HttpContext.Current.Server.MapPath(uploadFolder);
|
||||
Directory.CreateDirectory(root);
|
||||
return new MultipartFormDataExentisionStreamProvider(root);
|
||||
}
|
||||
|
||||
// http://stackoverflow.com/questions/16800820/asp-net-webapi-file-upload-using-guid-and-file-extension
|
||||
private class MultipartFormDataExentisionStreamProvider
|
||||
: MultipartFormDataStreamProvider
|
||||
{
|
||||
public MultipartFormDataExentisionStreamProvider(string rootPath) : base(rootPath)
|
||||
{
|
||||
}
|
||||
|
||||
public override string GetLocalFileName(HttpContentHeaders headers)
|
||||
{
|
||||
// override the filename which is stored by the provider (by default is bodypart_x)
|
||||
var oldfileName = headers.ContentDisposition.FileName.Replace("\"", string.Empty);
|
||||
var newFileName = Guid.NewGuid() + Path.GetExtension(oldfileName);
|
||||
|
||||
return newFileName;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,8 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
using System.Web.Mvc;
|
||||
using AutoMapper;
|
||||
using AutoMapper.QueryableExtensions;
|
||||
@@ -8,6 +10,7 @@ using InventoryTraker.Web.Attributes;
|
||||
using InventoryTraker.Web.Core;
|
||||
using InventoryTraker.Web.Data;
|
||||
using InventoryTraker.Web.Models;
|
||||
using InventoryTraker.Web.Services;
|
||||
using InventoryTraker.Web.Utilities;
|
||||
|
||||
namespace InventoryTraker.Web.Controllers
|
||||
@@ -16,11 +19,13 @@ namespace InventoryTraker.Web.Controllers
|
||||
{
|
||||
private readonly AppDbContext _context;
|
||||
private readonly IMapper _mapper;
|
||||
private readonly InventoryImporter _inventoryImporter;
|
||||
|
||||
public InventoryController(AppDbContext context, IMapper mapper)
|
||||
public InventoryController(AppDbContext context, IMapper mapper, InventoryImporter inventoryImporter)
|
||||
{
|
||||
_context = context;
|
||||
_mapper = mapper;
|
||||
_inventoryImporter = inventoryImporter;
|
||||
}
|
||||
|
||||
public ActionResult Index()
|
||||
@@ -38,7 +43,7 @@ namespace InventoryTraker.Web.Controllers
|
||||
return BetterJson(viewModels);
|
||||
}
|
||||
|
||||
public JsonResult Find(int id)
|
||||
public JsonResult Find(string id)
|
||||
{
|
||||
var inventory = _context.Inventories.Find(id);
|
||||
var viewModel = _mapper.Map<InventoryViewModel>(inventory);
|
||||
@@ -49,8 +54,8 @@ namespace InventoryTraker.Web.Controllers
|
||||
{
|
||||
return _context
|
||||
.Inventories
|
||||
.Where(x => x.Quantity > 0)
|
||||
.OrderBy(x => x.InventoryType.Name);
|
||||
.Where(i => i.Quantity > 0)
|
||||
.OrderByDescending(x => x.ShredReadyDate);
|
||||
}
|
||||
|
||||
public ActionResult Export()
|
||||
@@ -80,24 +85,9 @@ namespace InventoryTraker.Web.Controllers
|
||||
return GetModelStateErrorListJson();
|
||||
|
||||
var inventory = _mapper.Map<Inventory>(form);
|
||||
inventory.InventoryType = _context.InventoryTypes.Find(form.InventoryTypeId);
|
||||
|
||||
if (inventory.InventoryType == null)
|
||||
return GetErrorListJson("Inventory Type not found");
|
||||
|
||||
_context.Inventories.Add(inventory);
|
||||
inventory.Transactions = new List<Transaction>
|
||||
{
|
||||
new Transaction
|
||||
{
|
||||
TransactionType = TransactionType.Added,
|
||||
AddedQuantity = inventory.Quantity,
|
||||
CurrentQuantity = inventory.Quantity,
|
||||
Memo = "Arrival",
|
||||
Timestamp = DateTime.Now,
|
||||
TransactionDate = inventory.AddedDate
|
||||
}
|
||||
};
|
||||
inventory.Transactions = ModelHelper.GetAddedTransaction(inventory.AddedDate);
|
||||
_context.SaveChanges();
|
||||
|
||||
var model = _mapper.Map<InventoryViewModel>(inventory);
|
||||
@@ -105,61 +95,18 @@ namespace InventoryTraker.Web.Controllers
|
||||
}
|
||||
|
||||
[ActionLog]
|
||||
public JsonResult Distribute(InventoryDistributeForm form)
|
||||
public JsonResult Update(InventoryAddForm form)
|
||||
{
|
||||
if (!ModelState.IsValid)
|
||||
return GetModelStateErrorListJson();
|
||||
|
||||
if (form.InventoryQuantities == null || !form.InventoryQuantities.Any())
|
||||
return GetErrorListJson("Must add at least one item");
|
||||
|
||||
var errors = new List<string>();
|
||||
|
||||
foreach (var quantityForm in form.InventoryQuantities)
|
||||
{
|
||||
var inventory = _context.Inventories.Find(quantityForm.InventoryId);
|
||||
|
||||
// check if it's really there
|
||||
if (inventory == null)
|
||||
{
|
||||
errors.Add($"'{quantityForm.InventoryId}' not found");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (inventory.Quantity < quantityForm.Quantity)
|
||||
errors.Add(
|
||||
$"'{inventory.InventoryType.Name}' has only {inventory.Quantity} qty, " +
|
||||
$"cannot remove {quantityForm.Quantity}");
|
||||
|
||||
inventory.Quantity -= quantityForm.Quantity;
|
||||
|
||||
var mostRecentTransaction =
|
||||
inventory.Transactions.OrderByDescending(t => t.TransactionDate).First();
|
||||
if (form.DistributedDate < mostRecentTransaction.TransactionDate)
|
||||
errors.Add($"'{inventory.InventoryType.Name}' most recent transaction " +
|
||||
$"is {mostRecentTransaction.TransactionDate.ToShortDateString()}. " +
|
||||
$"Cannot add a transaction on {form.DistributedDate.ToShortDateString()}.");
|
||||
|
||||
inventory.Transactions.Add(new Transaction
|
||||
{
|
||||
TransactionType = TransactionType.Distributed,
|
||||
RemovedQuantity = quantityForm.Quantity,
|
||||
CurrentQuantity = inventory.Quantity,
|
||||
Destination = form.Destination,
|
||||
Memo = form.Memo,
|
||||
Timestamp = DateTime.Now,
|
||||
TransactionDate = form.DistributedDate
|
||||
});
|
||||
}
|
||||
|
||||
if (errors.Any())
|
||||
return GetErrorListJson(errors.ToArray());
|
||||
var inventory = _context.Inventories.Find(form.Id);
|
||||
_mapper.Map(form, inventory);
|
||||
|
||||
_context.SaveChanges();
|
||||
|
||||
return BetterJson(CurrentInventory()
|
||||
.ProjectTo<InventoryViewModel>(_mapper.ConfigurationProvider)
|
||||
.ToArray());
|
||||
var model = _mapper.Map<InventoryViewModel>(inventory);
|
||||
return BetterJson(model);
|
||||
}
|
||||
|
||||
[ActionLog]
|
||||
@@ -181,7 +128,7 @@ namespace InventoryTraker.Web.Controllers
|
||||
{
|
||||
if (inventory.Quantity < form.Quantity)
|
||||
errors.Add(
|
||||
$"'{inventory.InventoryType.Name}' has only {inventory.Quantity} qty, " +
|
||||
$"'{inventory.Id}' has only {inventory.Quantity} qty, " +
|
||||
$"cannot remove {form.Quantity}");
|
||||
|
||||
inventory.Quantity -= form.Quantity;
|
||||
@@ -189,7 +136,7 @@ namespace InventoryTraker.Web.Controllers
|
||||
var mostRecentTransaction =
|
||||
inventory.Transactions.OrderByDescending(t => t.TransactionDate).First();
|
||||
if (form.RemovedDate < mostRecentTransaction.TransactionDate)
|
||||
errors.Add($"'{inventory.InventoryType.Name}' most recent transaction " +
|
||||
errors.Add($"'{inventory.Id}' most recent transaction " +
|
||||
$"is {mostRecentTransaction.TransactionDate.ToShortDateString()}. " +
|
||||
$"Cannot add a transaction on {form.RemovedDate.ToShortDateString()}.");
|
||||
|
||||
|
||||
@@ -1,86 +0,0 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Web.Mvc;
|
||||
using AutoMapper;
|
||||
using AutoMapper.QueryableExtensions;
|
||||
using InventoryTraker.Web.Core;
|
||||
using InventoryTraker.Web.Data;
|
||||
using InventoryTraker.Web.Models;
|
||||
using InventoryTraker.Web.Utilities;
|
||||
|
||||
namespace InventoryTraker.Web.Controllers
|
||||
{
|
||||
public class InventoryTypeController : ControllerBase
|
||||
{
|
||||
private readonly AppDbContext _context;
|
||||
private readonly IMapper _mapper;
|
||||
|
||||
public InventoryTypeController(AppDbContext context, IMapper mapper)
|
||||
{
|
||||
_context = context;
|
||||
_mapper = mapper;
|
||||
}
|
||||
|
||||
public ActionResult Index()
|
||||
{
|
||||
return View();
|
||||
}
|
||||
|
||||
public JsonResult All()
|
||||
{
|
||||
var viewModels = _context.InventoryTypes
|
||||
.OrderByDescending(x => x.Name)
|
||||
.ProjectTo<InventoryTypeViewModel>(_mapper.ConfigurationProvider);
|
||||
|
||||
return BetterJson(viewModels.ToArray());
|
||||
}
|
||||
|
||||
public ActionResult Export()
|
||||
{
|
||||
var writer = new InventoryTypeReportWriter();
|
||||
|
||||
var viewModels =
|
||||
_context.InventoryTypes
|
||||
.OrderByDescending(x => x.Name)
|
||||
.ProjectTo<InventoryTypeViewModel>(_mapper.ConfigurationProvider)
|
||||
.ToArray();
|
||||
|
||||
var excel = writer.Write(viewModels);
|
||||
|
||||
var filename = $"CommodityTypes{DateTime.Today:yyyyMMdd}.xlsx";
|
||||
|
||||
return
|
||||
new FileContentResult(excel, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
|
||||
{
|
||||
FileDownloadName = filename
|
||||
};
|
||||
}
|
||||
|
||||
public JsonResult Add(InventoryTypeViewModel form)
|
||||
{
|
||||
if (!ModelState.IsValid)
|
||||
return GetModelStateErrorListJson();
|
||||
|
||||
var inventoryType = _mapper.Map<InventoryType>(form);
|
||||
_context.InventoryTypes.Add(inventoryType);
|
||||
_context.SaveChanges();
|
||||
|
||||
var model = _mapper.Map<InventoryTypeViewModel>(inventoryType);
|
||||
return BetterJson(model);
|
||||
}
|
||||
|
||||
public JsonResult Update(InventoryTypeViewModel form)
|
||||
{
|
||||
if (!ModelState.IsValid)
|
||||
return GetModelStateErrorListJson();
|
||||
|
||||
var inventoryType = _context.InventoryTypes.Find(form.Id);
|
||||
_mapper.Map(form, inventoryType);
|
||||
|
||||
_context.SaveChanges();
|
||||
|
||||
var model = _mapper.Map<InventoryTypeViewModel>(inventoryType);
|
||||
return BetterJson(model);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,81 +0,0 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Web.Mvc;
|
||||
using InventoryTraker.Web.Services;
|
||||
using InventoryTraker.Web.Utilities;
|
||||
|
||||
namespace InventoryTraker.Web.Controllers
|
||||
{
|
||||
public class ReportController : ControllerBase
|
||||
{
|
||||
private readonly ReportService _reportService;
|
||||
private readonly DistributionReportWriter _distributionReportWriter;
|
||||
private readonly MovementReportWriter _movementReportWriter;
|
||||
|
||||
public ReportController(
|
||||
ReportService reportService,
|
||||
DistributionReportWriter distributionReportWriter,
|
||||
MovementReportWriter movementReportWriter)
|
||||
{
|
||||
_reportService = reportService;
|
||||
_distributionReportWriter = distributionReportWriter;
|
||||
_movementReportWriter = movementReportWriter;
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public ActionResult Distribution()
|
||||
{
|
||||
return View();
|
||||
}
|
||||
|
||||
public ActionResult Distribution(DateTime startDate, DateTime endDate)
|
||||
{
|
||||
var report = _reportService.GetDistributionReport(startDate, endDate);
|
||||
|
||||
return BetterJson(report.ToArray());
|
||||
}
|
||||
|
||||
public ActionResult DistributionExcel(DateTime startDate, DateTime endDate)
|
||||
{
|
||||
var report = _reportService.GetDistributionReport(startDate, endDate);
|
||||
|
||||
var excel = _distributionReportWriter.Write(report);
|
||||
|
||||
var filename = $"InventoryDistributionReport{startDate:yyyyMMdd}-{endDate:yyyyMMdd}.xlsx";
|
||||
|
||||
return
|
||||
new FileContentResult(excel, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
|
||||
{
|
||||
FileDownloadName = filename
|
||||
};
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public ActionResult Movement()
|
||||
{
|
||||
return View();
|
||||
}
|
||||
|
||||
public ActionResult Movement(DateTime month)
|
||||
{
|
||||
var report = _reportService.GetMovementReport(month);
|
||||
|
||||
return BetterJson(report);
|
||||
}
|
||||
|
||||
public ActionResult MovementExcel(DateTime month)
|
||||
{
|
||||
var report = _reportService.GetMovementReport(month);
|
||||
|
||||
var excel = _movementReportWriter.Write(report);
|
||||
|
||||
var filename = $"MonthlyInventoryReport{report.Month:MMMMyyyy}.xlsx";
|
||||
|
||||
return
|
||||
new FileContentResult(excel, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
|
||||
{
|
||||
FileDownloadName = filename
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -35,15 +35,15 @@ namespace InventoryTraker.Web.Controllers
|
||||
return BetterJson(viewModels);
|
||||
}
|
||||
|
||||
public JsonResult Get(int? pageNumber, int? pageSize, int? inventoryId)
|
||||
public JsonResult Get(int? pageNumber, int? pageSize, string inventoryId)
|
||||
{
|
||||
IQueryable<Transaction> query =
|
||||
_context.Transactions
|
||||
.OrderByDescending(t => t.Timestamp);
|
||||
|
||||
if (inventoryId.HasValue)
|
||||
if (!string.IsNullOrEmpty(inventoryId))
|
||||
query =
|
||||
query.Where(t => t.Inventory.Id == inventoryId.Value);
|
||||
query.Where(t => t.Inventory.Id == inventoryId);
|
||||
|
||||
if (pageNumber.HasValue && pageSize.HasValue)
|
||||
query = query
|
||||
|
||||
@@ -1,27 +1,33 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace InventoryTraker.Web.Core
|
||||
{
|
||||
// AKA Commodity
|
||||
public class Inventory
|
||||
{
|
||||
public int Id { get; set; }
|
||||
[Key]
|
||||
[DatabaseGenerated(DatabaseGeneratedOption.None)]
|
||||
public string Id { get; set; }
|
||||
|
||||
public virtual InventoryType InventoryType { get; set; }
|
||||
[Required]
|
||||
public string ProgramName { get; set; }
|
||||
|
||||
public string ProgramSubtype { get; set; }
|
||||
|
||||
public string Description { get; set; }
|
||||
|
||||
public virtual ICollection<Transaction> Transactions { get; set; }
|
||||
|
||||
public int Quantity { get; set; }
|
||||
|
||||
[Required]
|
||||
public DateTime ExpirationDate { get; set; }
|
||||
public DateTime ShredReadyDate { get; set; }
|
||||
|
||||
[Required]
|
||||
public DateTime AddedDate { get; set; }
|
||||
|
||||
[Required]
|
||||
public int Quantity { get; set; }
|
||||
|
||||
public string Memo { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace InventoryTraker.Web.Core
|
||||
{
|
||||
public class InventoryType
|
||||
{
|
||||
public int Id { get; set; }
|
||||
|
||||
[Required]
|
||||
public string Identifier { get; set; }
|
||||
|
||||
[Required]
|
||||
public string Name { get; set; }
|
||||
|
||||
[Required]
|
||||
public int UnitsPerCase { get; set; }
|
||||
|
||||
[Required]
|
||||
public string ContainerType { get; set; }
|
||||
|
||||
public double WeightPerCase { get; set; }
|
||||
|
||||
public decimal PricePerCase { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -3,8 +3,8 @@ namespace InventoryTraker.Web.Core
|
||||
public enum TransactionType
|
||||
{
|
||||
Added,
|
||||
Distributed,
|
||||
Expired,
|
||||
Shreded,
|
||||
Loaned,
|
||||
Loss
|
||||
}
|
||||
}
|
||||
@@ -8,8 +8,6 @@ namespace InventoryTraker.Web.Data
|
||||
{
|
||||
public IDbSet<Inventory> Inventories { get; set; }
|
||||
|
||||
public IDbSet<InventoryType> InventoryTypes { get; set; }
|
||||
|
||||
public IDbSet<Transaction> Transactions { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Web;
|
||||
using System.Web.Http;
|
||||
using System.Web.Mvc;
|
||||
using System.Web.Optimization;
|
||||
using System.Web.Routing;
|
||||
@@ -11,12 +12,13 @@ namespace InventoryTraker.Web
|
||||
protected void Application_Start()
|
||||
{
|
||||
AreaRegistration.RegisterAllAreas();
|
||||
WebApiConfig.Register(GlobalConfiguration.Configuration);
|
||||
RouteConfig.RegisterRoutes(RouteTable.Routes);
|
||||
BundleConfig.RegisterBundles(BundleTable.Bundles);
|
||||
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
|
||||
EFConfig.Initialize();
|
||||
SeedData.Init();
|
||||
SeedData.AddAdminRole();
|
||||
//SeedData.Init();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -228,6 +228,7 @@
|
||||
<Content Include="Global.asax" />
|
||||
<Content Include="js\app.js" />
|
||||
<Content Include="js\authentication\LoginController.js" />
|
||||
<Content Include="js\inventory\InventoryImportDirective.js" />
|
||||
<Content Include="js\profile\profileSvc.js" />
|
||||
<Content Include="js\profile\ProfileEditDirective.js" />
|
||||
<Content Include="js\user\UserCreateDirective.js" />
|
||||
@@ -235,27 +236,16 @@
|
||||
<Content Include="js\user\UserEditDirective.js" />
|
||||
<Content Include="js\user\UserListDirective.js" />
|
||||
<Content Include="js\user\userSvc.js" />
|
||||
<Content Include="js\inventoryType\InventoryTypeAddDirective.js" />
|
||||
<Content Include="js\inventoryType\InventoryTypeListDirective.js" />
|
||||
<Content Include="js\inventoryType\InventoryTypeEditDirective.js" />
|
||||
<Content Include="js\inventoryType\InventoryTypeController.js" />
|
||||
<Content Include="js\inventory\InventoryAddDirective.js" />
|
||||
<Content Include="js\inventory\inventoryInfoDirective.js" />
|
||||
<Content Include="js\inventory\inventoryRemoveDirective.js" />
|
||||
<Content Include="js\inventory\InventoryListDirective.js" />
|
||||
<Content Include="js\inventory\InventoryListController.js" />
|
||||
<Content Include="js\inventoryType\inventoryTypeSvc.js" />
|
||||
<Content Include="js\inventory\inventorySvc.js" />
|
||||
<Content Include="js\inventory\InventoryEditDirective.js" />
|
||||
<Content Include="js\inventory\InventoryDistributeDirective.js" />
|
||||
<Content Include="js\profile\ProfileController.js" />
|
||||
<Content Include="js\report\MovementReportDirective.js" />
|
||||
<Content Include="js\report\MovementReportController.js" />
|
||||
<Content Include="js\report\DistributionReportDirective.js" />
|
||||
<Content Include="js\utility\MonthQueryDirective.js" />
|
||||
<Content Include="js\utility\DateRangeQueryDirective.js" />
|
||||
<Content Include="js\report\DistributionReportController.js" />
|
||||
<Content Include="js\report\reportSvc.js" />
|
||||
<Content Include="js\transaction\TransactionController.js" />
|
||||
<Content Include="js\transaction\transactionSvc.js" />
|
||||
<Content Include="js\utility\ArrayExtensions.js" />
|
||||
@@ -294,13 +284,6 @@
|
||||
<Content Include="fonts\fontawesome-webfont.eot" />
|
||||
<Content Include="Scripts\angular-strap.min.js.map" />
|
||||
<Content Include="fonts\glyphicons-halflings-regular.woff2" />
|
||||
<Content Include="App_Data\InventoryTypeSeedData.xlsx">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="js\inventory\templates\inventoryDistribute.tmpl.cshtml" />
|
||||
<Content Include="js\inventoryType\templates\inventoryTypeEdit.tmpl.cshtml" />
|
||||
<Content Include="js\inventoryType\templates\inventoryTypeAdd.tmpl.cshtml" />
|
||||
<Content Include="js\inventoryType\templates\inventoryTypeList.tmpl.cshtml" />
|
||||
<Content Include="js\inventory\templates\inventoryInfo.tmpl.cshtml" />
|
||||
<Content Include="js\inventory\templates\inventoryRemove.tmpl.cshtml" />
|
||||
<Content Include="NLog.config">
|
||||
@@ -308,14 +291,13 @@
|
||||
</Content>
|
||||
<Content Include="js\utility\templates\dateRangeQuery.tmpl.cshtml" />
|
||||
<Content Include="js\utility\templates\errorList.tmpl.cshtml" />
|
||||
<Content Include="js\report\templates\distributionReport.tmpl.cshtml" />
|
||||
<Content Include="js\utility\templates\statusMessage.tmpl.cshtml" />
|
||||
<Content Include="js\utility\templates\monthQuery.tmpl.cshtml" />
|
||||
<Content Include="js\report\templates\movementReport.tmpl.cshtml" />
|
||||
<Content Include="js\user\templates\userCreate.tmpl.cshtml" />
|
||||
<Content Include="js\user\templates\userEdit.tmpl.cshtml" />
|
||||
<Content Include="js\user\templates\userList.tmpl.cshtml" />
|
||||
<Content Include="js\profile\templates\profileEdit.tmpl.cshtml" />
|
||||
<Content Include="js\inventory\templates\inventoryImport.tmpl.cshtml" />
|
||||
<None Include="NLog.xsd">
|
||||
<SubType>Designer</SubType>
|
||||
</None>
|
||||
@@ -323,10 +305,19 @@
|
||||
<None Include="Scripts\jquery-1.9.1.intellisense.js" />
|
||||
<Content Include="Scripts\bootstrap.js" />
|
||||
<Content Include="Scripts\bootstrap.min.js" />
|
||||
<Content Include="Scripts\FileAPI.flash.swf" />
|
||||
<Content Include="Scripts\FileAPI.js" />
|
||||
<Content Include="Scripts\FileAPI.min.js" />
|
||||
<Content Include="Scripts\FileSaver.js" />
|
||||
<Content Include="Scripts\FileSaver.min.js" />
|
||||
<Content Include="Scripts\jquery-1.9.1.js" />
|
||||
<Content Include="Scripts\jquery-1.9.1.min.js" />
|
||||
<Content Include="Scripts\ng-file-upload-all.js" />
|
||||
<Content Include="Scripts\ng-file-upload-all.min.js" />
|
||||
<Content Include="Scripts\ng-file-upload-shim.js" />
|
||||
<Content Include="Scripts\ng-file-upload-shim.min.js" />
|
||||
<Content Include="Scripts\ng-file-upload.js" />
|
||||
<Content Include="Scripts\ng-file-upload.min.js" />
|
||||
<Content Include="Scripts\ui-grid.js" />
|
||||
<Content Include="Scripts\ui-grid.min.js" />
|
||||
<Content Include="Web.config">
|
||||
@@ -340,23 +331,23 @@
|
||||
<Compile Include="App_Start\EFConfig.cs" />
|
||||
<Compile Include="App_Start\FilterConfig.cs" />
|
||||
<Compile Include="App_Start\RouteConfig.cs" />
|
||||
<Compile Include="Utilities\ModelHelper.cs" />
|
||||
<Content Include="js\utility\DownloadService.js" />
|
||||
<Compile Include="App_Start\WebApiConfig.cs" />
|
||||
<Compile Include="Attributes\ExceptionHandlingAttribute.cs" />
|
||||
<Compile Include="Controllers\ImportController.cs" />
|
||||
<Compile Include="Controllers\UserController.cs" />
|
||||
<Compile Include="Migrations\SeedData.cs" />
|
||||
<Compile Include="App_Start\Startup.cs" />
|
||||
<Compile Include="App_Start\StructureMapConfig.cs" />
|
||||
<Compile Include="Attributes\ActionLogAttribute.cs" />
|
||||
<Compile Include="Controllers\ReportController.cs" />
|
||||
<Compile Include="Controllers\TransactionController.cs" />
|
||||
<Compile Include="Controllers\InventoryController.cs" />
|
||||
<Compile Include="Controllers\AuthenticationController.cs" />
|
||||
<Compile Include="Controllers\ControllerBase.cs" />
|
||||
<Compile Include="Controllers\HomeController.cs" />
|
||||
<Compile Include="Controllers\InventoryTypeController.cs" />
|
||||
<Compile Include="Controllers\ProfileController.cs" />
|
||||
<Compile Include="Controllers\TemplateController.cs" />
|
||||
<Compile Include="Core\Inventory.cs" />
|
||||
<Compile Include="Core\InventoryType.cs" />
|
||||
<Compile Include="Core\Transaction.cs" />
|
||||
<Compile Include="Core\TransactionType.cs" />
|
||||
<Compile Include="Core\User.cs" />
|
||||
@@ -372,39 +363,28 @@
|
||||
<Compile Include="Helpers\UIRatingTag.cs" />
|
||||
<Compile Include="Identity\ApplicationUserManager.cs" />
|
||||
<Compile Include="Identity\AspNetIdentityRegistry.cs" />
|
||||
<Compile Include="Migrations\201609201242047_Initial.cs" />
|
||||
<Compile Include="Migrations\201609201242047_Initial.Designer.cs">
|
||||
<DependentUpon>201609201242047_Initial.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Migrations\Configuration.cs" />
|
||||
<Compile Include="Models\UserEditForm.cs" />
|
||||
<Compile Include="Models\UserViewModel.cs" />
|
||||
<Compile Include="Models\UserCreateForm.cs" />
|
||||
<Compile Include="Models\DateRangeQuery.cs" />
|
||||
<Compile Include="Models\DistributionReport.cs" />
|
||||
<Compile Include="Models\InventoryDistributeForm.cs" />
|
||||
<Compile Include="Models\InventoryAddForm.cs" />
|
||||
<Compile Include="Models\InventoryQuantityForm.cs" />
|
||||
<Compile Include="Models\InventoryRemoveForm.cs" />
|
||||
<Compile Include="Models\MovementReport.cs" />
|
||||
<Compile Include="Models\MovementReportItem.cs" />
|
||||
<Compile Include="Models\InventoryTypeViewModel.cs" />
|
||||
<Compile Include="Models\InventoryViewModel.cs" />
|
||||
<Compile Include="Models\LoginForm.cs" />
|
||||
<Compile Include="Models\ProfileForm.cs" />
|
||||
<Compile Include="Models\TransactionViewModel.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Services\ReportService.cs" />
|
||||
<Compile Include="Services\ImportException.cs" />
|
||||
<Compile Include="Services\InventoryImporter.cs" />
|
||||
<Compile Include="Utilities\ControllerContextExtensions.cs" />
|
||||
<Compile Include="Utilities\InventoryTypeReportWriter.cs" />
|
||||
<Compile Include="Utilities\InventoryParser.cs" />
|
||||
<Compile Include="Utilities\InventoryReportWriter.cs" />
|
||||
<Compile Include="Utilities\ExcelParserBase.cs" />
|
||||
<Compile Include="Utilities\IEnumerableExtensions.cs" />
|
||||
<Compile Include="Utilities\InventoryTypeParser.cs" />
|
||||
<Compile Include="Utilities\DateExtensions.cs" />
|
||||
<Compile Include="Utilities\JsonExtensions.cs" />
|
||||
<Compile Include="Utilities\DistributionReportWriter.cs" />
|
||||
<Compile Include="Utilities\MovementReportWriter.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="Views\web.config" />
|
||||
@@ -418,14 +398,12 @@
|
||||
<Content Include="Scripts\angular-animate.min.js.map" />
|
||||
<Content Include="Scripts\jquery-1.9.1.min.map" />
|
||||
<Content Include="Views\Authentication\Login.cshtml" />
|
||||
<Content Include="Views\Home\Index.cshtml" />
|
||||
<Content Include="Views\Inventory\Index.cshtml" />
|
||||
<Content Include="Views\Profile\Index.cshtml" />
|
||||
<Content Include="Views\Shared\_NavigationNoAuth.cshtml" />
|
||||
<Content Include="Views\Shared\_Navigation.cshtml" />
|
||||
<Content Include="Views\_ViewStart.cshtml" />
|
||||
<Content Include="Views\Transaction\Index.cshtml" />
|
||||
<Content Include="Views\InventoryType\Index.cshtml" />
|
||||
<Content Include="Views\Report\Distribution.cshtml" />
|
||||
<Content Include="Views\Report\Movement.cshtml" />
|
||||
<Content Include="Views\User\Index.cshtml" />
|
||||
@@ -437,11 +415,8 @@
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="Migrations\201609201242047_Initial.resx">
|
||||
<DependentUpon>201609201242047_Initial.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<Folder Include="App_Data\" />
|
||||
</ItemGroup>
|
||||
<ItemGroup />
|
||||
<PropertyGroup>
|
||||
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion>
|
||||
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
|
||||
@@ -457,7 +432,7 @@
|
||||
<AutoAssignPort>True</AutoAssignPort>
|
||||
<DevelopmentServerPort>58523</DevelopmentServerPort>
|
||||
<DevelopmentServerVPath>/</DevelopmentServerVPath>
|
||||
<IISUrl>http://localhost:58446/</IISUrl>
|
||||
<IISUrl>http://localhost:58448/</IISUrl>
|
||||
<NTLMAuthentication>False</NTLMAuthentication>
|
||||
<UseCustomServer>False</UseCustomServer>
|
||||
<CustomServerUrl>
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
// <auto-generated />
|
||||
namespace InventoryTraker.Web.Migrations
|
||||
{
|
||||
using System.CodeDom.Compiler;
|
||||
using System.Data.Entity.Migrations;
|
||||
using System.Data.Entity.Migrations.Infrastructure;
|
||||
using System.Resources;
|
||||
|
||||
[GeneratedCode("EntityFramework.Migrations", "6.1.3-40302")]
|
||||
public sealed partial class Initial : IMigrationMetadata
|
||||
{
|
||||
private readonly ResourceManager Resources = new ResourceManager(typeof(Initial));
|
||||
|
||||
string IMigrationMetadata.Id
|
||||
{
|
||||
get { return "201609201242047_Initial"; }
|
||||
}
|
||||
|
||||
string IMigrationMetadata.Source
|
||||
{
|
||||
get { return null; }
|
||||
}
|
||||
|
||||
string IMigrationMetadata.Target
|
||||
{
|
||||
get { return Resources.GetString("Target"); }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,156 +0,0 @@
|
||||
namespace InventoryTraker.Web.Migrations
|
||||
{
|
||||
using System;
|
||||
using System.Data.Entity.Migrations;
|
||||
|
||||
public partial class Initial : DbMigration
|
||||
{
|
||||
|
||||
|
||||
public override void Up()
|
||||
{
|
||||
CreateTable(
|
||||
"dbo.Inventories",
|
||||
c => new
|
||||
{
|
||||
Id = c.Int(nullable: false, identity: true),
|
||||
ExpirationDate = c.DateTime(nullable: false),
|
||||
AddedDate = c.DateTime(nullable: false),
|
||||
Quantity = c.Int(nullable: false),
|
||||
Memo = c.String(),
|
||||
InventoryType_Id = c.Int(),
|
||||
})
|
||||
.PrimaryKey(t => t.Id)
|
||||
.ForeignKey("dbo.InventoryTypes", t => t.InventoryType_Id)
|
||||
.Index(t => t.InventoryType_Id);
|
||||
|
||||
CreateTable(
|
||||
"dbo.InventoryTypes",
|
||||
c => new
|
||||
{
|
||||
Id = c.Int(nullable: false, identity: true),
|
||||
Identifier = c.String(nullable: false),
|
||||
Name = c.String(nullable: false),
|
||||
UnitsPerCase = c.Int(nullable: false),
|
||||
ContainerType = c.String(nullable: false),
|
||||
WeightPerCase = c.Double(nullable: false),
|
||||
PricePerCase = c.Decimal(nullable: false, precision: 18, scale: 2),
|
||||
})
|
||||
.PrimaryKey(t => t.Id);
|
||||
|
||||
CreateTable(
|
||||
"dbo.Transactions",
|
||||
c => new
|
||||
{
|
||||
Id = c.Int(nullable: false, identity: true),
|
||||
TransactionType = c.Int(nullable: false),
|
||||
AddedQuantity = c.Int(nullable: false),
|
||||
RemovedQuantity = c.Int(nullable: false),
|
||||
CurrentQuantity = c.Int(nullable: false),
|
||||
TransactionDate = c.DateTime(nullable: false),
|
||||
Memo = c.String(),
|
||||
Destination = c.String(),
|
||||
Timestamp = c.DateTime(nullable: false),
|
||||
Inventory_Id = c.Int(),
|
||||
})
|
||||
.PrimaryKey(t => t.Id)
|
||||
.ForeignKey("dbo.Inventories", t => t.Inventory_Id)
|
||||
.Index(t => t.Inventory_Id);
|
||||
|
||||
CreateTable(
|
||||
"dbo.AspNetRoles",
|
||||
c => new
|
||||
{
|
||||
Id = c.String(nullable: false, maxLength: 128),
|
||||
Name = c.String(nullable: false, maxLength: 256),
|
||||
})
|
||||
.PrimaryKey(t => t.Id)
|
||||
.Index(t => t.Name, unique: true, name: "RoleNameIndex");
|
||||
|
||||
CreateTable(
|
||||
"dbo.AspNetUserRoles",
|
||||
c => new
|
||||
{
|
||||
UserId = c.String(nullable: false, maxLength: 128),
|
||||
RoleId = c.String(nullable: false, maxLength: 128),
|
||||
})
|
||||
.PrimaryKey(t => new { t.UserId, t.RoleId })
|
||||
.ForeignKey("dbo.AspNetRoles", t => t.RoleId, cascadeDelete: true)
|
||||
.ForeignKey("dbo.AspNetUsers", t => t.UserId, cascadeDelete: true)
|
||||
.Index(t => t.UserId)
|
||||
.Index(t => t.RoleId);
|
||||
|
||||
CreateTable(
|
||||
"dbo.AspNetUsers",
|
||||
c => new
|
||||
{
|
||||
Id = c.String(nullable: false, maxLength: 128),
|
||||
Email = c.String(maxLength: 256),
|
||||
EmailConfirmed = c.Boolean(nullable: false),
|
||||
PasswordHash = c.String(),
|
||||
SecurityStamp = c.String(),
|
||||
PhoneNumber = c.String(),
|
||||
PhoneNumberConfirmed = c.Boolean(nullable: false),
|
||||
TwoFactorEnabled = c.Boolean(nullable: false),
|
||||
LockoutEndDateUtc = c.DateTime(),
|
||||
LockoutEnabled = c.Boolean(nullable: false),
|
||||
AccessFailedCount = c.Int(nullable: false),
|
||||
UserName = c.String(nullable: false, maxLength: 256),
|
||||
})
|
||||
.PrimaryKey(t => t.Id)
|
||||
.Index(t => t.UserName, unique: true, name: "UserNameIndex");
|
||||
|
||||
CreateTable(
|
||||
"dbo.AspNetUserClaims",
|
||||
c => new
|
||||
{
|
||||
Id = c.Int(nullable: false, identity: true),
|
||||
UserId = c.String(nullable: false, maxLength: 128),
|
||||
ClaimType = c.String(),
|
||||
ClaimValue = c.String(),
|
||||
})
|
||||
.PrimaryKey(t => t.Id)
|
||||
.ForeignKey("dbo.AspNetUsers", t => t.UserId, cascadeDelete: true)
|
||||
.Index(t => t.UserId);
|
||||
|
||||
CreateTable(
|
||||
"dbo.AspNetUserLogins",
|
||||
c => new
|
||||
{
|
||||
LoginProvider = c.String(nullable: false, maxLength: 128),
|
||||
ProviderKey = c.String(nullable: false, maxLength: 128),
|
||||
UserId = c.String(nullable: false, maxLength: 128),
|
||||
})
|
||||
.PrimaryKey(t => new { t.LoginProvider, t.ProviderKey, t.UserId })
|
||||
.ForeignKey("dbo.AspNetUsers", t => t.UserId, cascadeDelete: true)
|
||||
.Index(t => t.UserId);
|
||||
|
||||
}
|
||||
|
||||
public override void Down()
|
||||
{
|
||||
DropForeignKey("dbo.AspNetUserRoles", "UserId", "dbo.AspNetUsers");
|
||||
DropForeignKey("dbo.AspNetUserLogins", "UserId", "dbo.AspNetUsers");
|
||||
DropForeignKey("dbo.AspNetUserClaims", "UserId", "dbo.AspNetUsers");
|
||||
DropForeignKey("dbo.AspNetUserRoles", "RoleId", "dbo.AspNetRoles");
|
||||
DropForeignKey("dbo.Transactions", "Inventory_Id", "dbo.Inventories");
|
||||
DropForeignKey("dbo.Inventories", "InventoryType_Id", "dbo.InventoryTypes");
|
||||
DropIndex("dbo.AspNetUserLogins", new[] { "UserId" });
|
||||
DropIndex("dbo.AspNetUserClaims", new[] { "UserId" });
|
||||
DropIndex("dbo.AspNetUsers", "UserNameIndex");
|
||||
DropIndex("dbo.AspNetUserRoles", new[] { "RoleId" });
|
||||
DropIndex("dbo.AspNetUserRoles", new[] { "UserId" });
|
||||
DropIndex("dbo.AspNetRoles", "RoleNameIndex");
|
||||
DropIndex("dbo.Transactions", new[] { "Inventory_Id" });
|
||||
DropIndex("dbo.Inventories", new[] { "InventoryType_Id" });
|
||||
DropTable("dbo.AspNetUserLogins");
|
||||
DropTable("dbo.AspNetUserClaims");
|
||||
DropTable("dbo.AspNetUsers");
|
||||
DropTable("dbo.AspNetUserRoles");
|
||||
DropTable("dbo.AspNetRoles");
|
||||
DropTable("dbo.Transactions");
|
||||
DropTable("dbo.InventoryTypes");
|
||||
DropTable("dbo.Inventories");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,126 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="Target" xml:space="preserve">
|
||||
<value>H4sIAAAAAAAEAO1dW2/kthV+L9D/IOipLZwZX7qLrWEncMZ2a3R96Y436ZvBkThjYXWZSJRjI8gv60N/Uv9CSV15FylpLhsEAYKxSH7nwkPy8JA8+7///Pfsu9codF5gmgVJfO4eTQ5dB8Ze4gfx6tzN0fKbD+533/7xD2dXfvTq/FDXOyH1cMs4O3efEVqfTqeZ9wwjkE2iwEuTLFmiiZdEU+An0+PDw79Nj46mEEO4GMtxzj7lMQoiWPyB/5wlsQfXKAfhbeLDMKu+45J5gercgQhma+DBc/cmfoExStK3xxR8genkR7iYXAIEXOciDADmZw7DpeuAOE4QQJjb088ZnKM0iVfzNf4Awse3NcT1liDMYCXFaVvdVKDDYyLQtG1YQ3l5hpLIEvDopNLQlG/eS89uo0Gswyusa/RGpC70SKnQdXhqp7MwJTXlep4lKZw0BQeOpM5BYyTYlsh/B84sD1GewvMY5igF4YHzkC/CwPsnfHtMvsD4PM7DkGYYs4zLmA/400OarGGK3j7BZS2G7zpTtt2Ub9g0o9rU8qGTY9e5w8TBIoSNPVC6mGPR4N9hDFOAoP8AEIJpTDBgoVGBOkfr6nUdpAUStk9Y0yW/H7HtS0jr4S58H/qjIP0rB5UAelXoUW5hlNQIeHzhCcN1bsHrRxiv0DMuBq+ucx28Qr/+UqF+jgM8v+BGKM1FInfgJVgVSuN7rrE1TNF1PsGwqJU9B+tyzLeG+cTVvU6T6FMS0iBslad5kqceUWyir/cI0hVE5kzjcRFnwCsYlfJMVXiihmXLsbRCw0fNr7xWLRXN7dm0nQ7MJolSh0MmClLv98lCP5rKessApiOMKcuRTP6/faq4NcoeYDoDGRw2E2H3AYEAa7401W0L8iMMVs+Ik+QywXZrj/WQBh7koaAXRCB0nYcU/6octQ+uM/cAwe3Sl/GIpyaRXuOdav/7aNd3M6Uqxma5JaEs6+MnjLPEf8JL/MtYYLM8TbF2xgGjlDSKS7QZZ4YjcgkzFMSVV79hWkQLGQLR2l413S7YmK4M73rpHZ5+rkw1KgkB3cx222ypLrL1HUSTuuGkhLxOMdzPSfplQiMeOMbt2hnw2HQGPDlaLE8+vHsP/JP3f4Un77Y/G0pM9Oj4ww78kON370ehqrTvzxnuHfnWgurvp6oatasQSsUNhVhlFJMmUOObdY26/6ZNOBXNW1qVCNRnJNQktj0aan43S9fY4ogaermFpOHX7Q9ur8+vIhCEI0yBBlTwpmkZpBFspPw+wQYHYvstC8gyPAP4/wDZ88bdmjn08hQb5px2bTZG7eE5ieFdHi1G2ZUb0xqtax5/Tq6xK5WkVzFpNRjvY+J9SXJ0FRdxyM/IE51LQ4BR2LnwPJhl19iYoT9L8hgN21OQiWrXLsgsBEEk90EIe091eet8UJ8Fr4Musw1dfkxWgSJoWcDW5Rwn5Wc5J1WZLScEQcNIVczxUXyVs1EWjeZ+Ffod3/8qYPffAdv3SMuuvLei+0aKRxpQ+gGE+dikeo2GYoyPPxoK2P0fDQWb+PNL4BOXwWBXUlfG8Eb15Rue7jHHcbbt4cCIuW3i25kD1MMlj+RR9nJ6uMmuQ7BqLyQMi7yPftaGdYD7LXzDOqPnbFbht5D4rXQA2nWKKencPRR6h6l8GWS4PxY5opoc6ZsU5+pU9WN99Y9JljV1T8Q+K3uH/niRZYkXFMrnI5/c0TJLFvvFjuE5cxvup0Klt7g/gjXuAWxF5+5fBLG68ZtzYQl+aW0sjcPJ5IjXCCW9XinygK+K5Y7or/T8w0YlHQflBgofpAxJhFDZeZpwIcUmE7RmOT1y+YXiPr6EIUTQufDKO0czkHnAF6dGbPC+BWMy/Qmhx65OwqsXJEc/ASBRBzzeQRAjcakLYi9Yg7BTS1xLQ7eUyN7Q4Esu4RrGhGCnJkyIyyONhIGGDtcpXRqyMER6m6jqaOmese3hMtS3FZOT7VAVtlbtszZibBKFbMHKJMKbUFXGvLdmXtXeX9upfCBgd+bFhR0U5lVtXDZnXqxCtmVerPBfh3mVER1tn3Lhnd0ZFxtM2v4yKWpjW5bFSL5nhlXuxJp7YfXGZL2+XJCP8BVJ9lmYv2qrlVUbPr7nCegcIm5TEJDwY7v3E91MwWeV4xSttVClC98Bx945FcAY97oDqgqtigwxvmmXeNxA0AG2g6UDtDqDF4DK4W/BUR1Q17JUuR4WsHV0XAtbLTkcLGXSEhvh7zZTtTuuQfOjzny32gjK2bwwkM03qBLI2vz5GZjVh4GuFBeRRE0ZbGAttrCUSOwQ1KhJv2k103sPDcmus0gMqWNLa7qppcSoxr/OcNR7UFod4pwyWCnM+ZqoDeW+qnNnRfFd6Vojv2xDpBC85nUcyesZSyG5zOXvdPrtJed8dYXkNa/jSF4ZkEJwiTPa5Y7ai816kSMZeh2QbtygpuxsWr6rqz6cTRUP8M5uwXodxCvqQV71xZmXr/Fm38ztH6hFJcbUY/TKO20NJTztgRXkSsmtfx9eB2mGyOu/RXFffuZHQjXG6VMs4DUp0a8T+61ez+s25Dfvx7EvEyfKtaXV5zUWMSIOdnHcKVsdxbYOeR4JQpBKjldnSZhHsdrZV7fmX63RSHyZOSr1eI0GpD6bY7U3yGmo9qs5Unnrm0Ypv4gIZ1Ouo4Q9jGAZwkaSNTYrU6x8o3GtUeYV2likvP1mrJJ+HsWitN/N0cpbPjRO+cUcgX28RCOxJeaI3CMmGpIrMsfkXibRmFyROSb7QomGZEv2ZgwxzvgoI4jeQtuPH23rzYwe4cyZhhIKLWd1+XTMFZljCm+OaFSh0GJ88c+PmBHGF/bSrbi+CYWbWJtUCMxzIxqIKbCQtH1SxMjYft6bMa9y2vssl3Ssq8dqqW2+meFuvrztyq0RdjWjdlUTRezfXWoIpUdQRbcZX0AR8Vaj1EfHzKSnOE7eWfepYkE9uqyI19p3k7zZhjZE5ZsMZh9UfrLEoK71C2BUmYUrxry8YFwxpsQckXteQUNyRRZc0o8oGCbpgl54Co3Ka1gsdMKzCWa9E0rNkSUPKGhoSXEPbAnPfJmFiye+sWDcPLHYYhPVPLjgJ809Xq+UIeCBC1Z5xjRsxVJgbGZeHGfBo+7JMw55+9kSq7oJL4BV3/fSppTB9YE2VR4wDrMpBYZ6FmLumbOTkPZyvBqTuTzORhw0l+fVeHaWu2n7YOP3ivgff+xrE+fj2xqHmMkphSoFhPxcV1Se2cTDYMnviFC89GdTeUWm9/yoZQx7H35Q3G66ycjbgeaOv43w/AmPtREpzsPtAl10S4uIlqRvtGfeQw1oDOPRHvPvp+n0MhvhfJCv0sx8zTkhdx54Vp3NdWftFA7ryiokp1U5heMNxluGYFQa3vyncBYGkLiTdYVbEAdLmKHyaYp7fHh0zKX83J/0m9Ms80PJ2Sb9Zk7xYGILjy4DotbOZ5W2mQukyS59/BuNkuyyNxKfb6qQfkB2qPgFpN4zSP8Ugdc/00gmbzXFuZ5iSriQeBP78PXc/aVofOrc/PuJb3/g3Kd4bJw6h86vel565n38bRinmFxR2YvWiYqGIcmSIPaxUGkKxGGsSdMaLsME2HMny2ro7yCr4W/DmhXJA/uYjTRXYB8gRabAXqYszxPYB0qRJbD3WjLaOiDJBDgIT8j211tE1qXsuTptaGVSHqVtYyjX/SM+HB9h8ehWLxGa/Co+H+BNAV45fspxwSNWKFExn6VmnNlTfx62pznazLWKjbZsyprrwB5mM7dZcVM2HcCNXT63r3cUMZnSpKjcKOifGG0R9PB4JEnRBs3w0sRngxAlyc3GwhtFharkZX2wlInLZOukibDyRGZ9WFMmMevj8PApzMznnrrlDtcXyenVV+uj79eCJCSjGjTQxYRTFnADkkr1sIyvLB/TaKvjg5huaTTsXZq2ynpGzNhDD5M+CXTkqH1T/vRLndJxw3/09+C6By4SYganfVtINWCXvsiyJzvsgnmErXqcvVnb2IZd6C/Kayxjd1bRM4/TvqRuah/Qa1/Xbzxj0zaTNGmu+5pGGLZkXKa5mXaV0USS80CfEWFjKU22bT+q23cW0ax9yr60DwZUZbdQGNCm0y1t24BUV+320YC68yvtg/3sahnbhfUYL187z6Ekvrrn+7K6Fibcc9GmSCqvA527/oIcsJX7P13OEyWZcpOmJlVdgdSQU+Sh4SkyrrpAjymVUdOliFFmFiqtXhSOKZZRK7NlyxNIqIi1w0xJsK2iJqrOXMETLucZgVj5WU/ATqrKedGKVdXRk1VkYNHRrtY9Le2qjp62IgfKDrNH0UNPkilAnLOku2tZ+667jQYq2FhSKEvW1WEAqrUuR9veZXuS5quRJXHrWOklKMp0cDvM7iSk9zEWk5l2FG93RhJ0jGRO/QVl5jjFg5KRBB2eu6m/mGOarUWuJvHONXby8picYpZ/XcIsWLUQ5Cp5DD3GvWvq3MTLpPYyOY7qKsIdKAR87PtdpChY4jkKF5MDzOKfVKiS7F9FC+jfxPc5WucIiwyjRchMhMRb1dEvElKxPJ/drwtfaQwRMJsBOfi9j7/Pg7D9hwSuJQcOCgjiBlfHhaQvETk2XL01SHdJbAhUqa/x3h9htA4xWHYfz8EL7MMbNr+PcAW8t/Z4SQXS3RGs2s8uA7BKQZRVGG17/Ce2YT96/fb/ZW0K6VaEAAA=</value>
|
||||
</data>
|
||||
<data name="DefaultSchema" xml:space="preserve">
|
||||
<value>dbo</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -1,12 +1,9 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
using InventoryTraker.Web.Core;
|
||||
using InventoryTraker.Web.Data;
|
||||
using InventoryTraker.Web.Identity;
|
||||
using InventoryTraker.Web.Utilities;
|
||||
using Microsoft.AspNet.Identity;
|
||||
using Microsoft.AspNet.Identity.EntityFramework;
|
||||
|
||||
@@ -14,7 +11,6 @@ namespace InventoryTraker.Web.Migrations
|
||||
{
|
||||
public static class SeedData
|
||||
{
|
||||
|
||||
public static void AddAdminRole()
|
||||
{
|
||||
using (var context = new AppDbContext())
|
||||
@@ -80,32 +76,16 @@ namespace InventoryTraker.Web.Migrations
|
||||
|
||||
if (!context.Inventories.Any())
|
||||
{
|
||||
AddInventoryTypes(context);
|
||||
//AddInventory(context);
|
||||
|
||||
context.SaveChanges();
|
||||
|
||||
AddInventory(context);
|
||||
|
||||
context.SaveChanges();
|
||||
}
|
||||
}
|
||||
|
||||
private static void AddInventoryTypes(AppDbContext context)
|
||||
{
|
||||
var folder = HttpContext.Current.Server.MapPath("~/App_Data");
|
||||
var inventoryTypeFile = Path.Combine(folder, "InventoryTypeSeedData.xlsx");
|
||||
var parser = new InventoryTypeParser(new FileInfo(inventoryTypeFile));
|
||||
foreach (var inventoryType in parser.Parse())
|
||||
{
|
||||
context.InventoryTypes.Add(inventoryType);
|
||||
}
|
||||
}
|
||||
|
||||
private static void AddInventory(AppDbContext context)
|
||||
{
|
||||
var r = new Random(1);
|
||||
var inventoryTypes = context.InventoryTypes.ToList();
|
||||
var counties = new List<string> {"Blount County", "Morgan County", "Knox County", "Anderson County", "Claiborne County", "Campbell County"};
|
||||
var programs = new List<string> { "Aging", "Corrections", "Employment", "Family", "Health", "Housing" };
|
||||
var colors = new List<string> {"Red", "Purple", "Blue", "Yellow", "White"};
|
||||
|
||||
for (var dd = DateTime.Today.AddYears(-4); dd < DateTime.Today.AddMonths(-2); dd = dd.AddMonths(3))
|
||||
@@ -114,31 +94,33 @@ namespace InventoryTraker.Web.Migrations
|
||||
// add some inventory
|
||||
for (int i = 0; i < r.Next(5,10); i++)
|
||||
{
|
||||
var inventoryType = inventoryTypes.ElementAt(r.Next(0, context.InventoryTypes.Count()));
|
||||
var addedDate = dd.AddDays(r.Next(-10, 10));
|
||||
var expiration = addedDate.AddMonths(r.Next(2, 48));
|
||||
var memo =
|
||||
r.Next(0, 3) > 0
|
||||
? colors.ElementAt(r.Next(0, colors.Count)) + $" {inventoryType.ContainerType}"
|
||||
? colors.ElementAt(r.Next(0, colors.Count)) + " box"
|
||||
: string.Empty;
|
||||
var quantity = r.Next(5, 112);
|
||||
var quantity = 1;
|
||||
var id = r.Next(10000000, 99999999).ToString();
|
||||
var program = programs.ElementAt(r.Next(0, programs.Count));
|
||||
|
||||
var addedTransaction = new Transaction
|
||||
{
|
||||
TransactionType = TransactionType.Added,
|
||||
AddedQuantity = quantity,
|
||||
Memo = "Arrival",
|
||||
Memo = "Added",
|
||||
CurrentQuantity = quantity,
|
||||
TransactionDate = addedDate,
|
||||
Timestamp = addedDate
|
||||
};
|
||||
var inventory = new Inventory
|
||||
{
|
||||
InventoryType = inventoryType,
|
||||
ExpirationDate = expiration,
|
||||
ShredReadyDate = expiration,
|
||||
AddedDate = addedDate,
|
||||
Memo = memo,
|
||||
Quantity = quantity,
|
||||
ProgramName = program,
|
||||
Id = id,
|
||||
Transactions = new List<Transaction> {addedTransaction}
|
||||
};
|
||||
context.Inventories.Add(inventory);
|
||||
@@ -148,135 +130,8 @@ namespace InventoryTraker.Web.Migrations
|
||||
ExprireLossInventory(context, dd, r);
|
||||
|
||||
dd = dd.AddDays(14);
|
||||
// distribute some inventory
|
||||
foreach (var destination in counties)
|
||||
{
|
||||
var availableInventories =
|
||||
context.Inventories.Local.Where(i => i.Quantity > 0).ToList();
|
||||
|
||||
for (
|
||||
var i = r.Next(0, availableInventories.Count);
|
||||
i < availableInventories.Count;
|
||||
i += r.Next(1, availableInventories.Count / 2))
|
||||
{
|
||||
var inventory = availableInventories.ElementAt(i);
|
||||
if (inventory.ExpirationDate <= dd)
|
||||
continue;
|
||||
|
||||
var quantityRemoved = r.Next(1, inventory.Quantity + 1);
|
||||
|
||||
var transMemo = $"Distributed to {destination}";
|
||||
var transType = TransactionType.Distributed;
|
||||
|
||||
var distributeTransaction = new Transaction
|
||||
{
|
||||
TransactionType = transType,
|
||||
RemovedQuantity = quantityRemoved,
|
||||
CurrentQuantity = inventory.Quantity - quantityRemoved,
|
||||
Inventory = inventory,
|
||||
Memo = transMemo,
|
||||
TransactionDate = dd,
|
||||
Timestamp = dd,
|
||||
Destination = destination
|
||||
};
|
||||
inventory.Quantity = distributeTransaction.CurrentQuantity;
|
||||
|
||||
inventory.Transactions.Add(distributeTransaction);
|
||||
}
|
||||
}
|
||||
ExprireLossInventory(context, dd, r);
|
||||
}
|
||||
|
||||
//for (int i = 0; i < 200; i++)
|
||||
//{
|
||||
// var inventoryType = inventoryTypes.ElementAt(r.Next(0, context.InventoryTypes.Count()));
|
||||
// var addedDate = DateTime.Today.AddMonths(-r.Next(1, 24));
|
||||
// var expiration = addedDate.AddMonths(r.Next(2, 48));
|
||||
// var memo =
|
||||
// r.Next(0,3) > 0
|
||||
// ? colors.ElementAt(r.Next(0, colors.Count)) + $" {inventoryType.ContainerType}"
|
||||
// : string.Empty;
|
||||
// var quantity = r.Next(5, 112);
|
||||
|
||||
// var previousTransaction = new Transaction
|
||||
// {
|
||||
// TransactionType = TransactionType.Added,
|
||||
// AddedQuantity = quantity,
|
||||
// Memo = "Arrival",
|
||||
// CurrentQuantity = quantity,
|
||||
// TransactionDate = addedDate,
|
||||
// Timestamp = addedDate
|
||||
// };
|
||||
// var inventory = new Inventory
|
||||
// {
|
||||
// InventoryType = inventoryType,
|
||||
// ExpirationDate = expiration,
|
||||
// AddedDate = addedDate,
|
||||
// Memo = memo,
|
||||
// Quantity = quantity,
|
||||
// Transactions = new List<Transaction> { previousTransaction}
|
||||
// };
|
||||
// context.Inventories.Add(inventory);
|
||||
|
||||
// for (int j = 0; j < 5 && previousTransaction.CurrentQuantity > 0; j++)
|
||||
// {
|
||||
// var transactionDate = previousTransaction.TransactionDate.AddDays(r.Next(1, 100));
|
||||
// if (transactionDate >= DateTime.Today)
|
||||
// break;
|
||||
|
||||
// Transaction transaction;
|
||||
// if (transactionDate >= expiration)
|
||||
// {
|
||||
// if (r.Next(1, 3) == 1)
|
||||
// break;
|
||||
|
||||
//transaction = new Transaction
|
||||
//{
|
||||
// TransactionType = TransactionType.Expired,
|
||||
// RemovedQuantity = previousTransaction.CurrentQuantity,
|
||||
// CurrentQuantity = 0,
|
||||
// Inventory = inventory,
|
||||
// Memo = $"Expired on {expiration.ToShortDateString()}",
|
||||
// TransactionDate = transactionDate,
|
||||
// Timestamp = transactionDate
|
||||
//};
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// var quantityRemoved = r.Next(1, 100);
|
||||
// if (quantityRemoved > previousTransaction.CurrentQuantity)
|
||||
// quantityRemoved = previousTransaction.CurrentQuantity;
|
||||
|
||||
// var destination = counties.ElementAt(r.Next(0, counties.Count));
|
||||
// var transMemo = $"Distributed to {destination}";
|
||||
// var transType = TransactionType.Distributed;
|
||||
|
||||
// if (r.Next(1, 15) == 1)
|
||||
// {
|
||||
// transMemo = "Loss";
|
||||
// transType = TransactionType.Loss;
|
||||
// }
|
||||
|
||||
// transaction = new Transaction
|
||||
// {
|
||||
// TransactionType = transType,
|
||||
// RemovedQuantity = quantityRemoved,
|
||||
// CurrentQuantity = previousTransaction.CurrentQuantity - quantityRemoved,
|
||||
// Inventory = inventory,
|
||||
// Memo = transMemo,
|
||||
// TransactionDate = transactionDate,
|
||||
// Timestamp = transactionDate,
|
||||
// Destination = destination
|
||||
// };
|
||||
// }
|
||||
|
||||
// inventory.Quantity = transaction.CurrentQuantity;
|
||||
|
||||
// inventory.Transactions.Add(transaction);
|
||||
|
||||
// previousTransaction = transaction;
|
||||
// }
|
||||
//}
|
||||
}
|
||||
|
||||
private static void ExprireLossInventory(AppDbContext context, DateTime dd, Random r)
|
||||
@@ -286,15 +141,15 @@ namespace InventoryTraker.Web.Migrations
|
||||
|
||||
foreach (var inventory in availableInventories)
|
||||
{
|
||||
if (inventory.ExpirationDate <= dd && r.Next(0, 4) > 0)
|
||||
if (inventory.ShredReadyDate <= dd && r.Next(0, 4) > 0)
|
||||
{
|
||||
var expiredTransaction = new Transaction
|
||||
{
|
||||
TransactionType = TransactionType.Expired,
|
||||
TransactionType = TransactionType.Shreded,
|
||||
RemovedQuantity = inventory.Quantity,
|
||||
CurrentQuantity = 0,
|
||||
Inventory = inventory,
|
||||
Memo = $"Expired on {inventory.ExpirationDate.ToShortDateString()}",
|
||||
Memo = $"Expired on {inventory.ShredReadyDate.ToShortDateString()}",
|
||||
TransactionDate = dd,
|
||||
Timestamp = dd
|
||||
};
|
||||
@@ -303,7 +158,7 @@ namespace InventoryTraker.Web.Migrations
|
||||
}
|
||||
else if (r.Next(0, 40) == 0)
|
||||
{
|
||||
var lossQty = r.Next(1, inventory.Quantity + 1);
|
||||
var lossQty = 1;
|
||||
var lossTransaction = new Transaction
|
||||
{
|
||||
TransactionType = TransactionType.Loss,
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace InventoryTraker.Web.Models
|
||||
{
|
||||
public class DistributionReport
|
||||
{
|
||||
public TransactionViewModel[] Transactions;
|
||||
|
||||
public string Destination { get; set; }
|
||||
|
||||
public DateTime Date { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
using System;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Web.Mvc;
|
||||
using AutoMapper;
|
||||
using InventoryTraker.Web.Core;
|
||||
|
||||
@@ -8,17 +7,20 @@ namespace InventoryTraker.Web.Models
|
||||
{
|
||||
public class InventoryAddForm
|
||||
{
|
||||
[HiddenInput(DisplayValue = false)]
|
||||
[Required]
|
||||
public int InventoryTypeId { get; set; }
|
||||
public string Id { get; set; }
|
||||
|
||||
[Required]
|
||||
public DateTime ExpirationDate { get; set; }
|
||||
public string ProgramName { get; set; }
|
||||
|
||||
[Required, Range(1, int.MaxValue, ErrorMessage = "Quantity must be greater than 0")]
|
||||
public int Quantity { get; set; }
|
||||
public string ProgramSubtype { get; set; }
|
||||
|
||||
[Required, Display(Name = "Arrival Date")]
|
||||
public string Description { get; set; }
|
||||
|
||||
[Required]
|
||||
public DateTime ShredReadyDate { get; set; }
|
||||
|
||||
[Required]
|
||||
public DateTime AddedDate { get; set; }
|
||||
|
||||
public string Memo { get; set; }
|
||||
@@ -27,7 +29,8 @@ namespace InventoryTraker.Web.Models
|
||||
{
|
||||
public AutoMapperProfile()
|
||||
{
|
||||
CreateMap<InventoryAddForm, Inventory>();
|
||||
CreateMap<InventoryAddForm, Inventory>()
|
||||
.AfterMap((form, inventory) => { inventory.Quantity = 1; });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace InventoryTraker.Web.Models
|
||||
{
|
||||
public class InventoryDistributeForm
|
||||
{
|
||||
public IList<InventoryQuantityForm> InventoryQuantities { get; set; }
|
||||
|
||||
[Required]
|
||||
public string Destination { get; set; }
|
||||
|
||||
[Required, Display(Name = "Distributed Date")]
|
||||
public DateTime DistributedDate { get; set; }
|
||||
|
||||
public string Memo { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,7 @@ namespace InventoryTraker.Web.Models
|
||||
public class InventoryQuantityForm
|
||||
{
|
||||
[Required]
|
||||
public int InventoryId { get; set; }
|
||||
public string InventoryId { get; set; }
|
||||
|
||||
[Required, Range(1, int.MaxValue, ErrorMessage = "Quantity must be greater than 0")]
|
||||
public int Quantity { get; set; }
|
||||
|
||||
@@ -7,7 +7,7 @@ namespace InventoryTraker.Web.Models
|
||||
public class InventoryRemoveForm
|
||||
{
|
||||
[Required]
|
||||
public int InventoryId { get; set; }
|
||||
public string InventoryId { get; set; }
|
||||
|
||||
[Required, Range(1, int.MaxValue, ErrorMessage = "Quantity must be greater than 0")]
|
||||
public int Quantity { get; set; }
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Web.Mvc;
|
||||
using AutoMapper;
|
||||
using InventoryTraker.Web.Core;
|
||||
|
||||
namespace InventoryTraker.Web.Models
|
||||
{
|
||||
public class InventoryTypeViewModel
|
||||
{
|
||||
[HiddenInput]
|
||||
public int Id { get; set; }
|
||||
|
||||
[Required]
|
||||
public string Identifier { get; set; }
|
||||
|
||||
[Required]
|
||||
public string Name { get; set; }
|
||||
|
||||
[Required]
|
||||
public int UnitsPerCase { get; set; }
|
||||
|
||||
[Required]
|
||||
public string ContainerType { get; set; }
|
||||
|
||||
[HiddenInput]
|
||||
public string UnitsPerCaseContainerType
|
||||
{
|
||||
get { return $"{UnitsPerCase} / {ContainerType}"; }
|
||||
}
|
||||
|
||||
[Required]
|
||||
public double WeightPerCase { get; set; }
|
||||
|
||||
[Required]
|
||||
public decimal PricePerCase { get; set; }
|
||||
|
||||
public class AutoMapperProfile : Profile
|
||||
{
|
||||
public AutoMapperProfile()
|
||||
{
|
||||
CreateMap<InventoryType, InventoryTypeViewModel>();
|
||||
CreateMap<InventoryTypeViewModel, InventoryType>();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,42 +6,27 @@ namespace InventoryTraker.Web.Models
|
||||
{
|
||||
public class InventoryViewModel
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string Id { get; set; }
|
||||
|
||||
public int InventoryTypeId { get; set; }
|
||||
|
||||
public string Name { get; set; }
|
||||
|
||||
public int UnitsPerCase { get; set; }
|
||||
|
||||
public string ContainerType { get; set; }
|
||||
|
||||
public double WeightPerCase { get; set; }
|
||||
|
||||
public decimal PricePerCase { get; set; }
|
||||
|
||||
public int Quantity { get; set; }
|
||||
|
||||
public DateTime ExpirationDate { get; set; }
|
||||
public DateTime ShredReadyDate { get; set; }
|
||||
|
||||
public DateTime AddedDate { get; set; }
|
||||
|
||||
public int Quantity { get; set; }
|
||||
|
||||
public string Memo { get; set; }
|
||||
|
||||
public bool IsExpired => ExpirationDate < DateTime.Today;
|
||||
public string ProgramName { get; set; }
|
||||
|
||||
public string ProgramSubtype { get; set; }
|
||||
|
||||
public string Description { get; set; }
|
||||
|
||||
public class AutoMapperProfile : Profile
|
||||
{
|
||||
public AutoMapperProfile()
|
||||
{
|
||||
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.UnitsPerCase, opt => opt.MapFrom(s => s.InventoryType.UnitsPerCase))
|
||||
.ForMember(d => d.ContainerType, opt => opt.MapFrom(s => s.InventoryType.ContainerType))
|
||||
.ForMember(d => d.WeightPerCase, opt => opt.MapFrom(s => s.InventoryType.WeightPerCase))
|
||||
.ForMember(d => d.PricePerCase, opt => opt.MapFrom(s => s.InventoryType.PricePerCase))
|
||||
.ForMember(d => d.AddedDate, opt => opt.MapFrom(s => s.AddedDate));
|
||||
CreateMap<Inventory, InventoryViewModel>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace InventoryTraker.Web.Models
|
||||
{
|
||||
public class MovementReport
|
||||
{
|
||||
public DateTime Month { get; set; }
|
||||
public IEnumerable<MovementReportItem> Items { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
namespace InventoryTraker.Web.Models
|
||||
{
|
||||
public class MovementReportItem
|
||||
{
|
||||
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; }
|
||||
}
|
||||
}
|
||||
@@ -7,16 +7,19 @@ namespace InventoryTraker.Web.Models
|
||||
{
|
||||
public class TransactionViewModel
|
||||
{
|
||||
[Required]
|
||||
public int Id { get; set; }
|
||||
public int InventoryId { get; set; }
|
||||
|
||||
public string Name { get; set; }
|
||||
public int UnitsPerCase { get; set; }
|
||||
public string ContainerType { get; set; }
|
||||
public DateTime ExpirationDate { get; set; }
|
||||
public string InventoryId { get; set; }
|
||||
|
||||
public string ProgramName { get; set; }
|
||||
|
||||
public string ProgramSubtype { get; set; }
|
||||
|
||||
public string Description { get; set; }
|
||||
|
||||
public DateTime ShredReadyDate { get; set; }
|
||||
|
||||
public DateTime AddedDate { get; set; }
|
||||
public double WeightPerCase { get; set; }
|
||||
|
||||
public string TransactionType { get; set; }
|
||||
|
||||
@@ -32,8 +35,6 @@ namespace InventoryTraker.Web.Models
|
||||
|
||||
public string Memo { get; set; }
|
||||
|
||||
public string Destination { get; set; }
|
||||
|
||||
public DateTime Timestamp { get; set; }
|
||||
|
||||
public class AutoMapperProfile : Profile
|
||||
@@ -43,18 +44,16 @@ namespace InventoryTraker.Web.Models
|
||||
CreateMap<Transaction, TransactionViewModel>()
|
||||
.ForMember(d => d.InventoryId,
|
||||
opt => opt.MapFrom(s => s.Inventory.Id))
|
||||
.ForMember(d => d.Name,
|
||||
opt => opt.MapFrom(s => s.Inventory.InventoryType.Name))
|
||||
.ForMember(d => d.ExpirationDate,
|
||||
opt => opt.MapFrom(s => s.Inventory.ExpirationDate))
|
||||
.ForMember(d => d.ProgramName,
|
||||
opt => opt.MapFrom(s => s.Inventory.ProgramName))
|
||||
.ForMember(d => d.ProgramSubtype,
|
||||
opt => opt.MapFrom(s => s.Inventory.ProgramSubtype))
|
||||
.ForMember(d => d.Description,
|
||||
opt => opt.MapFrom(s => s.Inventory.Description))
|
||||
.ForMember(d => d.ShredReadyDate,
|
||||
opt => opt.MapFrom(s => s.Inventory.ShredReadyDate))
|
||||
.ForMember(d => d.AddedDate,
|
||||
opt => opt.MapFrom(s => s.Inventory.AddedDate))
|
||||
.ForMember(d => d.UnitsPerCase,
|
||||
opt => opt.MapFrom(s => s.Inventory.InventoryType.UnitsPerCase))
|
||||
.ForMember(d => d.ContainerType,
|
||||
opt => opt.MapFrom(s => s.Inventory.InventoryType.ContainerType))
|
||||
.ForMember(d => d.WeightPerCase,
|
||||
opt => opt.MapFrom(s => s.Inventory.InventoryType.WeightPerCase))
|
||||
.ForMember(d => d.TransactionType,
|
||||
opt => opt.MapFrom(s => s.TransactionType.ToString()))
|
||||
.ForMember(d => d.PreviousQuantity,
|
||||
|
||||
@@ -11,13 +11,13 @@ by editing this MSBuild file. In order to learn more about this please visit htt
|
||||
<SiteUrlToLaunchAfterPublish />
|
||||
<LaunchSiteAfterPublish>True</LaunchSiteAfterPublish>
|
||||
<ExcludeApp_Data>False</ExcludeApp_Data>
|
||||
<DesktopBuildPackageLocation>C:\Users\poprhythm\Documents\code\PublishPackages\InventoryTraker.Web.zip</DesktopBuildPackageLocation>
|
||||
<DesktopBuildPackageLocation>C:\Users\poprhythm\Documents\code\PublishPackages\InventoryTraker-Box.Web.zip</DesktopBuildPackageLocation>
|
||||
<PackageAsSingleFile>true</PackageAsSingleFile>
|
||||
<DeployIisAppPath>Default Web Site</DeployIisAppPath>
|
||||
<DeployIisAppPath>InventoryTraker-Box</DeployIisAppPath>
|
||||
<PublishDatabaseSettings>
|
||||
<Objects xmlns="">
|
||||
<ObjectGroup Name="DefaultConnection" Order="1" Enabled="True">
|
||||
<Destination Path="Data Source=localhost;Initial Catalog=InventoryTraker;User ID=InventoryTrakerUser;Password=QcXxvpztGp1;Connect Timeout=60" Name="Data Source=localhost;Initial Catalog=InventoryTraker;User Id=InventoryTrakerUser;Password=QcXxvpztGp1;Connect Timeout=60" />
|
||||
<Destination Path="Data Source=localhost;Initial Catalog=InventoryTraker-Box;User ID=InventoryTraker-BoxUser;Password=QcXxvpztGp3;Connect Timeout=60" Name="Data Source=localhost;Initial Catalog=InventoryTraker-Box;User Id=InventoryTraker-BoxUser;Password=QcXxvpztGp3;Connect Timeout=60" />
|
||||
<Object Type="DbCodeFirst">
|
||||
<Source Path="DBMigration" DbContext="InventoryTraker.Web.Data.AppDbContext, InventoryTraker.Web" MigrationConfiguration="InventoryTraker.Web.Migrations.Configuration, InventoryTraker.Web" Origin="Convention" />
|
||||
</Object>
|
||||
@@ -27,7 +27,7 @@ by editing this MSBuild file. In order to learn more about this please visit htt
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<MSDeployParameterValue Include="$(DeployParameterPrefix)DefaultConnection-Web.config Connection String">
|
||||
<ParameterValue>Data Source=localhost;Initial Catalog=InventoryTraker;User Id=InventoryTrakerUser;Password=QcXxvpztGp1;Connect Timeout=60</ParameterValue>
|
||||
<ParameterValue>Data Source=localhost;Initial Catalog=InventoryTraker-Box;User Id=InventoryTraker-BoxUser;Password=QcXxvpztGp3;Connect Timeout=60</ParameterValue>
|
||||
</MSDeployParameterValue>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
Binary file not shown.
File diff suppressed because it is too large
Load Diff
+6
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
@@ -0,0 +1,421 @@
|
||||
/**!
|
||||
* AngularJS file upload directives and services. Supports: file upload/drop/paste, resume, cancel/abort,
|
||||
* progress, resize, thumbnail, preview, validation and CORS
|
||||
* FileAPI Flash shim for old browsers not supporting FormData
|
||||
* @author Danial <danial.farid@gmail.com>
|
||||
* @version 12.2.12
|
||||
*/
|
||||
|
||||
(function () {
|
||||
/** @namespace FileAPI.noContentTimeout */
|
||||
|
||||
function patchXHR(fnName, newFn) {
|
||||
window.XMLHttpRequest.prototype[fnName] = newFn(window.XMLHttpRequest.prototype[fnName]);
|
||||
}
|
||||
|
||||
function redefineProp(xhr, prop, fn) {
|
||||
try {
|
||||
Object.defineProperty(xhr, prop, {get: fn});
|
||||
} catch (e) {/*ignore*/
|
||||
}
|
||||
}
|
||||
|
||||
if (!window.FileAPI) {
|
||||
window.FileAPI = {};
|
||||
}
|
||||
|
||||
if (!window.XMLHttpRequest) {
|
||||
throw 'AJAX is not supported. XMLHttpRequest is not defined.';
|
||||
}
|
||||
|
||||
FileAPI.shouldLoad = !window.FormData || FileAPI.forceLoad;
|
||||
if (FileAPI.shouldLoad) {
|
||||
var initializeUploadListener = function (xhr) {
|
||||
if (!xhr.__listeners) {
|
||||
if (!xhr.upload) xhr.upload = {};
|
||||
xhr.__listeners = [];
|
||||
var origAddEventListener = xhr.upload.addEventListener;
|
||||
xhr.upload.addEventListener = function (t, fn) {
|
||||
xhr.__listeners[t] = fn;
|
||||
if (origAddEventListener) origAddEventListener.apply(this, arguments);
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
patchXHR('open', function (orig) {
|
||||
return function (m, url, b) {
|
||||
initializeUploadListener(this);
|
||||
this.__url = url;
|
||||
try {
|
||||
orig.apply(this, [m, url, b]);
|
||||
} catch (e) {
|
||||
if (e.message.indexOf('Access is denied') > -1) {
|
||||
this.__origError = e;
|
||||
orig.apply(this, [m, '_fix_for_ie_crossdomain__', b]);
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
patchXHR('getResponseHeader', function (orig) {
|
||||
return function (h) {
|
||||
return this.__fileApiXHR && this.__fileApiXHR.getResponseHeader ? this.__fileApiXHR.getResponseHeader(h) : (orig == null ? null : orig.apply(this, [h]));
|
||||
};
|
||||
});
|
||||
|
||||
patchXHR('getAllResponseHeaders', function (orig) {
|
||||
return function () {
|
||||
return this.__fileApiXHR && this.__fileApiXHR.getAllResponseHeaders ? this.__fileApiXHR.getAllResponseHeaders() : (orig == null ? null : orig.apply(this));
|
||||
};
|
||||
});
|
||||
|
||||
patchXHR('abort', function (orig) {
|
||||
return function () {
|
||||
return this.__fileApiXHR && this.__fileApiXHR.abort ? this.__fileApiXHR.abort() : (orig == null ? null : orig.apply(this));
|
||||
};
|
||||
});
|
||||
|
||||
patchXHR('setRequestHeader', function (orig) {
|
||||
return function (header, value) {
|
||||
if (header === '__setXHR_') {
|
||||
initializeUploadListener(this);
|
||||
var val = value(this);
|
||||
// fix for angular < 1.2.0
|
||||
if (val instanceof Function) {
|
||||
val(this);
|
||||
}
|
||||
} else {
|
||||
this.__requestHeaders = this.__requestHeaders || {};
|
||||
this.__requestHeaders[header] = value;
|
||||
orig.apply(this, arguments);
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
patchXHR('send', function (orig) {
|
||||
return function () {
|
||||
var xhr = this;
|
||||
if (arguments[0] && arguments[0].__isFileAPIShim) {
|
||||
var formData = arguments[0];
|
||||
var config = {
|
||||
url: xhr.__url,
|
||||
jsonp: false, //removes the callback form param
|
||||
cache: true, //removes the ?fileapiXXX in the url
|
||||
complete: function (err, fileApiXHR) {
|
||||
if (err && angular.isString(err) && err.indexOf('#2174') !== -1) {
|
||||
// this error seems to be fine the file is being uploaded properly.
|
||||
err = null;
|
||||
}
|
||||
xhr.__completed = true;
|
||||
if (!err && xhr.__listeners.load)
|
||||
xhr.__listeners.load({
|
||||
type: 'load',
|
||||
loaded: xhr.__loaded,
|
||||
total: xhr.__total,
|
||||
target: xhr,
|
||||
lengthComputable: true
|
||||
});
|
||||
if (!err && xhr.__listeners.loadend)
|
||||
xhr.__listeners.loadend({
|
||||
type: 'loadend',
|
||||
loaded: xhr.__loaded,
|
||||
total: xhr.__total,
|
||||
target: xhr,
|
||||
lengthComputable: true
|
||||
});
|
||||
if (err === 'abort' && xhr.__listeners.abort)
|
||||
xhr.__listeners.abort({
|
||||
type: 'abort',
|
||||
loaded: xhr.__loaded,
|
||||
total: xhr.__total,
|
||||
target: xhr,
|
||||
lengthComputable: true
|
||||
});
|
||||
if (fileApiXHR.status !== undefined) redefineProp(xhr, 'status', function () {
|
||||
return (fileApiXHR.status === 0 && err && err !== 'abort') ? 500 : fileApiXHR.status;
|
||||
});
|
||||
if (fileApiXHR.statusText !== undefined) redefineProp(xhr, 'statusText', function () {
|
||||
return fileApiXHR.statusText;
|
||||
});
|
||||
redefineProp(xhr, 'readyState', function () {
|
||||
return 4;
|
||||
});
|
||||
if (fileApiXHR.response !== undefined) redefineProp(xhr, 'response', function () {
|
||||
return fileApiXHR.response;
|
||||
});
|
||||
var resp = fileApiXHR.responseText || (err && fileApiXHR.status === 0 && err !== 'abort' ? err : undefined);
|
||||
redefineProp(xhr, 'responseText', function () {
|
||||
return resp;
|
||||
});
|
||||
redefineProp(xhr, 'response', function () {
|
||||
return resp;
|
||||
});
|
||||
if (err) redefineProp(xhr, 'err', function () {
|
||||
return err;
|
||||
});
|
||||
xhr.__fileApiXHR = fileApiXHR;
|
||||
if (xhr.onreadystatechange) xhr.onreadystatechange();
|
||||
if (xhr.onload) xhr.onload();
|
||||
},
|
||||
progress: function (e) {
|
||||
e.target = xhr;
|
||||
if (xhr.__listeners.progress) xhr.__listeners.progress(e);
|
||||
xhr.__total = e.total;
|
||||
xhr.__loaded = e.loaded;
|
||||
if (e.total === e.loaded) {
|
||||
// fix flash issue that doesn't call complete if there is no response text from the server
|
||||
var _this = this;
|
||||
setTimeout(function () {
|
||||
if (!xhr.__completed) {
|
||||
xhr.getAllResponseHeaders = function () {
|
||||
};
|
||||
_this.complete(null, {status: 204, statusText: 'No Content'});
|
||||
}
|
||||
}, FileAPI.noContentTimeout || 10000);
|
||||
}
|
||||
},
|
||||
headers: xhr.__requestHeaders
|
||||
};
|
||||
config.data = {};
|
||||
config.files = {};
|
||||
for (var i = 0; i < formData.data.length; i++) {
|
||||
var item = formData.data[i];
|
||||
if (item.val != null && item.val.name != null && item.val.size != null && item.val.type != null) {
|
||||
config.files[item.key] = item.val;
|
||||
} else {
|
||||
config.data[item.key] = item.val;
|
||||
}
|
||||
}
|
||||
|
||||
setTimeout(function () {
|
||||
if (!FileAPI.hasFlash) {
|
||||
throw 'Adode Flash Player need to be installed. To check ahead use "FileAPI.hasFlash"';
|
||||
}
|
||||
xhr.__fileApiXHR = FileAPI.upload(config);
|
||||
}, 1);
|
||||
} else {
|
||||
if (this.__origError) {
|
||||
throw this.__origError;
|
||||
}
|
||||
orig.apply(xhr, arguments);
|
||||
}
|
||||
};
|
||||
});
|
||||
window.XMLHttpRequest.__isFileAPIShim = true;
|
||||
window.FormData = FormData = function () {
|
||||
return {
|
||||
append: function (key, val, name) {
|
||||
if (val.__isFileAPIBlobShim) {
|
||||
val = val.data[0];
|
||||
}
|
||||
this.data.push({
|
||||
key: key,
|
||||
val: val,
|
||||
name: name
|
||||
});
|
||||
},
|
||||
data: [],
|
||||
__isFileAPIShim: true
|
||||
};
|
||||
};
|
||||
|
||||
window.Blob = Blob = function (b) {
|
||||
return {
|
||||
data: b,
|
||||
__isFileAPIBlobShim: true
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
})();
|
||||
|
||||
(function () {
|
||||
/** @namespace FileAPI.forceLoad */
|
||||
/** @namespace window.FileAPI.jsUrl */
|
||||
/** @namespace window.FileAPI.jsPath */
|
||||
|
||||
function isInputTypeFile(elem) {
|
||||
return elem[0].tagName.toLowerCase() === 'input' && elem.attr('type') && elem.attr('type').toLowerCase() === 'file';
|
||||
}
|
||||
|
||||
function hasFlash() {
|
||||
try {
|
||||
var fo = new ActiveXObject('ShockwaveFlash.ShockwaveFlash');
|
||||
if (fo) return true;
|
||||
} catch (e) {
|
||||
if (navigator.mimeTypes['application/x-shockwave-flash'] !== undefined) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function getOffset(obj) {
|
||||
var left = 0, top = 0;
|
||||
|
||||
if (window.jQuery) {
|
||||
return jQuery(obj).offset();
|
||||
}
|
||||
|
||||
if (obj.offsetParent) {
|
||||
do {
|
||||
left += (obj.offsetLeft - obj.scrollLeft);
|
||||
top += (obj.offsetTop - obj.scrollTop);
|
||||
obj = obj.offsetParent;
|
||||
} while (obj);
|
||||
}
|
||||
return {
|
||||
left: left,
|
||||
top: top
|
||||
};
|
||||
}
|
||||
|
||||
if (FileAPI.shouldLoad) {
|
||||
FileAPI.hasFlash = hasFlash();
|
||||
|
||||
//load FileAPI
|
||||
if (FileAPI.forceLoad) {
|
||||
FileAPI.html5 = false;
|
||||
}
|
||||
|
||||
if (!FileAPI.upload) {
|
||||
var jsUrl, basePath, script = document.createElement('script'), allScripts = document.getElementsByTagName('script'), i, index, src;
|
||||
if (window.FileAPI.jsUrl) {
|
||||
jsUrl = window.FileAPI.jsUrl;
|
||||
} else if (window.FileAPI.jsPath) {
|
||||
basePath = window.FileAPI.jsPath;
|
||||
} else {
|
||||
for (i = 0; i < allScripts.length; i++) {
|
||||
src = allScripts[i].src;
|
||||
index = src.search(/\/ng\-file\-upload[\-a-zA-z0-9\.]*\.js/);
|
||||
if (index > -1) {
|
||||
basePath = src.substring(0, index + 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (FileAPI.staticPath == null) FileAPI.staticPath = basePath;
|
||||
script.setAttribute('src', jsUrl || basePath + 'FileAPI.min.js');
|
||||
document.getElementsByTagName('head')[0].appendChild(script);
|
||||
}
|
||||
|
||||
FileAPI.ngfFixIE = function (elem, fileElem, changeFn) {
|
||||
if (!hasFlash()) {
|
||||
throw 'Adode Flash Player need to be installed. To check ahead use "FileAPI.hasFlash"';
|
||||
}
|
||||
var fixInputStyle = function () {
|
||||
var label = fileElem.parent();
|
||||
if (elem.attr('disabled')) {
|
||||
if (label) label.removeClass('js-fileapi-wrapper');
|
||||
} else {
|
||||
if (!fileElem.attr('__ngf_flash_')) {
|
||||
fileElem.unbind('change');
|
||||
fileElem.unbind('click');
|
||||
fileElem.bind('change', function (evt) {
|
||||
fileApiChangeFn.apply(this, [evt]);
|
||||
changeFn.apply(this, [evt]);
|
||||
});
|
||||
fileElem.attr('__ngf_flash_', 'true');
|
||||
}
|
||||
label.addClass('js-fileapi-wrapper');
|
||||
if (!isInputTypeFile(elem)) {
|
||||
label.css('position', 'absolute')
|
||||
.css('top', getOffset(elem[0]).top + 'px').css('left', getOffset(elem[0]).left + 'px')
|
||||
.css('width', elem[0].offsetWidth + 'px').css('height', elem[0].offsetHeight + 'px')
|
||||
.css('filter', 'alpha(opacity=0)').css('display', elem.css('display'))
|
||||
.css('overflow', 'hidden').css('z-index', '900000')
|
||||
.css('visibility', 'visible');
|
||||
fileElem.css('width', elem[0].offsetWidth + 'px').css('height', elem[0].offsetHeight + 'px')
|
||||
.css('position', 'absolute').css('top', '0px').css('left', '0px');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
elem.bind('mouseenter', fixInputStyle);
|
||||
|
||||
var fileApiChangeFn = function (evt) {
|
||||
var files = FileAPI.getFiles(evt);
|
||||
//just a double check for #233
|
||||
for (var i = 0; i < files.length; i++) {
|
||||
if (files[i].size === undefined) files[i].size = 0;
|
||||
if (files[i].name === undefined) files[i].name = 'file';
|
||||
if (files[i].type === undefined) files[i].type = 'undefined';
|
||||
}
|
||||
if (!evt.target) {
|
||||
evt.target = {};
|
||||
}
|
||||
evt.target.files = files;
|
||||
// if evt.target.files is not writable use helper field
|
||||
if (evt.target.files !== files) {
|
||||
evt.__files_ = files;
|
||||
}
|
||||
(evt.__files_ || evt.target.files).item = function (i) {
|
||||
return (evt.__files_ || evt.target.files)[i] || null;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
FileAPI.disableFileInput = function (elem, disable) {
|
||||
if (disable) {
|
||||
elem.removeClass('js-fileapi-wrapper');
|
||||
} else {
|
||||
elem.addClass('js-fileapi-wrapper');
|
||||
}
|
||||
};
|
||||
}
|
||||
})();
|
||||
|
||||
if (!window.FileReader) {
|
||||
window.FileReader = function () {
|
||||
var _this = this, loadStarted = false;
|
||||
this.listeners = {};
|
||||
this.addEventListener = function (type, fn) {
|
||||
_this.listeners[type] = _this.listeners[type] || [];
|
||||
_this.listeners[type].push(fn);
|
||||
};
|
||||
this.removeEventListener = function (type, fn) {
|
||||
if (_this.listeners[type]) _this.listeners[type].splice(_this.listeners[type].indexOf(fn), 1);
|
||||
};
|
||||
this.dispatchEvent = function (evt) {
|
||||
var list = _this.listeners[evt.type];
|
||||
if (list) {
|
||||
for (var i = 0; i < list.length; i++) {
|
||||
list[i].call(_this, evt);
|
||||
}
|
||||
}
|
||||
};
|
||||
this.onabort = this.onerror = this.onload = this.onloadstart = this.onloadend = this.onprogress = null;
|
||||
|
||||
var constructEvent = function (type, evt) {
|
||||
var e = {type: type, target: _this, loaded: evt.loaded, total: evt.total, error: evt.error};
|
||||
if (evt.result != null) e.target.result = evt.result;
|
||||
return e;
|
||||
};
|
||||
var listener = function (evt) {
|
||||
if (!loadStarted) {
|
||||
loadStarted = true;
|
||||
if (_this.onloadstart) _this.onloadstart(constructEvent('loadstart', evt));
|
||||
}
|
||||
var e;
|
||||
if (evt.type === 'load') {
|
||||
if (_this.onloadend) _this.onloadend(constructEvent('loadend', evt));
|
||||
e = constructEvent('load', evt);
|
||||
if (_this.onload) _this.onload(e);
|
||||
_this.dispatchEvent(e);
|
||||
} else if (evt.type === 'progress') {
|
||||
e = constructEvent('progress', evt);
|
||||
if (_this.onprogress) _this.onprogress(e);
|
||||
_this.dispatchEvent(e);
|
||||
} else {
|
||||
e = constructEvent('error', evt);
|
||||
if (_this.onerror) _this.onerror(e);
|
||||
_this.dispatchEvent(e);
|
||||
}
|
||||
};
|
||||
this.readAsDataURL = function (file) {
|
||||
FileAPI.readAsDataURL(file, listener);
|
||||
};
|
||||
this.readAsText = function (file) {
|
||||
FileAPI.readAsText(file, listener);
|
||||
};
|
||||
};
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
@@ -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; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Web.Mvc;
|
||||
using System.Web.Http.Filters;
|
||||
using System.Web.Mvc;
|
||||
|
||||
namespace InventoryTraker.Web.Utilities
|
||||
{
|
||||
@@ -10,5 +11,12 @@ namespace InventoryTraker.Web.Utilities
|
||||
var action = ctx.RouteData.Values["action"].ToString();
|
||||
return $"{controller}Controller.{action}";
|
||||
}
|
||||
|
||||
public static string GetLoggerName(this HttpActionExecutedContext ctx)
|
||||
{
|
||||
var controller = ctx.ActionContext.ControllerContext.ControllerDescriptor.ControllerName;
|
||||
var action = ctx.ActionContext.ActionDescriptor.ActionName;
|
||||
return $"{controller}Controller.{action}";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,97 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using AutoMapper;
|
||||
using ClosedXML.Excel;
|
||||
using CsvHelper;
|
||||
using CsvHelper.Configuration;
|
||||
using CsvHelper.Excel;
|
||||
using InventoryTraker.Web.Models;
|
||||
|
||||
namespace InventoryTraker.Web.Utilities
|
||||
{
|
||||
public class DistributionReportWriter
|
||||
{
|
||||
public class DistributionReportExportItem
|
||||
{
|
||||
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 class AutoMapperProfile : Profile
|
||||
{
|
||||
public AutoMapperProfile()
|
||||
{
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
||||
private readonly IMapper _mapper;
|
||||
|
||||
public DistributionReportWriter(IMapper mapper)
|
||||
{
|
||||
_mapper = mapper;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using CsvHelper.Configuration;
|
||||
using InventoryTraker.Web.Models;
|
||||
|
||||
namespace InventoryTraker.Web.Utilities
|
||||
{
|
||||
public class InventoryParser
|
||||
{
|
||||
private readonly FileSystemInfo _excelFile;
|
||||
|
||||
// ReSharper disable once ClassNeverInstantiated.Local
|
||||
private sealed class InventoryAddFormMap : CsvClassMap<InventoryAddForm>
|
||||
{
|
||||
public InventoryAddFormMap()
|
||||
{
|
||||
Map(m => m.Id).Name("Box ID");
|
||||
Map(m => m.ProgramName).Name("Program Name");
|
||||
Map(m => m.ProgramSubtype).Name("Program Subtype");
|
||||
Map(m => m.Description);
|
||||
Map(m => m.ShredReadyDate).Name("Shread Ready Date");
|
||||
Map(m => m.AddedDate).Name("Added Date");
|
||||
Map(m => m.Memo);
|
||||
}
|
||||
}
|
||||
|
||||
public InventoryParser(FileSystemInfo excelFile)
|
||||
{
|
||||
_excelFile = excelFile;
|
||||
}
|
||||
|
||||
public IList<InventoryAddForm> Parse()
|
||||
{
|
||||
var csvConfiguration =
|
||||
new CsvConfiguration { IsHeaderCaseSensitive = false, IgnoreReadingExceptions = false};
|
||||
csvConfiguration.RegisterClassMap<InventoryAddFormMap>();
|
||||
using (var reader = ExcelParserBase.OpenExcel(_excelFile, csvConfiguration))
|
||||
{
|
||||
return reader.GetRecords<InventoryAddForm>().ToList();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,15 +15,13 @@ namespace InventoryTraker.Web.Utilities
|
||||
{
|
||||
public InventoryViewModelMap()
|
||||
{
|
||||
Map(m => m.Name).Name("Name of Commodity");
|
||||
Map(m => m.UnitsPerCase).Name("Units per Case");
|
||||
Map(m => m.ContainerType).Name("Container Type");
|
||||
Map(m => m.Quantity).Name("Case Quantity");
|
||||
Map(m => m.ExpirationDate).Name("Expiration Date");
|
||||
Map(m => m.Id).Name("Box ID");
|
||||
Map(m => m.ProgramName).Name("Program Name");
|
||||
Map(m => m.ProgramSubtype).Name("Program Subtype");
|
||||
Map(m => m.Description).Name("Description");
|
||||
Map(m => m.ShredReadyDate).Name("Shread Ready Date");
|
||||
Map(m => m.AddedDate).Name("Added Date");
|
||||
Map(m => m.Memo).Name("Memo");
|
||||
Map(m => m.WeightPerCase).Name("Weight per Case");
|
||||
Map(m => m.PricePerCase).Name("Price per Case");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,7 +42,7 @@ namespace InventoryTraker.Web.Utilities
|
||||
using (var writer = new CsvWriter(new ExcelSerializer(worksheet)))
|
||||
{
|
||||
writer.Configuration.RegisterClassMap(new InventoryViewModelMap());
|
||||
writer.WriteRecords(items.OrderBy(i => i.Name));
|
||||
writer.WriteRecords(items.OrderBy(i => i.Id));
|
||||
workbook.SaveAs(stream);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using CsvHelper.Configuration;
|
||||
using InventoryTraker.Web.Core;
|
||||
|
||||
namespace InventoryTraker.Web.Utilities
|
||||
{
|
||||
public class InventoryTypeParser
|
||||
{
|
||||
private readonly FileSystemInfo _excelFile;
|
||||
|
||||
// ReSharper disable once ClassNeverInstantiated.Local
|
||||
private sealed class InventoryTypeMap : CsvClassMap<InventoryType>
|
||||
{
|
||||
public InventoryTypeMap()
|
||||
{
|
||||
Map(m => m.Identifier);
|
||||
Map(m => m.Name);
|
||||
Map(m => m.UnitsPerCase);
|
||||
Map(m => m.ContainerType);
|
||||
Map(m => m.WeightPerCase);
|
||||
Map(m => m.PricePerCase);
|
||||
}
|
||||
}
|
||||
|
||||
public InventoryTypeParser(FileSystemInfo excelFile)
|
||||
{
|
||||
_excelFile = excelFile;
|
||||
}
|
||||
|
||||
public IList<InventoryType> Parse()
|
||||
{
|
||||
var csvConfiguration =
|
||||
new CsvConfiguration { IsHeaderCaseSensitive = false, IgnoreReadingExceptions = true};
|
||||
csvConfiguration.RegisterClassMap<InventoryTypeMap>();
|
||||
using (var reader = ExcelParserBase.OpenExcel(_excelFile, csvConfiguration))
|
||||
{
|
||||
return reader.GetRecords<InventoryType>().ToList();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using ClosedXML.Excel;
|
||||
using CsvHelper;
|
||||
using CsvHelper.Configuration;
|
||||
using CsvHelper.Excel;
|
||||
using InventoryTraker.Web.Models;
|
||||
|
||||
namespace InventoryTraker.Web.Utilities
|
||||
{
|
||||
public class InventoryTypeReportWriter
|
||||
{
|
||||
private sealed class InventoryTypeViewModelMap : CsvClassMap<InventoryTypeViewModel>
|
||||
{
|
||||
public InventoryTypeViewModelMap()
|
||||
{
|
||||
Map(m => m.Identifier).Name("Identifier");
|
||||
Map(m => m.Name).Name("Name of Commodity");
|
||||
Map(m => m.UnitsPerCase).Name("Units per Case");
|
||||
Map(m => m.ContainerType).Name("Container Type");
|
||||
Map(m => m.WeightPerCase).Name("Weight per Case");
|
||||
Map(m => m.PricePerCase).Name("Price per Case");
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] Write(IEnumerable<InventoryTypeViewModel> items)
|
||||
{
|
||||
using (var stream = new MemoryStream())
|
||||
{
|
||||
WriteStream(items, stream);
|
||||
return stream.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
public void WriteStream(IEnumerable<InventoryTypeViewModel> items, Stream stream)
|
||||
{
|
||||
using (var workbook = new XLWorkbook(XLEventTracking.Disabled))
|
||||
{
|
||||
var worksheet = workbook.AddWorksheet("Commodity Types");
|
||||
using (var writer = new CsvWriter(new ExcelSerializer(worksheet)))
|
||||
{
|
||||
writer.Configuration.RegisterClassMap(new InventoryTypeViewModelMap());
|
||||
writer.WriteRecords(items.OrderBy(i => i.Name));
|
||||
workbook.SaveAs(stream);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.Entity.Infrastructure;
|
||||
using System.Data.SqlClient;
|
||||
using System.Text.RegularExpressions;
|
||||
using InventoryTraker.Web.Core;
|
||||
|
||||
namespace InventoryTraker.Web.Utilities
|
||||
{
|
||||
public static class ModelHelper
|
||||
{
|
||||
public static List<Transaction> GetAddedTransaction(DateTime addedDate)
|
||||
{
|
||||
return
|
||||
new List<Transaction>
|
||||
{
|
||||
new Transaction
|
||||
{
|
||||
TransactionType = TransactionType.Added,
|
||||
AddedQuantity = 1,
|
||||
CurrentQuantity = 1,
|
||||
Memo = "Added",
|
||||
Timestamp = DateTime.Now,
|
||||
TransactionDate = addedDate
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static string GetUpdateExceptionMessage(Exception e)
|
||||
{
|
||||
if (e.InnerException?.InnerException is SqlException)
|
||||
{
|
||||
var innerMessage = e.InnerException.InnerException.Message;
|
||||
if (innerMessage.StartsWith(@"Violation of PRIMARY KEY constraint 'PK_dbo.Inventories'."))
|
||||
{
|
||||
var id = Regex.Replace(innerMessage, @".*\((.*)\).*", "$1", RegexOptions.Singleline);
|
||||
return "Duplicate Inventory Id: " + id;
|
||||
}
|
||||
return innerMessage;
|
||||
}
|
||||
return e.InnerException?.Message ?? e.Message;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,125 +0,0 @@
|
||||
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 InventoryTraker.Web.Models;
|
||||
|
||||
namespace InventoryTraker.Web.Utilities
|
||||
{
|
||||
public class MovementReportWriter
|
||||
{
|
||||
public class MovementReportExportItem
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public string UnitsPerCaseContainerType { get; set; }
|
||||
public string BeginningQuantity { get; set; }
|
||||
public string AddedQuantity { get; set; }
|
||||
public string TotalAvailableQuantity { get; set; }
|
||||
public string DistributedQuantity { get; set; }
|
||||
public string AdjustmentQuantity { get; set; }
|
||||
public string EndingQuantity { get; set; }
|
||||
|
||||
public class AutoMapperProfile : Profile
|
||||
{
|
||||
public AutoMapperProfile()
|
||||
{
|
||||
Func<int, int, string> formatCases =
|
||||
(cases, unitsPerCase) => $"{cases * unitsPerCase} ({cases} cs)";
|
||||
|
||||
Func<int, int, string> hideEmptyCases =
|
||||
(cases, unitsPerCase) =>
|
||||
cases > 0
|
||||
? formatCases(cases, unitsPerCase)
|
||||
: "";
|
||||
|
||||
Func<int, int, string> negative =
|
||||
(cases, unitsPerCase) =>
|
||||
cases > 0
|
||||
? "- " + hideEmptyCases(cases, unitsPerCase)
|
||||
: "";
|
||||
|
||||
CreateMap<MovementReportItem, MovementReportExportItem>()
|
||||
.ForMember(d => d.Name, opt => opt.MapFrom(i => i.InventoryType.Name))
|
||||
.ForMember(d => d.UnitsPerCaseContainerType,
|
||||
opt => opt.MapFrom(i => i.InventoryType.UnitsPerCaseContainerType))
|
||||
.ForMember(d => d.BeginningQuantity,
|
||||
opt => opt.MapFrom(i =>
|
||||
formatCases(i.BeginningQuantity, i.InventoryType.UnitsPerCase)))
|
||||
.ForMember(d => d.AddedQuantity,
|
||||
opt => opt.MapFrom(i =>
|
||||
hideEmptyCases(i.AddedQuantity, i.InventoryType.UnitsPerCase)))
|
||||
.ForMember(d => d.TotalAvailableQuantity,
|
||||
opt => opt.MapFrom(i =>
|
||||
hideEmptyCases(i.TotalAvailableQuantity, i.InventoryType.UnitsPerCase)))
|
||||
.ForMember(d => d.AdjustmentQuantity,
|
||||
opt => opt.MapFrom(i =>
|
||||
negative(i.AdjustmentQuantity, i.InventoryType.UnitsPerCase)))
|
||||
.ForMember(d => d.DistributedQuantity,
|
||||
opt => opt.MapFrom(i =>
|
||||
hideEmptyCases(i.DistributedQuantity, i.InventoryType.UnitsPerCase)))
|
||||
.ForMember(d => d.EndingQuantity,
|
||||
opt => opt.MapFrom(i =>
|
||||
formatCases(i.EndingQuantity, i.InventoryType.UnitsPerCase)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private sealed class MovementReportMap : CsvClassMap<MovementReportExportItem>
|
||||
{
|
||||
public MovementReportMap()
|
||||
{
|
||||
Map(m => m.Name).Name("Name of Commodity");
|
||||
Map(m => m.UnitsPerCaseContainerType).Name("Pack Size / Units per Case");
|
||||
Map(m => m.BeginningQuantity).Name("Beginning Inventory");
|
||||
Map(m => m.AddedQuantity).Name("Units Rec'd");
|
||||
Map(m => m.TotalAvailableQuantity).Name("Total Units Available");
|
||||
Map(m => m.AdjustmentQuantity).Name("Adjustments (show + or -)");
|
||||
Map(m => m.DistributedQuantity).Name("Units Distributed");
|
||||
Map(m => m.EndingQuantity).Name("Ending Inventory");
|
||||
}
|
||||
}
|
||||
|
||||
private readonly IMapper _mapper;
|
||||
|
||||
public MovementReportWriter(IMapper mapper)
|
||||
{
|
||||
_mapper = mapper;
|
||||
}
|
||||
|
||||
public byte[] Write(MovementReport report)
|
||||
{
|
||||
using (var stream = new MemoryStream())
|
||||
{
|
||||
WriteStream(report, stream);
|
||||
return stream.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
public void WriteStream(MovementReport report, Stream stream)
|
||||
{
|
||||
using (var workbook = new XLWorkbook(XLEventTracking.Disabled))
|
||||
{
|
||||
var worksheet = workbook.AddWorksheet("Monthly Inventory Report");
|
||||
using (var writer = new CsvWriter(new ExcelSerializer(worksheet)))
|
||||
{
|
||||
writer.Configuration.RegisterClassMap(new MovementReportMap());
|
||||
writer.WriteField("Monthly Inventory Report");
|
||||
writer.NextRecord();
|
||||
writer.WriteField<string>($"Month: {report.Month:MMMM yyyy}");
|
||||
writer.NextRecord();
|
||||
var items =
|
||||
_mapper.Map<IEnumerable<MovementReportItem>, IEnumerable<MovementReportExportItem>>
|
||||
(report.Items)
|
||||
.OrderBy(i => i.Name);
|
||||
writer.WriteRecords(items);
|
||||
workbook.SaveAs(stream);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
@model dynamic
|
||||
|
||||
@{
|
||||
ViewBag.Title = "Dashboard";
|
||||
}
|
||||
|
||||
<h1 class="page-header">
|
||||
Dashboard
|
||||
</h1>
|
||||
|
||||
<div>
|
||||
Welcome to Heroic CRM! This is a simple app to demonstrate how .NET's type system
|
||||
can be used to generate client-side code in a strongly-typed way!
|
||||
</div>
|
||||
@@ -6,15 +6,18 @@
|
||||
<h1 class="page-header">
|
||||
<i class="fa fa-cubes"></i> @ViewBag.Title
|
||||
</h1>
|
||||
<div>
|
||||
<a class="btn btn-default" href="" ng-click="vm.add()">
|
||||
<i class="fa fa-plus-circle"></i> Add
|
||||
</a>
|
||||
<a class="btn btn-default" href="" ng-click="vm.import()">
|
||||
<i class="fa fa-file-excel-o"></i> Import
|
||||
</a>
|
||||
<a class="btn btn-default" href="" ng-click="vm.export()">
|
||||
<i class="fa fa-file-excel-o"></i> Export
|
||||
</a>
|
||||
</div>
|
||||
<h4>Current inventory</h4>
|
||||
<div class="pull-left">
|
||||
<a class="btn btn-default" href="" ng-click="vm.add()"><i class="fa fa-plus-circle"></i> Arrival</a>
|
||||
<a class="btn btn-default" href="" ng-click="vm.distribute()"><i class="fa fa-share-square"></i> Distribute</a>
|
||||
<a class="btn btn-default" href="" ng-click="vm.export()"><i class="fa fa-file-excel-o"></i> Export</a>
|
||||
</div>
|
||||
<div class="pull-right">
|
||||
<a class="btn btn-default" href="/InventoryType"><i class="fa fa-cube"></i> Commodity Types</a>
|
||||
</div>
|
||||
|
||||
<inventory-list inventories="vm.inventories"></inventory-list>
|
||||
</div>
|
||||
@@ -1,17 +0,0 @@
|
||||
@model dynamic
|
||||
|
||||
@{
|
||||
ViewBag.Title = "Commodity Types";
|
||||
}
|
||||
|
||||
<div ng-controller="InventoryTypeController as vm">
|
||||
<h1 class="page-header">
|
||||
<i class="fa fa-cube"></i> @ViewBag.Title
|
||||
</h1>
|
||||
<div class="pull-left">
|
||||
<a class="btn btn-default" href="" ng-click="vm.add()"><i class="fa fa-plus-circle"></i> Add</a>
|
||||
<a class="btn btn-default" href="" ng-click="vm.export()"><i class="fa fa-file-excel-o"></i> Export</a>
|
||||
</div>
|
||||
|
||||
<inventory-type-list inventory-types="vm.inventoryTypes"></inventory-type-list>
|
||||
</div>
|
||||
@@ -27,7 +27,7 @@
|
||||
{
|
||||
<footer class="footer hidden-print">
|
||||
<div class="container">
|
||||
<p>Inventory Traker © 2016 Kolpack Software Consulting LLC</p>
|
||||
<p>Inventory Traker © ETHRA, 2016 Kolpack Software Consulting LLC</p>
|
||||
</div>
|
||||
</footer>
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
</button>
|
||||
<a class="navbar-brand" href="~/"><i class="fa fa-fw fa-cubes"></i> Inventory Traker</a>
|
||||
<a class="navbar-brand" href="~/"><i class="fa fa-fw fa-cubes"></i> Inventory Traker (Box)</a>
|
||||
</div>
|
||||
<!-- Top Menu Items -->
|
||||
<ul class="nav navbar-right top-nav">
|
||||
@@ -39,17 +39,12 @@
|
||||
<li>
|
||||
<a href="@(Html.BuildUrlFromExpression<TransactionController>(c => c.Index()))"><i class="fa fa-fw fa-list"></i> Transaction History</a>
|
||||
</li>
|
||||
<li>
|
||||
@*<li>
|
||||
<a href="#"><i class="fa fa-fw fa-file-o"></i> Reports</a>
|
||||
<ul>
|
||||
<li>
|
||||
<a href="@(Html.BuildUrlFromExpression<ReportController>(c => c.Distribution()))"><i class="fa fa-fw fa-file-o"></i> Distribution</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="@(Html.BuildUrlFromExpression<ReportController>(c => c.Movement()))"><i class="fa fa-fw fa-file-o"></i> Monthly Inventory</a>
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
</li>
|
||||
</li>*@
|
||||
</ul>
|
||||
</div>
|
||||
<!-- /.navbar-collapse -->
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
@using InventoryTraker.Web.Helpers
|
||||
@using InventoryTraker.Web.Models
|
||||
@model dynamic
|
||||
@model dynamic
|
||||
|
||||
@{
|
||||
ViewBag.Title = "Inventory";
|
||||
@@ -8,7 +6,7 @@
|
||||
|
||||
<div ng-controller="TransactionController as vm">
|
||||
<h1 class="page-header">
|
||||
Transaction History
|
||||
<i class="fa fa-fw fa-list"></i> Transaction History
|
||||
</h1>
|
||||
<div class="pull-right">
|
||||
</div>
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
</appSettings>
|
||||
|
||||
<connectionStrings>
|
||||
<add name="DefaultConnection" connectionString="Data Source=(LocalDb)\MSSQLLocalDB;AttachDbFilename=|DataDirectory|\InventoryTraker.mdf;Initial Catalog=InventoryTraker;Integrated Security=True" providerName="System.Data.SqlClient" />
|
||||
<add name="DefaultConnection" connectionString="Data Source=(LocalDb)\MSSQLLocalDB;AttachDbFilename=|DataDirectory|\InventoryTrakerBox.mdf;Initial Catalog=InventoryTrakerBox;Integrated Security=True" providerName="System.Data.SqlClient" />
|
||||
</connectionStrings>
|
||||
|
||||
<system.web>
|
||||
|
||||
@@ -26,7 +26,7 @@ body {
|
||||
}
|
||||
|
||||
.navbar-brand i {
|
||||
color:palegreen
|
||||
color:palevioletred
|
||||
}
|
||||
|
||||
.navbar-brand:link,
|
||||
@@ -34,7 +34,7 @@ body {
|
||||
.navbar-brand:hover,
|
||||
.navbar-brand:active {
|
||||
font-weight: bolder;
|
||||
color: #92B9BD;
|
||||
color: papayawhip;
|
||||
}
|
||||
|
||||
.navbar.navbar-fixed-top {
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
window.app =
|
||||
angular
|
||||
.module('InventoryTraker', ['ngAnimate', 'ui.bootstrap', 'ui.grid', 'ui.grid.pagination', 'mgcrea.ngStrap'])
|
||||
.module('InventoryTraker', ['ngAnimate', 'ui.bootstrap', 'ui.grid', 'ui.grid.pagination', 'mgcrea.ngStrap', 'ngFileUpload'])
|
||||
.config(function($datepickerProvider) {
|
||||
angular.extend($datepickerProvider.defaults,
|
||||
{
|
||||
|
||||
@@ -10,38 +10,33 @@
|
||||
}
|
||||
});
|
||||
|
||||
controller.$inject = ['$scope', 'inventorySvc', 'inventoryTypeSvc'];
|
||||
function controller($scope, inventorySvc, inventoryTypeSvc) {
|
||||
controller.$inject = ['$scope', 'inventorySvc'];
|
||||
function controller($scope, inventorySvc) {
|
||||
var vm = this;
|
||||
|
||||
vm.add = add;
|
||||
vm.inventory = { };
|
||||
vm.inventoryTypes = inventoryTypeSvc.inventoryTypes;
|
||||
vm.programNames = [
|
||||
"Admin",
|
||||
"Aging",
|
||||
"CC",
|
||||
"CCFP",
|
||||
"CIS",
|
||||
"CSBG",
|
||||
"Homemaker",
|
||||
"HUD",
|
||||
"Misdemeanor",
|
||||
"Nutrition",
|
||||
"Title V",
|
||||
"Transportation",
|
||||
"WAP",
|
||||
"Workforce"
|
||||
];
|
||||
|
||||
vm.saving = false;
|
||||
vm.statusMessage = "Enter details for the inventory arrival below.";
|
||||
vm.statusMessage = "Enter details for the inventory addition below.";
|
||||
vm.errorMessages = [];
|
||||
|
||||
vm.quantity = quantity;
|
||||
|
||||
function zeroNaN(v) {
|
||||
return isNaN(v) ? 0 : v;
|
||||
}
|
||||
|
||||
function quantity() {
|
||||
vm.inventory.quantity =
|
||||
zeroNaN($scope.palletCount)
|
||||
* zeroNaN($scope.casesPerPallet)
|
||||
+ zeroNaN($scope.caseCount);
|
||||
|
||||
return vm.inventory.quantity > 0 ? vm.inventory.quantity : "";
|
||||
}
|
||||
|
||||
$scope.$watch('vm.commodity', function (newValue) {
|
||||
if (newValue)
|
||||
vm.inventory.inventoryTypeId = newValue.id;
|
||||
});
|
||||
|
||||
function add() {
|
||||
vm.statusMessage = null;
|
||||
vm.saving = true;
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
(function() {
|
||||
"use strict";
|
||||
|
||||
window.app.directive('inventoryDistribute',
|
||||
function() {
|
||||
return {
|
||||
templateUrl: '/inventory/template/inventoryDistribute.tmpl.cshtml',
|
||||
controller: controller,
|
||||
controllerAs: 'vm'
|
||||
}
|
||||
});
|
||||
|
||||
controller.$inject = ['$scope', 'inventorySvc'];
|
||||
function controller($scope, inventorySvc) {
|
||||
var vm = this;
|
||||
|
||||
vm.save = save;
|
||||
vm.quantities = angular.copy(inventorySvc.inventories);
|
||||
vm.distribution = {};
|
||||
|
||||
vm.saving = false;
|
||||
vm.statusMessage = "Enter details for the inventory distribution below.";
|
||||
vm.errorMessages = [];
|
||||
|
||||
function getInventoryDistributeQuantities(inventory) {
|
||||
var invQty = [];
|
||||
inventory.forEach(function (i) {
|
||||
if (i.distributeQuantity > 0)
|
||||
invQty.push({ inventoryId: i.id, quantity: i.distributeQuantity });
|
||||
});
|
||||
return invQty;
|
||||
}
|
||||
|
||||
function save() {
|
||||
vm.statusMessage = null;
|
||||
vm.saving = true;
|
||||
vm.distribution.inventoryQuantities = getInventoryDistributeQuantities(vm.quantities);
|
||||
inventorySvc.distribute(vm.distribution)
|
||||
.success(function () {
|
||||
//Close the modal
|
||||
$scope.$close();
|
||||
})
|
||||
.error(function(data) {
|
||||
vm.errorMessages = angular.copy(data.errorMessages, vm.errorMessages);
|
||||
})
|
||||
.finally(function() {
|
||||
vm.saving = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
})();
|
||||
@@ -17,6 +17,7 @@
|
||||
function controller($scope, $uibModal, inventorySvc, transactionSvc) {
|
||||
var vm = this;
|
||||
vm.inventory = $scope.inventory;
|
||||
vm.inventoryOriginal = angular.copy(vm.inventory);
|
||||
vm.transactions = [];
|
||||
|
||||
function refreshTransactions() {
|
||||
@@ -31,11 +32,15 @@
|
||||
angular.copy(data.transactions, vm.transactions);
|
||||
}
|
||||
})
|
||||
.finally(function(){vm.loadingTransactions = false;});
|
||||
.finally(function() {
|
||||
vm.loadingTransactions = false;
|
||||
vm.inventoryOriginal = angular.copy(vm.inventory);
|
||||
});
|
||||
}
|
||||
refreshTransactions(); // initial call
|
||||
|
||||
vm.save = save;
|
||||
vm.cancel = cancel;
|
||||
vm.deleteTransaction = deleteTransaction;
|
||||
vm.removeInventory = removeInventory;
|
||||
vm.saving = false;
|
||||
@@ -43,6 +48,9 @@
|
||||
vm.confirmDeleteTransaction = false;
|
||||
vm.loadingTransactions = false;
|
||||
|
||||
vm.isShredReady = function () { return inventorySvc.isShredReady(vm.inventory); };
|
||||
vm.isInInventory = function() { return vm.inventory.quantity > 0; }
|
||||
|
||||
function deleteTransaction(transactionId) {
|
||||
vm.confirmDeleteTransaction = false;
|
||||
transactionSvc
|
||||
@@ -71,5 +79,10 @@
|
||||
vm.saving = false;
|
||||
});
|
||||
}
|
||||
|
||||
function cancel() {
|
||||
angular.copy(vm.inventoryOriginal, $scope.inventory);
|
||||
$scope.$parent.$dismiss();
|
||||
}
|
||||
}
|
||||
})();
|
||||
@@ -0,0 +1,54 @@
|
||||
(function() {
|
||||
"use strict";
|
||||
|
||||
window.app.directive('inventoryImport',
|
||||
function() {
|
||||
return {
|
||||
templateUrl: '/inventory/template/inventoryImport.tmpl.cshtml',
|
||||
controller: controller,
|
||||
controllerAs: 'vm'
|
||||
};
|
||||
});
|
||||
|
||||
controller.$inject = ['$scope', 'inventorySvc'];
|
||||
function controller($scope, inventorySvc) {
|
||||
var vm = this;
|
||||
|
||||
vm.uploading = false;
|
||||
vm.file = "";
|
||||
|
||||
vm.statusMessage = "Import inventory items below.";
|
||||
vm.errorMessages = [];
|
||||
|
||||
// upload later on form submit or something similar
|
||||
vm.submit = function () {
|
||||
if (vm.form.file.$valid && vm.file) {
|
||||
vm.upload(vm.file);
|
||||
}
|
||||
};
|
||||
|
||||
// upload on file select or drop
|
||||
vm.upload = function(file) {
|
||||
vm.uploading = true;
|
||||
inventorySvc
|
||||
.importFile(file)
|
||||
.then(function(resp) {
|
||||
console.log("Success " + resp.config.data.file.name + "uploaded. Response: " + resp.data);
|
||||
vm.uploading = false;
|
||||
},
|
||||
function (resp) {
|
||||
if (angular.isArray(resp.data))
|
||||
angular.copy(resp.data, vm.errorMessages);
|
||||
else
|
||||
angular.copy([resp.data], vm.errorMessages);
|
||||
console.log("Error status: " + resp.status + " message: " + resp.data);
|
||||
vm.uploading = false;
|
||||
},
|
||||
function(evt) {
|
||||
var progressPercentage = parseInt(100.0 * evt.loaded / evt.total);
|
||||
console.log("progress: " + progressPercentage + "% " + evt.config.data.file.name);
|
||||
});
|
||||
};
|
||||
|
||||
}
|
||||
})();
|
||||
@@ -27,6 +27,13 @@
|
||||
inventorySvc.exportInventory()
|
||||
.success(downloadSvc.success);
|
||||
};
|
||||
|
||||
vm.import = function() {
|
||||
$uibModal.open({
|
||||
template: "<inventory-import />",
|
||||
backdrop: "static"
|
||||
});
|
||||
};
|
||||
}
|
||||
]);
|
||||
})();
|
||||
@@ -11,8 +11,8 @@
|
||||
}
|
||||
});
|
||||
|
||||
controller.$inject = ['$scope', '$uibModal'];
|
||||
function controller($scope, $uibModal) {
|
||||
controller.$inject = ['$scope', '$uibModal', 'inventorySvc'];
|
||||
function controller($scope, $uibModal, inventorySvc) {
|
||||
var vm = this;
|
||||
|
||||
vm.inventories = $scope.inventories;
|
||||
@@ -32,5 +32,7 @@
|
||||
scope: angular.extend($scope.$new(true), { inventory: inventory })
|
||||
});
|
||||
}
|
||||
|
||||
vm.isShredReady = inventorySvc.isShredReady;
|
||||
}
|
||||
})();
|
||||
@@ -11,9 +11,13 @@
|
||||
}
|
||||
});
|
||||
|
||||
controller.$inject = ['$scope'];
|
||||
function controller($scope) {
|
||||
controller.$inject = ['$scope', 'inventorySvc'];
|
||||
function controller($scope, inventorySvc) {
|
||||
var vm = this;
|
||||
vm.inventory = $scope.inventory;
|
||||
|
||||
vm.isShredReady = function () { return inventorySvc.isShredReady(vm.inventory); };
|
||||
|
||||
vm.isInInventory = function() { return vm.inventory.quantity > 0; }
|
||||
}
|
||||
})();
|
||||
@@ -21,7 +21,7 @@
|
||||
vm.removeForm = {
|
||||
inventoryId: vm.inventory.id,
|
||||
quantity: vm.inventory.quantity,
|
||||
transactionType: vm.inventory.isExpired ? "Expired" : null
|
||||
transactionType: vm.inventory.shredReadyDate ? "Shreded" : null
|
||||
};
|
||||
|
||||
vm.statusMessage = "Enter details for the inventory removal below.";
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
(function() {
|
||||
window.app.factory("inventorySvc",
|
||||
[
|
||||
"$http", "$filter",
|
||||
function($http, $filter) {
|
||||
"$http", "$filter", 'Upload',
|
||||
function($http, $filter, Upload) {
|
||||
var inventories = [];
|
||||
|
||||
loadInventories();
|
||||
@@ -15,8 +15,10 @@
|
||||
inventories: inventories,
|
||||
get: get,
|
||||
refresh: refresh,
|
||||
find: find,
|
||||
exportInventory: exportInventory
|
||||
load: load,
|
||||
exportInventory: exportInventory,
|
||||
isShredReady: isShredReady,
|
||||
importFile: importFile
|
||||
};
|
||||
|
||||
return svc;
|
||||
@@ -73,15 +75,34 @@
|
||||
function refresh(id) {
|
||||
var existingInventory = get(id);
|
||||
if (existingInventory) {
|
||||
find(id)
|
||||
load(id)
|
||||
.success(function(inventory) {
|
||||
angular.copy(inventory, existingInventory);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function find(id) {
|
||||
return $http.post("/Inventory/Find", { id: id });
|
||||
function load(id) {
|
||||
return $http.post("/Inventory/Find", { id: id })
|
||||
.success(function (inventory) {
|
||||
var existingInventory = get(id);
|
||||
if (existingInventory != null)
|
||||
angular.copy(inventory, existingInventory);
|
||||
else
|
||||
inventories.unshift(inventory);
|
||||
});
|
||||
}
|
||||
|
||||
function importFile(file) {
|
||||
return Upload.upload({
|
||||
url: "/api/Import",
|
||||
method: 'POST',
|
||||
data: { file: file}
|
||||
});
|
||||
}
|
||||
|
||||
function isShredReady(inventory) {
|
||||
return new Date(inventory.shredReadyDate) <= new Date();
|
||||
}
|
||||
}
|
||||
]);
|
||||
|
||||
@@ -9,78 +9,40 @@
|
||||
<fieldset ng-disabled="vm.saving">
|
||||
|
||||
<div class="modal-header">
|
||||
<h3 class="modal-title"><i class="fa fa-cubes"></i> Inventory Arrival</h3>
|
||||
<h3 class="modal-title"><i class="fa fa-cubes"></i> Inventory Addition</h3>
|
||||
</div>
|
||||
|
||||
<div class="modal-body">
|
||||
|
||||
<status-message message="vm.statusMessage"></status-message>
|
||||
<status-message message="vm.statusMessage" ng-hide="vm.errorMessages.length"></status-message>
|
||||
<error-list errors="vm.errorMessages"></error-list>
|
||||
|
||||
<script type="text/ng-template" id="commodityTypeahead.html">
|
||||
<script type="text/ng-template" id="programTypeahead.html">
|
||||
<a>
|
||||
<span ng-bind-html="match.label.name | uibTypeaheadHighlight:query"></span>
|
||||
</a>
|
||||
</script>
|
||||
|
||||
<div class="form-group" form-group-validation="Commodity">
|
||||
<label for="Commodity" class="control-label">Commodity</label>
|
||||
<input name="Commodity" type="text"
|
||||
ng-model="vm.commodity"
|
||||
@inventory.FormGroupFor(m => m.Id)
|
||||
|
||||
<div class="form-group" form-group-validation="ProgramName">
|
||||
<label for="ProgramName" class="control-label">Program Name</label>
|
||||
<input name="ProgramName" type="text"
|
||||
ng-model="vm.inventory.programName"
|
||||
required
|
||||
uib-typeahead=
|
||||
"inventoryType as inventoryType.name for inventoryType in vm.inventoryTypes
|
||||
| filter:{name:$viewValue}
|
||||
| limitTo:8"
|
||||
typeahead-editable='false'
|
||||
"programName for programName in vm.programNames
|
||||
|filter:$viewValue
|
||||
| limitTo:8"
|
||||
class="form-control">
|
||||
<i class="fa fa-search form-control-feedback"></i>
|
||||
<div class="panel panel-default" ng-show="vm.commodity.id">
|
||||
<div class="panel-body">
|
||||
<dl class="dl-horizontal">
|
||||
<dt>Commodity ID</dt>
|
||||
<dd>{{vm.commodity.identifier}}</dd>
|
||||
<dt>Units per Case</dt>
|
||||
<dd>{{vm.commodity.unitsPerCase}} / {{vm.commodity.containerType}}</dd>
|
||||
</dl>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@inventory.FormGroupFor(m => m.ExpirationDate)
|
||||
|
||||
<div class="form-group panel panel-default">
|
||||
<div class="panel-heading"><label>Quantity</label></div>
|
||||
<div class="panel-body container-fluid">
|
||||
<div class="row">
|
||||
<div class="col-sm-5"><label for="PalletCount">Pallets</label></div>
|
||||
<div class="col-sm-3">
|
||||
<input ng-model="palletCount" name="PalletCount" type="number" class="form-control" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-sm-4 col-sm-offset-1"><label for="CasesPerPallet">Cases per Pallet</label></div>
|
||||
<div class="col-sm-3">
|
||||
<input ng-model="casesPerPallet" name="CasesPerPallet" type="number" class="form-control" />
|
||||
</div>
|
||||
</div>
|
||||
<hr />
|
||||
<div class="row">
|
||||
<div class="col-sm-5"><label for="CaseCount">Individual Cases</label></div>
|
||||
<div class="col-sm-3">
|
||||
<input ng-model="caseCount" name="CaseCount" type="number" class="form-control" />
|
||||
</div>
|
||||
</div>
|
||||
<hr />
|
||||
<div class="row">
|
||||
<div class="col-sm-5"><strong>Total Units</strong></div>
|
||||
<div class="col-sm-3"><strong>{{vm.quantity()}}</strong></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@inventory.FormGroupFor(m => m.AddedDate)
|
||||
@inventory.FormGroupFor(m => m.Memo)
|
||||
@inventory.FormGroupFor(m => m.ProgramSubtype)
|
||||
@inventory.FormGroupFor(m => m.Description)
|
||||
@inventory.FormGroupFor(m => m.ShredReadyDate)
|
||||
@inventory.FormGroupFor(m => m.AddedDate)
|
||||
@inventory.FormGroupFor(m => m.Memo)
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
@@ -1,63 +0,0 @@
|
||||
@using InventoryTraker.Web.Helpers
|
||||
@model InventoryTraker.Web.Models.InventoryDistributeForm
|
||||
@{
|
||||
var distribution = Html.Angular().ModelFor("vm.distribution");
|
||||
}
|
||||
<form novalidate
|
||||
name="vm.form"
|
||||
ng-submit="vm.form.$valid && vm.save()">
|
||||
<fieldset ng-disabled="vm.saving">
|
||||
|
||||
<div class="modal-header">
|
||||
<h3 class="modal-title"><i class="fa fa-cubes"></i> Inventory Distribution</h3>
|
||||
</div>
|
||||
|
||||
<div class="modal-body">
|
||||
|
||||
<status-message message="vm.statusMessage"></status-message>
|
||||
<error-list errors="vm.errorMessages"></error-list>
|
||||
|
||||
@distribution.FormGroupFor(m => m.Destination)
|
||||
|
||||
@distribution.FormGroupFor(m => m.DistributedDate)
|
||||
|
||||
@distribution.FormGroupFor(m => m.Memo)
|
||||
|
||||
<table class="table table-condensed" ng-class="vm.getValidationClass()">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name<br/>Units per Case</th>
|
||||
<th>Expiration Date</th>
|
||||
<th>Available Case Qty</th>
|
||||
<th>Distribute Case Qty</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr ng-repeat="inventory in vm.quantities" inventory="inventory">
|
||||
<td>
|
||||
{{inventory.name}}<br/>
|
||||
{{inventory.unitsPerCase}} / {{inventory.containerType}}<br/>
|
||||
</td>
|
||||
<td ng-class="{ danger: inventory.isExpired }">{{inventory.expirationDate | date:'shortDate'}}</td>
|
||||
<td>{{inventory.quantity}}</td>
|
||||
<td>
|
||||
<div class="form-group col-sm-9" form-group-validation="DistributeQuantity{{inventory.name}}">
|
||||
<input name="DistributeQuantity{{inventory.name}}" type="number"
|
||||
class="form-control"
|
||||
ng-model="inventory.distributeQuantity"
|
||||
ng-max="{{inventory.quantity}}"
|
||||
ng-min="0" />
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="modal-footer">
|
||||
<button class="btn btn-success" ng-disabled="vm.form.$invalid || vm.form.$pristine">Save</button>
|
||||
<button type="button" class="btn" ng-click="$dismiss()">Cancel</button>
|
||||
</div>
|
||||
|
||||
</fieldset>
|
||||
</form>
|
||||
@@ -1,4 +1,8 @@
|
||||
@model InventoryTraker.Web.Models.InventoryAddForm
|
||||
@using InventoryTraker.Web.Helpers
|
||||
@model InventoryTraker.Web.Models.InventoryAddForm
|
||||
@{
|
||||
var inventory = Html.Angular().ModelFor("vm.inventory");
|
||||
}
|
||||
<form novalidate
|
||||
name="vm.form"
|
||||
ng-submit="vm.form.$valid && vm.save()">
|
||||
@@ -12,11 +16,22 @@
|
||||
|
||||
<error-list errors="vm.errorMessages"></error-list>
|
||||
|
||||
<inventory-info inventory="inventory"></inventory-info>
|
||||
<label class="control-label">Box Id</label>
|
||||
<p class="form-control-static">{{vm.inventory.id}}</p>
|
||||
<label class="control-label">Program Name</label>
|
||||
<p class="form-control-static">{{vm.inventory.programName}}<span ng-show="vm.inventory.programSubtype != null"> / {{vm.inventory.programSubtype}}</span></p>
|
||||
@inventory.FormGroupFor(m => m.Description)
|
||||
<label class="control-label">Currently in Inventory</label>
|
||||
<p class="form-control-static">{{vm.isInInventory() ? "Yes" : "No"}}</p>
|
||||
@inventory.FormGroupFor(m => m.ShredReadyDate)
|
||||
<label class="control-label">Added Date</label>
|
||||
<p class="form-control-static">{{vm.inventory.addedDate | date:'shortDate'}}</p>
|
||||
@inventory.FormGroupFor(m => m.Memo)
|
||||
|
||||
<div class="modal-footer">
|
||||
<button ng-click="vm.removeInventory()" class="btn btn-sm pull-left"><i class="fa fa-minus-circle"></i> Remove Inventory</button>
|
||||
<button type="button" class="btn btn-sm pull-left" ng-click="vm.removeInventory()"><i class="fa fa-minus-circle"></i> Remove Inventory</button>
|
||||
<button class="btn btn-success" ng-disabled="vm.form.$invalid || vm.form.$pristine">Save</button>
|
||||
<button type="button" class="btn" ng-click="$parent.$dismiss()">Cancel</button>
|
||||
<button type="button" class="btn" ng-click="vm.cancel()">Close</button>
|
||||
</div>
|
||||
|
||||
<hr />
|
||||
@@ -29,23 +44,16 @@
|
||||
<th>Type</th>
|
||||
<th>Memo</th>
|
||||
<th>Transaction Date</th>
|
||||
<th>Add Qty</th>
|
||||
<th>Remove Qty</th>
|
||||
<th>Qty</th>
|
||||
<th>In Inventory</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody ng-hide="vm.loadingTransactions">
|
||||
<tr ng-repeat-start="transaction in vm.transactions | orderBy:['-transactionDate', 'currentQuantity']">
|
||||
<td>
|
||||
{{transaction.transactionType}}
|
||||
<span ng-show="transaction.destination"><i class="fa fa-map-marker" title="{{transaction.destination}}"></i></span>
|
||||
</td>
|
||||
<td>{{transaction.transactionType}}</td>
|
||||
<td>{{transaction.memo}}</td>
|
||||
<td>{{transaction.transactionDate | date:'shortDate'}}</td>
|
||||
<td>{{transaction.addedQuantity}}</td>
|
||||
<td>{{transaction.removedQuantity}}</td>
|
||||
<td>{{transaction.currentQuantity}}</td>
|
||||
<td>{{transaction.currentQuantity > 0 ? "Yes" : "No"}}</td>
|
||||
<td>
|
||||
<a href="" ng-show="$first"
|
||||
ng-click="vm.confirmDeleteTransaction = !vm.confirmDeleteTransaction">
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
<form novalidate
|
||||
name="vm.form"
|
||||
ng-submit="vm.form.$valid && vm.submit()">
|
||||
<fieldset ng-disabled="vm.uploading">
|
||||
|
||||
<div class="modal-header">
|
||||
<h3 class="modal-title"><i class="fa fa-cubes"></i> Inventory Import</h3>
|
||||
</div>
|
||||
|
||||
<div class="modal-body">
|
||||
|
||||
<status-message message="vm.statusMessage" ng-hide="vm.errorMessages.length"></status-message>
|
||||
<error-list errors="vm.errorMessages"></error-list>
|
||||
|
||||
<div class="btn btn-default"
|
||||
ngf-select
|
||||
ng-model="vm.file"
|
||||
name="file"
|
||||
ngf-pattern="'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'"
|
||||
ngf-accept="'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'">Select</div>
|
||||
|
||||
<div>{{vm.file.name}}</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="modal-footer">
|
||||
<button class="btn btn-success" ng-disabled="vm.form.$invalid || vm.form.$pristine">Submit</button>
|
||||
<button type="button" class="btn" ng-click="$dismiss()">Cancel</button>
|
||||
</div>
|
||||
|
||||
</fieldset>
|
||||
</form>
|
||||
@@ -1,19 +1,19 @@
|
||||
<dl class="dl-horizontal">
|
||||
<dt>Name</dt>
|
||||
<dd>{{inventory.name}}</dd>
|
||||
<dt>Units per Case</dt>
|
||||
<dd>{{inventory.unitsPerCase}} / {{inventory.containerType}}</dd>
|
||||
<dt>Added Date</dt>
|
||||
<dd>{{inventory.addedDate | date:'shortDate'}}</dd>
|
||||
<dt>Expiration Date</dt>
|
||||
<dt>Box Id</dt>
|
||||
<dd>{{inventory.id}}</dd>
|
||||
<dt>Program Name</dt>
|
||||
<dd>{{inventory.programName}}<span ng-show="inventory.programSubtype != null"> / {{inventory.programSubtype}}</span></dd>
|
||||
<dt>Currently in Inventory</dt>
|
||||
<dd>{{vm.isInInventory() ? "Yes" : "No"}}</dd>
|
||||
<dt>Shred Ready Date</dt>
|
||||
<dd>
|
||||
<span ng-class="{ 'bg-danger': inventory.quantity && inventory.isExpired }">
|
||||
{{inventory.expirationDate | date:'shortDate'}}
|
||||
<span ng-show="inventory.isExpired" class="label label-danger">Expired</span>
|
||||
<span ng-class="{ 'bg-danger': inventory.quantity && vm.isShredReady() }">
|
||||
{{inventory.shredReadyDate | date:'shortDate'}}
|
||||
<span ng-show="vm.isShredReady()" class="label label-danger">Shred Ready</span>
|
||||
</span>
|
||||
</dd>
|
||||
<dt>Quantity (in Cases)</dt>
|
||||
<dd>{{inventory.quantity}}</dd>
|
||||
<dt>Added Date</dt>
|
||||
<dd>{{inventory.addedDate | date:'shortDate'}}</dd>
|
||||
<dt ng-show="inventory.memo">Memo</dt>
|
||||
<dd ng-show="inventory.memo">{{inventory.memo}}</dd>
|
||||
</dl>
|
||||
|
||||
@@ -8,26 +8,24 @@
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="control-column"></th>
|
||||
<th>Name</th>
|
||||
<th>Units per Case</th>
|
||||
<th>Case Qty</th>
|
||||
<th>Unit Qty</th>
|
||||
<th>Exp Date</th>
|
||||
<th>Id</th>
|
||||
<th>Program Name</th>
|
||||
<th>Description</th>
|
||||
<th>Shred Ready Date</th>
|
||||
<th>Added Date</th>
|
||||
<th>Memo</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr ng-repeat="inventory in vm.inventories | filter:{name: ''}">
|
||||
<tr ng-repeat="inventory in vm.inventories | filter:{quantity: 1}">
|
||||
<td>
|
||||
<a href="" ng-click="vm.edit(inventory)" title="Details"><i class="fa fa-edit"></i></a>
|
||||
</td>
|
||||
<td>@inventory.BindingFor(x => x.Name)</td>
|
||||
<td>@inventory.BindingFor(x => x.UnitsPerCase) / @inventory.BindingFor(x => x.ContainerType)</td>
|
||||
<td>@inventory.BindingFor(x => x.Quantity)</td>
|
||||
<td>{{inventory.quantity * inventory.unitsPerCase}}</td>
|
||||
<td ng-class="{ danger: inventory.isExpired }">
|
||||
@inventory.BindingFor(x => x.ExpirationDate, "date:'shortDate'")
|
||||
<td>@inventory.BindingFor(x => x.Id)</td>
|
||||
<td>@inventory.BindingFor(x => x.ProgramName)</td>
|
||||
<td>@inventory.BindingFor(x => x.Description)</td>
|
||||
<td ng-class="{ danger: vm.isShredReady(inventory) }">
|
||||
@inventory.BindingFor(x => x.ShredReadyDate, "date:'shortDate'")
|
||||
</td>
|
||||
<td>@inventory.BindingFor(x => x.AddedDate, "date:'shortDate'")</td>
|
||||
<td>@inventory.BindingFor(x => x.Memo)</td>
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
<div class="modal-body">
|
||||
|
||||
<status-message message="vm.statusMessage"></status-message>
|
||||
<status-message message="vm.statusMessage" ng-hide="vm.errorMessages.length"></status-message>
|
||||
<error-list errors="vm.errorMessages"></error-list>
|
||||
|
||||
<div class="panel panel-default">
|
||||
@@ -27,9 +27,9 @@
|
||||
<label class="radio-inline">
|
||||
<input type="radio" name="TransactionType"
|
||||
ng-model="vm.removeForm.transactionType"
|
||||
value="Expired"
|
||||
value="Shreded"
|
||||
required />
|
||||
Expired
|
||||
Shreded
|
||||
</label>
|
||||
<label class="radio-inline">
|
||||
<input type="radio" name="TransactionType"
|
||||
@@ -40,7 +40,6 @@
|
||||
</label>
|
||||
</div>
|
||||
|
||||
@removeForm.FormGroupFor(m => m.Quantity)
|
||||
@removeForm.FormGroupFor(m => m.RemovedDate)
|
||||
@removeForm.FormGroupFor(m => m.Memo)
|
||||
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
(function() {
|
||||
"use strict";
|
||||
|
||||
window.app.directive("inventoryTypeAdd",
|
||||
function() {
|
||||
return {
|
||||
templateUrl: "/inventoryType/template/inventoryTypeAdd.tmpl.cshtml",
|
||||
controller: controller,
|
||||
controllerAs: "vm"
|
||||
};
|
||||
});
|
||||
|
||||
controller.$inject = ['$scope', 'inventoryTypeSvc'];
|
||||
function controller($scope, inventoryTypeSvc){
|
||||
var vm = this;
|
||||
|
||||
vm.add = add;
|
||||
vm.saving = false;
|
||||
vm.inventoryType = {};
|
||||
|
||||
vm.statusMessage = "Add a new commodity";
|
||||
vm.errorMessages = [];
|
||||
|
||||
function add() {
|
||||
vm.statusMessage = null;
|
||||
vm.saving = true;
|
||||
inventoryTypeSvc.add(vm.inventoryType)
|
||||
.success(function () {
|
||||
//Close the modal
|
||||
$scope.$close();
|
||||
})
|
||||
.error(function (data) {
|
||||
vm.errorMessages = angular.copy(data.errorMessages, vm.errorMessages);
|
||||
})
|
||||
.finally(function() {
|
||||
vm.saving = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
})();
|
||||
@@ -1,24 +0,0 @@
|
||||
(function() {
|
||||
"use strict";
|
||||
|
||||
window.app.controller("InventoryTypeController",
|
||||
[
|
||||
"$uibModal", "inventoryTypeSvc", "downloadSvc",
|
||||
function($uibModal, inventoryTypeSvc, downloadSvc) {
|
||||
var vm = this;
|
||||
|
||||
vm.inventoryTypes = inventoryTypeSvc.inventoryTypes;
|
||||
|
||||
vm.add = function() {
|
||||
$uibModal.open({
|
||||
template: "<inventory-type-add />",
|
||||
backdrop: "static"
|
||||
});
|
||||
};
|
||||
vm.export = function() {
|
||||
inventoryTypeSvc.exportInventoryTypes()
|
||||
.success(downloadSvc.success);
|
||||
};
|
||||
}
|
||||
]);
|
||||
})();
|
||||
@@ -1,44 +0,0 @@
|
||||
(function() {
|
||||
"use strict";
|
||||
|
||||
window.app.directive('editInventoryType',
|
||||
function() {
|
||||
return {
|
||||
scope: {
|
||||
inventoryType: "="
|
||||
},
|
||||
templateUrl: '/inventoryType/template/inventoryTypeEdit.tmpl.cshtml',
|
||||
controller: controller,
|
||||
controllerAs: 'vm'
|
||||
}
|
||||
});
|
||||
|
||||
controller.$inject = ['$scope', 'inventoryTypeSvc'];
|
||||
function controller($scope, inventoryTypeSvc) {
|
||||
var vm = this;
|
||||
vm.inventoryType = angular.copy($scope.inventoryType);
|
||||
vm.save = save;
|
||||
|
||||
vm.saving = false;
|
||||
vm.inventoryTypeSvc = inventoryTypeSvc;
|
||||
|
||||
vm.statusMessage = "Edit this commodity";
|
||||
vm.errorMessages = [];
|
||||
|
||||
function save() {
|
||||
vm.statusMessage = null;
|
||||
vm.saving = true;
|
||||
inventoryTypeSvc.update($scope.inventoryType, vm.inventoryType)
|
||||
.success(function () {
|
||||
//Close the modal
|
||||
$scope.$parent.$close();
|
||||
})
|
||||
.error(function(data) {
|
||||
vm.errorMessages = angular.copy(data.errorMessages, vm.errorMessages);
|
||||
})
|
||||
.finally(function() {
|
||||
vm.saving = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
})();
|
||||
@@ -1,27 +0,0 @@
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
window.app.directive('inventoryTypeList',
|
||||
function() {
|
||||
return {
|
||||
scope: { "inventoryTypes": "=" },
|
||||
templateUrl: '/inventoryType/template/inventoryTypeList.tmpl.cshtml',
|
||||
controller: controller,
|
||||
controllerAs: 'vm'
|
||||
}
|
||||
});
|
||||
|
||||
controller.$inject = ['$scope', '$uibModal'];
|
||||
function controller($scope, $uibModal) {
|
||||
var vm = this;
|
||||
|
||||
vm.inventoryTypes = $scope.inventoryTypes;
|
||||
|
||||
vm.edit = function(inventoryType) {
|
||||
$uibModal.open({
|
||||
template: '<edit-inventory-type inventory-type="inventoryType" />',
|
||||
scope: angular.extend($scope.$new(true), { inventoryType: inventoryType })
|
||||
});
|
||||
};
|
||||
}
|
||||
})();
|
||||
@@ -1,45 +0,0 @@
|
||||
(function() {
|
||||
window.app.factory("inventoryTypeSvc",
|
||||
[
|
||||
"$http",
|
||||
function($http) {
|
||||
var inventoryTypes = [];
|
||||
|
||||
loadInventoryTypes();
|
||||
|
||||
var svc = {
|
||||
add: add,
|
||||
update: update,
|
||||
inventoryTypes: inventoryTypes,
|
||||
exportInventoryTypes: exportInventoryTypes
|
||||
};
|
||||
|
||||
return svc;
|
||||
|
||||
function loadInventoryTypes() {
|
||||
$http.post("/InventoryType/All")
|
||||
.success(function(data) {
|
||||
inventoryTypes.addRange(data);
|
||||
});
|
||||
}
|
||||
|
||||
function exportInventoryTypes() {
|
||||
return $http.post("/InventoryType/Export", {}, { responseType: "arraybuffer" });
|
||||
}
|
||||
|
||||
function add(inventoryType) {
|
||||
return $http.post("/InventoryType/Add", inventoryType)
|
||||
.success(function(inventoryType) {
|
||||
inventoryTypes.unshift(inventoryType);
|
||||
});
|
||||
}
|
||||
|
||||
function update(existingInventoryType, updatedInventoryType) {
|
||||
return $http.post("/InventoryType/Update", updatedInventoryType)
|
||||
.success(function(inventoryType) {
|
||||
angular.extend(existingInventoryType, inventoryType);
|
||||
});
|
||||
}
|
||||
}
|
||||
]);
|
||||
})();
|
||||
@@ -1,27 +0,0 @@
|
||||
@using InventoryTraker.Web.Helpers
|
||||
@model InventoryTraker.Web.Models.InventoryTypeViewModel
|
||||
|
||||
<form novalidate
|
||||
name="vm.form"
|
||||
ng-submit="vm.form.$valid && vm.add()">
|
||||
<fieldset ng-disabled="vm.saving">
|
||||
|
||||
<div class="modal-header">
|
||||
<h3 class="modal-title"><i class="fa fa-cube"></i> Add Commodity Type</h3>
|
||||
</div>
|
||||
|
||||
<div class="modal-body">
|
||||
<status-message message="vm.statusMessage"></status-message>
|
||||
<error-list errors="vm.errorMessages"></error-list>
|
||||
|
||||
@Html.Angular().FormForModel("vm.inventoryType")
|
||||
|
||||
</div>
|
||||
|
||||
<div class="modal-footer">
|
||||
<button class="btn btn-success" ng-disabled="vm.form.$invalid || vm.form.$pristine">Add</button>
|
||||
<button type="button" class="btn" ng-click="$dismiss()">Cancel</button>
|
||||
</div>
|
||||
|
||||
</fieldset>
|
||||
</form>
|
||||
@@ -1,27 +0,0 @@
|
||||
@using InventoryTraker.Web.Helpers
|
||||
@model InventoryTraker.Web.Models.InventoryTypeViewModel
|
||||
<form novalidate
|
||||
name="vm.form"
|
||||
ng-submit="vm.form.$valid && vm.save()">
|
||||
<fieldset ng-disabled="vm.saving">
|
||||
|
||||
<div class="modal-header">
|
||||
<h3 class="modal-title"><i class="fa fa-cube"></i> Edit Commodity Type</h3>
|
||||
</div>
|
||||
|
||||
<div class="modal-body">
|
||||
|
||||
<status-message message="vm.statusMessage"></status-message>
|
||||
<error-list errors="vm.errorMessages"></error-list>
|
||||
|
||||
@Html.Angular().FormForModel("vm.inventoryType")
|
||||
|
||||
</div>
|
||||
|
||||
<div class="modal-footer">
|
||||
<button class="btn btn-success" ng-disabled="vm.form.$invalid || vm.form.$pristine">Save</button>
|
||||
<button type="button" class="btn" ng-click="$parent.$dismiss()">Cancel</button>
|
||||
</div>
|
||||
|
||||
</fieldset>
|
||||
</form>
|
||||
@@ -1,24 +0,0 @@
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="control-column"></th>
|
||||
<th>ID</th>
|
||||
<th>Name</th>
|
||||
<th>Units per Case</th>
|
||||
<th>Container Type</th>
|
||||
<th>Weight Per Case</th>
|
||||
<th>Price Per Case</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr ng-repeat="inventoryType in vm.inventoryTypes | orderBy:'name'">
|
||||
<td><a href="" ng-click="vm.edit(inventoryType)"><i class="fa fa-edit"></i></a></td>
|
||||
<td>{{inventoryType.identifier}}</td>
|
||||
<td>{{inventoryType.name}}</td>
|
||||
<td>{{inventoryType.unitsPerCase}}</td>
|
||||
<td>{{inventoryType.containerType}}</td>
|
||||
<td>{{inventoryType.weightPerCase}} lbs</td>
|
||||
<td>{{inventoryType.pricePerCase | currency}}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user