using AutoMapper; using Kean.Domain; using Kean.Domain.Stock.Models; using Kean.Infrastructure.Database; using Kean.Infrastructure.Database.Repository.Default; using Kean.Infrastructure.Database.Repository.Default.Entities; using Kean.Infrastructure.Database.Repository.Default.Entities.Interface; using Newtonsoft.Json.Linq; using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Reflection; using System.Threading.Tasks; namespace Kean.Infrastructure.Repository { /// /// 存储仓库 /// public class StockRepository : Domain.Stock.Repositories.IStockRepository //Domain.Task.Repositories.IStockRepository { private readonly IMapper _mapper; // 模型映射 private readonly IDefaultDb _database; // 默认数据库 /// /// 依赖注入 /// public StockRepository( IMapper mapper, IDefaultDb database) { _mapper = mapper; _database = database; } /* * 实现 Kean.Domain.Stock.Repositories.IStockRepository.GetBarcode 方法 */ public async Task GetBarcode(int cell) { return (await _database.From() .Where(s => s.CELL_ID == cell) .Single(s => new { s.STOCK_BARCODE }))?.STOCK_BARCODE; } /* * 实现 Kean.Domain.Stock.Repositories.IStockRepository.GetCell 方法 */ public async Task GetCell(string barcode) { return (await _database.From() .Where(s => s.STOCK_BARCODE == barcode) .Single(s => new { s.CELL_ID }))?.CELL_ID; } /* * 实现 Kean.Domain.Stock.Repositories.IStockRepository.GetSpec 方法 */ public async Task GetSpec(string barcode) { return (await _database.From() .Where(s => s.STOCK_BARCODE == barcode) .Single(s => new { s.STOCK_SPEC }))?.STOCK_SPEC; } /* * 实现 Kean.Domain.Stock.Repositories.IStockRepository.GetStock 方法 */ public async Task GetStock(string barcode) { var storageMain = await _database.From() .Where(s => s.STOCK_BARCODE == barcode) .Single(); if (storageMain == null) { return null; } var stock = _mapper.Map(storageMain); stock.Lines = _mapper.Map>(await _database.From() .Where(s => s.STORAGE_ID == storageMain.STORAGE_ID) .Select()); return stock; } /* * 实现 Kean.Domain.Stock.Repositories.IStockRepository.GetLines 方法 */ public async Task> GetLines(string barcode) { var query = _database.From() .Where(s => s.STOCK_BARCODE == barcode) .Query(s => s.STORAGE_ID); return _mapper.Map>(await _database.From() .Where(s => query.Contains(s.STORAGE_ID)) .Select()); } /* * 实现 Kean.Domain.Stock.Repositories.IStockRepository.CreateStock 方法 */ public async Task CreateStock(Stock stock) { var timestamp = DateTime.Now; int? id = (await _database.From() .Where(s => s.STOCK_BARCODE == stock.Barcode) .Single(s => new { s.STORAGE_ID }))? .STORAGE_ID; if (!id.HasValue) { var storageMain = _mapper.Map(stock); storageMain.CREATE_TIME = timestamp; storageMain.UPDATE_TIME = timestamp; id = Convert.ToInt32(await _database.From().Add(storageMain)); } if (stock.Lines != null) { foreach (var item in stock.Lines) { if (item.Quantity <= 0) { throw new RepositoryException("入库数量必须表达为正数", new(nameof(item.Quantity), item.Quantity)); } var storageList = _mapper.Map(item); if (storageList.STORAGE_LIST_ID == 0) { storageList.STORAGE_ID = id.Value; storageList.INBOUND_TIME = item.InboundTime == default ? (item.InboundTime = stock.Timestamp) : item.InboundTime; storageList.INVENTORY_TIME = stock.Timestamp; storageList.CREATE_TIME = timestamp; storageList.UPDATE_TIME = timestamp; item.Id = Convert.ToInt32(await _database.From().Add(storageList)); item.InventoryAge = 1 + (int)timestamp.Subtract(item.InboundTime).TotalDays; if (item.ManufacturingDate.HasValue) { item.MaterialAge = 1 + (int)timestamp.Subtract(item.ManufacturingDate.Value).TotalDays; } } else { var existence = await _database.From() .Where(s => s.STORAGE_LIST_ID == storageList.STORAGE_LIST_ID && s.STORAGE_ID == id.Value) .Single(); if (existence == null) { throw new RepositoryException("找不到库存行记录", new(nameof(item.Id), item.Id)); } var quantity = item.Quantity; _mapper.Map(existence, item).Quantity = quantity; existence.STORAGE_LIST_QUANTITY += storageList.STORAGE_LIST_QUANTITY; existence.INVENTORY_TIME = stock.Timestamp; existence.UPDATE_TIME = timestamp; await _database.From().Update(existence); } } } } /* * 实现 Kean.Domain.Stock.Repositories.IStockRepository.DeleteStock 方法 */ public async Task DeleteStock(Stock stock) { var timestamp = DateTime.Now; if (stock.Lines == null) { int? storageid = (await _database.From() .Where(r => r.STOCK_BARCODE == stock.Barcode) .Single())?.STORAGE_ID; await _database.From() .Where(s => s.STORAGE_ID == storageid) .Delete(); await _database.From() .Where(s => s.STOCK_BARCODE == stock.Barcode) .Delete(); } else { foreach (var item in stock.Lines) { if (item.Quantity >= 0) { throw new RepositoryException("出库数量必须表达为负数", new(nameof(item.Quantity), item.Quantity)); } var existence = await _database.From() .Where(s => s.STORAGE_LIST_ID == item.Id) .Single(); if (existence == null) { throw new RepositoryException("找不到库存行记录", new(nameof(item.Id), item.Id)); } if ((existence.STORAGE_LIST_QUANTITY += item.Quantity) < 0) { throw new RepositoryException("出库数量大于库存数量", new(nameof(item.Quantity), item.Quantity)); } var quantity = item.Quantity; _mapper.Map(existence, item).Quantity = quantity; if (existence.STORAGE_LIST_QUANTITY == 0) { await _database.From() .Delete(existence); } else { existence.INVENTORY_TIME = stock.Timestamp; existence.UPDATE_TIME = timestamp; await _database.From().Update(existence); } } if ((await _database.From() .Join(Join.Inner, (m, l) => m.STORAGE_ID == l.STORAGE_ID) .Where((m, l) => m.STOCK_BARCODE == stock.Barcode) .Single((m, l) => new { Count = Function.Count(l.STORAGE_LIST_ID) })) .Count == 0) { await _database.From() .Where(s => s.STOCK_BARCODE == stock.Barcode) .Delete(); } else { await _database.From() .Where(s => s.STOCK_BARCODE == stock.Barcode) .Update(new { FULL_FLAG = false, UPDATE_TIME = timestamp }); } } } /* * 实现 Kean.Domain.Stock.Repositories.IStockRepository.UpdateStock 方法 */ public async Task UpdateStock(Stock stock) { var timestamp = DateTime.Now; var properties = new Dictionary(); foreach (var item in stock.Lines) { var existence = await _database.From() .Where(s => s.STORAGE_LIST_ID == item.Id) .Single(); if (existence == null) { throw new RepositoryException("找不到库存行记录", new(nameof(item.Id), item.Id)); } var remark = item.Remark as JObject; var key = remark["property"]?.Value(); if (!properties.ContainsKey(key)) { if (!string.IsNullOrEmpty(key) && (_mapper.ConfigurationProvider as global::AutoMapper.Internal.IGlobalConfiguration)? .FindTypeMapFor()?.PropertyMaps .FirstOrDefault(p => p.DestinationName.Equals(key, StringComparison.OrdinalIgnoreCase))? .CustomMapExpression.Body is MemberExpression expression) { properties.Add(key, ( typeof(T_STORAGE_LIST).GetProperty(expression.Member.Name), typeof(StockLine).GetProperty(key, BindingFlags.Public | BindingFlags.IgnoreCase | BindingFlags.Instance)) ); } else { throw new RepositoryException("找不到属性", new(nameof(item.Remark), item.Remark)); } } var (entity, model) = properties[key]; var oldValue = entity.GetValue(existence); var newValue = model.GetValue(item); if (newValue?.Equals(oldValue) == true) { var message = remark["message"]?.Value(); if (!string.IsNullOrEmpty(message)) { existence.STORAGE_LIST_REMARK = message; existence.UPDATE_TIME = timestamp; await _database.From().Update(existence); } item.Id = -item.Id; } else { entity.SetValue(existence, newValue); existence.INVENTORY_TIME = stock.Timestamp; existence.STORAGE_LIST_REMARK += remark["message"]?.Value(); existence.UPDATE_TIME = timestamp; await _database.From().Update(existence); _mapper.Map(existence, item); remark["@property"] = entity.Name; remark["@value"] = JToken.FromObject(oldValue); remark["@message"] = remark["message"]; } } } /* * 实现 Kean.Domain.Stock.Repositories.IStockRepository.SplitStock 方法 */ public async Task> SplitStock(IEnumerable lines) { var stock = new Dictionary(); foreach (var item in lines) { var existence = await _database.From() .Where(s => s.STORAGE_LIST_ID == item.Id) .Single(); if (existence == null) { throw new RepositoryException("找不到库存行记录", new(nameof(item.Id), item.Id)); } if (!stock.ContainsKey(existence.STORAGE_ID)) { stock.Add(existence.STORAGE_ID, _mapper.Map(await _database.From() .Where(s => s.STORAGE_ID == existence.STORAGE_ID) .Single())); stock[existence.STORAGE_ID].Lines = new List(); } var quantity = item.Quantity; _mapper.Map(existence, item).Quantity = quantity; (stock[existence.STORAGE_ID].Lines as List).Add(item); } return stock.Values; } /* * 实现 Kean.Domain.Stock.Repositories.IStockRepository.TakeStock 方法 */ public async Task> TakeStock(IEnumerable lines) { var dictionary = lines.ToDictionary(l => l.Id, l => l); foreach (var item in await _database.From() .Where(l => dictionary.Keys.Contains(l.STORAGE_LIST_ID)) .Select()) { var quantity = dictionary[item.STORAGE_LIST_ID].Quantity; _mapper.Map(item, dictionary[item.STORAGE_LIST_ID]).Quantity = quantity - item.STORAGE_LIST_QUANTITY; } return lines; } /* * 实现 Kean.Domain.Stock.Repositories.IStockRepository.TransferStock 方法 */ public async Task TransferStock(string barcode, int? spec, int destination) { await _database.From() .Where(s => s.STOCK_BARCODE == barcode) .Update(spec.HasValue ? new { APPLYIN_LANEWAY = 0, STOCK_SPEC = spec, CELL_ID = destination, UPDATE_TIME = DateTime.Now } : new { APPLYIN_LANEWAY = 0, CELL_ID = destination, UPDATE_TIME = DateTime.Now }); } /////////////////////////////////////////// /* * 实现 Kean.Domain.Stock.Repositories.IStockRepository.GetCell 方法 */ public async Task ChooseStorageCell( int destination, int goodsid, bool bEnable, string isLocal, string materialType,// ok-正常物料0(合格) check-验证物料1(待检) ng-N G物料2(不合格) string workOrderNo, string qualityState, string productDate) //N-不合格 Q-待检 Y-合格 M-免检 { var goodType = await _database.From().Where(r => r.GOODS_ID == goodsid).Single(); var stationsQuery = _database.From() .Where(r => r.CELL_TYPE == "Station" && r.CELL_OUT == true && r.AREA_ID == destination) .Query(r => r.CELL_ID); var laneway = _database.From() .Where(r => stationsQuery.Contains(r.END_DEVICE) && r.CONTROL_ROUTE_STATUS == 1 && r.CONTROL_ROUTE_TYPE == 2) .Query(r => r.START_DEVICE); var schema = _database.From() .Where(r => r.CELL_TYPE == nameof(Domain.Task.Models.Cell) && r.RUN_STATUS == nameof(Domain.Task.Enums.CellState.Enabled) && laneway.Contains(r.CELL_LANEWAY) && (r.STORAGE_LIST_FLAG == bEnable) //&& (r.GOODS_SUPPLIER != "unupload" || r.GOODS_SUPPLIER == null) //&& !manage.Contains(r.STOCK_BARCODE) ); if (!string.IsNullOrEmpty(materialType)) { schema.Where(r => r.GOODS_QC_STATE == materialType); } if (!string.IsNullOrEmpty(materialType) && materialType != "ng" && materialType != "check" && goodType.TYPE_ID != "4") { schema.Where(r=> r.GOODS_MFG >= DateTime.Now.AddDays(-7)); } //@=@ 固定值 排除空托盘5,9 if (!string.IsNullOrEmpty(isLocal) && goodType.TYPE_ID != "4") { schema.Where(r => r.IS_LOCAL == isLocal); } if (goodsid > 0) { schema.Where(r => r.GOODS_ID == goodsid); } if (!string.IsNullOrEmpty(workOrderNo)) { schema.Where(r => r.WORKORDER_NO == workOrderNo); } if (!string.IsNullOrEmpty(qualityState)) { schema.Where(r => r.IS_AGV == qualityState); } if (!string.IsNullOrEmpty(productDate)) { schema.Where(r => r.GOODS_MFG == Convert.ToDateTime(productDate)); } //if (goodsid == 5 || goodsid == 9 || goodsid == 57 || goodsid == 58 || goodsid == 60 || goodsid == 61 || goodsid == 62) if(goodType.TYPE_ID == "4") { schema = schema .OrderBy(r => r.CELL_DEEP, Order.Descending) .OrderBy(r => r.outerStatus, Order.Ascending) .OrderBy(r => r.INBOUND_TIME, Order.Ascending); } else { schema = schema .OrderBy(r => r.GOODS_MFG, Order.Ascending) .OrderBy(r => r.INBOUND_TIME, Order.Ascending); } var cell = await schema.Select(); int? result = null; //if (goodsid == 5 || goodsid == 9 || goodsid == 57 || goodsid == 58 || goodsid == 60 || goodsid == 61 || goodsid == 62) if (goodType.TYPE_ID == "4") { var lanewayRoute = (await _database.From() .Where(r => stationsQuery.Contains(r.END_DEVICE) && r.CONTROL_ROUTE_STATUS == 1 && r.CONTROL_ROUTE_TYPE == 2) .Select()) .Select(r => new { CELL_LANEWAY = Convert.ToInt32(r.START_DEVICE) }); var lanewayManageCount = (await _database.From() .Where(r => r.MANAGE_TYPE_CODE == "PalletOut") .Select()) .GroupBy(r => r.LANEWAY).Select(r => new { CELL_LANEWAY = r.Key, LANEWAY_MANAGE_COUNT = r.Count() }); List lsLaneway = new List(); foreach (var m in lanewayRoute) { int cell_laneway = m.CELL_LANEWAY; int laneway_manage_count = 0; var mc = lanewayManageCount.Where(r => r.CELL_LANEWAY == m.CELL_LANEWAY); if (mc.Count() > 0) { laneway_manage_count = mc.First().LANEWAY_MANAGE_COUNT; } lsLaneway.Add(new { CELL_LANEWAY = cell_laneway, LANEWAY_MANAGE_COUNT = laneway_manage_count }); } var query = from t in lsLaneway orderby t.LANEWAY_MANAGE_COUNT select t; foreach (var m in query) { foreach (var row in cell.Where(r => r.CELL_LANEWAY == m.CELL_LANEWAY && (r.CELL_DEEP > 0 || r.CELL_DEEP == 0 && r.outerStatus != "Full"))) { return result = row.CELL_ID; } } } foreach (var row in cell) { var differentList = await _database.From() .Where(r => r.STORAGE_ID == row.STORAGE_ID && r.GOODS_QC_STATE != row.GOODS_QC_STATE) .Single(); if (differentList == null) { return result = row.CELL_ID; } } return result; } /* * 实现 Kean.Domain.Stock.Repositories.IStockRepository.GetStorageMaterial 方法 */ public async Task GetStorageMaterial(string barcode) { var cell = await _database.From() .Where(r => r.STOCK_BARCODE == barcode) .Single(); return cell?.GOODS_ID; } /* * 实现 Kean.Domain.Stock.Repositories.IStockRepository.GetStorageBill 方法 */ public async Task GetStorageBill(string bill) { var storageList =await _database.From() .Where(r => r.GOODS_BILL_NO == bill) .Select(); if (storageList == null || storageList.Count() ==0) { return null; } int storageId = storageList.First().STORAGE_ID; var storageMain = await _database.From() .Where(s => s.STORAGE_ID == storageId) .Single(); if (storageMain == null) { return null; } var stock = _mapper.Map(storageMain); stock.Lines = _mapper.Map>(storageList); return stock; } /* * 实现 Kean.Domain.Stock.Repositories.IStockRepository.GetStorageUnupload 方法 */ public async Task GetStorageUnupload(string barcode) { var storageMain = await _database.From() .Where(s => s.STOCK_BARCODE == barcode) .Single(); if (storageMain == null) { return null; } var stock = _mapper.Map(storageMain); stock.Lines = _mapper.Map>(await _database.From() .Where(s => s.STORAGE_ID == storageMain.STORAGE_ID && s.GOODS_SUPPLIER == "unupload") .Select()); return stock; } /* * 实现 Kean.Domain.Stock.Repositories.IStockRepository.GetStorageLinesNum 方法 */ public async Task GetStorageLinesNum(int? cellId) { if (!cellId.HasValue) { return 0; } var storageList = await _database.From() .Where(s => s.CELL_ID == cellId) .Select(); if (storageList == null) { return 0; } return storageList.Count(); } /* * 实现 Kean.Domain.Stock.Repositories.IStockRepository.GetQcBarcode 方法 */ public async Task> GetQcBarcode( int? goodsCode, string batch, DateTime? manufacturingDateFrom, DateTime? manufacturingDateTo, DateTime? inboundTimeFrom, DateTime? inboundTimeTo, string barcode, string remark, bool enable) { var schema = _database.From(); if (goodsCode.HasValue) { schema = schema.Where(r => r.GOODS_ID == goodsCode); } if (batch != null) { schema = schema.Where(r => r.GOODS_BATCH_NO == batch); } if (manufacturingDateFrom.HasValue) { schema = schema.Where(r => r.GOODS_MFG >= manufacturingDateFrom.Value); } if (manufacturingDateTo.HasValue) { schema = schema.Where(r => r.GOODS_MFG <= manufacturingDateTo.Value.AddDays(1)); } if (inboundTimeFrom.HasValue) { schema = schema.Where(r => r.INBOUND_TIME >= inboundTimeFrom.Value); } if (inboundTimeTo.HasValue) { schema = schema.Where(r => r.INBOUND_TIME <= inboundTimeTo.Value.AddDays(1)); } if (barcode != null) { schema = schema.Where(r => r.STOCK_BARCODE == barcode); } if (enable && remark != null) { schema = schema.Where(r => r.STORAGE_LIST_REMARK.Contains(remark)); } return _mapper.Map>(await schema.Distinct().Select()); } ///* // * 实现 Kean.Domain.Stock.Repositories.IStockRepository.UpdateIsAgv 方法 // */ //public async Task UpdateIsAgv(string bill, string isAgv) //{ // var driver = Infrastructure.Database.Configuration.Configure("Default"); // using (var context = driver.CreateContext()) // { // await context.From() // .Where(r => r.GOODS_BILL_NO == bill) // .Update(new // { // IS_AGV = isAgv, // UPDATE_TIME = DateTime.Now // }); // } //} /* * 实现 Kean.Domain.Stock.Repositories.IStockRepository.UpdateStorageProperty 方法 */ public async Task UpdateStorageProperty(StockLine stockLine) { var storageList = await _database.From() .Where(r => r.GOODS_BILL_NO == stockLine.Bill) .Select(); if (storageList == null || storageList.Count() == 0) { return; } var entity = _mapper.Map(stockLine); entity.STORAGE_ID = storageList.First().STORAGE_ID; entity.UPDATE_TIME = DateTime.Now; await _database.From().Update(entity, nameof(T_GOODS_SAFETY.CREATE_TIME)); } /* * 实现 Kean.Domain.Stock.Repositories.IStockRepository.CleanTag 方法 */ public async Task CleanTag(string barcode) { await _database.From() .Where(s => s.STOCK_BARCODE == barcode) .Update( new { TAG = "" }); } /* * 实现 Kean.Domain.Stock.Repositories.IStockRepository.GetErrFeedback 方法 */ public async Task GetErrFeedback(int id) { var errFeedback = await _database.From() .Where(s => s.ID == id) .Single(); if (errFeedback == null) { return null; } return _mapper.Map(errFeedback); } /* * 实现 Kean.Domain.Stock.Repositories.IStockRepository.IsPallet 方法 */ public async Task IsPallet(int goodsid) { return (await _database.From() .Join(Join.Inner, (m, c) => m.CLASS_ID == c.CLASS_ID) .Where((m, c) => c.CLASS_FLAG == true && m.GOODS_ID == goodsid && c.CLASS_PARENT_ID == 4) .Single((m, c) => new { Count = Function.Count(c.CLASS_ID) })).Count > 0; } } }