Przeglądaj źródła

费用审核状态机

Qchen 1 rok temu
rodzic
commit
69b2c0d52c

+ 2 - 0
commons/src/main/java/com/jzg/commons/entity/po/PtlAgreementCost.java

@@ -38,6 +38,8 @@ public class PtlAgreementCost extends BaseModel {
 
     private Integer approved;
 
+    private String reviewDescription;
+
     private Boolean isValid;
 
     private Boolean isEnabled;

+ 2 - 1
tenant/organization/src/main/java/com/jzg/organization/controller/AgreementController.java

@@ -13,6 +13,7 @@ import com.jzg.organization.service.PtlAgreementDeptService;
 import com.jzg.organization.service.PtlAgreementService;
 import io.swagger.v3.oas.annotations.Operation;
 import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.annotation.Resource;
 import org.springframework.beans.BeanUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.validation.annotation.Validated;
@@ -31,7 +32,7 @@ import java.util.List;
 @RequestMapping("/agreement")
 public class AgreementController extends BaseController {
 
-    @Autowired
+    @Resource
     private PtlAgreementService agreementService;
 
     @Autowired

+ 13 - 0
tenant/organization/src/main/java/com/jzg/organization/controller/PtlAgreementCostController.java

@@ -5,6 +5,7 @@ import com.jzg.commons.core.page.HttpResult;
 import com.jzg.commons.entity.dto.CostAgreementParam;
 import com.jzg.commons.entity.dto.PtlAgreementCostAdd;
 import com.jzg.commons.entity.dto.PtlAgreementCostEnd;
+import com.jzg.commons.request.RequestSingleParam;
 import com.jzg.organization.service.PtlAgreementCostService;
 import io.swagger.v3.oas.annotations.Operation;
 import io.swagger.v3.oas.annotations.tags.Tag;
@@ -65,6 +66,18 @@ public class PtlAgreementCostController {
         return HttpResult.ok(ptlAgreementCostService.queryByAgreementId(costAgreementParam));
     }
 
+    @Operation(summary = "协议费用管理审核成功")
+    @PostMapping("auditSuccess")
+    public HttpResult auditSuccess(@RequestSingleParam(value = "ids") @NotEmpty(message = "id不能为空") List<String> ids){
+        return ptlAgreementCostService.auditSuccess(ids) ? HttpResult.ok("审核通过") : HttpResult.error("审核失败");
+    }
+
+    @Operation(summary = "协议费用管理审核失败")
+    @PostMapping("auditFailed")
+    public HttpResult auditFailed(@RequestParam(value = "ids") @NotEmpty(message = "id不能为空") List<String> ids, @RequestParam(value = "reason") String reason){
+        return ptlAgreementCostService.auditFailed(ids,reason) ? HttpResult.ok("审核不通过") : HttpResult.error("审核失败");
+    }
+
 
 //    @Schema(description = "协议费用管理分页列表")
 //    @PostMapping("pageList")

+ 3 - 0
tenant/organization/src/main/java/com/jzg/organization/service/PtlAgreementCostService.java

@@ -29,6 +29,9 @@ public interface PtlAgreementCostService extends IService<PtlAgreementCost> {
 
     void updateAuditMethod(List<Long> ids);
 
+    boolean auditSuccess(List<String> ids);
+
+    boolean auditFailed(List<String> ids,String reason);
 
 
 }

+ 68 - 0
tenant/organization/src/main/java/com/jzg/organization/service/impl/PtlAgreementCostServiceImpl.java

@@ -6,6 +6,7 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.jzg.commons.constants.Constants;
 import com.jzg.commons.constants.ReturnInformation;
+import com.jzg.commons.core.base.StateResult;
 import com.jzg.commons.core.page.HttpResult;
 import com.jzg.commons.entity.dto.CostAgreementParam;
 import com.jzg.commons.entity.dto.PtlAgreementCostAdd;
@@ -16,13 +17,20 @@ import com.jzg.commons.entity.po.PtlAgreementCostType;
 import com.jzg.commons.entity.po.RuleConditionsVerify;
 import com.jzg.commons.entity.vo.PtlAgreementCostRuleVo;
 import com.jzg.commons.entity.vo.PtlAgreementCostVo;
+import com.jzg.commons.exception.SystemException;
 import com.jzg.commons.util.ListUtils;
 import com.jzg.organization.mapper.PtlAgreementCostMapper;
 import com.jzg.organization.service.PtlAgreementCostRuleService;
 import com.jzg.organization.service.PtlAgreementCostService;
 import com.jzg.organization.service.PtlAgreementCostTypeService;
+import com.jzg.organization.state.CostState;
+import com.jzg.organization.state.UserState;
+import com.jzg.organization.state.listener.CostStateListener;
 import jakarta.annotation.Resource;
 import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.statemachine.StateMachine;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.util.CollectionUtils;
@@ -44,6 +52,15 @@ public class PtlAgreementCostServiceImpl extends ServiceImpl<PtlAgreementCostMap
     @Resource
     private PtlAgreementCostMapper ptlAgreementCostMapper;
 
+
+
+    @Autowired
+    @Qualifier("costStateMachine")
+    private StateMachine<CostState.CostStateEnum, CostState.CostStateEvent> costStateMachine;
+
+    @Resource
+    private CostStateListener costStateListener;
+
     @Override
     @Transactional(rollbackFor = Exception.class)
     public HttpResult save(List<PtlAgreementCostAdd> costAddList) {
@@ -156,5 +173,56 @@ public class PtlAgreementCostServiceImpl extends ServiceImpl<PtlAgreementCostMap
         baseMapper.update(ptlAgreementCost,new LambdaQueryWrapper<>(PtlAgreementCost.class).in(PtlAgreementCost::getId,ids));
     }
 
+    @Override
+    @Transactional
+    public boolean auditSuccess(List<String> ids) {
+        for (String id : ids) {
+            PtlAgreementCost ptlAgreementCost = baseMapper.selectById(id);
+            if (ObjectUtil.isNull(ptlAgreementCost)) {
+                throw new SystemException("该条费用不存在,请检查");
+            }
+            if (ptlAgreementCost.getApproved() == 1) {
+                throw new SystemException("该条费用已审核通过,请勿重复操作");
+            }
+            if (ptlAgreementCost.getApproved() == 2) {
+                throw new SystemException("该条费用已审核不通过,请勿重复操作");
+            }
+            if (ptlAgreementCost.getApproved() == 0) {
+                StateResult stateResult = costStateListener.auditSuccess(ptlAgreementCost);
+                if (stateResult.isResult()) {
+                    ptlAgreementCost.setApproved(stateResult.getCurrentState());
+                    baseMapper.updateById(ptlAgreementCost);
+                }
+            }
+        }
+        return true;
+    }
+
+    @Override
+    @Transactional
+    public boolean auditFailed(List<String> ids, String reason) {
+        for (String id : ids) {
+            PtlAgreementCost ptlAgreementCost = baseMapper.selectById(id);
+            if (ObjectUtil.isNull(ptlAgreementCost)) {
+                throw new SystemException("该条费用不存在,请检查");
+            }
+            if (ptlAgreementCost.getApproved() == 1) {
+                throw new SystemException("该条费用已审核通过,请勿重复操作");
+            }
+            if (ptlAgreementCost.getApproved() == 2) {
+                throw new SystemException("该条费用已审核不通过,请勿重复操作");
+            }
+            if (ptlAgreementCost.getApproved() == 0) {
+                StateResult stateResult = costStateListener.auditFailed(ptlAgreementCost);
+                if (stateResult.isResult()) {
+                    ptlAgreementCost.setApproved(stateResult.getCurrentState());
+                    ptlAgreementCost.setReviewDescription(reason);
+                    baseMapper.updateById(ptlAgreementCost);
+                }
+            }
+        }
+        return true;
+    }
+
 
 }

+ 43 - 0
tenant/organization/src/main/java/com/jzg/organization/state/CostState.java

@@ -0,0 +1,43 @@
+package com.jzg.organization.state;
+
+/**
+ * @author quchen
+ * @date 2025/2/26 10:19
+ */
+
+public class CostState {
+
+    public enum CostStateEnum {
+        AUDIT_WAIT(0), // 待审核
+
+        AUDIT_SUCCESS(1), // 审核通过
+
+        AUDIT_FAILED(2); // 审核不通过
+
+        private final int value;
+
+        CostStateEnum(int value) {
+            this.value = value;
+        }
+        public int getValue() {
+            return value;
+        }
+
+        public static CostStateEnum fromValue(int value) {
+            for (CostStateEnum costStateEnum : CostStateEnum.values()) {
+                if (costStateEnum.getValue() == value) {
+                    return costStateEnum;
+                }
+            }
+            return null;
+        }
+    }
+
+    public enum CostStateEvent {
+        AUDIT_SUCCESS_EVENT, // 审核通过事件
+
+        AUDIT_FAILED_EVENT, // 审核不通过事件
+
+        AUDIT_WAIT_EVENT; // 待审核事件
+    }
+}

+ 76 - 0
tenant/organization/src/main/java/com/jzg/organization/state/config/CostStateConfig.java

@@ -0,0 +1,76 @@
+package com.jzg.organization.state.config;
+
+import com.jzg.organization.state.CostState;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.statemachine.StateMachine;
+import org.springframework.statemachine.config.EnableStateMachine;
+import org.springframework.statemachine.config.StateMachineBuilder;
+import org.springframework.statemachine.config.StateMachineConfigurerAdapter;
+import org.springframework.statemachine.config.builders.StateMachineStateConfigurer;
+import org.springframework.statemachine.config.builders.StateMachineTransitionConfigurer;
+
+import java.util.EnumSet;
+import java.util.Map;
+
+/**
+ * @author quchen
+ * @date 2025/2/26 10:30
+ */
+
+@Configuration
+public class CostStateConfig extends StateMachineConfigurerAdapter<CostState.CostStateEnum, CostState.CostStateEvent> {
+
+    @Bean(name = "costStateMachine")
+    public StateMachine<CostState.CostStateEnum, CostState.CostStateEvent> costStateMachine() throws Exception {
+        StateMachineBuilder.Builder<CostState.CostStateEnum, CostState.CostStateEvent> builder = StateMachineBuilder.builder();
+        builder.configureStates()
+                .withStates()
+                .initial(CostState.CostStateEnum.AUDIT_WAIT)
+                .states(EnumSet.allOf(CostState.CostStateEnum.class));
+        builder.configureTransitions()
+                .withExternal()
+                // 待审核 -> 审核通过
+                .source(CostState.CostStateEnum.AUDIT_WAIT).target(CostState.CostStateEnum.AUDIT_SUCCESS).event(CostState.CostStateEvent.AUDIT_SUCCESS_EVENT)
+                .and()
+                .withExternal()
+                // 待审核 -> 审核失败
+                .source(CostState.CostStateEnum.AUDIT_WAIT).target(CostState.CostStateEnum.AUDIT_FAILED).event(CostState.CostStateEvent.AUDIT_FAILED_EVENT)
+                .and()
+                .withExternal()
+                // 审核通过 -> 待审核
+                .source(CostState.CostStateEnum.AUDIT_SUCCESS).target(CostState.CostStateEnum.AUDIT_WAIT).event(CostState.CostStateEvent.AUDIT_WAIT_EVENT)
+                .and()
+                .withExternal()
+                // 审核失败 -> 待审核
+                .source(CostState.CostStateEnum.AUDIT_FAILED).target(CostState.CostStateEnum.AUDIT_WAIT).event(CostState.CostStateEvent.AUDIT_WAIT_EVENT);
+        return builder.build();
+    }
+//    @Override
+//    public void configure(StateMachineStateConfigurer<CostState.CostStateEnum, CostState.CostStateEvent> states) throws Exception {
+//        states.withStates()
+//                .initial(CostState.CostStateEnum.AUDIT_WAIT)
+//                .states(EnumSet.allOf(CostState.CostStateEnum.class));
+//    }
+//
+//    @Override
+//    public void configure(StateMachineTransitionConfigurer<CostState.CostStateEnum, CostState.CostStateEvent> transitions) throws Exception {
+//        transitions
+//                .withExternal()
+//                // 待审核 -> 审核通过
+//                .source(CostState.CostStateEnum.AUDIT_WAIT).target(CostState.CostStateEnum.AUDIT_SUCCESS).event(CostState.CostStateEvent.AUDIT_SUCCESS_EVENT)
+//                .and()
+//                .withExternal()
+//                // 待审核 -> 审核失败
+//                .source(CostState.CostStateEnum.AUDIT_WAIT).target(CostState.CostStateEnum.AUDIT_FAILED).event(CostState.CostStateEvent.AUDIT_FAILED_EVENT)
+//                .and()
+//                .withExternal()
+//                // 审核通过 -> 待审核
+//                .source(CostState.CostStateEnum.AUDIT_SUCCESS).target(CostState.CostStateEnum.AUDIT_WAIT).event(CostState.CostStateEvent.AUDIT_WAIT_EVENT)
+//                .and()
+//                .withExternal()
+//                // 审核失败 -> 待审核
+//                .source(CostState.CostStateEnum.AUDIT_FAILED).target(CostState.CostStateEnum.AUDIT_WAIT).event(CostState.CostStateEvent.AUDIT_WAIT_EVENT);
+//    }
+
+}

+ 80 - 0
tenant/organization/src/main/java/com/jzg/organization/state/listener/CostStateListener.java

@@ -0,0 +1,80 @@
+package com.jzg.organization.state.listener;
+
+import com.jzg.commons.core.base.StateResult;
+import com.jzg.commons.entity.po.PtlAgreementCost;
+import com.jzg.organization.state.CostState;
+import jakarta.annotation.Resource;
+import org.springframework.messaging.Message;
+import org.springframework.messaging.support.MessageBuilder;
+import org.springframework.statemachine.StateMachine;
+import org.springframework.statemachine.StateMachineEventResult;
+import org.springframework.statemachine.support.DefaultStateMachineContext;
+import org.springframework.stereotype.Component;
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+
+/**
+ * @author quchen
+ * @date 2025/2/26 10:57
+ */
+
+@Component
+public class CostStateListener {
+
+    @Resource
+    private StateMachine<CostState.CostStateEnum, CostState.CostStateEvent> costStateMachine;
+
+    private synchronized boolean sendEvent(Mono<Message<CostState.CostStateEvent>> message) {
+        AtomicBoolean result = new AtomicBoolean(false);
+        try {
+            costStateMachine.stop(); // 停止状态机
+            Message<CostState.CostStateEvent> block = message.block();
+            PtlAgreementCost ptlAgreementCost = (PtlAgreementCost) block.getHeaders().get("entity");
+            costStateMachine.getStateMachineAccessor().doWithAllRegions(accessor -> {
+                accessor.resetStateMachineReactively(new DefaultStateMachineContext<>(
+                        CostState.CostStateEnum.fromValue(ptlAgreementCost.getApproved()), // 目标状态
+                        null, // 当前事件(可以为 null)
+                        null, // 扩展上下文(可以为 null)
+                        null  // 转换历史(通常为 null)
+                )).block();
+            });
+            Mono<Void> startMono = costStateMachine.startReactively(); //启用状态机
+            startMono.block();
+
+            Flux<StateMachineEventResult<CostState.CostStateEnum, CostState.CostStateEvent>> stateMachineEventResultFlux = costStateMachine.sendEvent(message);
+            StateMachineEventResult<CostState.CostStateEnum, CostState.CostStateEvent> eventResult = stateMachineEventResultFlux.blockFirst();
+
+            if (eventResult != null && eventResult.getResultType() == StateMachineEventResult.ResultType.ACCEPTED) {
+                result.set(true);
+            }
+        } catch (Exception e) {
+
+        } finally {
+            costStateMachine.stopReactively();
+            return result.get();
+        }
+    }
+
+    private StateResult callEvent(PtlAgreementCost ptlAgreementCost,CostState.CostStateEvent event) {
+        StateResult stateResult = new StateResult();
+        Mono<Message<CostState.CostStateEvent>> message = Mono.just(MessageBuilder.withPayload(event).setHeader("entity",ptlAgreementCost).build());
+        stateResult.setResult(sendEvent(message));
+        stateResult.setCurrentState(costStateMachine.getState().getId().getValue());
+        return stateResult;
+    }
+
+    public StateResult auditSuccess(PtlAgreementCost ptlAgreementCost) {
+        return callEvent(ptlAgreementCost,CostState.CostStateEvent.AUDIT_SUCCESS_EVENT);
+    }
+
+    public StateResult auditFailed(PtlAgreementCost ptlAgreementCost) {
+        return callEvent(ptlAgreementCost,CostState.CostStateEvent.AUDIT_FAILED_EVENT);
+    }
+
+    public StateResult auditWait(PtlAgreementCost ptlAgreementCost) {
+        return callEvent(ptlAgreementCost,CostState.CostStateEvent.AUDIT_WAIT_EVENT);
+    }
+}
+

+ 3 - 0
tenant/organization/src/main/resources/application.yml

@@ -76,3 +76,6 @@ data-scope:
     - ptl_scheme_info
     - ptl_scheme
     - sys_activity
+logging:
+  level:
+    org.springframework.statemachine: DEBUG