no message
parent
070fc764a1
commit
1e9854747d
|
|
@ -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;
|
||||
|
|
@ -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
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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 客户端
|
||||
|
|
|
|||
|
|
@ -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 环境中调用");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
/**
|
||||
* 取消操作
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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 业务类型,如 RK、CK、PK、MK
|
||||
* @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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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 业务类型,如 RK、CK、PK、MK
|
||||
* @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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in New Issue