add:添加mock;

add:添加工单报工倒扣逻辑
This commit is contained in:
zhangzq
2026-06-12 14:59:37 +08:00
parent bd54c8057f
commit bf66aae879
34 changed files with 1123 additions and 72 deletions

View File

@@ -40,7 +40,11 @@
<version>3.0.13</version>
<type>pom</type>
</dependency>
<!-- MQ-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<!-- 获取系统信息 -->
<dependency>
<groupId>com.github.oshi</groupId>

View File

@@ -0,0 +1,42 @@
/*
* Copyright 2019-2020 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.nl.common.annotation;
import org.nl.common.aspect.LimitType;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @author jacky
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Mock {
// 接口唯一标识(不填则默认 类名#方法名)
String value() default "";
// 接口描述
String desc() default "";
// 是否默认启用Mock
boolean enable() default false;
}

View File

@@ -0,0 +1,65 @@
package org.nl.common.aspect;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.nl.common.annotation.Mock;
import org.nl.wms.system_manage.mock.service.IMockConfigService;
import org.nl.wms.system_manage.mock.service.dao.MockConfig;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
@Aspect
@Component
@Slf4j
public class MockAspect {
@Autowired
private IMockConfigService mockConfigService;
@Around("@annotation(org.nl.common.annotation.Mock)")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method interfaceMethod = signature.getMethod();
Method method = AopUtils.getMostSpecificMethod(interfaceMethod, joinPoint.getTarget().getClass());
Mock mock = AnnotationUtils.findAnnotation(method, Mock.class);
if (mock == null) {
mock = AnnotationUtils.findAnnotation(interfaceMethod, Mock.class);
}
if (mock == null) {
return joinPoint.proceed();
}
MockConfig config = mockConfigService.createIfAbsent(method, mock);
if (config == null || !Boolean.TRUE.equals(config.getEnabled())) {
return joinPoint.proceed();
}
Integer delayMs = config.getDelay_ms();
if (delayMs != null && delayMs > 0) {
Thread.sleep(delayMs);
}
return buildMockResult(method, config.getResponse_data());
}
private Object buildMockResult(Method method, String responseData) {
Class<?> returnType = method.getReturnType();
if (Void.TYPE.equals(returnType)) {
return null;
}
if (String.class.equals(returnType)) {
return responseData;
}
if (responseData == null || responseData.trim().isEmpty()) {
return null;
}
Type genericReturnType = method.getGenericReturnType();
return JSON.parseObject(responseData, genericReturnType);
}
}

View File

@@ -0,0 +1,90 @@
package org.nl.wms.ext_manage.mes.controller;
import cn.dev33.satoken.annotation.SaIgnore;
import org.nl.common.base.TableDataInfo;
import org.nl.common.domain.query.PageQuery;
import org.nl.common.logging.annotation.Log;
import org.nl.wms.ext_manage.mes.mq.producer.WorkReportProducer;
import org.nl.wms.ext_manage.mes.service.MesApiService;
import org.nl.wms.ext_manage.mes.service.dto.WorkReportParam;
import org.nl.wms.pm_manage.demand.service.IPmDemandService;
import org.nl.wms.pm_manage.demand.service.dto.DemandInventryDto;
import org.nl.wms.pm_manage.demand.service.dto.PmDemandDto;
import org.nl.wms.pm_manage.demand.service.dto.PmDemandParam;
import org.nl.wms.pm_manage.demand.service.dto.PmDemandQuery;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.validation.Valid;
import java.util.Arrays;
import java.util.List;
@RestController
@RequestMapping("/api/mes")
@SaIgnore
public class MesController {
@Autowired
private IPmDemandService pmDemandService;
@Autowired
private WorkReportProducer workReportProducer;
@PostMapping("/report")
@Log("报工回传")
public ResponseEntity<Object> report(@RequestBody WorkReportParam workReportParam) {
// 2. 发送到MQ立即返回
workReportProducer.send(workReportParam);
return new ResponseEntity<>(HttpStatus.OK);
}
@PostMapping
@Log("新增需求单")
public ResponseEntity<Object> create(@Valid @RequestBody PmDemandParam param) {
pmDemandService.create(param);
return new ResponseEntity<>(HttpStatus.OK);
}
@PutMapping
@Log("修改需求单")
public ResponseEntity<Object> update(@Valid @RequestBody PmDemandDto param) {
pmDemandService.update(param);
return new ResponseEntity<>(HttpStatus.OK);
}
@DeleteMapping
@Log("删除需求单")
@Transactional(rollbackFor = Exception.class)
public ResponseEntity<Object> delete(@RequestBody String[] ids) {
List<String> idList = Arrays.asList(ids);
pmDemandService.deleteByIds(idList);
return new ResponseEntity<>(HttpStatus.OK);
}
@GetMapping("/queryInventory")
@Log("根据需求单查询所有库存信息")
public ResponseEntity<List<DemandInventryDto>> queryInventory(String skuCode) {
return new ResponseEntity<>(pmDemandService.queryInventory(skuCode), HttpStatus.OK);
}
@PostMapping("/allocate")
@Log("库存分配")
@Transactional(rollbackFor = Exception.class)
public ResponseEntity<Object> allocateInventory(@RequestBody PmDemandDto demand) {
pmDemandService.allocateInventory(demand.getId(), demand.getInventoryDis());
return new ResponseEntity<>(HttpStatus.OK);
}
@PostMapping("/push")
@Log("需求单下发")
@Transactional(rollbackFor = Exception.class)
public ResponseEntity<Object> push(@RequestBody List<PmDemandDto> pmDemandDtos) {
pmDemandService.pushDemand(pmDemandDtos);
return new ResponseEntity<>(HttpStatus.OK);
}
}

View File

@@ -0,0 +1,25 @@
package org.nl.wms.ext_manage.mes.mq.consumer;
import com.rabbitmq.client.Channel;
import org.nl.wms.ext_manage.mes.service.MesApiService;
import org.nl.wms.ext_manage.mes.service.dto.WorkReportParam;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.support.AmqpHeaders;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.handler.annotation.Header;
import org.springframework.stereotype.Component;
@Component
public class WorkReportConsumer {
@Autowired
MesApiService mesApiService;
@RabbitListener(queues = "Mes.workReport.Queue")
public void consume(WorkReportParam param, Channel channel,
@Header(AmqpHeaders.DELIVERY_TAG) long tag) {
System.out.println("======WorkReportConsumer======"+tag);
mesApiService.workReportReturn(param);
}
}

View File

@@ -0,0 +1,16 @@
package org.nl.wms.ext_manage.mes.mq.producer;
import org.nl.wms.ext_manage.mes.service.dto.WorkReportParam;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class WorkReportProducer {
@Autowired
private RabbitTemplate rabbitTemplate;
public void send(WorkReportParam param) {
rabbitTemplate.convertAndSend("Mes", "workReport", param);
}
}

View File

@@ -1,10 +1,13 @@
package org.nl.wms.ext_manage.mes.service;
import org.nl.wms.ext_manage.mes.service.dto.WorkOrderBomItem;
import org.nl.wms.ext_manage.mes.service.dto.WorkReportParam;
import java.util.List;
public interface MesApiService {
List<WorkOrderBomItem> workOrderMaterialList(String workOrder);
void workReportReturn(WorkReportParam workReportParam);
}

View File

@@ -0,0 +1,118 @@
package org.nl.wms.ext_manage.mes.service.dto;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import java.io.Serializable;
import java.math.BigDecimal;
@Data
public class WorkReportParam implements Serializable {
private static final long serialVersionUID = 1L; // 建议添加序列化版本号
/**
* ID
*/
@JsonProperty("Id")
private String id;
/**
* 工单编码
*/
@JsonProperty("WorkOrderCode")
private String workOrderCode;
/**
* 跟踪号/班组
*/
@JsonProperty("TrackNo")
private String trackNo;
/**
* 车间
*/
@JsonProperty("Workshop")
private String workshop;
/**
* 工作区域
*/
@JsonProperty("WorkArea")
private String workArea;
/**
* 序列号/控制码
*/
@JsonProperty("Sn")
private String sn;
/**
* 报工数量
*/
@JsonProperty("ReportedQty")
private BigDecimal reportedQty;
/**
* 状态码
*/
@JsonProperty("StatusCode")
private String statusCode;
/**
* 请求时间
*/
@JsonProperty("RequestTime")
private String requestTime;
/**
* 创建人
*/
@JsonProperty("CreatedBy")
private String createdBy;
/**
* 创建时间
*/
@JsonProperty("CreatedOn")
private String createdOn;
/**
* 订单编码
*/
@JsonProperty("OrderCode")
private String orderCode;
/**
* 组织编号
*/
@JsonProperty("OrgNo")
private String orgNo;
/**
* 部门编号
*/
@JsonProperty("DeptNo")
private String deptNo;
/**
* 业务时间
*/
@JsonProperty("BizTime")
private String bizTime;
/**
* 源单据编号
*/
@JsonProperty("SrcBillNo")
private String srcBillNo;
/**
* 源单据ID
*/
@JsonProperty("SrcBillId")
private String srcBillId;
/**
* 响应方
*/
@JsonProperty("ResponseBy")
private String responseBy;
}

