using Rhea.Common;
using Microsoft.AspNetCore.Http;
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 Newtonsoft.Json;
using Tiger.IBusiness;
namespace Tiger.Business.WMS.Transaction
{
///
/// 生产领料事务
///
public class OutSplit : WMSTransactionBase, IOutSplit
{
public IOutSplit Init(string id, string userCode, string apiHost, string orgCode, string fty)
{
TransID = id;
UserCode = userCode;
ApiHost = apiHost;
OrgCode = orgCode;
FTY_CODE = fty;
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 OrgCode { get; set; }
public string FTY_CODE { get; set; }
public string ReqNo { get; set; }
public string ExceedTranId { get; set; }
public Inventory CurInv { get; set; }
public ProductionPickToMes toMes { get; set; }
public AuthOption option { get; set; }
#endregion
#region Functions
///
/// 拆批扫描物料条码
///
///
///
public async Task> ScanItem(OutSplitInput input)
{
var action = new ApiAction();
try
{
if (input.SN.IsNullOrEmpty())
{
action.IsSuccessed = false;
action.LocaleMsg = Biz.L("条码不能为空");
return action;
}
//解析条码
Result result = WMS_ITEM_Biz.WmsItem.Get(input.SN, input.AuthOption, true);
if (!result.IsSuccessed)
{
action.IsSuccessed = false;
action.LocaleMsg = result.LocaleMsg;
return action;
}
CurInv = result.Data as Inventory;
if (string.IsNullOrEmpty(CurInv.ItemInfo?.ITEM_CODE))
{
action.IsSuccessed = false;
action.LocaleMsg = Biz.L("WMS.InReceipt.ScanItem.NotFound", CurInv.ItemInfo?.ITEM_CODE);
return action;
}
//物料验证
if (CurInv.ItemInfo.IsNullOrEmpty() || CurInv.ItemInfo.IS_ACTIVE == "N")
{
action.IsSuccessed = false;
action.LocaleMsg = Biz.L("WMS.ProdMReq.ScanItem.ItemCodeNotExistsOrNotActive", CurInv.ItemInfo.ITEM_CODE.IsNullOrEmpty(CurInv.Barcode.ItemCode));
return action;
}
if (!CurInv.isExists || CurInv.Status == WMS_ITEM.STATUSs.WaitIn)
{
action.IsSuccessed = false;
action.LocaleMsg = Biz.L("WMS.InReceipt.ScanItem.NotExist", CurInv.SN); //条码[{0}]不存在于系统中
return action;
}
ReqNo = input.ReqNo;
ExceedTranId = input.ExceedTranId;
option = input.AuthOption;
action.LocaleMsg = Biz.L($"条码[{CurInv.CurPkg.SN}]扫描成功!");
action.Data = new OutSplitOutput() {
MaterialCode = CurInv.ItemInfo.ITEM_CODE,
MaterialName = CurInv.ItemInfo.ITEM_NAME,
SupplierCode = CurInv.Items[0].SUPP_CODE,
Barcode = CurInv.SN, //批次号即为条码
DateCode = CurInv.Items[0].PROD_DATE,
LotNo = CurInv.Barcode.LotNo,
ScanQty = CurInv.CurPkg.QTY, //批次数量
Unit = CurInv.ItemInfo.UNIT
};
}
catch (Exception ex)
{
action.CatchExceptionWithLog(ex, $"扫描物料[{input.SN}]复核异常");
}
return action;
}
///
/// 拆分
///
///
///
public async Task> SplitBarcodeRecord(string qty)
{
var action = new ApiAction();
try
{
Logger.Interface.Info($"拆包 => [{CurInv.SN}]正在准备开始执行拆包操作......");
int splitNum = Convert.ToInt32(qty);
if (splitNum >= CurInv.CurPkg.QTY || splitNum <= 0)
{
action.IsSuccessed = false;
action.LocaleMsg = Biz.L($"拆批数量有误!");
return action;
}
Logger.Interface.Info($"拆包 => [{CurInv.SN}]当前数量[{CurInv.CurPkg.QTY}],实际数量[{splitNum}]");
//获取供应商信息
var vender = await Biz.Db.Queryable().Where(t => t.SUPP_CODE == CurInv.Items[0].SUPP_CODE).FirstAsync();
//生成条码
var cutSerial = Convert.ToString(CurInv.Barcode.ReprintNo ?? 0, 2);
cutSerial = cutSerial == "0" ? "1" : cutSerial;
var orglSn = CurInv.SN.Split("_")[0];
var nSplitSn = $"{orglSn}_CA{Convert.ToString(Convert.ToInt32(cutSerial + "0", 2), 16).ToUpper()}";
var nRemainSn = $"{orglSn}_CB{Convert.ToString(Convert.ToInt32(cutSerial + "1", 2), 16).ToUpper()}";
if (Biz.Db.Queryable().Any(t => t.SN == nRemainSn))
{
//throw new UserFriendlyException(1011, "生成的拆批条码已存在!", vender != null ? vender.VenderSName : "");
action.IsSuccessed = false;
action.LocaleMsg = Biz.L($"生成的拆批条码已存在!供应商:{vender?.SUPP_NAME_CN}");
return action;
}
//#region 操作条码信息
//条码一
var nSplitBarcode1 = CurInv.Items[0];
var nSplitBarcode2 = CurInv.Items[0].Clone();
nSplitBarcode1.SN = nSplitSn;
//nSplitBarcode1.BarcodeStatus = (int)Domain.InvStorageInfoSides.BarcodeStatus.Outstock; //出库状态
nSplitBarcode1.QTY = splitNum;
nSplitBarcode1.TRANS_CODE = nameof(OutSplit);
if (!ReqNo.IsNullOrEmpty())
{
nSplitBarcode1.STATUS = WMS_ITEM.STATUSs.Sended.GetValue();
nSplitBarcode1.LOCATION_ID = "";
nSplitBarcode1.REGION_ID = "";
nSplitBarcode1.WH_ID = "";
nSplitBarcode1.SHELF_ID = "";
}
var nSplitPgk1 = CurInv.CurPkg;
var nSplitPgk2 = CurInv.CurPkg.Clone();
nSplitPgk1.SN = nSplitSn;
nSplitPgk1.QTY = splitNum;
if (!ReqNo.IsNullOrEmpty())
{
nSplitPgk1.LOCATION_ID = "";
nSplitPgk1.REGION_ID = "";
nSplitPgk1.WH_ID = "";
nSplitPgk1.SHELF_ID = "";
}
//条码二
nSplitBarcode2.SN = nRemainSn;
var currentQty = nSplitBarcode2.QTY;//原条码实际数量
nSplitBarcode2.QTY = nSplitBarcode2.QTY - splitNum; //拆分后剩下的数量
nSplitBarcode2.ID = Guid.NewGuid().ToString("N");
nSplitBarcode2.TRANS_CODE = nameof(OutSplit);
if (!ReqNo.IsNullOrEmpty())
{
nSplitBarcode2.STATUS = WMS_ITEM.STATUSs.InStore.GetValue();
}
nSplitPgk2.SN = nRemainSn;
nSplitPgk2.QTY = nSplitBarcode2.QTY;
nSplitPgk2.ID = Guid.NewGuid().ToString("N");
string msg = ReqNo.IsNullOrEmpty() ? $"手工拆分物料:原条码[{CurInv.SN},条码一[{nSplitBarcode1.SN}],条码二[{nSplitBarcode2.SN}]]" : $"自动拆分物料:单据[{ReqNo}],原条码[{CurInv.SN},发料条码[{nSplitBarcode1.SN}],需要上架条码[{nSplitBarcode2.SN}]]";
if (!ExceedTranId.IsNullOrEmpty())
{
var MaterialReqTrans = Biz.Db.Queryable().Where(t => t.BILLCODE == ReqNo).Any();
var OthReqTrans = Biz.Db.Queryable().Where(t => t.BILLCODE == ReqNo).Any();
var SaleReqTrans = Biz.Db.Queryable().Where(t => t.BILLCODE == ReqNo).Any();
var TfTrans = Biz.Db.Queryable().Where(t => t.BILLCODE == ReqNo).Any();
ProductionMaterialReq trans = null;
OutWorkOrder owoTrans = null;
OutOther othTrans = null;
OutSale saleTrans = null;
OutTransfer tfTrans = null;
if (WMSContext.TransactionDic.ContainsKey(ExceedTranId))
{
trans = WMSContext.TransactionDic[ExceedTranId] as ProductionMaterialReq;
othTrans = WMSContext.TransactionDic[ExceedTranId] as OutOther;
saleTrans = WMSContext.TransactionDic[ExceedTranId] as OutSale;
tfTrans = WMSContext.TransactionDic[ExceedTranId] as OutTransfer;
//领料单发料或者工单发料
if (MaterialReqTrans)
{
if (trans == null)
{
owoTrans = WMSContext.TransactionDic[ExceedTranId] as OutWorkOrder;
if (!owoTrans.IsFinished)
{
lock (owoTrans.TransLock)
{
Logger.Interface.Info($"自动拆包 => 返回工单发料事务[{ExceedTranId}],开始确认发料并保存数据。");
var response = owoTrans.ConfirmExceed(new()
{
isExceed = true,
AuthOption = option
}).Result;
action.IsSuccessed = response.IsSuccessed;
action.LocaleMsg = response.IsSuccessed ? Biz.L(msg) : Biz.L(response.Message);
}
}
else
{
action.IsSuccessed = false;
action.LocaleMsg = Biz.L($"Transaction Error: 工单领料事务[ID:{ExceedTranId}]已经关闭,请重新打开工单领料功能");
}
}
else
{
if (!trans.IsFinished)
{
lock (trans.TransLock)
{
Logger.Interface.Info($"自动拆包 => 返回领料单发料事务[{ExceedTranId}],开始确认发料并保存数据。");
var response = trans.ConfirmExceed(new()
{
isExceed = true,
AuthOption = option
}).Result;
action.IsSuccessed = response.IsSuccessed;
action.LocaleMsg = response.IsSuccessed ? Biz.L(msg) : Biz.L(response.Message);
}
}
else
{
action.IsSuccessed = false;
action.LocaleMsg = Biz.L($"Transaction Error: 生产领料事务[ID:{ExceedTranId}]已经关闭,请重新打开生产领料功能");
}
}
}
//其他出库发料
if (OthReqTrans)
{
if (!othTrans.IsFinished)
{
lock (othTrans.TransLock)
{
Logger.Interface.Info($"自动拆包 => 返回其他出库发料事务[{ExceedTranId}],开始确认发料并保存数据。");
var response = othTrans.ConfirmExceed(new()
{
isExceed = "true",
AuthOption = option
}).Result;
action.IsSuccessed = response.IsSuccessed;
action.LocaleMsg = response.IsSuccessed ? Biz.L(msg) : Biz.L(response.Message);
}
}
else
{
action.IsSuccessed = false;
action.LocaleMsg = Biz.L($"Transaction Error: 其他出库事务[ID:{ExceedTranId}]已经关闭,请重新打开其他出库功能");
}
}
//销售出库发料
//if (SaleReqTrans)
//{
// if (!saleTrans.IsFinished)
// {
// lock (saleTrans.TransLock)
// {
// Logger.Interface.Info($"自动拆包 => 返回销售出库发料事务[{ExceedTranId}],开始确认发料并保存数据。");
// var response = saleTrans.ConfirmExceed(new()
// {
// isExceed = true,
// AuthOption = option
// }).Result;
// action.IsSuccessed = response.IsSuccessed;
// action.LocaleMsg = response.IsSuccessed ? Biz.L(msg) : Biz.L(response.Message);
// }
// }
// else
// {
// action.IsSuccessed = false;
// action.LocaleMsg = Biz.L($"Transaction Error: 销售出库事务[ID:{ExceedTranId}]已经关闭,请重新打开销售出库功能");
// }
//}
//调拨出库发料
if (TfTrans)
{
if (!tfTrans.IsFinished)
{
lock (tfTrans.TransLock)
{
Logger.Interface.Info($"自动拆包 => 返回调拨出库发料事务[{ExceedTranId}],开始确认发料并保存数据。");
var response = tfTrans.ConfirmExceed(new()
{
isExceed = "true",
AuthOption = option
}).Result;
action.IsSuccessed = response.IsSuccessed;
action.LocaleMsg = response.IsSuccessed ? Biz.L(msg) : Biz.L(response.Message);
}
}
else
{
action.IsSuccessed = false;
action.LocaleMsg = Biz.L($"Transaction Error: 调拨出库事务[ID:{ExceedTranId}]已经关闭,请重新打开调拨出库功能");
}
}
}
else
{
action.IsSuccessed = false;
action.LocaleMsg = Biz.L($"Transaction Error: 事务[ID:{ExceedTranId}]已经关闭,请重新打开功能");
}
action.LocaleMsg = action.IsSuccessed ? Biz.L(msg) : action.LocaleMsg;
}
if (action.IsSuccessed)
{
//保存数据库
var db = Business.Biz.Db;
var dbTran = db.UseTran(() =>
{//入库
db.Updateable(nSplitBarcode1, UserCode).ExecuteCommand();
db.Insertable(new WMS_ITEM_HIS(nSplitBarcode1, msg), UserCode).ExecuteCommand();
db.Insertable(nSplitBarcode2, UserCode).ExecuteCommand();
db.Insertable(new WMS_ITEM_HIS(nSplitBarcode2, msg), UserCode).ExecuteCommand();
db.Updateable(nSplitPgk1, UserCode).ExecuteCommand();
db.Insertable(nSplitPgk2, UserCode).ExecuteCommand();
});
if (!dbTran.IsSuccess)
{
Logger.Default.Fatal(dbTran.ErrorException, "Database transaction save exception");
this.Close(!dbTran.IsSuccess);
throw dbTran.ErrorException;
}
//通过工厂带出 MES api 和 agv api
MES_FACTORY _factory = db.Queryable()
.Where(x => x.FTY_CODE == FTY_CODE)
.First();
//发送到MES
if (Cache.SysParam["IsSend", "SendToMES"].PARAM_VALUE.ToString() == "Y" && !ReqNo.IsNullOrEmpty() && Biz.Db.Queryable().Where(x => x.BILLCODE == ReqNo).Any())
{
var dtl = Biz.Db.Queryable().Where(x => x.BILLCODE == ReqNo).First();
var sourcecode = dtl != null ? dtl.SOURCECODE : "";
var query = Biz.Db.Queryable().Where(x => x.ORIGINAL_WORKORDER == sourcecode).First();
var sctrwo = query != null ? (query.TARGET_WORKORDER.IsNullOrEmpty() ? sourcecode : query.TARGET_WORKORDER) : sourcecode;
toMes = new ProductionPickToMes()
{
qrcode = WMS_ITEM_Biz.WmsItem.GetQRCode(nSplitBarcode1.SN),
wo = sctrwo, // nCurrentLines.First().SourceCode,
pkgid = nSplitBarcode1.SN,
mfrkp = CurInv.Barcode.OEMItemCode,
kpno = CurInv.ItemInfo.ITEM_CODE,
dc = CurInv.Barcode.ProdDateStr,
lc = CurInv.Barcode.LotNo,
qty = nSplitBarcode1.QTY.ToString(),
erpBillCode = ReqNo, //MES接口增加字段,返回备料完成的当前领料单号 2023/05/17 Ben Lin
taskid = ""
};
var mesApi = _factory != null ? _factory.MES_API : Cache.SysParam["apiUrl", "SendToMES"].PARAM_VALUE.ToString();
var res = HttpHelper.PostAsync(mesApi, JsonConvert.SerializeObject(toMes)).Result;
var _action = JsonConvert.DeserializeObject(res.Message);
Logger.Interface.Info($"生产领料-自动拆分物料 =>拆分物料发料发送MES完成,单号:[{ReqNo}],MES传入Json:{JsonConvert.SerializeObject(toMes)},MES返回:{res.Message}");
}
}
action.Data = new OutSplitSubmit() {
nRemainSn = nRemainSn,
nSplitSn = nSplitSn,
SupplierCode = vender?.SUPP_CODE,
};
}
catch (Exception ex)
{
action.CatchExceptionWithLog(ex, $"系统异常");
}
return action;
}
private ApiAction Confirm(T trans) {
ApiAction action = new ApiAction();
return action;
}
///
/// 添加一个ApiAction的历史记录
///
///
public override void AddHistory(Microsoft.AspNetCore.Http.HttpRequest request, ApiAction action)
{
var his = action.History();
//his.TraceDic.Add("CurReqType", CurReqType);
//his.TraceDic.Add("CurInv", CurInv);
//his.TraceDic.Add("req", req);
//his.TraceDic.Add("toMes", toMes);
//his.TraceDic.Add("CurPoolList", CurPoolList);
ActionHistoryList.Add($"{request.HttpContext.TraceIdentifier} at {action.Timestamp:yyyy/MM/dd HH:mm:ss.fff}: {request.Path}", his);
LastActionTime = DateTime.Now;
}
#endregion
public override bool Close(bool needSaveHistoryLog = false)
{
//needSaveHistoryLog = true;
//保存操作日志
this.IsFinished = true;
return IsFinished ? base.Close(needSaveHistoryLog) : IsFinished;
}
}//endClass
}