Merge remote-tracking branch 'origin/dev' into dev

dev
xs 2 weeks ago
commit 880c808569

@ -113,4 +113,15 @@ public class ErpAfterSalesController extends BaseController {
return R.ok(list);
}
/**
*
*/
@SaCheckPermission("oa/erp:afterSales:add")
@Log(title = "项目售后信息", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping("/submitAndFlowStart")
public R<ErpAfterSalesVo> submitAndFlowStart(@Validated(AddGroup.class) @RequestBody ErpAfterSalesBo bo) {
return R.ok(erpAfterSalesService.submitAndFlowStart(bo));
}
}

@ -44,6 +44,7 @@ public class ErpProjectReportController extends BaseController {
@SaCheckPermission("oa/erp:projectReport:list")
@GetMapping("/list")
public TableDataInfo<ErpProjectReportVo> list(ErpProjectReportBo bo, PageQuery pageQuery) {
return erpProjectReportService.queryPageList(bo, pageQuery);
}

@ -15,7 +15,11 @@ import org.dromara.common.log.enums.BusinessType;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.web.core.BaseController;
import org.dromara.oa.erp.domain.bo.ErpContractInfoBo;
import org.dromara.oa.erp.domain.bo.ErpProjectReportBo;
import org.dromara.oa.erp.domain.bo.ErpProjectReportDetailBo;
import org.dromara.oa.erp.domain.bo.ProjectReportAndDetailWrapperBo;
import org.dromara.oa.erp.domain.vo.ErpContractInfoVo;
import org.dromara.oa.erp.domain.vo.ErpProjectReportDetailVo;
import org.dromara.oa.erp.service.IErpProjectReportDetailService;
import org.springframework.validation.annotation.Validated;
@ -114,4 +118,18 @@ public class ErpProjectReportDetailController extends BaseController {
return R.ok(list);
}
/**
*
* @param wrapper
* @return
*/
@SaCheckPermission("oa/erp:projectReportDetail:add")
@Log(title = "项目周报明细", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping("/projectReportSubmitAndFlowStart")
public R<ErpProjectReportDetailVo> projectReportSubmitAndFlowStart(@Validated(AddGroup.class) @RequestBody ProjectReportAndDetailWrapperBo wrapper) {
ErpProjectReportBo projectReport = wrapper.getProjectReport();
ErpProjectReportDetailBo projectDetailReport = wrapper.getProjectDetailReport();
return R.ok(erpProjectReportDetailService.projectReportSubmitAndFlowStart(projectReport, projectDetailReport));
}
}

@ -1,9 +1,6 @@
package org.dromara.oa.erp.domain;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.dromara.common.tenant.core.TenantEntity;
@ -27,7 +24,7 @@ public class ErpProjectReport extends TenantEntity {
/**
* ID
*/
@TableId(value = "report_id", type = IdType.AUTO)
@TableId(value = "report_id", type = IdType.ASSIGN_ID)
private Long reportId;
/**
@ -101,5 +98,27 @@ public class ErpProjectReport extends TenantEntity {
*/
private String projectCode;
/**
*
*/
@TableField(exist = false)
private String deptName;
/**
*
*/
@TableField(exist = false)
private String managerName;
/**
*
*/
@TableField(exist = false)
private String chargeName;
/**
*
*/
@TableField(exist = false)
private String deputyName;
}

@ -28,7 +28,7 @@ public class ErpProjectReportDetail extends TenantEntity {
/**
* ID
*/
@TableId(value = "report_detail_id", type = IdType.AUTO)
@TableId(value = "report_detail_id", type = IdType.ASSIGN_ID)
private Long reportDetailId;
/**

@ -13,10 +13,12 @@ import java.math.BigDecimal;
import java.util.Date;
import com.fasterxml.jackson.annotation.JsonFormat;
import java.util.List; // 1. 别忘了导包 List
import java.util.Map;
// 2. 导入两个子表的 BO 对象,因为前端传的是子表的业务数据
import org.dromara.oa.erp.domain.bo.ErpAfterSalesLaborCostsBo;
import org.dromara.oa.erp.domain.bo.ErpAfterSalesMaterialCostsBo;
import org.dromara.workflow.api.domain.RemoteFlowInstanceBizExt;
/**
* erp_after_sales
@ -180,5 +182,20 @@ public class ErpAfterSalesBo extends BaseEntity {
*/
private List<ErpAfterSalesMaterialCostsBo> materialCostsList;
/**
*
*/
private String flowCode;
/**
* {'entity': {}}
*/
private Map<String, Object> variables;
/**
*
*/
private RemoteFlowInstanceBizExt bizExt;
}

@ -1,5 +1,6 @@
package org.dromara.oa.erp.domain.bo;
import cn.idev.excel.annotation.ExcelProperty;
import io.github.linpeilie.annotations.AutoMapper;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
@ -90,5 +91,23 @@ public class ErpProjectReportBo extends BaseEntity {
*/
private String projectCode;
/**
*
*/
private String deptName;
/**
*
*/
private String managerName;
/**
*
*/
private String chargeName;
/**
*
*/
private String deputyName;
}

@ -1,5 +1,6 @@
package org.dromara.oa.erp.domain.bo;
import cn.hutool.core.util.ObjectUtil;
import io.github.linpeilie.annotations.AutoMapper;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
@ -7,8 +8,12 @@ import lombok.EqualsAndHashCode;
import org.dromara.common.core.validate.EditGroup;
import org.dromara.common.mybatis.core.domain.BaseEntity;
import org.dromara.oa.erp.domain.ErpProjectReportDetail;
import org.dromara.workflow.api.domain.RemoteFlowInstanceBizExt;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
/**
* erp_project_report_detail
@ -96,6 +101,10 @@ public class ErpProjectReportDetailBo extends BaseEntity {
*
*/
private String flowStatus;
/**
*
*/
private String flowCode;
/**
*
@ -127,5 +136,49 @@ public class ErpProjectReportDetailBo extends BaseEntity {
*/
private String activeFlag;
/**
* {'entity': {}}
*/
private Map<String, Object> variables;
/**
*
*/
private RemoteFlowInstanceBizExt bizExt;
/**
*
*/
private String deptName;
/**
*
*/
private String managerName;
/**
*
*/
private String chargeName;
/**
*
*/
private String deputyName;
public Map<String, Object> getVariables() {
if (variables == null) {
return new HashMap<>(16);
}
variables.entrySet().removeIf(entry -> Objects.isNull(entry.getValue()));
return variables;
}
public RemoteFlowInstanceBizExt getBizExt() {
if (ObjectUtil.isNull(bizExt)) {
bizExt = new RemoteFlowInstanceBizExt();
}
return bizExt;
}
}