View File

@@ -2,20 +2,45 @@ package org.nl.wms.ext_manage.mes.service.impl;
import cn.hutool.http.HttpRequest;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.apache.commons.lang3.StringUtils;
import org.nl.common.annotation.Mock;
import org.nl.common.exception.BadRequestException;
import org.nl.config.SpringContextHolder;
import org.nl.wms.basedata_manage.service.ISectattrService;
import org.nl.wms.basedata_manage.service.IStructattrService;
import org.nl.wms.basedata_manage.service.dao.Sectattr;
import org.nl.wms.basedata_manage.service.dao.Structattr;
import org.nl.wms.ext_manage.mes.service.MesApiService;
import org.nl.wms.ext_manage.mes.service.MesResponse;
import org.nl.wms.ext_manage.mes.service.dto.WorkOrderBomItem;
import org.nl.wms.ext_manage.mes.service.dto.WorkReportParam;
import org.nl.wms.pda_manage.ios_manage.service.PdaIosOutService;
import org.nl.wms.pda_manage.outBound.dto.LineSideDto;
import org.nl.wms.system_manage.enums.SysParamConstant;
import org.nl.wms.system_manage.service.param.dao.Param;
import org.nl.wms.system_manage.service.param.impl.SysParamServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
@Service
public class MesApiServiceImpl implements MesApiService {
@Autowired
private PdaIosOutService pdaIosOutService;
@Autowired
private IStructattrService iStructattrService;
@Autowired
private MesApiService mesApiService;
@Override
@Mock(desc = "工单bom清单接口",enable = true)
public List<WorkOrderBomItem> workOrderMaterialList(String workOrder){
final Param param = SpringContextHolder.getBean(SysParamServiceImpl.class).findByCode(SysParamConstant.MES_URL);
if (param ==null){
@@ -39,4 +64,31 @@ public class MesApiServiceImpl implements MesApiService {
throw new BadRequestException("中鼎需求单下发失败:" + e.getMessage());
}
}
@Override
public void workReportReturn(WorkReportParam workReportParam) {
String workOrderCode = workReportParam.getWorkOrderCode();
BigDecimal qty = workReportParam.getReportedQty();
if (StringUtils.isEmpty(workOrderCode)||qty == null){
throw new BadRequestException("工单报工同步失败,请求参数为空");
}
List<WorkOrderBomItem> workOrderBomItems = mesApiService.workOrderMaterialList(workOrderCode);
//TODO: 查询哪些是大件哪些是小件
//workAreag根据功能做区域查看对于的库区工作区域与库区编码一直
final Structattr one = iStructattrService.getOne(new LambdaQueryWrapper<Structattr>()
.eq(Structattr::getSect_code, workReportParam.getWorkArea()));
if (one == null){
throw new BadRequestException("当前工作区域对应的库区不存在");
}
Map<String, BigDecimal> map = workOrderBomItems.stream()
.collect(Collectors.toMap(
WorkOrderBomItem::getMaterialCode,
workOrderBomItem -> workOrderBomItem.getBomQty().multiply(qty)
));
final LineSideDto sideDto = new LineSideDto();
sideDto.setWorkOrder(workReportParam.getWorkOrderCode());
sideDto.setStorageVehicleCode(one.getStoragevehicle_code());
sideDto.setOutMaterials(map);
pdaIosOutService.directConfirm(sideDto);
}
}

View File

@@ -385,7 +385,8 @@ public class PdaIosInServiceImpl implements PdaIosInService {
// 预组织出入库单据明细的分配数据
whereJson.put("iostorinv_id", iostorinv_id);
Map<String, Object> jsonDtl = organizeDivData(whereJson);
// 调用分配,默认自动分配库位
// 调用分配,默认自动
// 分配库位
iRawAssistIStorService.divStruct(new JSONObject(jsonDtl));
// 下发任务
sendTask(whereJson);

View File

@@ -2,6 +2,7 @@ package org.nl.wms.pda_manage.ios_manage.service.impl;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
@@ -61,6 +62,7 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
import static org.nl.wms.warehouse_manage.enums.IOSEnum.GROUP_PLATE_STATUS;
@@ -81,11 +83,13 @@ public class PdaIosOutServiceImpl implements PdaIosOutService {
* 组盘记录mapper
*/
@Autowired
private MdPbGroupplateMapper mdPbGroupplateMapper; /**
* 组盘记录mapper
private MdPbGroupplateMapper mdPbGroupplateMapper;
/**
* 组盘记录
*/
@Autowired
private IMdPbGroupplateService iMdPbGroupplateService;
private IMdPbGroupplateService iMdPbGroupplateService; /**
/**
* 库区服务
*/
@@ -184,48 +188,115 @@ public class PdaIosOutServiceImpl implements PdaIosOutService {
@Override
@Transactional
public PdaResponse directConfirm(LineSideDto lineSideDto) {
public PdaResponse directConfirm(LineSideDto param) {
//创建出库单/明细/分配
MdMeMaterialbase materDao = iMdMeMaterialbaseService.getByCode(lineSideDto.getMaterialCode());
final GroupPlate group = iMdPbGroupplateService.getOne(new LambdaQueryWrapper<GroupPlate>()
.eq(GroupPlate::getMaterial_code, lineSideDto.getMaterialCode())
.eq(GroupPlate::getStoragevehicle_code, lineSideDto.getStorageVehicleCode()));
if (group ==null){
throw new BadRequestException("物料库存信息不存在");
}
Map<String, MdMeMaterialbase> materialMap = iMdMeMaterialbaseService
.list(new LambdaQueryWrapper<MdMeMaterialbase>()
.in(MdMeMaterialbase::getMaterial_code, param.getOutMaterials().keySet()))
.stream()
.collect(Collectors.toMap(MdMeMaterialbase::getMaterial_code, Function.identity()
));
final Structattr struct = iStructattrService.getOne(new LambdaQueryWrapper<Structattr>()
.eq(Structattr::getStoragevehicle_code, lineSideDto.getStorageVehicleCode()));
.eq(Structattr::getStoragevehicle_code, param.getStorageVehicleCode()));
if (struct ==null){
throw new BadRequestException("当前虚拟仓库未绑定"+lineSideDto.getStorageVehicleCode());
throw new BadRequestException("当前虚拟仓库未绑定"+param.getStorageVehicleCode());
}
JSONObject outBillParam = new JSONObject();
outBillParam.put("materialId", materDao.getMaterial_id());
outBillParam.put("materialCode", materDao.getMaterial_code());
outBillParam.put("stor_id", struct.getStor_id());
outBillParam.put("sourceBillCode", lineSideDto.getWorkOrder());
outBillParam.put("sourceBillType", "work_order");
outBillParam.put("storCode", struct.getSect_code());
outBillParam.put("storName", struct.getStor_name());
outBillParam.put("sectCode", struct.getSect_code());
outBillParam.put("sectId", struct.getSect_id());
outBillParam.put("qty", lineSideDto.getQty());
outBillParam.put("pcsn", group.getPcsn());
outBillParam.put("unitId", materDao.getQty_unit_id());
outBillParam.put("unitName", materDao.getQty_unit_name());
outBillParam.put("storagevehicleCode", lineSideDto.getStorageVehicleCode());
final List<GroupPlate> groupInventory = iMdPbGroupplateService.list(new LambdaQueryWrapper<GroupPlate>()
.eq(GroupPlate::getStoragevehicle_code, param.getStorageVehicleCode())
.eq(GroupPlate::getStatus, IOSEnum.GROUP_PLATE_STATUS.code("入库"))
.in(GroupPlate::getMaterial_code, param.getOutMaterials().keySet()));
if (groupInventory.size()!=param.getOutMaterials().size()){
throw new BadRequestException("库存扣减失败,库存不匹配");
}
Map<String, BigDecimal> groupInventoryMap = groupInventory.stream()
.collect(Collectors.toMap(
GroupPlate::getMaterial_code,
GroupPlate::getQty,
BigDecimal::add
));
Map<String, BigDecimal> finalOutMaterials = param.getOutMaterials().entrySet().stream()
.collect(Collectors.toMap(
Map.Entry::getKey,
entry -> {
BigDecimal outQty = entry.getValue();
BigDecimal inventoryQty = groupInventoryMap.getOrDefault(entry.getKey(), BigDecimal.ZERO);
return outQty.min(inventoryQty);
}
));
//创建出库单据
createOutBills(outBillParam);
//更新组盘记录表
mdPbGroupplateMapper.update(new GroupPlate(), new LambdaUpdateWrapper<>(GroupPlate.class)
.set(GroupPlate::getQty,group.getQty().subtract(lineSideDto.getQty()))
.eq(GroupPlate::getGroup_id, group.getGroup_id())
);
String now = DateUtil.now();
String currentUserId = SecurityUtils.getCurrentUserId();
String nickName = SecurityUtils.getCurrentNickName();
//主单
final IOStorInv ioStorInv = new IOStorInv();
ioStorInv.setIostorinv_id(IdUtil.getStringId());
ioStorInv.setBill_code(CodeUtil.getNewCode("IN_STORE_CODE"));
ioStorInv.setIo_type(IOSEnum.IO_TYPE.code("出库"));
ioStorInv.setBill_type(IOSEnum.BILL_TYPE.code("生产出库"));
ioStorInv.setBiz_date(DateUtil.today());
ioStorInv.setStor_code(struct.getStor_code());
ioStorInv.setStor_name(struct.getStor_name());
ioStorInv.setStor_id(struct.getStor_id());
ioStorInv.setDetail_count(param.getOutMaterials().size());
ioStorInv.setBill_status(IOSEnum.BILL_STATUS.code("完成"));
ioStorInv.setCreate_mode(IOSEnum.CREATE_MODE.code("终端产生"));
ioStorInv.setInput_optid(currentUserId);
ioStorInv.setInput_optname(nickName);
ioStorInv.setInput_time(now);
ioStorInv.setIs_delete(BaseDataEnum.IS_YES_NOT.code(""));
ioStorInv.setIs_upload(BaseDataEnum.IS_YES_NOT.code(""));
ioStorInv.setTotal_qty(param.getOutMaterials().values().stream().reduce(BigDecimal.ZERO, BigDecimal::add));
ioStorInvMapper.insert(ioStorInv);
//明细
int seq = 1;
for (String materialCode : finalOutMaterials.keySet()) {
BigDecimal qty = param.getOutMaterials().get(materialCode);
final IOStorInvDtl ioStorInvDtl = new IOStorInvDtl();
ioStorInvDtl.setIostorinv_id(ioStorInv.getIostorinv_id());
ioStorInvDtl.setIostorinvdtl_id(IdUtil.getStringId());
ioStorInvDtl.setSeq_no(String.valueOf(seq));
ioStorInvDtl.setMaterial_code(materialCode);
ioStorInvDtl.setMaterial_id(materialMap.get(materialCode).getMaterial_id());
ioStorInvDtl.setQty_unit_id(materialMap.get(materialCode).getQty_unit_id());
ioStorInvDtl.setQty_unit_name(materialMap.get(materialCode).getQty_unit_name());
ioStorInvDtl.setPcsn("1");
ioStorInvDtl.setBill_status(IOSEnum.BILL_STATUS.code("完成"));
ioStorInvDtl.setAssign_qty(qty);
ioStorInvDtl.setPlan_qty(qty);
ioStorInvDtl.setUnassign_qty(BigDecimal.ZERO);
ioStorInvDtl.setSource_bill_code(param.getWorkOrder());
ioStorInvDtl.setSource_bill_type("work_order");
ioStorInvDtlMapper.insert(ioStorInvDtl);
// 分配
final IOStorInvDis ioStorInvDis = new IOStorInvDis();
ioStorInvDis.setIostorinvdis_id(IdUtil.getStringId());
ioStorInvDis.setIostorinv_id(ioStorInv.getIostorinv_id()); // 修正变量名
ioStorInvDis.setIostorinvdtl_id(ioStorInvDtl.getIostorinvdtl_id()); // 从对象获取,而不是从 JSON
ioStorInvDis.setSeq_no("1"); // 直接用 int不需要 String
ioStorInvDis.setMaterial_id(materialMap.get(materialCode).getMaterial_id()); // 从 materialMap 获取
ioStorInvDis.setMaterial_code(materialCode); // 直接使用变量
ioStorInvDis.setPcsn("1"); // 或者根据实际情况从 materialMap 获取
ioStorInvDis.setStoragevehicle_code(param.getStorageVehicleCode()); // 假设从 param 获取
ioStorInvDis.setWork_status(IOSEnum.INBILL_DIS_STATUS.code("完成"));
ioStorInvDis.setIs_issued(BaseDataEnum.IS_YES_NOT.code(""));
ioStorInvDis.setQty_unit_id(materialMap.get(materialCode).getQty_unit_id()); // 从 materialMap 获取
ioStorInvDis.setQty_unit_name(materialMap.get(materialCode).getQty_unit_name()); // 从 materialMap 获取
ioStorInvDis.setPlan_qty(qty); // 直接使用 qty 变量
ioStorInvDisMapper.insert(ioStorInvDis);
//更新组盘记录表
final BigDecimal inventoryQty = groupInventoryMap.get(materialCode);
mdPbGroupplateMapper.update(new GroupPlate(), new LambdaUpdateWrapper<>(GroupPlate.class)
.set(GroupPlate::getQty,inventoryQty.subtract(qty))
.eq(GroupPlate::getStoragevehicle_code, param.getStorageVehicleCode())
.eq(GroupPlate::getStatus, IOSEnum.GROUP_PLATE_STATUS.code("入库"))
);
}
//TODO生成手工领料单
final PmStockReturn stockReturn = new PmStockReturn();
stockReturn.setCreate_time(DateUtil.now());
stockReturn.setRequest_type(IOSEnum.BILL_TYPE.code("生产出库"));
stockReturn.setStatus(StockReturnStatusEnum.TODO.getCode());
stockReturn.setRequest_data(outBillParam.toJSONString());
stockReturn.setRequest_data(JSON.toJSONString(ioStorInv));
iPmStockReturnService.save(stockReturn);
return PdaResponse.requestOk();
}

View File

@@ -3,14 +3,16 @@ package org.nl.wms.pda_manage.outBound.dto;
import lombok.Data;
import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
@Data
public class LineSideDto {
private String workOrder;
private String materialCode;
private Map<String,BigDecimal> outMaterials;
/**
* 线边库都是虚拟容器
*/
private String storageVehicleCode;
private BigDecimal qty;
}

View File

@@ -42,7 +42,7 @@ public class PmDemandController {
@PutMapping
@Log("修改需求单")
public ResponseEntity<Object> update(@Valid @RequestBody PmDemandParam param) {
public ResponseEntity<Object> update(@Valid @RequestBody PmDemandDto param) {
pmDemandService.update(param);
return new ResponseEntity<>(HttpStatus.OK);
}

View File

@@ -18,7 +18,7 @@ public interface IPmDemandService extends IService<PmDemand> {
void create(PmDemandParam param);
void batchCreate(List<PmDemandParam> param);
void update(PmDemandParam param);
void update(PmDemandDto param);
void deleteByIds(List<String> ids);

View File

@@ -17,8 +17,8 @@ public class PmDemandDto implements Serializable {
private String workOrder;
private String skuCode;
private String skuName;
private Integer qty;
private Integer assignQty;
private BigDecimal qty;
private BigDecimal assignQty;
private String unit;
private String targetArea;
private String productionLine;

View File

@@ -19,51 +19,58 @@ import java.math.BigDecimal;
public class PmDemandParam {
@NotBlank(message = "单据唯一ID不能为空")
private String id;
@JsonProperty(value = "Id")
private String Id;
@NotBlank(message = "操作人不能为空")
private String creator;
@JsonProperty(value = "Creator")
private String Creator;
@NotBlank(message = "需求日期不能为空")
private String createTime;
@JsonProperty(value = "CreateTime")
private String CreateTime;
@NotNull(message = "优先级不能为空")
private Integer priority;
@JsonProperty(value = "Priority")
private Integer Priority;
private String status;
@JsonProperty(value = "Status")
private String Status;
@NotBlank(message = "工单编号不能为空")
private String workOrder;
@JsonProperty(value = "WorkOrder")
private String WorkOrder;
@NotBlank(message = "物料编码不能为空")
private String skuCode;
@JsonProperty(value = "SkuCode")
private String SkuCode;
@NotBlank(message = "物料名称不能为空")
private String skuName;
@JsonProperty(value = "SkuName")
private String SkuName;
@NotNull(message = "数量不能为空")
@DecimalMin(value = "0", inclusive = false, message = "数量必须大于0")
private BigDecimal qty;
@JsonProperty(value = "Qty")
private BigDecimal Qty;
@DecimalMin(value = "0", inclusive = false, message = "数量必须大于0")
private BigDecimal assignQty;
@JsonProperty(value = "QssignQty")
private BigDecimal QssignQty;
@NotBlank(message = "单位不能为空")
private String unit;
@JsonProperty(value = "Unit")
private String Unit;
@NotBlank(message = "目标库存地点不能为空")
private String targetArea;
@JsonProperty(value = "TargetArea")
private String TargetArea;
@NotBlank(message = "产线不能为空")
private String productionLine;
@JsonProperty(value = "ProductionLine")
private String ProductionLine;
private String sn;
private String maxLoad;
@NotBlank(message = "目标仓别不能为空")
private String targetHouseCode;
private String batchNo;
private String remark;
@JsonProperty(value = "SN")
private String SN;
}

View File

@@ -85,7 +85,7 @@ public class PmDemandServiceImpl extends ServiceImpl<PmDemandMapper, PmDemand> i
demand.setUnit(param.getUnit());
demand.setTarget_area(param.getTargetArea());
demand.setProduction_line(param.getProductionLine());
demand.setSn(param.getSn());
demand.setSn(param.getSN());
demand.setCreate_at(DateUtil.now());
this.save(demand);
}
@@ -98,7 +98,7 @@ public class PmDemandServiceImpl extends ServiceImpl<PmDemandMapper, PmDemand> i
}
@Override
public void update(PmDemandParam param) {
public void update(PmDemandDto param) {
PmDemand dbDemand = this.getById(param.getId());
if (dbDemand == null) {
throw new BadRequestException("需求单不存在");

View File

@@ -0,0 +1,53 @@
package org.nl.wms.system_manage.mock.controller;
import cn.dev33.satoken.annotation.SaCheckPermission;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.nl.common.base.TableDataInfo;
import org.nl.common.domain.query.PageQuery;
import org.nl.common.logging.annotation.Log;
import org.nl.wms.system_manage.mock.service.IMockConfigService;
import org.nl.wms.system_manage.mock.service.dao.MockConfig;
import org.nl.wms.system_manage.mock.service.dto.MockQuery;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.Map;
@RestController
@RequestMapping("/api/mock-config")
public class MockConfigController {
@Autowired
private IMockConfigService mockConfigService;
@GetMapping
public ResponseEntity<Object> query(MockQuery query, PageQuery page) {
return new ResponseEntity<>(TableDataInfo.build(mockConfigService.page(page.build(), query.build())), HttpStatus.OK);
}
@PutMapping
@Log("修改Mock配置")
public ResponseEntity<Object> update(@Validated @RequestBody MockConfig mockConfig) {
mockConfigService.update(mockConfig);
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
}
@PostMapping("/sync")
@Log("同步Mock注解配置")
public ResponseEntity<Object> sync() {
int count = mockConfigService.syncAnnotatedMethods();
Map<String, Object> result = new HashMap<>();
result.put("count", count);
return new ResponseEntity<>(result, HttpStatus.OK);
}
}

View File

@@ -0,0 +1,21 @@
package org.nl.wms.system_manage.mock.service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.IService;
import org.nl.common.domain.query.PageQuery;
import org.nl.wms.system_manage.mock.service.dao.MockConfig;
import java.lang.reflect.Method;
import java.util.Map;
public interface IMockConfigService extends IService<MockConfig> {
void update(MockConfig mockConfig);
MockConfig findEnabledConfig(String className, String methodName, String mockId);
MockConfig createIfAbsent(Method method, org.nl.common.annotation.Mock mock);
int syncAnnotatedMethods();
}

View File

@@ -0,0 +1,37 @@
package org.nl.wms.system_manage.mock.service.dao;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serializable;
/**
* Mock 配置表
*/
@Data
@EqualsAndHashCode(callSuper = false)
@TableName("sys_mock_config")
public class MockConfig implements Serializable {
private static final long serialVersionUID = 1L;
@TableId(value = "id", type = IdType.AUTO)
private Long id;
private String class_name;
private String method_name;
private String description;
private Boolean enabled;
private String response_data;
private Integer delay_ms;
private String update_time;
}

View File

@@ -0,0 +1,7 @@
package org.nl.wms.system_manage.mock.service.dao.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.nl.wms.system_manage.mock.service.dao.MockConfig;
public interface MockConfigMapper extends BaseMapper<MockConfig> {
}

View File

@@ -0,0 +1,5 @@
<?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="org.nl.wms.system_manage.mock.service.dao.mapper.MockConfigMapper">
</mapper>

View File

@@ -0,0 +1,14 @@
package org.nl.wms.system_manage.mock.service.dto;
import org.nl.common.domain.query.BaseQuery;
import org.nl.common.domain.query.QParam;
import org.nl.common.enums.QueryTEnum;
import org.nl.wms.system_manage.mock.service.dao.MockConfig;
public class MockQuery extends BaseQuery<MockConfig> {
@Override
public void paramMapping() {
this.doP.put("blurry", QParam.builder().k(new String[]{"class_name", "method_name"}).type(QueryTEnum.ORLK).build());
}
}

View File

@@ -0,0 +1,128 @@
package org.nl.wms.system_manage.mock.service.impl;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.nl.common.annotation.Mock;
import org.nl.common.exception.BadRequestException;
import org.nl.config.SpringContextHolder;
import org.nl.wms.system_manage.mock.service.IMockConfigService;
import org.nl.wms.system_manage.mock.service.dao.MockConfig;
import org.nl.wms.system_manage.mock.service.dao.mapper.MockConfigMapper;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RestController;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.Set;
@Service
public class MockConfigServiceImpl extends ServiceImpl<MockConfigMapper, MockConfig> implements IMockConfigService {
@Autowired
private MockConfigMapper mockConfigMapper;
@Override
@Transactional(rollbackFor = Exception.class)
public void update(MockConfig mockConfig) {
if (mockConfig.getId() == null) {
throw new BadRequestException("Mock配置ID不能为空");
}
MockConfig db = mockConfigMapper.selectById(mockConfig.getId());
if (db == null) {
throw new BadRequestException("Mock配置不存在");
}
db.setDescription(mockConfig.getDescription());
db.setEnabled(mockConfig.getEnabled());
db.setResponse_data(mockConfig.getResponse_data());
db.setDelay_ms(mockConfig.getDelay_ms() == null ? 0 : mockConfig.getDelay_ms());
db.setUpdate_time(DateUtil.now());
mockConfigMapper.updateById(db);
}
@Override
public MockConfig findEnabledConfig(String className, String methodName, String mockId) {
return mockConfigMapper.selectOne(new LambdaQueryWrapper<MockConfig>()
.eq(MockConfig::getClass_name, className)
.eq(MockConfig::getMethod_name, methodName)
.eq(MockConfig::getEnabled, true));
}
@Override
@Transactional(rollbackFor = Exception.class)
public MockConfig createIfAbsent(Method method, Mock mock) {
String className = method.getDeclaringClass().getName();
String methodName = method.getName();
MockConfig db = mockConfigMapper.selectOne(new LambdaQueryWrapper<MockConfig>()
.eq(MockConfig::getClass_name, className)
.eq(MockConfig::getMethod_name, methodName));
if (db != null) {
return db;
}
MockConfig config = new MockConfig();
config.setClass_name(className);
config.setMethod_name(methodName);
config.setDescription(StrUtil.blankToDefault(mock.desc(), methodName));
config.setEnabled(mock.enable());
config.setResponse_data(null);
config.setDelay_ms(0);
config.setUpdate_time(DateUtil.now());
mockConfigMapper.insert(config);
return config;
}
@Override
public int syncAnnotatedMethods() {
int count = 0;
ApplicationContext context = SpringContextHolder.getApplicationContext();
// 定义需要扫描的注解类型
Class<?>[] targetAnnotations = {
RestController.class,
Controller.class,
Service.class,
Component.class
};
Set<Object> beans = new HashSet<>();
for (Class<?> annotation : targetAnnotations) {
beans.addAll(context.getBeansWithAnnotation((Class<? extends Annotation>) annotation).values());
}
for (Object bean : beans) {
Class<?> targetClass = AopUtils.getTargetClass(bean);
if (targetClass == null) {
continue;
}
Method[] methods = targetClass.getDeclaredMethods();
for (Method method : methods) {
Mock mock = method.getAnnotation(Mock.class);
if (mock == null) {
continue;
}
MockConfig before = createIfAbsent(method, mock);
if (ObjectUtil.isNotEmpty(before)) {
count++;
}
}
}
return count;
}
private String buildMockId(Method method, Mock mock) {
if (StrUtil.isNotBlank(mock.value())) {
return mock.value();
}
return method.getDeclaringClass().getSimpleName() + "#" + method.getName();
}
}

View File

@@ -976,6 +976,7 @@ public class OutBillServiceImpl extends ServiceImpl<IOStorInvMapper,IOStorInv> i
}
@Override
@Transactional
public void confirm(JSONObject whereJson) {
String iostorinv_id = whereJson.getString("iostorinv_id");
//查询主表信息
@@ -987,8 +988,10 @@ public class OutBillServiceImpl extends ServiceImpl<IOStorInvMapper,IOStorInv> i
throw new BadRequestException("主表状态必须为分配完!");
}
//解锁原货位点位
List<IOStorInvDis> storInvDisList = ioStorInvDisMapper.selectList(new LambdaQueryWrapper<>(IOStorInvDis.class)
List<IOStorInvDis> storInvDisList =
ioStorInvDisMapper.selectList(new LambdaQueryWrapper<>(IOStorInvDis.class)
.eq(IOStorInvDis::getIostorinv_id,whereJson.get("iostorinv_id"))
.eq(IOStorInvDis::getWork_status,IOSEnum.INBILL_DIS_STATUS.code("生成"))
);
// 判断此单据下的所有任务有没有完成的
boolean is_finish = iSchBaseTaskService.list(

View File

@@ -36,3 +36,16 @@ CREATE TABLE pmd_demand_dtl (
INDEX idx_order_uuid (order_uuid),
FOREIGN KEY (order_id) REFERENCES pm_demand_order(id) ON DELETE CASCADE
) AUTO_INCREMENT=10000 COMMENT='需求单明细表';
CREATE TABLE `sys_mock_config` (
`id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`class_name` VARCHAR(255) NOT NULL COMMENT '类名',
`method_name` VARCHAR(255) NOT NULL COMMENT '方法名',
`description` VARCHAR(500) DEFAULT NULL COMMENT '描述',
`enabled` TINYINT(1) DEFAULT 1 COMMENT '是否启用 (0-禁用, 1-启用)',
`response_data` LONGTEXT COMMENT 'Mock返回数据(JSON)',
`delay_ms` INT DEFAULT 0 COMMENT '延迟毫秒数',
`update_time` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`),
KEY `idx_class_method` (`class_name`, `method_name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='Mock配置表';