using Rhea.Common; using Tiger.Model.Minsun; using SqlSugar; using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Text; using System.Threading; using System.Threading.Tasks; using Tiger.Model; using Tiger.IBusiness; namespace Tiger.Business.WMS.Transaction { /// /// 客供料入库清点事务 /// public class CustSupplyChecking : WMSTransactionBase, ICustSupplyChecking { public ICustSupplyChecking Init(string id, string userCode, string apiHost) { TransID = id; UserCode = userCode; ApiHost = apiHost; var user = Biz.Db.Queryable().Where(t => t.Name == UserCode).First(); if (user != null) { UserId = user.Id; } else { UserId = 0; } Logger.Console.Info($"Start {this.GetType().Name} Transaction[ID: {TransID}]"); return this; } #region Propertys & Variables public string UserCode { get; set; } public long UserId { get; set; } public string VenderCode { get; set; } public string LotNo { get; set; } public string SecondVenderCode { get; set; } public string WarehouseCode { get; set; } public string WarehouseName { get; set; } public List suppliers { get; set; } #endregion #region Functions /// /// 扫描物料并复核,如果物料已经完成移库则货架上亮灯提醒储位 /// public async Task ScanItem(InputCustSupplyCheck input) { var action = new ApiAction(); try { if (string.IsNullOrEmpty(WarehouseCode)) { action.IsSuccessed = false; action.Message = $"库位不能为空!"; return action; } if (string.IsNullOrEmpty(input.SN)) { action.IsSuccessed = false; action.Message = $"条码不能为空!"; return action; } Result result = iWMS.SplitFullBarcode(input.SN); if (result.Flag != Result.Flags.Success) { action.IsSuccessed = false; action.Message = result.Message; return action; } var nDisassembleBarcode = result.Data; // 其它入库清点不能扫入拆包后带-1的标签 if (nDisassembleBarcode.Barcode.Contains("-1")) { action.IsSuccessed = false; action.Message = $"拆包带-1的标签不能入库,请重新扫描!"; return action; } if (string.IsNullOrEmpty(nDisassembleBarcode.MaterialCode)) { action.IsSuccessed = false; action.Message = $"条码未包含物料信息,请重新扫描!"; return action; } VenderCode = nDisassembleBarcode.VendorCode; string[] _strVenderCodes = input.StrVenderCode.Split(','); SecondVenderCode = _strVenderCodes[0]; LotNo = input.LotNo; if (string.IsNullOrEmpty(VenderCode)) { VenderCode = _strVenderCodes[1]; } //暂时不判断 //if (_strVenderCodes[1] != VenderCode) //{ // action.IsSuccessed = false; // action.Message = $"二级供应商代码不符!请重新选择二级供应商!"; // return action; //} var scanResult = new WMS_OTHERINSTOCK_SCAN { Id = Guid.NewGuid().ToString(), BUSINESSCODE = "CI", WAREHOUSECODE = WarehouseCode, BARCODE = nDisassembleBarcode.Barcode, MATERIALCODE = nDisassembleBarcode.MaterialCode, QTY = nDisassembleBarcode.LotQty, DATECODE = nDisassembleBarcode.LotDate, DATECODESTR = nDisassembleBarcode.LotDateString, LOTNO = nDisassembleBarcode.LotNo, STATUS = ScannedBarcodeStatus.Checked.ToString(), CreationTime = DateTime.Now, CreatorUserId = UserId, LastModificationTime = DateTime.Now, LastModifierUserId = UserId, }; // 其它入库清点扫描加入只能扫入最小包装标签的防呆 if (nDisassembleBarcode.Barcode.ToUpper().Substring(0, 1) == "C" || nDisassembleBarcode.Barcode.ToUpper().Substring(0, 1) == "P") { action.IsSuccessed = false; action.Message = $"其它入库清点只能扫入最小包装标签,请重新扫描"; return action; } //验证条码是否已做过清点 var nLogs = await Biz.Db.Queryable().Where(t => t.BARCODE.ToUpper() == nDisassembleBarcode.Barcode.ToUpper()).FirstAsync(); if (nLogs != null) { //return new OtherInstockPickScanResponse //{ // ActionType = "CANCEL", // Message = "确定要取消该条码的清点吗?", // Barcode = nBarcodeResult //}; action.IsSuccessed = false; action.Message = $"条码已做过清点"; return action; } if (Biz.Db.Queryable().Where(t => t.BARCODE.ToUpper() == nDisassembleBarcode.Barcode.ToUpper()).Any()) { action.IsSuccessed = false; action.Message = $"条码已经入过库,不允许重复扫描入库"; return action; //if (nBarcode.BARCODESTATUS == (int)InvStorageInfoSides.BarcodeStatus.Instock) //{ // action.IsSuccessed = false; // action.Message = $"条码状态为[在库],不允许重复扫描入库"; // return action; //} //scanResult = new WMS_OTHERINSTOCK_SCAN //{ // Id = Guid.NewGuid().ToString(), // BUSINESSCODE = "CI", // WAREHOUSECODE = WarehouseCode, // BARCODE = nBarcode.BARCODE, // MATERIALCODE = nDisassembleBarcode.MaterialCode, // QTY = nBarcode.CURRENTQTY ?? 0, // DATECODE = nBarcode.DATECODE, // DATECODESTR = nBarcode.DATECODE_STR, // LOTNO = nBarcode.LOTNO, // CreationTime=DateTime.Now, // CreatorUserId = UserId, // LastModificationTime =DateTime.Now, // LastModifierUserId = UserId, // STATUS = ScannedBarcodeStatus.Checked.ToString(), //}; } //保存到数据库 var db = Business.Biz.Db; var dbTran = db.UseTran(() => { db.Insertable(scanResult, "system").ExecuteCommand(); }); if (!dbTran.IsSuccess) { throw dbTran.ErrorException; } action.Data = new WMS_OTHERINSTOCK_SCANExt() { BUSINESSCODE = scanResult.BUSINESSCODE, WAREHOUSECODE = scanResult.WAREHOUSECODE, BARCODE = scanResult.BARCODE, MATERIALCODE = scanResult.MATERIALCODE, MName = nDisassembleBarcode.MaterialName, MDesc = nDisassembleBarcode.MaterialStandard, QTY = scanResult.QTY, DATECODE = scanResult.DATECODE, DATECODESTR = scanResult.DATECODESTR, LOTNO = scanResult.LOTNO, STATUS = scanResult.STATUS, }; } catch (Exception ex) { //取消当前操作 action.CatchExceptionWithLog(ex, $"扫描物料[{input.SN}]复核异常"); } return action; } /// /// 扫描库位 /// public async Task ScanWarehouse(string whcode) { var action = new ApiAction(); try { var query = await Biz.Db.Queryable().Where(t => t.WHCODE == whcode.Trim()).FirstAsync(); if (query != null) { action.Message = $"扫描库位{whcode}成功"; action.Data = query; WarehouseCode = query.WHCODE; WarehouseName = query.WHNAME; } else { action.IsSuccessed = false; action.Message = $"扫描库位{whcode}错误"; } } catch (Exception ex) { //取消当前操作 action.CatchExceptionWithLog(ex, $"扫描库位[{whcode}]异常"); } return action; } // /// 生成客供物料入库单据 /// /// /// public async Task SubmitInvBill() { var action = new ApiAction(); bool isIQCOk = true; try { //获取当前用户所有已清点、未制单的条码数据 var nScannedBarcodes = await Biz.Db.Queryable((t, m) => new JoinQueryInfos( JoinType.Left, t.MATERIALCODE == m.MCode )) .Where((t, m) => t.CreatorUserId == Convert.ToInt64(UserId) && t.WAREHOUSECODE.ToUpper() == WarehouseCode.ToUpper() && t.STATUS == ScannedBarcodeStatus.Checked.ToString()) .Select((t, m) => new WMS_OTHERINSTOCK_SCANExt { Id = t.Id, BARCODE = t.BARCODE, MATERIALCODE = t.MATERIALCODE, QTY = t.QTY, BUSINESSCODE = t.BUSINESSCODE, BUSINESSLINE = t.BUSINESSLINE, LastModificationTime = t.LastModificationTime, LastModifierUserId = t.LastModifierUserId, CreationTime = t.CreationTime, CreatorUserId = t.CreatorUserId, DATECODE = t.DATECODE, DATECODESTR = t.DATECODESTR, LOTNO = t.LOTNO, STATUS = t.STATUS, WAREHOUSECODE = t.WAREHOUSECODE, MUom = m.MUom, MName = m.MName, MDesc = m.MDesc, }) .ToListAsync(); if (!nScannedBarcodes.Any()) { action.IsSuccessed = false; action.Message = $"没有可以提交的清点数据"; return action; } // 查询条码清点表所有仓库代码 //var nWarehouseCodes = nScannedBarcodes.Select(x => x.WarehouseCode).Distinct().ToList(); //新建其他入库单据头 OtherInstockHeader string billCode = iWMS.GetBillNoByType("CI"); var nBillHeader = new WMS_OTHERINSTOCK_H { CreationTime = DateTime.Now, CreatorUserId = UserId, LastModificationTime = DateTime.Now, BILLCODE = billCode, BILLDATE = DateTime.Now.Date, WAREHOUSECODE = WarehouseCode, STATUS = OtherInstockSides.Status.INIT.ToString(), REMARK = LotNo }; // 查找待处理记录料号列表 var nMaterials = nScannedBarcodes.Select(x => x.MATERIALCODE).Distinct().ToList(); // 单据行号变量,初始值1 var nLineSeq = 1; List scanList = new List(); List detailList = new List(); List iqcHeaders = new List(); List details = new List(); // 按照料号列表处理单据明细 foreach (var matCode in nMaterials) { // 按照料号、计量单位汇总scanBarcode var lineMaterials = (from codes in nScannedBarcodes.Where(x => x.MATERIALCODE.ToUpper() == matCode.ToUpper()) group codes by new { codes.MATERIALCODE, codes.MUom } into g select new { g.Key.MATERIALCODE, g.Key.MUom, sumQty = g.Sum(x => x.QTY) } ).ToList(); // 循环处理每一行 foreach (var matLine in lineMaterials) { //插入单据明细行 var billDetail = new WMS_OTHERINSTOCK_D { WAREHOUSECODE = WarehouseCode, BILLCODE = billCode, BILLLINE = nLineSeq, LINESTATUS = OtherInstockSides.Status.INIT.ToString(), MATERIALCODE = matLine.MATERIALCODE, UNITCODE = matLine.MUom, PRQTY = matLine.sumQty, QTY = 0, CreationTime = DateTime.Now, CreatorUserId = Convert.ToInt64(UserId), LastModificationTime = DateTime.Now, LastModifierUserId = Convert.ToInt64(UserId), }; detailList.Add(billDetail); details.Add(new Detail { pmdtseq = nLineSeq.ToString(), pmdt001 = "", pmdt002 = "", pmdt003 = "", pmdt004 = "", pmdt006 = matLine.MATERIALCODE, //"K7015AA016141", pmdt018 = "创米科技", pmdt020 = matLine.sumQty.ToString(), //"100.00000", pmdtud011 = "0" }); //创建送检单 Result result = CreateIqcHeader(billDetail, "Y"); if (result.Flag != Result.Flags.Success) { action.IsSuccessed = false; action.Message = result.Message; return action; } iqcHeaders.Add(result.Data); // 更新清点表,单据号 foreach (WMS_OTHERINSTOCK_SCAN barcode in nScannedBarcodes.Where(x => x.MATERIALCODE == matLine.MATERIALCODE)) { barcode.BUSINESSCODE = billCode; barcode.BUSINESSLINE = nLineSeq; barcode.STATUS = ScannedBarcodeStatus.Billed.ToString(); barcode.LastModificationTime = DateTime.Now; barcode.LastModifierUserId = UserId; scanList.Add(barcode); } // 单据明细行号 ++ nLineSeq++; } } //调用T100接口生成到货单 var ret = ErpT100.GenerateCustReceipt(new CustReceiptInputParameter { parameter = new Parameter { pmds000 = "2", pmdsdocno = "3453", pmdsdocdt = DateTime.Now.ToString("yyyy-MM-dd"), //"2023-04-26", //当天时间 pmds002 = UserCode == "admin" ? "00000" : UserCode, //"L36783", //用户ID pmds003 = "", pmds007 = VenderCode, //"C0006", //供应商代码 pmds010 = "", //"测试客供料无采购收货", //送货单号 pmdsud001 = SecondVenderCode, //"CM017", //二级供应编号 detail = details }, datakey = new Datakey { EntId = "88", CompanyId = "DGXC" } }); if (ret.payload.std_data.execution.code == "0") //成功 { nBillHeader.ERP_BILL_CODE = ret.payload.std_data.parameter.docno; action.Message += $"{action.Message.IsNullOrEmpty("", ";")}{ret.payload.std_data.execution.description},返回的收货单号:[{ret.payload.std_data.parameter.docno}]"; #region 生成送检单 foreach (var item in iqcHeaders) { var retIns = ErpT100.GenerateInspection(new InsInputParameter { parameter = new InsParameter { pmdsdocno = ret.payload.std_data.parameter.docno, pmdsdocdt = DateTime.Now.ToString("yyyy-MM-dd"), pmdtseq = item.SOURCELINE.ToString(), pmdt020 = item.QCQTY.ToString(), qcbadocno = "3701", }, datakey = new Datakey { EntId = "88", CompanyId = "DGXC" } }); if (retIns.payload.std_data.execution.code != "0") { isIQCOk = false; action.IsSuccessed = false; action.Message = $"到货单[{ret.payload.std_data.parameter.docno}],当前用户[{UserCode}],供应商编号[{VenderCode}],二级供应商编号[{SecondVenderCode}],返回的信息:{retIns.payload.std_data.execution.description}"; ; //return action; } else { item.ERP_BILL_CODE = retIns.payload.std_data.parameter.docno; } } #endregion } else //失败 { action.IsSuccessed = false; action.Message = $"当前用户[{UserCode}],供应商编号[{VenderCode}],二级供应商编号[{SecondVenderCode}],返回的信息:{ret.payload.std_data.execution.description}"; return action; } //保存到数据库 var db = Business.Biz.Db; var dbTran = db.UseTran(() => { // 插入单据表头 var headerId = Biz.Db.Insertable(nBillHeader).ExecuteReturnBigIdentity(); var x = db.Storageable(detailList).ToStorage(); x.AsInsertable.ExecuteCommand();//不存在插入 x.AsUpdateable.IgnoreColumns(z => new { z.CreationTime, z.CreatorUserId }).ExecuteCommand();//存在更新,更新时忽略字段CreationTime、CreatorUserId db.Updateable(scanList).ExecuteCommand(); if (action.IsSuccessed && isIQCOk) { db.Insertable(iqcHeaders).ExecuteCommand(); action.Message += $"{action.Message.IsNullOrEmpty("", ";")}生成客供物料入库单据和送检单成功"; } //var ret = Biz.GenerateCustReceipt("", ""); }); if (!dbTran.IsSuccess) { throw dbTran.ErrorException; } } catch (System.Exception ex) { action.IsSuccessed = false; action.Message = ex.Message; return action; } return action; } /// /// 删除当前用户的已扫记录(缓存表) /// /// public async Task DeleteAllScannedBarcode() { var action = new ApiAction(); try { if (WarehouseCode.IsNullOrEmpty()) { action.IsSuccessed = false; action.Message = $"空,无法删除已清点条码"; return action; } else { await Biz.Db.Deleteable(x => x.CreatorUserId == UserId && x.WAREHOUSECODE == WarehouseCode && x.STATUS == ScannedBarcodeStatus.Checked.ToString() && x.BUSINESSCODE == "CI").ExecuteCommandAsync(); } } catch (System.Exception ex) { } return action; } /// /// 获取已清点的物料汇总 /// /// public async Task> GetScannedMaterialSummarys() { var query = await Biz.Db.Queryable((t, m) => new JoinQueryInfos( JoinType.Left, t.MATERIALCODE == m.MCode )) .Where((t, m) => t.CreatorUserId == UserId && t.WAREHOUSECODE.ToUpper() == WarehouseCode.ToUpper() && t.STATUS == ScannedBarcodeStatus.Checked.ToString() && t.BUSINESSCODE == "CI") .GroupBy((t, m) => new { t.WAREHOUSECODE,t.MATERIALCODE,m.MName, m.MDesc, m.MUom }) .Select((t, m) => new CustSupplyCheckList { WarehouseCode = t.WAREHOUSECODE, MaterialCode = t.MATERIALCODE, MaterialName = m.MName, MaterialStandard = m.MDesc, InventoryQty = SqlFunc.AggregateSum(t.QTY), Unit = m.MUom }) .ToListAsync(); return new PageAble() { data = query, totals = query.Count(), }; } /// /// 查询物料对应的条码 /// /// /// public async Task> GetScannedMaterialDetailBarcodes(string MaterialCode) { var query = await Biz.Db.Queryable((t, m) => new JoinQueryInfos( JoinType.Left, t.MATERIALCODE == m.MCode )) .Where((t, m) => t.CreatorUserId == UserId && t.WAREHOUSECODE.ToUpper() == WarehouseCode.ToUpper() && t.STATUS == ScannedBarcodeStatus.Checked.ToString() && t.MATERIALCODE.ToUpper() == MaterialCode.ToUpper() && t.BUSINESSCODE == "CI") .Select((t, m) => new CustSupplyCheckDetail { Barcode = t.BARCODE, BarcodeQty = t.QTY, Unit = m.MUom }) .ToListAsync(); return new PageAble() { data = query, totals = query.Count(), }; } /// /// 生成送检单 /// /// /// /// private static Result CreateIqcHeader(WMS_OTHERINSTOCK_D detail, string nUrgent) { Result result = new(Result.Flags.Success, $"生成送检单成功"); var nMaterial = Biz.Db.Queryable().Where(t => t.MCode.ToUpper() == detail.MATERIALCODE.ToUpper()).First(); var nAql = Biz.Db.Queryable().Where(t => t.MATERIALID.Equals(nMaterial.Id)).First(); var nIqcHeader = new WMS_IQC_H { BILLCODE = iWMS.GetBillNoByType("IQC"), SOURCETYPE = (int)InventoryTransferSides.BillType.CustSupplyInStock, SOURCECODE = detail.BILLCODE, SOURCELINE = detail.BILLLINE, PONO = detail.SOURCECODE, POLINE = detail.SOURCELINE ?? 0, MEASURE = nUrgent, QCTIMES = 0, QCSTATUS = (int)IqcManagementSides.QCStatus.Finished, /*(int)IqcManagementSides.QCStatus.UnFinish,*/ QCRESULT = (int)IqcManagementSides.QCResult.Wait, QCREVIEW = (int)IqcManagementSides.QCReview.UnReview, CreationTime = DateTime.Now, CreatorUserId = UserId, MATERIALCODE = detail.MATERIALCODE //ReceiveQty = detail.Qty, //生成送检单加上接收数量 2022/07/27 Ben Lin 2022/09/03 Ben Lin 注释 }; var nIQCMaterial = Biz.Db.Queryable().Where(t => t.MATERIALID.Equals(nMaterial.Id)).First(); if (nIQCMaterial == null) { nIqcHeader.QCLEVEL = (int)IqcManagementSides.QCLevel.NormalI; } //免检 else if (nIQCMaterial.CHECKTYPE == "Exemption") { nIqcHeader.QCLEVEL = (int)IqcManagementSides.QCLevel.Exemption; } //抽检 else if (nIQCMaterial.CHECKTYPE == "Sampling") { var nIQCMaterial2AQL = Biz.Db.Queryable().Where(t => t.IQCMATERIALID.Equals(nIQCMaterial.Id)).ToList(); if (nIQCMaterial2AQL.Any()) { var nIQCMaterial2CheckItem = Biz.Db.Queryable().Where(t => t.IQCMATERIALID.Equals(nIQCMaterial.Id)).ToList(); if (nIQCMaterial2CheckItem.Any()) { //高检II,抽检物料,AQL和检验项目都维护了 nIqcHeader.QCLEVEL = (int)IqcManagementSides.QCLevel.HighII; Result result1 = GetAqlSettingAsync(nAql, nIqcHeader, detail); if (result1.Flag != Result.Flags.Success) { result.Flag = result1.Flag; result.Message = result1.Message; } else { nIqcHeader = result1.Data; } } else { //高检I,抽检物料,维护了AQL、但是没有维护检验项目 nIqcHeader.QCLEVEL = (int)IqcManagementSides.QCLevel.HighI; Result result2 = GetAqlSettingAsync(nAql, nIqcHeader, detail); if (result2.Flag != Result.Flags.Success) { result.Flag = result2.Flag; result.Message = result2.Message; } else { nIqcHeader = result2.Data; } } } else { var nIQCMaterial2CheckItem = Biz.Db.Queryable().Where(t => t.IQCMATERIALID.Equals(nIQCMaterial.Id)).ToList(); if (nIQCMaterial2CheckItem.Any()) { //普检II,抽检物料,没有维护AQL、但是维护了检验项目 nIqcHeader.QCLEVEL = (int)IqcManagementSides.QCLevel.NormalII; } else { //普检I,抽检物料,但是没有维护AQL和检验项目 nIqcHeader.QCLEVEL = (int)IqcManagementSides.QCLevel.NormalI; } } } //全检 else if (nIQCMaterial.CHECKTYPE == "FullInspection") { nIqcHeader.QCLEVEL = (int)IqcManagementSides.QCLevel.FullInspection; nIqcHeader.SAMPLENGQTY = detail.QTY; } result.Data = nIqcHeader; return result; } private static Result GetAqlSettingAsync(WMS_IQCMATERIAL_AQL nAql, WMS_IQC_H nIqcHeader, WMS_OTHERINSTOCK_D nDetail) { Result result = new(Result.Flags.Success, $"获取Aql成功"); if (nAql.AUTOSTRICT == true) { nIqcHeader.STRICTLEVEL = nAql.CURRENTSTRICT.IsNullOrEmpty() ? nAql.DEFAULTSTRICT : nAql.CURRENTSTRICT; nIqcHeader.LEVELCODE = nIqcHeader.STRICTLEVEL.ToUpper() == "NORMAL" ? nAql.NORMALLEVEL : (nIqcHeader.STRICTLEVEL.ToUpper() == "STRICT" ? nAql.STRICTLEVEL : nAql.RELAXLEVEL); nIqcHeader.AQL = nIqcHeader.STRICTLEVEL.ToUpper() == "NORMAL" ? nAql.NORMALAQLLEVEL : (nIqcHeader.STRICTLEVEL.ToUpper() == "STRICT" ? nAql.STRICTAQLLEVEL : nAql.RELAXAQLLEVEL); } else { nIqcHeader.STRICTLEVEL = nAql.DEFAULTSTRICT; nIqcHeader.LEVELCODE = nAql.DEFAULTLEVEL; nIqcHeader.AQL = nAql.DEFAULTAQL; } //找到该 LevelCode和AqlCode配置下,符合的批次数量范围 var nAqlDetail = Biz.Db.Queryable< WMS_AQL_D>() .Where(t => t.LEVELCODE.ToUpper() == nIqcHeader.LEVELCODE.ToUpper() && t.AQLCODE.ToUpper() == nIqcHeader.AQL.ToUpper()) .Where(t => t.LOTMAXQTY >= nDetail.QTY && t.LOTMAXQTY <= nDetail.QTY) .First(); if (nAqlDetail == null) { result.Flag = Result.Flags.Failed; result.Message = $"未能在水准[{nIqcHeader.LEVELCODE}]下的AQL[{nIqcHeader.AQL}]下找到符合[{nDetail.QTY}]的批次范围"; } nIqcHeader.BEGINQTY = nAqlDetail.LOTMINQTY; nIqcHeader.ENDQTY = nAqlDetail.LOTMAXQTY; nIqcHeader.SAMPLEQTY = nAqlDetail.SAMPLEQTY > nDetail.QTY ? nDetail.QTY : nAqlDetail.SAMPLEQTY; result.Data = nIqcHeader; return result; } #endregion public override bool Close(bool needSaveHistoryLog = false) { //如果CurItem不为空则清空,且判断是否亮灯储位,如果是则灭灯 //if (CurItem != null) //{ // try // { // LocationLightOff(CurItem).Wait(); // } // catch (System.Exception ex) // { // Logger.Console.Fatal(ex, "一般移库事务Close关灯异常"); // } // CurItem = null; //} //保存操作日志 this.IsFinished = true; return IsFinished ? base.Close(needSaveHistoryLog) : IsFinished; } }//endClass }