@ -0,0 +1,12 @@
package org.dromara.oa.erp.domain.bo;
import jakarta.validation.Valid;
import lombok.Data;
@Data
public class ProjectReportAndDetailWrapperBo {
@Valid
private ErpProjectReportBo projectReport;
@Valid
private ErpProjectReportDetailBo projectDetailReport;
}

@ -155,5 +155,28 @@ public class ErpProjectReportDetailVo implements Serializable {
@ExcelDictFormat(readConverterExp = "1=是,0=否")
private String activeFlag;
/**
*
*/
@ExcelProperty(value = "部门名称")
private String deptName;
/**
*
*/
@ExcelProperty(value = "项目经理名称")
private String managerName;
/**
*
*/
@ExcelProperty(value = "部门负责人名称")
private String chargeName;
/**
*
*/
@ExcelProperty(value = "分管副总名称")
private String deputyName;
}

@ -66,4 +66,12 @@ public interface IErpAfterSalesService {
* @return
*/
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
/**
*
* @param bo
* @return
*/
ErpAfterSalesVo submitAndFlowStart(ErpAfterSalesBo bo);
}

@ -2,7 +2,11 @@ package org.dromara.oa.erp.service;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.oa.erp.domain.bo.ErpContractInfoBo;
import org.dromara.oa.erp.domain.bo.ErpProjectReportBo;
import org.dromara.oa.erp.domain.bo.ErpProjectReportDetailBo;
import org.dromara.oa.erp.domain.bo.ProjectReportAndDetailWrapperBo;
import org.dromara.oa.erp.domain.vo.ErpContractInfoVo;
import org.dromara.oa.erp.domain.vo.ErpProjectReportDetailVo;
import java.util.Collection;
@ -65,4 +69,11 @@ public interface IErpProjectReportDetailService {
* @return
*/
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
/**
*
* @param
* @return
*/
ErpProjectReportDetailVo projectReportSubmitAndFlowStart(ErpProjectReportBo projectReport, ErpProjectReportDetailBo projectDetailReport);
}

