using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Web;
using Curtain.DataAccess;
using Curtain.Log;
using System.Data;
using System.Drawing;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json;
///
/// AutoPacking 的摘要说明
///
public class Packing
{
///
/// 自动生成包装单 toQianrun = -1 不提交到乾润接口 toQianrun = 0 提交到润接口
///
public static int AutoPacking(int toQianrun = -1)
{
int PackingMinQueue = 2;
int PackingMaxQueue = 2;
int AutoPacking = 1;
int result = 1;
//从数据库加载配置
using (IDataAccess conn = DataAccess.Create())
{
//读取包装线配置表
DataTable dt = conn.ExecuteDatatable(@"
SELECT
SETTINGNAME,
SETTINGVALUE
FROM
TP_MST_PACKINGSETTING
WHERE
SETTINGTYPE = 1
"
);
//配置参数保存到Application中
//WareHouseRefreshTime 仓库队列刷新时间
//PackingStart 包装线启动地址
//PackingMinQueue 仓库队列最小值,小于此数值开始自动产生包装单
//PackingMaxQueue 仓库队列最大值,达到此数值,停止产生包装单
//AutoPacking 是否启用自动生成包装单
for (int i = 0; i < dt.Rows.Count; i++)
{
if (dt.Rows[i]["SETTINGNAME"].ToString() == "AutoPacking") AutoPacking = Convert.ToInt32(dt.Rows[i]["SETTINGVALUE"]);
if (dt.Rows[i]["SETTINGNAME"].ToString() == "PackingMinQueue") PackingMinQueue = Convert.ToInt32(dt.Rows[i]["SETTINGVALUE"]);
if (dt.Rows[i]["SETTINGNAME"].ToString() == "PackingMaxQueue") PackingMaxQueue = Convert.ToInt32(dt.Rows[i]["SETTINGVALUE"]);
}
}
//执行自动下单
if (AutoPacking == 1)
{
using (IDataAccess conn = DataAccess.Create())
{
#region 开启事务,默认走1号包装线,包装队列为0
conn.BeginTransaction();
string packingLine = "1";
int packingNum = 0;
int maxOrderNo = 0;
int minOrderNo = 0;
#endregion
#region 读取包装线号,用于判断哪条线队列小,优先走哪条线
//统计包装线队列数量
DataTable dt = conn.ExecuteDatatable(@"
SELECT
L.PACKINGLINE,
NVL( P.MAXORDERNO, 0 ) AS MAXORDERNO,
NVL( P.MINORDERNO, 0 ) AS MINORDERNO,
NVL( P.NUM, 0 ) AS NUM
FROM
(
( SELECT 1 AS PACKINGLINE FROM DUAL UNION SELECT 2 AS PACKINGLINE FROM DUAL ) L
LEFT JOIN (
SELECT
F.PACKINGLINE,
MAX( F.ORDERNO ) AS MAXORDERNO,
MIN( F.ORDERNO ) AS MINORDERNO,
COUNT( * ) AS NUM
FROM
TP_MST_PACKINGFORM F
WHERE
F.STATUS IN ( '-1', '0', '1' ) --统计 未确认-1、队列中0、执行中1 的包装单
GROUP BY
F.PACKINGLINE
) P ON L.PACKINGLINE = P.PACKINGLINE
)
ORDER BY
NUM
"
);
//取包装单最少的包装线,并记录包装单数量
if (dt.Rows.Count > 0)
{
packingLine = dt.Rows[0]["PACKINGLINE"].ToString();
packingNum = Convert.ToInt32(dt.Rows[0]["NUM"]);
maxOrderNo = Convert.ToInt32(dt.Rows[0]["MAXORDERNO"]);
minOrderNo = Convert.ToInt32(dt.Rows[0]["MINORDERNO"]);
}
Logger.Debug("自动生产包装单:线号 = " + packingLine.ToString());
#endregion
#region 读取最小最大队列阀值,确认是否自动生成包装单
//小于最小值时执行自动生成包装单,直到等于最大值停止
if (packingNum < PackingMinQueue)
{
//Logger.Debug((maxQueue - packingNum).ToString());
//生成包装单
for (int i = 0 ; i < PackingMaxQueue - packingNum ; i++)
{
if (result > 0)
{
result = CreatePacking(conn, packingLine, maxOrderNo + i + 1, toQianrun);
Logger.Debug("自动生产包装单:"+ result.ToString());
}
}
//最小化包装单执序号
//MinOrderNo(conn, packingLine, minOrderNo);
}
else
{
Logger.Debug("自动生产包装单:不满足条件");
}
#endregion
#region 执行成功提交,否则回滚
if (result > 0)
conn.Commit();
else
conn.Rollback();
#endregion
}
}
return result;
}
///
/// 按规则生成一个包装单
///
/// 数据连接
/// 包装线
/// 执行顺序
/// 1执行成功,-1执行失败
public static int CreatePacking(IDataAccess conn, string packingLine,int orderNo,int toQianrun = 0)
{
//生成包装单号
string packingFormCode = Guid.NewGuid().ToString();
string packingFormName = "系统自动包装单";
#region 乾润接口读成瓷库存,查找最多数量的产品,生成包装单(现阶段不验证包材充足)
//string goodsCode = "H0175M#CT175PD2210B01";
string goodsCode = "";
int goodsCount = 0;
//读取乾润接口读取
string goodsStr = QianRunApi.GetStorageStatus(1);
JObject json = JObject.Parse(goodsStr);
if (json["success"].ToString().ToLower() == "true")
{
//直接取第一个产品
int goodsIndex = 0;
//智能的只能下1线,9开头的是智能
//待处理========================
//==============================
//验证包材
//待处理========================
//==============================
goodsCode = json["rows"][goodsIndex]["GoodsType"].ToString();
goodsCount = Convert.ToInt32(json["rows"][goodsIndex]["GoodsCount"]);
//测试数据===============================
//goodsCode = "H0175L#CT175PD4210B01";
//goodsCount = 36;
//=======================================
//从队列中(未确定)读取数据,不要与队列产品重复
DataTable dtp = conn.ExecuteDatatable(@"
SELECT G.GOODSCODE||'#'||G.MATERIALCODE AS GOODSCODE FROM TP_MST_PACKINGFORM P LEFT JOIN V_GOODS_MATERIALCODE G ON P.GOODSID = G.GOODSID AND P.MATERIALCODE = G.MATERIALCODE WHERE STATUS = -1
");
if(dtp.Rows.Count>0)
{
string allgoods = ",";
for (int i = 0; i < dtp.Rows.Count; i++) allgoods += dtp.Rows[i]["GOODSCODE"] + ",";
int j = 0;
while(allgoods.IndexOf("," +json["rows"][j]["GoodsType"].ToString() + ",")>=0) j++;
if (j <= json["rows"].Count())
{
//记录不重复的产品
goodsCode = json["rows"][j]["GoodsType"].ToString();
goodsCount = Convert.ToInt32(json["rows"][j]["GoodsCount"]);
}
}
//-----------------------------------------------------------
Logger.Debug("自动生产包装单:产品型号 = " + goodsCode.ToString());
}
else
{
Logger.Debug("自动生产包装单:乾润接口库存数据读取失败!" + goodsStr);
return -1;
}
#endregion
//如果找到可出库的产品
if (goodsCode != "")
{
#region 从包装单配置找默认的包装配置属性
string packingBomId = "";
string goodsSeries = "";
string goodsId = "";
string materialCode = goodsCode.Split('#')[1];
DataTable bom = conn.ExecuteDatatable(@"
SELECT
p.PACKINGBOMID,
g.GOODSID,
p.MATNR,
g.PLATELIMITNUM,
DECODE( g.GOODSTYPEID, 18, 1, 19, 1, 2 ) AS GOODSSERIES
FROM
TP_MST_PACKINGBOM p
-- xuwei modify 2021-05-21 用物料码直接关联,因为可能存在多个产品使用同一BOM配置
--LEFT JOIN TP_MST_GOODS g ON g.GOODSID = p.GOODSID
LEFT JOIN V_GOODS_MATERIALCODE g ON g.MATERIALCODE = p.MATNR
WHERE
p.VALUEFLAG = '1'
AND p.DEFAULTFLAG = '1'
AND g.GOODSCODE = @GOODSCODE@
AND g.MATERIALCODE = @MATERIALCODE@
",
new CDAParameter("GOODSCODE", goodsCode.Split('#')[0]),
new CDAParameter("MATERIALCODE", goodsCode.Split('#')[1])
);
if (bom.Rows.Count > 0)
{
packingBomId = bom.Rows[0]["PACKINGBOMID"].ToString();
goodsId = bom.Rows[0]["GOODSID"].ToString();
goodsSeries = bom.Rows[0]["GOODSSERIES"].ToString();
//不取整板数量,按乾润整道数量直接出
//goodsCount = Convert.ToInt32(bom.Rows[0]["PLATELIMITNUM"]);
Logger.Debug("自动生产包装单:包装配置 = " + packingBomId);
}
else
{
Logger.Debug("自动生产包装单:包装配置单未找到产品" + goodsCode);
return -1;
}
#endregion
#region 写入包装单
int result = conn.ExecuteNonQuery(@"
INSERT INTO TP_MST_PACKINGFORM (
PACKINGFORMCODE,PACKINGFORMNAME,PACKINGLINE,PACKINGBOMID,
ORDERNO,STATUS,PLATENUM,OUTNUM,GOODSID,MATERIALCODE,
ACCOUNTID,CREATEUSERID,UPDATEUSERID
) VALUES (
@PACKINGFORMCODE@,@PACKINGFORMNAME@,@PACKINGLINE@,@PACKINGBOMID@,
@ORDERNO@,@STATUS@,@PLATENUM@,@OUTNUM@,@GOODSID@,@MATERIALCODE@,
@ACCOUNTID@,@CREATEUSERID@,@UPDATEUSERID@
)
",
new CDAParameter("PACKINGFORMCODE", packingFormCode),
new CDAParameter("PACKINGFORMNAME", packingFormName),
new CDAParameter("PACKINGLINE", packingLine),
new CDAParameter("PACKINGBOMID", packingBomId),
new CDAParameter("ORDERNO", orderNo),
new CDAParameter("STATUS", toQianrun), //自动建立的包装单,需要人工确认才能启动 2021-05-10 xuwei
new CDAParameter("PLATENUM", goodsCount),
new CDAParameter("OUTNUM", 0),
new CDAParameter("GOODSID", goodsId),
new CDAParameter("MATERIALCODE", materialCode),
new CDAParameter("ACCOUNTID", 1),
new CDAParameter("CREATEUSERID", 1),
new CDAParameter("UPDATEUSERID", 1)
);
if (result <= 0)
{
Logger.Debug("自动生产包装单:包装单写入失败!");
return -1;
}
else
{
Logger.Debug("自动生产包装单:包装单编码 = " + packingFormCode);
}
#endregion
#region 乾润接口包装单写入,toQianrun==0时调接口,toQianrun==-1时不调用接口
if (toQianrun == 0)
{
string data = QianRunApi.CreateOutStorageOrder(
packingLine,
packingFormCode,
goodsCode,
goodsSeries,
goodsCount,
orderNo,
DateTime.Now.ToString(),
0,0,0
);
JObject jsonOrder = JObject.Parse(data);
if (jsonOrder["Success"].ToString().ToLower() == "false")
{
Logger.Debug("自动生产包装单:乾润接口包装单创建失败!" + data);
return -1;
}
}
#endregion
//写入自动包装单生成日志
Logger.Debug("自动生产包装单" + (toQianrun == -1 ? "(未确认)" : "") + ":" + packingFormCode);
return 1;
}
else
{
//写入自动包装单生成日志
Logger.Debug("自动生产包装单:没有符合的产品");
return 0;
}
}
///
/// 更新出库数量 每次-1 只更新未完成的单子 并更新包装单状态
///
/// 数据连接
/// 包装单号
/// outNum=0执行异常终止操作
/// outNum=0时的异常中止原因
///
public static int updatePackingOutNum(IDataAccess conn,string packingFormCode, string innumcount="",int outNum = 1, string outMesssage="")
{
if (outNum < 0) outNum = 0;
int result = 0;
//20240118 qq 新增参数innumcount ,不传时启用老方式,传值则用新方式,
if (string.IsNullOrEmpty(innumcount))
{
//更新包装单数量
result = conn.ExecuteNonQuery(@"
UPDATE
TP_MST_PACKINGFORM
SET
OUTNUM = OUTNUM + @OUTNUM@
WHERE
STATUS <> 2 --不是完成状态的单子
AND STATUS >= 0 -- 已确认的单子,自动下单未确认的是-1,不能自动开启 2021-05-10
AND PACKINGFORMCODE = @PACKINGFORMCODE@
",
new CDAParameter("OUTNUM", outNum),
new CDAParameter("PACKINGFORMCODE", packingFormCode)
);
}
else
{
//更新包装单数量
DataTable dt = conn.ExecuteDatatable(@"
SELECT
F.PLATENUM
FROM
TP_MST_PACKINGFORM F
WHERE
STATUS <> 2 --不是完成状态的单子
AND STATUS >= 0 -- 已确认的单子,自动下单未确认的是-1,不能自动开启 2021-05-10
AND PACKINGFORMCODE = @PACKINGFORMCODE@
",
new CDAParameter("PACKINGFORMCODE", packingFormCode)
);
if (dt != null && dt.Rows.Count > 0)
{
if (Convert.ToInt32(dt.Rows[0]["PLATENUM"]) < Convert.ToInt32(innumcount))
{
innumcount = dt.Rows[0]["PLATENUM"].ToString();
}
}
result = conn.ExecuteNonQuery(@"
UPDATE
TP_MST_PACKINGFORM
SET
OUTNUM = PLATENUM - @INNUMCOUNT@
WHERE
STATUS <> 2 --不是完成状态的单子
AND STATUS >= 0 -- 已确认的单子,自动下单未确认的是-1,不能自动开启 2021-05-10
AND PACKINGFORMCODE = @PACKINGFORMCODE@
",
new CDAParameter("INNUMCOUNT", Convert.ToInt32(innumcount)),
new CDAParameter("PACKINGFORMCODE", packingFormCode)
);
}
//更新包装单状态
updatePackingStatus(conn, packingFormCode, outNum, outMesssage);
return result;
}
///
/// 计算并更新包装单状态
///
/// 数据连接
/// 包装单号
/// outNum=0执行异常终止操作
/// outNum=0时的异常中止原因
public static void updatePackingStatus(IDataAccess conn,string packingFormCode, int outNum = 1, string outMessage="")
{
//更新包装单为执行中状态,状态是0未开始执行的,有出库数量的,更新为执行中1
conn.ExecuteNonQuery(@"
UPDATE
TP_MST_PACKINGFORM
SET
BEGINTIME = SYSDATE,
STATUS = 1
WHERE
PACKINGFORMCODE = @PACKINGFORMCODE@
AND STATUS = 0
AND OUTNUM > 0
",
new CDAParameter("PACKINGFORMCODE", packingFormCode)
);
//兼容新老系统,不传 outNum,默认为1 ,为正常完成,否则为异常终止
if (outNum > 0)
{
//更新包装单为完成状态,状态是1执行中的,出库数量等于包装单数量的,更新为完成2
conn.ExecuteNonQuery(@"
UPDATE
TP_MST_PACKINGFORM
SET
ENDTIME = SYSDATE,
STATUS = 2
WHERE
PACKINGFORMCODE = @PACKINGFORMCODE@
AND OUTNUM = PLATENUM
AND STATUS = 1
",
new CDAParameter("PACKINGFORMCODE", packingFormCode)
);
}
//更新包装单为强制终止状态,状态是1执行中的,当出库数量等于0的,更新为异常终止3
if(outNum <= 0)
{
if (outMessage == "") outMessage = "异常终止!";
conn.ExecuteNonQuery(@"
UPDATE
TP_MST_PACKINGFORM
SET
ENDTIME = SYSDATE,
STATUS = 3,
REMARKS = @REMARKS@
WHERE
PACKINGFORMCODE = @PACKINGFORMCODE@
AND OUTNUM <> PLATENUM
AND STATUS = 1
",
new CDAParameter("PACKINGFORMCODE", packingFormCode),
new CDAParameter("REMARKS", outMessage)
);
}
}
///
/// 发送包装单给乾润
///
/// 包装单号
///
public static int sendToQianrun(string packingFormCode)
{
using (IDataAccess conn = DataAccess.Create())
{
conn.BeginTransaction();
//写入包装单状态 变更状态为队列中
int result = conn.ExecuteNonQuery(@"
UPDATE TP_MST_PACKINGFORM
SET
STATUS = 0
WHERE
PACKINGFORMCODE = @PACKINGFORMCODE@
",
new CDAParameter("PACKINGFORMCODE", packingFormCode)
);
if (result > 0)
{
//读取包装单必要的参数
DataTable dt = conn.ExecuteDatatable(@"
SELECT
P.PACKINGLINE,
P.PACKINGFORMCODE,
G.GOODSCODE,
G.MATERIALCODE,
DECODE(G.GOODSTYPEID, 18, 1, 19, 1, 2) AS GOODSSERIES,
P.PLATENUM AS GOODSCOUNT,
P.ORDERNO
FROM
TP_MST_PACKINGFORM P
--xuwei modify 2021-05-28
--LEFT JOIN TP_MST_GOODS G ON P.GOODSID = G.GOODSID
LEFT JOIN V_GOODS_MATERIALCODE G ON P.GOODSID = G.GOODSID AND P.MATERIALCODE = G.MATERIALCODE
WHERE
P.PACKINGFORMCODE = @PACKINGFORMCODE@
",
new CDAParameter("PACKINGFORMCODE", packingFormCode)
);
string packingLine = dt.Rows[0]["PACKINGLINE"].ToString();
string goodsCode = dt.Rows[0]["GOODSCODE"].ToString() + "#" + dt.Rows[0]["MATERIALCODE"].ToString();
string goodsSeries = dt.Rows[0]["GOODSSERIES"].ToString();
int goodsCount = Convert.ToInt32(dt.Rows[0]["GOODSCOUNT"]);
int orderNo = Convert.ToInt32(dt.Rows[0]["ORDERNO"]);
//调用乾润接口,发送包装单数据
string data = QianRunApi.CreateOutStorageOrder(
packingLine,
packingFormCode,
goodsCode,
goodsSeries,
goodsCount,
orderNo,
DateTime.Now.ToString(), 0, 0, 0
);
JObject jsonOrder = JObject.Parse(data);
if (jsonOrder["success"].ToString().ToLower() == "false")
{
conn.Rollback();
Logger.Debug("自动生产包装单:发送包装单,乾润接口包装单创建失败!" + data);
return -1;
}
else
{
conn.Commit();
Logger.Debug("自动生产包装单:发送包装单,乾润接口包装单创建成功!" + packingFormCode);
return 1;
}
}
else
{
conn.Rollback();
Logger.Debug("自动生产包装单:发送包装单,没找到包装单 = " + packingFormCode);
return -1;
}
}
}
///
/// 最小化执行顺序号
///
///
///
///
private static void MinOrderNo(IDataAccess conn, string packingLine, int minOrderNo)
{
int result = conn.ExecuteNonQuery(@"
UPDATE TP_MST_PACKINGFORM
SET
ORDERNO = ORDERNO - @MINORDERNO@
WHERE
VALUEFLAG = '1'
AND STATUS IN ('0','1') --统计未开始和执行中的包装单
AND PACKINGLINE = @PACKINGLINE@
",
new CDAParameter("MINORDERNO", minOrderNo),
new CDAParameter("PACKINGLINE", packingLine)
);
}
}