库存批次问题,扫码问题,扫码冲突问题

dev_2.5_inv
yewj 3 months ago
parent 48a37c363c
commit 816a071c79

@ -267,7 +267,7 @@ public class IoCodeTempController extends BaseController {
List<IoOrderEntity> orderEntities = data.getOrderEntities();
if (collectOrder == null && CollUtil.isNotEmpty(orderEntities)) {
collectOrder = collectOrderService.unionSearch(null, null, orderEntities.get(0).getBillNo());
collectOrder = collectOrderService.unionSearch(null, null, orderEntities.get(0).getBillNo());
}
if (collectOrder != null) {
@ -282,11 +282,11 @@ public class IoCodeTempController extends BaseController {
}
}
}
BaseResponse response = ResultVOUtils.error(501, com.glxp.api.util.StringUtils.isNotEmpty(baseResponse.getMessage())?
BaseResponse response = ResultVOUtils.error(501, com.glxp.api.util.StringUtils.isNotEmpty(baseResponse.getMessage()) ?
"单据存在未对照产品: " + baseResponse.getMessage() : "未找到匹配单据");
response.setData(code);
return response;
}else {
} else {
BaseResponse response = ResultVOUtils.error(501, baseResponse.getMessage());
response.setData(code);
return response;
@ -561,7 +561,7 @@ public class IoCodeTempController extends BaseController {
@RepeatSubmit()
@AuthRuleAnnotation("")
@PostMapping("warehouse/inout/addOrderWeb")
@CusRedissonAnnotation(cacheName = RedissonCacheKey.WEB_ADD_CODE, key = {"#addOrderRequest.corpOrderId", "#addOrderRequest.code"}, timeOutMsg = "系统正在处理,请勿重复扫码")
// @CusRedissonAnnotation(cacheName = RedissonCacheKey.WEB_ADD_CODE, key = {"#addOrderRequest.corpOrderId", "#addOrderRequest.code"}, timeOutMsg = "系统正在处理,请勿重复扫码")
@Log(title = "单据管理", businessType = BusinessType.INSERT)
public BaseResponse addOrderWeb(@RequestBody AddOrderRequest addOrderRequest, BindingResult bindingResult) {

@ -0,0 +1,9 @@
package com.glxp.api.dao.collect;
import com.glxp.api.dao.BaseMapperPlus;
import com.glxp.api.entity.collect.IoCollectErrorLog;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface IoCollectErrorLogMapper extends BaseMapperPlus<IoCollectErrorLogMapper, IoCollectErrorLog, IoCollectErrorLog> {
}

@ -0,0 +1,9 @@
package com.glxp.api.dao.inv;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.glxp.api.entity.inv.InvProductRecord;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface InvProductRecordMapper extends BaseMapper<InvProductRecord> {
}

@ -0,0 +1,71 @@
package com.glxp.api.entity.collect;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
import java.util.Date;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
*
*/
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@TableName(value = "io_collect_error_log")
public class IoCollectErrorLog implements Serializable {
@TableId(value = "id", type = IdType.INPUT)
private Integer id;
/**
*
*/
@TableField(value = "orderId")
private Long orderId;
/**
*
*/
@TableField(value = "autoCode")
private String autoCode;
/**
*
*/
@TableField(value = "manuCode")
private String manuCode;
/**
* 12
*/
@TableField(value = "`type`")
private Integer type;
/**
*
*/
@TableField(value = "updateTime")
private Date updateTime;
/**
*
*/
@TableField(value = "updateUser")
private Date updateUser;
/**
*
*/
@TableField(value = "remark")
private String remark;
private static final long serialVersionUID = 1L;
}

@ -15,7 +15,7 @@ import java.io.Serializable;
import java.util.Date;
/**
*
* ()
*/
@ApiModel(value = "com-glxp-api-entity-inout-IoSplitFifoCode")
@Data

@ -25,7 +25,7 @@ public class InvProductBatchEntity implements Serializable {
@TableId(value = "id", type = IdType.INPUT)
@ApiModelProperty(value = "")
private Integer id;
private Long id;
/**
@ -104,7 +104,6 @@ public class InvProductBatchEntity implements Serializable {
private Integer reCount;
/**
* ID
*/
@ -139,7 +138,12 @@ public class InvProductBatchEntity implements Serializable {
@TableField(value = "`invCode`")
@ApiModelProperty(value = "仓库编码")
private String invCode;
/**
* (1:,0:)
*/
@TableField(value = "`status`")
@ApiModelProperty(value = "库存批次状态")
private Integer status;
private static final long serialVersionUID = 1L;

@ -0,0 +1,123 @@
package com.glxp.api.entity.inv;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Date;
import lombok.Data;
/**
*
*/
@Data
@TableName(value = "inv_product_record")
public class InvProductRecord implements Serializable {
/**
* ID
*/
@TableId(value = "id", type = IdType.INPUT)
private Long id;
/**
* ID
*/
@TableField(value = "productId")
private Long productId;
/**
* ID
*/
@TableField(value = "warehouseId")
private Long warehouseId;
/**
*
*/
@TableField(value = "inBatchNo")
private String inBatchNo;
/**
*
*/
@TableField(value = "batchNo")
private String batchNo;
/**
*
*/
@TableField(value = "orderId")
private String orderId;
/**
* (1:,2:)
*/
@TableField(value = "orderType")
private Integer orderType;
/**
*
*/
@TableField(value = "quantity")
private Integer quantity;
/**
*
*/
@TableField(value = "unitPrice")
private BigDecimal unitPrice;
/**
*
*/
@TableField(value = "beforeQuantity")
private BigDecimal beforeQuantity;
/**
*
*/
@TableField(value = "afterQuantity")
private BigDecimal afterQuantity;
/**
*
*/
@TableField(value = "remark")
private String remark;
/**
*
*/
@TableField(value = "creator")
private String creator;
/**
*
*/
@TableField(value = "createTime")
private Date createTime;
/**
*
*/
@TableField(value = "updateTime")
private Date updateTime;
/**
*
*/
@TableField(value = "updater")
private String updater;
/**
* ID
*/
@TableField(value = "tenantId")
private Long tenantId;
private static final long serialVersionUID = 1L;
}

@ -0,0 +1,18 @@
package com.glxp.api.entity.inv;
import lombok.Builder;
import lombok.Data;
import java.math.BigDecimal;
/**
* @author AnthonyYwj
*/
@Data
@Builder
public class InventoryBatchAllocation {
private InvProductBatchEntity batch; // 批次信息
private Integer allocatedQuantity; // 分配数量
private BigDecimal unitPrice; // 单价
private String expiryDate; // 效期
}

@ -0,0 +1,12 @@
package com.glxp.api.service.collect;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.List;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.glxp.api.dao.collect.IoCollectErrorLogMapper;
import com.glxp.api.entity.collect.IoCollectErrorLog;
@Service
public class IoCollectErrorLogService extends ServiceImpl<IoCollectErrorLogMapper, IoCollectErrorLog> {
}

@ -10,6 +10,7 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.PageHelper;
import com.glxp.api.constant.Constant;
import com.glxp.api.dao.collect.IoCollectCodeBackMapper;
import com.glxp.api.dao.collect.IoCollectErrorLogMapper;
import com.glxp.api.dao.collect.IoCollectOrderBackupMapper;
import com.glxp.api.dao.inout.IoCodeLostMapper;
import com.glxp.api.dao.inout.IoSplitCodeMapper;
@ -130,23 +131,7 @@ public class IoSplitCodeService extends ServiceImpl<IoSplitCodeMapper, IoSplitCo
unCount = IntUtil.value(collectOrderBiz.getUnTagCount());
for (IoSplitCodeEntity ioSplitCodeEntity : ioSplitCodeEntities) {
count = IntUtil.value(ioSplitCodeEntity.getRemainCount()) - unCount;
collectOrderCodeAutoService.save(
IoCollectOrderCodeAuto.builder()
.codeIdFk(ioSplitCodeEntity.getId())
.udiCode(ioSplitCodeEntity.getCode())
.orderIdFk(collectOrder.getBillNo())
.batchNo(ioSplitCodeEntity.getBatchNo())
.productDate(ioSplitCodeEntity.getProduceDate())
.expireDate(ioSplitCodeEntity.getExpireDate())
.serialNo(ioSplitCodeEntity.getSerialNo())
.relId(collectOrderBiz.getRelId())
.bizIdFk(collectOrderBiz.getId())
.fifoSplit(1)
.createTime(new Date())
.updateTime(new Date())
.count(count > 0 ? count : 0)
.reCount(unCount)
.build());
collectOrderCodeAutoService.save(IoCollectOrderCodeAuto.builder().codeIdFk(ioSplitCodeEntity.getId()).udiCode(ioSplitCodeEntity.getCode()).orderIdFk(collectOrder.getBillNo()).batchNo(ioSplitCodeEntity.getBatchNo()).productDate(ioSplitCodeEntity.getProduceDate()).expireDate(ioSplitCodeEntity.getExpireDate()).serialNo(ioSplitCodeEntity.getSerialNo()).relId(collectOrderBiz.getRelId()).bizIdFk(collectOrderBiz.getId()).fifoSplit(1).createTime(new Date()).updateTime(new Date()).count(count > 0 ? count : 0).reCount(unCount).build());
if (count > 0) {
ioSplitCodeEntity.setRemainCount(count);
unCount = 0;
@ -169,7 +154,8 @@ public class IoSplitCodeService extends ServiceImpl<IoSplitCodeMapper, IoSplitCo
//预出库队列数量不足
collectOrderBiz.setTagStatus(2);
collectOrderBiz.setTagMsg("预出库队列码数量不足,赋码失败!");
if (isAuto) throw new JsonException(500, "提交失败,工位库存数量不足!");
if (isAuto)
throw new JsonException(500, "提交失败," + collectOrderBiz.getCpmctymc() + "工位库存数量不足!");
else return;
} else {
@ -178,21 +164,7 @@ public class IoSplitCodeService extends ServiceImpl<IoSplitCodeMapper, IoSplitCo
for (IoSplitCodeEntity ioSplitCodeEntity : ioSplitCodeEntities) {
if (IntUtil.value(ioSplitCodeEntity.getRemainCount()) > 0) {
count = IntUtil.value(ioSplitCodeEntity.getRemainCount()) - unCount;
collectOrderCodeAutoService.save(IoCollectOrderCodeAuto.builder()
.codeIdFk(ioSplitCodeEntity.getId())
.udiCode(ioSplitCodeEntity.getCode())
.orderIdFk(collectOrder.getBillNo())
.batchNo(ioSplitCodeEntity.getBatchNo())
.productDate(ioSplitCodeEntity.getProduceDate())
.expireDate(ioSplitCodeEntity.getExpireDate())
.serialNo(ioSplitCodeEntity.getSerialNo())
.relId(collectOrderBiz.getRelId())
.bizIdFk(collectOrderBiz.getId())
.fifoSplit(count > 0 ? count : 0)
.reCount(count)
.createTime(new Date())
.updateTime(new Date())
.build());
collectOrderCodeAutoService.save(IoCollectOrderCodeAuto.builder().codeIdFk(ioSplitCodeEntity.getId()).udiCode(ioSplitCodeEntity.getCode()).orderIdFk(collectOrder.getBillNo()).batchNo(ioSplitCodeEntity.getBatchNo()).productDate(ioSplitCodeEntity.getProduceDate()).expireDate(ioSplitCodeEntity.getExpireDate()).serialNo(ioSplitCodeEntity.getSerialNo()).relId(collectOrderBiz.getRelId()).bizIdFk(collectOrderBiz.getId()).fifoSplit(count > 0 ? count : 0).reCount(count).createTime(new Date()).updateTime(new Date()).build());
if (count > 0) {
ioSplitCodeEntity.setRemainCount(count);
splitCodeMapper.updateById(ioSplitCodeEntity);
@ -239,7 +211,12 @@ public class IoSplitCodeService extends ServiceImpl<IoSplitCodeMapper, IoSplitCo
//如果手动扫码判断该码是否在队列里,如果已在队列,则队列里剔除
List<IoCollectOrderCodeMan> collectOrderCodeMEN = collectOrderCodeManService.listByBillNo(collectOrder.getBillNo());
if (CollUtil.isNotEmpty(collectOrderCodeMEN)) {
// replaceCode(collectOrderCodeMEN, collectOrder);
for (IoCollectOrderCodeMan collectOrderCodeMan : collectOrderCodeMEN) {
if (IntUtil.value(collectOrderCodeMan.getRemoveFlag())) {
continue;
}
IoSplitFifoCodeEntity splitFifoCodeEntity = splitFifoCodeService.findByCode(collectOrderCodeMan.getUdiCode(), putWorkPlaceCode);
if (splitFifoCodeEntity != null) {
collectOrderCodeMan.setRemoveFlag(true);
@ -321,13 +298,7 @@ public class IoSplitCodeService extends ServiceImpl<IoSplitCodeMapper, IoSplitCo
splitCodeEntity.setRemainCount(-unTagCount);
splitCodeService.updateById(splitCodeEntity);
} else {
IoSplitCodeEntity ioSplitCodeEntity = IoSplitCodeEntity.builder()
.code(item.getUdiCode()).errUdiCode(item.getUdiCode())
.orderId(item.getOrderIdFk())
.action(collectOrder.getBusType()).relId(item.getRelId()).nameCode(item.getNameCode())
.batchNo(item.getBatchNo()).produceDate(item.getProductDate()).expireDate(item.getExpireDate()).serialNo(item.getSerialNo())
.scanCount(item.getScanCount()).totalCount(item.getScanCount()).workPlaceCode(putWorkPlaceCode)
.status(2).fifoSplit(1).createTime(new Date()).updateTime(new Date()).remainCount(item.getRemainCount()).build();
IoSplitCodeEntity ioSplitCodeEntity = IoSplitCodeEntity.builder().code(item.getUdiCode()).errUdiCode(item.getUdiCode()).orderId(item.getOrderIdFk()).action(collectOrder.getBusType()).relId(item.getRelId()).nameCode(item.getNameCode()).batchNo(item.getBatchNo()).produceDate(item.getProductDate()).expireDate(item.getExpireDate()).serialNo(item.getSerialNo()).scanCount(item.getScanCount()).totalCount(item.getScanCount()).workPlaceCode(putWorkPlaceCode).status(2).fifoSplit(1).createTime(new Date()).updateTime(new Date()).remainCount(item.getRemainCount()).build();
this.decorateUnpackExpireTime(ioSplitCodeEntity);
splitCodeService.save(ioSplitCodeEntity);
}
@ -354,20 +325,7 @@ public class IoSplitCodeService extends ServiceImpl<IoSplitCodeMapper, IoSplitCo
for (int i = 0; i < indexFlag; i++) {
IoSplitFifoCodeEntity splitFifoCodeEntity = ioSplitFifoCodeEntities.get(i);
collectOrderBiz.setUnTagCount(IntUtil.value(collectOrderBiz.getUnTagCount()) - IntUtil.value(udiRelevanceResponse.getBhxjsl()));
collectOrderCodeAutoService.save(IoCollectOrderCodeAuto.builder()
.codeIdFk(splitFifoCodeEntity.getId())
.udiCode(splitFifoCodeEntity.getCode())
.orderIdFk(collectOrder.getBillNo())
.batchNo(splitFifoCodeEntity.getBatchNo())
.productDate(splitFifoCodeEntity.getProduceDate())
.expireDate(splitFifoCodeEntity.getExpireDate())
.serialNo(splitFifoCodeEntity.getSerialNo())
.relId(collectOrderBiz.getRelId())
.bizIdFk(collectOrderBiz.getId())
.fifoSplit(2)
.createTime(new Date())
.updateTime(new Date())
.build());
collectOrderCodeAutoService.save(IoCollectOrderCodeAuto.builder().codeIdFk(splitFifoCodeEntity.getId()).udiCode(splitFifoCodeEntity.getCode()).orderIdFk(collectOrder.getBillNo()).batchNo(splitFifoCodeEntity.getBatchNo()).productDate(splitFifoCodeEntity.getProduceDate()).expireDate(splitFifoCodeEntity.getExpireDate()).serialNo(splitFifoCodeEntity.getSerialNo()).relId(collectOrderBiz.getRelId()).bizIdFk(collectOrderBiz.getId()).fifoSplit(2).createTime(new Date()).updateTime(new Date()).build());
splitFifoCodeService.removeById(splitFifoCodeEntity.getId());
IoSplitFifoInv splitFifoInv = splitFifoInvService.findByFifoCode(splitFifoCodeEntity);
if (splitFifoInv != null) {
@ -416,85 +374,74 @@ public class IoSplitCodeService extends ServiceImpl<IoSplitCodeMapper, IoSplitCo
for (IoCollectOrderCodeMan collectOrderCodeMan : collectOrderCodeManList) {
// 1. 查找已完成成单据扫码是否已被分配
List<IoCollectCodeBackup> collectCodeBackups = collectCodeBackMapper.selectList(new LambdaQueryWrapper<IoCollectCodeBackup>()
.eq(IoCollectCodeBackup::getBusType, collectOrder.getBusType())
.eq(IoCollectCodeBackup::getCode, collectOrderCodeMan.getUdiCode())
);
List<IoCollectCodeBackup> collectCodeBackups = collectCodeBackMapper.selectList(new LambdaQueryWrapper<IoCollectCodeBackup>().eq(IoCollectCodeBackup::getBusType, collectOrder.getBusType()).eq(IoCollectCodeBackup::getCode, collectOrderCodeMan.getUdiCode()));
if (CollUtil.isNotEmpty(collectCodeBackups)) {
IoCollectCodeBackup collectCodeBackup = collectCodeBackups.get(0);
if (IntUtil.value(collectCodeBackup.getFifoSplit()) == 3) {
throw new JsonException(500, collectCodeBackup.getCode() + "重复扫码,请盘查后重试!");
}
IoCollectOrderBackup collectOrderBackup = collectOrderBackupMapper.selectOne(new LambdaQueryWrapper<IoCollectOrderBackup>().eq(IoCollectOrderBackup::getBillNo, collectCodeBackup.getBillNo()));
collectOrderCodeMan.setRemoveFlag(true);
// 单据已被上传至医保
if (IntUtil.value(collectOrderBackup.getUploadStatus()) == 2) {
IoSplitFifoCodeEntity splitFifoCodeEntity = removeInvByCode(collectOrderCodeMan, collectOrder.getWorkPlaceCode());
if (splitFifoCodeEntity == null) {
throw new JsonException(500, "工位存量不足!");
}
IoCollectErrorLog ioCollectErrorLog = IoCollectErrorLog.builder().orderId(collectOrder.getId()).autoCode(splitFifoCodeEntity.getCode()).manuCode(collectOrderCodeMan.getUdiCode()).type(2) //未上传医保替换码
.updateTime(new Date()).build();
collectErrorLogMapper.insert(ioCollectErrorLog);
collectCodeBackup.setCode(splitFifoCodeEntity.getCode());
collectCodeBackMapper.updateById(collectCodeBackup);
} else {
//单据未上传医保,上传医保失败
IoSplitFifoCodeEntity splitFifoCodeEntity = removeInvByCode(collectOrderCodeMan, collectOrder.getWorkPlaceCode());
if (splitFifoCodeEntity == null) {
throw new JsonException(500, "工位存量不足!");
}
IoCollectErrorLog ioCollectErrorLog = IoCollectErrorLog.builder().orderId(collectOrder.getId()).autoCode(splitFifoCodeEntity.getCode()).manuCode(collectOrderCodeMan.getUdiCode()).type(1) //未上传医保替换码
.updateTime(new Date()).build();
collectErrorLogMapper.insert(ioCollectErrorLog);
//替换已完成单据的码
collectCodeBackup.setCode(splitFifoCodeEntity.getCode());
collectCodeBackMapper.updateById(collectCodeBackup);
}
}
// 2. 查找已完成单据码是否已被上传
// 3. 查找已完成码,标记该码已被手动赋码
// 4. 查找码库未被使用的码,赋码至已完成的码,插入码表记录
// 5. 如果已被上传,则标记该码已被上传,从码库查出未被使用的码,插入码表记录,标记该码已被上传,替换成已码库的码
// 5. 查找
}
}
@Resource
IoCollectErrorLogMapper collectErrorLogMapper;
/**
* 使
*/
public void removeInvByCode(IoCollectOrderCodeMan collectOrderCodeMan, Long putWorkPlaceCode) {
public IoSplitFifoCodeEntity removeInvByCode(IoCollectOrderCodeMan collectOrderCodeMan, Long putWorkPlaceCode) {
List<IoSplitFifoCodeEntity> splitFifoCodeEntitys = splitFifoCodeService.findByRelId(putWorkPlaceCode, collectOrderCodeMan.getRelId(), collectOrderCodeMan.getBatchNo(), null);
if (CollUtil.isNotEmpty(splitFifoCodeEntitys)) {
IoSplitFifoCodeEntity splitFifoCodeEntity = splitFifoCodeEntitys.get(0);
collectOrderCodeMan.setRemoveFlag(true);
if (IntUtil.value(splitFifoCodeEntity.getScanCount()) - IntUtil.value(collectOrderCodeMan.getScanCount()) <= 0) {
splitFifoCodeService.removeById(splitFifoCodeEntity.getId());
IoSplitFifoInv splitFifoInv = splitFifoInvService.findByFifoCode(splitFifoCodeEntity);
if (splitFifoInv != null) {
splitFifoInv.setOutCount(IntUtil.value(splitFifoInv.getOutCount()) + IntUtil.value(splitFifoCodeEntity.getTotalCount()));
splitFifoInv.setOutCodeCount(IntUtil.value(splitFifoInv.getOutCodeCount()) + IntUtil.value(splitFifoCodeEntity.getScanCount()));
int lockCount = IntUtil.value(splitFifoInv.getLockCount()) - IntUtil.value(splitFifoCodeEntity.getTotalCount());
splitFifoInv.setLockCount(lockCount > 0 ? lockCount : 0);
splitFifoInv.setReCount(IntUtil.value(splitFifoInv.getInCount()) - IntUtil.value(splitFifoInv.getOutCount()));
splitFifoInv.setReCodeCount(IntUtil.value(splitFifoInv.getInCodeCount()) - IntUtil.value(splitFifoInv.getOutCodeCount()));
splitFifoInv.setAvailableCount(IntUtil.value(splitFifoInv.getInCount()) - IntUtil.value(splitFifoInv.getLockCount()) - IntUtil.value(splitFifoInv.getOutCount()));
splitFifoInvService.updateById(splitFifoInv);
}
} else {
//队列码数量大于扫码数量更新数量(一般指无序列号)
FilterUdiRelRequest filterUdiRelRequest = new FilterUdiRelRequest();
filterUdiRelRequest.setId(collectOrderCodeMan.getRelId());
filterUdiRelRequest.setPackLevel("1");
UdiRelevanceResponse udiRelevanceResponse = udiRelevanceService.selectOneUdi(filterUdiRelRequest);
int removeCount = IntUtil.value(collectOrderCodeMan.getScanCount()) * udiRelevanceResponse.getBhxjsl();
splitFifoCodeService.updateById(IoSplitFifoCodeEntity.builder().id(splitFifoCodeEntity.getId()).scanCount(IntUtil.value(splitFifoCodeEntity.getScanCount()) - IntUtil.value(collectOrderCodeMan.getScanCount())).totalCount(IntUtil.value(splitFifoCodeEntity.getTotalCount()) - removeCount).build());
IoSplitFifoInv splitFifoInv = splitFifoInvService.findByFifoCode(splitFifoCodeEntity);
if (splitFifoInv != null) {
splitFifoInv.setOutCount(IntUtil.value(splitFifoInv.getOutCount()) + removeCount);
splitFifoInv.setOutCodeCount(IntUtil.value(splitFifoInv.getOutCodeCount()) + IntUtil.value(collectOrderCodeMan.getScanCount()));
int lockCount = IntUtil.value(splitFifoInv.getLockCount()) - removeCount;
splitFifoInv.setLockCount(lockCount > 0 ? lockCount : 0);
splitFifoInv.setReCount(IntUtil.value(splitFifoInv.getInCount()) - IntUtil.value(splitFifoInv.getOutCount()));
splitFifoInv.setReCodeCount(IntUtil.value(splitFifoInv.getInCodeCount()) - IntUtil.value(splitFifoInv.getOutCodeCount()));
splitFifoInv.setAvailableCount(IntUtil.value(splitFifoInv.getInCount()) - IntUtil.value(splitFifoInv.getLockCount()) - IntUtil.value(splitFifoInv.getOutCount()));
splitFifoInvService.updateById(splitFifoInv);
}
splitFifoCodeService.removeById(splitFifoCodeEntity.getId());
IoSplitFifoInv splitFifoInv = splitFifoInvService.findByFifoCode(splitFifoCodeEntity);
if (splitFifoInv != null) {
splitFifoInv.setOutCount(IntUtil.value(splitFifoInv.getOutCount()) + IntUtil.value(splitFifoCodeEntity.getTotalCount()));
splitFifoInv.setOutCodeCount(IntUtil.value(splitFifoInv.getOutCodeCount()) + IntUtil.value(splitFifoCodeEntity.getScanCount()));
int lockCount = IntUtil.value(splitFifoInv.getLockCount()) - IntUtil.value(splitFifoCodeEntity.getTotalCount());
splitFifoInv.setLockCount(lockCount > 0 ? lockCount : 0);
splitFifoInv.setReCount(IntUtil.value(splitFifoInv.getInCount()) - IntUtil.value(splitFifoInv.getOutCount()));
splitFifoInv.setReCodeCount(IntUtil.value(splitFifoInv.getInCodeCount()) - IntUtil.value(splitFifoInv.getOutCodeCount()));
splitFifoInv.setAvailableCount(IntUtil.value(splitFifoInv.getInCount()) - IntUtil.value(splitFifoInv.getLockCount()) - IntUtil.value(splitFifoInv.getOutCount()));
splitFifoInvService.updateById(splitFifoInv);
}
return splitFifoCodeEntity;
}
return null;
}
/**
@ -542,8 +489,7 @@ public class IoSplitCodeService extends ServiceImpl<IoSplitCodeMapper, IoSplitCo
IoCollectOrderService collectOrderService;
@Transactional(rollbackFor = Exception.class)
public ConfirmResponse confirmBizAutiTagCode(IoCollectOrderBiz collectOrderBiz, String queueCode, String
confirmSplitCode, Boolean skipSplitConfirm) {
public ConfirmResponse confirmBizAutiTagCode(IoCollectOrderBiz collectOrderBiz, String queueCode, String confirmSplitCode, Boolean skipSplitConfirm) {
ConfirmResponse confirmResponse = new ConfirmResponse();
IoCollectOrder collectOrder = collectOrderService.getByBillNo(collectOrderBiz.getOrderIdFk());
if (collectOrder == null) {
@ -631,21 +577,7 @@ public class IoSplitCodeService extends ServiceImpl<IoSplitCodeMapper, IoSplitCo
for (int i = 0; i < quotient; i++) {
IoSplitFifoCodeEntity splitFifoCodeEntity = availableCodes.get(i);
collectOrderBiz.setUnTagCount(IntUtil.value(collectOrderBiz.getUnTagCount()) - IntUtil.value(udiRelevanceResponse.getBhxjsl()));
collectOrderCodeAutoService.save(
IoCollectOrderCodeAuto.builder()
.codeIdFk(splitFifoCodeEntity.getId())
.udiCode(splitFifoCodeEntity.getCode())
.orderIdFk(collectOrder.getBillNo())
.batchNo(splitFifoCodeEntity.getBatchNo())
.productDate(splitFifoCodeEntity.getProduceDate())
.expireDate(splitFifoCodeEntity.getExpireDate())
.serialNo(splitFifoCodeEntity.getSerialNo())
.relId(collectOrderBiz.getRelId())
.bizIdFk(collectOrderBiz.getId())
.fifoSplit(2)
.createTime(new Date())
.updateTime(new Date())
.build());
collectOrderCodeAutoService.save(IoCollectOrderCodeAuto.builder().codeIdFk(splitFifoCodeEntity.getId()).udiCode(splitFifoCodeEntity.getCode()).orderIdFk(collectOrder.getBillNo()).batchNo(splitFifoCodeEntity.getBatchNo()).productDate(splitFifoCodeEntity.getProduceDate()).expireDate(splitFifoCodeEntity.getExpireDate()).serialNo(splitFifoCodeEntity.getSerialNo()).relId(collectOrderBiz.getRelId()).bizIdFk(collectOrderBiz.getId()).fifoSplit(2).createTime(new Date()).updateTime(new Date()).build());
splitFifoCodeService.removeById(splitFifoCodeEntity.getId());
IoSplitFifoInv splitFifoInv = splitFifoInvService.findByFifoCode(splitFifoCodeEntity);
if (splitFifoInv != null) {
@ -698,9 +630,7 @@ public class IoSplitCodeService extends ServiceImpl<IoSplitCodeMapper, IoSplitCo
} else return null;
}
public List<IoCollectOrderCodeMan> filterCode
(List<IoCollectOrderCodeMan> collectOrderCodes, IoCollectOrderBiz collectOrderBiz, UdiRelevanceResponse
udiRelevanceResponse) {
public List<IoCollectOrderCodeMan> filterCode(List<IoCollectOrderCodeMan> collectOrderCodes, IoCollectOrderBiz collectOrderBiz, UdiRelevanceResponse udiRelevanceResponse) {
int unTagCount = IntUtil.value(collectOrderBiz.getScanActCount()) - collectOrderBiz.getCount();
List<IoCollectOrderCodeMan> newList = new ArrayList<IoCollectOrderCodeMan>();
int count = 0;
@ -770,11 +700,7 @@ public class IoSplitCodeService extends ServiceImpl<IoSplitCodeMapper, IoSplitCo
if (CollUtil.isNotEmpty(splitFifoCodeEntities)) {
IoSplitFifoCodeEntity ioSplitFifoCodeEntity = splitFifoCodeEntities.get(0);
IoCodeLostEntity ioCodeLostEntity = ioCodeLostMapper.selectOne(
new QueryWrapper<IoCodeLostEntity>()
.eq("code", ioSplitFifoCodeEntity.getCode())
.last("limit 1")
);
IoCodeLostEntity ioCodeLostEntity = ioCodeLostMapper.selectOne(new QueryWrapper<IoCodeLostEntity>().eq("code", ioSplitFifoCodeEntity.getCode()).last("limit 1"));
if (ioCodeLostEntity != null && StringUtils.isNotEmpty(ioCodeLostEntity.getBatchNo())) {
collectOrderBiz.setBatchNo(ioCodeLostEntity.getBatchNo());
collectOrderBiz.setProductDate(ioCodeLostEntity.getProduceDate());
@ -840,8 +766,7 @@ public class IoSplitCodeService extends ServiceImpl<IoSplitCodeMapper, IoSplitCo
/**
*
*/
public Integer addFifoCode(Long relId, String batchNo, Integer needCount, Long putWorkPlaceCode, String
confirmSplitCode) {
public Integer addFifoCode(Long relId, String batchNo, Integer needCount, Long putWorkPlaceCode, String confirmSplitCode) {
List<IoSplitFifoCodeEntity> splitFifoCodeEntities;

@ -0,0 +1,12 @@
package com.glxp.api.service.inv;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.List;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.glxp.api.entity.inv.InvProductRecord;
import com.glxp.api.dao.inv.InvProductRecordMapper;
@Service
public class InvProductRecordService extends ServiceImpl<InvProductRecordMapper, InvProductRecord> {
}

@ -1,17 +1,226 @@
package com.glxp.api.service.inv.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.glxp.api.dao.inv.InvProductBatchDao;
import com.glxp.api.dao.inv.InvProductRecordMapper;
import com.glxp.api.entity.inv.InvProductRecord;
import com.glxp.api.entity.inv.InventoryBatchAllocation;
import com.glxp.api.entity.inout.IoOrderDetailResultEntity;
import com.glxp.api.entity.inout.IoOrderEntity;
import com.glxp.api.entity.inv.InvProductBatchEntity;
import com.glxp.api.exception.JsonException;
import com.glxp.api.service.inv.InvProductRecordService;
import io.swagger.models.auth.In;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
@Service
@Transactional(rollbackFor = Exception.class)
public class InvProductBatchService extends ServiceImpl<InvProductBatchDao, InvProductBatchEntity> {
@Resource
private InvProductBatchDao inventoryBatchMapper;
@Resource
InvProductRecordService inventoryRecordService;
public Long createInventoryBatch(InvProductBatchEntity inventoryBatchDO) {
// 插入
inventoryBatchMapper.insert(inventoryBatchDO);
// 返回
return inventoryBatchDO.getId();
}
public void updateInventoryBatch(InvProductBatchEntity inventoryBatchDO) {
// 校验存在
validateInventoryBatchExists(inventoryBatchDO.getId());
// 更新
inventoryBatchMapper.updateById(inventoryBatchDO);
}
public void deleteInventoryBatch(Long id) {
// 校验存在
validateInventoryBatchExists(id);
// 删除
inventoryBatchMapper.deleteById(id);
}
private void validateInventoryBatchExists(Long id) {
if (inventoryBatchMapper.selectById(id) == null) {
throw new JsonException("库存不存在");
}
}
/**
* FIFO
*/
public List<InventoryBatchAllocation> selectBatchesByFIFO(Long productId, Long warehouseId, Integer requiredQuantity) {
// 1. 按入库时间正序查询可用批次
List<InvProductBatchEntity> availableBatches = inventoryBatchMapper.selectList(new LambdaQueryWrapper<InvProductBatchEntity>()
.eq(InvProductBatchEntity::getRelIdFk, productId)
.eq(InvProductBatchEntity::getInvCode, warehouseId)
.gt(InvProductBatchEntity::getReCount, 0) // 修正数量大于0的批次
.eq(InvProductBatchEntity::getStatus, 1) // 添加:状态为正常的批次
.orderByAsc(InvProductBatchEntity::getCreateTime)); // 修改:按入库时间排序
List<InventoryBatchAllocation> allocations = new ArrayList<>();
int remainingQuantity = requiredQuantity;
// 2. FIFO分配
for (InvProductBatchEntity batch : availableBatches) {
if (remainingQuantity <= 0) break;
int allocateQuantity = Math.min(remainingQuantity, batch.getReCount());
allocations.add(InventoryBatchAllocation.builder()
.batch(batch)
.allocatedQuantity(allocateQuantity)
.unitPrice(batch.getPrice())
.expiryDate(batch.getExpireDate())
.build());
remainingQuantity -= allocateQuantity;
}
// 3. 检查是否满足出库数量
if (remainingQuantity > 0) {
throw new JsonException(400, "库存不足,缺少数量:" + remainingQuantity);
}
return allocations;
}
/**
*
*/
@Transactional(rollbackFor = Exception.class)
public void processOutboundAllocations(IoOrderEntity order, IoOrderDetailResultEntity item,
List<InventoryBatchAllocation> allocations) {
// 2. 更新批次库存
for (InventoryBatchAllocation allocation : allocations) {
// 更新批次数量
InvProductBatchEntity batchDO = allocation.getBatch();
batchDO.setReCount(batchDO.getReCount() - allocation.getAllocatedQuantity());
if (batchDO.getReCount() == 0) {
batchDO.setStatus(0); // 批次已清空
}
updateInventoryBatch(batchDO);
// 创建出库流水
createOutboundRecord(order, item, allocation);
}
// 3. 更新主表库存
int totalOutQuantity = allocations.stream()
.mapToInt(InventoryBatchAllocation::getAllocatedQuantity)
.sum();
// todo 更新inv_product 主表
}
/**
*
*/
private void createOutboundRecord(IoOrderEntity order, IoOrderDetailResultEntity item,
InventoryBatchAllocation allocation
) {
InvProductRecord recordDO = new InvProductRecord();
recordDO.setProductId(item.getBindRlFk());
recordDO.setWarehouseId(order.getWarehouseId());
recordDO.setInBatchNo(allocation.getBatch().getInBatchNo());
recordDO.setBatchNo(allocation.getBatch().getBatchNo());
recordDO.setOrderId(order.getBillNo());
recordDO.setOrderType(2); // 出库类型
recordDO.setQuantity(allocation.getAllocatedQuantity());
recordDO.setUnitPrice(allocation.getUnitPrice());
recordDO.setRemark("FIFO出库");
inventoryRecordService.save(recordDO);
}
/**
*
*/
public void validateOutbound(IoOrderEntity order, List<IoOrderDetailResultEntity> items) {
// 1. 验证库存是否足够
validateStock(items, order.getWarehouseId());
// 2. 验证效期
validateExpiry(items, order);
// 3. 验证业务规则
validateBusinessRules(order, items);
}
/**
*
*/
private void validateStock(List<IoOrderDetailResultEntity> items, Long warehouseId) {
for (IoOrderDetailResultEntity item : items) {
try {
// 尝试FIFO分配如果不足会抛出异常
selectBatchesByFIFO(item.getBindRlFk(), warehouseId, item.getReCount());
} catch (Exception e) {
throw new JsonException(400, "库存不足,缺少数量:" + item.getReCount());
}
}
}
/**
*
*/
private void validateExpiry(List<IoOrderDetailResultEntity> items, IoOrderEntity orderDO) {
LocalDateTime now = LocalDateTime.now();
for (IoOrderDetailResultEntity item : items) {
List<InvProductBatchEntity> batches = inventoryBatchMapper.selectList(
new LambdaQueryWrapper<InvProductBatchEntity>()
.eq(InvProductBatchEntity::getRelIdFk, item.getBindRlFk())
.eq(InvProductBatchEntity::getInvCode, orderDO.getWarehouseId())
.gt(InvProductBatchEntity::getReCount, 0)
.lt(InvProductBatchEntity::getExpireDate, now));
if (!batches.isEmpty()) {
throw new JsonException(400, "存在效期不足的批次");
}
}
}
/**
*
*/
private void validateBusinessRules(IoOrderEntity order, List<IoOrderDetailResultEntity> items) {
switch (order.getAction()) {
case "SALE": // 销售出库
break;
case "TRANSFER": // 调拨出库
break;
default:
// 其他类型的出库单据,可以添加相应的验证规则
break;
}
}
/**
*
*/
private void validateSaleRules(List<IoOrderDetailResultEntity> items) {
// 可以添加销售特有的验证规则
// 例如:价格检查、客户信用额度检查等
}
/**
*
*/
private void validateTransferRules(List<IoOrderDetailResultEntity> items) {
// 可以添加调拨特有的验证规则
// 例如:调入仓库容量检查、调拨权限检查等
}
}

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.glxp.api.dao.collect.IoCollectErrorLogMapper">
<resultMap id="BaseResultMap" type="com.glxp.api.entity.collect.IoCollectErrorLog">
<!--@mbg.generated-->
<!--@Table io_collect_error_log-->
<id column="id" jdbcType="INTEGER" property="id" />
<result column="orderId" jdbcType="BIGINT" property="orderId" />
<result column="autoCode" jdbcType="VARCHAR" property="autoCode" />
<result column="manuCode" jdbcType="VARCHAR" property="manuCode" />
<result column="type" jdbcType="INTEGER" property="type" />
<result column="updateTime" jdbcType="TIMESTAMP" property="updateTime" />
<result column="updateUser" jdbcType="TIMESTAMP" property="updateUser" />
<result column="remark" jdbcType="VARCHAR" property="remark" />
</resultMap>
<sql id="Base_Column_List">
<!--@mbg.generated-->
id, orderId, autoCode, manuCode, `type`, updateTime, updateUser, remark
</sql>
</mapper>

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.glxp.api.dao.inv.InvProductRecordMapper">
<resultMap id="BaseResultMap" type="com.glxp.api.entity.inv.InvProductRecord">
<!--@mbg.generated-->
<!--@Table inv_product_record-->
<id column="id" jdbcType="BIGINT" property="id" />
<result column="productId" jdbcType="BIGINT" property="productId" />
<result column="warehouseId" jdbcType="BIGINT" property="warehouseId" />
<result column="inBatchNo" jdbcType="VARCHAR" property="inBatchNo" />
<result column="batchNo" jdbcType="VARCHAR" property="batchNo" />
<result column="orderId" jdbcType="VARCHAR" property="orderId" />
<result column="orderType" jdbcType="TINYINT" property="orderType" />
<result column="quantity" jdbcType="DECIMAL" property="quantity" />
<result column="unitPrice" jdbcType="DECIMAL" property="unitPrice" />
<result column="beforeQuantity" jdbcType="DECIMAL" property="beforeQuantity" />
<result column="afterQuantity" jdbcType="DECIMAL" property="afterQuantity" />
<result column="remark" jdbcType="VARCHAR" property="remark" />
<result column="creator" jdbcType="VARCHAR" property="creator" />
<result column="createTime" jdbcType="TIMESTAMP" property="createTime" />
<result column="updateTime" jdbcType="TIMESTAMP" property="updateTime" />
<result column="updater" jdbcType="VARCHAR" property="updater" />
<result column="tenantId" jdbcType="BIGINT" property="tenantId" />
</resultMap>
<sql id="Base_Column_List">
<!--@mbg.generated-->
id, productId, warehouseId, inBatchNo, batchNo, orderId, orderType, quantity, unitPrice,
beforeQuantity, afterQuantity, remark, creator, createTime, updateTime, updater,
tenantId
</sql>
</mapper>

@ -5509,3 +5509,47 @@ CALL Pro_Temp_ColumnWork('io_collect_order_code_man', 'autoCode',
CALL Pro_Temp_ColumnWork('io_collect_order_backup', 'uploadYbTime',
' datetime DEFAULT NULL COMMENT ''医保上传时间''',
1);
CREATE TABLE IF NOT EXISTS `io_collect_error_log` (
`id` int NOT NULL AUTO_INCREMENT,
`orderId` bigint NULL DEFAULT NULL COMMENT '单据号',
`autoCode` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '自动赋码',
`manuCode` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '手动赋码',
`type` int NULL DEFAULT NULL COMMENT '错误类型1未上传医保替换码2已上传替换码',
`updateTime` datetime NULL DEFAULT NULL COMMENT '更新时间',
`updateUser` datetime NULL DEFAULT NULL COMMENT '更新人',
`remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '备注',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic COMMENT='手动扫码冲突替换码信息';
CALL Pro_Temp_ColumnWork('inv_product_batch', 'status',
'int NULL DEFAULT NULL COMMENT ''状态(1:正常,0:已清空)''',
1);
CREATE TABLE IF NOT EXISTS `inv_product_record` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`productId` bigint NULL DEFAULT NULL COMMENT '产品ID',
`warehouseId` bigint NULL DEFAULT NULL COMMENT '仓库ID',
`inBatchNo` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '内部批号',
`batchNo` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '批次号',
`orderId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '关联单据号',
`orderType` tinyint NULL DEFAULT NULL COMMENT '单据类型(1:入库,2:出库)',
`quantity` decimal(10, 2) NULL DEFAULT NULL COMMENT '操作数量',
`unitPrice` decimal(10, 2) NULL DEFAULT NULL COMMENT '单价',
`beforeQuantity` decimal(10, 2) NULL DEFAULT NULL COMMENT '操作前数量',
`afterQuantity` decimal(10, 2) NULL DEFAULT NULL COMMENT '操作后数量',
`remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '备注',
`creator` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '创建人',
`createTime` datetime NULL DEFAULT NULL COMMENT '创建时间',
`updateTime` datetime NULL DEFAULT NULL COMMENT '更新时间',
`updater` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '更新人',
`tenantId` bigint NULL DEFAULT NULL COMMENT '租户ID',
PRIMARY KEY (`id`) USING BTREE,
INDEX `idx_productId`(`productId` ASC) USING BTREE,
INDEX `idx_orderId`(`orderId` ASC) USING BTREE,
INDEX `idx_createTime`(`createTime` ASC) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 8 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '库存流水表' ROW_FORMAT = DYNAMIC;
Loading…
Cancel
Save