no message

main
HUOJIN\92525 2026-03-08 20:44:38 +08:00
parent 070fc764a1
commit 1e9854747d
28 changed files with 469 additions and 303 deletions

View File

@ -1,4 +1,4 @@
package org.cpte.modules.utils;
package org.cpte.common.util;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;

View File

@ -24,7 +24,7 @@ import java.util.Map;
*/
@FeignClient(
name = "wms-basic-service",
url = "${feign.client.wms-basic.url:http://wms-basic-service:80}",
url = "${feign.client.wms-basic.url:http://wms-basic-service:8001}",
configuration = FeignClientConfiguration.class,
fallbackFactory = BasicServiceFallbackFactory.class
)

View File

@ -16,6 +16,11 @@ import java.util.concurrent.TimeUnit;
@Configuration
public class FeignClientConfiguration {
@Bean
public FeignTokenInterceptor feignTokenInterceptor() {
return new FeignTokenInterceptor();
}
/**
* Feign 使 OkHttp HTTP
* @return OkHttp

View File

@ -0,0 +1,35 @@
package org.cpte.feign.config;
import feign.RequestInterceptor;
import feign.RequestTemplate;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
/**
* Feign Token
* Feign X-Access-Token
*/
@Slf4j
public class FeignTokenInterceptor implements RequestInterceptor {
@Override
public void apply(RequestTemplate template) {
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
if (attributes != null) {
HttpServletRequest request = attributes.getRequest();
String token = request.getHeader("X-Access-Token");
if (token == null) {
token = request.getParameter("token");
}
if (token != null && !token.isEmpty()) {
template.header("X-Access-Token", token);
} else {
log.error("Feign 请求未找到 Token请求头{}", request.getHeaderNames());
}
} else {
log.error("Feign 请求无法获取 RequestContext可能是在非 Web 环境中调用");
}
}
}

View File

@ -26,7 +26,7 @@ import java.util.Map;
@SpringBootApplication(scanBasePackages = {"org.jeecg","org.cpte","org.cpte.modules"})
@EnableAutoConfiguration(exclude = {MongoAutoConfiguration.class})
@ImportAutoConfiguration(JustAuthAutoConfiguration.class) // spring boot 3.x justauth 兼容性处理
@EnableFeignClients(basePackages = {"org.cpte.feign.client"}) // 启用 Feign 客户端
@EnableFeignClients(basePackages = {"org.cpte.feign"}) // 启用 Feign 客户端,包含 client 和 config 包
public class WmsBasicApplication extends SpringBootServletInitializer {
@Override

View File

@ -26,7 +26,7 @@ import java.util.Map;
@SpringBootApplication(scanBasePackages = {"org.jeecg", "org.cpte", "org.cpte.modules"})
@EnableAutoConfiguration(exclude = {MongoAutoConfiguration.class})
@ImportAutoConfiguration(JustAuthAutoConfiguration.class) // spring boot 3.x justauth 兼容性处理
@EnableFeignClients(basePackages = {"org.cpte.feign.client"}) // 启用 Feign 客户端
@EnableFeignClients(basePackages = {"org.cpte.feign"}) // 启用 Feign 客户端,包含 client 和 config 包
public class WmsInboundApplication extends SpringBootServletInitializer {
@Override

View File

@ -10,6 +10,7 @@ import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.cpte.modules.inbound.mapper.AsnDetailMapper;
import org.cpte.modules.inbound.request.ReceiveRequest;
import org.jeecgframework.poi.excel.ExcelImportUtil;
import org.jeecgframework.poi.excel.def.NormalExcelConstants;
import org.jeecgframework.poi.excel.entity.ExportParams;
@ -285,4 +286,17 @@ public class AsnController {
}
}
@AutoLog(value = "收货整理")
@Operation(summary = "收货整理")
@RequiresPermissions("inbound:data_asn:receive")
@PostMapping(value = "/receive")
public Result<String> receive(@RequestBody ReceiveRequest request) {
try {
asnService.receive(request);
return Result.OK("操作成功");
} catch (Exception e) {
return Result.error("收货整理异常:" + e.getMessage());
}
}
}

View File

@ -11,7 +11,6 @@ import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.jeecgframework.poi.excel.annotation.Excel;
import org.springframework.format.annotation.DateTimeFormat;
import java.io.Serializable;

View File

@ -32,7 +32,7 @@ public interface AsnDetailMapper extends BaseMapper<AsnDetail> {
List<AsnDetail> selectByMainId(@Param("mainId") Long mainId);
/**
* id
* ids
*
* @param asnIds id
* @return List<AsnDetail>
@ -49,4 +49,11 @@ public interface AsnDetailMapper extends BaseMapper<AsnDetail> {
*/
List<AsnDetail> queryByStockCode(@Param("stockId") Long stockId, @Param("status") Integer status);
/**
*
*
* @param asnIds id
*/
void deleteByBatchAsnIds(@Param("asnIds") List<Long> asnIds);
}

View File

@ -0,0 +1,30 @@
package org.cpte.modules.inbound.request;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import lombok.Data;
import java.io.Serializable;
/**
* @Description:
* @author: cpte
* @Date: 2026-03-08
* @Version: V1.0
*/
@Data
@Schema(description = "收货参数")
public class ReceiveRequest implements Serializable {
@NotBlank(message = "物料编码不能为空")
@Schema(description = "物料编码")
private String itemCode;
@NotBlank(message = "库位编码不能为空")
@Schema(description = "库位编码")
private String pointCode;
@NotBlank(message = "容器编码不能为空")
@Schema(description = "容器编码")
private String stockCode;
}

View File

@ -2,7 +2,7 @@ package org.cpte.modules.inbound.rule;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.cpte.modules.utils.CodeGeneratorUtil;
import org.cpte.common.util.CodeGeneratorUtil;
import org.jeecg.common.handler.IFillRuleHandler;
import org.jeecg.modules.system.mapper.SysFillRuleMapper;
import org.springframework.beans.factory.annotation.Autowired;

View File

@ -33,15 +33,6 @@ public interface IAsnDetailService extends IService<AsnDetail> {
*/
Map<Long, Asn> queryByAsnIdsToMap(List<Long> asnIds);
/**
*
*
* @param asn
* @param asnDetailList
*/
void processorSaveMain(Asn asn, List<AsnDetail> asnDetailList);
/**
*
*
@ -50,16 +41,4 @@ public interface IAsnDetailService extends IService<AsnDetail> {
*/
void refreshAsn(Asn asn, List<AsnDetail> asnDetails);
/**
*
*
* @param asnDetail
* @param receivedQty
* @param itemKey
* @param dstPointId ID
* @return ReceiveRecord
*/
ReceiveRecord buildReceiveRecord(AsnDetail asnDetail, BigDecimal receivedQty, ItemKeyDTO itemKey, Long dstPointId);
}

View File

@ -4,6 +4,8 @@ package org.cpte.modules.inbound.service;
import org.cpte.modules.inbound.entity.AsnDetail;
import org.cpte.modules.inbound.entity.Asn;
import com.baomidou.mybatisplus.extension.service.IService;
import org.cpte.modules.inbound.request.ReceiveRequest;
import java.io.Serializable;
import java.util.Collection;
import java.util.List;
@ -22,7 +24,7 @@ public interface IAsnService extends IService<Asn> {
* @param asn
* @param asnDetailList
*/
public void saveMain(Asn asn, List<AsnDetail> asnDetailList);
void saveMain(Asn asn, List<AsnDetail> asnDetailList);
/**
*
@ -30,21 +32,28 @@ public interface IAsnService extends IService<Asn> {
* @param asn
* @param asnDetailList
*/
public void updateMain(Asn asn, List<AsnDetail> asnDetailList);
void updateMain(Asn asn, List<AsnDetail> asnDetailList);
/**
*
*
* @param id
*/
public void delMain(Long id);
void delMain(Long id);
/**
*
*
* @param idList
*/
public void delBatchMain(Collection<? extends Serializable> idList);
void delBatchMain(Collection<? extends Serializable> idList);
/**
*
*
* @param request
*/
void receive(ReceiveRequest request);
/**
*

View File

@ -0,0 +1,70 @@
package org.cpte.modules.inbound.service.impl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.cpte.modules.inbound.entity.Asn;
import org.cpte.modules.inbound.mapper.AsnDetailMapper;
import org.cpte.modules.inbound.mapper.AsnMapper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
/**
* @Description:
* @author: cpte
* @Date: 2026-03-08
* @Version: V1.0
*/
@Service
@Slf4j
@RequiredArgsConstructor
public class AsnDataProcessor {
private final AsnDetailMapper asnDetailMapper;
private final AsnMapper asnMapper;
/**
*
*
* @param asn
*/
@Transactional(rollbackFor = Exception.class)
public void saveAsn(Asn asn) {
asnMapper.insert(asn);
}
/**
*
*
* @param asn
*/
@Transactional(rollbackFor = Exception.class)
public void updateAsn(Asn asn) {
asnMapper.updateById(asn);
}
/**
*
*
* @param asnIds ID
*/
@Transactional(rollbackFor = Exception.class)
public void batchDeleteAsn(List<Long> asnIds) {
asnDetailMapper.deleteByBatchAsnIds(asnIds);
asnMapper.deleteByIds(asnIds);
}
/**
*
*
* @param asnId ID
*/
@Transactional(rollbackFor = Exception.class)
public void deleteAsn(Long asnId) {
asnDetailMapper.deleteByMainId(asnId);
asnMapper.deleteById(asnId);
}
}

View File

@ -19,6 +19,7 @@ import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
@ -36,10 +37,6 @@ public class AsnDetailServiceImpl extends ServiceImpl<AsnDetailMapper, AsnDetail
@Autowired
private AsnMapper asnMapper;
@Autowired
private AsnSerialNumberRule asnSerialNumberRule;
@Override
public List<AsnDetail> selectByMainId(Long mainId) {
return this.baseMapper.selectByMainId(mainId);
@ -59,87 +56,42 @@ public class AsnDetailServiceImpl extends ServiceImpl<AsnDetailMapper, AsnDetail
}
@Override
@Transactional(rollbackFor = Exception.class)
public void processorSaveMain(Asn asn, List<AsnDetail> asnDetailList) {
LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
asn.setTenantId(Long.parseLong(sysUser.getRelTenantIds()));
asn.setSysOrgCode(sysUser.getOrgCode());
String orderNo = asnSerialNumberRule.generateSerialNumber(GeneralConstant.ASN_ORDER_NO);
asn.setOrderNo(orderNo);
asnMapper.insert(asn);
if (asnDetailList == null || asnDetailList.isEmpty()) {
throw new RuntimeException("请新增入库明细");
}
AtomicInteger lineNoCounter = new AtomicInteger(1);
for (AsnDetail entity : asnDetailList) {
if (entity.getLineNo() == null || entity.getLineNo() == 0) {
entity.setLineNo(lineNoCounter.getAndIncrement());
}
entity.setAsnId(asn.getId());
entity.setTenantId(Long.parseLong(sysUser.getRelTenantIds()));
entity.setSysOrgCode(sysUser.getOrgCode());
this.baseMapper.insert(entity);
}
//刷新入库单
refreshAsn(asn, asnDetailList);
}
public void refreshAsn(Asn asn, List<AsnDetail> asnDetails) {
if (asnDetails == null) {
asnDetails = new ArrayList<>();
if (CollectionUtils.isEmpty(asnDetails)) {
asnDetails = Collections.emptyList();
}
//需求数量
BigDecimal orderQty = asnDetails.stream().map(AsnDetail::getOrderQty).reduce(BigDecimal.ZERO, BigDecimal::add);
// 计算需求数量总和
BigDecimal orderQty = asnDetails.stream()
.map(AsnDetail::getOrderQty)
.filter(Objects::nonNull)
.reduce(BigDecimal.ZERO, BigDecimal::add);
//收货数量
BigDecimal receivedQty = asnDetails.stream().map(AsnDetail::getReceivedQty).reduce(BigDecimal.ZERO, BigDecimal::add);
// 计算收货数量总和
BigDecimal receivedQty = asnDetails.stream()
.map(AsnDetail::getReceivedQty)
.filter(Objects::nonNull)
.reduce(BigDecimal.ZERO, BigDecimal::add);
//当前状态
Integer status = asn.getStatus();
if (orderQty.compareTo(BigDecimal.ZERO) <= 0) {
// 无需求量时设为创建状态
status = AsnStatusEnum.CREATED.getValue();
} else if (receivedQty.compareTo(BigDecimal.ZERO) <= 0) {
// 未收货时为创建状态
// 计算入库单状态
int status;
if (orderQty.compareTo(BigDecimal.ZERO) <= 0 || receivedQty.compareTo(BigDecimal.ZERO) <= 0) {
// 无需求量或未收货:创建状态
status = AsnStatusEnum.CREATED.getValue();
} else if (receivedQty.compareTo(orderQty) >= 0) {
// 已完全收货
// 收货数量 >= 需求数量:收货完成
status = AsnStatusEnum.RECEIVED.getValue();
} else {
// 部分收货
// 收货数量 < 需求数量:部分收货
status = AsnStatusEnum.RECEIVING.getValue();
}
// 更新入库单
asn.setOrderQty(orderQty);
asn.setReceivedQty(receivedQty);
asn.setStatus(status);
asnMapper.updateById(asn);
}
@Override
public ReceiveRecord buildReceiveRecord(AsnDetail asnDetail, BigDecimal receivedQty, ItemKeyDTO itemKey, Long dstPointId) {
return ReceiveRecord.builder()
.id(IdWorker.getId())
.asnId(asnDetail.getAsnId())
.asnDetailId(asnDetail.getId())
.stockId(asnDetail.getStockId())
.fromPointId(asnDetail.getToPointId())
.toPointId(dstPointId)
.itemId(asnDetail.getItemId())
.itemKeyId(itemKey.getId())
.receivedQty(receivedQty)
.description(asnDetail.getDescription())
.tenantId(asnDetail.getTenantId())
.sysOrgCode(asnDetail.getSysOrgCode())
.createBy(asnDetail.getCreateBy())
.createTime(new Date())
.build();
}
}

View File

@ -2,26 +2,26 @@ package org.cpte.modules.inbound.service.impl;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.shiro.SecurityUtils;
import org.cpte.common.lock.RedissonLockExecutor;
import org.cpte.modules.constant.GeneralConstant;
import org.cpte.modules.constant.enums.AsnStatusEnum;
import org.cpte.modules.inbound.entity.Asn;
import org.cpte.modules.inbound.entity.AsnDetail;
import org.cpte.modules.inbound.mapper.AsnDetailMapper;
import org.cpte.modules.inbound.mapper.AsnMapper;
import org.cpte.modules.inbound.request.ReceiveRequest;
import org.cpte.modules.inbound.rule.AsnSerialNumberRule;
import org.cpte.modules.inbound.service.IAsnDetailService;
import org.cpte.modules.inbound.service.IAsnService;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.jeecg.common.system.vo.LoginUser;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import java.io.Serializable;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
/**
* @Description:
@ -35,138 +35,249 @@ public class AsnServiceImpl extends ServiceImpl<AsnMapper, Asn> implements IAsnS
@Autowired
private AsnDetailMapper asnDetailMapper;
@Autowired
private IAsnDetailService asnDetailService;
@Autowired
private RedissonClient redissonClient;
private ReceiveServiceImpl receiveService;
@Autowired
private AsnSerialNumberRule asnSerialNumberRule;
@Autowired
private RedissonLockExecutor redissonLockExecutor;
@Autowired
private AsnDataProcessor asnDataProcessor;
@Override
public void saveMain(Asn asn, List<AsnDetail> asnDetailList) {
String lockKey = "asn:lock:" + asn.getNo();
redissonLockExecutor.executeWithLock(lockKey, () -> {
asnDetailService.processorSaveMain(asn, asnDetailList);
processorSave(asn, asnDetailList);
});
}
@Override
@Transactional(rollbackFor = Exception.class)
public void updateMain(Asn asn, List<AsnDetail> asnDetailList) {
this.baseMapper.updateById(asn);
/**
*
*
* @param asn
* @param asnDetailList
*/
private void processorSave(Asn asn, List<AsnDetail> asnDetailList) {
// 获取当前登录用户信息
LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
if (sysUser == null) {
throw new RuntimeException("用户未登录");
}
if (asnDetailList == null || asnDetailList.isEmpty()) {
// 设置入库单基础信息
Long tenantId = Long.parseLong(sysUser.getRelTenantIds());
asn.setTenantId(tenantId);
asn.setSysOrgCode(sysUser.getOrgCode());
// 生成入库单号
String orderNo = asnSerialNumberRule.generateSerialNumber(GeneralConstant.ASN_ORDER_NO);
asn.setOrderNo(orderNo);
// 校验明细列表
if (CollectionUtils.isEmpty(asnDetailList)) {
throw new RuntimeException("请新增入库明细");
}
// 批量设置明细属性并插入
AtomicInteger lineNoCounter = new AtomicInteger(1);
List<AsnDetail> insertDetails = new ArrayList<>();
for (AsnDetail entity : asnDetailList) {
// 自动设置行号
if (entity.getLineNo() == null || entity.getLineNo() == 0) {
entity.setLineNo(lineNoCounter.getAndIncrement());
}
// 设置关联 ID 和租户信息
entity.setAsnId(asn.getId());
entity.setTenantId(tenantId);
entity.setSysOrgCode(sysUser.getOrgCode());
insertDetails.add(entity);
}
//保存入库单
asnDataProcessor.saveAsn(asn);
// 批量插入明细
if (CollectionUtils.isNotEmpty(insertDetails)) {
asnDetailService.saveBatch(insertDetails);
}
// 刷新入库单
asnDetailService.refreshAsn(asn, insertDetails);
}
@Override
public void updateMain(Asn asn, List<AsnDetail> asnDetailList) {
String lockKey = "asn:lock:" + asn.getNo();
redissonLockExecutor.executeWithWatchdog(lockKey, () -> {
processUpdate(asn, asnDetailList);
});
}
/**
*
*
* @param asn
* @param asnDetailList
*/
private void processUpdate(Asn asn, List<AsnDetail> asnDetailList) {
if (CollectionUtils.isEmpty(asnDetailList)) {
throw new RuntimeException("请新增入库明细");
}
AtomicInteger lineNoCounter = new AtomicInteger(1);
List<AsnDetail> insertDetails = new ArrayList<>();
List<AsnDetail> updateDetails = new ArrayList<>();
for (AsnDetail entity : asnDetailList) {
// 自动设置行号
if (entity.getLineNo() == null || entity.getLineNo() == 0) {
entity.setLineNo(lineNoCounter.getAndIncrement());
}
// 设置关联 ID
entity.setAsnId(asn.getId());
// 分类:新增或更新
if (entity.getId() != null) {
asnDetailMapper.updateById(entity);
updateDetails.add(entity);
} else {
asnDetailMapper.insert(entity);
insertDetails.add(entity);
}
}
// 刷新入库单状态
asnDetailService.refreshAsn(asn, asnDetailList);
asnDataProcessor.updateAsn(asn);
if (CollectionUtils.isNotEmpty(insertDetails)) {
asnDetailService.saveBatch(insertDetails);
}
if (CollectionUtils.isNotEmpty(updateDetails)) {
asnDetailService.updateBatchById(updateDetails);
}
// 3. 刷新入库单
asnDetailService.refreshAsn(asn, asnDetailList);
}
@Override
@Transactional(rollbackFor = Exception.class)
public void delMain(Long id) {
Asn asn = this.getById(id);
if (!AsnStatusEnum.CREATED.getValue().equals(asn.getStatus())) {
throw new RuntimeException("操作失败:【" + asn.getOrderNo() + "】入库单,非创建状态不允许删除");
}
asnDetailMapper.deleteByMainId(id);
this.baseMapper.deleteById(id);
asnDataProcessor.deleteAsn(id);
}
@Override
@Transactional(rollbackFor = Exception.class)
public void delBatchMain(Collection<? extends Serializable> idList) {
List<String> orderNoList = new ArrayList<>();
for (Serializable id : idList) {
Asn asn = this.getById(id);
if (CollectionUtils.isEmpty(idList)) {
throw new RuntimeException("请选择需要删除的入库单");
}
List<Long> asnIdList = idList.stream().map(id -> Long.parseLong(id.toString())).toList();
Map<Long, Asn> asnMap = asnDetailService.queryByAsnIdsToMap(asnIdList);
if (asnMap.isEmpty()) {
throw new RuntimeException("未找到需要删除的入库单");
}
List<String> invalidOrderNos = new ArrayList<>();
List<Long> asnIds = new ArrayList<>();
for (Map.Entry<Long, Asn> entry : asnMap.entrySet()) {
Asn asn = entry.getValue();
if (!AsnStatusEnum.CREATED.getValue().equals(asn.getStatus())) {
orderNoList.add(asn.getOrderNo());
invalidOrderNos.add(asn.getOrderNo());
continue;
}
asnDetailMapper.deleteByMainId(Long.parseLong(id.toString()));
this.baseMapper.deleteById(id);
asnIds.add(asn.getId());
}
if (!orderNoList.isEmpty()) {
throw new RuntimeException("操作失败:【" + orderNoList + "】入库单,非创建状态不允许删除");
if (CollectionUtils.isNotEmpty(invalidOrderNos)) {
String orderNos = String.join(",", invalidOrderNos);
throw new RuntimeException("操作失败:[" + orderNos + "] 入库单非创建状态,不允许删除");
}
if (CollectionUtils.isNotEmpty(asnIds)) {
asnDataProcessor.batchDeleteAsn(asnIds);
}
}
@Override
@Transactional(rollbackFor = Exception.class)
public void receive(ReceiveRequest request) {
String lockKey = "receive:stock:" + request.getStockCode();
redissonLockExecutor.executeWithWatchdog(lockKey, () -> {
receiveService.receive(request);
});
}
@Override
public void cancelAsn(Asn asn) {
String lockKey = "asn:lock:" + asn.getNo();
redissonLockExecutor.executeWithWatchdog(lockKey, () -> {
processCancel(asn);
});
}
/**
*
*
* @param asn
*/
private void processCancel(Asn asn) {
List<AsnDetail> details = asnDetailMapper.selectByMainId(asn.getId());
List<AsnDetail> updateToDetails = new ArrayList<>();
for (AsnDetail detail : details) {
detail.setStatus(AsnStatusEnum.CANCELED.getValue());
updateToDetails.add(detail);
}
if (CollectionUtils.isNotEmpty(updateToDetails)) {
asnDetailMapper.updateById(updateToDetails);
if (CollectionUtils.isNotEmpty(details)) {
for (AsnDetail detail : details) {
detail.setStatus(AsnStatusEnum.CANCELED.getValue());
}
asnDetailService.updateBatchById(details);
}
asn.setStatus(AsnStatusEnum.CANCELED.getValue());
this.baseMapper.updateById(asn);
/* if (CollectionUtils.isNotEmpty(details)) {
Stock stock = stockMapper.selectById(details.get(0).getStockId());
if (stock != null) {
stock.setStatus(CommonStatusEnum.FREE.getValue());
stockMapper.updateById(stock);
}
}*/
asnDataProcessor.updateAsn(asn);
}
@Override
@Transactional(rollbackFor = Exception.class)
public void closeAsn(List<Long> asnIds) {
if (CollectionUtils.isEmpty(asnIds)) {
throw new RuntimeException("请选择需要关闭的入库单");
}
Map<Long, Asn> asnMap = asnDetailService.queryByAsnIdsToMap(asnIds);
List<AsnDetail> asnDetails = asnDetailMapper.queryByAsnIds(asnIds);
//根据出库单 ID 分组
Map<Long, List<AsnDetail>> asnDetailMapGroup = asnDetails.stream().collect(Collectors.groupingBy(AsnDetail::getAsnId));
for (Map.Entry<Long, List<AsnDetail>> entry : asnDetailMapGroup.entrySet()) {
Asn asn = asnMap.get(entry.getKey());
List<AsnDetail> asnDetailList = entry.getValue();
for (AsnDetail asnDetail : asnDetailList) {
asnDetail.setStatus(AsnStatusEnum.CLOSED.getValue());
}
asnDetailMapper.updateById(asnDetailList);
asn.setStatus(AsnStatusEnum.CLOSED.getValue());
this.baseMapper.updateById(asn);
// 批量查询入库单
List<Asn> asnList = this.listByIds(asnIds);
if (CollectionUtils.isEmpty(asnList)) {
throw new RuntimeException("未找到需要关闭的入库单");
}
//库存可用
List<Long> stockIds = asnDetails.stream().map(AsnDetail::getStockId).distinct().toList();
/* if(CollectionUtils.isNotEmpty(stockIds)){
LambdaQueryWrapper<Inventory> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.in(Inventory::getStockId, stockIds);
List<Inventory> inventoryList = inventoryMapper.selectList(queryWrapper);
for (Inventory inventory : inventoryList){
inventory.setStatus(InventoryStatusEnum.AVAILABLE.getValue());
}
if (CollectionUtils.isNotEmpty(inventoryList)){
inventoryMapper.updateById(inventoryList);
}
}*/
// 提取有效的 ASN ID 集合
List<Long> validAsnIds = asnList.stream().map(Asn::getId).toList();
// 批量查询所有 ASN 明细
List<AsnDetail> allAsnDetails = asnDetailMapper.queryByAsnIds(validAsnIds);
// 批量更新明细状态为已关闭
if (CollectionUtils.isNotEmpty(allAsnDetails)) {
for (AsnDetail detail : allAsnDetails) {
detail.setStatus(AsnStatusEnum.CLOSED.getValue());
}
asnDetailService.updateBatchById(allAsnDetails);
}
// 批量更新主表状态为已关闭
for (Asn asn : asnList) {
asn.setStatus(AsnStatusEnum.CLOSED.getValue());
}
this.updateBatchById(asnList);
}
}

View File

@ -0,0 +1,64 @@
package org.cpte.modules.inbound.service.impl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.cpte.feign.client.BasicServiceClient;
import org.cpte.modules.basic.dto.ItemDTO;
import org.cpte.modules.inbound.request.ReceiveRequest;
import org.jeecg.common.api.vo.Result;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.text.SimpleDateFormat;
import java.util.Date;
@Service
@Slf4j
public class ReceiveServiceImpl {
@Autowired
private BasicServiceClient basicServiceClient;
public void receive(ReceiveRequest request) {
//获取当前时间yyyy-MM-dd HH:MM:ss 这种格式
String currentTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
log.info("开始收货:{},时间:{}", request, currentTime);
//1.参数校验
validateParams(request);
//2.校验物料
ItemDTO item = validateItem(request.getItemCode());
log.info("物料信息:{}", item);
}
/**
*
*/
private void validateParams(ReceiveRequest request) {
if (request == null) {
throw new IllegalArgumentException("收货参数不能为空");
}
if (StringUtils.isBlank(request.getItemCode())) {
throw new IllegalArgumentException("物料编码不能为空");
}
if (StringUtils.isBlank(request.getPointCode())) {
throw new IllegalArgumentException("库位编码不能为空");
}
if (StringUtils.isBlank(request.getStockCode())) {
throw new IllegalArgumentException("容器编码不能为空");
}
}
/**
*
*/
private ItemDTO validateItem(String itemCode) {
Result<ItemDTO> itemResult = basicServiceClient.getItemByCode(itemCode);
if (itemResult.isSuccess()) {
return itemResult.getResult();
}
throw new IllegalArgumentException(itemResult.getMessage());
}
}

View File

@ -1,17 +0,0 @@
package org.cpte.modules.inbound.vo;
import lombok.Data;
import org.cpte.modules.basic.dto.PointDTO;
import org.cpte.modules.basic.dto.StockDTO;
import org.cpte.modules.inbound.entity.Asn;
import org.cpte.modules.inbound.entity.AsnDetail;
import java.util.List;
@Data
public class ReceiveData {
private Asn asn ;
private List<AsnDetail> asnDetails;
private StockDTO stock;
private PointDTO point;
}

View File

@ -257,11 +257,11 @@ feign:
loggerLevel: BASIC
# 本地开发环境服务地址配置
wms-basic:
url: http://localhost:8001
url: http://localhost:8001/cpte-wms-basic
wms-inventory:
url: http://localhost:8004
url: http://localhost:8004/cpte-wms-inventory
wms-schedule:
url: http://localhost:8005
url: http://localhost:8005/cpte-wms-schedule
#第三方登录
justauth:

View File

@ -36,4 +36,14 @@
</foreach>
ORDER BY line_no
</select>
<delete id="deleteByBatchAsnIds">
DELETE
FROM data_asn_detail
WHERE
asn_id IN
<foreach item="asnId" index="index" collection="asnIds" open="(" separator="," close=")">
#{asnId}
</foreach>
</delete>
</mapper>

View File

@ -26,7 +26,7 @@ import java.util.Map;
@SpringBootApplication(scanBasePackages = {"org.jeecg", "org.cpte", "org.cpte.modules"})
@EnableAutoConfiguration(exclude = {MongoAutoConfiguration.class})
@ImportAutoConfiguration(JustAuthAutoConfiguration.class) // spring boot 3.x justauth 兼容性处理
@EnableFeignClients(basePackages = {"org.cpte.feign.client"}) // 启用 Feign 客户端
@EnableFeignClients(basePackages = {"org.cpte.feign"}) // 启用 Feign 客户端,包含 client 和 config 包
public class WmsInventoryApplication extends SpringBootServletInitializer {
@Override

View File

@ -2,7 +2,7 @@ package org.cpte.modules.inventory.rule;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.cpte.modules.utils.CodeGeneratorUtil;
import org.cpte.common.util.CodeGeneratorUtil;
import org.jeecg.common.handler.IFillRuleHandler;
import org.jeecg.modules.system.mapper.SysFillRuleMapper;
import org.springframework.beans.factory.annotation.Autowired;

View File

@ -2,7 +2,7 @@ package org.cpte.modules.inventory.rule;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.cpte.modules.utils.CodeGeneratorUtil;
import org.cpte.common.util.CodeGeneratorUtil;
import org.jeecg.common.handler.IFillRuleHandler;
import org.jeecg.modules.system.mapper.SysFillRuleMapper;
import org.springframework.beans.factory.annotation.Autowired;

View File

@ -1,51 +0,0 @@
package org.cpte.modules.utils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.CannotAcquireLockException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.List;
@Slf4j
@Component
public class CodeGeneratorUtil {
@Autowired
public JdbcTemplate jdbcTemplate;
private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyMMdd");
/**
*
*
* @param type RKCKPKMK
* @return
*/
@Transactional
public String generateSerialNumber(String type) {
try {
String dateStr = LocalDate.now().format(DATE_FORMATTER);
String sql = "SELECT current_seq FROM generator_sequence WHERE type = ? AND date_str = ? for update";
List<Integer> result = jdbcTemplate.queryForList(sql, Integer.class, type, dateStr);
if (result.isEmpty()) {
String insertSql = "INSERT INTO generator_sequence (type, date_str, current_seq) VALUES (?, ?, 1)";
jdbcTemplate.update(insertSql, type, dateStr);
return type + dateStr + "000001";
} else {
Integer currentSeq = result.get(0);
String updateSql = "UPDATE generator_sequence SET current_seq = current_seq + 1 WHERE type = ? AND date_str = ?";
jdbcTemplate.update(updateSql, type, dateStr);
String seqStr = String.format("%06d", currentSeq + 1);
return type + dateStr + seqStr;
}
} catch (CannotAcquireLockException e) {
throw new RuntimeException("单号生成中,请稍后重试", e);
}
}
}

View File

@ -26,7 +26,7 @@ import java.util.Map;
@SpringBootApplication(scanBasePackages = {"org.jeecg", "org.cpte", "org.cpte.modules"})
@EnableAutoConfiguration(exclude = {MongoAutoConfiguration.class})
@ImportAutoConfiguration(JustAuthAutoConfiguration.class) // spring boot 3.x justauth 兼容性处理
@EnableFeignClients(basePackages = {"org.cpte.feign.client"}) // 启用 Feign 客户端
@EnableFeignClients(basePackages = {"org.cpte.feign"}) // 启用 Feign 客户端,包含 client 和 config 包
public class WmsOutboundApplication extends SpringBootServletInitializer {
@Override

View File

@ -2,7 +2,7 @@ package org.cpte.modules.outbound.rule;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.cpte.modules.utils.CodeGeneratorUtil;
import org.cpte.common.util.CodeGeneratorUtil;
import org.jeecg.common.handler.IFillRuleHandler;
import org.jeecg.modules.system.mapper.SysFillRuleMapper;
import org.springframework.beans.factory.annotation.Autowired;

View File

@ -1,51 +0,0 @@
package org.cpte.modules.utils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.CannotAcquireLockException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.List;
@Slf4j
@Component
public class CodeGeneratorUtil {
@Autowired
public JdbcTemplate jdbcTemplate;
private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyMMdd");
/**
*
*
* @param type RKCKPKMK
* @return
*/
@Transactional
public String generateSerialNumber(String type) {
try {
String dateStr = LocalDate.now().format(DATE_FORMATTER);
String sql = "SELECT current_seq FROM generator_sequence WHERE type = ? AND date_str = ? for update";
List<Integer> result = jdbcTemplate.queryForList(sql, Integer.class, type, dateStr);
if (result.isEmpty()) {
String insertSql = "INSERT INTO generator_sequence (type, date_str, current_seq) VALUES (?, ?, 1)";
jdbcTemplate.update(insertSql, type, dateStr);
return type + dateStr + "000001";
} else {
Integer currentSeq = result.get(0);
String updateSql = "UPDATE generator_sequence SET current_seq = current_seq + 1 WHERE type = ? AND date_str = ?";
jdbcTemplate.update(updateSql, type, dateStr);
String seqStr = String.format("%06d", currentSeq + 1);
return type + dateStr + seqStr;
}
} catch (CannotAcquireLockException e) {
throw new RuntimeException("单号生成中,请稍后重试", e);
}
}
}

View File

@ -26,7 +26,7 @@ import java.util.Map;
@SpringBootApplication(scanBasePackages = {"org.jeecg", "org.cpte", "org.cpte.modules"})
@EnableAutoConfiguration(exclude = {MongoAutoConfiguration.class})
@ImportAutoConfiguration(JustAuthAutoConfiguration.class) // spring boot 3.x justauth 兼容性处理
@EnableFeignClients(basePackages = {"org.cpte.feign.client"}) // 启用 Feign 客户端
@EnableFeignClients(basePackages = {"org.cpte.feign"}) // 启用 Feign 客户端,包含 client 和 config 包
public class WmsScheduleApplication extends SpringBootServletInitializer {
@Override