You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

265 lines
11 KiB

  1. package com.example.demo.service.cash;
  2. import com.example.demo.Node.RefundApprovalNode;
  3. import com.example.demo.config.cash.RefundApprovalFlowConfig;
  4. import com.example.demo.domain.vo.cash.CashRecord;
  5. import com.example.demo.domain.vo.cash.Market;
  6. import com.example.demo.domain.vo.cash.RefundApprovalRecord;
  7. import com.example.demo.domain.vo.cash.User;
  8. import lombok.extern.slf4j.Slf4j;
  9. import org.springframework.stereotype.Service;
  10. import java.util.*;
  11. import java.util.concurrent.ConcurrentHashMap;
  12. import java.util.stream.Collectors;
  13. @Slf4j
  14. @Service
  15. public class RefundApprovalService {
  16. private final MarketService marketService;
  17. // 退款审批流程配置缓存
  18. private static final Map<String, RefundApprovalFlowConfig> REFUND_APPROVAL_FLOW_CONFIG = new ConcurrentHashMap<>();
  19. // 角色定义
  20. public static final String ROLE_REGIONAL_FINANCE = "REGIONAL_FINANCE";
  21. public static final String ROLE_REGIONAL_MANAGER = "REGIONAL_MANAGER";
  22. public static final String ROLE_HEADQUARTERS_FINANCE = "HEADQUARTERS_FINANCE";
  23. public static final String ROLE_EXECUTOR = "EXECUTOR";
  24. public static final String ROLE_SUBMITTER = "SUBMITTER";
  25. public RefundApprovalService(MarketService marketService) {
  26. this.marketService = marketService;
  27. initializeRefundFlowConfigs();
  28. }
  29. // 初始化退款审批流程配置(基于地区ID)
  30. private void initializeRefundFlowConfigs() {
  31. // 获取市场部下的所有具体市场ID
  32. Set<Integer> specificMarketIds = marketService.getSpecificMarketIdsUnderMarketDepartment();
  33. // 为每个具体市场创建审批流程
  34. for (Integer marketId : specificMarketIds) {
  35. Market market = marketService.getMarketById(marketId);
  36. if (market != null) {
  37. List<RefundApprovalNode> flowNodes = createRefundFlowForMarket(market);
  38. REFUND_APPROVAL_FLOW_CONFIG.put(marketId.toString(),
  39. new RefundApprovalFlowConfig(market.getName() + "退款审批流程", flowNodes));
  40. }
  41. }
  42. // 创建通用审批流程(用于没有特定配置的市场)
  43. List<RefundApprovalNode> commonRefundFlow = createCommonRefundFlow();
  44. REFUND_APPROVAL_FLOW_CONFIG.put("COMMON", new RefundApprovalFlowConfig("通用退款审批流程", commonRefundFlow));
  45. log.info("退款审批流程配置初始化完成,共配置{}个流程", REFUND_APPROVAL_FLOW_CONFIG.size());
  46. }
  47. private List<RefundApprovalNode> createRefundFlowForMarket(Market market) {
  48. Set<Integer> marketAndChildrenIds = new HashSet<>();
  49. marketAndChildrenIds.add(market.getId());
  50. marketAndChildrenIds.addAll(marketService.getAllChildrenIds(market.getId()));
  51. List<RefundApprovalNode> nodes = new ArrayList<>();
  52. nodes.add(new RefundApprovalNode("地区财务审核", 1, new String[]{ROLE_REGIONAL_FINANCE}, marketAndChildrenIds, true));
  53. nodes.add(new RefundApprovalNode("地区负责人审核", 2, new String[]{ROLE_REGIONAL_MANAGER}, marketAndChildrenIds, true));
  54. nodes.add(new RefundApprovalNode("总部财务审核", 3, new String[]{ROLE_HEADQUARTERS_FINANCE}, null, true)); // 总部不限制地区
  55. nodes.add(new RefundApprovalNode("执行人处理", 4, new String[]{ROLE_EXECUTOR}, null, true)); // 执行人不限制地区
  56. return nodes;
  57. }
  58. private List<RefundApprovalNode> createCommonRefundFlow() {
  59. List<RefundApprovalNode> nodes = new ArrayList<>();
  60. nodes.add(new RefundApprovalNode("地区财务审核", 1, new String[]{ROLE_REGIONAL_FINANCE}, null, true));
  61. nodes.add(new RefundApprovalNode("地区负责人审核", 2, new String[]{ROLE_REGIONAL_MANAGER}, null, true));
  62. nodes.add(new RefundApprovalNode("总部财务审核", 3, new String[]{ROLE_HEADQUARTERS_FINANCE}, null, true));
  63. nodes.add(new RefundApprovalNode("执行人处理", 4, new String[]{ROLE_EXECUTOR}, null, true));
  64. return nodes;
  65. }
  66. // 获取适合订单的审批流程(基于地区ID)
  67. private RefundApprovalFlowConfig getSuitableFlowConfig(CashRecord cashRecord) {
  68. Integer marketId = cashRecord.getPrimaryMarketId();
  69. if (marketId != null) {
  70. // 优先根据具体地区ID获取流程
  71. RefundApprovalFlowConfig specificConfig = REFUND_APPROVAL_FLOW_CONFIG.get(marketId.toString());
  72. if (specificConfig != null) {
  73. return specificConfig;
  74. }
  75. // 如果该市场没有特定配置,查找父级市场的配置
  76. Market market = marketService.getMarketById(marketId);
  77. if (market != null && market.getParentId() != null) {
  78. RefundApprovalFlowConfig parentConfig = REFUND_APPROVAL_FLOW_CONFIG.get(market.getParentId().toString());
  79. if (parentConfig != null) {
  80. return parentConfig;
  81. }
  82. }
  83. }
  84. // 默认返回通用流程
  85. return REFUND_APPROVAL_FLOW_CONFIG.get("COMMON");
  86. }
  87. // 获取用户有权限审批的订单状态(基于地区ID)
  88. public List<Integer> getUserVisibleStatuses(User user, CashRecord cashRecord) {
  89. if (!cashRecord.isRefundOrder()) {
  90. return new ArrayList<>();
  91. }
  92. RefundApprovalFlowConfig flowConfig = getSuitableFlowConfig(cashRecord);
  93. if (flowConfig != null) {
  94. return flowConfig.getVisibleStatuses(user, cashRecord.getPrimaryMarketId());
  95. }
  96. log.warn("未找到适合订单地区{}的退款审批流程配置", cashRecord.getPrimaryMarketId());
  97. return new ArrayList<>();
  98. }
  99. // 检查用户是否有权限审批指定订单(基于地区ID)
  100. public boolean canUserApproveOrder(User user, CashRecord cashRecord) {
  101. if (!cashRecord.isRefundOrder() || !cashRecord.isInApprovalProcess()) {
  102. return false;
  103. }
  104. RefundApprovalFlowConfig flowConfig = getSuitableFlowConfig(cashRecord);
  105. if (flowConfig != null) {
  106. return flowConfig.canUserApproveNode(user, cashRecord.getCurrentApprovalLevel(), cashRecord.getPrimaryMarketId());
  107. }
  108. return false;
  109. }
  110. // 检查用户是否可以撤回订单(只有提交人可以在第一个审批节点前撤回)
  111. public boolean canUserWithdrawOrder(User user, CashRecord cashRecord) {
  112. if (!cashRecord.isRefundOrder()) {
  113. return false;
  114. }
  115. // 只有订单提交人才能撤回
  116. boolean isSubmitter = cashRecord.getSubmitterId() != null &&
  117. cashRecord.getSubmitterId().equals(user.getId());
  118. return isSubmitter && cashRecord.canWithdraw();
  119. }
  120. // 提交退款审批
  121. public boolean submitRefundApproval(User user, CashRecord cashRecord, String approvalResult, String comments) {
  122. if (!canUserApproveOrder(user, cashRecord)) {
  123. log.warn("用户{}没有权限审批退款订单{}", user.getId(), cashRecord.getId());
  124. return false;
  125. }
  126. // 创建审批记录
  127. RefundApprovalRecord record = new RefundApprovalRecord();
  128. record.setCashRecordId(cashRecord.getId());
  129. record.setApprovalLevel(cashRecord.getCurrentApprovalLevel());
  130. record.setApproverId(user.getId());
  131. record.setApproverName(user.getName());
  132. record.setApprovalResult(approvalResult);
  133. record.setComments(comments);
  134. record.setApprovalTime(new Date());
  135. // 更新订单状态
  136. boolean approved = "APPROVED".equals(approvalResult);
  137. Integer nextStatus = cashRecord.getNextStatus(approved);
  138. cashRecord.setStatus(nextStatus);
  139. cashRecord.setUpdateTime(new Date());
  140. cashRecord.setAuditId(user.getId());
  141. cashRecord.setAuditTime(new Date());
  142. if (!approved) {
  143. cashRecord.setRejectReason(comments);
  144. }
  145. log.info("用户{}审批退款订单{},结果:{},新状态:{}",
  146. user.getName(), cashRecord.getId(), approvalResult, nextStatus);
  147. return true;
  148. }
  149. // 撤回退款订单(在第一个审批节点前)
  150. public boolean withdrawRefundOrder(User user, CashRecord cashRecord, String withdrawReason) {
  151. if (!canUserWithdrawOrder(user, cashRecord)) {
  152. log.warn("用户{}不能撤回退款订单{}", user.getId(), cashRecord.getId());
  153. return false;
  154. }
  155. // 创建撤回记录
  156. RefundApprovalRecord record = new RefundApprovalRecord();
  157. record.setCashRecordId(cashRecord.getId());
  158. record.setApprovalLevel(cashRecord.getCurrentApprovalLevel());
  159. record.setApproverId(user.getId());
  160. record.setApproverName(user.getName());
  161. record.setIsWithdrawal(true);
  162. record.setWithdrawnBy(user.getId());
  163. record.setWithdrawReason(withdrawReason);
  164. record.setWithdrawTime(new Date());
  165. // 更新订单状态为撤回
  166. boolean success = cashRecord.withdraw();
  167. if (success) {
  168. cashRecord.setUpdateTime(new Date());
  169. log.info("用户{}撤回退款订单{},原因:{}", user.getName(), cashRecord.getId(), withdrawReason);
  170. }
  171. return success;
  172. }
  173. // 重新提交撤回的退款订单
  174. public boolean resubmitRefundOrder(User user, CashRecord cashRecord) {
  175. if (!cashRecord.canResubmit()) {
  176. log.warn("退款订单{}不能重新提交", cashRecord.getId());
  177. return false;
  178. }
  179. // 检查用户是否是原提交人
  180. boolean isSubmitter = cashRecord.getSubmitterId() != null &&
  181. cashRecord.getSubmitterId().equals(user.getId());
  182. if (!isSubmitter) {
  183. log.warn("用户{}不是订单{}的提交人,不能重新提交", user.getId(), cashRecord.getId());
  184. return false;
  185. }
  186. boolean success = cashRecord.resubmit();
  187. if (success) {
  188. cashRecord.setUpdateTime(new Date());
  189. log.info("用户{}重新提交退款订单{}", user.getName(), cashRecord.getId());
  190. }
  191. return success;
  192. }
  193. // 获取下一个审批节点信息
  194. public RefundApprovalNode getNextApprovalNode(CashRecord cashRecord) {
  195. RefundApprovalFlowConfig flowConfig = getSuitableFlowConfig(cashRecord);
  196. if (flowConfig != null) {
  197. return flowConfig.getNextNode(cashRecord.getCurrentApprovalLevel());
  198. }
  199. return null;
  200. }
  201. // 动态添加退款审批流程配置
  202. public void addRefundFlowConfig(String marketId, RefundApprovalFlowConfig flowConfig) {
  203. REFUND_APPROVAL_FLOW_CONFIG.put(marketId, flowConfig);
  204. log.info("成功添加地区{}的退款审批流程配置:{}", marketId, flowConfig.getFlowName());
  205. }
  206. // 获取所有退款审批流程配置
  207. public Map<String, RefundApprovalFlowConfig> getAllRefundFlowConfigs() {
  208. return new HashMap<>(REFUND_APPROVAL_FLOW_CONFIG);
  209. }
  210. // 根据地区名称初始化审批流程配置
  211. public void initializeFlowForMarketName(String marketName) {
  212. Market market = marketService.getMarketByName(marketName);
  213. if (market != null) {
  214. List<RefundApprovalNode> flowNodes = createRefundFlowForMarket(market);
  215. REFUND_APPROVAL_FLOW_CONFIG.put(market.getId().toString(),
  216. new RefundApprovalFlowConfig(market.getName() + "退款审批流程", flowNodes));
  217. log.info("为地区{}初始化退款审批流程配置", marketName);
  218. }
  219. }
  220. }