using Kean.Application.Command.ViewModels; using Microsoft.AspNetCore.Mvc; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using OfficeOpenXml; using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; namespace Kean.Presentation.Rest.Controllers { /// /// 库存服务 /// [ApiController, Route("api/stocks")] public class StocksController : ControllerBase { private readonly Application.Command.Interfaces.IStockService _stockCommandService; // 库存命令服务 private readonly Application.Query.Interfaces.IStockService _stockQueryService; // 库存查询服务 private readonly Application.Query.Interfaces.IWarehouseService _warehouseQueryService; // 库房查询服务 private readonly Application.Query.Interfaces.IIdentityService _identityQueryService; // 身份查询服务 /// /// 依赖注入 /// public StocksController( Application.Command.Interfaces.IStockService stockCommandService, Application.Query.Interfaces.IStockService stockQueryService, Application.Query.Interfaces.IIdentityService identityQueryService, Application.Query.Interfaces.IWarehouseService warehouseQueryService) { _stockCommandService = stockCommandService; _stockQueryService = stockQueryService; _identityQueryService = identityQueryService; _warehouseQueryService = warehouseQueryService; } /// /// 获取库存列表 /// /// 成功 [HttpGet] [ProducesResponseType(200)] public async Task GetList( [FromQuery] int[] area, [FromQuery] bool? pallet, [FromQuery] bool? palletized, [FromQuery] int[] category, [FromQuery] string code, [FromQuery] string name, [FromQuery] string batch, [FromQuery] string barcode, [FromQuery] string cell, [FromQuery] string qc, [FromQuery] string qualityState, [FromQuery] string materialAgeStatus, [FromQuery] DateTime? inboundTimeFrom, [FromQuery] DateTime? inboundTimeTo, [FromQuery] DateTime? manufacturingDateFrom, [FromQuery] DateTime? manufacturingDateTo, [FromQuery] DateTime? inventoryTimeFrom, [FromQuery] DateTime? inventoryTimeTo, [FromQuery] bool? overdue, [FromQuery] bool? enabled, [FromQuery] bool? excludeTask, [FromQuery] string sort, [FromQuery] int? offset, [FromQuery] int? limit, [FromQuery] string remark, [FromQuery] string supplier, [FromQuery] string laneway, [FromQuery] string workorderNo, [FromQuery] bool bQty, [FromQuery] string bill) { if (area.Length == 0) { area = null; } if (category.Length == 0) { category = null; } var items = await _stockQueryService.GetStockList(area, pallet, palletized, category, code, name, batch, barcode, cell, qc, inboundTimeFrom, inboundTimeTo, inventoryTimeFrom, inventoryTimeTo, overdue, enabled, excludeTask, sort, offset, limit, qualityState, materialAgeStatus, manufacturingDateFrom, manufacturingDateTo, remark, supplier, laneway, workorderNo, bill); decimal qtyCurrent = 0; decimal qtySum = 0; decimal transQtyCurrent = 0; decimal transQtySum = 0; if (bQty) { qtyCurrent = await _stockQueryService.GetStockQtySum(area, pallet, palletized, category, code, name, batch, barcode, cell, qc, inboundTimeFrom, inboundTimeTo, inventoryTimeFrom, inventoryTimeTo, overdue, enabled, excludeTask, sort, offset, limit, qualityState, materialAgeStatus, manufacturingDateFrom, manufacturingDateTo, remark, supplier, laneway, workorderNo, bill); transQtyCurrent = qtyCurrent; } if (offset.HasValue || limit.HasValue) { var total = await _stockQueryService.GetStockCount(area, pallet, palletized, category, code, name, batch, barcode, cell, qc, inboundTimeFrom, inboundTimeTo, inventoryTimeFrom, inventoryTimeTo, overdue, enabled, excludeTask, qualityState, materialAgeStatus, manufacturingDateFrom, manufacturingDateTo, remark, supplier, laneway, workorderNo, bill); if (bQty) { qtySum = await _stockQueryService.GetStockQtySum(area, pallet, palletized, category, code, name, batch, barcode, cell, qc, inboundTimeFrom, inboundTimeTo, inventoryTimeFrom, inventoryTimeTo, overdue, enabled, excludeTask, null, null, null, qualityState, materialAgeStatus, manufacturingDateFrom, manufacturingDateTo, remark, supplier, laneway, workorderNo, bill); transQtySum = qtySum; Application.Query.ViewModels.Stock statistics = new Application.Query.ViewModels.Stock(); statistics.QualifiedNum = $"{qtyCurrent} / {qtySum}"; statistics.TransQty = $"{transQtyCurrent} / {transQtySum}"; statistics.Barcode = ""; items = items.Concat(new[]{ statistics}); } return StatusCode(200, new { items, total }); } else { if (bQty) { var statistics = new Application.Query.ViewModels.Stock(); statistics.QualifiedNum = $"{qtyCurrent} / {qtyCurrent}"; statistics.TransQty = $"{transQtyCurrent} / {transQtyCurrent}"; statistics.Barcode = ""; items = items.Concat(new[] { statistics }); } return StatusCode(200, new { items, total = items.Count() }); } } /// /// 导出库存列表 /// /// 成功 [HttpGet("excel")] [ProducesResponseType(200)] public async Task Export( [FromQuery] int[] area, [FromQuery] bool? pallet, [FromQuery] bool? palletized, [FromQuery] int[] category, [FromQuery] string code, [FromQuery] string name, [FromQuery] string batch, [FromQuery] string barcode, [FromQuery] string cell, [FromQuery] string qc, [FromQuery] string qualityState, [FromQuery] string materialAgeStatus, [FromQuery] DateTime? inboundTimeFrom, [FromQuery] DateTime? inboundTimeTo, [FromQuery] DateTime? inventoryTimeFrom, [FromQuery] DateTime? inventoryTimeTo, [FromQuery] bool? overdue, [FromQuery] bool? enabled, [FromQuery] bool? excludeTask, [FromQuery] DateTime? manufacturingDateFrom, [FromQuery] DateTime? manufacturingDateTo, [FromQuery] string remark, [FromQuery] string supplier, [FromQuery] string laneway, [FromQuery] string workorderNo, [FromQuery] string bill) { if (area.Length == 0) { area = null; } if (category.Length == 0) { category = null; } using var package = new ExcelPackage(); var worksheet = package.Workbook.Worksheets.Add("Sheet1"); var column = 0; worksheet.Cells[1, ++column].Value = "托盘"; worksheet.Cells[1, ++column].Value = "物料编码"; worksheet.Cells[1, ++column].Value = "物料名称"; worksheet.Cells[1, ++column].Value = "仓库"; worksheet.Cells[1, ++column].Value = "货位"; worksheet.Cells[1, ++column].Value = "膜卷码"; worksheet.Cells[1, ++column].Value = "质量状态"; worksheet.Cells[1, ++column].Value = "库存状态"; worksheet.Cells[1, ++column].Value = "过账状态"; worksheet.Cells[1, ++column].Value = "生产日期"; worksheet.Cells[1, ++column].Value = "货龄(天)"; worksheet.Cells[1, ++column].Value = "创建时间"; worksheet.Cells[1, ++column].Value = "工单号"; worksheet.Cells[1, ++column].Value = "数量"; worksheet.Cells[1, ++column].Value = "单位"; worksheet.Cells[1, ++column].Value = "备注"; var index = 1; foreach (var item in await _stockQueryService.GetStockList(area, pallet, palletized, category, code, name, batch, barcode, cell, qc, inboundTimeFrom, inboundTimeTo, inventoryTimeFrom, inventoryTimeTo, overdue, enabled, excludeTask, null, null, null, qualityState, materialAgeStatus, manufacturingDateFrom, manufacturingDateTo, remark, supplier, laneway, workorderNo, bill)) { index++; column = 0; worksheet.Cells[index, ++column].Value = item.Barcode; worksheet.Cells[index, ++column].Value = item.Code; worksheet.Cells[index, ++column].Value = item.Name; worksheet.Cells[index, ++column].Value = item.Warehouse; worksheet.Cells[index, ++column].Value = item.Cell; worksheet.Cells[index, ++column].Value = item.Bill; string qs = ""; if (item.QualityState == "ok") { qs = "合格"; } else if (item.QualityState == "ng") { qs = "NG"; } else if (item.QualityState == "check") { qs = "验证品"; } worksheet.Cells[index, ++column].Value = qs; worksheet.Cells[index, ++column].Value = item.Enabled == true? "可用": "冻结"; worksheet.Cells[index, ++column].Value = ""; worksheet.Cells[index, ++column].Value = item.ManufacturingDate; worksheet.Cells[index, column].Style.Numberformat.Format = "yyyy-MM-dd HH:mm:ss"; worksheet.Cells[index, ++column].Value = item.MaterialAge; worksheet.Cells[index, ++column].Value = item.InboundTime; worksheet.Cells[index, column].Style.Numberformat.Format = "yyyy-MM-dd HH:mm:ss"; worksheet.Cells[index, ++column].Value = item.WorkorderNo; worksheet.Cells[index, ++column].Value = item.TransQty; worksheet.Cells[index, ++column].Value = item.TransUnit; worksheet.Cells[index, ++column].Value = item.Remark; } return File(package.GetAsByteArray(), "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); } /// /// 创建库动 /// /// 成功 /// 非法操作 /// 请求内容错误 [HttpPost] [ProducesResponseType(201)] [ProducesResponseType(405)] [ProducesResponseType(422)] public async Task Operate( [FromMember] string operation, [FromMember] Stock stock, [FromMember] bool? full, [FromMember] int? destination, [FromMiddleware] int session) { stock.Operator = session; var user = await _identityQueryService.GetUser(session); try { JObject jObj = JObject.Parse(stock.Tag); JToken jPostUser = jObj.SelectToken("postUser"); if (jPostUser == null) { jObj.Add("postUser", user.Name); } else { jObj["postUser"] = user.Name; } stock.Tag = JsonConvert.SerializeObject(jObj); } catch { } Failure failure; (string Device, Failure Failure) commandResult; commandResult.Device = ""; switch (operation) { case "palletIn": failure = await _stockCommandService.PalletIn(stock, full, destination); break; case "scanInbound": commandResult = await _stockCommandService.ScanInbound(stock, full, destination); failure = commandResult.Failure; break; case "inbound": failure = await _stockCommandService.Inbound(stock, full, destination); break; case "outbound": failure = await _stockCommandService.Outbound(stock); break; case "update": failure = await _stockCommandService.Update(stock); break; case "combine": failure = await _stockCommandService.Combine(stock, full, destination); break; case "inventory": failure = await _stockCommandService.Inventory(stock); break; case "applyin": //var user = await _identityQueryService.GetUser(session); foreach (var r in stock.Lines) { r.Postuser = user.Name; } commandResult = await _stockCommandService.ApplyIn(stock, full, destination); failure = commandResult.Failure; break; default: return StatusCode(405); } if (failure == null) { return StatusCode(201, commandResult.Device); } else { return StatusCode(422, failure); } } /// /// 获取安全库存列表 /// /// 成功 [HttpGet("safeties")] [ProducesResponseType(200)] public async Task GetSafetyList( [FromQuery] string type, [FromQuery] int[] warehouse, [FromQuery] int[] category, [FromQuery] string code, [FromQuery] string name, [FromQuery] string sort, [FromQuery] int? offset, [FromQuery] int? limit) { if (warehouse.Length == 0) { warehouse = null; } if (category.Length == 0) { category = null; } var items = await _stockQueryService.GetSafetyList(type, warehouse, category, code, name, sort, offset, limit); if (offset.HasValue || limit.HasValue) { var total = await _stockQueryService.GetSafetyCount(type, warehouse, category, code, name); return StatusCode(200, new { items, total }); } else { return StatusCode(200, new { items, total = items.Count() }); } } /// /// 导出安全库存列表 /// /// 成功 [HttpGet("safeties/excel")] [ProducesResponseType(200)] public async Task ExportSafety( [FromQuery] string type, [FromQuery] int[] warehouse, [FromQuery] int[] category, [FromQuery] string code, [FromQuery] string name) { if (warehouse.Length == 0) { warehouse = null; } if (category.Length == 0) { category = null; } using var package = new ExcelPackage(); var worksheet = package.Workbook.Worksheets.Add("Sheet1"); var column = 0; worksheet.Cells[1, ++column].Value = "物料号"; worksheet.Cells[1, ++column].Value = "物料名"; worksheet.Cells[1, ++column].Value = "规格型号"; worksheet.Cells[1, ++column].Value = "数量"; worksheet.Cells[1, ++column].Value = "单位"; worksheet.Cells[1, ++column].Value = "安全库存"; var warehouseName = (await _warehouseQueryService.GetWarehouseList(null, null, null)).ToDictionary(w => w.Id.ToString(), w => w.Name); var index = 1; foreach (var item in await _stockQueryService.GetSafetyList(type, warehouse, category, code, name, null, null, null)) { index++; column = 0; worksheet.Cells[index, ++column].Value = item.Code; worksheet.Cells[index, ++column].Value = item.Name; worksheet.Cells[index, ++column].Value = item.Model; worksheet.Cells[index, ++column].Value = item.Quantity; worksheet.Cells[index, ++column].Value = item.Unit; worksheet.Cells[index, ++column].Value = $"{item.LowerLimit} ~ {item.UpperLimit} ( {string.Join(" + ", item.Warehouse.Split(',').Select(i => warehouseName.ContainsKey(i) ? warehouseName[i] : "?"))} )"; } return File(package.GetAsByteArray(), "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); } /////////////////////////////////////////////////////// /// /// 获取批次码列表 /// /// 成功 [HttpGet("batch")] [ProducesResponseType(200)] public async Task GetBatchList([FromQuery] int? material) { var items = await _stockQueryService.GetBatchList(material); return StatusCode(200, new { items }); } /// /// 冻结 /// /// 成功 /// 非法操作 /// 请求内容错误 [HttpPost("setQcStatus")] [ProducesResponseType(201)] [ProducesResponseType(405)] [ProducesResponseType(422)] public async Task SetQcStatus( [FromMember] string operation, [FromMember] int? code, [FromMember] string batch, [FromMember] DateTime? mfgFrom, [FromMember] DateTime? mfgTo, [FromMember] DateTime? inboundTimeFrom, [FromMember] DateTime? inboundTimeTo, [FromMember] string barcode, [FromMember] string supplier, [FromMember] string[] barcodes, [FromMiddleware] int session) { Failure failure; (int barcodeCount, Failure Failure) commandResult; commandResult.barcodeCount = 0; commandResult = await _stockCommandService.SetQcStatus(session, operation, code, batch, mfgFrom, mfgTo, inboundTimeFrom, inboundTimeTo, barcode, supplier, barcodes); failure = commandResult.Failure; if (failure == null) { return StatusCode(201, commandResult.barcodeCount); } else { return StatusCode(422, failure); } } } }