diff --git a/src/main/java/com/letian/modules/pda/dao/impl/ProcedureDaoImpl.java b/src/main/java/com/letian/modules/pda/dao/impl/ProcedureDaoImpl.java index ae64f00..ebcb4d2 100644 --- a/src/main/java/com/letian/modules/pda/dao/impl/ProcedureDaoImpl.java +++ b/src/main/java/com/letian/modules/pda/dao/impl/ProcedureDaoImpl.java @@ -13,8 +13,16 @@ import org.springframework.stereotype.Repository; import java.math.BigDecimal; import java.sql.*; import java.sql.Date; -import java.util.*; -import java.util.logging.Logger; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Collections; +import java.util.HashMap; +import java.util.IdentityHashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.slf4j.Logger; /** * @@ -27,60 +35,98 @@ import java.util.logging.Logger; @Repository public class ProcedureDaoImpl implements ProcedureDao { + private static final Logger log = LoggerFactory.getLogger(ProcedureDaoImpl.class); @Autowired private JdbcTemplate jdbcTemplate; - + + /** + * 输出 JDBC/SQL Server 异常链(含 SQLException.getNextException),便于定位库端真实报错。rqrq + */ + private void logJdbcThrowableChain(String context, Throwable throwable) { + if (throwable == null) { + return; + } + Throwable t = throwable; + Set seen = Collections.newSetFromMap(new IdentityHashMap<>()); + int depth = 0; + while (t != null && !seen.contains(t) && depth < 50) { + seen.add(t); + log.error("{} 异常链 depth={} class={} message={}", context, depth, t.getClass().getName(), t.getMessage()); + if (t instanceof SQLException) { + SQLException next = ((SQLException) t).getNextException(); + int nx = 0; + while (next != null && nx < 20) { + log.error("{} SQLException.getNextException[{}] SQLState={} errorCode={} message={}", context, nx, + next.getSQLState(), next.getErrorCode(), next.getMessage()); + next = next.getNextException(); + nx++; + } + } + t = t.getCause(); + depth++; + } + } @Override public List> soReceiveFgRmBackflush(String site, String orderNo, Date transDate, String transNo, float itemNo, float oldQty, float newQty, String OrderType, String userId, String receiver, String partnerId) { - return jdbcTemplate.execute(new CallableStatementCreator() { - - @Override - public CallableStatement createCallableStatement(Connection con) throws SQLException { - String sql = "EXEC SO_Receive_FG_RMBackflush ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?"; - CallableStatement cs = con.prepareCall(sql); - cs.setString(1, site); - cs.setString(2, orderNo); - cs.setDate(3, transDate); - cs.setString(4, transNo); - cs.setFloat(5, itemNo); - cs.setFloat(6, oldQty); - cs.setFloat(7, newQty); - cs.setString(8, OrderType); - cs.setString(9, userId); - cs.setString(10, receiver); - cs.setString(11, partnerId); - return cs; - } - }, new CallableStatementCallback>>() { + final String ctx = "SO_Receive_FG_RMBackflush site=" + site + " orderNo=" + orderNo + " transNo=" + transNo; + log.info( + "SO_Receive_FG_RMBackflush 入参 site={} orderNo={} transDate={} transNo={} itemNo={} oldQty={} newQty={} OrderType={} userId={} receiver={} partnerId={}", + site, orderNo, transDate, transNo, itemNo, oldQty, newQty, OrderType, userId, receiver, partnerId); + try { + return jdbcTemplate.execute(new CallableStatementCreator() { - @Override - public List> doInCallableStatement(CallableStatement cs) - throws SQLException, DataAccessException { - List> resultList = new ArrayList<>(); - ResultSet rs = cs.executeQuery(); - ResultSetMetaData rsmd = rs.getMetaData(); - int columns = rsmd.getColumnCount(); - //处理列名 - Map columnMap = new HashMap<>(); - for(int i = 1; i <= columns; i++){ - columnMap.put(rsmd.getColumnName(i), null); + @Override + public CallableStatement createCallableStatement(Connection con) throws SQLException { + String sql = "EXEC SO_Receive_FG_RMBackflush ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?"; + CallableStatement cs = con.prepareCall(sql); + cs.setString(1, site); + cs.setString(2, orderNo); + cs.setDate(3, transDate); + cs.setString(4, transNo); + cs.setFloat(5, itemNo); + cs.setFloat(6, oldQty); + cs.setFloat(7, newQty); + cs.setString(8, OrderType); + cs.setString(9, userId); + cs.setString(10, receiver); + cs.setString(11, partnerId); + return cs; } - //循环处理数据 - while(rs.next()){ - Map resultMap = new HashMap(); - //循环出当前行的所有数据 - for(String str : columnMap.keySet()){ - resultMap.put(str, rs.getObject(str)); + }, new CallableStatementCallback>>() { + + @Override + public List> doInCallableStatement(CallableStatement cs) + throws SQLException, DataAccessException { + List> resultList = new ArrayList<>(); + ResultSet rs = cs.executeQuery(); + ResultSetMetaData rsmd = rs.getMetaData(); + int columns = rsmd.getColumnCount(); + //处理列名 + Map columnMap = new HashMap<>(); + for (int i = 1; i <= columns; i++) { + columnMap.put(rsmd.getColumnName(i), null); } - resultList.add(resultMap); + //循环处理数据 + while (rs.next()) { + Map resultMap = new HashMap(); + //循环出当前行的所有数据 + for (String str : columnMap.keySet()) { + resultMap.put(str, rs.getObject(str)); + } + resultList.add(resultMap); + } + return resultList; } - return resultList; - } - }); + }); + } catch (RuntimeException ex) { + log.error("{} 调用失败(即将抛出)", ctx, ex); + logJdbcThrowableChain(ctx, ex); + throw ex; + } } diff --git a/src/main/java/com/letian/modules/pda/service/impl/OutBoundServiceImpl.java b/src/main/java/com/letian/modules/pda/service/impl/OutBoundServiceImpl.java index 7cc020a..8e10618 100644 --- a/src/main/java/com/letian/modules/pda/service/impl/OutBoundServiceImpl.java +++ b/src/main/java/com/letian/modules/pda/service/impl/OutBoundServiceImpl.java @@ -254,6 +254,21 @@ public class OutBoundServiceImpl implements OutBoundService { String userId = inData.getUserId(); String creditFlag = inData.getCreditFlag(); String palletFlag= inData.getPalletFlag(); + // 出库前重新校验通知单主表CustomerID,防止前端参数不一致。rqrq + List notifyHeaders = outBoundDao.getNotifyHeadersByCon(site, delNotifyNo); + if(notifyHeaders.size() != 1){ + throw new RuntimeException("通知单号:" + delNotifyNo + "不存在或数据异常,不允许保存!"); + } + NotifyHeaderOutData notifyHeader = notifyHeaders.get(0); + String dbCustomerId = notifyHeader.getCustomerId(); + if(dbCustomerId == null || "".equals(dbCustomerId.trim())){ + throw new RuntimeException("通知单号:" + delNotifyNo + "的CustomerID为空,不允许保存!"); + } + if(customerId != null && !"".equals(customerId.trim()) && !dbCustomerId.equals(customerId)){ + logger.warn("outBoundOperation CustomerID不一致,使用数据库值。site={}, delNotifyNo={}, requestCustomerId={}, dbCustomerId={}", + site, delNotifyNo, customerId, dbCustomerId); + } + customerId = dbCustomerId; //生成销售订单号 String salesOrderNo = procedureFunctionDao.getCoDeliveryDelNo(site, new Date()); //CoDelHeader生成数据 diff --git a/src/main/java/com/letian/modules/production/service/impl/PalletServiceImpl.java b/src/main/java/com/letian/modules/production/service/impl/PalletServiceImpl.java index 6c1d7a1..7dc5d2a 100644 --- a/src/main/java/com/letian/modules/production/service/impl/PalletServiceImpl.java +++ b/src/main/java/com/letian/modules/production/service/impl/PalletServiceImpl.java @@ -259,9 +259,17 @@ public class PalletServiceImpl implements PalletService { logger.info("发料"+ qtyList.get(i).getOrderNo()+"开始"); logger.info("发料参数:"+site+";"+qtyList.get(i).getOrderNo()+";"+new java.sql.Date(new Date().getTime())+";"+ transNo+";"+"1f"+";"+"0f"+";"+ qtyList.get(i).getQty()+";"+ "so"+";"+userId+";"+ userId+";"+""); - //先执行生产发料的动作 - List> resultList = procedureDao.soReceiveFgRmBackflush(site, qtyList.get(i).getOrderNo(), new java.sql.Date(new Date().getTime()), transNo, 1f, 0f, - qtyList.get(i).getQty(), "so", userId, userId, ""); + //先执行生产发料的动作(失败时 DAO 会打完整 JDBC/SQL 异常链日志;此处附业务键便于检索)rqrq + List> resultList; + try { + resultList = procedureDao.soReceiveFgRmBackflush(site, qtyList.get(i).getOrderNo(), new java.sql.Date(new Date().getTime()), transNo, 1f, 0f, + qtyList.get(i).getQty(), "so", userId, userId, ""); + } catch (RuntimeException ex) { + logger.error( + "transInPallet 发料存储过程失败 site={} palletNo={} orderNo={} transNo={} qtyIdx={} qty={} userId={}", + site, palletNo, qtyList.get(i).getOrderNo(), transNo, i, qtyList.get(i).getQty(), userId, ex); + throw ex; + } logger.info(resultList.toString()); //判断是否可以继续操作 Map resultMap = resultList.get(0);