From 020a7daa1f5626801f39c1ae5e987a3f5cb87ae0 Mon Sep 17 00:00:00 2001 From: wanghao Date: Wed, 3 Dec 2025 14:09:39 +0800 Subject: [PATCH 1/3] =?UTF-8?q?feat(wms):=20=E5=85=A5=E5=BA=93=E9=AA=8C?= =?UTF-8?q?=E8=AF=81=E5=BA=93=E5=AD=98=E6=98=AF=E5=90=A6=E5=AD=98=E5=9C=A8?= =?UTF-8?q?=EF=BC=8C=E6=9B=B4=E6=96=B0=E6=88=96=E6=96=B0=E5=A2=9E=E5=BA=93?= =?UTF-8?q?=E5=AD=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../wms/domain/WmsInventoryDetails.java | 1 + .../wms/domain/bo/WmsInventoryDetailsBo.java | 2 +- .../wms/mapper/WmsInventoryLedgerMapper.java | 2 + .../service/IWmsInventoryDetailsService.java | 3 +- .../impl/WmsInStockBillServiceImpl.java | 61 ++++++++++++++----- .../impl/WmsInventoryDetailsServiceImpl.java | 26 ++++---- .../impl/WmsOutStockBillServiceImpl.java | 14 +++++ 7 files changed, 78 insertions(+), 31 deletions(-) diff --git a/ruoyi-modules/ruoyi-wms/src/main/java/org/dromara/wms/domain/WmsInventoryDetails.java b/ruoyi-modules/ruoyi-wms/src/main/java/org/dromara/wms/domain/WmsInventoryDetails.java index e002eb46..a8b33c16 100644 --- a/ruoyi-modules/ruoyi-wms/src/main/java/org/dromara/wms/domain/WmsInventoryDetails.java +++ b/ruoyi-modules/ruoyi-wms/src/main/java/org/dromara/wms/domain/WmsInventoryDetails.java @@ -51,6 +51,7 @@ public class WmsInventoryDetails extends TenantEntity { * 库存数量 */ private Double inventoryAmount; + private Double startInventoryAmount; /** * 物料单位 diff --git a/ruoyi-modules/ruoyi-wms/src/main/java/org/dromara/wms/domain/bo/WmsInventoryDetailsBo.java b/ruoyi-modules/ruoyi-wms/src/main/java/org/dromara/wms/domain/bo/WmsInventoryDetailsBo.java index 379fd70f..d8236af1 100644 --- a/ruoyi-modules/ruoyi-wms/src/main/java/org/dromara/wms/domain/bo/WmsInventoryDetailsBo.java +++ b/ruoyi-modules/ruoyi-wms/src/main/java/org/dromara/wms/domain/bo/WmsInventoryDetailsBo.java @@ -50,7 +50,7 @@ public class WmsInventoryDetailsBo extends BaseEntity { * 库存数量 */ private Double inventoryAmount; - + private Double startInventoryAmount; /** * 锁定数量 */ diff --git a/ruoyi-modules/ruoyi-wms/src/main/java/org/dromara/wms/mapper/WmsInventoryLedgerMapper.java b/ruoyi-modules/ruoyi-wms/src/main/java/org/dromara/wms/mapper/WmsInventoryLedgerMapper.java index 126118e8..d6e03026 100644 --- a/ruoyi-modules/ruoyi-wms/src/main/java/org/dromara/wms/mapper/WmsInventoryLedgerMapper.java +++ b/ruoyi-modules/ruoyi-wms/src/main/java/org/dromara/wms/mapper/WmsInventoryLedgerMapper.java @@ -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 { /** diff --git a/ruoyi-modules/ruoyi-wms/src/main/java/org/dromara/wms/service/IWmsInventoryDetailsService.java b/ruoyi-modules/ruoyi-wms/src/main/java/org/dromara/wms/service/IWmsInventoryDetailsService.java index 079038c2..70664351 100644 --- a/ruoyi-modules/ruoyi-wms/src/main/java/org/dromara/wms/service/IWmsInventoryDetailsService.java +++ b/ruoyi-modules/ruoyi-wms/src/main/java/org/dromara/wms/service/IWmsInventoryDetailsService.java @@ -67,7 +67,8 @@ public interface IWmsInventoryDetailsService { */ Boolean deleteWithValidByIds(Collection ids, Boolean isValid); - void insertList(List inventoryDetailsList); TableDataInfo listCount(WmsInventoryDetailsBo bo, PageQuery pageQuery); + + WmsInventoryDetails queryInventory(WmsInventoryDetailsBo inventory); } diff --git a/ruoyi-modules/ruoyi-wms/src/main/java/org/dromara/wms/service/impl/WmsInStockBillServiceImpl.java b/ruoyi-modules/ruoyi-wms/src/main/java/org/dromara/wms/service/impl/WmsInStockBillServiceImpl.java index a352bf11..4e1e8a2a 100644 --- a/ruoyi-modules/ruoyi-wms/src/main/java/org/dromara/wms/service/impl/WmsInStockBillServiceImpl.java +++ b/ruoyi-modules/ruoyi-wms/src/main/java/org/dromara/wms/service/impl/WmsInStockBillServiceImpl.java @@ -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 inStockDetailsList = bo.getInStockDetailsList(); - List inventoryDetailsList = new ArrayList<>(inStockDetailsList.size());//库存集合 + List 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; } diff --git a/ruoyi-modules/ruoyi-wms/src/main/java/org/dromara/wms/service/impl/WmsInventoryDetailsServiceImpl.java b/ruoyi-modules/ruoyi-wms/src/main/java/org/dromara/wms/service/impl/WmsInventoryDetailsServiceImpl.java index 4ca7c339..1cf4ade9 100644 --- a/ruoyi-modules/ruoyi-wms/src/main/java/org/dromara/wms/service/impl/WmsInventoryDetailsServiceImpl.java +++ b/ruoyi-modules/ruoyi-wms/src/main/java/org/dromara/wms/service/impl/WmsInventoryDetailsServiceImpl.java @@ -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 ids, Boolean isValid) { - if (isValid) { - //TODO 做一些业务上的校验,判断是否需要校验 - } return baseMapper.deleteByIds(ids) > 0; } + + @Override - public void insertList(List inventoryDetailsList) { - baseMapper.insert(inventoryDetailsList); + public WmsInventoryDetails queryInventory(WmsInventoryDetailsBo bo) { + MPJLambdaWrapper 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); } } diff --git a/ruoyi-modules/ruoyi-wms/src/main/java/org/dromara/wms/service/impl/WmsOutStockBillServiceImpl.java b/ruoyi-modules/ruoyi-wms/src/main/java/org/dromara/wms/service/impl/WmsOutStockBillServiceImpl.java index a2deabde..7c247058 100644 --- a/ruoyi-modules/ruoyi-wms/src/main/java/org/dromara/wms/service/impl/WmsOutStockBillServiceImpl.java +++ b/ruoyi-modules/ruoyi-wms/src/main/java/org/dromara/wms/service/impl/WmsOutStockBillServiceImpl.java @@ -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 outStockDetailsList = bo.getOutStockDetailsList(); outStockDetailsList.forEach(item -> { + item.setOutStockBillId(outStockBillId); + // 从出库明细中获取库存ID + Long inventoryId = item.getInventoryDetailsId(); + WmsInventoryDetails inventory = wmsInventoryDetailsMapper.selectById(inventoryId); + if (inventory.getInventoryAmount() Date: Wed, 3 Dec 2025 15:41:21 +0800 Subject: [PATCH 2/3] =?UTF-8?q?=E9=A1=B9=E7=9B=AE=E5=91=A8=E6=8A=A5?= =?UTF-8?q?=E6=9F=A5=E8=AF=A2=E5=8A=9F=E8=83=BD=20=E9=A1=B9=E7=9B=AE?= =?UTF-8?q?=E5=91=A8=E6=8A=A5=E6=B5=81=E7=A8=8B=E6=8F=90=E4=BA=A4=E5=8A=9F?= =?UTF-8?q?=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ErpProjectReportController.java | 1 + .../ErpProjectReportDetailController.java | 18 +++ .../oa/erp/domain/ErpProjectReport.java | 29 ++++- .../oa/erp/domain/ErpProjectReportDetail.java | 2 +- .../oa/erp/domain/bo/ErpProjectReportBo.java | 19 ++++ .../domain/bo/ErpProjectReportDetailBo.java | 53 +++++++++ .../bo/ProjectReportAndDetailWrapperBo.java | 12 ++ .../domain/vo/ErpProjectReportDetailVo.java | 23 ++++ .../IErpProjectReportDetailService.java | 11 ++ .../ErpProjectReportDetailServiceImpl.java | 103 ++++++++++++++++++ .../impl/ErpProjectReportServiceImpl.java | 66 ++++++----- .../mapper/oa/erp/ErpProjectReportMapper.xml | 3 +- 12 files changed, 303 insertions(+), 37 deletions(-) create mode 100644 ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/domain/bo/ProjectReportAndDetailWrapperBo.java diff --git a/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/controller/ErpProjectReportController.java b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/controller/ErpProjectReportController.java index 2c103d0d..c0cd79ee 100644 --- a/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/controller/ErpProjectReportController.java +++ b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/controller/ErpProjectReportController.java @@ -44,6 +44,7 @@ public class ErpProjectReportController extends BaseController { @SaCheckPermission("oa/erp:projectReport:list") @GetMapping("/list") public TableDataInfo list(ErpProjectReportBo bo, PageQuery pageQuery) { + return erpProjectReportService.queryPageList(bo, pageQuery); } diff --git a/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/controller/ErpProjectReportDetailController.java b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/controller/ErpProjectReportDetailController.java index bae7f664..6c55eff3 100644 --- a/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/controller/ErpProjectReportDetailController.java +++ b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/controller/ErpProjectReportDetailController.java @@ -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 projectReportSubmitAndFlowStart(@Validated(AddGroup.class) @RequestBody ProjectReportAndDetailWrapperBo wrapper) { + ErpProjectReportBo projectReport = wrapper.getProjectReport(); + ErpProjectReportDetailBo projectDetailReport = wrapper.getProjectDetailReport(); + return R.ok(erpProjectReportDetailService.projectReportSubmitAndFlowStart(projectReport, projectDetailReport)); + } } diff --git a/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/domain/ErpProjectReport.java b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/domain/ErpProjectReport.java index 1ac85c87..8f8f070d 100644 --- a/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/domain/ErpProjectReport.java +++ b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/domain/ErpProjectReport.java @@ -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; } diff --git a/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/domain/ErpProjectReportDetail.java b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/domain/ErpProjectReportDetail.java index 3dbfde35..8b7bb2a9 100644 --- a/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/domain/ErpProjectReportDetail.java +++ b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/domain/ErpProjectReportDetail.java @@ -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; /** diff --git a/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/domain/bo/ErpProjectReportBo.java b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/domain/bo/ErpProjectReportBo.java index 4ee92d8a..92209544 100644 --- a/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/domain/bo/ErpProjectReportBo.java +++ b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/domain/bo/ErpProjectReportBo.java @@ -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; } diff --git a/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/domain/bo/ErpProjectReportDetailBo.java b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/domain/bo/ErpProjectReportDetailBo.java index b8b1a14c..c66444f7 100644 --- a/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/domain/bo/ErpProjectReportDetailBo.java +++ b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/domain/bo/ErpProjectReportDetailBo.java @@ -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 variables; + + /** + * 流程业务扩展信息 + */ + private RemoteFlowInstanceBizExt bizExt; + /** + * 部门名称 + */ + private String deptName; + + /** + * 项目经理名称 + */ + private String managerName; + + /** + * 部门负责人名称 + */ + private String chargeName; + + /** + * 分管副总名称 + */ + private String deputyName; + + public Map 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; + } + } diff --git a/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/domain/bo/ProjectReportAndDetailWrapperBo.java b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/domain/bo/ProjectReportAndDetailWrapperBo.java new file mode 100644 index 00000000..5db6429a --- /dev/null +++ b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/domain/bo/ProjectReportAndDetailWrapperBo.java @@ -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; +} diff --git a/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/domain/vo/ErpProjectReportDetailVo.java b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/domain/vo/ErpProjectReportDetailVo.java index ebe169a0..40c1e09e 100644 --- a/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/domain/vo/ErpProjectReportDetailVo.java +++ b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/domain/vo/ErpProjectReportDetailVo.java @@ -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; } diff --git a/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/service/IErpProjectReportDetailService.java b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/service/IErpProjectReportDetailService.java index ebc7b758..eddfdd78 100644 --- a/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/service/IErpProjectReportDetailService.java +++ b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/service/IErpProjectReportDetailService.java @@ -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 ids, Boolean isValid); + + /** + * 提交项目周报并提交流程 + * @param + * @return + */ + ErpProjectReportDetailVo projectReportSubmitAndFlowStart(ErpProjectReportBo projectReport, ErpProjectReportDetailBo projectDetailReport); } diff --git a/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/service/impl/ErpProjectReportDetailServiceImpl.java b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/service/impl/ErpProjectReportDetailServiceImpl.java index 978698b8..b1247d25 100644 --- a/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/service/impl/ErpProjectReportDetailServiceImpl.java +++ b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/service/impl/ErpProjectReportDetailServiceImpl.java @@ -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 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); + }); + } } diff --git a/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/service/impl/ErpProjectReportServiceImpl.java b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/service/impl/ErpProjectReportServiceImpl.java index 10e74258..19d98791 100644 --- a/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/service/impl/ErpProjectReportServiceImpl.java +++ b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/service/impl/ErpProjectReportServiceImpl.java @@ -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 queryPageList(ErpProjectReportBo bo, PageQuery pageQuery) { - MPJLambdaWrapper lqw = buildQueryWrapper(bo); - Page result = baseMapper.selectCustomErpProjectReportVoList(pageQuery.build(), lqw); - return TableDataInfo.build(result); - } + /** + * 分页查询项目周报信息列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 项目周报信息分页列表 + */ + @Override + public TableDataInfo queryPageList(ErpProjectReportBo bo, PageQuery pageQuery) { + MPJLambdaWrapper lqw = buildQueryWrapper(bo); + Page result = baseMapper.selectCustomErpProjectReportVoList(pageQuery.build(), lqw); + return TableDataInfo.build(result); + } /** * 查询符合条件的项目周报信息列表 @@ -71,21 +71,27 @@ public class ErpProjectReportServiceImpl implements IErpProjectReportService { private MPJLambdaWrapper buildQueryWrapper(ErpProjectReportBo bo) { Map params = bo.getParams(); MPJLambdaWrapper 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 ids, Boolean isValid) { - if(isValid){ + if (isValid) { //TODO 做一些业务上的校验,判断是否需要校验 } return baseMapper.deleteByIds(ids) > 0; diff --git a/ruoyi-modules/ruoyi-oa/src/main/resources/mapper/oa/erp/ErpProjectReportMapper.xml b/ruoyi-modules/ruoyi-oa/src/main/resources/mapper/oa/erp/ErpProjectReportMapper.xml index f31353d3..900372e4 100644 --- a/ruoyi-modules/ruoyi-oa/src/main/resources/mapper/oa/erp/ErpProjectReportMapper.xml +++ b/ruoyi-modules/ruoyi-oa/src/main/resources/mapper/oa/erp/ErpProjectReportMapper.xml @@ -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} + From 387967167df149b820e3af450e762a88f0473824 Mon Sep 17 00:00:00 2001 From: Yangk Date: Thu, 4 Dec 2025 10:12:52 +0800 Subject: [PATCH 3/3] =?UTF-8?q?add=E9=A1=B9=E7=9B=AE=E5=94=AE=E5=90=8E?= =?UTF-8?q?=E4=BF=A1=E6=81=AF=E5=B7=A5=E4=BD=9C=E6=B5=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/ErpAfterSalesController.java | 11 ++ .../oa/erp/domain/bo/ErpAfterSalesBo.java | 17 ++ .../oa/erp/service/IErpAfterSalesService.java | 8 + .../impl/ErpAfterSalesServiceImpl.java | 158 ++++++++++++++---- 4 files changed, 159 insertions(+), 35 deletions(-) diff --git a/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/controller/ErpAfterSalesController.java b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/controller/ErpAfterSalesController.java index d452016c..0ef6d794 100644 --- a/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/controller/ErpAfterSalesController.java +++ b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/controller/ErpAfterSalesController.java @@ -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 submitAndFlowStart(@Validated(AddGroup.class) @RequestBody ErpAfterSalesBo bo) { + return R.ok(erpAfterSalesService.submitAndFlowStart(bo)); + } + } diff --git a/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/domain/bo/ErpAfterSalesBo.java b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/domain/bo/ErpAfterSalesBo.java index 3da4e06d..d45df539 100644 --- a/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/domain/bo/ErpAfterSalesBo.java +++ b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/domain/bo/ErpAfterSalesBo.java @@ -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 materialCostsList; + /** + * 流程定义编码 + */ + private String flowCode; + + /** + * 流程变量 前端会提交一个元素{'entity': {业务详情数据对象}} + */ + private Map variables; + + /** + * 业务扩展参数 + */ + private RemoteFlowInstanceBizExt bizExt; + } diff --git a/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/service/IErpAfterSalesService.java b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/service/IErpAfterSalesService.java index 386b5e46..6c4418f2 100644 --- a/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/service/IErpAfterSalesService.java +++ b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/service/IErpAfterSalesService.java @@ -66,4 +66,12 @@ public interface IErpAfterSalesService { * @return 是否删除成功 */ Boolean deleteWithValidByIds(Collection ids, Boolean isValid); + + /** + * 提交售后信息并启动流程 + * @param bo + * @return + */ + ErpAfterSalesVo submitAndFlowStart(ErpAfterSalesBo bo); + } diff --git a/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/service/impl/ErpAfterSalesServiceImpl.java b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/service/impl/ErpAfterSalesServiceImpl.java index afd8fe6c..0e6e3554 100644 --- a/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/service/impl/ErpAfterSalesServiceImpl.java +++ b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/service/impl/ErpAfterSalesServiceImpl.java @@ -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 laborEntities = laborCostsService.list( new LambdaQueryWrapper() .eq(ErpAfterSalesLaborCosts::getAfterSalesId, afterSalesId) ); - // 2.2 将 Entity 列表转换为 VO 列表 (核心修复点) List laborVos = MapstructUtils.convert(laborEntities, ErpAfterSalesLaborCostsVo.class); - // 2.3 塞入主表对象 vo.setLaborCostsList(laborVos); - // ============ 处理材料费 ============ - // 3.1 使用 list 方法查询出 Entity 列表 List materialEntities = materialCostsService.list( new LambdaQueryWrapper() .eq(ErpAfterSalesMaterialCosts::getAfterSalesId, afterSalesId) ); - // 3.2 将 Entity 列表转换为 VO 列表 List 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 laborBoList = bo.getLaborCostsList(); - // 使用 CollUtil.isNotEmpty 判断列表不为空 if (CollUtil.isNotEmpty(laborBoList)) { - // 将 BO 列表转为 Entity 列表 List laborList = MapstructUtils.convert(laborBoList, ErpAfterSalesLaborCosts.class); - // 遍历每个子对象,把主表 ID 填进去,建立外键关联 laborList.forEach(item -> item.setAfterSalesId(afterSalesId)); - // 批量保存 laborCostsService.saveBatch(laborList); } - // --- 处理子表 B:材料费用 --- List materialBoList = bo.getMaterialCostsList(); if (CollUtil.isNotEmpty(materialBoList)) { List 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() .eq(ErpAfterSalesLaborCosts::getAfterSalesId, afterSalesId)); @@ -223,7 +214,7 @@ public class ErpAfterSalesServiceImpl implements IErpAfterSalesService { if (CollUtil.isNotEmpty(laborBoList)) { List 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() .eq(ErpAfterSalesMaterialCosts::getAfterSalesId, afterSalesId)); - // 后新增新的 List materialBoList = bo.getMaterialCostsList(); if (CollUtil.isNotEmpty(materialBoList)) { List 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); + }); + } + + }