@ -1,6 +1,12 @@
package org.dromara.oa.erp.service.impl;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.seata.spring.annotation.GlobalTransactional;
import org.dromara.common.core.enums.BusinessStatusEnum;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.TableDataInfo;
@ -10,6 +16,7 @@ import com.github.yulichang.toolkit.JoinWrappers;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import org.dromara.common.tenant.helper.TenantHelper;
import org.dromara.oa.erp.domain.ErpAfterSalesLaborCosts;
import org.dromara.oa.erp.domain.ErpAfterSalesMaterialCosts;
import org.dromara.oa.erp.domain.bo.ErpAfterSalesLaborCostsBo;
@ -18,6 +25,8 @@ import org.dromara.oa.erp.domain.vo.ErpAfterSalesLaborCostsVo;
import org.dromara.oa.erp.domain.vo.ErpAfterSalesMaterialCostsVo;
import org.dromara.oa.erp.service.IErpAfterSalesLaborCostsService;
import org.dromara.oa.erp.service.IErpAfterSalesMaterialCostsService;
import org.dromara.workflow.api.RemoteWorkflowService;
import org.dromara.workflow.api.domain.RemoteStartProcess;
import org.springframework.stereotype.Service;
import org.dromara.oa.erp.domain.bo.ErpAfterSalesBo;
import org.dromara.oa.erp.domain.vo.ErpAfterSalesVo;
@ -26,7 +35,12 @@ import org.dromara.oa.erp.mapper.ErpAfterSalesMapper;
import org.dromara.oa.erp.service.IErpAfterSalesService;
import org.springframework.transaction.annotation.Transactional;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.springframework.context.event.EventListener;
import org.dromara.workflow.api.event.ProcessEvent;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Collection;
@ -39,12 +53,14 @@ import java.util.Collection;
*/
@RequiredArgsConstructor
@Service
@Slf4j
public class ErpAfterSalesServiceImpl implements IErpAfterSalesService {
private final ErpAfterSalesMapper baseMapper;
// 【修改点 1】注入两个子表的 Service
// 注意:这里必须加 final配合 @RequiredArgsConstructor 使用
@DubboReference(timeout = 30000)
private RemoteWorkflowService remoteWorkflowService;
private final IErpAfterSalesLaborCostsService laborCostsService;
private final IErpAfterSalesMaterialCostsService materialCostsService;
@ -56,31 +72,21 @@ public class ErpAfterSalesServiceImpl implements IErpAfterSalesService {
*/
@Override
public ErpAfterSalesVo queryById(Long afterSalesId){
// 1. 查询主表 VO
ErpAfterSalesVo vo = baseMapper.selectVoById(afterSalesId);
// 2. 如果主表存在,继续查询子表
if (vo != null) {
// ============ 处理人工费 ============
// 2.1 使用 list 方法查询出 Entity 列表
List<ErpAfterSalesLaborCosts> laborEntities = laborCostsService.list(
new LambdaQueryWrapper<ErpAfterSalesLaborCosts>()
.eq(ErpAfterSalesLaborCosts::getAfterSalesId, afterSalesId)
);
// 2.2 将 Entity 列表转换为 VO 列表 (核心修复点)
List<ErpAfterSalesLaborCostsVo> laborVos = MapstructUtils.convert(laborEntities, ErpAfterSalesLaborCostsVo.class);
// 2.3 塞入主表对象
vo.setLaborCostsList(laborVos);
// ============ 处理材料费 ============
// 3.1 使用 list 方法查询出 Entity 列表
List<ErpAfterSalesMaterialCosts> materialEntities = materialCostsService.list(
new LambdaQueryWrapper<ErpAfterSalesMaterialCosts>()
.eq(ErpAfterSalesMaterialCosts::getAfterSalesId, afterSalesId)
);
// 3.2 将 Entity 列表转换为 VO 列表
List<ErpAfterSalesMaterialCostsVo> materialVos = MapstructUtils.convert(materialEntities, ErpAfterSalesMaterialCostsVo.class);
// 3.3 塞入主表对象
vo.setMaterialCostsList(materialVos);
}
return vo;
@ -155,35 +161,23 @@ public class ErpAfterSalesServiceImpl implements IErpAfterSalesService {
@Override
@Transactional(rollbackFor = Exception.class) // 【重要】开启事务!如果子表保存失败,主表也要回滚,防止数据不一致
public Boolean insertByBo(ErpAfterSalesBo bo) {
// 1. 将 BO (业务对象) 转换为 Entity (数据库实体)
// MapstructUtils 是 Plus 封装的高性能 Bean 拷贝工具
ErpAfterSales add = MapstructUtils.convert(bo, ErpAfterSales.class);
// 2. 校验数据(这是生成的代码自带的)
validEntityBeforeSave(add);
// 3. 保存主表
// baseMapper.insert(add) 返回受影响行数大于0表示成功
// 成功后MyBatis 会自动把生成的 ID 回填到 add 对象中
boolean flag = baseMapper.insert(add) > 0;
bo.setAfterSalesId(add.getAfterSalesId()); // 将生成的 ID 回填给 BO
// 4. 如果主表保存成功,开始处理子表
if (flag) {
Long afterSalesId = add.getAfterSalesId(); // 拿到主表刚才生成的 ID
Long afterSalesId = add.getAfterSalesId();
// --- 处理子表 A人员费用 ---
List<ErpAfterSalesLaborCostsBo> laborBoList = bo.getLaborCostsList();
// 使用 CollUtil.isNotEmpty 判断列表不为空
if (CollUtil.isNotEmpty(laborBoList)) {
// 将 BO 列表转为 Entity 列表
List<ErpAfterSalesLaborCosts> laborList = MapstructUtils.convert(laborBoList, ErpAfterSalesLaborCosts.class);
// 遍历每个子对象,把主表 ID 填进去,建立外键关联
laborList.forEach(item -> item.setAfterSalesId(afterSalesId));
// 批量保存
laborCostsService.saveBatch(laborList);
}
// --- 处理子表 B材料费用 ---
List<ErpAfterSalesMaterialCostsBo> materialBoList = bo.getMaterialCostsList();
if (CollUtil.isNotEmpty(materialBoList)) {
List<ErpAfterSalesMaterialCosts> materialList = MapstructUtils.convert(materialBoList, ErpAfterSalesMaterialCosts.class);
@ -203,17 +197,14 @@ public class ErpAfterSalesServiceImpl implements IErpAfterSalesService {
@Override
@Transactional(rollbackFor = Exception.class) // 【重要】开启事务
public Boolean updateByBo(ErpAfterSalesBo bo) {
// 1. 更新主表数据
ErpAfterSales update = MapstructUtils.convert(bo, ErpAfterSales.class);
validEntityBeforeSave(update);
// updateById 会根据主键 ID 更新其他字段
int row = baseMapper.updateById(update);
// 2. 如果主表更新成功,开始处理子表
if (row > 0) {
Long afterSalesId = bo.getAfterSalesId();
// ================== 1. 处理人员费用 ==================
// ================== 处理人员费用 ==================
// 先删除旧的
laborCostsService.remove(new LambdaQueryWrapper<ErpAfterSalesLaborCosts>()
.eq(ErpAfterSalesLaborCosts::getAfterSalesId, afterSalesId));
@ -223,7 +214,7 @@ public class ErpAfterSalesServiceImpl implements IErpAfterSalesService {
if (CollUtil.isNotEmpty(laborBoList)) {
List<ErpAfterSalesLaborCosts> laborList = MapstructUtils.convert(laborBoList, ErpAfterSalesLaborCosts.class);
// 【核心修改点 👇】遍历列表,清空 ID
// 遍历列表,清空 ID
laborList.forEach(item -> {
item.setLaborCostsId(null); // 关键清空ID让MP重新生成雪花ID避免和逻辑删除的数据冲突
item.setAfterSalesId(afterSalesId);
@ -232,17 +223,14 @@ public class ErpAfterSalesServiceImpl implements IErpAfterSalesService {
laborCostsService.saveBatch(laborList);
}
// ================== 2. 处理材料费用 ==================
// 先删除旧的
// ================== 处理材料费用 ==================
materialCostsService.remove(new LambdaQueryWrapper<ErpAfterSalesMaterialCosts>()
.eq(ErpAfterSalesMaterialCosts::getAfterSalesId, afterSalesId));
// 后新增新的
List<ErpAfterSalesMaterialCostsBo> materialBoList = bo.getMaterialCostsList();
if (CollUtil.isNotEmpty(materialBoList)) {
List<ErpAfterSalesMaterialCosts> materialList = MapstructUtils.convert(materialBoList, ErpAfterSalesMaterialCosts.class);
// 【核心修改点 👇】遍历列表,清空 ID
materialList.forEach(item -> {
item.setMaterialCostsId(null); // 关键清空ID
item.setAfterSalesId(afterSalesId);
@ -275,4 +263,104 @@ public class ErpAfterSalesServiceImpl implements IErpAfterSalesService {
}
return baseMapper.deleteByIds(ids) > 0;
}
/**
*
*
* @param bo
* @return
*/
@Override
@GlobalTransactional(rollbackFor = Exception.class) // 开启全局事务
public ErpAfterSalesVo submitAndFlowStart(ErpAfterSalesBo bo) {
ErpAfterSales add = MapstructUtils.convert(bo, ErpAfterSales.class);
validEntityBeforeSave(add);
if (bo.getAfterSalesId() == null) {
this.insertByBo(bo);
} else {
this.updateByBo(bo);
}
// 准备启动流程参数
// 后端发起需要忽略权限
if (bo.getVariables() == null) {
bo.setVariables(new HashMap<>());
}
bo.getVariables().put("ignore", true);
RemoteStartProcess startProcess = new RemoteStartProcess();
startProcess.setBusinessId(bo.getAfterSalesId().toString());
startProcess.setFlowCode(bo.getFlowCode());
startProcess.setVariables(bo.getVariables());
startProcess.setBizExt(bo.getBizExt());
// 确保 BizExt 里也有 BusinessId
if (bo.getBizExt() != null) {
bo.getBizExt().setBusinessId(startProcess.getBusinessId());
}
// 调用远程服务启动流程
// startCompleteTask 表示“启动并自动完成第一个发起节点”,直接流转到下一个审批人
boolean flagOne = remoteWorkflowService.startCompleteTask(startProcess);
if (!flagOne) {
throw new ServiceException("流程发起异常");
}
return MapstructUtils.convert(add, ErpAfterSalesVo.class);
}
/**
* (: 稿退)
*
* @param processEvent
*/
@EventListener(condition = "#processEvent.flowCode == 'OAAS'")
public void processHandler(ProcessEvent processEvent) {
// 多租户上下文切换(防止异步线程找不到租户)
TenantHelper.dynamic(processEvent.getTenantId(), () -> {
log.info("【售后流程监听】开始处理: key={}, status={}", processEvent.getFlowCode(), processEvent.getStatus());
// 根据 BusinessId 查询出当前的售后单
Long afterSalesId = Convert.toLong(processEvent.getBusinessId());
ErpAfterSales afterSales = baseMapper.selectById(afterSalesId);
if (afterSales == null) {
log.error("未找到对应的售后单据id={}", afterSalesId);
return;
}
// 同步流程状态 (flow_status)
afterSales.setFlowStatus(processEvent.getStatus());
// 根据流程状态,更新业务状态 (after_sales_status)
String status = processEvent.getStatus();
// A. 审批中
if (BusinessStatusEnum.WAITING.getStatus().equals(status)) {
afterSales.setAfterSalesStatus("1");
}
// B. 流程结束/审批通过 (Finish)
else if (BusinessStatusEnum.FINISH.getStatus().equals(status)) {
afterSales.setAfterSalesStatus("2");
}
// C. 驳回 (Back) 或 撤销 (Cancel)
else if (BusinessStatusEnum.BACK.getStatus().equals(status)
|| BusinessStatusEnum.CANCEL.getStatus().equals(status)) {
afterSales.setAfterSalesStatus("0");
}
// D. 作废 (Invalid) 或 终止 (Termination)
else if (BusinessStatusEnum.INVALID.getStatus().equals(status)
|| BusinessStatusEnum.TERMINATION.getStatus().equals(status)) {
afterSales.setAfterSalesStatus("0");
}
// 4. 更新数据库
baseMapper.updateById(afterSales);
});
}
}

@ -1,23 +1,46 @@
package org.dromara.oa.erp.service.impl;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.map.MapUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.yulichang.toolkit.JoinWrappers;
import lombok.extern.slf4j.Slf4j;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import lombok.RequiredArgsConstructor;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.seata.spring.annotation.GlobalTransactional;
import org.dromara.common.core.enums.BusinessStatusEnum;
import org.dromara.common.core.enums.OAStatusEnum;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.tenant.helper.TenantHelper;
import org.dromara.oa.erp.domain.ErpContractInfo;
import org.dromara.oa.erp.domain.ErpProjectReport;
import org.dromara.oa.erp.domain.ErpProjectReportDetail;
import org.dromara.oa.erp.domain.bo.ErpContractInfoBo;
import org.dromara.oa.erp.domain.bo.ErpProjectReportBo;
import org.dromara.oa.erp.domain.bo.ErpProjectReportDetailBo;
import org.dromara.oa.erp.domain.bo.ProjectReportAndDetailWrapperBo;
import org.dromara.oa.erp.domain.vo.ErpContractInfoVo;
import org.dromara.oa.erp.domain.vo.ErpProjectReportDetailVo;
import org.dromara.oa.erp.domain.vo.ErpProjectReportVo;
import org.dromara.oa.erp.mapper.ErpProjectReportDetailMapper;
import org.dromara.oa.erp.mapper.ErpProjectReportMapper;
import org.dromara.oa.erp.service.IErpProjectReportDetailService;
import org.dromara.oa.erp.service.IErpProjectReportService;
import org.dromara.workflow.api.RemoteWorkflowService;
import org.dromara.workflow.api.domain.RemoteStartProcess;
import org.dromara.workflow.api.event.ProcessEvent;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Service;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Objects;
/**
* Service
@ -27,10 +50,17 @@ import java.util.Map;
*/
@RequiredArgsConstructor
@Service
@Slf4j
public class ErpProjectReportDetailServiceImpl implements IErpProjectReportDetailService {
private final IErpProjectReportService erpProjectReportService;
private final ErpProjectReportDetailMapper baseMapper;
@DubboReference(timeout = 30000)
private RemoteWorkflowService remoteWorkflowService;
/**
*
*
@ -146,4 +176,77 @@ public class ErpProjectReportDetailServiceImpl implements IErpProjectReportDetai
}
return baseMapper.deleteByIds(ids) > 0;
}
/**
*
* @param projectReport
* @param projectDetailReport
* @return
*/
@Override
@GlobalTransactional(rollbackFor = Exception.class)
public ErpProjectReportDetailVo projectReportSubmitAndFlowStart(ErpProjectReportBo projectReport, ErpProjectReportDetailBo projectDetailReport) {
if (projectReport.getReportId() != null) {
ErpProjectReportVo existingReport = erpProjectReportService.queryById(projectReport.getReportId());
if (existingReport != null) {
erpProjectReportService.updateByBo(projectReport);
} else {
erpProjectReportService.insertByBo(projectReport);
}
} else {
erpProjectReportService.insertByBo(projectReport);
}
ErpProjectReportDetail erpProjectReportDetail = MapstructUtils.convert(projectDetailReport, ErpProjectReportDetail.class);
validEntityBeforeSave(erpProjectReportDetail);
if (StringUtils.isNull(projectDetailReport.getReportDetailId())) {
this.insertByBo(projectDetailReport);
} else {
this.updateByBo(projectDetailReport);
}
// 后端发起需要忽略权限
projectDetailReport.getVariables().put("ignore", true);
RemoteStartProcess startProcess = new RemoteStartProcess();
startProcess.setBusinessId(projectDetailReport.getReportDetailId().toString());
startProcess.setFlowCode(projectDetailReport.getFlowCode());
startProcess.setVariables(projectDetailReport.getVariables());
startProcess.setBizExt(projectDetailReport.getBizExt());
projectDetailReport.getBizExt().setBusinessId(startProcess.getBusinessId());
boolean flagOne = remoteWorkflowService.startCompleteTask(startProcess);
if (!flagOne) {
throw new ServiceException("流程发起异常");
}
return MapstructUtils.convert(erpProjectReportDetail, ErpProjectReportDetailVo.class);
}
/**
* (: 稿退)
*
* @param processEvent
*/
@EventListener(condition = "#processEvent.flowCode =='XMZB'")
public void processHandler(ProcessEvent processEvent) {
TenantHelper.dynamic(processEvent.getTenantId(), () -> {
log.info("当前任务执行了{}", processEvent.toString());
ErpProjectReportDetail projectReportDetail = baseMapper.selectById(Convert.toLong(processEvent.getBusinessId()));
projectReportDetail.setFlowStatus(processEvent.getStatus());
Map<String, Object> params = processEvent.getParams();
if (MapUtil.isNotEmpty(params)) {
// 办理人
String handler = Convert.toStr(params.get("handler"));
}
if (Objects.equals(processEvent.getStatus(), BusinessStatusEnum.WAITING.getStatus())) {
projectReportDetail.setProjectReportStatus(OAStatusEnum.APPROVING.getStatus());
} else if (Objects.equals(processEvent.getStatus(), BusinessStatusEnum.FINISH.getStatus())) {
projectReportDetail.setProjectReportStatus(OAStatusEnum.COMPLETED.getStatus());
} else if (Objects.equals(processEvent.getStatus(), BusinessStatusEnum.INVALID.getStatus())
|| Objects.equals(processEvent.getStatus(), BusinessStatusEnum.TERMINATION.getStatus())) {
projectReportDetail.setProjectReportStatus(OAStatusEnum.INVALID.getStatus());
} else if (Objects.equals(processEvent.getStatus(), BusinessStatusEnum.BACK.getStatus())
|| Objects.equals(processEvent.getStatus(), BusinessStatusEnum.CANCEL.getStatus())) {
projectReportDetail.setProjectReportStatus(OAStatusEnum.DRAFT.getStatus());
}
baseMapper.updateById(projectReportDetail);
});
}
}

@ -38,23 +38,23 @@ public class ErpProjectReportServiceImpl implements IErpProjectReportService {
* @return
*/
@Override
public ErpProjectReportVo queryById(Long reportId){
public ErpProjectReportVo queryById(Long reportId) {
return baseMapper.selectVoById(reportId);
}
/**
*
*
* @param bo
* @param pageQuery
* @return
*/
@Override
public TableDataInfo<ErpProjectReportVo> queryPageList(ErpProjectReportBo bo, PageQuery pageQuery) {
MPJLambdaWrapper<ErpProjectReport> lqw = buildQueryWrapper(bo);
Page<ErpProjectReportVo> result = baseMapper.selectCustomErpProjectReportVoList(pageQuery.build(), lqw);
return TableDataInfo.build(result);
}
/**
*
*
* @param bo
* @param pageQuery
* @return
*/
@Override
public TableDataInfo<ErpProjectReportVo> queryPageList(ErpProjectReportBo bo, PageQuery pageQuery) {
MPJLambdaWrapper<ErpProjectReport> lqw = buildQueryWrapper(bo);
Page<ErpProjectReportVo> result = baseMapper.selectCustomErpProjectReportVoList(pageQuery.build(), lqw);
return TableDataInfo.build(result);
}
/**
*
@ -71,21 +71,27 @@ public class ErpProjectReportServiceImpl implements IErpProjectReportService {
private MPJLambdaWrapper<ErpProjectReport> buildQueryWrapper(ErpProjectReportBo bo) {
Map<String, Object> params = bo.getParams();
MPJLambdaWrapper<ErpProjectReport> lqw = JoinWrappers.lambda(ErpProjectReport.class)
.selectAll(ErpProjectReport.class)
.eq(bo.getProjectId() != null, ErpProjectReport::getProjectId, bo.getProjectId())
.like(StringUtils.isNotBlank(bo.getProjectName()), ErpProjectReport::getProjectName, bo.getProjectName())
.eq(StringUtils.isNotBlank(bo.getMilestonePlan()), ErpProjectReport::getMilestonePlan, bo.getMilestonePlan())
.eq(bo.getManagerId() != null, ErpProjectReport::getManagerId, bo.getManagerId())
.eq(bo.getDeptId() != null, ErpProjectReport::getDeptId, bo.getDeptId())
.eq(bo.getChargeId() != null, ErpProjectReport::getChargeId, bo.getChargeId())
.eq(bo.getDeputyId() != null, ErpProjectReport::getDeputyId, bo.getDeputyId())
.eq(StringUtils.isNotBlank(bo.getInformationNote()), ErpProjectReport::getInformationNote, bo.getInformationNote())
.eq(bo.getSortOrder() != null, ErpProjectReport::getSortOrder, bo.getSortOrder())
.eq(StringUtils.isNotBlank(bo.getOssId()), ErpProjectReport::getOssId, bo.getOssId())
.eq(StringUtils.isNotBlank(bo.getActiveFlag()), ErpProjectReport::getActiveFlag, bo.getActiveFlag())
.eq(StringUtils.isNotBlank(bo.getProjectCode()), ErpProjectReport::getProjectCode, bo.getProjectCode())
;
.selectAll(ErpProjectReport.class)
.eq(bo.getProjectId() != null, ErpProjectReport::getProjectId, bo.getProjectId())
.eq(StringUtils.isNotBlank(bo.getMilestonePlan()), ErpProjectReport::getMilestonePlan, bo.getMilestonePlan())
.eq(bo.getManagerId() != null, ErpProjectReport::getManagerId, bo.getManagerId())
.eq(bo.getDeptId() != null, ErpProjectReport::getDeptId, bo.getDeptId())
.eq(bo.getChargeId() != null, ErpProjectReport::getChargeId, bo.getChargeId())
.eq(bo.getDeputyId() != null, ErpProjectReport::getDeputyId, bo.getDeputyId())
.eq(StringUtils.isNotBlank(bo.getInformationNote()), ErpProjectReport::getInformationNote, bo.getInformationNote())
.eq(bo.getSortOrder() != null, ErpProjectReport::getSortOrder, bo.getSortOrder())
.eq(StringUtils.isNotBlank(bo.getOssId()), ErpProjectReport::getOssId, bo.getOssId())
.eq(StringUtils.isNotBlank(bo.getActiveFlag()), ErpProjectReport::getActiveFlag, bo.getActiveFlag())
.like(StringUtils.isNotBlank(bo.getProjectName()), ErpProjectReport::getProjectName, bo.getProjectName())
.like(StringUtils.isNotBlank(bo.getProjectCode()), ErpProjectReport::getProjectCode, bo.getProjectCode())
// 关联表条件 - 使用 apply 方法添加
.apply(StringUtils.isNotBlank(bo.getDeptName()), "d.dept_name LIKE CONCAT('%', {0}, '%')", bo.getDeptName())
.apply(StringUtils.isNotBlank(bo.getManagerName()), "u1.nick_name LIKE CONCAT('%', {0}, '%')", bo.getManagerName())
.apply(StringUtils.isNotBlank(bo.getChargeName()), "u2.nick_name LIKE CONCAT('%', {0}, '%')", bo.getChargeName())
.apply(StringUtils.isNotBlank(bo.getDeputyName()), "u3.nick_name LIKE CONCAT('%', {0}, '%')", bo.getDeputyName());
return lqw;
}
/**
@ -121,7 +127,7 @@ public class ErpProjectReportServiceImpl implements IErpProjectReportService {
/**
*
*/
private void validEntityBeforeSave(ErpProjectReport entity){
private void validEntityBeforeSave(ErpProjectReport entity) {
//TODO 做一些数据校验,如唯一约束
}
@ -134,7 +140,7 @@ public class ErpProjectReportServiceImpl implements IErpProjectReportService {
*/
@Override
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
if(isValid){
if (isValid) {
//TODO 做一些业务上的校验,判断是否需要校验
}
return baseMapper.deleteByIds(ids) > 0;

@ -37,7 +37,8 @@
left join sys_user u1 on u1.user_id = t.manager_id
left join sys_user u2 on u2.user_id = t.charge_id
left join sys_user u3 on u3.user_id = t.deputy_id
${ew.getCustomSqlSegment}
${ew.getCustomSqlSegment}
</select>
</mapper>

@ -51,6 +51,7 @@ public class WmsInventoryDetails extends TenantEntity {
*
*/
private Double inventoryAmount;
private Double startInventoryAmount;
/**
*

@ -50,7 +50,7 @@ public class WmsInventoryDetailsBo extends BaseEntity {
*
*/
private Double inventoryAmount;
private Double startInventoryAmount;
/**
*
*/

@ -8,6 +8,7 @@ import org.apache.ibatis.annotations.Param;
import org.dromara.wms.domain.WmsInventoryLedger;
import org.dromara.wms.domain.vo.WmsInventoryLedgerVo;
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
import org.springframework.stereotype.Repository;
/**
* Mapper
@ -15,6 +16,7 @@ import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
* @author Yinq
* @date 2025-12-02
*/
@Repository
public interface WmsInventoryLedgerMapper extends BaseMapperPlus<WmsInventoryLedger, WmsInventoryLedgerVo> {
/**

@ -67,7 +67,8 @@ public interface IWmsInventoryDetailsService {
*/
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
void insertList(List<WmsInventoryDetails> inventoryDetailsList);
TableDataInfo<WmsInventoryDetailsVo> listCount(WmsInventoryDetailsBo bo, PageQuery pageQuery);
WmsInventoryDetails queryInventory(WmsInventoryDetailsBo inventory);
}

@ -14,13 +14,15 @@ import org.dromara.system.api.RemoteCodeRuleService;
import org.dromara.wms.domain.WmsInStockBill;
import org.dromara.wms.domain.WmsInStockDetails;
import org.dromara.wms.domain.WmsInventoryDetails;
import org.dromara.wms.domain.WmsInventoryLedger;
import org.dromara.wms.domain.bo.WmsInStockBillBo;
import org.dromara.wms.domain.bo.WmsInventoryDetailsBo;
import org.dromara.wms.domain.vo.WmsInStockBillVo;
import org.dromara.wms.mapper.WmsInStockBillMapper;
import org.dromara.wms.mapper.WmsInStockDetailsMapper;
import org.dromara.wms.mapper.WmsInventoryLedgerMapper;
import org.dromara.wms.service.IWmsInStockBillService;
import org.dromara.wms.service.IWmsInventoryDetailsService;
import org.dromara.wms.service.IWmsWarehouseInfoService;
import org.dromara.workflow.api.RemoteWorkflowService;
import org.dromara.workflow.api.domain.RemoteStartProcess;
import org.dromara.workflow.api.event.ProcessEvent;
@ -42,7 +44,8 @@ public class WmsInStockBillServiceImpl implements IWmsInStockBillService {
private final WmsInStockBillMapper baseMapper;
private final WmsInStockDetailsMapper wmsInStockDetailsMapper;
private final IWmsInventoryDetailsService inventoryService;
private final IWmsWarehouseInfoService warehouseService;
// private final IWmsWarehouseInfoService warehouseService;
private final WmsInventoryLedgerMapper wmsInventoryLedgerMapper;
@DubboReference
private RemoteCodeRuleService remoteCodeRuleService;
@DubboReference(timeout = 30000)//超时时间
@ -110,31 +113,57 @@ public class WmsInStockBillServiceImpl implements IWmsInStockBillService {
@Override
public Boolean insertByBo(WmsInStockBillBo bo) {
WmsInStockBill add = MapstructUtils.convert(bo, WmsInStockBill.class);
add.setInStockCode(remoteCodeRuleService.selectCodeRuleCode("1005"));
String inStockType = add.getInStockType();
add.setInStockCode(remoteCodeRuleService.selectCodeRuleCode("1005"));// 物料入库编码
add.setInStockBillStatus("3");
boolean flag = baseMapper.insert(add) > 0;
boolean flag = baseMapper.insert(add) > 0;//插入主表
if (flag) {
Long inStockBillId = add.getInStockBillId();
List<WmsInStockDetails> inStockDetailsList = bo.getInStockDetailsList();
List<WmsInventoryDetails> inventoryDetailsList = new ArrayList<>(inStockDetailsList.size());//库存集合
List<WmsInventoryLedger> wmsInventoryLedgers = new ArrayList<>(inStockDetailsList.size());//库存集合
Long projectId = bo.getProjectId();// 项目ID
inStockDetailsList.forEach(item -> {
item.setInStockBillId(inStockBillId); // 设置入库单明细的入库单ID
item.setProjectId(projectId); // 关联项目
WmsInventoryDetails inventory = new WmsInventoryDetails();
inventory.setWarehouseId(item.getWarehouseId()); // 关联仓库
inventory.setProjectId(projectId); // 关联项目
inventory.setBatchNumber(item.getBatchNumber()); // 关联批次号
inventory.setMaterielId(item.getMaterialId()); // 关联物料
inventory.setUnitPrice(item.getUnitPrice());
Double inStockAmount = item.getInStockAmount();
inventory.setInventoryAmount(inStockAmount);
inventory.setStartInventoryAmount(inStockAmount); // 初始库存数量
inventoryDetailsList.add(inventory);
Double inventoryTableAmount = 0.0;// 库存表数量
// 构建库存明细
WmsInventoryDetailsBo inventory = new WmsInventoryDetailsBo();
inventory.setWarehouseId(item.getWarehouseId());
inventory.setProjectId(projectId);
inventory.setBatchNumber(item.getBatchNumber());
inventory.setMaterielId(item.getMaterialId());
inventory.setUnitPrice(item.getUnitPrice());
// 查询相同项目 相同仓库 相同批次 相同单价的物料
WmsInventoryDetails queryInventory = inventoryService.queryInventory(inventory);
if (queryInventory != null) {
WmsInventoryDetailsBo inventoryUpdate = new WmsInventoryDetailsBo();
inventoryUpdate.setInventoryDetailsId(queryInventory.getInventoryDetailsId());
inventoryTableAmount = queryInventory.getInventoryAmount() ;
inventoryUpdate.setInventoryAmount(inventoryTableAmount+ inStockAmount);
inventoryService.updateByBo(inventoryUpdate); // 更新库存数量
} else {
inventory.setUnitName(item.getUnitName());
inventory.setInventoryAmount(inStockAmount);
inventory.setStartInventoryAmount(inStockAmount); // 初始库存数量
inventoryService.insertByBo(inventory);
}
//库存变动
WmsInventoryLedger wmsInventoryLedger = new WmsInventoryLedger();
wmsInventoryLedger.setWarehouseId(item.getWarehouseId());
wmsInventoryLedger.setBatchNumber(item.getBatchNumber());
wmsInventoryLedger.setMaterielId(item.getMaterialId());
wmsInventoryLedger.setChangeType(inStockType);//变动类型
wmsInventoryLedger.setLedgerState("1");
wmsInventoryLedger.setChangeAmount(inStockAmount);
wmsInventoryLedger.setInventoryAmount(inventoryTableAmount);
wmsInventoryLedgers.add(wmsInventoryLedger);
});
wmsInStockDetailsMapper.insert(inStockDetailsList); //插入子表
inventoryService.insertList(inventoryDetailsList); //插入库存
wmsInventoryLedgerMapper.insert(wmsInventoryLedgers);
}
return flag;
}

@ -127,7 +127,6 @@ public class WmsInventoryDetailsServiceImpl implements IWmsInventoryDetailsServi
@Override
public Boolean insertByBo(WmsInventoryDetailsBo bo) {
WmsInventoryDetails add = MapstructUtils.convert(bo, WmsInventoryDetails.class);
validEntityBeforeSave(add);
boolean flag = baseMapper.insert(add) > 0;
if (flag) {
bo.setInventoryDetailsId(add.getInventoryDetailsId());
@ -144,16 +143,9 @@ public class WmsInventoryDetailsServiceImpl implements IWmsInventoryDetailsServi
@Override
public Boolean updateByBo(WmsInventoryDetailsBo bo) {
WmsInventoryDetails update = MapstructUtils.convert(bo, WmsInventoryDetails.class);
validEntityBeforeSave(update);
return baseMapper.updateById(update) > 0;
}
/**
*
*/
private void validEntityBeforeSave(WmsInventoryDetails entity) {
//TODO 做一些数据校验,如唯一约束
}
/**
*
@ -164,14 +156,22 @@ public class WmsInventoryDetailsServiceImpl implements IWmsInventoryDetailsServi
*/
@Override
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
if (isValid) {
//TODO 做一些业务上的校验,判断是否需要校验
}
return baseMapper.deleteByIds(ids) > 0;
}
@Override
public void insertList(List<WmsInventoryDetails> inventoryDetailsList) {
baseMapper.insert(inventoryDetailsList);
public WmsInventoryDetails queryInventory(WmsInventoryDetailsBo bo) {
MPJLambdaWrapper<WmsInventoryDetails> lqw = JoinWrappers.lambda(WmsInventoryDetails.class)
.selectAll(WmsInventoryDetails.class)
.eq(StringUtils.isNotBlank(bo.getLocationCode()), WmsInventoryDetails::getLocationCode, bo.getLocationCode())
.eq(bo.getWarehouseId() != null, WmsInventoryDetails::getWarehouseId, bo.getWarehouseId())
.eq(bo.getMaterielId() != null, WmsInventoryDetails::getMaterielId, bo.getMaterielId())
.eq(bo.getProjectId() != null, WmsInventoryDetails::getProjectId, bo.getProjectId())
.eq(StringUtils.isNotBlank(bo.getBatchNumber()), WmsInventoryDetails::getBatchNumber, bo.getBatchNumber())
.eq(bo.getUnitPrice() != null, WmsInventoryDetails::getUnitPrice, bo.getUnitPrice());
return baseMapper.selectOne(lqw);
}
}

@ -10,14 +10,18 @@ import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.system.api.RemoteCodeRuleService;
import org.dromara.wms.domain.WmsInventoryDetails;
import org.dromara.wms.domain.WmsOutStockBill;
import org.dromara.wms.domain.WmsOutStockDetails;
import org.dromara.wms.domain.bo.WmsOutStockBillBo;
import org.dromara.wms.domain.vo.WmsInventoryDetailsVo;
import org.dromara.wms.domain.vo.WmsOutStockBillVo;
import org.dromara.wms.mapper.WmsInventoryDetailsMapper;
import org.dromara.wms.mapper.WmsOutStockBillMapper;
import org.dromara.wms.mapper.WmsOutStockDetailsMapper;
import org.dromara.wms.service.IWmsOutStockBillService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.Collection;
import java.util.List;
@ -37,6 +41,7 @@ public class WmsOutStockBillServiceImpl implements IWmsOutStockBillService {
private final WmsOutStockDetailsMapper wmsOutStockDetailsMapper;
@DubboReference
private RemoteCodeRuleService remoteCodeRuleService;
private final WmsInventoryDetailsMapper wmsInventoryDetailsMapper;
/**
*
@ -98,6 +103,7 @@ public class WmsOutStockBillServiceImpl implements IWmsOutStockBillService {
* @return
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean insertByBo(WmsOutStockBillBo bo) {
WmsOutStockBill add = MapstructUtils.convert(bo, WmsOutStockBill.class);
add.setOutStockCode(remoteCodeRuleService.selectCodeRuleCode("1006"));
@ -107,7 +113,15 @@ public class WmsOutStockBillServiceImpl implements IWmsOutStockBillService {
Long outStockBillId = add.getOutStockBillId();
List<WmsOutStockDetails> outStockDetailsList = bo.getOutStockDetailsList();
outStockDetailsList.forEach(item -> {
item.setOutStockBillId(outStockBillId);
// 从出库明细中获取库存ID
Long inventoryId = item.getInventoryDetailsId();
WmsInventoryDetails inventory = wmsInventoryDetailsMapper.selectById(inventoryId);
if (inventory.getInventoryAmount()<item.getOutStockAmount()) {
throw new IllegalArgumentException("库存数量不足");
}
});
//插入出库明细
wmsOutStockDetailsMapper.insert(outStockDetailsList);

Loading…
Cancel
Save