Merge remote-tracking branch 'origin/test' into dev-ty1.2

This commit is contained in:
rcx
2026-09-15 09:53:04 +08:00
84 changed files with 5049 additions and 217 deletions
@@ -33,6 +33,7 @@ import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.formula.functions.T;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.text.ParseException;
import java.util.List;
@@ -223,12 +224,13 @@ public class HandoverTaskOrderApplicationService {
* @param handoverTaskOrderDO
* @return Boolean
*/
@Transactional(rollbackFor = Exception.class)
public Boolean completeHandover(HandoverTaskOrderDO handoverTaskOrderDO){
Boolean result = handoverTaskOrderDomainService.completeHandover(handoverTaskOrderDO);
List<MaterialInventoryParamDO> clearoutParamDOs = handoverTaskOrderDomainService.getLastClearoutParamDOs();
// for (MaterialInventoryParamDO paramDO : clearoutParamDOs) {
// materialInventoryApplicationService.pushBillingRecordClearout(paramDO.getMaterialInventoryId(), paramDO.getQuantity());
// }
for (MaterialInventoryParamDO paramDO : clearoutParamDOs) {
materialInventoryApplicationService.pushBillingRecordClearout(paramDO.getMaterialInventoryId(), paramDO.getQuantity());
}
return result;
}
@@ -573,10 +573,11 @@ public class MaterialBaseInfoApplicationService {
normalizeImportBarCodeWhenDuplicateOfHs(row);
fillIdsFromExistingMasterData(row);
fillOrganizationFromShipperIfNeeded(row);
if (!isValidOrgId(row.getOrganizationId()) && isValidOrgId(loginOrgId)) {
// 登录组织优先:以登录账号的组织为准,覆盖货主解析带来的组织,避免用货主组织导致包装规格等主数据查不到
if (isValidOrgId(loginOrgId)) {
row.setOrganizationId(loginOrgId);
}
if (row.getTopOrganizationId() == null && isValidOrgId(loginTopOrgId)) {
if (isValidOrgId(loginTopOrgId)) {
row.setTopOrganizationId(loginTopOrgId);
}
fillOrganizationName(row, loginUser);
@@ -128,10 +128,11 @@ public class MaterialBaseInfoAsyncService {
materialBaseInfoApplicationService.normalizeImportBarCodeWhenDuplicateOfHs(row);
materialBaseInfoApplicationService.fillIdsFromExistingMasterData(row);
materialBaseInfoApplicationService.fillOrganizationFromShipperIfNeeded(row);
if (!isValidOrgId(row.getOrganizationId()) && isValidOrgId(loginOrgId)) {
// 登录组织优先:以登录账号的组织为准,覆盖货主解析带来的组织,避免用货主组织(如2841)导致包装规格等主数据查不到
if (isValidOrgId(loginOrgId)) {
row.setOrganizationId(loginOrgId);
}
if (row.getTopOrganizationId() == null && isValidOrgId(loginTopOrgId)) {
if (isValidOrgId(loginTopOrgId)) {
row.setTopOrganizationId(loginTopOrgId);
}
materialBaseInfoApplicationService.fillOrganizationName(row, loginUser);
@@ -2075,21 +2075,71 @@ public class StockInOrderApplicationService {
r.getMaterialCode(), topOrganizationId, shipperId);
List<MaterialBaseInfoPO> materialList = materialBaseInfoService.queryList(queryDO);
log.info("料号查询结果,查询到 {} 条记录", materialList != null ? materialList.size() : 0);
MaterialBaseInfoPO materialBaseInfoPO = null;
if (materialList != null && !materialList.isEmpty()) {
materialBaseInfoPO = materialList.get(0);
MaterialBaseInfoPO materialBaseInfoPO = pickMaterialByCode(materialList, r.getMaterialCode(), shipperId, order.getShipperName());
// 兜底:按名称解析出的shipperId可能与物料档案shipper_id不一致(系统中存在同名货主账号,
// 按user_name精确匹配解析到了另一个同名列货主),此时去掉货主ID条件再查一次,
// 用物料档案冗余的shipper_name与Excel客户名称等值匹配
if (materialBaseInfoPO == null && StringUtils.isNotBlank(order.getShipperName())) {
MaterialBaseInfoDO fallbackDO = new MaterialBaseInfoDO();
fallbackDO.setMaterialCode(r.getMaterialCode());
if (topOrganizationId != null) {
fallbackDO.setTopOrganizationId(topOrganizationId);
}
List<MaterialBaseInfoPO> fallbackList = materialBaseInfoService.queryList(fallbackDO);
materialBaseInfoPO = pickMaterialByCode(fallbackList, r.getMaterialCode(), null, order.getShipperName());
if (materialBaseInfoPO != null) {
log.warn("导入料号校验:按解析shipperId未匹配到物料,已按档案货主名称兜底匹配。料号: [{}], 解析shipperId: {}, 档案shipperId: {}, 档案shipperName: {}",
r.getMaterialCode(), shipperId, materialBaseInfoPO.getShipperId(), materialBaseInfoPO.getShipperName());
// 以档案货主为准纠正单据货主信息,避免后续shipperParam按错误的shipperId反查覆盖货主名称
if (materialBaseInfoPO.getShipperId() != null) {
shipperId = materialBaseInfoPO.getShipperId();
order.setShipperId(shipperId);
}
if (StringUtils.isNotBlank(materialBaseInfoPO.getShipperCode())) {
order.setShipperCode(materialBaseInfoPO.getShipperCode());
}
if (StringUtils.isNotBlank(materialBaseInfoPO.getShipperName())) {
order.setShipperName(materialBaseInfoPO.getShipperName());
}
}
}
if (materialBaseInfoPO != null) {
materialBaseInfoId = materialBaseInfoPO.getMaterialBaseInfoId();
log.info("通过料号查询到物料基础信息,料号: {}, 物料ID: {}, 货主ID: {}",
log.info("通过料号查询到物料基础信息,料号: {}, 物料ID: {}, 货主ID: {}",
r.getMaterialCode(), materialBaseInfoId, shipperId);
} else {
// 如果提供了料号但查询不到(或不属于该货主),直接报错,不允许导入
String errorMsg = String.format("导入失败:该货主下不存在该料号(货主名称=%s,料号=%s)。请确保该料号已在物料管理中创建,且属于该货主",
order.getShipperName(), r.getMaterialCode());
// 诊断对照查询(仅用于日志定位,不影响流程):去掉货主ID条件再查一次,
// 用于区分两类原因:A-按名称解析出的shipperId与物料档案shipper_id不一致(货主错配);
// B-登录人topOrganizationId与物料档案top_organization_id不一致(组织口径不一致)
try {
MaterialBaseInfoDO diagDO = new MaterialBaseInfoDO();
diagDO.setMaterialCode(r.getMaterialCode());
if (topOrganizationId != null) {
diagDO.setTopOrganizationId(topOrganizationId);
}
List<MaterialBaseInfoPO> diagList = materialBaseInfoService.queryList(diagDO);
if (diagList != null && !diagList.isEmpty()) {
MaterialBaseInfoPO diagPo = diagList.get(0);
log.error("导入料号校验诊断:去掉货主条件后可查到物料,判定为货主解析错配(原因A)。料号: [{}], 解析shipperId: {}, 登录topOrganizationId: {}, 物料ID: {}, 档案shipperId: {}, 档案shipperName: {}, 档案topOrganizationId: {}",
r.getMaterialCode(), shipperId, topOrganizationId,
diagPo.getMaterialBaseInfoId(), diagPo.getShipperId(), diagPo.getShipperName(), diagPo.getTopOrganizationId());
} else {
log.error("导入料号校验诊断:去掉货主条件后仍查不到物料,判定为组织口径不一致(原因B)。料号: [{}], 解析shipperId: {}, 登录topOrganizationId: {}",
r.getMaterialCode(), shipperId, topOrganizationId);
}
} catch (Exception diagEx) {
log.warn("导入料号校验诊断查询异常,料号: [{}], 错误: {}", r.getMaterialCode(), diagEx.getMessage());
}
String errorMsg = String.format("导入失败:该货主下不存在该料号(货主名称=%s,料号=%s,解析shipperId=%s,登录topOrganizationId=%s)。请确保该料号已在物料管理中创建,且属于该货主",
order.getShipperName(), r.getMaterialCode(),
shipperId == null ? "" : shipperId, topOrganizationId == null ? "" : topOrganizationId);
log.error(errorMsg);
throw new ServiceException(errorMsg);
}
// 校验料号与规格型号/SKU码一致性:按料号查到档案后逐项比对,任何一项不符直接报对应错误
// 双方(trim后)必须完全一致:Excel留空而档案有值、或Excel填了值而档案为空,均视为不一致报错
// 规格型号trim后)双方必须完全一致:Excel留空而档案有值、或Excel填了值而档案为空,均视为不一致报错
// SKU码:档案条码(barCode)为空时跳过比对(存量档案普遍未维护条码);档案有值时仍严格比对
String excelSpec = StringUtils.trimToEmpty(r.getSpecificationModel());
String dbSpec = StringUtils.trimToEmpty(materialBaseInfoPO.getSpecificationModel());
if (!excelSpec.equals(dbSpec)) {
@@ -2099,7 +2149,7 @@ public class StockInOrderApplicationService {
}
String excelSku = StringUtils.trimToEmpty(r.getSkuCode());
String dbSku = StringUtils.trimToEmpty(materialBaseInfoPO.getBarCode());
if (!excelSku.equals(dbSku)) {
if (StringUtils.isNotEmpty(dbSku) && !excelSku.equals(dbSku)) {
throw new ServiceException(String.format("导入失败:料号[%s](商品名称:%s)SKU码与物料档案不一致(Excel:%s / 档案:%s",
r.getMaterialCode(), r.getMaterialName(),
excelSku.isEmpty() ? "" : excelSku, dbSku.isEmpty() ? "" : dbSku));
@@ -2433,6 +2483,46 @@ public class StockInOrderApplicationService {
return oid != null && loginOrganizationId.equals(oid);
}
/**
* 导入校验:从按料号(SQL为LIKE模糊)查出的物料列表中挑选匹配记录。
* 优先级:料号精确等值优先于模糊命中(避免子串料号误匹配);
* 同级内优先 shipperId 精确匹配,其次 shipperName 等值匹配,最后取排序第一条(与原 get(0) 行为一致)。
*/
private MaterialBaseInfoPO pickMaterialByCode(List<MaterialBaseInfoPO> materialList, String materialCode, Long shipperId, String shipperName) {
if (materialList == null || materialList.isEmpty()) {
return null;
}
String code = StringUtils.trimToEmpty(materialCode);
String name = StringUtils.trimToEmpty(shipperName);
MaterialBaseInfoPO exactCodeFirst = null;
MaterialBaseInfoPO anyFirst = null;
// 第一轮:料号精确等值中优先 shipperId 精确匹配
for (MaterialBaseInfoPO po : materialList) {
if (anyFirst == null) {
anyFirst = po;
}
if (StringUtils.isEmpty(code) || !code.equals(StringUtils.trimToEmpty(po.getMaterialCode()))) {
continue;
}
if (exactCodeFirst == null) {
exactCodeFirst = po;
}
if (shipperId != null && shipperId.equals(po.getShipperId())) {
return po;
}
}
// 第二轮:料号精确等值中按档案货主名称等值匹配
if (StringUtils.isNotEmpty(name)) {
for (MaterialBaseInfoPO po : materialList) {
if (StringUtils.isNotEmpty(code) && code.equals(StringUtils.trimToEmpty(po.getMaterialCode()))
&& name.equals(StringUtils.trimToEmpty(po.getShipperName()))) {
return po;
}
}
}
return exactCodeFirst != null ? exactCodeFirst : anyFirst;
}
/**
* @description 根据货主名称或编号获取货主ID(用于导入时提前获取货主ID)
* @param shipperName 货主名称
@@ -1032,7 +1032,7 @@ public class MaterialInventoryImpl extends ServiceImpl<MaterialInventoryMapper,
MaterialInventory materialInventory = new MaterialInventory();
materialInventoryPO.setUpdateTime(new Date());
com.mhd.common.core.utils.bean.BeanUtils.copyProperties(materialInventoryPO, materialInventory);
materialInventoryMapper.updateById(materialInventory);
materialInventoryMapper.updateById(materialInventoryPO);
}
}
private void qxff(BigDecimal netWeight, BigDecimal grossWeight, BigDecimal volume, BigDecimal area, BigDecimal quantity, Long materialInventoryId) {
@@ -1130,7 +1130,7 @@ public class MaterialInventoryImpl extends ServiceImpl<MaterialInventoryMapper,
materialInventoryPO.setUpdateTime(new Date());
MaterialInventory materialInventory = new MaterialInventory();
com.mhd.common.core.utils.bean.BeanUtils.copyProperties(materialInventoryPO, materialInventory);
materialInventoryMapper.updateById(materialInventory);
materialInventoryMapper.updateById(materialInventoryPO);
Long warehouseId = materialInventoryPO.getWarehouseId();
boolean needPush = false;
@@ -893,7 +893,9 @@ public class StockShelfOrderDomainService {
//修改入库单状态: 1-已创建 2-已审核 3-收货中 4-上架中 5-已入库
updateStockInOrder(stockShelfOrderPO, 5);
//上架修改物料库存
List<ShelfMaterialDetail> shelfMaterialDetailList = shelfMaterialDetailService.list(new QueryWrapper<ShelfMaterialDetail>().lambda().eq(ShelfMaterialDetail::getShelfOrderNumber, stockShelfOrderPO.getShelfOrderNumber()));
List<ShelfMaterialDetail> shelfMaterialDetailList = shelfMaterialDetailService.list(new QueryWrapper<ShelfMaterialDetail>().lambda()
.eq(ShelfMaterialDetail::getShelfOrderNumber, stockShelfOrderPO.getShelfOrderNumber())
.eq(ShelfMaterialDetail::getDelFlag, 1));
//修改库存
StockShelfOrderDO stockShelfOrderDO = new StockShelfOrderDO();
BeanUtils.copyProperties(stockShelfOrderPO, stockShelfOrderDO);
@@ -9,46 +9,46 @@ import org.springframework.context.annotation.Configuration;
/**
* XXL-JOB 配置类
*/
//@Configuration
@Configuration
public class XxlJobConfig {
// private Logger logger = LoggerFactory.getLogger(XxlJobConfig.class);
//
// @Value("${xxl.job.admin.addresses}")
// private String adminAddresses;
//
// @Value("${xxl.job.accessToken}")
// private String accessToken;
//
// @Value("${xxl.job.executor.appname}")
// private String appname;
//
// @Value("${xxl.job.executor.address}")
// private String address;
//
// @Value("${xxl.job.executor.ip}")
// private String ip;
//
// @Value("${xxl.job.executor.port}")
// private int port;
//
// @Value("${xxl.job.executor.logpath}")
// private String logPath;
//
// @Value("${xxl.job.executor.logretentiondays}")
// private int logRetentionDays;
//
// @Bean
// public XxlJobSpringExecutor xxlJobExecutor() {
// logger.info(">>>>>>>>>>> xxl-job config init.");
// XxlJobSpringExecutor xxlJobSpringExecutor = new XxlJobSpringExecutor();
// xxlJobSpringExecutor.setAdminAddresses(adminAddresses);
// xxlJobSpringExecutor.setAppname(appname);
// xxlJobSpringExecutor.setAddress(address);
// xxlJobSpringExecutor.setIp(ip);
// xxlJobSpringExecutor.setPort(port);
// xxlJobSpringExecutor.setAccessToken(accessToken);
// xxlJobSpringExecutor.setLogPath(logPath);
// xxlJobSpringExecutor.setLogRetentionDays(logRetentionDays);
// return xxlJobSpringExecutor;
// }
private Logger logger = LoggerFactory.getLogger(XxlJobConfig.class);
@Value("${xxl.job.admin.addresses}")
private String adminAddresses;
@Value("${xxl.job.accessToken}")
private String accessToken;
@Value("${xxl.job.executor.appname}")
private String appname;
@Value("${xxl.job.executor.address}")
private String address;
@Value("${xxl.job.executor.ip}")
private String ip;
@Value("${xxl.job.executor.port}")
private int port;
@Value("${xxl.job.executor.logpath}")
private String logPath;
@Value("${xxl.job.executor.logretentiondays}")
private int logRetentionDays;
@Bean
public XxlJobSpringExecutor xxlJobExecutor() {
logger.info(">>>>>>>>>>> xxl-job config init.");
XxlJobSpringExecutor xxlJobSpringExecutor = new XxlJobSpringExecutor();
xxlJobSpringExecutor.setAdminAddresses(adminAddresses);
xxlJobSpringExecutor.setAppname(appname);
xxlJobSpringExecutor.setAddress(address);
xxlJobSpringExecutor.setIp(ip);
xxlJobSpringExecutor.setPort(port);
xxlJobSpringExecutor.setAccessToken(accessToken);
xxlJobSpringExecutor.setLogPath(logPath);
xxlJobSpringExecutor.setLogRetentionDays(logRetentionDays);
return xxlJobSpringExecutor;
}
}
@@ -1864,7 +1864,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
LEFT JOIN NGWL_TEST_BMS.SETTLEMENT_CUSTOMERS bms ON sys.SETTLEMENT_CUSTOMERS_ID = bms.SETTLEMENT_CUSTOMERS_ID
WHERE
1 = 1
AND CONTRACT_MANAGE_ID = #{contractManageId} AND DEL_FLAG = 1
AND sys.CONTRACT_MANAGE_ID = #{contractManageId} AND sys.DEL_FLAG = 1
</select>