@ -8,7 +8,6 @@ import com.fasterxml.jackson.databind.ObjectMapper;
import com.gaotao.common.exception.XJException ;
import com.gaotao.common.exception.XJException ;
import com.gaotao.common.utils.* ;
import com.gaotao.common.utils.* ;
import com.gaotao.modules.common.i18n.AppI18n ;
import com.gaotao.modules.common.i18n.AppI18n ;
import com.gaotao.modules.api.entity.dto.IfsChangeExpiryDateDto ;
import com.gaotao.modules.api.entity.issueAndReturnVo.InventoryPartVo ;
import com.gaotao.modules.api.entity.issueAndReturnVo.InventoryPartVo ;
import com.gaotao.modules.api.service.IfsApiIssueAndReturnService ;
import com.gaotao.modules.api.service.IfsApiIssueAndReturnService ;
import com.gaotao.modules.api.service.IfsApiService ;
import com.gaotao.modules.api.service.IfsApiService ;
@ -16,7 +15,6 @@ import com.gaotao.modules.factory.dao.AccessSiteMapper;
import com.gaotao.modules.factory.dao.PartAttributeMapper ;
import com.gaotao.modules.factory.dao.PartAttributeMapper ;
import com.gaotao.modules.factory.entity.PartAttribute ;
import com.gaotao.modules.factory.entity.PartAttribute ;
import com.gaotao.modules.factory.entity.Site ;
import com.gaotao.modules.factory.entity.Site ;
import com.gaotao.modules.warehouse.mapper.HandlingUnitSpecialMapper ;
import lombok.extern.slf4j.Slf4j ;
import lombok.extern.slf4j.Slf4j ;
import java.math.RoundingMode ;
import java.math.RoundingMode ;
@ -93,9 +91,6 @@ public class PoServiceImpl extends ServiceImpl<PoMapper, PurchaseOrder> implemen
@Autowired
@Autowired
private IfsApiService ifsApiService ;
private IfsApiService ifsApiService ;
@Autowired
private HandlingUnitSpecialMapper handlingUnitSpecialMapper ;
@Autowired
@Autowired
private AppI18n i18n ;
private AppI18n i18n ;
@ -183,15 +178,23 @@ public class PoServiceImpl extends ServiceImpl<PoMapper, PurchaseOrder> implemen
@Transactional
@Transactional
public String saveTrans ( TransDetailDto inData ) {
public String saveTrans ( TransDetailDto inData ) {
try {
try {
List < InventoryPartVo > parts = ifsApiIssueAndReturnService . getInventoryPart ( inData . getPartNo ( ) , inData . getSite ( ) ) ;
Integer shelfLife = null ; / / 有效期
if ( parts ! = null & & ! parts . isEmpty ( ) ) {
shelfLife = parts . getFirst ( ) . getDurabilityDays ( ) ! = 0 ? parts . getFirst ( ) . getDurabilityDays ( ) : null ;
}
/ / 如果物料没有设置shelfLife , 报错提示 : 请联系工程维护产品有效期 !
if ( shelfLife = = null ) {
/ / 有效期仍要有 : 页面按同一口径预填失效日期 , 没维护时不能入库
if ( resolveShelfLife ( inData . getPartNo ( ) , inData . getSite ( ) ) = = null ) {
throw new XJException ( i18n . text ( "purchase.po.shelfLifeMissing" ) ) ;
throw new XJException ( i18n . text ( "purchase.po.shelfLifeMissing" ) ) ;
}
}
/ / 失效日期以前端提交为准 , 允许在计算结果上改 , 但不能空 、 不能早于今天
if ( inData . getExpiredDate ( ) = = null ) {
throw new XJException ( i18n . text ( "purchase.po.expiredDateRequired" ) ) ;
}
if ( isBeforeToday ( inData . getExpiredDate ( ) ) ) {
String expiredDateText = DateUtils . format ( inData . getExpiredDate ( ) , DateUtils . DATE_PATTERN ) ;
log . warn ( "采购入库失效日期早于当前日期,拒绝入库,poNo={}, partNo={}, expiredDate={}" ,
inData . getPoNo ( ) , inData . getPartNo ( ) , expiredDateText ) ;
throw new XJException ( i18n . text ( "purchase.po.expiredDateBeforeToday" , expiredDateText ) ) ;
}
log . info ( "采购入库使用前端失效日期,poNo={}, partNo={}, expiredDate={}" ,
inData . getPoNo ( ) , inData . getPartNo ( ) ,
DateUtils . format ( inData . getExpiredDate ( ) , DateUtils . DATE_PATTERN ) ) ;
/ / 根据库位获取仓库ID
/ / 根据库位获取仓库ID
String warehouseId = null ;
String warehouseId = null ;
Location location = locationService . getByLocationIdAndSite ( inData . getFuSite ( ) , inData . getLocationNo ( ) ) ;
Location location = locationService . getByLocationIdAndSite ( inData . getFuSite ( ) , inData . getLocationNo ( ) ) ;
@ -199,7 +202,7 @@ public class PoServiceImpl extends ServiceImpl<PoMapper, PurchaseOrder> implemen
warehouseId = location . getWarehouseId ( ) ;
warehouseId = location . getWarehouseId ( ) ;
}
}
/ / 创建采购接收记录 - 在库存更新之前创建
/ / 创建采购接收记录 - 在库存更新之前创建
PoReceiptDetail receiptDetail = createPoReceiptRecords ( inData , shelfLife , warehouseId ) ;
PoReceiptDetail receiptDetail = createPoReceiptRecords ( inData , warehouseId ) ;
String receiptNo = receiptDetail . getReceiptNo ( ) ;
String receiptNo = receiptDetail . getReceiptNo ( ) ;
SysUserEntity currentUser = ( SysUserEntity ) SecurityUtils . getSubject ( ) . getPrincipal ( ) ;
SysUserEntity currentUser = ( SysUserEntity ) SecurityUtils . getSubject ( ) . getPrincipal ( ) ;
String transType = "CRT" ;
String transType = "CRT" ;
@ -237,10 +240,9 @@ public class PoServiceImpl extends ServiceImpl<PoMapper, PurchaseOrder> implemen
} else {
} else {
inData . setNeedHandlingUnit ( "Y" ) ;
inData . setNeedHandlingUnit ( "Y" ) ;
}
}
/ / 创建Handling Unit相关数据 ( 仅收集本次操作生成的HU )
List < HandlingUnit > currentHandlingUnits = new ArrayList < > ( ) ;
/ / 创建Handling Unit相关数据
for ( int i = 0 ; i < inData . getHandlingUnitList ( ) . size ( ) ; i + + ) {
for ( int i = 0 ; i < inData . getHandlingUnitList ( ) . size ( ) ; i + + ) {
currentHandlingUnits . addAll ( handlingUnitPart ( inData , i , transHeader , currentUser , shelfLife , receiptDetail ) ) ;
handlingUnitPart ( inData , i , transHeader , currentUser , receiptDetail ) ;
}
}
/ / 免检更新库存 待检验的出入库记录状态为待检验
/ / 免检更新库存 待检验的出入库记录状态为待检验
/ * if ( "N" . equals ( inData . getNeedCheck ( ) ) ) {
/ * if ( "N" . equals ( inData . getNeedCheck ( ) ) ) {
@ -248,24 +250,8 @@ public class PoServiceImpl extends ServiceImpl<PoMapper, PurchaseOrder> implemen
} * /
} * /
/ / 处理料件属性 ( 创建或更新 )
/ / 处理料件属性 ( 创建或更新 )
handlePartAttribute ( inData ) ;
handlePartAttribute ( inData ) ;
/ / RegisterArrival 的 expirationDate 以本次生成 HU 的失效日期为准 。
/ / 同一批标签按同一基准日和有效期计算 , 取第一条非空日期即可 , 避免和标签不一致 。
for ( HandlingUnit handlingUnit : currentHandlingUnits ) {
if ( handlingUnit . getExpiredDate ( ) ! = null ) {
inData . setExpiredDate ( handlingUnit . getExpiredDate ( ) ) ;
break ;
}
}
/ / 同步到IFS
/ / 同步到IFS , expirationDate 使用前端传入的失效日期
ifsApiService . registerArrivalToIFS ( inData ) ;
ifsApiService . registerArrivalToIFS ( inData ) ;
/ / 当用户选择供应商生产日期时 , 失效日期需要按供应商生产日期 + 有效期重新同步到IFS
/ * if ( inData . getSupplierManufactureDate ( ) ! = null ) {
Date supplierExpiryDate = calculateExpiryDate ( inData . getSupplierManufactureDate ( ) , shelfLife ) ;
if ( supplierExpiryDate ! = null ) {
inData . setExpiredDate ( supplierExpiryDate ) ;
changeExpiryDate ( currentHandlingUnits , inData ) ;
}
} * /
return receiptNo ;
return receiptNo ;
} catch ( Exception e ) {
} catch ( Exception e ) {
log . error ( "采购入库失败,PO号: {}, 错误: {}" , inData . getPoNo ( ) , e . getMessage ( ) ) ;
log . error ( "采购入库失败,PO号: {}, 错误: {}" , inData . getPoNo ( ) , e . getMessage ( ) ) ;
@ -274,9 +260,8 @@ public class PoServiceImpl extends ServiceImpl<PoMapper, PurchaseOrder> implemen
}
}
}
}
private List < HandlingUnit > handlingUnitPart ( TransDetailDto inData , int i , TransHeader transHeader ,
SysUserEntity currentUser , Integer shelfLife , PoReceiptDetail receiptDetail ) {
List < HandlingUnit > createdHandlingUnits = new ArrayList < > ( ) ;
private void handlingUnitPart ( TransDetailDto inData , int i , TransHeader transHeader ,
SysUserEntity currentUser , PoReceiptDetail receiptDetail ) {
TransDetailSubDto huInfo = inData . getHandlingUnitList ( ) . get ( i ) ;
TransDetailSubDto huInfo = inData . getHandlingUnitList ( ) . get ( i ) ;
Date supplierManufactureDate = inData . getSupplierManufactureDate ( ) ;
Date supplierManufactureDate = inData . getSupplierManufactureDate ( ) ;
for ( int j = 0 ; j < huInfo . getPackageQty ( ) ; j + + ) {
for ( int j = 0 ; j < huInfo . getPackageQty ( ) ; j + + ) {
@ -330,37 +315,9 @@ public class PoServiceImpl extends ServiceImpl<PoMapper, PurchaseOrder> implemen
handlingUnit . setBatchNo ( inData . getBatchNo ( ) ) ;
handlingUnit . setBatchNo ( inData . getBatchNo ( ) ) ;
handlingUnit . setLocationId ( inData . getLocationNo ( ) ) ;
handlingUnit . setLocationId ( inData . getLocationNo ( ) ) ;
handlingUnit . setWarehouseId ( transHeader . getWarehouseId ( ) ) ;
handlingUnit . setWarehouseId ( transHeader . getWarehouseId ( ) ) ;
/ / 记下参与计算的基准日 , 过期时报错要告诉用户是供应商生产日期还是到达日期导致的
String expiryBaseName = null ;
Date expiryBaseDate = null ;
if ( shelfLife = = null | | shelfLife = = 0 ) {
handlingUnit . setExpiredDate ( null ) ;
} else if ( inData . getSupplierManufactureDate ( ) ! = null ) {
/ / 有供应商生产日期时优先用它推算 , 页面字段同名
expiryBaseName = i18n . text ( "purchase.po.expiryBaseSupplierManufactureDate" ) ;
expiryBaseDate = inData . getSupplierManufactureDate ( ) ;
java . util . Calendar calendar = java . util . Calendar . getInstance ( ) ;
calendar . setTime ( expiryBaseDate ) ;
calendar . add ( java . util . Calendar . DAY_OF_YEAR , shelfLife ) ;
handlingUnit . setExpiredDate ( calendar . getTime ( ) ) ;
} else if ( inData . getArrivalDate ( ) ! = null ) {
/ / 没有供应商生产日期才退回到达日期 , 避免两套基准日同时参与计算
expiryBaseName = i18n . text ( "purchase.po.expiryBaseArrivalDate" ) ;
expiryBaseDate = inData . getArrivalDate ( ) ;
java . util . Calendar calendar = java . util . Calendar . getInstance ( ) ;
calendar . setTime ( expiryBaseDate ) ;
calendar . add ( java . util . Calendar . DAY_OF_YEAR , shelfLife ) ;
handlingUnit . setExpiredDate ( calendar . getTime ( ) ) ;
}
/ / 按自然日比较 : 当天仍可入库 , 早于今天说明物料已过期 , 必须拦住 , 避免过期料进入库存
if ( isBeforeToday ( handlingUnit . getExpiredDate ( ) ) ) {
String expiredDateText = DateUtils . format ( handlingUnit . getExpiredDate ( ) , DateUtils . DATE_PATTERN ) ;
String baseDateText = DateUtils . format ( expiryBaseDate , DateUtils . DATE_PATTERN ) ;
log . warn ( "采购入库失效日期早于当前日期,拒绝入库,poNo={}, partNo={}, baseDateName={}, baseDate={}, shelfLife={}, expiredDate={}" ,
inData . getPoNo ( ) , inData . getPartNo ( ) , expiryBaseName , baseDateText , shelfLife , expiredDateText ) ;
throw new XJException ( i18n . text ( "purchase.po.expiredDateBeforeToday" ,
expiryBaseName , baseDateText , shelfLife , expiredDateText ) ) ;
}
/ / 失效日期以前端提交为准 。 页面按供应商生产日期优先 、 否则到达日期 , 再加有效期预填 , 用户可改 。
/ / 标签必须和接收明细 、 IFS 用同一天 , 否则手改后会对不上 。
handlingUnit . setExpiredDate ( inData . getExpiredDate ( ) ) ;
handlingUnit . setWdr ( inData . getWdr ( ) ! = null ? inData . getWdr ( ) : "*" ) ;
handlingUnit . setWdr ( inData . getWdr ( ) ! = null ? inData . getWdr ( ) : "*" ) ;
handlingUnit . setStatus ( "ACTIVE" ) ;
handlingUnit . setStatus ( "ACTIVE" ) ;
handlingUnit . setStatusDb ( "ACTIVE" ) ;
handlingUnit . setStatusDb ( "ACTIVE" ) ;
@ -428,9 +385,7 @@ public class PoServiceImpl extends ServiceImpl<PoMapper, PurchaseOrder> implemen
huInfo . getPerQty ( ) , currentUser . getUserDisplay ( ) ,
huInfo . getPerQty ( ) , currentUser . getUserDisplay ( ) ,
"Y" , "保存成功"
"Y" , "保存成功"
) ;
) ;
createdHandlingUnits . add ( handlingUnit ) ;
}
}
return createdHandlingUnits ;
}
}
private void genInventoryStock ( TransDetailDto inData , TransHeader transHeader , PoReceiptDetail receiptDetail ) {
private void genInventoryStock ( TransDetailDto inData , TransHeader transHeader , PoReceiptDetail receiptDetail ) {
@ -534,80 +489,6 @@ public class PoServiceImpl extends ServiceImpl<PoMapper, PurchaseOrder> implemen
}
}
}
}
private void changeExpiryDate ( List < HandlingUnit > handlingUnits , TransDetailDto inData ) {
if ( handlingUnits = = null | | handlingUnits . isEmpty ( ) ) {
log . warn ( "供应商生产日期模式下未查询到标签信息,跳过失效日期同步,transNo={}" , inData . getTransNo ( ) ) ;
return ;
}
if ( inData . getExpiredDate ( ) = = null ) {
log . warn ( "供应商生产日期模式下失效日期为空,跳过失效日期同步,transNo={}" , inData . getTransNo ( ) ) ;
return ;
}
String ifsExpiryDate = DateUtils . format ( inData . getExpiredDate ( ) , DateUtils . DATE_PATTERN ) ;
String modifiedBy = "SYSTEM" ;
try {
SysUserEntity currentUser = ( SysUserEntity ) SecurityUtils . getSubject ( ) . getPrincipal ( ) ;
if ( currentUser ! = null & & StringUtils . isNotBlank ( currentUser . getUserDisplay ( ) ) ) {
modifiedBy = currentUser . getUserDisplay ( ) ;
}
} catch ( Exception e ) {
log . warn ( "获取当前用户失败,失效日期同步将使用默认操作人" ) ;
}
/ / 参考标签特殊信息批量修改逻辑 , 按库存关键字去重后调用IFS
Map < String , HandlingUnit > inventoryKeyMap = new LinkedHashMap < > ( ) ;
for ( HandlingUnit item : handlingUnits ) {
String key = buildInventoryKey ( item ) ;
if ( ! inventoryKeyMap . containsKey ( key ) ) {
inventoryKeyMap . put ( key , item ) ;
}
}
log . info ( "供应商生产日期模式开始同步失效日期,标签数:{},去重后调用次数:{},新失效日期:{}" ,
handlingUnits . size ( ) , inventoryKeyMap . size ( ) , ifsExpiryDate ) ;
for ( HandlingUnit item : inventoryKeyMap . values ( ) ) {
try {
IfsChangeExpiryDateDto dto = new IfsChangeExpiryDateDto ( ) ;
dto . setIfsSiteID ( item . getSite ( ) ) ;
dto . setIfsPartNo ( item . getPartNo ( ) ) ;
dto . setIfsLocationNo ( item . getLocationId ( ) ) ;
dto . setIfsLotBatchNo ( item . getBatchNo ( ) ) ;
dto . setIfsWdrNo ( StringUtils . isNotBlank ( item . getWdr ( ) ) ? item . getWdr ( ) : "*" ) ;
dto . setIfsEngChgLevel ( StringUtils . isNotBlank ( item . getEngChgLevel ( ) ) ? item . getEngChgLevel ( ) : "1" ) ;
dto . setIfsExpiryDate ( ifsExpiryDate ) ;
ifsApiService . changeExpiryDate ( dto ) ;
int updatedRows = handlingUnitSpecialMapper . updateExpiryDateByInventoryKey (
item . getSite ( ) ,
item . getPartNo ( ) ,
item . getLocationId ( ) ,
item . getBatchNo ( ) ,
StringUtils . isNotBlank ( item . getWdr ( ) ) ? item . getWdr ( ) : "*" ,
StringUtils . isNotBlank ( item . getEngChgLevel ( ) ) ? item . getEngChgLevel ( ) : "1" ,
ifsExpiryDate ,
modifiedBy
) ;
log . info ( "失效日期同步成功,unitId={},影响行数={}" , item . getUnitId ( ) , updatedRows ) ;
} catch ( Exception e ) {
log . error ( "失效日期同步失败,unitId={},error={}" , item . getUnitId ( ) , e . getMessage ( ) , e ) ;
}
}
}
private String buildInventoryKey ( HandlingUnit item ) {
return String . join ( "|" ,
item . getSite ( ) ! = null ? item . getSite ( ) : "" ,
item . getPartNo ( ) ! = null ? item . getPartNo ( ) : "" ,
item . getLocationId ( ) ! = null ? item . getLocationId ( ) : "" ,
item . getBatchNo ( ) ! = null ? item . getBatchNo ( ) : "" ,
item . getWdr ( ) ! = null ? item . getWdr ( ) : "" ,
item . getEngChgLevel ( ) ! = null ? item . getEngChgLevel ( ) : ""
) ;
}
/ * *
/ * *
* 失效日期早于今天则视为已过期 。 只比较自然日 , 当天不算过期 。
* 失效日期早于今天则视为已过期 。 只比较自然日 , 当天不算过期 。
* /
* /
@ -630,20 +511,30 @@ public class PoServiceImpl extends ServiceImpl<PoMapper, PurchaseOrder> implemen
return expired . before ( today ) ;
return expired . before ( today ) ;
}
}
private Date calculateExpiryDate ( Date baseDate , Integer shelfLife ) {
if ( baseDate = = null | | shelfLife = = null | | shelfLife < = 0 ) {
return null ;
/ * *
* 取 IFS 物料有效期天数 。 0 视为未维护 , 和入库校验口径一致 。
* /
private Integer resolveShelfLife ( String partNo , String site ) {
List < InventoryPartVo > parts = ifsApiIssueAndReturnService . getInventoryPart ( partNo , site ) ;
if ( parts ! = null & & ! parts . isEmpty ( ) & & parts . getFirst ( ) . getDurabilityDays ( ) ! = 0 ) {
return parts . getFirst ( ) . getDurabilityDays ( ) ;
}
return null ;
}
@Override
public Integer getPartShelfLife ( String partNo , String site ) {
Integer shelfLife = resolveShelfLife ( partNo , site ) ;
if ( shelfLife = = null ) {
throw new XJException ( i18n . text ( "purchase.po.shelfLifeMissing" ) ) ;
}
}
Calendar calendar = Calendar . getInstance ( ) ;
calendar . setTime ( baseDate ) ;
calendar . add ( Calendar . DAY_OF_YEAR , shelfLife ) ;
return calendar . getTime ( ) ;
return shelfLife ;
}
}
/ * *
/ * *
* 创建采购接收记录
* 创建采购接收记录
* /
* /
private PoReceiptDetail createPoReceiptRecords ( TransDetailDto inData , Integer shelfLife , String warehouseId ) {
private PoReceiptDetail createPoReceiptRecords ( TransDetailDto inData , String warehouseId ) {
/ / 生成接收单号
/ / 生成接收单号
TransNoControl receiptNoControl = transNoService . getTransNo ( inData . getSite ( ) , "PR" , 10 ) ;
TransNoControl receiptNoControl = transNoService . getTransNo ( inData . getSite ( ) , "PR" , 10 ) ;
String receiptNo = receiptNoControl . getNewTransNo ( ) ;
String receiptNo = receiptNoControl . getNewTransNo ( ) ;
@ -777,22 +668,8 @@ public class PoServiceImpl extends ServiceImpl<PoMapper, PurchaseOrder> implemen
if ( inData . getManufactureDate ( ) ! = null ) {
if ( inData . getManufactureDate ( ) ! = null ) {
poReceiptDetail . setManuFactureDate ( inData . getManufactureDate ( ) ) ;
poReceiptDetail . setManuFactureDate ( inData . getManufactureDate ( ) ) ;
}
}
/ / 失效日期是根据生产日期ManufactureDate + 有效期计算 , 如果生产日期为空 , 再用接收日期arrivalDate + 有效期 , 如果有效期为空 , 失效日期就为空
if ( shelfLife = = null | | shelfLife = = 0 ) {
poReceiptDetail . setExpiredDate ( null ) ;
} else if ( inData . getManufactureDate ( ) ! = null ) {
/ / 如果有制造日期 , 计算失效日期
java . util . Calendar calendar = java . util . Calendar . getInstance ( ) ;
calendar . setTime ( inData . getManufactureDate ( ) ) ;
calendar . add ( java . util . Calendar . DAY_OF_YEAR , shelfLife ) ;
poReceiptDetail . setExpiredDate ( calendar . getTime ( ) ) ;
} else if ( inData . getArrivalDate ( ) ! = null ) {
/ / 如果制造日期 , 但有接收日期 , 尝试用接收日期计算
java . util . Calendar calendar = java . util . Calendar . getInstance ( ) ;
calendar . setTime ( inData . getArrivalDate ( ) ) ;
calendar . add ( java . util . Calendar . DAY_OF_YEAR , shelfLife ) ;
poReceiptDetail . setExpiredDate ( calendar . getTime ( ) ) ;
}
/ / 接收明细与标签 、 IFS 共用前端传入的失效日期 , 不再按制造日期重算
poReceiptDetail . setExpiredDate ( inData . getExpiredDate ( ) ) ;
poReceiptDetail . setDeliveryDate ( inData . getDeliveryDate ( ) ) ;
poReceiptDetail . setDeliveryDate ( inData . getDeliveryDate ( ) ) ;
poReceiptDetail . setArrivalDate ( inData . getArrivalDate ( ) ) ;
poReceiptDetail . setArrivalDate ( inData . getArrivalDate ( ) ) ;
poReceiptDetail . setSupplierBatchNo ( inData . getSupplierBatchNo ( ) ) ;
poReceiptDetail . setSupplierBatchNo ( inData . getSupplierBatchNo ( ) ) ;