Commit 15102e6e by yubin

出库

parent 389f53a1
......@@ -68,3 +68,12 @@ export function listInventoryByMaterialId(materialId) {
params: { materialId: materialId }
})
}
export function Ship(data) {
return request({
url: '/inventory/inventory/ship',
method: 'post',
data: data
})
}
......@@ -51,3 +51,11 @@ export function listWarehouseInventory(warehouseId) {
params: { warehouseId: warehouseId }
})
}
export function ship(data) {
return request({
url: '/inventory/orders/ship',
method: 'post',
data: data
})
}
\ No newline at end of file
......@@ -4,7 +4,7 @@ import java.util.List;
import java.util.UUID;
import javax.servlet.http.HttpServletResponse;
import com.ruoyi.common.core.domain.entity.Materials;
import com.ruoyi.inventory.domain.InboundOrderItems;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
......@@ -19,7 +19,6 @@ import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.inventory.domain.InboundOrderItems;
import com.ruoyi.inventory.service.IInboundOrderItemsService;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.common.core.page.TableDataInfo;
......
......@@ -118,6 +118,10 @@
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
</dependency>
</dependencies>
......
package com.ruoyi.common.annotation;
import java.lang.annotation.*;
/**
* 若依框架适配 - 方法串行执行注解
* 标记该注解的方法,同一分组内串行执行,不同分组并行
*
* @author RuoYi
*/
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SerialExecution {
/**
* 串行分组(默认空,全局串行)
*/
String group() default "";
/**
* 是否公平锁(按线程等待顺序执行)
*/
boolean fair() default false;
}
\ No newline at end of file
package com.ruoyi.common.aspectj;
import com.ruoyi.common.annotation.SerialExecution;
import com.ruoyi.common.utils.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* 若依框架适配 - 串行执行注解切面
* 参考若依 SysLogAspect 实现风格
*
* @author RuoYi
*/
@Aspect
@Component
public class SerialExecutionAspect {
/**
* 分组锁缓存:key=分组名,value=锁对象
*/
private final Map<String, Lock> groupLockCache = new ConcurrentHashMap<>();
/**
* 切入点:拦截所有标记@SerialExecution的方法
*/
@Pointcut("@annotation(com.ruoyi.common.annotation.SerialExecution)")
public void serialExecutionPointCut() {
}
/**
* 环绕通知:加锁执行,确保串行
*/
@Around("serialExecutionPointCut()")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
// 1. 获取方法注解信息(参考若依日志切面的参数解析方式)
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
SerialExecution serialAnnotation = method.getAnnotation(SerialExecution.class);
if (serialAnnotation == null) {
return joinPoint.proceed();
}
// 2. 解析分组(默认空=全局分组)
String group = StringUtils.trimToEmpty(serialAnnotation.group());
boolean fair = serialAnnotation.fair();
// 3. 获取/创建分组锁(复用若依 StringUtils 工具类)
Lock lock = groupLockCache.computeIfAbsent(group, k -> new ReentrantLock(fair));
// 4. 加锁执行(try-finally 确保锁释放,避免死锁)
try {
lock.lock();
// 执行原方法(若依业务方法的执行逻辑)
return joinPoint.proceed();
} finally {
lock.unlock();
// 可选:若依日志记录(可接入若依的日志框架)
// LogUtils.info("串行方法执行完成,分组:{},方法:{}", group, method.getName());
}
}
}
\ No newline at end of file
......@@ -78,7 +78,16 @@ public class OutboundOrderItemsController extends BaseController
@PostMapping
public AjaxResult add(@RequestBody OutboundOrderItems outboundOrderItems)
{
return toAjax(outboundOrderItemsService.insertOutboundOrderItems(outboundOrderItems));
try {
// 调用业务层校验+插入逻辑
outboundOrderItemsService.insertOutboundOrderItems(outboundOrderItems);
// 校验通过:返回成功(若依标准成功响应)
return success("新增出库单明细成功");
} catch (Exception e) {
// 校验失败:捕获异常,返回"库存被修改请重新确认"(前端弹窗用)
logger.error("新增出库单明细失败", e);
return error("库存被修改请重新确认");
}
}
/**
......@@ -89,9 +98,19 @@ public class OutboundOrderItemsController extends BaseController
@PutMapping
public AjaxResult edit(@RequestBody OutboundOrderItems outboundOrderItems)
{
return toAjax(outboundOrderItemsService.updateOutboundOrderItems(outboundOrderItems));
try {
// 调用业务层校验+插入逻辑
outboundOrderItemsService.updateOutboundOrderItems(outboundOrderItems);
// 校验通过:返回成功(若依标准成功响应)
return success("新增出库单明细成功");
} catch (Exception e) {
// 校验失败:捕获异常,返回"库存被修改请重新确认"(前端弹窗用)
logger.error("新增出库单明细失败", e);
return error("库存被修改请重新确认");
}
}
/**
* 删除出库单明细
*/
......
......@@ -2,6 +2,8 @@ package com.ruoyi.inventory.controller;
import java.util.List;
import javax.servlet.http.HttpServletResponse;
import com.ruoyi.inventory.domain.Inventory;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
......@@ -70,6 +72,17 @@ public class OutboundOrdersController extends BaseController
}
/**
* 出货
*/
@PreAuthorize("@ss.hasPermi('inventory:inventory:edit')")
@Log(title = "出货", businessType = BusinessType.UPDATE)
@PostMapping("/ship")
public AjaxResult Ship(@RequestBody OutboundOrders outboundOrders )
{
return toAjax(outboundOrdersService.ship(outboundOrders));
}
/**
* 新增出库单主
*/
@PreAuthorize("@ss.hasPermi('inventory:orders:add')")
......
......@@ -40,6 +40,10 @@ public class OutboundOrderItems extends BaseEntity
@Excel(name = "库位ID 检索条件")
private String locationId;
/** 库存ID */
private String inventoryId;
/** 计划数量 */
@Excel(name = "计划数量")
private Long plannedQuantity;
......@@ -89,7 +93,15 @@ public class OutboundOrderItems extends BaseEntity
@Excel(name = "排序号")
private String updateUserCode;
public void setId(String id)
public String getInventoryId() {
return inventoryId;
}
public void setInventoryId(String inventoryId) {
this.inventoryId = inventoryId;
}
public void setId(String id)
{
this.id = id;
}
......@@ -292,6 +304,7 @@ public class OutboundOrderItems extends BaseEntity
.append("createTime", getCreateTime())
.append("createUserCode", getCreateUserCode())
.append("updateTime", getUpdateTime())
.append("inventoryId", getInventoryId())
.append("updateUserCode", getUpdateUserCode())
.toString();
}
......
......@@ -22,6 +22,9 @@ public class OutboundOrderLog extends BaseEntity
@Excel(name = "出货单号ID")
private String orderId;
/** 库存ID */
private String inventoryId;
/** 货物ID */
@Excel(name = "货物ID")
private String materialId;
......@@ -81,7 +84,15 @@ public class OutboundOrderLog extends BaseEntity
this.warehouseId = warehouseId;
}
public String getWarehouseId()
public String getInventoryId() {
return inventoryId;
}
public void setInventoryId(String inventoryId) {
this.inventoryId = inventoryId;
}
public String getWarehouseId()
{
return warehouseId;
}
......@@ -137,6 +148,7 @@ public class OutboundOrderLog extends BaseEntity
.append("materialId", getMaterialId())
.append("warehouseId", getWarehouseId())
.append("batchCode", getBatchCode())
.append("inventoryId", getInventoryId())
.append("actualQuantity", getActualQuantity())
.append("itemStatus", getItemStatus())
.append("isUsed", getIsUsed())
......
......@@ -53,6 +53,8 @@ public interface InventoryMapper
*/
public int updateInventory(Inventory inventory);
/**
* 删除库存
*
......@@ -69,7 +71,7 @@ public interface InventoryMapper
*/
public int deleteInventoryByIds(String[] ids);
public List<Inventory> listByMatreialId(String materialId);
public List<Inventory> listByMaterialId(String materialId);
/**
* @description: 获取库存盘点详细信息
......
package com.ruoyi.inventory.mapper;
import java.util.List;
import com.ruoyi.inventory.domain.OutboundOrderItems;
import com.ruoyi.inventory.domain.OutboundOrderLog;
/**
......@@ -19,6 +21,7 @@ public interface OutboundOrderLogMapper
*/
public OutboundOrderLog selectOutboundOrderLogById(String id);
/**
* 查询出库明细子(仅用于锁定数量统计)列表
*
......@@ -34,7 +37,8 @@ public interface OutboundOrderLogMapper
* @param outboundOrderLog 出库明细子(仅用于锁定数量统计)
* @return 出库明细子(仅用于锁定数量统计)集合
*/
public Long selectLockedQuantity(OutboundOrderLog outboundOrderLog);
public Long selectLockedQuantityByInventory(String id);
/**
* 新增出库明细子(仅用于锁定数量统计)
......@@ -66,6 +70,24 @@ public interface OutboundOrderLogMapper
* @param ids 需要删除的数据主键集合
* @return 结果
*/
public int deleteOutboundOrderLogByOrdersId(String id);
/**
* 批量删除出库明细子(仅用于锁定数量统计)
*
* @param ids 需要删除的数据主键集合
* @return 结果
*/
public int deleteOutboundOrderLogByIds(String[] ids);
/**
* 批量新增出库单明细
*
* @param outboundOrderItemsList 出库单明细列表
* @return 结果
*/
public int batchOutboundOrderLog(List<OutboundOrderLog> outboundOrderLogs);
}
......@@ -2,21 +2,23 @@ package com.ruoyi.inventory.service;
import java.util.List;
import com.ruoyi.common.annotation.SerialExecution;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.inventory.domain.Inventory;
import com.ruoyi.inventory.domain.OutboundOrderItems;
import com.ruoyi.inventory.domain.StocktakeItems;
/**
* 库存Service接口
*
*
* @author ruoyi
* @date 2025-12-03
*/
public interface IInventoryService
public interface IInventoryService
{
/**
* 查询库存
*
*
* @param id 库存主键
* @return 库存
*/
......@@ -24,7 +26,7 @@ public interface IInventoryService
/**
* 查询库存列表
*
*
* @param inventory 库存
* @return 库存集合
*/
......@@ -34,7 +36,7 @@ public interface IInventoryService
/**
* 新增库存
*
*
* @param inventory 库存
* @return 结果
*/
......@@ -49,15 +51,23 @@ public interface IInventoryService
public int insertInventoryList(List<Inventory> inventoryList);
/**
* 修改库存
*
*
* @param inventory 库存
* @return 结果
*/
public int updateInventory(Inventory inventory);
int RefreshInventory(List<String> inventoryIds);
@SerialExecution(group = "inventoryRefresh", fair = true)
int ship(List<OutboundOrderItems> outboundOrderItems);
@SerialExecution(group = "inventoryRefresh", fair = true)
boolean inventoryLockValidation(List<OutboundOrderItems> outboundOrderItems);
/**
* 批量删除库存
*
*
* @param ids 需要删除的库存主键集合
* @return 结果
*/
......@@ -65,14 +75,13 @@ public interface IInventoryService
/**
* 删除库存信息
*
*
* @param id 库存主键
* @return 结果
*/
public int deleteInventoryById(String id);
public List<Inventory> listByMatreialId(String materialId);
/**
* @description: 获取库存盘点详细信息
* @author cs
......@@ -80,4 +89,6 @@ public interface IInventoryService
* @version 1.0
*/
public List<StocktakeItems> selectstocktakeItemsList();
}
......@@ -35,7 +35,6 @@ public interface IOutboundOrderLogService
*/
public int insertOutboundOrderLog(OutboundOrderLog outboundOrderLog);
Long selectLockedQuantity(OutboundOrderLog outboundOrderLog);
/**
* 修改出库明细子(仅用于锁定数量统计)
......
......@@ -58,4 +58,13 @@ public interface IOutboundOrdersService
* @return 结果
*/
public int deleteOutboundOrdersById(String id);
/**
* 出货
*
* @param id 出库单主主键
* @return 结果
*/
public int ship(OutboundOrders outboundOrders);
}
package com.ruoyi.inventory.service.impl;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;
import com.ruoyi.common.annotation.SerialExecution;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.inventory.domain.OutboundOrderItems;
import com.ruoyi.inventory.domain.OutboundOrderLog;
import com.ruoyi.inventory.domain.StocktakeItems;
import com.ruoyi.inventory.mapper.OutboundOrderLogMapper;
import org.springframework.beans.BeanUtils;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.SystemUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.ruoyi.inventory.mapper.InventoryMapper;
......@@ -16,7 +21,7 @@ import com.ruoyi.inventory.service.IInventoryService;
/**
* 库存Service业务层处理
*
*
* @author ruoyi
* @date 2025-12-03
*/
......@@ -30,7 +35,7 @@ public class InventoryServiceImpl implements IInventoryService
/**
* 查询库存
*
*
* @param id 库存主键
* @return 库存
*/
......@@ -42,7 +47,7 @@ public class InventoryServiceImpl implements IInventoryService
/**
* 查询库存列表
*
*
* @param inventory 库存
* @return 库存
*/
......@@ -52,19 +57,16 @@ public class InventoryServiceImpl implements IInventoryService
return inventoryMapper.selectInventoryList(inventory);
}
@Override
public Inventory selectInventory(Inventory inventory)
{
Inventory inventory1 = inventoryMapper.selectInventory(inventory);
OutboundOrderLog outboundOrderLog = new OutboundOrderLog();
BeanUtils.copyProperties(inventory1,outboundOrderLog);
inventory1.setLockedQuantity(outboundOrderLogMapper.selectLockedQuantity(outboundOrderLog));
return inventory1;
return inventoryMapper.selectInventory(inventory);
}
/**
* 新增库存
*
*
* @param inventory 库存
* @return 结果
*/
......@@ -72,6 +74,7 @@ public class InventoryServiceImpl implements IInventoryService
public int insertInventory(Inventory inventory)
{
inventory.setCreateTime(DateUtils.getNowDate());
inventory.setCreateBy(SystemUtils.getUserName());
return inventoryMapper.insertInventory(inventory);
}
......@@ -85,25 +88,80 @@ public class InventoryServiceImpl implements IInventoryService
}
return count;
}
/**
* 修改库存
*
*
* @param inventory 库存
* @return 结果
*/
@Override
public int updateInventory(Inventory inventory)
{
List<Inventory> inventoryList = Collections.singletonList(inventory);
inventory.setUpdateTime(DateUtils.getNowDate());
inventory.setUpdateBy(SystemUtils.getUserName());
return inventoryMapper.updateInventory(inventory);
}
@SerialExecution( group = "inventoryRefresh", fair = true)
@Override
public int RefreshInventory(List<String> inventoryIds)
{
for (String inventoryId : inventoryIds) {
// 1. 空值前置校验:跳过空的循环项
if (inventoryId == null) {
continue;
}
// 6. 查询锁定数量(优化:只查一次)
Long lockedQuantity = outboundOrderLogMapper.selectLockedQuantityByInventory(inventoryId);
Inventory inventory = new Inventory();
inventory.setLockedQuantity(lockedQuantity);
inventory.setId(inventoryId);
inventoryMapper.updateInventory(inventory);
}
return 1;
}
@SerialExecution(group = "inventoryRefresh", fair = true)
@Override
public int ship(List<OutboundOrderItems> outboundOrderItems)
{
if (!outboundOrderItems.isEmpty()) {
for (OutboundOrderItems outboundOrderItem : outboundOrderItems) {
OutboundOrderLog outboundOrderLog = outboundOrderLogMapper.selectOutboundOrderLogById(outboundOrderItem.getId());
Inventory inventory =inventoryMapper.selectInventoryById(outboundOrderLog.getInventoryId());
inventory.setQuantity(inventory.getQuantity()-outboundOrderItem.getActualQuantity());
inventory.setLockedQuantity(inventory.getQuantity()-outboundOrderItem.getActualQuantity());
if (inventory.getQuantity()==0){
inventory.setInventoryStatus(0l);
}
updateInventory(inventory);
}
}
return 1;
}
@SerialExecution(group = "inventoryRefresh", fair = true)
@Override
public boolean inventoryLockValidation(List<OutboundOrderItems> outboundOrderItems)
{
if (!outboundOrderItems.isEmpty()) {
for (OutboundOrderItems outboundOrderItem : outboundOrderItems) {
Inventory inventory = inventoryMapper.selectInventoryById(outboundOrderItem.getInventoryId());
if (inventory.getLockedQuantity()+outboundOrderItem.getActualQuantity()>inventory.getQuantity()){
return false;
}
}
return true;
}
return true;
}
/**
* 批量删除库存
*
*
* @param ids 需要删除的库存主键
* @return 结果
*/
......@@ -115,7 +173,7 @@ public class InventoryServiceImpl implements IInventoryService
/**
* 删除库存信息
*
*
* @param id 库存主键
* @return 结果
*/
......@@ -125,11 +183,19 @@ public class InventoryServiceImpl implements IInventoryService
return inventoryMapper.deleteInventoryById(id);
}
@SerialExecution(group = "inventoryRefresh", fair = true)
@Override
public List<Inventory> listByMatreialId(String materialId) {
return inventoryMapper.listByMatreialId(materialId);
Inventory inventory = new Inventory();
inventory.setMaterialId(materialId);
List<String> inventoryIds = CollectionUtils.isEmpty(inventoryMapper.listByMaterialId(materialId))
? Collections.emptyList() // 空时返回空列表,避免后续NPE
: inventoryMapper.listByMaterialId(materialId).stream()
.map(inventory2 -> inventory2.getId()) // 提取ID(核心修正)
.collect(Collectors.toList());
RefreshInventory(inventoryIds);
return inventoryMapper.listByMaterialId(materialId);
}
/**
* @description: 获取库存盘点详细信息
* @author cs
......
package com.ruoyi.inventory.service.impl;
import java.util.ArrayList;
import java.util.List;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.inventory.domain.Inventory;
import com.ruoyi.inventory.domain.OutboundOrderLog;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.ruoyi.inventory.mapper.OutboundOrderItemsMapper;
......@@ -53,12 +49,7 @@ public class OutboundOrderItemsServiceImpl implements IOutboundOrderItemsService
return outboundOrderItemsMapper.selectOutboundOrderItemsList(outboundOrderItems);
}
/**
* 新增出库单明细
*
* @param outboundOrderItemsInventory 出库单明细库存DTO
* @return 结果
*/
@Override
public int insertOutboundOrderItems(OutboundOrderItems outboundOrderItems)
{
......@@ -66,12 +57,7 @@ public class OutboundOrderItemsServiceImpl implements IOutboundOrderItemsService
return outboundOrderItemsMapper.insertOutboundOrderItems(outboundOrderItems);
}
/**
* 修改出库单明细
*
* @param outboundOrderItemsInventory 出库单明细库存DTO
* @return 结果
*/
@Override
public int updateOutboundOrderItems(OutboundOrderItems outboundOrderItems)
{
......
......@@ -54,10 +54,6 @@ public class OutboundOrderLogServiceImpl implements IOutboundOrderLogService
{
return outboundOrderLogMapper.insertOutboundOrderLog(outboundOrderLog);
}
@Override
public Long selectLockedQuantity(OutboundOrderLog outboundOrderLog){
return outboundOrderLogMapper.selectLockedQuantity(outboundOrderLog);
}
/**
* 修改出库明细子(仅用于锁定数量统计)
*
......
package com.ruoyi.inventory.service.impl;
import java.util.List;
import com.ruoyi.common.annotation.SerialExecution;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.inventory.domain.Inventory;
import com.ruoyi.inventory.domain.OutboundOrderLog;
import com.ruoyi.inventory.mapper.InventoryMapper;
import com.ruoyi.inventory.mapper.OutboundOrderItemsMapper;
import com.ruoyi.inventory.mapper.OutboundOrderLogMapper;
import org.apache.commons.lang3.SystemUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.UUID;
import com.ruoyi.common.utils.StringUtils;
import org.springframework.transaction.annotation.Transactional;
import com.ruoyi.inventory.domain.OutboundOrderItems;
......@@ -14,19 +25,26 @@ import com.ruoyi.inventory.service.IOutboundOrdersService;
/**
* 出库单主Service业务层处理
*
*
* @author ruoyi
* @date 2025-12-03
*/
@Service
public class OutboundOrdersServiceImpl implements IOutboundOrdersService
public class OutboundOrdersServiceImpl implements IOutboundOrdersService
{
@Autowired
private OutboundOrdersMapper outboundOrdersMapper;
@Autowired
private OutboundOrderItemsMapper outboundOrderItemsMapper;
@Autowired
private OutboundOrderLogMapper outboundOrderLogMapper;
@Autowired
private InventoryServiceImpl inventoryService;
/**
* 查询出库单主
*
*
* @param id 出库单主主键
* @return 出库单主
*/
......@@ -39,7 +57,7 @@ public class OutboundOrdersServiceImpl implements IOutboundOrdersService
/**
* 查询出库单主列表
*
*
* @param outboundOrders 出库单主
* @return 出库单主
*/
......@@ -51,7 +69,7 @@ public class OutboundOrdersServiceImpl implements IOutboundOrdersService
/**
* 新增出库单主
*
*
* @param outboundOrders 出库单主
* @return 结果
*/
......@@ -60,6 +78,8 @@ public class OutboundOrdersServiceImpl implements IOutboundOrdersService
public int insertOutboundOrders(OutboundOrders outboundOrders)
{
outboundOrders.setCreateTime(DateUtils.getNowDate());
outboundOrders.setCreateBy(SystemUtils.getUserName());
outboundOrders.setId(UUID.randomUUID().toString());
int rows = outboundOrdersMapper.insertOutboundOrders(outboundOrders);
insertOutboundOrderItems(outboundOrders);
return rows;
......@@ -67,7 +87,7 @@ public class OutboundOrdersServiceImpl implements IOutboundOrdersService
/**
* 修改出库单主
*
*
* @param outboundOrders 出库单主
* @return 结果
*/
......@@ -77,13 +97,14 @@ public class OutboundOrdersServiceImpl implements IOutboundOrdersService
{
outboundOrders.setUpdateTime(DateUtils.getNowDate());
outboundOrdersMapper.deleteOutboundOrderItemsByOrderId(outboundOrders.getId());
outboundOrderLogMapper.deleteOutboundOrderLogByOrdersId(outboundOrders.getId());
insertOutboundOrderItems(outboundOrders);
return outboundOrdersMapper.updateOutboundOrders(outboundOrders);
}
/**
* 批量删除出库单主
*
*
* @param ids 需要删除的出库单主主键
* @return 结果
*/
......@@ -97,7 +118,7 @@ public class OutboundOrdersServiceImpl implements IOutboundOrdersService
/**
* 删除出库单主信息
*
*
* @param id 出库单主主键
* @return 结果
*/
......@@ -108,26 +129,88 @@ public class OutboundOrdersServiceImpl implements IOutboundOrdersService
outboundOrdersMapper.deleteOutboundOrderItemsByOrderId(id);
return outboundOrdersMapper.deleteOutboundOrdersById(id);
}
@SerialExecution(group = "inventoryRefresh", fair = true)
@Override
public int ship(OutboundOrders outboundOrders) {
OutboundOrderItems outboundOrderItems1 = new OutboundOrderItems();
outboundOrderItems1.setOrderId(outboundOrders.getId());
List<OutboundOrderItems> outboundOrderItems = outboundOrderItemsMapper.selectOutboundOrderItemsList(outboundOrderItems1);
List<OutboundOrderItems> outboundOrderItems2 = outboundOrderItems;
OutboundOrderLog outboundOrderLog = new OutboundOrderLog();
for (OutboundOrderItems outboundOrderItem : outboundOrderItems) {
outboundOrderItem.setItemStatus(3l);
outboundOrderItemsMapper.updateOutboundOrderItems(outboundOrderItem);
outboundOrderLog.setId(outboundOrderItem.getId());
outboundOrderLog.setItemStatus(outboundOrderItem.getItemStatus());
outboundOrderLogMapper.updateOutboundOrderLog(outboundOrderLog);
}
outboundOrders.setId(outboundOrders.getId());
outboundOrders.setOrderStatus(3l);
outboundOrders.setUpdateTime(DateUtils.getNowDate());
outboundOrders.setUpdateBy(SystemUtils.getUserName());
outboundOrdersMapper.updateOutboundOrders(outboundOrders);
inventoryService.ship(outboundOrderItems2);
return 1;
}
/**
* 新增出库单明细信息
*
*
* @param outboundOrders 出库单主对象
*/
public void insertOutboundOrderItems(OutboundOrders outboundOrders)
{
public void insertOutboundOrderItems(OutboundOrders outboundOrders) {
List<OutboundOrderItems> outboundOrderItemsList = outboundOrders.getOutboundOrderItemsList();
String id = outboundOrders.getId();
if (StringUtils.isNotNull(outboundOrderItemsList))
{
for (OutboundOrderItems outboundOrderItems : outboundOrderItemsList)
{
outboundOrderItems.setOrderId(id);
}
if (outboundOrderItemsList.size() > 0)
{
outboundOrdersMapper.batchOutboundOrderItems(outboundOrderItemsList);
}
// 1. 先做空列表校验(提前返回,避免无效逻辑)
if (outboundOrderItemsList == null || outboundOrderItemsList.isEmpty()) {
return;
}
// 2. 库存校验:失败时抛异常(核心修正:! 取反 + 异常抛出后代码立即终止)
boolean isValid = inventoryService.inventoryLockValidation(outboundOrderItemsList);
if (!isValid) { // 校验失败(返回false)时抛异常
throw new RuntimeException("库存被修改请重新确认"); // 抛异常后,方法立即停止运行
}
// 2. 为明细设置订单ID和主键ID
for (OutboundOrderItems items : outboundOrderItemsList) {
items.setOrderId(id);
// 生成无横线的UUID作为主键
items.setId(UUID.randomUUID().toString().replace("-", ""));
}
// 3. 批量插入出库单明细
outboundOrdersMapper.batchOutboundOrderItems(outboundOrderItemsList);
// 4. 正确拷贝明细列表到日志列表(修复核心错误:遍历逐个拷贝)
List<String> inventoryIds = new ArrayList<>();
List<OutboundOrderLog> outboundOrderLogs = new ArrayList<>();
for (OutboundOrderItems items : outboundOrderItemsList) {
OutboundOrderLog log = new OutboundOrderLog();
BeanUtils.copyProperties(items, log); // 单个对象属性拷贝
outboundOrderLogs.add(log);
inventoryIds.add(log.getInventoryId());
deleteOutboundOrdersById(items.getId());
}
// 5. 非空校验后插入日志(避免空列表触发SQL语法错误)
if (!outboundOrderLogs.isEmpty()) {
outboundOrderLogMapper.batchOutboundOrderLog(outboundOrderLogs);
}
// 7. 非空校验后刷新库存
if (!inventoryIds.isEmpty()) {
inventoryService.RefreshInventory(inventoryIds);
}
}
}
......@@ -123,9 +123,16 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<include refid="selectInventoryVo"/>
where id = #{id}
</select>
<select id="listByMatreialId" parameterType="String" resultMap="InventoryResult">
<select id="listByMaterialId" parameterType="String" resultMap="InventoryResult">
<include refid="selectInventoryVo"/>
where material_id = #{materialId}
where 1=1
<if test="materialId != null and materialId.trim() != ''">
and material_id = #{materialId}
</if>
<![CDATA[
and inventory_status = '1'
and quantity > locked_quantity
]]>
</select>
<insert id="insertInventory" parameterType="Inventory">
insert into inventory
......
......@@ -11,6 +11,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<result property="batchCode" column="batch_code" />
<result property="warehouseId" column="warehouse_id" />
<result property="locationId" column="location_id" />
<result property="inventoryId" column="inventory_id" />
<result property="plannedQuantity" column="planned_quantity" />
<result property="actualQuantity" column="actual_quantity" />
<result property="divisor" column="divisor" />
......@@ -29,7 +30,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</resultMap>
<sql id="selectOutboundOrderItemsVo">
select id, order_id, material_id, batch_code, warehouse_id, location_id, planned_quantity, actual_quantity, divisor, label_color, voucher_number, item_status, shipped_at, shipped_by, remark, is_used, sort_no, create_time, create_user_code, update_time, update_user_code from outbound_order_items
select id, order_id, material_id, batch_code, warehouse_id, location_id, inventory_id, planned_quantity, actual_quantity, divisor, label_color, voucher_number, item_status, shipped_at, shipped_by, remark, is_used, sort_no, create_time, create_user_code, update_time, update_user_code from outbound_order_items
</sql>
<select id="selectOutboundOrderItemsList" parameterType="OutboundOrderItems" resultMap="OutboundOrderItemsResult">
......@@ -40,6 +41,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="batchCode != null and batchCode != ''"> and batch_code = #{batchCode}</if>
<if test="warehouseId != null and warehouseId != ''"> and warehouse_id = #{warehouseId}</if>
<if test="locationId != null and locationId != ''"> and location_id = #{locationId}</if>
<if test="inventoryId != null and inventoryId != ''"> and inventory_id = #{inventoryId}</if>
<if test="plannedQuantity != null "> and planned_quantity = #{plannedQuantity}</if>
<if test="actualQuantity != null "> and actual_quantity = #{actualQuantity}</if>
<if test="divisor != null "> and divisor = #{divisor}</if>
......@@ -69,6 +71,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="batchCode != null">batch_code,</if>
<if test="warehouseId != null">warehouse_id,</if>
<if test="locationId != null">location_id,</if>
<if test="inventoryId != null">inventory_id,</if>
<if test="plannedQuantity != null">planned_quantity,</if>
<if test="actualQuantity != null">actual_quantity,</if>
<if test="divisor != null">divisor,</if>
......@@ -92,6 +95,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="batchCode != null">#{batchCode},</if>
<if test="warehouseId != null">#{warehouseId},</if>
<if test="locationId != null">#{locationId},</if>
<if test="inventoryId != null">#{inventoryId},</if>
<if test="plannedQuantity != null">#{plannedQuantity},</if>
<if test="actualQuantity != null">#{actualQuantity},</if>
<if test="divisor != null">#{divisor},</if>
......@@ -118,6 +122,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="batchCode != null">batch_code = #{batchCode},</if>
<if test="warehouseId != null">warehouse_id = #{warehouseId},</if>
<if test="locationId != null">location_id = #{locationId},</if>
<if test="inventoryId != null">inventory_id = #{inventoryId},</if>
<if test="plannedQuantity != null">planned_quantity = #{plannedQuantity},</if>
<if test="actualQuantity != null">actual_quantity = #{actualQuantity},</if>
<if test="divisor != null">divisor = #{divisor},</if>
......
......@@ -7,6 +7,7 @@
<resultMap type="OutboundOrderLog" id="OutboundOrderLogResult">
<result property="id" column="id" />
<result property="orderId" column="order_id" />
<result property="inventoryId" column="inventory_id" />
<result property="materialId" column="material_id" />
<result property="warehouseId" column="warehouse_id" />
<result property="batchCode" column="batch_code" />
......@@ -15,8 +16,9 @@
<result property="isUsed" column="is_used" />
</resultMap>
<!-- 补充inventory_id到查询字段中 -->
<sql id="selectOutboundOrderLogVo">
select id, order_id, material_id, warehouse_id, batch_code, actual_quantity, item_status, is_used
select id, order_id, inventory_id, material_id, warehouse_id, batch_code, actual_quantity, item_status, is_used
from outbound_order_log
</sql>
......@@ -24,6 +26,7 @@
<include refid="selectOutboundOrderLogVo"/>
<where>
<if test="orderId != null and orderId != ''"> and order_id = #{orderId}</if>
<if test="inventoryId != null and inventoryId != ''"> and inventory_id = #{inventoryId}</if>
<if test="materialId != null and materialId != ''"> and material_id = #{materialId}</if>
<if test="warehouseId != null and warehouseId != ''"> and warehouse_id = #{warehouseId}</if>
<if test="batchCode != null and batchCode != ''"> and batch_code = #{batchCode}</if>
......@@ -33,26 +36,39 @@
</where>
</select>
<select id="selectLockedQuantity" parameterType="OutboundOrderLog" resultType="java.lang.Long">
select ifnull(sum(actual_quantity), 0)
from outbound_order_log
<select id="deleteLog" parameterType="OutboundOrderLog" resultMap="OutboundOrderLogResult">
delete from outbound_order_log
<where>
<if test="materialId != null and materialId != ''"> and material_id = #{materialId}</if>
<if test="warehouseId != null and warehouseId != ''"> and warehouse_id = #{warehouseId}</if>
<if test="batchCode != null and batchCode != ''"> and batch_code = #{batchCode}</if>
<if test="itemStatus != null "> and item_status = #{itemStatus}</if>
<!-- 补充inventory_id条件 -->
<if test="inventoryId != null and inventoryId != ''"> and inventory_id = #{inventoryId}</if>
</where>
</select>
<!-- 修正参数错误:原#{id}改为#{inventoryId} -->
<select id="selectLockedQuantityByInventory" parameterType="OutboundOrderLog" resultType="java.lang.Long">
select ifnull(sum(actual_quantity), 0)
from outbound_order_log
where item_status=1
<if test="inventoryId != null and inventoryId != ''"> and inventory_id = #{inventoryId}</if>
</select>
<select id="selectOutboundOrderLogById" parameterType="String" resultMap="OutboundOrderLogResult">
<include refid="selectOutboundOrderLogVo"/>
where id = #{id}
</select>
<!-- 插入语句补充inventory_id -->
<insert id="insertOutboundOrderLog" parameterType="OutboundOrderLog">
insert into outbound_order_log
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="id != null">id,</if>
<if test="orderId != null">order_id,</if>
<if test="inventoryId != null">inventory_id,</if>
<if test="materialId != null">material_id,</if>
<if test="warehouseId != null">warehouse_id,</if>
<if test="batchCode != null">batch_code,</if>
......@@ -63,6 +79,7 @@
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="id != null">#{id},</if>
<if test="orderId != null">#{orderId},</if>
<if test="inventoryId != null">#{inventoryId},</if>
<if test="materialId != null">#{materialId},</if>
<if test="warehouseId != null">#{warehouseId},</if>
<if test="batchCode != null">#{batchCode},</if>
......@@ -72,10 +89,12 @@
</trim>
</insert>
<!-- 更新语句补充inventory_id -->
<update id="updateOutboundOrderLog" parameterType="OutboundOrderLog">
update outbound_order_log
<trim prefix="SET" suffixOverrides=",">
<if test="orderId != null">order_id = #{orderId},</if>
<if test="inventoryId != null">inventory_id = #{inventoryId},</if>
<if test="materialId != null">material_id = #{materialId},</if>
<if test="warehouseId != null">warehouse_id = #{warehouseId},</if>
<if test="batchCode != null">batch_code = #{batchCode},</if>
......@@ -90,10 +109,39 @@
delete from outbound_order_log where id = #{id}
</delete>
<delete id="deleteOutboundOrderLogByIds" parameterType="String">
delete from outbound_order_log where id in
<foreach item="id" collection="array" open="(" separator="," close=")">
#{id}
</foreach>
<delete id="deleteOutboundOrderLogByOrdersId" parameterType="String">
delete from outbound_order_log where order_id = #{id}
</delete>
<!-- 批量插入补充inventory_id -->
<insert id="batchOutboundOrderLog">
<!-- 增加非空判断,避免空列表导致SQL语法错误 -->
<if test="list != null and list.size() > 0">
insert into outbound_order_log(
id,
order_id,
inventory_id, <!-- 新增 -->
material_id,
warehouse_id,
batch_code, <!-- 对应实体类batchCode -->
actual_quantity,
item_status,
is_used
) values
<foreach item="item" index="index" collection="list" separator=",">
(
#{item.id},
#{item.orderId},
#{item.inventoryId},
#{item.materialId},
#{item.warehouseId},
#{item.batchCode},
#{item.actualQuantity},
#{item.itemStatus},
#{item.isUsed}
)
</foreach>
</if>
</insert>
</mapper>
\ No newline at end of file
<?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">
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ruoyi.inventory.mapper.OutboundOrdersMapper">
<resultMap type="OutboundOrders" id="OutboundOrdersResult">
<result property="id" column="id" />
<result property="orderId" column="order_id" />
......@@ -31,40 +31,40 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<collection property="outboundOrderItemsList" ofType="OutboundOrderItems" column="id" select="selectOutboundOrderItemsList" />
</resultMap>
<!-- 修复:仅保留子表outbound_order_items的字段映射,删除错误的主表字段 -->
<resultMap type="OutboundOrderItems" id="OutboundOrderItemsResult">
<result property="id" column="id" />
<result property="orderId" column="order_id" />
<result property="materialId" column="material_id" />
<result property="batchId" column="batch_id" />
<result property="warehouseId" column="warehouse_id" />
<result property="locationId" column="location_id" />
<result property="plannedQuantity" column="planned_quantity" />
<result property="actualQuantity" column="actual_quantity" />
<result property="plannedPackages" column="planned_packages" />
<result property="actualPackages" column="actual_packages" />
<result property="divisor" column="divisor" />
<result property="labelColor" column="label_color" />
<result property="voucherNumber" column="voucher_number" />
<result property="unitPrice" column="unit_price" />
<result property="itemStatus" column="item_status" />
<result property="receivedAt" column="received_at" />
<result property="receivedBy" column="received_by" />
<result property="remark" column="remark" />
<result property="isUsed" column="is_used" />
<result property="sortNo" column="sort_no" />
<result property="createTime" column="create_time" />
<result property="createUserCode" column="create_user_code" />
<result property="updateTime" column="update_time" />
<result property="updateUserCode" column="update_user_code" />
<result property="id" column="id" />
<result property="orderId" column="order_id" />
<result property="materialId" column="material_id" />
<result property="batchCode" column="batch_code" />
<result property="warehouseId" column="warehouse_id" />
<result property="locationId" column="location_id" />
<result property="plannedQuantity" column="planned_quantity" />
<result property="inventoryId" column="inventory_id" />
<result property="actualQuantity" column="actual_quantity" />
<result property="divisor" column="divisor" />
<result property="labelColor" column="label_color" />
<result property="voucherNumber" column="voucher_number" />
<result property="itemStatus" column="item_status" />
<result property="shippedAt" column="shipped_at" />
<result property="shippedBy" column="shipped_by" />
<result property="remark" column="remark" />
<result property="isUsed" column="is_used" />
<result property="sortNo" column="sort_no" />
<result property="createTime" column="create_time" />
<result property="createUserCode" column="create_user_code" />
<result property="updateTime" column="update_time" />
<result property="updateUserCode" column="update_user_code" />
</resultMap>
<sql id="selectOutboundOrdersVo">
select id, order_id, system_no, order_type_id, batch_code, warehouse_id, owner_id, order_status, inbound_date, destination, total_planned_quantity, total_actual_quantity, total_packages, remark, is_used, sort_no, create_time, create_user_code, update_time, update_user_code from outbound_orders
</sql>
<select id="selectOutboundOrdersList" parameterType="OutboundOrders" resultMap="OutboundOrdersResult">
<include refid="selectOutboundOrdersVo"/>
<where>
<where>
<if test="orderId != null and orderId != ''"> and order_id = #{orderId}</if>
<if test="systemNo != null and systemNo != ''"> and system_no = #{systemNo}</if>
<if test="orderTypeId != null and orderTypeId != ''"> and order_type_id = #{orderTypeId}</if>
......@@ -83,16 +83,17 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="updateUserCode != null and updateUserCode != ''"> and update_user_code = #{updateUserCode}</if>
</where>
</select>
<select id="selectOutboundOrdersById" parameterType="String" resultMap="OutboundOrdersOutboundOrderItemsResult">
select id, order_id, system_no, order_type_id, batch_code, warehouse_id, owner_id, order_status, inbound_date, destination, total_planned_quantity, total_actual_quantity, total_packages, remark, is_used, sort_no, create_time, create_user_code, update_time, update_user_code
from outbound_orders
where id = #{id}
</select>
<!-- 仅保留子表查询逻辑,字段完整且映射正确 -->
<select id="selectOutboundOrderItemsList" parameterType="String" resultMap="OutboundOrderItemsResult">
select id, order_id, material_id, batch_code, warehouse_id, location_id, planned_quantity, actual_quantity, divisor, label_color, voucher_number, item_status, shipped_at, shipped_by, remark, is_used, sort_no, create_time, create_user_code, update_time, update_user_code
from outbound_order_items
select id, order_id, material_id, batch_code, warehouse_id, location_id, planned_quantity, actual_quantity, divisor, label_color, voucher_number, item_status, shipped_at, shipped_by, remark, is_used, sort_no, create_time, create_user_code, update_time, update_user_code , inventory_id
from outbound_order_items
where order_id = #{id}
</select>
......@@ -119,7 +120,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="createUserCode != null">create_user_code,</if>
<if test="updateTime != null">update_time,</if>
<if test="updateUserCode != null">update_user_code,</if>
</trim>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="id != null">#{id},</if>
<if test="orderId != null">#{orderId},</if>
......@@ -141,7 +142,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="createUserCode != null">#{createUserCode},</if>
<if test="updateTime != null">#{updateTime},</if>
<if test="updateUserCode != null">#{updateUserCode},</if>
</trim>
</trim>
</insert>
<update id="updateOutboundOrders" parameterType="OutboundOrders">
......@@ -175,14 +176,14 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</delete>
<delete id="deleteOutboundOrdersByIds" parameterType="String">
delete from outbound_orders where id in
delete from outbound_orders where id in
<foreach item="id" collection="array" open="(" separator="," close=")">
#{id}
</foreach>
</delete>
<delete id="deleteOutboundOrderItemsByOrderIds" parameterType="String">
delete from outbound_order_items where order_id in
delete from outbound_order_items where order_id in
<foreach item="orderId" collection="array" open="(" separator="," close=")">
#{orderId}
</foreach>
......@@ -193,9 +194,20 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</delete>
<insert id="batchOutboundOrderItems">
insert into outbound_order_items( id, order_id, material_id, batch_id, warehouse_id, location_id, planned_quantity, actual_quantity, planned_packages, actual_packages, divisor, label_color, voucher_number, unit_price, item_status, received_at, received_by, remark, is_used, sort_no, create_time, create_user_code, update_time, update_user_code) values
insert into outbound_order_items(
id, order_id, material_id, batch_code, warehouse_id, location_id,
planned_quantity, actual_quantity, divisor, label_color, voucher_number,
item_status, shipped_at, shipped_by, remark, is_used, sort_no,
create_time, create_user_code, update_time, update_user_code,inventory_id
) values
<foreach item="item" index="index" collection="list" separator=",">
( #{item.id}, #{item.orderId}, #{item.materialId}, #{item.batchId}, #{item.warehouseId}, #{item.locationId}, #{item.plannedQuantity}, #{item.actualQuantity}, #{item.plannedPackages}, #{item.actualPackages}, #{item.divisor}, #{item.labelColor}, #{item.voucherNumber}, #{item.unitPrice}, #{item.itemStatus}, #{item.receivedAt}, #{item.receivedBy}, #{item.remark}, #{item.isUsed}, #{item.sortNo}, #{item.createTime}, #{item.createUserCode}, #{item.updateTime}, #{item.updateUserCode})
(
#{item.id}, #{item.orderId}, #{item.materialId}, #{item.batchCode}, #{item.warehouseId},
#{item.locationId}, #{item.plannedQuantity}, #{item.actualQuantity}, #{item.divisor},
#{item.labelColor}, #{item.voucherNumber}, #{item.itemStatus}, #{item.shippedAt},
#{item.shippedBy}, #{item.remark}, #{item.isUsed}, #{item.sortNo}, #{item.createTime},
#{item.createUserCode}, #{item.updateTime}, #{item.updateUserCode},#{item.inventoryId}
)
</foreach>
</insert>
</mapper>
\ No newline at end of file
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论