using Admin.NET.Core.Service; using Admin.NET.Application.Entity; using Microsoft.AspNetCore.Http; using AngleSharp.Dom; using Admin.NET.Application; using static SKIT.FlurlHttpClient.Wechat.Api.Models.ProductOrderGetResponse.Types.Order.Types; using System.Web; using System.Data; using System.Text; using Admin.NET.Core.Helper.ExcelHelper; using Admin.NET.Application.CommonHelper; using System.Net.Mail; namespace Admin.NET.Application; /// /// ASN主表服务 /// [ApiDescriptionSettings(ApplicationConst.WmsOrderGroupName, Order = 100)] public class WmsOrderAsnService : IDynamicApiController, ITransient { private readonly SqlSugarRepository _rep; private readonly SqlSugarRepository _WmsOrderAsnDetailsRep; private readonly SqlSugarRepository _BaseCustomerRep; private readonly SqlSugarRepository _purchaseOrderDetailsRep; private readonly SqlSugarRepository _WmsOrderPurchaseRep; private readonly SqlSugarRepository _wmsMaterialRep; private readonly SqlSugarRepository _WmsBaseBusinessTypeRep; private readonly SysConfigService _sysConfigService; private readonly SqlSugarRepository _repRuleDetailRep; private readonly SqlSugarRepository _repSNRep; private readonly SqlSugarRepository _WmsNoCreateRuleRep; private readonly SqlSugarRepository _wareActionLogRep; public WmsOrderAsnService(SqlSugarRepository rep, SqlSugarRepository baseCustomerRep, SqlSugarRepository wmsOrderAsnDetailsRep, SqlSugarRepository purchaseOrderDetailsRep, SqlSugarRepository wmsOrderPurchaseRep , SqlSugarRepository wmsMaterialRep , SqlSugarRepository WmsBaseBusinessType, SysConfigService sysConfigService, SqlSugarRepository repSNRep, SqlSugarRepository repRuleDetailRep , SqlSugarRepository wmsNoCreateRuleRep , SqlSugarRepository wareActionLogRep ) { _rep = rep; _BaseCustomerRep = baseCustomerRep; _WmsOrderAsnDetailsRep = wmsOrderAsnDetailsRep; _purchaseOrderDetailsRep = purchaseOrderDetailsRep; _WmsOrderPurchaseRep = wmsOrderPurchaseRep; _wmsMaterialRep = wmsMaterialRep; _WmsBaseBusinessTypeRep = WmsBaseBusinessType; _sysConfigService = sysConfigService; _repSNRep = repSNRep; _repRuleDetailRep = repRuleDetailRep; _WmsNoCreateRuleRep = wmsNoCreateRuleRep; _wareActionLogRep = wareActionLogRep; } /// /// 分页查询ASN主表 /// /// /// [HttpPost] [ApiDescriptionSettings(Name = "Page")] [Description("WmsOrderAsn/Page")] public async Task> Page(WmsOrderAsnInput input) { var query = CommonPageFilter(input); return await query .OrderBy(x => x.AsnStatus).OrderByDescending(x => x.CreateTime) //.OrderBuilder(input) .ToPagedListAsync(input.Page, input.PageSize); } /// /// 不分页查询ASN主表 /// /// /// [HttpGet] [ApiDescriptionSettings(Name = "List")] [Description("WmsOrderAsn/List")] public async Task> List([FromQuery] WmsOrderAsnInput input) { var query = CommonPageFilter(input); return await query.OrderBuilder(input).Select().ToListAsync(); } /// /// 增加ASN主表 /// /// /// [HttpPost] [ApiDescriptionSettings(Name = "Add")] [Description("WmsOrderAsn/Add")] public async Task Add(DiyAddWmsOrderAsnInput input) { if (input.orderDetails is null || input.orderDetails.Count == 0) { throw Oops.Oh("明细不能为空"); } var hearId = await AddOrderEFsql(input); return hearId; } private async Task AddOrderEFsql(DiyAddWmsOrderAsnInput input) { //新增表头 var warehousOrder = input.Adapt(); var hearId = Yitter.IdGenerator.YitIdHelper.NextId(); warehousOrder.Id = hearId; //创建ASN单 单据类型 默认是ASN单 update by liuwq 2024-05-23 warehousOrder.AsnTypeName = OrderTypeEnum.ASN单.GetDescription(); warehousOrder.AsnType = OrderTypeEnum.ASN单; var BusinessTypeItem = await _WmsBaseBusinessTypeRep.GetFirstAsync(u => u.BusinessTypeValue == input.BusinessType); if (BusinessTypeItem == null) { throw Oops.Oh("业务类型:" + input.BusinessType + "不存在"); } if (BusinessTypeItem.IsDisabled == true) { throw Oops.Oh("业务类型:" + input.BusinessType + "已禁用"); } warehousOrder.BusinessType = BusinessTypeItem.BusinessTypeValue;//对应原来枚举类型的值 warehousOrder.BusinessTypeName = BusinessTypeItem.BusinessTypeName; // 获取当前时间 DateTime currentTime = DateTime.Now; // 格式化为年月日字符串 string formattedDate = currentTime.ToString("yyyyMMdd"); //按照单号规则生成单号 - 查找最新的创建的一条单据记录 var newestOrder = await _rep.AsQueryable().Where(p => p.AsnType == OrderTypeEnum.ASN单).Where(p => p.AsnNo.Contains(formattedDate)).OrderBy(it => it.CreateTime, OrderByType.Desc) .FirstAsync(); //按照单号规则生成单号-ly warehousOrder.AsnNo = await SerialUtilOrder.GetSerialOrder(OrderTypeEnum.ASN单, _WmsNoCreateRuleRep, _repSNRep, warehousOrder.BusinessType, newestOrder == null ? null : newestOrder.AsnNo); if (warehousOrder.AsnNo == null || warehousOrder.AsnNo == "") { warehousOrder.AsnNo = await SerialUtil.GetSerial(SerialTypeEnum.ASN单号, _repRuleDetailRep, _repSNRep); } warehousOrder.AsnStatus = OrderStatusEnum.新建; warehousOrder.AsnStatusName = GetEnumDescriptionUtil.GetEnumDescription(OrderStatusEnum.新建); warehousOrder.Quantity = (decimal)input.orderDetails.Sum(x => x.Quantity); warehousOrder.GoodsQuantity = (decimal)input.orderDetails.Sum(x => x.GoodsQuantity); warehousOrder.FactoryId = 1;//TODO 工厂到底用不用?? //新增明细 var warehousOrderDetails1 = input.orderDetails.Adapt>(); //------------------ly-验证物料 + 关联PO单业务 验证po数量是否有剩余物料可用---------------- List queryMaterialCodeList = input.orderDetails.Select(v => v.MaterialCode).Distinct().ToList(); var handMaterialleList = await _wmsMaterialRep.GetListAsync(u => queryMaterialCodeList.Contains(u.MaterialCode) && u.IsDelete == false); await HandleValidDetail(input, handMaterialleList); //------------------ly-验证物料 + 关联PO单业务 ---------------- //----------------验证供应商集合--------------- List queryCustCodeList = input.orderDetails.Select(v => v.SupplierCode).Distinct().ToList(); var handqueryCustCodeList = await _BaseCustomerRep.GetListAsync(u => queryCustCodeList.Contains(u.CustCode) && u.IsDelete == false); //----------------验证供应商集合----------------- int index = 0; foreach (var w in warehousOrderDetails1) { if (w.POQuantity <= 0 || w.POQuantity == null) { throw Oops.Oh("创建失败:数量需要大于0"); } //上面已经验证物料 此处无效再校验了 var materials = handMaterialleList.FirstOrDefault(u => u.MaterialCode == w.MaterialCode); if (materials == null) { throw Oops.Oh("物料:" + w.MaterialCode + "不存在"); } w.Quantity = ((decimal)w.POQuantity * (decimal)materials.TranslateRate); w.TranslateRate = (decimal)materials.TranslateRate; index++; string myLineNumeber = index.ToString(); var idMaterial = Yitter.IdGenerator.YitIdHelper.NextId(); w.Id = idMaterial; w.AsnNo = warehousOrder.AsnNo; w.AsnId = warehousOrder.Id; w.AsnStatus = OrderStatusEnum.新建; w.AsnStatusName = GetEnumDescriptionUtil.GetEnumDescription(OrderStatusEnum.新建); w.ErpOrderNo = w.ErpOrderNo; w.POUnit = materials.POUnit; w.MaterialUnit = materials.MaterialUnit; w.AsnLineNumber = OrderHelper.AutoCompleEBELP(myLineNumeber, 4); if (w.SupplierCode != null) { var Info_BaseCustomer = handqueryCustCodeList.FirstOrDefault(u => u.CustCode == w.SupplierCode); if (Info_BaseCustomer != null) { w.SupplierName = Info_BaseCustomer.CustChinaName; } else { w.SupplierName = w.SupplierName; //物料自带的没有 } } else { throw Oops.Oh(w.MaterialCode + "供应商编号不能为空"); } //ERP库存地必赋值 if (String.IsNullOrEmpty(w.ErpCode)) { var strErpCode = await ErpCodeValidDetail(w); w.ErpCode = strErpCode; } w.IsDelete = false; } try { await _rep.AsTenant().BeginTranAsync(); //插入主表 await _rep.InsertAsync(warehousOrder); //插入明细表 await _WmsOrderAsnDetailsRep.InsertRangeAsync(warehousOrderDetails1); await _rep.AsTenant().CommitTranAsync(); } catch { await _rep.AsTenant().RollbackTranAsync(); throw; } return hearId; } /// /// 验证系统是否配置 ERP库存地 /// /// /// private async Task ErpCodeValidDetail(WmsOrderAsnDetails w) { /* 0806 自建ASN单时,如果用户没有填写ERP库存地,那么新建单子时,系统自动寻找(平台管理-参数配置)系统参数default_erpCode(默认的ERP库存地),写入到ASN单的erp库存地中 **/ var strErpCode =""; if (String.IsNullOrEmpty(w.ErpCode)) { //系统配置 默认的ERP库存地 strErpCode = await _sysConfigService.GetConfigValue(CommonConst.DefaultErpCode); if (String.IsNullOrEmpty(strErpCode)) { throw Oops.Oh("参数配置:默认的ERP库存地[default_erpCode]不存在"); } } return strErpCode; } /// /// ly-0725 验证po单是否还有物料可用 /// /// /// private async Task HandleValidDetail(DiyAddWmsOrderAsnInput input, List handMaterialleList) { //------------验证物料----------- if (handMaterialleList == null || handMaterialleList.Count <= 0) { throw Oops.Oh($"物料不存在!"); } //------------验证物料----------- //------------验证Asn和po----------- List handleListAsn = new List(); List handleListPurchaseDetails = new List(); List queryCodeListForAsn = input.orderDetails.Select(v => v.PoNo).Distinct().ToList(); if (queryCodeListForAsn.Count > 0) { //查询asn中已关联po的数据 handleListAsn = await _WmsOrderAsnDetailsRep.GetListAsync(u => queryCodeListForAsn.Contains(u.PoNo) && u.IsDelete == false); //查询所有相关po的数据 handleListPurchaseDetails = await _purchaseOrderDetailsRep.GetListAsync(u => queryCodeListForAsn.Contains(u.PoNo) && u.IsDelete == false); } //------------验证Asn和po----------- foreach (var item in input.orderDetails) { var materials = handMaterialleList.FirstOrDefault(v => item.MaterialCode == v.MaterialCode); if (materials == null) { throw Oops.Oh("物料:" + item.MaterialCode + "不可用"); } if (materials.TranslateRate == null) { throw Oops.Oh("物料:" + item.MaterialCode + "换算率不能为空"); } if (materials.TranslateRate <= 0) { throw Oops.Oh("物料:" + item.MaterialCode + "换算率不能小于等于0"); } if (materials.POUnit == null) { throw Oops.Oh(item.MaterialCode + "采购单位不可为空"); } if (materials.MaterialUnit == null) { throw Oops.Oh(item.MaterialCode + "库存单位不可为空"); } if (!String.IsNullOrEmpty(item.PoNo)) { //所有PO总数 decimal hasUsedPoQty = handleListPurchaseDetails.Where(x => x.MaterialCode == item.MaterialCode && x.PoLineNumber == item.PoLineNumber && x.PoNo == item.PoNo && (x.PoDetailStatus == OrderStatusEnum.新建 || x.PoDetailStatus == OrderStatusEnum.处理中)).Sum(x => x.Quantity); //所有PO已收 decimal hasUsedPoGoodsQuantity = handleListPurchaseDetails.Where(x => x.MaterialCode == item.MaterialCode && x.PoLineNumber == item.PoLineNumber && x.PoNo == item.PoNo && (x.PoDetailStatus == OrderStatusEnum.新建 || x.PoDetailStatus == OrderStatusEnum.处理中)).Sum(x => x.GoodsQuantity); decimal usedQtyPo = hasUsedPoQty - hasUsedPoGoodsQuantity; //po单中改物料 剩余可用数量: PO总数 - 已收货数 //所有asn中已关联po总数 decimal hasUsedPoQtyInAsn = handleListAsn.Where(x => x.MaterialCode == item.MaterialCode && x.PoLineNumber == item.PoLineNumber && x.PoNo == item.PoNo && (x.AsnStatus == OrderStatusEnum.新建 || x.AsnStatus == OrderStatusEnum.处理中) && x.AsnNo != item.AsnNo).Sum(x => (decimal)x.POQuantity); if (usedQtyPo < hasUsedPoQtyInAsn) //ASN中已关联po总数 { throw Oops.Oh($"创建失败:PO单号{item.PoNo},物料编号{item.MaterialCode},PO行号{item.PoLineNumber}需求数量{item.POQuantity}已全部创建ASN单!"); } decimal usedQtyHasNow = usedQtyPo - hasUsedPoQtyInAsn; if (usedQtyHasNow < item.POQuantity) { throw Oops.Oh($"创建失败:PO单号{item.PoNo},物料编号{item.MaterialCode},DO行号{item.PoLineNumber}在未绑定ASN单中剩余可用数{usedQtyHasNow}不足!"); } //标包物料:出现相同物料 PO号 行号一样的多条数据 decimal? usedQtyAllForPo = input.orderDetails.Where(x => x.MaterialCode == item.MaterialCode && x.PoLineNumber == item.PoLineNumber && x.PoNo == item.PoNo) .Sum(x => (decimal)x.POQuantity); if (usedQtyHasNow < usedQtyAllForPo) { throw Oops.Oh($"创建失败:PO单号{item.PoNo},物料编号{item.MaterialCode},DO行号{item.PoLineNumber}剩余可用数{usedQtyHasNow}不足了!"); } } } } /// /// ly-取消ASN主表 /// /// /// [HttpPost] [ApiDescriptionSettings(Name = "Delete")] [Description("WmsOrderAsn/Delete")] public async Task Delete(DeleteWmsOrderAsnInput input) { var entity = await _rep.GetFirstAsync(u => u.Id == input.Id) ?? throw Oops.Oh(ErrorCodeEnum.D1002); entity.AsnStatus = OrderStatusEnum.已取消; entity.AsnStatusName = GetEnumDescriptionUtil.GetEnumDescription(OrderStatusEnum.已取消); var AsnOrderDetails = await _WmsOrderAsnDetailsRep.AsQueryable() .Where(x => x.AsnId == entity.Id) .Where(u => u.IsDelete == false) .Select() .ToListAsync(); //删明细 List deleteWareAsnOrderDetails = new List(); var deleteList = AsnOrderDetails.Where(x => x.IsDelete == false).ToList(); foreach (var item in deleteList) { if (item.AsnStatus != OrderStatusEnum.新建) { throw Oops.Oh($"物料{item.MaterialCode}的状态{item.AsnStatusName},不允许取消"); } if (item.GoodsQuantity > 0) { throw Oops.Oh($"物料{item.MaterialCode}的已收数量{item.GoodsQuantity}大于0,不允许取消"); } item.AsnStatus = OrderStatusEnum.已取消; item.AsnStatusName = GetEnumDescriptionUtil.GetEnumDescription(OrderStatusEnum.已取消); deleteWareAsnOrderDetails.Add(item); } try { await _rep.AsTenant().BeginTranAsync(); await _rep.UpdateAsync(entity); //更新状态 await _WmsOrderAsnDetailsRep.UpdateRangeAsync(deleteWareAsnOrderDetails); //更新状态 //await _rep.DeleteAsync(entity); //真删除 //await _rep.FakeDeleteAsync(entity); //假删除 //await _WmsOrderAsnDetailsRep.DeleteAsync(deleteWareAsnOrderDetails); await _rep.AsTenant().CommitTranAsync(); } catch { await _rep.AsTenant().RollbackTranAsync(); throw; } } /// /// 更新ASN主表 /// /// /// [HttpPost] [ApiDescriptionSettings(Name = "Update")] [Description("WmsOrderAsn/Update")] public async Task Update(DiyAddWmsOrderAsnInput input) { if (input.orderDetails is null || input.orderDetails.Count == 0) { throw Oops.Oh("明细不能为空"); } var dbOrder = await _rep.GetFirstAsync(w => w.AsnNo == input.AsnNo); if (dbOrder == null) { throw Oops.Oh($"订单{input.AsnNo}不存在"); } //返回包含逻辑删除的明细,用于计算行号 var allAsnOrderDetails = await _WmsOrderAsnDetailsRep.AsQueryable() .Where(x => x.AsnId == dbOrder.Id) .Select() .ToListAsync(); //有效单据明细 var AsnOrderDetails = allAsnOrderDetails.Where(u => u.IsDelete == false).ToList(); //验证数量是否正确 foreach (var item in input.orderDetails) { if (item.Quantity < item.GoodsQuantity) { throw Oops.Oh($"物料{item.MaterialCode}的需求数量{item.Quantity}不能小于已收数量{item.GoodsQuantity}"); } } List addWareAsnOrderDetails = new List(); List updateWareAsnOrderDetails = new List(); List deleteWareAsnOrderDetails = new List(); //------------------ly-验证物料 + 验证关联PO单业务---------------- List queryMaterialCodeList = input.orderDetails.Select(v => v.MaterialCode).Distinct().ToList(); var handMaterialleList = await _wmsMaterialRep.GetListAsync(u => queryMaterialCodeList.Contains(u.MaterialCode) && u.IsDelete == false); await HandleValidDetail(input, handMaterialleList); //------------------ly-验证物料 + 验证关联PO单业务---------------- //----------------验证供应商集合--------------- List queryCustCodeList = input.orderDetails.Select(v => v.SupplierCode).Distinct().ToList(); var handqueryCustCodeList = await _BaseCustomerRep.GetListAsync(u => queryCustCodeList.Contains(u.CustCode) && u.IsDelete == false); //----------------验证供应商集合----------------- //寻找更新的 var updateList = AsnOrderDetails.Where(x => input.orderDetails.Any(p => p.AsnLineNumber == x.AsnLineNumber && p.MaterialCode == x.MaterialCode)).ToList(); foreach (var item in updateList) { if (item.POQuantity <= 0 || item.POQuantity == null) { throw Oops.Oh("创建失败:数量需要大于0"); } //上面已经验证物料 此处无效再校验了 var materials = handMaterialleList.FirstOrDefault(u => u.MaterialCode == item.MaterialCode && u.IsDisabled == false); if (materials == null) { throw Oops.Oh("物料:" + materials.MaterialCode + "不存在"); } var orderDetails = input.orderDetails.FirstOrDefault(x => x.MaterialCode == item.MaterialCode && x.Id == item.Id); if (orderDetails == null) { continue; } else { if (orderDetails.SupplierCode == null) { throw Oops.Oh("供应商编号不能为空"); } item.POQuantity = orderDetails.POQuantity; item.Quantity = ((decimal)orderDetails.POQuantity * (decimal)materials.TranslateRate); item.TranslateRate = (decimal)materials.TranslateRate; item.ProjectNo = orderDetails.ProjectNo; item.SupplierCode = orderDetails.SupplierCode; item.PoLineNumber = orderDetails.PoLineNumber; item.AsnLineNumber = orderDetails.AsnLineNumber; item.PlannedStartTime = orderDetails.PlannedStartTime; item.PlannedEndTime = orderDetails.PlannedEndTime; item.Dock = orderDetails.Dock; item.IsFreeze = orderDetails.IsFreeze; item.FreezeReason = orderDetails.FreezeReason; item.POUnit = materials.POUnit; item.MaterialUnit = materials.MaterialUnit; item.SupplierBatch = orderDetails.SupplierBatch; if (!String.IsNullOrEmpty(orderDetails.ErpCode)) { item.ErpCode = orderDetails.ErpCode; } else { //ERP库存地必赋值 var strErpCode = await ErpCodeValidDetail(item); item.ErpCode = strErpCode; } } if (item.Quantity < item.GoodsQuantity) { throw Oops.Oh($"物料{item.MaterialCode}的采购数量{item.Quantity}不能小于已收数量{item.GoodsQuantity}"); } //变更明细的状态 updateWareAsnOrderDetails.Add(item); } //寻找删除的 var deleteList = AsnOrderDetails.Where(x => !input.orderDetails.Any(p => p.AsnLineNumber == x.AsnLineNumber && p.MaterialCode == x.MaterialCode)).ToList(); foreach (var item in deleteList) { if (item.GoodsQuantity > 0) { throw Oops.Oh($"物料{item.MaterialCode}的已收数量{item.GoodsQuantity}大于0,不允许删除"); } deleteWareAsnOrderDetails.Add(item); } //寻找新增的 .Adapt>() var addList = input.orderDetails.Where(x => !AsnOrderDetails.Any(p => p.AsnLineNumber == x.AsnLineNumber && p.MaterialCode == x.MaterialCode)).ToList(); //获取最大行号 var maxAsnLineNumber = allAsnOrderDetails.Max(u => u.AsnLineNumber); int index = Convert.ToInt32(maxAsnLineNumber); foreach (var w in addList) { if (w.POQuantity == 0 || w.POQuantity == null) { throw Oops.Oh("创建失败:数量需要大于0"); } //上面已经验证物料 此处无效再校验了 var materials = handMaterialleList.FirstOrDefault(u => u.MaterialCode == w.MaterialCode && u.IsDisabled == false); if (materials == null) { throw Oops.Oh("物料:" + materials.MaterialCode + "不存在"); } if (w.SupplierCode == null) { throw Oops.Oh("供应商编号不能为空!"); } var Info_BaseCustomer = handqueryCustCodeList.FirstOrDefault(u => u.CustCode == w.SupplierCode); if (Info_BaseCustomer == null) { throw Oops.Oh("供应商不存在!"); } var idMaterial = Yitter.IdGenerator.YitIdHelper.NextId(); index++;//行号递增 var newLineNumber = OrderHelper.AutoCompleEBELP(index.ToString(), 4); if (String.IsNullOrEmpty(w.ErpCode)) { w.ErpCode = await ErpCodeValidDetail(w.Adapt()); //ERP库存地必赋值 } WmsOrderAsnDetails item = new WmsOrderAsnDetails() { Id = idMaterial, AsnStatus = OrderStatusEnum.新建, AsnStatusName = GetEnumDescriptionUtil.GetEnumDescription(OrderStatusEnum.新建), AsnNo = dbOrder.AsnNo, AsnId = dbOrder.Id, //PoId = w.PoId, PoNo = w.PoNo, PoLineNumber = w.PoLineNumber, AsnLineNumber = newLineNumber,//新增明细赋值行号 MaterialCode = w.MaterialCode, MaterialName = w.MaterialName, PlannedStartTime = w.PlannedStartTime, PlannedEndTime = w.PlannedEndTime, IsDelete = false, ProjectNo = input.ProjectNo, SupplierCode = w.SupplierCode, SupplierName = Info_BaseCustomer.CustChinaName, Dock = w.Dock, IsFreeze = w.IsFreeze, FreezeReason = w.FreezeReason, POUnit = materials.POUnit, MaterialUnit = materials.MaterialUnit, POQuantity = (decimal)w.POQuantity, Quantity = ((decimal)w.POQuantity * (decimal)materials.TranslateRate), TranslateRate = (decimal)materials.TranslateRate, ErpCode = w.ErpCode //ERP库存地必赋值 }; addWareAsnOrderDetails.Add(item); } try { await _rep.AsTenant().BeginTranAsync(); await _rep.UpdateAsync(dbOrder); if (addWareAsnOrderDetails.Count > 0) { await _WmsOrderAsnDetailsRep.InsertRangeAsync(addWareAsnOrderDetails); } if (updateWareAsnOrderDetails.Count > 0) { await _WmsOrderAsnDetailsRep.UpdateRangeAsync(updateWareAsnOrderDetails); } if (deleteWareAsnOrderDetails.Count > 0) { await _WmsOrderAsnDetailsRep.DeleteAsync(deleteWareAsnOrderDetails); } await _rep.AsTenant().CommitTranAsync(); } catch { await _rep.AsTenant().RollbackTranAsync(); throw; } } /// /// 获取ASN主表 /// /// /// [HttpGet] [ApiDescriptionSettings(Name = "Detail")] [Description("WmsOrderAsn/Detail")] public async Task Detail([FromQuery] QueryByIdWmsOrderAsnInput input) { return await _rep.GetFirstAsync(u => u.Id == input.Id); } /// /// 关闭Asn单-ly0708 /// /// /// [HttpPost] [ApiDescriptionSettings(Name = "CloseOrder")] [Description("WmsOrderAsn/CloseOrder")] public async Task CloseOrder(DeleteWmsOrderAsnDetailsInput input) { var entity = await _rep.GetFirstAsync(u => u.Id == input.Id) ?? throw Oops.Oh(ErrorCodeEnum.D1002); if (entity.AsnStatus == OrderStatusEnum.已完成 || entity.AsnStatus == OrderStatusEnum.已取消) { throw Oops.Oh($"单据状态{entity.AsnStatusName},不允许操作!"); } entity.AsnStatus = OrderStatusEnum.已关闭; entity.AsnStatusName = GetEnumDescriptionUtil.GetEnumDescription(OrderStatusEnum.已关闭); var OrderDetails = await _WmsOrderAsnDetailsRep.AsQueryable() .Where(x => x.AsnId == entity.Id) .Where(u => u.IsDelete == false) .Select() .ToListAsync(); //关闭明细 List deleteWareOrderDetails = new List(); var deleteList = OrderDetails.Where(x => x.IsDelete == false).ToList(); foreach (var item in deleteList) { item.AsnStatus = OrderStatusEnum.已关闭; item.AsnStatusName = GetEnumDescriptionUtil.GetEnumDescription(OrderStatusEnum.已关闭); deleteWareOrderDetails.Add(item); } // ----------------记录操作日志 List addWareActionLogList = new List(); string actionTitle = $"{OrderTypeEnum.ASN单}{entity.AsnNo}{GetEnumDescriptionUtil.GetEnumDescription(OrderStatusEnum.已关闭)}";//操作履历标题 var idWmsLogAction = Yitter.IdGenerator.YitIdHelper.NextId(); WmsLogAction wareActionLog = LogActionHelper.CreateWmsLogAction(idWmsLogAction, actionTitle); addWareActionLogList.Add(wareActionLog); // ----------------记录操作日志 try { await _rep.AsTenant().BeginTranAsync(); await _rep.UpdateAsync(entity); //更新状态 await _WmsOrderAsnDetailsRep.UpdateRangeAsync(deleteWareOrderDetails); //更新状态 await _wareActionLogRep.InsertRangeAsync(addWareActionLogList); //操作日志 await _rep.AsTenant().CommitTranAsync(); } catch { await _rep.AsTenant().RollbackTranAsync(); throw; } } #region 私有方法 /// /// 公共查询ASN主表条件 /// /// /// private ISugarQueryable CommonPageFilter(WmsOrderAsnInput input) { var query = _rep.AsQueryable() .WhereIF(!string.IsNullOrWhiteSpace(input.SearchKey), u => u.AsnNo.Contains(input.SearchKey.Trim()) || u.AsnTypeName.Contains(input.SearchKey.Trim()) || u.BusinessTypeName.Contains(input.SearchKey.Trim()) || u.AsnStatusName.Contains(input.SearchKey.Trim()) || u.TrackingNumber.Contains(input.SearchKey.Trim()) || u.ReleaseStatusName.Contains(input.SearchKey.Trim()) || u.FactoryName.Contains(input.SearchKey.Trim()) || u.FactoryCode.Contains(input.SearchKey.Trim()) ) .WhereIF(!string.IsNullOrWhiteSpace(input.AsnNo), u => u.AsnNo.Contains(input.AsnNo.Trim())) .WhereIF(input.AsnType.HasValue, u => u.AsnType == input.AsnType) .WhereIF(!string.IsNullOrWhiteSpace(input.AsnTypeName), u => u.AsnTypeName.Contains(input.AsnTypeName.Trim())) .WhereIF(input.BusinessType.HasValue, u => u.BusinessType == input.BusinessType) .WhereIF(!string.IsNullOrWhiteSpace(input.BusinessTypeName), u => u.BusinessTypeName.Contains(input.BusinessTypeName.Trim())) .WhereIF(input.AsnStatus.HasValue, u => u.AsnStatus == input.AsnStatus) .WhereIF(!string.IsNullOrWhiteSpace(input.AsnStatusName), u => u.AsnStatusName.Contains(input.AsnStatusName.Trim())) .WhereIF(!string.IsNullOrWhiteSpace(input.TrackingNumber), u => u.TrackingNumber.Contains(input.TrackingNumber.Trim())) .WhereIF(input.ReleaseStatus > 0, u => u.ReleaseStatus == input.ReleaseStatus) .WhereIF(!string.IsNullOrWhiteSpace(input.ReleaseStatusName), u => u.ReleaseStatusName.Contains(input.ReleaseStatusName.Trim())) //.WhereIF(input.IsFreeze.HasValue, u => u.IsFreeze == input.IsFreeze) .WhereIF(!string.IsNullOrWhiteSpace(input.FactoryName), u => u.FactoryName.Contains(input.FactoryName.Trim())) .WhereIF(!string.IsNullOrWhiteSpace(input.FactoryCode), u => u.FactoryCode.Contains(input.FactoryCode.Trim())) .Select(); if (input.EstimatedDateRange != null && input.EstimatedDateRange.Count > 0) { DateTime? start = input.EstimatedDateRange[0].Value.AddDays(-1); query = query.WhereIF(start.HasValue, u => u.EstimatedDate > start); if (input.EstimatedDateRange.Count > 1 && input.EstimatedDateRange[1].HasValue) { var end = input.EstimatedDateRange[1].Value.AddDays(1); query = query.Where(u => u.EstimatedDate < end); } } return query; } /// /// 重复性验证 /// /// 验证对象 /// 是否是编辑 /// private async Task CheckExist(WmsOrderAsn input, bool isEdit = false) { //没有配置组合校验,不需要验重 //没有配置单独校验,不需要验重 } #endregion #region 导入 /// /// Excel模板导入ASN单功能-ly /// /// Excel模板文件 /// 导入的记录数 [HttpPost] [ApiDescriptionSettings(Name = "ImportExcel")] [Description("WmsOrderAsn/ImportExcel")] public async Task ImportExcelAsync(IFormFile file) { int _HeadStartLine = 2;//第1行是说明,第2行是列名 int _DataStartLine = 3;//第3行开始是数据 DataTable importDataTable = ExcelUtil.ImportExcelToDataTable(file, _HeadStartLine, _DataStartLine); var addListAll = await CommonImport(importDataTable, _DataStartLine); // 获取当前时间 DateTime currentTime = DateTime.Now; // 格式化为年月日字符串 string formattedDate = currentTime.ToString("yyyyMMdd"); //按照单号规则生成单号 - 查找最新的创建的一条单据记录 var newestOrder = await _rep.AsQueryable().Where(p => p.AsnType == OrderTypeEnum.ASN单).Where(p => p.AsnNo.Contains(formattedDate)).OrderBy(it => it.CreateTime, OrderByType.Desc) .FirstAsync(); //按照单号规则生成单号-ly var AsnNo = await SerialUtilOrder.GetSerialOrder(OrderTypeEnum.ASN单, _WmsNoCreateRuleRep, _repSNRep, (int)BusinessTypeEnum.采购收货, newestOrder == null ? null : newestOrder.AsnNo); if (AsnNo == null || AsnNo == "") { AsnNo = Yitter.IdGenerator.YitIdHelper.NextId().ToString(); } if (addListAll.OrderDeliver.BusinessType == 0) throw Oops.Oh("该业务类型不存在于ASN单中"); //主表 addListAll.OrderDeliver.Id = Yitter.IdGenerator.YitIdHelper.NextId(); addListAll.OrderDeliver.AsnNo = AsnNo; addListAll.OrderDeliver.AsnTypeName = "ASN单"; addListAll.OrderDeliver.Id = Yitter.IdGenerator.YitIdHelper.NextId(); addListAll.OrderDeliver.AsnType = OrderTypeEnum.ASN单; addListAll.OrderDeliver.AsnStatus = OrderStatusEnum.新建; addListAll.OrderDeliver.AsnStatusName = GetEnumDescriptionUtil.GetEnumDescription(OrderStatusEnum.新建); //addListAll.OrderDeliver.BusinessType = (int)BusinessTypeEnum.采购收货; //addListAll.OrderDeliver.BusinessTypeName = GetEnumDescriptionUtil.GetEnumDescription(BusinessTypeEnum.采购收货); addListAll.OrderDeliver.BusinessTypeName = addListAll.OrderDeliver.BusinessType == 101 ? GetEnumDescriptionUtil.GetEnumDescription(BusinessTypeEnum.采购收货) : GetEnumDescriptionUtil.GetEnumDescription(BusinessTypeEnum.采购收货); //addListAll.OrderDeliver.OrderSocure = "导入"; //(string)SourceByEnum.导入 addListAll.OrderDeliver.AsnStatus = OrderStatusEnum.新建; addListAll.OrderDeliver.AsnStatusName = GetEnumDescriptionUtil.GetEnumDescription(OrderStatusEnum.新建); //检验物料不存在 List queryCodeList = addListAll.OrderDeliverDetails.Select(v => v.MaterialCode).Distinct().ToList(); var handleList = await _wmsMaterialRep.GetListAsync(u => queryCodeList.Contains(u.MaterialCode) && u.IsDelete == false); if (handleList == null || handleList.Count <= 0) { throw Oops.Oh($"物料不存在!"); } List handleListAsn = new List(); List handleListPurchaseDetails = new List(); List queryCodeListForAsn = addListAll.OrderDeliverDetails.Select(v => v.PoNo).Distinct().ToList(); if (queryCodeListForAsn.Count > 0) { //查询asn中已关联po的数据 handleListAsn = await _WmsOrderAsnDetailsRep.GetListAsync(u => queryCodeListForAsn.Contains(u.PoNo) && u.IsDelete == false); //查询所有相关po的数据 handleListPurchaseDetails = await _purchaseOrderDetailsRep.GetListAsync(u => queryCodeListForAsn.Contains(u.PoNo) && u.IsDelete == false); } int index = 0; //明细表 foreach (var item in addListAll.OrderDeliverDetails) { if (item.POQuantity == 0 || item.POQuantity == null) { throw Oops.Oh("创建失败:数量需要大于0"); } var materials = handleList.Where(u => u.MaterialCode == item.MaterialCode).FirstOrDefault(); if (materials == null) { throw Oops.Oh("物料:" + item.MaterialCode + "不存在"); } var Info_BaseCustomer = await _BaseCustomerRep.GetFirstAsync(u => u.CustCode == item.SupplierCode); if (Info_BaseCustomer == null) { throw Oops.Oh("供应商编号" + item.SupplierCode + "不存在!"); } item.AsnNo = Convert.ToString(AsnNo); //item.PoId = Yitter.IdGenerator.YitIdHelper.NextId().ToString(); item.AsnStatus = OrderStatusEnum.新建; item.AsnId = addListAll.OrderDeliver.Id; item.AsnStatusName = GetEnumDescriptionUtil.GetEnumDescription(OrderStatusEnum.新建); item.MaterialName = materials.MaterialName; item.GoodsQuantity = item.GoodsQuantity; //item.SupplierCode = addListAll.OrderDeliver.SupplierCode; item.SupplierName = Info_BaseCustomer.CustChinaName; item.Quantity = materials.TranslateRate == null ? item.Quantity : ((decimal)item.POQuantity * (decimal)materials.TranslateRate); item.POUnit = materials.POUnit; item.MaterialUnit = materials.MaterialUnit; //ERP库存地必赋值 var strErpCode = await ErpCodeValidDetail(item); item.ErpCode = strErpCode; if (item.PoNo != null) { if (addListAll.OrderDeliver.BusinessType != 101) throw Oops.Oh("导入模板中" + item.PoNo + "为PO单所以单据业务类型必须为采购收货"); //所有PO总数 decimal hasUsedPoQty = handleListPurchaseDetails.Where(x => x.MaterialCode == item.MaterialCode && x.PoLineNumber == item.PoLineNumber && x.PoNo == item.PoNo && (x.PoDetailStatus == OrderStatusEnum.新建 || x.PoDetailStatus == OrderStatusEnum.处理中)).Sum(x => x.Quantity); //所有PO已收 decimal hasUsedPoGoodsQuantity = handleListPurchaseDetails.Where(x => x.MaterialCode == item.MaterialCode && x.PoLineNumber == item.PoLineNumber && x.PoNo == item.PoNo && (x.PoDetailStatus == OrderStatusEnum.新建 || x.PoDetailStatus == OrderStatusEnum.处理中)).Sum(x => x.GoodsQuantity); decimal usedQtyPo = hasUsedPoQty - hasUsedPoGoodsQuantity; //po单中改物料 剩余可用数量: PO总数 - 已收货数 //所有asn中已关联po总数 decimal hasUsedPoQtyInAsn = (decimal)handleListAsn.Where(x => x.MaterialCode == item.MaterialCode && x.PoLineNumber == item.PoLineNumber && x.PoNo == item.PoNo && (x.AsnStatus == OrderStatusEnum.新建 || x.AsnStatus == OrderStatusEnum.处理中)).Sum(x => x.POQuantity); if (usedQtyPo < hasUsedPoQtyInAsn) //ASN中已关联po总数 { throw Oops.Oh($"创建失败:PO单号{item.PoNo},物料编号{item.MaterialCode},PO行号{item.PoLineNumber}需求数量{item.POQuantity}已全部创建ASN单!"); } decimal usedQtyHasNow = usedQtyPo - hasUsedPoQtyInAsn; if (usedQtyHasNow < item.POQuantity) { throw Oops.Oh($"创建失败:PO单号{item.PoNo},物料编号{item.MaterialCode},DO行号{item.PoLineNumber}在未绑定ASN单中剩余可用数{usedQtyHasNow}不足!"); } index++; string myLineNumeber = index.ToString(); var idMaterial = Yitter.IdGenerator.YitIdHelper.NextId(); item.Id = idMaterial; item.AsnNo = addListAll.OrderDeliver.AsnNo; item.AsnId = addListAll.OrderDeliver.Id; item.AsnStatus = OrderStatusEnum.新建; item.AsnStatusName = GetEnumDescriptionUtil.GetEnumDescription(OrderStatusEnum.新建); item.ErpOrderNo = item.ErpOrderNo; item.AsnLineNumber = OrderHelper.AutoCompleEBELP(myLineNumeber, 4); item.PoLineNumber = item.PoLineNumber; item.SupplierName = Info_BaseCustomer.CustChinaName; item.IsDelete = false; } } try { await _rep.AsTenant().BeginTranAsync(); await _rep.InsertAsync(addListAll.OrderDeliver); //插入主表 await _WmsOrderAsnDetailsRep.InsertRangeAsync(addListAll.OrderDeliverDetails); //插入明细表 await _rep.AsTenant().CommitTranAsync(); } catch { await _rep.AsTenant().RollbackTranAsync(); throw; } return 200; } /// /// DataTable转换实体对象列表 /// /// /// 模版列名开始行 /// private async Task CommonImport(DataTable dataTable, int dataStartLine) { var detailsAll = new WmsOrderAsnExportOutput(); var addItem = new WmsOrderAsn(); var detailsMaterial = new List(); int index = dataStartLine;//模版列名开始行 foreach (System.Data.DataRow row in dataTable.Rows) { index++; //导入模版定制化代码(替换模版使用) var addItemMaterial = new WmsOrderAsnDetails(); #region 定义变量 var _BusinessTypeName = "";//业务类型 var _CustCode = "";//客户编号 var MaterialCode = "";//物料编号 var DoLineNumber = "";//行号 var POQuantity = "";//需求数 //var _Quantity = "";//送货数量 //var _GoodsQuantity = "";//已收数量 var _PoNo = "";//PO单号 var _PoLineNumber = "";//PO单行号 #endregion #region 取值 _BusinessTypeName = row["业务类型"]?.ToString(); MaterialCode = row["物料编号"]?.ToString(); DoLineNumber = row["行号"]?.ToString(); POQuantity = row["需求数"]?.ToString(); _CustCode = row["供应商编号"]?.ToString(); //_Quantity = row["送货数量"]?.ToString(); //_GoodsQuantity = row["已收数量"]?.ToString(); _PoNo = row["PO单号"]?.ToString(); _PoLineNumber = row["PO单行号"]?.ToString(); #endregion #region 验证 //if (string.IsNullOrEmpty(_DeliverNo)) //{ // throw Oops.Oh($"第{index}行[DO单号]{_DeliverNo}不能为空!"); //} if (!string.IsNullOrEmpty(_PoNo)) { addItemMaterial.PoNo = (string)(_PoNo.Trim()); } if (string.IsNullOrEmpty(MaterialCode)) { throw Oops.Oh($"第{index}行[物料编号]{MaterialCode}不能为空!"); } if (!string.IsNullOrEmpty(MaterialCode)) { addItemMaterial.MaterialCode = (string)(MaterialCode.Trim()); } if (string.IsNullOrEmpty(DoLineNumber)) { throw Oops.Oh($"第{index}行[行号]{DoLineNumber}不能为空!"); } if (!string.IsNullOrEmpty(DoLineNumber)) { // addItemMaterial.PoLineNumber = (string)(DoLineNumber.Trim()); addItemMaterial.AsnLineNumber = (string)(DoLineNumber.Trim()); } if (!string.IsNullOrEmpty(_PoLineNumber)) { addItemMaterial.PoLineNumber = (string)(_PoLineNumber.Trim()); } if (string.IsNullOrEmpty(POQuantity)) { throw Oops.Oh($"第{index}行[需求数]{POQuantity}不能为空!"); } decimal qty = Convert.ToDecimal(POQuantity.Trim()); if (qty <= 0) { throw Oops.Oh($"第{index}行[需求数]{POQuantity}不能小于0!"); } addItemMaterial.POQuantity = qty; //if (string.IsNullOrEmpty(_CustCode)) //{ // throw Oops.Oh($"第{index}行[客户编号]{_CustCode}不能为空!"); //} if (!string.IsNullOrEmpty(_BusinessTypeName)) { //if (!int.TryParse(_BusinessType, out int businessType) && !string.IsNullOrEmpty(_BusinessType)) //{ // throw Oops.Oh($"第{index}行[优先级]{_BusinessType}值不正确!"); //} //if (businessType <= 0 && !string.IsNullOrEmpty(_BusinessType)) //{ // throw Oops.Oh($"第{index}行[优先级]{_BusinessType}值不能小于等于0!"); //} //else //{ // addItem.BusinessType = businessType; //} if (_BusinessTypeName == "收货1001") { addItem.BusinessTypeName = _BusinessTypeName.Trim(); addItem.BusinessType = BusinessTypeHelper.GetBusinessNameInfoFromDB(_BusinessTypeName, _WmsBaseBusinessTypeRep).BusinessTypeValue; } else if (_BusinessTypeName == "采购收货") { addItem.BusinessTypeName = _BusinessTypeName.Trim(); addItem.BusinessType = BusinessTypeHelper.GetBusinessNameInfoFromDB(_BusinessTypeName, _WmsBaseBusinessTypeRep).BusinessTypeValue; ; } else { addItem.BusinessType = 0; } } if (index == 4) { //if (string.IsNullOrEmpty(_CustCode)) //{ // throw Oops.Oh($"第{index}行[供应商编号]{_CustCode}不能为空!"); //} //if (!string.IsNullOrEmpty(_CustCode)) //{ // addItemMaterial.SupplierCode = (string)(_CustCode.Trim()); //} //if (!string.IsNullOrEmpty(_Remark)) //{ // addItem.Remark = (string)(_Remark.Trim()); //} //if (!string.IsNullOrEmpty(_ErpOrderNo)) //{ // addItem.ErpOrderNo = (string)(_ErpOrderNo.Trim()); //} } if (string.IsNullOrEmpty(_CustCode)) { throw Oops.Oh($"第{index}行[供应商编号]{_CustCode}不能为空!"); } if (!string.IsNullOrEmpty(_CustCode)) { addItemMaterial.SupplierCode = (string)(_CustCode.Trim()); } #endregion detailsMaterial.Add(addItemMaterial); } //验重 //await CheckExisitForImport(details); // await CheckExisitForImport(detailsMaterial); detailsAll.OrderDeliver = addItem; detailsAll.OrderDeliverDetails = detailsMaterial; return detailsAll; } /// /// 根据版本下载ASN单的Excel导入模板 /// /// 下载的模板文件 [HttpGet] [ApiDescriptionSettings(Name = "DownloadExcelTemplate")] [Description("WmsOrderAsn/DownloadExcelTemplate")] public IActionResult DownloadExcelTemplate() { string _path = TemplateConst.EXCEL_TEMPLATEFILE_导入模版路径 + $"\\ASN单{TemplateConst.EXCEL_TEMPLATEFILE_导入模版名称后缀}.xlsx"; var fileName = HttpUtility.UrlEncode($"导入模板(ASN单).xlsx", Encoding.GetEncoding("UTF-8")); return new FileStreamResult(new FileStream(_path, FileMode.Open), "application/octet-stream") { FileDownloadName = fileName }; } #endregion /// /// Do单主表明细导出 /// /// /// [HttpGet] [ApiDescriptionSettings(Name = "DOOrderExcelOutting")] [Description("WmsOrderAsn/DOOrderExcelOutting")] [AllowAnonymous] public async Task DOOrderExcelOutting([FromQuery] WmsOrderAsnInput input) { var vs = (from p in _WmsOrderAsnDetailsRep.AsQueryable().ToList() join m in _rep.AsQueryable() .WhereIF(!string.IsNullOrWhiteSpace(input.SearchKey), u => u.AsnNo.Contains(input.SearchKey.Trim()) || u.AsnTypeName.Contains(input.SearchKey.Trim()) || u.BusinessTypeName.Contains(input.SearchKey.Trim()) || u.AsnStatusName.Contains(input.SearchKey.Trim()) || u.TrackingNumber.Contains(input.SearchKey.Trim()) || u.ReleaseStatusName.Contains(input.SearchKey.Trim()) || u.FactoryName.Contains(input.SearchKey.Trim()) || u.FactoryCode.Contains(input.SearchKey.Trim()) ) .WhereIF(!string.IsNullOrWhiteSpace(input.AsnNo), u => u.AsnNo.Contains(input.AsnNo.Trim())) .WhereIF(input.AsnType.HasValue, u => u.AsnType == input.AsnType) .WhereIF(!string.IsNullOrWhiteSpace(input.AsnTypeName), u => u.AsnTypeName.Contains(input.AsnTypeName.Trim())) .WhereIF(input.BusinessType.HasValue, u => u.BusinessType == input.BusinessType) .WhereIF(!string.IsNullOrWhiteSpace(input.BusinessTypeName), u => u.BusinessTypeName.Contains(input.BusinessTypeName.Trim())) .WhereIF(input.AsnStatus.HasValue, u => u.AsnStatus == input.AsnStatus) .WhereIF(!string.IsNullOrWhiteSpace(input.AsnStatusName), u => u.AsnStatusName.Contains(input.AsnStatusName.Trim())) .WhereIF(!string.IsNullOrWhiteSpace(input.TrackingNumber), u => u.TrackingNumber.Contains(input.TrackingNumber.Trim())) .WhereIF(input.ReleaseStatus > 0, u => u.ReleaseStatus == input.ReleaseStatus) .WhereIF(!string.IsNullOrWhiteSpace(input.ReleaseStatusName), u => u.ReleaseStatusName.Contains(input.ReleaseStatusName.Trim())) .WhereIF(!string.IsNullOrWhiteSpace(input.FactoryName), u => u.FactoryName.Contains(input.FactoryName.Trim())) .WhereIF(!string.IsNullOrWhiteSpace(input.FactoryCode), u => u.FactoryCode.Contains(input.FactoryCode.Trim())).ToList() on p.AsnId equals m.Id select new WmsOrderAsnExcelOutput { //BusinessTypeName = m.BusinessTypeName, //AsnStatusName = p.AsnStatusName, AsnNo = m.AsnNo, BusinessTypeName = m.BusinessTypeName, AsnStatusName = m.AsnStatusName, CreateTime = m.CreateTime, UpdateTime = m.UpdateTime, CreateUserName = m.CreateUserName, UpdateUserName = m.UpdateUserName, MaterialName = p.MaterialName, MaterialCode = p.MaterialCode, Quantity = p.Quantity, GoodsQuantity = p.GoodsQuantity, AsnLineNumber = p.AsnLineNumber, PoNo = p.PoNo, PoLineNumber = p.PoLineNumber, SupplierCode = p.SupplierCode, SupplierName = p.SupplierName, POUnit = p.POUnit, SN_1d = p.SN_1d, SN_2d = p.SN_2d, Package = p.Package, PlannedStartTime = p.PlannedStartTime, ProjectNo = p.ProjectNo, Dock = p.Dock, SupplierBatch = p.SupplierBatch, ErpCode = p.ErpCode, ErpOrderNo = p.ErpOrderNo }).ToList(); var fileName = "ASN单详情"; var excelBaseResult = new Excel2003Result(vs, fileName, false, "ASN单导出详情"); return new FileStreamResult(excelBaseResult.GetExcelStream(), "application/vnd.ms-excel"); } }